Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tests.py 56KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547
  1. from __future__ import with_statement
  2. import os
  3. import sys
  4. import warnings
  5. from distutils.version import LooseVersion
  6. import operator
  7. from unittest import TestCase
  8. import django
  9. from django import template
  10. from django.core.exceptions import ImproperlyConfigured
  11. from django.template import Context, RequestContext
  12. from django.test import RequestFactory
  13. from classytags import arguments
  14. from classytags import core
  15. from classytags import exceptions
  16. from classytags import helpers
  17. from classytags import parser
  18. from classytags import utils
  19. from classytags import values
  20. from classytags.blocks import BlockDefinition
  21. from classytags.blocks import VariableBlockName
  22. from classytags.compat import compat_next
  23. from classytags.test.context_managers import SettingsOverride
  24. from classytags.test.context_managers import TemplateTags
  25. DJANGO_1_4_OR_HIGHER = (
  26. LooseVersion(django.get_version()) >= LooseVersion('1.4')
  27. )
  28. DJANGO_1_5_OR_HIGHER = (
  29. LooseVersion(django.get_version()) >= LooseVersion('1.5')
  30. )
  31. CLASSY_TAGS_DIR = os.path.abspath(os.path.dirname(__file__))
  32. class DummyTokens(list):
  33. def __init__(self, *tokens):
  34. super(DummyTokens, self).__init__(['dummy_tag'] + list(tokens))
  35. def split_contents(self):
  36. return self
  37. class DummyParser(object):
  38. @staticmethod
  39. def compile_filter(token):
  40. return utils.TemplateConstant(token)
  41. dummy_parser = DummyParser()
  42. class _Warning(object):
  43. def __init__(self, message, category, filename, lineno):
  44. self.message = message
  45. self.category = category
  46. self.filename = filename
  47. self.lineno = lineno
  48. def _collect_warnings(observe_warning, f, *args, **kwargs):
  49. def show_warning(message, category, filename, lineno, file=None,
  50. line=None):
  51. assert isinstance(message, Warning)
  52. observe_warning(
  53. _Warning(message.args[0], category, filename, lineno)
  54. )
  55. # Disable the per-module cache for every module otherwise if the warning
  56. # which the caller is expecting us to collect was already emitted it won't
  57. # be re-emitted by the call to f which happens below.
  58. for v in sys.modules.values(): # pragma: no cover
  59. if v is not None:
  60. try:
  61. v.__warningregistry__ = None
  62. except:
  63. # Don't specify a particular exception type to handle in case
  64. # some wacky object raises some wacky exception in response to
  65. # the setattr attempt.
  66. pass
  67. orig_filters = warnings.filters[:]
  68. orig_show = warnings.showwarning
  69. warnings.simplefilter('always')
  70. try:
  71. warnings.showwarning = show_warning
  72. result = f(*args, **kwargs)
  73. finally:
  74. warnings.filters[:] = orig_filters
  75. warnings.showwarning = orig_show
  76. return result
  77. class ClassytagsTests(TestCase):
  78. def failUnlessWarns(self, category, message, f, *args, **kwargs):
  79. warnings_shown = []
  80. result = _collect_warnings(warnings_shown.append, f, *args, **kwargs)
  81. if not warnings_shown: # pragma: no cover
  82. self.fail("No warnings emitted")
  83. first = warnings_shown[0]
  84. for other in warnings_shown[1:]: # pragma: no cover
  85. if ((other.message, other.category) !=
  86. (first.message, first.category)):
  87. self.fail("Can't handle different warnings")
  88. self.assertEqual(first.message, message)
  89. self.assertTrue(first.category is category)
  90. return result
  91. assertWarns = failUnlessWarns
  92. def _tag_tester(self, klass, templates):
  93. """
  94. Helper method to test a template tag by rendering it and checkout
  95. output.
  96. *klass* is a template tag class (subclass of core.Tag)
  97. *templates* is a sequence of a triple (template-string, output-string,
  98. context)
  99. """
  100. tag_message = ("Rendering of template %(in)r resulted in "
  101. "%(realout)r, expected %(out)r using %(ctx)r.")
  102. with TemplateTags(klass):
  103. for tpl, out, ctx in templates:
  104. t = template.Template(tpl)
  105. c = template.Context(ctx)
  106. s = t.render(c)
  107. self.assertEqual(s, out, tag_message % {
  108. 'in': tpl,
  109. 'out': out,
  110. 'ctx': ctx,
  111. 'realout': s,
  112. })
  113. for key, value in ctx.items():
  114. self.assertEqual(c.get(key), value)
  115. def test_simple_parsing(self):
  116. """
  117. Test very basic single argument parsing
  118. """
  119. options = core.Options(
  120. arguments.Argument('myarg'),
  121. )
  122. dummy_tokens = DummyTokens('myval')
  123. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  124. self.assertEqual(blocks, {})
  125. self.assertEqual(len(kwargs), 1)
  126. dummy_context = {}
  127. self.assertEqual(kwargs['myarg'].resolve(dummy_context), 'myval')
  128. def test_simple_parsing_too_many_arguments(self):
  129. options = core.Options(
  130. arguments.Argument('myarg'),
  131. )
  132. dummy_tokens = DummyTokens('myval', 'myval2')
  133. self.assertRaises(exceptions.TooManyArguments,
  134. options.parse, dummy_parser, dummy_tokens)
  135. def test_optional_default(self):
  136. """
  137. Test basic optional argument parsing
  138. """
  139. options = core.Options(
  140. arguments.Argument('myarg'),
  141. arguments.Argument('optarg', required=False, default=None),
  142. )
  143. dummy_tokens = DummyTokens('myval')
  144. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  145. self.assertEqual(blocks, {})
  146. self.assertEqual(len(kwargs), 2)
  147. dummy_context = {}
  148. self.assertEqual(kwargs['myarg'].resolve(dummy_context), 'myval')
  149. self.assertEqual(kwargs['optarg'].resolve(dummy_context), None)
  150. def test_optional_given(self):
  151. options = core.Options(
  152. arguments.Argument('myarg'),
  153. arguments.Argument('optarg', required=False, default=None),
  154. )
  155. dummy_tokens = DummyTokens('myval', 'optval')
  156. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  157. self.assertEqual(blocks, {})
  158. self.assertEqual(len(kwargs), 2)
  159. dummy_context = {}
  160. self.assertEqual(kwargs['myarg'].resolve(dummy_context), 'myval')
  161. self.assertEqual(kwargs['optarg'].resolve(dummy_context), 'optval')
  162. def test_breakpoints_not_enough_arguments(self):
  163. """
  164. Test parsing with breakpoints
  165. """
  166. options = core.Options(
  167. arguments.Argument('myarg'),
  168. 'as',
  169. arguments.Argument('varname'),
  170. 'using',
  171. arguments.Argument('using'),
  172. )
  173. dummy_tokens = DummyTokens('myval')
  174. self.assertRaises(exceptions.ArgumentRequiredError,
  175. options.parse, dummy_parser, dummy_tokens)
  176. def test_breakpoint_breakpoint_expected(self):
  177. options = core.Options(
  178. arguments.Argument('myarg'),
  179. 'as',
  180. arguments.Argument('varname'),
  181. 'using',
  182. arguments.Argument('using'),
  183. )
  184. dummy_tokens = DummyTokens('myval', 'myname')
  185. self.assertRaises(exceptions.BreakpointExpected,
  186. options.parse, dummy_parser, dummy_tokens)
  187. def test_breakpoint_breakpoint_expected_second(self):
  188. options = core.Options(
  189. arguments.Argument('myarg'),
  190. 'as',
  191. arguments.Argument('varname'),
  192. 'using',
  193. arguments.Argument('using'),
  194. )
  195. dummy_tokens = DummyTokens('myval', 'as', 'myname', 'something')
  196. self.assertRaises(exceptions.BreakpointExpected,
  197. options.parse, dummy_parser, dummy_tokens)
  198. def test_breakpoint_trailing(self):
  199. options = core.Options(
  200. arguments.Argument('myarg'),
  201. 'as',
  202. arguments.Argument('varname', required=False),
  203. )
  204. dummy_tokens = DummyTokens('myval', 'as')
  205. self.assertRaises(exceptions.TrailingBreakpoint,
  206. options.parse, dummy_parser, dummy_tokens)
  207. def test_breakpoint_okay(self):
  208. options = core.Options(
  209. arguments.Argument('myarg'),
  210. 'as',
  211. arguments.Argument('varname'),
  212. 'using',
  213. arguments.Argument('using'),
  214. )
  215. dummy_tokens = DummyTokens('myval', 'as', 'myname', 'using',
  216. 'something')
  217. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  218. self.assertEqual(blocks, {})
  219. self.assertEqual(len(kwargs), 3)
  220. dummy_context = {}
  221. self.assertEqual(kwargs['myarg'].resolve(dummy_context), 'myval')
  222. self.assertEqual(kwargs['varname'].resolve(dummy_context), 'myname')
  223. self.assertEqual(kwargs['using'].resolve(dummy_context), 'something')
  224. def test_flag_true_value(self):
  225. """
  226. Test flag arguments
  227. """
  228. options = core.Options(
  229. arguments.Flag('myflag', true_values=['on'], false_values=['off'])
  230. )
  231. dummy_tokens = DummyTokens('on')
  232. dummy_context = {}
  233. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  234. self.assertEqual(blocks, {})
  235. self.assertEqual(kwargs['myflag'].resolve(dummy_context), True)
  236. def test_flag_false_value(self):
  237. options = core.Options(
  238. arguments.Flag('myflag', true_values=['on'], false_values=['off'])
  239. )
  240. dummy_tokens = DummyTokens('off')
  241. dummy_context = {}
  242. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  243. self.assertEqual(blocks, {})
  244. self.assertEqual(kwargs['myflag'].resolve(dummy_context), False)
  245. def test_flag_wrong_value(self):
  246. options = core.Options(
  247. arguments.Flag('myflag', true_values=['on'], false_values=['off'])
  248. )
  249. # test exceptions
  250. dummy_tokens = DummyTokens('myval')
  251. self.assertRaises(exceptions.InvalidFlag,
  252. options.parse, dummy_parser, dummy_tokens)
  253. def test_flag_wrong_value_no_false(self):
  254. options = core.Options(
  255. arguments.Flag('myflag', true_values=['on'])
  256. )
  257. dummy_tokens = DummyTokens('myval')
  258. self.assertRaises(exceptions.InvalidFlag,
  259. options.parse, dummy_parser, dummy_tokens)
  260. def test_flag_wrong_value_no_true(self):
  261. options = core.Options(
  262. arguments.Flag('myflag', false_values=['off'])
  263. )
  264. dummy_tokens = DummyTokens('myval')
  265. self.assertRaises(exceptions.InvalidFlag,
  266. options.parse, dummy_parser, dummy_tokens)
  267. self.assertRaises(ImproperlyConfigured, arguments.Flag, 'myflag')
  268. def test_case_sensitive_flag_typo(self):
  269. # test case sensitive flag
  270. options = core.Options(
  271. arguments.Flag('myflag', true_values=['on'], default=False,
  272. case_sensitive=True)
  273. )
  274. dummy_tokens = DummyTokens('On')
  275. dummy_context = {}
  276. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  277. self.assertEqual(blocks, {})
  278. self.assertEqual(kwargs['myflag'].resolve(dummy_context), False)
  279. def test_case_sensitive_flag_okay(self):
  280. options = core.Options(
  281. arguments.Flag(
  282. 'myflag',
  283. true_values=['on'],
  284. default=False,
  285. case_sensitive=True
  286. )
  287. )
  288. dummy_tokens = DummyTokens('on')
  289. dummy_context = {}
  290. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  291. self.assertEqual(blocks, {})
  292. self.assertEqual(kwargs['myflag'].resolve(dummy_context), True)
  293. def test_multiflag(self):
  294. # test multi-flag
  295. options = core.Options(
  296. arguments.Flag('flagone', true_values=['on'], default=False),
  297. arguments.Flag('flagtwo', false_values=['off'], default=True),
  298. )
  299. dummy_tokens = DummyTokens('On', 'On')
  300. dummy_context = {}
  301. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  302. self.assertEqual(blocks, {})
  303. self.assertEqual(kwargs['flagone'].resolve(dummy_context), True)
  304. self.assertEqual(kwargs['flagtwo'].resolve(dummy_context), True)
  305. def test_multi_value_single_value(self):
  306. """
  307. Test simple multi value arguments
  308. """
  309. options = core.Options(
  310. arguments.MultiValueArgument('myarg')
  311. )
  312. # test single token MVA
  313. dummy_tokens = DummyTokens('myval')
  314. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  315. self.assertEqual(blocks, {})
  316. self.assertEqual(len(kwargs), 1)
  317. dummy_context = {}
  318. # test resolving to list
  319. self.assertEqual(kwargs['myarg'].resolve(dummy_context), ['myval'])
  320. def test_multi_value_two_values(self):
  321. options = core.Options(
  322. arguments.MultiValueArgument('myarg')
  323. )
  324. # test double token MVA
  325. dummy_tokens = DummyTokens('myval', 'myval2')
  326. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  327. self.assertEqual(blocks, {})
  328. self.assertEqual(len(kwargs), 1)
  329. dummy_context = {}
  330. self.assertEqual(kwargs['myarg'].resolve(dummy_context),
  331. ['myval', 'myval2'])
  332. def test_multi_value_three_values(self):
  333. options = core.Options(
  334. arguments.MultiValueArgument('myarg')
  335. )
  336. # test triple token MVA
  337. dummy_tokens = DummyTokens('myval', 'myval2', 'myval3')
  338. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  339. self.assertEqual(blocks, {})
  340. self.assertEqual(len(kwargs), 1)
  341. dummy_context = {}
  342. self.assertEqual(kwargs['myarg'].resolve(dummy_context),
  343. ['myval', 'myval2', 'myval3'])
  344. def test_multi_value_max_values_single(self):
  345. # test max_values option
  346. options = core.Options(
  347. arguments.MultiValueArgument('myarg', max_values=2)
  348. )
  349. dummy_tokens = DummyTokens('myval')
  350. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  351. self.assertEqual(blocks, {})
  352. self.assertEqual(len(kwargs), 1)
  353. dummy_context = {}
  354. self.assertEqual(kwargs['myarg'].resolve(dummy_context), ['myval'])
  355. def test_multi_value_max_values_double(self):
  356. options = core.Options(
  357. arguments.MultiValueArgument('myarg', max_values=2)
  358. )
  359. dummy_tokens = DummyTokens('myval', 'myval2')
  360. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  361. self.assertEqual(blocks, {})
  362. self.assertEqual(len(kwargs), 1)
  363. dummy_context = {}
  364. self.assertEqual(kwargs['myarg'].resolve(dummy_context),
  365. ['myval', 'myval2'])
  366. def test_multi_value_max_values_too_many(self):
  367. options = core.Options(
  368. arguments.MultiValueArgument('myarg', max_values=2)
  369. )
  370. dummy_tokens = DummyTokens('myval', 'myval2', 'myval3')
  371. self.assertRaises(exceptions.TooManyArguments,
  372. options.parse, dummy_parser, dummy_tokens)
  373. def test_multi_value_no_resolve(self):
  374. # test no resolve
  375. options = core.Options(
  376. arguments.MultiValueArgument('myarg', resolve=False)
  377. )
  378. argparser = parser.Parser(options)
  379. dummy_tokens = DummyTokens('myval', "'myval2'")
  380. kwargs, blocks = argparser.parse(dummy_parser, dummy_tokens)
  381. self.assertEqual(blocks, {})
  382. dummy_context = {}
  383. self.assertEqual(kwargs['myarg'].resolve(dummy_context),
  384. ['myval', 'myval2'])
  385. def test_multi_value_defaults(self):
  386. # test default
  387. options = core.Options(
  388. arguments.MultiValueArgument('myarg', default=['hello', 'world']),
  389. )
  390. argparser = parser.Parser(options)
  391. dummy_tokens = DummyTokens()
  392. kwargs, blocks = argparser.parse(dummy_parser, dummy_tokens)
  393. self.assertEqual(blocks, {})
  394. dummy_context = {}
  395. self.assertEqual(kwargs['myarg'].resolve(dummy_context),
  396. ['hello', 'world'])
  397. def test_complex_all_arguments(self):
  398. """
  399. test a complex tag option parser
  400. """
  401. options = core.Options(
  402. arguments.Argument('singlearg'),
  403. arguments.MultiValueArgument('multiarg', required=False),
  404. 'as',
  405. arguments.Argument('varname', required=False),
  406. 'safe',
  407. arguments.Flag('safe', true_values=['on', 'true'], default=False)
  408. )
  409. # test simple 'all arguments given'
  410. dummy_tokens = DummyTokens(1, 2, 3, 'as', 4, 'safe', 'true')
  411. dummy_context = {}
  412. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  413. self.assertEqual(blocks, {})
  414. self.assertEqual(len(kwargs), 4)
  415. expected = [
  416. ('singlearg', 1),
  417. ('multiarg', [2, 3]),
  418. ('varname', 4),
  419. ('safe', True)
  420. ]
  421. for key, value in expected:
  422. self.assertEqual(kwargs[key].resolve(dummy_context), value)
  423. def test_complex_only_first_argument(self):
  424. options = core.Options(
  425. arguments.Argument('singlearg'),
  426. arguments.MultiValueArgument('multiarg', required=False),
  427. 'as',
  428. arguments.Argument('varname', required=False),
  429. 'safe',
  430. arguments.Flag('safe', true_values=['on', 'true'], default=False)
  431. )
  432. # test 'only first argument given'
  433. dummy_tokens = DummyTokens(1)
  434. dummy_context = {}
  435. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  436. self.assertEqual(blocks, {})
  437. self.assertEqual(len(kwargs), 4)
  438. expected = [
  439. ('singlearg', 1),
  440. ('multiarg', []),
  441. ('varname', None),
  442. ('safe', False)
  443. ]
  444. for key, value in expected:
  445. self.assertEqual(kwargs[key].resolve(dummy_context), value)
  446. def test_complext_first_and_last_argument(self):
  447. options = core.Options(
  448. arguments.Argument('singlearg'),
  449. arguments.MultiValueArgument('multiarg', required=False),
  450. 'as',
  451. arguments.Argument('varname', required=False),
  452. 'safe',
  453. arguments.Flag('safe', true_values=['on', 'true'], default=False)
  454. )
  455. # test first argument and last argument given
  456. dummy_tokens = DummyTokens(2, 'safe', 'false')
  457. dummy_context = {}
  458. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  459. self.assertEqual(blocks, {})
  460. self.assertEqual(len(kwargs), 4)
  461. expected = [
  462. ('singlearg', 2),
  463. ('multiarg', []),
  464. ('varname', None),
  465. ('safe', False)
  466. ]
  467. for key, value in expected:
  468. self.assertEqual(kwargs[key].resolve(dummy_context), value)
  469. def test_cycle(self):
  470. """
  471. This test re-implements django's cycle tag (because it's quite crazy)
  472. and checks if it works.
  473. """
  474. from itertools import cycle as itertools_cycle
  475. class Cycle(core.Tag):
  476. name = 'classy_cycle'
  477. options = core.Options(
  478. arguments.MultiValueArgument('values'),
  479. 'as',
  480. arguments.Argument('varname', required=False, resolve=False),
  481. )
  482. def render_tag(self, context, values, varname):
  483. if self not in context.render_context:
  484. context.render_context[self] = itertools_cycle(values)
  485. cycle_iter = context.render_context[self]
  486. value = compat_next(cycle_iter)
  487. if varname:
  488. context[varname] = value
  489. return value
  490. origtpl = template.Template(
  491. '{% for thing in sequence %}'
  492. '{% cycle "1" "2" "3" "4" %}'
  493. '{% endfor %}'
  494. )
  495. sequence = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  496. context = template.Context({'sequence': sequence})
  497. original = origtpl.render(context)
  498. with TemplateTags(Cycle):
  499. classytpl = template.Template(
  500. '{% for thing in sequence %}'
  501. '{% classy_cycle "1" "2" "3" "4" %}'
  502. '{% endfor %}'
  503. )
  504. classy = classytpl.render(context)
  505. self.assertEqual(original, classy)
  506. origtpl = template.Template(
  507. '{% for thing in sequence %}'
  508. '{% cycle "1" "2" "3" "4" as myvarname %}'
  509. '{% endfor %}'
  510. )
  511. sequence = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  512. context = template.Context({'sequence': sequence})
  513. original = origtpl.render(context)
  514. with TemplateTags(Cycle):
  515. classytpl = template.Template(
  516. '{% for thing in sequence %}'
  517. '{% classy_cycle "1" "2" "3" "4" as myvarname %}'
  518. '{% endfor %}'
  519. )
  520. classy = classytpl.render(context)
  521. self.assertEqual(original, classy)
  522. def test_naming(self):
  523. # test implicit naming
  524. class MyTag(core.Tag):
  525. pass
  526. lib = template.Library()
  527. lib.tag(MyTag)
  528. msg = "'my_tag' not in %s" % lib.tags.keys()
  529. self.assertTrue('my_tag' in lib.tags, msg)
  530. # test explicit naming
  531. class MyTag2(core.Tag):
  532. name = 'my_tag_2'
  533. lib = template.Library()
  534. lib.tag(MyTag2)
  535. msg = "'my_tag_2' not in %s" % lib.tags.keys()
  536. self.assertTrue('my_tag_2' in lib.tags, msg)
  537. # test named registering
  538. lib = template.Library()
  539. lib.tag('my_tag_3', MyTag)
  540. msg = "'my_tag_3' not in %s" % lib.tags.keys()
  541. self.assertTrue('my_tag_3' in lib.tags, msg)
  542. msg = "'my_tag' in %s" % lib.tags.keys()
  543. self.assertTrue('my_tag' not in lib.tags, msg)
  544. lib = template.Library()
  545. lib.tag('my_tag_4', MyTag2)
  546. msg = "'my_tag_4' not in %s" % lib.tags.keys()
  547. self.assertTrue('my_tag_4' in lib.tags, msg)
  548. msg = "'my_tag2' in %s" % lib.tags.keys()
  549. self.assertTrue('my_tag2' not in lib.tags, msg)
  550. def test_hello_world(self):
  551. class Hello(core.Tag):
  552. options = core.Options(
  553. arguments.Argument('name', required=False, default='world'),
  554. 'as',
  555. arguments.Argument('varname', required=False, resolve=False)
  556. )
  557. def render_tag(self, context, name, varname):
  558. output = 'hello %s' % name
  559. if varname:
  560. context[varname] = output
  561. return ''
  562. return output
  563. tpls = [
  564. ('{% hello %}', 'hello world', {}),
  565. ('{% hello "classytags" %}', 'hello classytags', {}),
  566. ('{% hello as myvar %}', '', {'myvar': 'hello world'}),
  567. ('{% hello "my friend" as othervar %}', '',
  568. {'othervar': 'hello my friend'})
  569. ]
  570. self._tag_tester(Hello, tpls)
  571. def test_filters_in_arguments(self):
  572. class Filtered(core.Tag):
  573. options = core.Options(
  574. arguments.Argument('value'),
  575. )
  576. def render_tag(self, context, value):
  577. return value
  578. tpls = [
  579. ('{% filtered "hello" %}', 'hello', {}),
  580. ('{% filtered var %}', 'world', {'var': 'world'}),
  581. ('{% filtered var|default:"foo" %}', 'foo', {}),
  582. ]
  583. self._tag_tester(Filtered, tpls)
  584. def test_filtered_multi_keyword(self):
  585. class Filtered(core.Tag):
  586. options = core.Options(
  587. arguments.MultiKeywordArgument('kwargs'),
  588. )
  589. def render_tag(self, context, kwargs):
  590. return '|'.join('%s:%s' % (k, v) for k, v in kwargs.items())
  591. tpls = [
  592. ('{% filtered hello="world" %}', 'hello:world', {}),
  593. ('{% filtered hello=var %}', 'hello:world', {'var': 'world'}),
  594. ('{% filtered hello=var|default:"foo" %}', 'hello:foo', {}),
  595. ]
  596. self._tag_tester(Filtered, tpls)
  597. def test_blocks(self):
  598. class Blocky(core.Tag):
  599. options = core.Options(
  600. blocks=['a', 'b', 'c', 'd', 'e'],
  601. )
  602. def render_tag(self, context, **nodelists):
  603. tpl = "%(a)s;%(b)s;%(c)s;%(d)s;%(e)s"
  604. data = {}
  605. for key, value in nodelists.items():
  606. data[key] = value.render(context)
  607. return tpl % data
  608. templates = [
  609. ('{% blocky %}1{% a %}2{% b %}3{% c %}4{% d %}5{% e %}',
  610. '1;2;3;4;5', {},),
  611. ('{% blocky %}12{% b %}3{% c %}4{% d %}5{% e %}', '12;;3;4;5',
  612. {},),
  613. ('{% blocky %}123{% c %}4{% d %}5{% e %}', '123;;;4;5', {},),
  614. ('{% blocky %}1234{% d %}5{% e %}', '1234;;;;5', {},),
  615. ('{% blocky %}12345{% e %}', '12345;;;;', {},),
  616. ('{% blocky %}1{% a %}23{% c %}4{% d %}5{% e %}', '1;23;;4;5',
  617. {},),
  618. ('{% blocky %}1{% a %}23{% c %}45{% e %}', '1;23;;45;', {},),
  619. ]
  620. self._tag_tester(Blocky, templates)
  621. def test_astag(self):
  622. class Dummy(helpers.AsTag):
  623. options = core.Options(
  624. 'as',
  625. arguments.Argument('varname', resolve=False, required=False),
  626. )
  627. def get_value(self, context):
  628. return "dummy"
  629. templates = [
  630. ('{% dummy %}:{{ varname }}', 'dummy:', {},),
  631. ('{% dummy as varname %}:{{ varname }}', ':dummy', {},),
  632. ]
  633. self._tag_tester(Dummy, templates)
  634. def test_inclusion_tag(self):
  635. class Inc(helpers.InclusionTag):
  636. template = 'test.html'
  637. options = core.Options(
  638. arguments.Argument('var'),
  639. )
  640. def get_context(self, context, var):
  641. return {'var': var}
  642. templates = [
  643. ('{% inc var %}', 'inc', {'var': 'inc'},),
  644. ]
  645. self._tag_tester(Inc, templates)
  646. class Inc2(helpers.InclusionTag):
  647. template = 'test.html'
  648. templates = [
  649. ('{% inc2 %}', '', {},),
  650. ]
  651. self._tag_tester(Inc2, templates)
  652. def test_inclusion_tag_push_pop_context(self):
  653. class IncPollute(helpers.InclusionTag):
  654. template = 'test.html'
  655. options = core.Options(
  656. arguments.Argument('var')
  657. )
  658. def get_context(self, context, var):
  659. context.update({'var': 'polluted'})
  660. return context
  661. with TemplateTags(IncPollute):
  662. tpl = template.Template('{% inc_pollute var %}')
  663. ctx = template.Context({'var': 'test'})
  664. out = tpl.render(ctx)
  665. self.assertEqual(out, 'polluted')
  666. self.assertEqual(ctx['var'], 'polluted')
  667. # now enable pollution control
  668. IncPollute.push_context = True
  669. with TemplateTags(IncPollute):
  670. tpl = template.Template('{% inc_pollute var %}')
  671. ctx = template.Context({'var': 'test'})
  672. out = tpl.render(ctx)
  673. self.assertEqual(out, 'polluted')
  674. self.assertEqual(ctx['var'], 'test')
  675. def test_integer_variable(self):
  676. options = core.Options(
  677. arguments.IntegerArgument('integer', resolve=False),
  678. )
  679. # test okay
  680. with SettingsOverride(DEBUG=False):
  681. dummy_tokens = DummyTokens('1')
  682. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  683. dummy_context = {}
  684. self.assertEqual(kwargs['integer'].resolve(dummy_context), 1)
  685. # test warning
  686. dummy_tokens = DummyTokens('one')
  687. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  688. dummy_context = {}
  689. one = repr('one')
  690. message = arguments.IntegerValue.errors['clean'] % {'value': one}
  691. self.assertWarns(exceptions.TemplateSyntaxWarning,
  692. message, kwargs['integer'].resolve, dummy_context)
  693. self.assertEqual(kwargs['integer'].resolve(dummy_context),
  694. values.IntegerValue.value_on_error)
  695. # test exception
  696. with SettingsOverride(DEBUG=True):
  697. dummy_tokens = DummyTokens('one')
  698. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  699. dummy_context = {}
  700. message = values.IntegerValue.errors['clean'] % {
  701. 'value': repr('one')
  702. }
  703. self.assertRaises(template.TemplateSyntaxError,
  704. kwargs['integer'].resolve, dummy_context)
  705. # test the same as above but with resolving
  706. class IntegerTag(core.Tag):
  707. options = core.Options(
  708. arguments.IntegerArgument('integer')
  709. )
  710. def render_tag(self, context, integer):
  711. return integer
  712. with TemplateTags(IntegerTag):
  713. tpl = template.Template("{% integer_tag i %}")
  714. with SettingsOverride(DEBUG=False):
  715. # test okay
  716. context = template.Context({'i': '1'})
  717. self.assertEqual(tpl.render(context), '1')
  718. # test warning
  719. context = template.Context({'i': 'one'})
  720. message = values.IntegerValue.errors['clean'] % {
  721. 'value': repr('one')
  722. }
  723. self.assertWarns(exceptions.TemplateSyntaxWarning,
  724. message, tpl.render, context)
  725. self.assertEqual(int(tpl.render(context)),
  726. values.IntegerValue.value_on_error)
  727. # test exception
  728. with SettingsOverride(DEBUG=True):
  729. context = template.Context({'i': 'one'})
  730. message = arguments.IntegerValue.errors['clean'] % {'value': one}
  731. self.assertRaises(template.TemplateSyntaxError, tpl.render,
  732. context)
  733. # reset settings
  734. def test_not_implemented_errors(self):
  735. class Fail(core.Tag):
  736. pass
  737. class Fail2(helpers.AsTag):
  738. pass
  739. class Fail3(helpers.AsTag):
  740. options = core.Options(
  741. 'as',
  742. )
  743. class Fail4(helpers.AsTag):
  744. options = core.Options(
  745. 'as',
  746. arguments.Argument('varname', resolve=False),
  747. )
  748. if DJANGO_1_4_OR_HIGHER:
  749. exc_class = NotImplementedError
  750. else: # pragma: no cover
  751. exc_class = template.TemplateSyntaxError
  752. with TemplateTags(Fail, Fail2, Fail3, Fail4):
  753. context = template.Context({})
  754. tpl = template.Template("{% fail %}")
  755. self.assertRaises(exc_class, tpl.render, context)
  756. self.assertRaises(ImproperlyConfigured,
  757. template.Template, "{% fail2 %}")
  758. self.assertRaises(ImproperlyConfigured,
  759. template.Template, "{% fail3 %}")
  760. tpl = template.Template("{% fail4 as something %}")
  761. self.assertRaises(exc_class, tpl.render, context)
  762. def test_too_many_arguments(self):
  763. class NoArg(core.Tag):
  764. pass
  765. with TemplateTags(NoArg):
  766. self.assertRaises(exceptions.TooManyArguments,
  767. template.Template, "{% no_arg a arg %}")
  768. def test_choice_argument(self):
  769. options = core.Options(
  770. arguments.ChoiceArgument('choice',
  771. choices=['one', 'two', 'three']),
  772. )
  773. # this is settings dependant!
  774. with SettingsOverride(DEBUG=True):
  775. for good in ('one', 'two', 'three'):
  776. dummy_tokens = DummyTokens(good)
  777. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  778. dummy_context = {}
  779. self.assertEqual(kwargs['choice'].resolve(dummy_context), good)
  780. bad = 'four'
  781. dummy_tokens = DummyTokens(bad)
  782. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  783. dummy_context = {}
  784. self.assertRaises(template.TemplateSyntaxError,
  785. kwargs['choice'].resolve, dummy_context)
  786. with SettingsOverride(DEBUG=False):
  787. self.assertEqual(kwargs['choice'].resolve(dummy_context), 'one')
  788. # test other value class
  789. class IntegerChoiceArgument(arguments.ChoiceArgument):
  790. value_class = values.IntegerValue
  791. default = 2
  792. options = core.Options(
  793. IntegerChoiceArgument('choice', choices=[1, 2, 3],
  794. default=default),
  795. )
  796. with SettingsOverride(DEBUG=True):
  797. for good in ('1', '2', '3'):
  798. dummy_tokens = DummyTokens(good)
  799. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  800. dummy_context = {}
  801. self.assertEqual(kwargs['choice'].resolve(dummy_context),
  802. int(good))
  803. bad = '4'
  804. dummy_tokens = DummyTokens(bad)
  805. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  806. dummy_context = {}
  807. self.assertRaises(template.TemplateSyntaxError,
  808. kwargs['choice'].resolve, dummy_context)
  809. with SettingsOverride(DEBUG=False):
  810. self.assertEqual(kwargs['choice'].resolve(dummy_context), default)
  811. # reset settings
  812. def test_keyword_argument(self):
  813. class KeywordArgumentTag(core.Tag):
  814. name = 'kwarg_tag'
  815. options = core.Options(
  816. arguments.KeywordArgument('named', defaultkey='defaultkey'),
  817. )
  818. def render_tag(self, context, named):
  819. return '%s:%s' % (
  820. list(named.keys())[0], list(named.values())[0]
  821. )
  822. ctx = {'key': 'thekey', 'value': 'thevalue'}
  823. templates = [
  824. ("{% kwarg_tag key='value' %}", 'key:value', ctx),
  825. ("{% kwarg_tag 'value' %}", 'defaultkey:value', ctx),
  826. ("{% kwarg_tag key=value %}", 'key:thevalue', ctx),
  827. ("{% kwarg_tag value %}", 'defaultkey:thevalue', ctx),
  828. ]
  829. self._tag_tester(KeywordArgumentTag, templates)
  830. class KeywordArgumentTag2(KeywordArgumentTag):
  831. name = 'kwarg_tag'
  832. options = core.Options(
  833. arguments.KeywordArgument(
  834. 'named',
  835. defaultkey='defaultkey',
  836. resolve=False,
  837. required=False,
  838. default='defaultvalue'
  839. ),
  840. )
  841. templates = [
  842. ("{% kwarg_tag %}", 'defaultkey:defaultvalue', ctx),
  843. ("{% kwarg_tag key='value' %}", 'key:value', ctx),
  844. ("{% kwarg_tag 'value' %}", 'defaultkey:value', ctx),
  845. ("{% kwarg_tag key=value %}", 'key:value', ctx),
  846. ("{% kwarg_tag value %}", 'defaultkey:value', ctx),
  847. ]
  848. self._tag_tester(KeywordArgumentTag2, templates)
  849. def test_multi_keyword_argument(self):
  850. opts = core.Options(
  851. arguments.MultiKeywordArgument('multi', max_values=2),
  852. )
  853. class MultiKeywordArgumentTag(core.Tag):
  854. name = 'multi_kwarg_tag'
  855. options = opts
  856. def render_tag(self, context, multi):
  857. items = sorted(multi.items())
  858. return ','.join(['%s:%s' % item for item in items])
  859. ctx = {'key': 'thekey', 'value': 'thevalue'}
  860. templates = [
  861. ("{% multi_kwarg_tag key='value' key2='value2' %}",
  862. 'key:value,key2:value2', ctx),
  863. ("{% multi_kwarg_tag key=value %}", 'key:thevalue', ctx),
  864. ]
  865. self._tag_tester(MultiKeywordArgumentTag, templates)
  866. dummy_tokens = DummyTokens('key="value"', 'key2="value2"',
  867. 'key3="value3"')
  868. self.assertRaises(exceptions.TooManyArguments,
  869. opts.parse, dummy_parser, dummy_tokens)
  870. def test_custom_parser(self):
  871. class CustomParser(parser.Parser):
  872. def parse_blocks(self):
  873. return
  874. options = core.Options(
  875. blocks=[
  876. ('end_my_tag', 'nodelist'),
  877. ],
  878. parser_class=CustomParser
  879. )
  880. dummy_tokens = DummyTokens()
  881. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  882. self.assertEqual(blocks, {})
  883. def test_repr(self):
  884. class MyTag(core.Tag):
  885. name = 'mytag'
  886. tag = MyTag(dummy_parser, DummyTokens())
  887. self.assertEqual('<Tag: mytag>', repr(tag))
  888. def test_non_required_multikwarg(self):
  889. options = core.Options(
  890. arguments.MultiKeywordArgument('multi', required=False),
  891. )
  892. dummy_tokens = DummyTokens()
  893. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  894. self.assertTrue('multi' in kwargs)
  895. self.assertEqual(kwargs['multi'], {})
  896. options = core.Options(
  897. arguments.MultiKeywordArgument('multi', required=False,
  898. default={'hello': 'world'}),
  899. )
  900. dummy_tokens = DummyTokens()
  901. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  902. self.assertTrue('multi' in kwargs)
  903. self.assertEqual(kwargs['multi'].resolve({}), {'hello': 'world'})
  904. def test_resolve_kwarg(self):
  905. class ResolveKwarg(core.Tag):
  906. name = 'kwarg'
  907. options = core.Options(
  908. arguments.KeywordArgument('named'),
  909. )
  910. def render_tag(self, context, named):
  911. return '%s:%s' % (
  912. list(named.keys())[0], list(named.values())[0]
  913. )
  914. class NoResolveKwarg(core.Tag):
  915. name = 'kwarg'
  916. options = core.Options(
  917. arguments.KeywordArgument('named', resolve=False),
  918. )
  919. def render_tag(self, context, named):
  920. return '%s:%s' % (
  921. list(named.keys())[0], list(named.values())[0]
  922. )
  923. resolve_templates = [
  924. ("{% kwarg key=value %}", "key:test", {'value': 'test'}),
  925. ("{% kwarg key='value' %}", "key:value", {'value': 'test'}),
  926. ]
  927. noresolve_templates = [
  928. ("{% kwarg key=value %}", "key:value", {'value': 'test'}),
  929. ]
  930. self._tag_tester(ResolveKwarg, resolve_templates)
  931. self._tag_tester(NoResolveKwarg, noresolve_templates)
  932. def test_kwarg_default(self):
  933. options = core.Options(
  934. arguments.KeywordArgument('kwarg', required=False,
  935. defaultkey='mykey'),
  936. )
  937. dummy_tokens = DummyTokens()
  938. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  939. self.assertTrue('kwarg' in kwargs)
  940. self.assertEqual(kwargs['kwarg'].resolve({}), {'mykey': None})
  941. options = core.Options(
  942. arguments.KeywordArgument('kwarg', required=False,
  943. default='hello'),
  944. )
  945. dummy_tokens = DummyTokens()
  946. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  947. self.assertTrue('kwarg' in kwargs)
  948. self.assertEqual(kwargs['kwarg'].resolve({}), {})
  949. options = core.Options(
  950. arguments.KeywordArgument('kwarg', required=False,
  951. default='hello', defaultkey='key'),
  952. )
  953. dummy_tokens = DummyTokens()
  954. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  955. self.assertTrue('kwarg' in kwargs)
  956. self.assertEqual(kwargs['kwarg'].resolve({}), {'key': 'hello'})
  957. def test_multikwarg_no_key(self):
  958. options = core.Options(
  959. arguments.MultiKeywordArgument('multi'),
  960. )
  961. with SettingsOverride(DEBUG=True):
  962. dummy_tokens = DummyTokens('value')
  963. self.assertRaises(template.TemplateSyntaxError,
  964. options.parse, dummy_parser, dummy_tokens)
  965. with SettingsOverride(DEBUG=False):
  966. dummy_tokens = DummyTokens('value')
  967. self.assertRaises(template.TemplateSyntaxError,
  968. options.parse, dummy_parser, dummy_tokens)
  969. def test_inclusion_tag_context_pollution(self):
  970. """
  971. Check the `keep_render_context` and `push_pop_context` attributes on
  972. InclusionTag work as advertised and prevent 'context pollution'
  973. """
  974. class NoPushPop(helpers.InclusionTag):
  975. template = 'inclusion.html'
  976. def get_context(self, context):
  977. return context.update({'pollution': True})
  978. class Standard(helpers.InclusionTag):
  979. template = 'inclusion.html'
  980. def get_context(self, context):
  981. return {'pollution': True}
  982. with TemplateTags(NoPushPop, Standard):
  983. # push pop pollution
  984. ctx1 = template.Context({'pollution': False})
  985. tpl1 = template.Template("{% no_push_pop %}")
  986. tpl1.render(ctx1)
  987. self.assertEqual(ctx1['pollution'], True)
  988. ctx2 = template.Context({'pollution': False})
  989. tpl2 = template.Template("{% standard %}")
  990. tpl2.render(ctx2)
  991. self.assertEqual(ctx2['pollution'], False)
  992. def test_named_block(self):
  993. class StartBlock(core.Tag):
  994. options = core.Options(
  995. arguments.Argument("myarg"),
  996. blocks=[
  997. BlockDefinition("nodelist",
  998. VariableBlockName("end_block %(value)s",
  999. 'myarg'),
  1000. "end_block")
  1001. ]
  1002. )
  1003. def render_tag(self, context, myarg, nodelist):
  1004. return "nodelist:%s;myarg:%s" % (nodelist.render(context),
  1005. myarg)
  1006. with TemplateTags(StartBlock):
  1007. ctx = template.Context()
  1008. tpl = template.Template(
  1009. "{% start_block 'hello' %}nodelist-content"
  1010. "{% end_block 'hello' %}"
  1011. )
  1012. output = tpl.render(ctx)
  1013. expected_output = 'nodelist:nodelist-content;myarg:hello'
  1014. self.assertEqual(output, expected_output)
  1015. ctx = template.Context({'hello': 'world'})
  1016. tpl = template.Template(
  1017. "{% start_block hello %}nodelist-content{% end_block hello %}"
  1018. )
  1019. output = tpl.render(ctx)
  1020. expected_output = 'nodelist:nodelist-content;myarg:world'
  1021. self.assertEqual(output, expected_output)
  1022. def test_fail_named_block(self):
  1023. vbn = VariableBlockName('endblock %(value)s', 'myarg')
  1024. self.assertRaises(ImproperlyConfigured, core.Options,
  1025. blocks=[BlockDefinition('nodelist', vbn)])
  1026. def test_named_block_noresolve(self):
  1027. class StartBlock(core.Tag):
  1028. options = core.Options(
  1029. arguments.Argument("myarg", resolve=False),
  1030. blocks=[
  1031. BlockDefinition("nodelist",
  1032. VariableBlockName("end_block %(value)s",
  1033. 'myarg'),
  1034. "end_block")
  1035. ]
  1036. )
  1037. def render_tag(self, context, myarg, nodelist):
  1038. return "nodelist:%s;myarg:%s" % (nodelist.render(context),
  1039. myarg)
  1040. with TemplateTags(StartBlock):
  1041. ctx = template.Context()
  1042. tpl = template.Template(
  1043. "{% start_block 'hello' %}nodelist-content"
  1044. "{% end_block 'hello' %}"
  1045. )
  1046. output = tpl.render(ctx)
  1047. expected_output = 'nodelist:nodelist-content;myarg:hello'
  1048. self.assertEqual(output, expected_output)
  1049. def test_strict_string(self):
  1050. options = core.Options(
  1051. arguments.StringArgument('string', resolve=False),
  1052. )
  1053. with SettingsOverride(DEBUG=False):
  1054. # test ok
  1055. dummy_tokens = DummyTokens('string')
  1056. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  1057. dummy_context = {}
  1058. self.assertEqual(
  1059. kwargs['string'].resolve(dummy_context), 'string'
  1060. )
  1061. # test warning
  1062. dummy_tokens = DummyTokens(1)
  1063. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  1064. dummy_context = {}
  1065. message = values.StrictStringValue.errors['clean'] % {
  1066. 'value': repr(1)
  1067. }
  1068. self.assertWarns(
  1069. exceptions.TemplateSyntaxWarning,
  1070. message,
  1071. kwargs['string'].resolve,
  1072. dummy_context
  1073. )
  1074. with SettingsOverride(DEBUG=True):
  1075. # test exception
  1076. dummy_tokens = DummyTokens(1)
  1077. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  1078. dummy_context = {}
  1079. self.assertRaises(
  1080. template.TemplateSyntaxError,
  1081. kwargs['string'].resolve,
  1082. dummy_context
  1083. )
  1084. def test_get_value_for_context(self):
  1085. message = 'exception handled'
  1086. class MyException(Exception):
  1087. pass
  1088. class SuppressException(helpers.AsTag):
  1089. options = core.Options(
  1090. arguments.Argument('name'),
  1091. 'as',
  1092. arguments.Argument('var', resolve=False, required=False),
  1093. )
  1094. def get_value(self, context, name):
  1095. raise MyException(name)
  1096. def get_value_for_context(self, context, name):
  1097. try:
  1098. return self.get_value(context, name)
  1099. except MyException:
  1100. return message
  1101. dummy_tokens_with_as = DummyTokens('name', 'as', 'var')
  1102. tag = SuppressException(DummyParser(), dummy_tokens_with_as)
  1103. context = {}
  1104. self.assertEqual(tag.render(context), '')
  1105. self.assertEqual(context['var'], message)
  1106. dummy_tokens_no_as = DummyTokens('name')
  1107. tag = SuppressException(DummyParser(), dummy_tokens_no_as)
  1108. self.assertRaises(MyException, tag.render, {})
  1109. class MultiBreakpointTests(TestCase):
  1110. def test_optional_firstonly(self):
  1111. options = core.Options(
  1112. arguments.Argument('first'),
  1113. 'also',
  1114. 'using',
  1115. arguments.Argument('second', required=False),
  1116. )
  1117. # check only using the first argument
  1118. dummy_tokens = DummyTokens('firstval')
  1119. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  1120. self.assertEqual(blocks, {})
  1121. self.assertEqual(len(kwargs), 2)
  1122. dummy_context = {}
  1123. self.assertEqual(kwargs['first'].resolve(dummy_context), 'firstval')
  1124. self.assertEqual(kwargs['second'].resolve(dummy_context), None)
  1125. def test_optional_both(self):
  1126. options = core.Options(
  1127. arguments.Argument('first'),
  1128. 'also',
  1129. 'using',
  1130. arguments.Argument('second', required=False),
  1131. )
  1132. # check using both arguments and both breakpoints
  1133. dummy_tokens = DummyTokens('firstval', 'also', 'using', 'secondval')
  1134. kwargs, blocks = options.parse(dummy_parser, dummy_tokens)
  1135. self.assertEqual(blocks, {})
  1136. self.assertEqual(len(kwargs), 2)
  1137. dummy_context = {}
  1138. self.assertEqual(kwargs['first'].resolve(dummy_context), 'firstval')
  1139. self.assertEqual(kwargs['second'].resolve(dummy_context), 'secondval')
  1140. def test_partial_breakpoints(self):
  1141. options = core.Options(
  1142. arguments.Argument('first'),
  1143. 'also',
  1144. 'using',
  1145. arguments.Argument('second', required=False),
  1146. )
  1147. # check only using the first breakpoint
  1148. dummy_tokens = DummyTokens('firstval', 'also')
  1149. self.assertRaises(
  1150. exceptions.TrailingBreakpoint,
  1151. options.parse, dummy_parser, dummy_tokens
  1152. )
  1153. def test_partial_breakpoints_second(self):
  1154. options = core.Options(
  1155. arguments.Argument('first'),
  1156. 'also',
  1157. 'using',
  1158. arguments.Argument('second', required=False),
  1159. )
  1160. # check only using the second breakpoint
  1161. dummy_tokens = DummyTokens('firstval', 'using')
  1162. self.assertRaises(
  1163. exceptions.BreakpointExpected,
  1164. options.parse, dummy_parser, dummy_tokens
  1165. )
  1166. def test_partial_breakpoints_both(self):
  1167. options = core.Options(
  1168. arguments.Argument('first'),
  1169. 'also',
  1170. 'using',
  1171. arguments.Argument('second', required=False),
  1172. )
  1173. # check only using the first breakpoint
  1174. dummy_tokens = DummyTokens('firstval', 'also', 'secondval')
  1175. # should raise an exception
  1176. self.assertRaises(
  1177. exceptions.BreakpointExpected,
  1178. options.parse, dummy_parser, dummy_tokens
  1179. )
  1180. def test_partial_breakpoints_second_both(self):
  1181. options = core.Options(
  1182. arguments.Argument('first'),
  1183. 'also',
  1184. 'using',
  1185. arguments.Argument('second', required=False),
  1186. )
  1187. # check only using the second breakpoint
  1188. dummy_tokens = DummyTokens('firstval', 'using', 'secondval')
  1189. self.assertRaises(
  1190. exceptions.BreakpointExpected,
  1191. options.parse, dummy_parser, dummy_tokens
  1192. )
  1193. def test_partial_breakpoints_both_trailing(self):
  1194. options = core.Options(
  1195. arguments.Argument('first'),
  1196. 'also',
  1197. 'using',
  1198. arguments.Argument('second', required=False),
  1199. )
  1200. dummy_tokens = DummyTokens('firstval', 'also', 'using')
  1201. self.assertRaises(
  1202. exceptions.TrailingBreakpoint,
  1203. options.parse, dummy_parser, dummy_tokens
  1204. )
  1205. def test_add_options(self):
  1206. options1 = core.Options(
  1207. arguments.Argument('first')
  1208. )
  1209. options2 = core.Options(
  1210. arguments.Argument('second')
  1211. )
  1212. combined = options1 + options2
  1213. self.assertEqual(len(combined.options), 1, combined.options)
  1214. self.assertIn(None, combined.options)
  1215. self.assertEqual(len(combined.options[None]), 2, combined.options[None])
  1216. self.assertEqual(combined.all_argument_names, ['first', 'second'])
  1217. self.assertEqual(len(combined.blocks), 0, combined.blocks)
  1218. def test_add_options_blocks_first(self):
  1219. options1 = core.Options(
  1220. arguments.Argument('first'),
  1221. blocks=['a']
  1222. )
  1223. options2 = core.Options(
  1224. arguments.Argument('second'),
  1225. )
  1226. combined = options1 + options2
  1227. self.assertEqual(len(combined.blocks), 1, combined.blocks)
  1228. self.assertEqual(combined.blocks[0].alias, 'a')
  1229. self.assertEqual(combined.blocks[0].names, ('a', ))
  1230. def test_add_options_blocks_second(self):
  1231. options1 = core.Options(
  1232. arguments.Argument('first'),
  1233. )
  1234. options2 = core.Options(
  1235. arguments.Argument('second'),
  1236. blocks=['a']
  1237. )
  1238. combined = options1 + options2
  1239. self.assertEqual(len(combined.blocks), 1, combined.blocks)
  1240. self.assertEqual(combined.blocks[0].alias, 'a')
  1241. self.assertEqual(combined.blocks[0].names, ('a', ))
  1242. def test_add_options_blocks_both(self):
  1243. options1 = core.Options(
  1244. arguments.Argument('first'),
  1245. blocks=['a'],
  1246. )
  1247. options2 = core.Options(
  1248. arguments.Argument('second'),
  1249. blocks=['a']
  1250. )
  1251. self.assertRaises(
  1252. ValueError,
  1253. operator.add,
  1254. options1,
  1255. options2,
  1256. )
  1257. def test_add_options_not_options(self):
  1258. options = core.Options(
  1259. arguments.Argument('first'),
  1260. )
  1261. self.assertRaises(
  1262. TypeError,
  1263. operator.add,
  1264. options,
  1265. 1
  1266. )
  1267. def test_add_options_custom_parser_same(self):
  1268. class CustomParser(parser.Parser):
  1269. def parse_blocks(self):
  1270. return
  1271. options1 = core.Options(
  1272. parser_class=CustomParser,
  1273. )
  1274. options2 = core.Options(
  1275. parser_class=CustomParser,
  1276. )
  1277. combined = options1 + options2
  1278. self.assertIs(combined.parser_class, CustomParser)
  1279. def test_add_options_custom_parser_different(self):
  1280. class CustomParser(parser.Parser):
  1281. def parse_blocks(self):
  1282. return
  1283. options1 = core.Options(
  1284. parser_class=CustomParser,
  1285. )
  1286. options2 = core.Options(
  1287. parser_class=parser.Parser,
  1288. )
  1289. self.assertRaises(
  1290. ValueError,
  1291. operator.add,
  1292. options1,
  1293. options2,
  1294. )
  1295. def test_repr(self):
  1296. options = core.Options(
  1297. arguments.Argument('first'),
  1298. 'breakpoint',
  1299. arguments.Flag('flag', true_values=['yes']),
  1300. blocks=['block']
  1301. )
  1302. self.assertEqual(
  1303. repr(options),
  1304. '<Options:<Argument: first>,breakpoint,<Flag: flag>;block>'
  1305. )
  1306. def test_flatten_context(self):
  1307. context = Context({'foo': 'bar'})
  1308. context.push()
  1309. context.update({'bar': 'baz'})
  1310. context.push()
  1311. context.update({'foo': 'test'})
  1312. flat = utils.flatten_context(context)
  1313. expected = {
  1314. 'foo': 'test',
  1315. 'bar': 'baz',
  1316. }
  1317. if DJANGO_1_5_OR_HIGHER:
  1318. expected.update({
  1319. 'None': None,
  1320. 'True': True,
  1321. 'False': False,
  1322. })
  1323. self.assertEqual(flat, expected)
  1324. context.flatten = None
  1325. flat = utils.flatten_context(context)
  1326. self.assertEqual(flat, expected)
  1327. flat = utils.flatten_context({'foo': 'test', 'bar': 'baz'})
  1328. self.assertEqual(flat, {'foo': 'test', 'bar': 'baz'})
  1329. def test_flatten_requestcontext(self):
  1330. factory = RequestFactory()
  1331. request = factory.get('/')
  1332. expected = {
  1333. 'foo': 'test',
  1334. 'request': 'bar',
  1335. 'bar': 'baz',
  1336. }
  1337. if DJANGO_1_5_OR_HIGHER:
  1338. expected.update({
  1339. 'None': None,
  1340. 'True': True,
  1341. 'False': False,
  1342. })
  1343. checked_keys = expected.keys()
  1344. # Adding a requestcontext to a plain context
  1345. context = Context({'foo': 'bar'})
  1346. context.push()
  1347. context.update({'bar': 'baz'})
  1348. context.push()
  1349. rcontext = RequestContext(request, {})
  1350. rcontext.update({'request': 'bar'})
  1351. context.update(rcontext)
  1352. context.push()
  1353. context.update({'foo': 'test'})
  1354. flat = utils.flatten_context(context)
  1355. self.assertEqual(
  1356. expected, dict(filter(lambda item: item[0] in checked_keys, flat.items()))
  1357. )
  1358. # Adding a plain context to a requestcontext
  1359. context = RequestContext(request, {})
  1360. context.update({'request': 'bar'})
  1361. normal_context = Context({'foo': 'bar'})
  1362. context.push()
  1363. context.update({'bar': 'baz'})
  1364. context.push()
  1365. context.update(normal_context)
  1366. context.push()
  1367. context.update({'foo': 'test'})
  1368. flat = utils.flatten_context(context)
  1369. self.assertEqual(
  1370. expected, dict(filter(lambda item: item[0] in checked_keys, flat.items()))
  1371. )
  1372. # Adding a requestcontext to a requestcontext
  1373. context = RequestContext(request, {})
  1374. context.update({'request': 'bar'})
  1375. rcontext = RequestContext(request, {'foo': 'bar'})
  1376. context.push()
  1377. context.update({'bar': 'baz'})
  1378. context.push()
  1379. context.update(rcontext)
  1380. context.push()
  1381. context.update({'foo': 'test'})
  1382. flat = utils.flatten_context(context)
  1383. self.assertEqual(
  1384. expected, dict(filter(lambda item: item[0] in checked_keys, flat.items()))
  1385. )