Files
999/test/word_of_the_day_test.dart

166 lines
6.0 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:words999/models/syncretic_session_model.dart';
import 'package:words999/models/word_of_day_model.dart';
import 'package:words999/services/word_of_the_day_service.dart';
import 'package:words999/services/words_repository.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
setUpAll(() async {
SharedPreferences.setMockInitialValues({});
await WordsRepository().init(remoteDailyShuffle: false);
await WordOfTheDayService().init();
});
group('WordOfTheDayService & Model Tests', () {
test('Date key format and parse consistency', () {
final date = DateTime(2026, 9, 28);
final key = WordOfTheDayService.formatDateKey(date);
expect(key, '2026-09-28');
final parsed = WordOfTheDayService.parseDateKey(key);
expect(parsed.year, 2026);
expect(parsed.month, 9);
expect(parsed.day, 28);
});
test('Deterministic daily word hash is consistent for identical dates', () {
final date1 = DateTime(2026, 9, 28);
final date2 = DateTime(2026, 9, 28, 23, 59, 59);
final idx1 = WordOfTheDayService.calculateWordIndexForDate(date1, 1000);
final idx2 = WordOfTheDayService.calculateWordIndexForDate(date2, 1000);
expect(idx1, equals(idx2));
final word1 = WordOfTheDayService().getWordForDate(date1);
final word2 = WordOfTheDayService().getWordForDate(date2);
expect(word1.id, equals(word2.id));
expect(word1.word, equals(word2.word));
});
test('Adjacent dates yield distinct words across calendar', () {
final day1 = DateTime(2026, 9, 27);
final day2 = DateTime(2026, 9, 28);
final day3 = DateTime(2026, 9, 29);
final idx1 = WordOfTheDayService.calculateWordIndexForDate(day1, 1000);
final idx2 = WordOfTheDayService.calculateWordIndexForDate(day2, 1000);
final idx3 = WordOfTheDayService.calculateWordIndexForDate(day3, 1000);
expect(idx1, isNot(equals(idx2)));
expect(idx2, isNot(equals(idx3)));
});
test('Triptych mode provides 3 distinct words for Morning, Day, and Evening', () {
final date = DateTime(2026, 9, 28);
final triptych = WordOfTheDayService().getTriptychWordsForDate(date);
expect(triptych.morning.id, isNot(equals(triptych.day.id)));
expect(triptych.day.id, isNot(equals(triptych.evening.id)));
expect(triptych.morning.id, isNot(equals(triptych.evening.id)));
});
test('WordOfDayRecord JSON serialization and copyWith with Triptych', () {
const rec = WordOfDayRecord(
dateKey: '2026-09-28',
wordId: 42,
isRevealed: true,
isStepCompleted: false,
diaryNote: 'Удивительная синхрония в разговоре',
isTriptychMode: true,
morningWordId: 10,
dayWordId: 20,
eveningWordId: 30,
isMorningRevealed: true,
isDayRevealed: true,
isEveningRevealed: false,
isDayStepCompleted: true,
);
final jsonStr = rec.toJson();
final decoded = WordOfDayRecord.fromJson(jsonStr);
expect(decoded.dateKey, '2026-09-28');
expect(decoded.wordId, 42);
expect(decoded.isTriptychMode, isTrue);
expect(decoded.morningWordId, 10);
expect(decoded.dayWordId, 20);
expect(decoded.eveningWordId, 30);
expect(decoded.isMorningRevealed, isTrue);
expect(decoded.isDayRevealed, isTrue);
expect(decoded.isEveningRevealed, isFalse);
expect(decoded.isDayStepCompleted, isTrue);
expect(decoded.isAnyRevealed, isTrue);
expect(decoded.areAllTriptychRevealed, isFalse);
final allRevealed = decoded.copyWith(isEveningRevealed: true);
expect(allRevealed.areAllTriptychRevealed, isTrue);
});
test('Reveal specific triptych phases and persist', () async {
final service = WordOfTheDayService();
final testDate = DateTime(2026, 11, 20);
await service.setRecordTriptychMode(testDate, true);
var rec = service.getRecord(testDate);
expect(rec.isTriptychMode, isTrue);
expect(rec.isMorningRevealed, isFalse);
await service.revealWord(testDate, phase: 'morning');
rec = service.getRecord(testDate);
expect(rec.isMorningRevealed, isTrue);
expect(rec.isDayRevealed, isFalse);
await service.revealWord(testDate, phase: 'day');
rec = service.getRecord(testDate);
expect(rec.isDayRevealed, isTrue);
expect(rec.isEveningRevealed, isFalse);
await service.revealWord(testDate, phase: 'evening');
rec = service.getRecord(testDate);
expect(rec.isEveningRevealed, isTrue);
expect(rec.areAllTriptychRevealed, isTrue);
await service.toggleStepCompleted(testDate, true, isDayStep: true);
rec = service.getRecord(testDate);
expect(rec.isDayStepCompleted, isTrue);
});
test('SyncreticSession can incorporate Triptych reading', () async {
final triptych = WordOfTheDayService().getTriptychWordsForDate(DateTime(2026, 9, 28));
final reading = SyncreticReading(
id: 'trip_test_1',
systemId: 'word_of_day',
systemName: 'Триптих Дня',
systemIcon: '⏳',
timestamp: DateTime.now(),
layoutTitle: 'Триптих Суток',
items: [
ReadingSignItem(
title: 'Утро: ${triptych.morning.word}',
linkedWord: triptych.morning,
),
ReadingSignItem(
title: 'День: ${triptych.day.word}',
linkedWord: triptych.day,
),
ReadingSignItem(
title: 'Вечер: ${triptych.evening.word}',
linkedWord: triptych.evening,
),
],
);
final repo = WordsRepository();
await repo.addReadingToSyncreticSession(reading);
final current = repo.currentSyncreticSession;
expect(current.readings.any((r) => r.id == 'trip_test_1'), isTrue);
expect(current.readings.firstWhere((r) => r.id == 'trip_test_1').items.length, 3);
});
});
}