145 lines
5.0 KiB
Python
145 lines
5.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from odoo.tests.common import TransactionCase
|
|
from odoo.exceptions import ValidationError
|
|
from psycopg2 import IntegrityError
|
|
|
|
|
|
class TestModelConstraints(TransactionCase):
|
|
"""Test cases for model constraints and validation."""
|
|
|
|
def setUp(self):
|
|
"""Set up test data."""
|
|
super().setUp()
|
|
|
|
self.Model = self.env['model.name']
|
|
|
|
# Set up minimal test data
|
|
self.partner = self.env['res.partner'].search([], limit=1)
|
|
if not self.partner:
|
|
self.skipTest("No partner available for testing")
|
|
|
|
def test_01_python_constraint_positive_value(self):
|
|
"""Test Python constraint for positive values."""
|
|
record = self.Model.create({
|
|
'name': 'Test Record',
|
|
'partner_id': self.partner.id,
|
|
'amount': 100.0,
|
|
})
|
|
|
|
# Test valid positive value
|
|
record.write({'amount': 50.0})
|
|
self.assertEqual(record.amount, 50.0)
|
|
|
|
# Test that negative value raises ValidationError
|
|
with self.assertRaises(ValidationError) as context:
|
|
record.write({'amount': -10.0})
|
|
|
|
self.assertIn('must be positive', str(context.exception).lower())
|
|
|
|
def test_02_sql_constraint_unique(self):
|
|
"""Test SQL constraint for unique values."""
|
|
# Create first record
|
|
self.Model.create({
|
|
'name': 'Test Record',
|
|
'code': 'UNIQUE001',
|
|
'partner_id': self.partner.id,
|
|
})
|
|
|
|
# Try to create duplicate
|
|
with self.assertRaises(IntegrityError):
|
|
with self.cr.savepoint():
|
|
self.Model.create({
|
|
'name': 'Test Record 2',
|
|
'code': 'UNIQUE001', # Duplicate code
|
|
'partner_id': self.partner.id,
|
|
})
|
|
|
|
def test_03_required_field_validation(self):
|
|
"""Test that required fields are enforced."""
|
|
# Test missing required field raises ValidationError
|
|
with self.assertRaises(ValidationError):
|
|
self.Model.create({
|
|
'name': 'Test Record',
|
|
# Missing required 'partner_id'
|
|
})
|
|
|
|
def test_04_field_domain_constraint(self):
|
|
"""Test field domain constraints."""
|
|
record = self.Model.create({
|
|
'name': 'Test Record',
|
|
'partner_id': self.partner.id,
|
|
'state': 'draft',
|
|
})
|
|
|
|
# Test valid state
|
|
record.write({'state': 'confirmed'})
|
|
self.assertEqual(record.state, 'confirmed')
|
|
|
|
# Test invalid state raises ValidationError
|
|
with self.assertRaises(ValidationError):
|
|
record.write({'state': 'invalid_state'})
|
|
|
|
def test_05_dependent_field_constraint(self):
|
|
"""Test constraints that depend on multiple fields."""
|
|
# Test that start_date must be before end_date
|
|
with self.assertRaises(ValidationError) as context:
|
|
self.Model.create({
|
|
'name': 'Test Record',
|
|
'partner_id': self.partner.id,
|
|
'start_date': '2024-12-31',
|
|
'end_date': '2024-01-01', # End before start
|
|
})
|
|
|
|
self.assertIn('end date', str(context.exception).lower())
|
|
self.assertIn('start date', str(context.exception).lower())
|
|
|
|
def test_06_conditional_constraint(self):
|
|
"""Test constraints that apply conditionally."""
|
|
# Create record in state where constraint doesn't apply
|
|
record = self.Model.create({
|
|
'name': 'Test Record',
|
|
'partner_id': self.partner.id,
|
|
'state': 'draft',
|
|
'approval_required': False,
|
|
})
|
|
|
|
# Confirm - now constraint should apply
|
|
record.write({'state': 'confirmed', 'approval_required': True})
|
|
|
|
# Test that missing approval raises error
|
|
with self.assertRaises(ValidationError) as context:
|
|
record.write({'approved_by': False}) # Clear approval
|
|
|
|
self.assertIn('approval', str(context.exception).lower())
|
|
|
|
def test_07_cascading_constraint(self):
|
|
"""Test constraints that cascade to related records."""
|
|
parent = self.Model.create({
|
|
'name': 'Parent Record',
|
|
'partner_id': self.partner.id,
|
|
})
|
|
|
|
child = self.Model.create({
|
|
'name': 'Child Record',
|
|
'parent_id': parent.id,
|
|
'partner_id': self.partner.id,
|
|
})
|
|
|
|
# Test that deleting parent with children raises error
|
|
with self.assertRaises(ValidationError) as context:
|
|
parent.unlink()
|
|
|
|
self.assertIn('child', str(context.exception).lower())
|
|
|
|
def test_08_constraint_bypass_with_context(self):
|
|
"""Test bypassing constraints with context (if applicable)."""
|
|
# Some constraints can be bypassed with special context
|
|
record = self.Model.with_context(skip_validation=True).create({
|
|
'name': 'Test Record',
|
|
'partner_id': self.partner.id,
|
|
'amount': -100.0, # Normally not allowed
|
|
})
|
|
|
|
self.assertEqual(record.amount, -100.0)
|