Unverified Commit adb2aeeb authored by Todd Volkert's avatar Todd Volkert Committed by GitHub

Ensure that cache dirs and files have appropriate permissions (#28090)

This is a partial re-application of #24669, which was
reverted due to Fuchsia breakages.

https://github.com/flutter/flutter/issues/24413
parent dd51afd1
...@@ -27,7 +27,15 @@ abstract class OperatingSystemUtils { ...@@ -27,7 +27,15 @@ abstract class OperatingSystemUtils {
OperatingSystemUtils._private(); OperatingSystemUtils._private();
/// Make the given file executable. This may be a no-op on some platforms. /// Make the given file executable. This may be a no-op on some platforms.
ProcessResult makeExecutable(File file); void makeExecutable(File file);
/// Updates the specified file system [entity] to have the file mode
/// bits set to the value defined by [mode], which can be specified in octal
/// (e.g. `644`) or symbolically (e.g. `u+x`).
///
/// On operating systems that do not support file mode bits, this will be a
/// no-op.
void chmod(FileSystemEntity entity, String mode);
/// Return the path (with symlinks resolved) to the given executable, or null /// Return the path (with symlinks resolved) to the given executable, or null
/// if `which` was not able to locate the binary. /// if `which` was not able to locate the binary.
...@@ -111,8 +119,24 @@ class _PosixUtils extends OperatingSystemUtils { ...@@ -111,8 +119,24 @@ class _PosixUtils extends OperatingSystemUtils {
_PosixUtils() : super._private(); _PosixUtils() : super._private();
@override @override
ProcessResult makeExecutable(File file) { void makeExecutable(File file) {
return processManager.runSync(<String>['chmod', 'a+x', file.path]); chmod(file, 'a+x');
}
@override
void chmod(FileSystemEntity entity, String mode) {
try {
final ProcessResult result = processManager.runSync(<String>['chmod', mode, entity.path]);
if (result.exitCode != 0) {
printTrace(
'Error trying to run chmod on ${entity.absolute.path}'
'\nstdout: ${result.stdout}'
'\nstderr: ${result.stderr}',
);
}
} on ProcessException catch (error) {
printTrace('Error trying to run chmod on ${entity.absolute.path}: $error');
}
} }
@override @override
...@@ -185,11 +209,11 @@ class _PosixUtils extends OperatingSystemUtils { ...@@ -185,11 +209,11 @@ class _PosixUtils extends OperatingSystemUtils {
class _WindowsUtils extends OperatingSystemUtils { class _WindowsUtils extends OperatingSystemUtils {
_WindowsUtils() : super._private(); _WindowsUtils() : super._private();
// This is a no-op.
@override @override
ProcessResult makeExecutable(File file) { void makeExecutable(File file) {}
return ProcessResult(0, 0, null, null);
} @override
void chmod(FileSystemEntity entity, String mode) {}
@override @override
List<File> _which(String execName, { bool all = false }) { List<File> _which(String execName, { bool all = false }) {
......
...@@ -207,8 +207,10 @@ class Cache { ...@@ -207,8 +207,10 @@ class Cache {
/// Return a directory in the cache dir. For `pkg`, this will return `bin/cache/pkg`. /// Return a directory in the cache dir. For `pkg`, this will return `bin/cache/pkg`.
Directory getCacheDir(String name) { Directory getCacheDir(String name) {
final Directory dir = fs.directory(fs.path.join(getRoot().path, name)); final Directory dir = fs.directory(fs.path.join(getRoot().path, name));
if (!dir.existsSync()) if (!dir.existsSync()) {
dir.createSync(recursive: true); dir.createSync(recursive: true);
os.chmod(dir, '755');
}
return dir; return dir;
} }
...@@ -280,8 +282,10 @@ class Cache { ...@@ -280,8 +282,10 @@ class Cache {
final Directory thirdPartyDir = getArtifactDirectory('third_party'); final Directory thirdPartyDir = getArtifactDirectory('third_party');
final Directory serviceDir = fs.directory(fs.path.join(thirdPartyDir.path, serviceName)); final Directory serviceDir = fs.directory(fs.path.join(thirdPartyDir.path, serviceName));
if (!serviceDir.existsSync()) if (!serviceDir.existsSync()) {
serviceDir.createSync(recursive: true); serviceDir.createSync(recursive: true);
os.chmod(serviceDir, '755');
}
final File cachedFile = fs.file(fs.path.join(serviceDir.path, url.pathSegments.last)); final File cachedFile = fs.file(fs.path.join(serviceDir.path, url.pathSegments.last));
if (!cachedFile.existsSync()) { if (!cachedFile.existsSync()) {
...@@ -633,13 +637,16 @@ abstract class EngineCachedArtifact extends CachedArtifact { ...@@ -633,13 +637,16 @@ abstract class EngineCachedArtifact extends CachedArtifact {
return true; return true;
} }
void _makeFilesExecutable(Directory dir) { void _makeFilesExecutable(Directory dir) {
for (FileSystemEntity entity in dir.listSync()) { os.chmod(dir, 'a+r,a+x');
for (FileSystemEntity entity in dir.listSync(recursive: true)) {
if (entity is File) { if (entity is File) {
final String name = fs.path.basename(entity.path); final FileStat stat = entity.statSync();
if (name == 'flutter_tester') final bool isUserExecutable = ((stat.mode >> 6) & 0x1) == 1;
os.makeExecutable(entity); if (entity.basename == 'flutter_tester' || isUserExecutable) {
// Make the file readable and executable by all users.
os.chmod(entity, 'a+r,a+x');
}
} }
} }
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
...@@ -12,102 +13,106 @@ import '../src/common.dart'; ...@@ -12,102 +13,106 @@ import '../src/common.dart';
import '../src/context.dart'; import '../src/context.dart';
void main() { void main() {
group('CachedArtifacts', () { group('Artifacts', () {
MemoryFileSystem memoryFileSystem;
Directory tempDir; Directory tempDir;
CachedArtifacts artifacts;
setUp(() { setUp(() {
tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_artifacts_test_cached.'); memoryFileSystem = MemoryFileSystem();
artifacts = CachedArtifacts(); tempDir = memoryFileSystem.systemTempDirectory.createTempSync('artifacts_test.');
}); });
tearDown(() { tearDown(() {
tryToDelete(tempDir); tryToDelete(tempDir);
}); });
testUsingContext('getArtifactPath', () { group('CachedArtifacts', () {
expect( CachedArtifacts artifacts;
setUp(() {
artifacts = CachedArtifacts();
});
testUsingContext('getArtifactPath', () {
expect(
artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release), artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release),
fs.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'engine', 'ios-release', 'Flutter.framework'), fs.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'engine', 'ios-release', 'Flutter.framework'),
); );
expect( expect(
artifacts.getArtifactPath(Artifact.flutterTester), artifacts.getArtifactPath(Artifact.flutterTester),
fs.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'engine', 'linux-x64', 'flutter_tester'), fs.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'engine', 'linux-x64', 'flutter_tester'),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir), Cache: () => Cache(rootOverride: tempDir),
Platform: () => FakePlatform(operatingSystem: 'linux'), FileSystem: () => memoryFileSystem,
}); Platform: () => FakePlatform(operatingSystem: 'linux'),
});
testUsingContext('getEngineType', () { testUsingContext('getEngineType', () {
expect( expect(
artifacts.getEngineType(TargetPlatform.android_arm, BuildMode.debug), artifacts.getEngineType(TargetPlatform.android_arm, BuildMode.debug),
'android-arm', 'android-arm',
); );
expect( expect(
artifacts.getEngineType(TargetPlatform.ios, BuildMode.release), artifacts.getEngineType(TargetPlatform.ios, BuildMode.release),
'ios-release', 'ios-release',
); );
expect( expect(
artifacts.getEngineType(TargetPlatform.darwin_x64), artifacts.getEngineType(TargetPlatform.darwin_x64),
'darwin-x64', 'darwin-x64',
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir), Cache: () => Cache(rootOverride: tempDir),
Platform: () => FakePlatform(operatingSystem: 'linux'), FileSystem: () => memoryFileSystem,
Platform: () => FakePlatform(operatingSystem: 'linux'),
});
}); });
});
group('LocalEngineArtifacts', () {
Directory tempDir;
LocalEngineArtifacts artifacts;
setUp(() { group('LocalEngineArtifacts', () {
tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_artifacts_test_local.'); LocalEngineArtifacts artifacts;
artifacts = LocalEngineArtifacts(tempDir.path,
fs.path.join(tempDir.path, 'out', 'android_debug_unopt'),
fs.path.join(tempDir.path, 'out', 'host_debug_unopt'),
);
});
tearDown(() { setUp(() {
tryToDelete(tempDir); artifacts = LocalEngineArtifacts(tempDir.path,
}); memoryFileSystem.path.join(tempDir.path, 'out', 'android_debug_unopt'),
memoryFileSystem.path.join(tempDir.path, 'out', 'host_debug_unopt'),
);
});
testUsingContext('getArtifactPath', () { testUsingContext('getArtifactPath', () {
expect( expect(
artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release), artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release),
fs.path.join(tempDir.path, 'out', 'android_debug_unopt', 'Flutter.framework'), fs.path.join(tempDir.path, 'out', 'android_debug_unopt', 'Flutter.framework'),
); );
expect( expect(
artifacts.getArtifactPath(Artifact.flutterTester), artifacts.getArtifactPath(Artifact.flutterTester),
fs.path.join(tempDir.path, 'out', 'android_debug_unopt', 'flutter_tester'), fs.path.join(tempDir.path, 'out', 'android_debug_unopt', 'flutter_tester'),
); );
expect( expect(
artifacts.getArtifactPath(Artifact.engineDartSdkPath), artifacts.getArtifactPath(Artifact.engineDartSdkPath),
fs.path.join(tempDir.path, 'out', 'host_debug_unopt', 'dart-sdk'), fs.path.join(tempDir.path, 'out', 'host_debug_unopt', 'dart-sdk'),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => FakePlatform(operatingSystem: 'linux'), FileSystem: () => memoryFileSystem,
}); Platform: () => FakePlatform(operatingSystem: 'linux'),
});
testUsingContext('getEngineType', () { testUsingContext('getEngineType', () {
expect( expect(
artifacts.getEngineType(TargetPlatform.android_arm, BuildMode.debug), artifacts.getEngineType(TargetPlatform.android_arm, BuildMode.debug),
'android_debug_unopt', 'android_debug_unopt',
); );
expect( expect(
artifacts.getEngineType(TargetPlatform.ios, BuildMode.release), artifacts.getEngineType(TargetPlatform.ios, BuildMode.release),
'android_debug_unopt', 'android_debug_unopt',
); );
expect( expect(
artifacts.getEngineType(TargetPlatform.darwin_x64), artifacts.getEngineType(TargetPlatform.darwin_x64),
'android_debug_unopt', 'android_debug_unopt',
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => FakePlatform(operatingSystem: 'linux'), FileSystem: () => memoryFileSystem,
Platform: () => FakePlatform(operatingSystem: 'linux'),
});
}); });
}); });
} }
...@@ -6,14 +6,20 @@ import 'dart:async'; ...@@ -6,14 +6,20 @@ import 'dart:async';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart' show InternetAddress, SocketException; import 'package:flutter_tools/src/base/io.dart' show InternetAddress, SocketException;
import 'package:flutter_tools/src/base/net.dart';
import 'package:flutter_tools/src/base/os.dart';
import '../src/common.dart'; import '../src/common.dart';
import '../src/context.dart'; import '../src/context.dart';
import '../src/testbed.dart';
void main() { void main() {
group('$Cache.checkLockAcquired', () { group('$Cache.checkLockAcquired', () {
...@@ -51,8 +57,13 @@ void main() { ...@@ -51,8 +57,13 @@ void main() {
}); });
group('Cache', () { group('Cache', () {
final MockCache mockCache = MockCache(); MockCache mockCache;
final MemoryFileSystem fs = MemoryFileSystem(); MemoryFileSystem memoryFileSystem;
setUp(() {
mockCache = MockCache();
memoryFileSystem = MemoryFileSystem();
});
testUsingContext('Gradle wrapper should not be up to date, if some cached artifact is not available', () { testUsingContext('Gradle wrapper should not be up to date, if some cached artifact is not available', () {
final GradleWrapper gradleWrapper = GradleWrapper(mockCache); final GradleWrapper gradleWrapper = GradleWrapper(mockCache);
...@@ -63,7 +74,7 @@ void main() { ...@@ -63,7 +74,7 @@ void main() {
expect(gradleWrapper.isUpToDateInner(), false); expect(gradleWrapper.isUpToDateInner(), false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Cache: ()=> mockCache, Cache: ()=> mockCache,
FileSystem: () => fs, FileSystem: () => memoryFileSystem,
}); });
testUsingContext('Gradle wrapper should be up to date, only if all cached artifact are available', () { testUsingContext('Gradle wrapper should be up to date, only if all cached artifact are available', () {
...@@ -78,7 +89,7 @@ void main() { ...@@ -78,7 +89,7 @@ void main() {
expect(gradleWrapper.isUpToDateInner(), true); expect(gradleWrapper.isUpToDateInner(), true);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Cache: ()=> mockCache, Cache: ()=> mockCache,
FileSystem: () => fs, FileSystem: () => memoryFileSystem,
}); });
test('should not be up to date, if some cached artifact is not', () { test('should not be up to date, if some cached artifact is not', () {
...@@ -157,6 +168,74 @@ void main() { ...@@ -157,6 +168,74 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MockFileSystem(), FileSystem: () => MockFileSystem(),
}); });
group('EngineCachedArtifact', () {
FakeHttpClient fakeHttpClient;
FakePlatform fakePlatform;
MemoryFileSystem memoryFileSystem;
MockCache mockCache;
MockOperatingSystemUtils mockOperatingSystemUtils;
setUp(() {
fakeHttpClient = FakeHttpClient();
fakePlatform = FakePlatform()..environment = const <String, String>{};
memoryFileSystem = MemoryFileSystem();
mockCache = MockCache();
mockOperatingSystemUtils = MockOperatingSystemUtils();
when(mockOperatingSystemUtils.verifyZip(any)).thenReturn(true);
});
testUsingContext('makes binary dirs readable and executable by all', () async {
final Directory artifactDir = fs.systemTempDirectory.createTempSync('artifact.');
final Directory downloadDir = fs.systemTempDirectory.createTempSync('download.');
when(mockCache.getArtifactDirectory(any)).thenReturn(artifactDir);
when(mockCache.getDownloadDir()).thenReturn(downloadDir);
final FakeCachedArtifact artifact = FakeCachedArtifact(
cache: mockCache,
binaryDirs: <List<String>>[
<String>['bin_dir', 'unused_url_path'],
],
);
await artifact.updateInner();
final Directory dir = memoryFileSystem.systemTempDirectory
.listSync(recursive: true)
.whereType<Directory>()
.singleWhere((Directory directory) => directory.basename == 'bin_dir', orElse: () => null);
expect(dir, isNotNull);
expect(dir.path, artifactDir.childDirectory('bin_dir').path);
verify(mockOperatingSystemUtils.chmod(argThat(hasPath(dir.path)), 'a+r,a+x'));
}, overrides: <Type, Generator>{
Cache: ()=> mockCache,
FileSystem: () => memoryFileSystem,
HttpClientFactory: () => () => fakeHttpClient,
OperatingSystemUtils: () => mockOperatingSystemUtils,
Platform: () => fakePlatform,
});
});
}
class FakeCachedArtifact extends EngineCachedArtifact {
FakeCachedArtifact({
String stampName = 'STAMP',
@required Cache cache,
Set<DevelopmentArtifact> requiredArtifacts = const <DevelopmentArtifact>{},
this.binaryDirs = const <List<String>>[],
this.licenseDirs = const <String>[],
this.packageDirs = const <String>[],
}) : super(stampName, cache, requiredArtifacts);
final List<List<String>> binaryDirs;
final List<String> licenseDirs;
final List<String> packageDirs;
@override
List<List<String>> getBinaryDirs() => binaryDirs;
@override
List<String> getLicenseDirs() => licenseDirs;
@override
List<String> getPackageDirs() => packageDirs;
} }
class MockFileSystem extends ForwardingFileSystem { class MockFileSystem extends ForwardingFileSystem {
...@@ -179,3 +258,4 @@ class MockRandomAccessFile extends Mock implements RandomAccessFile {} ...@@ -179,3 +258,4 @@ class MockRandomAccessFile extends Mock implements RandomAccessFile {}
class MockCachedArtifact extends Mock implements CachedArtifact {} class MockCachedArtifact extends Mock implements CachedArtifact {}
class MockInternetAddress extends Mock implements InternetAddress {} class MockInternetAddress extends Mock implements InternetAddress {}
class MockCache extends Mock implements Cache {} class MockCache extends Mock implements Cache {}
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
...@@ -10,9 +10,9 @@ import 'package:flutter_tools/src/doctor.dart'; ...@@ -10,9 +10,9 @@ import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/reporting/usage.dart'; import 'package:flutter_tools/src/reporting/usage.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/testbed.dart'; import '../../src/testbed.dart';
void main() { void main() {
group('usageValues', () { group('usageValues', () {
Testbed testbed; Testbed testbed;
......
...@@ -401,16 +401,14 @@ void main() { ...@@ -401,16 +401,14 @@ void main() {
group('fuchsia app start and stop: ', () { group('fuchsia app start and stop: ', () {
MemoryFileSystem memoryFileSystem; MemoryFileSystem memoryFileSystem;
MockOperatingSystemUtils osUtils; FakeOperatingSystemUtils osUtils;
FakeFuchsiaDeviceTools fuchsiaDeviceTools; FakeFuchsiaDeviceTools fuchsiaDeviceTools;
MockFuchsiaSdk fuchsiaSdk; MockFuchsiaSdk fuchsiaSdk;
setUp(() { setUp(() {
memoryFileSystem = MemoryFileSystem(); memoryFileSystem = MemoryFileSystem();
osUtils = MockOperatingSystemUtils(); osUtils = FakeOperatingSystemUtils();
fuchsiaDeviceTools = FakeFuchsiaDeviceTools(); fuchsiaDeviceTools = FakeFuchsiaDeviceTools();
fuchsiaSdk = MockFuchsiaSdk(); fuchsiaSdk = MockFuchsiaSdk();
when(osUtils.findFreePort()).thenAnswer((_) => Future<int>.value(12345));
}); });
Future<LaunchResult> setupAndStartApp({ Future<LaunchResult> setupAndStartApp({
...@@ -640,8 +638,6 @@ class MockProcessManager extends Mock implements ProcessManager {} ...@@ -640,8 +638,6 @@ class MockProcessManager extends Mock implements ProcessManager {}
class MockProcessResult extends Mock implements ProcessResult {} class MockProcessResult extends Mock implements ProcessResult {}
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
class MockFile extends Mock implements File {} class MockFile extends Mock implements File {}
class MockProcess extends Mock implements Process {} class MockProcess extends Mock implements Process {}
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
...@@ -11,8 +10,6 @@ import 'package:mockito/mockito.dart'; ...@@ -11,8 +10,6 @@ import 'package:mockito/mockito.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
class MockFile extends Mock implements File {} class MockFile extends Mock implements File {}
void main() { void main() {
......
...@@ -19,6 +19,7 @@ import 'package:json_rpc_2/json_rpc_2.dart'; ...@@ -19,6 +19,7 @@ import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import '../src/common.dart'; import '../src/common.dart';
import '../src/context.dart';
import '../src/testbed.dart'; import '../src/testbed.dart';
void main() { void main() {
......
...@@ -33,8 +33,8 @@ export 'package:flutter_tools/src/base/context.dart' show Generator; ...@@ -33,8 +33,8 @@ export 'package:flutter_tools/src/base/context.dart' show Generator;
/// Return the test logger. This assumes that the current Logger is a BufferLogger. /// Return the test logger. This assumes that the current Logger is a BufferLogger.
BufferLogger get testLogger => context.get<Logger>(); BufferLogger get testLogger => context.get<Logger>();
MockDeviceManager get testDeviceManager => context.get<DeviceManager>(); FakeDeviceManager get testDeviceManager => context.get<DeviceManager>();
MockDoctor get testDoctor => context.get<Doctor>(); FakeDoctor get testDoctor => context.get<Doctor>();
typedef ContextInitializer = void Function(AppContext testContext); typedef ContextInitializer = void Function(AppContext testContext);
...@@ -71,8 +71,8 @@ void testUsingContext( ...@@ -71,8 +71,8 @@ void testUsingContext(
name: 'mocks', name: 'mocks',
overrides: <Type, Generator>{ overrides: <Type, Generator>{
Config: () => buildConfig(fs), Config: () => buildConfig(fs),
DeviceManager: () => MockDeviceManager(), DeviceManager: () => FakeDeviceManager(),
Doctor: () => MockDoctor(), Doctor: () => FakeDoctor(),
FlutterVersion: () => MockFlutterVersion(), FlutterVersion: () => MockFlutterVersion(),
HttpClient: () => MockHttpClient(), HttpClient: () => MockHttpClient(),
IOSSimulatorUtils: () { IOSSimulatorUtils: () {
...@@ -82,10 +82,10 @@ void testUsingContext( ...@@ -82,10 +82,10 @@ void testUsingContext(
}, },
OutputPreferences: () => OutputPreferences(showColor: false), OutputPreferences: () => OutputPreferences(showColor: false),
Logger: () => BufferLogger(), Logger: () => BufferLogger(),
OperatingSystemUtils: () => MockOperatingSystemUtils(), OperatingSystemUtils: () => FakeOperatingSystemUtils(),
SimControl: () => MockSimControl(), SimControl: () => MockSimControl(),
Usage: () => MockUsage(), Usage: () => FakeUsage(),
XcodeProjectInterpreter: () => MockXcodeProjectInterpreter(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreter(),
FileSystem: () => LocalFileSystemBlockingSetCurrentDirectory(), FileSystem: () => LocalFileSystemBlockingSetCurrentDirectory(),
TimeoutConfiguration: () => const TimeoutConfiguration(), TimeoutConfiguration: () => const TimeoutConfiguration(),
}, },
...@@ -135,7 +135,7 @@ void _printBufferedErrors(AppContext testContext) { ...@@ -135,7 +135,7 @@ void _printBufferedErrors(AppContext testContext) {
} }
} }
class MockDeviceManager implements DeviceManager { class FakeDeviceManager implements DeviceManager {
List<Device> devices = <Device>[]; List<Device> devices = <Device>[];
String _specifiedDeviceId; String _specifiedDeviceId;
...@@ -198,12 +198,12 @@ class MockDeviceManager implements DeviceManager { ...@@ -198,12 +198,12 @@ class MockDeviceManager implements DeviceManager {
} }
} }
class MockAndroidLicenseValidator extends AndroidLicenseValidator { class FakeAndroidLicenseValidator extends AndroidLicenseValidator {
@override @override
Future<LicensesAccepted> get licensesAccepted async => LicensesAccepted.all; Future<LicensesAccepted> get licensesAccepted async => LicensesAccepted.all;
} }
class MockDoctor extends Doctor { class FakeDoctor extends Doctor {
// True for testing. // True for testing.
@override @override
bool get canListAnything => true; bool get canListAnything => true;
...@@ -220,7 +220,7 @@ class MockDoctor extends Doctor { ...@@ -220,7 +220,7 @@ class MockDoctor extends Doctor {
final List<DoctorValidator> superValidators = super.validators; final List<DoctorValidator> superValidators = super.validators;
return superValidators.map<DoctorValidator>((DoctorValidator v) { return superValidators.map<DoctorValidator>((DoctorValidator v) {
if (v is AndroidLicenseValidator) { if (v is AndroidLicenseValidator) {
return MockAndroidLicenseValidator(); return FakeAndroidLicenseValidator();
} }
return v; return v;
}).toList(); }).toList();
...@@ -233,10 +233,13 @@ class MockSimControl extends Mock implements SimControl { ...@@ -233,10 +233,13 @@ class MockSimControl extends Mock implements SimControl {
} }
} }
class MockOperatingSystemUtils implements OperatingSystemUtils { class FakeOperatingSystemUtils implements OperatingSystemUtils {
@override @override
ProcessResult makeExecutable(File file) => null; ProcessResult makeExecutable(File file) => null;
@override
void chmod(FileSystemEntity entity, String mode) { }
@override @override
File which(String execName) => null; File which(String execName) => null;
...@@ -273,7 +276,7 @@ class MockOperatingSystemUtils implements OperatingSystemUtils { ...@@ -273,7 +276,7 @@ class MockOperatingSystemUtils implements OperatingSystemUtils {
class MockIOSSimulatorUtils extends Mock implements IOSSimulatorUtils {} class MockIOSSimulatorUtils extends Mock implements IOSSimulatorUtils {}
class MockUsage implements Usage { class FakeUsage implements Usage {
@override @override
bool get isFirstRun => false; bool get isFirstRun => false;
...@@ -314,7 +317,7 @@ class MockUsage implements Usage { ...@@ -314,7 +317,7 @@ class MockUsage implements Usage {
void printWelcome() { } void printWelcome() { }
} }
class MockXcodeProjectInterpreter implements XcodeProjectInterpreter { class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter {
@override @override
bool get isInstalled => true; bool get isInstalled => true;
......
...@@ -9,6 +9,7 @@ import 'dart:typed_data'; ...@@ -9,6 +9,7 @@ import 'dart:typed_data';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/context.dart'; import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
...@@ -33,6 +34,7 @@ final Map<Type, Generator> _testbedDefaults = <Type, Generator>{ ...@@ -33,6 +34,7 @@ final Map<Type, Generator> _testbedDefaults = <Type, Generator>{
? FileSystemStyle.windows ? FileSystemStyle.windows
: FileSystemStyle.posix), : FileSystemStyle.posix),
Logger: () => BufferLogger(), // Allows reading logs and prevents stdout. Logger: () => BufferLogger(), // Allows reading logs and prevents stdout.
OperatingSystemUtils: () => FakeOperatingSystemUtils(),
OutputPreferences: () => OutputPreferences(showColor: false), // configures BufferLogger to avoid color codes. OutputPreferences: () => OutputPreferences(showColor: false), // configures BufferLogger to avoid color codes.
Usage: () => NoOpUsage(), // prevent addition of analytics from burdening test mocks Usage: () => NoOpUsage(), // prevent addition of analytics from burdening test mocks
FlutterVersion: () => FakeFlutterVersion() // prevent requirement to mock git for test runner. FlutterVersion: () => FakeFlutterVersion() // prevent requirement to mock git for test runner.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment