import 'package:block_seasons/game/models/season.dart'; import 'package:flutter_test/flutter_test.dart'; const packJson = { 'schemaVersion': 1, 'seasonId': 'season_001', 'version': 2, 'title': {'en': 'First Bloom', 'ko': '첫 개화'}, 'theme': {'tileSet': 'spring', 'background': 'background.webp'}, 'stages': [ { 'id': 's001_001', 'seed': 101, 'moveLimit': 18, 'preset': [ {'x': 3, 'y': 3, 't': 'gem'}, ], 'objectives': [ {'type': 'clearGems', 'count': 1}, ], 'stars': { 'two': {'movesLeft': 4}, 'three': {'movesLeft': 8}, }, 'generatorProfile': 'easy', }, ], }; void main() { group('SeasonPack', () { test('parses the pack schema', () { final pack = SeasonPack.fromJson(packJson); expect(pack.schemaVersion, 1); expect(pack.seasonId, 'season_001'); expect(pack.version, 2); expect(pack.theme.tileSet, 'spring'); expect(pack.stages, hasLength(1)); expect(pack.stages.first.id, 's001_001'); }); test('round-trips to JSON', () { final pack = SeasonPack.fromJson(packJson); // toJson() always emits all SeasonTheme fields (new fields added in // Task 1). Compare everything except theme separately so that adding // more theme fields in the future only requires updating theme tests. final json = pack.toJson(); expect(json['schemaVersion'], packJson['schemaVersion']); expect(json['seasonId'], packJson['seasonId']); expect(json['version'], packJson['version']); expect(json['title'], packJson['title']); expect(json['stages'], packJson['stages']); // Theme: legacy fields preserved, new fields present with defaults. final theme = json['theme'] as Map; expect(theme['tileSet'], 'spring'); expect(theme['background'], 'background.webp'); expect(theme['backgroundGradient'], SeasonTheme.defaultGradient); expect(theme['accentColor'], 0xFFFF7EB3); expect(theme['particleType'], 'petals'); expect(theme.containsKey('tilePalette'), isFalse); expect(theme.containsKey('boardTint'), isFalse); }); test('localized title falls back to English', () { final pack = SeasonPack.fromJson(packJson); expect(pack.titleFor('ko'), '첫 개화'); expect(pack.titleFor('en'), 'First Bloom'); expect(pack.titleFor('ja'), 'First Bloom'); }); test('rejects unsupported schema versions', () { expect( () => SeasonPack.fromJson({...packJson, 'schemaVersion': 99}), throwsFormatException, ); }); }); group('SeasonTheme visuals', () { test('legacy theme json (tileSet/background only) gets defaults', () { final theme = SeasonTheme.fromJson({ 'tileSet': 'spring', 'background': 'background.webp', }); expect(theme.backgroundGradient, SeasonTheme.defaultGradient); expect(theme.accentColor, 0xFFFF7EB3); expect(theme.particleType, 'petals'); expect(theme.tilePalette, isNull); expect(theme.boardTint, isNull); }); test('full theme json round-trips', () { final theme = SeasonTheme( tileSet: 'summer', background: 'bg.webp', backgroundGradient: const [0xFF0A2430, 0xFF10394A, 0xFF1E5A66], accentColor: 0xFF6FCDF5, particleType: 'snow', tilePalette: const [0xFF111111, 0xFF222222], boardTint: 0xFF041016, ); final decoded = SeasonTheme.fromJson(theme.toJson()); expect(decoded.backgroundGradient, theme.backgroundGradient); expect(decoded.accentColor, theme.accentColor); expect(decoded.particleType, theme.particleType); expect(decoded.tilePalette, theme.tilePalette); expect(decoded.boardTint, theme.boardTint); }); test('fallback constant matches season 1 defaults', () { expect(SeasonTheme.fallback.backgroundGradient, const [0xFF0E1430, 0xFF16204A, 0xFF2A2E5E]); expect(SeasonTheme.fallback.particleType, 'petals'); }); }); }