Skip to content

Commit

Permalink
Upgrading to Swift 3 (#30)
Browse files Browse the repository at this point in the history
This is a mostly backwards compatible API change with the previous version and only updates Swift 3 syntax
It does however, require removing the LYT prefix from device constants on Swift because CGFloats are no longer bridged
  • Loading branch information
plivesey authored Sep 23, 2016
1 parent 56cf751 commit 9ac2fa3
Show file tree
Hide file tree
Showing 20 changed files with 177 additions and 141 deletions.
20 changes: 12 additions & 8 deletions LayoutTest.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
61ADE1E81C0CA81600585946 /* LayoutTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61ADE1C41C0CA81600585946 /* LayoutTestCase.swift */; };
61ADE2491C0CAFE900585946 /* LYTLayoutTestCase.h in Headers */ = {isa = PBXBuildFile; fileRef = 61ADE2341C0CAFE900585946 /* LYTLayoutTestCase.h */; settings = {ATTRIBUTES = (Public, ); }; };
61ADE24A1C0CAFE900585946 /* LYTLayoutTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 61ADE2351C0CAFE900585946 /* LYTLayoutTestCase.m */; };
61BCF9E31D930B010034F8BA /* DeviceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61BCF9E21D930B010034F8BA /* DeviceConstants.swift */; };
61CACFAD1C1A4F7300369461 /* LYTViewSize.h in Headers */ = {isa = PBXBuildFile; fileRef = 61CACFA91C1A4F7300369461 /* LYTViewSize.h */; settings = {ATTRIBUTES = (Public, ); }; };
61CACFAE1C1A4F7300369461 /* LYTViewSize.m in Sources */ = {isa = PBXBuildFile; fileRef = 61CACFAA1C1A4F7300369461 /* LYTViewSize.m */; };
61CACFAF1C1A4F7300369461 /* UIView+LYTViewSize.h in Headers */ = {isa = PBXBuildFile; fileRef = 61CACFAB1C1A4F7300369461 /* UIView+LYTViewSize.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -169,6 +170,7 @@
61ADE1C41C0CA81600585946 /* LayoutTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutTestCase.swift; sourceTree = "<group>"; };
61ADE2341C0CAFE900585946 /* LYTLayoutTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LYTLayoutTestCase.h; sourceTree = "<group>"; };
61ADE2351C0CAFE900585946 /* LYTLayoutTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LYTLayoutTestCase.m; sourceTree = "<group>"; };
61BCF9E21D930B010034F8BA /* DeviceConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceConstants.swift; sourceTree = "<group>"; };
61CACFA91C1A4F7300369461 /* LYTViewSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LYTViewSize.h; sourceTree = "<group>"; };
61CACFAA1C1A4F7300369461 /* LYTViewSize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LYTViewSize.m; sourceTree = "<group>"; };
61CACFAB1C1A4F7300369461 /* UIView+LYTViewSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+LYTViewSize.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -424,17 +426,18 @@
isa = PBXGroup;
children = (
61ADE1C41C0CA81600585946 /* LayoutTestCase.swift */,
61BCF9E21D930B010034F8BA /* DeviceConstants.swift */,
);
path = Swift;
sourceTree = "<group>";
};
61ADE2331C0CAFE900585946 /* TestCase */ = {
isa = PBXGroup;
children = (
5667F6691C65FCE50042C3BB /* LYTLayoutFailingTestSnapshotRecorder.h */,
5667F66A1C65FCE50042C3BB /* LYTLayoutFailingTestSnapshotRecorder.m */,
61ADE2341C0CAFE900585946 /* LYTLayoutTestCase.h */,
61ADE2351C0CAFE900585946 /* LYTLayoutTestCase.m */,
5667F6691C65FCE50042C3BB /* LYTLayoutFailingTestSnapshotRecorder.h */,
5667F66A1C65FCE50042C3BB /* LYTLayoutFailingTestSnapshotRecorder.m */,
);
path = TestCase;
sourceTree = "<group>";
Expand Down Expand Up @@ -627,6 +630,7 @@
files = (
61ADE24A1C0CAFE900585946 /* LYTLayoutTestCase.m in Sources */,
5667F66C1C65FCE50042C3BB /* LYTLayoutFailingTestSnapshotRecorder.m in Sources */,
61BCF9E31D930B010034F8BA /* DeviceConstants.swift in Sources */,
61ADE1E81C0CA81600585946 /* LayoutTestCase.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -728,7 +732,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_VERSION = 2.3;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
Expand Down Expand Up @@ -762,7 +766,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "";
SWIFT_VERSION = 2.3;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
Expand All @@ -787,7 +791,7 @@
PRODUCT_BUNDLE_IDENTIFIER = LinkedIn.LayoutTestTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 2.3;
SWIFT_VERSION = 3.0;
};
name = Debug;
};
Expand All @@ -809,7 +813,7 @@
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = LinkedIn.LayoutTestTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 2.3;
SWIFT_VERSION = 3.0;
};
name = Release;
};
Expand Down Expand Up @@ -921,7 +925,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 2.3;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
Expand Down Expand Up @@ -953,7 +957,7 @@
PRODUCT_BUNDLE_IDENTIFIER = LinkedIn.LayoutTestBase;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 2.3;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
Expand Down
31 changes: 31 additions & 0 deletions LayoutTest/Swift/DeviceConstants.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// DeviceConstants.swift
// LayoutTest
//
// Created by Peter Livesey on 9/21/16.
// Copyright © 2016 LinkedIn. All rights reserved.
//

import Foundation

/**
This file redefines all the constants in LYTDeviceConstants for use in Swift.
This wasn't needed in previous version of Swift because this conversion was done automatically.
*/

public let iPhone4Width = NSNumber(value: Double(LYTiPhone4Width))
public let iPhone4Height = NSNumber(value: Double(LYTiPhone4Height))
public let iPhone5Width = NSNumber(value: Double(LYTiPhone5Width))
public let iPhone5Height = NSNumber(value: Double(LYTiPhone5Height))
public let iPhone6Width = NSNumber(value: Double(LYTiPhone6Width))
public let iPhone6Height = NSNumber(value: Double(LYTiPhone6Height))
public let iPhone6PlusWidth = NSNumber(value: Double(LYTiPhone6PlusWidth))
public let iPhone6PlusHeight = NSNumber(value: Double(LYTiPhone6PlusHeight))
public let iPadWidth = NSNumber(value: Double(LYTiPadWidth))
public let iPadHeight = NSNumber(value: Double(LYTiPadHeight))
public let iPadProWidth = NSNumber(value: Double(LYTiPadProWidth))
public let iPadProHeight = NSNumber(value: Double(LYTiPadProHeight))
public let AppleWatch38Width = NSNumber(value: Double(LYTAppleWatch38Width))
public let AppleWatch38Height = NSNumber(value: Double(LYTAppleWatch38Height))
public let AppleWatch42Width = NSNumber(value: Double(LYTAppleWatch42Width))
public let AppleWatch42Height = NSNumber(value: Double(LYTAppleWatch42Height))
19 changes: 10 additions & 9 deletions LayoutTest/Swift/LayoutTestCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The basic test will just call one of the methods starting with runLayoutTests. T
It's also recommended that you create your own subclass of this for your own project, and have all your other tests subclass this class. This allows you to add
and remove features in the future. There is a category in the superclass which lists some methods you may want to consider overriding.
*/
public class LayoutTestCase: LYTLayoutTestCase {
open class LayoutTestCase: LYTLayoutTestCase {

/**
This is the main method that runs your tests. It is a more Swift friendly version than its Objective-C counterparts. This method assumes your view
Expand All @@ -47,14 +47,14 @@ public class LayoutTestCase: LYTLayoutTestCase {
- Parameter validation: (view, data, context) Closure to validate the view given the data. The data here will not contain any LYTDataValues subclasses.
Here you should assert on the properties of the view. If you set a context in your viewForData: method, it will be passed back here.
*/
public func runLayoutTests<TestableView: LYTViewProvider where TestableView: UIView>(limitResults limitResults: LYTTesterLimitResults = .None,
validation: (TestableView, [NSObject : AnyObject], Any?) -> Void) {
runLayoutTestsWithViewProvider(TestableView.self, limitResults: limitResults) { (view, data, context) in
open func runLayoutTests<TestableView: LYTViewProvider>(limitResults: LYTTesterLimitResults = LYTTesterLimitResults(),
validation: (TestableView, [AnyHashable: Any], Any?) -> Void) where TestableView: UIView {
self.runLayoutTests(withViewProvider: TestableView.self, limitResults: limitResults) { (view, data, context) in
if let view = view as? TestableView {
validation(view, data, context)
} else {
self.failTest("The view wasn't of the expected type. Change your method signature to declare the view in the validation closure " +
"of the correct type. Expected: \(TestableView.self) Actual: \(view.dynamicType)", view: view as? UIView)
"of the correct type. Expected: \(TestableView.self) Actual: \(type(of: (view) as AnyObject))", view: view as? UIView)
}
}
}
Expand Down Expand Up @@ -86,14 +86,15 @@ public class LayoutTestCase: LYTLayoutTestCase {
- Parameter validation: (view, data, context) Block to validate the view given the data. The data here will not contain any LYTDataValues subclasses.
Here you should assert on the properties of the view. If you set a context in your viewForData: method, it will be passed back here.
*/
public func runLayoutTestsWithViewProvider<TestableView: UIView, ViewProvider: LYTViewProvider>(viewProvider: ViewProvider.Type,
limitResults: LYTTesterLimitResults = .None, validation: (TestableView, [NSObject : AnyObject], Any?) -> Void) {
runLayoutTestsWithViewProvider(viewProvider, limitResults: limitResults) { (view: AnyObject, data, context) in
open func runLayoutTestsWithViewProvider<TestableView: UIView, ViewProvider: LYTViewProvider>(_ viewProvider: ViewProvider.Type,
limitResults: LYTTesterLimitResults = LYTTesterLimitResults(),
validation: (TestableView, [AnyHashable: Any], Any?) -> Void) {
self.runLayoutTests(withViewProvider: viewProvider, limitResults: limitResults) { (view: Any, data, context) in
if let view = view as? TestableView {
validation(view, data, context)
} else {
self.failTest("The view wasn't of the expected type. Change your method signature to declare the view in the validation closure " +
"of the correct type. Expected: \(TestableView.self) Actual: \(view.dynamicType)", view: view as? UIView)
"of the correct type. Expected: \(TestableView.self) Actual: \(type(of: view))", view: view as? UIView)
}
}
}
Expand Down
14 changes: 2 additions & 12 deletions LayoutTest/TestCase/LYTLayoutTestCase.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,7 @@

#import <XCTest/XCTest.h>

/*
This is a work around for an issue where we don't know how LayoutTestBase doesn't exist.
See https://github.com/linkedin/LayoutTest-iOS/issues/8 for more info.
It looks like this will be fixed in CocoaPods 1.0.0, so we should be able to remove this at some point https://github.com/CocoaPods/CocoaPods/issues/4420
We have a project which ensures this behavior works (TestProjects/SampleAppiOS7).
*/
#if __has_include(<LayoutTestBase/LayoutTestBase-umbrella.h>)
@import LayoutTestBase;
#else
#import <LayoutTestBase/LYTLayoutPropertyTester.h>
#endif

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -79,7 +69,7 @@ NS_ASSUME_NONNULL_BEGIN
it will be passed back here.
*/
- (void)runLayoutTestsWithViewProvider:(Class)viewProvider
validation:(void(^)(id view, NSDictionary *data, id _Nullable context))validation;
validation:(__attribute__((noescape)) void(^)(id view, NSDictionary *data, id _Nullable context))validation;

/**
This is the main method that runs your tests. You pass in a class that conforms to LYTViewProvider and it will run multiple combinations
Expand Down Expand Up @@ -108,7 +98,7 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)runLayoutTestsWithViewProvider:(Class)viewProvider
limitResults:(LYTTesterLimitResults)limitResults
validation:(void(^)(id view, NSDictionary *data, id _Nullable context))validation;
validation:(__attribute__((noescape)) void(^)(id view, NSDictionary *data, id _Nullable context))validation;

/**
This method recusively adds all of the subviews of a view to viewsAllowingOverlap. It does NOT add the view you pass in. This is useful if a
Expand Down
46 changes: 23 additions & 23 deletions LayoutTest/TestCase/LYTLayoutTestCase.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ + (void)tearDown {
}

- (void)runLayoutTestsWithViewProvider:(Class)viewProvider
validation:(void(^)(id, NSDictionary *, id _Nullable))validation {
validation:(void(^)(id, NSDictionary *, id _Nullable))validation {
[self runLayoutTestsWithViewProvider:viewProvider
limitResults:LYTTesterLimitResultsNone
validation:validation];
limitResults:LYTTesterLimitResultsNone
validation:validation];
}

- (void)runLayoutTestsWithViewProvider:(Class)viewProvider
limitResults:(LYTTesterLimitResults)limitResults
validation:(void(^)(id view, NSDictionary *data, id _Nullable context))validation {
limitResults:(LYTTesterLimitResults)limitResults
validation:(void(^)(id view, NSDictionary *data, id _Nullable context))validation {

// It's too early to do this in setUp because they may override this property in setUp. So, let's do it here. It's ok if we call this multiple times per test. We'll just clean up in tearDown.
if (self.interceptsAutolayoutErrors) {
[LYTAutolayoutFailureIntercepter interceptAutolayoutFailuresWithBlock:^{
Expand All @@ -60,23 +60,23 @@ - (void)runLayoutTestsWithViewProvider:(Class)viewProvider
}

[LYTLayoutPropertyTester runPropertyTestsWithViewProvider:viewProvider
limitResults:limitResults
validation:^(id view, NSDictionary *data, id _Nullable context) {
//Keep a reference to the view and the data so that we can render a snapshot of them if the test fails
self.viewUnderTest = view;
self.dataForViewUnderTest = data;
// We must run this first to give the user a chance to add to viewsAllowingOverlap
validation(view, data, context);

// Now, let's run our tests
[self runBasicRecursiveViewTests:view];

// Now, let's reset these for the next run
self.viewsAllowingOverlap = [NSMutableSet set];
self.viewsAllowingAccessibilityErrors = [NSMutableSet set];
}];
limitResults:limitResults
validation:^(id view, NSDictionary *data, id _Nullable context) {

//Keep a reference to the view and the data so that we can render a snapshot of them if the test fails
self.viewUnderTest = view;
self.dataForViewUnderTest = data;

// We must run this first to give the user a chance to add to viewsAllowingOverlap
validation(view, data, context);
// Now, let's run our tests
[self runBasicRecursiveViewTests:view];

// Now, let's reset these for the next run
self.viewsAllowingOverlap = [NSMutableSet set];
self.viewsAllowingAccessibilityErrors = [NSMutableSet set];
}];
}

#pragma mark - Test Lifecycle
Expand Down
4 changes: 2 additions & 2 deletions LayoutTestBase/Core/Testers/LYTLayoutPropertyTester.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ typedef NS_OPTIONS(NSInteger, LYTTesterLimitResults) {
\param validation Block to validate the view given the data. The data here will not contain any LYTDataValues subclasses and both the view and data
will never be nil. Here you should assert on the properties of the view. If you set a context in your viewForData: method, it will be passed back here.
*/
+ (void)runPropertyTestsWithViewProvider:(Class)viewProvider validation:(void(^)(id view, NSDictionary *data, _Nullable id context))validation;
+ (void)runPropertyTestsWithViewProvider:(Class)viewProvider validation:(__attribute__((noescape)) void(^)(id view, NSDictionary *data, _Nullable id context))validation;

/**
Runs a suite of tests on a given viewProvider. This is the main method to be used for your unit tests.
Expand All @@ -50,7 +50,7 @@ typedef NS_OPTIONS(NSInteger, LYTTesterLimitResults) {
\param limitResults Use this parameter to run less combinations. This is useful if you're running into performance problems. See LYTTesterLimitResults
docs for more info.
*/
+ (void)runPropertyTestsWithViewProvider:(Class)viewProvider limitResults:(LYTTesterLimitResults)limitResults validation:(void(^)(id view, NSDictionary *data, id _Nullable context))validation;
+ (void)runPropertyTestsWithViewProvider:(Class)viewProvider limitResults:(LYTTesterLimitResults)limitResults validation:(__attribute__((noescape)) void(^)(id view, NSDictionary *data, id _Nullable context))validation;

@end

Expand Down
Loading

0 comments on commit 9ac2fa3

Please sign in to comment.