diff options
author | Ryan Heard <ryanwheard@gmail.com> | 2021-07-02 15:09:13 -0500 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-03-04 12:55:37 +0100 |
commit | c6b4d62fa2c7f73b87f6ae7e8cf1d64ee5312dc5 (patch) | |
tree | 238bd8c3045c8d4577e09bd913de9748dcd49968 /tests/xor_lookups | |
parent | 795da6306a048b18c0158496b0d49e8e4f197a32 (diff) | |
download | django-c6b4d62fa2c7f73b87f6ae7e8cf1d64ee5312dc5.tar.gz |
Fixed #29865 -- Added logical XOR support for Q() and querysets.
Diffstat (limited to 'tests/xor_lookups')
-rw-r--r-- | tests/xor_lookups/__init__.py | 0 | ||||
-rw-r--r-- | tests/xor_lookups/models.py | 8 | ||||
-rw-r--r-- | tests/xor_lookups/tests.py | 67 |
3 files changed, 75 insertions, 0 deletions
diff --git a/tests/xor_lookups/__init__.py b/tests/xor_lookups/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/xor_lookups/__init__.py diff --git a/tests/xor_lookups/models.py b/tests/xor_lookups/models.py new file mode 100644 index 0000000000..22e79aa94f --- /dev/null +++ b/tests/xor_lookups/models.py @@ -0,0 +1,8 @@ +from django.db import models + + +class Number(models.Model): + num = models.IntegerField() + + def __str__(self): + return str(self.num) diff --git a/tests/xor_lookups/tests.py b/tests/xor_lookups/tests.py new file mode 100644 index 0000000000..a9cdf9cb31 --- /dev/null +++ b/tests/xor_lookups/tests.py @@ -0,0 +1,67 @@ +from django.db.models import Q +from django.test import TestCase + +from .models import Number + + +class XorLookupsTests(TestCase): + @classmethod + def setUpTestData(cls): + cls.numbers = [Number.objects.create(num=i) for i in range(10)] + + def test_filter(self): + self.assertCountEqual( + Number.objects.filter(num__lte=7) ^ Number.objects.filter(num__gte=3), + self.numbers[:3] + self.numbers[8:], + ) + self.assertCountEqual( + Number.objects.filter(Q(num__lte=7) ^ Q(num__gte=3)), + self.numbers[:3] + self.numbers[8:], + ) + + def test_filter_negated(self): + self.assertCountEqual( + Number.objects.filter(Q(num__lte=7) ^ ~Q(num__lt=3)), + self.numbers[:3] + self.numbers[8:], + ) + self.assertCountEqual( + Number.objects.filter(~Q(num__gt=7) ^ ~Q(num__lt=3)), + self.numbers[:3] + self.numbers[8:], + ) + self.assertCountEqual( + Number.objects.filter(Q(num__lte=7) ^ ~Q(num__lt=3) ^ Q(num__lte=1)), + [self.numbers[2]] + self.numbers[8:], + ) + self.assertCountEqual( + Number.objects.filter(~(Q(num__lte=7) ^ ~Q(num__lt=3) ^ Q(num__lte=1))), + self.numbers[:2] + self.numbers[3:8], + ) + + def test_exclude(self): + self.assertCountEqual( + Number.objects.exclude(Q(num__lte=7) ^ Q(num__gte=3)), + self.numbers[3:8], + ) + + def test_stages(self): + numbers = Number.objects.all() + self.assertSequenceEqual( + numbers.filter(num__gte=0) ^ numbers.filter(num__lte=11), + [], + ) + self.assertSequenceEqual( + numbers.filter(num__gt=0) ^ numbers.filter(num__lt=11), + [self.numbers[0]], + ) + + def test_pk_q(self): + self.assertCountEqual( + Number.objects.filter(Q(pk=self.numbers[0].pk) ^ Q(pk=self.numbers[1].pk)), + self.numbers[:2], + ) + + def test_empty_in(self): + self.assertCountEqual( + Number.objects.filter(Q(pk__in=[]) ^ Q(num__gte=5)), + self.numbers[5:], + ) |