1
0
mirror of https://github.com/django/django.git synced 2025-01-05 07:55:47 +00:00

Refs #34553 -- Split constraint escaping test in subtests.

This ensures that constraint violations are tested in isolation from
each other as an IntegrityError only ensures a least one constraint is
violated.

For example, the assertion added in 42e8cf4 break both the
name_constraint_rhs and the rebate_constraint constraints and thus
doesn't constitute a proper regression test. Refs #32369.
This commit is contained in:
Simon Charette 2023-05-09 22:18:05 -04:00 committed by Mariusz Felisiak
parent 6e32d1fa1d
commit e0f8104a96

View File

@ -3652,47 +3652,44 @@ class OperationTests(OperationTestBase):
), ),
] ]
from_state = self.apply_operations(app_label, ProjectState(), operations) from_state = self.apply_operations(app_label, ProjectState(), operations)
# "%" generated in startswith lookup should be escaped in a way that is checks = [
# considered a leading wildcard. # "%" generated in startswith lookup should be escaped in a way
check = models.Q(name__startswith="Albert") # that is considered a leading wildcard.
constraint = models.CheckConstraint(check=check, name="name_constraint") (
operation = migrations.AddConstraint("Author", constraint) models.Q(name__startswith="Albert"),
to_state = from_state.clone() {"name": "Alberta"},
operation.state_forwards(app_label, to_state) {"name": "Artur"},
with connection.schema_editor() as editor: ),
operation.database_forwards(app_label, editor, from_state, to_state)
Author = to_state.apps.get_model(app_label, "Author")
with self.assertRaises(IntegrityError), transaction.atomic():
Author.objects.create(name="Artur")
# Literal "%" should be escaped in a way that is not a considered a # Literal "%" should be escaped in a way that is not a considered a
# wildcard. # wildcard.
check = models.Q(rebate__endswith="%") (models.Q(rebate__endswith="%"), {"rebate": "10%"}, {"rebate": "10$"}),
constraint = models.CheckConstraint(check=check, name="rebate_constraint") # Right-hand-side baked "%" literals should not be used for
# parameters interpolation.
(
~models.Q(surname__startswith=models.F("name")),
{"name": "Albert"},
{"name": "Albert", "surname": "Alberto"},
),
]
for check, valid, invalid in checks:
with self.subTest(check=check, valid=valid, invalid=invalid):
constraint = models.CheckConstraint(check=check, name="constraint")
operation = migrations.AddConstraint("Author", constraint) operation = migrations.AddConstraint("Author", constraint)
from_state = to_state
to_state = from_state.clone()
operation.state_forwards(app_label, to_state)
Author = to_state.apps.get_model(app_label, "Author")
with connection.schema_editor() as editor:
operation.database_forwards(app_label, editor, from_state, to_state)
Author = to_state.apps.get_model(app_label, "Author")
with self.assertRaises(IntegrityError), transaction.atomic():
Author.objects.create(name="Albert", rebate="10$")
author = Author.objects.create(name="Albert", rebate="10%")
self.assertEqual(Author.objects.get(), author)
# Right-hand-side baked "%" literals should not be used for parameters
# interpolation.
check = ~models.Q(surname__startswith=models.F("name"))
constraint = models.CheckConstraint(check=check, name="name_constraint_rhs")
operation = migrations.AddConstraint("Author", constraint)
from_state = to_state
to_state = from_state.clone() to_state = from_state.clone()
operation.state_forwards(app_label, to_state) operation.state_forwards(app_label, to_state)
with connection.schema_editor() as editor: with connection.schema_editor() as editor:
operation.database_forwards(app_label, editor, from_state, to_state) operation.database_forwards(app_label, editor, from_state, to_state)
Author = to_state.apps.get_model(app_label, "Author") Author = to_state.apps.get_model(app_label, "Author")
try:
with transaction.atomic():
Author.objects.create(**valid).delete()
with self.assertRaises(IntegrityError), transaction.atomic(): with self.assertRaises(IntegrityError), transaction.atomic():
Author.objects.create(name="Albert", surname="Alberto") Author.objects.create(**invalid)
finally:
with connection.schema_editor() as editor:
operation.database_backwards(
app_label, editor, from_state, to_state
)
@skipUnlessDBFeature("supports_table_check_constraints") @skipUnlessDBFeature("supports_table_check_constraints")
def test_add_or_constraint(self): def test_add_or_constraint(self):