import 'package:flutter_test/flutter_test.dart'; import 'package:friendly_map/modules/events/events.dart'; void main() { // 파이썬 korean-lunar-calendar 로 미리 뽑아 둔 무작위 60쌍과 맞춰 본다. final pairs = <(DateTime, int, int, int, bool)>[ (DateTime(2010, 2, 7), 2009, 12, 24, false), (DateTime(1979, 1, 25), 1978, 12, 27, false), (DateTime(2022, 11, 4), 2022, 10, 11, false), (DateTime(1960, 8, 30), 1960, 7, 9, false), (DateTime(1964, 12, 30), 1964, 11, 27, false), (DateTime(2048, 2, 25), 2048, 1, 12, false), (DateTime(1968, 11, 20), 1968, 10, 1, false), (DateTime(2017, 8, 12), 2017, 6, 21, false), (DateTime(1962, 5, 29), 1962, 4, 26, false), (DateTime(2043, 1, 18), 2042, 12, 8, false), (DateTime(1990, 7, 10), 1990, 5, 18, true), (DateTime(1958, 9, 23), 1958, 8, 11, false), (DateTime(1967, 6, 3), 1967, 4, 26, false), (DateTime(2029, 10, 22), 2029, 9, 15, false), (DateTime(2027, 1, 12), 2026, 12, 5, false), (DateTime(1964, 7, 14), 1964, 6, 6, false), (DateTime(1995, 3, 8), 1995, 2, 8, false), (DateTime(1968, 4, 10), 1968, 3, 13, false), (DateTime(2028, 3, 3), 2028, 2, 8, false), (DateTime(1962, 8, 9), 1962, 7, 10, false), (DateTime(1974, 3, 19), 1974, 2, 26, false), (DateTime(1992, 1, 21), 1991, 12, 17, false), (DateTime(1963, 2, 6), 1963, 1, 13, false), (DateTime(2023, 3, 5), 2023, 2, 14, false), (DateTime(1960, 11, 23), 1960, 10, 5, false), (DateTime(1991, 9, 1), 1991, 7, 23, false), (DateTime(1960, 5, 10), 1960, 4, 15, false), (DateTime(1975, 11, 23), 1975, 10, 21, false), (DateTime(2003, 12, 18), 2003, 11, 25, false), (DateTime(2027, 3, 16), 2027, 2, 9, false), (DateTime(1977, 11, 18), 1977, 10, 8, false), (DateTime(1973, 2, 18), 1973, 1, 16, false), (DateTime(2007, 5, 8), 2007, 3, 22, false), (DateTime(1984, 6, 5), 1984, 5, 6, false), (DateTime(1970, 6, 28), 1970, 5, 25, false), (DateTime(1985, 9, 16), 1985, 8, 2, false), (DateTime(2018, 10, 26), 2018, 9, 18, false), (DateTime(1969, 6, 25), 1969, 5, 11, false), (DateTime(1963, 4, 7), 1963, 3, 14, false), (DateTime(1962, 9, 11), 1962, 8, 13, false), (DateTime(1988, 12, 14), 1988, 11, 6, false), (DateTime(2041, 1, 26), 2040, 12, 24, false), (DateTime(2047, 5, 28), 2047, 5, 4, false), (DateTime(2028, 9, 20), 2028, 8, 2, false), (DateTime(2008, 5, 13), 2008, 4, 9, false), (DateTime(2035, 7, 17), 2035, 6, 13, false), (DateTime(2033, 4, 24), 2033, 3, 25, false), (DateTime(2016, 11, 16), 2016, 10, 17, false), (DateTime(2005, 10, 14), 2005, 9, 12, false), (DateTime(1996, 7, 28), 1996, 6, 13, false), (DateTime(1984, 4, 3), 1984, 3, 3, false), (DateTime(1995, 10, 19), 1995, 8, 25, true), (DateTime(1966, 9, 8), 1966, 7, 24, false), (DateTime(2005, 11, 15), 2005, 10, 14, false), (DateTime(2046, 3, 27), 2046, 2, 20, false), (DateTime(2040, 11, 1), 2040, 9, 27, false), (DateTime(2013, 8, 18), 2013, 7, 12, false), (DateTime(2032, 7, 13), 2032, 6, 7, false), (DateTime(2003, 8, 31), 2003, 8, 4, false), (DateTime(1965, 2, 18), 1965, 1, 17, false), ]; group('음력 변환', () { test('무작위 60일을 양력 → 음력 → 양력으로 왕복해도 같다', () { for (final (solar, y, m, d, leap) in pairs) { expect(solarToLunar(solar), LunarDate(y, m, d, leap: leap), reason: '$solar'); expect(lunarToSolar(y, m, d, leap: leap), solar, reason: '$y-$m-$d'); } }); test('알려진 날: 2026 설날=2/17, 추석=9/25, 2026-10-26=음력 9/16', () { expect(lunarToSolar(2026, 1, 1), DateTime(2026, 2, 17)); expect(lunarToSolar(2026, 8, 15), DateTime(2026, 9, 25)); expect(solarToLunar(DateTime(2026, 10, 26)), const LunarDate(2026, 9, 16)); }); test('윤달과 표 밖', () { expect(lunarToSolar(1952, 5, 1, leap: true), isNotNull); expect(lunarToSolar(2026, 5, 1, leap: true), isNull); // 2026 은 윤달 없음 expect(lunarToSolar(1900, 1, 1), isNull); expect(solarToLunar(DateTime(1940, 1, 1)), isNull); }); }); group('음력 일정', () { test('음력 기일은 올해 지났으면 내년 양력 날로, 해가 어긋나는 연말 음력도 찾는다', () { const e = FamilyEvent(personId: 'a', kind: EventKind.memorial, month: 8, day: 15, lunar: true); expect(e.nextFrom(DateTime(2026, 10, 26)), lunarToSolar(2027, 8, 15)); expect(e.nextFrom(DateTime(2026, 9, 25)), DateTime(2026, 9, 25)); // 음력 12월 말은 양력으로는 다음 해 1~2월 const f = FamilyEvent(personId: 'a', kind: EventKind.memorial, month: 12, day: 25, lunar: true); final next = f.nextFrom(DateTime(2026, 1, 10)); expect(next.isBefore(DateTime(2026, 1, 10)), false); expect(solarToLunar(next), const LunarDate(2025, 12, 25)); }); test('윤달 기일은 윤달이 든 해에만 잡힌다', () { // 1952년에는 윤5월이 있었다. 2025년에는 윤6월이 있었다. const e = FamilyEvent(personId: 'a', kind: EventKind.memorial, month: 6, day: 10, lunar: true, leap: true); final next = e.nextFrom(DateTime(2026, 1, 1)); final l = solarToLunar(next)!; expect((l.month, l.day, l.leap), (6, 10, true)); expect(next.year > 2026, true); // 2026 에는 윤달 없음 → 이후 윤6월 해 expect(e.label('할머니'), '할머니 기일(음력 윤달)'); expect(e.key.contains('LL'), true); }); test('라벨·키에 음력 표시, 30일이 없는 달이면 마지막 날', () { const e = FamilyEvent(personId: 'a', kind: EventKind.memorial, month: 8, day: 15, lunar: true); expect(e.label('할아버지'), '할아버지 기일(음력)'); expect(e.key.contains('L'), true); final d29 = lunarToSolar(2026, 1, 30); // 정월은 29일까지일 수 있다 expect(d29, isNotNull); }); }); }