first commit - migrated from codeberg

This commit is contained in:
Charlotte Croce 2025-04-20 11:17:03 -04:00
commit 5ead03e1f7
567 changed files with 102721 additions and 0 deletions

View file

@ -0,0 +1,182 @@
// test/features/bloodwork_tracker/models/bloodwork_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:nokken/src/features/bloodwork_tracker/models/bloodwork.dart';
void main() {
group('Bloodwork Model', () {
// Test constructor and validation
test('should create valid bloodwork record', () {
// Arrange - create a valid bloodwork object
final bloodwork = Bloodwork(
date: DateTime(2023, 6, 15),
appointmentType: AppointmentType.bloodwork,
hormoneReadings: [
HormoneReading(name: 'Estradiol', value: 120.5, unit: 'pg/mL'),
HormoneReading(name: 'Testosterone', value: 30.2, unit: 'ng/dL'),
],
location: 'City Hospital',
doctor: 'Dr. Smith',
notes: 'Regular checkup',
);
// Assert - verify properties are set correctly
expect(bloodwork.date, equals(DateTime(2023, 6, 15)));
expect(bloodwork.appointmentType, equals(AppointmentType.bloodwork));
expect(bloodwork.hormoneReadings.length, equals(2));
expect(bloodwork.location, equals('City Hospital'));
expect(bloodwork.doctor, equals('Dr. Smith'));
expect(bloodwork.notes, equals('Regular checkup'));
expect(bloodwork.id, isNotEmpty); // Auto-generated ID should not be empty
});
test('should throw exception for negative hormone levels', () {
// Arrange & Act - try to create bloodwork with negative hormone level
invalidReading() => Bloodwork(
date: DateTime(2023, 6, 15),
appointmentType: AppointmentType.bloodwork,
hormoneReadings: [
HormoneReading(name: 'Estradiol', value: -10.0, unit: 'pg/mL'),
],
);
// Assert - verify exception is thrown
expect(invalidReading, throwsA(isA<BloodworkException>()));
});
test('should allow future dates for appointment types', () {
// Arrange - future date with no hormone values
final futureBloodwork = Bloodwork(
date: DateTime.now().add(const Duration(days: 30)),
appointmentType: AppointmentType.appointment, // Not bloodwork type
location: 'City Hospital',
);
// Assert - verify this is valid
expect(
futureBloodwork.appointmentType, equals(AppointmentType.appointment));
});
test(
'should throw exception for bloodwork type with no hormone readings on past date',
() {
// Past date with no hormone readings for bloodwork type should throw exception
final pastDate = DateTime.now().subtract(const Duration(days: 1));
// Arrange & Act - try to create invalid bloodwork
invalidBloodwork() => Bloodwork(
date: pastDate,
appointmentType: AppointmentType.bloodwork,
hormoneReadings: [], // No readings
);
// Assert - verify exception is thrown
expect(invalidBloodwork, throwsA(isA<BloodworkException>()));
});
// Test JSON conversion
test('should convert to and from JSON correctly', () {
// Arrange - create a bloodwork object
final original = Bloodwork(
id: 'test-id-123',
date: DateTime(2023, 6, 15),
appointmentType: AppointmentType.bloodwork,
hormoneReadings: [
HormoneReading(name: 'Estradiol', value: 120.5, unit: 'pg/mL'),
],
location: 'City Hospital',
);
// Act - convert to JSON and back
final json = original.toJson();
final restored = Bloodwork.fromJson(json);
// Assert - verify properties match
expect(restored.id, equals(original.id));
expect(restored.date.year, equals(original.date.year));
expect(restored.date.month, equals(original.date.month));
expect(restored.date.day, equals(original.date.day));
expect(restored.appointmentType, equals(original.appointmentType));
expect(restored.hormoneReadings.length,
equals(original.hormoneReadings.length));
expect(restored.hormoneReadings[0].name,
equals(original.hormoneReadings[0].name));
expect(restored.hormoneReadings[0].value,
equals(original.hormoneReadings[0].value));
expect(restored.location, equals(original.location));
});
// Test HormoneReading
test('HormoneReading should convert to and from JSON correctly', () {
// Arrange - create a hormone reading
final reading = HormoneReading(
name: 'Estradiol',
value: 120.5,
unit: 'pg/mL',
);
// Act - convert to JSON and back
final json = reading.toJson();
final restored = HormoneReading.fromJson(json);
// Assert - verify properties match
expect(restored.name, equals(reading.name));
expect(restored.value, equals(reading.value));
expect(restored.unit, equals(reading.unit));
});
// Test copyWith
test('copyWith should create a new instance with updated values', () {
// Arrange - create a bloodwork object
final original = Bloodwork(
date: DateTime(2023, 6, 15),
appointmentType: AppointmentType.bloodwork,
hormoneReadings: [
HormoneReading(name: 'Estradiol', value: 120.5, unit: 'pg/mL'),
],
);
// Act - create a copy with updated values
final updated = original.copyWith(
date: DateTime(2023, 7, 20),
appointmentType: AppointmentType.appointment,
notes: 'Updated notes',
);
// Assert - verify original is unchanged and copy has updates
expect(original.date, equals(DateTime(2023, 6, 15)));
expect(original.appointmentType, equals(AppointmentType.bloodwork));
expect(original.notes, isNull);
expect(updated.date, equals(DateTime(2023, 7, 20)));
expect(updated.appointmentType, equals(AppointmentType.appointment));
expect(updated.notes, equals('Updated notes'));
expect(updated.id, equals(original.id)); // ID should remain the same
expect(updated.hormoneReadings,
equals(original.hormoneReadings)); // Readings unchanged
});
});
// Test HormoneTypes utility class
group('HormoneTypes', () {
test('should provide default units for hormone types', () {
// Act & Assert - check a few default units
expect(HormoneTypes.getDefaultUnit('Estradiol'), equals('pg/mL'));
expect(HormoneTypes.getDefaultUnit('Testosterone'), equals('ng/dL'));
expect(HormoneTypes.getDefaultUnit('Progesterone'), equals('ng/mL'));
expect(HormoneTypes.getDefaultUnit('Unknown'), equals(''));
});
test('should provide list of available hormone types', () {
// Act - get the list of hormone types
final types = HormoneTypes.getHormoneTypes();
// Assert - verify the list contains expected types
expect(types, contains('Estradiol'));
expect(types, contains('Testosterone'));
expect(types, contains('Prolactin'));
expect(
types.length, greaterThanOrEqualTo(5)); // Should have several types
});
});
}

