helpdesk_rating_five_stars/tests/test_api_compatibility.py
2025-11-26 10:39:26 +07:00

386 lines
15 KiB
Python

# -*- coding: utf-8 -*-
from odoo.tests.common import TransactionCase
from hypothesis import given, strategies as st, settings, assume
import inspect
class TestAPICompatibility(TransactionCase):
"""Test cases for API compatibility with standard Odoo rating system"""
def setUp(self):
super(TestAPICompatibility, self).setUp()
self.Rating = self.env['rating.rating']
self.Partner = self.env['res.partner']
self.User = self.env['res.users']
self.HelpdeskTicket = self.env['helpdesk.ticket']
self.HelpdeskTeam = self.env['helpdesk.team']
# Create test data
self.test_partner = self.Partner.create({
'name': 'Test Customer',
'email': 'test@example.com',
})
self.test_user = self.User.create({
'name': 'Test User',
'login': 'testuser_api',
'email': 'testuser_api@example.com',
})
# Create helpdesk team and ticket for realistic testing
self.helpdesk_team = self.HelpdeskTeam.create({
'name': 'Test Support Team',
'use_rating': True,
})
self.test_ticket = self.HelpdeskTicket.create({
'name': 'Test Ticket for API',
'team_id': self.helpdesk_team.id,
'partner_id': self.test_partner.id,
})
def _create_rating(self, rating_value, **kwargs):
"""Helper method to create a rating with given value"""
# Get the ir.model record for helpdesk.ticket
res_model_id = self.env['ir.model'].search([('model', '=', 'helpdesk.ticket')], limit=1)
vals = {
'rating': rating_value,
'partner_id': self.test_partner.id,
'rated_partner_id': self.test_user.partner_id.id,
'res_model_id': res_model_id.id,
'res_id': self.test_ticket.id,
}
vals.update(kwargs)
return self.Rating.create(vals)
# Feature: helpdesk-rating-five-stars, Property 14: API compatibility maintained
@given(rating_value=st.floats(min_value=1.0, max_value=5.0, allow_nan=False, allow_infinity=False))
@settings(max_examples=100, deadline=None)
def test_property_create_method_signature(self, rating_value):
"""
Property 14: API compatibility maintained - create method
For any overridden rating method, the method signature and return type
should remain compatible with the standard Odoo rating API.
This test verifies that the create() method:
- Accepts the same parameters as the base model
- Returns a rating.rating recordset
- Properly stores the rating value
Validates: Requirements 6.3
"""
# Create rating using standard API
rating = self._create_rating(rating_value)
# Verify return type is a rating.rating recordset
self.assertEqual(rating._name, 'rating.rating',
"create() should return a rating.rating recordset")
# Verify the record exists
self.assertTrue(rating.id, "create() should return a record with an ID")
# Verify the rating value was stored correctly
self.assertGreaterEqual(rating.rating, 1.0,
"Rating value should be >= 1.0")
self.assertLessEqual(rating.rating, 5.0,
"Rating value should be <= 5.0")
# Verify standard fields are accessible
self.assertTrue(hasattr(rating, 'res_model'),
"Standard field 'res_model' should be accessible")
self.assertTrue(hasattr(rating, 'res_id'),
"Standard field 'res_id' should be accessible")
self.assertTrue(hasattr(rating, 'partner_id'),
"Standard field 'partner_id' should be accessible")
self.assertTrue(hasattr(rating, 'rated_partner_id'),
"Standard field 'rated_partner_id' should be accessible")
self.assertTrue(hasattr(rating, 'feedback'),
"Standard field 'feedback' should be accessible")
self.assertTrue(hasattr(rating, 'consumed'),
"Standard field 'consumed' should be accessible")
self.assertTrue(hasattr(rating, 'access_token'),
"Standard field 'access_token' should be accessible")
@given(
initial_rating=st.floats(min_value=1.0, max_value=5.0, allow_nan=False, allow_infinity=False),
new_rating=st.floats(min_value=1.0, max_value=5.0, allow_nan=False, allow_infinity=False)
)
@settings(max_examples=100, deadline=None)
def test_property_write_method_signature(self, initial_rating, new_rating):
"""
Property 14: API compatibility maintained - write method
For any overridden rating method, the method signature and return type
should remain compatible with the standard Odoo rating API.
This test verifies that the write() method:
- Accepts the same parameters as the base model
- Returns True (standard Odoo write behavior)
- Properly updates the rating value
Validates: Requirements 6.3
"""
# Create initial rating
rating = self._create_rating(initial_rating)
initial_id = rating.id
# Update rating using standard API
result = rating.write({'rating': new_rating})
# Verify return value is True (standard Odoo behavior)
self.assertTrue(result, "write() should return True")
# Verify the record still exists with same ID
self.assertEqual(rating.id, initial_id,
"write() should not change record ID")
# Verify the rating value was updated
self.assertAlmostEqual(rating.rating, new_rating, places=2,
msg=f"Rating should be updated to {new_rating}")
# Verify we can update other standard fields
rating.write({'feedback': 'Test feedback'})
self.assertEqual(rating.feedback, 'Test feedback',
"Standard field 'feedback' should be writable")
@given(rating_value=st.floats(min_value=1.0, max_value=5.0, allow_nan=False, allow_infinity=False))
@settings(max_examples=100, deadline=None)
def test_property_reset_method_compatibility(self, rating_value):
"""
Property 14: API compatibility maintained - reset method
For any overridden rating method, the method signature and return type
should remain compatible with the standard Odoo rating API.
This test verifies that the reset() method:
- Works as expected (resets rating to 0)
- Resets consumed flag
- Generates new access token
- Clears feedback
Validates: Requirements 6.3
"""
# Create rating with value and feedback
rating = self._create_rating(rating_value,
feedback='Test feedback',
consumed=True)
original_token = rating.access_token
# Reset the rating
rating.reset()
# Verify rating is reset to 0
self.assertEqual(rating.rating, 0.0,
"reset() should set rating to 0")
# Verify consumed flag is reset
self.assertFalse(rating.consumed,
"reset() should set consumed to False")
# Verify feedback is cleared
self.assertFalse(rating.feedback,
"reset() should clear feedback")
# Verify new access token is generated
self.assertNotEqual(rating.access_token, original_token,
"reset() should generate new access token")
@given(rating_value=st.floats(min_value=1.0, max_value=5.0, allow_nan=False, allow_infinity=False))
@settings(max_examples=100, deadline=None)
def test_property_action_open_rated_object_compatibility(self, rating_value):
"""
Property 14: API compatibility maintained - action_open_rated_object method
For any overridden rating method, the method signature and return type
should remain compatible with the standard Odoo rating API.
This test verifies that the action_open_rated_object() method:
- Returns a proper action dictionary
- Contains required keys (type, res_model, res_id, views)
- Points to the correct record
Validates: Requirements 6.3
"""
# Create rating
rating = self._create_rating(rating_value)
# Call action_open_rated_object
action = rating.action_open_rated_object()
# Verify return type is a dictionary
self.assertIsInstance(action, dict,
"action_open_rated_object() should return a dictionary")
# Verify required keys are present
self.assertIn('type', action,
"Action should contain 'type' key")
self.assertIn('res_model', action,
"Action should contain 'res_model' key")
self.assertIn('res_id', action,
"Action should contain 'res_id' key")
self.assertIn('views', action,
"Action should contain 'views' key")
# Verify action points to correct record
self.assertEqual(action['type'], 'ir.actions.act_window',
"Action type should be 'ir.actions.act_window'")
self.assertEqual(action['res_model'], rating.res_model,
"Action res_model should match rating res_model")
self.assertEqual(action['res_id'], rating.res_id,
"Action res_id should match rating res_id")
def test_property_field_compatibility(self):
"""
Property 14: API compatibility maintained - field compatibility
For any overridden rating method, the method signature and return type
should remain compatible with the standard Odoo rating API.
This test verifies that all standard rating fields are accessible
and work as expected.
Validates: Requirements 6.3
"""
# Create rating
rating = self._create_rating(3.0, feedback='Great service!')
# Test standard field access
standard_fields = [
'rating', 'res_model', 'res_id', 'partner_id',
'rated_partner_id', 'feedback', 'consumed', 'access_token',
'create_date', 'write_date', 'res_name', 'rating_text',
'message_id', 'is_internal'
]
for field_name in standard_fields:
self.assertTrue(hasattr(rating, field_name),
f"Standard field '{field_name}' should be accessible")
# Try to read the field (should not raise exception)
try:
value = getattr(rating, field_name)
# Field access should work
self.assertIsNotNone(field_name,
f"Field '{field_name}' should be readable")
except Exception as e:
self.fail(f"Field '{field_name}' access raised exception: {e}")
def test_property_computed_fields_compatibility(self):
"""
Property 14: API compatibility maintained - computed fields
For any overridden rating method, the method signature and return type
should remain compatible with the standard Odoo rating API.
This test verifies that computed fields work correctly.
Validates: Requirements 6.3
"""
# Create rating
rating = self._create_rating(4.0)
# Test computed fields
self.assertTrue(hasattr(rating, 'res_name'),
"Computed field 'res_name' should exist")
self.assertTrue(hasattr(rating, 'rating_text'),
"Computed field 'rating_text' should exist")
# Verify res_name is computed
self.assertTrue(rating.res_name,
"res_name should be computed and not empty")
# Verify rating_text is computed
self.assertTrue(rating.rating_text,
"rating_text should be computed and not empty")
@given(rating_value=st.floats(min_value=1.0, max_value=5.0, allow_nan=False, allow_infinity=False))
@settings(max_examples=100, deadline=None)
def test_property_search_compatibility(self, rating_value):
"""
Property 14: API compatibility maintained - search compatibility
For any overridden rating method, the method signature and return type
should remain compatible with the standard Odoo rating API.
This test verifies that search operations work correctly with the
extended rating model.
Validates: Requirements 6.3
"""
# Create rating
rating = self._create_rating(rating_value)
# Test search by rating value
found_ratings = self.Rating.search([
('rating', '=', rating_value),
('id', '=', rating.id)
])
self.assertIn(rating, found_ratings,
"Search should find the created rating")
# Test search by standard fields
found_by_partner = self.Rating.search([
('partner_id', '=', self.test_partner.id),
('id', '=', rating.id)
])
self.assertIn(rating, found_by_partner,
"Search by partner_id should work")
# Test search by res_model
found_by_model = self.Rating.search([
('res_model', '=', 'helpdesk.ticket'),
('id', '=', rating.id)
])
self.assertIn(rating, found_by_model,
"Search by res_model should work")
def test_property_unlink_compatibility(self):
"""
Property 14: API compatibility maintained - unlink compatibility
For any overridden rating method, the method signature and return type
should remain compatible with the standard Odoo rating API.
This test verifies that unlink() works correctly.
Validates: Requirements 6.3
"""
# Create rating
rating = self._create_rating(3.0)
rating_id = rating.id
# Unlink the rating
result = rating.unlink()
# Verify return value is True
self.assertTrue(result, "unlink() should return True")
# Verify rating no longer exists
exists = self.Rating.search([('id', '=', rating_id)])
self.assertFalse(exists,
"Rating should not exist after unlink()")
def test_property_method_signatures_match(self):
"""
Property 14: API compatibility maintained - method signatures
For any overridden rating method, the method signature should match
the base model signature.
This test verifies that overridden methods have compatible signatures.
Validates: Requirements 6.3
"""
# Get the extended rating model class
extended_rating_class = self.Rating.__class__
# Check that key methods exist
key_methods = ['create', 'write', 'reset', 'action_open_rated_object']
for method_name in key_methods:
self.assertTrue(hasattr(extended_rating_class, method_name),
f"Method '{method_name}' should exist in extended model")
method = getattr(extended_rating_class, method_name)
self.assertTrue(callable(method),
f"'{method_name}' should be callable")