Skip to content

Split API into cross-platform OS-detection and native-only Platform i… #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
### 4.0.0

* New API split into OS-detection, which works cross-platform,
and accessing `dart:io` through a mockable abstraction, which still only
works when compiled to native.
Retains a minimal backwards compatible API, which will be deprecated soon.

### 3.1.0

* Removed `Platform.packageRoot`, which was already marked deprecated, and which
Expand Down
57 changes: 52 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,58 @@
[![Coverage Status -](https://coveralls.io/repos/github/google/platform.dart/badge.svg?branch=master)](https://coveralls.io/github/google/platform.dart?branch=master)
[![Pub](https://img.shields.io/pub/v/platform.svg)](https://pub.dartlang.org/packages/platform)


A generic platform abstraction for Dart.

Like `dart:io`, `package:platform` supplies a rich, Dart-idiomatic API for
accessing platform-specific information.
The [HostPlatform] API, exposed by `package:platform/host.dart`,
provides cross-platform OS detection.
Rather than accessing the `Platform.operatingSystem` from `dart:io` directly,
it can be accessed using `HostPlatform.current.operatingSystem`.
That getter also works in browsers, where `dart:io` is not available,
reporting an `operatingSystem` value of `"browser"`.

Like `dart:io`, `package:platform/native.dart` supplies a rich,
Dart-idiomatic API for accessing platform-specific information.
The [NativePlatform] API provides a lightweight wrapper
around the static `Platform` properties that exist in `dart:io`.
However, the `NativePlatform` class exposes instance properties rather
than static properties, making it possible to inject a mock object
for testing.
The [NativePlatform] API should still only be used by code that
will only run on native platforms. It requires `dart:io` to work
correctly.

For testing, use the [MockHostPlatform] from `package:platform/host_test.dart`
to create and inject a mock `HostPlatform` value,
and the [MockNativePlatform] from `package:platform/native_test.dart`
to mock a `NativePlatform`.

A library should only need to import one of these libraries.
The exported classes from the libraries are:
| Library | `HostPlatform` | `NativePlatform` | `MockHostPlatform` | `MockNativePlatform` |
|:--:|:--:|:--:|:--:|:--:|
| `host.dart` | ✓ | |||
| `native.dart`| ✓ | ✓ | | |
| `host_test.dart` | ✓ | | ✓ | |
| `native_test.dart` | ✓ | ✓ | ✓ | ✓ |

A non-test Dart library should not import a one of the `*_test.dart` libraries,
since the use of a mock can affect how well a compiled can optimize tests
against the operating system ID. If only the non-test libraries are used,
a well-optimizing compiler which knows the host platform it's compiling for,
may be able to deduce the result of tests at compile-time, and efficiently
omit code that won't be reachable on the current host platform.
Just creating a `MockHostPlatform` in the same program may affect
such optimization.

A test file can import any of the libraries, but only need a `*_test.dart`
library if it intends to create a mock of `HostPlatform` or `NativePlatform`.

The `package:platform/platform.dart` library provides a
(mostly) backwards compatible renaming of the classes, to match the names
used in prior versions of this package.
It exposes `NativePlatform` as `Platform`, `MockNativePlatform` as
`MockPlatform`, and a `LocalPlatform` class with a constructor that
should always be invoked with `const`, and which then creates the same
objects as `NativePlatform.current`.

`package:platform` provides a lightweight wrapper around the static `Platform`
properties that exist in `dart:io`. However, it uses instance properties rather
than static properties, making it possible to mock out in tests.
2 changes: 1 addition & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
include: package:lints/recommended.yaml
include: package:dart_flutter_team_lints/analysis_options.yaml

analyzer:
errors:
Expand Down
47 changes: 47 additions & 0 deletions lib/host.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// Operating system detection and mocking for tests.
///
/// This library provides an interface, [HostPlatform],
/// a default implementation provided by [HostPlatform.current],
/// and a mockable implementation [MockHostPlatform],
/// which can be used for testing.
///
/// The [HostPlatform.operatingSystem] string can be used to recognize
/// known host platforms. On currently supported platforms the value is one of
/// * `"android"` when running on an Android host.
/// * `"browser"` when running inside a browser.
/// * `"fuchsia"` when running on a Fuchsia OS host.
/// * `"ios"` when running on Apple iOS host.
/// * `"linux"` when running on a Linux host.
/// * `"macos"` when running on an Apple MacOS/OSX host.
/// * `"windows"` when running on a Microsoft Windows host.
///
/// When running inside a browser, it's not possible to detect the underlying
/// host platform that the browser is running on through this library.
///
/// The currently recognized ID strings are available as static properties of
/// [HostPlatform], for example [HostPlatform.android], [HostPlatform.macOS]
/// and [HostPlatform.windows],
/// and as a list, [HostPlatform.operatingSystemValues].
///
/// The [HostPlatform] has a number of helpers properties,
/// [HostPlatform.isAndroid] through [HostPlatform.isWindows],
/// which checks the [HostPlatform.operatingSystem] values against these
/// known values.
///
/// By using an object to provide access to the information,
/// instead of directly accessing the static getters from `dart:io`,
/// `Platform.operatingSystem` and `Platform.operatingSystemVersion`,
/// code can be parameterized by a `HostPlatform` object,
/// and a custom/mock implementation can be provided for testing.
///
/// Use the `package:platform/host_test.dart` instead of this one
/// in tests that need to introduce a mock platform.
///
/// {@canonicalFor platforms.HostPlatform}
library;

export 'src/platforms.dart' show HostPlatform;
50 changes: 50 additions & 0 deletions lib/host_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// Operating system detection and mocking for tests.
///
/// This library provides an interface, [HostPlatform],
/// a default implementation provided by [HostPlatform.current],
/// and a mockable implementation [MockHostPlatform],
/// which can be used for testing.
///
/// The [HostPlatform.operatingSystem] string can be used to recognize
/// known host platforms. On currently supported platforms the value is one of
/// * `"android"` when running on an Android host.
/// * `"browser"` when running inside a browser.
/// * `"fuchsia"` when running on a Fuchsia OS host.
/// * `"ios"` when running on Apple iOS host.
/// * `"linux"` when running on a Linux host.
/// * `"macos"` when running on an Apple MacOS/OSX host.
/// * `"windows"` when running on a Microsoft Windows host.
///
/// When running inside a browser, it's not possible to detect the underlying
/// host platform that the browser is running on through this library.
///
/// The currently recognized ID strings are available as static properties of
/// [HostPlatform], for example [HostPlatform.android], [HostPlatform.macOS]
/// and [HostPlatform.windows],
/// and as a list, [HostPlatform.operatingSystemValues].
///
/// The [HostPlatform] has a number of helpers properties,
/// [HostPlatform.isAndroid] through [HostPlatform.isWindows],
/// which checks the [HostPlatform.operatingSystem] values against these
/// known values.
///
/// By using an object to provide access to the information,
/// instead of direct access to the static getters from `dart:io`,
/// `Platform.operatingSystem` and `Platform.operatingSystemVersion`,
/// code can be parameterized by a `HostPlatform` object,
/// and one can then provide a custom/mock implementation,
/// using [MockHostPlatform], for testing.
/// Also, the [MockHostPlatform.run] method provides a way to *override* the
/// [HostPlatform.current] getter while running its argument function,
/// which works for asynchronous functions using a custom zone.
/// Using that, even code using, e.g., `HostPlatform.current.isLinux` directly
/// can still have its behavior modified during testing.
///
/// {@canonicalFor platforms.MockHostPlatform}
library;

export 'src/platforms.dart' show HostPlatform, MockHostPlatform;
42 changes: 42 additions & 0 deletions lib/native.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// Native platform information access.
///
/// This library is only available on native host platforms,
/// that is, not in the browser.
///
/// When using this library, the program should not be running in a browser,
/// since correct behavior depends on using the `dart:io` library.
/// Use `package:platform/host.dart` for host-platform detection that also
/// works in a browser.
///
/// This library provides an interface, [NativePlatform],
/// a default implementation provided by [NativePlatform.current].
///
/// The [NativePlatform] provides access to most of the static properties
/// of the [dart:io.Platform] namespace, and a few other properties
/// from `dart:io`.
/// The [NativePlatform] is a drop-in replacement for [HostPlatform]
/// but also exposes *more* native properties that are only available to
/// native programs, those not running in a browser.
/// See [HostPlatform] for how to detect the host operating system.
///
/// By using an object to provide access to the members of `dart:io`'s
/// `Platform`, `stdin` and `stdout`,
/// instead directly accessing the static getters in `dart:io`,
/// code can be parameterized by a `NativePlatform` object,
/// and a custom/mock implementation can be provided for testing.
///
/// Use the `package:platform/native_test.dart` library instead of this one
/// in tests that need to introduce a mock platform.
///
/// {@canonicalFor platforms.NativePlatform}
library;

export 'src/platforms.dart'
if (dart.library.html) 'src/no_native_platform.dart'
if (dart.library.io) 'src/platforms.dart'
if (dart.library.core) 'src/no_native_platform.dart'
show HostPlatform, NativePlatform;
44 changes: 44 additions & 0 deletions lib/native_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// Native platform information access, and mocking for tests.
///
/// When using this library, the program should not be running in a browser,
/// since correct behavior depends on using the `dart:io` library.
/// Use `package:platform/host_test.dart` for host-platform detection
/// and mocking that also works in a browser.
///
/// This library provides an interface, [NativePlatform],
/// a default implementation provided by [NativePlatform.current],
/// and a mockable implementation [MockNativePlatform],
/// which can be used for testing.
///
/// The [NativePlatform] provides access to most of the static properties
/// of the [dart:io.Platform] namespace, and a few other properties
/// from `dart:io`.
/// The [NativePlatform] is a drop-in replacement for [HostPlatform]
/// but also exposes *more* native properties that are only available to
/// native programs, those not running in a browser.
/// See [HostPlatform] for how to detect the host operating system.
///
/// By using an object to provide access to the members of `dart:io`'s
/// `Platform`, `stdin` and `stdout`,
/// instead using direct access to the static getters in `dart:io`,
/// code can be parameterized by a `NativePlatform` object,
/// and one can then provide a custom/mock implementation
/// using [MockNativePlatform], for testing.
/// Also, the [MockNativePlatform.run] method provides a way to *override* the
/// [NativePlatform.current] getter while running its argument function,
/// which works for asynchronous functions using a custom zone.
/// Using that, even code using, e.g., `NativePlatform.current.isLinux` directly
/// can still have its behavior modified during testing.
///
/// {@canonicalFor platforms.MockNativePlatform}
library;

export 'src/platforms.dart'
if (dart.library.html) 'src/no_native_platform.dart'
if (dart.library.io) 'src/platforms.dart'
if (dart.library.core) 'src/no_native_platform.dart'
show HostPlatform, MockHostPlatform, MockNativePlatform, NativePlatform;
30 changes: 25 additions & 5 deletions lib/platform.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// Core interfaces & classes.
export 'src/interface/local_platform.dart';
export 'src/interface/platform.dart';
export 'src/testing/fake_platform.dart';
/// Backwards compatibility for users of earlier versions of this package.
///
/// New users should use the `package:platform/host.dart` library's
/// [HostPlatform] class to detect the current operating system,
/// and they can use native-only/`dart:io`-specific
/// `package:platform/native.dart` library's [NativePlatform] as an abstraction
/// over the `Platform` data from `dart:io`.
///
/// Both of these libraries have an associated library only intended for
/// testing, `package:platform/host_test.dart` and
/// `package:platform/native_test.dart`.
/// Those libraries provide a configurable mock that can be injected
/// into code that are parameterized by `HostPlatform` or `NativePlatform`
/// objects, and a way to dynamically override the default value provided by
/// [HostPlatform.current] and [NativePlatform.current] properties.
library;

export 'host.dart';

export 'src/platforms.dart'
if (dart.library.html) 'src/no_native_platform.dart'
if (dart.library.io) 'src/platforms.dart'
if (dart.library.core) 'src/no_native_platform.dart'
show FakePlatform, LocalPlatform, Platform;
58 changes: 0 additions & 58 deletions lib/src/interface/local_platform.dart

This file was deleted.

Loading