# -*- coding: utf-8 -*-

"""
smallwp unittests for mediawiki template processing.
"""

import testhelpers

from smallwp import templates


class ExprTemplateTest(testhelpers.WPDataTest):
	def testParse(self):
		tNode = templates.getTree("{{#ifexpr: T<=0|a=b|b|c}}").children[0]
		args = templates.Arguments.fromNode({}, tNode)
		self.assertEqual(args[0], "ifexpr: T<=0")
		self.assertEqual(args["a"], "b")
		self.assertEqual(args[1], "b")

	def _assertAbs(self, inData, expected):
		context = templates.WikitextContext(self.wpData, {"LAT": inData})
		tNode = templates.getTree("{{abs|{{{LAT|0}}}}}")
		self.assertEqual(templates.makeWikitext(context, tNode), expected)

	def testPositiveIntAbs(self):
		self._assertAbs("70", "70.0")
	
	def testNegativeIntAbs(self):
		self._assertAbs("-70", "70.0")

	def testZeroAbs(self):
		self._assertAbs("0", "0.0")


class MiscArgumentTest(testhelpers.WPDataTest):
	def testPlainArgs(self):
		tNode = templates.getTree("{{T|a|b|c}}").children[0]
		args = templates.Arguments.fromNode({}, tNode)
		self.assertEqual(args[0], "T")
		self.assertEqual(args[1], "a")
		self.assertEqual(args[2], "b")
		self.assertEqual(args[3], "c")
		self.assertEqual(args[4], "")
	

	def testContext(self):
		tNode = templates.getTree("{{foo|x=1|y=2|c}}")
		context = templates.WikitextContext(self.wpData,
			templates.Arguments.fromNode(templates.WikitextContext(self.wpData), 
				tNode.children[0]))
		tree = templates.getTree("{{{x}}}{{{1}}}{{{y}}}{{{2}}}{{{3}}}{{{4|d}}}")
		self.assertEqual(templates.makeWikitext(context, tree), '1122cd')


class MiscParseTest(testhelpers.WPDataTest):
	def testFourBracesOpen(self):
		templates._buildTree(
			"<includeonly>{{{{SUBJECTPAGENAME}}/Doku}}</includeonly>", )

	def testFourBracesClose(self):
		tree = templates._buildTree("{{x{{ab}}}}")
		self.assertEqual(tree.children[0].children[0], "x")
		self.assertEqual(tree.children[0].children[1].children[0], "ab")

	def testInsanity(self):
		tree = templates._buildTree("{{{!}}")
		self.assertEqual(tree.children[1].children[0], "!")

	def testSimple(self):
		tree = templates._buildTree("{{Navigationsleiste Städte"
			" und Gemeinden im Kreis Nordfriesland}}")
		self.assertEqual(len(tree.children), 1)


class _ExpansionTest(testhelpers.WPDataTest):
	
	def _getExpansion(self, template, context={}):
		if not isinstance(context, templates.WikitextContext):
			context = templates.WikitextContext(
				self.wpData, context, pageName="Testing")
		tree = templates._buildTree(template)
		return templates.makeWikitext(context, tree)


class WhitespaceTest(_ExpansionTest):
	def testNamedOrNotnamed(self):
		context = templates.WikitextContext(self.wpData)
		args = templates.Arguments.fromNode(context, 
			templates._buildTree("{{foo|x= a  }}").children[0])
		self.assertEqual(self._getExpansion("{{{x}}}, {{{1}}}$", args),
			"a, a  $")


