blob: ae3dcb658be03f1dbec53699018ba6d4e9d83ba6 [file] [log] [blame]
Yegor361afef2017-04-07 21:08:53 -07001// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Yegor361afef2017-04-07 21:08:53 -07005import 'package:file/file.dart';
6import 'package:file/memory.dart';
Todd Volkertadb2aee2019-07-18 15:29:06 -07007import 'package:file_testing/file_testing.dart';
8import 'package:meta/meta.dart';
Yegor361afef2017-04-07 21:08:53 -07009import 'package:mockito/mockito.dart';
Yegor361afef2017-04-07 21:08:53 -070010import 'package:platform/platform.dart';
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -070011import 'package:process/process.dart';
Yegor361afef2017-04-07 21:08:53 -070012
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -070013import 'package:flutter_tools/src/android/gradle.dart';
Zachary Anderson99d66f22019-07-30 12:16:32 -070014import 'package:flutter_tools/src/base/common.dart';
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -070015import 'package:flutter_tools/src/base/io.dart';
Yegor361afef2017-04-07 21:08:53 -070016import 'package:flutter_tools/src/cache.dart';
Todd Volkertadb2aee2019-07-18 15:29:06 -070017import 'package:flutter_tools/src/base/file_system.dart';
xsterbdc06192018-04-06 18:44:05 -070018import 'package:flutter_tools/src/base/io.dart' show InternetAddress, SocketException;
Todd Volkertadb2aee2019-07-18 15:29:06 -070019import 'package:flutter_tools/src/base/net.dart';
20import 'package:flutter_tools/src/base/os.dart';
Yegor361afef2017-04-07 21:08:53 -070021
Ian Hicksond919e692019-07-13 11:51:44 -070022import '../src/common.dart';
23import '../src/context.dart';
Todd Volkertadb2aee2019-07-18 15:29:06 -070024import '../src/testbed.dart';
Yegor361afef2017-04-07 21:08:53 -070025
26void main() {
27 group('$Cache.checkLockAcquired', () {
Zachary Anderson99d66f22019-07-30 12:16:32 -070028 MockFileSystem mockFileSystem;
29 MemoryFileSystem memoryFileSystem;
30 MockFile mockFile;
31 MockRandomAccessFile mockRandomAccessFile;
32
Yegor361afef2017-04-07 21:08:53 -070033 setUp(() {
Zachary Anderson99d66f22019-07-30 12:16:32 -070034 mockFileSystem = MockFileSystem();
35 memoryFileSystem = MemoryFileSystem();
36 mockFile = MockFile();
37 mockRandomAccessFile = MockRandomAccessFile();
38 when(mockFileSystem.path).thenReturn(memoryFileSystem.path);
39
Yegor361afef2017-04-07 21:08:53 -070040 Cache.enableLocking();
41 });
42
43 tearDown(() {
44 // Restore locking to prevent potential side-effects in
45 // tests outside this group (this option is globally shared).
46 Cache.enableLocking();
Zachary Anderson99d66f22019-07-30 12:16:32 -070047 Cache.releaseLockEarly();
Yegor361afef2017-04-07 21:08:53 -070048 });
49
50 test('should throw when locking is not acquired', () {
51 expect(() => Cache.checkLockAcquired(), throwsStateError);
52 });
53
54 test('should not throw when locking is disabled', () {
55 Cache.disableLocking();
56 Cache.checkLockAcquired();
57 });
58
59 testUsingContext('should not throw when lock is acquired', () async {
Zachary Anderson99d66f22019-07-30 12:16:32 -070060 when(mockFileSystem.file(argThat(endsWith('lockfile')))).thenReturn(mockFile);
61 when(mockFile.openSync(mode: anyNamed('mode'))).thenReturn(mockRandomAccessFile);
Yegor361afef2017-04-07 21:08:53 -070062 await Cache.lock();
63 Cache.checkLockAcquired();
Zachary Anderson99d66f22019-07-30 12:16:32 -070064 Cache.releaseLockEarly();
Yegor361afef2017-04-07 21:08:53 -070065 }, overrides: <Type, Generator>{
Zachary Anderson99d66f22019-07-30 12:16:32 -070066 FileSystem: () => mockFileSystem,
Ian Hickson3597bae2019-10-21 20:15:20 -070067 ProcessManager: () => FakeProcessManager.any(),
Zachary Anderson99d66f22019-07-30 12:16:32 -070068 });
69
70 testUsingContext('throws tool exit when lockfile open fails', () async {
71 when(mockFileSystem.file(argThat(endsWith('lockfile')))).thenReturn(mockFile);
72 when(mockFile.openSync(mode: anyNamed('mode'))).thenThrow(const FileSystemException());
73 expect(() async => await Cache.lock(), throwsA(isA<ToolExit>()));
74 }, overrides: <Type, Generator>{
75 FileSystem: () => mockFileSystem,
Ian Hickson3597bae2019-10-21 20:15:20 -070076 ProcessManager: () => FakeProcessManager.any(),
Yegor361afef2017-04-07 21:08:53 -070077 });
78
79 testUsingContext('should not throw when FLUTTER_ALREADY_LOCKED is set', () async {
80 Cache.checkLockAcquired();
81 }, overrides: <Type, Generator>{
Alexandre Ardhuind927c932018-09-12 08:29:29 +020082 Platform: () => FakePlatform()..environment = <String, String>{'FLUTTER_ALREADY_LOCKED': 'true'},
Yegor361afef2017-04-07 21:08:53 -070083 });
84 });
Ian Hicksone1fa0352017-09-28 17:37:34 -070085
Mikkel Nygaard Ravnc5999c72017-06-26 12:47:43 +020086 group('Cache', () {
Todd Volkertadb2aee2019-07-18 15:29:06 -070087 MockCache mockCache;
88 MemoryFileSystem memoryFileSystem;
89
90 setUp(() {
91 mockCache = MockCache();
92 memoryFileSystem = MemoryFileSystem();
93 });
KyleWong87d6e932019-01-09 10:34:58 +080094
95 testUsingContext('Gradle wrapper should not be up to date, if some cached artifact is not available', () {
96 final GradleWrapper gradleWrapper = GradleWrapper(mockCache);
97 final Directory directory = fs.directory('/Applications/flutter/bin/cache');
98 directory.createSync(recursive: true);
99 fs.file(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper', 'gradle', 'wrapper', 'gradle-wrapper.jar')).createSync(recursive: true);
100 when(mockCache.getCacheDir(fs.path.join('artifacts', 'gradle_wrapper'))).thenReturn(fs.directory(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper')));
Jonah Williams8c0cf1d2019-03-08 13:31:51 -0800101 expect(gradleWrapper.isUpToDateInner(), false);
KyleWong87d6e932019-01-09 10:34:58 +0800102 }, overrides: <Type, Generator>{
103 Cache: ()=> mockCache,
Todd Volkertadb2aee2019-07-18 15:29:06 -0700104 FileSystem: () => memoryFileSystem,
Ian Hickson3597bae2019-10-21 20:15:20 -0700105 ProcessManager: () => FakeProcessManager.any(),
KyleWong87d6e932019-01-09 10:34:58 +0800106 });
107
108 testUsingContext('Gradle wrapper should be up to date, only if all cached artifact are available', () {
109 final GradleWrapper gradleWrapper = GradleWrapper(mockCache);
110 final Directory directory = fs.directory('/Applications/flutter/bin/cache');
111 directory.createSync(recursive: true);
112 fs.file(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper', 'gradle', 'wrapper', 'gradle-wrapper.jar')).createSync(recursive: true);
113 fs.file(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper', 'gradlew')).createSync(recursive: true);
114 fs.file(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper', 'gradlew.bat')).createSync(recursive: true);
115
116 when(mockCache.getCacheDir(fs.path.join('artifacts', 'gradle_wrapper'))).thenReturn(fs.directory(fs.path.join(directory.path, 'artifacts', 'gradle_wrapper')));
Jonah Williams8c0cf1d2019-03-08 13:31:51 -0800117 expect(gradleWrapper.isUpToDateInner(), true);
KyleWong87d6e932019-01-09 10:34:58 +0800118 }, overrides: <Type, Generator>{
119 Cache: ()=> mockCache,
Todd Volkertadb2aee2019-07-18 15:29:06 -0700120 FileSystem: () => memoryFileSystem,
Ian Hickson3597bae2019-10-21 20:15:20 -0700121 ProcessManager: () => FakeProcessManager.any(),
KyleWong87d6e932019-01-09 10:34:58 +0800122 });
123
Mikkel Nygaard Ravnc5999c72017-06-26 12:47:43 +0200124 test('should not be up to date, if some cached artifact is not', () {
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200125 final CachedArtifact artifact1 = MockCachedArtifact();
126 final CachedArtifact artifact2 = MockCachedArtifact();
Jonah Williams164dae32019-03-26 10:01:22 -0700127 when(artifact1.isUpToDate()).thenReturn(true);
128 when(artifact2.isUpToDate()).thenReturn(false);
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200129 final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
Jonah Williams164dae32019-03-26 10:01:22 -0700130 expect(cache.isUpToDate(), isFalse);
Mikkel Nygaard Ravnc5999c72017-06-26 12:47:43 +0200131 });
132 test('should be up to date, if all cached artifacts are', () {
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200133 final CachedArtifact artifact1 = MockCachedArtifact();
134 final CachedArtifact artifact2 = MockCachedArtifact();
Jonah Williams164dae32019-03-26 10:01:22 -0700135 when(artifact1.isUpToDate()).thenReturn(true);
136 when(artifact2.isUpToDate()).thenReturn(true);
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200137 final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
Jonah Williams164dae32019-03-26 10:01:22 -0700138 expect(cache.isUpToDate(), isTrue);
Mikkel Nygaard Ravnc5999c72017-06-26 12:47:43 +0200139 });
140 test('should update cached artifacts which are not up to date', () async {
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200141 final CachedArtifact artifact1 = MockCachedArtifact();
142 final CachedArtifact artifact2 = MockCachedArtifact();
Jonah Williams164dae32019-03-26 10:01:22 -0700143 when(artifact1.isUpToDate()).thenReturn(true);
144 when(artifact2.isUpToDate()).thenReturn(false);
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200145 final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700146 await cache.updateAll(<DevelopmentArtifact>{
147 null,
148 });
149 verifyNever(artifact1.update());
150 verify(artifact2.update());
Mikkel Nygaard Ravnc5999c72017-06-26 12:47:43 +0200151 });
Christopher Fujino102ab1e2019-07-15 09:22:29 -0700152 testUsingContext('getter dyLdLibEntry concatenates the output of each artifact\'s dyLdLibEntry getter', () async {
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700153 final IosUsbArtifacts artifact1 = MockIosUsbArtifacts();
154 final IosUsbArtifacts artifact2 = MockIosUsbArtifacts();
155 final IosUsbArtifacts artifact3 = MockIosUsbArtifacts();
156 when(artifact1.environment)
157 .thenReturn(<String, String>{
158 'DYLD_LIBRARY_PATH': '/path/to/alpha:/path/to/beta',
159 });
160 when(artifact2.environment)
161 .thenReturn(<String, String>{
162 'DYLD_LIBRARY_PATH': '/path/to/gamma:/path/to/delta:/path/to/epsilon',
163 });
164 when(artifact3.environment)
165 .thenReturn(<String, String>{
166 'DYLD_LIBRARY_PATH': '',
167 });
Christopher Fujino102ab1e2019-07-15 09:22:29 -0700168 final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2, artifact3]);
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700169
Christopher Fujino102ab1e2019-07-15 09:22:29 -0700170 expect(cache.dyLdLibEntry.key, 'DYLD_LIBRARY_PATH');
171 expect(
172 cache.dyLdLibEntry.value,
173 '/path/to/alpha:/path/to/beta:/path/to/gamma:/path/to/delta:/path/to/epsilon',
174 );
175 }, overrides: <Type, Generator>{
176 Cache: ()=> mockCache,
177 });
xsterbdc06192018-04-06 18:44:05 -0700178 testUsingContext('failed storage.googleapis.com download shows China warning', () async {
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200179 final CachedArtifact artifact1 = MockCachedArtifact();
180 final CachedArtifact artifact2 = MockCachedArtifact();
Jonah Williams164dae32019-03-26 10:01:22 -0700181 when(artifact1.isUpToDate()).thenReturn(false);
182 when(artifact2.isUpToDate()).thenReturn(false);
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200183 final MockInternetAddress address = MockInternetAddress();
xsterbdc06192018-04-06 18:44:05 -0700184 when(address.host).thenReturn('storage.googleapis.com');
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700185 when(artifact1.update()).thenThrow(SocketException(
xsterbdc06192018-04-06 18:44:05 -0700186 'Connection reset by peer',
187 address: address,
188 ));
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200189 final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
xsterbdc06192018-04-06 18:44:05 -0700190 try {
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700191 await cache.updateAll(<DevelopmentArtifact>{
192 null,
193 });
xsterbdc06192018-04-06 18:44:05 -0700194 fail('Mock thrown exception expected');
195 } catch (e) {
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700196 verify(artifact1.update());
xsterbdc06192018-04-06 18:44:05 -0700197 // Don't continue when retrieval fails.
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700198 verifyNever(artifact2.update());
xsterbdc06192018-04-06 18:44:05 -0700199 expect(
200 testLogger.errorText,
Tim Sneath52918972019-04-05 11:39:30 -0700201 contains('https://flutter.dev/community/china'),
xsterbdc06192018-04-06 18:44:05 -0700202 );
203 }
204 });
Mikkel Nygaard Ravnc5999c72017-06-26 12:47:43 +0200205 });
Michael Goderbauera67df9e2018-01-17 16:08:19 -0800206
207 testUsingContext('flattenNameSubdirs', () {
Tim Sneath52918972019-04-05 11:39:30 -0700208 expect(flattenNameSubdirs(Uri.parse('http://flutter.dev/foo/bar')), 'flutter.dev/foo/bar');
Michael Goderbauera67df9e2018-01-17 16:08:19 -0800209 expect(flattenNameSubdirs(Uri.parse('http://docs.flutter.io/foo/bar')), 'docs.flutter.io/foo/bar');
Tim Sneath52918972019-04-05 11:39:30 -0700210 expect(flattenNameSubdirs(Uri.parse('https://www.flutter.dev')), 'www.flutter.dev');
Alexandre Ardhuinc02b6a82018-02-02 23:27:29 +0100211 }, overrides: <Type, Generator>{
Zachary Anderson99d66f22019-07-30 12:16:32 -0700212 FileSystem: () => MemoryFileSystem(),
Ian Hickson3597bae2019-10-21 20:15:20 -0700213 ProcessManager: () => FakeProcessManager.any(),
Michael Goderbauera67df9e2018-01-17 16:08:19 -0800214 });
Todd Volkertadb2aee2019-07-18 15:29:06 -0700215
Jonah Williamsc9a5f942019-07-29 16:13:47 -0700216 test('Unstable artifacts', () {
Jonah Williams861fe0a2019-10-09 16:27:39 -0700217 expect(DevelopmentArtifact.web.unstable, false);
Jonah Williamsc9a5f942019-07-29 16:13:47 -0700218 expect(DevelopmentArtifact.linux.unstable, true);
219 expect(DevelopmentArtifact.macOS.unstable, true);
220 expect(DevelopmentArtifact.windows.unstable, true);
221 expect(DevelopmentArtifact.fuchsia.unstable, true);
222 expect(DevelopmentArtifact.flutterRunner.unstable, true);
223 });
224
Todd Volkertadb2aee2019-07-18 15:29:06 -0700225 group('EngineCachedArtifact', () {
226 FakeHttpClient fakeHttpClient;
227 FakePlatform fakePlatform;
228 MemoryFileSystem memoryFileSystem;
229 MockCache mockCache;
230 MockOperatingSystemUtils mockOperatingSystemUtils;
231
232 setUp(() {
233 fakeHttpClient = FakeHttpClient();
234 fakePlatform = FakePlatform()..environment = const <String, String>{};
235 memoryFileSystem = MemoryFileSystem();
236 mockCache = MockCache();
237 mockOperatingSystemUtils = MockOperatingSystemUtils();
238 when(mockOperatingSystemUtils.verifyZip(any)).thenReturn(true);
239 });
240
241 testUsingContext('makes binary dirs readable and executable by all', () async {
Ian Hicksoncdc2d992019-10-07 16:43:04 -0700242 final Directory artifactDir = fs.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
243 final Directory downloadDir = fs.systemTempDirectory.createTempSync('flutter_cache_test_download.');
Todd Volkertadb2aee2019-07-18 15:29:06 -0700244 when(mockCache.getArtifactDirectory(any)).thenReturn(artifactDir);
245 when(mockCache.getDownloadDir()).thenReturn(downloadDir);
246 final FakeCachedArtifact artifact = FakeCachedArtifact(
247 cache: mockCache,
248 binaryDirs: <List<String>>[
249 <String>['bin_dir', 'unused_url_path'],
250 ],
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700251 requiredArtifacts: DevelopmentArtifact.universal,
Todd Volkertadb2aee2019-07-18 15:29:06 -0700252 );
253 await artifact.updateInner();
254 final Directory dir = memoryFileSystem.systemTempDirectory
255 .listSync(recursive: true)
256 .whereType<Directory>()
257 .singleWhere((Directory directory) => directory.basename == 'bin_dir', orElse: () => null);
258 expect(dir, isNotNull);
259 expect(dir.path, artifactDir.childDirectory('bin_dir').path);
260 verify(mockOperatingSystemUtils.chmod(argThat(hasPath(dir.path)), 'a+r,a+x'));
261 }, overrides: <Type, Generator>{
262 Cache: ()=> mockCache,
263 FileSystem: () => memoryFileSystem,
Ian Hickson3597bae2019-10-21 20:15:20 -0700264 ProcessManager: () => FakeProcessManager.any(),
Todd Volkertadb2aee2019-07-18 15:29:06 -0700265 HttpClientFactory: () => () => fakeHttpClient,
266 OperatingSystemUtils: () => mockOperatingSystemUtils,
267 Platform: () => fakePlatform,
268 });
269 });
Jonah Williams77e15102019-08-09 16:21:32 -0700270
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700271 group('AndroidMavenArtifacts', () {
272 MemoryFileSystem memoryFileSystem;
273 MockProcessManager processManager;
274 MockCache mockCache;
Jonah Williams77e15102019-08-09 16:21:32 -0700275
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700276 setUp(() {
277 memoryFileSystem = MemoryFileSystem();
278 processManager = MockProcessManager();
279 mockCache = MockCache();
280 });
281
282 test('development artifact', () async {
283 final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts();
284 expect(mavenArtifacts.developmentArtifact, DevelopmentArtifact.androidMaven);
285 });
286
287 testUsingContext('update', () async {
288 final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts();
289 expect(mavenArtifacts.isUpToDate(), isFalse);
290
Ian Hicksoncdc2d992019-10-07 16:43:04 -0700291 final Directory gradleWrapperDir = fs.systemTempDirectory.createTempSync('flutter_cache_test_gradle_wrapper.');
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700292 when(mockCache.getArtifactDirectory('gradle_wrapper')).thenReturn(gradleWrapperDir);
293
294 fs.directory(gradleWrapperDir.childDirectory('gradle').childDirectory('wrapper'))
295 .createSync(recursive: true);
296 fs.file(fs.path.join(gradleWrapperDir.path, 'gradlew')).writeAsStringSync('irrelevant');
297 fs.file(fs.path.join(gradleWrapperDir.path, 'gradlew.bat')).writeAsStringSync('irrelevant');
298
299 when(processManager.run(any, environment: captureAnyNamed('environment')))
300 .thenAnswer((Invocation invocation) {
301 final List<String> args = invocation.positionalArguments[0];
302 expect(args.length, 6);
303 expect(args[1], '-b');
304 expect(args[2].endsWith('resolve_dependencies.gradle'), isTrue);
305 expect(args[5], 'resolveDependencies');
306 expect(invocation.namedArguments[#environment], gradleEnv);
307 return Future<ProcessResult>.value(ProcessResult(0, 0, '', ''));
308 });
309
310 await mavenArtifacts.update();
311
312 expect(mavenArtifacts.isUpToDate(), isFalse);
313 }, overrides: <Type, Generator>{
314 Cache: ()=> mockCache,
315 FileSystem: () => memoryFileSystem,
316 ProcessManager: () => processManager,
317 });
Jonah Williams77e15102019-08-09 16:21:32 -0700318 });
Lau Ching Jun5a413742019-10-09 22:24:15 -0700319
320 group('Unsigned mac artifacts', () {
321 MockCache mockCache;
322
323 setUp(() {
324 mockCache = MockCache();
325 });
326
327 testUsingContext('use unsigned when specified', () async {
328 when(mockCache.useUnsignedMacBinaries).thenReturn(true);
329
330 final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('name', mockCache);
331 expect(iosUsbArtifacts.archiveUri.toString(), contains('/unsigned/'));
332 }, overrides: <Type, Generator>{
333 Cache: () => mockCache,
334 });
335
336 testUsingContext('not use unsigned when not specified', () async {
337 when(mockCache.useUnsignedMacBinaries).thenReturn(false);
338
339 final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('name', mockCache);
340 expect(iosUsbArtifacts.archiveUri.toString(), isNot(contains('/unsigned/')));
341 }, overrides: <Type, Generator>{
342 Cache: () => mockCache,
343 });
344 });
Todd Volkertadb2aee2019-07-18 15:29:06 -0700345}
346
347class FakeCachedArtifact extends EngineCachedArtifact {
348 FakeCachedArtifact({
349 String stampName = 'STAMP',
350 @required Cache cache,
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700351 DevelopmentArtifact requiredArtifacts,
Todd Volkertadb2aee2019-07-18 15:29:06 -0700352 this.binaryDirs = const <List<String>>[],
353 this.licenseDirs = const <String>[],
354 this.packageDirs = const <String>[],
355 }) : super(stampName, cache, requiredArtifacts);
356
357 final List<List<String>> binaryDirs;
358 final List<String> licenseDirs;
359 final List<String> packageDirs;
360
361 @override
362 List<List<String>> getBinaryDirs() => binaryDirs;
363
364 @override
365 List<String> getLicenseDirs() => licenseDirs;
366
367 @override
368 List<String> getPackageDirs() => packageDirs;
Yegor361afef2017-04-07 21:08:53 -0700369}
370
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700371class MockProcessManager extends Mock implements ProcessManager {}
Zachary Anderson99d66f22019-07-30 12:16:32 -0700372class MockFileSystem extends Mock implements FileSystem {}
373class MockFile extends Mock implements File {}
Jonah Williams77e15102019-08-09 16:21:32 -0700374class MockDirectory extends Mock implements Directory {}
Yegor361afef2017-04-07 21:08:53 -0700375
376class MockRandomAccessFile extends Mock implements RandomAccessFile {}
Mikkel Nygaard Ravnc5999c72017-06-26 12:47:43 +0200377class MockCachedArtifact extends Mock implements CachedArtifact {}
Emmanuel Garcia8a1bf5b2019-09-17 08:19:33 -0700378class MockIosUsbArtifacts extends Mock implements IosUsbArtifacts {}
xsterbdc06192018-04-06 18:44:05 -0700379class MockInternetAddress extends Mock implements InternetAddress {}
Alexandre Ardhuin4c1f4d12019-03-06 09:37:32 +0100380class MockCache extends Mock implements Cache {}
Todd Volkertadb2aee2019-07-18 15:29:06 -0700381class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}