Files
clide/test/daemon/pql_commands_errors_test.dart
T
jpmschweitzerandClaude Opus 4.7 91128a8f7f
test / unit + widget + golden + a11y (push) Failing after 29s
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 sweep: cover daemon pql/git command exception branches (T-91)
Two fault-injection test files driving every pql.* and git.* daemon
handler with a Client whose toolchain points at a non-existent
binary. Each underlying Process.run throws ProcessException → wrapped
as PqlException / GitException → the handler's catch branch fires
and surfaces a toolError IpcResponse.

- pql_commands_errors_test (18 cases): every pql.* command lands in
  the catch + _pqlError helper.
- git_commands_errors_test (14 cases): every git.* command lands in
  the catch + _gitError helper. Skipped: stage-hunk + unstage-hunk
  which go through GitClient._applyPatch (uses Process.start, throws
  ProcessException directly without rewrapping in GitException).

Coverage: src/daemon/pql_commands.dart 105/149 -> 148/149 (99%);
src/daemon/git_commands.dart 122/146 -> 142/146 (97%).

Total coverage 91.59% -> 92.33%; floor bumped to 92.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 13:14:20 +02:00

68 lines
2.4 KiB
Dart

/// Drives every pql.* daemon handler with a PqlClient whose toolchain
/// points at a non-existent binary. Each underlying call throws
/// PqlException, exercising the catch branches in
/// `lib/src/daemon/pql_commands.dart` that the happy-path suite can't
/// reach.
library;
import 'dart:io';
import 'package:clide/clide.dart';
import 'package:clide/kernel/src/toolchain.dart';
import 'package:clide/src/daemon/pql_commands.dart';
import 'package:clide/src/pql/client.dart';
import 'package:test/test.dart';
void main() {
late DaemonDispatcher dispatcher;
setUp(() {
final toolchain = Toolchain();
toolchain.applyResolved(const ResolvedPaths(pql: '/tmp/clide-no-such-pql-binary'));
final pql = PqlClient(workDir: Directory.current, toolchain: toolchain);
dispatcher = DaemonDispatcher();
registerPqlCommands(dispatcher, pql);
});
Future<IpcResponse> call(String cmd, [Map<String, Object?> args = const {}]) {
return dispatcher.dispatch(IpcRequest(id: '1', cmd: cmd, args: args));
}
// Each pql.* command, when the underlying binary is missing, should
// surface a toolError with the pql operation name in the message.
final commandsWithSimpleArgs = [
('pql.files', const <String, Object?>{}),
('pql.meta', const {'path': 'CLAUDE.md'}),
('pql.backlinks', const {'path': 'CLAUDE.md'}),
('pql.outlinks', const {'path': 'CLAUDE.md'}),
('pql.tags', const <String, Object?>{}),
('pql.schema', const <String, Object?>{}),
('pql.query', const {'query': 'SELECT name'}),
('pql.search', const {'terms': 'clide'}),
('pql.doctor', const <String, Object?>{}),
('pql.decisions.sync', const <String, Object?>{}),
('pql.decisions.list', const <String, Object?>{}),
('pql.decisions.read', const {'id': 'D-1'}),
('pql.decisions.show', const {'id': 'D-1'}),
('pql.tickets.list', const <String, Object?>{}),
('pql.tickets.show', const {'id': 'T-1'}),
(
'pql.tickets.status',
const {
'ids': ['T-1'],
'status': 'done',
}
),
('pql.tickets.board', const <String, Object?>{}),
('pql.plan.status', const <String, Object?>{}),
];
for (final (cmd, args) in commandsWithSimpleArgs) {
test('$cmd surfaces PqlException as a toolError', () async {
final r = await call(cmd, args);
expect(r.ok, isFalse, reason: cmd);
expect(r.error?.kind, IpcErrorKind.toolError, reason: cmd);
});
}
}