mirrored_repositories/awesome-flutter/examples/plugins/packages/plugin_platform_interface
// 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.

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 {}
