Skip to content

Commit

Permalink
Improve tests and coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
dyve committed May 3, 2021
1 parent 58a9e28 commit 6878dcd
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 82 deletions.
1 change: 0 additions & 1 deletion src/django_bootstrap5/size.py
@@ -1,7 +1,6 @@
from .css import merge_css_classes
from .text import text_value

SIZE_XS = "xs"
SIZE_SM = "sm"
SIZE_MD = "md"
SIZE_LG = "lg"
Expand Down
@@ -1,4 +1,4 @@
{% load django_bootstrap5 %}
{% for message in messages %}
{% bootstrap_alert message alert_type=message|bootstrap_message_alert_type extra_classes=message.extra_tags %}
{% bootstrap_alert message|default:"" alert_type=message|bootstrap_message_alert_type extra_classes=message.extra_tags %}
{% endfor %}
30 changes: 11 additions & 19 deletions src/django_bootstrap5/templatetags/django_bootstrap5.py
Expand Up @@ -38,7 +38,7 @@ def bootstrap_setting(value):

@register.filter
def bootstrap_message_alert_type(message):
"""Return the alert type for a bootstrap message, defaults to `info`."""
"""Return the alert type for a message, defaults to `info`."""
try:
level = message.level
except AttributeError:
Expand Down Expand Up @@ -627,7 +627,6 @@ def bootstrap_messages(context, *args, **kwargs):
{% bootstrap_messages %}
"""
# Force Context to dict
if isinstance(context, Context):
context = context.flatten()
context.update({"message_constants": message_constants})
Expand Down Expand Up @@ -703,29 +702,23 @@ def get_pagination_context(
pages_to_show = int(pages_to_show)
if pages_to_show < 1:
raise ValueError(f"Pagination pages_to_show should be a positive integer, you specified {pages_to_show}.")

num_pages = page.paginator.num_pages
current_page = page.number
half_page_num = int(floor(pages_to_show / 2))
if half_page_num < 0:
half_page_num = 0
first_page = current_page - half_page_num
if first_page <= 1:
first_page = 1
if first_page > 1:
pages_back = first_page - half_page_num
if pages_back < 1:
pages_back = 1
else:
pages_back = None

delta_pages = int(floor(pages_to_show / 2))

first_page = max(1, current_page - delta_pages)
pages_back = max(1, first_page - delta_pages) if first_page > 1 else None

last_page = first_page + pages_to_show - 1
if pages_back is None:
last_page += 1
if last_page > num_pages:
last_page = num_pages

if last_page < num_pages:
pages_forward = last_page + half_page_num
if pages_forward > num_pages:
pages_forward = num_pages
pages_forward = min(last_page + delta_pages, num_pages)
else:
pages_forward = None
if first_page > 1:
Expand All @@ -734,6 +727,7 @@ def get_pagination_context(
pages_back -= 1
else:
pages_back = None

pages_shown = []
for i in range(first_page, last_page + 1):
pages_shown.append(i)
Expand All @@ -750,8 +744,6 @@ def get_pagination_context(
if size:
pagination_size_class = get_size_class(size, prefix="pagination", skip="md")
if pagination_size_class:
if pagination_size_class not in ["pagination-sm", "pagination-lg"]:
raise ValueError("Invalid size for pagination, only 'sm' and 'lg' are allowed, '{size}' given.")
pagination_css_classes.append(pagination_size_class)

if justify_content:
Expand Down
4 changes: 2 additions & 2 deletions tests/test_bootstrap_alert.py
Expand Up @@ -4,13 +4,13 @@
class BootstrapAlertTestCase(BootstrapTestCase):
def test_bootstrap_alert(self):
self.assertEqual(
self.render('{% bootstrap_alert "content" dismissible=False %}', None),
self.render('{% bootstrap_alert "content" dismissible=False %}'),
'<div class="alert alert-info" role="alert">content</div>',
)

def test_bootstrap_alert_type_invalid(self):
with self.assertRaises(ValueError):
self.render('{% bootstrap_alert "content" alert_type="nope" %}', None)
self.render('{% bootstrap_alert "content" alert_type="nope" %}')

def test_bootstrap_alert_dismissible(self):
self.assertEqual(
Expand Down
10 changes: 10 additions & 0 deletions tests/test_bootstrap_css_and_js_tags.py
Expand Up @@ -17,12 +17,22 @@ def test_bootstrap_javascript_tag(self):
self.render("{% bootstrap_javascript %}"),
self.expected_bootstrap_js,
)
with self.settings(BOOTSTRAP5={"javascript_url": "//example.com/bootstrap.js"}):
self.assertHTMLEqual(
self.render("{% bootstrap_javascript %}"),
'<script src="//example.com/bootstrap.js">',
)

def test_bootstrap_css_tag(self):
self.assertHTMLEqual(
self.render("{% bootstrap_css %}"),
self.expected_bootstrap_css,
)
with self.settings(BOOTSTRAP5={"css_url": "//example.com/bootstrap.css"}):
self.assertHTMLEqual(
self.render("{% bootstrap_css %}"),
'<link href="//example.com/bootstrap.css" rel="stylesheet">',
)

def test_bootstrap_css_tag_with_theme(self):
with self.settings(BOOTSTRAP5={"theme_url": "//example.com/theme.css"}):
Expand Down
82 changes: 42 additions & 40 deletions tests/test_bootstrap_messages.py
Expand Up @@ -3,7 +3,7 @@
from tests.base import BootstrapTestCase


class FakeMessage(object):
class MockMessage(object):
"""Follows the `django.contrib.messages.storage.base.Message` API."""

level = None
Expand All @@ -20,53 +20,55 @@ def __str__(self):


class MessagesTestCase(BootstrapTestCase):
def test_bootstrap_messages(self):
messages = [FakeMessage(DEFAULT_MESSAGE_LEVELS.WARNING, "hello")]
html = self.render("{% bootstrap_messages messages %}", {"messages": messages})
expected = (
'<div class="alert alert-warning alert-dismissible fade show" role="alert">'
"hello"
def _html(self, content, css_class):
return (
f'<div class="alert {css_class} alert-dismissible fade show" role="alert">'
f"{content}"
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>'
"</div>"
)
self.assertHTMLEqual(html, expected)

messages = [FakeMessage(DEFAULT_MESSAGE_LEVELS.ERROR, "hello")]
html = self.render("{% bootstrap_messages messages %}", {"messages": messages})
expected = (
'<div class="alert alert-danger alert-dismissible fade show" role="alert">'
"hello"
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>'
"</div>"
def test_bootstrap_messages(self):
messages = [MockMessage(DEFAULT_MESSAGE_LEVELS.WARNING, "hello")]
self.assertHTMLEqual(
self.render("{% bootstrap_messages messages %}", {"messages": messages}),
self._html(content="hello", css_class="alert-warning"),
)
self.assertHTMLEqual(html, expected)

messages = [FakeMessage(None, "hello")]
html = self.render("{% bootstrap_messages messages %}", {"messages": messages})
expected = (
'<div class="alert alert-info alert-dismissible fade show" role="alert">'
"hello"
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>'
"</div>"
messages = [MockMessage(DEFAULT_MESSAGE_LEVELS.ERROR, "hello")]
self.assertHTMLEqual(
self.render("{% bootstrap_messages messages %}", {"messages": messages}),
self._html(content="hello", css_class="alert-danger"),
)
self.assertHTMLEqual(html, expected)

messages = [FakeMessage(DEFAULT_MESSAGE_LEVELS.ERROR, "hello http://example.com")]
html = self.render("{% bootstrap_messages messages %}", {"messages": messages})
expected = (
'<div class="alert alert-danger alert-dismissible fade show" role="alert">'
"hello http://example.com"
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>'
"</div>"
def test_bootstrap_messages_with_other_levels(self):
messages = [MockMessage(None, "hello")]
self.assertHTMLEqual(
self.render("{% bootstrap_messages messages %}", {"messages": messages}),
self._html(content="hello", css_class="alert-info"),
)
messages = [MockMessage(999, "hello")]
self.assertHTMLEqual(
self.render("{% bootstrap_messages messages %}", {"messages": messages}),
self._html(content="hello", css_class="alert-info"),
)
self.assertHTMLEqual(html, expected)

messages = [FakeMessage(DEFAULT_MESSAGE_LEVELS.ERROR, "hello\nthere")]
html = self.render("{% bootstrap_messages messages %}", {"messages": messages})
expected = (
'<div class="alert alert-danger alert-dismissible fade show" role="alert">'
"hello there"
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>'
"</div>"
def test_bootstrap_messages_with_other_content(self):
messages = [MockMessage(DEFAULT_MESSAGE_LEVELS.ERROR, "hello http://example.com")]
self.assertHTMLEqual(
self.render("{% bootstrap_messages messages %}", {"messages": messages}),
self._html(content="hello http://example.com", css_class="alert-danger"),
)

messages = [MockMessage(DEFAULT_MESSAGE_LEVELS.ERROR, "hello\nthere")]
self.assertHTMLEqual(
self.render("{% bootstrap_messages messages %}", {"messages": messages}),
self._html(content="hello there", css_class="alert-danger"),
)

def test_bootstrap_messages_with_invalid_message(self):
messages = [None]
self.assertHTMLEqual(
self.render("{% bootstrap_messages messages %}", {"messages": messages}),
self._html(content="", css_class="alert-info"),
)
self.assertHTMLEqual(html, expected)
127 changes: 108 additions & 19 deletions tests/test_bootstrap_pagination.py
Expand Up @@ -5,6 +5,11 @@


class PaginatorTestCase(BootstrapTestCase):
@classmethod
def setUpTestData(cls):
cls.beatles = ["john", "paul", "george", "ringo"]
cls.paginator = Paginator(cls.beatles, 2)

def test_url_replace_param(self):
self.assertEqual(url_replace_param("/foo/bar?baz=foo", "baz", "yohoo"), "/foo/bar?baz=yohoo")
self.assertEqual(url_replace_param("/foo/bar?baz=foo", "baz", None), "/foo/bar")
Expand All @@ -15,34 +20,118 @@ def bootstrap_pagination(self, page, extra=""):
return self.render(f"{{% bootstrap_pagination page {extra} %}}", {"page": page})

def test_paginator(self):
objects = ["john", "paul", "george", "ringo"]
paginator = Paginator(objects, 2)

html = self.bootstrap_pagination(paginator.page(2), extra='url="/projects/?foo=bar"')
html = self.bootstrap_pagination(self.paginator.page(2), extra='url="/projects/?foo=bar"')
self.assertHTMLEqual(
html,
"""
<nav>
<ul class="pagination">
<li class="page-item"><a class="page-link" href="/projects/?foo=bar&page=1">&laquo;</a></li>
<li class="page-item"><a class="page-link" href="/projects/?foo=bar&page=1">1</a></li>
<li class="page-item active"><a class="page-link" href="#">2</a></li>
<li class="page-item disabled"><a class="page-link" href="#">&raquo;</a></li>
</ul>
</nav>
""",
(
"<nav>"
'<ul class="pagination">'
'<li class="page-item"><a class="page-link" href="/projects/?foo=bar&page=1">&laquo;</a></li>'
'<li class="page-item"><a class="page-link" href="/projects/?foo=bar&page=1">1</a></li>'
'<li class="page-item active"><a class="page-link" href="#">2</a></li>'
'<li class="page-item disabled"><a class="page-link" href="#">&raquo;</a></li>'
"</ul>"
"</nav>"
),
)
self.assertIn("/projects/?foo=bar&page=1", html)
self.assertNotIn("/projects/?foo=bar&page=2", html)

html = self.bootstrap_pagination(paginator.page(2), extra='url="/projects/#id"')
html = self.bootstrap_pagination(self.paginator.page(2), extra='url="/projects/#id"')
self.assertIn("/projects/?page=1#id", html)
self.assertNotIn("/projects/?page=2#id", html)

html = self.bootstrap_pagination(paginator.page(2), extra='url="/projects/?page=3#id"')
html = self.bootstrap_pagination(self.paginator.page(2), extra='url="/projects/?page=3#id"')
self.assertIn("/projects/?page=1#id", html)
self.assertNotIn("/projects/?page=2#id", html)

html = self.bootstrap_pagination(paginator.page(2), extra='url="/projects/?page=3" extra="id=20"')
html = self.bootstrap_pagination(self.paginator.page(2), extra='url="/projects/?page=3" extra="id=20"')
self.assertIn("/projects/?page=1&id=20", html)
self.assertNotIn("/projects/?page=2&id=20", html)

def test_paginator_size(self):
self.assertHTMLEqual(
self.render('{% bootstrap_pagination page size="sm" %}', {"page": self.paginator.page(2)}),
(
"<nav>"
'<ul class="pagination pagination-sm">'
'<li class="page-item"><a class="page-link" href="?page=1">&laquo;</a></li>'
'<li class="page-item"><a class="page-link" href="?page=1">1</a></li>'
'<li class="page-item active"><a class="page-link" href="#">2</a></li>'
'<li class="page-item disabled"><a class="page-link" href="#">&raquo;</a></li>'
"</ul>"
"</nav>"
),
)
self.assertHTMLEqual(
self.render('{% bootstrap_pagination page size="lg" %}', {"page": self.paginator.page(2)}),
(
"<nav>"
'<ul class="pagination pagination-lg">'
'<li class="page-item"><a class="page-link" href="?page=1">&laquo;</a></li>'
'<li class="page-item"><a class="page-link" href="?page=1">1</a></li>'
'<li class="page-item active"><a class="page-link" href="#">2</a></li>'
'<li class="page-item disabled"><a class="page-link" href="#">&raquo;</a></li>'
"</ul>"
"</nav>"
),
)
self.assertHTMLEqual(
self.render('{% bootstrap_pagination page size="md" %}', {"page": self.paginator.page(2)}),
(
"<nav>"
'<ul class="pagination">'
'<li class="page-item"><a class="page-link" href="?page=1">&laquo;</a></li>'
'<li class="page-item"><a class="page-link" href="?page=1">1</a></li>'
'<li class="page-item active"><a class="page-link" href="#">2</a></li>'
'<li class="page-item disabled"><a class="page-link" href="#">&raquo;</a></li>'
"</ul>"
"</nav>"
),
)

with self.assertRaisesRegex(ValueError, 'Invalid value "xl" for parameter'):
self.render('{% bootstrap_pagination page size="xl" %}', {"page": self.paginator.page(2)})

def test_paginator_justify(self):
self.assertHTMLEqual(
self.render('{% bootstrap_pagination page justify_content="center" %}', {"page": self.paginator.page(2)}),
(
"<nav>"
'<ul class="pagination justify-content-center">'
'<li class="page-item"><a class="page-link" href="?page=1">&laquo;</a></li>'
'<li class="page-item"><a class="page-link" href="?page=1">1</a></li>'
'<li class="page-item active"><a class="page-link" href="#">2</a></li>'
'<li class="page-item disabled"><a class="page-link" href="#">&raquo;</a></li>'
"</ul>"
"</nav>"
),
)
with self.assertRaises(ValueError):
self.render(
'{{% bootstrap_pagination page justify_content="somewhere" %}', {"page": self.paginator.page(2)}
)

def test_paginator_illegal(self):
with self.assertRaises(ValueError):
self.render('{% bootstrap_pagination page pages_to_show="foo" %}', {"page": self.paginator.page(2)})
with self.assertRaises(ValueError):
self.render("{{% bootstrap_pagination page pages_to_show=-5 %}", {"page": self.paginator.page(2)})


class LargePaginatorTestCase(BootstrapTestCase):
@classmethod
def setUpTestData(cls):
cls.numbers = [f"{number}" for number in range(1, 100)]
cls.paginator = Paginator(cls.numbers, 2)

def test_paginator_ellipsis(self):
html = self.render("{{% bootstrap_pagination page %}", {"page": self.paginator.page(33)})
self.assertInHTML('<li class="page-item"><a class="page-link" href="?page=23">&hellip;</a></li>', html)
self.assertInHTML('<li class="page-item"><a class="page-link" href="?page=43">&hellip;</a></li>', html)

html = self.render("{{% bootstrap_pagination page %}", {"page": self.paginator.page(2)})
self.assertInHTML('<li class="page-item"><a class="page-link" href="?page=17">&hellip;</a></li>', html)
self.assertInHTML("&hellip;", html, count=1)

html = self.render("{{% bootstrap_pagination page %}", {"page": self.paginator.page(49)})
self.assertInHTML('<li class="page-item"><a class="page-link" href="?page=38">&hellip;</a></li>', html)
self.assertInHTML("&hellip;", html, count=1)

0 comments on commit 6878dcd

Please sign in to comment.