import os
os.environ["GAVO_OOTTEST"] = "dontcare"

from gavo import api
from gavo import utils
from gavo.helpers import testhelpers


FAKE_REGISTRY = {
	"ivo://exa/foo": "",
	"ivo://exa": "vg:authority",
	"ivo://exa/..../here": "",
}


RD = api.getRD("ivoidval/q")
modName = os.path.join(RD.resdir, "bin/validator")
userModule, _ = utils.loadPythonModule(modName)


for toImport in """validateURI mc ERR_URI ERR_SCHEME CODE_BROKEN
		CODE_BADVAL ERR_AUTHORITY CODE_MISSING CODE_BADCHAR ERR_RESKEY""".split():
	globals()[toImport] = getattr(userModule, toImport)


userModule.getResType = lambda ivorn: FAKE_REGISTRY[ivorn.lower()]


class URITest(testhelpers.VerboseTest):
	def assertErrorCodePresent(self, uri, major, minor):
		foundCodes = set(r[2] for r in validateURI(uri) if r[0]=="ERROR")
		expected = mc(major, minor)
		self.assertTrue(expected in foundCodes,
			"%s not in %s"%(expected, foundCodes))

	def assertWarningsPresent(self, uri, *warnings):
		foundWarnings = set(r[1] for r in validateURI(uri) if r[0]=="WARNING")
		for w in warnings:
			self.assertTrue(w in foundWarnings,
				"'%s' not in %s"%(w, foundWarnings))

	def assertOkAndInfos(self, uri, *expectedInfos):
		res = validateURI(uri)
		for r in res:
			if r[0]=="ERROR":
				self.fail("Expected valid ivoid but encountered error '%s'"%
					r[1])

		foundInfos = set(r[1] for r in res if r[0]=="INFO")
		for info in expectedInfos:
			self.assertTrue(info in foundInfos, "Info '%s' missing in %s"%(
				info, foundInfos))


class PlainErrorsTest(URITest):
	def testEmpty(self):
		self.assertErrorCodePresent("", ERR_SCHEME, CODE_MISSING)

	def nonASCII(self):
		self.assertErrorCodePresent("ivo://exa/\xe4", ERR_SCHEME, CODE_MISSING)

	def testBeyondRepair(self):
		self.assertErrorCodePresent("]:&%!", ERR_URI, CODE_BROKEN)
	
	def testWrongScheme(self):
		self.assertErrorCodePresent("http://foo.bar", ERR_SCHEME, CODE_BADVAL)
	
	def testShortURI(self):
		self.assertErrorCodePresent("ivo://", ERR_AUTHORITY, CODE_MISSING)

	def testEmptyAuthority(self):
		self.assertErrorCodePresent("ivo:///key", ERR_AUTHORITY, CODE_MISSING)

	def testWildAuthority(self):
		self.assertErrorCodePresent("ivo://my@authority",
			ERR_AUTHORITY, CODE_BADCHAR)

	def testShortAuthority(self):
		self.assertErrorCodePresent("ivo://my", ERR_AUTHORITY, CODE_BADVAL)

	def testEmptySegment(self):
		self.assertErrorCodePresent("ivo://exa/bar//foo", ERR_RESKEY, CODE_BADVAL)

	def testDotSegment(self):
		self.assertErrorCodePresent("ivo://exa/bar/../x", ERR_RESKEY, CODE_BADVAL)

	def testTrailingSlash(self):
		self.assertErrorCodePresent("ivo://exa/bar/", ERR_RESKEY, CODE_BADVAL)

	def testPercentEncodingInPath(self):
		self.assertErrorCodePresent("ivo://exa/bar%65/u",
			ERR_RESKEY, CODE_BADCHAR)


class ClassificationTest(URITest):
	def testWithFragment(self):
		self.assertOkAndInfos("iVo://exa/foo#part",
			"Validating as a full ivoid")

	def testWithQuery(self):
		self.assertOkAndInfos("ivo://exa/foo?bar",
			"Validating as a full ivoid")
	
	def testRegistryReference(self):
		self.assertOkAndInfos("ivo://exa/foo",
			"Validating as a Registry reference")

	def testAuthority(self):
		self.assertOkAndInfos("ivo://exa",
			"Validating as an authority ID")


class ValidTests(URITest):
	def testManyDots(self):
		self.assertOkAndInfos("ivo://exa/..../here")


class MiscTests(URITest):
	def testReservedInKey(self):
		self.assertWarningsPresent("ivo://exa/one!two",
			"Sub-delimiter found in resource key; this ivoid must only"
			" be used with specialised clients")

	def testNoUTF8Query(self):
		self.assertWarningsPresent("ivo://exa/bar?%cf",
			"Percent-encoded characters in query part are invalid utf-8")

	def testNoUTF8Query(self):
		self.assertWarningsPresent("ivo://exa/bar#%cf",
			"Percent-encoded characters in fragment part are invalid utf-8")



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