diff options
| author | Srinivas Reddy Thatiparthy <thatiparthysreenivas@gmail.com> | 2018-07-01 02:19:20 +0530 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2018-09-10 15:08:55 -0400 |
| commit | 34d6bceec46c5d4234c156ed682573d2e5de474a (patch) | |
| tree | 7239bb1c2d435f9ddd4caf2e565d0d673f6e9735 /tests/db_functions | |
| parent | 76dfa834e7ceeca97cd8e3cfa86651a955aa3f0c (diff) | |
Fixed #29500 -- Fixed SQLite function crashes on null values.
Co-authored-by: Srinivas Reddy Thatiparthy <thatiparthysreenivas@gmail.com>
Co-authored-by: Nick Pope <nick.pope@flightdataservices.com>
Diffstat (limited to 'tests/db_functions')
23 files changed, 154 insertions, 5 deletions
diff --git a/tests/db_functions/datetime/test_extract_trunc.py b/tests/db_functions/datetime/test_extract_trunc.py index 99d33b252c..065a06f4be 100644 --- a/tests/db_functions/datetime/test_extract_trunc.py +++ b/tests/db_functions/datetime/test_extract_trunc.py @@ -66,11 +66,14 @@ class DateFunctionTests(TestCase): def create_model(self, start_datetime, end_datetime): return DTModel.objects.create( - name=start_datetime.isoformat(), - start_datetime=start_datetime, end_datetime=end_datetime, - start_date=start_datetime.date(), end_date=end_datetime.date(), - start_time=start_datetime.time(), end_time=end_datetime.time(), - duration=(end_datetime - start_datetime), + name=start_datetime.isoformat() if start_datetime else 'None', + start_datetime=start_datetime, + end_datetime=end_datetime, + start_date=start_datetime.date() if start_datetime else None, + end_date=end_datetime.date() if end_datetime else None, + start_time=start_datetime.time() if start_datetime else None, + end_time=end_datetime.time() if end_datetime else None, + duration=(end_datetime - start_datetime) if start_datetime and end_datetime else None, ) def test_extract_year_exact_lookup(self): @@ -215,6 +218,12 @@ class DateFunctionTests(TestCase): self.assertEqual(DTModel.objects.filter(start_date__month=Extract('start_date', 'month')).count(), 2) self.assertEqual(DTModel.objects.filter(start_time__hour=Extract('start_time', 'hour')).count(), 2) + def test_extract_none(self): + self.create_model(None, None) + for t in (Extract('start_datetime', 'year'), Extract('start_date', 'year'), Extract('start_time', 'hour')): + with self.subTest(t): + self.assertIsNone(DTModel.objects.annotate(extracted=t).first().extracted) + @skipUnlessDBFeature('has_native_duration_field') def test_extract_duration(self): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) @@ -608,6 +617,12 @@ class DateFunctionTests(TestCase): qs = DTModel.objects.filter(start_datetime__date=Trunc('start_datetime', 'day', output_field=DateField())) self.assertEqual(qs.count(), 2) + def test_trunc_none(self): + self.create_model(None, None) + for t in (Trunc('start_datetime', 'year'), Trunc('start_date', 'year'), Trunc('start_time', 'hour')): + with self.subTest(t): + self.assertIsNone(DTModel.objects.annotate(truncated=t).first().truncated) + def test_trunc_year_func(self): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = truncate_to(datetime(2016, 6, 15, 14, 10, 50, 123), 'year') @@ -761,6 +776,10 @@ class DateFunctionTests(TestCase): with self.assertRaisesMessage(ValueError, "Cannot truncate TimeField 'start_time' to DateField"): list(DTModel.objects.annotate(truncated=TruncDate('start_time', output_field=TimeField()))) + def test_trunc_date_none(self): + self.create_model(None, None) + self.assertIsNone(DTModel.objects.annotate(truncated=TruncDate('start_datetime')).first().truncated) + def test_trunc_time_func(self): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = datetime(2016, 6, 15, 14, 10, 50, 123) @@ -785,6 +804,10 @@ class DateFunctionTests(TestCase): with self.assertRaisesMessage(ValueError, "Cannot truncate DateField 'start_date' to TimeField"): list(DTModel.objects.annotate(truncated=TruncTime('start_date', output_field=DateField()))) + def test_trunc_time_none(self): + self.create_model(None, None) + self.assertIsNone(DTModel.objects.annotate(truncated=TruncTime('start_datetime')).first().truncated) + def test_trunc_day_func(self): start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321) end_datetime = truncate_to(datetime(2016, 6, 15, 14, 10, 50, 123), 'day') diff --git a/tests/db_functions/math/test_abs.py b/tests/db_functions/math/test_abs.py index 484cd2e306..b87f6844bc 100644 --- a/tests/db_functions/math/test_abs.py +++ b/tests/db_functions/math/test_abs.py @@ -10,6 +10,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class AbsTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_abs=Abs('normal')).first() + self.assertIsNone(obj.null_abs) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-0.8'), n2=Decimal('1.2')) obj = DecimalModel.objects.annotate(n1_abs=Abs('n1'), n2_abs=Abs('n2')).first() diff --git a/tests/db_functions/math/test_acos.py b/tests/db_functions/math/test_acos.py index a9ba079e4f..04fdf2cf40 100644 --- a/tests/db_functions/math/test_acos.py +++ b/tests/db_functions/math/test_acos.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class ACosTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_acos=ACos('normal')).first() + self.assertIsNone(obj.null_acos) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-0.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_acos=ACos('n1'), n2_acos=ACos('n2')).first() diff --git a/tests/db_functions/math/test_asin.py b/tests/db_functions/math/test_asin.py index dc135a6786..a9074e4305 100644 --- a/tests/db_functions/math/test_asin.py +++ b/tests/db_functions/math/test_asin.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class ASinTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_asin=ASin('normal')).first() + self.assertIsNone(obj.null_asin) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('0.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_asin=ASin('n1'), n2_asin=ASin('n2')).first() diff --git a/tests/db_functions/math/test_atan.py b/tests/db_functions/math/test_atan.py index 36c07ae306..fbeeded48c 100644 --- a/tests/db_functions/math/test_atan.py +++ b/tests/db_functions/math/test_atan.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class ATanTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_atan=ATan('normal')).first() + self.assertIsNone(obj.null_atan) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_atan=ATan('n1'), n2_atan=ATan('n2')).first() diff --git a/tests/db_functions/math/test_atan2.py b/tests/db_functions/math/test_atan2.py index 195892dfdd..ca12e64479 100644 --- a/tests/db_functions/math/test_atan2.py +++ b/tests/db_functions/math/test_atan2.py @@ -9,6 +9,15 @@ from ..models import DecimalModel, FloatModel, IntegerModel class ATan2Tests(TestCase): + def test_null(self): + IntegerModel.objects.create(big=100) + obj = IntegerModel.objects.annotate( + null_atan2_sn=ATan2('small', 'normal'), + null_atan2_nb=ATan2('normal', 'big'), + ).first() + self.assertIsNone(obj.null_atan2_sn) + self.assertIsNone(obj.null_atan2_nb) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-9.9'), n2=Decimal('4.6')) obj = DecimalModel.objects.annotate(n_atan2=ATan2('n1', 'n2')).first() diff --git a/tests/db_functions/math/test_ceil.py b/tests/db_functions/math/test_ceil.py index a62c33a19f..af4ee44e31 100644 --- a/tests/db_functions/math/test_ceil.py +++ b/tests/db_functions/math/test_ceil.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class CeilTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_ceil=Ceil('normal')).first() + self.assertIsNone(obj.null_ceil) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_ceil=Ceil('n1'), n2_ceil=Ceil('n2')).first() diff --git a/tests/db_functions/math/test_cos.py b/tests/db_functions/math/test_cos.py index 15975e247d..99cf96620e 100644 --- a/tests/db_functions/math/test_cos.py +++ b/tests/db_functions/math/test_cos.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class CosTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_cos=Cos('normal')).first() + self.assertIsNone(obj.null_cos) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_cos=Cos('n1'), n2_cos=Cos('n2')).first() diff --git a/tests/db_functions/math/test_cot.py b/tests/db_functions/math/test_cot.py index 0407f3b45d..5af0403221 100644 --- a/tests/db_functions/math/test_cot.py +++ b/tests/db_functions/math/test_cot.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class CotTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_cot=Cot('normal')).first() + self.assertIsNone(obj.null_cot) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_cot=Cot('n1'), n2_cot=Cot('n2')).first() diff --git a/tests/db_functions/math/test_degrees.py b/tests/db_functions/math/test_degrees.py index e5a551992f..a474d276a5 100644 --- a/tests/db_functions/math/test_degrees.py +++ b/tests/db_functions/math/test_degrees.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class DegreesTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_degrees=Degrees('normal')).first() + self.assertIsNone(obj.null_degrees) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_degrees=Degrees('n1'), n2_degrees=Degrees('n2')).first() diff --git a/tests/db_functions/math/test_exp.py b/tests/db_functions/math/test_exp.py index 0981d4fce3..fac2f6c08d 100644 --- a/tests/db_functions/math/test_exp.py +++ b/tests/db_functions/math/test_exp.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class ExpTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_exp=Exp('normal')).first() + self.assertIsNone(obj.null_exp) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_exp=Exp('n1'), n2_exp=Exp('n2')).first() diff --git a/tests/db_functions/math/test_floor.py b/tests/db_functions/math/test_floor.py index ee567cfea6..0c193ef1af 100644 --- a/tests/db_functions/math/test_floor.py +++ b/tests/db_functions/math/test_floor.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class FloorTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_floor=Floor('normal')).first() + self.assertIsNone(obj.null_floor) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_floor=Floor('n1'), n2_floor=Floor('n2')).first() diff --git a/tests/db_functions/math/test_ln.py b/tests/db_functions/math/test_ln.py index 96d4599bb3..3c690d56cc 100644 --- a/tests/db_functions/math/test_ln.py +++ b/tests/db_functions/math/test_ln.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class LnTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_ln=Ln('normal')).first() + self.assertIsNone(obj.null_ln) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_ln=Ln('n1'), n2_ln=Ln('n2')).first() diff --git a/tests/db_functions/math/test_log.py b/tests/db_functions/math/test_log.py index 02cbe084d3..469bb7cd3a 100644 --- a/tests/db_functions/math/test_log.py +++ b/tests/db_functions/math/test_log.py @@ -9,6 +9,15 @@ from ..models import DecimalModel, FloatModel, IntegerModel class LogTests(TestCase): + def test_null(self): + IntegerModel.objects.create(big=100) + obj = IntegerModel.objects.annotate( + null_log_small=Log('small', 'normal'), + null_log_normal=Log('normal', 'big'), + ).first() + self.assertIsNone(obj.null_log_small) + self.assertIsNone(obj.null_log_normal) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('12.9'), n2=Decimal('3.6')) obj = DecimalModel.objects.annotate(n_log=Log('n1', 'n2')).first() diff --git a/tests/db_functions/math/test_mod.py b/tests/db_functions/math/test_mod.py index 0e90175ddc..dc363432b7 100644 --- a/tests/db_functions/math/test_mod.py +++ b/tests/db_functions/math/test_mod.py @@ -9,6 +9,15 @@ from ..models import DecimalModel, FloatModel, IntegerModel class ModTests(TestCase): + def test_null(self): + IntegerModel.objects.create(big=100) + obj = IntegerModel.objects.annotate( + null_mod_small=Mod('small', 'normal'), + null_mod_normal=Mod('normal', 'big'), + ).first() + self.assertIsNone(obj.null_mod_small) + self.assertIsNone(obj.null_mod_normal) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-9.9'), n2=Decimal('4.6')) obj = DecimalModel.objects.annotate(n_mod=Mod('n1', 'n2')).first() diff --git a/tests/db_functions/math/test_power.py b/tests/db_functions/math/test_power.py index 01ca2b34d9..a2d6156e3d 100644 --- a/tests/db_functions/math/test_power.py +++ b/tests/db_functions/math/test_power.py @@ -8,6 +8,15 @@ from ..models import DecimalModel, FloatModel, IntegerModel class PowerTests(TestCase): + def test_null(self): + IntegerModel.objects.create(big=100) + obj = IntegerModel.objects.annotate( + null_power_small=Power('small', 'normal'), + null_power_normal=Power('normal', 'big'), + ).first() + self.assertIsNone(obj.null_power_small) + self.assertIsNone(obj.null_power_normal) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('1.0'), n2=Decimal('-0.6')) obj = DecimalModel.objects.annotate(n_power=Power('n1', 'n2')).first() diff --git a/tests/db_functions/math/test_radians.py b/tests/db_functions/math/test_radians.py index 873659e7ad..3c257bb278 100644 --- a/tests/db_functions/math/test_radians.py +++ b/tests/db_functions/math/test_radians.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class RadiansTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_radians=Radians('normal')).first() + self.assertIsNone(obj.null_radians) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_radians=Radians('n1'), n2_radians=Radians('n2')).first() diff --git a/tests/db_functions/math/test_round.py b/tests/db_functions/math/test_round.py index d242f2de0f..4c2634c3c2 100644 --- a/tests/db_functions/math/test_round.py +++ b/tests/db_functions/math/test_round.py @@ -10,6 +10,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class RoundTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_round=Round('normal')).first() + self.assertIsNone(obj.null_round) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_round=Round('n1'), n2_round=Round('n2')).first() diff --git a/tests/db_functions/math/test_sin.py b/tests/db_functions/math/test_sin.py index 0f7e0c7c0b..f2e2edd4da 100644 --- a/tests/db_functions/math/test_sin.py +++ b/tests/db_functions/math/test_sin.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class SinTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_sin=Sin('normal')).first() + self.assertIsNone(obj.null_sin) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_sin=Sin('n1'), n2_sin=Sin('n2')).first() diff --git a/tests/db_functions/math/test_sqrt.py b/tests/db_functions/math/test_sqrt.py index 81f13361e1..0e6238a141 100644 --- a/tests/db_functions/math/test_sqrt.py +++ b/tests/db_functions/math/test_sqrt.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class SqrtTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_sqrt=Sqrt('normal')).first() + self.assertIsNone(obj.null_sqrt) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_sqrt=Sqrt('n1'), n2_sqrt=Sqrt('n2')).first() diff --git a/tests/db_functions/math/test_tan.py b/tests/db_functions/math/test_tan.py index 82dcec94fc..6db760725b 100644 --- a/tests/db_functions/math/test_tan.py +++ b/tests/db_functions/math/test_tan.py @@ -11,6 +11,11 @@ from ..models import DecimalModel, FloatModel, IntegerModel class TanTests(TestCase): + def test_null(self): + IntegerModel.objects.create() + obj = IntegerModel.objects.annotate(null_tan=Tan('normal')).first() + self.assertIsNone(obj.null_tan) + def test_decimal(self): DecimalModel.objects.create(n1=Decimal('-12.9'), n2=Decimal('0.6')) obj = DecimalModel.objects.annotate(n1_tan=Tan('n1'), n2_tan=Tan('n2')).first() diff --git a/tests/db_functions/text/test_pad.py b/tests/db_functions/text/test_pad.py index 2cec280b4d..88309e5641 100644 --- a/tests/db_functions/text/test_pad.py +++ b/tests/db_functions/text/test_pad.py @@ -1,3 +1,4 @@ +from django.db import connection from django.db.models import CharField, Value from django.db.models.functions import Length, LPad, RPad from django.test import TestCase @@ -8,6 +9,7 @@ from ..models import Author class PadTests(TestCase): def test_pad(self): Author.objects.create(name='John', alias='j') + none_value = '' if connection.features.interprets_empty_strings_as_nulls else None tests = ( (LPad('name', 7, Value('xy')), 'xyxJohn'), (RPad('name', 7, Value('xy')), 'Johnxyx'), @@ -21,6 +23,10 @@ class PadTests(TestCase): (RPad('name', 2), 'Jo'), (LPad('name', 0), ''), (RPad('name', 0), ''), + (LPad('name', None), none_value), + (RPad('name', None), none_value), + (LPad('goes_by', 1), none_value), + (RPad('goes_by', 1), none_value), ) for function, padded_name in tests: with self.subTest(function=function): diff --git a/tests/db_functions/text/test_repeat.py b/tests/db_functions/text/test_repeat.py index f45544d97e..d302e6da28 100644 --- a/tests/db_functions/text/test_repeat.py +++ b/tests/db_functions/text/test_repeat.py @@ -1,3 +1,4 @@ +from django.db import connection from django.db.models import CharField, Value from django.db.models.functions import Length, Repeat from django.test import TestCase @@ -8,11 +9,14 @@ from ..models import Author class RepeatTests(TestCase): def test_basic(self): Author.objects.create(name='John', alias='xyz') + none_value = '' if connection.features.interprets_empty_strings_as_nulls else None tests = ( (Repeat('name', 0), ''), (Repeat('name', 2), 'JohnJohn'), (Repeat('name', Length('alias'), output_field=CharField()), 'JohnJohnJohn'), (Repeat(Value('x'), 3, output_field=CharField()), 'xxx'), + (Repeat('name', None), none_value), + (Repeat('goes_by', 1), none_value), ) for function, repeated_text in tests: with self.subTest(function=function): |
