Add a unit test for MDMModalMovementTiming. (#12)

* Add a MDMMotionTiming type prefix to MDMModalMovementTiming.

This allows the macro to be used in variable assignments like so:

    timing = MDMModalMovementTiming;

* Add unit test.

* Remove type change.

* DI.

* Rework test to remove need for dispatch_async.

* Self.

* Use Xcode 8.1 compatible expectations API.

* Property.

* Comma.
diff --git a/examples/apps/Catalog/MotionInterchangeCatalog.xcodeproj/project.pbxproj b/examples/apps/Catalog/MotionInterchangeCatalog.xcodeproj/project.pbxproj
index 29dcd40..c0139ca 100644
--- a/examples/apps/Catalog/MotionInterchangeCatalog.xcodeproj/project.pbxproj
+++ b/examples/apps/Catalog/MotionInterchangeCatalog.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		6619E1D91FA0ED0300F3AB25 /* MDMModalMovementTimingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6619E1D81FA0ED0300F3AB25 /* MDMModalMovementTimingTests.m */; };
 		663ED7C51EDF1F0C0096B2A9 /* ExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663ED7C01EDF1F0C0096B2A9 /* ExampleViewController.swift */; };
 		663ED7C61EDF1F0C0096B2A9 /* ExampleViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663ED7C11EDF1F0C0096B2A9 /* ExampleViews.swift */; };
 		663ED7C71EDF1F0C0096B2A9 /* HexColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663ED7C21EDF1F0C0096B2A9 /* HexColor.swift */; };
@@ -46,6 +47,7 @@
 		09CEA5DEA01BA723D08D84E6 /* Pods-UnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.release.xcconfig"; path = "../../../Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.release.xcconfig"; sourceTree = "<group>"; };
 		2DE76D4D35953D836F578CDE /* Pods-MotionInterchangeCatalog.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MotionInterchangeCatalog.debug.xcconfig"; path = "../../../Pods/Target Support Files/Pods-MotionInterchangeCatalog/Pods-MotionInterchangeCatalog.debug.xcconfig"; sourceTree = "<group>"; };
 		4AAB8EBB088513D48896641A /* Pods-MotionInterchangeCatalog.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MotionInterchangeCatalog.release.xcconfig"; path = "../../../Pods/Target Support Files/Pods-MotionInterchangeCatalog/Pods-MotionInterchangeCatalog.release.xcconfig"; sourceTree = "<group>"; };
+		6619E1D81FA0ED0300F3AB25 /* MDMModalMovementTimingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MDMModalMovementTimingTests.m; sourceTree = "<group>"; };
 		663ED7C01EDF1F0C0096B2A9 /* ExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleViewController.swift; sourceTree = "<group>"; };
 		663ED7C11EDF1F0C0096B2A9 /* ExampleViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleViews.swift; sourceTree = "<group>"; };
 		663ED7C21EDF1F0C0096B2A9 /* HexColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HexColor.swift; sourceTree = "<group>"; };
@@ -162,6 +164,7 @@
 			children = (
 				663ED8001EE628BA0096B2A9 /* MDMMotionCurveTests.swift */,
 				663ED8021EE6299A0096B2A9 /* MDMMotionCurveTests.m */,
+				6619E1D81FA0ED0300F3AB25 /* MDMModalMovementTimingTests.m */,
 			);
 			name = tests;
 			path = ../../../tests/unit;
@@ -477,6 +480,7 @@
 			files = (
 				663ED8031EE6299A0096B2A9 /* MDMMotionCurveTests.m in Sources */,
 				663ED8011EE628BA0096B2A9 /* MDMMotionCurveTests.swift in Sources */,
+				6619E1D91FA0ED0300F3AB25 /* MDMModalMovementTimingTests.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/tests/unit/MDMModalMovementTimingTests.m b/tests/unit/MDMModalMovementTimingTests.m
new file mode 100644
index 0000000..f955a9a
--- /dev/null
+++ b/tests/unit/MDMModalMovementTimingTests.m
@@ -0,0 +1,87 @@
+/*
+ Copyright 2017-present The Material Motion Authors. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#import <XCTest/XCTest.h>
+
+#import "MotionInterchange.h"
+
+@interface MDMModalMovementTimingTests : XCTestCase
+@property(nonatomic, strong) UIWindow *window;
+@end
+
+@interface ModalPresentationExtractionViewController : UIViewController
+@property(nonatomic, strong) CAAnimation *presentationPositionAnimation;
+@end
+
+@implementation ModalPresentationExtractionViewController
+
+- (void)viewDidLayoutSubviews {
+  [super viewDidLayoutSubviews];
+
+  // We just want the first position key path animation that affects this view controller.
+  if (!self.presentationPositionAnimation) {
+    self.presentationPositionAnimation = [self.view.layer animationForKey:@"position"];
+  }
+}
+
+@end
+
+@implementation MDMModalMovementTimingTests
+
+- (void)setUp {
+  [super setUp];
+
+  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
+  self.window.rootViewController = [[UIViewController alloc] initWithNibName:nil bundle:nil];
+  [self.window makeKeyAndVisible];
+}
+
+- (void)tearDown {
+  self.window = nil;
+
+  [super tearDown];
+}
+
+- (void)testSystemModalMovementTimingCurveMatchesModalMovementTiming {
+  ModalPresentationExtractionViewController *presentedViewController =
+      [[ModalPresentationExtractionViewController alloc] initWithNibName:nil bundle:nil];
+  XCTestExpectation *didComplete = [self expectationWithDescription:@"Animation completed"];
+  [self.window.rootViewController presentViewController:presentedViewController
+                                               animated:YES
+                                             completion:^{
+                                               [didComplete fulfill];
+                                             }];
+
+  [self waitForExpectationsWithTimeout:1 handler:nil];
+
+  XCTAssertTrue([presentedViewController.presentationPositionAnimation
+                 isKindOfClass:[CASpringAnimation class]]);
+  CASpringAnimation *springAnimation =
+      (CASpringAnimation *)presentedViewController.presentationPositionAnimation;
+
+  MDMMotionTiming timing = MDMModalMovementTiming;
+  XCTAssertEqualWithAccuracy(timing.curve.data[MDMSpringMotionCurveDataIndexMass],
+                             springAnimation.mass,
+                             0.001);
+  XCTAssertEqualWithAccuracy(timing.curve.data[MDMSpringMotionCurveDataIndexTension],
+                             springAnimation.stiffness,
+                             0.001);
+  XCTAssertEqualWithAccuracy(timing.curve.data[MDMSpringMotionCurveDataIndexFriction],
+                             springAnimation.damping,
+                             0.001);
+}
+
+@end