import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:words999/services/houses_service.dart'; import 'package:words999/services/words_repository.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('HousesService 33x30 Field & 10 Archons Tests', () { late HousesService service; setUp(() async { SharedPreferences.setMockInitialValues({}); final repo = WordsRepository(); await repo.init(remoteDailyShuffle: false); service = HousesService(); }); test('Session generation creates exactly 10 Archons and 990 Houses without overlap', () { final session = service.createNewSession(question: 'Тестовый вопрос'); expect(session.sectors.length, equals(10)); expect(session.grid.length, equals(990)); final allWords = {}; // Check Archons for (int i = 0; i < 10; i++) { final s = session.sectors[i]; expect(s.index, equals(i)); expect(s.startCol, equals(i * 3)); expect(s.endCol, equals(i * 3 + 2)); expect(s.archonWord.word.isNotEmpty, isTrue); allWords.add(s.archonWord.word.toLowerCase()); } expect(allWords.length, equals(10), reason: '10 Archons must be unique'); // Check Houses (33 rows x 30 cols) for (int r = 0; r < 33; r++) { for (int c = 0; c < 30; c++) { final idx = r * 30 + c; final cell = session.grid[idx]; expect(cell.row, equals(r)); expect(cell.col, equals(c)); expect(cell.houseIndex, equals(idx)); expect(cell.sectorIndex, equals(c ~/ 3)); expect(cell.houseWord.word.isNotEmpty, isTrue); allWords.add(cell.houseWord.word.toLowerCase()); } } // Exactly 1000 unique words partitioned expect(allWords.length, equals(1000)); }); test('Divination with 5 chosen houses populates guests and computes chains', () { final session = service.createNewSession(); final chosen = [ session.grid[0].copyWith(selectionOrder: 1), session.grid[15].copyWith(selectionOrder: 2), session.grid[42].copyWith(selectionOrder: 3), session.grid[100].copyWith(selectionOrder: 4), session.grid[500].copyWith(selectionOrder: 5), ]; final result = service.completeDivination(session, chosen); expect(result.selectedHouses.length, equals(5)); for (int i = 0; i < 5; i++) { final h = result.selectedHouses[i]; expect(h.guestWord, isNotNull); expect(h.selectionOrder, equals(i + 1)); } expect(result.chains.isNotEmpty, isTrue); for (final chain in result.chains) { expect(chain.steps.isNotEmpty, isTrue); expect(chain.steps.first.house, isNotNull); expect(chain.steps.first.guest, isNotNull); } }); test('Chain length is capped at maximum 9 links', () { final session = service.createNewSession(); final chosen = [ session.grid[0].copyWith(selectionOrder: 1), ]; final result = service.completeDivination(session, chosen); for (final chain in result.chains) { expect(chain.steps.length, lessThanOrEqualTo(9)); } }); test('Querent word is guaranteed to be in houses and its index matches dynamically', () { final repo = WordsRepository(); final manWord = repo.allWords.firstWhere((w) => w.word.toLowerCase() == 'мужчина'); final session1 = service.createNewSession(querentWord: manWord); expect(session1.querentHouseIndex, isNotNull); final qIndex1 = session1.querentHouseIndex!; expect(session1.grid[qIndex1].houseWord.word.toLowerCase(), equals('мужчина')); // Reshuffle matrix multiple times: the querent must always match the house word at its index for (int i = 0; i < 5; i++) { final sessionRe = service.createNewSession(querentWord: manWord); expect(sessionRe.querentHouseIndex, isNotNull); final qIdx = sessionRe.querentHouseIndex!; expect(sessionRe.grid[qIdx].houseWord.word.toLowerCase(), equals('мужчина')); } }); }); }