Index: pkg/analyzer_cli/test/driver_test.dart |
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart |
index ceac0aad30967ae4632eb65f0ed301b946ebb092..ac3c6743796c1a174dad02a61d8e5ac2d4866fc5 100644 |
--- a/pkg/analyzer_cli/test/driver_test.dart |
+++ b/pkg/analyzer_cli/test/driver_test.dart |
@@ -21,743 +21,575 @@ import 'package:analyzer_cli/src/driver.dart'; |
import 'package:analyzer_cli/src/options.dart'; |
import 'package:path/path.dart' as path; |
import 'package:test/test.dart'; |
+import 'package:test_reflective_loader/test_reflective_loader.dart'; |
import 'package:yaml/src/yaml_node.dart'; |
import 'utils.dart'; |
main() { |
- StringSink savedOutSink, savedErrorSink; |
- int savedExitCode; |
- ExitHandler savedExitHandler; |
+ defineReflectiveSuite(() { |
+ defineReflectiveTests(BuildModeTest); |
+ defineReflectiveTests(ExitCodesTest); |
+ defineReflectiveTests(LinterTest); |
+ defineReflectiveTests(OptionsTest); |
+ }, name: 'Driver'); |
+} |
- /// Base setup. |
- _setUp() { |
- ansi.runningTests = true; |
- savedOutSink = outSink; |
- savedErrorSink = errorSink; |
- savedExitHandler = exitHandler; |
- savedExitCode = exitCode; |
- exitHandler = (code) => exitCode = code; |
- outSink = new StringBuffer(); |
- errorSink = new StringBuffer(); |
+@reflectiveTest |
+class BuildModeTest extends _BaseTest { |
+ test_buildLinked() async { |
+ await withTempDirAsync((tempDir) async { |
+ var outputPath = path.join(tempDir, 'test_file.dart.sum'); |
+ await _doDrive(path.join('data', 'test_file.dart'), additionalArgs: [ |
+ '--build-summary-only', |
+ '--build-summary-output=$outputPath' |
+ ]); |
+ var output = new File(outputPath); |
+ expect(output.existsSync(), isTrue); |
+ PackageBundle bundle = |
+ new PackageBundle.fromBuffer(await output.readAsBytes()); |
+ var testFileUri = 'file:///test_file.dart'; |
+ expect(bundle.unlinkedUnitUris, equals([testFileUri])); |
+ expect(bundle.linkedLibraryUris, equals([testFileUri])); |
+ expect(exitCode, 0); |
+ }); |
} |
- /// Base teardown. |
- _tearDown() { |
- outSink = savedOutSink; |
- errorSink = savedErrorSink; |
- exitCode = savedExitCode; |
- exitHandler = savedExitHandler; |
- ansi.runningTests = false; |
+ test_buildSuppressExitCode_fail_whenFileNotFound() async { |
+ await _doDrive(path.join('data', 'non_existent_file.dart'), |
+ additionalArgs: ['--build-suppress-exit-code']); |
+ expect(exitCode, isNot(0)); |
} |
- setUp(() => _setUp()); |
- |
- tearDown(() => _tearDown()); |
+ test_buildSuppressExitCode_success_evenIfHasError() async { |
+ await _doDrive(path.join('data', 'file_with_error.dart'), |
+ additionalArgs: ['--build-suppress-exit-code']); |
+ expect(exitCode, 0); |
+ } |
- group('Driver', () { |
- group('options', () { |
- test('todos', () async { |
- await drive('data/file_with_todo.dart'); |
- expect(outSink.toString().contains('[info]'), isFalse); |
- }); |
+ test_buildUnlinked() async { |
+ await withTempDirAsync((tempDir) async { |
+ var outputPath = path.join(tempDir, 'test_file.dart.sum'); |
+ await _doDrive(path.join('data', 'test_file.dart'), additionalArgs: [ |
+ '--build-summary-only', |
+ '--build-summary-only-unlinked', |
+ '--build-summary-output=$outputPath' |
+ ]); |
+ var output = new File(outputPath); |
+ expect(output.existsSync(), isTrue); |
+ PackageBundle bundle = |
+ new PackageBundle.fromBuffer(await output.readAsBytes()); |
+ var testFileUri = 'file:///test_file.dart'; |
+ expect(bundle.unlinkedUnits.length, 1); |
+ expect(bundle.unlinkedUnitUris, equals([testFileUri])); |
+ expect(bundle.linkedLibraryUris, isEmpty); |
+ expect(exitCode, 0); |
}); |
- |
- _test_exitCodes(); |
- _test_linter(); |
- _test_optionsProcessing(); |
- _test_buildMode(); |
- |
-//TODO(pq): fix to be bot-friendly (sdk#25258). |
Brian Wilkerson
2017/07/07 16:25:30
Did we loose these tests?
scheglov
2017/07/07 16:37:53
Yes, we did.
Comments is a good long-term code arc
|
-// group('in temp directory', () { |
-// Directory savedCurrentDirectory; |
-// Directory tempDir; |
-// setUp(() { |
-// // Call base setUp. |
-// _setUp(); |
-// savedCurrentDirectory = Directory.current; |
-// tempDir = Directory.systemTemp.createTempSync('analyzer_'); |
-// }); |
-// tearDown(() { |
-// Directory.current = savedCurrentDirectory; |
-// tempDir.deleteSync(recursive: true); |
-// // Call base tearDown. |
-// _tearDown(); |
-// }); |
-// |
-// test('packages folder', () { |
-// Directory.current = tempDir; |
-// new File(path.join(tempDir.path, 'test.dart')).writeAsStringSync(''' |
-//import 'package:foo/bar.dart'; |
-//main() { |
-// baz(); |
-//} |
-// '''); |
-// Directory packagesDir = |
-// new Directory(path.join(tempDir.path, 'packages')); |
-// packagesDir.createSync(); |
-// Directory fooDir = new Directory(path.join(packagesDir.path, 'foo')); |
-// fooDir.createSync(); |
-// new File(path.join(fooDir.path, 'bar.dart')).writeAsStringSync(''' |
-//void baz() {} |
-// '''); |
-// new Driver().start(['test.dart']); |
-// expect(exitCode, 0); |
-// }); |
-// |
-// test('no package resolution', () { |
-// Directory.current = tempDir; |
-// new File(path.join(tempDir.path, 'test.dart')).writeAsStringSync(''' |
-//import 'package:path/path.dart'; |
-//main() {} |
-// '''); |
-// new Driver().start(['test.dart']); |
-// expect(exitCode, 3); |
-// String stdout = outSink.toString(); |
-// expect(stdout, contains('[error] Target of URI does not exist')); |
-// expect(stdout, contains('1 error found.')); |
-// expect(errorSink.toString(), ''); |
-// }); |
-// |
-// test('bad package root', () { |
-// new Driver().start(['--package-root', 'does/not/exist', 'test.dart']); |
-// String stdout = outSink.toString(); |
-// expect(exitCode, 3); |
-// expect( |
-// stdout, |
-// contains( |
-// 'Package root directory (does/not/exist) does not exist.')); |
-// }); |
-// }); |
- }); |
-} |
- |
-const emptyOptionsFile = 'data/empty_options.yaml'; |
- |
-/// Shared driver. |
-Driver driver; |
- |
-List<ErrorProcessor> get processors => |
- driver.context.analysisOptions.errorProcessors; |
- |
-/// Convert a file specification from a relative path to an absolute path. |
-/// Handles the case where the file specification is of the form "$uri|$path". |
-String adjustFileSpec(String fileSpec) { |
- int uriPrefixLength = fileSpec.indexOf('|') + 1; |
- String uriPrefix = fileSpec.substring(0, uriPrefixLength); |
- String relativePath = fileSpec.substring(uriPrefixLength); |
- return '$uriPrefix${path.join(testDirectory, relativePath)}'; |
-} |
- |
-/// Start a driver for the given [source], optionally providing additional |
-/// [args] and an [options] file path. The value of [options] defaults to |
-/// an empty options file to avoid unwanted configuration from an otherwise |
-/// discovered options file. |
-Future<Null> drive(String source, |
- {String options: emptyOptionsFile, |
- List<String> args: const <String>[]}) async { |
- driver = new Driver(isTesting: true); |
- var cmd = [ |
- '--options', |
- path.join(testDirectory, options), |
- adjustFileSpec(source) |
- ]..addAll(args); |
- await driver.start(cmd); |
-} |
- |
-/// Try to find a appropriate directory to pass to "--dart-sdk" that will |
-/// allow summaries to be found. |
-String findSdkDirForSummaries() { |
- Set<String> triedDirectories = new Set<String>(); |
- bool isSuitable(String sdkDir) { |
- triedDirectories.add(sdkDir); |
- return new File(path.join(sdkDir, 'lib', '_internal', 'spec.sum')) |
- .existsSync(); |
- } |
- |
- // Usually the sdk directory is the parent of the parent of the "dart" |
- // executable. |
- Directory executableParent = new File(Platform.executable).parent; |
- Directory executableGrandparent = executableParent.parent; |
- if (isSuitable(executableGrandparent.path)) { |
- return executableGrandparent.path; |
- } |
- // During buildbot execution, the sdk directory is simply the parent of the |
- // "dart" executable. |
- if (isSuitable(executableParent.path)) { |
- return executableParent.path; |
- } |
- // If neither of those are suitable, assume we are running locally within the |
- // SDK project (e.g. within an IDE). Find the build output directory and |
- // search all built configurations. |
- Directory sdkRootDir = |
- new File(Platform.script.toFilePath()).parent.parent.parent.parent; |
- for (String outDirName in ['out', 'xcodebuild']) { |
- Directory outDir = new Directory(path.join(sdkRootDir.path, outDirName)); |
- if (outDir.existsSync()) { |
- for (FileSystemEntity subdir in outDir.listSync()) { |
- if (subdir is Directory) { |
- String candidateSdkDir = path.join(subdir.path, 'dart-sdk'); |
- if (isSuitable(candidateSdkDir)) { |
- return candidateSdkDir; |
- } |
- } |
- } |
- } |
} |
- throw new Exception('Could not find an SDK directory containing summaries.' |
- ' Tried: ${triedDirectories.toList()}'); |
-} |
-Map<String, YamlNode> parseOptions(String src) => |
- new AnalysisOptionsProvider().getOptionsFromString(src); |
- |
-ErrorProcessor processorFor(AnalysisError error) => |
- processors.firstWhere((p) => p.appliesTo(error)); |
- |
-/// Normalize text with bullets. |
-String _bulletToDash(item) => '$item'.replaceAll('•', '-'); |
- |
-void _test_buildMode() { |
- void createTests(String designator, String optionsFileName) { |
- group('build-mode - $designator', () { |
- // Shared driver command. |
- Future<Null> doDrive(String path, |
- {String uri, List<String> additionalArgs: const []}) async { |
- uri ??= 'file:///test_file.dart'; |
- await drive('$uri|$path', |
- args: [ |
- '--dart-sdk', |
- findSdkDirForSummaries(), |
- '--build-mode', |
- '--format=machine' |
- ]..addAll(additionalArgs), |
- options: 'data/options_tests_project/$optionsFileName'); |
- } |
- |
- test('no stats', () async { |
- await doDrive(path.join('data', 'test_file.dart')); |
- // Should not print stat summary. |
- expect(outSink.toString(), isEmpty); |
- expect(errorSink.toString(), isEmpty); |
- expect(exitCode, 0); |
- }); |
- |
- test( |
- 'Fails if file not found, even when --build-suppress-exit-code is given', |
- () async { |
- await doDrive(path.join('data', 'non_existent_file.dart'), |
- additionalArgs: ['--build-suppress-exit-code']); |
- expect(exitCode, isNot(0)); |
- }); |
- |
- test('Fails if there are errors', () async { |
- await doDrive(path.join('data', 'file_with_error.dart')); |
- expect(exitCode, isNot(0)); |
- }); |
- |
- test( |
- 'Succeeds if there are errors, when --build-suppress-exit-code is given', |
- () async { |
- await doDrive(path.join('data', 'file_with_error.dart'), |
- additionalArgs: ['--build-suppress-exit-code']); |
- expect(exitCode, 0); |
- }); |
+ test_consumeLinked() async { |
+ await withTempDirAsync((tempDir) async { |
+ var aDart = path.join(tempDir, 'a.dart'); |
+ var bDart = path.join(tempDir, 'b.dart'); |
+ var cDart = path.join(tempDir, 'c.dart'); |
- test('Consume summaries', () async { |
- await withTempDirAsync((tempDir) async { |
- var aDart = path.join(tempDir, 'a.dart'); |
- var bDart = path.join(tempDir, 'b.dart'); |
- var cDart = path.join(tempDir, 'c.dart'); |
+ var aUri = 'package:aaa/a.dart'; |
+ var bUri = 'package:bbb/b.dart'; |
+ var cUri = 'package:ccc/c.dart'; |
- var aUri = 'package:aaa/a.dart'; |
- var bUri = 'package:bbb/b.dart'; |
- var cUri = 'package:ccc/c.dart'; |
+ var aSum = path.join(tempDir, 'a.sum'); |
+ var bSum = path.join(tempDir, 'b.sum'); |
+ var cSum = path.join(tempDir, 'c.sum'); |
- var aSum = path.join(tempDir, 'a.sum'); |
- var bSum = path.join(tempDir, 'b.sum'); |
- var cSum = path.join(tempDir, 'c.sum'); |
- |
- new File(aDart).writeAsStringSync('class A {}'); |
- new File(bDart).writeAsStringSync(''' |
+ new File(aDart).writeAsStringSync('class A {}'); |
+ new File(bDart).writeAsStringSync(''' |
export 'package:aaa/a.dart'; |
class B {} |
'''); |
- new File(cDart).writeAsStringSync(''' |
+ new File(cDart).writeAsStringSync(''' |
import 'package:bbb/b.dart'; |
var a = new A(); |
var b = new B(); |
'''); |
- // Analyze package:aaa/a.dart and compute summary. |
- { |
- await doDrive(aDart, |
- uri: aUri, additionalArgs: ['--build-summary-output=$aSum']); |
- expect(exitCode, 0); |
- var bytes = new File(aSum).readAsBytesSync(); |
- var bundle = new PackageBundle.fromBuffer(bytes); |
- expect(bundle.unlinkedUnitUris, equals([aUri])); |
- expect(bundle.linkedLibraryUris, equals([aUri])); |
- } |
+ // Analyze package:aaa/a.dart and compute summary. |
+ { |
+ await _doDrive(aDart, |
+ uri: aUri, additionalArgs: ['--build-summary-output=$aSum']); |
+ expect(exitCode, 0); |
+ var bytes = new File(aSum).readAsBytesSync(); |
+ var bundle = new PackageBundle.fromBuffer(bytes); |
+ expect(bundle.unlinkedUnitUris, equals([aUri])); |
+ expect(bundle.linkedLibraryUris, equals([aUri])); |
+ } |
- // Analyze package:bbb/b.dart and compute summary. |
- { |
- await doDrive(bDart, uri: bUri, additionalArgs: [ |
- '--build-summary-input=$aSum', |
- '--build-summary-output=$bSum' |
- ]); |
- expect(exitCode, 0); |
- var bytes = new File(bSum).readAsBytesSync(); |
- var bundle = new PackageBundle.fromBuffer(bytes); |
- expect(bundle.unlinkedUnitUris, equals([bUri])); |
- expect(bundle.linkedLibraryUris, equals([bUri])); |
- } |
+ // Analyze package:bbb/b.dart and compute summary. |
+ { |
+ await _doDrive(bDart, uri: bUri, additionalArgs: [ |
+ '--build-summary-input=$aSum', |
+ '--build-summary-output=$bSum' |
+ ]); |
+ expect(exitCode, 0); |
+ var bytes = new File(bSum).readAsBytesSync(); |
+ var bundle = new PackageBundle.fromBuffer(bytes); |
+ expect(bundle.unlinkedUnitUris, equals([bUri])); |
+ expect(bundle.linkedLibraryUris, equals([bUri])); |
+ } |
- // Analyze package:ccc/c.dart and compute summary. |
- { |
- await doDrive(cDart, uri: cUri, additionalArgs: [ |
- '--build-summary-input=$aSum,$bSum', |
- '--build-summary-output=$cSum' |
- ]); |
- expect(exitCode, 0); |
- var bytes = new File(cSum).readAsBytesSync(); |
- var bundle = new PackageBundle.fromBuffer(bytes); |
- expect(bundle.unlinkedUnitUris, equals([cUri])); |
- expect(bundle.linkedLibraryUris, equals([cUri])); |
- } |
- }); |
- }); |
+ // Analyze package:ccc/c.dart and compute summary. |
+ { |
+ await _doDrive(cDart, uri: cUri, additionalArgs: [ |
+ '--build-summary-input=$aSum,$bSum', |
+ '--build-summary-output=$cSum' |
+ ]); |
+ expect(exitCode, 0); |
+ var bytes = new File(cSum).readAsBytesSync(); |
+ var bundle = new PackageBundle.fromBuffer(bytes); |
+ expect(bundle.unlinkedUnitUris, equals([cUri])); |
+ expect(bundle.linkedLibraryUris, equals([cUri])); |
+ } |
+ }); |
+ } |
- test('Error - unlinked summary as linked', () async { |
- await withTempDirAsync((tempDir) async { |
- var aDart = path.join(tempDir, 'a.dart'); |
- var bDart = path.join(tempDir, 'b.dart'); |
+ test_error_linkedAsUnlinked() async { |
+ await withTempDirAsync((tempDir) async { |
+ var aDart = path.join(tempDir, 'a.dart'); |
+ var bDart = path.join(tempDir, 'b.dart'); |
- var aUri = 'package:aaa/a.dart'; |
- var bUri = 'package:bbb/b.dart'; |
+ var aUri = 'package:aaa/a.dart'; |
+ var bUri = 'package:bbb/b.dart'; |
- var aSum = path.join(tempDir, 'a.sum'); |
- var bSum = path.join(tempDir, 'b.sum'); |
+ var aSum = path.join(tempDir, 'a.sum'); |
+ var bSum = path.join(tempDir, 'b.sum'); |
- new File(aDart).writeAsStringSync('class A {}'); |
+ new File(aDart).writeAsStringSync('class A {}'); |
- // Build unlinked a.sum |
- await doDrive(aDart, uri: aUri, additionalArgs: [ |
- '--build-summary-only', |
- '--build-summary-only-unlinked', |
- '--build-summary-output=$aSum' |
- ]); |
- expect(new File(aSum).existsSync(), isTrue); |
- |
- // Try to consume unlinked a.sum as linked. |
- try { |
- await doDrive(bDart, uri: bUri, additionalArgs: [ |
- '--build-summary-input=$aSum', |
- '--build-summary-output=$bSum' |
- ]); |
- fail('ArgumentError expected.'); |
- } on ArgumentError catch (e) { |
- expect(e.message, |
- contains('Got an unlinked summary for --build-summary-input')); |
- } |
- }); |
- }); |
+ // Build linked a.sum |
+ await _doDrive(aDart, uri: aUri, additionalArgs: [ |
+ '--build-summary-only', |
+ '--build-summary-output=$aSum' |
+ ]); |
+ expect(new File(aSum).existsSync(), isTrue); |
+ |
+ // Try to consume linked a.sum as unlinked. |
+ try { |
+ await _doDrive(bDart, uri: bUri, additionalArgs: [ |
+ '--build-summary-unlinked-input=$aSum', |
+ '--build-summary-output=$bSum' |
+ ]); |
+ fail('ArgumentError expected.'); |
+ } on ArgumentError catch (e) { |
+ expect( |
+ e.message, |
+ contains( |
+ 'Got a linked summary for --build-summary-input-unlinked')); |
+ } |
+ }); |
+ } |
- test('Error - linked summary as unlinked', () async { |
- await withTempDirAsync((tempDir) async { |
- var aDart = path.join(tempDir, 'a.dart'); |
- var bDart = path.join(tempDir, 'b.dart'); |
+ test_error_unlinkedAsLinked() async { |
+ await withTempDirAsync((tempDir) async { |
+ var aDart = path.join(tempDir, 'a.dart'); |
+ var bDart = path.join(tempDir, 'b.dart'); |
- var aUri = 'package:aaa/a.dart'; |
- var bUri = 'package:bbb/b.dart'; |
+ var aUri = 'package:aaa/a.dart'; |
+ var bUri = 'package:bbb/b.dart'; |
- var aSum = path.join(tempDir, 'a.sum'); |
- var bSum = path.join(tempDir, 'b.sum'); |
+ var aSum = path.join(tempDir, 'a.sum'); |
+ var bSum = path.join(tempDir, 'b.sum'); |
- new File(aDart).writeAsStringSync('class A {}'); |
+ new File(aDart).writeAsStringSync('class A {}'); |
- // Build linked a.sum |
- await doDrive(aDart, uri: aUri, additionalArgs: [ |
- '--build-summary-only', |
- '--build-summary-output=$aSum' |
- ]); |
- expect(new File(aSum).existsSync(), isTrue); |
- |
- // Try to consume linked a.sum as unlinked. |
- try { |
- await doDrive(bDart, uri: bUri, additionalArgs: [ |
- '--build-summary-unlinked-input=$aSum', |
- '--build-summary-output=$bSum' |
- ]); |
- fail('ArgumentError expected.'); |
- } on ArgumentError catch (e) { |
- expect( |
- e.message, |
- contains( |
- 'Got a linked summary for --build-summary-input-unlinked')); |
- } |
- }); |
- }); |
- |
- test('Linked summary', () async { |
- await withTempDirAsync((tempDir) async { |
- var outputPath = path.join(tempDir, 'test_file.dart.sum'); |
- await doDrive(path.join('data', 'test_file.dart'), additionalArgs: [ |
- '--build-summary-only', |
- '--build-summary-output=$outputPath' |
- ]); |
- var output = new File(outputPath); |
- expect(output.existsSync(), isTrue); |
- PackageBundle bundle = |
- new PackageBundle.fromBuffer(await output.readAsBytes()); |
- var testFileUri = 'file:///test_file.dart'; |
- expect(bundle.unlinkedUnitUris, equals([testFileUri])); |
- expect(bundle.linkedLibraryUris, equals([testFileUri])); |
- expect(exitCode, 0); |
- }); |
- }); |
- |
- test('Unlinked summary only', () async { |
- await withTempDirAsync((tempDir) async { |
- var outputPath = path.join(tempDir, 'test_file.dart.sum'); |
- await doDrive(path.join('data', 'test_file.dart'), additionalArgs: [ |
- '--build-summary-only', |
- '--build-summary-only-unlinked', |
- '--build-summary-output=$outputPath' |
- ]); |
- var output = new File(outputPath); |
- expect(output.existsSync(), isTrue); |
- PackageBundle bundle = |
- new PackageBundle.fromBuffer(await output.readAsBytes()); |
- var testFileUri = 'file:///test_file.dart'; |
- expect(bundle.unlinkedUnits.length, 1); |
- expect(bundle.unlinkedUnitUris, equals([testFileUri])); |
- expect(bundle.linkedLibraryUris, isEmpty); |
- expect(exitCode, 0); |
- }); |
- }); |
+ // Build unlinked a.sum |
+ await _doDrive(aDart, uri: aUri, additionalArgs: [ |
+ '--build-summary-only', |
+ '--build-summary-only-unlinked', |
+ '--build-summary-output=$aSum' |
+ ]); |
+ expect(new File(aSum).existsSync(), isTrue); |
+ |
+ // Try to consume unlinked a.sum as linked. |
+ try { |
+ await _doDrive(bDart, uri: bUri, additionalArgs: [ |
+ '--build-summary-input=$aSum', |
+ '--build-summary-output=$bSum' |
+ ]); |
+ fail('ArgumentError expected.'); |
+ } on ArgumentError catch (e) { |
+ expect(e.message, |
+ contains('Got an unlinked summary for --build-summary-input')); |
+ } |
}); |
} |
- createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE); |
- createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); |
+ test_fail_whenHasError() async { |
+ await _doDrive(path.join('data', 'file_with_error.dart')); |
+ expect(exitCode, isNot(0)); |
+ } |
+ |
+ test_noStatistics() async { |
+ await _doDrive(path.join('data', 'test_file.dart')); |
+ // Should not print statistics summary. |
+ expect(outSink.toString(), isEmpty); |
+ expect(errorSink.toString(), isEmpty); |
+ expect(exitCode, 0); |
+ } |
+ |
+ Future<Null> _doDrive(String path, |
+ {String uri, List<String> additionalArgs: const []}) async { |
+ uri ??= 'file:///test_file.dart'; |
+ var optionsFileName = AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE; |
+ await drive('$uri|$path', |
+ args: [ |
+ '--dart-sdk', |
+ _findSdkDirForSummaries(), |
+ '--build-mode', |
+ '--format=machine' |
+ ]..addAll(additionalArgs), |
+ options: 'data/options_tests_project/$optionsFileName'); |
+ } |
+ |
+ /// Try to find a appropriate directory to pass to "--dart-sdk" that will |
+ /// allow summaries to be found. |
+ String _findSdkDirForSummaries() { |
+ Set<String> triedDirectories = new Set<String>(); |
+ bool isSuitable(String sdkDir) { |
+ triedDirectories.add(sdkDir); |
+ return new File(path.join(sdkDir, 'lib', '_internal', 'spec.sum')) |
+ .existsSync(); |
+ } |
+ |
+ // Usually the sdk directory is the parent of the parent of the "dart" |
+ // executable. |
+ Directory executableParent = new File(Platform.executable).parent; |
+ Directory executableGrandparent = executableParent.parent; |
+ if (isSuitable(executableGrandparent.path)) { |
+ return executableGrandparent.path; |
+ } |
+ // During build bot execution, the sdk directory is simply the parent of the |
+ // "dart" executable. |
+ if (isSuitable(executableParent.path)) { |
+ return executableParent.path; |
+ } |
+ // If neither of those are suitable, assume we are running locally within the |
+ // SDK project (e.g. within an IDE). Find the build output directory and |
+ // search all built configurations. |
+ Directory sdkRootDir = |
+ new File(Platform.script.toFilePath()).parent.parent.parent.parent; |
+ for (String outDirName in ['out', 'xcodebuild']) { |
+ Directory outDir = new Directory(path.join(sdkRootDir.path, outDirName)); |
+ if (outDir.existsSync()) { |
+ for (FileSystemEntity subdir in outDir.listSync()) { |
+ if (subdir is Directory) { |
+ String candidateSdkDir = path.join(subdir.path, 'dart-sdk'); |
+ if (isSuitable(candidateSdkDir)) { |
+ return candidateSdkDir; |
+ } |
+ } |
+ } |
+ } |
+ } |
+ throw new Exception('Could not find an SDK directory containing summaries.' |
+ ' Tried: ${triedDirectories.toList()}'); |
+ } |
} |
-void _test_exitCodes() { |
- group('exit codes', () { |
- test('fatal hints', () async { |
- await drive('data/file_with_hint.dart', args: ['--fatal-hints']); |
- expect(exitCode, 1); |
+@reflectiveTest |
+class ExitCodesTest extends _BaseTest { |
+ test_bazelWorkspace_relativePath() async { |
+ // Copy to temp dir so that existing analysis options |
+ // in the test directory hierarchy do not interfere |
+ await withTempDirAsync((String tempDirPath) async { |
+ String dartSdkPath = path.absolute(getSdkPath()); |
+ await recursiveCopy( |
+ new Directory(path.join(testDirectory, 'data', 'bazel')), |
+ tempDirPath); |
+ Directory origWorkingDir = Directory.current; |
+ try { |
+ Directory.current = path.join(tempDirPath, 'proj'); |
+ Driver driver = new Driver(isTesting: true); |
+ try { |
+ await driver.start([ |
+ path.join('lib', 'file.dart'), |
+ '--dart-sdk', |
+ dartSdkPath, |
+ ]); |
+ } catch (e) { |
+ print('=== debug info ==='); |
+ print('dartSdkPath: $dartSdkPath'); |
+ print('stderr:\n${errorSink.toString()}'); |
+ rethrow; |
+ } |
+ expect(errorSink.toString(), isEmpty); |
+ expect(outSink.toString(), contains('No issues found')); |
+ expect(exitCode, 0); |
+ } finally { |
+ Directory.current = origWorkingDir; |
+ } |
}); |
+ } |
- test('not fatal hints', () async { |
- await drive('data/file_with_hint.dart'); |
- expect(exitCode, 0); |
- }); |
+ test_enableAssertInitializer() async { |
+ await drive('data/file_with_assert_initializers.dart', |
+ args: ['--enable-assert-initializers']); |
+ expect(exitCode, 0); |
+ } |
- test('fatal errors', () async { |
- await drive('data/file_with_error.dart'); |
- expect(exitCode, 3); |
- }); |
+ test_fatalErrors() async { |
+ await drive('data/file_with_error.dart'); |
+ expect(exitCode, 3); |
+ } |
- test('not fatal warnings', () async { |
- await drive('data/file_with_warning.dart'); |
- expect(exitCode, 0); |
- }); |
+ test_fatalHints() async { |
+ await drive('data/file_with_hint.dart', args: ['--fatal-hints']); |
+ expect(exitCode, 1); |
+ } |
- test('fatal warnings', () async { |
- await drive('data/file_with_warning.dart', args: ['--fatal-warnings']); |
- expect(exitCode, 2); |
- }); |
+ test_fatalWarnings() async { |
+ await drive('data/file_with_warning.dart', args: ['--fatal-warnings']); |
+ expect(exitCode, 2); |
+ } |
- test('not parse enableAssertInitializer', () async { |
- await drive('data/file_with_assert_initializers.dart', |
- args: ['--enable-assert-initializers']); |
- expect(exitCode, 0); |
- }); |
+ test_missingDartFile() async { |
+ await drive('data/NO_DART_FILE_HERE.dart'); |
+ expect(exitCode, 3); |
+ } |
- test('missing options file', () async { |
- await drive('data/test_file.dart', options: 'data/NO_OPTIONS_HERE'); |
- expect(exitCode, 3); |
- }); |
+ test_missingOptionsFile() async { |
+ await drive('data/test_file.dart', options: 'data/NO_OPTIONS_HERE'); |
+ expect(exitCode, 3); |
+ } |
- test('missing dart file', () async { |
- await drive('data/NO_DART_FILE_HERE.dart'); |
- expect(exitCode, 3); |
- }); |
+ test_notFatalHints() async { |
+ await drive('data/file_with_hint.dart'); |
+ expect(exitCode, 0); |
+ } |
- test('part file', () async { |
- await drive('data/library_and_parts/part2.dart'); |
- expect(exitCode, 3); |
- }); |
+ test_notFatalWarnings() async { |
+ await drive('data/file_with_warning.dart'); |
+ expect(exitCode, 0); |
+ } |
- test('non-dangling part file', () async { |
- Driver driver = new Driver(isTesting: true); |
- await driver.start([ |
- path.join(testDirectory, 'data/library_and_parts/lib.dart'), |
- path.join(testDirectory, 'data/library_and_parts/part1.dart') |
- ]); |
- expect(exitCode, 0); |
- }); |
+ test_partFile() async { |
+ Driver driver = new Driver(isTesting: true); |
+ await driver.start([ |
+ path.join(testDirectory, 'data/library_and_parts/lib.dart'), |
+ path.join(testDirectory, 'data/library_and_parts/part1.dart') |
+ ]); |
+ expect(exitCode, 0); |
+ } |
- test('extra part file', () async { |
- Driver driver = new Driver(isTesting: true); |
- await driver.start([ |
- path.join(testDirectory, 'data/library_and_parts/lib.dart'), |
- path.join(testDirectory, 'data/library_and_parts/part1.dart'), |
- path.join(testDirectory, 'data/library_and_parts/part2.dart') |
- ]); |
- expect(exitCode, 3); |
- }); |
+ test_partFile_dangling() async { |
+ await drive('data/library_and_parts/part2.dart'); |
+ expect(exitCode, 3); |
+ } |
- test('bazel workspace relative path', () async { |
- // Copy to temp dir so that existing analysis options |
- // in the test directory hierarchy do not interfere |
- await withTempDirAsync((String tempDirPath) async { |
- String dartSdkPath = path.absolute(getSdkPath()); |
- await recursiveCopy( |
- new Directory(path.join(testDirectory, 'data', 'bazel')), |
- tempDirPath); |
- Directory origWorkingDir = Directory.current; |
- try { |
- Directory.current = path.join(tempDirPath, 'proj'); |
- Driver driver = new Driver(isTesting: true); |
- try { |
- await driver.start([ |
- path.join('lib', 'file.dart'), |
- '--dart-sdk', |
- dartSdkPath, |
- ]); |
- } catch (e) { |
- print('=== debug info ==='); |
- print('dartSdkPath: $dartSdkPath'); |
- print('stderr:\n${errorSink.toString()}'); |
- rethrow; |
- } |
- expect(errorSink.toString(), isEmpty); |
- expect(outSink.toString(), contains('No issues found')); |
- expect(exitCode, 0); |
- } finally { |
- Directory.current = origWorkingDir; |
- } |
- }); |
- }); |
- }); |
+ test_partFile_extra() async { |
+ Driver driver = new Driver(isTesting: true); |
+ await driver.start([ |
+ path.join(testDirectory, 'data/library_and_parts/lib.dart'), |
+ path.join(testDirectory, 'data/library_and_parts/part1.dart'), |
+ path.join(testDirectory, 'data/library_and_parts/part2.dart') |
+ ]); |
+ expect(exitCode, 3); |
+ } |
} |
-void _test_linter() { |
- test('containsLintRuleEntry', () { |
+@reflectiveTest |
+class LinterTest extends _BaseTest { |
+ String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE; |
+ |
+ test_containsLintRuleEntry() async { |
Map<String, YamlNode> options; |
- options = parseOptions(''' |
+ options = _parseOptions(''' |
linter: |
rules: |
- foo |
'''); |
expect(containsLintRuleEntry(options), true); |
- options = parseOptions(''' |
+ options = _parseOptions(''' |
'''); |
expect(containsLintRuleEntry(options), false); |
- options = parseOptions(''' |
+ options = _parseOptions(''' |
linter: |
rules: |
# - foo |
'''); |
expect(containsLintRuleEntry(options), true); |
- options = parseOptions(''' |
+ options = _parseOptions(''' |
linter: |
# rules: |
# - foo |
'''); |
expect(containsLintRuleEntry(options), false); |
- }); |
- |
- group('linter', () { |
- void createTests(String designator, String optionsFileName) { |
- group('lints in options - $designator', () { |
- // Shared lint command. |
- Future<Null> runLinter() async { |
- return await drive('data/linter_project/test_file.dart', |
- options: 'data/linter_project/$optionsFileName', |
- args: ['--lints']); |
- } |
+ } |
- test('gets analysis options', () async { |
- await runLinter(); |
- |
- /// Lints should be enabled. |
- expect(driver.context.analysisOptions.lint, isTrue); |
- |
- /// The analysis options file only specifies 'camel_case_types'. |
- var lintNames = getLints(driver.context).map((r) => r.name); |
- expect(lintNames, orderedEquals(['camel_case_types'])); |
- }); |
- |
- test('generates lints', () async { |
- await runLinter(); |
- expect(_bulletToDash(outSink), |
- contains('lint - Name types using UpperCamelCase')); |
- }); |
- }); |
- |
- group('default lints - $designator', () { |
- // Shared lint command. |
- Future<Null> runLinter() async { |
- return await drive('data/linter_project/test_file.dart', |
- options: 'data/linter_project/$optionsFileName', |
- args: ['--lints']); |
- } |
+ test_defaultLints_generatedLints() async { |
+ await _runLinter_defaultLints(); |
+ expect(_bulletToDash(outSink), |
+ contains('lint - Name types using UpperCamelCase')); |
+ } |
- test('gets default lints', () async { |
- await runLinter(); |
- |
- /// Lints should be enabled. |
- expect(driver.context.analysisOptions.lint, isTrue); |
- |
- /// Default list should include camel_case_types. |
- var lintNames = getLints(driver.context).map((r) => r.name); |
- expect(lintNames, contains('camel_case_types')); |
- }); |
- |
- test('generates lints', () async { |
- await runLinter(); |
- expect(_bulletToDash(outSink), |
- contains('lint - Name types using UpperCamelCase')); |
- }); |
- }); |
- |
- group('no `--lints` flag (none in options) - $designator', () { |
- // Shared lint command. |
- Future<Null> runLinter() async { |
- return await drive('data/no_lints_project/test_file.dart', |
- options: 'data/no_lints_project/$optionsFileName'); |
- } |
+ test_defaultLints_getsDefaultLints() async { |
+ await _runLinter_defaultLints(); |
- test('lints disabled', () async { |
- await runLinter(); |
- expect(driver.context.analysisOptions.lint, isFalse); |
- }); |
- |
- test('no registered lints', () async { |
- await runLinter(); |
- expect(getLints(driver.context), isEmpty); |
- }); |
- |
- test('no generated warnings', () async { |
- await runLinter(); |
- expect(outSink.toString(), contains('No issues found')); |
- }); |
- }); |
- } |
+ /// Lints should be enabled. |
+ expect(driver.context.analysisOptions.lint, isTrue); |
- createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE); |
- createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); |
- }); |
+ /// Default list should include camel_case_types. |
+ var lintNames = getLints(driver.context).map((r) => r.name); |
+ expect(lintNames, contains('camel_case_types')); |
+ } |
+ |
+ test_lintsInOptions_generatedLints() async { |
+ await _runLinter_lintsInOptions(); |
+ expect(_bulletToDash(outSink), |
+ contains('lint - Name types using UpperCamelCase')); |
+ } |
+ |
+ test_lintsInOptions_getAnalysisOptions() async { |
+ await _runLinter_lintsInOptions(); |
+ |
+ /// Lints should be enabled. |
+ expect(driver.context.analysisOptions.lint, isTrue); |
+ |
+ /// The analysis options file only specifies 'camel_case_types'. |
+ var lintNames = getLints(driver.context).map((r) => r.name); |
+ expect(lintNames, orderedEquals(['camel_case_types'])); |
+ } |
+ |
+ test_noLints_lintsDisabled() async { |
+ await _runLinter_noLintsFlag(); |
+ expect(driver.context.analysisOptions.lint, isFalse); |
+ } |
+ |
+ test_noLints_noGeneratedWarnings() async { |
+ await _runLinter_noLintsFlag(); |
+ expect(outSink.toString(), contains('No issues found')); |
+ } |
+ |
+ test_noLints_noRegisteredLints() async { |
+ await _runLinter_noLintsFlag(); |
+ expect(getLints(driver.context), isEmpty); |
+ } |
+ |
+ Map<String, YamlNode> _parseOptions(String src) => |
+ new AnalysisOptionsProvider().getOptionsFromString(src); |
+ |
+ Future<Null> _runLinter_defaultLints() async { |
+ await drive('data/linter_project/test_file.dart', |
+ options: 'data/linter_project/$optionsFileName', args: ['--lints']); |
+ } |
+ |
+ Future<Null> _runLinter_lintsInOptions() async { |
+ await drive('data/linter_project/test_file.dart', |
+ options: 'data/linter_project/$optionsFileName', args: ['--lints']); |
+ } |
+ |
+ Future<Null> _runLinter_noLintsFlag() async { |
+ await drive('data/no_lints_project/test_file.dart', |
+ options: 'data/no_lints_project/$optionsFileName'); |
+ } |
} |
-void _test_optionsProcessing() { |
- group('options processing', () { |
- void createTests(String designator, String optionsFileName) { |
- group('basic config - $designator', () { |
- // Shared driver command. |
- Future<Null> doDrive() async { |
- await drive('data/options_tests_project/test_file.dart', |
- options: 'data/options_tests_project/$optionsFileName'); |
- } |
+@reflectiveTest |
+class OptionsTest extends _BaseTest { |
+ String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE; |
+ |
+ List<ErrorProcessor> get processors => |
+ driver.context.analysisOptions.errorProcessors; |
+ |
+ ErrorProcessor processorFor(AnalysisError error) => |
+ processors.firstWhere((p) => p.appliesTo(error)); |
+ |
+ test_basic_filters() async { |
+ await _driveBasic(); |
+ expect(processors, hasLength(3)); |
+ |
+ // unused_local_variable: ignore |
+ var unused_local_variable = new AnalysisError( |
+ new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [ |
+ ['x'] |
+ ]); |
+ expect(processorFor(unused_local_variable).severity, isNull); |
+ |
+ // missing_return: error |
+ var missing_return = |
+ new AnalysisError(new TestSource(), 0, 1, HintCode.MISSING_RETURN, [ |
+ ['x'] |
+ ]); |
+ expect(processorFor(missing_return).severity, ErrorSeverity.ERROR); |
+ expect(_bulletToDash(outSink), |
+ contains("error - This function declares a return type of 'int'")); |
+ expect(outSink.toString(), contains("1 error and 1 warning found.")); |
+ } |
- test('filters', () async { |
- await doDrive(); |
- expect(processors, hasLength(3)); |
+ test_basic_language() async { |
+ await _driveBasic(); |
+ expect(driver.context.analysisOptions.enableSuperMixins, isTrue); |
+ } |
- // unused_local_variable: ignore |
- var unused_local_variable = new AnalysisError( |
- new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [ |
- ['x'] |
- ]); |
- expect(processorFor(unused_local_variable).severity, isNull); |
+ test_basic_strongMode() async { |
+ await _driveBasic(); |
+ expect(driver.context.analysisOptions.strongMode, isTrue); |
+ // https://github.com/dart-lang/sdk/issues/26129 |
+ AnalysisContext sdkContext = driver.context.sourceFactory.dartSdk.context; |
+ expect(sdkContext.analysisOptions.strongMode, isTrue); |
+ } |
- // missing_return: error |
- var missing_return = new AnalysisError( |
- new TestSource(), 0, 1, HintCode.MISSING_RETURN, [ |
- ['x'] |
- ]); |
- expect(processorFor(missing_return).severity, ErrorSeverity.ERROR); |
- expect( |
- _bulletToDash(outSink), |
- contains( |
- "error - This function declares a return type of 'int'")); |
- expect(outSink.toString(), contains("1 error and 1 warning found.")); |
- }); |
- |
- test('language', () async { |
- await doDrive(); |
- expect(driver.context.analysisOptions.enableSuperMixins, isTrue); |
- }); |
- |
- test('strongMode', () async { |
- await doDrive(); |
- expect(driver.context.analysisOptions.strongMode, isTrue); |
- //https://github.com/dart-lang/sdk/issues/26129 |
- AnalysisContext sdkContext = |
- driver.context.sourceFactory.dartSdk.context; |
- expect(sdkContext.analysisOptions.strongMode, isTrue); |
- }); |
- }); |
- |
- group('with flags - $designator', () { |
- // Shared driver command. |
- Future<Null> doDrive() async { |
- await drive('data/options_tests_project/test_file.dart', |
- args: ['--fatal-warnings'], |
- options: 'data/options_tests_project/$optionsFileName'); |
- } |
+ test_includeDirective() async { |
+ String testDir = path.join( |
+ testDirectory, 'data', 'options_include_directive_tests_project'); |
+ await drive( |
+ path.join(testDir, 'lib', 'test_file.dart'), |
+ args: [ |
+ '--fatal-warnings', |
+ '--packages', |
+ path.join(testDir, '_packages'), |
+ ], |
+ options: path.join(testDir, 'analysis_options.yaml'), |
+ ); |
+ expect(exitCode, 3); |
+ expect(outSink.toString(), |
+ contains('but doesn\'t end with a return statement')); |
+ expect(outSink.toString(), contains('isn\'t defined')); |
+ expect(outSink.toString(), contains('Avoid empty else statements')); |
+ } |
- test('override fatal warning', () async { |
- await doDrive(); |
- // missing_return: error |
- var undefined_function = new AnalysisError(new TestSource(), 0, 1, |
- StaticTypeWarningCode.UNDEFINED_FUNCTION, [ |
- ['x'] |
- ]); |
- expect( |
- processorFor(undefined_function).severity, ErrorSeverity.WARNING); |
- // Should not be made fatal by `--fatal-warnings`. |
- expect(_bulletToDash(outSink), |
- contains("warning - The function 'baz' isn't defined")); |
- expect(outSink.toString(), contains("1 error and 1 warning found.")); |
- }); |
- }); |
- } |
+ test_strongSdk() async { |
+ String testDir = path.join(testDirectory, 'data', 'strong_sdk'); |
+ await drive(path.join(testDir, 'main.dart'), args: ['--strong']); |
+ expect(driver.context.analysisOptions.strongMode, isTrue); |
+ expect(outSink.toString(), contains('No issues found')); |
+ expect(exitCode, 0); |
+ } |
- createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE); |
- createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); |
+ test_todo() async { |
+ await drive('data/file_with_todo.dart'); |
+ expect(outSink.toString().contains('[info]'), isFalse); |
+ } |
- test('include directive', () async { |
- String testDir = path.join( |
- testDirectory, 'data', 'options_include_directive_tests_project'); |
- await drive( |
- path.join(testDir, 'lib', 'test_file.dart'), |
- args: [ |
- '--fatal-warnings', |
- '--packages', |
- path.join(testDir, '_packages'), |
- ], |
- options: path.join(testDir, 'analysis_options.yaml'), |
- ); |
- expect(exitCode, 3); |
- expect(outSink.toString(), |
- contains('but doesn\'t end with a return statement')); |
- expect(outSink.toString(), contains('isn\'t defined')); |
- expect(outSink.toString(), contains('Avoid empty else statements')); |
- }); |
+ test_withFlags_overrideFatalWarning() async { |
+ await drive('data/options_tests_project/test_file.dart', |
+ args: ['--fatal-warnings'], |
+ options: 'data/options_tests_project/$optionsFileName'); |
+ |
+ // missing_return: error |
+ var undefined_function = new AnalysisError( |
+ new TestSource(), 0, 1, StaticTypeWarningCode.UNDEFINED_FUNCTION, [ |
+ ['x'] |
+ ]); |
+ expect(processorFor(undefined_function).severity, ErrorSeverity.WARNING); |
+ // Should not be made fatal by `--fatal-warnings`. |
+ expect(_bulletToDash(outSink), |
+ contains("warning - The function 'baz' isn't defined")); |
+ expect(outSink.toString(), contains("1 error and 1 warning found.")); |
+ } |
- test('test strong SDK', () async { |
- String testDir = path.join(testDirectory, 'data', 'strong_sdk'); |
- await drive(path.join(testDir, 'main.dart'), args: ['--strong']); |
- expect(driver.context.analysisOptions.strongMode, isTrue); |
- expect(outSink.toString(), contains('No issues found')); |
- expect(exitCode, 0); |
- }); |
- }); |
+ Future<Null> _driveBasic() async { |
+ await drive('data/options_tests_project/test_file.dart', |
+ options: 'data/options_tests_project/$optionsFileName'); |
+ } |
} |
class TestSource implements Source { |
@@ -766,3 +598,60 @@ class TestSource implements Source { |
@override |
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
} |
+ |
+class _BaseTest { |
+ static const emptyOptionsFile = 'data/empty_options.yaml'; |
+ |
+ StringSink _savedOutSink, _savedErrorSink; |
+ int _savedExitCode; |
+ ExitHandler _savedExitHandler; |
+ |
+ Driver driver; |
+ |
+ /// Start a driver for the given [source], optionally providing additional |
+ /// [args] and an [options] file path. The value of [options] defaults to |
+ /// an empty options file to avoid unwanted configuration from an otherwise |
+ /// discovered options file. |
+ Future<Null> drive(String source, |
+ {String options: emptyOptionsFile, |
+ List<String> args: const <String>[]}) async { |
+ driver = new Driver(isTesting: true); |
+ var cmd = [ |
+ '--options', |
+ path.join(testDirectory, options), |
+ _adjustFileSpec(source) |
+ ]..addAll(args); |
+ await driver.start(cmd); |
+ } |
+ |
+ void setUp() { |
+ ansi.runningTests = true; |
+ _savedOutSink = outSink; |
+ _savedErrorSink = errorSink; |
+ _savedExitHandler = exitHandler; |
+ _savedExitCode = exitCode; |
+ exitHandler = (code) => exitCode = code; |
+ outSink = new StringBuffer(); |
+ errorSink = new StringBuffer(); |
+ } |
+ |
+ void tearDown() { |
+ outSink = _savedOutSink; |
+ errorSink = _savedErrorSink; |
+ exitCode = _savedExitCode; |
+ exitHandler = _savedExitHandler; |
+ ansi.runningTests = false; |
+ } |
+ |
+ /// Convert a file specification from a relative path to an absolute path. |
+ /// Handles the case where the file specification is of the form "$uri|$path". |
+ String _adjustFileSpec(String fileSpec) { |
+ int uriPrefixLength = fileSpec.indexOf('|') + 1; |
+ String uriPrefix = fileSpec.substring(0, uriPrefixLength); |
+ String relativePath = fileSpec.substring(uriPrefixLength); |
+ return '$uriPrefix${path.join(testDirectory, relativePath)}'; |
+ } |
+ |
+ /// Normalize text with bullets. |
+ String _bulletToDash(item) => '$item'.replaceAll('•', '-'); |
+} |