class SwitchTest(_ExpansionTest):
	def testBadSyntax(self):
		context = templates.WikitextContext(self.wpData, {})
		self.assertEqual(self._getExpansion("{{#foo 0|a|b|c}}", context), "")
		self.failUnless(context.errorFlag)

	def testSimpleHit(self):
		self.assertEqual(self._getExpansion(
			"{{#switch: {{{arg}}} |a=urks|b=klonk|#default = nop }}",
			{"arg": "a"}), "urks")

	def testSimpleHit2(self):
		self.assertEqual(self._getExpansion(
			"{{#switch: {{{arg}}} |a=urks|b=klonk|#default = nop }}",
			{"arg": "b"}), "klonk")

	def testSimpleMiss(self):
		self.assertEqual(self._getExpansion(
			"{{#switch: {{{arg}}} |a=urks|b=klonk|#default = nop }}",
			{"arg": "foo"}), "nop")
	
	def testDoubleEx(self):
		self.assertEqual(self._getExpansion(
			"{{#switch: {{{arg}}} |a={{{nunk}}}}}",
			{"arg": "a", "nunk": "holla"}), "holla")
	
	def testFallthrough(self):
		self.assertEqual(self._getExpansion(
			"{{#switch: {{{arg}}} |a|b|c=anything}}",
			{"arg": "b"}), "anything")


class ExprTest(_ExpansionTest):
	def testSimple(self):
		self.assertEqual(self._getExpansion("{{#expr:4+4}}", {}), "8")
	
	def testExpanded(self):
		self.assertEqual(self._getExpansion("{{#expr:{{{n}}}+4}}", 
			{"n":"34"}), "38")

	def testExpNumArg(self):
		self.assertEqual(self._getExpansion(
			"{{#expr: exp 0}}", {}),
			"1")
	
	def testExpExprArg(self):
		self.assertEqual(self._getExpansion(
			"{{#expr: exp ln 5}}", {}),
			"5")

	def testComplexFunctionCall(self):
		self.assertEqual(self._getExpansion(
			"{{#expr: 5+exp ln (2+3)}}", {}),
			"10")

	def testWithNamed(self):
		self.assertEqual(self._getExpansion(
			"{{#expr: trunc pi+trunc e}}", {}),
			"5")
	
	def testWithPower(self):
		self.assertEqual(self._getExpansion(
			"{{#expr: 2^4+1}}", {}),
			"17")

	def testFunnyBoolean(self):
		self.assertEqual(self._getExpansion(
			"{{#expr:(35.51147 >= 0) and (35.51147 <= 100) and (7.88583544304"
				">= 0) and (7.88583544304 <=100)}}", {}),
			"1")

	def testComparsion(self):
		self.assertEqual(self._getExpansion(
			"{{#expr: 12<13}}", {}),
			"1")

	def testLogicalOperator(self):
		self.assertEqual(self._getExpansion(
			"{{#expr: (12<13) and (1>2)}}", {}),
			"0")

	def testBooleanExprTrue(self):
		self.assertEqual(self._getExpansion("{{#ifexpr: 0{{{Einwohner|}}} > 0"
			" and 0{{{Einwohner|}}} < 10000 | Dorf | Undorf}}",
			{"Einwohner": "10"}), "Dorf")

	def testBooleanExprFalse(self):
		self.assertEqual(self._getExpansion("{{#ifexpr: 0{{{Einwohner|}}} > 0"
			" and 0{{{Einwohner|}}} < 10000 | Dorf | Undorf}}",
			{"Einwohner": "100000"}), "Undorf")

	def testRound(self):
		self.assertEqual(self._getExpansion("{{#ifexpr: 0{{{Einwohner|}}}"
			" > 0 and 0{{{Einwohner|}}} < 10000 | {{#expr:{{{Einwohner}}} round 0}}"
			" | {{formatnum:{{{Einwohner}}}}} }}",
			{"Einwohner": "100000"}), "100000")


