frindlymap/test/app_test.dart

330 lines
15 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:friendly_map/modules/app/app.dart';
import 'package:friendly_map/modules/platform/platform.dart';
import 'package:friendly_map/modules/storage/storage.dart';
import 'package:friendly_map/modules/transport/transport.dart';
import 'support/app_device.dart';
const pa = '+821011112222';
const pb = '+821022223333';
Future<(AppDevice, AppDevice)> pair({String? modeB}) async {
final hub = MemoryHub();
final a = await AppDevice.create(hub, '010-1111-2222', pa, '가');
final b = await AppDevice.create(hub, '010-2222-3333', pb, '나');
if (modeB != null) await b.app.settings.update(exchangeMode: modeB);
return (a, b);
}
Future<void> befriend(AppDevice a, AppDevice b) async {
await a.app.friends.add(b.phone, b.name);
await AppDevice.settleAll();
await b.app.friends.accept(a.phone);
await AppDevice.settleAll();
}
void main() {
group('처음 시작', () {
test('번호·이름을 정하면 종류별 기본 명함 5장이 생기고, 개인 명함만 새 친구에게 기본 공유', () async {
final (a, _) = await pair();
final cards = await a.app.cards.mine();
expect(cards.map((c) => c.kind).toList(), ['personal', 'company', 'school', 'group', 'family']);
expect(cards.where((c) => c.shareDefault).map((c) => c.kind).toList(), ['personal']);
expect(decodeFields(cards.first.fieldsJson)['name'], '가');
expect((await a.app.profile.me())!.phone, pa);
});
test('올바르지 않은 번호·이름은 거절', () async {
final (a, _) = await pair();
expect(await a.app.profile.setUp('abc', '가'), null);
expect(await a.app.profile.setUp('010-1111-2222', ' '), null);
});
});
group('친구 추가와 명함 교환', () {
test('요청 후 수락하면 서로 키를 알고, 개인 명함이 서로에게 간다', () async {
final (a, b) = await pair();
final added = await a.app.friends.add(pb, '나');
expect(added!.publicKey, null);
await AppDevice.settleAll();
final req = (await b.app.friends.requests()).single;
expect(req.phone, pa);
expect(req.name, '가');
await b.app.friends.accept(pa);
await AppDevice.settleAll();
final bOfA = (await a.app.friends.person(added.id))!;
expect(bOfA.publicKey, b.key);
final aOfB = (await b.app.friends.people()).single;
expect(aOfB.publicKey, a.key);
final got = await b.app.deps.storage.receivedCards.byPerson(aOfB.id);
expect(got.single.kind, 'personal');
expect(await b.app.friends.requests(), isEmpty);
final back = await a.app.deps.storage.receivedCards.byPerson(bOfA.id);
expect(back.single.kind, 'personal');
});
test('자동 수락 설정이면 요청 없이 바로 친구가 됨', () async {
final (a, b) = await pair(modeB: 'auto');
final added = await a.app.friends.add(pb, '나');
await AppDevice.settleAll();
expect(await b.app.friends.requests(), isEmpty);
expect((await b.app.friends.people()).single.phone, pa);
expect((await a.app.friends.person(added!.id))!.publicKey, b.key);
});
test('거절하면 친구가 되지 않음', () async {
final (a, b) = await pair();
await a.app.friends.add(pb, '나');
await AppDevice.settleAll();
await b.app.friends.decline(pa);
expect(await b.app.friends.requests(), isEmpty);
expect(await b.app.friends.people(), isEmpty);
});
test('QR 로 추가하면 키를 바로 알고, 내 QR 은 읽으면 같은 정보', () async {
final (a, b) = await pair();
final qr = (await b.app.friends.myQr())!.encode();
final p = await a.app.friends.addFromQr(qr);
expect(p!.phone, pb);
expect(p.publicKey, b.key);
expect(await a.app.friends.addFromQr('https://x.y'), null);
});
test('번호 확인: 형식 오류, 내 번호, 같은 번호·이름 변경 후보', () async {
final (a, b) = await pair();
expect((await a.app.friends.check('abc', '나')).error, isNotNull);
expect((await a.app.friends.check('010-1111-2222', '나')).error, '내 번호예요');
await a.app.friends.add(pb, '나');
final r = await a.app.friends.check('010 2222 3333', '나 아님');
expect(r.match!.kind, MatchKind.nameDiffers);
final c = await a.app.friends.check('010-9999-8888', '나');
expect(c.match!.kind, MatchKind.phoneDiffers);
final same = await a.app.friends.add(c.phone!, '나', samePersonId: c.match!.candidates.first.id);
expect(same!.phone, '+821099998888');
expect(await a.app.deps.storage.people.byPhone(pb), isNotNull); // 이전 번호로도 찾아짐
expect(b.phone, pb);
});
});
group('숨기기·근처 사람', () {
test('모든 정보 숨기기를 켜면 모르는 사람의 요청은 쌓이지 않고, 아는 사람은 그대로', () async {
final (a, b) = await pair();
await b.app.settings.setHideAll(true);
expect(await b.app.settings.hideAll(), true);
await a.app.friends.add(pb, '나');
await AppDevice.settleAll();
expect(await b.app.friends.requests(), isEmpty);
await b.app.settings.setHideAll(false);
await a.app.friends.add(pb, '나');
await AppDevice.settleAll();
expect((await b.app.friends.requests()).single.phone, pa);
});
test('근처에서 번호로만 추가한 사람은 답 인사가 오면 진짜 이름으로 바뀜', () async {
final (a, b) = await pair(modeB: 'auto');
final p = await a.app.friends.add(pb, pb); // 이름 대신 번호
expect(p!.name, pb);
await AppDevice.settleAll();
expect((await a.app.friends.person(p.id))!.name, '나');
});
});
group('수락 전에 정한 공유', () {
test('상대가 수락하기 전에 고른 회사 명함도 수락 뒤에 전달됨', () async {
final (a, b) = await pair();
final added = await a.app.friends.add(pb, '나');
final company = (await a.app.cards.mine()).firstWhere((c) => c.kind == 'company');
await a.app.cards.shareWith(added!.id, [company.id]); // 아직 키를 모름
await AppDevice.settleAll();
await b.app.friends.accept(pa);
await AppDevice.settleAll();
final aOfB = (await b.app.friends.people()).single;
final kinds = (await b.app.network.receivedCards(aOfB.id)).map((c) => c.kind).toSet();
expect(kinds, {'personal', 'company'});
});
});
group('근처 사람', () {
test('발견한 사람이 보이고, 번호로 추가하면 친구 목록에 들어가며 나 자신은 빠짐', () async {
final lan = FakeLan();
final hub = MemoryHub();
final a = await AppDevice.create(hub, '010-1111-2222', pa, '가', lan: lan);
await AppDevice.create(hub, '010-2222-3333', pb, '나');
lan.ctl.add(const LanPeer(phone: pa, host: '10.0.0.1', port: 1));
lan.ctl.add(const LanPeer(phone: pb, host: '10.0.0.2', port: 2));
final near = await a.app.friends.nearby();
expect(near.map((e) => e.phone).toList(), [pb]);
expect(near.single.known, null);
final p = await a.app.friends.addNearby(pb);
expect(p!.name, pb);
expect((await a.app.friends.nearby()).single.known!.id, p.id);
});
});
group('명함 공유', () {
test('회사 명함을 골라 공유하면 상대가 받고, 고치면 다시 보내기 전까지 상대 것은 그대로', () async {
final (a, b) = await pair();
await befriend(a, b);
final bOfA = (await a.app.friends.people()).single;
final company = (await a.app.cards.mine()).firstWhere((c) => c.kind == 'company');
await a.app.cards.edit(company.id, fields: {'name': '가', 'company': '한빛'});
expect(await a.app.cards.shareWith(bOfA.id, [company.id]), 1);
expect(await a.app.cards.shareWith(bOfA.id, [company.id]), 0); // 이미 공유 중
await AppDevice.settleAll();
final aOfB = (await b.app.friends.people()).single;
var got = (await b.app.deps.storage.receivedCards.byPerson(aOfB.id)).firstWhere((c) => c.kind == 'company');
expect(decodeFields(got.fieldsJson)['company'], '한빛');
await a.app.cards.edit(company.id, fields: {'name': '가', 'company': '새빛'});
await AppDevice.settleAll();
got = (await b.app.deps.storage.receivedCards.byPerson(aOfB.id)).firstWhere((c) => c.kind == 'company');
expect(decodeFields(got.fieldsJson)['company'], '한빛'); // 아직 그대로
final need = await a.app.cards.needingResend();
expect(need.single.targetId, company.id);
expect(await a.app.cards.resend(need.single.id), true);
await AppDevice.settleAll();
got = (await b.app.deps.storage.receivedCards.byPerson(aOfB.id)).firstWhere((c) => c.kind == 'company');
expect(decodeFields(got.fieldsJson)['company'], '새빛');
expect(await a.app.cards.needingResend(), isEmpty);
});
test('명함 만들기·순서 바꾸기·지우기', () async {
final (a, _) = await pair();
final tpls = await a.app.layout.templates();
final made = (await a.app.cards.createFromTemplate(tpls[1].id))!;
expect((await a.app.cards.mine()).length, 6);
await a.app.cards.move(made.id, 0);
expect((await a.app.cards.mine()).first.id, made.id);
await a.app.cards.delete(made.id);
expect((await a.app.cards.mine()).length, 5);
expect(await a.app.cards.createFromTemplate('없는틀'), null);
});
});
group('대화', () {
test('개인 대화는 바로 되고, 주고받는 대화가 양쪽에 남음', () async {
final (a, b) = await pair();
await befriend(a, b);
final bOfA = (await a.app.friends.people()).single;
final room = (await a.app.chats.openDirect(bOfA.id, 'personal'))!;
await a.app.chats.send(room.id, '안녕하세요');
await AppDevice.settleAll();
final aRooms = await b.app.chats.summaries();
expect(aRooms.single.last!.body, '안녕하세요');
await b.app.chats.send(aRooms.single.room.id, '반가워요');
await AppDevice.settleAll();
final mine = await a.app.chats.messages(room.id);
expect(mine.map((m) => m.body).toList(), ['안녕하세요', '반가워요']);
expect(mine.first.senderId, ChatService.me);
expect(await a.app.chats.openDirect(bOfA.id, 'personal'), isNotNull);
expect((await a.app.chats.summaries()).length, 1); // 같은 방을 다시 열어도 하나
});
test('회사 대화는 회사 명함을 공유해야 열리고, 받는 쪽도 명함을 받아야 보임', () async {
final (a, b) = await pair();
await befriend(a, b);
final bOfA = (await a.app.friends.people()).single;
expect(await a.app.chats.openDirect(bOfA.id, 'company'), null);
final company = (await a.app.cards.mine()).firstWhere((c) => c.kind == 'company');
await a.app.cards.shareWith(bOfA.id, [company.id]);
final room = (await a.app.chats.openDirect(bOfA.id, 'company'))!;
await a.app.chats.send(room.id, '업무 이야기');
await AppDevice.settleAll();
final rooms = await b.app.chats.summaries();
expect(rooms.single.room.contextKind, 'company');
expect(rooms.single.last!.body, '업무 이야기');
});
test('빈 메시지·없는 방은 보내지 않음', () async {
final (a, b) = await pair();
await befriend(a, b);
final bOfA = (await a.app.friends.people()).single;
final room = (await a.app.chats.openDirect(bOfA.id, 'personal'))!;
expect(await a.app.chats.send(room.id, ' '), null);
expect(await a.app.chats.send('없는방', '안녕'), null);
});
});
group('인맥', () {
test('같은 학교 명함을 주고받으면 동창으로 추측하고, 확정하면 추천에서 빠짐', () async {
final (a, b) = await pair();
await befriend(a, b);
final bOfA = (await a.app.friends.people()).single;
final aOfB = (await b.app.friends.people()).single;
for (final d in [a, b]) {
final school = (await d.app.cards.mine()).firstWhere((c) => c.kind == 'school');
await d.app.cards.edit(school.id, fields: {'name': d.name, 'school': '가람초', 'year': '2007'});
}
final aSchool = (await a.app.cards.mine()).firstWhere((c) => c.kind == 'school');
await a.app.cards.shareWith(bOfA.id, [aSchool.id]);
await AppDevice.settleAll();
final guesses = await b.app.network.guessesFor(aOfB.id);
expect(guesses.first.relation, '동창');
final sug = await b.app.network.suggestions();
expect(sug.single.person.id, aOfB.id);
await b.app.network.addLink(aOfB.id, guesses.first.relation, guesses.first.detail);
expect(await b.app.network.suggestions(), isEmpty);
final cl = await b.app.network.clusters('school');
expect(cl.single.people.single.id, aOfB.id);
expect((await b.app.network.links(aOfB.id)).single.confirmed, true);
final recv = await b.app.network.receivedCards(aOfB.id);
expect(recv.map((c) => c.kind).toSet(), {'personal', 'school'});
await b.app.network.deleteReceivedCard(recv.first.id);
expect((await b.app.network.receivedCards(aOfB.id)).length, 1);
});
test('가족 명함을 받으면 가족 목록에 나옴', () async {
final (a, b) = await pair();
await befriend(a, b);
final bOfA = (await a.app.friends.people()).single;
final fam = (await a.app.cards.mine()).firstWhere((c) => c.kind == 'family');
await a.app.cards.edit(fam.id, fields: {'name': '가', 'relation': '형'});
await a.app.cards.shareWith(bOfA.id, [fam.id]);
await AppDevice.settleAll();
final members = await b.app.network.family();
expect(members.single.relation, '형');
});
});
group('설정·배치', () {
test('설정은 범위 안으로 맞춰지고, 복구 조각 수는 필요한 수보다 작아지지 않음', () async {
final (a, _) = await pair();
var s = await a.app.settings.update(storageUsagePercent: 99, recoveryShares: 4, recoveryThreshold: 9);
expect(s.storageUsagePercent, 95);
expect(s.recoveryShares, 4);
expect(s.recoveryThreshold, 4);
s = await a.app.settings.update(recoveryShares: 2);
expect(s.recoveryThreshold, 2);
expect((await a.app.settings.load()).exchangeMode, 'request');
});
test('홈 구성·명함 틀 편집이 저장되고 변경 알림이 감', () async {
final (a, _) = await pair();
var n = 0;
a.app.changes.listen((_) => n++);
await a.app.layout.moveHome(0, 2);
await a.app.layout.removeHome('family');
expect((await a.app.layout.home()).any((e) => e.id == 'family'), false);
await a.app.layout.resetHome();
expect((await a.app.layout.home()).first.id, 'chats');
expect(n >= 3, true);
});
test('대화가 1MB 를 넘으면 별도 저장을 권하고 범위를 나눌 수 있음', () async {
final (a, b) = await pair();
await befriend(a, b);
final bOfA = (await a.app.friends.people()).single;
final room = (await a.app.chats.openDirect(bOfA.id, 'personal'))!;
for (var i = 0; i < 3; i++) {
await a.app.chats.send(room.id, 'x' * 400000);
}
expect((await a.app.settings.adviseRoom(room.id)).overText, true);
final span = (await a.app.settings.selectableSpan(room.id))!;
expect(await a.app.settings.archiveRange(room.id, span.$1, span.$1), 1);
expect((await a.app.settings.adviseRoom(room.id)).overText, false);
expect((await a.app.chats.messages(room.id)).length, 2);
});
});
}