summaryrefslogtreecommitdiff
path: root/tests/db_functions
diff options
context:
space:
mode:
authorNick Pope <nick.pope@flightdataservices.com>2018-08-16 00:45:11 +0100
committerTim Graham <timograham@gmail.com>2018-08-16 15:44:31 -0400
commit328898582267d963d79eb871300a7f4d5f5e5959 (patch)
tree86cbe0844f59a5f7887217f28c1a37bcedc86fef /tests/db_functions
parentcd790ed1a6dbdf910c41da44c306ddae6ea6fd4d (diff)
Reorganized text db function tests.
Diffstat (limited to 'tests/db_functions')
-rw-r--r--tests/db_functions/tests.py256
-rw-r--r--tests/db_functions/text/__init__.py0
-rw-r--r--tests/db_functions/text/test_chr.py (renamed from tests/db_functions/test_chr.py)2
-rw-r--r--tests/db_functions/text/test_concat.py81
-rw-r--r--tests/db_functions/text/test_left.py (renamed from tests/db_functions/test_left.py)2
-rw-r--r--tests/db_functions/text/test_length.py48
-rw-r--r--tests/db_functions/text/test_lower.py42
-rw-r--r--tests/db_functions/text/test_ord.py (renamed from tests/db_functions/test_ord.py)2
-rw-r--r--tests/db_functions/text/test_pad.py (renamed from tests/db_functions/test_pad.py)2
-rw-r--r--tests/db_functions/text/test_repeat.py (renamed from tests/db_functions/test_repeat.py)2
-rw-r--r--tests/db_functions/text/test_replace.py (renamed from tests/db_functions/test_replace.py)2
-rw-r--r--tests/db_functions/text/test_right.py (renamed from tests/db_functions/test_right.py)2
-rw-r--r--tests/db_functions/text/test_strindex.py (renamed from tests/db_functions/test_strindex.py)2
-rw-r--r--tests/db_functions/text/test_substr.py53
-rw-r--r--tests/db_functions/text/test_trim.py (renamed from tests/db_functions/test_trim.py)2
-rw-r--r--tests/db_functions/text/test_upper.py43
16 files changed, 277 insertions, 264 deletions
diff --git a/tests/db_functions/tests.py b/tests/db_functions/tests.py
index 4331e02ef6..507d2669b8 100644
--- a/tests/db_functions/tests.py
+++ b/tests/db_functions/tests.py
@@ -6,8 +6,7 @@ from django.db import connection
from django.db.models import CharField, TextField, Value as V
from django.db.models.expressions import RawSQL
from django.db.models.functions import (
- Coalesce, Concat, ConcatPair, Greatest, Least, Length, Lower, Now,
- StrIndex, Substr, Upper,
+ Coalesce, Greatest, Least, Length, Lower, Now, Upper,
)
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.utils import timezone
@@ -311,214 +310,6 @@ class FunctionTests(TestCase):
[obj],
)
- def test_concat(self):
- Author.objects.create(name='Jayden')
- Author.objects.create(name='John Smith', alias='smithj', goes_by='John')
- Author.objects.create(name='Margaret', goes_by='Maggie')
- Author.objects.create(name='Rhonda', alias='adnohR')
-
- authors = Author.objects.annotate(joined=Concat('alias', 'goes_by'))
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- '',
- 'smithjJohn',
- 'Maggie',
- 'adnohR',
- ],
- lambda a: a.joined
- )
-
- with self.assertRaisesMessage(ValueError, 'Concat must take at least two expressions'):
- Author.objects.annotate(joined=Concat('alias'))
-
- def test_concat_many(self):
- Author.objects.create(name='Jayden')
- Author.objects.create(name='John Smith', alias='smithj', goes_by='John')
- Author.objects.create(name='Margaret', goes_by='Maggie')
- Author.objects.create(name='Rhonda', alias='adnohR')
-
- authors = Author.objects.annotate(
- joined=Concat('name', V(' ('), 'goes_by', V(')'), output_field=CharField()),
- )
-
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- 'Jayden ()',
- 'John Smith (John)',
- 'Margaret (Maggie)',
- 'Rhonda ()',
- ],
- lambda a: a.joined
- )
-
- def test_concat_mixed_char_text(self):
- Article.objects.create(title='The Title', text=lorem_ipsum, written=timezone.now())
- article = Article.objects.annotate(
- title_text=Concat('title', V(' - '), 'text', output_field=TextField()),
- ).get(title='The Title')
- self.assertEqual(article.title + ' - ' + article.text, article.title_text)
-
- # wrap the concat in something else to ensure that we're still
- # getting text rather than bytes
- article = Article.objects.annotate(
- title_text=Upper(Concat('title', V(' - '), 'text', output_field=TextField())),
- ).get(title='The Title')
- expected = article.title + ' - ' + article.text
- self.assertEqual(expected.upper(), article.title_text)
-
- @skipUnless(connection.vendor == 'sqlite', "sqlite specific implementation detail.")
- def test_concat_coalesce_idempotent(self):
- pair = ConcatPair(V('a'), V('b'))
- # Check nodes counts
- self.assertEqual(len(list(pair.flatten())), 3)
- self.assertEqual(len(list(pair.coalesce().flatten())), 7) # + 2 Coalesce + 2 Value()
- self.assertEqual(len(list(pair.flatten())), 3)
-
- def test_concat_sql_generation_idempotency(self):
- qs = Article.objects.annotate(description=Concat('title', V(': '), 'summary'))
- # Multiple compilations should not alter the generated query.
- self.assertEqual(str(qs.query), str(qs.all().query))
-
- def test_lower(self):
- Author.objects.create(name='John Smith', alias='smithj')
- Author.objects.create(name='Rhonda')
- authors = Author.objects.annotate(lower_name=Lower('name'))
-
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- 'john smith',
- 'rhonda',
- ],
- lambda a: a.lower_name
- )
-
- Author.objects.update(name=Lower('name'))
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- ('john smith', 'john smith'),
- ('rhonda', 'rhonda'),
- ],
- lambda a: (a.lower_name, a.name)
- )
-
- with self.assertRaisesMessage(TypeError, "'Lower' takes exactly 1 argument (2 given)"):
- Author.objects.update(name=Lower('name', 'name'))
-
- def test_upper(self):
- Author.objects.create(name='John Smith', alias='smithj')
- Author.objects.create(name='Rhonda')
- authors = Author.objects.annotate(upper_name=Upper('name'))
-
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- 'JOHN SMITH',
- 'RHONDA',
- ],
- lambda a: a.upper_name
- )
-
- Author.objects.update(name=Upper('name'))
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- ('JOHN SMITH', 'JOHN SMITH'),
- ('RHONDA', 'RHONDA'),
- ],
- lambda a: (a.upper_name, a.name)
- )
-
- def test_length(self):
- Author.objects.create(name='John Smith', alias='smithj')
- Author.objects.create(name='Rhonda')
- authors = Author.objects.annotate(
- name_length=Length('name'),
- alias_length=Length('alias'))
-
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- (10, 6),
- (6, None),
- ],
- lambda a: (a.name_length, a.alias_length)
- )
-
- self.assertEqual(authors.filter(alias_length__lte=Length('name')).count(), 1)
-
- def test_length_ordering(self):
- Author.objects.create(name='John Smith', alias='smithj')
- Author.objects.create(name='John Smith', alias='smithj1')
- Author.objects.create(name='Rhonda', alias='ronny')
-
- authors = Author.objects.order_by(Length('name'), Length('alias'))
-
- self.assertQuerysetEqual(
- authors, [
- ('Rhonda', 'ronny'),
- ('John Smith', 'smithj'),
- ('John Smith', 'smithj1'),
- ],
- lambda a: (a.name, a.alias)
- )
-
- def test_substr(self):
- Author.objects.create(name='John Smith', alias='smithj')
- Author.objects.create(name='Rhonda')
- authors = Author.objects.annotate(name_part=Substr('name', 5, 3))
-
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- ' Sm',
- 'da',
- ],
- lambda a: a.name_part
- )
-
- authors = Author.objects.annotate(name_part=Substr('name', 2))
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- 'ohn Smith',
- 'honda',
- ],
- lambda a: a.name_part
- )
-
- # if alias is null, set to first 5 lower characters of the name
- Author.objects.filter(alias__isnull=True).update(
- alias=Lower(Substr('name', 1, 5)),
- )
-
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- 'smithj',
- 'rhond',
- ],
- lambda a: a.alias
- )
-
- def test_substr_start(self):
- Author.objects.create(name='John Smith', alias='smithj')
- a = Author.objects.annotate(
- name_part_1=Substr('name', 1),
- name_part_2=Substr('name', 2),
- ).get(alias='smithj')
-
- self.assertEqual(a.name_part_1[1:], a.name_part_2)
-
- with self.assertRaisesMessage(ValueError, "'pos' must be greater than 0"):
- Author.objects.annotate(raises=Substr('name', 0))
-
- def test_substr_with_expressions(self):
- Author.objects.create(name='John Smith', alias='smithj')
- Author.objects.create(name='Rhonda')
- substr = Substr(Upper('name'), StrIndex('name', V('h')), 5, output_field=CharField())
- authors = Author.objects.annotate(name_part=substr)
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- 'HN SM',
- 'HONDA',
- ],
- lambda a: a.name_part
- )
-
def test_nested_function_ordering(self):
Author.objects.create(name='John Smith')
Author.objects.create(name='Rhonda Simpson', alias='ronny')
@@ -578,51 +369,6 @@ class FunctionTests(TestCase):
lambda a: a.title
)
- def test_length_transform(self):
- try:
- CharField.register_lookup(Length)
- Author.objects.create(name='John Smith', alias='smithj')
- Author.objects.create(name='Rhonda')
- authors = Author.objects.filter(name__length__gt=7)
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- 'John Smith',
- ],
- lambda a: a.name
- )
- finally:
- CharField._unregister_lookup(Length)
-
- def test_lower_transform(self):
- try:
- CharField.register_lookup(Lower)
- Author.objects.create(name='John Smith', alias='smithj')
- Author.objects.create(name='Rhonda')
- authors = Author.objects.filter(name__lower__exact='john smith')
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- 'John Smith',
- ],
- lambda a: a.name
- )
- finally:
- CharField._unregister_lookup(Lower)
-
- def test_upper_transform(self):
- try:
- CharField.register_lookup(Upper)
- Author.objects.create(name='John Smith', alias='smithj')
- Author.objects.create(name='Rhonda')
- authors = Author.objects.filter(name__upper__exact='JOHN SMITH')
- self.assertQuerysetEqual(
- authors.order_by('name'), [
- 'John Smith',
- ],
- lambda a: a.name
- )
- finally:
- CharField._unregister_lookup(Upper)
-
def test_func_transform_bilateral(self):
class UpperBilateral(Upper):
bilateral = True
diff --git a/tests/db_functions/text/__init__.py b/tests/db_functions/text/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/db_functions/text/__init__.py
diff --git a/tests/db_functions/test_chr.py b/tests/db_functions/text/test_chr.py
index 0b4b0cc77c..d48793457a 100644
--- a/tests/db_functions/test_chr.py
+++ b/tests/db_functions/text/test_chr.py
@@ -2,7 +2,7 @@ from django.db.models import IntegerField
from django.db.models.functions import Chr, Left, Ord
from django.test import TestCase
-from .models import Author
+from ..models import Author
class ChrTests(TestCase):
diff --git a/tests/db_functions/text/test_concat.py b/tests/db_functions/text/test_concat.py
new file mode 100644
index 0000000000..9850b2fd0d
--- /dev/null
+++ b/tests/db_functions/text/test_concat.py
@@ -0,0 +1,81 @@
+from unittest import skipUnless
+
+from django.db import connection
+from django.db.models import CharField, TextField, Value as V
+from django.db.models.functions import Concat, ConcatPair, Upper
+from django.test import TestCase
+from django.utils import timezone
+
+from ..models import Article, Author
+
+lorem_ipsum = """
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua."""
+
+
+class ConcatTests(TestCase):
+
+ def test_basic(self):
+ Author.objects.create(name='Jayden')
+ Author.objects.create(name='John Smith', alias='smithj', goes_by='John')
+ Author.objects.create(name='Margaret', goes_by='Maggie')
+ Author.objects.create(name='Rhonda', alias='adnohR')
+ authors = Author.objects.annotate(joined=Concat('alias', 'goes_by'))
+ self.assertQuerysetEqual(
+ authors.order_by('name'), [
+ '',
+ 'smithjJohn',
+ 'Maggie',
+ 'adnohR',
+ ],
+ lambda a: a.joined
+ )
+
+ def test_gt_two_expressions(self):
+ with self.assertRaisesMessage(ValueError, 'Concat must take at least two expressions'):
+ Author.objects.annotate(joined=Concat('alias'))
+
+ def test_many(self):
+ Author.objects.create(name='Jayden')
+ Author.objects.create(name='John Smith', alias='smithj', goes_by='John')
+ Author.objects.create(name='Margaret', goes_by='Maggie')
+ Author.objects.create(name='Rhonda', alias='adnohR')
+ authors = Author.objects.annotate(
+ joined=Concat('name', V(' ('), 'goes_by', V(')'), output_field=CharField()),
+ )
+ self.assertQuerysetEqual(
+ authors.order_by('name'), [
+ 'Jayden ()',
+ 'John Smith (John)',
+ 'Margaret (Maggie)',
+ 'Rhonda ()',
+ ],
+ lambda a: a.joined
+ )
+
+ def test_mixed_char_text(self):
+ Article.objects.create(title='The Title', text=lorem_ipsum, written=timezone.now())
+ article = Article.objects.annotate(
+ title_text=Concat('title', V(' - '), 'text', output_field=TextField()),
+ ).get(title='The Title')
+ self.assertEqual(article.title + ' - ' + article.text, article.title_text)
+ # Wrap the concat in something else to ensure that text is returned
+ # rather than bytes.
+ article = Article.objects.annotate(
+ title_text=Upper(Concat('title', V(' - '), 'text', output_field=TextField())),
+ ).get(title='The Title')
+ expected = article.title + ' - ' + article.text
+ self.assertEqual(expected.upper(), article.title_text)
+
+ @skipUnless(connection.vendor == 'sqlite', "sqlite specific implementation detail.")
+ def test_coalesce_idempotent(self):
+ pair = ConcatPair(V('a'), V('b'))
+ # Check nodes counts
+ self.assertEqual(len(list(pair.flatten())), 3)
+ self.assertEqual(len(list(pair.coalesce().flatten())), 7) # + 2 Coalesce + 2 Value()
+ self.assertEqual(len(list(pair.flatten())), 3)
+
+ def test_sql_generation_idempotency(self):
+ qs = Article.objects.annotate(description=Concat('title', V(': '), 'summary'))
+ # Multiple compilations should not alter the generated query.
+ self.assertEqual(str(qs.query), str(qs.all().query))
diff --git a/tests/db_functions/test_left.py b/tests/db_functions/text/test_left.py
index f853ac21ac..5bb3d6c4fa 100644
--- a/tests/db_functions/test_left.py
+++ b/tests/db_functions/text/test_left.py
@@ -2,7 +2,7 @@ from django.db.models import CharField, Value
from django.db.models.functions import Left, Lower
from django.test import TestCase
-from .models import Author
+from ..models import Author
class LeftTests(TestCase):
diff --git a/tests/db_functions/text/test_length.py b/tests/db_functions/text/test_length.py
new file mode 100644
index 0000000000..8fbe6887aa
--- /dev/null
+++ b/tests/db_functions/text/test_length.py
@@ -0,0 +1,48 @@
+from django.db.models import CharField
+from django.db.models.functions import Length
+from django.test import TestCase
+
+from ..models import Author
+
+
+class LengthTests(TestCase):
+
+ def test_basic(self):
+ Author.objects.create(name='John Smith', alias='smithj')
+ Author.objects.create(name='Rhonda')
+ authors = Author.objects.annotate(
+ name_length=Length('name'),
+ alias_length=Length('alias'),
+ )
+ self.assertQuerysetEqual(
+ authors.order_by('name'), [(10, 6), (6, None)],
+ lambda a: (a.name_length, a.alias_length)
+ )
+ self.assertEqual(authors.filter(alias_length__lte=Length('name')).count(), 1)
+
+ def test_ordering(self):
+ Author.objects.create(name='John Smith', alias='smithj')
+ Author.objects.create(name='John Smith', alias='smithj1')
+ Author.objects.create(name='Rhonda', alias='ronny')
+ authors = Author.objects.order_by(Length('name'), Length('alias'))
+ self.assertQuerysetEqual(
+ authors, [
+ ('Rhonda', 'ronny'),
+ ('John Smith', 'smithj'),
+ ('John Smith', 'smithj1'),
+ ],
+ lambda a: (a.name, a.alias)
+ )
+
+ def test_transform(self):
+ try:
+ CharField.register_lookup(Length)
+ Author.objects.create(name='John Smith', alias='smithj')
+ Author.objects.create(name='Rhonda')
+ authors = Author.objects.filter(name__length__gt=7)
+ self.assertQuerysetEqual(
+ authors.order_by('name'), ['John Smith'],
+ lambda a: a.name
+ )
+ finally:
+ CharField._unregister_lookup(Length)
diff --git a/tests/db_functions/text/test_lower.py b/tests/db_functions/text/test_lower.py
new file mode 100644
index 0000000000..f438682f1d
--- /dev/null
+++ b/tests/db_functions/text/test_lower.py
@@ -0,0 +1,42 @@
+from django.db.models import CharField
+from django.db.models.functions import Lower
+from django.test import TestCase
+
+from ..models import Author
+
+
+class LowerTests(TestCase):
+
+ def test_basic(self):
+ Author.objects.create(name='John Smith', alias='smithj')
+ Author.objects.create(name='Rhonda')
+ authors = Author.objects.annotate(lower_name=Lower('name'))
+ self.assertQuerysetEqual(
+ authors.order_by('name'), ['john smith', 'rhonda'],
+ lambda a: a.lower_name
+ )
+ Author.objects.update(name=Lower('name'))
+ self.assertQuerysetEqual(
+ authors.order_by('name'), [
+ ('john smith', 'john smith'),
+ ('rhonda', 'rhonda'),
+ ],
+ lambda a: (a.lower_name, a.name)
+ )
+
+ def test_num_args(self):
+ with self.assertRaisesMessage(TypeError, "'Lower' takes exactly 1 argument (2 given)"):
+ Author.objects.update(name=Lower('name', 'name'))
+
+ def test_transform(self):
+ try:
+ CharField.register_lookup(Lower)
+ Author.objects.create(name='John Smith', alias='smithj')
+ Author.objects.create(name='Rhonda')
+ authors = Author.objects.filter(name__lower__exact='john smith')
+ self.assertQuerysetEqual(
+ authors.order_by('name'), ['John Smith'],
+ lambda a: a.name
+ )
+ finally:
+ CharField._unregister_lookup(Lower)
diff --git a/tests/db_functions/test_ord.py b/tests/db_functions/text/test_ord.py
index 93ec38b076..c4ad730f6c 100644
--- a/tests/db_functions/test_ord.py
+++ b/tests/db_functions/text/test_ord.py
@@ -2,7 +2,7 @@ from django.db.models import CharField, Value
from django.db.models.functions import Left, Ord
from django.test import TestCase
-from .models import Author
+from ..models import Author
class OrdTests(TestCase):
diff --git a/tests/db_functions/test_pad.py b/tests/db_functions/text/test_pad.py
index 1c2caf06b5..2cec280b4d 100644
--- a/tests/db_functions/test_pad.py
+++ b/tests/db_functions/text/test_pad.py
@@ -2,7 +2,7 @@ from django.db.models import CharField, Value
from django.db.models.functions import Length, LPad, RPad
from django.test import TestCase
-from .models import Author
+from ..models import Author
class PadTests(TestCase):
diff --git a/tests/db_functions/test_repeat.py b/tests/db_functions/text/test_repeat.py
index d3f294c409..f45544d97e 100644
--- a/tests/db_functions/test_repeat.py
+++ b/tests/db_functions/text/test_repeat.py
@@ -2,7 +2,7 @@ from django.db.models import CharField, Value
from django.db.models.functions import Length, Repeat
from django.test import TestCase
-from .models import Author
+from ..models import Author
class RepeatTests(TestCase):
diff --git a/tests/db_functions/test_replace.py b/tests/db_functions/text/test_replace.py
index 91a1749d70..ae87781b8c 100644
--- a/tests/db_functions/test_replace.py
+++ b/tests/db_functions/text/test_replace.py
@@ -2,7 +2,7 @@ from django.db.models import F, Value
from django.db.models.functions import Concat, Replace
from django.test import TestCase
-from .models import Author
+from ..models import Author
class ReplaceTests(TestCase):
diff --git a/tests/db_functions/test_right.py b/tests/db_functions/text/test_right.py
index b75bfd5155..6dcbcc18f5 100644
--- a/tests/db_functions/test_right.py
+++ b/tests/db_functions/text/test_right.py
@@ -2,7 +2,7 @@ from django.db.models import CharField, Value
from django.db.models.functions import Lower, Right
from django.test import TestCase
-from .models import Author
+from ..models import Author
class RightTests(TestCase):
diff --git a/tests/db_functions/test_strindex.py b/tests/db_functions/text/test_strindex.py
index 32a153bcbc..1670df00fd 100644
--- a/tests/db_functions/test_strindex.py
+++ b/tests/db_functions/text/test_strindex.py
@@ -3,7 +3,7 @@ from django.db.models.functions import StrIndex
from django.test import TestCase
from django.utils import timezone
-from .models import Article, Author
+from ..models import Article, Author
class StrIndexTests(TestCase):
diff --git a/tests/db_functions/text/test_substr.py b/tests/db_functions/text/test_substr.py
new file mode 100644
index 0000000000..5cc12c0288
--- /dev/null
+++ b/tests/db_functions/text/test_substr.py
@@ -0,0 +1,53 @@
+from django.db.models import CharField, Value as V
+from django.db.models.functions import Lower, StrIndex, Substr, Upper
+from django.test import TestCase
+
+from ..models import Author
+
+
+class SubstrTests(TestCase):
+
+ def test_basic(self):
+ Author.objects.create(name='John Smith', alias='smithj')
+ Author.objects.create(name='Rhonda')
+ authors = Author.objects.annotate(name_part=Substr('name', 5, 3))
+ self.assertQuerysetEqual(
+ authors.order_by('name'), [' Sm', 'da'],
+ lambda a: a.name_part
+ )
+ authors = Author.objects.annotate(name_part=Substr('name', 2))
+ self.assertQuerysetEqual(
+ authors.order_by('name'), ['ohn Smith', 'honda'],
+ lambda a: a.name_part
+ )
+ # If alias is null, set to first 5 lower characters of the name.
+ Author.objects.filter(alias__isnull=True).update(
+ alias=Lower(Substr('name', 1, 5)),
+ )
+ self.assertQuerysetEqual(
+ authors.order_by('name'), ['smithj', 'rhond'],
+ lambda a: a.alias
+ )
+
+ def test_start(self):
+ Author.objects.create(name='John Smith', alias='smithj')
+ a = Author.objects.annotate(
+ name_part_1=Substr('name', 1),
+ name_part_2=Substr('name', 2),
+ ).get(alias='smithj')
+
+ self.assertEqual(a.name_part_1[1:], a.name_part_2)
+
+ def test_pos_gt_zero(self):
+ with self.assertRaisesMessage(ValueError, "'pos' must be greater than 0"):
+ Author.objects.annotate(raises=Substr('name', 0))
+
+ def test_expressions(self):
+ Author.objects.create(name='John Smith', alias='smithj')
+ Author.objects.create(name='Rhonda')
+ substr = Substr(Upper('name'), StrIndex('name', V('h')), 5, output_field=CharField())
+ authors = Author.objects.annotate(name_part=substr)
+ self.assertQuerysetEqual(
+ authors.order_by('name'), ['HN SM', 'HONDA'],
+ lambda a: a.name_part
+ )
diff --git a/tests/db_functions/test_trim.py b/tests/db_functions/text/test_trim.py
index 687d1522d3..3144aef028 100644
--- a/tests/db_functions/test_trim.py
+++ b/tests/db_functions/text/test_trim.py
@@ -2,7 +2,7 @@ from django.db.models import CharField
from django.db.models.functions import LTrim, RTrim, Trim
from django.test import TestCase
-from .models import Author
+from ..models import Author
class TrimTests(TestCase):
diff --git a/tests/db_functions/text/test_upper.py b/tests/db_functions/text/test_upper.py
new file mode 100644
index 0000000000..091e815d6a
--- /dev/null
+++ b/tests/db_functions/text/test_upper.py
@@ -0,0 +1,43 @@
+from django.db.models import CharField
+from django.db.models.functions import Upper
+from django.test import TestCase
+
+from ..models import Author
+
+
+class UpperTests(TestCase):
+
+ def test_basic(self):
+ Author.objects.create(name='John Smith', alias='smithj')
+ Author.objects.create(name='Rhonda')
+ authors = Author.objects.annotate(upper_name=Upper('name'))
+ self.assertQuerysetEqual(
+ authors.order_by('name'), [
+ 'JOHN SMITH',
+ 'RHONDA',
+ ],
+ lambda a: a.upper_name
+ )
+ Author.objects.update(name=Upper('name'))
+ self.assertQuerysetEqual(
+ authors.order_by('name'), [
+ ('JOHN SMITH', 'JOHN SMITH'),
+ ('RHONDA', 'RHONDA'),
+ ],
+ lambda a: (a.upper_name, a.name)
+ )
+
+ def test_transform(self):
+ try:
+ CharField.register_lookup(Upper)
+ Author.objects.create(name='John Smith', alias='smithj')
+ Author.objects.create(name='Rhonda')
+ authors = Author.objects.filter(name__upper__exact='JOHN SMITH')
+ self.assertQuerysetEqual(
+ authors.order_by('name'), [
+ 'John Smith',
+ ],
+ lambda a: a.name
+ )
+ finally:
+ CharField._unregister_lookup(Upper)