import 'package:flutter_test/flutter_test.dart'; import 'package:life_helper/ai/tools/habit_tools.dart'; import 'package:life_helper/ai/tools/tracker_tools.dart'; import 'package:life_helper/ai/tools/tool_envelope.dart'; import '_tool_test_helpers.dart'; void main() { group('log_tracker_entry', () { test('정상 done 기록', () async { final ctx = await bootstrapToolDeps(); addTearDown(() => ctx.db.close()); final addRes = await addHabitTool.handler({ 'protocol_id': 'morning_sunlight', 'frame_level': 'L2', 'framed_text': '햇빛', }, ctx.deps); final habitId = (addRes as ToolOk).data['habit_id'] as String; final r = await logTrackerEntryTool.handler({ 'habit_id': habitId, 'value': 'done', 'date': '2026-06-15', }, ctx.deps); expect(r, isA(), reason: '$r'); final data = (r as ToolOk).data; expect(data['habit_id'], habitId); expect(data['value'], 'done'); }); test('value 유효성', () async { final ctx = await bootstrapToolDeps(); addTearDown(() => ctx.db.close()); final r = await logTrackerEntryTool.handler({ 'habit_id': 'whatever', 'value': 'maybe', }, ctx.deps); expect(r, isA()); expect((r as ToolErr).code, 'validation'); }); test('미존재 habit_id', () async { final ctx = await bootstrapToolDeps(); addTearDown(() => ctx.db.close()); final r = await logTrackerEntryTool.handler({ 'habit_id': 'hb_no_such', 'value': 'done', }, ctx.deps); expect(r, isA()); expect((r as ToolErr).code, 'not_found'); }); test('같은 (habit_id, date) 중복 → duplicate', () async { final ctx = await bootstrapToolDeps(); addTearDown(() => ctx.db.close()); final addRes = await addHabitTool.handler({ 'protocol_id': 'morning_sunlight', 'frame_level': 'L2', 'framed_text': '햇빛', }, ctx.deps); final habitId = (addRes as ToolOk).data['habit_id'] as String; await logTrackerEntryTool.handler({ 'habit_id': habitId, 'value': 'done', 'date': '2026-06-15', }, ctx.deps); final r2 = await logTrackerEntryTool.handler({ 'habit_id': habitId, 'value': 'blank', 'date': '2026-06-15', }, ctx.deps); expect(r2, isA()); expect((r2 as ToolErr).code, 'duplicate'); }); test('date 형식 오류', () async { final ctx = await bootstrapToolDeps(); addTearDown(() => ctx.db.close()); final r = await logTrackerEntryTool.handler({ 'habit_id': 'h', 'value': 'done', 'date': '2026/06/15', }, ctx.deps); expect(r, isA()); expect((r as ToolErr).code, 'validation'); }); }); group('get_streak', () { test('습관 없음 → not_found', () async { final ctx = await bootstrapToolDeps(); addTearDown(() => ctx.db.close()); final r = await getStreakTool.handler({'habit_id': 'hb_no'}, ctx.deps); expect(r, isA()); expect((r as ToolErr).code, 'not_found'); }); test('정상 — 기록 없을 때 0 streak', () async { final ctx = await bootstrapToolDeps(); addTearDown(() => ctx.db.close()); final addRes = await addHabitTool.handler({ 'protocol_id': 'morning_sunlight', 'frame_level': 'L2', 'framed_text': '햇빛', }, ctx.deps); final habitId = (addRes as ToolOk).data['habit_id'] as String; final r = await getStreakTool.handler({'habit_id': habitId}, ctx.deps); expect(r, isA(), reason: '$r'); final data = (r as ToolOk).data; expect(data['current_streak'], 0); expect(data['tier'], isNotNull); }); }); }