1
0
mirror of https://github.com/django/django.git synced 2025-01-03 15:06:09 +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) # Literal "%" should be escaped in a way that is not a considered a
Author = to_state.apps.get_model(app_label, "Author") # wildcard.
with self.assertRaises(IntegrityError), transaction.atomic(): (models.Q(rebate__endswith="%"), {"rebate": "10%"}, {"rebate": "10$"}),
Author.objects.create(name="Artur") # Right-hand-side baked "%" literals should not be used for
# Literal "%" should be escaped in a way that is not a considered a # parameters interpolation.
# wildcard. (
check = models.Q(rebate__endswith="%") ~models.Q(surname__startswith=models.F("name")),
constraint = models.CheckConstraint(check=check, name="rebate_constraint") {"name": "Albert"},
operation = migrations.AddConstraint("Author", constraint) {"name": "Albert", "surname": "Alberto"},
from_state = to_state ),
to_state = from_state.clone() ]
operation.state_forwards(app_label, to_state) for check, valid, invalid in checks:
Author = to_state.apps.get_model(app_label, "Author") with self.subTest(check=check, valid=valid, invalid=invalid):
with connection.schema_editor() as editor: constraint = models.CheckConstraint(check=check, name="constraint")
operation.database_forwards(app_label, editor, from_state, to_state) operation = migrations.AddConstraint("Author", constraint)
Author = to_state.apps.get_model(app_label, "Author") to_state = from_state.clone()
with self.assertRaises(IntegrityError), transaction.atomic(): operation.state_forwards(app_label, to_state)
Author.objects.create(name="Albert", rebate="10$") with connection.schema_editor() as editor:
author = Author.objects.create(name="Albert", rebate="10%") operation.database_forwards(app_label, editor, from_state, to_state)
self.assertEqual(Author.objects.get(), author) Author = to_state.apps.get_model(app_label, "Author")
# Right-hand-side baked "%" literals should not be used for parameters try:
# interpolation. with transaction.atomic():
check = ~models.Q(surname__startswith=models.F("name")) Author.objects.create(**valid).delete()
constraint = models.CheckConstraint(check=check, name="name_constraint_rhs") with self.assertRaises(IntegrityError), transaction.atomic():
operation = migrations.AddConstraint("Author", constraint) Author.objects.create(**invalid)
from_state = to_state finally:
to_state = from_state.clone() with connection.schema_editor() as editor:
operation.state_forwards(app_label, to_state) operation.database_backwards(
with connection.schema_editor() as editor: 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")
with self.assertRaises(IntegrityError), transaction.atomic():
Author.objects.create(name="Albert", surname="Alberto")
@skipUnlessDBFeature("supports_table_check_constraints") @skipUnlessDBFeature("supports_table_check_constraints")
def test_add_or_constraint(self): def test_add_or_constraint(self):