blob: 8fc71d997bf51a221d91ea65c09d511fc48c29ec [file] [log] [blame]
// Copyright (c) 2014, 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/args.dart';
import 'package:matcher/matcher.dart';
import 'package:path/path.dart' as path;
import 'fuzz/server_manager.dart';
/**
* Start analysis server as a separate process and use the stdio to communicate
* with the server.
*/
void main(List<String> args) {
new _FuzzTest().run(args);
}
/**
* Instances of [_FuzzTest] launch and test an analysis server.
* You must specify the location of the Dart SDK and the directory
* containing sources to be analyzed.
*/
class _FuzzTest {
//TODO (danrubel) extract common behavior for use in multiple test scenarios
//TODO (danrubel) cleanup test to use async/await for better readability
// VM flag --enable_async
static const String DART_SDK_OPTION = 'dart-sdk';
static const String HELP_OPTION = 'help';
File serverSnapshot;
Directory appDir;
/// Parse the arguments and initialize the receiver
/// Return `true` if proper arguments were provided
bool parseArgs(List<String> args) {
ArgParser parser = new ArgParser();
void error(String errMsg) {
stderr.writeln(errMsg);
print('');
_printUsage(parser);
exitCode = 11;
}
parser.addOption(DART_SDK_OPTION, help: '[sdkPath] path to Dart SDK');
parser.addFlag(
HELP_OPTION,
help: 'print this help message without starting analysis',
defaultsTo: false,
negatable: false);
ArgResults results;
try {
results = parser.parse(args);
} on FormatException catch (e) {
error(e.message);
return false;
}
if (results[HELP_OPTION]) {
_printUsage(parser);
return false;
}
String sdkPath = results[DART_SDK_OPTION];
if (sdkPath is! String) {
error('Missing path to Dart SDK');
return false;
}
Directory sdkDir = new Directory(sdkPath);
if (!sdkDir.existsSync()) {
error('Specified Dart SDK does not exist: $sdkPath');
return false;
}
if (results.rest.length == 0) {
error('Expected directory to analyze');
return false;
}
appDir = new Directory(results.rest[0]);
if (!appDir.existsSync()) {
error('Specified application directory does not exist: $appDir');
return false;
}
if (results.rest.length > 1) {
error('Unexpected arguments after $appDir');
return false;
}
serverSnapshot = new File(
path.join(sdkDir.path, 'bin', 'snapshots', 'analysis_server.dart.snapshot'));
if (!serverSnapshot.existsSync()) {
error('Analysis Server snapshot not found: $serverSnapshot');
return false;
}
return true;
}
/// Main entry point for launching, testing, and shutting down the server
void run(List<String> args) {
if (!parseArgs(args)) return;
ServerManager.start(serverSnapshot.path).then((ServerManager manager) {
runZoned(() {
test(manager).then(manager.stop).then((_) {
expect(manager.errorOccurred, isFalse);
print('Test completed successfully');
});
}, onError: (error, stack) {
stderr.writeln(error);
print(stack);
exitCode = 12;
manager.stop();
});
});
}
/// Use manager to exercise the analysis server
Future test(ServerManager manager) {
// perform initial analysis
return manager.analyze(appDir).then((AnalysisResults analysisResults) {
print(
'Found ${analysisResults.errorCount} errors,'
' ${analysisResults.warningCount} warnings,'
' and ${analysisResults.hintCount} hints in ${analysisResults.elapsed}');
// edit a method body
return manager.openFileNamed(
'domain_completion.dart').then((Editor editor) {
return editor.moveAfter('Response processRequest(Request request) {');
}).then((Editor editor) {
return editor.replace(0, '\nOb');
}).then((Editor editor) {
// request code completion and assert results
return editor.getSuggestions().then((List<CompletionResults> list) {
expect(list, isNotNull);
expect(list.length, equals(0));
list.forEach((CompletionResults results) {
print('${results.elapsed} received ${results.suggestionCount} suggestions');
});
return editor;
});
}).then((Editor editor) {
print('tests complete');
});
});
}
void _printAnalysisSummary(AnalysisResults results) {
print(
'Found ${results.errorCount} errors, ${results.warningCount} warnings,'
' and ${results.hintCount} hints in $results.elapsed');
}
/// Print information about how to use the server.
void _printUsage(ArgParser parser) {
print('Usage: analyzer [flags] <application_directory>');
print('');
print('Supported flags are:');
print(parser.getUsage());
}
}