View file

@ -0,0 +1,196 @@
// test/features/medication_tracker/models/injection_details_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:nokken/src/features/medication_tracker/models/medication.dart';
void main() {
group('InjectionDetails', () {
// Test constructor
test('should create valid injection details with new fields', () {
// Arrange & Act - create injection details with all fields
final details = InjectionDetails(
drawingNeedleType: '18G 1.5"',
drawingNeedleCount: 10,
drawingNeedleRefills: 2,
injectingNeedleType: '25G 1"',
injectingNeedleCount: 8,
injectingNeedleRefills: 2,
syringeType: '3ml Luer Lock',
syringeCount: 12,
syringeRefills: 3,
injectionSiteNotes: 'Rotate injection sites',
frequency: InjectionFrequency.weekly,
subtype: InjectionSubtype.intramuscular,
);
// Assert - verify properties
expect(details.drawingNeedleType, equals('18G 1.5"'));
expect(details.drawingNeedleCount, equals(10));
expect(details.drawingNeedleRefills, equals(2));
expect(details.injectingNeedleType, equals('25G 1"'));
expect(details.injectingNeedleCount, equals(8));
expect(details.injectingNeedleRefills, equals(2));
expect(details.syringeType, equals('3ml Luer Lock'));
expect(details.syringeCount, equals(12));
expect(details.syringeRefills, equals(3));
expect(details.injectionSiteNotes, equals('Rotate injection sites'));
expect(details.frequency, equals(InjectionFrequency.weekly));
expect(details.subtype, equals(InjectionSubtype.intramuscular));
});
// Test JSON conversion
test('should convert to and from JSON correctly including new fields', () {
// Arrange - create injection details
final original = InjectionDetails(
drawingNeedleType: '18G 1.5"',
drawingNeedleCount: 10,
drawingNeedleRefills: 2,
injectingNeedleType: '25G 1"',
injectingNeedleCount: 8,
injectingNeedleRefills: 2,
syringeType: '3ml Luer Lock',
syringeCount: 12,
syringeRefills: 3,
injectionSiteNotes: 'Rotate injection sites',
frequency: InjectionFrequency.weekly,
subtype: InjectionSubtype.subcutaneous,
);
// Act - convert to JSON and back
final json = original.toJson();
final restored = InjectionDetails.fromJson(json);
// Assert - verify properties match
expect(restored.drawingNeedleType, equals(original.drawingNeedleType));
expect(restored.drawingNeedleCount, equals(original.drawingNeedleCount));
expect(
restored.drawingNeedleRefills, equals(original.drawingNeedleRefills));
expect(
restored.injectingNeedleType, equals(original.injectingNeedleType));
expect(
restored.injectingNeedleCount, equals(original.injectingNeedleCount));
expect(restored.injectingNeedleRefills,
equals(original.injectingNeedleRefills));
expect(restored.syringeType, equals(original.syringeType));
expect(restored.syringeCount, equals(original.syringeCount));
expect(restored.syringeRefills, equals(original.syringeRefills));
expect(restored.injectionSiteNotes, equals(original.injectionSiteNotes));
expect(restored.frequency, equals(original.frequency));
expect(restored.subtype, equals(original.subtype));
});
test('should handle missing new fields in JSON with defaults', () {
// Arrange - create incomplete JSON without new fields
final incompleteJson = {
'drawingNeedleType': '18G',
'drawingNeedleCount': 10,
'drawingNeedleRefills': 2,
'injectingNeedleType': '25G',
'injectingNeedleCount': 8,
'injectingNeedleRefills': 2,
'injectionSiteNotes': 'Notes',
'frequency': 'InjectionFrequency.weekly',
// Missing syringeType, syringeCount, syringeRefills, subtype
};
// Act - create from incomplete JSON
final details = InjectionDetails.fromJson(incompleteJson);
// Assert - verify defaults are used where fields are missing
expect(details.syringeType, equals(''));
expect(details.syringeCount, equals(0));
expect(details.syringeRefills, equals(0));
expect(details.subtype, equals(InjectionSubtype.intramuscular));
});
// Test integration with Medication
test('should support all injection subtypes in Medication', () {
// Arrange & Act - create medications with different subtypes
final imInjection = Medication(
name: 'IM Injectable',
dosage: '100mg',
startDate: DateTime(2023, 6, 15),
frequency: 1,
timeOfDay: [DateTime(2023, 6, 15, 9, 0)],
daysOfWeek: {'Su'},
currentQuantity: 5,
refillThreshold: 2,
medicationType: MedicationType.injection,
injectionDetails: InjectionDetails(
drawingNeedleType: '18G',
drawingNeedleCount: 10,
drawingNeedleRefills: 2,
injectingNeedleType: '25G',
injectingNeedleCount: 8,
injectingNeedleRefills: 2,
syringeType: '3ml',
syringeCount: 10,
syringeRefills: 2,
injectionSiteNotes: 'Notes',
frequency: InjectionFrequency.weekly,
subtype: InjectionSubtype.intramuscular,
),
);
final scInjection = Medication(
name: 'SC Injectable',
dosage: '50mg',
startDate: DateTime(2023, 6, 15),
frequency: 1,
timeOfDay: [DateTime(2023, 6, 15, 9, 0)],
daysOfWeek: {'Su'},
currentQuantity: 5,
refillThreshold: 2,
medicationType: MedicationType.injection,
injectionDetails: InjectionDetails(
drawingNeedleType: '22G',
drawingNeedleCount: 10,
drawingNeedleRefills: 2,
injectingNeedleType: '27G',
injectingNeedleCount: 8,
injectingNeedleRefills: 2,
syringeType: '1ml',
syringeCount: 10,
syringeRefills: 2,
injectionSiteNotes: 'Notes',
frequency: InjectionFrequency.weekly,
subtype: InjectionSubtype.subcutaneous,
),
);
final ivInjection = Medication(
name: 'IV Injectable',
dosage: '200mg',
startDate: DateTime(2023, 6, 15),
frequency: 1,
timeOfDay: [DateTime(2023, 6, 15, 9, 0)],
daysOfWeek: {'Su'},
currentQuantity: 5,
refillThreshold: 2,
medicationType: MedicationType.injection,
injectionDetails: InjectionDetails(
drawingNeedleType: '16G',
drawingNeedleCount: 10,
drawingNeedleRefills: 2,
injectingNeedleType: '20G',
injectingNeedleCount: 8,
injectingNeedleRefills: 2,
syringeType: '10ml',
syringeCount: 10,
syringeRefills: 2,
injectionSiteNotes: 'Notes',
frequency: InjectionFrequency.weekly,
subtype: InjectionSubtype.intravenous,
),
);
// Assert - verify subtypes are correctly stored
expect(imInjection.injectionDetails?.subtype,
equals(InjectionSubtype.intramuscular));
expect(scInjection.injectionDetails?.subtype,
equals(InjectionSubtype.subcutaneous));
expect(ivInjection.injectionDetails?.subtype,
equals(InjectionSubtype.intravenous));
});
});
}

