summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2023-05-09 22:18:05 -0400
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-05-10 17:25:57 +0200
commite0f8104a968d316925f736e961a63bef73a686b4 (patch)
tree94a8288558dcf8c59b34e7e833e7e2dbae67789d
parent6e32d1fa1dafd0c9cd9f93997ecebb26cd9a1b62 (diff)
downloaddjango-e0f8104a968d316925f736e961a63bef73a686b4.tar.gz
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.
-rw-r--r--tests/migrations/test_operations.py79
1 files changed, 38 insertions, 41 deletions
diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py
index df12ff428d..0135dbc538 100644
--- a/tests/migrations/test_operations.py
+++ b/tests/migrations/test_operations.py
@@ -3652,47 +3652,44 @@ class OperationTests(OperationTestBase):
),
]
from_state = self.apply_operations(app_label, ProjectState(), operations)
- # "%" generated in startswith lookup should be escaped in a way that is
- # considered a leading wildcard.
- check = models.Q(name__startswith="Albert")
- constraint = models.CheckConstraint(check=check, name="name_constraint")
- operation = migrations.AddConstraint("Author", constraint)
- to_state = from_state.clone()
- operation.state_forwards(app_label, to_state)
- 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
- # wildcard.
- check = models.Q(rebate__endswith="%")
- constraint = models.CheckConstraint(check=check, name="rebate_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()
- operation.state_forwards(app_label, to_state)
- 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", surname="Alberto")
+ checks = [
+ # "%" generated in startswith lookup should be escaped in a way
+ # that is considered a leading wildcard.
+ (
+ models.Q(name__startswith="Albert"),
+ {"name": "Alberta"},
+ {"name": "Artur"},
+ ),
+ # Literal "%" should be escaped in a way that is not a considered a
+ # wildcard.
+ (models.Q(rebate__endswith="%"), {"rebate": "10%"}, {"rebate": "10$"}),
+ # 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)
+ to_state = from_state.clone()
+ operation.state_forwards(app_label, to_state)
+ 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")
+ try:
+ with transaction.atomic():
+ Author.objects.create(**valid).delete()
+ with self.assertRaises(IntegrityError), transaction.atomic():
+ 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")
def test_add_or_constraint(self):