From e0f8104a968d316925f736e961a63bef73a686b4 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Tue, 9 May 2023 22:18:05 -0400 Subject: 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. --- tests/migrations/test_operations.py | 79 ++++++++++++++++++------------------- 1 file 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): -- cgit v1.2.1