4
4
import os
5
5
import shutil
6
6
import subprocess
7
+ import traceback
7
8
import uuid
8
9
from pathlib import Path
10
+ from time import perf_counter
9
11
10
12
import js2py
11
13
from deepdiff import DeepDiff
17
19
from django .template .utils import InvalidTemplateEngineError
18
20
from django .test import TestCase , override_settings
19
21
from django .urls import reverse
22
+ from django .urls .exceptions import NoReverseMatch
20
23
from django .utils .module_loading import import_string
21
24
from render_static import placeholders
22
25
from render_static .backends import StaticDjangoTemplates , StaticJinja2Templates
@@ -1538,7 +1541,7 @@ def tearDown(self):
1538
1541
1539
1542
1540
1543
@override_settings (ROOT_URLCONF = 'render_static.tests.urls2' )
1541
- class UnregisteredURLTest (URLJavascriptMixin , BaseTestCase ):
1544
+ class CornerCaseTest (URLJavascriptMixin , BaseTestCase ):
1542
1545
1543
1546
def setUp (self ):
1544
1547
self .clear_placeholder_registries ()
@@ -1574,7 +1577,38 @@ def test_no_default_registered(self):
1574
1577
self .compare ('default' , args = ['unnamed' ])
1575
1578
1576
1579
@override_settings (STATIC_TEMPLATES = {
1577
- 'context' : {'include' : ['default' ]},
1580
+ 'ENGINES' : [{
1581
+ 'BACKEND' : 'render_static.backends.StaticDjangoTemplates' ,
1582
+ 'OPTIONS' : {
1583
+ 'loaders' : [
1584
+ ('render_static.loaders.StaticLocMemLoader' , {
1585
+ 'urls.js' : ('{% urls_to_js '
1586
+ 'visitor="render_static.ClassURLWriter" '
1587
+ 'include=include '
1588
+ '%}' )
1589
+ })
1590
+ ],
1591
+ 'builtins' : ['render_static.templatetags.render_static' ]
1592
+ },
1593
+ }],
1594
+ 'templates' : {'urls.js' : {'context' : {'include' : ['no_capture' ]}}}
1595
+ })
1596
+ def test_non_capturing_unnamed (self ):
1597
+ """
1598
+ Tests that unnamed arguments can still work when the users also include non-capturing groups
1599
+ for whatever reason. Hard to imagine an actual use case for these - but reverse still seems
1600
+ to work, so javascript reverse should too
1601
+ :return:
1602
+ """
1603
+ self .es6_mode = True
1604
+ self .url_js = None
1605
+ self .class_mode = ClassURLWriter .class_name_
1606
+
1607
+ placeholders .register_unnamed_placeholders ('no_capture' , ['0000' ])
1608
+ call_command ('render_static' , 'urls.js' )
1609
+ self .compare ('no_capture' , args = ['5555' ])
1610
+
1611
+ @override_settings (STATIC_TEMPLATES = {
1578
1612
'ENGINES' : [{
1579
1613
'BACKEND' : 'render_static.backends.StaticDjangoTemplates' ,
1580
1614
'OPTIONS' : {
@@ -1599,22 +1633,20 @@ def test_named_unnamed_conflation1(self):
1599
1633
self .url_js = None
1600
1634
self .class_mode = ClassURLWriter .class_name_
1601
1635
1602
- print (reverse ('special' , kwargs = {'choice' : 'first' }))
1603
- print (reverse ('special' , args = ['first' ]))
1604
-
1605
1636
self .assertRaises (CommandError , lambda : call_command ('render_static' , 'urls.js' ))
1606
1637
1607
1638
placeholders .register_variable_placeholder ('choice' , 'first' )
1639
+ placeholders .register_variable_placeholder ('choice1' , 'second' )
1608
1640
self .assertRaises (CommandError , lambda : call_command ('render_static' , 'urls.js' ))
1609
- placeholders .register_unnamed_placeholders ('special' , ['first ' ])
1641
+ placeholders .register_unnamed_placeholders ('special' , ['third ' ])
1610
1642
1611
1643
call_command ('render_static' , 'urls.js' )
1612
- self .compare ('special' , {'choice' : 'first ' })
1613
- self .compare ('special' , [ ' first'] )
1614
-
1644
+ self .compare ('special' , {'choice' : 'second ' })
1645
+ self .compare ('special' , { 'choice' : 'second' , 'choice1' : ' first'} )
1646
+ self . compare ( 'special' , args = [ 'third' ])
1615
1647
1616
1648
@override_settings (
1617
- ROOT_URLCONF = 'render_static.tests.urls2 ' ,
1649
+ ROOT_URLCONF = 'render_static.tests.urls3 ' ,
1618
1650
STATIC_TEMPLATES = {
1619
1651
'context' : {'include' : ['default' ]},
1620
1652
'ENGINES' : [{
@@ -1642,23 +1674,130 @@ def test_named_unnamed_conflation2(self):
1642
1674
self .url_js = None
1643
1675
self .class_mode = ClassURLWriter .class_name_
1644
1676
1645
- print (reverse ('special' , kwargs = {'choice' : 'first' }))
1646
- print (reverse ('special' , args = ['first' ]))
1647
-
1648
1677
self .assertRaises (CommandError , lambda : call_command ('render_static' , 'urls.js' ))
1649
1678
1650
1679
placeholders .register_variable_placeholder ('choice' , 'first' )
1680
+ placeholders .register_variable_placeholder ('choice1' , 'second' )
1651
1681
self .assertRaises (CommandError , lambda : call_command ('render_static' , 'urls.js' ))
1682
+ placeholders .register_unnamed_placeholders ('special' , ['third' ])
1683
+
1684
+ call_command ('render_static' , 'urls.js' )
1685
+ self .compare ('special' , {'choice' : 'second' })
1686
+ self .compare ('special' , {'choice' : 'second' , 'choice1' : 'first' })
1687
+ self .compare ('special' , args = ['third' ])
1688
+
1689
+ @override_settings (
1690
+ ROOT_URLCONF = 'render_static.tests.urls4' ,
1691
+ STATIC_TEMPLATES = {
1692
+ 'context' : {'include' : ['default' ]},
1693
+ 'ENGINES' : [{
1694
+ 'BACKEND' : 'render_static.backends.StaticDjangoTemplates' ,
1695
+ 'OPTIONS' : {
1696
+ 'loaders' : [
1697
+ ('render_static.loaders.StaticLocMemLoader' , {
1698
+ 'urls.js' : '{% urls_to_js visitor="render_static.ClassURLWriter" %}'
1699
+ })
1700
+ ],
1701
+ 'builtins' : ['render_static.templatetags.render_static' ]
1702
+ },
1703
+ }]
1704
+ }
1705
+ )
1706
+ def test_named_unnamed_conflation3 (self ):
1707
+ """
1708
+ This tests surfaces what appears to be a Django bug in reverse(). urls_to_js should not
1709
+ fail in this circumstance, but should leave a comment breadcrumb in the generated JS that
1710
+ indicates why no reversal was produced - alternatively if bug is fixed it should also pass
1711
+
1712
+ https://github.com/bckohan/django-render-static/issues/9
1713
+ """
1714
+ self .es6_mode = True
1715
+ self .url_js = None
1716
+ self .class_mode = ClassURLWriter .class_name_
1717
+
1718
+ placeholders .register_variable_placeholder ('choice' , 'first' )
1652
1719
placeholders .register_unnamed_placeholders ('special' , ['first' ])
1720
+ call_command ('render_static' , 'urls.js' )
1721
+
1722
+ with open (GLOBAL_STATIC_DIR / 'urls.js' , 'r' ) as urls :
1723
+ if 'reverse matched unexpected pattern' not in urls .read ():
1724
+ self .compare ('special' , kwargs = {'choice' : 'first' }) # pragma: no cover
1725
+ self .compare ('special' , args = ['first' ]) # pragma: no cover
1726
+
1727
+ self .assertTrue (True )
1653
1728
1729
+ @override_settings (
1730
+ STATIC_TEMPLATES = {
1731
+ 'context' : {'include' : ['bad_mix' ]},
1732
+ 'ENGINES' : [{
1733
+ 'BACKEND' : 'render_static.backends.StaticDjangoTemplates' ,
1734
+ 'OPTIONS' : {
1735
+ 'loaders' : [
1736
+ ('render_static.loaders.StaticLocMemLoader' , {
1737
+ 'urls.js' : '{% urls_to_js '
1738
+ 'visitor="render_static.ClassURLWriter" '
1739
+ 'include=include %}'
1740
+ })
1741
+ ],
1742
+ 'builtins' : ['render_static.templatetags.render_static' ]
1743
+ },
1744
+ }]
1745
+ }
1746
+ )
1747
+ def test_named_unnamed_bad_mix (self ):
1748
+ """
1749
+ Mix of named and unnamed arguments should not be reversible!
1750
+ """
1751
+ self .es6_mode = True
1752
+ self .url_js = None
1753
+ self .class_mode = ClassURLWriter .class_name_
1754
+
1755
+ placeholders .register_variable_placeholder ('named' , '1111' )
1756
+ placeholders .register_unnamed_placeholders ('bad_mix' , ['unnamed' ])
1654
1757
call_command ('render_static' , 'urls.js' )
1655
- self .compare ('special' , {'choice' : 'first' })
1656
- self .compare ('special' , ['first' ])
1657
1758
1759
+ with open (GLOBAL_STATIC_DIR / 'urls.js' , 'r' ) as urls :
1760
+ self .assertTrue ('this path may not be reversible' in urls .read ())
1761
+
1762
+ self .assertRaises (
1763
+ ValueError ,
1764
+ lambda : reverse (
1765
+ 'bad_mix' ,
1766
+ kwargs = {'named' : '1111' }, args = ['unnamed' ])
1767
+ )
1768
+ self .assertRaises (NoReverseMatch , lambda : reverse ('bad_mix' , kwargs = {'named' : '1111' }))
1769
+
1770
+ @override_settings (
1771
+ STATIC_TEMPLATES = {
1772
+ 'context' : {'include' : ['bad_mix2' ]},
1773
+ 'ENGINES' : [{
1774
+ 'BACKEND' : 'render_static.backends.StaticDjangoTemplates' ,
1775
+ 'OPTIONS' : {
1776
+ 'loaders' : [
1777
+ ('render_static.loaders.StaticLocMemLoader' , {
1778
+ 'urls.js' : '{% urls_to_js '
1779
+ 'visitor="render_static.ClassURLWriter" '
1780
+ 'include=include %}'
1781
+ })
1782
+ ],
1783
+ 'builtins' : ['render_static.templatetags.render_static' ]
1784
+ },
1785
+ }]
1786
+ }
1787
+ )
1788
+ def test_named_unnamed_bad_mix2 (self ):
1789
+ """
1790
+ Mix of named and unnamed arguments should not be reversible!
1791
+ """
1792
+ self .es6_mode = True
1793
+ self .url_js = None
1794
+ self .class_mode = ClassURLWriter .class_name_
1795
+
1796
+ placeholders .register_variable_placeholder ('named' , '1111' )
1797
+ placeholders .register_unnamed_placeholders ('bad_mix2' , ['unnamed' ])
1798
+ self .assertRaises (CommandError , lambda : call_command ('render_static' , 'urls.js' ))
1658
1799
1659
- """
1660
1800
@override_settings (STATIC_TEMPLATES = {
1661
- 'context': {'include': ['default']},
1662
1801
'ENGINES' : [{
1663
1802
'BACKEND' : 'render_static.backends.StaticDjangoTemplates' ,
1664
1803
'OPTIONS' : {
@@ -1673,20 +1812,58 @@ def test_named_unnamed_conflation2(self):
1673
1812
'builtins' : ['render_static.templatetags.render_static' ]
1674
1813
},
1675
1814
}],
1676
- 'templates': {'urls.js': {'context': {'include': ['special ']}}}
1815
+ 'templates' : {'urls.js' : {'context' : {'include' : ['complex ' ]}}}
1677
1816
})
1678
1817
def test_complexity_boundary (self ):
1818
+ """
1679
1819
https://github.com/bckohan/django-render-static/issues/10
1820
+
1680
1821
For URLs with lots of unregistered arguments, the reversal attempts may produce an explosion
1681
- of complexity. If there are
1822
+ of complexity. Check that the failsafe is working.
1682
1823
:return:
1824
+ """
1683
1825
self .es6_mode = True
1826
+ self .class_mode = ClassURLWriter .class_name_
1684
1827
self .url_js = None
1685
1828
1686
- self.assertRaises(CommandError, call_command('render_static', 'urls.js'))
1829
+ t1 = perf_counter ()
1830
+ tb_str = ''
1831
+ try :
1832
+ call_command ('render_static' , 'urls.js' )
1833
+ except Exception as complexity_error :
1834
+ tb_str = traceback .format_exc ()
1835
+ t2 = perf_counter ()
1836
+
1837
+ self .assertTrue ('ReversalLimitHit' in tb_str )
1838
+
1839
+ # very generous reversal timing threshold of 20 seconds - anecdotally the default limit of
1840
+ # 2**15 should be hit in about 3 seconds.
1841
+ self .assertTrue (t2 - t1 < 20 )
1842
+
1843
+ placeholders .register_variable_placeholder ('one' , '666' )
1844
+ placeholders .register_variable_placeholder ('two' , '666' )
1845
+ placeholders .register_variable_placeholder ('three' , '666' )
1846
+ placeholders .register_variable_placeholder ('four' , '666' )
1847
+ placeholders .register_variable_placeholder ('five' , '666' )
1848
+ placeholders .register_variable_placeholder ('six' , '666' )
1849
+ placeholders .register_variable_placeholder ('seven' , '666' )
1850
+ placeholders .register_variable_placeholder ('eight' , '666' )
1687
1851
1688
- self.compare('default')
1689
- """
1852
+ call_command ('render_static' , 'urls.js' )
1853
+
1854
+ self .compare (
1855
+ 'complex' ,
1856
+ {
1857
+ 'one' : 666 ,
1858
+ 'two' : 666 ,
1859
+ 'three' : 666 ,
1860
+ 'four' : 666 ,
1861
+ 'five' : 666 ,
1862
+ 'six' : 666 ,
1863
+ 'seven' : 666 ,
1864
+ 'eight' : 666 ,
1865
+ }
1866
+ )
1690
1867
1691
1868
# uncomment to not delete generated js
1692
1869
def tearDown (self ):
@@ -1854,7 +2031,6 @@ def test_unknown_pattern(self):
1854
2031
self .assertRaises (CommandError , lambda : call_command ('render_static' , 'urls.js' ))
1855
2032
1856
2033
def test_register_bogus_converter (self ):
1857
- from render_static import placeholders as gen
1858
2034
self .assertRaises (
1859
2035
ValueError ,
1860
2036
lambda : placeholders .register_converter_placeholder ('Not a converter type!' , 1234 )
0 commit comments