import 'package:flutter_test/flutter_test.dart'; import 'package:glp1_companion/features/medication/domain/entities/injection_site.dart'; import 'package:glp1_companion/features/medication/domain/value_objects/glp1_compound.dart'; void main() { group('InjectionSite model', () { test('exposes exactly twelve anatomical quadrants', () { expect(InjectionSite.values, hasLength(12)); }); test('quadrants span three regions with four sites each', () { for (final region in InjectionBodyRegion.values) { expect( InjectionSite.values.where((site) => site.region == region), hasLength(4), reason: 'region ${region.name} should own four quadrants', ); } }); test('tryParse round-trips the persistence key', () { for (final site in InjectionSite.values) { expect(InjectionSite.tryParse(site.persistenceKey), site); expect(InjectionSite.tryParse(site.displayName), site); } expect(InjectionSite.tryParse(null), isNull); expect(InjectionSite.tryParse(' '), isNull); expect(InjectionSite.tryParse('unknown-quadrant'), isNull); }); }); group('InjectionSite.leastRecentlyUsed', () { final now = DateTime(2026, 10, 16); test('never-used quadrants win over used ones', () { final lastUsed = { InjectionSite.abdomenRightUpper: now, InjectionSite.thighLeftLateral: now.subtract(const Duration(days: 90)), }; final suggestion = InjectionSite.leastRecentlyUsed(lastUsed); expect( lastUsed.containsKey(suggestion), isFalse, reason: 'suggested site must be one that was never used', ); }); test('with full history the oldest site is chosen', () { final lastUsed = { for (var i = 0; i < InjectionSite.values.length; i++) InjectionSite.values[i]: now.subtract(Duration(days: i)), }; expect( InjectionSite.leastRecentlyUsed(lastUsed), InjectionSite.values.last, ); }); test('ties resolve deterministically to declaration order', () { final lastUsed = { for (final site in InjectionSite.values) site: now, }; expect(InjectionSite.leastRecentlyUsed(lastUsed), InjectionSite.values.first); expect(InjectionSite.leastRecentlyUsed(const {}), InjectionSite.values.first); }); }); group('Glp1Compound', () { test('models the three supported agonists with published half-lives', () { expect(Glp1Compound.semaglutide.halfLifeHours, 168); expect(Glp1Compound.tirzepatide.halfLifeHours, 120); expect(Glp1Compound.liraglutide.halfLifeHours, 13); }); test('tryParse resolves generic names, brands, and free text', () { expect(Glp1Compound.tryParse('semaglutide'), Glp1Compound.semaglutide); expect(Glp1Compound.tryParse('OZEMPIC'), Glp1Compound.semaglutide); expect(Glp1Compound.tryParse('Mounjaro'), Glp1Compound.tirzepatide); expect(Glp1Compound.tryParse('Zepbound'), Glp1Compound.tirzepatide); expect(Glp1Compound.tryParse('Saxenda'), Glp1Compound.liraglutide); expect( Glp1Compound.tryParse('Semaglutide (compounded)'), Glp1Compound.semaglutide, ); expect(Glp1Compound.tryParse('unknown'), isNull); expect(Glp1Compound.tryParse(null), isNull); }); }); }