diff --git a/test/kernel/src/syntax/language_map_test.dart b/test/kernel/src/syntax/language_map_test.dart new file mode 100644 index 00000000..e88064d7 --- /dev/null +++ b/test/kernel/src/syntax/language_map_test.dart @@ -0,0 +1,48 @@ +/// Pure-Dart tests for `grammarForPath` in +/// `lib/kernel/src/syntax/language_map.dart`. +library; + +import 'package:clide/kernel/src/syntax/language_map.dart'; +import 'package:test/test.dart'; + +void main() { + group('grammarForPath', () { + test('maps common file extensions to grammar names', () { + expect(grammarForPath('foo.dart'), 'dart'); + expect(grammarForPath('a/b/c.go'), 'go'); + expect(grammarForPath('script.py'), 'python'); + expect(grammarForPath('view.tsx'), 'typescript'); + expect(grammarForPath('config.yaml'), 'yaml'); + expect(grammarForPath('config.yml'), 'yaml'); + expect(grammarForPath('readme.md'), 'markdown'); + }); + + test('extension match is case-insensitive', () { + expect(grammarForPath('a.R'), 'r'); + expect(grammarForPath('Q.PY'), 'python'); + }); + + test('special filenames bypass the extension lookup', () { + expect(grammarForPath('Makefile'), 'make'); + expect(grammarForPath('a/b/Dockerfile'), 'dockerfile'); + expect(grammarForPath('.gitignore'), 'gitignore'); + expect(grammarForPath('justfile'), 'just'); + }); + + test('special filename + recognised extension still picks the special name', () { + // Makefile has no '.' so the extension branch wouldn't fire anyway — + // this just locks in that the filename map runs first. + expect(grammarForPath('Makefile'), 'make'); + }); + + test('returns null when there is no dot and no special filename match', () { + expect(grammarForPath('README'), isNull); + expect(grammarForPath('a/b/UNKNOWNFILE'), isNull); + }); + + test('returns null for an unknown extension', () { + expect(grammarForPath('foo.unknownextension'), isNull); + expect(grammarForPath('a/b/c.xyz'), isNull); + }); + }); +} diff --git a/test/kernel/src/syntax/tree_sitter_service_test.dart b/test/kernel/src/syntax/tree_sitter_service_test.dart new file mode 100644 index 00000000..c917f864 --- /dev/null +++ b/test/kernel/src/syntax/tree_sitter_service_test.dart @@ -0,0 +1,66 @@ +/// Tests the graceful-fallback paths of `TreeSitterService` when the +/// native `libtree-sitter` library isn't dlopen-resolvable. In that +/// environment the service short-circuits every public method without +/// throwing — which is also how the running app behaves on platforms +/// where the library hasn't been bundled. +library; + +import 'package:clide/kernel/src/syntax/tree_sitter_service.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('TreeSitterService — fallback paths', () { + final svc = TreeSitterService.shared; + + test('hasGrammar(path) returns false for an unknown extension', () async { + expect(await svc.hasGrammar('foo.unknownextension'), isFalse); + }); + + test('hasGrammar(path) returns false when the library cannot load', () async { + // 'foo.dart' resolves to grammar "dart", which still requires the + // native library + asset to actually load. In the test runner the + // native lib isn't on the dlopen search path, so _init() fails and + // hasGrammar reports false. + expect(await svc.hasGrammar('foo.dart'), isFalse); + }); + + test('languageFor(path) returns null when the language is unknown', () async { + expect(await svc.languageFor('foo.unknownextension'), isNull); + }); + + test('languageFor(path) returns null when the library cannot load', () async { + expect(await svc.languageFor('foo.dart'), isNull); + }); + + test('highlight returns an empty result for unknown extensions', () async { + final r = await svc.highlight('foo.unknownextension', 'whatever'); + expect(r.spans, isEmpty); + }); + + test('highlight returns an empty result when the library cannot load', () async { + final r = await svc.highlight('foo.dart', 'void main() {}'); + expect(r.spans, isEmpty); + }); + + test('loadedLanguages getter returns a list (may be empty)', () { + // Just exercise the getter — the actual contents depend on the + // environment. + expect(svc.loadedLanguages, isA>()); + }); + }); + + group('SyntaxResult / SyntaxSpan', () { + test('SyntaxResult.empty has no spans', () { + expect(SyntaxResult.empty.spans, isEmpty); + }); + + test('SyntaxSpan stores start / end / role', () { + const s = SyntaxSpan(start: 3, end: 7, role: 'keyword'); + expect(s.start, 3); + expect(s.end, 7); + expect(s.role, 'keyword'); + }); + }); +}