class IferrorTest(_ExpansionTest):
	def testSimpleErrorFire(self):
		self.assertEqual(self._getExpansion(
				"{{#iferror: {{#expr: 1*{{{Para|}}}}} | Keine Zahl | Zahl }}",
				{"Para": "abc"}),
			"Keine Zahl")
	
	def testSimpleErrorNoFire(self):
		self.assertEqual(self._getExpansion(
				"{{#iferror: {{#expr: 1*{{{Para|}}}}} | Keine Zahl | Zahl }}",
				{"Para": "23"}),
			"Zahl")

	def testNoCasesNoFire(self):
		self.assertEqual(self._getExpansion(
				"{{#iferror: {{#expr: 1*{{{Para|}}}}}}}",
				{"Para": "23"}),
			"23")

	def testNoCasesFire(self):
		self.assertEqual(self._getExpansion(
				"{{#iferror: {{#expr: 1*{{{Para|}}}}} }}",
				{"Para": "abc"}),
			"")

	def testOneCaseFire(self):
		self.assertEqual(self._getExpansion(
				"{{#iferror: {{#expr: 1*{{{Para|}}}}} | Keine Zahl}}",
				{"Para": "abc"}),
			"Keine Zahl")

	def testOneCaseNoFire(self):
		self.assertEqual(self._getExpansion(
				"{{#iferror: {{#expr: 1*{{{Para|}}}}} | Keine Zahl }}",
				{"Para": "23"}),
			"23")


class IfTest(_ExpansionTest):
	def testNonExistingVar(self):
		self.assertEqual(self._getExpansion(
				"{{#if: {{{par}}}|Ja|Nein}}", {}),
			"Ja")

	def testFalse(self):
		self.assertEqual(self._getExpansion(
				"{{#if: {{{par}}}|Ja|Nein}}", {"par": ""}),
			"Nein")

	def testTrue(self):
		self.assertEqual(self._getExpansion(
				"{{#if: {{{par}}}|Ja|Nein}}", {"par": "xy"}),
			"Ja")

	def testOneParFalse(self):
		self.assertEqual(self._getExpansion(
				"{{#if: {{{par}}}|Ja}}", {"par": ""}),
			"")


class TitlepartsTest(_ExpansionTest):
	def testSimple(self):
		self.assertEqual(self._getExpansion(
			"{{#titleparts:Hilfe:Verweis/a/b|0}}", {}),
			"Hilfe:Verweis/a/b")

	def testCut1(self):
		self.assertEqual(self._getExpansion(
			"{{#titleparts:Hilfe:Verweis/a/b|1}}", {}),
			"Hilfe:Verweis")
	
	def testCut2(self):
		self.assertEqual(self._getExpansion(
			"{{#titleparts:Hilfe:Verweis/a/b|2}}", {}),
			"Hilfe:Verweis/a")
	
	def testWithstart1(self):
		self.assertEqual(self._getExpansion(
			"{{#titleparts:Hilfe:Verweis/a/b|1|2}}", {}),
			"a")

	def testWithstart2(self):
		self.assertEqual(self._getExpansion(
			"{{#titleparts:Hilfe:Verweis/a/b|2|2}}", {}),
			"a/b")
	
	def testNegative(self):
		self.assertEqual(self._getExpansion(
			"{{#titleparts:Hilfe:Verweis/a/b|1|-1}}", {}),
			"b")
	
	def testWitherror(self):
		self.assertEqual(self._getExpansion(
			"{{#titleparts:Hilfe:Verweis/a/b|foo|-1}}", {}),
			"Hilfe:Verweis/a/b")
	
	def testExpanded(self):
		self.assertEqual(self._getExpansion(
			"{{#titleparts:{{{path}}}|{{{num}}}|{{{start}}}}}", 
				{"path": "Hilfe:Verweis/a/b", "num": "1", "start": "-1"}),
			"b")


class InclusionsTest(_ExpansionTest):
	def testNoinc(self):
		self.assertEqual(self._getExpansion(
				"ab <noinclude>quatsch</noinclude> cd", {}),
			"ab  cd")

	def testInconly(self):
		self.assertEqual(self._getExpansion(
				"ab <includeonly>quatsch</includeonly> cd", {}),
			"ab quatsch cd")

	def testOnlyinc(self):
		self.assertEqual(templates.formatTemplate(
				"ab <onlyinclude>quatsch</onlyinclude> cd",
				self.wpData, "oincpage"),
			"quatsch")


