import 'package:flutter_test/flutter_test.dart'; import 'package:friendly_map/modules/kinship/kinship.dart'; const M = Gender.male, F = Gender.female; /// 시험용 가족. 나(남, 1990)와 아내, 아들, 양가 친척. KinGraph family() { final g = KinGraph(); void p(String id, Gender gen, int year) => g.put(KinPerson(id, gender: gen, birthYear: year)); p('me', M, 1990); p('father', M, 1960); p('mother', F, 1962); p('gf', M, 1930); // 친할아버지 p('gm', F, 1932); // 친할머니 p('mgm', F, 1935); // 외할머니 p('bigUncle', M, 1955); // 아버지의 형 p('bigAunt', F, 1957); // 큰아버지의 아내 p('aunt', F, 1965); // 아버지의 여동생(고모) p('mUncle', M, 1964); // 어머니의 남동생(외삼촌) p('mAunt', F, 1966); // 이모 p('cousinElder', M, 1985); // 큰아버지의 아들 p('cousinGojong', F, 1992); // 고모의 딸 p('cousinOe', M, 1995); // 외삼촌의 아들 p('sister', F, 1993); p('wife', F, 1991); p('wifeFather', M, 1962); p('wifeSister', F, 1994); p('son', M, 2020); p('daughterInLaw', F, 1990); p('grandson', M, 2045); for (final c in ['father', 'bigUncle', 'aunt']) { g.addParent(c, 'gf'); } g.addParent('father', 'gm'); g.addParent('bigUncle', 'gm'); g.addParent('aunt', 'gm'); g.addParent('mother', 'mgm'); g.addParent('mUncle', 'mgm'); g.addParent('mAunt', 'mgm'); g.addParent('me', 'father'); g.addParent('me', 'mother'); g.addParent('sister', 'father'); g.addParent('sister', 'mother'); g.addParent('cousinElder', 'bigUncle'); g.addParent('cousinGojong', 'aunt'); g.addParent('cousinOe', 'mUncle'); g.addParent('wife', 'wifeFather'); g.addParent('wifeSister', 'wifeFather'); g.addParent('son', 'me'); g.addParent('son', 'wife'); g.addParent('grandson', 'son'); g.addSpouse('me', 'wife'); g.addSpouse('father', 'mother'); g.addSpouse('gf', 'gm'); g.addSpouse('bigUncle', 'bigAunt'); g.addSpouse('son', 'daughterInLaw'); return g; } String t(KinGraph g, String a, String b) => relate(g, a, b).title; int? c(KinGraph g, String a, String b) => relate(g, a, b).chon; void main() { final g = family(); group('직계', () { test('부모·자녀 1촌, 조부모·손주 2촌', () { expect((t(g, 'me', 'father'), c(g, 'me', 'father')), ('아버지', 1)); expect((t(g, 'me', 'mother'), c(g, 'me', 'mother')), ('어머니', 1)); expect((t(g, 'me', 'son'), c(g, 'me', 'son')), ('아들', 1)); expect((t(g, 'me', 'gf'), c(g, 'me', 'gf')), ('친할아버지', 2)); expect(t(g, 'me', 'mgm'), '외할머니'); expect((t(g, 'me', 'grandson'), c(g, 'me', 'grandson')), ('손자', 2)); }); test('거꾸로도 맞다: 아들 입장에서 나는 아버지', () { expect(t(g, 'son', 'me'), '아버지'); expect(t(g, 'grandson', 'gf'), '고조할아버지'); // 손자 → 아들 → 나 → 아버지 → 할아버지: 4대 위 expect(t(g, 'son', 'gf'), '증조할아버지'); }); }); group('형제와 방계', () { test('형제자매는 2촌, 나이로 형·동생 구분', () { expect((t(g, 'me', 'sister'), c(g, 'me', 'sister')), ('여동생', 2)); expect(t(g, 'sister', 'me'), '오빠'); }); test('아버지 쪽 삼촌: 큰아버지·고모, 어머니 쪽: 외삼촌·이모 (모두 3촌)', () { expect((t(g, 'me', 'bigUncle'), c(g, 'me', 'bigUncle')), ('큰아버지', 3)); expect(t(g, 'me', 'aunt'), '고모'); expect(t(g, 'me', 'mUncle'), '외삼촌'); expect(t(g, 'me', 'mAunt'), '이모'); }); test('사촌은 4촌: 친사촌·고종사촌·외사촌, 나이에 따라 형·동생', () { expect((t(g, 'me', 'cousinElder'), c(g, 'me', 'cousinElder')), ('친사촌 형', 4)); expect(t(g, 'me', 'cousinGojong'), '고종사촌 여동생'); expect(t(g, 'me', 'cousinOe'), '외사촌 남동생'); }); test('내 아들 입장: 아버지의 사촌은 당숙(5촌), 큰아버지는 4촌 할아버지 항렬이 아니라 5촌이 아님을 구분', () { expect((t(g, 'son', 'cousinElder'), c(g, 'son', 'cousinElder')), ('당숙', 5)); expect(c(g, 'son', 'bigUncle'), 4); expect(c(g, 'son', 'sister'), 3); // 고모 expect(t(g, 'son', 'sister'), '고모'); }); test('조카: 나의 형제의 자녀는 3촌', () { final g2 = family(); g2.put(const KinPerson('nephew', gender: Gender.male, birthYear: 2018)); g2.addParent('nephew', 'sister'); expect((t(g2, 'me', 'nephew'), c(g2, 'me', 'nephew')), ('조카', 3)); }); }); group('인척', () { test('배우자 0촌, 며느리·사위 1촌', () { expect((t(g, 'me', 'wife'), c(g, 'me', 'wife')), ('아내', 0)); expect(t(g, 'wife', 'me'), '남편'); expect((t(g, 'me', 'daughterInLaw'), c(g, 'me', 'daughterInLaw')), ('며느리', 1)); }); test('아내의 부모는 장인, 아내의 동생은 처제', () { expect((t(g, 'me', 'wifeFather'), c(g, 'me', 'wifeFather')), ('장인', 1)); expect(t(g, 'me', 'wifeSister'), '처제'); expect(t(g, 'wife', 'father'), '시아버지'); }); test('큰아버지의 아내는 큰어머니(3촌)', () { expect((t(g, 'me', 'bigAunt'), c(g, 'me', 'bigAunt')), ('큰어머니', 3)); }); test('모르는 사이는 none', () { g.put(const KinPerson('stranger')); final r = relate(g, 'me', 'stranger'); expect(r.related, false); expect(r.chon, null); }); }); group('이름표·가계도 관리', () { test('label 은 촌수까지 읽기 좋게', () { expect(relate(g, 'me', 'bigUncle').label, '큰아버지 (3촌)'); expect(relate(g, 'me', 'wife').label, '아내'); expect(relate(g, 'me', 'me').label, '본인'); }); test('나이를 모르면 형·동생 대신 형제', () { final g3 = KinGraph(); g3.put(const KinPerson('me', gender: M)); g3.put(const KinPerson('x', gender: M)); g3.put(const KinPerson('p', gender: M)); g3.addParent('me', 'p'); g3.addParent('x', 'p'); expect(t(g3, 'me', 'x'), '형제'); }); test('부모 순환·셋째 부모는 거절', () { final g4 = KinGraph(); for (final id in ['a', 'b', 'c', 'd']) { g4.put(KinPerson(id)); } expect(g4.addParent('a', 'b'), true); expect(g4.addParent('b', 'a'), false); // 순환 expect(g4.addParent('a', 'c'), true); expect(g4.addParent('a', 'd'), false); // 부모는 최대 둘 expect(g4.addParent('a', 'a'), false); }); test('글자로 저장했다 복원하면 같은 계산, 깨진 글자는 빈 가계도', () { final back = KinGraph.fromJson(g.toJson()); expect(t(back, 'me', 'bigUncle'), '큰아버지'); expect(t(back, 'me', 'wifeFather'), '장인'); expect(KinGraph.fromJson('{깨짐').people, isEmpty); expect(KinGraph.fromJson(null).people, isEmpty); }); test('사람을 지우면 연결도 사라진다', () { final g5 = KinGraph.fromJson(g.toJson()); g5.removePerson('father'); expect(g5.has('father'), false); expect(g5.parentsOf('me').contains('father'), false); expect(relate(g5, 'me', 'bigUncle').related, false); }); }); }