blob: bec70e6645eff37a999ba24420feb9525fc1e557 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. 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 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/analyze.dart';
import 'package:flutter_tools/src/commands/create.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:test/test.dart';
import '../src/common.dart';
import '../src/context.dart';
void main() {
final String analyzerSeparator = platform.isWindows ? '-' : '•';
group('analyze once', () {
Directory tempDir;
String projectPath;
File libMain;
setUpAll(() {
Cache.disableLocking();
tempDir = fs.systemTempDirectory.createTempSync('analyze_once_test_').absolute;
projectPath = fs.path.join(tempDir.path, 'flutter_project');
libMain = fs.file(fs.path.join(projectPath, 'lib', 'main.dart'));
});
tearDownAll(() {
tempDir?.deleteSync(recursive: true);
});
// Create a project to be analyzed
testUsingContext('flutter create', () async {
await runCommand(
command: new CreateCommand(),
arguments: <String>['create', projectPath],
statusTextContains: <String>[
'All done!',
'Your main program file is lib/main.dart',
],
);
expect(libMain.existsSync(), isTrue);
});
// Analyze in the current directory - no arguments
testUsingContext('flutter analyze working directory', () async {
await runCommand(
command: new AnalyzeCommand(workingDirectory: fs.directory(projectPath)),
arguments: <String>['analyze'],
statusTextContains: <String>['No issues found!'],
);
});
// Analyze a specific file outside the current directory
testUsingContext('flutter analyze one file', () async {
await runCommand(
command: new AnalyzeCommand(),
arguments: <String>['analyze', libMain.path],
statusTextContains: <String>['No issues found!'],
);
});
// Analyze in the current directory - no arguments
testUsingContext('flutter analyze working directory with errors', () async {
// Break the code to produce the "The parameter 'child' is required" hint
// that is upgraded to a warning in package:flutter/analysis_options_user.yaml
// to assert that we are using the default Flutter analysis options.
// Also insert a statement that should not trigger a lint here
// but will trigger a lint later on when an analysis_options.yaml is added.
String source = await libMain.readAsString();
source = source.replaceFirst(
'child: new Icon(Icons.add),',
'// child: new Icon(Icons.add),',
);
source = source.replaceFirst(
'_counter++;',
'_counter++; throw "an error message";',
);
await libMain.writeAsString(source);
// Analyze in the current directory - no arguments
await runCommand(
command: new AnalyzeCommand(workingDirectory: fs.directory(projectPath)),
arguments: <String>['analyze'],
statusTextContains: <String>[
'Analyzing',
'warning $analyzerSeparator The parameter \'child\' is required',
'1 issue found.',
],
toolExit: true,
);
});
// Analyze a specific file outside the current directory
testUsingContext('flutter analyze one file with errors', () async {
await runCommand(
command: new AnalyzeCommand(),
arguments: <String>['analyze', libMain.path],
statusTextContains: <String>[
'Analyzing',
'warning $analyzerSeparator The parameter \'child\' is required',
'1 issue found.',
],
toolExit: true,
);
});
// Analyze in the current directory - no arguments
testUsingContext('flutter analyze working directory with local options', () async {
// Insert an analysis_options.yaml file in the project
// which will trigger a lint for broken code that was inserted earlier
final File optionsFile = fs.file(fs.path.join(projectPath, 'analysis_options.yaml'));
await optionsFile.writeAsString('''
include: package:flutter/analysis_options_user.yaml
linter:
rules:
- only_throw_errors
''');
// Analyze in the current directory - no arguments
await runCommand(
command: new AnalyzeCommand(workingDirectory: fs.directory(projectPath)),
arguments: <String>['analyze'],
statusTextContains: <String>[
'Analyzing',
'warning $analyzerSeparator The parameter \'child\' is required',
'lint $analyzerSeparator Only throw instances of classes extending either Exception or Error',
'2 issues found.',
],
toolExit: true,
);
});
testUsingContext('flutter analyze no duplicate issues', () async {
final Directory tempDir = fs.systemTempDirectory.createTempSync('analyze_once_test_').absolute;
try {
final File foo = fs.file(fs.path.join(tempDir.path, 'foo.dart'));
foo.writeAsStringSync('''
import 'bar.dart';
foo() => bar();
''');
final File bar = fs.file(fs.path.join(tempDir.path, 'bar.dart'));
bar.writeAsStringSync('''
import 'dart:async'; // unused
void bar() {
}
''');
// Analyze in the current directory - no arguments
await runCommand(
command: new AnalyzeCommand(workingDirectory: tempDir),
arguments: <String>['analyze'],
statusTextContains: <String>[
'Analyzing',
'1 issue found.',
],
toolExit: true,
);
} finally {
tempDir.deleteSync(recursive: true);
}
});
// Analyze a specific file outside the current directory
testUsingContext('flutter analyze one file with local options', () async {
await runCommand(
command: new AnalyzeCommand(),
arguments: <String>['analyze', libMain.path],
statusTextContains: <String>[
'Analyzing',
'warning $analyzerSeparator The parameter \'child\' is required',
'lint $analyzerSeparator Only throw instances of classes extending either Exception or Error',
'2 issues found.',
],
toolExit: true,
);
});
});
}
void assertContains(String text, List<String> patterns) {
if (patterns == null) {
expect(text, isEmpty);
} else {
for (String pattern in patterns) {
expect(text, contains(pattern));
}
}
}
Future<Null> runCommand({
FlutterCommand command,
List<String> arguments,
List<String> statusTextContains,
List<String> errorTextContains,
bool toolExit: false,
}) async {
try {
arguments.insert(0, '--flutter-root=${Cache.flutterRoot}');
await createTestCommandRunner(command).run(arguments);
expect(toolExit, isFalse, reason: 'Expected ToolExit exception');
} on ToolExit {
if (!toolExit) {
testLogger.clear();
rethrow;
}
}
assertContains(testLogger.statusText, statusTextContains);
assertContains(testLogger.errorText, errorTextContains);
testLogger.clear();
}