Add FakePlatform.copyWith to allow overriding some values only (#33)

This adds a copyWith function to FakePlatform so that it is easy to override just one value from another platform. This can cut down a lot on duplicate code in tests, since you can make one template platform, and then just customize bits of it in each test.

Also, updated travis.sh to work with "dart format" instead of "dartfmt", and bumped the version number.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 664defd..bd9140b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+### 3.0.2
+
+* Added `FakePlatform.copyWith` function.
+
 ### 3.0.1
 
 * Added string constants for each of the supported platforms for use in switch
diff --git a/dev/travis.sh b/dev/travis.sh
index 6f80e56..a805dbd 100755
--- a/dev/travis.sh
+++ b/dev/travis.sh
@@ -4,9 +4,9 @@
 # BSD-style license that can be found in the LICENSE file.
 
 # Make sure dartfmt is run on everything
-echo "Checking dartfmt..."
-needs_dartfmt="$(dartfmt -n lib test dev)"
-if [[ -n "$needs_dartfmt" ]]; then
+echo "Checking dart format..."
+needs_dartfmt="$(dart format --set-exit-if-changed --output=none lib test dev)"
+if [[ $? != 0 ]]; then
   echo "FAILED"
   echo "$needs_dartfmt"
   exit 1
diff --git a/lib/src/testing/fake_platform.dart b/lib/src/testing/fake_platform.dart
index d28d059..046dd0a 100644
--- a/lib/src/testing/fake_platform.dart
+++ b/lib/src/testing/fake_platform.dart
@@ -93,6 +93,46 @@
     );
   }
 
+  /// Creates a new [FakePlatform] from this one, with some properties replaced by the given properties.
+  FakePlatform copyWith({
+    int? numberOfProcessors,
+    String? pathSeparator,
+    String? operatingSystem,
+    String? operatingSystemVersion,
+    String? localHostname,
+    Map<String, String>? environment,
+    String? executable,
+    String? resolvedExecutable,
+    Uri? script,
+    List<String>? executableArguments,
+    String? packageRoot,
+    String? packageConfig,
+    String? version,
+    bool? stdinSupportsAnsi,
+    bool? stdoutSupportsAnsi,
+    String? localeName,
+  }) {
+    return FakePlatform(
+      numberOfProcessors: numberOfProcessors ?? this.numberOfProcessors,
+      pathSeparator: pathSeparator ?? this.pathSeparator,
+      operatingSystem: operatingSystem ?? this.operatingSystem,
+      operatingSystemVersion:
+          operatingSystemVersion ?? this.operatingSystemVersion,
+      localHostname: localHostname ?? this.localHostname,
+      environment: environment ?? this.environment,
+      executable: executable ?? this.executable,
+      resolvedExecutable: resolvedExecutable ?? this.resolvedExecutable,
+      script: script ?? this.script,
+      executableArguments: executableArguments ?? this.executableArguments,
+      packageRoot: packageRoot ?? this.packageRoot,
+      packageConfig: packageConfig ?? this.packageConfig,
+      version: version ?? this.version,
+      stdinSupportsAnsi: stdinSupportsAnsi ?? this.stdinSupportsAnsi,
+      stdoutSupportsAnsi: stdoutSupportsAnsi ?? this.stdoutSupportsAnsi,
+      localeName: localeName ?? this.localeName,
+    );
+  }
+
   @override
   int get numberOfProcessors => _throwIfNull(_numberOfProcessors);
   int? _numberOfProcessors;
diff --git a/pubspec.yaml b/pubspec.yaml
index 480f98e..de10923 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: platform
-version: 3.0.1
+version: 3.0.2
 description: A pluggable, mockable platform abstraction for Dart.
 homepage: https://github.com/google/platform.dart
 
diff --git a/test/fake_platform_test.dart b/test/fake_platform_test.dart
index 7dc28ec..3f954b6 100644
--- a/test/fake_platform_test.dart
+++ b/test/fake_platform_test.dart
@@ -59,6 +59,70 @@
       });
     });
 
+    group('copyWith', () {
+      setUp(() {
+        fake = new FakePlatform.fromPlatform(local);
+      });
+
+      test('overrides a value, but leaves others intact', () {
+        FakePlatform copy = fake.copyWith(
+          numberOfProcessors: -1,
+        );
+        expect(copy.numberOfProcessors, equals(-1));
+        expect(copy.pathSeparator, local.pathSeparator);
+        expect(copy.operatingSystem, local.operatingSystem);
+        expect(copy.operatingSystemVersion, local.operatingSystemVersion);
+        expect(copy.localHostname, local.localHostname);
+        expect(copy.environment, local.environment);
+        expect(copy.executable, local.executable);
+        expect(copy.resolvedExecutable, local.resolvedExecutable);
+        expect(copy.script, local.script);
+        expect(copy.executableArguments, local.executableArguments);
+        // ignore: deprecated_member_use_from_same_package
+        expect(copy.packageRoot, local.packageRoot);
+        expect(copy.packageConfig, local.packageConfig);
+        expect(copy.version, local.version);
+        expect(copy.localeName, local.localeName);
+      });
+      test('can override all values', () {
+        fake = new FakePlatform(
+          numberOfProcessors: 8,
+          pathSeparator: ':',
+          operatingSystem: 'fake',
+          operatingSystemVersion: '0.1.0',
+          localHostname: 'host',
+          environment: <String, String>{'PATH': '.'},
+          executable: 'executable',
+          resolvedExecutable: '/executable',
+          script: new Uri.file('/platform/test/fake_platform_test.dart'),
+          executableArguments: <String>['scriptarg'],
+          version: '0.1.1',
+          stdinSupportsAnsi: false,
+          stdoutSupportsAnsi: true,
+          localeName: 'local',
+        );
+        FakePlatform copy = fake.copyWith(
+          numberOfProcessors: local.numberOfProcessors,
+          pathSeparator: local.pathSeparator,
+          operatingSystem: local.operatingSystem,
+          operatingSystemVersion: local.operatingSystemVersion,
+          localHostname: local.localHostname,
+          environment: local.environment,
+          executable: local.executable,
+          resolvedExecutable: local.resolvedExecutable,
+          script: local.script,
+          executableArguments: local.executableArguments,
+          packageRoot: local.packageRoot,
+          packageConfig: local.packageConfig,
+          version: local.version,
+          stdinSupportsAnsi: local.stdinSupportsAnsi,
+          stdoutSupportsAnsi: local.stdoutSupportsAnsi,
+          localeName: local.localeName,
+        );
+        _expectPlatformsEqual(copy, local);
+      });
+    });
+
     group('json', () {
       test('fromJson', () {
         String json = new io.File('test/platform.json').readAsStringSync();