View file

@ -0,0 +1,240 @@
// test/features/medication_tracker/models/medication_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:nokken/src/features/medication_tracker/models/medication.dart';
void main() {
group('Medication', () {
test('needsRefill should return true when quantity is below threshold', () {
// Setup - using minimal valid parameters
final medication = Medication(
name: 'Test Med',
dosage: '10mg',
startDate: DateTime(2023, 1, 1),
frequency: 1,
timeOfDay: [DateTime(2023, 1, 1, 8, 0)],
daysOfWeek: {'M'},
currentQuantity: 3,
refillThreshold: 5,
medicationType: MedicationType.oral,
oralSubtype: OralSubtype.tablets,
);
// Test and verify
expect(medication.needsRefill(), true);
});
test('needsRefill should return false when quantity is above threshold',
() {
// Setup - using minimal valid parameters
final medication = Medication(
name: 'Test Med',
dosage: '10mg',
startDate: DateTime(2023, 1, 1),
frequency: 1,
timeOfDay: [DateTime(2023, 1, 1, 8, 0)],
daysOfWeek: {'M'},
currentQuantity: 10,
refillThreshold: 5,
medicationType: MedicationType.oral,
oralSubtype: OralSubtype.tablets,
);
// Test and verify
expect(medication.needsRefill(), false);
});
test('every medication has a unique ID', () {
// Create two medications with identical properties
final medication1 = Medication(
name: 'Test Med',
dosage: '10mg',
startDate: DateTime(2023, 1, 1),
frequency: 1,
timeOfDay: [DateTime(2023, 1, 1, 8, 0)],
daysOfWeek: {'M'},
currentQuantity: 10,
refillThreshold: 5,
medicationType: MedicationType.oral,
oralSubtype: OralSubtype.tablets,
);
final medication2 = Medication(
name: 'Test Med',
dosage: '10mg',
startDate: DateTime(2023, 1, 1),
frequency: 1,
timeOfDay: [DateTime(2023, 1, 1, 8, 0)],
daysOfWeek: {'M'},
currentQuantity: 10,
refillThreshold: 5,
medicationType: MedicationType.oral,
oralSubtype: OralSubtype.tablets,
);
// Verify each has a unique ID
expect(medication1.id, isNot(equals(medication2.id)));
expect(medication1.id, isNotEmpty);
expect(medication2.id, isNotEmpty);
});
test('should validate that oral medications have oral subtype', () {
// Should succeed
final validOral = Medication(
name: 'Test Med',
dosage: '10mg',
startDate: DateTime(2023, 1, 1),
frequency: 1,
timeOfDay: [DateTime(2023, 1, 1, 8, 0)],
daysOfWeek: {'M'},
currentQuantity: 10,
refillThreshold: 5,
medicationType: MedicationType.oral,
oralSubtype: OralSubtype.tablets,
);
expect(validOral.oralSubtype, equals(OralSubtype.tablets));
// Should throw exception when oral medication has no subtype
expect(
() => Medication(
name: 'Test Med',
dosage: '10mg',
startDate: DateTime(2023, 1, 1),
frequency: 1,
timeOfDay: [DateTime(2023, 1, 1, 8, 0)],
daysOfWeek: {'M'},
currentQuantity: 10,
refillThreshold: 5,
medicationType: MedicationType.oral,
oralSubtype: null,
),
throwsA(isA<MedicationException>()));
});
test('should validate that topical medications have topical subtype', () {
// Should succeed
final validTopical = Medication(
name: 'Test Med',
dosage: '10mg',
startDate: DateTime(2023, 1, 1),
frequency: 1,
timeOfDay: [DateTime(2023, 1, 1, 8, 0)],
daysOfWeek: {'M'},
currentQuantity: 10,
refillThreshold: 5,
medicationType: MedicationType.topical,
topicalSubtype: TopicalSubtype.gel,
);
expect(validTopical.topicalSubtype, equals(TopicalSubtype.gel));
// Should throw exception when topical medication has no subtype
expect(
() => Medication(
name: 'Test Med',
dosage: '10mg',
startDate: DateTime(2023, 1, 1),
frequency: 1,
timeOfDay: [DateTime(2023, 1, 1, 8, 0)],
daysOfWeek: {'M'},
currentQuantity: 10,
refillThreshold: 5,
medicationType: MedicationType.topical,
topicalSubtype: null,
),
throwsA(isA<MedicationException>()));
});
test('patch medication does not require subtypes', () {
// Should succeed
final validPatch = Medication(
name: 'Test Med',
dosage: '10mg',
startDate: DateTime(2023, 1, 1),
frequency: 1,
timeOfDay: [DateTime(2023, 1, 1, 8, 0)],
daysOfWeek: {'M'},
currentQuantity: 10,
refillThreshold: 5,
medicationType: MedicationType.patch,
);
expect(validPatch.medicationType, equals(MedicationType.patch));
expect(validPatch.oralSubtype, isNull);
expect(validPatch.topicalSubtype, isNull);
expect(validPatch.injectionDetails, isNull);
});
test('doctor and pharmacy fields are optional', () {
// Create medication with doctor and pharmacy
final medication = Medication(
name: 'Test Med',
dosage: '10mg',
startDate: DateTime(2023, 1, 1),
frequency: 1,
timeOfDay: [DateTime(2023, 1, 1, 8, 0)],
daysOfWeek: {'M'},
currentQuantity: 10,
refillThreshold: 5,
medicationType: MedicationType.oral,
oralSubtype: OralSubtype.tablets,
doctor: 'Dr. Smith',
pharmacy: 'City Pharmacy',
);
// Verify fields are set
expect(medication.doctor, 'Dr. Smith');
expect(medication.pharmacy, 'City Pharmacy');
});
test('JSON conversion preserves all fields', () {
// Create a complex medication object
final original = Medication(
name: 'Test Injectable',
dosage: '100mg',
startDate: DateTime(2023, 6, 15),
frequency: 1,
timeOfDay: [DateTime(2023, 6, 15, 9, 0)],
daysOfWeek: {'Su'},
currentQuantity: 5,
refillThreshold: 2,
medicationType: MedicationType.injection,
doctor: 'Dr. Jones',
pharmacy: 'Medical Supply Store',
injectionDetails: InjectionDetails(
drawingNeedleType: '18G',
drawingNeedleCount: 10,
drawingNeedleRefills: 2,
injectingNeedleType: '25G',
injectingNeedleCount: 8,
injectingNeedleRefills: 2,
syringeType: '3ml Luer Lock',
syringeCount: 12,
syringeRefills: 3,
injectionSiteNotes: 'Rotate injection sites',
frequency: InjectionFrequency.biweekly,
subtype: InjectionSubtype.intramuscular,
),
);
// Convert to JSON and back
final json = original.toJson();
final restored = Medication.fromJson(json);
// Verify all fields are preserved
expect(restored.name, equals(original.name));
expect(restored.dosage, equals(original.dosage));
expect(restored.medicationType, equals(original.medicationType));
expect(restored.doctor, equals(original.doctor));
expect(restored.pharmacy, equals(original.pharmacy));
// Check injection details
expect(restored.injectionDetails?.syringeType, equals('3ml Luer Lock'));
expect(restored.injectionDetails?.syringeCount, equals(12));
expect(restored.injectionDetails?.syringeRefills, equals(3));
expect(restored.injectionDetails?.subtype,
equals(InjectionSubtype.intramuscular));
});
});
}