blob: 6e425a19a048ffa9249c17332655ee616ae6801c [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library plugin_platform_interface;
import 'package:meta/meta.dart';
/// Base class for platform interfaces.
///
/// Provides a static helper method for ensuring that platform interfaces are
/// implemented using `extends` instead of `implements`.
///
/// Platform interface classes are expected to have a private static token object which will be
/// be passed to [verifyToken] along with a platform interface object for verification.
///
/// Sample usage:
///
/// ```dart
/// abstract class UrlLauncherPlatform extends PlatformInterface {
/// UrlLauncherPlatform() : super(token: _token);
///
/// static UrlLauncherPlatform _instance = MethodChannelUrlLauncher();
///
/// static const Object _token = Object();
///
/// static UrlLauncherPlatform get instance => _instance;
///
/// /// Platform-specific plugins should set this with their own platform-specific
/// /// class that extends [UrlLauncherPlatform] when they register themselves.
/// static set instance(UrlLauncherPlatform instance) {
/// PlatformInterface.verifyToken(instance, _token);
/// _instance = instance;
/// }
///
/// }
/// ```
///
/// Mockito mocks of platform interfaces will fail the verification, in test code only it is possible
/// to include the [MockPlatformInterfaceMixin] for the verification to be temporarily disabled. See
/// [MockPlatformInterfaceMixin] for a sample of using Mockito to mock a platform interface.
abstract class PlatformInterface {
/// Pass a private, class-specific `const Object()` as the `token`.
PlatformInterface({required Object token}) : _instanceToken = token;
final Object? _instanceToken;
/// Ensures that the platform instance has a token that matches the
/// provided token and throws [AssertionError] if not.
///
/// This is used to ensure that implementers are using `extends` rather than
/// `implements`.
///
/// Subclasses of [MockPlatformInterfaceMixin] are assumed to be valid in debug
/// builds.
///
/// This is implemented as a static method so that it cannot be overridden
/// with `noSuchMethod`.
static void verifyToken(PlatformInterface instance, Object token) {
if (instance is MockPlatformInterfaceMixin) {
bool assertionsEnabled = false;
assert(() {
assertionsEnabled = true;
return true;
}());
if (!assertionsEnabled) {
throw AssertionError(
'`MockPlatformInterfaceMixin` is not intended for use in release builds.');
}
return;
}
if (!identical(token, instance._instanceToken)) {
throw AssertionError(
'Platform interfaces must not be implemented with `implements`');
}
}
}
/// A [PlatformInterface] mixin that can be combined with mockito's `Mock`.
///
/// It passes the [PlatformInterface.verifyToken] check even though it isn't
/// using `extends`.
///
/// This class is intended for use in tests only.
///
/// Sample usage (assuming UrlLauncherPlatform extends [PlatformInterface]:
///
/// ```dart
/// class UrlLauncherPlatformMock extends Mock
/// with MockPlatformInterfaceMixin
/// implements UrlLauncherPlatform {}
/// ```
@visibleForTesting
abstract class MockPlatformInterfaceMixin implements PlatformInterface {}