373 lines
14 KiB
Python
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")
|