feat: complete academic symbol lexicon heal, 2-column Cooper extraction, and updated assets
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user