blob: 523162cad38d208143a61871033c8a909bec2517 [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 'package:flutter_migrate/src/base/common.dart';
import 'package:flutter_migrate/src/base/file_system.dart';
import 'package:flutter_migrate/src/base/logger.dart';
import 'package:flutter_migrate/src/base/project.dart';
import 'package:flutter_migrate/src/base/signals.dart';
import 'package:flutter_migrate/src/compute.dart';
import 'package:flutter_migrate/src/environment.dart';
import 'package:flutter_migrate/src/flutter_project_metadata.dart';
import 'package:flutter_migrate/src/migrate_logger.dart';
import 'package:flutter_migrate/src/result.dart';
import 'package:flutter_migrate/src/utils.dart';
import 'package:path/path.dart';
import 'package:process/process.dart';
import 'environment_test.dart';
import 'src/common.dart';
import 'src/context.dart';
import 'src/test_utils.dart';
import 'test_data/migrate_project.dart';
void main() {
late FileSystem fileSystem;
late BufferLogger logger;
late MigrateUtils utils;
late MigrateContext context;
late MigrateResult result;
late Directory targetFlutterDirectory;
late Directory newerTargetFlutterDirectory;
late Directory currentDir;
late FlutterToolsEnvironment environment;
late ProcessManager processManager;
late FakeProcessManager envProcessManager;
late String separator;
const String oldSdkRevision = '5391447fae6209bb21a89e6a5a6583cac1af9b4b';
const String newSdkRevision = '85684f9300908116a78138ea4c6036c35c9a1236';
Future<void> setUpFullEnv() async {
fileSystem = LocalFileSystem.test(signals: LocalSignals.instance);
currentDir = createResolvedTempDirectorySync('current_app.');
logger = BufferLogger.test();
processManager = const LocalProcessManager();
utils = MigrateUtils(
logger: logger,
fileSystem: fileSystem,
processManager: processManager,
);
await MigrateProject.installProject('version:1.22.6_stable', currentDir);
final FlutterProjectFactory flutterFactory = FlutterProjectFactory();
final FlutterProject flutterProject =
flutterFactory.fromDirectory(currentDir);
result = MigrateResult.empty();
final MigrateLogger migrateLogger =
MigrateLogger(logger: logger, verbose: true);
migrateLogger.start();
separator = isWindows ? r'\\' : '/';
envProcessManager = FakeProcessManager('''
{
"FlutterProject.directory": "/Users/test/flutter",
"FlutterProject.metadataFile": "/Users/test/flutter/.metadata",
"FlutterProject.android.exists": false,
"FlutterProject.ios.exists": false,
"FlutterProject.web.exists": false,
"FlutterProject.macos.exists": false,
"FlutterProject.linux.exists": false,
"FlutterProject.windows.exists": false,
"FlutterProject.fuchsia.exists": false,
"FlutterProject.android.isKotlin": false,
"FlutterProject.ios.isSwift": false,
"FlutterProject.isModule": false,
"FlutterProject.isPlugin": false,
"FlutterProject.manifest.appname": "test_app_name",
"FlutterVersion.frameworkRevision": "4e181f012c717777681862e4771af5a941774bb9",
"Platform.operatingSystem": "macos",
"Platform.isAndroid": true,
"Platform.isIOS": false,
"Platform.isWindows": ${isWindows ? 'true' : 'false'},
"Platform.isMacOS": ${isMacOS ? 'true' : 'false'},
"Platform.isFuchsia": false,
"Platform.pathSeparator": "$separator",
"Cache.flutterRoot": "/Users/test/flutter"
}
''');
environment =
await FlutterToolsEnvironment.initializeFlutterToolsEnvironment(
envProcessManager, logger);
context = MigrateContext(
flutterProject: flutterProject,
skippedPrefixes: <String>{},
fileSystem: fileSystem,
migrateLogger: migrateLogger,
migrateUtils: utils,
environment: environment,
);
targetFlutterDirectory =
createResolvedTempDirectorySync('targetFlutterDir.');
newerTargetFlutterDirectory =
createResolvedTempDirectorySync('newerTargetFlutterDir.');
await context.migrateUtils
.cloneFlutter(oldSdkRevision, targetFlutterDirectory.absolute.path);
await context.migrateUtils.cloneFlutter(
newSdkRevision, newerTargetFlutterDirectory.absolute.path);
}
group('MigrateFlutterProject', () {
setUp(() async {
await setUpFullEnv();
});
tearDown(() async {
tryToDelete(targetFlutterDirectory);
tryToDelete(newerTargetFlutterDirectory);
});
testUsingContext('MigrateTargetFlutterProject creates', () async {
final Directory workingDir =
createResolvedTempDirectorySync('migrate_working_dir.');
final Directory targetDir =
createResolvedTempDirectorySync('target_dir.');
result.generatedTargetTemplateDirectory = targetDir;
workingDir.createSync(recursive: true);
final MigrateTargetFlutterProject targetProject =
MigrateTargetFlutterProject(
path: null,
directory: targetDir,
name: 'base',
androidLanguage: 'java',
iosLanguage: 'objc',
);
await targetProject.createProject(
context,
result,
oldSdkRevision, //targetRevision
targetFlutterDirectory, //targetFlutterDirectory
);
expect(targetDir.childFile('pubspec.yaml').existsSync(), true);
expect(
targetDir
.childDirectory('android')
.childFile('build.gradle')
.existsSync(),
true);
}, timeout: const Timeout(Duration(seconds: 500)));
testUsingContext('MigrateBaseFlutterProject creates', () async {
final Directory workingDir =
createResolvedTempDirectorySync('migrate_working_dir.');
final Directory baseDir = createResolvedTempDirectorySync('base_dir.');
result.generatedBaseTemplateDirectory = baseDir;
workingDir.createSync(recursive: true);
final MigrateBaseFlutterProject baseProject = MigrateBaseFlutterProject(
path: null,
directory: baseDir,
name: 'base',
androidLanguage: 'java',
iosLanguage: 'objc',
);
await baseProject.createProject(
context,
result,
<String>[oldSdkRevision], //revisionsList
<String, List<MigratePlatformConfig>>{
oldSdkRevision: <MigratePlatformConfig>[
MigratePlatformConfig(component: FlutterProjectComponent.android),
MigratePlatformConfig(component: FlutterProjectComponent.ios)
],
}, //revisionToConfigs
oldSdkRevision, //fallbackRevision
oldSdkRevision, //targetRevision
targetFlutterDirectory, //targetFlutterDirectory
);
expect(baseDir.childFile('pubspec.yaml').existsSync(), true);
expect(
baseDir
.childDirectory('android')
.childFile('build.gradle')
.existsSync(),
true);
}, timeout: const Timeout(Duration(seconds: 500)));
testUsingContext('Migrate___FlutterProject skips when path exists',
() async {
final Directory workingDir =
createResolvedTempDirectorySync('migrate_working_dir.');
final Directory targetDir =
createResolvedTempDirectorySync('target_dir.');
final Directory baseDir = createResolvedTempDirectorySync('base_dir.');
result.generatedTargetTemplateDirectory = targetDir;
result.generatedBaseTemplateDirectory = baseDir;
workingDir.createSync(recursive: true);
final MigrateBaseFlutterProject baseProject = MigrateBaseFlutterProject(
path: 'some_existing_base_path',
directory: baseDir,
name: 'base',
androidLanguage: 'java',
iosLanguage: 'objc',
);
final MigrateTargetFlutterProject targetProject =
MigrateTargetFlutterProject(
path: 'some_existing_target_path',
directory: targetDir,
name: 'base',
androidLanguage: 'java',
iosLanguage: 'objc',
);
await baseProject.createProject(
context,
result,
<String>[oldSdkRevision], //revisionsList
<String, List<MigratePlatformConfig>>{
oldSdkRevision: <MigratePlatformConfig>[
MigratePlatformConfig(component: FlutterProjectComponent.android),
MigratePlatformConfig(component: FlutterProjectComponent.ios)
],
}, //revisionToConfigs
oldSdkRevision, //fallbackRevision
oldSdkRevision, //targetRevision
targetFlutterDirectory, //targetFlutterDirectory
);
expect(baseDir.childFile('pubspec.yaml').existsSync(), false);
expect(
baseDir
.childDirectory('android')
.childFile('build.gradle')
.existsSync(),
false);
await targetProject.createProject(
context,
result,
oldSdkRevision, //revisionsList
targetFlutterDirectory, //targetFlutterDirectory
);
expect(targetDir.childFile('pubspec.yaml').existsSync(), false);
expect(
targetDir
.childDirectory('android')
.childFile('build.gradle')
.existsSync(),
false);
}, timeout: const Timeout(Duration(seconds: 500)));
},
// TODO(stuartmorgan): These should not be unit tests, see
// https://github.com/flutter/flutter/issues/121257.
skip: 'TODO: Speed up, or move to another type of test');
group('MigrateRevisions', () {
setUp(() async {
fileSystem = LocalFileSystem.test(signals: LocalSignals.instance);
currentDir = createResolvedTempDirectorySync('current_app.');
logger = BufferLogger.test();
utils = MigrateUtils(
logger: logger,
fileSystem: fileSystem,
processManager: const LocalProcessManager(),
);
await MigrateProject.installProject('version:1.22.6_stable', currentDir);
final FlutterProjectFactory flutterFactory = FlutterProjectFactory();
final FlutterProject flutterProject =
flutterFactory.fromDirectory(currentDir);
result = MigrateResult.empty();
final MigrateLogger migrateLogger =
MigrateLogger(logger: logger, verbose: true);
migrateLogger.start();
context = MigrateContext(
flutterProject: flutterProject,
skippedPrefixes: <String>{},
fileSystem: fileSystem,
migrateLogger: migrateLogger,
migrateUtils: utils,
environment: environment,
);
});
testUsingContext('extracts revisions underpopulated metadata', () async {
final MigrateRevisions revisions = MigrateRevisions(
context: context,
baseRevision: oldSdkRevision,
allowFallbackBaseRevision: true,
platforms: <SupportedPlatform>[
SupportedPlatform.android,
SupportedPlatform.ios
],
environment: environment,
);
expect(revisions.revisionsList, <String>[oldSdkRevision]);
expect(revisions.fallbackRevision, oldSdkRevision);
expect(revisions.metadataRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(revisions.config.unmanagedFiles.isEmpty, false);
expect(revisions.config.platformConfigs.isEmpty, false);
expect(revisions.config.platformConfigs.length, 3);
expect(
revisions.config.platformConfigs
.containsKey(FlutterProjectComponent.root),
true);
expect(
revisions.config.platformConfigs
.containsKey(FlutterProjectComponent.android),
true);
expect(
revisions.config.platformConfigs
.containsKey(FlutterProjectComponent.ios),
true);
});
testUsingContext('extracts revisions full metadata', () async {
final File metadataFile =
context.flutterProject.directory.childFile('.metadata');
if (metadataFile.existsSync()) {
if (!tryToDelete(metadataFile)) {
// TODO(garyq): Inaccessible .metadata on windows.
// Skip test for now. We should reneable.
return;
}
}
metadataFile.createSync(recursive: true);
metadataFile.writeAsStringSync('''
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
channel: unknown
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
base_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
- platform: android
create_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
base_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
- platform: ios
create_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
base_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
- platform: linux
create_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
base_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
- platform: macos
create_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
base_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
- platform: web
create_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
base_revision: 9b2d32b605630f28625709ebd9d78ab3016b2bf6
- platform: windows
create_revision: 36427af29421f406ac95ff55ea31d1dc49a45b5f
base_revision: 36427af29421f406ac95ff55ea31d1dc49a45b5f
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'blah.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
''', flush: true);
final MigrateRevisions revisions = MigrateRevisions(
context: context,
baseRevision: oldSdkRevision,
allowFallbackBaseRevision: true,
platforms: <SupportedPlatform>[
SupportedPlatform.android,
SupportedPlatform.ios
],
environment: environment,
);
expect(revisions.revisionsList, <String>[oldSdkRevision]);
expect(revisions.fallbackRevision, oldSdkRevision);
expect(revisions.metadataRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(revisions.config.unmanagedFiles.isEmpty, false);
expect(revisions.config.unmanagedFiles.length, 3);
expect(revisions.config.unmanagedFiles.contains('lib/main.dart'), true);
expect(revisions.config.unmanagedFiles.contains('blah.dart'), true);
expect(
revisions.config.unmanagedFiles
.contains('ios/Runner.xcodeproj/project.pbxproj'),
true);
expect(revisions.config.platformConfigs.length, 7);
expect(
revisions.config.platformConfigs
.containsKey(FlutterProjectComponent.root),
true);
expect(
revisions.config.platformConfigs
.containsKey(FlutterProjectComponent.android),
true);
expect(
revisions.config.platformConfigs
.containsKey(FlutterProjectComponent.ios),
true);
expect(
revisions.config.platformConfigs
.containsKey(FlutterProjectComponent.linux),
true);
expect(
revisions.config.platformConfigs
.containsKey(FlutterProjectComponent.macos),
true);
expect(
revisions.config.platformConfigs
.containsKey(FlutterProjectComponent.web),
true);
expect(
revisions.config.platformConfigs
.containsKey(FlutterProjectComponent.windows),
true);
expect(
revisions.config.platformConfigs[FlutterProjectComponent.root]!
.createRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.android]!
.createRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.ios]!
.createRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.linux]!
.createRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.macos]!
.createRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.web]!
.createRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.windows]!
.createRevision,
'36427af29421f406ac95ff55ea31d1dc49a45b5f');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.root]!
.baseRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.android]!
.baseRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.ios]!
.baseRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.linux]!
.baseRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.macos]!
.baseRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.web]!
.baseRevision,
'9b2d32b605630f28625709ebd9d78ab3016b2bf6');
expect(
revisions.config.platformConfigs[FlutterProjectComponent.windows]!
.baseRevision,
'36427af29421f406ac95ff55ea31d1dc49a45b5f');
});
},
// TODO(stuartmorgan): These should not be unit tests, see
// https://github.com/flutter/flutter/issues/121257.
skip: 'TODO: Speed up, or move to another type of test');
group('project operations', () {
setUp(() async {
await setUpFullEnv();
});
tearDown(() async {
tryToDelete(targetFlutterDirectory);
tryToDelete(newerTargetFlutterDirectory);
});
testUsingContext('diff base and target', () async {
final Directory workingDir =
createResolvedTempDirectorySync('migrate_working_dir.');
final Directory targetDir =
createResolvedTempDirectorySync('target_dir.');
final Directory baseDir = createResolvedTempDirectorySync('base_dir.');
result.generatedTargetTemplateDirectory = targetDir;
result.generatedBaseTemplateDirectory = baseDir;
workingDir.createSync(recursive: true);
final MigrateBaseFlutterProject baseProject = MigrateBaseFlutterProject(
path: null,
directory: baseDir,
name: 'base',
androidLanguage: 'java',
iosLanguage: 'objc',
);
final MigrateTargetFlutterProject targetProject =
MigrateTargetFlutterProject(
path: null,
directory: targetDir,
name: 'base',
androidLanguage: 'java',
iosLanguage: 'objc',
);
await baseProject.createProject(
context,
result,
<String>[oldSdkRevision], //revisionsList
<String, List<MigratePlatformConfig>>{
oldSdkRevision: <MigratePlatformConfig>[
MigratePlatformConfig(component: FlutterProjectComponent.android),
MigratePlatformConfig(component: FlutterProjectComponent.ios)
],
}, //revisionToConfigs
oldSdkRevision, //fallbackRevision
oldSdkRevision, //targetRevision
targetFlutterDirectory, //targetFlutterDirectory
);
expect(baseDir.childFile('pubspec.yaml').existsSync(), true);
expect(
baseDir
.childDirectory('android')
.childFile('build.gradle')
.existsSync(),
true);
await targetProject.createProject(
context,
result,
newSdkRevision, //revisionsList
newerTargetFlutterDirectory, //targetFlutterDirectory
);
expect(targetDir.childFile('pubspec.yaml').existsSync(), true);
expect(
targetDir
.childDirectory('android')
.childFile('build.gradle')
.existsSync(),
true);
final Map<String, DiffResult> diffResults =
await baseProject.diff(context, targetProject);
final Map<String, DiffResult> canonicalizedDiffResults =
<String, DiffResult>{};
for (final MapEntry<String, DiffResult> entry in diffResults.entries) {
canonicalizedDiffResults[canonicalize(entry.key)] = entry.value;
}
result.diffMap.addAll(diffResults);
List<String> expectedFiles = <String>[
'.metadata',
'ios/Runner.xcworkspace/contents.xcworkspacedata',
'ios/Runner/AppDelegate.h',
'ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png',
'ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png',
'ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md',
'ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json',
'ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png',
'ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png',
'ios/Runner/Base.lproj/LaunchScreen.storyboard',
'ios/Runner/Base.lproj/Main.storyboard',
'ios/Runner/main.m',
'ios/Runner/AppDelegate.m',
'ios/Runner/Info.plist',
'ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata',
'ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme',
'ios/Flutter/Debug.xcconfig',
'ios/Flutter/Release.xcconfig',
'ios/Flutter/AppFrameworkInfo.plist',
'pubspec.yaml',
'.gitignore',
'android/base_android.iml',
'android/app/build.gradle',
'android/app/src/main/res/mipmap-mdpi/ic_launcher.png',
'android/app/src/main/res/mipmap-hdpi/ic_launcher.png',
'android/app/src/main/res/drawable/launch_background.xml',
'android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png',
'android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png',
'android/app/src/main/res/values/styles.xml',
'android/app/src/main/res/mipmap-xhdpi/ic_launcher.png',
'android/app/src/main/AndroidManifest.xml',
'android/app/src/main/java/com/example/base/MainActivity.java',
'android/local.properties',
'android/gradle/wrapper/gradle-wrapper.jar',
'android/gradle/wrapper/gradle-wrapper.properties',
'android/gradlew',
'android/build.gradle',
'android/gradle.properties',
'android/gradlew.bat',
'android/settings.gradle',
'base.iml',
'.idea/runConfigurations/main_dart.xml',
'.idea/libraries/Dart_SDK.xml',
'.idea/libraries/KotlinJavaRuntime.xml',
'.idea/libraries/Flutter_for_Android.xml',
'.idea/workspace.xml',
'.idea/modules.xml',
];
expectedFiles =
List<String>.from(expectedFiles.map((String e) => canonicalize(e)));
expect(diffResults.length, 62);
expect(expectedFiles.length, 62);
for (final String diffResultPath in canonicalizedDiffResults.keys) {
expect(expectedFiles.contains(diffResultPath), true);
}
// Spot check diffs on key files:
expect(
canonicalizedDiffResults[canonicalize('android/build.gradle')]!.diff,
contains(r'''
@@ -1,18 +1,20 @@
buildscript {
+ ext.kotlin_version = '1.6.10'
repositories {
google()
- jcenter()
+ mavenCentral()
}'''));
expect(
canonicalizedDiffResults[canonicalize('android/build.gradle')]!.diff,
contains(r'''
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
+ classpath 'com.android.tools.build:gradle:7.1.2'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}'''));
expect(
canonicalizedDiffResults[canonicalize('android/build.gradle')]!.diff,
contains(r'''
allprojects {
repositories {
google()
- jcenter()
+ mavenCentral()
}
}'''));
expect(
canonicalizedDiffResults[
canonicalize('android/app/src/main/AndroidManifest.xml')]!
.diff,
contains(r'''
@@ -1,39 +1,34 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.base">
-
- <!-- The INTERNET permission is required for development. Specifically,
- flutter needs it to communicate with the running application
- to allow setting breakpoints, to provide hot reload, etc.
- -->
- <uses-permission android:name="android.permission.INTERNET"/>
-
- <!-- io.flutter.app.FlutterApplication is an android.app.Application that
- calls FlutterMain.startInitialization(this); in its onCreate method.
- In most cases you can leave this as-is, but you if you want to provide
- additional functionality it is fine to subclass or reimplement
- FlutterApplication and put your custom class here. -->
- <application
- android:name="io.flutter.app.FlutterApplication"
+ <application
android:label="base"
+ android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
+ android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
- android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
+ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
- <!-- This keeps the window background of the activity showing
- until Flutter renders its first frame. It can be removed if
- there is no splash screen (such as the default splash screen
- defined in @style/LaunchTheme). -->
+ <!-- Specifies an Android theme to apply to this Activity as soon as
+ the Android process has started. This theme is visible to the user
+ while the Flutter UI initializes. After that, this theme continues
+ to determine the Window background behind the Flutter UI. -->
<meta-data
- android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
- android:value="true" />
+ android:name="io.flutter.embedding.android.NormalTheme"
+ android:resource="@style/NormalTheme"
+ />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <!-- Don't delete the meta-data below.
+ This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
+ <meta-data
+ android:name="flutterEmbedding"
+ android:value="2" />
</application>
</manifest>'''));
}, timeout: const Timeout(Duration(seconds: 500)));
testUsingContext('Merge succeeds', () async {
final Directory workingDir =
createResolvedTempDirectorySync('migrate_working_dir.');
final Directory targetDir =
createResolvedTempDirectorySync('target_dir.');
final Directory baseDir = createResolvedTempDirectorySync('base_dir.');
result.generatedTargetTemplateDirectory = targetDir;
result.generatedBaseTemplateDirectory = baseDir;
workingDir.createSync(recursive: true);
final MigrateBaseFlutterProject baseProject = MigrateBaseFlutterProject(
path: null,
directory: baseDir,
name: 'base',
androidLanguage: 'java',
iosLanguage: 'objc',
);
final MigrateTargetFlutterProject targetProject =
MigrateTargetFlutterProject(
path: null,
directory: targetDir,
name: 'base',
androidLanguage: 'java',
iosLanguage: 'objc',
);
await baseProject.createProject(
context,
result,
<String>[oldSdkRevision], //revisionsList
<String, List<MigratePlatformConfig>>{
oldSdkRevision: <MigratePlatformConfig>[
MigratePlatformConfig(component: FlutterProjectComponent.android),
MigratePlatformConfig(component: FlutterProjectComponent.ios)
],
}, //revisionToConfigs
oldSdkRevision, //fallbackRevision
oldSdkRevision, //targetRevision
targetFlutterDirectory, //targetFlutterDirectory
);
expect(baseDir.childFile('pubspec.yaml').existsSync(), true);
expect(baseDir.childFile('.metadata').existsSync(), true);
expect(
baseDir
.childDirectory('android')
.childFile('build.gradle')
.existsSync(),
true);
await targetProject.createProject(
context,
result,
newSdkRevision, //revisionsList
newerTargetFlutterDirectory, //targetFlutterDirectory
);
expect(targetDir.childFile('pubspec.yaml').existsSync(), true);
expect(targetDir.childFile('.metadata').existsSync(), true);
expect(
targetDir
.childDirectory('android')
.childFile('build.gradle')
.existsSync(),
true);
result.diffMap.addAll(await baseProject.diff(context, targetProject));
await MigrateFlutterProject.merge(
context,
result,
baseProject,
targetProject,
<String>[], // unmanagedFiles
<String>[], // unmanagedDirectories
false, // preferTwoWayMerge
);
List<String> expectedMergedPaths = <String>[
'.metadata',
'ios/Runner/Info.plist',
'ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata',
'ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme',
'ios/Flutter/AppFrameworkInfo.plist',
'pubspec.yaml',
'.gitignore',
'android/app/build.gradle',
'android/app/src/main/res/values/styles.xml',
'android/app/src/main/AndroidManifest.xml',
'android/gradle/wrapper/gradle-wrapper.properties',
'android/build.gradle',
];
expectedMergedPaths = List<String>.from(
expectedMergedPaths.map((String e) => canonicalize(e)));
expect(result.mergeResults.length, 12);
expect(expectedMergedPaths.length, 12);
for (final MergeResult mergeResult in result.mergeResults) {
expect(
expectedMergedPaths.contains(canonicalize(mergeResult.localPath)),
true);
}
expect(result.mergeResults[0].exitCode, 0);
expect(result.mergeResults[1].exitCode, 0);
expect(result.mergeResults[2].exitCode, 0);
expect(result.mergeResults[3].exitCode, 0);
expect(result.mergeResults[4].exitCode, 0);
expect(result.mergeResults[5].exitCode, 0);
expect(result.mergeResults[6].exitCode, 0);
expect(result.mergeResults[7].exitCode, 0);
expect(result.mergeResults[8].exitCode, 0);
expect(result.mergeResults[9].exitCode, 0);
expect(result.mergeResults[10].exitCode, 0);
expect(result.mergeResults[11].exitCode, 0);
expect(result.mergeResults[0].hasConflict, false);
expect(result.mergeResults[1].hasConflict, false);
expect(result.mergeResults[2].hasConflict, false);
expect(result.mergeResults[3].hasConflict, false);
expect(result.mergeResults[4].hasConflict, false);
expect(result.mergeResults[5].hasConflict, false);
expect(result.mergeResults[6].hasConflict, false);
expect(result.mergeResults[7].hasConflict, false);
expect(result.mergeResults[8].hasConflict, false);
expect(result.mergeResults[9].hasConflict, false);
expect(result.mergeResults[10].hasConflict, false);
expect(result.mergeResults[11].hasConflict, false);
}, timeout: const Timeout(Duration(seconds: 500)));
},
// TODO(stuartmorgan): These should not be unit tests, see
// https://github.com/flutter/flutter/issues/121257.
skip: 'TODO: Speed up, or move to another type of test');
}