import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:motorcycle_dash/services/motorcycle_image_service.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('Motorcycle Image Selection & Hierarchy Audit', () { late MotorcycleImageService service; setUp(() { MotorcycleImageService.resetRegistry(); service = MotorcycleImageService.instance; }); tearDown(() { MotorcycleImageService.resetRegistry(); }); test('1. 2001 Yamaha YZF-R6 returns verified authentic photograph', () { final ref = service.getReferenceImage( make: 'Yamaha', model: 'YZF-R6', year: 2001, ); expect(ref.isPhoto, isTrue); expect(ref.hasImage, isTrue); expect( ref.assetPath, equals('assets/images/motorcycles/yamaha_yzf_r6_2001.jpg'), ); expect(ref.caption, contains('2001 Yamaha YZF-R6')); expect(ref.attribution, contains('James McCauley')); expect(ref.attribution, contains('CC BY 2.0')); expect( service.hasPhotographicAsset( make: 'Yamaha', model: 'YZF-R6', year: 2001, ), isTrue, ); }); test('2. 1st Generation Yamaha YZF-R6 aliases resolve correctly', () { final r6Alias = service.getReferenceImage( make: 'Yamaha', model: 'R6', year: 2001, ); expect(r6Alias.isPhoto, isTrue); expect( r6Alias.assetPath, equals('assets/images/motorcycles/yamaha_yzf_r6_2001.jpg'), ); final spaceAlias = service.getReferenceImage( make: 'Yamaha', model: 'YZF R6', year: 2001, ); expect(spaceAlias.isPhoto, isTrue); final noSpaceAlias = service.getReferenceImage( make: 'Yamaha', model: 'YZFR6', year: 2000, ); expect(noSpaceAlias.isPhoto, isTrue); }); test('3. Model-generation year matching works for 1999-2002 5EB', () { final gen1999 = service.getReferenceImage( make: 'Yamaha', model: 'YZF-R6', year: 1999, ); expect(gen1999.isPhoto, isTrue); final gen2002 = service.getReferenceImage( make: 'Yamaha', model: 'YZF-R6', year: 2002, ); expect(gen2002.isPhoto, isTrue); final gen2008 = service.getReferenceImage( make: 'Yamaha', model: 'YZF-R6', year: 2008, ); expect(gen2008.isPhoto, isFalse); expect(gen2008.assetPath, isNull); expect(gen2008.caption, equals('2008 Yamaha YZF-R6')); expect(gen2008.attribution, equals('Technical Schematic')); }); test( '4. Motorcycle with no bundled photograph returns graceful technical schematic', () { final ref = service.getReferenceImage( make: 'Honda', model: 'CBR600RR', year: 2018, ); expect(ref.isPhoto, isFalse); expect(ref.hasImage, isFalse); expect(ref.assetPath, isNull); expect(ref.caption, equals('2018 Honda CBR600RR')); expect(ref.attribution, equals('Technical Schematic')); expect( service.hasPhotographicAsset( make: 'Honda', model: 'CBR600RR', year: 2018, ), isFalse, ); }, ); test('5. Unknown make and model returns generic technical fallback', () { final nullRef = service.getReferenceImage( make: null, model: null, year: null, ); expect(nullRef.isPhoto, isFalse); expect(nullRef.assetPath, isNull); expect(nullRef.caption, equals('Motorcycle Technical Reference')); final emptyRef = service.getReferenceImage( make: '', model: '', year: 2020, ); expect(emptyRef.isPhoto, isFalse); expect(emptyRef.assetPath, isNull); final customRef = service.getReferenceImage( make: 'Custom', model: 'Cafe Racer', year: 1982, ); expect(customRef.isPhoto, isFalse); expect(customRef.assetPath, isNull); expect(customRef.caption, equals('1982 Custom Cafe Racer')); expect(customRef.attribution, equals('Technical Schematic')); }); test( '6. Yamaha R6 photograph is NEVER returned for an unrelated motorcycle', () { final testCases = [ {'make': 'Honda', 'model': 'CBR600RR', 'year': 2001}, {'make': 'Honda', 'model': 'CBR1000RR-R', 'year': 2024}, {'make': 'Suzuki', 'model': 'GSX-R600', 'year': 2001}, {'make': 'Suzuki', 'model': 'Hayabusa GSX1300R', 'year': 2022}, {'make': 'Kawasaki', 'model': 'Ninja ZX-6R', 'year': 2001}, {'make': 'Kawasaki', 'model': 'Ninja H2', 'year': 2023}, {'make': 'Ducati', 'model': 'Panigale V4 S', 'year': 2023}, {'make': 'Ducati', 'model': 'Monster 821', 'year': 2019}, {'make': 'BMW', 'model': 'S1000RR', 'year': 2022}, {'make': 'BMW', 'model': 'R1250GS Adventure', 'year': 2021}, {'make': 'KTM', 'model': '390 Duke', 'year': 2020}, {'make': 'KTM', 'model': '1290 Super Duke R', 'year': 2022}, {'make': 'Triumph', 'model': 'Daytona 675', 'year': 2012}, {'make': 'Triumph', 'model': 'Street Triple 765 RS', 'year': 2023}, {'make': 'Harley-Davidson', 'model': 'Sportster S', 'year': 2022}, {'make': 'Aprilia', 'model': 'RSV4 1100 Factory', 'year': 2023}, ]; for (final tc in testCases) { final make = tc['make'] as String; final model = tc['model'] as String; final year = tc['year'] as int; final ref = service.getReferenceImage( make: make, model: model, year: year, ); expect( ref.assetPath, isNot(equals('assets/images/motorcycles/yamaha_yzf_r6_2001.jpg')), reason: 'Failed isolation: $make $model returned R6 asset!', ); expect( ref.isPhoto, isFalse, reason: 'Expected schematic fallback for unbundled $make $model', ); expect(ref.caption, equals('$year $make $model')); expect(ref.attribution, equals('Technical Schematic')); } }, ); test( '7. Architecture is genuinely extensible via dynamic descriptor registration', () { final beforeReg = service.getReferenceImage( make: 'Ducati', model: 'Panigale V4', year: 2024, ); expect(beforeReg.isPhoto, isFalse); MotorcycleImageService.registerDescriptor( const MotorcycleImageDescriptor( make: 'Ducati', model: 'Panigale V4', minYear: 2022, maxYear: 2025, modelAliases: ['PanigaleV4', 'Panigale V4 S'], assetPath: 'assets/images/motorcycles/ducati_panigale_v4.png', caption: 'Ducati Panigale V4 (Desmosedici Stradale)', attribution: 'Factory Superbike Reference', isPhoto: true, ), ); final afterReg = service.getReferenceImage( make: 'Ducati', model: 'Panigale V4', year: 2024, ); expect(afterReg.isPhoto, isTrue); expect( afterReg.assetPath, equals('assets/images/motorcycles/ducati_panigale_v4.png'), ); expect(afterReg.caption, contains('Ducati Panigale V4')); final aliasReg = service.getReferenceImage( make: 'Ducati', model: 'Panigale V4 S', year: 2023, ); expect(aliasReg.isPhoto, isTrue); }, ); test('8. Bundled photographic assets physically exist on disk', () { final bundledAssets = MotorcycleImageService.bundledPhotographicAssets; expect(bundledAssets, isNotEmpty); for (final assetPath in bundledAssets) { final file = File(assetPath); expect( file.existsSync(), isTrue, reason: 'Bundled asset $assetPath does not exist on disk!', ); expect( file.lengthSync(), greaterThan(100000), reason: 'Bundled photographic asset $assetPath is an undersized render or corrupt', ); } }); test('9. getCachedOrCuratedImage synchronously provides curated photo', () { final img = service.getCachedOrCuratedImage( make: 'Yamaha', model: 'YZF-R6', year: 2001, ); expect(img, isNotNull); expect(img!.isPhoto, isTrue); expect( img.assetPath, equals('assets/images/motorcycles/yamaha_yzf_r6_2001.jpg'), ); }); test( '10. resolve returns curated photo directly without network', () async { final img = await service.resolve( make: 'Yamaha', model: 'YZF-R6', year: 2001, ); expect(img, isNotNull); expect(img!.isPhoto, isTrue); expect( img.assetPath, equals('assets/images/motorcycles/yamaha_yzf_r6_2001.jpg'), ); }, ); }); }