flutter/packages/flutter_tools/test/commands/analyze_once_test.dart
Ian Hickson 3dec6a6930
Clean up usage of temporary directories (#20682)
All temporary directory start with `flutter_` and have their random component separated from the name by a period, as in `flutter_test_bundle.YFYQMY`.

I've tried to find some of the places where we didn't cleanly delete temporary directories, too. This greatly reduces, though it does not entirely eliminate, the directories we leave behind when running tests, especially `flutter_tools` tests.

While I was at it I standardized on `tempDir` as the variable name for temporary directories, since it was the most common, removing occurrences of `temp` and `tmp`, among others.

Also I factored out some common code that used to catch exceptions that happen on Windows, and made more places use that pattern.
2018-08-17 13:17:23 -07:00

220 lines
7.3 KiB
Dart

// 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 '../src/common.dart';
import '../src/context.dart';
/// Test case timeout for tests involving project analysis.
const Timeout allowForSlowAnalyzeTests = Timeout.factor(5.0);
void main() {
final String analyzerSeparator = platform.isWindows ? '-' : '';
group('analyze once', () {
Directory tempDir;
String projectPath;
File libMain;
setUpAll(() {
Cache.disableLocking();
tempDir = fs.systemTempDirectory.createTempSync('flutter_analyze_once_test_1.').absolute;
projectPath = fs.path.join(tempDir.path, 'flutter_project');
libMain = fs.file(fs.path.join(projectPath, 'lib', 'main.dart'));
});
tearDownAll(() {
tryToDelete(tempDir);
});
// 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);
}, timeout: allowForRemotePubInvocation);
// Analyze in the current directory - no arguments
testUsingContext('working directory', () async {
await runCommand(
command: new AnalyzeCommand(workingDirectory: fs.directory(projectPath)),
arguments: <String>['analyze'],
statusTextContains: <String>['No issues found!'],
);
}, timeout: allowForSlowAnalyzeTests);
// Analyze a specific file outside the current directory
testUsingContext('passing one file throws', () async {
await runCommand(
command: new AnalyzeCommand(),
arguments: <String>['analyze', libMain.path],
toolExit: true,
exitMessageContains: 'is not a directory',
);
});
// Analyze in the current directory - no arguments
testUsingContext('working directory with errors', () async {
// Break the code to produce the "The parameter 'onPressed' 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(
'onPressed: _incrementCounter,',
'// onPressed: _incrementCounter,',
);
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 \'onPressed\' is required',
'info $analyzerSeparator The method \'_incrementCounter\' isn\'t used',
'2 issues found.',
],
toolExit: true,
);
}, timeout: allowForSlowAnalyzeTests);
// Analyze in the current directory - no arguments
testUsingContext('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 \'onPressed\' is required',
'info $analyzerSeparator The method \'_incrementCounter\' isn\'t used',
'info $analyzerSeparator Only throw instances of classes extending either Exception or Error',
'3 issues found.',
],
toolExit: true,
);
}, timeout: allowForSlowAnalyzeTests);
testUsingContext('no duplicate issues', () async {
final Directory tempDir = fs.systemTempDirectory.createTempSync('flutter_analyze_once_test_2.').absolute;
try {
final File foo = fs.file(fs.path.join(tempDir.path, 'foo.dart'));
foo.writeAsStringSync('''
import 'bar.dart';
void 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 {
tryToDelete(tempDir);
}
});
testUsingContext('analyze', () async {
const String contents = '''
StringBuffer bar = StringBuffer('baz');
''';
final Directory tempDir = fs.systemTempDirectory.createTempSync('flutter_analyze_once_test_3.');
tempDir.childFile('main.dart').writeAsStringSync(contents);
try {
await runCommand(
command: new AnalyzeCommand(workingDirectory: fs.directory(tempDir)),
arguments: <String>['analyze'],
statusTextContains: <String>['No issues found!'],
);
} finally {
tryToDelete(tempDir);
}
});
});
}
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,
String exitMessageContains,
}) async {
try {
arguments.insert(0, '--flutter-root=${Cache.flutterRoot}');
await createTestCommandRunner(command).run(arguments);
expect(toolExit, isFalse, reason: 'Expected ToolExit exception');
} on ToolExit catch (e) {
if (!toolExit) {
testLogger.clear();
rethrow;
}
if (exitMessageContains != null) {
expect(e.message, contains(exitMessageContains));
}
}
assertContains(testLogger.statusText, statusTextContains);
assertContains(testLogger.errorText, errorTextContains);
testLogger.clear();
}