from django.core.exceptions import ValidationError from django.db import IntegrityError, connection, models from django.db.models.constraints import BaseConstraint from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature from .models import Product def get_constraints(table): with connection.cursor() as cursor: return connection.introspection.get_constraints(cursor, table) class BaseConstraintTests(SimpleTestCase): def test_constraint_sql(self): c = BaseConstraint('name') msg = 'This method must be implemented by a subclass.' with self.assertRaisesMessage(NotImplementedError, msg): c.constraint_sql(None, None) def test_create_sql(self): c = BaseConstraint('name') msg = 'This method must be implemented by a subclass.' with self.assertRaisesMessage(NotImplementedError, msg): c.create_sql(None, None) def test_remove_sql(self): c = BaseConstraint('name') msg = 'This method must be implemented by a subclass.' with self.assertRaisesMessage(NotImplementedError, msg): c.remove_sql(None, None) class CheckConstraintTests(TestCase): def test_repr(self): check = models.Q(price__gt=models.F('discounted_price')) name = 'price_gt_discounted_price' constraint = models.CheckConstraint(check=check, name=name) self.assertEqual( repr(constraint), "".format(check, name), ) def test_deconstruction(self): check = models.Q(price__gt=models.F('discounted_price')) name = 'price_gt_discounted_price' constraint = models.CheckConstraint(check=check, name=name) path, args, kwargs = constraint.deconstruct() self.assertEqual(path, 'django.db.models.CheckConstraint') self.assertEqual(args, ()) self.assertEqual(kwargs, {'check': check, 'name': name}) @skipUnlessDBFeature('supports_table_check_constraints') def test_database_constraint(self): Product.objects.create(name='Valid', price=10, discounted_price=5) with self.assertRaises(IntegrityError): Product.objects.create(name='Invalid', price=10, discounted_price=20) @skipUnlessDBFeature('supports_table_check_constraints') def test_name(self): constraints = get_constraints(Product._meta.db_table) expected_name = 'price_gt_discounted_price' self.assertIn(expected_name, constraints) class UniqueConstraintTests(TestCase): @classmethod def setUpTestData(cls): cls.p1 = Product.objects.create(name='p1') def test_repr(self): fields = ['foo', 'bar'] name = 'unique_fields' constraint = models.UniqueConstraint(fields=fields, name=name) self.assertEqual( repr(constraint), "", ) def test_deconstruction(self): fields = ['foo', 'bar'] name = 'unique_fields' check = models.UniqueConstraint(fields=fields, name=name) path, args, kwargs = check.deconstruct() self.assertEqual(path, 'django.db.models.UniqueConstraint') self.assertEqual(args, ()) self.assertEqual(kwargs, {'fields': tuple(fields), 'name': name}) def test_database_constraint(self): with self.assertRaises(IntegrityError): Product.objects.create(name=self.p1.name) def test_model_validation(self): with self.assertRaisesMessage(ValidationError, 'Product with this Name already exists.'): Product(name=self.p1.name).validate_unique() def test_name(self): constraints = get_constraints(Product._meta.db_table) expected_name = 'unique_name' self.assertIn(expected_name, constraints)