"""
Tests related to building and running cores.

This should probably take quite a bit more from servicetest.py; tests
more concerned with interfacing the cores should go there, anyway
"""

#c Copyright 2008-2024, the GAVO project <gavo@ari.uni-heidelberg.de>
#c
#c This program is free software, covered by the GNU GPL.  See the
#c COPYING file in the source distribution.


from gavo.helpers import testhelpers

from gavo import base
from gavo import rscdesc
from gavo import svcs
from gavo import utils
from gavo.helpers import trialhelpers
from gavo.protocols import scs

import tresc


class DbCoreTest(testhelpers.VerboseTest):
	def testColumnQuerying(self):
		c = base.parseFromString(svcs.DBCore,
			"""<dbCore queriedTable="//tap#columns"/>""")
		it = svcs.CoreArgs(c.inputTable, {"size": "20", "table_name": "foo"}, None)
		self.assertEqual(
			c._getSQLWhere(it, svcs.emptyQueryMeta), (
				'(table_name=%(table_name0)s) AND ("size"=%(size0)s)',
				{'table_name0': 'foo', 'size0': '20'}))


class PythonCoreTest(testhelpers.VerboseTest):
	def testBasic(self):
		svc = base.resolveCrossId("data/cores#pc")
		res = trialhelpers.runSvcWith(svc, "form",
				dict(opre="1", opim=1, powers=["2 3 4"])
			).getPrimaryTable()
		self.assertEqual(res.rows[0]["re"], 0)
		self.assertEqual(res.rows[1]["im"], 2.0)
		self.assertAlmostEqual(res.rows[2]["log_value"], 1.3862943611198906)
		self.assertEqual(len(res.rows), 3)

	def testDefaulting(self):
		svc = base.resolveCrossId("data/cores#pc")
		res = trialhelpers.runSvcWith(svc, "form", dict(opre="1", opim=1)
			).getPrimaryTable()
		self.assertEqual(len(res), 3)

	def testMissing(self):
		svc = base.resolveCrossId("data/cores#pc")
		self.assertRaisesWithMsg(base.ValidationError,
			"Field opre: Required parameter 'opre' missing.",
			trialhelpers.runSvcWith,
			(svc, "form", dict(opim=1, powers=[2,3,4])))


class CustomCoreTest(testhelpers.VerboseTest):
	def testRunning(self):
		svc = base.resolveCrossId("data/cores#cc")
		res = trialhelpers.runSvcWith(svc, "qp", dict(x="10"))
		self.assertEqual(res, ('text/plain', 'xxxxxxxxxx'))

	def testInputTable(self):
		core = base.resolveCrossId("data/cores#cc").core
		self.assertEqual(
			core.inputTable.inputKeys.getColumnByName("x").type,
			"integer")

	def testInputTableWithRDDef(self):
		core = base.parseFromString(rscdesc.RD,
			"""<resource schema="data">
				<service id="u"><customCore module="testcore" id="hu">
				<inputTable>
					<inputKey name="y" type="text"/></inputTable></customCore>
			</service></resource>""").getById("hu")
		self.assertEqual(
			core.inputTable.inputKeys.getColumnByName("y").type,
			"text")

	def testMissingModuleAttribute(self):
		self.assertRaisesWithMsg(
			base.StructureError,
			'At IO:\'<resource schema="data"> <service id="u"><customCore/...\','
			" (2, 33): Attribute module is mandatory",
			base.parseFromString,
			(rscdesc.RD,
			"""<resource schema="data">
				<service id="u"><customCore/></service></resource>"""))
	
	def testMissingModuleFile(self):
		self.assertRaisesWithMsg(
			base.StructureError,
			utils.EqualingRE(r'At IO:\'<resource schema="data"> <service id="u"><customCore ...\', \(2, 48\): Cannot load custom core .*/_gavo_test/inputs/data/knenk: \[Errno 2\] No such file or directory: \'.*/_gavo_test/inputs/data/knenk.py\''),
			base.parseFromString,
			(rscdesc.RD,
			"""<resource schema="data">
				<service id="u"><customCore module="knenk"/></service></resource>"""))

	def testBadModuleFile(self):
		with testhelpers.testFile(
				"borken.py",
				"return\n",
				inDir=base.getConfig("inputsDir") / "data"):
			self.assertRaisesWithMsg(
				base.StructureError,
				utils.EqualingRE(r'At IO:\'<resource schema="data"> <service id="u"><customCore ...\', \(2, 50\): Cannot load custom core .*/_gavo_test/inputs/data/borken: \'return\' outside function \(borken.py, line 1\)'),
				base.parseFromString,
				(rscdesc.RD,
				"""<resource schema="data">
					<service id="u"><customCore module="borken"/>
					</service></resource>"""))


class HumanCoordParseTest(testhelpers.VerboseTest,
		metaclass=testhelpers.SamplesBasedAutoTest):
	resources = [("fs", tresc.fakedSimbad)]

	def _runTest(self, sample):
		literal, parsed = sample
		self.assertEqual(scs.parseHumanSpoint(literal), parsed)
	
	samples = [
		("23.5, -21.75", (23.5, -21.75)),
		("23.5 -21.75", (23.5, -21.75)),
		("23 30, 11 15 30.6", (352.5, 11.2585)),
		("23:30:45, 11:15:30.6", (352.6875, 11.2585)),
		("Aldebaran",  (68.9375, 16.46875)),]

	def testException(self):
		self.assertRaisesWithMsg(base.ValidationError,
			"Unidentified Field: $&& zefixx is neither a RA,DEC pair nor"
			" a simbad resolvable object.",
			scs.parseHumanSpoint,
			("$&& zefixx",))


class FancyQueryCoreTest(testhelpers.VerboseTest):
	def testBasic(self):
		svc = base.parseFromString(svcs.Service,
			r"""<service id="c" allowed="api">
				<meta name="id">testing 1 2 3</meta>
				<fancyQueryCore queriedTable="//tap#tables"
				query="select table_name, '\metaString{id}' as id
						from tap_schema.tables %s">
					<outputTable autoCols="table_name">
						<outputField name="id" type="text"/>
					</outputTable>
					<condDesc buildFrom="table_name"/>
				</fancyQueryCore>
			</service>""")
		rows = trialhelpers.runSvcWith(
			svc, "api", {"table_name": "tap_schema.tables"}).getPrimaryTable().rows
		self.assertEqual(
			rows,
			[{'table_name': 'tap_schema.tables', 'id': 'testing 1 2 3'}])


if __name__=="__main__":
	testhelpers.main(DbCoreTest)
