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

373 lines
14 KiB
Python

# -*- coding: utf-8 -*-
from odoo.tests import tagged
from odoo.tests.common import TransactionCase
from hypothesis import given, strategies as st, settings, assume
@tagged('post_install', '-at_install', 'helpdesk_rating_five_stars')
class TestRatingExport(TransactionCase):
"""
Property-based tests for rating export functionality
Requirements: 4.5
- Requirement 4.5: Export rating data with values in 0-5 range
"""
def setUp(self):
super(TestRatingExport, self).setUp()
self.Rating = self.env['rating.rating']
self.HelpdeskTeam = self.env['helpdesk.team']
self.HelpdeskTicket = self.env['helpdesk.ticket']
# Create a helpdesk team with rating enabled
self.team = self.HelpdeskTeam.create({
'name': 'Test Support Team',
'use_rating': True,
})
def _create_tickets_with_ratings(self, rating_values):
"""
Helper method to create multiple tickets with ratings
Args:
rating_values: List of rating values (0-5)
Returns:
list: List of rating records
"""
ratings = []
for i, rating_value in enumerate(rating_values):
# Create a ticket
ticket = self.HelpdeskTicket.create({
'name': f'Test Ticket {i} - Rating {rating_value}',
'team_id': self.team.id,
})
# Create rating for the ticket
rating = self.Rating.create({
'res_model_id': self.env['ir.model']._get('helpdesk.ticket').id,
'res_model': 'helpdesk.ticket',
'res_id': ticket.id,
'rating': float(rating_value),
'consumed': True,
})
ratings.append(rating)
return ratings
# Feature: helpdesk-rating-five-stars, Property 12: Export contains valid rating values
@given(rating_values=st.lists(
st.floats(min_value=0.0, max_value=5.0, allow_nan=False, allow_infinity=False),
min_size=1,
max_size=20
))
@settings(max_examples=100, deadline=None)
def test_property_export_contains_valid_values(self, rating_values):
"""
Property 12: Export contains valid rating values
For any exported rating data, all Rating_Value entries should be within the 0-5 range.
This property verifies that:
1. All exported rating values are in the 0-5 range
2. Export data structure is correct
3. No data corruption occurs during export
4. Export includes all expected fields
Validates: Requirements 4.5
"""
# Skip if we have no valid ratings
assume(len(rating_values) > 0)
# Filter out invalid values (between 0 and 1, exclusive)
valid_rating_values = []
for val in rating_values:
if val == 0.0 or (val >= 1.0 and val <= 5.0):
valid_rating_values.append(val)
# Skip if no valid values after filtering
assume(len(valid_rating_values) > 0)
# Create ratings
ratings = self._create_tickets_with_ratings(valid_rating_values)
rating_ids = [r.id for r in ratings]
# Get the rating records
rating_records = self.Rating.browse(rating_ids)
# Define fields to export (common fields that would be exported)
export_fields = ['id', 'rating', 'res_model', 'res_id', 'consumed']
# Use Odoo's export_data method to export the ratings
export_result = rating_records.export_data(export_fields)
# Verify export was successful
self.assertIn('datas', export_result,
"Export result should contain 'datas' key")
exported_data = export_result['datas']
# Verify we exported the correct number of records
self.assertEqual(len(exported_data), len(valid_rating_values),
f"Should export {len(valid_rating_values)} records")
# Find the index of the 'rating' field in export
rating_field_index = export_fields.index('rating')
# Verify all exported rating values are in valid range (0-5)
for i, row in enumerate(exported_data):
exported_rating = float(row[rating_field_index])
# Verify rating is in valid 0-5 range
self.assertGreaterEqual(exported_rating, 0.0,
f"Exported rating {exported_rating} at row {i} should be >= 0.0")
self.assertLessEqual(exported_rating, 5.0,
f"Exported rating {exported_rating} at row {i} should be <= 5.0")
# Verify rating is either 0 or between 1-5
if exported_rating > 0:
self.assertGreaterEqual(exported_rating, 1.0,
f"Non-zero exported rating {exported_rating} should be >= 1.0")
# Verify exported value matches original value
original_value = valid_rating_values[i]
self.assertAlmostEqual(exported_rating, original_value, places=2,
msg=f"Exported rating {exported_rating} should match original {original_value}")
@given(
num_ratings=st.integers(min_value=1, max_value=50),
include_zero=st.booleans()
)
@settings(max_examples=100, deadline=None)
def test_property_export_completeness(self, num_ratings, include_zero):
"""
Property: Export includes all ratings without data loss
For any set of ratings, the export should include all records with correct values.
Validates: Requirements 4.5
"""
assume(num_ratings > 0)
# Generate rating values
rating_values = []
for i in range(num_ratings):
if include_zero and i == 0:
rating_values.append(0.0)
else:
# Generate values between 1-5
rating_values.append(float((i % 5) + 1))
# Create ratings
ratings = self._create_tickets_with_ratings(rating_values)
rating_ids = [r.id for r in ratings]
# Get the rating records
rating_records = self.Rating.browse(rating_ids)
# Export with multiple fields
export_fields = ['id', 'rating', 'res_model', 'res_id', 'consumed', 'feedback']
export_result = rating_records.export_data(export_fields)
exported_data = export_result['datas']
# Verify completeness: all records exported
self.assertEqual(len(exported_data), num_ratings,
f"Should export all {num_ratings} ratings")
# Verify all rating values are valid
rating_field_index = export_fields.index('rating')
for row in exported_data:
exported_rating = float(row[rating_field_index])
# Verify in valid range
self.assertGreaterEqual(exported_rating, 0.0,
f"Exported rating should be >= 0.0")
self.assertLessEqual(exported_rating, 5.0,
f"Exported rating should be <= 5.0")
def test_export_with_zero_ratings(self):
"""
Test that export correctly handles zero ratings (no rating)
Zero ratings should be exported as 0.0 and remain in valid range.
Validates: Requirements 4.5
"""
# Create ratings with mix of values including zero
rating_values = [0.0, 1.0, 3.0, 5.0]
ratings = self._create_tickets_with_ratings(rating_values)
rating_ids = [r.id for r in ratings]
# Export ratings
rating_records = self.Rating.browse(rating_ids)
export_fields = ['id', 'rating']
export_result = rating_records.export_data(export_fields)
exported_data = export_result['datas']
# Verify all exported values are valid
rating_field_index = export_fields.index('rating')
exported_ratings = [float(row[rating_field_index]) for row in exported_data]
# Verify we have the zero rating
self.assertIn(0.0, exported_ratings,
"Export should include zero rating")
# Verify all are in valid range
for rating in exported_ratings:
self.assertGreaterEqual(rating, 0.0,
f"Exported rating {rating} should be >= 0.0")
self.assertLessEqual(rating, 5.0,
f"Exported rating {rating} should be <= 5.0")
def test_export_extreme_values(self):
"""
Test that export correctly handles extreme values (0, 1, 5)
Validates: Requirements 4.5
"""
# Create ratings with extreme values
rating_values = [0.0, 1.0, 5.0]
ratings = self._create_tickets_with_ratings(rating_values)
rating_ids = [r.id for r in ratings]
# Export ratings
rating_records = self.Rating.browse(rating_ids)
export_fields = ['id', 'rating']
export_result = rating_records.export_data(export_fields)
exported_data = export_result['datas']
# Verify all exported values match expected
rating_field_index = export_fields.index('rating')
exported_ratings = [float(row[rating_field_index]) for row in exported_data]
# Verify we have all extreme values
self.assertIn(0.0, exported_ratings, "Export should include 0.0")
self.assertIn(1.0, exported_ratings, "Export should include 1.0")
self.assertIn(5.0, exported_ratings, "Export should include 5.0")
# Verify all are in valid range
for rating in exported_ratings:
self.assertIn(rating, [0.0, 1.0, 5.0],
f"Exported rating {rating} should be one of the extreme values")
def test_export_with_all_fields(self):
"""
Test that export works correctly with all rating fields
Validates: Requirements 4.5
"""
# Create a rating with all fields populated
ticket = self.HelpdeskTicket.create({
'name': 'Test Ticket for Full Export',
'team_id': self.team.id,
})
rating = self.Rating.create({
'res_model_id': self.env['ir.model']._get('helpdesk.ticket').id,
'res_model': 'helpdesk.ticket',
'res_id': ticket.id,
'rating': 4.0,
'consumed': True,
'feedback': 'Great service!',
})
# Export with all common fields
export_fields = [
'id',
'rating',
'res_model',
'res_id',
'consumed',
'feedback',
'rating_stars_filled',
'rating_stars_empty'
]
export_result = rating.export_data(export_fields)
exported_data = export_result['datas']
# Verify export successful
self.assertEqual(len(exported_data), 1,
"Should export 1 record")
# Verify rating value is valid
rating_field_index = export_fields.index('rating')
exported_rating = float(exported_data[0][rating_field_index])
self.assertEqual(exported_rating, 4.0,
"Exported rating should be 4.0")
self.assertGreaterEqual(exported_rating, 0.0,
"Exported rating should be >= 0.0")
self.assertLessEqual(exported_rating, 5.0,
"Exported rating should be <= 5.0")
def test_export_large_dataset(self):
"""
Test that export works correctly with a large dataset
Validates: Requirements 4.5
"""
# Create a large number of ratings
rating_values = [float((i % 5) + 1) for i in range(100)]
ratings = self._create_tickets_with_ratings(rating_values)
rating_ids = [r.id for r in ratings]
# Export ratings
rating_records = self.Rating.browse(rating_ids)
export_fields = ['id', 'rating']
export_result = rating_records.export_data(export_fields)
exported_data = export_result['datas']
# Verify all records exported
self.assertEqual(len(exported_data), 100,
"Should export all 100 records")
# Verify all rating values are valid
rating_field_index = export_fields.index('rating')
for row in exported_data:
exported_rating = float(row[rating_field_index])
self.assertGreaterEqual(exported_rating, 1.0,
f"Exported rating {exported_rating} should be >= 1.0")
self.assertLessEqual(exported_rating, 5.0,
f"Exported rating {exported_rating} should be <= 5.0")
def test_export_preserves_precision(self):
"""
Test that export preserves rating value precision
Validates: Requirements 4.5
"""
# Create ratings with decimal values
rating_values = [1.0, 2.5, 3.7, 4.2, 5.0]
ratings = self._create_tickets_with_ratings(rating_values)
rating_ids = [r.id for r in ratings]
# Export ratings
rating_records = self.Rating.browse(rating_ids)
export_fields = ['id', 'rating']
export_result = rating_records.export_data(export_fields)
exported_data = export_result['datas']
# Verify precision is preserved
rating_field_index = export_fields.index('rating')
for i, row in enumerate(exported_data):
exported_rating = float(row[rating_field_index])
original_rating = rating_values[i]
# Verify values match with reasonable precision
self.assertAlmostEqual(exported_rating, original_rating, places=1,
msg=f"Exported rating should preserve precision: {exported_rating} vs {original_rating}")
# Verify in valid range
self.assertGreaterEqual(exported_rating, 0.0,
f"Exported rating should be >= 0.0")
self.assertLessEqual(exported_rating, 5.0,
f"Exported rating should be <= 5.0")