이클립스 방어 횟수 즉시 표시·진동 · Music Shake 영상 재생 중 흔들기 판정 · 결과 공유
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'package:fake_cloud_firestore/fake_cloud_firestore.dart';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart' show SetOptions;
|
||||
import 'package:fancake/core/data/backend.dart';
|
||||
import 'package:fancake/features/quest/quest_data.dart';
|
||||
import 'package:fancake/features/quest/quest_evidence.dart';
|
||||
@@ -335,52 +336,51 @@ service cloud.firestore {
|
||||
expect(reward.rewardedPop, 0);
|
||||
});
|
||||
|
||||
test('Music Shake — 박마다 구간을 세고 판정표 · 곡 ID 를 서버에 보낸다', () async {
|
||||
test('Music Shake — 영상 · BPM · 구간 수를 퀘스트에서 읽고 판정표 · 곡 ID 를 서버에 보낸다', () async {
|
||||
final db = await _seed();
|
||||
// 600 BPM = 박 100ms · 3 구간. 박 0 과 박 1 근처에서만 흔든다.
|
||||
await db.doc('config/policy').set({
|
||||
'musicShake': {'perfectWindow': 0.1, 'goodWindow': 0.4, 'pop': 3},
|
||||
}, SetOptions(merge: true));
|
||||
await db.doc('quests/shake').set({
|
||||
'type': 'musicshake', 'title': '응원 흔들기', 'dailyLimit': 1,
|
||||
'trackIds': ['track-a'], 'totalSegments': 3, 'bpm': 600,
|
||||
'totalSegments': 3, 'bpm': 120,
|
||||
'link': {'url': 'https://youtu.be/WMweEpGlu_U', 'title': 'BTS - Butter'},
|
||||
});
|
||||
final backend = _RecordingBackend(db);
|
||||
final repo = FirestoreQuestRepository(
|
||||
backend,
|
||||
shakes: () async* {
|
||||
final start = DateTime.now();
|
||||
yield start;
|
||||
await Future<void>.delayed(const Duration(milliseconds: 100));
|
||||
yield start.add(const Duration(milliseconds: 140));
|
||||
},
|
||||
);
|
||||
final repo = FirestoreQuestRepository(backend);
|
||||
final card = _card(await repo.load(), 'shake');
|
||||
expect(card.type.verifiable, isTrue);
|
||||
expect(card.goal, 3);
|
||||
expect(card.progress, 0);
|
||||
// Figma 「목표BPM」 — 목표 줄은 곡 BPM 이다. 보상은 운영값 musicShake.pop.
|
||||
expect(card.goal, 120);
|
||||
expect(card.rewardPop, 3);
|
||||
|
||||
final setup = await repo.musicShakeSetup('shake');
|
||||
expect(setup.videoId, 'WMweEpGlu_U');
|
||||
expect(setup.title, 'BTS - Butter');
|
||||
expect((setup.bpm, setup.segments), (120.0, 3));
|
||||
expect((setup.windows.perfect, setup.windows.good), (0.1, 0.4));
|
||||
|
||||
// 판을 끝내기 전에는 서버를 부르지 않는다.
|
||||
await expectLater(repo.verify(card), throwsA(isA<BackendException>()));
|
||||
expect(backend.calls, isEmpty);
|
||||
|
||||
expect(await repo.progressStream(card).toList(), [1, 2, 3]);
|
||||
repo.recordShake(ShakeJudge(bpm: 120, segments: 3, windows: setup.windows)
|
||||
..add(Duration.zero));
|
||||
await repo.verify(card);
|
||||
final call = backend.calls.single;
|
||||
expect(call.name, 'fnQuestVerifyMusicShake');
|
||||
expect(call.payload['questId'], 'shake');
|
||||
expect(call.payload['trackId'], 'track-a');
|
||||
expect(call.payload['trackId'], 'WMweEpGlu_U');
|
||||
expect(call.payload['totalSegments'], 3);
|
||||
final j = call.payload['judgement'] as Map;
|
||||
expect(j['perfect']! + j['good']! + j['miss']!, 3);
|
||||
expect(j['miss'], 1);
|
||||
expect(call.payload['judgement'], {'perfect': 1, 'good': 0, 'miss': 2, 'maxCombo': 1});
|
||||
});
|
||||
|
||||
test('ShakeJudge — 박과의 거리로 perfect · good · miss 를 가르고 최장 연속을 센다', () {
|
||||
final start = DateTime(2026, 10, 5);
|
||||
final judge = ShakeJudge(bpm: 60, segments: 4, start: start)
|
||||
..add(start.add(const Duration(milliseconds: 100))) // 박 0 · perfect
|
||||
..add(start.add(const Duration(milliseconds: 1400))) // 박 1 · good
|
||||
..add(start.add(const Duration(milliseconds: 3000))); // 박 3 · perfect, 박 2 miss
|
||||
expect(judge.judgement(), {'perfect': 2, 'good': 1, 'miss': 1, 'maxCombo': 2});
|
||||
expect(judge.end, start.add(const Duration(milliseconds: 3500)));
|
||||
test('Music Shake — 영상 · BPM · 구간 수가 없으면 판을 열지 않는다(값을 지어내지 않는다)', () async {
|
||||
final db = await _seed();
|
||||
await db.doc('quests/shake').set({'type': 'musicshake', 'title': '흔들기', 'totalSegments': 3});
|
||||
final repo = FirestoreQuestRepository(_RecordingBackend(db));
|
||||
await expectLater(repo.musicShakeSetup('shake'), throwsA(isA<BackendException>()));
|
||||
expect(_card(await repo.load(), 'shake').goal, 0);
|
||||
});
|
||||
|
||||
test('생성은 fn-quest-create 로 — 종료일은 날짜 + 그 시각의 UTC 오프셋(C-06)', () async {
|
||||
|
||||
Reference in New Issue
Block a user