aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Brant2013-03-10 22:48:15 -0500
committerSean Brant2013-03-10 22:48:15 -0500
commit63ff8bab7cf4b818da6e50251f8a79cf1e1209d8 (patch)
tree655caff061bdbdb081c450a65f368798819ef7cc
parent9ad7a3fc99ecd77e215a9422fd05ed5da6a3f841 (diff)
downloadpykss-63ff8bab7cf4b818da6e50251f8a79cf1e1209d8.tar.bz2
Adds tests for django template tag
-rw-r--r--conftest.py23
-rw-r--r--examples/djangoproject/djangoproject/templates/styleguide.html11
-rw-r--r--pykss/contrib/django/templatetags/pykss.py52
-rw-r--r--pykss/exceptions.py2
-rw-r--r--pykss/parser.py6
-rw-r--r--pykss/section.py2
-rw-r--r--setup.py9
-rw-r--r--tests/templates/django.html18
-rw-r--r--tests/test_contrib/__init__.py0
-rw-r--r--tests/test_contrib/test_django/__init__.py0
-rw-r--r--tests/test_contrib/test_django/test_templatetags/__init__.py0
-rw-r--r--tests/test_contrib/test_django/test_templatetags/test_pykss.py93
12 files changed, 202 insertions, 14 deletions
diff --git a/conftest.py b/conftest.py
new file mode 100644
index 0000000..ea7d23d
--- /dev/null
+++ b/conftest.py
@@ -0,0 +1,23 @@
+import os
+from django.conf import settings
+
+
+def pytest_configure(config):
+ PROJECT_ROOT = os.path.dirname(__file__)
+
+ if not settings.configured:
+ settings.configure(
+ DATABASES={
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': ':memory:',
+ },
+ },
+ DEBUG=False,
+ INSTALLED_APPS=[
+ 'pykss.contrib.django',
+ ],
+ PROJECT_ROOT=PROJECT_ROOT,
+ TEMPLATE_DEBUG=True,
+ TEMPLATE_DIRS=[os.path.join(PROJECT_ROOT, 'tests', 'templates')],
+ )
diff --git a/examples/djangoproject/djangoproject/templates/styleguide.html b/examples/djangoproject/djangoproject/templates/styleguide.html
index 05d736d..2aa6500 100644
--- a/examples/djangoproject/djangoproject/templates/styleguide.html
+++ b/examples/djangoproject/djangoproject/templates/styleguide.html
@@ -2,6 +2,17 @@
{% load pykss %}
{% block content %}
+{% comment %}
+
+{% styleguideblock styleguide "1.1" %}
+...
+{% endstyleguideblock %}
+
+{% styleguideblock styleguide "1.1" using "custom.html" %}
+...
+{% endstyleguideblock %}
+
+{% endcomment %}
{% styleguideblock styleguide "1.1" %}
<button class="{{ modifier.class_name }}">Example Button</button>
{% endstyleguideblock %}
diff --git a/pykss/contrib/django/templatetags/pykss.py b/pykss/contrib/django/templatetags/pykss.py
index f833ade..c7be567 100644
--- a/pykss/contrib/django/templatetags/pykss.py
+++ b/pykss/contrib/django/templatetags/pykss.py
@@ -1,5 +1,8 @@
from django import template
+from django.conf import settings
from django.template.loader import render_to_string
+from django.utils.safestring import mark_safe
+from django.utils.html import escape
register = template.Library()
@@ -21,22 +24,29 @@ class StyleGuideBlockNode(template.Node):
reference = self.reference.resolve(context)
template_name = self.template_name.resolve(context)
- section = styleguide.section(reference)
+ try:
+ section = styleguide.section(reference)
+ except Exception as e:
+ if settings.TEMPLATE_DEBUG:
+ raise e
+ return ''
- example_html = self.nodelist.render(context)
+ example_html = self.nodelist.render(context).strip()
modifier_examples = []
for modifier in section.modifiers:
context.update({'modifier': modifier})
+ html = self.nodelist.render(context).strip()
modifier_examples.append({
'modifier': modifier,
- 'html': self.nodelist.render(context),
+ 'html': mark_safe(html),
})
output = render_to_string(template_name, {
'section': section,
- 'example_html': example_html,
+ 'example_html': mark_safe(example_html),
'modifier_examples': modifier_examples,
+ "escaped_html": escape(example_html),
})
return output
@@ -44,17 +54,37 @@ class StyleGuideBlockNode(template.Node):
@register.tag
def styleguideblock(parser, token):
- bits = token.contents.split()
+ """
+ {% styleguideblock styleguide "1.1" %}
+ <button class="{{ modifier.class_name }}">Example Button</button>
+ {% endstyleguideblock %}
- if len(bits) != 3:
- raise template.TemplateSyntaxError("styleguideblock expected at least two arguments")
+ {% styleguideblock styleguide "1.1" using "custom.html" %}
+ <button class="{{ modifier.class_name }}">Example Button</button>
+ {% endstyleguideblock %}
- try:
- tag, styleguide, reference, template_name = bits
- except ValueError:
- tag, styleguide, reference = bits
+ """
+ bits = token.split_contents()[1:]
+
+ if len(bits) < 2:
+ raise template.TemplateSyntaxError("styleguideblock expected at "
+ "least two arguments")
+
+ elif len(bits) == 2:
+ styleguide, reference = bits
template_name = '"pykss/styleguideblock.html"'
+ elif len(bits) >= 3 and bits[2] != 'using':
+ raise template.TemplateSyntaxError("styleguideblock expected using "
+ "as the third argument")
+
+ elif len(bits) == 3:
+ raise template.TemplateSyntaxError("styleguideblock expects a "
+ "template name after 'using'")
+
+ else:
+ styleguide, reference, _using, template_name = bits
+
nodelist = parser.parse(('endstyleguideblock',))
parser.delete_first_token()
diff --git a/pykss/exceptions.py b/pykss/exceptions.py
new file mode 100644
index 0000000..418b94f
--- /dev/null
+++ b/pykss/exceptions.py
@@ -0,0 +1,2 @@
+class SectionDoesNotExist(Exception):
+ pass
diff --git a/pykss/parser.py b/pykss/parser.py
index fe18c9f..382cb1f 100644
--- a/pykss/parser.py
+++ b/pykss/parser.py
@@ -1,6 +1,7 @@
import os
from pykss.comment import CommentParser
+from pykss.exceptions import SectionDoesNotExist
from pykss.section import Section
@@ -33,4 +34,7 @@ class Parser(object):
return self._sections
def section(self, reference):
- return self.sections.get(reference, Section())
+ try:
+ return self.sections[reference]
+ except KeyError:
+ raise SectionDoesNotExist('Section "%s" does not exist.' % reference)
diff --git a/pykss/section.py b/pykss/section.py
index bda7e7e..9a98d0f 100644
--- a/pykss/section.py
+++ b/pykss/section.py
@@ -14,7 +14,7 @@ reference_re = re.compile('%s ([\d\.]+)' % REFERENCE_START)
class Section(object):
def __init__(self, comment=None, filename=None):
- self.comment = comment
+ self.comment = comment or ''
self.filename = filename
def parse(self):
diff --git a/setup.py b/setup.py
index e5a195a..a96d65e 100644
--- a/setup.py
+++ b/setup.py
@@ -23,5 +23,12 @@ setup(
],
zip_safe=False,
test_suite='runtests.runtests',
- extras_require={'tests': ['pytest', 'flake8']},
+ extras_require={
+ 'tests': [
+ 'Django>=1.5',
+ 'flake8',
+ 'mock',
+ 'pytest',
+ ],
+ },
)
diff --git a/tests/templates/django.html b/tests/templates/django.html
new file mode 100644
index 0000000..7c52f40
--- /dev/null
+++ b/tests/templates/django.html
@@ -0,0 +1,18 @@
+{# it's probably a terrible idea to render JSON by hand... #}
+{
+ "section": "{{ section.section }}",
+ "filename": "{{ section.filename }}",
+ "description": "{{ section.description }}",
+ "modifiers": [
+ {% for modifier in section.modifiers %}
+ ["{{ modifier.name }}","{{ modifier.description }}"]{% if not forloop.last %},{% endif %}
+ {% endfor %}
+ ],
+ "example_html": "{{ example_html|escapejs }}",
+ "modifier_examples": [
+ {% for example in modifier_examples %}
+ ["{{ example.modifier.name }}","{{ example.html|escapejs }}"]{% if not forloop.last %},{% endif %}
+ {% endfor %}
+ ],
+ "escaped_html": "{{ escaped_html|escapejs }}"
+}
diff --git a/tests/test_contrib/__init__.py b/tests/test_contrib/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/test_contrib/__init__.py
diff --git a/tests/test_contrib/test_django/__init__.py b/tests/test_contrib/test_django/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/test_contrib/test_django/__init__.py
diff --git a/tests/test_contrib/test_django/test_templatetags/__init__.py b/tests/test_contrib/test_django/test_templatetags/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/test_contrib/test_django/test_templatetags/__init__.py
diff --git a/tests/test_contrib/test_django/test_templatetags/test_pykss.py b/tests/test_contrib/test_django/test_templatetags/test_pykss.py
new file mode 100644
index 0000000..1f0d967
--- /dev/null
+++ b/tests/test_contrib/test_django/test_templatetags/test_pykss.py
@@ -0,0 +1,93 @@
+import os
+
+from django.conf import settings
+from django.template import Context, Template, TemplateSyntaxError
+from django.test import TestCase
+from django.utils import simplejson
+
+from mock import patch, ANY
+
+from pykss.exceptions import SectionDoesNotExist
+from pykss.parser import Parser
+
+
+class StyleGuideBlockTestCase(TestCase):
+
+ def setUp(self):
+ css = os.path.join(settings.PROJECT_ROOT, 'tests', 'fixtures', 'css')
+ self.styleguide = Parser(css)
+
+ def test_when_section_does_not_exist_and_in_debug(self):
+ template = Template("""
+ {% load pykss %}
+ {% styleguideblock styleguide "99" %}
+ {% endstyleguideblock %}
+ """)
+ context = Context({'styleguide': self.styleguide})
+ self.assertRaises(SectionDoesNotExist, template.render, context)
+
+ def test_when_section_does_not_exist_and_not_in_debug(self):
+ with self.settings(TEMPLATE_DEBUG=False):
+ template = Template("""
+ {% load pykss %}
+ {% styleguideblock styleguide "99" %}
+ {% endstyleguideblock %}
+ """)
+ context = Context({'styleguide': self.styleguide})
+ results = template.render(context)
+ self.assertEqual(results.strip(), '')
+
+ @patch('pykss.contrib.django.templatetags.pykss.render_to_string')
+ def test_uses_default_template(self, mock_render_to_string):
+ template = Template("""
+ {% load pykss %}
+ {% styleguideblock styleguide "2.1.1" %}
+ {% endstyleguideblock %}
+ """)
+ context = Context({'styleguide': self.styleguide})
+ template.render(context)
+ mock_render_to_string.assert_called_with('pykss/styleguideblock.html', ANY)
+
+ @patch('pykss.contrib.django.templatetags.pykss.render_to_string')
+ def test_allows_overiding_template(self, mock_render_to_string):
+ template = Template("""
+ {% load pykss %}
+ {% styleguideblock styleguide "2.1.1" using "custom.html" %}
+ {% endstyleguideblock %}
+ """)
+ context = Context({'styleguide': self.styleguide})
+ template.render(context)
+ mock_render_to_string.assert_called_with('custom.html', ANY)
+
+ def test_when_using_argument_is_wrong(self):
+ text = """
+ {% load pykss %}
+ {% styleguideblock styleguide "2.1.1" "custom.html" %}
+ {% endstyleguideblock %}
+ """
+ self.assertRaises(TemplateSyntaxError, Template, text)
+
+ def test_when_using_is_defined_without_template(self):
+ text = """
+ {% load pykss %}
+ {% styleguideblock styleguide "2.1.1" using %}
+ {% endstyleguideblock %}
+ """
+ self.assertRaises(TemplateSyntaxError, Template, text)
+
+ def test_renders_correctly(self):
+ template = Template("""
+ {% load pykss %}
+ {% styleguideblock styleguide "2.1.1" using "django.html" %}
+ <i class="{{ modifier.class_name }}"></i>
+ {% endstyleguideblock %}
+ """)
+ context = Context({'styleguide': self.styleguide})
+ results = simplejson.loads(template.render(context))
+ self.assertEqual(results['section'], '2.1.1')
+ self.assertEqual(results['filename'], 'buttons.css')
+ self.assertEqual(results['description'], 'Your standard form button.')
+ self.assertEqual(results['modifiers'][0], [':hover', 'Highlights when hovering.'])
+ self.assertEqual(results['example_html'], '<i class=""></i>')
+ self.assertEqual(results['modifier_examples'][0], [':hover', '<i class="pseudo-class-hover"></i>'])
+ self.assertEqual(results['escaped_html'], '&lt;i class=&quot;&quot;&gt;&lt;/i&gt;')