test sweep: cover kernel/src/syntax (T-91)
test / unit + widget + golden + a11y (push) Failing after 31s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m2s
test / unit + widget + golden + a11y (push) Failing after 31s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m2s
Two test files covering the pure-Dart and fallback paths of the
tree-sitter integration. The native-FFI parsing depth stays
untested — DynamicLibrary.open('libtree-sitter.so') doesn't resolve
under the flutter test runner because the bundled lib sits at
native/linux-x64/ rather than on the linker search path. Real
parsing coverage would need an integration-test harness that copies
or symlinks the lib into the runner's working directory.
- test/kernel/src/syntax/language_map_test.dart (6 tests): every
branch of grammarForPath — common extensions, case-insensitive
matching, special filenames (Makefile / Dockerfile / .gitignore /
justfile), no-dot/no-special-match fallthrough, unknown extension.
- test/kernel/src/syntax/tree_sitter_service_test.dart (9 tests):
graceful-fallback paths of TreeSitterService when the library
can't load — hasGrammar / languageFor / highlight all short-
circuit cleanly, plus SyntaxResult.empty and SyntaxSpan field
storage.
Coverage: language_map.dart 0/7 -> 7/7; tree_sitter_service.dart
1/131 -> 22/131 (the rest is deep FFI work); tree_sitter_ffi.dart
0/15 -> 1/15 (init entry only).
Total coverage 75.11% -> 75.42%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -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<List<String>>());
|
||||
});
|
||||
});
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user