Initial Commit
This commit is contained in:
@@ -0,0 +1,285 @@
|
||||
"""
|
||||
Unit Tests for MakeNameMapper
|
||||
|
||||
Tests the make name normalization functionality including:
|
||||
- Standard filename to display name conversion
|
||||
- Special capitalization cases (BMW, GMC, etc.)
|
||||
- Multi-word names (underscore to space conversion)
|
||||
- Validation against authoritative makes list
|
||||
- Error handling for edge cases
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import tempfile
|
||||
import json
|
||||
import os
|
||||
from unittest.mock import patch, mock_open
|
||||
|
||||
# Import the class we're testing
|
||||
from ..utils.make_name_mapper import MakeNameMapper, ValidationReport
|
||||
|
||||
|
||||
class TestMakeNameMapper(unittest.TestCase):
|
||||
"""Test cases for MakeNameMapper utility"""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test environment before each test"""
|
||||
self.mapper = MakeNameMapper()
|
||||
|
||||
def test_normalize_single_word_makes(self):
|
||||
"""Test normalization of single-word make names"""
|
||||
test_cases = [
|
||||
('toyota.json', 'Toyota'),
|
||||
('honda.json', 'Honda'),
|
||||
('ford.json', 'Ford'),
|
||||
('audi.json', 'Audi'),
|
||||
('tesla.json', 'Tesla'),
|
||||
]
|
||||
|
||||
for filename, expected in test_cases:
|
||||
with self.subTest(filename=filename):
|
||||
result = self.mapper.normalize_make_name(filename)
|
||||
self.assertEqual(result, expected,
|
||||
f"Expected '{expected}' for '{filename}', got '{result}'")
|
||||
|
||||
def test_normalize_multi_word_makes(self):
|
||||
"""Test normalization of multi-word make names (underscore to space)"""
|
||||
test_cases = [
|
||||
('alfa_romeo.json', 'Alfa Romeo'),
|
||||
('land_rover.json', 'Land Rover'),
|
||||
('rolls_royce.json', 'Rolls Royce'),
|
||||
('aston_martin.json', 'Aston Martin'),
|
||||
]
|
||||
|
||||
for filename, expected in test_cases:
|
||||
with self.subTest(filename=filename):
|
||||
result = self.mapper.normalize_make_name(filename)
|
||||
self.assertEqual(result, expected,
|
||||
f"Expected '{expected}' for '{filename}', got '{result}'")
|
||||
|
||||
def test_normalize_special_cases(self):
|
||||
"""Test special capitalization cases"""
|
||||
test_cases = [
|
||||
('bmw.json', 'BMW'),
|
||||
('gmc.json', 'GMC'),
|
||||
('mini.json', 'MINI'),
|
||||
('mclaren.json', 'McLaren'),
|
||||
]
|
||||
|
||||
for filename, expected in test_cases:
|
||||
with self.subTest(filename=filename):
|
||||
result = self.mapper.normalize_make_name(filename)
|
||||
self.assertEqual(result, expected,
|
||||
f"Expected '{expected}' for '{filename}', got '{result}'")
|
||||
|
||||
def test_normalize_edge_cases(self):
|
||||
"""Test edge cases and error handling"""
|
||||
test_cases = [
|
||||
# Edge cases that should still work
|
||||
('test.json', 'Test'),
|
||||
('test_brand.json', 'Test Brand'),
|
||||
# Error cases that should return "Unknown"
|
||||
('.json', 'Unknown'),
|
||||
('', 'Unknown'),
|
||||
]
|
||||
|
||||
for filename, expected in test_cases:
|
||||
with self.subTest(filename=filename):
|
||||
result = self.mapper.normalize_make_name(filename)
|
||||
self.assertEqual(result, expected,
|
||||
f"Expected '{expected}' for '{filename}', got '{result}'")
|
||||
|
||||
def test_validate_mapping_valid_makes(self):
|
||||
"""Test validation of valid make names"""
|
||||
# These should be in the authoritative list
|
||||
valid_cases = [
|
||||
('toyota.json', 'Toyota'),
|
||||
('alfa_romeo.json', 'Alfa Romeo'),
|
||||
('bmw.json', 'BMW'),
|
||||
('land_rover.json', 'Land Rover'),
|
||||
]
|
||||
|
||||
for filename, display_name in valid_cases:
|
||||
with self.subTest(filename=filename):
|
||||
is_valid = self.mapper.validate_mapping(filename, display_name)
|
||||
self.assertTrue(is_valid, f"'{display_name}' should be valid")
|
||||
|
||||
def test_validate_mapping_invalid_makes(self):
|
||||
"""Test validation of invalid make names"""
|
||||
invalid_cases = [
|
||||
('unknown.json', 'Unknown Brand'),
|
||||
('fake.json', 'Fake'),
|
||||
('test.json', 'Test Make'),
|
||||
]
|
||||
|
||||
for filename, display_name in invalid_cases:
|
||||
with self.subTest(filename=filename):
|
||||
is_valid = self.mapper.validate_mapping(filename, display_name)
|
||||
self.assertFalse(is_valid, f"'{display_name}' should be invalid")
|
||||
|
||||
def test_reverse_lookup(self):
|
||||
"""Test reverse lookup functionality"""
|
||||
test_cases = [
|
||||
('Toyota', 'toyota.json'),
|
||||
('Alfa Romeo', 'alfa_romeo.json'),
|
||||
('BMW', 'bmw.json'),
|
||||
('Land Rover', 'land_rover.json'),
|
||||
('McLaren', 'mclaren.json'),
|
||||
]
|
||||
|
||||
for display_name, expected_filename in test_cases:
|
||||
with self.subTest(display_name=display_name):
|
||||
result = self.mapper.get_filename_for_display_name(display_name)
|
||||
self.assertEqual(result, expected_filename,
|
||||
f"Expected '{expected_filename}' for '{display_name}', got '{result}'")
|
||||
|
||||
def test_get_all_mappings(self):
|
||||
"""Test getting all mappings from a directory"""
|
||||
# Create temporary directory with test files
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# Create test JSON files
|
||||
test_files = ['toyota.json', 'alfa_romeo.json', 'bmw.json']
|
||||
|
||||
for filename in test_files:
|
||||
file_path = os.path.join(temp_dir, filename)
|
||||
with open(file_path, 'w') as f:
|
||||
json.dump({"test": "data"}, f)
|
||||
|
||||
mappings = self.mapper.get_all_mappings(temp_dir)
|
||||
|
||||
# Check that all files were processed
|
||||
self.assertEqual(len(mappings), len(test_files))
|
||||
|
||||
# Check specific mappings
|
||||
expected_mappings = {
|
||||
'toyota.json': 'Toyota',
|
||||
'alfa_romeo.json': 'Alfa Romeo',
|
||||
'bmw.json': 'BMW'
|
||||
}
|
||||
|
||||
for filename, expected_display in expected_mappings.items():
|
||||
self.assertIn(filename, mappings)
|
||||
self.assertEqual(mappings[filename], expected_display)
|
||||
|
||||
def test_validation_report(self):
|
||||
"""Test validation report generation"""
|
||||
# Create temporary directory with test files
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# Mix of valid and invalid files
|
||||
test_files = {
|
||||
'toyota.json': {"test": "data"}, # Valid
|
||||
'alfa_romeo.json': {"test": "data"}, # Valid
|
||||
'unknown_brand.json': {"test": "data"} # Invalid
|
||||
}
|
||||
|
||||
for filename, content in test_files.items():
|
||||
file_path = os.path.join(temp_dir, filename)
|
||||
with open(file_path, 'w') as f:
|
||||
json.dump(content, f)
|
||||
|
||||
report = self.mapper.validate_all_mappings(temp_dir)
|
||||
|
||||
# Check report structure
|
||||
self.assertIsInstance(report, ValidationReport)
|
||||
self.assertEqual(report.total_files, 3)
|
||||
self.assertEqual(report.valid_mappings, 2) # toyota and alfa_romeo should be valid
|
||||
self.assertEqual(len(report.mismatches), 1) # unknown_brand should be invalid
|
||||
|
||||
# Check success rate
|
||||
expected_rate = 2/3 # 2 valid out of 3 total
|
||||
self.assertAlmostEqual(report.success_rate, expected_rate, places=2)
|
||||
|
||||
# Check mismatch details
|
||||
mismatch = report.mismatches[0]
|
||||
self.assertEqual(mismatch['filename'], 'unknown_brand.json')
|
||||
self.assertEqual(mismatch['mapped_name'], 'Unknown Brand')
|
||||
self.assertEqual(mismatch['status'], 'NOT_FOUND_IN_AUTHORITATIVE')
|
||||
|
||||
@patch('builtins.open', mock_open(read_data='{"manufacturers": ["Toyota", "BMW", "Custom Brand"]}'))
|
||||
def test_load_custom_authoritative_makes(self):
|
||||
"""Test loading custom authoritative makes from file"""
|
||||
with patch('os.path.exists', return_value=True):
|
||||
mapper = MakeNameMapper(sources_dir='test_sources')
|
||||
|
||||
# Should have loaded the custom list
|
||||
self.assertIn('Toyota', mapper.authoritative_makes)
|
||||
self.assertIn('BMW', mapper.authoritative_makes)
|
||||
self.assertIn('Custom Brand', mapper.authoritative_makes)
|
||||
|
||||
# Test validation with custom list
|
||||
self.assertTrue(mapper.validate_mapping('custom.json', 'Custom Brand'))
|
||||
|
||||
def test_make_statistics(self):
|
||||
"""Test make statistics calculation"""
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
# Create test files representing different categories
|
||||
test_files = [
|
||||
'toyota.json', # Single word
|
||||
'honda.json', # Single word
|
||||
'alfa_romeo.json', # Multi word
|
||||
'land_rover.json', # Multi word
|
||||
'bmw.json', # Special case
|
||||
'gmc.json', # Special case
|
||||
]
|
||||
|
||||
for filename in test_files:
|
||||
file_path = os.path.join(temp_dir, filename)
|
||||
with open(file_path, 'w') as f:
|
||||
json.dump({"test": "data"}, f)
|
||||
|
||||
stats = self.mapper.get_make_statistics(temp_dir)
|
||||
|
||||
expected_stats = {
|
||||
'total': 6,
|
||||
'single_words': 2, # toyota, honda
|
||||
'multi_words': 2, # alfa_romeo, land_rover
|
||||
'special_cases': 2 # bmw, gmc
|
||||
}
|
||||
|
||||
self.assertEqual(stats, expected_stats)
|
||||
|
||||
def test_error_handling(self):
|
||||
"""Test error handling for various failure scenarios"""
|
||||
# Test with non-existent directory
|
||||
mappings = self.mapper.get_all_mappings('/non/existent/directory')
|
||||
self.assertEqual(mappings, {})
|
||||
|
||||
# Test validation report with non-existent directory
|
||||
report = self.mapper.validate_all_mappings('/non/existent/directory')
|
||||
self.assertEqual(report.total_files, 0)
|
||||
self.assertEqual(report.valid_mappings, 0)
|
||||
self.assertEqual(len(report.mismatches), 0)
|
||||
|
||||
|
||||
class TestValidationReport(unittest.TestCase):
|
||||
"""Test cases for ValidationReport dataclass"""
|
||||
|
||||
def test_success_rate_calculation(self):
|
||||
"""Test success rate calculation"""
|
||||
# Test normal case
|
||||
report = ValidationReport(
|
||||
total_files=10,
|
||||
valid_mappings=8,
|
||||
mismatches=[]
|
||||
)
|
||||
self.assertEqual(report.success_rate, 0.8)
|
||||
|
||||
# Test zero division case
|
||||
report_empty = ValidationReport(
|
||||
total_files=0,
|
||||
valid_mappings=0,
|
||||
mismatches=[]
|
||||
)
|
||||
self.assertEqual(report_empty.success_rate, 0.0)
|
||||
|
||||
# Test perfect score
|
||||
report_perfect = ValidationReport(
|
||||
total_files=5,
|
||||
valid_mappings=5,
|
||||
mismatches=[]
|
||||
)
|
||||
self.assertEqual(report_perfect.success_rate, 1.0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user