import 'package:flutter_test/flutter_test.dart'; import 'package:tasq/models/programmer_task_work_log.model.dart'; import 'package:tasq/utils/app_time.dart'; import 'package:tasq/utils/programmer_task_ledger.dart'; import 'package:tasq/utils/task_duration.dart'; ProgrammerTaskWorkLog _log(String author, int? minutes) => ProgrammerTaskWorkLog( id: 'l-$author-$minutes', taskId: 't1', authorId: author, description: 'work', minutes: minutes, createdAt: DateTime.utc(2026, 1, 1), ); void main() { setUpAll(AppTime.initialize); group('computeTaskLedger', () { test('assignee only (no work logs)', () { final ledger = computeTaskLedger( assigneeId: 'a', assigneeDuration: const Duration(hours: 1), workLogs: const [], ); expect(ledger.assignee?.duration, const Duration(hours: 1)); expect(ledger.helpers, isEmpty); expect(ledger.total, const Duration(hours: 1)); }); test('sums helper minutes per person; assignee notes excluded', () { final ledger = computeTaskLedger( assigneeId: 'a', assigneeDuration: const Duration(minutes: 60), workLogs: [ _log('h1', 30), _log('h1', 15), _log('h2', 20), _log('a', null), // assignee progress note — no minutes, excluded _log('a', 99), // even if an assignee row had minutes, exclude it ], ); expect(ledger.assignee?.duration, const Duration(minutes: 60)); final byUser = {for (final e in ledger.helpers) e.userId: e.duration}; expect(byUser['h1'], const Duration(minutes: 45)); expect(byUser['h2'], const Duration(minutes: 20)); expect(byUser.containsKey('a'), isFalse); expect(ledger.total, const Duration(minutes: 60 + 45 + 20)); }); test('helpers sorted by descending duration', () { final ledger = computeTaskLedger( assigneeId: 'a', assigneeDuration: Duration.zero, workLogs: [_log('h1', 10), _log('h2', 40)], ); expect(ledger.helpers.first.userId, 'h2'); }); test('no assignee id → assignee entry is null', () { final ledger = computeTaskLedger( assigneeId: null, assigneeDuration: const Duration(hours: 5), workLogs: [_log('h1', 30)], ); expect(ledger.assignee, isNull); expect(ledger.total, const Duration(minutes: 30)); }); }); group('computeEffectiveDuration adjustment', () { final base = DateTime.utc(2026, 1, 1, 9); test('subtracts the adjustment', () { final worked = computeEffectiveDuration( fallbackStartedAt: base, endAt: base.add(const Duration(hours: 2)), events: const [], adjustment: const Duration(minutes: 30), ); expect(worked, const Duration(hours: 1, minutes: 30)); }); test('clamps to zero when the adjustment exceeds worked time', () { final worked = computeEffectiveDuration( fallbackStartedAt: base, endAt: base.add(const Duration(minutes: 20)), events: const [], adjustment: const Duration(hours: 1), ); expect(worked, Duration.zero); }); test('default adjustment is zero (existing behavior unchanged)', () { final worked = computeEffectiveDuration( fallbackStartedAt: base, endAt: base.add(const Duration(hours: 1)), events: const [], ); expect(worked, const Duration(hours: 1)); }); }); }