2019-11-27 23:04:02 +00:00
|
|
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
2016-05-16 19:53:13 +00:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
import 'dart:async';
|
2019-12-10 02:58:02 +00:00
|
|
|
import 'dart:convert';
|
2016-05-16 19:53:13 +00:00
|
|
|
|
2017-01-07 00:51:44 +00:00
|
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
2017-01-09 16:37:00 +00:00
|
|
|
import 'package:flutter_tools/src/base/io.dart';
|
2016-05-16 19:53:13 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
import '../src/common.dart';
|
|
|
|
import 'test_utils.dart';
|
2016-05-16 19:53:13 +00:00
|
|
|
|
|
|
|
// This test depends on some files in ///dev/automated_tests/flutter_test/*
|
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
final String automatedTestsDirectory = fileSystem.path.join('..', '..', 'dev', 'automated_tests');
|
|
|
|
final String missingDependencyDirectory = fileSystem.path.join('..', '..', 'dev', 'missing_dependency_tests');
|
|
|
|
final String flutterTestDirectory = fileSystem.path.join(automatedTestsDirectory, 'flutter_test');
|
|
|
|
final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', platform.isWindows ? 'flutter.bat' : 'flutter');
|
2017-03-10 17:39:01 +00:00
|
|
|
|
2016-05-16 19:53:13 +00:00
|
|
|
void main() {
|
2020-10-07 15:46:11 +00:00
|
|
|
setUpAll(() async {
|
|
|
|
await processManager.run(
|
|
|
|
<String>[
|
|
|
|
flutterBin,
|
|
|
|
'pub',
|
|
|
|
'get'
|
|
|
|
],
|
|
|
|
workingDirectory: flutterTestDirectory
|
|
|
|
);
|
|
|
|
await processManager.run(
|
|
|
|
<String>[
|
|
|
|
flutterBin,
|
|
|
|
'pub',
|
|
|
|
'get'
|
|
|
|
],
|
|
|
|
workingDirectory: missingDependencyDirectory
|
|
|
|
);
|
|
|
|
});
|
2017-03-10 17:39:01 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should not have extraneous error messages', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
return _testFile('trivial_widget', automatedTestsDirectory, flutterTestDirectory, exitCode: isZero);
|
|
|
|
});
|
2017-03-10 17:39:01 +00:00
|
|
|
|
2021-01-26 06:34:03 +00:00
|
|
|
testWithoutContext('flutter test set the working directory correctly', () async {
|
|
|
|
return _testFile('working_directory', automatedTestsDirectory, flutterTestDirectory, exitCode: isZero);
|
|
|
|
});
|
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should report nice errors for exceptions thrown within testWidgets()', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
return _testFile('exception_handling', automatedTestsDirectory, flutterTestDirectory);
|
|
|
|
});
|
2017-03-10 17:39:01 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should report a nice error when a guarded function was called without await', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
return _testFile('test_async_utils_guarded', automatedTestsDirectory, flutterTestDirectory);
|
|
|
|
});
|
2017-12-09 00:51:59 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should report a nice error when an async function was called without await', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
return _testFile('test_async_utils_unguarded', automatedTestsDirectory, flutterTestDirectory);
|
|
|
|
});
|
2019-07-09 17:18:30 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should report a nice error when a Ticker is left running', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
return _testFile('ticker', automatedTestsDirectory, flutterTestDirectory);
|
|
|
|
});
|
2019-07-09 17:18:30 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should report a nice error when a pubspec.yaml is missing a flutter_test dependency', () async {
|
|
|
|
final String missingDependencyTests = fileSystem.path.join('..', '..', 'dev', 'missing_dependency_tests');
|
2019-12-10 02:58:02 +00:00
|
|
|
return _testFile('trivial', missingDependencyTests, missingDependencyTests);
|
|
|
|
});
|
2017-06-30 00:26:19 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should report which user-created widget caused the error', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
return _testFile('print_user_created_ancestor', automatedTestsDirectory, flutterTestDirectory,
|
2019-10-14 01:41:22 +00:00
|
|
|
extraArguments: const <String>['--track-widget-creation']);
|
2019-12-10 02:58:02 +00:00
|
|
|
});
|
2019-10-14 01:41:22 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should report which user-created widget caused the error - no flag', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
return _testFile('print_user_created_ancestor_no_flag', automatedTestsDirectory, flutterTestDirectory,
|
|
|
|
extraArguments: const <String>['--no-track-widget-creation']);
|
|
|
|
});
|
2019-07-16 16:47:42 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should report the correct user-created widget that caused the error', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
return _testFile('print_correct_local_widget', automatedTestsDirectory, flutterTestDirectory,
|
|
|
|
extraArguments: const <String>['--track-widget-creation']);
|
|
|
|
});
|
2017-06-30 00:26:19 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should can load assets within its own package', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
return _testFile('package_assets', automatedTestsDirectory, flutterTestDirectory, exitCode: isZero);
|
|
|
|
});
|
2017-08-04 23:33:38 +00:00
|
|
|
|
2020-11-18 22:52:49 +00:00
|
|
|
testWithoutContext('flutter test should support dart defines', () async {
|
|
|
|
return _testFile('dart_defines', automatedTestsDirectory, flutterTestDirectory, exitCode: isZero,
|
|
|
|
extraArguments: <String>['--dart-define=flutter.test.foo=bar']);
|
|
|
|
});
|
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should run a test when its name matches a regexp', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory,
|
|
|
|
extraArguments: const <String>['--name', 'inc.*de']);
|
|
|
|
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
|
|
|
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
|
|
}
|
|
|
|
expect(result.exitCode, 0);
|
|
|
|
});
|
2017-06-30 00:26:19 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should run a test when its name contains a string', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory,
|
|
|
|
extraArguments: const <String>['--plain-name', 'include']);
|
|
|
|
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
|
|
|
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
|
|
}
|
|
|
|
expect(result.exitCode, 0);
|
|
|
|
});
|
2019-08-13 21:57:43 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should run a test with a given tag', () async {
|
2020-04-21 17:35:13 +00:00
|
|
|
final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory,
|
|
|
|
extraArguments: const <String>['--tags', 'include-tag']);
|
|
|
|
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
|
|
|
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
|
|
}
|
|
|
|
expect(result.exitCode, 0);
|
|
|
|
});
|
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should not run a test with excluded tag', () async {
|
2020-04-21 17:35:13 +00:00
|
|
|
final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory,
|
|
|
|
extraArguments: const <String>['--exclude-tags', 'exclude-tag']);
|
|
|
|
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
|
|
|
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
|
|
}
|
|
|
|
expect(result.exitCode, 0);
|
|
|
|
});
|
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should run all tests when tags are unspecified', () async {
|
2020-04-21 17:35:13 +00:00
|
|
|
final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory);
|
|
|
|
if (!(result.stdout as String).contains('+1 -1: Some tests failed')) {
|
|
|
|
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
|
|
}
|
|
|
|
expect(result.exitCode, 1);
|
|
|
|
});
|
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should run a widgetTest with a given tag', () async {
|
2020-04-28 22:49:01 +00:00
|
|
|
final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory,
|
|
|
|
extraArguments: const <String>['--tags', 'include-tag']);
|
|
|
|
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
|
|
|
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
|
|
}
|
|
|
|
expect(result.exitCode, 0);
|
|
|
|
});
|
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should not run a widgetTest with excluded tag', () async {
|
2020-04-28 22:49:01 +00:00
|
|
|
final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory,
|
|
|
|
extraArguments: const <String>['--exclude-tags', 'exclude-tag']);
|
|
|
|
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
|
|
|
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
|
|
}
|
|
|
|
expect(result.exitCode, 0);
|
|
|
|
});
|
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should run all widgetTest when tags are unspecified', () async {
|
2020-04-28 22:49:01 +00:00
|
|
|
final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory);
|
|
|
|
if (!(result.stdout as String).contains('+1 -1: Some tests failed')) {
|
|
|
|
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
|
|
}
|
|
|
|
expect(result.exitCode, 1);
|
|
|
|
});
|
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should test runs to completion', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
final ProcessResult result = await _runFlutterTest('trivial', automatedTestsDirectory, flutterTestDirectory,
|
|
|
|
extraArguments: const <String>['--verbose']);
|
|
|
|
final String stdout = result.stdout as String;
|
|
|
|
if ((!stdout.contains('+1: All tests passed')) ||
|
|
|
|
(!stdout.contains('test 0: starting shell process')) ||
|
|
|
|
(!stdout.contains('test 0: deleting temporary directory')) ||
|
|
|
|
(!stdout.contains('test 0: finished')) ||
|
|
|
|
(!stdout.contains('test package returned with exit code 0'))) {
|
|
|
|
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
|
|
}
|
|
|
|
if ((result.stderr as String).isNotEmpty) {
|
|
|
|
fail('unexpected error output from test:\n\n${result.stderr}\n-- end stderr --\n\n');
|
|
|
|
}
|
|
|
|
expect(result.exitCode, 0);
|
|
|
|
});
|
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
testWithoutContext('flutter test should run all tests inside of a directory with no trailing slash', () async {
|
2019-12-10 02:58:02 +00:00
|
|
|
final ProcessResult result = await _runFlutterTest(null, automatedTestsDirectory, flutterTestDirectory + '/child_directory',
|
|
|
|
extraArguments: const <String>['--verbose']);
|
|
|
|
final String stdout = result.stdout as String;
|
|
|
|
if ((!stdout.contains('+2: All tests passed')) ||
|
|
|
|
(!stdout.contains('test 0: starting shell process')) ||
|
|
|
|
(!stdout.contains('test 0: deleting temporary directory')) ||
|
|
|
|
(!stdout.contains('test 0: finished')) ||
|
|
|
|
(!stdout.contains('test package returned with exit code 0'))) {
|
|
|
|
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
|
|
}
|
|
|
|
if ((result.stderr as String).isNotEmpty) {
|
|
|
|
fail('unexpected error output from test:\n\n${result.stderr}\n-- end stderr --\n\n');
|
|
|
|
}
|
|
|
|
expect(result.exitCode, 0);
|
2018-01-18 00:08:07 +00:00
|
|
|
});
|
2016-05-16 19:53:13 +00:00
|
|
|
}
|
|
|
|
|
2019-07-09 17:18:30 +00:00
|
|
|
Future<void> _testFile(
|
2019-10-04 09:00:18 +00:00
|
|
|
String testName,
|
|
|
|
String workingDirectory,
|
|
|
|
String testDirectory, {
|
|
|
|
Matcher exitCode,
|
|
|
|
List<String> extraArguments = const <String>[],
|
|
|
|
}) async {
|
2018-01-18 22:06:35 +00:00
|
|
|
exitCode ??= isNonZero;
|
2020-10-07 15:46:11 +00:00
|
|
|
final String fullTestExpectation = fileSystem.path.join(testDirectory, '${testName}_expectation.txt');
|
|
|
|
final File expectationFile = fileSystem.file(fullTestExpectation);
|
2019-09-13 21:51:35 +00:00
|
|
|
if (!expectationFile.existsSync()) {
|
2017-08-04 23:33:38 +00:00
|
|
|
fail('missing expectation file: $expectationFile');
|
2019-09-13 21:51:35 +00:00
|
|
|
}
|
2017-03-10 17:39:01 +00:00
|
|
|
|
2019-07-09 17:18:30 +00:00
|
|
|
final ProcessResult exec = await _runFlutterTest(
|
|
|
|
testName,
|
|
|
|
workingDirectory,
|
|
|
|
testDirectory,
|
|
|
|
extraArguments: extraArguments,
|
|
|
|
);
|
2017-03-10 17:39:01 +00:00
|
|
|
|
2018-01-18 22:06:35 +00:00
|
|
|
expect(exec.exitCode, exitCode);
|
2019-11-24 05:54:43 +00:00
|
|
|
final List<String> output = (exec.stdout as String).split('\n');
|
2020-05-27 22:30:46 +00:00
|
|
|
if (output.first.startsWith('Waiting for another flutter command to release the startup lock...')) {
|
2017-03-22 18:07:58 +00:00
|
|
|
output.removeAt(0);
|
2019-09-13 21:51:35 +00:00
|
|
|
}
|
|
|
|
if (output.first.startsWith('Running "flutter pub get" in')) {
|
2018-08-16 11:22:13 +00:00
|
|
|
output.removeAt(0);
|
2019-09-13 21:51:35 +00:00
|
|
|
}
|
2017-01-10 19:31:24 +00:00
|
|
|
output.add('<<stderr>>');
|
2019-11-24 05:54:43 +00:00
|
|
|
output.addAll((exec.stderr as String).split('\n'));
|
2020-10-07 15:46:11 +00:00
|
|
|
final List<String> expectations = fileSystem.file(fullTestExpectation).readAsLinesSync();
|
2016-05-16 19:53:13 +00:00
|
|
|
bool allowSkip = false;
|
|
|
|
int expectationLineNumber = 0;
|
|
|
|
int outputLineNumber = 0;
|
2017-01-10 19:31:24 +00:00
|
|
|
bool haveSeenStdErrMarker = false;
|
2016-05-16 19:53:13 +00:00
|
|
|
while (expectationLineNumber < expectations.length) {
|
2018-09-20 22:45:48 +00:00
|
|
|
expect(
|
|
|
|
output,
|
|
|
|
hasLength(greaterThan(outputLineNumber)),
|
|
|
|
reason: 'Failure in $testName to compare to $fullTestExpectation',
|
|
|
|
);
|
2016-05-16 19:53:13 +00:00
|
|
|
final String expectationLine = expectations[expectationLineNumber];
|
2019-05-01 18:20:12 +00:00
|
|
|
String outputLine = output[outputLineNumber];
|
2016-05-16 19:53:13 +00:00
|
|
|
if (expectationLine == '<<skip until matching line>>') {
|
|
|
|
allowSkip = true;
|
|
|
|
expectationLineNumber += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (allowSkip) {
|
2018-09-12 06:29:29 +00:00
|
|
|
if (!RegExp(expectationLine).hasMatch(outputLine)) {
|
2016-05-16 19:53:13 +00:00
|
|
|
outputLineNumber += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
allowSkip = false;
|
|
|
|
}
|
2017-01-10 19:31:24 +00:00
|
|
|
if (expectationLine == '<<stderr>>') {
|
|
|
|
expect(haveSeenStdErrMarker, isFalse);
|
|
|
|
haveSeenStdErrMarker = true;
|
|
|
|
}
|
2019-05-01 18:20:12 +00:00
|
|
|
if (!RegExp(expectationLine).hasMatch(outputLine) && outputLineNumber + 1 < output.length) {
|
|
|
|
// Check if the RegExp can match the next two lines in the output so
|
|
|
|
// that it is possible to write expectations that still hold even if a
|
|
|
|
// line is wrapped slightly differently due to for example a file name
|
|
|
|
// being longer on one platform than another.
|
|
|
|
final String mergedLines = '$outputLine\n${output[outputLineNumber+1]}';
|
|
|
|
if (RegExp(expectationLine).hasMatch(mergedLines)) {
|
|
|
|
outputLineNumber += 1;
|
|
|
|
outputLine = mergedLines;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-23 23:08:25 +00:00
|
|
|
expect(outputLine, matches(expectationLine), reason: 'Full output:\n- - - -----8<----- - - -\n${output.join("\n")}\n- - - -----8<----- - - -');
|
2016-05-16 19:53:13 +00:00
|
|
|
expectationLineNumber += 1;
|
|
|
|
outputLineNumber += 1;
|
|
|
|
}
|
|
|
|
expect(allowSkip, isFalse);
|
2019-09-13 21:51:35 +00:00
|
|
|
if (!haveSeenStdErrMarker) {
|
2017-01-10 19:31:24 +00:00
|
|
|
expect(exec.stderr, '');
|
2019-09-13 21:51:35 +00:00
|
|
|
}
|
2016-05-16 19:53:13 +00:00
|
|
|
}
|
2017-06-30 00:26:19 +00:00
|
|
|
|
2017-08-04 23:33:38 +00:00
|
|
|
Future<ProcessResult> _runFlutterTest(
|
|
|
|
String testName,
|
|
|
|
String workingDirectory,
|
|
|
|
String testDirectory, {
|
2019-07-09 17:18:30 +00:00
|
|
|
List<String> extraArguments = const <String>[],
|
2017-08-04 23:33:38 +00:00
|
|
|
}) async {
|
|
|
|
|
2019-08-13 21:57:43 +00:00
|
|
|
String testPath;
|
|
|
|
if (testName == null) {
|
|
|
|
// Test everything in the directory.
|
|
|
|
testPath = testDirectory;
|
2020-10-07 15:46:11 +00:00
|
|
|
final Directory directoryToTest = fileSystem.directory(testPath);
|
2019-09-13 21:51:35 +00:00
|
|
|
if (!directoryToTest.existsSync()) {
|
2019-08-13 21:57:43 +00:00
|
|
|
fail('missing test directory: $directoryToTest');
|
2019-09-13 21:51:35 +00:00
|
|
|
}
|
2019-08-13 21:57:43 +00:00
|
|
|
} else {
|
|
|
|
// Test just a specific test file.
|
2020-10-07 15:46:11 +00:00
|
|
|
testPath = fileSystem.path.join(testDirectory, '${testName}_test.dart');
|
|
|
|
final File testFile = fileSystem.file(testPath);
|
2019-09-13 21:51:35 +00:00
|
|
|
if (!testFile.existsSync()) {
|
2019-08-13 21:57:43 +00:00
|
|
|
fail('missing test file: $testFile');
|
2019-09-13 21:51:35 +00:00
|
|
|
}
|
2019-08-13 21:57:43 +00:00
|
|
|
}
|
2017-06-30 00:26:19 +00:00
|
|
|
|
2019-06-27 19:23:16 +00:00
|
|
|
final List<String> args = <String>[
|
|
|
|
'test',
|
|
|
|
'--no-color',
|
2020-02-26 23:36:02 +00:00
|
|
|
'--no-version-check',
|
2020-10-07 15:46:11 +00:00
|
|
|
'--no-pub',
|
2019-07-09 17:18:30 +00:00
|
|
|
...extraArguments,
|
2019-09-24 06:06:09 +00:00
|
|
|
testPath,
|
2019-06-27 19:23:16 +00:00
|
|
|
];
|
2017-06-30 00:26:19 +00:00
|
|
|
|
2020-10-07 15:46:11 +00:00
|
|
|
return Process.run(
|
|
|
|
flutterBin, // Uses the precompiled flutter tool for faster tests,
|
|
|
|
args,
|
|
|
|
workingDirectory: workingDirectory,
|
|
|
|
stdoutEncoding: utf8,
|
|
|
|
stderrEncoding: utf8,
|
|
|
|
);
|
2017-06-30 00:26:19 +00:00
|
|
|
}
|