Example #1
0
 def test_httprequest_repr(self):
     request = HttpRequest()
     request.path = '/somepath/'
     request.method = 'GET'
     request.GET = {'get-key': 'get-value'}
     request.POST = {'post-key': 'post-value'}
     request.COOKIES = {'post-key': 'post-value'}
     request.META = {'post-key': 'post-value'}
     self.assertEqual(repr(request),
                      str_prefix("<HttpRequest: GET '/somepath/'>"))
     self.assertEqual(
         build_request_repr(request),
         str_prefix(
             "<HttpRequest\npath:/somepath/,\nGET:{%(_)s'get-key': %(_)s'get-value'},\nPOST:{%(_)s'post-key': %(_)s'post-value'},\nCOOKIES:{%(_)s'post-key': %(_)s'post-value'},\nMETA:{%(_)s'post-key': %(_)s'post-value'}>"
         ))
     self.assertEqual(
         build_request_repr(request,
                            path_override='/otherpath/',
                            GET_override={'a': 'b'},
                            POST_override={'c': 'd'},
                            COOKIES_override={'e': 'f'},
                            META_override={'g': 'h'}),
         str_prefix(
             "<HttpRequest\npath:/otherpath/,\nGET:{%(_)s'a': %(_)s'b'},\nPOST:{%(_)s'c': %(_)s'd'},\nCOOKIES:{%(_)s'e': %(_)s'f'},\nMETA:{%(_)s'g': %(_)s'h'}>"
         ))
Example #2
0
 def test_httprequest_repr(self):
     request = HttpRequest()
     request.path = "/somepath/"
     request.GET = {"get-key": "get-value"}
     request.POST = {"post-key": "post-value"}
     request.COOKIES = {"post-key": "post-value"}
     request.META = {"post-key": "post-value"}
     self.assertEqual(
         repr(request),
         str_prefix(
             "<HttpRequest\npath:/somepath/,\nGET:{%(_)s'get-key': %(_)s'get-value'},\nPOST:{%(_)s'post-key': %(_)s'post-value'},\nCOOKIES:{%(_)s'post-key': %(_)s'post-value'},\nMETA:{%(_)s'post-key': %(_)s'post-value'}>"
         ),
     )
     self.assertEqual(build_request_repr(request), repr(request))
     self.assertEqual(
         build_request_repr(
             request,
             path_override="/otherpath/",
             GET_override={"a": "b"},
             POST_override={"c": "d"},
             COOKIES_override={"e": "f"},
             META_override={"g": "h"},
         ),
         str_prefix(
             "<HttpRequest\npath:/otherpath/,\nGET:{%(_)s'a': %(_)s'b'},\nPOST:{%(_)s'c': %(_)s'd'},\nCOOKIES:{%(_)s'e': %(_)s'f'},\nMETA:{%(_)s'g': %(_)s'h'}>"
         ),
     )
Example #3
0
    def test_unknown_error(self):
        "An assertion is raised if the field doesn't contain the provided error"
        post_data = {
            "text": "Hello World",
            "email": "not an email address",
            "value": 37,
            "single": "b",
            "multi": ("b", "c", "e"),
        }
        response = self.client.post("/test_client/form_view/", post_data)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "Invalid POST Template")

        try:
            self.assertFormError(response, "form", "email", "Some error.")
        except AssertionError as e:
            self.assertIn(
                str_prefix(
                    "The field 'email' on form 'form' in context 0 does not contain the error 'Some error.' (actual errors: [%(_)s'Enter a valid email address.'])"
                ),
                str(e),
            )
        try:
            self.assertFormError(response, "form", "email", "Some error.", msg_prefix="abc")
        except AssertionError as e:
            self.assertIn(
                str_prefix(
                    "abc: The field 'email' on form 'form' in context 0 does not contain the error 'Some error.' (actual errors: [%(_)s'Enter a valid email address.'])"
                ),
                str(e),
            )
Example #4
0
 def test_wsgirequest_repr(self):
     request = WSGIRequest({"PATH_INFO": "/somepath/", "REQUEST_METHOD": "get", "wsgi.input": BytesIO(b"")})
     request.GET = {"get-key": "get-value"}
     request.POST = {"post-key": "post-value"}
     request.COOKIES = {"post-key": "post-value"}
     request.META = {"post-key": "post-value"}
     self.assertEqual(
         repr(request),
         str_prefix(
             "<WSGIRequest\npath:/somepath/,\nGET:{%(_)s'get-key': %(_)s'get-value'},\nPOST:{%(_)s'post-key': %(_)s'post-value'},\nCOOKIES:{%(_)s'post-key': %(_)s'post-value'},\nMETA:{%(_)s'post-key': %(_)s'post-value'}>"
         ),
     )
     self.assertEqual(build_request_repr(request), repr(request))
     self.assertEqual(
         build_request_repr(
             request,
             path_override="/otherpath/",
             GET_override={"a": "b"},
             POST_override={"c": "d"},
             COOKIES_override={"e": "f"},
             META_override={"g": "h"},
         ),
         str_prefix(
             "<WSGIRequest\npath:/otherpath/,\nGET:{%(_)s'a': %(_)s'b'},\nPOST:{%(_)s'c': %(_)s'd'},\nCOOKIES:{%(_)s'e': %(_)s'f'},\nMETA:{%(_)s'g': %(_)s'h'}>"
         ),
     )
Example #5
0
 def test_wsgirequest_repr(self):
     request = WSGIRequest({
         'PATH_INFO': '/somepath/',
         'REQUEST_METHOD': 'get',
         'wsgi.input': BytesIO(b'')
     })
     request.GET = {'get-key': 'get-value'}
     request.POST = {'post-key': 'post-value'}
     request.COOKIES = {'post-key': 'post-value'}
     request.META = {'post-key': 'post-value'}
     self.assertEqual(
         repr(request),
         str_prefix(
             "<WSGIRequest\npath:/somepath/,\nGET:{%(_)s'get-key': %(_)s'get-value'},\nPOST:{%(_)s'post-key': %(_)s'post-value'},\nCOOKIES:{%(_)s'post-key': %(_)s'post-value'},\nMETA:{%(_)s'post-key': %(_)s'post-value'}>"
         ))
     self.assertEqual(build_request_repr(request), repr(request))
     self.assertEqual(
         build_request_repr(request,
                            path_override='/otherpath/',
                            GET_override={'a': 'b'},
                            POST_override={'c': 'd'},
                            COOKIES_override={'e': 'f'},
                            META_override={'g': 'h'}),
         str_prefix(
             "<WSGIRequest\npath:/otherpath/,\nGET:{%(_)s'a': %(_)s'b'},\nPOST:{%(_)s'c': %(_)s'd'},\nCOOKIES:{%(_)s'e': %(_)s'f'},\nMETA:{%(_)s'g': %(_)s'h'}>"
         ))
Example #6
0
 def test_message_dict(self):
     v = ValidationError({'first': ['First Problem']})
     self.assertEqual(str(v),
                      str_prefix("{%(_)s'first': [%(_)s'First Problem']}"))
     self.assertEqual(
         repr(v),
         str_prefix(
             "ValidationError({%(_)s'first': [%(_)s'First Problem']})"))
Example #7
0
 def test_wsgirequest_repr(self):
     request = WSGIRequest({'REQUEST_METHOD': 'get', 'wsgi.input': BytesIO(b'')})
     self.assertEqual(repr(request), str_prefix("<WSGIRequest: GET '/'>"))
     request = WSGIRequest({'PATH_INFO': '/somepath/', 'REQUEST_METHOD': 'get', 'wsgi.input': BytesIO(b'')})
     request.GET = {'get-key': 'get-value'}
     request.POST = {'post-key': 'post-value'}
     request.COOKIES = {'post-key': 'post-value'}
     request.META = {'post-key': 'post-value'}
     self.assertEqual(repr(request), str_prefix("<WSGIRequest: GET '/somepath/'>"))
Example #8
0
 def test_httprequest_repr_invalid_method_and_path(self):
     request = HttpRequest()
     self.assertEqual(repr(request), str_prefix("<HttpRequest>"))
     request = HttpRequest()
     request.method = "GET"
     self.assertEqual(repr(request), str_prefix("<HttpRequest>"))
     request = HttpRequest()
     request.path = ""
     self.assertEqual(repr(request), str_prefix("<HttpRequest>"))
Example #9
0
 def test_wsgirequest_repr(self):
     request = WSGIRequest({'REQUEST_METHOD': 'get', 'wsgi.input': BytesIO(b'')})
     self.assertEqual(repr(request), str_prefix("<WSGIRequest: GET '/'>"))
     request = WSGIRequest({'PATH_INFO': '/somepath/', 'REQUEST_METHOD': 'get', 'wsgi.input': BytesIO(b'')})
     request.GET = {'get-key': 'get-value'}
     request.POST = {'post-key': 'post-value'}
     request.COOKIES = {'post-key': 'post-value'}
     request.META = {'post-key': 'post-value'}
     self.assertEqual(repr(request), str_prefix("<WSGIRequest: GET '/somepath/'>"))
Example #10
0
 def test_httprequest_repr_invalid_method_and_path(self):
     request = HttpRequest()
     self.assertEqual(repr(request), str_prefix("<HttpRequest>"))
     request = HttpRequest()
     request.method = "GET"
     self.assertEqual(repr(request), str_prefix("<HttpRequest>"))
     request = HttpRequest()
     request.path = ""
     self.assertEqual(repr(request), str_prefix("<HttpRequest>"))
Example #11
0
 def test_wsgirequest_repr(self):
     request = WSGIRequest({"REQUEST_METHOD": "get", "wsgi.input": BytesIO(b"")})
     self.assertEqual(repr(request), str_prefix("<WSGIRequest: GET '/'>"))
     request = WSGIRequest({"PATH_INFO": "/somepath/", "REQUEST_METHOD": "get", "wsgi.input": BytesIO(b"")})
     request.GET = {"get-key": "get-value"}
     request.POST = {"post-key": "post-value"}
     request.COOKIES = {"post-key": "post-value"}
     request.META = {"post-key": "post-value"}
     self.assertEqual(repr(request), str_prefix("<WSGIRequest: GET '/somepath/'>"))
Example #12
0
 def test_message_list(self):
     v = ValidationError(['First Problem', 'Second Problem'])
     self.assertEqual(
         str(v),
         str_prefix("[%(_)s'First Problem', %(_)s'Second Problem']"))
     self.assertEqual(
         repr(v),
         str_prefix(
             "ValidationError([%(_)s'First Problem', %(_)s'Second Problem'])"
         ))
Example #13
0
File: tests.py Project: 10sr/hue
 def test_wsgirequest_repr(self):
     request = WSGIRequest({'PATH_INFO': '/somepath/', 'REQUEST_METHOD': 'get', 'wsgi.input': BytesIO(b'')})
     request.GET = {'get-key': 'get-value'}
     request.POST = {'post-key': 'post-value'}
     request.COOKIES = {'post-key': 'post-value'}
     request.META = {'post-key': 'post-value'}
     self.assertEqual(repr(request), str_prefix("<WSGIRequest\npath:/somepath/,\nGET:{%(_)s'get-key': %(_)s'get-value'},\nPOST:{%(_)s'post-key': %(_)s'post-value'},\nCOOKIES:{%(_)s'post-key': %(_)s'post-value'},\nMETA:{%(_)s'post-key': %(_)s'post-value'}>"))
     self.assertEqual(build_request_repr(request), repr(request))
     self.assertEqual(build_request_repr(request, path_override='/otherpath/', GET_override={'a': 'b'}, POST_override={'c': 'd'}, COOKIES_override={'e': 'f'}, META_override={'g': 'h'}),
                      str_prefix("<WSGIRequest\npath:/otherpath/,\nGET:{%(_)s'a': %(_)s'b'},\nPOST:{%(_)s'c': %(_)s'd'},\nCOOKIES:{%(_)s'e': %(_)s'f'},\nMETA:{%(_)s'g': %(_)s'h'}>"))
Example #14
0
File: tests.py Project: 10sr/hue
 def test_httprequest_repr(self):
     request = HttpRequest()
     request.path = '/somepath/'
     request.GET = {'get-key': 'get-value'}
     request.POST = {'post-key': 'post-value'}
     request.COOKIES = {'post-key': 'post-value'}
     request.META = {'post-key': 'post-value'}
     self.assertEqual(repr(request), str_prefix("<HttpRequest\npath:/somepath/,\nGET:{%(_)s'get-key': %(_)s'get-value'},\nPOST:{%(_)s'post-key': %(_)s'post-value'},\nCOOKIES:{%(_)s'post-key': %(_)s'post-value'},\nMETA:{%(_)s'post-key': %(_)s'post-value'}>"))
     self.assertEqual(build_request_repr(request), repr(request))
     self.assertEqual(build_request_repr(request, path_override='/otherpath/', GET_override={'a': 'b'}, POST_override={'c': 'd'}, COOKIES_override={'e': 'f'}, META_override={'g': 'h'}),
                      str_prefix("<HttpRequest\npath:/otherpath/,\nGET:{%(_)s'a': %(_)s'b'},\nPOST:{%(_)s'c': %(_)s'd'},\nCOOKIES:{%(_)s'e': %(_)s'f'},\nMETA:{%(_)s'g': %(_)s'h'}>"))
Example #15
0
    def test_basic_distinct_on(self):
        """QuerySet.distinct('field', ...) works"""
        # (qset, expected) tuples
        qsets = (
            (Staff.objects.distinct().order_by("name"), ["<Staff: p1>", "<Staff: p1>", "<Staff: p2>", "<Staff: p3>"]),
            (Staff.objects.distinct("name").order_by("name"), ["<Staff: p1>", "<Staff: p2>", "<Staff: p3>"]),
            (Staff.objects.distinct("organisation").order_by("organisation", "name"), ["<Staff: p1>", "<Staff: p1>"]),
            (
                Staff.objects.distinct("name", "organisation").order_by("name", "organisation"),
                ["<Staff: p1>", "<Staff: p1>", "<Staff: p2>", "<Staff: p3>"],
            ),
            (
                Celebrity.objects.filter(fan__in=[self.fan1, self.fan2, self.fan3]).distinct("name").order_by("name"),
                ["<Celebrity: c1>", "<Celebrity: c2>"],
            ),
            # Does combining querysets work?
            (
                (
                    Celebrity.objects.filter(fan__in=[self.fan1, self.fan2]).distinct("name").order_by("name")
                    | Celebrity.objects.filter(fan__in=[self.fan3]).distinct("name").order_by("name")
                ),
                ["<Celebrity: c1>", "<Celebrity: c2>"],
            ),
            (StaffTag.objects.distinct("staff", "tag"), ["<StaffTag: t1 -> p1>"]),
            (Tag.objects.order_by("parent__pk", "pk").distinct("parent"), ["<Tag: t2>", "<Tag: t4>", "<Tag: t1>"]),
            (
                StaffTag.objects.select_related("staff").distinct("staff__name").order_by("staff__name"),
                ["<StaffTag: t1 -> p1>"],
            ),
            # Fetch the alphabetically first coworker for each worker
            (
                (Staff.objects.distinct("id").order_by("id", "coworkers__name").values_list("id", "coworkers__name")),
                [str_prefix("(1, %(_)s'p2')"), str_prefix("(2, %(_)s'p1')"), str_prefix("(3, %(_)s'p1')"), "(4, None)"],
            ),
        )
        for qset, expected in qsets:
            self.assertQuerysetEqual(qset, expected)
            self.assertEqual(qset.count(), len(expected))

        # Combining queries with different distinct_fields is not allowed.
        base_qs = Celebrity.objects.all()
        self.assertRaisesMessage(
            AssertionError,
            "Cannot combine queries with different distinct fields.",
            lambda: (base_qs.distinct("id") & base_qs.distinct("name")),
        )

        # Test join unreffing
        c1 = Celebrity.objects.distinct("greatest_fan__id", "greatest_fan__fan_of")
        self.assertIn("OUTER JOIN", str(c1.query))
        c2 = c1.distinct("pk")
        self.assertNotIn("OUTER JOIN", str(c2.query))
Example #16
0
 def test_no_interpolation_on_sqlite(self):
     # Regression for #17158
     # This shouldn't raise an exception
     query = "SELECT strftime('%Y', 'now');"
     connection.cursor().execute(query)
     self.assertEqual(connection.queries[-1]['sql'],
         str_prefix("QUERY = %(_)s\"SELECT strftime('%%Y', 'now');\" - PARAMS = ()"))
Example #17
0
 def test_no_interpolation_on_sqlite(self):
     # Regression for #17158
     # This shouldn't raise an exception
     query = "SELECT strftime('%Y', 'now');"
     connection.cursor().execute(query)
     self.assertEqual(connection.queries[-1]['sql'],
         str_prefix("QUERY = %(_)s\"SELECT strftime('%%Y', 'now');\" - PARAMS = ()"))
