mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
FlutterProject refactoring and test coverage (#20296)
This commit is contained in:
parent
e60087a1a7
commit
3c83c52697
@ -200,22 +200,26 @@ distributionUrl=https\\://services.gradle.org/distributions/gradle-$gradleVersio
|
||||
}
|
||||
}
|
||||
|
||||
/// Overwrite android/local.properties in the specified Flutter project, if needed.
|
||||
/// Overwrite local.properties in the specified Flutter project's Android
|
||||
/// sub-project, if needed.
|
||||
///
|
||||
/// Throws, if `pubspec.yaml` or Android SDK cannot be located.
|
||||
/// Throws tool exit, if `pubspec.yaml` is invalid.
|
||||
///
|
||||
/// If [requireSdk] is `true` this will fail with a tool-exit if no Android Sdk
|
||||
/// If [requireSdk] is `true` this will fail with a tool exit if no Android Sdk
|
||||
/// is found.
|
||||
Future<void> updateLocalProperties({
|
||||
@required FlutterProject project,
|
||||
BuildInfo buildInfo,
|
||||
bool requireAndroidSdk = true,
|
||||
}) async {
|
||||
if (project.manifest == null) {
|
||||
throwToolExit('Invalid `pubspec.yaml`');
|
||||
}
|
||||
if (requireAndroidSdk && androidSdk == null) {
|
||||
throwToolExit('Unable to locate Android SDK. Please run `flutter doctor` for more details.');
|
||||
}
|
||||
|
||||
final File localProperties = project.androidLocalPropertiesFile;
|
||||
final File localProperties = project.android.localPropertiesFile;
|
||||
bool changed = false;
|
||||
|
||||
SettingsFile settings;
|
||||
|
||||
@ -15,7 +15,6 @@ import '../base/process.dart';
|
||||
import '../base/process_manager.dart';
|
||||
import '../base/utils.dart';
|
||||
import '../build_info.dart';
|
||||
import '../bundle.dart' as bundle;
|
||||
import '../cache.dart';
|
||||
import '../flutter_manifest.dart';
|
||||
import '../globals.dart';
|
||||
@ -28,25 +27,6 @@ String flutterFrameworkDir(BuildMode mode) {
|
||||
return fs.path.normalize(fs.path.dirname(artifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, mode)));
|
||||
}
|
||||
|
||||
/// Writes default Xcode properties files in the Flutter project at [projectPath],
|
||||
/// if project is an iOS project and such files are out of date or do not
|
||||
/// already exist.
|
||||
Future<void> generateXcodeProperties({FlutterProject project}) async {
|
||||
if (project.manifest.isModule ||
|
||||
project.ios.directory.existsSync()) {
|
||||
if (!Cache.instance.fileOlderThanToolsStamp(project.generatedXcodePropertiesFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await updateGeneratedXcodeProperties(
|
||||
project: project,
|
||||
buildInfo: BuildInfo.debug,
|
||||
targetOverride: bundle.defaultMainPath,
|
||||
previewDart2: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes or rewrites Xcode property files with the specified information.
|
||||
///
|
||||
/// targetOverride: Optional parameter, if null or unspecified the default value
|
||||
@ -119,7 +99,7 @@ Future<void> updateGeneratedXcodeProperties({
|
||||
localsBuffer.writeln('TRACK_WIDGET_CREATION=true');
|
||||
}
|
||||
|
||||
final File generatedXcodePropertiesFile = project.generatedXcodePropertiesFile;
|
||||
final File generatedXcodePropertiesFile = project.ios.generatedXcodePropertiesFile;
|
||||
generatedXcodePropertiesFile.createSync(recursive: true);
|
||||
generatedXcodePropertiesFile.writeAsStringSync(localsBuffer.toString());
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin>
|
||||
};
|
||||
|
||||
final String javaSourcePath = fs.path.join(
|
||||
project.androidPluginRegistrantHost.path,
|
||||
project.android.pluginRegistrantHost.path,
|
||||
'src',
|
||||
'main',
|
||||
'java',
|
||||
@ -247,8 +247,8 @@ Future<void> _writeIOSPluginRegistrant(FlutterProject project, List<Plugin> plug
|
||||
'plugins': iosPlugins,
|
||||
};
|
||||
|
||||
final String registryDirectory = project.iosPluginRegistrantHost.path;
|
||||
if (project.manifest.isModule) {
|
||||
final String registryDirectory = project.ios.pluginRegistrantHost.path;
|
||||
if (project.isModule) {
|
||||
final String registryClassesDirectory = fs.path.join(registryDirectory, 'Classes');
|
||||
_renderTemplateToFile(
|
||||
_iosPluginRegistrantPodspecTemplate,
|
||||
|
||||
@ -5,8 +5,11 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'android/gradle.dart' as gradle;
|
||||
import 'base/file_system.dart';
|
||||
import 'build_info.dart';
|
||||
import 'bundle.dart' as bundle;
|
||||
import 'cache.dart';
|
||||
import 'flutter_manifest.dart';
|
||||
@ -16,21 +19,27 @@ import 'template.dart';
|
||||
|
||||
/// Represents the contents of a Flutter project at the specified [directory].
|
||||
///
|
||||
/// Instances should be treated as immutable snapshots, to be replaced by new
|
||||
/// instances on changes to `pubspec.yaml` files.
|
||||
/// [FlutterManifest] information is read from `pubspec.yaml` and
|
||||
/// `example/pubspec.yaml` files on construction of a [FlutterProject] instance.
|
||||
/// The constructed instance carries an immutable snapshot representation of the
|
||||
/// presence and content of those files. Accordingly, [FlutterProject] instances
|
||||
/// should be discarded upon changes to the `pubspec.yaml` files, but can be
|
||||
/// used across changes to other files, as no other file-level information is
|
||||
/// cached.
|
||||
class FlutterProject {
|
||||
FlutterProject._(this.directory, this.manifest, this._exampleManifest);
|
||||
@visibleForTesting
|
||||
FlutterProject(this.directory, this.manifest, this._exampleManifest);
|
||||
|
||||
/// Returns a future that completes with a FlutterProject view of the given directory.
|
||||
static Future<FlutterProject> fromDirectory(Directory directory) async {
|
||||
final FlutterManifest manifest = await FlutterManifest.createFromPath(
|
||||
directory.childFile(bundle.defaultManifestPath).path,
|
||||
);
|
||||
final Directory exampleDirectory = directory.childDirectory('example');
|
||||
final Directory exampleDirectory = _exampleDirectory(directory);
|
||||
final FlutterManifest exampleManifest = await FlutterManifest.createFromPath(
|
||||
exampleDirectory.childFile(bundle.defaultManifestPath).path,
|
||||
);
|
||||
return new FlutterProject._(directory, manifest, exampleManifest);
|
||||
return new FlutterProject(directory, manifest, exampleManifest);
|
||||
}
|
||||
|
||||
/// Returns a future that completes with a FlutterProject view of the current directory.
|
||||
@ -73,83 +82,56 @@ class FlutterProject {
|
||||
}
|
||||
|
||||
/// The iOS sub project of this project.
|
||||
IosProject get ios => new IosProject(directory.childDirectory('ios'));
|
||||
IosProject get ios => new IosProject._(this);
|
||||
|
||||
/// The Android sub project of this project.
|
||||
AndroidProject get android {
|
||||
if (manifest.isModule) {
|
||||
return new AndroidProject(directory.childDirectory('.android'));
|
||||
}
|
||||
return new AndroidProject(directory.childDirectory('android'));
|
||||
}
|
||||
|
||||
/// The generated AndroidModule sub project of this module project.
|
||||
AndroidModuleProject get androidModule => new AndroidModuleProject(directory.childDirectory('.android'));
|
||||
|
||||
/// The generated IosModule sub project of this module project.
|
||||
IosModuleProject get iosModule => new IosModuleProject(directory.childDirectory('.ios'));
|
||||
|
||||
File get androidLocalPropertiesFile {
|
||||
return directory
|
||||
.childDirectory(manifest.isModule ? '.android' : 'android')
|
||||
.childFile('local.properties');
|
||||
}
|
||||
|
||||
File get generatedXcodePropertiesFile {
|
||||
return directory
|
||||
.childDirectory(manifest.isModule ? '.ios' : 'ios')
|
||||
.childDirectory('Flutter')
|
||||
.childFile('Generated.xcconfig');
|
||||
}
|
||||
AndroidProject get android => new AndroidProject._(this);
|
||||
|
||||
File get flutterPluginsFile => directory.childFile('.flutter-plugins');
|
||||
|
||||
Directory get androidPluginRegistrantHost {
|
||||
return manifest.isModule
|
||||
? directory.childDirectory('.android').childDirectory('Flutter')
|
||||
: directory.childDirectory('android').childDirectory('app');
|
||||
}
|
||||
|
||||
Directory get iosPluginRegistrantHost {
|
||||
// In a module create the GeneratedPluginRegistrant as a pod to be included
|
||||
// from a hosting app.
|
||||
// For a non-module create the GeneratedPluginRegistrant as source files
|
||||
// directly in the iOS project.
|
||||
return manifest.isModule
|
||||
? directory.childDirectory('.ios').childDirectory('Flutter').childDirectory('FlutterPluginRegistrant')
|
||||
: directory.childDirectory('ios').childDirectory('Runner');
|
||||
}
|
||||
|
||||
/// The example sub-project of this project.
|
||||
FlutterProject get example => new FlutterProject._(_exampleDirectory, _exampleManifest, FlutterManifest.empty());
|
||||
FlutterProject get example => new FlutterProject(
|
||||
_exampleDirectory(directory),
|
||||
_exampleManifest,
|
||||
FlutterManifest.empty(),
|
||||
);
|
||||
|
||||
/// True, if this project has an example application
|
||||
bool get hasExampleApp => _exampleDirectory.childFile('pubspec.yaml').existsSync();
|
||||
bool get isModule => manifest != null && manifest.isModule;
|
||||
|
||||
/// True, if this project has an example application.
|
||||
bool get hasExampleApp => _exampleDirectory(directory).existsSync();
|
||||
|
||||
/// The directory that will contain the example if an example exists.
|
||||
Directory get _exampleDirectory => directory.childDirectory('example');
|
||||
static Directory _exampleDirectory(Directory directory) => directory.childDirectory('example');
|
||||
|
||||
/// Generates project files necessary to make Gradle builds work on Android
|
||||
/// and CocoaPods+Xcode work on iOS, for app and module projects only.
|
||||
Future<void> ensureReadyForPlatformSpecificTooling() async {
|
||||
if (!directory.existsSync() || hasExampleApp) {
|
||||
if (!directory.existsSync() || hasExampleApp)
|
||||
return;
|
||||
}
|
||||
if (manifest.isModule) {
|
||||
await androidModule.ensureReadyForPlatformSpecificTooling(this);
|
||||
await iosModule.ensureReadyForPlatformSpecificTooling();
|
||||
}
|
||||
await xcode.generateXcodeProperties(project: this);
|
||||
await android.ensureReadyForPlatformSpecificTooling();
|
||||
await ios.ensureReadyForPlatformSpecificTooling();
|
||||
await injectPlugins(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the contents of the ios/ folder of a Flutter project.
|
||||
/// Represents the iOS sub-project of a Flutter project.
|
||||
///
|
||||
/// Instances will reflect the contents of the `ios/` sub-folder of
|
||||
/// Flutter applications and the `.ios/` sub-folder of Flutter modules.
|
||||
class IosProject {
|
||||
static final RegExp _productBundleIdPattern = new RegExp(r'^\s*PRODUCT_BUNDLE_IDENTIFIER\s*=\s*(.*);\s*$');
|
||||
IosProject(this.directory);
|
||||
|
||||
final Directory directory;
|
||||
IosProject._(this.parent);
|
||||
|
||||
/// The parent of this project.
|
||||
final FlutterProject parent;
|
||||
|
||||
/// The directory of this project.
|
||||
Directory get directory => parent.directory.childDirectory(isModule ? '.ios' : 'ios');
|
||||
|
||||
/// True, if the parent Flutter project is a module.
|
||||
bool get isModule => parent.isModule;
|
||||
|
||||
/// The xcode config file for [mode].
|
||||
File xcodeConfigFor(String mode) => directory.childDirectory('Flutter').childFile('$mode.xcconfig');
|
||||
@ -167,33 +149,55 @@ class IosProject {
|
||||
final File projectFile = directory.childDirectory('Runner.xcodeproj').childFile('project.pbxproj');
|
||||
return _firstMatchInFile(projectFile, _productBundleIdPattern).then((Match match) => match?.group(1));
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the contents of the .ios/ folder of a Flutter module
|
||||
/// project.
|
||||
class IosModuleProject {
|
||||
IosModuleProject(this.directory);
|
||||
|
||||
final Directory directory;
|
||||
|
||||
Future<void> ensureReadyForPlatformSpecificTooling() async {
|
||||
if (_shouldRegenerate()) {
|
||||
if (isModule && _shouldRegenerateFromTemplate()) {
|
||||
final Template template = new Template.fromName(fs.path.join('module', 'ios'));
|
||||
template.render(directory, <String, dynamic>{}, printStatusWhenWriting: false);
|
||||
}
|
||||
if (!directory.existsSync())
|
||||
return;
|
||||
if (Cache.instance.fileOlderThanToolsStamp(generatedXcodePropertiesFile)) {
|
||||
await xcode.updateGeneratedXcodeProperties(
|
||||
project: parent,
|
||||
buildInfo: BuildInfo.debug,
|
||||
targetOverride: bundle.defaultMainPath,
|
||||
previewDart2: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool _shouldRegenerate() {
|
||||
bool _shouldRegenerateFromTemplate() {
|
||||
return Cache.instance.fileOlderThanToolsStamp(directory.childFile('podhelper.rb'));
|
||||
}
|
||||
|
||||
File get generatedXcodePropertiesFile => directory.childDirectory('Flutter').childFile('Generated.xcconfig');
|
||||
|
||||
Directory get pluginRegistrantHost {
|
||||
return isModule
|
||||
? directory.childDirectory('Flutter').childDirectory('FlutterPluginRegistrant')
|
||||
: directory.childDirectory('Runner');
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the contents of the android/ folder of a Flutter project.
|
||||
/// Represents the Android sub-project of a Flutter project.
|
||||
///
|
||||
/// Instances will reflect the contents of the `android/` sub-folder of
|
||||
/// Flutter applications and the `.android/` sub-folder of Flutter modules.
|
||||
class AndroidProject {
|
||||
static final RegExp _applicationIdPattern = new RegExp('^\\s*applicationId\\s+[\'\"](.*)[\'\"]\\s*\$');
|
||||
static final RegExp _groupPattern = new RegExp('^\\s*group\\s+[\'\"](.*)[\'\"]\\s*\$');
|
||||
|
||||
AndroidProject(this.directory);
|
||||
AndroidProject._(this.parent);
|
||||
|
||||
/// The parent of this project.
|
||||
final FlutterProject parent;
|
||||
|
||||
/// The directory of this project.
|
||||
Directory get directory => parent.directory.childDirectory(isModule ? '.android' : 'android');
|
||||
|
||||
/// True, if the parent Flutter project is a module.
|
||||
bool get isModule => parent.isModule;
|
||||
|
||||
File get gradleManifestFile {
|
||||
return isUsingGradle()
|
||||
@ -211,8 +215,6 @@ class AndroidProject {
|
||||
return directory.childFile('build.gradle').existsSync();
|
||||
}
|
||||
|
||||
final Directory directory;
|
||||
|
||||
Future<String> applicationId() {
|
||||
final File gradleFile = directory.childDirectory('app').childFile('build.gradle');
|
||||
return _firstMatchInFile(gradleFile, _applicationIdPattern).then((Match match) => match?.group(1));
|
||||
@ -222,32 +224,31 @@ class AndroidProject {
|
||||
final File gradleFile = directory.childFile('build.gradle');
|
||||
return _firstMatchInFile(gradleFile, _groupPattern).then((Match match) => match?.group(1));
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the contents of the .android/ folder of a Flutter module project.
|
||||
class AndroidModuleProject {
|
||||
AndroidModuleProject(this.directory);
|
||||
|
||||
final Directory directory;
|
||||
|
||||
Future<void> ensureReadyForPlatformSpecificTooling(FlutterProject project) async {
|
||||
if (_shouldRegenerate()) {
|
||||
Future<void> ensureReadyForPlatformSpecificTooling() async {
|
||||
if (isModule && _shouldRegenerateFromTemplate()) {
|
||||
final Template template = new Template.fromName(fs.path.join('module', 'android'));
|
||||
template.render(
|
||||
directory,
|
||||
<String, dynamic>{
|
||||
'androidIdentifier': project.manifest.androidPackage,
|
||||
'androidIdentifier': parent.manifest.androidPackage,
|
||||
},
|
||||
printStatusWhenWriting: false,
|
||||
);
|
||||
gradle.injectGradleWrapper(directory);
|
||||
}
|
||||
await gradle.updateLocalProperties(project: project, requireAndroidSdk: false);
|
||||
if (!directory.existsSync())
|
||||
return;
|
||||
await gradle.updateLocalProperties(project: parent, requireAndroidSdk: false);
|
||||
}
|
||||
|
||||
bool _shouldRegenerate() {
|
||||
bool _shouldRegenerateFromTemplate() {
|
||||
return Cache.instance.fileOlderThanToolsStamp(directory.childFile('build.gradle'));
|
||||
}
|
||||
|
||||
File get localPropertiesFile => directory.childFile('local.properties');
|
||||
|
||||
Directory get pluginRegistrantHost => directory.childDirectory(isModule ? 'Flutter' : 'app');
|
||||
}
|
||||
|
||||
/// Asynchronously returns the first line-based match for [regExp] in [file].
|
||||
|
||||
@ -3,12 +3,14 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:flutter_tools/src/base/context.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/flutter_manifest.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
|
||||
import 'src/context.dart';
|
||||
|
||||
void main() {
|
||||
@ -23,73 +25,151 @@ void main() {
|
||||
(await FlutterProject.fromPath(directory.path)).directory.absolute.path,
|
||||
directory.absolute.path,
|
||||
);
|
||||
expect(
|
||||
(await FlutterProject.current()).directory.absolute.path,
|
||||
fs.currentDirectory.absolute.path,
|
||||
);
|
||||
});
|
||||
|
||||
group('ensure ready for platform-specific tooling', () {
|
||||
testInMemory('does nothing, if project is not created', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
final FlutterProject project = new FlutterProject(
|
||||
fs.directory('not_created'),
|
||||
FlutterManifest.empty(),
|
||||
FlutterManifest.empty(),
|
||||
);
|
||||
await project.ensureReadyForPlatformSpecificTooling();
|
||||
expect(project.directory.existsSync(), isFalse);
|
||||
});
|
||||
testInMemory('does nothing in plugin or package root project', () async {
|
||||
final FlutterProject project = await aPluginProject();
|
||||
final FlutterProject project = aPluginProject();
|
||||
await project.ensureReadyForPlatformSpecificTooling();
|
||||
expect(project.ios.directory.childFile('Runner/GeneratedPluginRegistrant.h').existsSync(), isFalse);
|
||||
expect(project.android.directory.childFile(
|
||||
'app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
|
||||
).existsSync(), isFalse);
|
||||
expect(project.ios.directory.childFile('Flutter/Generated.xcconfig').existsSync(), isFalse);
|
||||
expect(project.android.directory.childFile('local.properties').existsSync(), isFalse);
|
||||
});
|
||||
testInMemory('injects plugins', () async {
|
||||
final FlutterProject project = await aProjectWithIos();
|
||||
testInMemory('injects plugins for iOS', () async {
|
||||
final FlutterProject project = someProject();
|
||||
await project.ensureReadyForPlatformSpecificTooling();
|
||||
expect(project.ios.directory.childFile('Runner/GeneratedPluginRegistrant.h').existsSync(), isTrue);
|
||||
});
|
||||
testInMemory('generates Xcode configuration', () async {
|
||||
final FlutterProject project = await aProjectWithIos();
|
||||
testInMemory('generates Xcode configuration for iOS', () async {
|
||||
final FlutterProject project = someProject();
|
||||
await project.ensureReadyForPlatformSpecificTooling();
|
||||
expect(project.ios.directory.childFile('Flutter/Generated.xcconfig').existsSync(), isTrue);
|
||||
});
|
||||
testInMemory('injects plugins for Android', () async {
|
||||
final FlutterProject project = someProject();
|
||||
await project.ensureReadyForPlatformSpecificTooling();
|
||||
expect(project.android.directory.childFile(
|
||||
'app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
|
||||
).existsSync(), isTrue);
|
||||
});
|
||||
testInMemory('updates local properties for Android', () async {
|
||||
final FlutterProject project = someProject();
|
||||
await project.ensureReadyForPlatformSpecificTooling();
|
||||
expect(project.android.directory.childFile('local.properties').existsSync(), isTrue);
|
||||
});
|
||||
testInMemory('creates Android library in module', () async {
|
||||
final FlutterProject project = aModuleProject();
|
||||
await project.ensureReadyForPlatformSpecificTooling();
|
||||
expect(project.android.directory.childFile('template_content').existsSync(), isTrue);
|
||||
expect(project.android.directory.childFile('local.properties').existsSync(), isTrue);
|
||||
expect(project.android.directory.childFile(
|
||||
'Flutter/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
|
||||
).existsSync(), isTrue);
|
||||
});
|
||||
testInMemory('creates iOS pod in module', () async {
|
||||
final FlutterProject project = aModuleProject();
|
||||
await project.ensureReadyForPlatformSpecificTooling();
|
||||
final Directory flutter = project.ios.directory.childDirectory('Flutter');
|
||||
expect(flutter.childFile('template_content').existsSync(), isTrue);
|
||||
expect(flutter.childFile('Generated.xcconfig').existsSync(), isTrue);
|
||||
expect(flutter.childFile(
|
||||
'FlutterPluginRegistrant/Classes/GeneratedPluginRegistrant.h',
|
||||
).existsSync(), isTrue);
|
||||
expect(flutter.childFile(
|
||||
'FlutterPluginRegistrant/Classes/GeneratedPluginRegistrant.m',
|
||||
).existsSync(), isTrue);
|
||||
});
|
||||
});
|
||||
|
||||
group('module status', () {
|
||||
testInMemory('is known for module', () async {
|
||||
final FlutterProject project = aModuleProject();
|
||||
expect(project.isModule, isTrue);
|
||||
expect(project.android.isModule, isTrue);
|
||||
expect(project.ios.isModule, isTrue);
|
||||
expect(project.android.directory.path, startsWith('module_project/.android'));
|
||||
expect(project.ios.directory.path, startsWith('module_project/.ios'));
|
||||
});
|
||||
testInMemory('is known for non-module', () async {
|
||||
final FlutterProject project = someProject();
|
||||
expect(project.isModule, isFalse);
|
||||
expect(project.android.isModule, isFalse);
|
||||
expect(project.ios.isModule, isFalse);
|
||||
expect(project.android.directory.path, startsWith('some_project/android'));
|
||||
expect(project.ios.directory.path, startsWith('some_project/ios'));
|
||||
});
|
||||
});
|
||||
|
||||
group('example', () {
|
||||
testInMemory('exists for plugin', () async {
|
||||
final FlutterProject project = aPluginProject();
|
||||
expect(project.hasExampleApp, isTrue);
|
||||
});
|
||||
testInMemory('does not exist for non-plugin', () async {
|
||||
final FlutterProject project = someProject();
|
||||
expect(project.hasExampleApp, isFalse);
|
||||
});
|
||||
});
|
||||
|
||||
group('organization names set', () {
|
||||
testInMemory('is empty, if project not created', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
final FlutterProject project = someProject();
|
||||
expect(await project.organizationNames(), isEmpty);
|
||||
});
|
||||
testInMemory('is empty, if no platform folders exist', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
final FlutterProject project = someProject();
|
||||
project.directory.createSync();
|
||||
expect(await project.organizationNames(), isEmpty);
|
||||
});
|
||||
testInMemory('is populated from iOS bundle identifier', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
final FlutterProject project = someProject();
|
||||
addIosWithBundleId(project.directory, 'io.flutter.someProject');
|
||||
expect(await project.organizationNames(), <String>['io.flutter']);
|
||||
});
|
||||
testInMemory('is populated from Android application ID', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
final FlutterProject project = someProject();
|
||||
addAndroidWithApplicationId(project.directory, 'io.flutter.someproject');
|
||||
expect(await project.organizationNames(), <String>['io.flutter']);
|
||||
});
|
||||
testInMemory('is populated from iOS bundle identifier in plugin example', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
final FlutterProject project = someProject();
|
||||
addIosWithBundleId(project.example.directory, 'io.flutter.someProject');
|
||||
expect(await project.organizationNames(), <String>['io.flutter']);
|
||||
});
|
||||
testInMemory('is populated from Android application ID in plugin example', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
final FlutterProject project = someProject();
|
||||
addAndroidWithApplicationId(project.example.directory, 'io.flutter.someproject');
|
||||
expect(await project.organizationNames(), <String>['io.flutter']);
|
||||
});
|
||||
testInMemory('is populated from Android group in plugin', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
final FlutterProject project = someProject();
|
||||
addAndroidWithGroup(project.directory, 'io.flutter.someproject');
|
||||
expect(await project.organizationNames(), <String>['io.flutter']);
|
||||
});
|
||||
testInMemory('is singleton, if sources agree', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
final FlutterProject project = someProject();
|
||||
addIosWithBundleId(project.directory, 'io.flutter.someProject');
|
||||
addAndroidWithApplicationId(project.directory, 'io.flutter.someproject');
|
||||
expect(await project.organizationNames(), <String>['io.flutter']);
|
||||
});
|
||||
testInMemory('is non-singleton, if sources disagree', () async {
|
||||
final FlutterProject project = await someProject();
|
||||
final FlutterProject project = someProject();
|
||||
addIosWithBundleId(project.directory, 'io.flutter.someProject');
|
||||
addAndroidWithApplicationId(project.directory, 'io.clutter.someproject');
|
||||
expect(
|
||||
@ -101,30 +181,88 @@ void main() {
|
||||
});
|
||||
}
|
||||
|
||||
Future<FlutterProject> someProject() => FlutterProject.fromPath('some_project');
|
||||
|
||||
Future<FlutterProject> aProjectWithIos() {
|
||||
final Directory directory = fs.directory('ios_project');
|
||||
directory.childFile('pubspec.yaml').createSync(recursive: true);
|
||||
FlutterProject someProject() {
|
||||
final Directory directory = fs.directory('some_project');
|
||||
directory.childFile('.packages').createSync(recursive: true);
|
||||
directory.childDirectory('ios').createSync(recursive: true);
|
||||
return FlutterProject.fromDirectory(directory);
|
||||
directory.childDirectory('android').createSync(recursive: true);
|
||||
return new FlutterProject(
|
||||
directory,
|
||||
FlutterManifest.empty(),
|
||||
FlutterManifest.empty(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<FlutterProject> aPluginProject() {
|
||||
final Directory directory = fs.directory('plugin_project/example');
|
||||
directory.childFile('pubspec.yaml').createSync(recursive: true);
|
||||
directory.childFile('.packages').createSync(recursive: true);
|
||||
FlutterProject aPluginProject() {
|
||||
final Directory directory = fs.directory('plugin_project');
|
||||
directory.childDirectory('ios').createSync(recursive: true);
|
||||
return FlutterProject.fromDirectory(directory.parent);
|
||||
directory.childDirectory('android').createSync(recursive: true);
|
||||
directory.childDirectory('example').createSync(recursive: true);
|
||||
return new FlutterProject(
|
||||
directory,
|
||||
FlutterManifest.mock(const <String, dynamic>{
|
||||
'flutter': <String, dynamic>{
|
||||
'plugin': <String, dynamic>{}
|
||||
}
|
||||
}),
|
||||
FlutterManifest.empty(),
|
||||
);
|
||||
}
|
||||
|
||||
FlutterProject aModuleProject() {
|
||||
final Directory directory = fs.directory('module_project');
|
||||
directory.childFile('.packages').createSync(recursive: true);
|
||||
return new FlutterProject(
|
||||
directory,
|
||||
FlutterManifest.mock(const <String, dynamic>{
|
||||
'flutter': <String, dynamic>{
|
||||
'module': <String, dynamic>{
|
||||
'androidPackage': 'com.example'
|
||||
}
|
||||
}
|
||||
}),
|
||||
FlutterManifest.empty(),
|
||||
);
|
||||
}
|
||||
|
||||
void testInMemory(String description, Future<Null> testMethod()) {
|
||||
Cache.flutterRoot = 'flutter';
|
||||
final FileSystem fs = new MemoryFileSystem();
|
||||
// Pretend we have a Flutter module project template.
|
||||
fs.directory(Cache.flutterRoot)
|
||||
.childDirectory('packages')
|
||||
.childDirectory('flutter_tools')
|
||||
.childDirectory('templates')
|
||||
.childDirectory('module')
|
||||
.childDirectory('android')
|
||||
.childFile('template_content.copy.tmpl')
|
||||
.createSync(recursive: true);
|
||||
fs.directory(Cache.flutterRoot)
|
||||
.childDirectory('packages')
|
||||
.childDirectory('flutter_tools')
|
||||
.childDirectory('templates')
|
||||
.childDirectory('module')
|
||||
.childDirectory('ios')
|
||||
.childDirectory('Flutter.tmpl')
|
||||
.childFile('template_content.copy.tmpl')
|
||||
.createSync(recursive: true);
|
||||
|
||||
// Sets up cache in a test execution context where `fs` is the file system.
|
||||
Cache cacheCreator() {
|
||||
final Cache cache = new Cache(rootOverride: fs.directory('flutter'));
|
||||
cache.getArtifactDirectory('gradle_wrapper')
|
||||
.childDirectory('gradle')
|
||||
.childDirectory('wrapper')
|
||||
.childFile('gradle-wrapper.properties')
|
||||
.createSync(recursive: true);
|
||||
return cache;
|
||||
}
|
||||
testUsingContext(
|
||||
description,
|
||||
testMethod,
|
||||
overrides: <Type, Generator>{
|
||||
FileSystem: () => new MemoryFileSystem(),
|
||||
FileSystem: () => fs,
|
||||
Cache: cacheCreator,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user