From a79d207f532751b8351e455cad446b83121e22dd Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Thu, 28 May 2026 11:30:06 +0300 Subject: [PATCH] test(theme): expand theme pipeline unit and fixture coverage (#58) Add Dracula/One Dark/JSONC fixtures, integration tests for tokenColors import, codec/resolver coverage, and ThemeController shadcn theme tests. --- .../apply_token_colors_to_editor_test.dart | 28 ++++++ .../theme/parser/jsonc_preprocessor_test.dart | 11 +++ .../theme_fixtures_integration_test.dart | 41 +++++++++ .../theme/parser/token_colors_codec_test.dart | 28 ++++++ test/core/theme/querya_app_theme_test.dart | 86 +++++++++++++++++++ .../core/theme/theme_import_service_test.dart | 12 +++ .../themes/invalid-trailing-comma.jsonc | 15 ++++ test/fixtures/themes/one_dark.json | 24 ++++++ 8 files changed, 245 insertions(+) create mode 100644 test/core/theme/parser/apply_token_colors_to_editor_test.dart create mode 100644 test/core/theme/parser/theme_fixtures_integration_test.dart create mode 100644 test/core/theme/parser/token_colors_codec_test.dart create mode 100644 test/core/theme/querya_app_theme_test.dart create mode 100644 test/fixtures/themes/invalid-trailing-comma.jsonc create mode 100644 test/fixtures/themes/one_dark.json diff --git a/test/core/theme/parser/apply_token_colors_to_editor_test.dart b/test/core/theme/parser/apply_token_colors_to_editor_test.dart new file mode 100644 index 00000000..1320eccd --- /dev/null +++ b/test/core/theme/parser/apply_token_colors_to_editor_test.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:querya_desktop/core/theme/parser/apply_token_colors_to_editor.dart'; +import 'package:querya_desktop/core/theme/parser/vscode_theme_manifest.dart'; +import 'package:querya_desktop/core/theme/querya_editor_theme.dart'; + +void main() { + test('applyTokenColorsToEditor maps comment and keyword scopes', () { + const rules = [ + TokenColorRule(scopes: ['comment'], foreground: '#111111'), + TokenColorRule(scopes: ['keyword'], foreground: '#222222'), + TokenColorRule(scopes: ['string'], foreground: '#333333'), + ]; + + const base = QueryaEditorTheme.darkDefault; + final next = applyTokenColorsToEditor(base, rules); + + expect(next.comment, const Color(0xFF111111)); + expect(next.keyword, const Color(0xFF222222)); + expect(next.string, const Color(0xFF333333)); + expect(next.foreground, base.foreground); + }); + + test('empty rules returns unchanged editor theme', () { + const base = QueryaEditorTheme.darkDefault; + expect(applyTokenColorsToEditor(base, const []), base); + }); +} diff --git a/test/core/theme/parser/jsonc_preprocessor_test.dart b/test/core/theme/parser/jsonc_preprocessor_test.dart index 1759bfde..77c94752 100644 --- a/test/core/theme/parser/jsonc_preprocessor_test.dart +++ b/test/core/theme/parser/jsonc_preprocessor_test.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter_test/flutter_test.dart'; import 'package:querya_desktop/core/theme/parser/jsonc_preprocessor.dart'; @@ -31,5 +33,14 @@ void main() { const input = '{"a": 1,}'; expect(stripJsonc(input), '{"a": 1}'); }); + + test('parses invalid-trailing-comma.jsonc fixture via manifest', () { + final raw = File('test/fixtures/themes/invalid-trailing-comma.jsonc') + .readAsStringSync(); + final cleaned = stripJsonc(raw); + expect(cleaned.contains('//'), isFalse); + expect(cleaned.contains(',}'), isFalse); + expect(cleaned, contains('"editor.background"')); + }); }); } diff --git a/test/core/theme/parser/theme_fixtures_integration_test.dart b/test/core/theme/parser/theme_fixtures_integration_test.dart new file mode 100644 index 00000000..e954ceef --- /dev/null +++ b/test/core/theme/parser/theme_fixtures_integration_test.dart @@ -0,0 +1,41 @@ +import 'dart:io'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:querya_desktop/core/theme/parser/querya_theme_from_vscode.dart'; +import 'package:querya_desktop/core/theme/parser/vscode_theme_manifest.dart'; +import 'package:querya_desktop/core/theme/querya_theme.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; + +void main() { + group('theme fixtures', () { + test('dracula_tokens.json parses colors and tokenColors', () { + final raw = + File('test/fixtures/themes/dracula_tokens.json').readAsStringSync(); + final manifest = VsCodeThemeManifest.fromJsonString(raw); + expect(manifest.name, 'Dracula Fixture'); + expect(manifest.isDark, isTrue); + expect(manifest.colors['editor.background'], '#282a36'); + expect(manifest.tokenColors.length, 4); + }); + + test('one_dark.json builds QueryaTheme with editor background', () { + final raw = File('test/fixtures/themes/one_dark.json').readAsStringSync(); + final manifest = VsCodeThemeManifest.fromJsonString(raw); + final theme = buildQueryaThemeFromVsCodeManifest( + manifest, + fallback: QueryaTheme.darkDefault, + ); + expect(theme.workbench.editorBackground, const Color(0xFF282C34)); + expect(theme.tokenColors.length, 3); + expect(theme.editor.comment, const Color(0xFF5C6370)); + }); + + test('invalid-trailing-comma.jsonc parses after JSONC strip', () { + final raw = File('test/fixtures/themes/invalid-trailing-comma.jsonc') + .readAsStringSync(); + final manifest = VsCodeThemeManifest.fromJsonString(raw); + expect(manifest.colors['editor.background'], '#282c34'); + expect(manifest.tokenColors.single.scopes, ['comment']); + }); + }); +} diff --git a/test/core/theme/parser/token_colors_codec_test.dart b/test/core/theme/parser/token_colors_codec_test.dart new file mode 100644 index 00000000..cb553616 --- /dev/null +++ b/test/core/theme/parser/token_colors_codec_test.dart @@ -0,0 +1,28 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:querya_desktop/core/theme/parser/token_colors_codec.dart'; +import 'package:querya_desktop/core/theme/parser/vscode_theme_manifest.dart'; + +void main() { + test('tokenColorRulesToJson round-trips rules', () { + const rules = [ + TokenColorRule( + scopes: ['comment', 'comment.line'], + foreground: '#6272a4', + fontStyle: 'italic', + ), + TokenColorRule( + scopes: ['keyword'], + foreground: '#ff79c6', + ), + ]; + + final json = tokenColorRulesToJson(rules); + final restored = tokenColorRulesFromJson(json); + + expect(restored.length, 2); + expect(restored.first.scopes, ['comment', 'comment.line']); + expect(restored.first.foreground, '#6272a4'); + expect(restored.first.fontStyle, 'italic'); + expect(restored[1].scopes, ['keyword']); + }); +} diff --git a/test/core/theme/querya_app_theme_test.dart b/test/core/theme/querya_app_theme_test.dart new file mode 100644 index 00000000..161ce2b0 --- /dev/null +++ b/test/core/theme/querya_app_theme_test.dart @@ -0,0 +1,86 @@ +import 'dart:io'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; +import 'package:querya_desktop/core/storage/app_settings.dart'; +import 'package:querya_desktop/core/storage/local_db.dart'; +import 'package:querya_desktop/core/theme/querya_theme.dart'; +import 'package:querya_desktop/core/theme/theme_controller.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; + +class _FakePathProvider extends PathProviderPlatform { + _FakePathProvider(this._root); + final String _root; + + @override + Future getApplicationSupportPath() async => _root; + + @override + Future getTemporaryPath() async => _root; + + @override + Future getApplicationDocumentsPath() async => _root; +} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + late Directory tempDir; + + setUpAll(() async { + tempDir = await Directory.systemTemp.createTemp('querya_app_theme_test_'); + PathProviderPlatform.instance = _FakePathProvider(tempDir.path); + await LocalDb.initFfi(); + }); + + tearDownAll(() async { + await LocalDb.instance.close(); + if (await tempDir.exists()) { + await tempDir.delete(recursive: true); + } + }); + + tearDown(() async { + await AppSettings.instance.clearThemeSettings(); + await ThemeController.instance.load(); + }); + + test('ThemeController shadcn themes differ for light vs dark background', () async { + final controller = ThemeController.instance; + await controller.load(); + + expect( + controller.darkShadcnTheme.colorScheme.background, + QueryaTheme.darkDefault.colorScheme.background, + ); + expect( + controller.lightShadcnTheme.colorScheme.background, + QueryaTheme.lightDefault.colorScheme.background, + ); + expect( + controller.darkShadcnTheme.colorScheme.background, + isNot(controller.lightShadcnTheme.colorScheme.background), + ); + }); + + test('setThemeMode switches activeTheme and shadcn background', () async { + final controller = ThemeController.instance; + await controller.load(); + + expect( + controller.activeTheme.colorScheme.background, + QueryaTheme.darkDefault.colorScheme.background, + ); + + await controller.setThemeMode(ThemeMode.light); + + expect( + controller.activeTheme.colorScheme.background, + QueryaTheme.lightDefault.colorScheme.background, + ); + expect( + controller.darkShadcnTheme.colorScheme.background, + isNot(controller.lightShadcnTheme.colorScheme.background), + ); + }); +} diff --git a/test/core/theme/theme_import_service_test.dart b/test/core/theme/theme_import_service_test.dart index da998cb8..0a6fa510 100644 --- a/test/core/theme/theme_import_service_test.dart +++ b/test/core/theme/theme_import_service_test.dart @@ -52,6 +52,18 @@ void main() { expect(reloaded?['editor.background'], '#1e1e1e'); }); + test('importFromPath persists tokenColors from dracula fixture', () async { + final fixture = File('test/fixtures/themes/dracula_tokens.json'); + final result = await ThemeImportService.importFromPath(fixture.path); + expect(result, isA()); + final success = result as ThemeImportSuccess; + expect(success.tokenColors, isNotEmpty); + + final tokens = await ThemeImportService.loadPersistedTokenColors(); + expect(tokens.length, success.tokenColors.length); + expect(tokens.first.scopes, contains('comment')); + }); + test('importFromPath returns failure for missing file', () async { final result = await ThemeImportService.importFromPath('/no/such/theme.json'); diff --git a/test/fixtures/themes/invalid-trailing-comma.jsonc b/test/fixtures/themes/invalid-trailing-comma.jsonc new file mode 100644 index 00000000..b8a098f1 --- /dev/null +++ b/test/fixtures/themes/invalid-trailing-comma.jsonc @@ -0,0 +1,15 @@ +{ + // One Dark–like fixture with JSONC trailing comma + "name": "JSONC Trailing Comma", + "type": "dark", + "colors": { + "editor.background": "#282c34", + "sideBar.background": "#21252b", + }, + "tokenColors": [ + { + "scope": "comment", + "settings": { "foreground": "#5c6370" }, + }, + ], +} diff --git a/test/fixtures/themes/one_dark.json b/test/fixtures/themes/one_dark.json new file mode 100644 index 00000000..1a652d9b --- /dev/null +++ b/test/fixtures/themes/one_dark.json @@ -0,0 +1,24 @@ +{ + "name": "One Dark Fixture", + "type": "dark", + "colors": { + "editor.background": "#282c34", + "editor.foreground": "#abb2bf", + "sideBar.background": "#21252b", + "activityBar.background": "#21252b" + }, + "tokenColors": [ + { + "scope": "comment", + "settings": { "foreground": "#5c6370" } + }, + { + "scope": "keyword", + "settings": { "foreground": "#c678dd" } + }, + { + "scope": "string", + "settings": { "foreground": "#98c379" } + } + ] +}