// Copyright 2019 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 'package:file/memory.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/commands/build_aot.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/ios/ios_workflow.dart'; import 'package:flutter_tools/src/macos/xcode.dart'; import 'package:mockito/mockito.dart'; import 'package:process/process.dart'; import '../../src/common.dart'; import '../../src/context.dart'; import '../../src/mocks.dart'; void main() { MockXcode mockXcode; MemoryFileSystem memoryFileSystem; MockProcessManager mockProcessManager; BufferLogger bufferLogger; MockIOSWorkflow mockIOSWorkflow; setUp(() { mockXcode = MockXcode(); memoryFileSystem = MemoryFileSystem(style: FileSystemStyle.posix); mockProcessManager = MockProcessManager(); bufferLogger = BufferLogger(); mockIOSWorkflow = MockIOSWorkflow(); }); testUsingContext('build aot validates building with bitcode requires a local engine', () async { await expectToolExitLater( validateBitcode(), equals('Bitcode is only supported with a local engine built with --bitcode.'), ); }); testUsingContext('build aot validates existence of Flutter.framework in engine', () async { await expectToolExitLater( validateBitcode(), equals('Flutter.framework not found at ios_profile/Flutter.framework'), ); }, overrides: { Artifacts: () => LocalEngineArtifacts('/engine', 'ios_profile', 'host_profile'), FileSystem: () => memoryFileSystem, }); testUsingContext('build aot validates Flutter.framework/Flutter contains bitcode', () async { final Directory flutterFramework = memoryFileSystem.directory('ios_profile/Flutter.framework') ..createSync(recursive: true); flutterFramework.childFile('Flutter').createSync(); flutterFramework.childFile('Info.plist').createSync(); final RunResult otoolResult = RunResult( FakeProcessResult(stdout: '', stderr: ''), const ['foo'], ); when(mockXcode.otool(any)).thenAnswer((_) => Future.value(otoolResult)); await expectToolExitLater( validateBitcode(), equals('The Flutter.framework at ios_profile/Flutter.framework does not contain bitcode.'), ); }, overrides: { Artifacts: () => LocalEngineArtifacts('/engine', 'ios_profile', 'host_profile'), FileSystem: () => memoryFileSystem, ProcessManager: () => mockProcessManager, Xcode: () => mockXcode, }); testUsingContext('build aot validates Flutter.framework/Flutter was built with same toolchain', () async { final Directory flutterFramework = memoryFileSystem.directory('ios_profile/Flutter.framework') ..createSync(recursive: true); flutterFramework.childFile('Flutter').createSync(); final File infoPlist = flutterFramework.childFile('Info.plist')..createSync(); final RunResult otoolResult = RunResult( FakeProcessResult(stdout: '__LLVM', stderr: ''), const ['foo'], ); final RunResult clangResult = RunResult( FakeProcessResult(stdout: 'BadVersion\nBlahBlah\n', stderr: ''), const ['foo'], ); when(mockXcode.otool(any)).thenAnswer((_) => Future.value(otoolResult)); when(mockXcode.clang(any)).thenAnswer((_) => Future.value(clangResult)); when(mockIOSWorkflow.getPlistValueFromFile(infoPlist.path, 'ClangVersion')).thenReturn('Apple LLVM Version 10.0.1'); await validateBitcode(); expect( bufferLogger.statusText, startsWith('The Flutter.framework at ${flutterFramework.path} was built with "Apple LLVM Version 10.0.1'), ); }, overrides: { Artifacts: () => LocalEngineArtifacts('/engine', 'ios_profile', 'host_profile'), FileSystem: () => memoryFileSystem, ProcessManager: () => mockProcessManager, Xcode: () => mockXcode, Logger: () => bufferLogger, IOSWorkflow: () => mockIOSWorkflow, }); testUsingContext('build aot validates and succeeds', () async { final Directory flutterFramework = memoryFileSystem.directory('ios_profile/Flutter.framework') ..createSync(recursive: true); flutterFramework.childFile('Flutter').createSync(); final File infoPlist = flutterFramework.childFile('Info.plist')..createSync(); final RunResult otoolResult = RunResult( FakeProcessResult(stdout: '__LLVM', stderr: ''), const ['foo'], ); final RunResult clangResult = RunResult( FakeProcessResult(stdout: 'Apple LLVM Version 10.0.1\nBlahBlah\n', stderr: ''), const ['foo'], ); when(mockXcode.otool(any)).thenAnswer((_) => Future.value(otoolResult)); when(mockXcode.clang(any)).thenAnswer((_) => Future.value(clangResult)); when(mockIOSWorkflow.getPlistValueFromFile(infoPlist.path, 'ClangVersion')).thenReturn('Apple LLVM Version 10.0.1'); await validateBitcode(); expect(bufferLogger.statusText, ''); }, overrides: { Artifacts: () => LocalEngineArtifacts('/engine', 'ios_profile', 'host_profile'), FileSystem: () => memoryFileSystem, ProcessManager: () => mockProcessManager, Xcode: () => mockXcode, Logger: () => bufferLogger, IOSWorkflow: () => mockIOSWorkflow, }); } class MockXcode extends Mock implements Xcode {} class MockIOSWorkflow extends Mock implements IOSWorkflow {}