Unverified Commit 186765b3 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] cleanups to plugin test cases (#67242)

Removes usage of global variables, expands documentation, and fixes some formatting inconsistencies. Increased test coverage for android plugin to prove it can determine the embedding version.
parent 304e2c57
......@@ -7,7 +7,6 @@ import 'package:yaml/yaml.dart';
import 'base/common.dart';
import 'base/file_system.dart';
import 'globals.dart' as globals;
/// Constant for 'pluginClass' key in plugin maps.
const String kPluginClass = 'pluginClass';
......@@ -38,18 +37,22 @@ class AndroidPlugin extends PluginPlatform {
@required this.package,
@required this.pluginClass,
@required this.pluginPath,
});
@required FileSystem fileSystem,
}) : _fileSystem = fileSystem;
factory AndroidPlugin.fromYaml(String name, YamlMap yaml, String pluginPath) {
factory AndroidPlugin.fromYaml(String name, YamlMap yaml, String pluginPath, FileSystem fileSystem) {
assert(validate(yaml));
return AndroidPlugin(
name: name,
package: yaml['package'] as String,
pluginClass: yaml['pluginClass'] as String,
pluginPath: pluginPath,
fileSystem: fileSystem,
);
}
final FileSystem _fileSystem;
static bool validate(YamlMap yaml) {
if (yaml == null) {
return false;
......@@ -91,7 +94,7 @@ class AndroidPlugin extends PluginPlatform {
Set<String> _getSupportedEmbeddings() {
assert(pluginPath != null);
final Set<String> supportedEmbeddings = <String>{};
final String baseMainPath = globals.fs.path.join(
final String baseMainPath = _fileSystem.path.join(
pluginPath,
'android',
'src',
......@@ -99,16 +102,16 @@ class AndroidPlugin extends PluginPlatform {
);
final List<String> mainClassCandidates = <String>[
globals.fs.path.join(
_fileSystem.path.join(
baseMainPath,
'java',
package.replaceAll('.', globals.fs.path.separator),
package.replaceAll('.', _fileSystem.path.separator),
'$pluginClass.java',
),
globals.fs.path.join(
_fileSystem.path.join(
baseMainPath,
'kotlin',
package.replaceAll('.', globals.fs.path.separator),
package.replaceAll('.', _fileSystem.path.separator),
'$pluginClass.kt',
)
];
......@@ -116,7 +119,7 @@ class AndroidPlugin extends PluginPlatform {
File mainPluginClass;
bool mainClassFound = false;
for (final String mainClassCandidate in mainClassCandidates) {
mainPluginClass = globals.fs.file(mainClassCandidate);
mainPluginClass = _fileSystem.file(mainClassCandidate);
if (mainPluginClass.existsSync()) {
mainClassFound = true;
break;
......@@ -132,15 +135,7 @@ class AndroidPlugin extends PluginPlatform {
);
}
String mainClassContent;
try {
mainClassContent = mainPluginClass.readAsStringSync();
} on FileSystemException {
throwToolExit(
"Couldn't read file ${mainPluginClass.path} even though it exists. "
'Please verify that this file has read permission and try again.'
);
}
final String mainClassContent = mainPluginClass.readAsStringSync();
if (mainClassContent
.contains('io.flutter.embedding.engine.plugins.FlutterPlugin')) {
supportedEmbeddings.add('2');
......@@ -167,7 +162,7 @@ class IOSPlugin extends PluginPlatform {
});
factory IOSPlugin.fromYaml(String name, YamlMap yaml) {
assert(validate(yaml));
assert(validate(yaml)); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/67241
return IOSPlugin(
name: name,
classPrefix: '',
......
......@@ -68,16 +68,17 @@ class Plugin {
String name,
String path,
YamlMap pluginYaml,
List<String> dependencies,
) {
List<String> dependencies, {
@required FileSystem fileSystem,
}) {
final List<String> errors = validatePluginYaml(pluginYaml);
if (errors.isNotEmpty) {
throwToolExit('Invalid plugin specification $name.\n${errors.join('\n')}');
}
if (pluginYaml != null && pluginYaml['platforms'] != null) {
return Plugin._fromMultiPlatformYaml(name, path, pluginYaml, dependencies);
return Plugin._fromMultiPlatformYaml(name, path, pluginYaml, dependencies, fileSystem);
}
return Plugin._fromLegacyYaml(name, path, pluginYaml, dependencies);
return Plugin._fromLegacyYaml(name, path, pluginYaml, dependencies, fileSystem);
}
factory Plugin._fromMultiPlatformYaml(
......@@ -85,6 +86,7 @@ class Plugin {
String path,
dynamic pluginYaml,
List<String> dependencies,
FileSystem fileSystem,
) {
assert (pluginYaml != null && pluginYaml['platforms'] != null,
'Invalid multi-platform plugin specification $name.');
......@@ -100,6 +102,7 @@ class Plugin {
name,
platformsYaml[AndroidPlugin.kConfigKey] as YamlMap,
path,
fileSystem,
);
}
......@@ -141,6 +144,7 @@ class Plugin {
String path,
dynamic pluginYaml,
List<String> dependencies,
FileSystem fileSystem,
) {
final Map<String, PluginPlatform> platforms = <String, PluginPlatform>{};
final String pluginClass = pluginYaml['pluginClass'] as String;
......@@ -152,6 +156,7 @@ class Plugin {
package: pluginYaml['androidPackage'] as String,
pluginClass: pluginClass,
pluginPath: path,
fileSystem: fileSystem,
);
}
......@@ -332,6 +337,7 @@ Plugin _pluginFromPackage(String name, Uri packageRoot) {
packageRootPath,
flutterConfig['plugin'] as YamlMap,
dependencies == null ? <String>[] : <String>[...dependencies.keys.cast<String>()],
fileSystem: globals.fs,
);
}
......
// 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/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/platform_plugins.dart';
import '../src/common.dart';
void main() {
testWithoutContext('AndroidPlugin throws tool exit if the plugin main class can not be found', () {
final FileSystem fileSystem = MemoryFileSystem.test();
final AndroidPlugin androidPlugin = AndroidPlugin(
name: 'pluginA',
package: 'com.company',
pluginClass: 'PluginA',
pluginPath: '.pub_cache/plugin_a',
fileSystem: fileSystem,
);
expect(() => androidPlugin.toMap(), throwsToolExit(
message: "The plugin `pluginA` doesn't have a main class defined in "
'.pub_cache/plugin_a/android/src/main/java/com/company/PluginA.java '
'or .pub_cache/plugin_a/android/src/main/kotlin/com/company/PluginA.kt'
));
});
testWithoutContext('AndroidPlugin parses embedding version 2 from the Java search path', () {
final FileSystem fileSystem = MemoryFileSystem.test();
final AndroidPlugin androidPlugin = AndroidPlugin(
name: 'pluginA',
package: 'com.company',
pluginClass: 'PluginA',
pluginPath: '.pub_cache/plugin_a',
fileSystem: fileSystem,
);
fileSystem.file('.pub_cache/plugin_a/android/src/main/java/com/company/PluginA.java')
..createSync(recursive: true)
..writeAsStringSync('io.flutter.embedding.engine.plugins.FlutterPlugin');
expect(androidPlugin.toMap(), <String, Object>{
'name': 'pluginA',
'package': 'com.company',
'class': 'PluginA',
'supportsEmbeddingV1': false,
'supportsEmbeddingV2': true,
});
});
testWithoutContext('AndroidPlugin parses embedding version 1 from the Java search path', () {
final FileSystem fileSystem = MemoryFileSystem.test();
final AndroidPlugin androidPlugin = AndroidPlugin(
name: 'pluginA',
package: 'com.company',
pluginClass: 'PluginA',
pluginPath: '.pub_cache/plugin_a',
fileSystem: fileSystem,
);
fileSystem.file('.pub_cache/plugin_a/android/src/main/java/com/company/PluginA.java')
..createSync(recursive: true)
..writeAsStringSync('some.other.string');
expect(androidPlugin.toMap(), <String, Object>{
'name': 'pluginA',
'package': 'com.company',
'class': 'PluginA',
'supportsEmbeddingV1': true,
'supportsEmbeddingV2': false,
});
});
testWithoutContext('AndroidPlugin parses embedding version 2 from the Kotlin search path', () {
final FileSystem fileSystem = MemoryFileSystem.test();
final AndroidPlugin androidPlugin = AndroidPlugin(
name: 'pluginA',
package: 'com.company',
pluginClass: 'PluginA',
pluginPath: '.pub_cache/plugin_a',
fileSystem: fileSystem,
);
fileSystem.file('.pub_cache/plugin_a/android/src/main/kotlin/com/company/PluginA.kt')
..createSync(recursive: true)
..writeAsStringSync('io.flutter.embedding.engine.plugins.FlutterPlugin');
expect(androidPlugin.toMap(), <String, Object>{
'name': 'pluginA',
'package': 'com.company',
'class': 'PluginA',
'supportsEmbeddingV1': false,
'supportsEmbeddingV2': true,
});
});
testWithoutContext('AndroidPlugin parses embedding version 1 from the Kotlin search path', () {
final FileSystem fileSystem = MemoryFileSystem.test();
final AndroidPlugin androidPlugin = AndroidPlugin(
name: 'pluginA',
package: 'com.company',
pluginClass: 'PluginA',
pluginPath: '.pub_cache/plugin_a',
fileSystem: fileSystem,
);
fileSystem.file('.pub_cache/plugin_a/android/src/main/kotlin/com/company/PluginA.kt')
..createSync(recursive: true)
..writeAsStringSync('some.other.string');
expect(androidPlugin.toMap(), <String, Object>{
'name': 'pluginA',
'package': 'com.company',
'class': 'PluginA',
'supportsEmbeddingV1': true,
'supportsEmbeddingV2': false,
});
});
}
// 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/file.dart';
import 'package:flutter_tools/src/platform_plugins.dart';
import 'package:mockito/mockito.dart';
import 'package:path/path.dart' as p;
import '../src/common.dart';
import '../src/context.dart';
void main() {
group('AndroidPlugin', () {
MockFileSystem mockFileSystem;
MockPathContext pathContext;
setUp(() {
pathContext = MockPathContext();
when(pathContext.separator).thenReturn('/');
mockFileSystem = MockFileSystem();
when(mockFileSystem.path).thenReturn(pathContext);
});
testUsingContext("throws tool exit if the plugin main class can't be read", () {
when(pathContext.join('.pub_cache/plugin_a', 'android', 'src', 'main'))
.thenReturn('.pub_cache/plugin_a/android/src/main');
when(pathContext.join('.pub_cache/plugin_a/android/src/main', 'java', 'com/company', 'PluginA.java'))
.thenReturn('.pub_cache/plugin_a/android/src/main/java/com/company/PluginA.java');
when(pathContext.join('.pub_cache/plugin_a/android/src/main', 'kotlin', 'com/company', 'PluginA.kt'))
.thenReturn('.pub_cache/plugin_a/android/src/main/kotlin/com/company/PluginA.kt');
final MockFile pluginJavaMainClass = MockFile();
when(pluginJavaMainClass.existsSync()).thenReturn(true);
when(pluginJavaMainClass.readAsStringSync(encoding: anyNamed('encoding'))).thenThrow(const FileSystemException());
when(mockFileSystem.file('.pub_cache/plugin_a/android/src/main/java/com/company/PluginA.java'))
.thenReturn(pluginJavaMainClass);
final MockFile pluginKotlinMainClass = MockFile();
when(pluginKotlinMainClass.existsSync()).thenReturn(false);
when(mockFileSystem.file('.pub_cache/plugin_a/android/src/main/kotlin/com/company/PluginA.kt'))
.thenReturn(pluginKotlinMainClass);
expect(() {
AndroidPlugin(
name: 'pluginA',
package: 'com.company',
pluginClass: 'PluginA',
pluginPath: '.pub_cache/plugin_a',
).toMap();
}, throwsToolExit(
message: "Couldn't read file null even though it exists. "
'Please verify that this file has read permission and try again.'
));
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
});
}
class MockFile extends Mock implements File {}
class MockFileSystem extends Mock implements FileSystem {}
class MockPathContext extends Mock implements p.Context {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment