glp-companion/test/features/medication/domain/injection_site_test.dart

90 lines
3.3 KiB
Dart

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);
});
});
}