| // Copyright 2014 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/base/file_system.dart'; |
| import 'package:flutter_tools/src/base/platform.dart'; |
| import 'package:flutter_tools/src/build_info.dart'; |
| import 'package:flutter_tools/src/build_system/build_system.dart'; |
| import 'package:flutter_tools/src/cache.dart'; |
| import 'package:flutter_tools/src/commands/build_ios_framework.dart'; |
| import 'package:flutter_tools/src/commands/build_macos_framework.dart'; |
| import 'package:flutter_tools/src/version.dart'; |
| |
| import '../../src/common.dart'; |
| import '../../src/context.dart'; |
| import '../../src/fake_process_manager.dart'; |
| import '../../src/fakes.dart'; |
| import '../../src/test_build_system.dart'; |
| |
| void main() { |
| late MemoryFileSystem memoryFileSystem; |
| late Directory outputDirectory; |
| late FakePlatform fakePlatform; |
| |
| setUpAll(() { |
| Cache.disableLocking(); |
| }); |
| |
| const String storageBaseUrl = 'https://fake.googleapis.com'; |
| setUp(() { |
| memoryFileSystem = MemoryFileSystem.test(); |
| fakePlatform = FakePlatform( |
| operatingSystem: 'macos', |
| environment: <String, String>{ |
| 'FLUTTER_STORAGE_BASE_URL': storageBaseUrl, |
| }, |
| ); |
| |
| outputDirectory = memoryFileSystem.systemTempDirectory |
| .createTempSync('flutter_build_framework_test_output.') |
| .childDirectory('Debug') |
| ..createSync(); |
| }); |
| |
| group('build ios-framework', () { |
| group('podspec', () { |
| const String engineRevision = '0123456789abcdef'; |
| late Cache cache; |
| |
| setUp(() { |
| final Directory rootOverride = memoryFileSystem.directory('cache'); |
| cache = Cache.test( |
| rootOverride: rootOverride, |
| platform: fakePlatform, |
| fileSystem: memoryFileSystem, |
| processManager: FakeProcessManager.any(), |
| ); |
| rootOverride.childDirectory('bin').childDirectory('internal').childFile('engine.version') |
| ..createSync(recursive: true) |
| ..writeAsStringSync(engineRevision); |
| }); |
| |
| testUsingContext('version unknown', () async { |
| const String frameworkVersion = '0.0.0-unknown'; |
| final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion(frameworkVersion: frameworkVersion); |
| |
| final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| |
| expect(() => command.produceFlutterPodspec(BuildMode.debug, outputDirectory), |
| throwsToolExit(message: 'Detected version is $frameworkVersion')); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('throws when not on a released version', () async { |
| const String frameworkVersion = 'v1.13.10+hotfix-pre.2'; |
| const GitTagVersion gitTagVersion = GitTagVersion( |
| x: 1, |
| y: 13, |
| z: 10, |
| hotfix: 13, |
| commits: 2, |
| ); |
| final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion( |
| gitTagVersion: gitTagVersion, |
| frameworkVersion: frameworkVersion, |
| ); |
| |
| final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| |
| expect(() => command.produceFlutterPodspec(BuildMode.debug, outputDirectory), |
| throwsToolExit(message: 'Detected version is $frameworkVersion')); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('throws when license not found', () async { |
| final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion( |
| gitTagVersion: const GitTagVersion( |
| x: 1, |
| y: 13, |
| z: 10, |
| hotfix: 13, |
| commits: 0, |
| ), |
| ); |
| |
| final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| |
| expect(() => command.produceFlutterPodspec(BuildMode.debug, outputDirectory), |
| throwsToolExit(message: 'Could not find license')); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| group('is created', () { |
| const String frameworkVersion = 'v1.13.11+hotfix.13'; |
| const String licenseText = 'This is the license!'; |
| |
| setUp(() { |
| // cache.getLicenseFile() relies on the flutter root being set. |
| Cache.flutterRoot ??= getFlutterRoot(); |
| cache.getLicenseFile() |
| ..createSync(recursive: true) |
| ..writeAsStringSync(licenseText); |
| }); |
| |
| group('on master channel', () { |
| testUsingContext('created when forced', () async { |
| const GitTagVersion gitTagVersion = GitTagVersion( |
| x: 1, |
| y: 13, |
| z: 11, |
| hotfix: 13, |
| commits: 100, |
| ); |
| final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion( |
| gitTagVersion: gitTagVersion, |
| frameworkVersion: frameworkVersion, |
| ); |
| |
| final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| command.produceFlutterPodspec(BuildMode.debug, outputDirectory, force: true); |
| |
| final File expectedPodspec = outputDirectory.childFile('Flutter.podspec'); |
| expect(expectedPodspec.existsSync(), isTrue); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| }); |
| |
| group('not on master channel', () { |
| late FakeFlutterVersion fakeFlutterVersion; |
| setUp(() { |
| const GitTagVersion gitTagVersion = GitTagVersion( |
| x: 1, |
| y: 13, |
| z: 11, |
| hotfix: 13, |
| commits: 0, |
| ); |
| fakeFlutterVersion = FakeFlutterVersion( |
| gitTagVersion: gitTagVersion, |
| frameworkVersion: frameworkVersion, |
| ); |
| }); |
| |
| testUsingContext('contains license and version', () async { |
| final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| command.produceFlutterPodspec(BuildMode.debug, outputDirectory); |
| |
| final File expectedPodspec = outputDirectory.childFile('Flutter.podspec'); |
| final String podspecContents = expectedPodspec.readAsStringSync(); |
| expect(podspecContents, contains("'1.13.1113'")); |
| expect(podspecContents, contains('# $frameworkVersion')); |
| expect(podspecContents, contains(licenseText)); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('debug URL', () async { |
| final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| command.produceFlutterPodspec(BuildMode.debug, outputDirectory); |
| |
| final File expectedPodspec = outputDirectory.childFile('Flutter.podspec'); |
| final String podspecContents = expectedPodspec.readAsStringSync(); |
| expect(podspecContents, contains("'$storageBaseUrl/flutter_infra_release/flutter/$engineRevision/ios/artifacts.zip'")); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('profile URL', () async { |
| final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| command.produceFlutterPodspec(BuildMode.profile, outputDirectory); |
| |
| final File expectedPodspec = outputDirectory.childFile('Flutter.podspec'); |
| final String podspecContents = expectedPodspec.readAsStringSync(); |
| expect(podspecContents, contains("'$storageBaseUrl/flutter_infra_release/flutter/$engineRevision/ios-profile/artifacts.zip'")); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('release URL', () async { |
| final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| command.produceFlutterPodspec(BuildMode.release, outputDirectory); |
| |
| final File expectedPodspec = outputDirectory.childFile('Flutter.podspec'); |
| final String podspecContents = expectedPodspec.readAsStringSync(); |
| expect(podspecContents, contains("'$storageBaseUrl/flutter_infra_release/flutter/$engineRevision/ios-release/artifacts.zip'")); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| group('build macos-framework', () { |
| group('podspec', () { |
| const String engineRevision = '0123456789abcdef'; |
| late Cache cache; |
| |
| setUp(() { |
| final Directory rootOverride = memoryFileSystem.directory('cache'); |
| cache = Cache.test( |
| rootOverride: rootOverride, |
| platform: fakePlatform, |
| fileSystem: memoryFileSystem, |
| processManager: FakeProcessManager.any(), |
| ); |
| rootOverride.childDirectory('bin').childDirectory('internal').childFile('engine.version') |
| ..createSync(recursive: true) |
| ..writeAsStringSync(engineRevision); |
| }); |
| |
| testUsingContext('version unknown', () async { |
| const String frameworkVersion = '0.0.0-unknown'; |
| final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion(frameworkVersion: frameworkVersion); |
| |
| final BuildMacOSFrameworkCommand command = BuildMacOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| |
| expect(() => command.produceFlutterPodspec(BuildMode.debug, outputDirectory), |
| throwsToolExit(message: 'Detected version is $frameworkVersion')); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('throws when not on a released version', () async { |
| const String frameworkVersion = 'v1.13.10+hotfix-pre.2'; |
| const GitTagVersion gitTagVersion = GitTagVersion( |
| x: 1, |
| y: 13, |
| z: 10, |
| hotfix: 13, |
| commits: 2, |
| ); |
| final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion( |
| gitTagVersion: gitTagVersion, |
| frameworkVersion: frameworkVersion, |
| ); |
| |
| final BuildMacOSFrameworkCommand command = BuildMacOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| |
| expect(() => command.produceFlutterPodspec(BuildMode.debug, outputDirectory), |
| throwsToolExit(message: 'Detected version is $frameworkVersion')); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('throws when license not found', () async { |
| final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion( |
| gitTagVersion: const GitTagVersion( |
| x: 1, |
| y: 13, |
| z: 10, |
| hotfix: 13, |
| commits: 0, |
| ), |
| ); |
| |
| final BuildMacOSFrameworkCommand command = BuildMacOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| |
| expect(() => command.produceFlutterPodspec(BuildMode.debug, outputDirectory), |
| throwsToolExit(message: 'Could not find license')); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| group('is created', () { |
| const String frameworkVersion = 'v1.13.11+hotfix.13'; |
| const String licenseText = 'This is the license!'; |
| |
| setUp(() { |
| // cache.getLicenseFile() relies on the flutter root being set. |
| Cache.flutterRoot ??= getFlutterRoot(); |
| cache.getLicenseFile() |
| ..createSync(recursive: true) |
| ..writeAsStringSync(licenseText); |
| }); |
| |
| group('on master channel', () { |
| testUsingContext('created when forced', () async { |
| const GitTagVersion gitTagVersion = GitTagVersion( |
| x: 1, |
| y: 13, |
| z: 11, |
| hotfix: 13, |
| commits: 100, |
| ); |
| final FakeFlutterVersion fakeFlutterVersion = FakeFlutterVersion( |
| gitTagVersion: gitTagVersion, |
| frameworkVersion: frameworkVersion, |
| ); |
| |
| final BuildMacOSFrameworkCommand command = BuildMacOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| command.produceFlutterPodspec(BuildMode.debug, outputDirectory, force: true); |
| |
| final File expectedPodspec = outputDirectory.childFile('FlutterMacOS.podspec'); |
| expect(expectedPodspec.existsSync(), isTrue); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| }); |
| |
| group('not on master channel', () { |
| late FakeFlutterVersion fakeFlutterVersion; |
| setUp(() { |
| const GitTagVersion gitTagVersion = GitTagVersion( |
| x: 1, |
| y: 13, |
| z: 11, |
| hotfix: 13, |
| commits: 0, |
| ); |
| fakeFlutterVersion = FakeFlutterVersion( |
| gitTagVersion: gitTagVersion, |
| frameworkVersion: frameworkVersion, |
| ); |
| }); |
| |
| testUsingContext('contains license and version', () async { |
| final BuildMacOSFrameworkCommand command = BuildMacOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| command.produceFlutterPodspec(BuildMode.debug, outputDirectory); |
| |
| final File expectedPodspec = outputDirectory.childFile('FlutterMacOS.podspec'); |
| final String podspecContents = expectedPodspec.readAsStringSync(); |
| expect(podspecContents, contains("'1.13.1113'")); |
| expect(podspecContents, contains('# $frameworkVersion')); |
| expect(podspecContents, contains(licenseText)); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('debug URL', () async { |
| final BuildMacOSFrameworkCommand command = BuildMacOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| command.produceFlutterPodspec(BuildMode.debug, outputDirectory); |
| |
| final File expectedPodspec = outputDirectory.childFile('FlutterMacOS.podspec'); |
| final String podspecContents = expectedPodspec.readAsStringSync(); |
| expect(podspecContents, contains("'$storageBaseUrl/flutter_infra_release/flutter/$engineRevision/darwin-x64/artifacts.zip'")); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('profile URL', () async { |
| final BuildMacOSFrameworkCommand command = BuildMacOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| command.produceFlutterPodspec(BuildMode.profile, outputDirectory); |
| |
| final File expectedPodspec = outputDirectory.childFile('FlutterMacOS.podspec'); |
| final String podspecContents = expectedPodspec.readAsStringSync(); |
| expect(podspecContents, contains("'$storageBaseUrl/flutter_infra_release/flutter/$engineRevision/darwin-x64-profile/artifacts.zip'")); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('release URL', () async { |
| final BuildMacOSFrameworkCommand command = BuildMacOSFrameworkCommand( |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| platform: fakePlatform, |
| flutterVersion: fakeFlutterVersion, |
| cache: cache, |
| verboseHelp: false, |
| ); |
| command.produceFlutterPodspec(BuildMode.release, outputDirectory); |
| |
| final File expectedPodspec = outputDirectory.childFile('FlutterMacOS.podspec'); |
| final String podspecContents = expectedPodspec.readAsStringSync(); |
| expect(podspecContents, contains("'$storageBaseUrl/flutter_infra_release/flutter/$engineRevision/darwin-x64-release/artifacts.zip'")); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFileSystem, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| group('XCFrameworks', () { |
| late MemoryFileSystem fileSystem; |
| late FakeProcessManager fakeProcessManager; |
| |
| setUp(() { |
| fileSystem = MemoryFileSystem.test(); |
| fakeProcessManager = FakeProcessManager.empty(); |
| }); |
| |
| testWithoutContext('created', () async { |
| final Directory frameworkA = fileSystem.directory('FrameworkA.framework')..createSync(); |
| final Directory frameworkB = fileSystem.directory('FrameworkB.framework')..createSync(); |
| final Directory output = fileSystem.directory('output'); |
| |
| fakeProcessManager.addCommand(FakeCommand( |
| command: <String>[ |
| 'xcrun', |
| 'xcodebuild', |
| '-create-xcframework', |
| '-framework', |
| frameworkA.path, |
| '-framework', |
| frameworkB.path, |
| '-output', |
| output.childDirectory('Combine.xcframework').path, |
| ], |
| )); |
| await BuildFrameworkCommand.produceXCFramework( |
| <Directory>[frameworkA, frameworkB], |
| 'Combine', |
| output, |
| fakeProcessManager, |
| ); |
| expect(fakeProcessManager, hasNoRemainingExpectations); |
| }); |
| |
| testWithoutContext('created with symbols', () async { |
| final Directory parentA = fileSystem.directory('FrameworkA')..createSync(); |
| final File bcsymbolmapA = parentA.childFile('ABC123.bcsymbolmap')..createSync(); |
| final File dSYMA = parentA.childFile('FrameworkA.framework.dSYM')..createSync(); |
| final Directory frameworkA = parentA.childDirectory('FrameworkA.framework')..createSync(); |
| |
| final Directory parentB = fileSystem.directory('FrameworkB')..createSync(); |
| final File bcsymbolmapB = parentB.childFile('ZYX987.bcsymbolmap')..createSync(); |
| final File dSYMB = parentB.childFile('FrameworkB.framework.dSYM')..createSync(); |
| final Directory frameworkB = parentB.childDirectory('FrameworkB.framework')..createSync(); |
| final Directory output = fileSystem.directory('output'); |
| |
| fakeProcessManager.addCommand(FakeCommand( |
| command: <String>[ |
| 'xcrun', |
| 'xcodebuild', |
| '-create-xcframework', |
| '-framework', |
| frameworkA.path, |
| '-debug-symbols', |
| bcsymbolmapA.path, |
| '-debug-symbols', |
| dSYMA.path, |
| '-framework', |
| frameworkB.path, |
| '-debug-symbols', |
| bcsymbolmapB.path, |
| '-debug-symbols', |
| dSYMB.path, |
| '-output', |
| output.childDirectory('Combine.xcframework').path, |
| ], |
| )); |
| await BuildFrameworkCommand.produceXCFramework( |
| <Directory>[frameworkA, frameworkB], |
| 'Combine', |
| output, |
| fakeProcessManager, |
| ); |
| expect(fakeProcessManager, hasNoRemainingExpectations); |
| }); |
| }); |
| } |