// Copyright 2015 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 'dart:io' as io; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/dart/sdk.dart'; import 'package:test/test.dart'; import '../src/context.dart'; // This test depends on some files in ///dev/automated_tests/flutter_test/* Future _testExclusionLock; void main() { group('flutter test should', () { final String automatedTestsDirectory = fs.path.join('..', '..', 'dev', 'automated_tests'); final String flutterTestDirectory = fs.path.join(automatedTestsDirectory, 'flutter_test'); testUsingContext('report nice errors for exceptions thrown within testWidgets()', () async { Cache.flutterRoot = '../..'; return _testFile('exception_handling', automatedTestsDirectory, flutterTestDirectory); }, skip: io.Platform.isWindows); // Dart on Windows has trouble with unicode characters in output testUsingContext('report a nice error when a guarded function was called without await', () async { Cache.flutterRoot = '../..'; return _testFile('test_async_utils_guarded', automatedTestsDirectory, flutterTestDirectory); }, skip: io.Platform.isWindows); // Dart on Windows has trouble with unicode characters in output testUsingContext('report a nice error when an async function was called without await', () async { Cache.flutterRoot = '../..'; return _testFile('test_async_utils_unguarded', automatedTestsDirectory, flutterTestDirectory); }, skip: io.Platform.isWindows); // Dart on Windows has trouble with unicode characters in output testUsingContext('report a nice error when a Ticker is left running', () async { Cache.flutterRoot = '../..'; return _testFile('ticker', automatedTestsDirectory, flutterTestDirectory); }, skip: io.Platform.isWindows); // Dart on Windows has trouble with unicode characters in output testUsingContext('report a nice error when a pubspec.yaml is missing a flutter_test dependency', () async { final String missingDependencyTests = fs.path.join('..', '..', 'dev', 'missing_dependency_tests'); Cache.flutterRoot = '../..'; return _testFile('trivial', missingDependencyTests, missingDependencyTests); }, skip: io.Platform.isWindows); // Dart on Windows has trouble with unicode characters in output testUsingContext('run a test when its name matches a regexp', () async { Cache.flutterRoot = '../..'; final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory, extraArgs: const ['--name', 'inc.*de']); if (!result.stdout.contains('+1: All tests passed')) fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); expect(result.exitCode, 0); }); testUsingContext('run a test when its name contains a string', () async { Cache.flutterRoot = '../..'; final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory, extraArgs: const ['--plain-name', 'include']); if (!result.stdout.contains('+1: All tests passed')) fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n'); expect(result.exitCode, 0); }); testUsingContext('test runs to completion', () async { Cache.flutterRoot = '../..'; final ProcessResult result = await _runFlutterTest('trivial', automatedTestsDirectory, flutterTestDirectory, extraArgs: const ['--verbose']); if ((!result.stdout.contains('+1: All tests passed')) || (!result.stdout.contains('test 0: starting shell process')) || (!result.stdout.contains('test 0: deleting temporary directory')) || (!result.stdout.contains('test 0: finished')) || (!result.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.isNotEmpty) fail('unexpected error output from test:\n\n${result.stderr}\n-- end stderr --\n\n'); expect(result.exitCode, 0); }); }); } Future _testFile(String testName, String workingDirectory, String testDirectory) async { final String fullTestExpectation = fs.path.join(testDirectory, '${testName}_expectation.txt'); final File expectationFile = fs.file(fullTestExpectation); if (!expectationFile.existsSync()) fail('missing expectation file: $expectationFile'); while (_testExclusionLock != null) await _testExclusionLock; final ProcessResult exec = await _runFlutterTest(testName, workingDirectory, testDirectory); expect(exec.exitCode, isNonZero); final List output = exec.stdout.split('\n'); if (output.first == 'Waiting for another flutter command to release the startup lock...') output.removeAt(0); output.add('<>'); output.addAll(exec.stderr.split('\n')); final List expectations = fs.file(fullTestExpectation).readAsLinesSync(); bool allowSkip = false; int expectationLineNumber = 0; int outputLineNumber = 0; bool haveSeenStdErrMarker = false; while (expectationLineNumber < expectations.length) { expect(output, hasLength(greaterThan(outputLineNumber))); final String expectationLine = expectations[expectationLineNumber]; final String outputLine = output[outputLineNumber]; if (expectationLine == '<>') { allowSkip = true; expectationLineNumber += 1; continue; } if (allowSkip) { if (!new RegExp(expectationLine).hasMatch(outputLine)) { outputLineNumber += 1; continue; } allowSkip = false; } if (expectationLine == '<>') { expect(haveSeenStdErrMarker, isFalse); haveSeenStdErrMarker = true; } expect(outputLine, matches(expectationLine), reason: 'Full output:\n- - - -----8<----- - - -\n${output.join("\n")}\n- - - -----8<----- - - -'); expectationLineNumber += 1; outputLineNumber += 1; } expect(allowSkip, isFalse); if (!haveSeenStdErrMarker) expect(exec.stderr, ''); } Future _runFlutterTest( String testName, String workingDirectory, String testDirectory, { List extraArgs: const [], }) async { final String testFilePath = fs.path.join(testDirectory, '${testName}_test.dart'); final File testFile = fs.file(testFilePath); if (!testFile.existsSync()) fail('missing test file: $testFile'); final List args = [] ..addAll(dartVmFlags) ..add(fs.path.absolute(fs.path.join('bin', 'flutter_tools.dart'))) ..add('test') ..add('--no-color') ..addAll(extraArgs) ..add(testFilePath); while (_testExclusionLock != null) await _testExclusionLock; final Completer testExclusionCompleter = new Completer(); _testExclusionLock = testExclusionCompleter.future; try { return await Process.run( fs.path.join(dartSdkPath, 'bin', 'dart'), args, workingDirectory: workingDirectory, ); } finally { _testExclusionLock = null; testExclusionCompleter.complete(); } }