import unittest import cv2 import numpy as np from PIL import Image import os from typing import Dict, Any, Optional, TypedDict, List, Tuple, cast from src.utils.barcode import Barcode class BarcodeResult(TypedDict): type: str data: str valid: bool class TestBarcode(unittest.TestCase): def setUp(self): self.barcode = Barcode() # Create test directory if it doesn't exist self.test_dir = os.path.dirname(os.path.abspath(__file__)) self.test_images_dir = os.path.join(self.test_dir, 'test_images') os.makedirs(self.test_images_dir, exist_ok=True) def test_validate_barcode(self): """Test barcode validation for different formats""" # Test valid EAN-13 self.assertTrue(self.barcode.validate_barcode('5901234123457', 'EAN13')) # Test invalid EAN-13 self.assertFalse(self.barcode.validate_barcode('5901234123458', 'EAN13')) # Test valid EAN-8 self.assertTrue(self.barcode.validate_barcode('40170725', 'EAN8')) # Test invalid EAN-8 self.assertFalse(self.barcode.validate_barcode('40170726', 'EAN8')) # Test valid UPC-A self.assertTrue(self.barcode.validate_barcode('042100005264', 'UPCA')) # Test invalid UPC-A self.assertFalse(self.barcode.validate_barcode('042100005265', 'UPCA')) def test_scan_and_validate_from_pil(self): """Test barcode scanning from PIL Image""" # Create a simple test image with a barcode # This is a placeholder - you should replace with actual barcode images test_image_path = os.path.join(self.test_images_dir, 'test_barcode.png') if not os.path.exists(test_image_path): # Create a blank image if test image doesn't exist img = Image.new('RGB', (400, 200), color='white') img.save(test_image_path) # Load test image image = Image.open(test_image_path) # Test scanning results = self.barcode.scan_and_validate(image) # Basic structure test self.assertIsInstance(results, list) # If a barcode is found, verify the result structure for result in results: typed_result = cast(BarcodeResult, result) self.assertIsInstance(result, dict) self.assertTrue(all(key in result for key in ['type', 'data', 'valid'])) self.assertIsInstance(typed_result['type'], str) self.assertIsInstance(typed_result['data'], str) self.assertIsInstance(typed_result['valid'], bool) def test_scan_and_validate_from_cv2(self): """Test barcode scanning from OpenCV image""" # Create a test image using OpenCV test_image_path = os.path.join(self.test_images_dir, 'test_barcode_cv2.png') if not os.path.exists(test_image_path): # Create a blank image if test image doesn't exist img = np.full((200, 400, 3), 255, dtype=np.uint8) # White background cv2.imwrite(test_image_path, img) # Load test image image = cv2.imread(test_image_path) # Test scanning with show_image=True scan_result = self.barcode.scan_and_validate(image, show_image=True) self.assertIsInstance(scan_result, tuple) results, annotated_image = scan_result # Verify results self.assertIsInstance(results, list) self.assertIsInstance(annotated_image, np.ndarray) # Check if the annotated image has the same dimensions as input self.assertEqual(annotated_image.shape, image.shape) def test_error_handling(self): """Test error handling for invalid inputs""" # Test with None - should raise an exception with self.assertRaises(Exception): self.barcode.scan_and_validate(None) # type: ignore # Test with invalid image type - should raise an exception with self.assertRaises(Exception): self.barcode.scan_and_validate("not an image") # type: ignore # Test empty strings are always invalid self.assertFalse(self.barcode.validate_barcode("", "EAN13")) self.assertFalse(self.barcode.validate_barcode("", "UNKNOWN")) # Test validation with unknown format # For unknown formats, we validate against known formats first self.assertFalse(self.barcode.validate_barcode("invalid", "UNKNOWN")) # Invalid data structure self.assertFalse(self.barcode.validate_barcode("12345678", "UNKNOWN")) # Valid structure but not a valid barcode self.assertTrue(self.barcode.validate_barcode("5901234123457", "UNKNOWN")) # Valid EAN13 structure if __name__ == '__main__': unittest.main()