import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:fake_cloud_firestore/fake_cloud_firestore.dart'; import 'package:fancake/core/data/backend.dart'; import 'package:firebase_auth_mocks/firebase_auth_mocks.dart'; import 'package:flutter_test/flutter_test.dart'; /// 서버 연동 계층 — 로그인 강제와 문서 값 읽기 규칙. /// /// 문서 값 읽기가 틀리면 화면은 조용히 0 이나 빈 칸을 그리므로 눈으로는 잡히지 않는다. void main() { group('로그인 강제', () { test('로그인하지 않았으면 카탈로그 코드 E-AUTH-03 으로 끊는다', () { final backend = Backend( firestore: FakeFirebaseFirestore(), auth: MockFirebaseAuth(), ); expect(backend.uid, isNull); expect( () => backend.requireUid, throwsA(isA().having((e) => e.code, 'code', 'E-AUTH-03')), ); }); test('로그인했으면 UID 를 돌려준다', () { final backend = Backend( firestore: FakeFirebaseFirestore(), auth: MockFirebaseAuth(signedIn: true, mockUser: MockUser(uid: 'u-test')), ); expect(backend.requireUid, 'u-test'); }); }); group('문서 값 읽기', () { test('없는 필드는 기본값으로 받는다', () { final doc = {}; expect(doc.intOr('pop'), 0); expect(doc.strOr('name', '이름 없음'), '이름 없음'); expect(doc.boolOr('active'), isFalse); expect(doc.mapsOr('items'), isEmpty); }); test('실수는 반올림해 정수로 받는다', () { expect({'pop': 12.6}.intOr('pop'), 13); }); test('빈 문자열은 없는 값으로 본다', () { expect({'name': ''}.strOr('name', '팬'), '팬'); }); test('서버 시각은 DateTime 으로 옮긴다', () { final at = DateTime(2026, 9, 1, 9); final doc = {'createdAt': Timestamp.fromDate(at)}; expect(doc.dateOr('createdAt', DateTime(2000)), at); expect(doc.dateOr('missing', DateTime(2000)), DateTime(2000)); }); test('목록 안의 맵만 골라 받는다', () { final doc = { 'items': [ {'id': 1}, 'x', {'id': 2}, ], }; expect(doc.mapsOr('items').map((m) => m['id']), [1, 2]); }); }); }