class BuiltinTemplatesTest(_ExpansionTest):
	def testSitename(self):
		self.assertEqual(self._getExpansion("{{SITENAME}}", {}),
			"Small Wikipedia Server")

	def testSitenameNocase(self):
		self.assertEqual(self._getExpansion("{{SiTeNaMe}}", {}),
			"Small Wikipedia Server")
	
	def testServer(self):
		# should make sure we're not using some user config here
		self.assertEqual(self._getExpansion("{{Server}}", {}),
			"http://127.0.0.1:8780") 
	
	def testServername(self):
		self.assertEqual(self._getExpansion("{{ServerName}}", {}),
			"127.0.0.1")

	def testContentlanguage(self):
		self.assertEqual(self._getExpansion("{{contentlanguage}}", {}),
			"ts")
	
	def testPagename(self):
		self.assertEqual(self._getExpansion("{{Pagename}}", 
			templates.WikitextContext(self.wpData, pageName="knack:Urks & Murks")),
			"Urks & Murks")

	def testPagenamee(self):
		self.assertEqual(self._getExpansion("{{PAGENAMEE}}", 
			templates.WikitextContext(self.wpData, pageName="knack:Urks & Murks")),
			"Urks_&_Murks")


class MagicNamespaceTest(_ExpansionTest):
	def testSample(self):
		self.assertEqual(self._getExpansion("/{{NS:0}}/{{NS:1}}/{{ns:media}}/"
			"{{NS:300}}/{{ns: image }}"),
			"//Alt/Media/Invalid Namespace/Arch")


class CombinedTest(_ExpansionTest):
	def testParmPart(self):
		self.assertEqual(self._getExpansion("""{{#ifeq:/{{{2|}}}
			|{{#titleparts:/{{{2|}}}|1|{{#expr:1+{{{1|1}}}}}}}
			|
			|{{#titleparts:/{{{2|}}}|1|{{#expr:1+{{{1|1}}}}}}}
			}}""", {}),
			"")
	
	_istZahl = """{{#ifeq:{{#iferror:{{#expr:{{#switch:{{{2|}}}
| Z+ | N = abs trunc
| R+ = abs
| R- = -abs
| Z = trunc
| Z- = -abs trunc
| R | default = }}({{{1}}}) = 1*({{{1}}}) {{#if:{{{3|}}} | round ({{{3}}}) }} }} | }}  | 1 | 1 | }}"""
	
	def testIstZahlSimpleYes(self):
		self.assertEqual(self._getExpansion(self._istZahl, {'1': "23"}), 
			"1")

	def testIstZahlSimpleNo(self):
		self.assertEqual(self._getExpansion(self._istZahl, {'1': "gobbel"}), 
			"")

	def testIstZahlNegativeNo(self):
		self.assertEqual(self._getExpansion(self._istZahl, 
			{'1': "-1", "2": "Z+"}), 
			"")

	def testIstZahlNaturalNo(self):
		self.assertEqual(self._getExpansion(self._istZahl, 
			{'1': "3.14", "2": "N"}), 
			"")

	def testIstZahlIntYes(self):
		self.assertEqual(self._getExpansion(self._istZahl, 
			{'1': "-17", "2": "Z"}), 
			"1")

	def testIstZahlLeadingZero(self):
		self.assertEqual(self._getExpansion(self._istZahl, 
			{'1': "0398", "2": "Z"}), 
			"1")


class WithDataTest(_ExpansionTest):
	def testNowikiHonored(self):
		exp = self._getExpansion("{{Muh:Arb}}")
		self.failUnless("Bartonka." in exp)
		self.failUnless("<nowiki>{{Muh:Arb}}</nowiki>" in exp)



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