217 lines
9.6 KiB
Dart
217 lines
9.6 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:friendly_map/modules/core/core.dart';
|
||
import 'package:friendly_map/modules/groups/groups.dart';
|
||
|
||
void main() {
|
||
group('그룹 목록', () {
|
||
test('처음에는 맨 위에 가족·학교·회사·그룹·여행 네 개', () {
|
||
final b = GroupBook();
|
||
expect(b.roots.map((g) => g.name), ['가족', '학교', '회사', '그룹·여행']);
|
||
expect(b.roots.map((g) => g.kind), [CardKinds.family, CardKinds.school, CardKinds.company, CardKinds.group]);
|
||
});
|
||
|
||
test('처음 하위 그룹: 학교는 초등~대학원, 가족은 친가·외가·처가·시가·촌수 모름', () {
|
||
final b = GroupBook();
|
||
expect(b.children(CardKinds.school).map((g) => g.name), ['초등학교', '중학교', '고등학교', '대학교', '대학원']);
|
||
expect(b.children(CardKinds.family).map((g) => g.name), ['친가', '외가', '처가·시가', '친척(촌수 모름)']);
|
||
expect(b.byId(Group.unknownRelatives)!.parent, CardKinds.family);
|
||
expect(b.children(CardKinds.company), isEmpty);
|
||
expect(b.groups.indexOf(b.byId('school.high')!), greaterThan(b.groups.indexOf(b.byId(CardKinds.school)!)));
|
||
});
|
||
|
||
test('더하기·이름 바꾸기·지우기, 빈 이름과 겹치는 이름은 거절', () {
|
||
final b = GroupBook();
|
||
final g = b.add(' 동호회 ', CardKinds.group)!;
|
||
expect(g.name, '동호회');
|
||
expect(b.add('', CardKinds.group), isNull);
|
||
expect(b.add('가족', CardKinds.family), isNull);
|
||
expect(b.rename(g.id, '등산 모임'), isTrue);
|
||
expect(b.rename(g.id, '학교'), isFalse);
|
||
expect(b.rename(g.id, '등산 모임'), isTrue, reason: '자기 이름 그대로는 괜찮다');
|
||
expect(b.byId(g.id)!.name, '등산 모임');
|
||
expect(b.remove(g.id), {g.id});
|
||
expect(b.byId(g.id), isNull);
|
||
expect(b.remove('없음'), isEmpty);
|
||
});
|
||
|
||
test('이름은 20자까지 자른다', () {
|
||
final b = GroupBook();
|
||
expect(b.add('가' * 30, CardKinds.group)!.name.length, 20);
|
||
});
|
||
|
||
test('순서 바꾸기', () {
|
||
final b = GroupBook();
|
||
b.move(CardKinds.group, 0);
|
||
expect(b.groups.first.id, CardKinds.group);
|
||
b.move(CardKinds.group, 99);
|
||
expect(b.groups.last.id, CardKinds.group);
|
||
});
|
||
|
||
test('구성원 더하기·빼기, 사람이 든 그룹, 사람 지우기', () {
|
||
final b = GroupBook();
|
||
expect(b.addMembers(CardKinds.family, ['a', 'b']), 2);
|
||
expect(b.addMembers(CardKinds.family, ['b', 'c']), 1, reason: '이미 든 사람은 다시 세지 않는다');
|
||
b.addMembers(CardKinds.school, ['a']);
|
||
expect(b.groupsOf('a').map((g) => g.id), [CardKinds.family, CardKinds.school]);
|
||
expect(b.removeMember(CardKinds.family, 'c'), isTrue);
|
||
expect(b.removeMember(CardKinds.family, 'c'), isFalse);
|
||
b.forgetPerson('a');
|
||
expect(b.groupsOf('a'), isEmpty);
|
||
expect(b.byId(CardKinds.family)!.members, {'b'});
|
||
});
|
||
|
||
test('잠긴 그룹이 닫혀 있으면 구성원을 숨긴다 (다른 그룹에도 있어도)', () async {
|
||
final b = GroupBook();
|
||
b.addMembers(CardKinds.family, ['a', 'b']);
|
||
b.addMembers(CardKinds.school, ['a', 'c']);
|
||
b.setLock(CardKinds.family, await Pin.make('1234', iterations: 10));
|
||
expect(b.hiddenPeople((g) => true), {'a', 'b'});
|
||
expect(b.hiddenPeople((g) => false), isEmpty);
|
||
});
|
||
|
||
test('글자로 저장했다 되살리면 같고, 깨진 글자는 처음 그룹', () async {
|
||
final b = GroupBook(relockMinutes: 10);
|
||
final g = b.add('동호회', CardKinds.group)!;
|
||
b.addMembers(g.id, ['x']);
|
||
b.setLock(g.id, await Pin.make('abcd', iterations: 10));
|
||
final c = GroupBook.fromJson(b.toJson());
|
||
expect(c.groups.map((x) => x.name), b.groups.map((x) => x.name));
|
||
expect(c.byId(g.id)!.members, {'x'});
|
||
expect(c.byId(g.id)!.locked, isTrue);
|
||
expect(c.relockMinutes, 10);
|
||
expect(c.add('새 그룹', CardKinds.group)!.id, isNot(g.id), reason: '새 번호표는 겹치지 않는다');
|
||
expect(GroupBook.fromJson('{깨짐').roots.length, 4);
|
||
expect(GroupBook.fromJson(null).roots.length, 4);
|
||
});
|
||
});
|
||
|
||
group('비밀번호', () {
|
||
test('맞는 비밀번호만 통과, 원문은 남지 않는다', () async {
|
||
final h = await Pin.make('2580', iterations: 100);
|
||
expect(await Pin.verify('2580', h), isTrue);
|
||
expect(await Pin.verify('2581', h), isFalse);
|
||
expect(h.toJson().toString(), isNot(contains('2580')));
|
||
final again = await Pin.make('2580', iterations: 100);
|
||
expect(again.salt, isNot(h.salt), reason: '같은 비밀번호도 소금이 달라 다른 값');
|
||
});
|
||
|
||
test('짧거나 길거나 앞뒤 빈칸이면 안내', () {
|
||
expect(Pin.problem('123'), isNotNull);
|
||
expect(Pin.problem('1' * 17), isNotNull);
|
||
expect(Pin.problem(' 1234'), isNotNull);
|
||
expect(Pin.problem('1234'), isNull);
|
||
});
|
||
|
||
test('깨진 저장값은 통과하지 않는다', () async {
|
||
expect(await Pin.verify('1234', const PinHash('!!', '??', 10)), isFalse);
|
||
expect(PinHash.fromJson({'salt': 1}), isNull);
|
||
});
|
||
});
|
||
|
||
group('여러 번 틀리면 기다리기', () {
|
||
test('5번까지는 바로, 그 뒤로 30초·60초…', () {
|
||
final g = UnlockGuard();
|
||
for (var i = 0; i < 4; i++) {
|
||
g.failure(0);
|
||
expect(g.waitLeft(0), 0);
|
||
}
|
||
expect(g.triesLeft(), 1);
|
||
g.failure(0);
|
||
expect(g.waitLeft(0), 3000);
|
||
expect(g.waitLeft(3000), 0);
|
||
g.failure(3000);
|
||
expect(g.waitLeft(3000), 6000);
|
||
g.success();
|
||
expect(g.waitLeft(3000), 0);
|
||
expect(g.triesLeft(), 5);
|
||
});
|
||
|
||
test('기다림은 1시간을 넘지 않는다', () {
|
||
final g = UnlockGuard();
|
||
for (var i = 0; i < 40; i++) {
|
||
g.failure(0);
|
||
}
|
||
expect(g.waitLeft(0), 360000);
|
||
});
|
||
});
|
||
|
||
group('하위 그룹', () {
|
||
test('회사 > 한빛전자 > 결제팀, 같은 이름은 부모가 다르면 괜찮다', () {
|
||
final b = GroupBook();
|
||
final hb = b.add('한빛전자', CardKinds.company, parent: CardKinds.company)!;
|
||
final pay = b.add('결제팀', CardKinds.company, parent: hb.id)!;
|
||
final other = b.add('누리소프트', CardKinds.company, parent: CardKinds.company)!;
|
||
expect(b.add('결제팀', CardKinds.company, parent: other.id), isNotNull);
|
||
expect(b.add('결제팀', CardKinds.company, parent: hb.id), isNull);
|
||
expect(b.path(pay.id), '회사 › 한빛전자 › 결제팀');
|
||
expect(b.depth(pay.id), 3);
|
||
expect(b.ancestors(pay.id).map((g) => g.id), [hb.id, CardKinds.company]);
|
||
expect(b.add('없는 부모 아래', CardKinds.group, parent: '없음'), isNull);
|
||
});
|
||
|
||
test('4단까지만 만들 수 있다', () {
|
||
final b = GroupBook();
|
||
final a = b.add('2단', CardKinds.group, parent: CardKinds.group)!;
|
||
final c = b.add('3단', CardKinds.group, parent: a.id)!;
|
||
final d = b.add('4단', CardKinds.group, parent: c.id)!;
|
||
expect(b.add('5단', CardKinds.group, parent: d.id), isNull);
|
||
});
|
||
|
||
test('하위까지 합친 구성원, 지우면 하위 그룹도 함께', () {
|
||
final b = GroupBook();
|
||
b.addMembers(CardKinds.school, ['a']);
|
||
b.addMembers('school.high', ['b', 'a']);
|
||
b.addMembers('school.university', ['c']);
|
||
expect(b.membersDeep(CardKinds.school), {'a', 'b', 'c'});
|
||
expect(b.remove(CardKinds.school), containsAll([CardKinds.school, 'school.high', 'school.graduate']));
|
||
expect(b.byId('school.high'), isNull);
|
||
expect(b.roots.length, 3);
|
||
});
|
||
|
||
test('잠긴 부모가 닫히면 하위 그룹 사람도 숨긴다', () async {
|
||
final b = GroupBook();
|
||
b.addMembers('family.maternal', ['m']);
|
||
b.setLock(CardKinds.family, await Pin.make('1234', iterations: 10));
|
||
expect(b.hiddenPeople((g) => true), {'m'});
|
||
});
|
||
|
||
test('같은 부모 아래에서만 순서가 바뀐다', () {
|
||
final b = GroupBook();
|
||
b.move('school.graduate', 0);
|
||
expect(b.children(CardKinds.school).first.id, 'school.graduate');
|
||
expect(b.roots.first.id, CardKinds.family);
|
||
});
|
||
|
||
test('저장하면 나무 모양이 유지되고, 없는 부모·돌고 도는 부모는 맨 위로', () {
|
||
final b = GroupBook();
|
||
final hb = b.add('한빛전자', CardKinds.company, parent: CardKinds.company)!;
|
||
final c = GroupBook.fromJson(b.toJson());
|
||
expect(c.byId(hb.id)!.parent, CardKinds.company);
|
||
const bad = '{"groups":[{"id":"x","name":"X","parent":"y"},{"id":"y","name":"Y","parent":"x"},{"id":"z","name":"Z","parent":"없음"}]}';
|
||
final d = GroupBook.fromJson(bad);
|
||
expect(d.groups.map((g) => g.id).toSet(), {'x', 'y', 'z'});
|
||
expect(d.byId('z')!.parent, isNull);
|
||
});
|
||
});
|
||
|
||
test('이전 구성원: 흐리게 남기고, 다시 넣으면 구성원으로, 잠긴 그룹이 닫히면 숨김, 저장 유지', () async {
|
||
final b = GroupBook();
|
||
b.addMembers(CardKinds.company, ['a']);
|
||
expect(b.markFormer(CardKinds.company, 'a'), isTrue);
|
||
expect(b.markFormer(CardKinds.company, 'a'), isFalse);
|
||
expect(b.byId(CardKinds.company)!.members, isEmpty);
|
||
expect(b.byId(CardKinds.company)!.formers, {'a'});
|
||
expect(GroupBook.fromJson(b.toJson()).byId(CardKinds.company)!.formers, {'a'});
|
||
b.setLock(CardKinds.company, await Pin.make('1234', iterations: 10));
|
||
expect(b.hiddenPeople((g) => true), {'a'});
|
||
b.addMembers(CardKinds.company, ['a']);
|
||
expect(b.byId(CardKinds.company)!.formers, isEmpty);
|
||
b.markFormer(CardKinds.company, 'a');
|
||
expect(b.removeFormer(CardKinds.company, 'a'), isTrue);
|
||
b.addMembers(CardKinds.school, ['z']);
|
||
b.markFormer(CardKinds.school, 'z');
|
||
b.forgetPerson('z');
|
||
expect(b.byId(CardKinds.school)!.formers, isEmpty);
|
||
});
|
||
}
|