import 'package:flutter_test/flutter_test.dart'; import 'package:tane/data/variety_repository.dart'; import 'package:tane/db/database.dart'; import 'package:tane/db/enums.dart'; import '../support/test_support.dart'; void main() { late AppDatabase db; late VarietyRepository repo; setUp(() { db = newTestDatabase(); repo = newTestRepository(db); }); tearDown(() async => db.close()); Future newLot({String? originName, String? originPlace}) async { final varietyId = await repo.addQuickVariety(label: 'Tomate rosa'); return repo.addLot( varietyId: varietyId, harvestYear: 2025, originName: originName, originPlace: originPlace, ); } group('recordCultivation', () { test('records a sown movement with defaults', () async { final lotId = await newLot(); final id = await repo.recordCultivation( lotId: lotId, type: MovementType.sown, ); expect(id, isNotEmpty); final history = await repo.lotHistory(lotId); final sown = history.where( (e) => e.movementType == MovementType.sown, ); expect(sown, hasLength(1)); expect(sown.first.kind, LotHistoryKind.movement); expect(sown.first.when, isNotNull); }); test('records a harvested movement with a note and date', () async { final lotId = await newLot(); await repo.recordCultivation( lotId: lotId, type: MovementType.harvested, occurredOn: DateTime(2026, 7, 1).millisecondsSinceEpoch, notes: 'great year', ); final history = await repo.lotHistory(lotId); final harvested = history.singleWhere( (e) => e.movementType == MovementType.harvested, ); expect(harvested.notes, 'great year'); expect( harvested.when, DateTime(2026, 7, 1).millisecondsSinceEpoch, ); }); test('rejects non-cultivation movement types', () async { final lotId = await newLot(); expect( () => repo.recordCultivation(lotId: lotId, type: MovementType.given), throwsA(isA()), ); }); }); group('lotHistory', () { test('starts with the lot creation entry carrying its origin', () async { final lotId = await newLot(originName: 'María', originPlace: 'Aiako'); final history = await repo.lotHistory(lotId); expect(history, isNotEmpty); // Most-recent first: creation is the last entry. final created = history.last; expect(created.kind, LotHistoryKind.created); expect(created.originName, 'María'); expect(created.originPlace, 'Aiako'); }); test('merges movements, germination tests and condition checks', () async { final lotId = await newLot(); await repo.addGerminationTest( lotId: lotId, testedOn: DateTime(2026, 2, 1).millisecondsSinceEpoch, sampleSize: 10, germinatedCount: 8, ); await repo.addConditionCheck( lotId: lotId, checkedOn: DateTime(2026, 3, 1).millisecondsSinceEpoch, containerCount: 2, desiccantState: DesiccantState.dry, ); await repo.recordCultivation( lotId: lotId, type: MovementType.sown, occurredOn: DateTime(2026, 4, 1).millisecondsSinceEpoch, ); await repo.recordHandover( lotId: lotId, direction: HandoverDirection.iGave, counterparty: 'Pepe', ); final history = await repo.lotHistory(lotId); expect(history.map((e) => e.kind).toSet(), { LotHistoryKind.created, LotHistoryKind.movement, LotHistoryKind.germinationTest, LotHistoryKind.conditionCheck, }); final germination = history.singleWhere( (e) => e.kind == LotHistoryKind.germinationTest, ); expect(germination.germinationRate, closeTo(0.8, 1e-9)); final check = history.singleWhere( (e) => e.kind == LotHistoryKind.conditionCheck, ); expect(check.containerCount, 2); // Most-recent first: the handover (today) leads, creation closes. expect(history.first.movementType, MovementType.given); expect(history.last.kind, LotHistoryKind.created); // The middle entries are ordered by their explicit dates, descending. final dated = history .where((e) => e.kind != LotHistoryKind.created) .toList(); for (var i = 0; i + 1 < dated.length; i++) { expect(dated[i].when ?? 0, greaterThanOrEqualTo(dated[i + 1].when ?? 0)); } }); test('includes garden outcomes as story lines', () async { final lotId = await newLot(); await repo.addGardenOutcome( lotId: lotId, year: 2026, rating: GardenOutcomeRating.good, notes: 'true to type, keeping it', ); final history = await repo.lotHistory(lotId); final outcome = history.singleWhere( (e) => e.kind == LotHistoryKind.gardenOutcome, ); expect(outcome.rating, GardenOutcomeRating.good); expect(outcome.year, 2026); expect(outcome.notes, 'true to type, keeping it'); }); test('ignores other lots', () async { final lotId = await newLot(); final otherLot = await newLot(); await repo.recordCultivation(lotId: otherLot, type: MovementType.sown); final history = await repo.lotHistory(lotId); expect( history.where((e) => e.kind == LotHistoryKind.movement), isEmpty, ); }); }); }