Improve dartdev testing

* Auto-dispose the TestProject (several instances were never disposed)
* Don't rely on package:test by default from the test-project.

Change-Id: I383eb36cbacb341b702f42075af562d20a2be45d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/291069
Reviewed-by: Jonas Jensen <jonasfj@google.com>
Commit-Queue: Sigurd Meldgaard <sigurdm@google.com>
This commit is contained in:
Sigurd Meldgaard 2023-03-27 14:52:23 +00:00 committed by Commit Queue
parent 782b5d65cc
commit d5da8dc67d
24 changed files with 122 additions and 178 deletions

View file

@ -21,8 +21,6 @@ void main() {
p = project();
});
tearDown(() async => await p.dispose());
test('can start', () async {
AnalysisServer server = AnalysisServer(
null,

View file

@ -141,9 +141,7 @@ void main() {
});
test('pub get dry run', () async {
final p = project(logAnalytics: true, pubspec: {
'name': 'foo',
'environment': {'sdk': '>=2.12.0 <3.0.0'},
final p = project(logAnalytics: true, pubspecExtras: {
'dependencies': {'lints': '2.0.1'}
});
final result = await p.run(['pub', 'get', '--dry-run']);
@ -176,9 +174,7 @@ void main() {
});
test('pub get', () async {
final p = project(logAnalytics: true, pubspec: {
'name': 'foo',
'environment': {'sdk': '>=2.12.0 <3.0.0'},
final p = project(logAnalytics: true, pubspecExtras: {
'dependencies': {'lints': '2.0.1'}
});
final result = await p.run(['pub', 'get']);

View file

@ -195,8 +195,6 @@ void defineAnalysisError() {
void defineAnalyze() {
late TestProject p;
tearDown(() async => await p.dispose());
test('--help', () async {
p = project();
var result = await p.runAnalyze(['--help']);
@ -220,8 +218,6 @@ void defineAnalyze() {
group('multiple items', () {
late TestProject secondProject;
tearDown(() async => await secondProject.dispose());
test('folder and file', () async {
p = project(mainSrc: "int get foo => 'str';\n");
secondProject = project(mainSrc: "int get foo => 'str';\n");

View file

@ -21,8 +21,6 @@ void main() {
r'The Resident Frontend Compiler instance at ([a-zA-Z0-9:/=_\-\.\[\]]+) was successfully shutdown.',
);
tearDown(() async => await p.dispose());
test('shutdown issued with no server running', () async {
p = project();
final serverInfoFile = path.join(p.dirPath, 'info');

View file

@ -20,19 +20,12 @@ void main() {
}
void defineCreateTests() {
TestProject? proj;
setUp(() => proj = null);
tearDown(() async => await proj?.dispose());
// Create tests for each template.
for (String templateId
in CreateCommand.legalTemplateIds(includeDeprecated: true)) {
test(templateId, () async {
const projectName = 'template_project';
proj = project();
final p = proj!;
final p = project();
final templateGenerator = getGenerator(templateId)!;
print('$templateId: creating template');

View file

@ -18,15 +18,9 @@ void main() {
}
void defineCreateTests() {
TestProject? p;
setUp(() => p = null);
tearDown(() async => await p?.dispose());
test('--help', () async {
p = project();
var result = await p!.run(['create', '--help']);
final p = project();
var result = await p.run(['create', '--help']);
expect(result.stdout, contains('Create a new Dart project.'));
expect(
@ -40,8 +34,8 @@ void defineCreateTests() {
});
test('--help --verbose', () async {
p = project();
var result = await p!.run(['create', '--help', '--verbose']);
final p = project();
var result = await p.run(['create', '--help', '--verbose']);
expect(result.stdout, contains('Create a new Dart project.'));
expect(
@ -74,9 +68,9 @@ void defineCreateTests() {
});
test('list templates', () async {
p = project();
final p = project();
ProcessResult result = await p!.run(['create', '--list-templates']);
ProcessResult result = await p.run(['create', '--list-templates']);
expect(result.exitCode, 0);
String output = result.stdout.toString();
@ -87,27 +81,27 @@ void defineCreateTests() {
});
test('no directory given', () async {
p = project();
final p = project();
ProcessResult result = await p!.run(['create']);
ProcessResult result = await p.run(['create']);
expect(result.exitCode, 1);
});
test('directory already exists', () async {
p = project();
final p = project();
ProcessResult result = await p!.run(
['create', '--template', CreateCommand.defaultTemplateId, p!.dir.path]);
ProcessResult result = await p.run(
['create', '--template', CreateCommand.defaultTemplateId, p.dir.path]);
expect(result.exitCode, 73);
});
test('project in current directory', () async {
final tempDir = Directory.systemTemp.createTempSync('create_test');
try {
p = project();
final p = project();
final projectDir = Directory.fromUri(tempDir.uri.resolve('foo/'))
..createSync();
final result = await p!.run(
final result = await p.run(
['create', '--force', '.'],
workingDir: projectDir.path,
);
@ -120,9 +114,9 @@ void defineCreateTests() {
});
test('project with normalized package name', () async {
p = project();
final p = project();
final result =
await p!.run(['create', '--no-pub', 'requires-normalization']);
await p.run(['create', '--no-pub', 'requires-normalization']);
expect(result.stderr, isEmpty);
expect(
result.stdout,
@ -132,8 +126,8 @@ void defineCreateTests() {
});
test('project with an invalid package name', () async {
p = project();
final result = await p!.run(['create', 'bad-package^name']);
final p = project();
final result = await p.run(['create', 'bad-package^name']);
expect(
result.stderr,
contains(
@ -145,10 +139,10 @@ void defineCreateTests() {
});
test('bad template id', () async {
p = project();
final p = project();
ProcessResult result = await p!
.run(['create', '--no-pub', '--template', 'foo-bar', p!.dir.path]);
ProcessResult result = await p
.run(['create', '--no-pub', '--template', 'foo-bar', p.dir.path]);
expect(result.exitCode, isNot(0));
});
@ -156,9 +150,9 @@ void defineCreateTests() {
for (String templateId
in CreateCommand.legalTemplateIds(includeDeprecated: true)) {
test(templateId, () async {
p = project();
final p = project();
const projectName = 'template_project';
ProcessResult result = await p!.run([
ProcessResult result = await p.run([
'create',
'--force',
'--no-pub',
@ -170,7 +164,7 @@ void defineCreateTests() {
String entry = templates.getGenerator(templateId)!.entrypoint!.path;
entry = entry.replaceAll('__projectName__', projectName);
File entryFile = File(path.join(p!.dir.path, projectName, entry));
File entryFile = File(path.join(p.dir.path, projectName, entry));
expect(entryFile.existsSync(), true,
reason: 'File not found: ${entryFile.path}');

View file

@ -16,8 +16,6 @@ void main() {
void devtools() {
late TestProject p;
tearDown(() async => await p.dispose());
test('--help', () async {
p = project();
var result = await p.run(['devtools', '--help']);

View file

@ -33,8 +33,6 @@ void defineFix() {
TestProject? p;
late ProcessResult result;
tearDown(() async => await p?.dispose());
void assertResult({int exitCode = 0}) {
String message;
if (result.exitCode != exitCode) {
@ -246,7 +244,6 @@ linter:
);
var result = await p!.runFix(['--apply', path.join('lib', 'main.dart')],
workingDir: p!.dirPath);
expect(result.exitCode, 0);
expect(result.stderr, isEmpty);
expect(
result.stdout,
@ -256,6 +253,7 @@ linter:
' prefer_single_quotes $bullet 1 fix',
'1 fix made in 1 file.',
]));
expect(result.exitCode, 0);
});
test('--apply --code=(single)', () async {

View file

@ -67,8 +67,6 @@ void command() {
void help() {
late TestProject p;
tearDown(() async => await p.dispose());
test('--help', () async {
p = project();
var result = await p.run(['--help']);
@ -148,8 +146,6 @@ void help() {
void invalidFlags() {
late TestProject p;
tearDown(() async => await p.dispose());
test('Regress #49437', () async {
// Regression test for https://github.com/dart-lang/sdk/issues/49437
p = project();

View file

@ -16,8 +16,6 @@ void main() {
void format() {
late TestProject p;
tearDown(() async => await p.dispose());
test('--help', () async {
p = project();
var result = await p.run(['format', '--help']);

View file

@ -15,8 +15,6 @@ void main() {
void help() {
late TestProject p;
tearDown(() async => await p.dispose());
/// Commands not tested by the following loop.
List<String> commandsNotTested = <String>[
'help', // `dart help help` is redundant

View file

@ -34,8 +34,6 @@ void main() {
group('info linux', () {
late TestProject p;
tearDown(() async => await p.dispose());
test('shows process info', () async {
p = project(mainSrc: 'void main() {}');
final runResult = await p.run(['info']);

View file

@ -41,8 +41,6 @@ void main() {
group('info macos', () {
late TestProject p;
tearDown(() async => await p.dispose());
test('shows process info', () async {
p = project(mainSrc: 'void main() {}');
final runResult = await p.run(['info']);

View file

@ -12,8 +12,6 @@ void main() {
group('info', () {
late TestProject p;
tearDown(() async => await p.dispose());
test('--help', () async {
p = project();
final result = await p.run(['info', '--help']);
@ -55,9 +53,7 @@ void main() {
test('getProjectInfo', () {
p = project(
mainSrc: 'void main() {}',
pubspec: {
'name': 'foo',
'environment': {'sdk': '>=2.10.0 <3.0.0'},
pubspecExtras: {
'dependencies': {'dummy_pkg': '0.0.1'},
},
);

View file

@ -42,8 +42,6 @@ void main() {
group('info windows', () {
late TestProject p;
tearDown(() async => await p.dispose());
test('shows process info', () async {
p = project(mainSrc: 'void main() {}');
final runResult = await p.run(['info']);

View file

@ -27,8 +27,6 @@ void defineLanguageServerTests() {
late utils.TestProject project;
Process? process;
tearDown(() async => await project.dispose());
Future runWithLsp(List<String> args) async {
project = utils.project();

View file

@ -13,10 +13,6 @@ void main() {
}
void pub() {
TestProject p = project();
tearDown(() async => await p.dispose());
void assertPubHelpInvoked(ProcessResult result) {
expect(result, isNotNull);
expect(result.exitCode, 0);
@ -43,7 +39,7 @@ void pub() {
});
test('help cache', () async {
p = project();
final p = project();
var result = await p.run(['help', 'pub', 'cache']);
var result2 = await p.run(['pub', 'cache', '--help']);
@ -57,7 +53,7 @@ void pub() {
});
test('help publish', () async {
p = project();
final p = project();
var result = await p.run(['help', 'pub', 'publish']);
var result2 = await p.run(['pub', 'publish', '--help']);
@ -71,7 +67,7 @@ void pub() {
});
test('solve failure', () async {
p = project(pubspec: {
final p = project(pubspecExtras: {
'name': 'myapp',
'environment': {'sdk': '^2.19.0'},
'dependencies': {
@ -91,7 +87,7 @@ void pub() {
});
test('failure unknown option', () async {
p = project(mainSrc: 'int get foo => 1;\n');
final p = project(mainSrc: 'int get foo => 1;\n');
var result = await p.run(['pub', 'deps', '--foo']);
expect(result.exitCode, 64);
expect(result.stdout, isEmpty);

View file

@ -34,8 +34,6 @@ void main() async {
void run() {
late TestProject p;
tearDown(() async => await p.dispose());
test('--help', () async {
p = project();
var result = await p.run(['run', '--help']);
@ -178,7 +176,7 @@ void run() {
test('from path-dependency with cyclic dependency', () async {
p = project(name: 'foo');
final bar = TestProject(name: 'bar');
final bar = project(name: 'bar');
p.file('pubspec.yaml', '''
name: foo
environment:
@ -191,22 +189,18 @@ import 'package:bar/bar.dart';
final b = "FOO $bar";
''');
try {
bar.file('lib/bar.dart', 'final bar = "BAR";');
bar.file('lib/bar.dart', 'final bar = "BAR";');
bar.file('bin/main.dart', r'''
bar.file('bin/main.dart', r'''
import 'package:foo/foo.dart';
void main(List<String> args) => print("$b $args");
''');
ProcessResult result = await p.run(['run', 'bar:main', '--arg1', 'arg2']);
ProcessResult result = await p.run(['run', 'bar:main', '--arg1', 'arg2']);
expect(result.stderr, isEmpty);
expect(result.stdout, contains('FOO BAR [--arg1, arg2]'));
expect(result.exitCode, 0);
} finally {
await bar.dispose();
}
expect(result.stderr, isEmpty);
expect(result.stdout, contains('FOO BAR [--arg1, arg2]'));
expect(result.exitCode, 0);
});
test('with absolute file path', () async {
@ -341,10 +335,7 @@ void main(List<String> args) => print("$b $args");
expect(result.stderr, isEmpty);
expect(result.stdout, isEmpty);
expect(result.exitCode, 0);
expect(
p
.findFile(path.join(p.dirPath, 'dart-timeline.json'))!
.readAsStringSync(),
expect(p.findFile('dart-timeline.json')!.readAsStringSync(),
contains('"name":"sync","cat":"Dart"'));
});
@ -753,12 +744,8 @@ void residentRun() {
File(path.join(serverInfoDirectory.dirPath, 'info')),
);
} catch (_) {}
serverInfoDirectory.dispose();
});
tearDown(() async => await p.dispose());
test("'Hello World'", () async {
p = project(mainSrc: "void main() { print('Hello World'); }");
final result = await p.run([
@ -784,7 +771,7 @@ void residentRun() {
p = project(
mainSrc: r"void main() { print(('hello','world').$1); }",
sdkConstraint: VersionConstraint.parse(
'>=2.19.0 <3.0.0',
'^3.0.0',
),
);
final result = await p.run([
@ -811,7 +798,6 @@ void residentRun() {
test('same server used from different directories', () async {
p = project(mainSrc: "void main() { print('1'); }");
TestProject p2 = project(mainSrc: "void main() { print('2'); }");
addTearDown(() async => p2.dispose());
final runResult1 = await p.run([
'run',
@ -1031,13 +1017,11 @@ void residentRun() {
test('custom package_config path', () async {
p = project(name: 'foo');
final bar = TestProject(name: 'bar');
final baz = TestProject(name: 'baz', mainSrc: '''
final bar = project(name: 'bar');
final baz = project(name: 'baz', mainSrc: '''
import 'package:bar/bar.dart'
void main() {}
''');
addTearDown(() async => bar.dispose());
addTearDown(() async => baz.dispose());
p.file('custom_packages.json', '''
{

View file

@ -19,12 +19,10 @@ void main() {
}
void defineTest(List<Experiment> experiments) {
late TestProject p;
tearDown(() async => await p.dispose());
test('--help', () async {
p = project();
final p = project(pubspecExtras: {
'dev_dependencies': {'test': 'any'}
});
final result = await p.run(['test', '--help']);
@ -38,7 +36,9 @@ Usage: dart test [files or directories...]
});
test('dart help test', () async {
p = project();
final p = project(pubspecExtras: {
'dev_dependencies': {'test': 'any'}
});
final result = await p.run(['help', 'test']);
@ -48,7 +48,9 @@ Usage: dart test [files or directories...]
});
test('no pubspec.yaml', () async {
p = project();
final p = project(pubspecExtras: {
'dev_dependencies': {'test': 'any'}
});
var pubspec = File(path.join(p.dirPath, 'pubspec.yaml'));
pubspec.deleteSync();
@ -69,7 +71,9 @@ No pubspec.yaml file found - run this command in your project folder.
});
test('runs test', () async {
p = project();
final p = project(pubspecExtras: {
'dev_dependencies': {'test': 'any'}
});
p.file('test/foo_test.dart', '''
import 'package:test/test.dart';
@ -89,7 +93,12 @@ void main() {
});
test('no package:test dependency', () async {
p = project(mainSrc: 'int get foo => 1;\n');
final p = project(
mainSrc: 'int get foo => 1;\n',
pubspecExtras: {
'dev_dependencies': {'test': 'any'}
},
);
p.file('pubspec.yaml', '''
name: ${p.name}
environment:
@ -125,7 +134,12 @@ void main() {
});
test('has package:test dependency', () async {
p = project(mainSrc: 'int get foo => 1;\n');
final p = project(
mainSrc: 'int get foo => 1;\n',
pubspecExtras: {
'dev_dependencies': {'test': 'any'}
},
);
p.file('test/foo_test.dart', '''
import 'package:test/test.dart';
@ -144,6 +158,7 @@ void main() {
});
group('--enable-experiment', () {
late TestProject p;
Future<ProcessResult> runTestWithExperimentFlag(String? flag) async {
return await p.run([
if (flag != null) flag,
@ -171,8 +186,12 @@ void main() {
test(experiment.name, () async {
final currentSdk = Version.parse(Platform.version.split(' ').first);
p = project(
mainSrc: experiment.validation,
sdkConstraint: VersionConstraint.compatibleWith(currentSdk));
mainSrc: experiment.validation,
sdkConstraint: VersionConstraint.compatibleWith(currentSdk),
pubspecExtras: {
'dev_dependencies': {'test': 'any'}
},
);
p.file('test/experiment_test.dart', '''
import 'package:dartdev_temp/main.dart' as imported;
import 'package:test/test.dart';

View file

@ -110,18 +110,14 @@ void _packageConfig() {
}
void _project() {
late TestProject p;
tearDown(() async => await p.dispose());
test('hasPubspecFile positive', () {
p = project();
final p = project();
Project coreProj = Project.fromDirectory(p.dir);
expect(coreProj.hasPubspecFile, isTrue);
});
test('hasPubspecFile negative', () {
p = project();
final p = project();
var pubspec = File(path.join(p.dirPath, 'pubspec.yaml'));
pubspec.deleteSync();
@ -130,7 +126,7 @@ void _project() {
});
test('hasPackageConfigFile positive', () {
p = project();
final p = project();
p.file('.dart_tool/package_config.json', _packageData);
Project coreProj = Project.fromDirectory(p.dir);
expect(coreProj.hasPackageConfigFile, isTrue);
@ -139,7 +135,7 @@ void _project() {
});
test('hasPackageConfigFile negative', () {
p = project();
final p = project();
Project coreProj = Project.fromDirectory(p.dir);
expect(coreProj.hasPackageConfigFile, isFalse);
});

View file

@ -18,11 +18,8 @@ Future<FixOutput> runFix(List<String> args) async {
}
void _driver() {
late TestProject p;
tearDown(() async => await p.dispose());
test('no fixes', () async {
p = project(mainSrc: 'int get foo => 1;\n');
final p = project(mainSrc: 'int get foo => 1;\n');
var result = await runFix(['--apply', p.dirPath]);
expect(result.stdout, contains('Nothing to fix!'));
expect(result.returnCode, 0);

View file

@ -12,7 +12,6 @@ void main() {
late TestProject p;
setUp(() => p = project(mainSrc: "void main() { print('Hello World'); }"));
tearDown(() async => await p.dispose());
test("Fallback to dartdev.dill from dartdev.dart.snapshot for 'Hello World'",
() async {

View file

@ -10,7 +10,6 @@ void main() {
late TestProject p;
setUp(() async => p = project());
tearDown(() async => await p.dispose());
test('Ensure parsing fails after encountering invalid file', () async {
// Regression test for https://github.com/dart-lang/sdk/issues/43991

View file

@ -27,28 +27,36 @@ void initGlobalState() {
log = Logger.standard();
}
/// Creates a test-project in a temp-dir that will [dispose] itself at the end
/// of the test.
TestProject project(
{String? mainSrc,
String? analysisOptions,
bool logAnalytics = false,
String name = TestProject._defaultProjectName,
VersionConstraint? sdkConstraint,
Map<String, dynamic>? pubspec}) =>
TestProject(
mainSrc: mainSrc,
analysisOptions: analysisOptions,
logAnalytics: logAnalytics,
sdkConstraint: sdkConstraint,
pubspec: pubspec);
{String? mainSrc,
String? analysisOptions,
bool logAnalytics = false,
String name = TestProject._defaultProjectName,
VersionConstraint? sdkConstraint,
Map<String, dynamic>? pubspecExtras}) {
var testProject = TestProject(
mainSrc: mainSrc,
name: name,
analysisOptions: analysisOptions,
logAnalytics: logAnalytics,
sdkConstraint: sdkConstraint,
pubspecExtras: pubspecExtras);
addTearDown(() => testProject.dispose());
return testProject;
}
class TestProject {
static const String _defaultProjectName = 'dartdev_temp';
late Directory dir;
late Directory root;
String get dirPath => dir.path;
Directory get dir => Directory(dirPath);
String get pubCachePath => path.join(dirPath, 'pub_cache');
String get dirPath => path.join(root.path, 'myapp');
String get pubCachePath => path.join(root.path, 'pub_cache');
String get pubCacheBinPath => path.join(pubCachePath, 'bin');
@ -60,33 +68,28 @@ class TestProject {
final bool logAnalytics;
final VersionConstraint? sdkConstraint;
final Map<String, dynamic>? pubspec;
Process? _process;
TestProject(
{String? mainSrc,
String? analysisOptions,
this.name = _defaultProjectName,
this.logAnalytics = false,
this.sdkConstraint,
this.pubspec}) {
TestProject({
String? mainSrc,
String? analysisOptions,
this.name = _defaultProjectName,
this.logAnalytics = false,
VersionConstraint? sdkConstraint,
Map<String, dynamic>? pubspecExtras,
}) {
initGlobalState();
dir = Directory.systemTemp.createTempSync('a');
root = Directory.systemTemp.createTempSync('dartdev');
file(
'pubspec.yaml',
pubspec == null
? '''
name: $name
environment:
sdk: '${sdkConstraint ?? '>=2.19.0 <4.0.0'}'
dev_dependencies:
test: any
'''
: json.encode(pubspec));
'pubspec.yaml',
JsonEncoder.withIndent(' ').convert(
{
'name': name,
'environment': {'sdk': sdkConstraint?.toString() ?? '^2.19.0'},
...?pubspecExtras,
},
),
);
if (analysisOptions != null) {
file('analysis_options.yaml', analysisOptions);
}
@ -97,7 +100,7 @@ dev_dependencies:
void file(String name, String contents) {
var file = File(path.join(dir.path, name));
file.parent.createSync();
file.parent.createSync(recursive: true);
file.writeAsStringSync(contents);
}
@ -111,7 +114,7 @@ dev_dependencies:
_process?.kill();
await _process?.exitCode;
_process = null;
await deleteDirectory(dir);
await deleteDirectory(root);
}
Future<ProcessResult> runAnalyze(