summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorRodrigo Vieira <rodrigo.vieira@gmail.com>2026-04-22 18:53:13 -0300
committerJacob Walls <jacobtylerwalls@gmail.com>2026-04-22 22:22:55 -0400
commita586f03f36f511064f171c0e30f4ca2ebfd60085 (patch)
tree9c7aced48d60452fdcbe5bf6bf99e8de05d60ffa /tests
parent61a62be313e395ce1265132bfc99f51476fb3c95 (diff)
Refs #10919 -- Refactored walk_items as module-level _walk_items and added truncated_unordered_list filter.
Diffstat (limited to 'tests')
-rw-r--r--tests/admin_views/test_templatetags.py118
-rw-r--r--tests/template_tests/filter_tests/test_unordered_list.py13
2 files changed, 130 insertions, 1 deletions
diff --git a/tests/admin_views/test_templatetags.py b/tests/admin_views/test_templatetags.py
index 69bae27412..519bd14954 100644
--- a/tests/admin_views/test_templatetags.py
+++ b/tests/admin_views/test_templatetags.py
@@ -1,7 +1,9 @@
import datetime
import unittest
+from django import template
from django.contrib.admin import ModelAdmin
+from django.contrib.admin.templatetags.admin_filters import truncated_unordered_list
from django.contrib.admin.templatetags.admin_list import date_hierarchy
from django.contrib.admin.templatetags.admin_modify import submit_row
from django.contrib.admin.templatetags.base import InclusionAdminNode
@@ -9,7 +11,7 @@ from django.contrib.auth import get_permission_codename
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from django.template.base import Token, TokenType
-from django.test import RequestFactory, TestCase
+from django.test import RequestFactory, SimpleTestCase, TestCase
from django.urls import reverse
from django.utils.version import PY314
@@ -18,6 +20,120 @@ from .models import Article, Question
from .tests import AdminViewBasicTestCase, get_perm
+class TruncatedUnorderedListTests(SimpleTestCase):
+ def test_no_max_items(self):
+ result = truncated_unordered_list(["item 1", "item 2"], None)
+ self.assertEqual(result, ("\t<li>item 1</li>\n" "\t<li>item 2</li>"))
+ self.assertNotIn("more object", result)
+
+ def test_max_items_zero(self):
+ result = truncated_unordered_list(["a", "b", "c"], 0)
+ self.assertEqual(result, "")
+ self.assertNotIn("more object", result)
+
+ def test_flat_list_truncated(self):
+ self.assertEqual(
+ truncated_unordered_list(["a", "b", "c", "d", "e"], 3),
+ (
+ "\t<li>a</li>\n"
+ "\t<li>b</li>\n"
+ "\t<li>c</li>\n"
+ "\t<li>…and 2 more objects.</li>"
+ ),
+ )
+
+ def test_nested_two_levels_truncated(self):
+ self.assertEqual(
+ truncated_unordered_list(["a", ["a1", "a2"], "b", "c", "d", "e"], 3),
+ (
+ "\t<li>a\n"
+ "\t<ul>\n"
+ "\t\t<li>a1</li>\n"
+ "\t\t<li>a2</li>\n"
+ "\t</ul>\n"
+ "\t</li>\n"
+ "\t<li>…and 4 more objects.</li>"
+ ),
+ )
+
+ def test_nested_and_top_level_truncated(self):
+ self.assertEqual(
+ truncated_unordered_list(
+ ["a", ["n1", "n2", "n3", "n4", "n5"], "b", "c", "d", "e"],
+ 3,
+ ),
+ (
+ "\t<li>a\n"
+ "\t<ul>\n"
+ "\t\t<li>n1</li>\n"
+ "\t\t<li>n2</li>\n"
+ "\t</ul>\n"
+ "\t</li>\n"
+ "\t<li>…and 7 more objects.</li>"
+ ),
+ )
+
+ def test_nested_three_levels_truncated(self):
+ self.assertEqual(
+ truncated_unordered_list(["a", ["a1", ["a1x"]], "b", "c", "d", "e"], 3),
+ (
+ "\t<li>a\n"
+ "\t<ul>\n"
+ "\t\t<li>a1\n"
+ "\t\t<ul>\n"
+ "\t\t\t<li>a1x</li>\n"
+ "\t\t</ul>\n"
+ "\t\t</li>\n"
+ "\t</ul>\n"
+ "\t</li>\n"
+ "\t<li>…and 4 more objects.</li>"
+ ),
+ )
+
+ def test_max_items_equal_to_length(self):
+ self.assertEqual(
+ truncated_unordered_list(["a", "b", "c"], 3),
+ ("\t<li>a</li>\n" "\t<li>b</li>\n" "\t<li>c</li>"),
+ )
+
+ def test_max_items_greater_than_length(self):
+ self.assertEqual(
+ truncated_unordered_list(["a", "b"], 10),
+ ("\t<li>a</li>\n" "\t<li>b</li>"),
+ )
+
+ def test_truncated_single_remaining(self):
+ self.assertEqual(
+ truncated_unordered_list(["a", "b", "c"], 2),
+ ("\t<li>a</li>\n" "\t<li>b</li>\n" "\t<li>…and 1 more object.</li>"),
+ )
+
+ def test_autoescape(self):
+ self.assertEqual(
+ truncated_unordered_list(["<a>item</a>", "safe"], 1),
+ ("\t<li>&lt;a&gt;item&lt;/a&gt;</li>\n" "\t<li>…and 1 more object.</li>"),
+ )
+
+ def test_autoescape_off(self):
+ self.assertEqual(
+ truncated_unordered_list(["<a>item</a>", "safe"], 1, autoescape=False),
+ ("\t<li><a>item</a></li>\n" "\t<li>…and 1 more object.</li>"),
+ )
+
+ def test_empty_list(self):
+ self.assertEqual(truncated_unordered_list([], 5), "")
+
+ def test_template_rendering(self):
+ t = template.Template(
+ "{% load admin_filters %}{{ items|truncated_unordered_list:2 }}"
+ )
+ result = t.render(template.Context({"items": ["a", "b", "c"]}))
+ self.assertIn("<li>a</li>", result)
+ self.assertIn("<li>b</li>", result)
+ self.assertIn("<li>…and 1 more object.</li>", result)
+ self.assertNotIn("<li>c</li>", result)
+
+
class AdminTemplateTagsTest(AdminViewBasicTestCase):
request_factory = RequestFactory()
diff --git a/tests/template_tests/filter_tests/test_unordered_list.py b/tests/template_tests/filter_tests/test_unordered_list.py
index 1748a0fb54..ddbaedcc70 100644
--- a/tests/template_tests/filter_tests/test_unordered_list.py
+++ b/tests/template_tests/filter_tests/test_unordered_list.py
@@ -160,6 +160,19 @@ class FunctionTests(SimpleTestCase):
"<li>D</li>",
)
+ def test_non_iterable_list_subclass(self):
+ class NonIterableList(list):
+ def __iter__(self):
+ raise TypeError
+
+ def __str__(self):
+ return "non-iterable-list"
+
+ self.assertEqual(
+ unordered_list(["A", NonIterableList(["x"]), "B"]),
+ "\t<li>A</li>\n\t<li>non-iterable-list</li>\n\t<li>B</li>",
+ )
+
def test_ulitem_autoescape_off(self):
class ULItem:
def __init__(self, title):