blob: 4b6a05becbb1c25f1184f2b60b28e44be2fd2464 [file] [log] [blame]
// Copyright 2013 The Flutter 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:io' as io;
import 'package:async_helper/async_helper.dart';
import 'package:engine_repo_tools/engine_repo_tools.dart';
import 'package:litetest/litetest.dart';
import 'package:path/path.dart' as p;
void main() {
late io.Directory emptyDir;
void setUp() {
emptyDir = io.Directory.systemTemp.createTempSync('engine_repo_tools.test');
}
void tearDown() {
emptyDir.deleteSync(recursive: true);
}
group('Engine.fromSrcPath', () {
group('should fail when', () {
test('the path does not end in `${p.separator}src`', () {
setUp();
try {
expect(
() => Engine.fromSrcPath(emptyDir.path),
_throwsInvalidEngineException,
);
} finally {
tearDown();
}
});
test('the path does not exist', () {
setUp();
try {
expect(
() => Engine.fromSrcPath(p.join(emptyDir.path, 'src')),
_throwsInvalidEngineException,
);
} finally {
tearDown();
}
});
test('the path does not contain a "flutter" directory', () {
setUp();
try {
final io.Directory srcDir = io.Directory(p.join(emptyDir.path, 'src'))..createSync();
expect(
() => Engine.fromSrcPath(srcDir.path),
_throwsInvalidEngineException,
);
} finally {
tearDown();
}
});
test('returns an Engine', () {
setUp();
try {
final io.Directory srcDir = io.Directory(p.join(emptyDir.path, 'src'))..createSync();
io.Directory(p.join(srcDir.path, 'flutter')).createSync();
io.Directory(p.join(srcDir.path, 'out')).createSync();
final Engine engine = Engine.fromSrcPath(srcDir.path);
expect(engine.srcDir.path, srcDir.path);
expect(engine.flutterDir.path, p.join(srcDir.path, 'flutter'));
expect(engine.outDir.path, p.join(srcDir.path, 'out'));
} finally {
tearDown();
}
});
});
});
group('Engine.findWithin', () {
late io.Directory emptyDir;
void setUp() {
emptyDir = io.Directory.systemTemp.createTempSync('engine_repo_tools.test');
}
void tearDown() {
emptyDir.deleteSync(recursive: true);
}
group('should fail when', () {
test('the path does not contain a "src" directory', () {
setUp();
try {
expect(
() => Engine.findWithin(emptyDir.path),
throwsStateError,
);
} finally {
tearDown();
}
});
test('the path contains a "src" directory but it is not an engine root', () {
setUp();
try {
final io.Directory srcDir = io.Directory(p.join(emptyDir.path, 'src'))..createSync();
expect(
() => Engine.findWithin(srcDir.path),
throwsStateError,
);
} finally {
tearDown();
}
});
test('returns an Engine', () {
setUp();
try {
final io.Directory srcDir = io.Directory(p.join(emptyDir.path, 'src'))..createSync();
io.Directory(p.join(srcDir.path, 'flutter')).createSync();
io.Directory(p.join(srcDir.path, 'out')).createSync();
final Engine engine = Engine.findWithin(srcDir.path);
expect(engine.srcDir.path, srcDir.path);
expect(engine.flutterDir.path, p.join(srcDir.path, 'flutter'));
expect(engine.outDir.path, p.join(srcDir.path, 'out'));
} finally {
tearDown();
}
});
test('returns an Engine even if a "src" directory exists deeper in the tree', () {
// It's common to have "src" directories, so if we have something like:
// /Users/.../engine/src/foo/bar/src/baz
//
// And we use `Engine.findWithin('/Users/.../engine/src/flutter/bar/src/baz')`,
// we should still find the engine (in this case, the engine root is
// `/Users/.../engine/src`).
setUp();
try {
final io.Directory srcDir = io.Directory(p.join(emptyDir.path, 'src'))..createSync();
io.Directory(p.join(srcDir.path, 'flutter')).createSync();
io.Directory(p.join(srcDir.path, 'out')).createSync();
final io.Directory nestedSrcDir = io.Directory(p.join(srcDir.path, 'flutter', 'bar', 'src', 'baz'))..createSync(recursive: true);
final Engine engine = Engine.findWithin(nestedSrcDir.path);
expect(engine.srcDir.path, srcDir.path);
expect(engine.flutterDir.path, p.join(srcDir.path, 'flutter'));
expect(engine.outDir.path, p.join(srcDir.path, 'out'));
} finally {
tearDown();
}
});
});
});
test('outputs an empty list of targets', () {
setUp();
try {
// Create a valid engine.
io.Directory(p.join(emptyDir.path, 'src', 'flutter')).createSync(recursive: true);
io.Directory(p.join(emptyDir.path, 'src', 'out')).createSync(recursive: true);
final Engine engine = Engine.fromSrcPath(p.join(emptyDir.path, 'src'));
expect(engine.outputs(), <Output>[]);
expect(engine.latestOutput(), isNull);
} finally {
tearDown();
}
});
test('outputs a list of targets', () {
setUp();
try {
// Create a valid engine.
io.Directory(p.join(emptyDir.path, 'src', 'flutter')).createSync(recursive: true);
io.Directory(p.join(emptyDir.path, 'src', 'out')).createSync(recursive: true);
// Create two targets in out: host_debug and host_debug_unopt_arm64.
io.Directory(p.join(emptyDir.path, 'src', 'out', 'host_debug')).createSync(recursive: true);
io.Directory(p.join(emptyDir.path, 'src', 'out', 'host_debug_unopt_arm64')).createSync(recursive: true);
final Engine engine = Engine.fromSrcPath(p.join(emptyDir.path, 'src'));
final List<String> outputs = engine.outputs().map((Output o) => p.basename(o.path.path)).toList()..sort();
expect(outputs, <String>[
'host_debug',
'host_debug_unopt_arm64',
]);
} finally {
tearDown();
}
});
test('outputs the latest target and compile_commands.json', () {
setUp();
try {
// Create a valid engine.
final io.Directory srcDir = io.Directory(p.join(emptyDir.path, 'src'))
..createSync(recursive: true);
final io.Directory flutterDir = io.Directory(p.join(srcDir.path, 'flutter'))
..createSync(recursive: true);
final io.Directory outDir = io.Directory(p.join(srcDir.path, 'out'))
..createSync(recursive: true);
// Create two targets in out: host_debug and host_debug_unopt_arm64.
final io.Directory hostDebug = io.Directory(p.join(outDir.path, 'host_debug'))
..createSync(recursive: true);
final io.Directory hostDebugUnoptArm64 = io.Directory(
p.join(outDir.path, 'host_debug_unopt_arm64'),
)..createSync(recursive: true);
final Engine engine = TestEngine.withPaths(
srcDir: srcDir,
flutterDir: flutterDir,
outDir: outDir,
outputs: <TestOutput>[
TestOutput(
hostDebug,
lastModified: DateTime.utc(2023, 9, 23, 21, 16),
),
TestOutput(
hostDebugUnoptArm64,
lastModified: DateTime.utc(2023, 9, 23, 22, 16),
),
],
);
final Output? latestOutput = engine.latestOutput();
expect(latestOutput, isNotNull);
expect(p.basename(latestOutput!.path.path), 'host_debug_unopt_arm64');
expect(latestOutput.compileCommandsJson, isNotNull);
} finally {
tearDown();
}
});
}
// This is needed because async_minitest and friends is not a proper testing
// library and is missing a lot of functionality that was exclusively added
// to pkg/test.
void _throwsInvalidEngineException(Object? o) {
_checkThrow<InvalidEngineException>(o, (_){});
}
// Mostly copied from async_minitest.
void _checkThrow<T extends Object>(dynamic v, void Function(dynamic error) onError) {
if (v is Future) {
asyncStart();
v.then((_) {
Expect.fail('Did not throw');
}, onError: (Object e, StackTrace s) {
if (e is! T) {
// ignore: only_throw_errors
throw e;
}
onError(e);
asyncEnd();
});
return;
}
v as void Function();
Expect.throws<T>(v, (T e) {
onError(e);
return true;
});
}