blob: 406e8e3aef5cbe103ffaf04e788b1992e75324ee [file] [edit]
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:dartdev/src/commands/dart_mcp_server.dart';
import 'package:dartdev/src/sdk.dart';
import 'package:test/test.dart';
void main() {
group('DartMCPServerCommand', () {
late FakeRunner runner;
late DartMCPServerCommand command;
setUp(() {
runner = FakeRunner();
command = DartMCPServerCommand();
runner.addCommand(command);
});
test('mcpServerSnapshot path is non-empty', () {
expect(sdk.mcpServerSnapshot, isNotEmpty);
expect(sdk.mcpServerSnapshot, contains('mcp_server.dart.snapshot'));
});
test(
'delegates to `run dart_mcp_server@` when snapshot does not exist',
() async {
await runner.run(['mcp-server']);
expect(runner.capturedArgs, equals(['run', 'dart_mcp_server@']));
},
);
test('launches snapshot directly when snapshot exists', () async {
final snapshotFile = File(sdk.mcpServerSnapshot);
final shouldCreateDir = !snapshotFile.parent.existsSync();
if (shouldCreateDir) {
snapshotFile.parent.createSync(recursive: true);
}
final shouldCreateFile = !snapshotFile.existsSync();
if (shouldCreateFile) {
snapshotFile.writeAsStringSync('');
}
try {
final result = await runner.run(['mcp-server']);
expect(result, equals(0));
// Should intercept and run via VmInteropHandler instead of falling back
// to `run dart_mcp_server@`.
expect(runner.capturedArgs, isNull);
} finally {
if (shouldCreateFile) {
snapshotFile.deleteSync();
}
}
});
test('forwards command arguments', () async {
await runner.run(['mcp-server', '--help', '--log-file', 'foo.log']);
expect(
runner.capturedArgs,
equals(['run', 'dart_mcp_server@', '--help', '--log-file', 'foo.log']),
);
});
test('strips experimental flag', () async {
await runner.run(['mcp-server', '--experimental-mcp-server']);
expect(runner.capturedArgs, equals(['run', 'dart_mcp_server@']));
});
test('strips experimental flag and keeps other args', () async {
await runner.run(['mcp-server', '--experimental-mcp-server', 'foo']);
expect(runner.capturedArgs, equals(['run', 'dart_mcp_server@', 'foo']));
});
test('forwards global arguments', () async {
runner.argParser.addFlag('global-flag', negatable: false);
await runner.run(['--global-flag', 'mcp-server']);
expect(
runner.capturedArgs,
equals(['--global-flag', 'run', 'dart_mcp_server@']),
);
});
});
}
class FakeRunner extends CommandRunner<int> {
List<String>? capturedArgs;
bool isFirstCall = true;
FakeRunner() : super('dart', 'dart command runner');
@override
Future<int?> run(Iterable<String> args) async {
if (isFirstCall) {
isFirstCall = false;
return await super.run(args);
} else {
capturedArgs = args.toList();
return 0;
}
}
}