Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/plugin_platform_interface/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
## NEXT
## 2.1.3

* Minor fixes for new analysis options.
* Adds additional tests for `PlatformInterface` and `MockPlatformInterfaceMixin`.
* Modifies `PlatformInterface` to use an expando for detecting if a customer
tries to implement PlatformInterface using `implements` rather than `extends`.
This ensures that `verify` will continue to work as advertized after
https://github.com/dart-lang/language/issues/2020 is implemented.

## 2.1.2

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,20 @@ abstract class PlatformInterface {
/// derived classes.
///
/// @param token The same, non-`const` `Object` that will be passed to `verify`.
PlatformInterface({required Object token}) : _instanceToken = token;
PlatformInterface({required Object token}) {
_instanceTokens[this] = token;
}

final Object? _instanceToken;
/// Expando mapping instances of PlatformInterface to their associated tokens.
/// The reason this is not simply a private field of type `Object?` is because
/// as of the implementation of field promotion in Dart
/// (https://github.com/dart-lang/language/issues/2020), it is a runtime error
/// to invoke a private member that is mocked in another library. The expando
/// approach prevents [_verify] from triggering this runtime exception when
/// encountering an implementation that uses `implements` rather than
/// `extends`. This in turn allows [_verify] to throw an [AssertionError] (as
/// documented).
static final Expando<Object> _instanceTokens = Expando<Object>();

/// Ensures that the platform instance was constructed with a non-`const` token
/// that matches the provided token and throws [AssertionError] if not.
Expand Down Expand Up @@ -89,10 +100,10 @@ abstract class PlatformInterface {
return;
}
if (preventConstObject &&
identical(instance._instanceToken, const Object())) {
identical(_instanceTokens[instance], const Object())) {
throw AssertionError('`const Object()` cannot be used as the token.');
}
if (!identical(token, instance._instanceToken)) {
if (!identical(token, _instanceTokens[instance])) {
throw AssertionError(
'Platform interfaces must not be implemented with `implements`');
}
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin_platform_interface/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+
# be done when absolutely necessary and after the ecosystem has already migrated to 2.X.Y version
# that is forward compatible with 3.0.0 (ideally the ecosystem have migrated to depend on:
# `plugin_platform_interface: >=2.X.Y <4.0.0`).
version: 2.1.2
version: 2.1.3

environment:
sdk: ">=2.12.0 <3.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ class SamplePluginPlatform extends PlatformInterface {
class ImplementsSamplePluginPlatform extends Mock
implements SamplePluginPlatform {}

class ImplementsSamplePluginPlatformUsingNoSuchMethod
implements SamplePluginPlatform {
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}

class ImplementsSamplePluginPlatformUsingMockPlatformInterfaceMixin extends Mock
with MockPlatformInterfaceMixin
implements SamplePluginPlatform {}
Expand Down Expand Up @@ -98,6 +104,13 @@ void main() {
}, throwsA(isA<AssertionError>()));
});

test('prevents implmentation with `implements` and `noSuchMethod`', () {
expect(() {
SamplePluginPlatform.instance =
ImplementsSamplePluginPlatformUsingNoSuchMethod();
}, throwsA(isA<AssertionError>()));
});

test('allows mocking with `implements`', () {
final SamplePluginPlatform mock =
ImplementsSamplePluginPlatformUsingMockPlatformInterfaceMixin();
Expand Down