Example #18
0
 def test_httprequest_repr(self):
     request = HttpRequest()
     request.path = "/somepath/"
     request.method = "GET"
     request.GET = {"get-key": "get-value"}
     request.POST = {"post-key": "post-value"}
     request.COOKIES = {"post-key": "post-value"}
     request.META = {"post-key": "post-value"}
     self.assertEqual(repr(request), str_prefix("<HttpRequest: GET '/somepath/'>"))
Example #19
0
    def test_nonexistent_field(self):
        class SongAdmin(admin.ModelAdmin):
            readonly_fields = ("title", "nonexistent")

        self.assertRaisesMessage(ImproperlyConfigured,
            str_prefix("SongAdmin.readonly_fields[1], %(_)s'nonexistent' is not a callable "
                       "or an attribute of 'SongAdmin' or found in the model 'Song'."),
            SongAdmin.validate,
            Song)
Example #20
0
 def test_load_backend_invalid_name(self):
     msg = str_prefix(
         "'foo' isn't an available database backend.\n"
         "Try using 'django.db.backends.XXX', where XXX is one of:\n"
         "    %(_)s'mysql', %(_)s'oracle', %(_)s'postgresql_psycopg2', %(_)s'sqlite3'\n"
         "Error was: No module named %%s"
     ) % "foo.base" if six.PY2 else "'foo'"
     with self.assertRaisesMessage(ImproperlyConfigured, msg):
         load_backend('foo')
Example #21
0
 def test_httprequest_repr(self):
     request = HttpRequest()
     request.path = '/somepath/'
     request.method = 'GET'
     request.GET = {'get-key': 'get-value'}
     request.POST = {'post-key': 'post-value'}
     request.COOKIES = {'post-key': 'post-value'}
     request.META = {'post-key': 'post-value'}
     self.assertEqual(repr(request), str_prefix("<HttpRequest: GET '/somepath/'>"))
Example #22
0
    def test_nonexistent_field(self):
        class SongAdmin(admin.ModelAdmin):
            readonly_fields = ("title", "nonexistent")

        self.assertRaisesMessage(ImproperlyConfigured,
            str_prefix("SongAdmin.readonly_fields[1], %(_)s'nonexistent' is not a callable "
                       "or an attribute of 'SongAdmin' or found in the model 'Song'."),
            SongAdmin.validate,
            Song)
Example #23
0
 def test_httprequest_repr(self):
     request = HttpRequest()
     request.path = '/somepath/'
     request.method = 'GET'
     request.GET = {'get-key': 'get-value'}
     request.POST = {'post-key': 'post-value'}
     request.COOKIES = {'post-key': 'post-value'}
     request.META = {'post-key': 'post-value'}
     self.assertEqual(repr(request), str_prefix("<HttpRequest: GET '/somepath/'>"))
Example #24
0
    def test_nonexistent_field_on_inline(self):
        class CityInline(admin.TabularInline):
            model = City
            readonly_fields = ['i_dont_exist']  # Missing attribute

        self.assertRaisesMessage(ImproperlyConfigured,
            str_prefix("CityInline.readonly_fields[0], %(_)s'i_dont_exist' is not a callable "
                       "or an attribute of 'CityInline' or found in the model 'City'."),
            CityInline.validate,
            City)
Example #25
0
    def test_nonexistent_field_on_inline(self):
        class CityInline(admin.TabularInline):
            model = City
            readonly_fields = ['i_dont_exist']  # Missing attribute

        self.assertRaisesMessage(ImproperlyConfigured,
            str_prefix("CityInline.readonly_fields[0], %(_)s'i_dont_exist' is not a callable "
                       "or an attribute of 'CityInline' or found in the model 'City'."),
            CityInline.validate,
            City)
Example #26
0
    def test_nonexistent_field(self):
        class SongAdmin(admin.ModelAdmin):
            readonly_fields = ("title", "nonexistent")

        with warnings.catch_warnings(record=True):
            warnings.filterwarnings('ignore', module='django.contrib.admin.options')
            self.assertRaisesMessage(ImproperlyConfigured,
                str_prefix("SongAdmin.readonly_fields[1], %(_)s'nonexistent' is not a callable "
                           "or an attribute of 'SongAdmin' or found in the model 'Song'."),
                SongAdmin.validate,
                Song)
Example #27
0
    def test_nonexistent_field_on_inline(self):
        class CityInline(admin.TabularInline):
            model = City
            readonly_fields = ['i_dont_exist']  # Missing attribute

        with warnings.catch_warnings(record=True):
            warnings.filterwarnings('ignore', module='django.contrib.admin.options')
            self.assertRaisesMessage(ImproperlyConfigured,
                str_prefix("CityInline.readonly_fields[0], %(_)s'i_dont_exist' is not a callable "
                           "or an attribute of 'CityInline' or found in the model 'City'."),
                CityInline.validate,
                City)
Example #28
0
    def test_unknown_error(self):
        "An assertion is raised if the field doesn't contain the provided error"
        post_data = {
            'text': 'Hello World',
            'email': 'not an email address',
            'value': 37,
            'single': 'b',
            'multi': ('b','c','e')
        }
        response = self.client.post('/test_client/form_view/', post_data)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "Invalid POST Template")

        try:
            self.assertFormError(response, 'form', 'email', 'Some error.')
        except AssertionError as e:
            self.assertIn(str_prefix("The field 'email' on form 'form' in context 0 does not contain the error 'Some error.' (actual errors: [%(_)s'Enter a valid e-mail address.'])"), str(e))
        try:
            self.assertFormError(response, 'form', 'email', 'Some error.', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn(str_prefix("abc: The field 'email' on form 'form' in context 0 does not contain the error 'Some error.' (actual errors: [%(_)s'Enter a valid e-mail address.'])"), str(e))
Example #29
0
    def test_unknown_error(self):
        "An assertion is raised if the field doesn't contain the provided error"
        post_data = {
            'text': 'Hello World',
            'email': 'not an email address',
            'value': 37,
            'single': 'b',
            'multi': ('b','c','e')
        }
        response = self.client.post('/test_client/form_view/', post_data)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "Invalid POST Template")

        try:
            self.assertFormError(response, 'form', 'email', 'Some error.')
        except AssertionError as e:
            self.assertIn(str_prefix("The field 'email' on form 'form' in context 0 does not contain the error 'Some error.' (actual errors: [%(_)s'Enter a valid email address.'])"), str(e))
        try:
            self.assertFormError(response, 'form', 'email', 'Some error.', msg_prefix='abc')
        except AssertionError as e:
            self.assertIn(str_prefix("abc: The field 'email' on form 'form' in context 0 does not contain the error 'Some error.' (actual errors: [%(_)s'Enter a valid email address.'])"), str(e))
Example #30
0
    def test_list_display_validation(self):
        class ValidationTestModelAdmin(ModelAdmin):
            list_display = 10

        six.assertRaisesRegex(
            self,
            ImproperlyConfigured,
            "'ValidationTestModelAdmin.list_display' must be a list or tuple.",
            validate,
            ValidationTestModelAdmin,
            ValidationTestModel,
        )

        class ValidationTestModelAdmin(ModelAdmin):
            list_display = ('non_existent_field', )

        six.assertRaisesRegex(
            self,
            ImproperlyConfigured,
            str_prefix(
                "ValidationTestModelAdmin.list_display\[0\], %(_)s'non_existent_field' is not a callable or an attribute of 'ValidationTestModelAdmin' or found in the model 'ValidationTestModel'."
            ),
            validate,
            ValidationTestModelAdmin,
            ValidationTestModel,
        )

        class ValidationTestModelAdmin(ModelAdmin):
            list_display = ('users', )

        six.assertRaisesRegex(
            self,
            ImproperlyConfigured,
            "'ValidationTestModelAdmin.list_display\[0\]', 'users' is a ManyToManyField which is not supported.",
            validate,
            ValidationTestModelAdmin,
            ValidationTestModel,
        )

        def a_callable(obj):
            pass

        class ValidationTestModelAdmin(ModelAdmin):
            def a_method(self, obj):
                pass

            list_display = ('name', 'decade_published_in', 'a_method',
                            a_callable)

        validate(ValidationTestModelAdmin, ValidationTestModel)
Example #31
0
    def test_list_display_validation(self):
        class ValidationTestModelAdmin(ModelAdmin):
            list_display = 10

        six.assertRaisesRegex(
            self,
            ImproperlyConfigured,
            "'ValidationTestModelAdmin.list_display' must be a list or tuple.",
            ValidationTestModelAdmin.validate,
            ValidationTestModel,
        )

        class ValidationTestModelAdmin(ModelAdmin):
            list_display = ("non_existent_field",)

        six.assertRaisesRegex(
            self,
            ImproperlyConfigured,
            str_prefix(
                "ValidationTestModelAdmin.list_display\[0\], %(_)s'non_existent_field' is not a callable or an attribute of 'ValidationTestModelAdmin' or found in the model 'ValidationTestModel'."
            ),
            ValidationTestModelAdmin.validate,
            ValidationTestModel,
        )

        class ValidationTestModelAdmin(ModelAdmin):
            list_display = ("users",)

        six.assertRaisesRegex(
            self,
            ImproperlyConfigured,
            "'ValidationTestModelAdmin.list_display\[0\]', 'users' is a ManyToManyField which is not supported.",
            ValidationTestModelAdmin.validate,
            ValidationTestModel,
        )

        def a_callable(obj):
            pass

        class ValidationTestModelAdmin(ModelAdmin):
            def a_method(self, obj):
                pass

            list_display = ("name", "decade_published_in", "a_method", a_callable)

        ValidationTestModelAdmin.validate(ValidationTestModel)
Example #32
0
 def test_single_message(self):
     v = ValidationError('Not Valid')
     self.assertEqual(str(v), str_prefix("[%(_)s'Not Valid']"))
     self.assertEqual(repr(v),
                      str_prefix("ValidationError([%(_)s'Not Valid'])"))
Example #33
0
 def test_message_dict(self):
     v = ValidationError({'first': ['First Problem']})
     self.assertEqual(str(v), str_prefix("{%(_)s'first': [%(_)s'First Problem']}"))
     self.assertEqual(repr(v), str_prefix("ValidationError({%(_)s'first': [%(_)s'First Problem']})"))
Example #34
0
 def test_message_list(self):
     v = ValidationError(['First Problem', 'Second Problem'])
     self.assertEqual(str(v), str_prefix("[%(_)s'First Problem', %(_)s'Second Problem']"))
     self.assertEqual(repr(v), str_prefix("ValidationError([%(_)s'First Problem', %(_)s'Second Problem'])"))
Example #35
0
 def test_single_message(self):
     v = ValidationError('Not Valid')
     self.assertEqual(str(v), str_prefix("[%(_)s'Not Valid']"))
     self.assertEqual(repr(v), str_prefix("ValidationError([%(_)s'Not Valid'])"))
Example #36
0
def get_filter_tests():
    now = datetime.now()
    now_tz = datetime.now(LocalTimezone(now))
    now_tz_i = datetime.now(FixedOffset((3 * 60) + 15))  # imaginary time zone
    today = date.today()

    # NOTE: \xa0 avoids wrapping between value and unit
    return {
        # Default compare with datetime.now()
        "filter-timesince01": (
            "{{ a|timesince }}",
            {"a": datetime.now() + timedelta(minutes=-1, seconds=-10)},
            "1\xa0minute",
        ),
        "filter-timesince02": ("{{ a|timesince }}", {"a": datetime.now() - timedelta(days=1, minutes=1)}, "1\xa0day"),
        "filter-timesince03": (
            "{{ a|timesince }}",
            {"a": datetime.now() - timedelta(hours=1, minutes=25, seconds=10)},
            "1\xa0hour, 25\xa0minutes",
        ),
        # Compare to a given parameter
        "filter-timesince04": (
            "{{ a|timesince:b }}",
            {"a": now - timedelta(days=2), "b": now - timedelta(days=1)},
            "1\xa0day",
        ),
        "filter-timesince05": (
            "{{ a|timesince:b }}",
            {"a": now - timedelta(days=2, minutes=1), "b": now - timedelta(days=2)},
            "1\xa0minute",
        ),
        # Check that timezone is respected
        "filter-timesince06": ("{{ a|timesince:b }}", {"a": now_tz - timedelta(hours=8), "b": now_tz}, "8\xa0hours"),
        # Regression for #7443
        "filter-timesince07": ("{{ earlier|timesince }}", {"earlier": now - timedelta(days=7)}, "1\xa0week"),
        "filter-timesince08": (
            "{{ earlier|timesince:now }}",
            {"now": now, "earlier": now - timedelta(days=7)},
            "1\xa0week",
        ),
        "filter-timesince09": ("{{ later|timesince }}", {"later": now + timedelta(days=7)}, "0\xa0minutes"),
        "filter-timesince10": (
            "{{ later|timesince:now }}",
            {"now": now, "later": now + timedelta(days=7)},
            "0\xa0minutes",
        ),
        # Ensures that differing timezones are calculated correctly
        "filter-timesince11": ("{{ a|timesince }}", {"a": now}, "0\xa0minutes"),
        "filter-timesince12": ("{{ a|timesince }}", {"a": now_tz}, "0\xa0minutes"),
        "filter-timesince13": ("{{ a|timesince }}", {"a": now_tz_i}, "0\xa0minutes"),
        "filter-timesince14": ("{{ a|timesince:b }}", {"a": now_tz, "b": now_tz_i}, "0\xa0minutes"),
        "filter-timesince15": ("{{ a|timesince:b }}", {"a": now, "b": now_tz_i}, ""),
        "filter-timesince16": ("{{ a|timesince:b }}", {"a": now_tz_i, "b": now}, ""),
        # Regression for #9065 (two date objects).
        "filter-timesince17": ("{{ a|timesince:b }}", {"a": today, "b": today}, "0\xa0minutes"),
        "filter-timesince18": ("{{ a|timesince:b }}", {"a": today, "b": today + timedelta(hours=24)}, "1\xa0day"),
        # Default compare with datetime.now()
        "filter-timeuntil01": (
            "{{ a|timeuntil }}",
            {"a": datetime.now() + timedelta(minutes=2, seconds=10)},
            "2\xa0minutes",
        ),
        "filter-timeuntil02": (
            "{{ a|timeuntil }}",
            {"a": (datetime.now() + timedelta(days=1, seconds=10))},
            "1\xa0day",
        ),
        "filter-timeuntil03": (
            "{{ a|timeuntil }}",
            {"a": (datetime.now() + timedelta(hours=8, minutes=10, seconds=10))},
            "8\xa0hours, 10\xa0minutes",
        ),
        # Compare to a given parameter
        "filter-timeuntil04": (
            "{{ a|timeuntil:b }}",
            {"a": now - timedelta(days=1), "b": now - timedelta(days=2)},
            "1\xa0day",
        ),
        "filter-timeuntil05": (
            "{{ a|timeuntil:b }}",
            {"a": now - timedelta(days=2), "b": now - timedelta(days=2, minutes=1)},
            "1\xa0minute",
        ),
        # Regression for #7443
        "filter-timeuntil06": ("{{ earlier|timeuntil }}", {"earlier": now - timedelta(days=7)}, "0\xa0minutes"),
        "filter-timeuntil07": (
            "{{ earlier|timeuntil:now }}",
            {"now": now, "earlier": now - timedelta(days=7)},
            "0\xa0minutes",
        ),
        "filter-timeuntil08": ("{{ later|timeuntil }}", {"later": now + timedelta(days=7, hours=1)}, "1\xa0week"),
        "filter-timeuntil09": (
            "{{ later|timeuntil:now }}",
            {"now": now, "later": now + timedelta(days=7)},
            "1\xa0week",
        ),
        # Ensures that differing timezones are calculated correctly
        "filter-timeuntil10": ("{{ a|timeuntil }}", {"a": now_tz_i}, "0\xa0minutes"),
        "filter-timeuntil11": ("{{ a|timeuntil:b }}", {"a": now_tz_i, "b": now_tz}, "0\xa0minutes"),
        # Regression for #9065 (two date objects).
        "filter-timeuntil12": ("{{ a|timeuntil:b }}", {"a": today, "b": today}, "0\xa0minutes"),
        "filter-timeuntil13": ("{{ a|timeuntil:b }}", {"a": today, "b": today - timedelta(hours=24)}, "1\xa0day"),
        "filter-addslash01": (
            "{% autoescape off %}{{ a|addslashes }} {{ b|addslashes }}{% endautoescape %}",
            {"a": "<a>'", "b": mark_safe("<a>'")},
            r"<a>\' <a>\'",
        ),
        "filter-addslash02": (
            "{{ a|addslashes }} {{ b|addslashes }}",
            {"a": "<a>'", "b": mark_safe("<a>'")},
            r"&lt;a&gt;\&#39; <a>\'",
        ),
        "filter-capfirst01": (
            "{% autoescape off %}{{ a|capfirst }} {{ b|capfirst }}{% endautoescape %}",
            {"a": "fred>", "b": mark_safe("fred&gt;")},
            "Fred> Fred&gt;",
        ),
        "filter-capfirst02": (
            "{{ a|capfirst }} {{ b|capfirst }}",
            {"a": "fred>", "b": mark_safe("fred&gt;")},
            "Fred&gt; Fred&gt;",
        ),
        # Note that applying fix_ampsersands in autoescape mode leads to
        # double escaping.
        "filter-fix_ampersands01": (
            "{% autoescape off %}{{ a|fix_ampersands }} {{ b|fix_ampersands }}{% endautoescape %}",
            {"a": "a&b", "b": mark_safe("a&b")},
            "a&amp;b a&amp;b",
        ),
        "filter-fix_ampersands02": (
            "{{ a|fix_ampersands }} {{ b|fix_ampersands }}",
            {"a": "a&b", "b": mark_safe("a&b")},
            "a&amp;amp;b a&amp;b",
        ),
        "filter-floatformat01": (
            "{% autoescape off %}{{ a|floatformat }} {{ b|floatformat }}{% endautoescape %}",
            {"a": "1.42", "b": mark_safe("1.42")},
            "1.4 1.4",
        ),
        "filter-floatformat02": (
            "{{ a|floatformat }} {{ b|floatformat }}",
            {"a": "1.42", "b": mark_safe("1.42")},
            "1.4 1.4",
        ),
        # The contents of "linenumbers" is escaped according to the current
        # autoescape setting.
        "filter-linenumbers01": (
            "{{ a|linenumbers }} {{ b|linenumbers }}",
            {"a": "one\n<two>\nthree", "b": mark_safe("one\n&lt;two&gt;\nthree")},
            "1. one\n2. &lt;two&gt;\n3. three 1. one\n2. &lt;two&gt;\n3. three",
        ),
        "filter-linenumbers02": (
            "{% autoescape off %}{{ a|linenumbers }} {{ b|linenumbers }}{% endautoescape %}",
            {"a": "one\n<two>\nthree", "b": mark_safe("one\n&lt;two&gt;\nthree")},
            "1. one\n2. <two>\n3. three 1. one\n2. &lt;two&gt;\n3. three",
        ),
        "filter-lower01": (
            "{% autoescape off %}{{ a|lower }} {{ b|lower }}{% endautoescape %}",
            {"a": "Apple & banana", "b": mark_safe("Apple &amp; banana")},
            "apple & banana apple &amp; banana",
        ),
        "filter-lower02": (
            "{{ a|lower }} {{ b|lower }}",
            {"a": "Apple & banana", "b": mark_safe("Apple &amp; banana")},
            "apple &amp; banana apple &amp; banana",
        ),
        # The make_list filter can destroy existing escaping, so the results are
        # escaped.
        "filter-make_list01": (
            "{% autoescape off %}{{ a|make_list }}{% endautoescape %}",
            {"a": mark_safe("&")},
            str_prefix("[%(_)s'&']"),
        ),
        "filter-make_list02": ("{{ a|make_list }}", {"a": mark_safe("&")}, str_prefix("[%(_)s&#39;&amp;&#39;]")),
        "filter-make_list03": (
            '{% autoescape off %}{{ a|make_list|stringformat:"s"|safe }}{% endautoescape %}',
            {"a": mark_safe("&")},
            str_prefix("[%(_)s'&']"),
        ),
        "filter-make_list04": (
            '{{ a|make_list|stringformat:"s"|safe }}',
            {"a": mark_safe("&")},
            str_prefix("[%(_)s'&']"),
        ),
        # Running slugify on a pre-escaped string leads to odd behavior,
        # but the result is still safe.
        "filter-slugify01": (
            "{% autoescape off %}{{ a|slugify }} {{ b|slugify }}{% endautoescape %}",
            {"a": "a & b", "b": mark_safe("a &amp; b")},
            "a-b a-amp-b",
        ),
        "filter-slugify02": (
            "{{ a|slugify }} {{ b|slugify }}",
            {"a": "a & b", "b": mark_safe("a &amp; b")},
            "a-b a-amp-b",
        ),
        # Notice that escaping is applied *after* any filters, so the string
        # formatting here only needs to deal with pre-escaped characters.
        "filter-stringformat01": (
            '{% autoescape off %}.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.{% endautoescape %}',
            {"a": "a<b", "b": mark_safe("a<b")},
            ".  a<b. .  a<b.",
        ),
        "filter-stringformat02": (
            '.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.',
            {"a": "a<b", "b": mark_safe("a<b")},
            ".  a&lt;b. .  a<b.",
        ),
        # Test the title filter
        "filter-title1": ("{{ a|title }}", {"a": "JOE'S CRAB SHACK"}, "Joe&#39;s Crab Shack"),
        "filter-title2": ("{{ a|title }}", {"a": "555 WEST 53RD STREET"}, "555 West 53rd Street"),
        "filter-truncatewords01": (
            '{% autoescape off %}{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}{% endautoescape %}',
            {"a": "alpha & bravo", "b": mark_safe("alpha &amp; bravo")},
            "alpha & ... alpha &amp; ...",
        ),
        "filter-truncatewords02": (
            '{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}',
            {"a": "alpha & bravo", "b": mark_safe("alpha &amp; bravo")},
            "alpha &amp; ... alpha &amp; ...",
        ),
        "filter-truncatechars01": ("{{ a|truncatechars:5 }}", {"a": "Testing, testing"}, "Te..."),
        "filter-truncatechars02": ("{{ a|truncatechars:7 }}", {"a": "Testing"}, "Testing"),
        # The "upper" filter messes up entities (which are case-sensitive),
        # so it's not safe for non-escaping purposes.
        "filter-upper01": (
            "{% autoescape off %}{{ a|upper }} {{ b|upper }}{% endautoescape %}",
            {"a": "a & b", "b": mark_safe("a &amp; b")},
            "A & B A &AMP; B",
        ),
        "filter-upper02": (
            "{{ a|upper }} {{ b|upper }}",
            {"a": "a & b", "b": mark_safe("a &amp; b")},
            "A &amp; B A &amp;AMP; B",
        ),
        "filter-urlize01": (
            "{% autoescape off %}{{ a|urlize }} {{ b|urlize }}{% endautoescape %}",
            {"a": "http://example.com/?x=&y=", "b": mark_safe("http://example.com?x=&amp;y=")},
            '<a href="http://example.com/?x=&y=" rel="nofollow">http://example.com/?x=&y=</a> <a href="http://example.com?x=&amp;y=" rel="nofollow">http://example.com?x=&amp;y=</a>',
        ),
        "filter-urlize02": (
            "{{ a|urlize }} {{ b|urlize }}",
            {"a": "http://example.com/?x=&y=", "b": mark_safe("http://example.com?x=&amp;y=")},
            '<a href="http://example.com/?x=&amp;y=" rel="nofollow">http://example.com/?x=&amp;y=</a> <a href="http://example.com?x=&amp;y=" rel="nofollow">http://example.com?x=&amp;y=</a>',
        ),
        "filter-urlize03": (
            "{% autoescape off %}{{ a|urlize }}{% endautoescape %}",
            {"a": mark_safe("a &amp; b")},
            "a &amp; b",
        ),
        "filter-urlize04": ("{{ a|urlize }}", {"a": mark_safe("a &amp; b")}, "a &amp; b"),
        # This will lead to a nonsense result, but at least it won't be
        # exploitable for XSS purposes when auto-escaping is on.
        "filter-urlize05": (
            "{% autoescape off %}{{ a|urlize }}{% endautoescape %}",
            {"a": "<script>alert('foo')</script>"},
            "<script>alert('foo')</script>",
        ),
        "filter-urlize06": (
            "{{ a|urlize }}",
            {"a": "<script>alert('foo')</script>"},
            "&lt;script&gt;alert(&#39;foo&#39;)&lt;/script&gt;",
        ),
        # mailto: testing for urlize
        "filter-urlize07": (
            "{{ a|urlize }}",
            {"a": "Email me at [email protected]"},
            'Email me at <a href="mailto:[email protected]">[email protected]</a>',
        ),
        "filter-urlize08": (
            "{{ a|urlize }}",
            {"a": "Email me at <*****@*****.**>"},
            'Email me at &lt;<a href="mailto:[email protected]">[email protected]</a>&gt;',
        ),
        "filter-urlizetrunc01": (
            '{% autoescape off %}{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}{% endautoescape %}',
            {"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe("&quot;Safe&quot; http://example.com?x=&amp;y=")},
            '"Unsafe" <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&amp;y=" rel="nofollow">http:...</a>',
        ),
        "filter-urlizetrunc02": (
            '{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}',
            {"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe("&quot;Safe&quot; http://example.com?x=&amp;y=")},
            '&quot;Unsafe&quot; <a href="http://example.com/x=&amp;y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&amp;y=" rel="nofollow">http:...</a>',
        ),
        "filter-wordcount01": (
            "{% autoescape off %}{{ a|wordcount }} {{ b|wordcount }}{% endautoescape %}",
            {"a": "a & b", "b": mark_safe("a &amp; b")},
            "3 3",
        ),
        "filter-wordcount02": (
            "{{ a|wordcount }} {{ b|wordcount }}",
            {"a": "a & b", "b": mark_safe("a &amp; b")},
            "3 3",
        ),
        "filter-wordwrap01": (
            '{% autoescape off %}{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}{% endautoescape %}',
            {"a": "a & b", "b": mark_safe("a & b")},
            "a &\nb a &\nb",
        ),
        "filter-wordwrap02": (
            '{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}',
            {"a": "a & b", "b": mark_safe("a & b")},
            "a &amp;\nb a &\nb",
        ),
        "filter-ljust01": (
            '{% autoescape off %}.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.{% endautoescape %}',
            {"a": "a&b", "b": mark_safe("a&b")},
            ".a&b  . .a&b  .",
        ),
        "filter-ljust02": (
            '.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.',
            {"a": "a&b", "b": mark_safe("a&b")},
            ".a&amp;b  . .a&b  .",
        ),
        "filter-rjust01": (
            '{% autoescape off %}.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.{% endautoescape %}',
            {"a": "a&b", "b": mark_safe("a&b")},
            ".  a&b. .  a&b.",
        ),
        "filter-rjust02": (
            '.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.',
            {"a": "a&b", "b": mark_safe("a&b")},
            ".  a&amp;b. .  a&b.",
        ),
        "filter-center01": (
            '{% autoescape off %}.{{ a|center:"5" }}. .{{ b|center:"5" }}.{% endautoescape %}',
            {"a": "a&b", "b": mark_safe("a&b")},
            ". a&b . . a&b .",
        ),
        "filter-center02": (
            '.{{ a|center:"5" }}. .{{ b|center:"5" }}.',
            {"a": "a&b", "b": mark_safe("a&b")},
            ". a&amp;b . . a&b .",
        ),
        "filter-cut01": (
            '{% autoescape off %}{{ a|cut:"x" }} {{ b|cut:"x" }}{% endautoescape %}',
            {"a": "x&y", "b": mark_safe("x&amp;y")},
            "&y &amp;y",
        ),
        "filter-cut02": ('{{ a|cut:"x" }} {{ b|cut:"x" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "&amp;y &amp;y"),
        "filter-cut03": (
            '{% autoescape off %}{{ a|cut:"&" }} {{ b|cut:"&" }}{% endautoescape %}',
            {"a": "x&y", "b": mark_safe("x&amp;y")},
            "xy xamp;y",
        ),
        "filter-cut04": ('{{ a|cut:"&" }} {{ b|cut:"&" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "xy xamp;y"),
        # Passing ';' to cut can break existing HTML entities, so those strings
        # are auto-escaped.
        "filter-cut05": (
            '{% autoescape off %}{{ a|cut:";" }} {{ b|cut:";" }}{% endautoescape %}',
            {"a": "x&y", "b": mark_safe("x&amp;y")},
            "x&y x&ampy",
        ),
        "filter-cut06": (
            '{{ a|cut:";" }} {{ b|cut:";" }}',
            {"a": "x&y", "b": mark_safe("x&amp;y")},
            "x&amp;y x&amp;ampy",
        ),
        # The "escape" filter works the same whether autoescape is on or off,
        # but it has no effect on strings already marked as safe.
        "filter-escape01": ("{{ a|escape }} {{ b|escape }}", {"a": "x&y", "b": mark_safe("x&y")}, "x&amp;y x&y"),
        "filter-escape02": (
            "{% autoescape off %}{{ a|escape }} {{ b|escape }}{% endautoescape %}",
            {"a": "x&y", "b": mark_safe("x&y")},
            "x&amp;y x&y",
        ),
        # It is only applied once, regardless of the number of times it
        # appears in a chain.
        "filter-escape03": ("{% autoescape off %}{{ a|escape|escape }}{% endautoescape %}", {"a": "x&y"}, "x&amp;y"),
        "filter-escape04": ("{{ a|escape|escape }}", {"a": "x&y"}, "x&amp;y"),
        # Force_escape is applied immediately. It can be used to provide
        # double-escaping, for example.
        "filter-force-escape01": (
            "{% autoescape off %}{{ a|force_escape }}{% endautoescape %}",
            {"a": "x&y"},
            "x&amp;y",
        ),
        "filter-force-escape02": ("{{ a|force_escape }}", {"a": "x&y"}, "x&amp;y"),
        "filter-force-escape03": (
            "{% autoescape off %}{{ a|force_escape|force_escape }}{% endautoescape %}",
            {"a": "x&y"},
            "x&amp;amp;y",
        ),
        "filter-force-escape04": ("{{ a|force_escape|force_escape }}", {"a": "x&y"}, "x&amp;amp;y"),
        # Because the result of force_escape is "safe", an additional
        # escape filter has no effect.
        "filter-force-escape05": (
            "{% autoescape off %}{{ a|force_escape|escape }}{% endautoescape %}",
            {"a": "x&y"},
            "x&amp;y",
        ),
        "filter-force-escape06": ("{{ a|force_escape|escape }}", {"a": "x&y"}, "x&amp;y"),
        "filter-force-escape07": (
            "{% autoescape off %}{{ a|escape|force_escape }}{% endautoescape %}",
            {"a": "x&y"},
            "x&amp;y",
        ),
        "filter-force-escape08": ("{{ a|escape|force_escape }}", {"a": "x&y"}, "x&amp;y"),
        # The contents in "linebreaks" and "linebreaksbr" are escaped
        # according to the current autoescape setting.
        "filter-linebreaks01": (
            "{{ a|linebreaks }} {{ b|linebreaks }}",
            {"a": "x&\ny", "b": mark_safe("x&\ny")},
            "<p>x&amp;<br />y</p> <p>x&<br />y</p>",
        ),
        "filter-linebreaks02": (
            "{% autoescape off %}{{ a|linebreaks }} {{ b|linebreaks }}{% endautoescape %}",
            {"a": "x&\ny", "b": mark_safe("x&\ny")},
            "<p>x&<br />y</p> <p>x&<br />y</p>",
        ),
        "filter-linebreaksbr01": (
            "{{ a|linebreaksbr }} {{ b|linebreaksbr }}",
            {"a": "x&\ny", "b": mark_safe("x&\ny")},
            "x&amp;<br />y x&<br />y",
        ),
        "filter-linebreaksbr02": (
            "{% autoescape off %}{{ a|linebreaksbr }} {{ b|linebreaksbr }}{% endautoescape %}",
            {"a": "x&\ny", "b": mark_safe("x&\ny")},
            "x&<br />y x&<br />y",
        ),
        "filter-safe01": ("{{ a }} -- {{ a|safe }}", {"a": "<b>hello</b>"}, "&lt;b&gt;hello&lt;/b&gt; -- <b>hello</b>"),
        "filter-safe02": (
            "{% autoescape off %}{{ a }} -- {{ a|safe }}{% endautoescape %}",
            {"a": "<b>hello</b>"},
            "<b>hello</b> -- <b>hello</b>",
        ),
        "filter-safeseq01": (
            '{{ a|join:", " }} -- {{ a|safeseq|join:", " }}',
            {"a": ["&", "<"]},
            "&amp;, &lt; -- &, <",
        ),
        "filter-safeseq02": (
            '{% autoescape off %}{{ a|join:", " }} -- {{ a|safeseq|join:", " }}{% endautoescape %}',
            {"a": ["&", "<"]},
            "&, < -- &, <",
        ),
        "filter-removetags01": (
            '{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}',
            {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")},
            "x &lt;p&gt;y&lt;/p&gt; x <p>y</p>",
        ),
        "filter-removetags02": (
            '{% autoescape off %}{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}{% endautoescape %}',
            {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")},
            "x <p>y</p> x <p>y</p>",
        ),
        "filter-striptags01": (
            "{{ a|striptags }} {{ b|striptags }}",
            {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")},
            "x y x y",
        ),
        "filter-striptags02": (
            "{% autoescape off %}{{ a|striptags }} {{ b|striptags }}{% endautoescape %}",
            {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")},
            "x y x y",
        ),
        "filter-first01": (
            "{{ a|first }} {{ b|first }}",
            {"a": ["a&b", "x"], "b": [mark_safe("a&b"), "x"]},
            "a&amp;b a&b",
        ),
        "filter-first02": (
            "{% autoescape off %}{{ a|first }} {{ b|first }}{% endautoescape %}",
            {"a": ["a&b", "x"], "b": [mark_safe("a&b"), "x"]},
            "a&b a&b",
        ),
        "filter-last01": (
            "{{ a|last }} {{ b|last }}",
            {"a": ["x", "a&b"], "b": ["x", mark_safe("a&b")]},
            "a&amp;b a&b",
        ),
        "filter-last02": (
            "{% autoescape off %}{{ a|last }} {{ b|last }}{% endautoescape %}",
            {"a": ["x", "a&b"], "b": ["x", mark_safe("a&b")]},
            "a&b a&b",
        ),
        "filter-random01": (
            "{{ a|random }} {{ b|random }}",
            {"a": ["a&b", "a&b"], "b": [mark_safe("a&b"), mark_safe("a&b")]},
            "a&amp;b a&b",
        ),
        "filter-random02": (
            "{% autoescape off %}{{ a|random }} {{ b|random }}{% endautoescape %}",
            {"a": ["a&b", "a&b"], "b": [mark_safe("a&b"), mark_safe("a&b")]},
            "a&b a&b",
        ),
        "filter-slice01": ('{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}', {"a": "a&b", "b": mark_safe("a&b")}, "&amp;b &b"),
        "filter-slice02": (
            '{% autoescape off %}{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}{% endautoescape %}',
            {"a": "a&b", "b": mark_safe("a&b")},
            "&b &b",
        ),
        "filter-unordered_list01": (
            "{{ a|unordered_list }}",
            {"a": ["x>", [["<y", []]]]},
            "\t<li>x&gt;\n\t<ul>\n\t\t<li>&lt;y</li>\n\t</ul>\n\t</li>",
        ),
        "filter-unordered_list02": (
            "{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}",
            {"a": ["x>", [["<y", []]]]},
            "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>",
        ),
        "filter-unordered_list03": (
            "{{ a|unordered_list }}",
            {"a": ["x>", [[mark_safe("<y"), []]]]},
            "\t<li>x&gt;\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>",
        ),
        "filter-unordered_list04": (
            "{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}",
            {"a": ["x>", [[mark_safe("<y"), []]]]},
            "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>",
        ),
        "filter-unordered_list05": (
            "{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}",
            {"a": ["x>", [["<y", []]]]},
            "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>",
        ),
        # Literal string arguments to the default filter are always treated as
        # safe strings, regardless of the auto-escaping state.
        #
        # Note: we have to use {"a": ""} here, otherwise the invalid template
        # variable string interferes with the test result.
        "filter-default01": ('{{ a|default:"x<" }}', {"a": ""}, "x<"),
        "filter-default02": ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": ""}, "x<"),
        "filter-default03": ('{{ a|default:"x<" }}', {"a": mark_safe("x>")}, "x>"),
        "filter-default04": (
            '{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}',
            {"a": mark_safe("x>")},
            "x>",
        ),
        "filter-default_if_none01": ('{{ a|default:"x<" }}', {"a": None}, "x<"),
        "filter-default_if_none02": ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": None}, "x<"),
        "filter-phone2numeric01": (
            "{{ a|phone2numeric }} {{ b|phone2numeric }}",
            {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>")},
            "&lt;1-800-2255-63&gt; <1-800-2255-63>",
        ),
        "filter-phone2numeric02": (
            "{% autoescape off %}{{ a|phone2numeric }} {{ b|phone2numeric }}{% endautoescape %}",
            {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>")},
            "<1-800-2255-63> <1-800-2255-63>",
        ),
        "filter-phone2numeric03": (
            "{{ a|phone2numeric }}",
            {"a": "How razorback-jumping frogs can level six piqued gymnasts!"},
            "469 729672225-5867464 37647 226 53835 749 747833 49662787!",
        ),
        # Ensure iriencode keeps safe strings:
        "filter-iriencode01": ("{{ url|iriencode }}", {"url": "?test=1&me=2"}, "?test=1&amp;me=2"),
        "filter-iriencode02": (
            "{% autoescape off %}{{ url|iriencode }}{% endautoescape %}",
            {"url": "?test=1&me=2"},
            "?test=1&me=2",
        ),
        "filter-iriencode03": ("{{ url|iriencode }}", {"url": mark_safe("?test=1&me=2")}, "?test=1&me=2"),
        "filter-iriencode04": (
            "{% autoescape off %}{{ url|iriencode }}{% endautoescape %}",
            {"url": mark_safe("?test=1&me=2")},
            "?test=1&me=2",
        ),
        # urlencode
        "filter-urlencode01": ("{{ url|urlencode }}", {"url": '/test&"/me?/'}, "/test%26%22/me%3F/"),
        "filter-urlencode02": ('/test/{{ urlbit|urlencode:"" }}/', {"urlbit": "escape/slash"}, "/test/escape%2Fslash/"),
        # Chaining a bunch of safeness-preserving filters should not alter
        # the safe status either way.
        "chaining01": (
            '{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}',
            {"a": "a < b", "b": mark_safe("a < b")},
            " A &lt; b . A < b ",
        ),
        "chaining02": (
            '{% autoescape off %}{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}{% endautoescape %}',
            {"a": "a < b", "b": mark_safe("a < b")},
            " A < b . A < b ",
        ),
        # Using a filter that forces a string back to unsafe:
        "chaining03": (
            '{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}',
            {"a": "a < b", "b": mark_safe("a < b")},
            "A &lt; .A < ",
        ),
        "chaining04": (
            '{% autoescape off %}{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}{% endautoescape %}',
            {"a": "a < b", "b": mark_safe("a < b")},
            "A < .A < ",
        ),
        # Using a filter that forces safeness does not lead to double-escaping
        "chaining05": ("{{ a|escape|capfirst }}", {"a": "a < b"}, "A &lt; b"),
        "chaining06": ("{% autoescape off %}{{ a|escape|capfirst }}{% endautoescape %}", {"a": "a < b"}, "A &lt; b"),
        # Force to safe, then back (also showing why using force_escape too
        # early in a chain can lead to unexpected results).
        "chaining07": ('{{ a|force_escape|cut:";" }}', {"a": "a < b"}, "a &amp;lt b"),
        "chaining08": (
            '{% autoescape off %}{{ a|force_escape|cut:";" }}{% endautoescape %}',
            {"a": "a < b"},
            "a &lt b",
        ),
        "chaining09": ('{{ a|cut:";"|force_escape }}', {"a": "a < b"}, "a &lt; b"),
        "chaining10": (
            '{% autoescape off %}{{ a|cut:";"|force_escape }}{% endautoescape %}',
            {"a": "a < b"},
            "a &lt; b",
        ),
        "chaining11": ('{{ a|cut:"b"|safe }}', {"a": "a < b"}, "a < "),
        "chaining12": ('{% autoescape off %}{{ a|cut:"b"|safe }}{% endautoescape %}', {"a": "a < b"}, "a < "),
        "chaining13": ("{{ a|safe|force_escape }}", {"a": "a < b"}, "a &lt; b"),
        "chaining14": ("{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}", {"a": "a < b"}, "a &lt; b"),
        # Filters decorated with stringfilter still respect is_safe.
        "autoescape-stringfilter01": (r"{{ unsafe|capfirst }}", {"unsafe": UnsafeClass()}, "You &amp; me"),
        "autoescape-stringfilter02": (
            r"{% autoescape off %}{{ unsafe|capfirst }}{% endautoescape %}",
            {"unsafe": UnsafeClass()},
            "You & me",
        ),
        "autoescape-stringfilter03": (r"{{ safe|capfirst }}", {"safe": SafeClass()}, "You &gt; me"),
        "autoescape-stringfilter04": (
            r"{% autoescape off %}{{ safe|capfirst }}{% endautoescape %}",
            {"safe": SafeClass()},
            "You &gt; me",
        ),
        "escapejs01": (
            r"{{ a|escapejs }}",
            {"a": "testing\r\njavascript 'string\" <b>escaping</b>"},
            "testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E",
        ),
        "escapejs02": (
            r"{% autoescape off %}{{ a|escapejs }}{% endautoescape %}",
            {"a": "testing\r\njavascript 'string\" <b>escaping</b>"},
            "testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E",
        ),
        # length filter.
        "length01": ("{{ list|length }}", {"list": ["4", None, True, {}]}, "4"),
        "length02": ("{{ list|length }}", {"list": []}, "0"),
        "length03": ("{{ string|length }}", {"string": ""}, "0"),
        "length04": ("{{ string|length }}", {"string": "django"}, "6"),
        # Invalid uses that should fail silently.
        "length05": ("{{ int|length }}", {"int": 7}, ""),
        "length06": ("{{ None|length }}", {"None": None}, ""),
        # length_is filter.
        "length_is01": (
            '{% if some_list|length_is:"4" %}Four{% endif %}',
            {"some_list": ["4", None, True, {}]},
            "Four",
        ),
        "length_is02": (
            '{% if some_list|length_is:"4" %}Four{% else %}Not Four{% endif %}',
            {"some_list": ["4", None, True, {}, 17]},
            "Not Four",
        ),
        "length_is03": ('{% if mystring|length_is:"4" %}Four{% endif %}', {"mystring": "word"}, "Four"),
        "length_is04": (
            '{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}',
            {"mystring": "Python"},
            "Not Four",
        ),
        "length_is05": (
            '{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}',
            {"mystring": ""},
            "Not Four",
        ),
        "length_is06": ("{% with var|length as my_length %}{{ my_length }}{% endwith %}", {"var": "django"}, "6"),
        # Boolean return value from length_is should not be coerced to a string
        "length_is07": (r'{% if "X"|length_is:0 %}Length is 0{% else %}Length not 0{% endif %}', {}, "Length not 0"),
        "length_is08": (r'{% if "X"|length_is:1 %}Length is 1{% else %}Length not 1{% endif %}', {}, "Length is 1"),
        # Invalid uses that should fail silently.
        "length_is09": ('{{ var|length_is:"fish" }}', {"var": "django"}, ""),
        "length_is10": ('{{ int|length_is:"1" }}', {"int": 7}, ""),
        "length_is11": ('{{ none|length_is:"1" }}', {"none": None}, ""),
        "join01": (r'{{ a|join:", " }}', {"a": ["alpha", "beta & me"]}, "alpha, beta &amp; me"),
        "join02": (
            r'{% autoescape off %}{{ a|join:", " }}{% endautoescape %}',
            {"a": ["alpha", "beta & me"]},
            "alpha, beta & me",
        ),
        "join03": (r'{{ a|join:" &amp; " }}', {"a": ["alpha", "beta & me"]}, "alpha &amp; beta &amp; me"),
        "join04": (
            r'{% autoescape off %}{{ a|join:" &amp; " }}{% endautoescape %}',
            {"a": ["alpha", "beta & me"]},
            "alpha &amp; beta & me",
        ),
        # Test that joining with unsafe joiners don't result in unsafe strings (#11377)
        "join05": (r"{{ a|join:var }}", {"a": ["alpha", "beta & me"], "var": " & "}, "alpha &amp; beta &amp; me"),
        "join06": (
            r"{{ a|join:var }}",
            {"a": ["alpha", "beta & me"], "var": mark_safe(" & ")},
            "alpha & beta &amp; me",
        ),
        "join07": (r"{{ a|join:var|lower }}", {"a": ["Alpha", "Beta & me"], "var": " & "}, "alpha &amp; beta &amp; me"),
        "join08": (
            r"{{ a|join:var|lower }}",
            {"a": ["Alpha", "Beta & me"], "var": mark_safe(" & ")},
            "alpha & beta &amp; me",
        ),
        "date01": (r'{{ d|date:"m" }}', {"d": datetime(2008, 1, 1)}, "01"),
        "date02": (r"{{ d|date }}", {"d": datetime(2008, 1, 1)}, "Jan. 1, 2008"),
        # Ticket 9520: Make sure |date doesn't blow up on non-dates
        "date03": (r'{{ d|date:"m" }}', {"d": "fail_string"}, ""),
        # ISO date formats
        "date04": (r'{{ d|date:"o" }}', {"d": datetime(2008, 12, 29)}, "2009"),
        "date05": (r'{{ d|date:"o" }}', {"d": datetime(2010, 1, 3)}, "2009"),
        # Timezone name
        "date06": (r'{{ d|date:"e" }}', {"d": datetime(2009, 3, 12, tzinfo=FixedOffset(30))}, "+0030"),
        "date07": (r'{{ d|date:"e" }}', {"d": datetime(2009, 3, 12)}, ""),
        # Ticket 19370: Make sure |date doesn't blow up on a midnight time object
        "date08": (r'{{ t|date:"H:i" }}', {"t": time(0, 1)}, "00:01"),
        "date09": (r'{{ t|date:"H:i" }}', {"t": time(0, 0)}, "00:00"),
        # Ticket 20693: Add timezone support to built-in time template filter
        "time01": (r'{{ dt|time:"e:O:T:Z" }}', {"dt": now_tz_i}, "+0315:+0315:+0315:11700"),
        "time02": (r'{{ dt|time:"e:T" }}', {"dt": now}, ":" + now_tz.tzinfo.tzname(now_tz)),
        "time03": (r'{{ t|time:"P:e:O:T:Z" }}', {"t": time(4, 0, tzinfo=FixedOffset(30))}, "4 a.m.::::"),
        "time04": (r'{{ t|time:"P:e:O:T:Z" }}', {"t": time(4, 0)}, "4 a.m.::::"),
        "time05": (r'{{ d|time:"P:e:O:T:Z" }}', {"d": today}, ""),
        "time06": (r'{{ obj|time:"P:e:O:T:Z" }}', {"obj": "non-datetime-value"}, ""),
        # Tests for #11687 and #16676
        "add01": (r'{{ i|add:"5" }}', {"i": 2000}, "2005"),
        "add02": (r'{{ i|add:"napis" }}', {"i": 2000}, ""),
        "add03": (r"{{ i|add:16 }}", {"i": "not_an_int"}, ""),
        "add04": (r'{{ i|add:"16" }}', {"i": "not_an_int"}, "not_an_int16"),
        "add05": (r"{{ l1|add:l2 }}", {"l1": [1, 2], "l2": [3, 4]}, "[1, 2, 3, 4]"),
        "add06": (r"{{ t1|add:t2 }}", {"t1": (3, 4), "t2": (1, 2)}, "(3, 4, 1, 2)"),
        "add07": (r"{{ d|add:t }}", {"d": date(2000, 1, 1), "t": timedelta(10)}, "Jan. 11, 2000"),
    }
Example #37
0
 def test_make_list04(self):
     output = self.engine.render_to_string('make_list04',
                                           {"a": mark_safe("&")})
     self.assertEqual(output, str_prefix("[%(_)s'&']"))
Example #38
0
 def test_make_list04(self):
     output = render('make_list04', {"a": mark_safe("&")})
     self.assertEqual(output, str_prefix("[%(_)s'&']"))
Example #39
0
 def test_make_list02(self):
     output = render('make_list02', {"a": mark_safe("&")})
     self.assertEqual(output, str_prefix("[%(_)s&#39;&amp;&#39;]"))
Example #40
0
def get_filter_tests():
    now = datetime.now()
    now_tz = datetime.now(LocalTimezone(now))
    now_tz_i = datetime.now(FixedOffset((3 * 60) + 15)) # imaginary time zone
    today = date.today()

    return {
        # Default compare with datetime.now()
        'filter-timesince01' : ('{{ a|timesince }}', {'a': datetime.now() + timedelta(minutes=-1, seconds = -10)}, '1 minute'),
        'filter-timesince02' : ('{{ a|timesince }}', {'a': datetime.now() - timedelta(days=1, minutes = 1)}, '1 day'),
        'filter-timesince03' : ('{{ a|timesince }}', {'a': datetime.now() - timedelta(hours=1, minutes=25, seconds = 10)}, '1 hour, 25 minutes'),

        # Compare to a given parameter
        'filter-timesince04' : ('{{ a|timesince:b }}', {'a':now - timedelta(days=2), 'b':now - timedelta(days=1)}, '1 day'),
        'filter-timesince05' : ('{{ a|timesince:b }}', {'a':now - timedelta(days=2, minutes=1), 'b':now - timedelta(days=2)}, '1 minute'),

        # Check that timezone is respected
        'filter-timesince06' : ('{{ a|timesince:b }}', {'a':now_tz - timedelta(hours=8), 'b':now_tz}, '8 hours'),

        # Regression for #7443
        'filter-timesince07': ('{{ earlier|timesince }}', { 'earlier': now - timedelta(days=7) }, '1 week'),
        'filter-timesince08': ('{{ earlier|timesince:now }}', { 'now': now, 'earlier': now - timedelta(days=7) }, '1 week'),
        'filter-timesince09': ('{{ later|timesince }}', { 'later': now + timedelta(days=7) }, '0 minutes'),
        'filter-timesince10': ('{{ later|timesince:now }}', { 'now': now, 'later': now + timedelta(days=7) }, '0 minutes'),

        # Ensures that differing timezones are calculated correctly
        'filter-timesince11' : ('{{ a|timesince }}', {'a': now}, '0 minutes'),
        'filter-timesince12' : ('{{ a|timesince }}', {'a': now_tz}, '0 minutes'),
        'filter-timesince13' : ('{{ a|timesince }}', {'a': now_tz_i}, '0 minutes'),
        'filter-timesince14' : ('{{ a|timesince:b }}', {'a': now_tz, 'b': now_tz_i}, '0 minutes'),
        'filter-timesince15' : ('{{ a|timesince:b }}', {'a': now, 'b': now_tz_i}, ''),
        'filter-timesince16' : ('{{ a|timesince:b }}', {'a': now_tz_i, 'b': now}, ''),

        # Regression for #9065 (two date objects).
        'filter-timesince17' : ('{{ a|timesince:b }}', {'a': today, 'b': today}, '0 minutes'),
        'filter-timesince18' : ('{{ a|timesince:b }}', {'a': today, 'b': today + timedelta(hours=24)}, '1 day'),

        # Default compare with datetime.now()
        'filter-timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2 minutes'),
        'filter-timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1, seconds = 10))}, '1 day'),
        'filter-timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10, seconds = 10))}, '8 hours, 10 minutes'),

        # Compare to a given parameter
        'filter-timeuntil04' : ('{{ a|timeuntil:b }}', {'a':now - timedelta(days=1), 'b':now - timedelta(days=2)}, '1 day'),
        'filter-timeuntil05' : ('{{ a|timeuntil:b }}', {'a':now - timedelta(days=2), 'b':now - timedelta(days=2, minutes=1)}, '1 minute'),

        # Regression for #7443
        'filter-timeuntil06': ('{{ earlier|timeuntil }}', { 'earlier': now - timedelta(days=7) }, '0 minutes'),
        'filter-timeuntil07': ('{{ earlier|timeuntil:now }}', { 'now': now, 'earlier': now - timedelta(days=7) }, '0 minutes'),
        'filter-timeuntil08': ('{{ later|timeuntil }}', { 'later': now + timedelta(days=7, hours=1) }, '1 week'),
        'filter-timeuntil09': ('{{ later|timeuntil:now }}', { 'now': now, 'later': now + timedelta(days=7) }, '1 week'),

        # Ensures that differing timezones are calculated correctly
        'filter-timeuntil10' : ('{{ a|timeuntil }}', {'a': now_tz_i}, '0 minutes'),
        'filter-timeuntil11' : ('{{ a|timeuntil:b }}', {'a': now_tz_i, 'b': now_tz}, '0 minutes'),

        # Regression for #9065 (two date objects).
        'filter-timeuntil12' : ('{{ a|timeuntil:b }}', {'a': today, 'b': today}, '0 minutes'),
        'filter-timeuntil13' : ('{{ a|timeuntil:b }}', {'a': today, 'b': today - timedelta(hours=24)}, '1 day'),

        'filter-addslash01': ("{% autoescape off %}{{ a|addslashes }} {{ b|addslashes }}{% endautoescape %}", {"a": "<a>'", "b": mark_safe("<a>'")}, r"<a>\' <a>\'"),
        'filter-addslash02': ("{{ a|addslashes }} {{ b|addslashes }}", {"a": "<a>'", "b": mark_safe("<a>'")}, r"&lt;a&gt;\&#39; <a>\'"),

        'filter-capfirst01': ("{% autoescape off %}{{ a|capfirst }} {{ b|capfirst }}{% endautoescape %}", {"a": "fred>", "b": mark_safe("fred&gt;")}, "Fred> Fred&gt;"),
        'filter-capfirst02': ("{{ a|capfirst }} {{ b|capfirst }}", {"a": "fred>", "b": mark_safe("fred&gt;")}, "Fred&gt; Fred&gt;"),

        # Note that applying fix_ampsersands in autoescape mode leads to
        # double escaping.
        'filter-fix_ampersands01': ("{% autoescape off %}{{ a|fix_ampersands }} {{ b|fix_ampersands }}{% endautoescape %}", {"a": "a&b", "b": mark_safe("a&b")}, "a&amp;b a&amp;b"),
        'filter-fix_ampersands02': ("{{ a|fix_ampersands }} {{ b|fix_ampersands }}", {"a": "a&b", "b": mark_safe("a&b")}, "a&amp;amp;b a&amp;b"),

        'filter-floatformat01': ("{% autoescape off %}{{ a|floatformat }} {{ b|floatformat }}{% endautoescape %}", {"a": "1.42", "b": mark_safe("1.42")}, "1.4 1.4"),
        'filter-floatformat02': ("{{ a|floatformat }} {{ b|floatformat }}", {"a": "1.42", "b": mark_safe("1.42")}, "1.4 1.4"),

        # The contents of "linenumbers" is escaped according to the current
        # autoescape setting.
        'filter-linenumbers01': ("{{ a|linenumbers }} {{ b|linenumbers }}", {"a": "one\n<two>\nthree", "b": mark_safe("one\n&lt;two&gt;\nthree")}, "1. one\n2. &lt;two&gt;\n3. three 1. one\n2. &lt;two&gt;\n3. three"),
        'filter-linenumbers02': ("{% autoescape off %}{{ a|linenumbers }} {{ b|linenumbers }}{% endautoescape %}", {"a": "one\n<two>\nthree", "b": mark_safe("one\n&lt;two&gt;\nthree")}, "1. one\n2. <two>\n3. three 1. one\n2. &lt;two&gt;\n3. three"),

        'filter-lower01': ("{% autoescape off %}{{ a|lower }} {{ b|lower }}{% endautoescape %}", {"a": "Apple & banana", "b": mark_safe("Apple &amp; banana")}, "apple & banana apple &amp; banana"),
        'filter-lower02': ("{{ a|lower }} {{ b|lower }}", {"a": "Apple & banana", "b": mark_safe("Apple &amp; banana")}, "apple &amp; banana apple &amp; banana"),

        # The make_list filter can destroy existing escaping, so the results are
        # escaped.
        'filter-make_list01': ("{% autoescape off %}{{ a|make_list }}{% endautoescape %}", {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),
        'filter-make_list02': ("{{ a|make_list }}", {"a": mark_safe("&")}, "[u&#39;&amp;&#39;]"),
        'filter-make_list03': ('{% autoescape off %}{{ a|make_list|stringformat:"s"|safe }}{% endautoescape %}', {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),
        'filter-make_list04': ('{{ a|make_list|stringformat:"s"|safe }}', {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),

        # Running slugify on a pre-escaped string leads to odd behavior,
        # but the result is still safe.
        'filter-slugify01': ("{% autoescape off %}{{ a|slugify }} {{ b|slugify }}{% endautoescape %}", {"a": "a & b", "b": mark_safe("a &amp; b")}, "a-b a-amp-b"),
        'filter-slugify02': ("{{ a|slugify }} {{ b|slugify }}", {"a": "a & b", "b": mark_safe("a &amp; b")}, "a-b a-amp-b"),

        # Notice that escaping is applied *after* any filters, so the string
        # formatting here only needs to deal with pre-escaped characters.
        'filter-stringformat01': ('{% autoescape off %}.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.{% endautoescape %}',
            {"a": "a<b", "b": mark_safe("a<b")}, ".  a<b. .  a<b."),
        'filter-stringformat02': ('.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.', {"a": "a<b", "b": mark_safe("a<b")},
            ".  a&lt;b. .  a<b."),

        # Test the title filter
        'filter-title1' : ('{{ a|title }}', {'a' : 'JOE\'S CRAB SHACK'}, 'Joe&#39;s Crab Shack'),
        'filter-title2' : ('{{ a|title }}', {'a' : '555 WEST 53RD STREET'}, '555 West 53rd Street'),

        'filter-truncatewords01': ('{% autoescape off %}{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}{% endautoescape %}',
            {"a": "alpha & bravo", "b": mark_safe("alpha &amp; bravo")}, "alpha & ... alpha &amp; ..."),
        'filter-truncatewords02': ('{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}',
            {"a": "alpha & bravo", "b": mark_safe("alpha &amp; bravo")}, "alpha &amp; ... alpha &amp; ..."),

        'filter-truncatechars01': ('{{ a|truncatechars:5 }}', {'a': "Testing, testing"}, "Te..."),
        'filter-truncatechars02': ('{{ a|truncatechars:7 }}', {'a': "Testing"}, "Testing"),

        # The "upper" filter messes up entities (which are case-sensitive),
        # so it's not safe for non-escaping purposes.
        'filter-upper01': ('{% autoescape off %}{{ a|upper }} {{ b|upper }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "A & B A &AMP; B"),
        'filter-upper02': ('{{ a|upper }} {{ b|upper }}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "A &amp; B A &amp;AMP; B"),

        'filter-urlize01': ('{% autoescape off %}{{ a|urlize }} {{ b|urlize }}{% endautoescape %}', {"a": "http://example.com/?x=&y=", "b": mark_safe("http://example.com?x=&amp;y=")}, '<a href="http://example.com/?x=&y=" rel="nofollow">http://example.com/?x=&y=</a> <a href="http://example.com?x=&amp;y=" rel="nofollow">http://example.com?x=&amp;y=</a>'),
        'filter-urlize02': ('{{ a|urlize }} {{ b|urlize }}', {"a": "http://example.com/?x=&y=", "b": mark_safe("http://example.com?x=&amp;y=")}, '<a href="http://example.com/?x=&amp;y=" rel="nofollow">http://example.com/?x=&amp;y=</a> <a href="http://example.com?x=&amp;y=" rel="nofollow">http://example.com?x=&amp;y=</a>'),
        'filter-urlize03': ('{% autoescape off %}{{ a|urlize }}{% endautoescape %}', {"a": mark_safe("a &amp; b")}, 'a &amp; b'),
        'filter-urlize04': ('{{ a|urlize }}', {"a": mark_safe("a &amp; b")}, 'a &amp; b'),

        # This will lead to a nonsense result, but at least it won't be
        # exploitable for XSS purposes when auto-escaping is on.
        'filter-urlize05': ('{% autoescape off %}{{ a|urlize }}{% endautoescape %}', {"a": "<script>alert('foo')</script>"}, "<script>alert('foo')</script>"),
        'filter-urlize06': ('{{ a|urlize }}', {"a": "<script>alert('foo')</script>"}, '&lt;script&gt;alert(&#39;foo&#39;)&lt;/script&gt;'),

        # mailto: testing for urlize
        'filter-urlize07': ('{{ a|urlize }}', {"a": "Email me at [email protected]"}, 'Email me at <a href="mailto:[email protected]">[email protected]</a>'),
        'filter-urlize08': ('{{ a|urlize }}', {"a": "Email me at <*****@*****.**>"}, 'Email me at &lt;<a href="mailto:[email protected]">[email protected]</a>&gt;'),

        'filter-urlizetrunc01': ('{% autoescape off %}{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}{% endautoescape %}', {"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y=')}, '"Unsafe" <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&amp;y=" rel="nofollow">http:...</a>'),
        'filter-urlizetrunc02': ('{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}', {"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y=')}, '&quot;Unsafe&quot; <a href="http://example.com/x=&amp;y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&amp;y=" rel="nofollow">http:...</a>'),

        'filter-wordcount01': ('{% autoescape off %}{{ a|wordcount }} {{ b|wordcount }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "3 3"),
        'filter-wordcount02': ('{{ a|wordcount }} {{ b|wordcount }}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "3 3"),

        'filter-wordwrap01': ('{% autoescape off %}{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a & b")}, "a &\nb a &\nb"),
        'filter-wordwrap02': ('{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}', {"a": "a & b", "b": mark_safe("a & b")}, "a &amp;\nb a &\nb"),

        'filter-ljust01': ('{% autoescape off %}.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, ".a&b  . .a&b  ."),
        'filter-ljust02': ('.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ".a&amp;b  . .a&b  ."),

        'filter-rjust01': ('{% autoescape off %}.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, ".  a&b. .  a&b."),
        'filter-rjust02': ('.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ".  a&amp;b. .  a&b."),

        'filter-center01': ('{% autoescape off %}.{{ a|center:"5" }}. .{{ b|center:"5" }}.{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, ". a&b . . a&b ."),
        'filter-center02': ('.{{ a|center:"5" }}. .{{ b|center:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ". a&amp;b . . a&b ."),

        'filter-cut01': ('{% autoescape off %}{{ a|cut:"x" }} {{ b|cut:"x" }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "&y &amp;y"),
        'filter-cut02': ('{{ a|cut:"x" }} {{ b|cut:"x" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "&amp;y &amp;y"),
        'filter-cut03': ('{% autoescape off %}{{ a|cut:"&" }} {{ b|cut:"&" }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "xy xamp;y"),
        'filter-cut04': ('{{ a|cut:"&" }} {{ b|cut:"&" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "xy xamp;y"),
        # Passing ';' to cut can break existing HTML entities, so those strings
        # are auto-escaped.
        'filter-cut05': ('{% autoescape off %}{{ a|cut:";" }} {{ b|cut:";" }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "x&y x&ampy"),
        'filter-cut06': ('{{ a|cut:";" }} {{ b|cut:";" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "x&amp;y x&amp;ampy"),

        # The "escape" filter works the same whether autoescape is on or off,
        # but it has no effect on strings already marked as safe.
        'filter-escape01': ('{{ a|escape }} {{ b|escape }}', {"a": "x&y", "b": mark_safe("x&y")}, "x&amp;y x&y"),
        'filter-escape02': ('{% autoescape off %}{{ a|escape }} {{ b|escape }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&y")}, "x&amp;y x&y"),

        # It is only applied once, regardless of the number of times it
        # appears in a chain.
        'filter-escape03': ('{% autoescape off %}{{ a|escape|escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
        'filter-escape04': ('{{ a|escape|escape }}', {"a": "x&y"}, "x&amp;y"),

        # Force_escape is applied immediately. It can be used to provide
        # double-escaping, for example.
        'filter-force-escape01': ('{% autoescape off %}{{ a|force_escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
        'filter-force-escape02': ('{{ a|force_escape }}', {"a": "x&y"}, "x&amp;y"),
        'filter-force-escape03': ('{% autoescape off %}{{ a|force_escape|force_escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;amp;y"),
        'filter-force-escape04': ('{{ a|force_escape|force_escape }}', {"a": "x&y"}, "x&amp;amp;y"),

        # Because the result of force_escape is "safe", an additional
        # escape filter has no effect.
        'filter-force-escape05': ('{% autoescape off %}{{ a|force_escape|escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
        'filter-force-escape06': ('{{ a|force_escape|escape }}', {"a": "x&y"}, "x&amp;y"),
        'filter-force-escape07': ('{% autoescape off %}{{ a|escape|force_escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
        'filter-force-escape08': ('{{ a|escape|force_escape }}', {"a": "x&y"}, "x&amp;y"),

        # The contents in "linebreaks" and "linebreaksbr" are escaped
        # according to the current autoescape setting.
        'filter-linebreaks01': ('{{ a|linebreaks }} {{ b|linebreaks }}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "<p>x&amp;<br />y</p> <p>x&<br />y</p>"),
        'filter-linebreaks02': ('{% autoescape off %}{{ a|linebreaks }} {{ b|linebreaks }}{% endautoescape %}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "<p>x&<br />y</p> <p>x&<br />y</p>"),

        'filter-linebreaksbr01': ('{{ a|linebreaksbr }} {{ b|linebreaksbr }}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "x&amp;<br />y x&<br />y"),
        'filter-linebreaksbr02': ('{% autoescape off %}{{ a|linebreaksbr }} {{ b|linebreaksbr }}{% endautoescape %}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "x&<br />y x&<br />y"),

        'filter-safe01': ("{{ a }} -- {{ a|safe }}", {"a": "<b>hello</b>"}, "&lt;b&gt;hello&lt;/b&gt; -- <b>hello</b>"),
        'filter-safe02': ("{% autoescape off %}{{ a }} -- {{ a|safe }}{% endautoescape %}", {"a": "<b>hello</b>"}, "<b>hello</b> -- <b>hello</b>"),

        'filter-safeseq01': ('{{ a|join:", " }} -- {{ a|safeseq|join:", " }}', {"a": ["&", "<"]}, "&amp;, &lt; -- &, <"),
        'filter-safeseq02': ('{% autoescape off %}{{ a|join:", " }} -- {{ a|safeseq|join:", " }}{% endautoescape %}', {"a": ["&", "<"]}, "&, < -- &, <"),

        'filter-removetags01': ('{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x &lt;p&gt;y&lt;/p&gt; x <p>y</p>"),
        'filter-removetags02': ('{% autoescape off %}{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}{% endautoescape %}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x <p>y</p> x <p>y</p>"),

        'filter-striptags01': ('{{ a|striptags }} {{ b|striptags }}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x y x y"),
        'filter-striptags02': ('{% autoescape off %}{{ a|striptags }} {{ b|striptags }}{% endautoescape %}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x y x y"),

        'filter-first01': ('{{ a|first }} {{ b|first }}', {"a": ["a&b", "x"], "b": [mark_safe("a&b"), "x"]}, "a&amp;b a&b"),
        'filter-first02': ('{% autoescape off %}{{ a|first }} {{ b|first }}{% endautoescape %}', {"a": ["a&b", "x"], "b": [mark_safe("a&b"), "x"]}, "a&b a&b"),

        'filter-last01': ('{{ a|last }} {{ b|last }}', {"a": ["x", "a&b"], "b": ["x", mark_safe("a&b")]}, "a&amp;b a&b"),
        'filter-last02': ('{% autoescape off %}{{ a|last }} {{ b|last }}{% endautoescape %}', {"a": ["x", "a&b"], "b": ["x", mark_safe("a&b")]}, "a&b a&b"),

        'filter-random01': ('{{ a|random }} {{ b|random }}', {"a": ["a&b", "a&b"], "b": [mark_safe("a&b"), mark_safe("a&b")]}, "a&amp;b a&b"),
        'filter-random02': ('{% autoescape off %}{{ a|random }} {{ b|random }}{% endautoescape %}', {"a": ["a&b", "a&b"], "b": [mark_safe("a&b"), mark_safe("a&b")]}, "a&b a&b"),

        'filter-slice01': ('{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}', {"a": "a&b", "b": mark_safe("a&b")}, "&amp;b &b"),
        'filter-slice02': ('{% autoescape off %}{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, "&b &b"),

        'filter-unordered_list01': ('{{ a|unordered_list }}', {"a": ["x>", [["<y", []]]]}, "\t<li>x&gt;\n\t<ul>\n\t\t<li>&lt;y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list02': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [["<y", []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list03': ('{{ a|unordered_list }}', {"a": ["x>", [[mark_safe("<y"), []]]]}, "\t<li>x&gt;\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list04': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [[mark_safe("<y"), []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list05': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [["<y", []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),

        # Literal string arguments to the default filter are always treated as
        # safe strings, regardless of the auto-escaping state.
        #
        # Note: we have to use {"a": ""} here, otherwise the invalid template
        # variable string interferes with the test result.
        'filter-default01': ('{{ a|default:"x<" }}', {"a": ""}, "x<"),
        'filter-default02': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": ""}, "x<"),
        'filter-default03': ('{{ a|default:"x<" }}', {"a": mark_safe("x>")}, "x>"),
        'filter-default04': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": mark_safe("x>")}, "x>"),

        'filter-default_if_none01': ('{{ a|default:"x<" }}', {"a": None}, "x<"),
        'filter-default_if_none02': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": None}, "x<"),

        'filter-phone2numeric01': ('{{ a|phone2numeric }} {{ b|phone2numeric }}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "&lt;1-800-2255-63&gt; <1-800-2255-63>"),
        'filter-phone2numeric02': ('{% autoescape off %}{{ a|phone2numeric }} {{ b|phone2numeric }}{% endautoescape %}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "<1-800-2255-63> <1-800-2255-63>"),
        'filter-phone2numeric03': ('{{ a|phone2numeric }}', {"a": "How razorback-jumping frogs can level six piqued gymnasts!"}, "469 729672225-5867464 37647 226 53835 749 747833 49662787!"),

        # Ensure iriencode keeps safe strings:
        'filter-iriencode01': ('{{ url|iriencode }}', {'url': '?test=1&me=2'}, '?test=1&amp;me=2'),
        'filter-iriencode02': ('{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {'url': '?test=1&me=2'}, '?test=1&me=2'),
        'filter-iriencode03': ('{{ url|iriencode }}', {'url': mark_safe('?test=1&me=2')}, '?test=1&me=2'),
        'filter-iriencode04': ('{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {'url': mark_safe('?test=1&me=2')}, '?test=1&me=2'),

        # urlencode
        'filter-urlencode01': ('{{ url|urlencode }}', {'url': '/test&"/me?/'}, '/test%26%22/me%3F/'),
        'filter-urlencode02': ('/test/{{ urlbit|urlencode:"" }}/', {'urlbit': 'escape/slash'}, '/test/escape%2Fslash/'),

        # Chaining a bunch of safeness-preserving filters should not alter
        # the safe status either way.
        'chaining01': ('{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}', {"a": "a < b", "b": mark_safe("a < b")}, " A &lt; b . A < b "),
        'chaining02': ('{% autoescape off %}{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}{% endautoescape %}', {"a": "a < b", "b": mark_safe("a < b")}, " A < b . A < b "),

        # Using a filter that forces a string back to unsafe:
        'chaining03': ('{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}', {"a": "a < b", "b": mark_safe("a < b")}, "A &lt; .A < "),
        'chaining04': ('{% autoescape off %}{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}{% endautoescape %}', {"a": "a < b", "b": mark_safe("a < b")}, "A < .A < "),

        # Using a filter that forces safeness does not lead to double-escaping
        'chaining05': ('{{ a|escape|capfirst }}', {"a": "a < b"}, "A &lt; b"),
        'chaining06': ('{% autoescape off %}{{ a|escape|capfirst }}{% endautoescape %}', {"a": "a < b"}, "A &lt; b"),

        # Force to safe, then back (also showing why using force_escape too
        # early in a chain can lead to unexpected results).
        'chaining07': ('{{ a|force_escape|cut:";" }}', {"a": "a < b"}, "a &amp;lt b"),
        'chaining08': ('{% autoescape off %}{{ a|force_escape|cut:";" }}{% endautoescape %}', {"a": "a < b"}, "a &lt b"),
        'chaining09': ('{{ a|cut:";"|force_escape }}', {"a": "a < b"}, "a &lt; b"),
        'chaining10': ('{% autoescape off %}{{ a|cut:";"|force_escape }}{% endautoescape %}', {"a": "a < b"}, "a &lt; b"),
        'chaining11': ('{{ a|cut:"b"|safe }}', {"a": "a < b"}, "a < "),
        'chaining12': ('{% autoescape off %}{{ a|cut:"b"|safe }}{% endautoescape %}', {"a": "a < b"}, "a < "),
        'chaining13': ('{{ a|safe|force_escape }}', {"a": "a < b"}, "a &lt; b"),
        'chaining14': ('{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}', {"a": "a < b"}, "a &lt; b"),

        # Filters decorated with stringfilter still respect is_safe.
        'autoescape-stringfilter01': (r'{{ unsafe|capfirst }}', {'unsafe': UnsafeClass()}, 'You &amp; me'),
        'autoescape-stringfilter02': (r'{% autoescape off %}{{ unsafe|capfirst }}{% endautoescape %}', {'unsafe': UnsafeClass()}, 'You & me'),
        'autoescape-stringfilter03': (r'{{ safe|capfirst }}', {'safe': SafeClass()}, 'You &gt; me'),
        'autoescape-stringfilter04': (r'{% autoescape off %}{{ safe|capfirst }}{% endautoescape %}', {'safe': SafeClass()}, 'You &gt; me'),

        'escapejs01': (r'{{ a|escapejs }}', {'a': 'testing\r\njavascript \'string" <b>escaping</b>'}, 'testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E'),
        'escapejs02': (r'{% autoescape off %}{{ a|escapejs }}{% endautoescape %}', {'a': 'testing\r\njavascript \'string" <b>escaping</b>'}, 'testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E'),


        # length filter.
        'length01': ('{{ list|length }}', {'list': ['4', None, True, {}]}, '4'),
        'length02': ('{{ list|length }}', {'list': []}, '0'),
        'length03': ('{{ string|length }}', {'string': ''}, '0'),
        'length04': ('{{ string|length }}', {'string': 'django'}, '6'),
        # Invalid uses that should fail silently.
        'length05': ('{{ int|length }}', {'int': 7}, ''),
        'length06': ('{{ None|length }}', {'None': None}, ''),

        # length_is filter.
        'length_is01': ('{% if some_list|length_is:"4" %}Four{% endif %}', {'some_list': ['4', None, True, {}]}, 'Four'),
        'length_is02': ('{% if some_list|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'some_list': ['4', None, True, {}, 17]}, 'Not Four'),
        'length_is03': ('{% if mystring|length_is:"4" %}Four{% endif %}', {'mystring': 'word'}, 'Four'),
        'length_is04': ('{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'mystring': 'Python'}, 'Not Four'),
        'length_is05': ('{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'mystring': ''}, 'Not Four'),
        'length_is06': ('{% with var|length as my_length %}{{ my_length }}{% endwith %}', {'var': 'django'}, '6'),
        # Boolean return value from length_is should not be coerced to a string
        'length_is07': (r'{% if "X"|length_is:0 %}Length is 0{% else %}Length not 0{% endif %}', {}, 'Length not 0'),
        'length_is08': (r'{% if "X"|length_is:1 %}Length is 1{% else %}Length not 1{% endif %}', {}, 'Length is 1'),
        # Invalid uses that should fail silently.
        'length_is09': ('{{ var|length_is:"fish" }}', {'var': 'django'}, ''),
        'length_is10': ('{{ int|length_is:"1" }}', {'int': 7}, ''),
        'length_is11': ('{{ none|length_is:"1" }}', {'none': None}, ''),

        'join01': (r'{{ a|join:", " }}', {'a': ['alpha', 'beta & me']}, 'alpha, beta &amp; me'),
        'join02': (r'{% autoescape off %}{{ a|join:", " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha, beta & me'),
        'join03': (r'{{ a|join:" &amp; " }}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta &amp; me'),
        'join04': (r'{% autoescape off %}{{ a|join:" &amp; " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta & me'),

        # Test that joining with unsafe joiners don't result in unsafe strings (#11377)
        'join05': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': ' & '}, 'alpha &amp; beta &amp; me'),
        'join06': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; me'),
        'join07': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': ' & ' }, 'alpha &amp; beta &amp; me'),
        'join08': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; me'),

        'date01': (r'{{ d|date:"m" }}', {'d': datetime(2008, 1, 1)}, '01'),
        'date02': (r'{{ d|date }}', {'d': datetime(2008, 1, 1)}, 'Jan. 1, 2008'),
        #Ticket 9520: Make sure |date doesn't blow up on non-dates
        'date03': (r'{{ d|date:"m" }}', {'d': 'fail_string'}, ''),
        # ISO date formats
        'date04': (r'{{ d|date:"o" }}', {'d': datetime(2008, 12, 29)}, '2009'),
        'date05': (r'{{ d|date:"o" }}', {'d': datetime(2010, 1, 3)}, '2009'),
        # Timezone name
        'date06': (r'{{ d|date:"e" }}', {'d': datetime(2009, 3, 12, tzinfo=FixedOffset(30))}, '+0030'),
        'date07': (r'{{ d|date:"e" }}', {'d': datetime(2009, 3, 12)}, ''),

         # Tests for #11687 and #16676
         'add01': (r'{{ i|add:"5" }}', {'i': 2000}, '2005'),
         'add02': (r'{{ i|add:"napis" }}', {'i': 2000}, ''),
         'add03': (r'{{ i|add:16 }}', {'i': 'not_an_int'}, ''),
         'add04': (r'{{ i|add:"16" }}', {'i': 'not_an_int'}, 'not_an_int16'),
         'add05': (r'{{ l1|add:l2 }}', {'l1': [1, 2], 'l2': [3, 4]}, '[1, 2, 3, 4]'),
         'add06': (r'{{ t1|add:t2 }}', {'t1': (3, 4), 't2': (1, 2)}, '(3, 4, 1, 2)'),
         'add07': (r'{{ d|add:t }}', {'d': date(2000, 1, 1), 't': timedelta(10)}, 'Jan. 11, 2000'),
    }
Example #41
0
 def test_str(self):
     self.assertEqual(str_prefix("I am _ComplexObject(%(_)s'joe')"),
         str(SimpleLazyObject(complex_object)))
Example #42
0
 def test_str(self):
     self.assertEqual(str_prefix("I am _ComplexObject(%(_)s'joe')"),
                      str(SimpleLazyObject(complex_object)))
Example #43
0
    def test_basic_distinct_on(self):
        """QuerySet.distinct('field', ...) works"""
        # (qset, expected) tuples
        qsets = (
            (
                Staff.objects.distinct().order_by('name'),
                ['<Staff: p1>', '<Staff: p1>', '<Staff: p2>', '<Staff: p3>'],
            ),
            (
                Staff.objects.distinct('name').order_by('name'),
                ['<Staff: p1>', '<Staff: p2>', '<Staff: p3>'],
            ),
            (
                Staff.objects.distinct('organisation').order_by('organisation', 'name'),
                ['<Staff: p1>', '<Staff: p1>'],
            ),
            (
                Staff.objects.distinct('name', 'organisation').order_by('name', 'organisation'),
                ['<Staff: p1>', '<Staff: p1>', '<Staff: p2>', '<Staff: p3>'],
            ),
            (
                Celebrity.objects.filter(fan__in=[self.fan1, self.fan2, self.fan3]).distinct('name').order_by('name'),
                ['<Celebrity: c1>', '<Celebrity: c2>'],
            ),
            # Does combining querysets work?
            (
                (Celebrity.objects.filter(fan__in=[self.fan1, self.fan2]).
                    distinct('name').order_by('name') |
                 Celebrity.objects.filter(fan__in=[self.fan3]).
                    distinct('name').order_by('name')),
                ['<Celebrity: c1>', '<Celebrity: c2>'],
            ),
            (
                StaffTag.objects.distinct('staff', 'tag'),
                ['<StaffTag: t1 -> p1>'],
            ),
            (
                Tag.objects.order_by('parent__pk', 'pk').distinct('parent'),
                ['<Tag: t2>', '<Tag: t4>', '<Tag: t1>'],
            ),
            (
                StaffTag.objects.select_related('staff').distinct('staff__name').order_by('staff__name'),
                ['<StaffTag: t1 -> p1>'],
            ),
            # Fetch the alphabetically first coworker for each worker
            (
                (Staff.objects.distinct('id').order_by('id', 'coworkers__name').
                    values_list('id', 'coworkers__name')),
                [str_prefix("(1, %(_)s'p2')"), str_prefix("(2, %(_)s'p1')"),
                 str_prefix("(3, %(_)s'p1')"), "(4, None)"]
            ),
        )
        for qset, expected in qsets:
            self.assertQuerysetEqual(qset, expected)
            self.assertEqual(qset.count(), len(expected))

        # Combining queries with different distinct_fields is not allowed.
        base_qs = Celebrity.objects.all()
        self.assertRaisesMessage(
            AssertionError,
            "Cannot combine queries with different distinct fields.",
            lambda: (base_qs.distinct('id') & base_qs.distinct('name'))
        )

        # Test join unreffing
        c1 = Celebrity.objects.distinct('greatest_fan__id', 'greatest_fan__fan_of')
        self.assertIn('OUTER JOIN', str(c1.query))
        c2 = c1.distinct('pk')
        self.assertNotIn('OUTER JOIN', str(c2.query))
Example #44
0
def get_filter_tests():
    now = datetime.now()
    now_tz = datetime.now(LocalTimezone(now))
    now_tz_i = datetime.now(FixedOffset((3 * 60) + 15)) # imaginary time zone
    today = date.today()

    # NOTE: \xa0 avoids wrapping between value and unit
    return {
        # Default compare with datetime.now()
        'filter-timesince01' : ('{{ a|timesince }}', {'a': datetime.now() + timedelta(minutes=-1, seconds = -10)}, '1\xa0minute'),
        'filter-timesince02' : ('{{ a|timesince }}', {'a': datetime.now() - timedelta(days=1, minutes = 1)}, '1\xa0day'),
        'filter-timesince03' : ('{{ a|timesince }}', {'a': datetime.now() - timedelta(hours=1, minutes=25, seconds = 10)}, '1\xa0hour, 25\xa0minutes'),

        # Compare to a given parameter
        'filter-timesince04' : ('{{ a|timesince:b }}', {'a':now - timedelta(days=2), 'b':now - timedelta(days=1)}, '1\xa0day'),
        'filter-timesince05' : ('{{ a|timesince:b }}', {'a':now - timedelta(days=2, minutes=1), 'b':now - timedelta(days=2)}, '1\xa0minute'),

        # Check that timezone is respected
        'filter-timesince06' : ('{{ a|timesince:b }}', {'a':now_tz - timedelta(hours=8), 'b':now_tz}, '8\xa0hours'),

        # Regression for #7443
        'filter-timesince07': ('{{ earlier|timesince }}', { 'earlier': now - timedelta(days=7) }, '1\xa0week'),
        'filter-timesince08': ('{{ earlier|timesince:now }}', { 'now': now, 'earlier': now - timedelta(days=7) }, '1\xa0week'),
        'filter-timesince09': ('{{ later|timesince }}', { 'later': now + timedelta(days=7) }, '0\xa0minutes'),
        'filter-timesince10': ('{{ later|timesince:now }}', { 'now': now, 'later': now + timedelta(days=7) }, '0\xa0minutes'),

        # Ensures that differing timezones are calculated correctly
        'filter-timesince11' : ('{{ a|timesince }}', {'a': now}, '0\xa0minutes'),
        'filter-timesince12' : ('{{ a|timesince }}', {'a': now_tz}, '0\xa0minutes'),
        'filter-timesince13' : ('{{ a|timesince }}', {'a': now_tz_i}, '0\xa0minutes'),
        'filter-timesince14' : ('{{ a|timesince:b }}', {'a': now_tz, 'b': now_tz_i}, '0\xa0minutes'),
        'filter-timesince15' : ('{{ a|timesince:b }}', {'a': now, 'b': now_tz_i}, ''),
        'filter-timesince16' : ('{{ a|timesince:b }}', {'a': now_tz_i, 'b': now}, ''),

        # Regression for #9065 (two date objects).
        'filter-timesince17' : ('{{ a|timesince:b }}', {'a': today, 'b': today}, '0\xa0minutes'),
        'filter-timesince18' : ('{{ a|timesince:b }}', {'a': today, 'b': today + timedelta(hours=24)}, '1\xa0day'),

        # Default compare with datetime.now()
        'filter-timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2\xa0minutes'),
        'filter-timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1, seconds = 10))}, '1\xa0day'),
        'filter-timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10, seconds = 10))}, '8\xa0hours, 10\xa0minutes'),

        # Compare to a given parameter
        'filter-timeuntil04' : ('{{ a|timeuntil:b }}', {'a':now - timedelta(days=1), 'b':now - timedelta(days=2)}, '1\xa0day'),
        'filter-timeuntil05' : ('{{ a|timeuntil:b }}', {'a':now - timedelta(days=2), 'b':now - timedelta(days=2, minutes=1)}, '1\xa0minute'),

        # Regression for #7443
        'filter-timeuntil06': ('{{ earlier|timeuntil }}', { 'earlier': now - timedelta(days=7) }, '0\xa0minutes'),
        'filter-timeuntil07': ('{{ earlier|timeuntil:now }}', { 'now': now, 'earlier': now - timedelta(days=7) }, '0\xa0minutes'),
        'filter-timeuntil08': ('{{ later|timeuntil }}', { 'later': now + timedelta(days=7, hours=1) }, '1\xa0week'),
        'filter-timeuntil09': ('{{ later|timeuntil:now }}', { 'now': now, 'later': now + timedelta(days=7) }, '1\xa0week'),

        # Ensures that differing timezones are calculated correctly
        'filter-timeuntil10' : ('{{ a|timeuntil }}', {'a': now_tz_i}, '0\xa0minutes'),
        'filter-timeuntil11' : ('{{ a|timeuntil:b }}', {'a': now_tz_i, 'b': now_tz}, '0\xa0minutes'),

        # Regression for #9065 (two date objects).
        'filter-timeuntil12' : ('{{ a|timeuntil:b }}', {'a': today, 'b': today}, '0\xa0minutes'),
        'filter-timeuntil13' : ('{{ a|timeuntil:b }}', {'a': today, 'b': today - timedelta(hours=24)}, '1\xa0day'),

        'filter-addslash01': ("{% autoescape off %}{{ a|addslashes }} {{ b|addslashes }}{% endautoescape %}", {"a": "<a>'", "b": mark_safe("<a>'")}, r"<a>\' <a>\'"),
        'filter-addslash02': ("{{ a|addslashes }} {{ b|addslashes }}", {"a": "<a>'", "b": mark_safe("<a>'")}, r"&lt;a&gt;\&#39; <a>\'"),

        'filter-capfirst01': ("{% autoescape off %}{{ a|capfirst }} {{ b|capfirst }}{% endautoescape %}", {"a": "fred>", "b": mark_safe("fred&gt;")}, "Fred> Fred&gt;"),
        'filter-capfirst02': ("{{ a|capfirst }} {{ b|capfirst }}", {"a": "fred>", "b": mark_safe("fred&gt;")}, "Fred&gt; Fred&gt;"),

        # Note that applying fix_ampsersands in autoescape mode leads to
        # double escaping.
        'filter-fix_ampersands01': ("{% autoescape off %}{{ a|fix_ampersands }} {{ b|fix_ampersands }}{% endautoescape %}", {"a": "a&b", "b": mark_safe("a&b")}, "a&amp;b a&amp;b"),
        'filter-fix_ampersands02': ("{{ a|fix_ampersands }} {{ b|fix_ampersands }}", {"a": "a&b", "b": mark_safe("a&b")}, "a&amp;amp;b a&amp;b"),

        'filter-floatformat01': ("{% autoescape off %}{{ a|floatformat }} {{ b|floatformat }}{% endautoescape %}", {"a": "1.42", "b": mark_safe("1.42")}, "1.4 1.4"),
        'filter-floatformat02': ("{{ a|floatformat }} {{ b|floatformat }}", {"a": "1.42", "b": mark_safe("1.42")}, "1.4 1.4"),

        # The contents of "linenumbers" is escaped according to the current
        # autoescape setting.
        'filter-linenumbers01': ("{{ a|linenumbers }} {{ b|linenumbers }}", {"a": "one\n<two>\nthree", "b": mark_safe("one\n&lt;two&gt;\nthree")}, "1. one\n2. &lt;two&gt;\n3. three 1. one\n2. &lt;two&gt;\n3. three"),
        'filter-linenumbers02': ("{% autoescape off %}{{ a|linenumbers }} {{ b|linenumbers }}{% endautoescape %}", {"a": "one\n<two>\nthree", "b": mark_safe("one\n&lt;two&gt;\nthree")}, "1. one\n2. <two>\n3. three 1. one\n2. &lt;two&gt;\n3. three"),

        'filter-lower01': ("{% autoescape off %}{{ a|lower }} {{ b|lower }}{% endautoescape %}", {"a": "Apple & banana", "b": mark_safe("Apple &amp; banana")}, "apple & banana apple &amp; banana"),
        'filter-lower02': ("{{ a|lower }} {{ b|lower }}", {"a": "Apple & banana", "b": mark_safe("Apple &amp; banana")}, "apple &amp; banana apple &amp; banana"),

        # The make_list filter can destroy existing escaping, so the results are
        # escaped.
        'filter-make_list01': ("{% autoescape off %}{{ a|make_list }}{% endautoescape %}", {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),
        'filter-make_list02': ("{{ a|make_list }}", {"a": mark_safe("&")}, str_prefix("[%(_)s&#39;&amp;&#39;]")),
        'filter-make_list03': ('{% autoescape off %}{{ a|make_list|stringformat:"s"|safe }}{% endautoescape %}', {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),
        'filter-make_list04': ('{{ a|make_list|stringformat:"s"|safe }}', {"a": mark_safe("&")}, str_prefix("[%(_)s'&']")),

        # Running slugify on a pre-escaped string leads to odd behavior,
        # but the result is still safe.
        'filter-slugify01': ("{% autoescape off %}{{ a|slugify }} {{ b|slugify }}{% endautoescape %}", {"a": "a & b", "b": mark_safe("a &amp; b")}, "a-b a-amp-b"),
        'filter-slugify02': ("{{ a|slugify }} {{ b|slugify }}", {"a": "a & b", "b": mark_safe("a &amp; b")}, "a-b a-amp-b"),

        # Notice that escaping is applied *after* any filters, so the string
        # formatting here only needs to deal with pre-escaped characters.
        'filter-stringformat01': ('{% autoescape off %}.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.{% endautoescape %}',
            {"a": "a<b", "b": mark_safe("a<b")}, ".  a<b. .  a<b."),
        'filter-stringformat02': ('.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.', {"a": "a<b", "b": mark_safe("a<b")},
            ".  a&lt;b. .  a<b."),

        # Test the title filter
        'filter-title1' : ('{{ a|title }}', {'a' : 'JOE\'S CRAB SHACK'}, 'Joe&#39;s Crab Shack'),
        'filter-title2' : ('{{ a|title }}', {'a' : '555 WEST 53RD STREET'}, '555 West 53rd Street'),

        'filter-truncatewords01': ('{% autoescape off %}{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}{% endautoescape %}',
            {"a": "alpha & bravo", "b": mark_safe("alpha &amp; bravo")}, "alpha & ... alpha &amp; ..."),
        'filter-truncatewords02': ('{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}',
            {"a": "alpha & bravo", "b": mark_safe("alpha &amp; bravo")}, "alpha &amp; ... alpha &amp; ..."),

        'filter-truncatechars01': ('{{ a|truncatechars:5 }}', {'a': "Testing, testing"}, "Te..."),
        'filter-truncatechars02': ('{{ a|truncatechars:7 }}', {'a': "Testing"}, "Testing"),

        # The "upper" filter messes up entities (which are case-sensitive),
        # so it's not safe for non-escaping purposes.
        'filter-upper01': ('{% autoescape off %}{{ a|upper }} {{ b|upper }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "A & B A &AMP; B"),
        'filter-upper02': ('{{ a|upper }} {{ b|upper }}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "A &amp; B A &amp;AMP; B"),

        'filter-urlize01': ('{% autoescape off %}{{ a|urlize }} {{ b|urlize }}{% endautoescape %}', {"a": "http://example.com/?x=&y=", "b": mark_safe("http://example.com?x=&amp;y=")}, '<a href="http://example.com/?x=&y=" rel="nofollow">http://example.com/?x=&y=</a> <a href="http://example.com?x=&amp;y=" rel="nofollow">http://example.com?x=&amp;y=</a>'),
        'filter-urlize02': ('{{ a|urlize }} {{ b|urlize }}', {"a": "http://example.com/?x=&y=", "b": mark_safe("http://example.com?x=&amp;y=")}, '<a href="http://example.com/?x=&amp;y=" rel="nofollow">http://example.com/?x=&amp;y=</a> <a href="http://example.com?x=&amp;y=" rel="nofollow">http://example.com?x=&amp;y=</a>'),
        'filter-urlize03': ('{% autoescape off %}{{ a|urlize }}{% endautoescape %}', {"a": mark_safe("a &amp; b")}, 'a &amp; b'),
        'filter-urlize04': ('{{ a|urlize }}', {"a": mark_safe("a &amp; b")}, 'a &amp; b'),

        # This will lead to a nonsense result, but at least it won't be
        # exploitable for XSS purposes when auto-escaping is on.
        'filter-urlize05': ('{% autoescape off %}{{ a|urlize }}{% endautoescape %}', {"a": "<script>alert('foo')</script>"}, "<script>alert('foo')</script>"),
        'filter-urlize06': ('{{ a|urlize }}', {"a": "<script>alert('foo')</script>"}, '&lt;script&gt;alert(&#39;foo&#39;)&lt;/script&gt;'),

        # mailto: testing for urlize
        'filter-urlize07': ('{{ a|urlize }}', {"a": "Email me at [email protected]"}, 'Email me at <a href="mailto:[email protected]">[email protected]</a>'),
        'filter-urlize08': ('{{ a|urlize }}', {"a": "Email me at <*****@*****.**>"}, 'Email me at &lt;<a href="mailto:[email protected]">[email protected]</a>&gt;'),

        'filter-urlizetrunc01': ('{% autoescape off %}{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}{% endautoescape %}', {"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y=')}, '"Unsafe" <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&amp;y=" rel="nofollow">http:...</a>'),
        'filter-urlizetrunc02': ('{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}', {"a": '"Unsafe" http://example.com/x=&y=', "b": mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y=')}, '&quot;Unsafe&quot; <a href="http://example.com/x=&amp;y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&amp;y=" rel="nofollow">http:...</a>'),

        'filter-wordcount01': ('{% autoescape off %}{{ a|wordcount }} {{ b|wordcount }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "3 3"),
        'filter-wordcount02': ('{{ a|wordcount }} {{ b|wordcount }}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "3 3"),

        'filter-wordwrap01': ('{% autoescape off %}{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}{% endautoescape %}', {"a": "a & b", "b": mark_safe("a & b")}, "a &\nb a &\nb"),
        'filter-wordwrap02': ('{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}', {"a": "a & b", "b": mark_safe("a & b")}, "a &amp;\nb a &\nb"),

        'filter-ljust01': ('{% autoescape off %}.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, ".a&b  . .a&b  ."),
        'filter-ljust02': ('.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ".a&amp;b  . .a&b  ."),

        'filter-rjust01': ('{% autoescape off %}.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, ".  a&b. .  a&b."),
        'filter-rjust02': ('.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ".  a&amp;b. .  a&b."),

        'filter-center01': ('{% autoescape off %}.{{ a|center:"5" }}. .{{ b|center:"5" }}.{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, ". a&b . . a&b ."),
        'filter-center02': ('.{{ a|center:"5" }}. .{{ b|center:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ". a&amp;b . . a&b ."),

        'filter-cut01': ('{% autoescape off %}{{ a|cut:"x" }} {{ b|cut:"x" }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "&y &amp;y"),
        'filter-cut02': ('{{ a|cut:"x" }} {{ b|cut:"x" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "&amp;y &amp;y"),
        'filter-cut03': ('{% autoescape off %}{{ a|cut:"&" }} {{ b|cut:"&" }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "xy xamp;y"),
        'filter-cut04': ('{{ a|cut:"&" }} {{ b|cut:"&" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "xy xamp;y"),
        # Passing ';' to cut can break existing HTML entities, so those strings
        # are auto-escaped.
        'filter-cut05': ('{% autoescape off %}{{ a|cut:";" }} {{ b|cut:";" }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "x&y x&ampy"),
        'filter-cut06': ('{{ a|cut:";" }} {{ b|cut:";" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "x&amp;y x&amp;ampy"),

        # The "escape" filter works the same whether autoescape is on or off,
        # but it has no effect on strings already marked as safe.
        'filter-escape01': ('{{ a|escape }} {{ b|escape }}', {"a": "x&y", "b": mark_safe("x&y")}, "x&amp;y x&y"),
        'filter-escape02': ('{% autoescape off %}{{ a|escape }} {{ b|escape }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&y")}, "x&amp;y x&y"),

        # It is only applied once, regardless of the number of times it
        # appears in a chain.
        'filter-escape03': ('{% autoescape off %}{{ a|escape|escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
        'filter-escape04': ('{{ a|escape|escape }}', {"a": "x&y"}, "x&amp;y"),

        # Force_escape is applied immediately. It can be used to provide
        # double-escaping, for example.
        'filter-force-escape01': ('{% autoescape off %}{{ a|force_escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
        'filter-force-escape02': ('{{ a|force_escape }}', {"a": "x&y"}, "x&amp;y"),
        'filter-force-escape03': ('{% autoescape off %}{{ a|force_escape|force_escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;amp;y"),
        'filter-force-escape04': ('{{ a|force_escape|force_escape }}', {"a": "x&y"}, "x&amp;amp;y"),

        # Because the result of force_escape is "safe", an additional
        # escape filter has no effect.
        'filter-force-escape05': ('{% autoescape off %}{{ a|force_escape|escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
        'filter-force-escape06': ('{{ a|force_escape|escape }}', {"a": "x&y"}, "x&amp;y"),
        'filter-force-escape07': ('{% autoescape off %}{{ a|escape|force_escape }}{% endautoescape %}', {"a": "x&y"}, "x&amp;y"),
        'filter-force-escape08': ('{{ a|escape|force_escape }}', {"a": "x&y"}, "x&amp;y"),

        # The contents in "linebreaks" and "linebreaksbr" are escaped
        # according to the current autoescape setting.
        'filter-linebreaks01': ('{{ a|linebreaks }} {{ b|linebreaks }}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "<p>x&amp;<br />y</p> <p>x&<br />y</p>"),
        'filter-linebreaks02': ('{% autoescape off %}{{ a|linebreaks }} {{ b|linebreaks }}{% endautoescape %}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "<p>x&<br />y</p> <p>x&<br />y</p>"),

        'filter-linebreaksbr01': ('{{ a|linebreaksbr }} {{ b|linebreaksbr }}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "x&amp;<br />y x&<br />y"),
        'filter-linebreaksbr02': ('{% autoescape off %}{{ a|linebreaksbr }} {{ b|linebreaksbr }}{% endautoescape %}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "x&<br />y x&<br />y"),

        'filter-safe01': ("{{ a }} -- {{ a|safe }}", {"a": "<b>hello</b>"}, "&lt;b&gt;hello&lt;/b&gt; -- <b>hello</b>"),
        'filter-safe02': ("{% autoescape off %}{{ a }} -- {{ a|safe }}{% endautoescape %}", {"a": "<b>hello</b>"}, "<b>hello</b> -- <b>hello</b>"),

        'filter-safeseq01': ('{{ a|join:", " }} -- {{ a|safeseq|join:", " }}', {"a": ["&", "<"]}, "&amp;, &lt; -- &, <"),
        'filter-safeseq02': ('{% autoescape off %}{{ a|join:", " }} -- {{ a|safeseq|join:", " }}{% endautoescape %}', {"a": ["&", "<"]}, "&, < -- &, <"),

        'filter-removetags01': ('{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x &lt;p&gt;y&lt;/p&gt; x <p>y</p>"),
        'filter-removetags02': ('{% autoescape off %}{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}{% endautoescape %}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x <p>y</p> x <p>y</p>"),

        'filter-striptags01': ('{{ a|striptags }} {{ b|striptags }}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x y x y"),
        'filter-striptags02': ('{% autoescape off %}{{ a|striptags }} {{ b|striptags }}{% endautoescape %}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x y x y"),

        'filter-first01': ('{{ a|first }} {{ b|first }}', {"a": ["a&b", "x"], "b": [mark_safe("a&b"), "x"]}, "a&amp;b a&b"),
        'filter-first02': ('{% autoescape off %}{{ a|first }} {{ b|first }}{% endautoescape %}', {"a": ["a&b", "x"], "b": [mark_safe("a&b"), "x"]}, "a&b a&b"),

        'filter-last01': ('{{ a|last }} {{ b|last }}', {"a": ["x", "a&b"], "b": ["x", mark_safe("a&b")]}, "a&amp;b a&b"),
        'filter-last02': ('{% autoescape off %}{{ a|last }} {{ b|last }}{% endautoescape %}', {"a": ["x", "a&b"], "b": ["x", mark_safe("a&b")]}, "a&b a&b"),

        'filter-random01': ('{{ a|random }} {{ b|random }}', {"a": ["a&b", "a&b"], "b": [mark_safe("a&b"), mark_safe("a&b")]}, "a&amp;b a&b"),
        'filter-random02': ('{% autoescape off %}{{ a|random }} {{ b|random }}{% endautoescape %}', {"a": ["a&b", "a&b"], "b": [mark_safe("a&b"), mark_safe("a&b")]}, "a&b a&b"),

        'filter-slice01': ('{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}', {"a": "a&b", "b": mark_safe("a&b")}, "&amp;b &b"),
        'filter-slice02': ('{% autoescape off %}{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}{% endautoescape %}', {"a": "a&b", "b": mark_safe("a&b")}, "&b &b"),

        'filter-unordered_list01': ('{{ a|unordered_list }}', {"a": ["x>", [["<y", []]]]}, "\t<li>x&gt;\n\t<ul>\n\t\t<li>&lt;y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list02': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [["<y", []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list03': ('{{ a|unordered_list }}', {"a": ["x>", [[mark_safe("<y"), []]]]}, "\t<li>x&gt;\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list04': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [[mark_safe("<y"), []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list05': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [["<y", []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),

        # Literal string arguments to the default filter are always treated as
        # safe strings, regardless of the auto-escaping state.
        #
        # Note: we have to use {"a": ""} here, otherwise the invalid template
        # variable string interferes with the test result.
        'filter-default01': ('{{ a|default:"x<" }}', {"a": ""}, "x<"),
        'filter-default02': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": ""}, "x<"),
        'filter-default03': ('{{ a|default:"x<" }}', {"a": mark_safe("x>")}, "x>"),
        'filter-default04': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": mark_safe("x>")}, "x>"),

        'filter-default_if_none01': ('{{ a|default:"x<" }}', {"a": None}, "x<"),
        'filter-default_if_none02': ('{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {"a": None}, "x<"),

        'filter-phone2numeric01': ('{{ a|phone2numeric }} {{ b|phone2numeric }}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "&lt;1-800-2255-63&gt; <1-800-2255-63>"),
        'filter-phone2numeric02': ('{% autoescape off %}{{ a|phone2numeric }} {{ b|phone2numeric }}{% endautoescape %}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "<1-800-2255-63> <1-800-2255-63>"),
        'filter-phone2numeric03': ('{{ a|phone2numeric }}', {"a": "How razorback-jumping frogs can level six piqued gymnasts!"}, "469 729672225-5867464 37647 226 53835 749 747833 49662787!"),

        # Ensure iriencode keeps safe strings:
        'filter-iriencode01': ('{{ url|iriencode }}', {'url': '?test=1&me=2'}, '?test=1&amp;me=2'),
        'filter-iriencode02': ('{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {'url': '?test=1&me=2'}, '?test=1&me=2'),
        'filter-iriencode03': ('{{ url|iriencode }}', {'url': mark_safe('?test=1&me=2')}, '?test=1&me=2'),
        'filter-iriencode04': ('{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {'url': mark_safe('?test=1&me=2')}, '?test=1&me=2'),

        # urlencode
        'filter-urlencode01': ('{{ url|urlencode }}', {'url': '/test&"/me?/'}, '/test%26%22/me%3F/'),
        'filter-urlencode02': ('/test/{{ urlbit|urlencode:"" }}/', {'urlbit': 'escape/slash'}, '/test/escape%2Fslash/'),

        # Chaining a bunch of safeness-preserving filters should not alter
        # the safe status either way.
        'chaining01': ('{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}', {"a": "a < b", "b": mark_safe("a < b")}, " A &lt; b . A < b "),
        'chaining02': ('{% autoescape off %}{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}{% endautoescape %}', {"a": "a < b", "b": mark_safe("a < b")}, " A < b . A < b "),

        # Using a filter that forces a string back to unsafe:
        'chaining03': ('{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}', {"a": "a < b", "b": mark_safe("a < b")}, "A &lt; .A < "),
        'chaining04': ('{% autoescape off %}{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}{% endautoescape %}', {"a": "a < b", "b": mark_safe("a < b")}, "A < .A < "),

        # Using a filter that forces safeness does not lead to double-escaping
        'chaining05': ('{{ a|escape|capfirst }}', {"a": "a < b"}, "A &lt; b"),
        'chaining06': ('{% autoescape off %}{{ a|escape|capfirst }}{% endautoescape %}', {"a": "a < b"}, "A &lt; b"),

        # Force to safe, then back (also showing why using force_escape too
        # early in a chain can lead to unexpected results).
        'chaining07': ('{{ a|force_escape|cut:";" }}', {"a": "a < b"}, "a &amp;lt b"),
        'chaining08': ('{% autoescape off %}{{ a|force_escape|cut:";" }}{% endautoescape %}', {"a": "a < b"}, "a &lt b"),
        'chaining09': ('{{ a|cut:";"|force_escape }}', {"a": "a < b"}, "a &lt; b"),
        'chaining10': ('{% autoescape off %}{{ a|cut:";"|force_escape }}{% endautoescape %}', {"a": "a < b"}, "a &lt; b"),
        'chaining11': ('{{ a|cut:"b"|safe }}', {"a": "a < b"}, "a < "),
        'chaining12': ('{% autoescape off %}{{ a|cut:"b"|safe }}{% endautoescape %}', {"a": "a < b"}, "a < "),
        'chaining13': ('{{ a|safe|force_escape }}', {"a": "a < b"}, "a &lt; b"),
        'chaining14': ('{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}', {"a": "a < b"}, "a &lt; b"),

        # Filters decorated with stringfilter still respect is_safe.
        'autoescape-stringfilter01': (r'{{ unsafe|capfirst }}', {'unsafe': UnsafeClass()}, 'You &amp; me'),
        'autoescape-stringfilter02': (r'{% autoescape off %}{{ unsafe|capfirst }}{% endautoescape %}', {'unsafe': UnsafeClass()}, 'You & me'),
        'autoescape-stringfilter03': (r'{{ safe|capfirst }}', {'safe': SafeClass()}, 'You &gt; me'),
        'autoescape-stringfilter04': (r'{% autoescape off %}{{ safe|capfirst }}{% endautoescape %}', {'safe': SafeClass()}, 'You &gt; me'),

        'escapejs01': (r'{{ a|escapejs }}', {'a': 'testing\r\njavascript \'string" <b>escaping</b>'}, 'testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E'),
        'escapejs02': (r'{% autoescape off %}{{ a|escapejs }}{% endautoescape %}', {'a': 'testing\r\njavascript \'string" <b>escaping</b>'}, 'testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E'),


        # length filter.
        'length01': ('{{ list|length }}', {'list': ['4', None, True, {}]}, '4'),
        'length02': ('{{ list|length }}', {'list': []}, '0'),
        'length03': ('{{ string|length }}', {'string': ''}, '0'),
        'length04': ('{{ string|length }}', {'string': 'django'}, '6'),
        # Invalid uses that should fail silently.
        'length05': ('{{ int|length }}', {'int': 7}, ''),
        'length06': ('{{ None|length }}', {'None': None}, ''),

        # length_is filter.
        'length_is01': ('{% if some_list|length_is:"4" %}Four{% endif %}', {'some_list': ['4', None, True, {}]}, 'Four'),
        'length_is02': ('{% if some_list|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'some_list': ['4', None, True, {}, 17]}, 'Not Four'),
        'length_is03': ('{% if mystring|length_is:"4" %}Four{% endif %}', {'mystring': 'word'}, 'Four'),
        'length_is04': ('{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'mystring': 'Python'}, 'Not Four'),
        'length_is05': ('{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}', {'mystring': ''}, 'Not Four'),
        'length_is06': ('{% with var|length as my_length %}{{ my_length }}{% endwith %}', {'var': 'django'}, '6'),
        # Boolean return value from length_is should not be coerced to a string
        'length_is07': (r'{% if "X"|length_is:0 %}Length is 0{% else %}Length not 0{% endif %}', {}, 'Length not 0'),
        'length_is08': (r'{% if "X"|length_is:1 %}Length is 1{% else %}Length not 1{% endif %}', {}, 'Length is 1'),
        # Invalid uses that should fail silently.
        'length_is09': ('{{ var|length_is:"fish" }}', {'var': 'django'}, ''),
        'length_is10': ('{{ int|length_is:"1" }}', {'int': 7}, ''),
        'length_is11': ('{{ none|length_is:"1" }}', {'none': None}, ''),

        'join01': (r'{{ a|join:", " }}', {'a': ['alpha', 'beta & me']}, 'alpha, beta &amp; me'),
        'join02': (r'{% autoescape off %}{{ a|join:", " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha, beta & me'),
        'join03': (r'{{ a|join:" &amp; " }}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta &amp; me'),
        'join04': (r'{% autoescape off %}{{ a|join:" &amp; " }}{% endautoescape %}', {'a': ['alpha', 'beta & me']}, 'alpha &amp; beta & me'),

        # Test that joining with unsafe joiners don't result in unsafe strings (#11377)
        'join05': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': ' & '}, 'alpha &amp; beta &amp; me'),
        'join06': (r'{{ a|join:var }}', {'a': ['alpha', 'beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; me'),
        'join07': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': ' & ' }, 'alpha &amp; beta &amp; me'),
        'join08': (r'{{ a|join:var|lower }}', {'a': ['Alpha', 'Beta & me'], 'var': mark_safe(' & ')}, 'alpha & beta &amp; me'),

        'date01': (r'{{ d|date:"m" }}', {'d': datetime(2008, 1, 1)}, '01'),
        'date02': (r'{{ d|date }}', {'d': datetime(2008, 1, 1)}, 'Jan. 1, 2008'),
        #Ticket 9520: Make sure |date doesn't blow up on non-dates
        'date03': (r'{{ d|date:"m" }}', {'d': 'fail_string'}, ''),
        # ISO date formats
        'date04': (r'{{ d|date:"o" }}', {'d': datetime(2008, 12, 29)}, '2009'),
        'date05': (r'{{ d|date:"o" }}', {'d': datetime(2010, 1, 3)}, '2009'),
        # Timezone name
        'date06': (r'{{ d|date:"e" }}', {'d': datetime(2009, 3, 12, tzinfo=FixedOffset(30))}, '+0030'),
        'date07': (r'{{ d|date:"e" }}', {'d': datetime(2009, 3, 12)}, ''),
        # Ticket 19370: Make sure |date doesn't blow up on a midnight time object
        'date08': (r'{{ t|date:"H:i" }}', {'t': time(0, 1)}, '00:01'),
        'date09': (r'{{ t|date:"H:i" }}', {'t': time(0, 0)}, '00:00'),

         # Tests for #11687 and #16676
         'add01': (r'{{ i|add:"5" }}', {'i': 2000}, '2005'),
         'add02': (r'{{ i|add:"napis" }}', {'i': 2000}, ''),
         'add03': (r'{{ i|add:16 }}', {'i': 'not_an_int'}, ''),
         'add04': (r'{{ i|add:"16" }}', {'i': 'not_an_int'}, 'not_an_int16'),
         'add05': (r'{{ l1|add:l2 }}', {'l1': [1, 2], 'l2': [3, 4]}, '[1, 2, 3, 4]'),
         'add06': (r'{{ t1|add:t2 }}', {'t1': (3, 4), 't2': (1, 2)}, '(3, 4, 1, 2)'),
         'add07': (r'{{ d|add:t }}', {'d': date(2000, 1, 1), 't': timedelta(10)}, 'Jan. 11, 2000'),
    }
Example #45
0
File: tests.py Project: 01-/django
    def test_basic_distinct_on(self):
        """QuerySet.distinct('field', ...) works"""
        # (qset, expected) tuples
        qsets = (
            (
                Staff.objects.distinct().order_by('name'),
                ['<Staff: p1>', '<Staff: p1>', '<Staff: p2>', '<Staff: p3>'],
            ),
            (
                Staff.objects.distinct('name').order_by('name'),
                ['<Staff: p1>', '<Staff: p2>', '<Staff: p3>'],
            ),
            (
                Staff.objects.distinct('organisation').order_by('organisation', 'name'),
                ['<Staff: p1>', '<Staff: p1>'],
            ),
            (
                Staff.objects.distinct('name', 'organisation').order_by('name', 'organisation'),
                ['<Staff: p1>', '<Staff: p1>', '<Staff: p2>', '<Staff: p3>'],
            ),
            (
                Celebrity.objects.filter(fan__in=[self.fan1, self.fan2, self.fan3]).distinct('name').order_by('name'),
                ['<Celebrity: c1>', '<Celebrity: c2>'],
            ),
            # Does combining querysets work?
            (
                (Celebrity.objects.filter(fan__in=[self.fan1, self.fan2]).
                    distinct('name').order_by('name') |
                 Celebrity.objects.filter(fan__in=[self.fan3]).
                    distinct('name').order_by('name')),
                ['<Celebrity: c1>', '<Celebrity: c2>'],
            ),
            (
                StaffTag.objects.distinct('staff', 'tag'),
                ['<StaffTag: t1 -> p1>'],
            ),
            (
                Tag.objects.order_by('parent__pk', 'pk').distinct('parent'),
                ['<Tag: t2>', '<Tag: t4>', '<Tag: t1>'],
            ),
            (
                StaffTag.objects.select_related('staff').distinct('staff__name').order_by('staff__name'),
                ['<StaffTag: t1 -> p1>'],
            ),
            # Fetch the alphabetically first coworker for each worker
            (
                (Staff.objects.distinct('id').order_by('id', 'coworkers__name').
                    values_list('id', 'coworkers__name')),
                [str_prefix("(1, %(_)s'p2')"), str_prefix("(2, %(_)s'p1')"),
                 str_prefix("(3, %(_)s'p1')"), "(4, None)"]
            ),
        )
        for qset, expected in qsets:
            self.assertQuerysetEqual(qset, expected)
            self.assertEqual(qset.count(), len(expected))

        # Combining queries with different distinct_fields is not allowed.
        base_qs = Celebrity.objects.all()
        with self.assertRaisesMessage(AssertionError, "Cannot combine queries with different distinct fields."):
            base_qs.distinct('id') & base_qs.distinct('name')

        # Test join unreffing
        c1 = Celebrity.objects.distinct('greatest_fan__id', 'greatest_fan__fan_of')
        self.assertIn('OUTER JOIN', str(c1.query))
        c2 = c1.distinct('pk')
        self.assertNotIn('OUTER JOIN', str(c2.query))
Example #46
0
 def test_make_list04(self):
     output = self.engine.render_to_string('make_list04', {"a": mark_safe("&")})
     self.assertEqual(output, str_prefix("[%(_)s'&']"))