├── .swift-version ├── Nimble ├── .swift-version ├── .hound.yml ├── Tests │ ├── .swiftlint.yml │ ├── NimbleTests │ │ ├── Helpers │ │ │ ├── ObjectWithLazyProperty.swift │ │ │ └── XCTestCaseProvider.swift │ │ ├── LinuxSupport.swift │ │ ├── objc │ │ │ ├── ObjCSyncTest.m │ │ │ ├── ObjCBeNilTest.m │ │ │ ├── NimbleSpecHelper.h │ │ │ ├── ObjcStringersTest.m │ │ │ ├── ObjCMatchTest.m │ │ │ ├── ObjCBeKindOfTest.m │ │ │ ├── ObjCBeginWithTest.m │ │ │ ├── ObjCEndWithTest.m │ │ │ ├── ObjCBeAnInstanceOfTest.m │ │ │ ├── ObjCBeTrueTest.m │ │ │ ├── ObjCBeFalseTest.m │ │ │ ├── ObjCBeLessThanTest.m │ │ │ ├── ObjCSatisfyAnyOfTest.m │ │ │ ├── ObjCBeGreaterThanTest.m │ │ │ ├── ObjCBeLessThanOrEqualToTest.m │ │ │ ├── ObjCBeCloseToTest.m │ │ │ ├── ObjCAsyncTest.m │ │ │ ├── ObjCBeGreaterThanOrEqualToTest.m │ │ │ ├── ObjCBeFalsyTest.m │ │ │ ├── ObjCBeTruthyTest.m │ │ │ ├── ObjCAllPassTest.m │ │ │ ├── ObjCUserDescriptionTest.m │ │ │ ├── ObjCContainTest.m │ │ │ ├── ObjCBeIdenticalToTest.m │ │ │ └── ObjCContainElementSatisfying.m │ │ ├── Matchers │ │ │ ├── BeNilTest.swift │ │ │ ├── BeVoidTest.swift │ │ │ ├── ToSucceedTest.swift │ │ │ ├── MatchTest.swift │ │ │ ├── BeGreaterThanTest.swift │ │ │ ├── BeLessThanOrEqualToTest.swift │ │ │ ├── ThrowAssertionTest.swift │ │ │ ├── BeLessThanTest.swift │ │ │ ├── BeginWithTest.swift │ │ │ ├── HaveCountTest.swift │ │ │ ├── EndWithTest.swift │ │ │ ├── BeGreaterThanOrEqualToTest.swift │ │ │ ├── SatisfyAnyOfTest.swift │ │ │ ├── BeIdenticalToTest.swift │ │ │ ├── BeIdenticalToObjectTest.swift │ │ │ └── BeEmptyTest.swift │ │ ├── Info.plist │ │ └── UserDescriptionTest.swift │ └── LinuxMain.swift ├── Dockerfile.test ├── Gemfile ├── Sources │ ├── NimbleObjectiveC │ │ ├── NMBStringify.m │ │ ├── CurrentTestCaseTracker.h │ │ ├── NMBExceptionCapture.h │ │ ├── NMBStringify.h │ │ └── NMBExceptionCapture.m │ ├── Nimble │ │ ├── Nimble.h │ │ ├── Utils │ │ │ ├── Functional.swift │ │ │ ├── SourceLocation.swift │ │ │ └── Errors.swift │ │ ├── Matchers │ │ │ ├── BeVoid.swift │ │ │ ├── BeNil.swift │ │ │ ├── Match.swift │ │ │ ├── ToSucceed.swift │ │ │ ├── BeIdenticalTo.swift │ │ │ ├── BeLessThan.swift │ │ │ ├── BeGreaterThan.swift │ │ │ ├── BeLessThanOrEqual.swift │ │ │ ├── BeGreaterThanOrEqualTo.swift │ │ │ ├── MatchError.swift │ │ │ ├── ContainElementSatisfying.swift │ │ │ ├── BeAnInstanceOf.swift │ │ │ ├── PostNotification.swift │ │ │ ├── BeAKindOf.swift │ │ │ ├── ThrowAssertion.swift │ │ │ └── BeginWith.swift │ │ ├── Adapters │ │ │ ├── AssertionDispatcher.swift │ │ │ ├── AdapterProtocols.swift │ │ │ ├── NonObjectiveC │ │ │ │ └── ExceptionCapture.swift │ │ │ └── NimbleEnvironment.swift │ │ ├── Info.plist │ │ └── DSL.swift │ └── Lib │ │ └── CwlPreconditionTesting │ │ ├── CwlPreconditionTesting │ │ ├── Posix │ │ │ └── CwlPreconditionTesting.h │ │ ├── Mach │ │ │ └── CwlPreconditionTesting.h │ │ └── CwlDarwinDefinitions.swift │ │ ├── CwlCatchExceptionSupport │ │ ├── CwlCatchException.m │ │ └── include │ │ │ └── CwlCatchException.h │ │ ├── CwlCatchException │ │ └── CwlCatchException.swift │ │ └── CwlMachBadInstructionHandler │ │ └── include │ │ └── CwlMachBadInstructionHandler.h ├── Nimble.xcodeproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Package.swift ├── .swiftlint.yml ├── .gitignore ├── .github │ ├── PULL_REQUEST_TEMPLATE │ └── ISSUE_TEMPLATE ├── .travis.yml ├── Gemfile.lock └── Nimble.podspec ├── Swiftility.xcodeproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── Swiftility ├── Sources │ ├── Type Safety │ │ ├── UIView.swift │ │ ├── UIViewController.swift │ │ ├── MVVM.swift │ │ ├── UITableView.swift │ │ ├── Storyboard.swift │ │ ├── Nib.swift │ │ └── UICollectionView.swift │ ├── Core │ │ ├── ObjC.h │ │ ├── SwiftExtensions.swift │ │ ├── ObjC.m │ │ └── ObjcExtensions.swift │ ├── Swiftility.swift │ ├── Extensions │ │ ├── Objc │ │ │ ├── UIView+Extensions.h │ │ │ └── UIView+Extensions.m │ │ ├── UIKit │ │ │ ├── CGExtensions.swift │ │ │ ├── UIImageViewExtensions.swift │ │ │ ├── UIPageViewControllerExtensions.swift │ │ │ ├── UILabelExtensions.swift │ │ │ ├── UINavigationBarExtensions.swift │ │ │ ├── UITabBarControllerExtensions.swift │ │ │ ├── UIFontExtensions.swift │ │ │ ├── UIApplicationExtensions.swift │ │ │ ├── UIScrollViewExtensions.swift │ │ │ ├── UIImageEffects │ │ │ │ └── UIImageEffectsExtension.swift │ │ │ ├── UIDeviceExtensions.swift │ │ │ ├── UICollectionViewExtensions.swift │ │ │ └── UINavigationControllerExtensions.swift │ │ ├── DictionaryExtensions.swift │ │ ├── CollectionExtensions.swift │ │ ├── ArrayExtensions.swift │ │ └── Foundation │ │ │ ├── Operation.swift │ │ │ ├── NotificationCenterExtensions.swift │ │ │ ├── WeakTimer.swift │ │ │ └── DateExtensions.swift │ └── Types │ │ └── Weak.swift ├── Swiftility.h └── Info.plist ├── Package.swift ├── Swiftility.xcworkspace └── contents.xcworkspacedata ├── .travis.yml ├── Swiftility.podspec ├── SwiftilityTests ├── Extensions │ ├── CollectionExtensionsTests.swift │ ├── ArrayExtensionsTests.swift │ └── StringExtensionsTests.swift ├── Type Safe UIKIt │ ├── Common │ │ ├── TestNonExistingCell.xib │ │ ├── TestCell.xib │ │ └── TestCollectionViewCell.xib │ ├── UIViewControllerTests.swift │ ├── NibTests.swift │ ├── StoryboardTests.swift │ ├── UITableViewTests.swift │ └── UICollectionViewTests.swift ├── Info.plist └── RegexTests.swift ├── .gitignore └── LICENSE /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /Nimble/.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /Nimble/.hound.yml: -------------------------------------------------------------------------------- 1 | swift: 2 | config_file: .swiftlint.yml 3 | -------------------------------------------------------------------------------- /Nimble/Tests/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - line_length 3 | -------------------------------------------------------------------------------- /Nimble/Dockerfile.test: -------------------------------------------------------------------------------- 1 | FROM swift:latest 2 | COPY . . 3 | CMD ./test swiftpm 4 | -------------------------------------------------------------------------------- /Nimble/Gemfile: -------------------------------------------------------------------------------- 1 | # A sample Gemfile 2 | source "https://rubygems.org" 3 | 4 | gem 'cocoapods', '1.2.0' 5 | -------------------------------------------------------------------------------- /Nimble/Sources/NimbleObjectiveC/NMBStringify.m: -------------------------------------------------------------------------------- 1 | #import "NMBStringify.h" 2 | #import 3 | 4 | NSString *_Nonnull NMBStringify(id _Nullable anyObject) { 5 | return [NMBStringer stringify:anyObject]; 6 | } 7 | -------------------------------------------------------------------------------- /Nimble/Nimble.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Swiftility.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Helpers/ObjectWithLazyProperty.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class ObjectWithLazyProperty { 4 | init() {} 5 | lazy var value: String = "hello" 6 | lazy var anotherValue: String = { return "world" }() 7 | } 8 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/LinuxSupport.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | #if os(Linux) 4 | extension NSNotification.Name { 5 | init(_ rawValue: String) { 6 | self.init(rawValue: rawValue) 7 | } 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /Swiftility/Sources/Type Safety/UIView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 1/29/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UIView: SelfNibConvertible {} -------------------------------------------------------------------------------- /Nimble/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:3.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Nimble", 7 | exclude: [ 8 | "Sources/Lib", 9 | "Sources/NimbleObjectiveC", 10 | "Tests/NimbleTests/objc", 11 | ] 12 | ) 13 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Package.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/20/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import PackageDescription 10 | 11 | let package = Package( 12 | name: "Swiftility" 13 | ) 14 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Nimble.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NMBExceptionCapture.h" 3 | #import "NMBStringify.h" 4 | #import "DSL.h" 5 | 6 | #import "CwlPreconditionTesting.h" 7 | 8 | FOUNDATION_EXPORT double NimbleVersionNumber; 9 | FOUNDATION_EXPORT const unsigned char NimbleVersionString[]; 10 | -------------------------------------------------------------------------------- /Swiftility.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Utils/Functional.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Sequence { 4 | internal func all(_ fn: (Iterator.Element) -> Bool) -> Bool { 5 | for item in self { 6 | if !fn(item) { 7 | return false 8 | } 9 | } 10 | return true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Nimble/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - todo 3 | - variable_name 4 | - force_try 5 | - force_cast 6 | 7 | included: 8 | - Sources 9 | - Tests 10 | 11 | excluded: 12 | - Sources/Lib 13 | 14 | trailing_comma: 15 | mandatory_comma: true 16 | 17 | line_length: 18 | ignores_comments: true 19 | ignores_function_declarations: true 20 | -------------------------------------------------------------------------------- /Nimble/Sources/NimbleObjectiveC/CurrentTestCaseTracker.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | SWIFT_CLASS("_TtC6Nimble22CurrentTestCaseTracker") 5 | @interface CurrentTestCaseTracker : NSObject 6 | + (CurrentTestCaseTracker *)sharedInstance; 7 | @end 8 | 9 | @interface CurrentTestCaseTracker (Register) @end 10 | -------------------------------------------------------------------------------- /Swiftility/Sources/Core/ObjC.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjC.h 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/21/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ObjC : NSObject 12 | 13 | + (BOOL)catchException:(void(^)(void))tryBlock error:(__autoreleasing NSError **)error; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Swiftility/Sources/Swiftility.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Swiftility.swift 3 | // Swiftility 4 | // 5 | // Created by Allan BARBATO on 20/09/2017. 6 | // Copyright © 2017 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public enum Swiftility { 12 | 13 | public static func initialize() { 14 | UIViewController._setupSwizzle() 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Swiftility/Sources/Core/SwiftExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 10/27/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public func < (a: T, b: T) -> Bool where T.RawValue: Comparable 12 | { 13 | return a.rawValue < b.rawValue 14 | } 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | 3 | xcode_project: Swiftility.xcodeproj 4 | xcode_scheme: Swiftility 5 | osx_image: xcode8 6 | xcode_sdk: iphonesimulator10.0 7 | 8 | before_install: 9 | - gem install xcpretty 10 | 11 | script: 12 | - set -o pipefail 13 | - xcodebuild -project $TRAVIS_XCODE_PROJECT -scheme $TRAVIS_XCODE_SCHEME -sdk $TRAVIS_XCODE_SDK -destination 'name=iPhone 6' test | xcpretty -c 14 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/Objc/UIView+Extensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Extensions.h 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 10/14/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (Extensions) 12 | 13 | + (nonnull instancetype)appearanceWhenContainedInClass:(nonnull Class)ContainerClass; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/CGExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 11/10/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension CGSize 12 | { 13 | public static var greatestFiniteMagnitude: CGSize { 14 | return CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Nimble/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | **/xcuserdata/* 3 | **/*.xccheckout 4 | **/*.xcscmblueprint 5 | build/ 6 | .idea 7 | DerivedData/ 8 | Nimble.framework.zip 9 | 10 | # Carthage 11 | # 12 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 13 | # Carthage/Checkouts 14 | 15 | Carthage/Build 16 | 17 | # Swift Package Manager 18 | # 19 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 20 | # Packages/ 21 | .build/ 22 | -------------------------------------------------------------------------------- /Nimble/Sources/NimbleObjectiveC/NMBExceptionCapture.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface NMBExceptionCapture : NSObject 5 | 6 | - (nonnull instancetype)initWithHandler:(void(^ _Nullable)(NSException * _Nonnull))handler finally:(void(^ _Nullable)(void))finally; 7 | - (void)tryBlock:(__attribute__((noescape)) void(^ _Nonnull)(void))unsafeBlock NS_SWIFT_NAME(tryBlock(_:)); 8 | 9 | @end 10 | 11 | typedef void(^NMBSourceCallbackBlock)(BOOL successful); 12 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UIImageViewExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageViewExtentions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/18/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIImageView 12 | { 13 | public func setImage(_ image: UIImage?, withColor color: UIColor) 14 | { 15 | self.image = image?.withRenderingMode(.alwaysTemplate) 16 | self.tintColor = color 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCSyncTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "NimbleSpecHelper.h" 4 | 5 | @interface ObjCSyncTest : XCTestCase 6 | 7 | @end 8 | 9 | @implementation ObjCSyncTest 10 | 11 | - (void)testFailureExpectation { 12 | expectFailureMessage(@"fail() always fails", ^{ 13 | fail(); 14 | }); 15 | 16 | expectFailureMessage(@"This always fails", ^{ 17 | failWithMessage(@"This always fails"); 18 | }); 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/Objc/UIView+Extensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Extensions.m 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 10/14/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | #import "UIView+Extensions.h" 10 | 11 | @implementation UIView (Extensions) 12 | 13 | + (nonnull instancetype)appearanceWhenContainedInClass:(nonnull Class)containerClass; 14 | { 15 | return [self appearanceWhenContainedIn:containerClass, nil]; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Swiftility/Sources/Type Safety/UIViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 1/29/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension FromStoryboard where Self: UIViewController 12 | { 13 | public static func instantiateFromStoryboard() -> Self 14 | { 15 | return UIStoryboard(name: self.storyboardName).instantiateViewController() 16 | } 17 | } 18 | 19 | extension UIViewController: SelfNibConvertible {} 20 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/DictionaryExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DictionaryExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 6/7/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Dictionary 12 | { 13 | /// Convenience call to Dictionary.updateValue for each value of `other` 14 | public mutating func update(_ other: Dictionary) 15 | { 16 | for (key, value) in other { 17 | self.updateValue(value, forKey: key) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Swiftility/Sources/Types/Weak.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Weak.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 10/2/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Weak 12 | { 13 | public weak var value : T? 14 | 15 | public init (_ value: T) { 16 | self.value = value 17 | } 18 | } 19 | 20 | public struct Unowned 21 | { 22 | public unowned var value : T 23 | 24 | public init (_ value: T) { 25 | self.value = value 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Swiftility/Sources/Core/ObjC.m: -------------------------------------------------------------------------------- 1 | // 2 | // ObjC.m 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/21/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | #import "ObjC.h" 10 | 11 | @implementation ObjC 12 | 13 | + (BOOL)catchException:(void(^)(void))tryBlock error:(__autoreleasing NSError **)error 14 | { 15 | @try { 16 | tryBlock(); 17 | return YES; 18 | } 19 | @catch (NSException *exception) { 20 | *error = [[NSError alloc] initWithDomain:exception.name code:0 userInfo:exception.userInfo]; 21 | } 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeNilTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeNilTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeNilTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(nil).to(beNil()); 12 | expect(@NO).toNot(beNil()); 13 | } 14 | 15 | - (void)testNegativeMatches { 16 | expectFailureMessage(@"expected to be nil, got <1>", ^{ 17 | expect(@1).to(beNil()); 18 | }); 19 | expectFailureMessage(@"expected to not be nil, got ", ^{ 20 | expect(nil).toNot(beNil()); 21 | }); 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/BeVoid.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is Void. 4 | public func beVoid() -> Predicate<()> { 5 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 6 | failureMessage.postfixMessage = "be void" 7 | let actualValue: ()? = try actualExpression.evaluate() 8 | return actualValue != nil 9 | } 10 | } 11 | 12 | public func == (lhs: Expectation<()>, rhs: ()) { 13 | lhs.to(beVoid()) 14 | } 15 | 16 | public func != (lhs: Expectation<()>, rhs: ()) { 17 | lhs.toNot(beVoid()) 18 | } 19 | -------------------------------------------------------------------------------- /Swiftility.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "Swiftility" 4 | s.version = "4.0.0" 5 | s.summary = "allbto utility library to use across my projects." 6 | s.homepage = "https://github.com/allbto/swiftility" 7 | s.license = { :type => "MIT" } 8 | s.author = "Allan Bto" 9 | 10 | s.platform = :ios, "8.0" 11 | 12 | s.source = { :git => "https://github.com/allbto/swiftility.git", :tag => s.version } 13 | 14 | s.public_header_files = "Swiftility/**/*.h" 15 | s.source_files = "Swiftility/Sources/**/*.{h,m,swift}" 16 | 17 | s.requires_arc = true 18 | 19 | end 20 | -------------------------------------------------------------------------------- /Nimble/.github/PULL_REQUEST_TEMPLATE: -------------------------------------------------------------------------------- 1 | The PR should summarize what was changed and why. Here are some questions to 2 | help you if you're not sure: 3 | 4 | - What behavior was changed? 5 | - What code was refactored / updated to support this change? 6 | - What issues are related to this PR? Or why was this change introduced? 7 | 8 | Checklist - While not every PR needs it, new features should consider this list: 9 | 10 | - [ ] Does this have tests? 11 | - [ ] Does this have documentation? 12 | - [ ] Does this break the public API (Requires major version bump)? 13 | - [ ] Is this a new feature (Requires minor version bump)? 14 | 15 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UIPageViewControllerExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIPageViewControllerExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/16/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIPageViewController 12 | { 13 | /// Retrieve the scrollView of a UIPageViewController if available 14 | public var scrollView: UIScrollView? { 15 | for view in self.view.subviews { 16 | if let scrollView = view as? UIScrollView { 17 | return scrollView 18 | } 19 | } 20 | 21 | return nil 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /SwiftilityTests/Extensions/CollectionExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionExtensionsTests.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/21/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import Swiftility 12 | 13 | class CollectionExtensionsTests: XCTestCase 14 | { 15 | func testMapOptional() 16 | { 17 | let arr: [Int?] = [1, nil, 0, 12, nil, 0, 2] 18 | let arrCleaned = arr.optionalMap({ $0 }) 19 | 20 | XCTAssert(arrCleaned == [1, 0, 12, 0, 2]) 21 | XCTAssert(arrCleaned.optionalMap({ $0 > 1 ? $0 : nil }) == [12, 2]) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Swiftility/Swiftility.h: -------------------------------------------------------------------------------- 1 | // 2 | // Swiftility.h 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 12/14/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Swiftility. 12 | FOUNDATION_EXPORT double SwiftilityVersionNumber; 13 | 14 | //! Project version string for Swiftility. 15 | FOUNDATION_EXPORT const unsigned char SwiftilityVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | #import 20 | #import 21 | #import 22 | -------------------------------------------------------------------------------- /SwiftilityTests/Type Safe UIKIt/Common/TestNonExistingCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/BeNil.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is nil. 4 | public func beNil() -> Predicate { 5 | return Predicate.simpleNilable("be nil") { actualExpression in 6 | let actualValue = try actualExpression.evaluate() 7 | return PredicateStatus(bool: actualValue == nil) 8 | } 9 | } 10 | 11 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 12 | extension NMBObjCMatcher { 13 | @objc public class func beNilMatcher() -> NMBObjCMatcher { 14 | return NMBObjCMatcher { actualExpression, failureMessage in 15 | return try! beNil().matches(actualExpression, failureMessage: failureMessage) 16 | } 17 | } 18 | } 19 | #endif 20 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/NimbleSpecHelper.h: -------------------------------------------------------------------------------- 1 | @import Nimble; 2 | #import "NimbleTests-Swift.h" 3 | 4 | // Use this when you want to verify the failure message for when an expectation fails 5 | #define expectFailureMessage(MSG, BLOCK) \ 6 | [NimbleHelper expectFailureMessage:(MSG) block:(BLOCK) file:@(__FILE__) line:__LINE__]; 7 | 8 | #define expectFailureMessages(MSGS, BLOCK) \ 9 | [NimbleHelper expectFailureMessages:(MSGS) block:(BLOCK) file:@(__FILE__) line:__LINE__]; 10 | 11 | 12 | // Use this when you want to verify the failure message with the nil message postfixed 13 | // to it: " (use beNil() to match nils)" 14 | #define expectNilFailureMessage(MSG, BLOCK) \ 15 | [NimbleHelper expectFailureMessageForNil:(MSG) block:(BLOCK) file:@(__FILE__) line:__LINE__]; 16 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Adapters/AssertionDispatcher.swift: -------------------------------------------------------------------------------- 1 | /// AssertionDispatcher allows multiple AssertionHandlers to receive 2 | /// assertion messages. 3 | /// 4 | /// @warning Does not fully dispatch if one of the handlers raises an exception. 5 | /// This is possible with XCTest-based assertion handlers. 6 | /// 7 | public class AssertionDispatcher: AssertionHandler { 8 | let handlers: [AssertionHandler] 9 | 10 | public init(handlers: [AssertionHandler]) { 11 | self.handlers = handlers 12 | } 13 | 14 | public func assert(_ assertion: Bool, message: FailureMessage, location: SourceLocation) { 15 | for handler in handlers { 16 | handler.assert(assertion, message: message, location: location) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UILabelExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UILabelExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 12/22/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UILabel 12 | { 13 | /// Init label with font, textColor and textAlignement 14 | /// 15 | /// - Parameters: 16 | /// - font: Label font 17 | /// - textColor: Label color 18 | /// - textAlignment: default .left 19 | public convenience init(font: UIFont, textColor: UIColor, textAlignment: NSTextAlignment = .left) 20 | { 21 | self.init() 22 | 23 | self.font = font 24 | self.textColor = textColor 25 | self.textAlignment = textAlignment 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Adapters/AdapterProtocols.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Protocol for the assertion handler that Nimble uses for all expectations. 4 | public protocol AssertionHandler { 5 | func assert(_ assertion: Bool, message: FailureMessage, location: SourceLocation) 6 | } 7 | 8 | /// Global backing interface for assertions that Nimble creates. 9 | /// Defaults to a private test handler that passes through to XCTest. 10 | /// 11 | /// If XCTest is not available, you must assign your own assertion handler 12 | /// before using any matchers, otherwise Nimble will abort the program. 13 | /// 14 | /// @see AssertionHandler 15 | public var NimbleAssertionHandler: AssertionHandler = { () -> AssertionHandler in 16 | return isXCTestAvailable() ? NimbleXCTestHandler() : NimbleXCTestUnavailableHandler() 17 | }() 18 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjcStringersTest.m: -------------------------------------------------------------------------------- 1 | @import XCTest; 2 | @import Nimble; 3 | 4 | @interface ObjcStringersTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjcStringersTest 9 | 10 | - (void)testItCanStringifyArrays { 11 | NSArray *array = @[@1, @2, @3]; 12 | NSString *result = NMBStringify(array); 13 | 14 | expect(result).to(equal(@"(1, 2, 3)")); 15 | } 16 | 17 | - (void)testItCanStringifyIndexSets { 18 | NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 3)]; 19 | NSString *result = NMBStringify(indexSet); 20 | 21 | expect(result).to(equal(@"(1, 2, 3)")); 22 | } 23 | 24 | - (void)testItRoundsLongDecimals { 25 | NSNumber *num = @291.123782163; 26 | NSString *result = NMBStringify(num); 27 | 28 | expect(result).to(equal(@"291.1238")); 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/BeNilTest.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Nimble 3 | 4 | final class BeNilTest: XCTestCase, XCTestCaseProvider { 5 | static var allTests: [(String, (BeNilTest) -> () throws -> Void)] { 6 | return [ 7 | ("testBeNil", testBeNil), 8 | ] 9 | } 10 | 11 | func producesNil() -> [Int]? { 12 | return nil 13 | } 14 | 15 | func testBeNil() { 16 | expect(nil as Int?).to(beNil()) 17 | expect(1 as Int?).toNot(beNil()) 18 | expect(self.producesNil()).to(beNil()) 19 | 20 | failsWithErrorMessage("expected to not be nil, got ") { 21 | expect(nil as Int?).toNot(beNil()) 22 | } 23 | 24 | failsWithErrorMessage("expected to be nil, got <1>") { 25 | expect(1 as Int?).to(beNil()) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /SwiftilityTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Nimble/Sources/NimbleObjectiveC/NMBStringify.h: -------------------------------------------------------------------------------- 1 | @class NSString; 2 | 3 | /** 4 | * Returns a string appropriate for displaying in test output 5 | * from the provided value. 6 | * 7 | * @param anyObject A value that will show up in a test's output. 8 | * 9 | * @return The string that is returned can be 10 | * customized per type by conforming a type to the `TestOutputStringConvertible` 11 | * protocol. When stringifying a non-`TestOutputStringConvertible` type, this 12 | * function will return the value's debug description and then its 13 | * normal description if available and in that order. Otherwise it 14 | * will return the result of constructing a string from the value. 15 | * 16 | * @see `TestOutputStringConvertible` 17 | */ 18 | extern NSString *_Nonnull NMBStringify(id _Nullable anyObject) __attribute__((warn_unused_result)); 19 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UINavigationBarExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UINavigationBarExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 10/16/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UINavigationBar 12 | { 13 | /** 14 | Make the navigation bar transparant and translucent by default 15 | 16 | - parameter transparent: Is transparent 17 | - parameter translucent: =`transparent`; Is translucent, default is value of `transparent` 18 | */ 19 | public func setTransparent(_ transparent: Bool, translucent: Bool? = nil) 20 | { 21 | self.setBackgroundImage((transparent ? UIImage() : nil), for: .default) 22 | self.shadowImage = (transparent ? UIImage() : nil) 23 | self.isTranslucent = translucent ?? transparent 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SwiftilityTests/Type Safe UIKIt/UIViewControllerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewControllerTests.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 1/31/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Swiftility 11 | 12 | class UIViewControllerTests: XCTestCase 13 | { 14 | func testInstantiateFromStoryboard() 15 | { 16 | _ = TestVC.instantiateFromStoryboard() 17 | XCTAssert(true, "vc instantiation should not crash") 18 | } 19 | 20 | func testNibConvertible() 21 | { 22 | XCTAssert(TestVC.ownNib.nibName == "TestVC") 23 | XCTAssert(TestVC.ownNib.bundle == nil) 24 | } 25 | 26 | func testViewNibConvertible() 27 | { 28 | XCTAssert(TestView.ownNib.nibName == "TestView") 29 | XCTAssert(TestView.ownNib.bundle == nil) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Swiftility/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Nimble/.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode8.3 2 | language: generic 3 | matrix: 4 | include: 5 | - os: osx 6 | sudo: required 7 | env: TYPE=podspec 8 | - os: osx 9 | env: TYPE=ios NIMBLE_RUNTIME_IOS_SDK_VERSION=10.0 10 | - os: osx 11 | env: TYPE=tvos NIMBLE_RUNTIME_TVOS_SDK_VERSION=10.0 12 | - os: osx 13 | env: TYPE=macos 14 | - os: osx 15 | env: TYPE=macos 16 | osx_image: xcode9 17 | - os: osx 18 | env: TYPE=swiftpm 19 | - os: osx 20 | env: TYPE=swiftpm 21 | osx_image: xcode9 22 | - os: linux 23 | dist: trusty 24 | sudo: required 25 | env: TYPE=swiftpm 26 | install: 27 | - eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)" 28 | install: 29 | - if [[ "$TYPE" == "podspec" ]]; then sudo gem install bundler; bundle install; fi 30 | script: 31 | - ./test $TYPE 32 | -------------------------------------------------------------------------------- /Swiftility/Sources/Core/ObjcExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // swizzle.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/26/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // MARK: Swizzle 12 | public func swizzle(_ originalSelector: Selector, with swizzleSelector: Selector, on object: AnyClass) 13 | { 14 | guard 15 | let originalMethod = class_getInstanceMethod(object, originalSelector), 16 | let swizzleMethod = class_getInstanceMethod(object, swizzleSelector) else 17 | { 18 | return 19 | } 20 | 21 | if class_addMethod(object, originalSelector, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod)) { 22 | class_replaceMethod(object, swizzleSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) 23 | } else { 24 | method_exchangeImplementations(originalMethod, swizzleMethod) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UITabBarControllerExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UITabBarController.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 11/2/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UITabBarController 12 | { 13 | /// Retrives the first UIViewController matching the type given 14 | /// by looking at self.viewControllers children and for each the first child if it's a UINavigationController 15 | public func viewController() -> T? 16 | { 17 | guard let vcs = self.viewControllers else { return nil } 18 | 19 | for vc in vcs { 20 | if let vc = vc as? T { 21 | return vc 22 | } else if let navVC = vc as? UINavigationController, let vc = navVC.viewControllers.first as? T { 23 | return vc 24 | } 25 | } 26 | 27 | return nil 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/CollectionExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 7/5/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Collection 12 | { 13 | /// Returns an `Array` containing the results of mapping `transform` over `self` + Filters out the nil values. 14 | /// - Complexity: O(N). 15 | public func optionalMap(_ transform: (Self.Iterator.Element) throws -> T?) rethrows -> [T] 16 | { 17 | let count: Int = numericCast(self.count) 18 | guard count > 0 else { return [] } 19 | 20 | var results = [T]() 21 | 22 | results.reserveCapacity(count) 23 | 24 | for element in self { 25 | if let transformed = try transform(element) { 26 | results.append(transformed) 27 | } 28 | } 29 | 30 | return results 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/BeVoidTest.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Nimble 3 | 4 | final class BeVoidTest: XCTestCase, XCTestCaseProvider { 5 | static var allTests: [(String, (BeVoidTest) -> () throws -> Void)] { 6 | return [ 7 | ("testBeVoid", testBeVoid), 8 | ] 9 | } 10 | 11 | func testBeVoid() { 12 | expect(()).to(beVoid()) 13 | expect(() as ()?).to(beVoid()) 14 | expect(nil as ()?).toNot(beVoid()) 15 | 16 | expect(()) == () 17 | expect(() as ()?) == () 18 | expect(nil as ()?) != () 19 | 20 | failsWithErrorMessage("expected to not be void, got <()>") { 21 | expect(()).toNot(beVoid()) 22 | } 23 | 24 | failsWithErrorMessage("expected to not be void, got <()>") { 25 | expect(() as ()?).toNot(beVoid()) 26 | } 27 | 28 | failsWithErrorMessage("expected to be void, got ") { 29 | expect(nil as ()?).to(beVoid()) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Nimble/Sources/NimbleObjectiveC/NMBExceptionCapture.m: -------------------------------------------------------------------------------- 1 | #import "NMBExceptionCapture.h" 2 | 3 | @interface NMBExceptionCapture () 4 | @property (nonatomic, copy) void(^ _Nullable handler)(NSException * _Nullable); 5 | @property (nonatomic, copy) void(^ _Nullable finally)(void); 6 | @end 7 | 8 | @implementation NMBExceptionCapture 9 | 10 | - (nonnull instancetype)initWithHandler:(void(^ _Nullable)(NSException * _Nonnull))handler finally:(void(^ _Nullable)(void))finally { 11 | self = [super init]; 12 | if (self) { 13 | self.handler = handler; 14 | self.finally = finally; 15 | } 16 | return self; 17 | } 18 | 19 | - (void)tryBlock:(void(^ _Nonnull)(void))unsafeBlock { 20 | @try { 21 | unsafeBlock(); 22 | } 23 | @catch (NSException *exception) { 24 | if (self.handler) { 25 | self.handler(exception); 26 | } 27 | } 28 | @finally { 29 | if (self.finally) { 30 | self.finally(); 31 | } 32 | } 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UIFontExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIFontExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 1/8/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UIFont 12 | { 13 | /** 14 | Prints all the fonts available 15 | 16 | - parameter filter: Optional filter on the family name of the fonts 17 | */ 18 | public static func printAllFonts(familyFilter filter: String? = nil) 19 | { 20 | print("\n--- FONTS\((filter != nil) ? " familyFilter=\(filter!)" : "") ---\n") 21 | 22 | UIFont.familyNames.forEach { name in 23 | guard filter == nil || name.contains(filter!) else { return } 24 | 25 | print(name) 26 | 27 | UIFont.fontNames(forFamilyName: name).forEach { font in 28 | print(" \(font)") 29 | } 30 | } 31 | 32 | print("\n--- END FONTS ---\n") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSHumanReadableCopyright 24 | Copyright © 2014 Jeff Hui. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCMatchTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCMatchTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCMatchTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@"11:14").to(match(@"\\d{2}:\\d{2}")); 12 | expect(@"hello").toNot(match(@"\\d{2}:\\d{2}")); 13 | } 14 | 15 | - (void)testNegativeMatches { 16 | expectFailureMessage(@"expected to match <\\d{2}:\\d{2}>, got ", ^{ 17 | expect(@"hello").to(match(@"\\d{2}:\\d{2}")); 18 | }); 19 | expectFailureMessage(@"expected to not match <\\d{2}:\\d{2}>, got <11:22>", ^{ 20 | expect(@"11:22").toNot(match(@"\\d{2}:\\d{2}")); 21 | }); 22 | } 23 | 24 | - (void)testNilMatches { 25 | expectNilFailureMessage(@"expected to match <\\d{2}:\\d{2}>, got ", ^{ 26 | expect(nil).to(match(@"\\d{2}:\\d{2}")); 27 | }); 28 | expectNilFailureMessage(@"expected to not match <\\d{2}:\\d{2}>, got ", ^{ 29 | expect(nil).toNot(match(@"\\d{2}:\\d{2}")); 30 | }); 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Utils/SourceLocation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // Ideally we would always use `StaticString` as the type for tracking the file name 4 | // that expectations originate from, for consistency with `assert` etc. from the 5 | // stdlib, and because recent versions of the XCTest overlay require `StaticString` 6 | // when calling `XCTFail`. Under the Objective-C runtime (i.e. building on Mac), we 7 | // have to use `String` instead because StaticString can't be generated from Objective-C 8 | #if SWIFT_PACKAGE 9 | public typealias FileString = StaticString 10 | #else 11 | public typealias FileString = String 12 | #endif 13 | 14 | public final class SourceLocation: NSObject { 15 | public let file: FileString 16 | public let line: UInt 17 | 18 | override init() { 19 | file = "Unknown File" 20 | line = 0 21 | } 22 | 23 | init(file: FileString, line: UInt) { 24 | self.file = file 25 | self.line = line 26 | } 27 | 28 | override public var description: String { 29 | return "\(file):\(line)" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /SwiftilityTests/Extensions/ArrayExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArrayExtensionsTests.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/21/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import Swiftility 12 | 13 | class ArrayExtensionsTests: XCTestCase 14 | { 15 | func testGet() 16 | { 17 | let arr = ["0", "1", "2"] 18 | 19 | XCTAssert(arr.get(0) == "0") 20 | XCTAssert(arr.get(-0) == "0") 21 | XCTAssert(arr.get(-1) == nil) 22 | XCTAssert(arr.get(2) == "2") 23 | XCTAssert(arr.get(3) == nil) 24 | XCTAssert(arr.get(99999999999) == nil) 25 | XCTAssert(arr.get(-99999999999) == nil) 26 | } 27 | 28 | func testRemove() 29 | { 30 | var arr = ["0", "1", "2"] 31 | 32 | let removedIndex = arr.remove("0") 33 | XCTAssert(arr == ["1", "2"]) 34 | XCTAssert(removedIndex == 0) 35 | 36 | let notRemovedIndex = arr.remove("3") 37 | XCTAssert(arr == ["1", "2"]) 38 | XCTAssert(notRemovedIndex == nil) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Allan Barbato 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeKindOfTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeKindOfTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeKindOfTest 9 | 10 | - (void)testPositiveMatches { 11 | NSMutableArray *array = [NSMutableArray array]; 12 | expect(array).to(beAKindOf([NSArray class])); 13 | expect(@1).toNot(beAKindOf([NSNull class])); 14 | } 15 | 16 | - (void)testNegativeMatches { 17 | expectFailureMessage(@"expected to be a kind of NSNull, got <__NSCFNumber instance>", ^{ 18 | expect(@1).to(beAKindOf([NSNull class])); 19 | }); 20 | expectFailureMessage(@"expected to not be a kind of NSNull, got ", ^{ 21 | expect([NSNull null]).toNot(beAKindOf([NSNull class])); 22 | }); 23 | } 24 | 25 | - (void)testNilMatches { 26 | expectNilFailureMessage(@"expected to be a kind of NSNull, got ", ^{ 27 | expect(nil).to(beAKindOf([NSNull class])); 28 | }); 29 | expectNilFailureMessage(@"expected to not be a kind of NSNull, got ", ^{ 30 | expect(nil).toNot(beAKindOf([NSNull class])); 31 | }); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeginWithTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeginWithTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeginWithTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@"hello world!").to(beginWith(@"hello")); 12 | expect(@"hello world!").toNot(beginWith(@"world")); 13 | 14 | NSArray *array = @[@1, @2]; 15 | expect(array).to(beginWith(@1)); 16 | expect(array).toNot(beginWith(@2)); 17 | } 18 | 19 | - (void)testNegativeMatches { 20 | expectFailureMessage(@"expected to begin with , got ", ^{ 21 | expect(@"foo").to(beginWith(@"bar")); 22 | }); 23 | expectFailureMessage(@"expected to not begin with , got ", ^{ 24 | expect(@"foo").toNot(beginWith(@"foo")); 25 | }); 26 | } 27 | 28 | - (void)testNilMatches { 29 | expectNilFailureMessage(@"expected to begin with <1>, got ", ^{ 30 | expect(nil).to(beginWith(@1)); 31 | }); 32 | expectNilFailureMessage(@"expected to not begin with <1>, got ", ^{ 33 | expect(nil).toNot(beginWith(@1)); 34 | }); 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/ToSucceedTest.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Nimble 3 | 4 | final class ToSucceedTest: XCTestCase, XCTestCaseProvider { 5 | static var allTests: [(String, (ToSucceedTest) -> () throws -> Void)] { 6 | return [ 7 | ("testToSucceed", testToSucceed), 8 | ] 9 | } 10 | 11 | func testToSucceed() { 12 | expect({ 13 | return .succeeded 14 | }).to(succeed()) 15 | 16 | expect({ 17 | return .failed(reason: "") 18 | }).toNot(succeed()) 19 | 20 | failsWithErrorMessageForNil("expected a closure, got ") { 21 | expect(nil as (() -> ToSucceedResult)?).to(succeed()) 22 | } 23 | 24 | failsWithErrorMessage("expected to succeed, got because ") { 25 | expect({ 26 | .failed(reason: "something went wrong") 27 | }).to(succeed()) 28 | } 29 | 30 | failsWithErrorMessage("expected to not succeed, got ") { 31 | expect({ 32 | return .succeeded 33 | }).toNot(succeed()) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SwiftilityTests/Type Safe UIKIt/NibTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NibTests.swift 3 | // SwiftilityTests 4 | // 5 | // Created by Allan Barbato on 12/14/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import Nimble 11 | @testable import Swiftility 12 | 13 | class NibTests: XCTestCase 14 | { 15 | let storyboard = UIStoryboard(name: "MainStoryboard", bundle: Bundle(for: StoryboardTests.self)) 16 | 17 | func testNibConvertible() 18 | { 19 | let nib = NibsDefault.TestCell 20 | 21 | XCTAssert(nib.nibName == "TestCell") 22 | XCTAssert(nib.bundle == nil) 23 | } 24 | 25 | func testInstantiateFromNib() 26 | { 27 | // Instantiate non existing nib 28 | 29 | expect { 30 | _ = TestNonExistingCell.instantiateFromNib(NibContainer("TestNonExistingCell", bundle: Bundle(for: StoryboardTests.self))) 31 | }.to(throwAssertion()) 32 | 33 | // Instantiate existing nib 34 | 35 | _ = TestCell.instantiateFromNib() 36 | 37 | XCTAssert(true, "cell instantiation should not crash") 38 | } 39 | } 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UIApplicationExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIApplicationExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 12/21/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UIApplication 12 | { 13 | // MARK: - Settings 14 | 15 | public func openSettings(options: [String: Any] = [:], completionHandler completion: ((Bool) -> Void)? = nil) 16 | { 17 | let url = URL(string: UIApplicationOpenSettingsURLString)! 18 | 19 | if #available(iOS 10, *) { 20 | self.open(url, options: options, completionHandler: completion) 21 | } else { 22 | self.openURL(url) 23 | } 24 | } 25 | 26 | // MARK: - Push notifications 27 | 28 | @available(iOS, introduced: 8.0, deprecated: 10.0, message: "Use UserNotifications Framework's UNAuthorizationOptions") 29 | public func hasAllowedPushNotifications() -> Bool 30 | { 31 | guard let types = currentUserNotificationSettings?.types else { return false } 32 | 33 | return types != UIUserNotificationType() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCEndWithTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCEndWithTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCEndWithTest 9 | 10 | - (void)testPositiveMatches { 11 | NSArray *array = @[@1, @2]; 12 | expect(@"hello world!").to(endWith(@"world!")); 13 | expect(@"hello world!").toNot(endWith(@"hello")); 14 | expect(array).to(endWith(@2)); 15 | expect(array).toNot(endWith(@1)); 16 | expect(@1).toNot(contain(@"foo")); 17 | } 18 | 19 | - (void)testNegativeMatches { 20 | expectFailureMessage(@"expected to end with , got ", ^{ 21 | expect(@"hello world!").to(endWith(@"?")); 22 | }); 23 | expectFailureMessage(@"expected to not end with , got ", ^{ 24 | expect(@"hello world!").toNot(endWith(@"!")); 25 | }); 26 | } 27 | 28 | - (void)testNilMatches { 29 | expectNilFailureMessage(@"expected to end with <1>, got ", ^{ 30 | expect(nil).to(endWith(@1)); 31 | }); 32 | expectNilFailureMessage(@"expected to not end with <1>, got ", ^{ 33 | expect(nil).toNot(endWith(@1)); 34 | }); 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Adapters/NonObjectiveC/ExceptionCapture.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | #if !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) 4 | // swift-corelibs-foundation doesn't provide NSException at all, so provide a dummy 5 | class NSException {} 6 | #endif 7 | 8 | // NOTE: This file is not intended to be included in the Xcode project. It 9 | // is picked up by the Swift Package Manager during its build process. 10 | 11 | /// A dummy reimplementation of the `NMBExceptionCapture` class to serve 12 | /// as a stand-in for build and runtime environments that don't support 13 | /// Objective C. 14 | internal class ExceptionCapture { 15 | let finally: (() -> Void)? 16 | 17 | init(handler: ((NSException) -> Void)?, finally: (() -> Void)?) { 18 | self.finally = finally 19 | } 20 | 21 | func tryBlock(_ unsafeBlock: (() -> Void)) { 22 | // We have no way of handling Objective C exceptions in Swift, 23 | // so we just go ahead and run the unsafeBlock as-is 24 | unsafeBlock() 25 | 26 | finally?() 27 | } 28 | } 29 | 30 | /// Compatibility with the actual Objective-C implementation 31 | typealias NMBExceptionCapture = ExceptionCapture 32 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeAnInstanceOfTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeAnInstanceOfTest : XCTestCase 5 | @end 6 | 7 | @implementation ObjCBeAnInstanceOfTest 8 | 9 | - (void)testPositiveMatches { 10 | NSNull *obj = [NSNull null]; 11 | expect(obj).to(beAnInstanceOf([NSNull class])); 12 | expect(@1).toNot(beAnInstanceOf([NSNull class])); 13 | } 14 | 15 | - (void)testNegativeMatches { 16 | expectFailureMessage(@"expected to be an instance of NSNull, got <__NSCFNumber instance>", ^{ 17 | expect(@1).to(beAnInstanceOf([NSNull class])); 18 | }); 19 | expectFailureMessage(@"expected to not be an instance of NSNull, got ", ^{ 20 | expect([NSNull null]).toNot(beAnInstanceOf([NSNull class])); 21 | }); 22 | } 23 | 24 | - (void)testNilMatches { 25 | expectNilFailureMessage(@"expected to be an instance of NSNull, got ", ^{ 26 | expect(nil).to(beAnInstanceOf([NSNull class])); 27 | }); 28 | 29 | expectNilFailureMessage(@"expected to not be an instance of NSNull, got ", ^{ 30 | expect(nil).toNot(beAnInstanceOf([NSNull class])); 31 | }); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/Match.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual string satisfies the regular expression 4 | /// described by the expected string. 5 | public func match(_ expectedValue: String?) -> Predicate { 6 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 7 | failureMessage.postfixMessage = "match <\(stringify(expectedValue))>" 8 | 9 | if let actual = try actualExpression.evaluate() { 10 | if let regexp = expectedValue { 11 | return actual.range(of: regexp, options: .regularExpression) != nil 12 | } 13 | } 14 | 15 | return false 16 | }.requireNonNil 17 | } 18 | 19 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 20 | 21 | extension NMBObjCMatcher { 22 | @objc public class func matchMatcher(_ expected: NSString) -> NMBMatcher { 23 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 24 | let actual = actualExpression.cast { $0 as? String } 25 | return try! match(expected.description).matches(actual, failureMessage: failureMessage) 26 | } 27 | } 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /Swiftility/Sources/Type Safety/MVVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MVVM.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 1/29/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ViewModelController 12 | { 13 | associatedtype VM 14 | var viewModel: VM! { get set } 15 | } 16 | 17 | extension ViewModelController where Self: UIViewController 18 | { 19 | public init(viewModel: Self.VM) 20 | { 21 | self.init() 22 | 23 | self.viewModel = viewModel 24 | } 25 | } 26 | 27 | extension FromStoryboard where Self: UIViewController, Self: ViewModelController 28 | { 29 | public static func instantiateFromStoryboard(viewModel: Self.VM) -> Self 30 | { 31 | return UIStoryboard(name: self.storyboardName).instantiateViewController(Self.self, vm: viewModel) 32 | } 33 | } 34 | 35 | extension UIStoryboard 36 | { 37 | public func instantiateViewController(_ type: T.Type, vm: T.VM) -> T where T: UIViewController, T: ViewModelController 38 | { 39 | var vc: T = self.instantiateViewController() 40 | 41 | vc.viewModel = vm 42 | 43 | return vc 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UIScrollViewExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollViewExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 1/18/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UIScrollView 12 | { 13 | /** 14 | Horizontaly scroll rect to given page 15 | TODO: Verification of frame 16 | 17 | - parameter page: To scroll to 18 | - parameter animated: Show animation 19 | */ 20 | public func scroll(toPage page: Int, animated: Bool) 21 | { 22 | var frame = self.frame 23 | 24 | frame.origin.x = frame.size.width * CGFloat(page) 25 | frame.origin.y = 0 26 | 27 | self.scrollRectToVisible(frame, animated: animated) 28 | } 29 | 30 | /// Get or Set animated the current horizontal page 31 | public var currentPage: Int { 32 | get { 33 | let pageWidth = self.frame.size.width 34 | let fractionalPage = self.contentOffset.x / pageWidth 35 | 36 | return lround(Double(fractionalPage)) 37 | } 38 | 39 | set { 40 | self.scroll(toPage: newValue, animated: true) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/ToSucceed.swift: -------------------------------------------------------------------------------- 1 | /** 2 | Used by the `toSucceed` matcher. 3 | 4 | This is the return type for the closure. 5 | */ 6 | public enum ToSucceedResult { 7 | case succeeded 8 | case failed(reason: String) 9 | } 10 | 11 | /** 12 | A Nimble matcher that takes in a closure for validation. 13 | 14 | Return `.succeeded` when the validation succeeds. 15 | Return `.failed` with a failure reason when the validation fails. 16 | */ 17 | public func succeed() -> Predicate<() -> ToSucceedResult> { 18 | return Predicate.define { actualExpression in 19 | let optActual = try actualExpression.evaluate() 20 | guard let actual = optActual else { 21 | return PredicateResult(status: .fail, message: .fail("expected a closure, got ")) 22 | } 23 | 24 | switch actual() { 25 | case .succeeded: 26 | return PredicateResult( 27 | bool: true, 28 | message: .expectedCustomValueTo("succeed", "") 29 | ) 30 | case .failed(let reason): 31 | return PredicateResult( 32 | bool: false, 33 | message: .expectedCustomValueTo("succeed", " because <\(reason)>") 34 | ) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeTrueTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeTrueTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeTrueTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@YES).to(beTrue()); 12 | expect(@NO).toNot(beTrue()); 13 | expect(nil).toNot(beTrue()); 14 | 15 | expect(true).to(beTrue()); 16 | expect(false).toNot(beTrue()); 17 | 18 | expect(YES).to(beTrue()); 19 | expect(NO).toNot(beTrue()); 20 | } 21 | 22 | - (void)testNegativeMatches { 23 | expectFailureMessage(@"expected to be true, got <0>", ^{ 24 | expect(@NO).to(beTrue()); 25 | }); 26 | expectFailureMessage(@"expected to be true, got ", ^{ 27 | expect(nil).to(beTrue()); 28 | }); 29 | 30 | expectFailureMessage(@"expected to be true, got <0>", ^{ 31 | expect(false).to(beTrue()); 32 | }); 33 | 34 | expectFailureMessage(@"expected to not be true, got <1>", ^{ 35 | expect(true).toNot(beTrue()); 36 | }); 37 | 38 | expectFailureMessage(@"expected to be true, got <0>", ^{ 39 | expect(NO).to(beTrue()); 40 | }); 41 | 42 | expectFailureMessage(@"expected to not be true, got <1>", ^{ 43 | expect(YES).toNot(beTrue()); 44 | }); 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/ArrayExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArrayExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/15/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Array 12 | { 13 | /** 14 | Allow to fetch object optionally 15 | 16 | - parameter index: index to fetch 17 | 18 | - returns: Element of Array or nil if out of bounds 19 | */ 20 | public func get(_ index: Int) -> Element? 21 | { 22 | if index < self.count && index >= 0 { 23 | return self[index] 24 | } 25 | 26 | return nil 27 | } 28 | 29 | /** 30 | Removes the first object matching the passed object 31 | 32 | - parameter object: object to remove 33 | 34 | - returns: index of the removed element or nil if not found 35 | */ 36 | @discardableResult 37 | public mutating func remove(_ object: U) -> Int? 38 | { 39 | for (index, objectToCompare) in self.enumerated() { 40 | if let to = objectToCompare as? U, object == to { 41 | self.remove(at: index) 42 | return index 43 | } 44 | } 45 | 46 | return nil 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UIImageEffects/UIImageEffectsExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageEffectsExtension.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/22/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIImage 12 | { 13 | public func applyingLightEffect() -> UIImage? 14 | { 15 | return UIImageEffects.imageByApplyingLightEffect(to: self) 16 | } 17 | 18 | public func applyingExtraLightEffect() -> UIImage? 19 | { 20 | return UIImageEffects.imageByApplyingExtraLightEffect(to: self) 21 | } 22 | 23 | public func applyingDarkEffect() -> UIImage? 24 | { 25 | return UIImageEffects.imageByApplyingDarkEffect(to: self) 26 | } 27 | 28 | public func applyingTintEffect(with color: UIColor) -> UIImage? 29 | { 30 | return UIImageEffects.imageByApplyingTintEffect(with: color, to: self) 31 | } 32 | 33 | public func applyingBlur(withRadius radius: CGFloat, tintColor: UIColor? = nil, saturationDeltaFactor: CGFloat = 1.8, maskImage: UIImage? = nil) -> UIImage? 34 | { 35 | return UIImageEffects.imageByApplyingBlur(to: self, withRadius: radius, tintColor: tintColor, saturationDeltaFactor: saturationDeltaFactor, maskImage: maskImage) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeFalseTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeFalseTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeFalseTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@NO).to(beFalse()); 12 | expect(@YES).toNot(beFalse()); 13 | 14 | expect(false).to(beFalse()); 15 | expect(true).toNot(beFalse()); 16 | 17 | expect(NO).to(beFalse()); 18 | expect(YES).toNot(beFalse()); 19 | 20 | expect(10).toNot(beFalse()); 21 | } 22 | 23 | - (void)testNegativeMatches { 24 | expectNilFailureMessage(@"expected to be false, got ", ^{ 25 | expect(nil).to(beFalse()); 26 | }); 27 | expectNilFailureMessage(@"expected to not be false, got ", ^{ 28 | expect(nil).toNot(beFalse()); 29 | }); 30 | 31 | expectFailureMessage(@"expected to be false, got <1>", ^{ 32 | expect(true).to(beFalse()); 33 | }); 34 | expectFailureMessage(@"expected to not be false, got <0>", ^{ 35 | expect(false).toNot(beFalse()); 36 | }); 37 | 38 | expectFailureMessage(@"expected to be false, got <1>", ^{ 39 | expect(YES).to(beFalse()); 40 | }); 41 | expectFailureMessage(@"expected to not be false, got <0>", ^{ 42 | expect(NO).toNot(beFalse()); 43 | }); 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeLessThanTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeLessThanTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeLessThanTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@2).to(beLessThan(@3)); 12 | expect(@2).toNot(beLessThan(@2)); 13 | expect(2).to(beLessThan(3)); 14 | expect(2).toNot(beLessThan(2)); 15 | expect(2).toNot(beLessThan(0)); 16 | } 17 | 18 | - (void)testNegativeMatches { 19 | expectFailureMessage(@"expected to be less than <0>, got <1>", ^{ 20 | expect(@(1)).to(beLessThan(@0)); 21 | }); 22 | expectFailureMessage(@"expected to not be less than <1>, got <0>", ^{ 23 | expect(@0).toNot(beLessThan(@1)); 24 | }); 25 | expectFailureMessage(@"expected to be less than <0>, got <1>", ^{ 26 | expect(1).to(beLessThan(0)); 27 | }); 28 | expectFailureMessage(@"expected to not be less than <1>, got <0>", ^{ 29 | expect(0).toNot(beLessThan(1)); 30 | }); 31 | } 32 | 33 | - (void)testNilMatches { 34 | expectNilFailureMessage(@"expected to be less than <-1>, got ", ^{ 35 | expect(nil).to(beLessThan(@(-1))); 36 | }); 37 | expectNilFailureMessage(@"expected to not be less than <1>, got ", ^{ 38 | expect(nil).toNot(beLessThan(@1)); 39 | }); 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UIDeviceExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIDeviceExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 10/16/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | // MARK: - Properties 13 | extension UIDevice 14 | { 15 | public var version: Float { 16 | return (self.systemVersion as NSString).floatValue 17 | } 18 | 19 | public var isPhone: Bool { 20 | return self.userInterfaceIdiom == .phone 21 | } 22 | 23 | public var isPad: Bool { 24 | return self.userInterfaceIdiom == .pad 25 | } 26 | 27 | public var isRetina: Bool { 28 | return UIScreen.main.scale == 2.0 29 | } 30 | 31 | public var size: CGSize { 32 | return UIScreen.main.bounds.size 33 | } 34 | } 35 | 36 | // MARK: - Size 37 | extension UIDevice 38 | { 39 | public enum DeviceSize: CGFloat, Equatable, Comparable 40 | { 41 | case inches_3_5 = 480 42 | case inches_4 = 568 43 | case inches_4_7 = 667 44 | case inches_5_5 = 736 45 | } 46 | 47 | public var deviceSize: DeviceSize { 48 | guard let size = DeviceSize(rawValue: self.size.height) else { 49 | fatalError("Size not handled") 50 | } 51 | 52 | return size 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Nimble/Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/Posix/CwlPreconditionTesting.h: -------------------------------------------------------------------------------- 1 | // 2 | // CwlPreconditionTesting.h 3 | // CwlPreconditionTesting 4 | // 5 | // Created by Matt Gallagher on 2016/01/10. 6 | // Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved. 7 | // 8 | // Permission to use, copy, modify, and/or distribute this software for any 9 | // purpose with or without fee is hereby granted, provided that the above 10 | // copyright notice and this permission notice appear in all copies. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 15 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 18 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | // 20 | 21 | #import 22 | 23 | //! Project version number for CwlUtils. 24 | FOUNDATION_EXPORT double CwlPreconditionTestingVersionNumber; 25 | 26 | //! Project version string for CwlUtils. 27 | FOUNDATION_EXPORT const unsigned char CwlAssertingTestingVersionString[]; 28 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCSatisfyAnyOfTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCSatisfyAnyOfTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCSatisfyAnyOfTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@2).to(satisfyAnyOf(equal(@2), equal(@3))); 12 | expect(@2).toNot(satisfyAnyOf(equal(@3), equal(@16))); 13 | expect(@[@1, @2, @3]).to(satisfyAnyOf(equal(@[@1, @2, @3]), allPass(beLessThan(@4)))); 14 | expect(@NO).to(satisfyAnyOf(beTrue(), beFalse())); 15 | expect(@YES).to(satisfyAnyOf(beTrue(), beFalse())); 16 | } 17 | 18 | - (void)testNegativeMatches { 19 | expectFailureMessage(@"expected to match one of: {equal <3>}, or {equal <4>}, or {equal <5>}, got 2", ^{ 20 | expect(@2).to(satisfyAnyOf(equal(@3), equal(@4), equal(@5))); 21 | }); 22 | 23 | expectFailureMessage(@"expected to match one of: {all be less than <4>, but failed first at element" 24 | " <5> in <[5, 6, 7]>}, or {equal <(1, 2, 3, 4)>}, got (5,6,7)", ^{ 25 | expect(@[@5, @6, @7]).to(satisfyAnyOf(allPass(beLessThan(@4)), equal(@[@1, @2, @3, @4]))); 26 | }); 27 | 28 | expectFailureMessage(@"satisfyAnyOf must be called with at least one matcher", ^{ 29 | expect(@"turtles").to(satisfyAnyOf()); 30 | }); 31 | } 32 | @end 33 | -------------------------------------------------------------------------------- /Nimble/Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import NimbleTests 3 | 4 | // This is the entry point for NimbleTests on Linux 5 | 6 | XCTMain([ 7 | testCase(AsyncTest.allTests), 8 | testCase(SynchronousTest.allTests), 9 | testCase(UserDescriptionTest.allTests), 10 | 11 | // Matchers 12 | testCase(AllPassTest.allTests), 13 | testCase(BeAKindOfSwiftTest.allTests), 14 | testCase(BeAnInstanceOfTest.allTests), 15 | testCase(BeCloseToTest.allTests), 16 | testCase(BeginWithTest.allTests), 17 | testCase(BeGreaterThanOrEqualToTest.allTests), 18 | testCase(BeGreaterThanTest.allTests), 19 | testCase(BeIdenticalToObjectTest.allTests), 20 | testCase(BeIdenticalToTest.allTests), 21 | testCase(BeLessThanOrEqualToTest.allTests), 22 | testCase(BeLessThanTest.allTests), 23 | testCase(BeTruthyTest.allTests), 24 | testCase(BeTrueTest.allTests), 25 | testCase(BeFalsyTest.allTests), 26 | testCase(BeFalseTest.allTests), 27 | testCase(BeNilTest.allTests), 28 | testCase(ContainTest.allTests), 29 | testCase(EndWithTest.allTests), 30 | testCase(EqualTest.allTests), 31 | testCase(HaveCountTest.allTests), 32 | testCase(MatchTest.allTests), 33 | // testCase(RaisesExceptionTest.allTests), 34 | testCase(ThrowErrorTest.allTests), 35 | testCase(SatisfyAnyOfTest.allTests), 36 | testCase(PostNotificationTest.allTests), 37 | ]) 38 | -------------------------------------------------------------------------------- /Nimble/.github/ISSUE_TEMPLATE: -------------------------------------------------------------------------------- 1 | - [ ] I have read [CONTRIBUTING](https://github.com/Quick/Nimble/blob/master/CONTRIBUTING.md) and have done my best to follow them. 2 | 3 | ### What did you do? 4 | 5 | Please replace this with what you did. 6 | 7 | ### What did you expect to happen? 8 | 9 | Please replace this with what you expected to happen. 10 | 11 | ### What actually happened instead? 12 | 13 | Please replace this with what happened instead. 14 | 15 | ### Environment 16 | 17 | List the software versions you're using: 18 | 19 | - Quick: *?.?.?* 20 | - Nimble: *?.?.?* 21 | - Xcode Version: *?.? (????)* (Open Xcode; In menubar: Xcode > About Xcode) 22 | - Swift Version: *?.?* (Open Xcode Preferences; Components > Toolchains. If none, use `Xcode Default`.) 23 | 24 | Please also mention which package manager you used and its version. Delete the 25 | other package managers in this list: 26 | 27 | - Cocoapods: *?.?.?* (Use `pod --version` in Terminal) 28 | - Carthage: *?.?* (Use `carthage version` in Terminal) 29 | - Swift Package Manager *?.?.? (swiftpm-???)* (Use `swift build --version` in Terminal) 30 | 31 | ### Project that demonstrates the issue 32 | 33 | Please link to a project we can download that reproduces the issue. Feel free 34 | to delete this section if it's not relevant to the issue (eg - feature request). 35 | 36 | The project should be [short, self-contained, and correct example](http://sscce.org/). 37 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/Foundation/Operation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Operation.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 12/22/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class ConcurrentOperation: Operation 12 | { 13 | override open var isAsynchronous: Bool { 14 | return true 15 | } 16 | 17 | private var _executing = false { 18 | willSet { 19 | willChangeValue(forKey: "isExecuting") 20 | } 21 | didSet { 22 | didChangeValue(forKey: "isExecuting") 23 | } 24 | } 25 | 26 | override open var isExecuting: Bool { 27 | return _executing 28 | } 29 | 30 | private var _finished = false { 31 | willSet { 32 | willChangeValue(forKey: "isFinished") 33 | } 34 | 35 | didSet { 36 | didChangeValue(forKey: "isFinished") 37 | } 38 | } 39 | 40 | override open var isFinished: Bool { 41 | return _finished 42 | } 43 | 44 | override open func start() 45 | { 46 | _executing = true 47 | execute() 48 | } 49 | 50 | open func execute() 51 | { 52 | // Execute your async task here. 53 | } 54 | 55 | open func finish() 56 | { 57 | _executing = false 58 | _finished = true 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeGreaterThanTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeGreaterThanTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeGreaterThanTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@2).to(beGreaterThan(@1)); 12 | expect(@2).toNot(beGreaterThan(@2)); 13 | expect(@2).to(beGreaterThan(0)); 14 | expect(@2).toNot(beGreaterThan(2)); 15 | expect(2.5).to(beGreaterThan(1.5)); 16 | } 17 | 18 | - (void)testNegativeMatches { 19 | expectFailureMessage(@"expected to be greater than <0>, got <-1>", ^{ 20 | expect(@(-1)).to(beGreaterThan(@(0))); 21 | }); 22 | expectFailureMessage(@"expected to not be greater than <1>, got <2>", ^{ 23 | expect(@2).toNot(beGreaterThan(@(1))); 24 | }); 25 | expectFailureMessage(@"expected to be greater than <0>, got <-1>", ^{ 26 | expect(-1).to(beGreaterThan(0)); 27 | }); 28 | expectFailureMessage(@"expected to not be greater than <1>, got <2>", ^{ 29 | expect(2).toNot(beGreaterThan(1)); 30 | }); 31 | } 32 | 33 | - (void)testNilMatches { 34 | expectNilFailureMessage(@"expected to be greater than <-1>, got ", ^{ 35 | expect(nil).to(beGreaterThan(@(-1))); 36 | }); 37 | expectNilFailureMessage(@"expected to not be greater than <1>, got ", ^{ 38 | expect(nil).toNot(beGreaterThan(@(1))); 39 | }); 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Nimble/Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/Mach/CwlPreconditionTesting.h: -------------------------------------------------------------------------------- 1 | // 2 | // CwlPreconditionTesting.h 3 | // CwlPreconditionTesting 4 | // 5 | // Created by Matt Gallagher on 2016/01/10. 6 | // Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved. 7 | // 8 | // Permission to use, copy, modify, and/or distribute this software for any 9 | // purpose with or without fee is hereby granted, provided that the above 10 | // copyright notice and this permission notice appear in all copies. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 15 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 18 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | // 20 | 21 | #import 22 | 23 | //! Project version number for CwlUtils. 24 | FOUNDATION_EXPORT double CwlPreconditionTestingVersionNumber; 25 | 26 | //! Project version string for CwlUtils. 27 | FOUNDATION_EXPORT const unsigned char CwlAssertingTestingVersionString[]; 28 | 29 | #include "CwlMachBadInstructionHandler.h" 30 | #include "CwlCatchException.h" 31 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/Foundation/NotificationCenterExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationCenterExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 10/26/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension NotificationCenter 12 | { 13 | /// NSNotificationCenter.addObserver:forName with default parameters 14 | public func addObserver(withName name: NSNotification.Name, 15 | object obj: Any? = nil, 16 | queue: OperationQueue? = nil, 17 | using closure: @escaping (Notification) -> Void) -> NSObjectProtocol 18 | { 19 | return self.addObserver(forName: name, object: obj, queue: queue, using: closure) 20 | } 21 | 22 | /// Applying NSNotificationCenter.addObserverWithName for all the notifications in `names` 23 | public func addObserver(withNames names: [NSNotification.Name], 24 | object obj: Any? = nil, 25 | queue: OperationQueue? = nil, 26 | using closure: @escaping (Notification) -> Void) -> [NSObjectProtocol] 27 | { 28 | return names.map { self.addObserver(forName: $0, object: obj, queue: queue, using: closure) } 29 | } 30 | 31 | /// Applying NSNotificationCenter.removeObserver to list of observers 32 | public func removeObservers(_ observers: [Any]) 33 | { 34 | observers.forEach { 35 | self.removeObserver($0) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Nimble/Sources/Lib/CwlPreconditionTesting/CwlCatchExceptionSupport/CwlCatchException.m: -------------------------------------------------------------------------------- 1 | // 2 | // CwlCatchException.m 3 | // CwlAssertionTesting 4 | // 5 | // Created by Matt Gallagher on 2016/01/10. 6 | // Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved. 7 | // 8 | // Permission to use, copy, modify, and/or distribute this software for any 9 | // purpose with or without fee is hereby granted, provided that the above 10 | // copyright notice and this permission notice appear in all copies. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 15 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 18 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | // 20 | 21 | #import "CwlCatchException.h" 22 | 23 | #if !SWIFT_PACKAGE && NON_SWIFT_PACKAGE 24 | __attribute__((visibility("hidden"))) 25 | #endif 26 | NSException* catchExceptionOfKind(Class __nonnull type, __attribute__((noescape)) void (^ __nonnull inBlock)(void)) { 27 | @try { 28 | inBlock(); 29 | } @catch (NSException *exception) { 30 | if ([exception isKindOfClass:type]) { 31 | return exception; 32 | } else { 33 | @throw; 34 | } 35 | } 36 | return nil; 37 | } 38 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeLessThanOrEqualToTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeLessThanOrEqualToTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeLessThanOrEqualToTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@2).to(beLessThanOrEqualTo(@2)); 12 | expect(@2).toNot(beLessThanOrEqualTo(@1)); 13 | expect(2).to(beLessThanOrEqualTo(2)); 14 | expect(2).toNot(beLessThanOrEqualTo(1)); 15 | expect(2).toNot(beLessThanOrEqualTo(0)); 16 | } 17 | 18 | - (void)testNegativeMatches { 19 | expectFailureMessage(@"expected to be less than or equal to <1>, got <2>", ^{ 20 | expect(@2).to(beLessThanOrEqualTo(@1)); 21 | }); 22 | expectFailureMessage(@"expected to not be less than or equal to <1>, got <1>", ^{ 23 | expect(@1).toNot(beLessThanOrEqualTo(@1)); 24 | }); 25 | 26 | expectFailureMessage(@"expected to be less than or equal to <1>, got <2>", ^{ 27 | expect(2).to(beLessThanOrEqualTo(1)); 28 | }); 29 | expectFailureMessage(@"expected to not be less than or equal to <1>, got <1>", ^{ 30 | expect(1).toNot(beLessThanOrEqualTo(1)); 31 | }); 32 | } 33 | 34 | - (void)testNilMatches { 35 | expectNilFailureMessage(@"expected to be less than or equal to <1>, got ", ^{ 36 | expect(nil).to(beLessThanOrEqualTo(@1)); 37 | }); 38 | expectNilFailureMessage(@"expected to not be less than or equal to <-1>, got ", ^{ 39 | expect(nil).toNot(beLessThanOrEqualTo(@(-1))); 40 | }); 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /SwiftilityTests/Type Safe UIKIt/Common/TestCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Adapters/NimbleEnvironment.swift: -------------------------------------------------------------------------------- 1 | import Dispatch 2 | import Foundation 3 | 4 | /// "Global" state of Nimble is stored here. Only DSL functions should access / be aware of this 5 | /// class' existence 6 | internal class NimbleEnvironment { 7 | static var activeInstance: NimbleEnvironment { 8 | get { 9 | let env = Thread.current.threadDictionary["NimbleEnvironment"] 10 | if let env = env as? NimbleEnvironment { 11 | return env 12 | } else { 13 | let newEnv = NimbleEnvironment() 14 | self.activeInstance = newEnv 15 | return newEnv 16 | } 17 | } 18 | set { 19 | Thread.current.threadDictionary["NimbleEnvironment"] = newValue 20 | } 21 | } 22 | 23 | // TODO: eventually migrate the global to this environment value 24 | var assertionHandler: AssertionHandler { 25 | get { return NimbleAssertionHandler } 26 | set { NimbleAssertionHandler = newValue } 27 | } 28 | 29 | var suppressTVOSAssertionWarning: Bool = false 30 | var awaiter: Awaiter 31 | 32 | init() { 33 | let timeoutQueue: DispatchQueue 34 | if #available(OSX 10.10, *) { 35 | timeoutQueue = DispatchQueue.global(qos: .userInitiated) 36 | } else { 37 | timeoutQueue = DispatchQueue.global(priority: .high) 38 | } 39 | 40 | awaiter = Awaiter( 41 | waitLock: AssertionWaitLock(), 42 | asyncQueue: .main, 43 | timeoutQueue: timeoutQueue) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Nimble/Sources/Lib/CwlPreconditionTesting/CwlCatchExceptionSupport/include/CwlCatchException.h: -------------------------------------------------------------------------------- 1 | // 2 | // CwlCatchException.h 3 | // CwlCatchException 4 | // 5 | // Created by Matt Gallagher on 2016/01/10. 6 | // Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved. 7 | // 8 | // Permission to use, copy, modify, and/or distribute this software for any 9 | // purpose with or without fee is hereby granted, provided that the above 10 | // copyright notice and this permission notice appear in all copies. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 15 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 18 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | // 20 | 21 | #import 22 | 23 | //! Project version number for CwlCatchException. 24 | FOUNDATION_EXPORT double CwlCatchExceptionVersionNumber; 25 | 26 | //! Project version string for CwlCatchException. 27 | FOUNDATION_EXPORT const unsigned char CwlCatchExceptionVersionString[]; 28 | 29 | #if !SWIFT_PACKAGE && NON_SWIFT_PACKAGE 30 | __attribute__((visibility("hidden"))) 31 | #endif 32 | NSException* __nullable catchExceptionOfKind(Class __nonnull type, __attribute__((noescape)) void (^ __nonnull inBlock)(void)); 33 | 34 | -------------------------------------------------------------------------------- /Nimble/Sources/Lib/CwlPreconditionTesting/CwlCatchException/CwlCatchException.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CwlCatchException.swift 3 | // CwlAssertionTesting 4 | // 5 | // Created by Matt Gallagher on 2016/01/10. 6 | // Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved. 7 | // 8 | // Permission to use, copy, modify, and/or distribute this software for any 9 | // purpose with or without fee is hereby granted, provided that the above 10 | // copyright notice and this permission notice appear in all copies. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 15 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 18 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | // 20 | 21 | import Foundation 22 | 23 | #if SWIFT_PACKAGE 24 | import CwlCatchExceptionSupport 25 | #endif 26 | 27 | private func catchReturnTypeConverter(_ instance: T, block: () -> Void) -> T? { 28 | // Get the type from an *instance*, instead of a receiving the type directly 29 | return catchExceptionOfKind(T.self, block) as? T 30 | } 31 | 32 | extension NSException { 33 | public static func catchException(in block: () -> Void) -> Self? { 34 | // Use a dummy instance of Self to provide the type 35 | return catchReturnTypeConverter(self.init(), block: block) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeCloseToTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeCloseToTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeCloseToTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@1.2).to(beCloseTo(@1.2001)); 12 | expect(@1.2).to(beCloseTo(@2).within(10)); 13 | expect(@2).toNot(beCloseTo(@1)); 14 | expect(@1.00001).toNot(beCloseTo(@1).within(0.00000001)); 15 | 16 | expect(1.2).to(beCloseTo(1.2001)); 17 | expect(1.2).to(beCloseTo(2).within(10)); 18 | expect(2).toNot(beCloseTo(1)); 19 | expect(1.00001).toNot(beCloseTo(1).within(0.00000001)); 20 | } 21 | 22 | - (void)testNegativeMatches { 23 | expectFailureMessage(@"expected to be close to <0> (within 0.001), got <1>", ^{ 24 | expect(@1).to(beCloseTo(@0)); 25 | }); 26 | expectFailureMessage(@"expected to not be close to <0> (within 0.001), got <0.0001>", ^{ 27 | expect(@(0.0001)).toNot(beCloseTo(@0)); 28 | }); 29 | expectFailureMessage(@"expected to be close to <0> (within 0.001), got <1>", ^{ 30 | expect(1).to(beCloseTo(0)); 31 | }); 32 | expectFailureMessage(@"expected to not be close to <0> (within 0.001), got <0.0001>", ^{ 33 | expect(0.0001).toNot(beCloseTo(0)); 34 | }); 35 | } 36 | 37 | - (void)testNilMatches { 38 | expectNilFailureMessage(@"expected to be close to <0> (within 0.001), got ", ^{ 39 | expect(nil).to(beCloseTo(@0)); 40 | }); 41 | expectNilFailureMessage(@"expected to not be close to <0> (within 0.001), got ", ^{ 42 | expect(nil).toNot(beCloseTo(@0)); 43 | }); 44 | } 45 | 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /SwiftilityTests/Type Safe UIKIt/Common/TestCollectionViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/MatchTest.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Nimble 3 | 4 | final class MatchTest: XCTestCase, XCTestCaseProvider { 5 | static var allTests: [(String, (MatchTest) -> () throws -> Void)] { 6 | return [ 7 | ("testMatchPositive", testMatchPositive), 8 | ("testMatchNegative", testMatchNegative), 9 | ("testMatchPositiveMessage", testMatchPositiveMessage), 10 | ("testMatchNegativeMessage", testMatchNegativeMessage), 11 | ("testMatchNils", testMatchNils), 12 | ] 13 | } 14 | 15 | func testMatchPositive() { 16 | expect("11:14").to(match("\\d{2}:\\d{2}")) 17 | } 18 | 19 | func testMatchNegative() { 20 | expect("hello").toNot(match("\\d{2}:\\d{2}")) 21 | } 22 | 23 | func testMatchPositiveMessage() { 24 | let message = "expected to match <\\d{2}:\\d{2}>, got " 25 | failsWithErrorMessage(message) { 26 | expect("hello").to(match("\\d{2}:\\d{2}")) 27 | } 28 | } 29 | 30 | func testMatchNegativeMessage() { 31 | let message = "expected to not match <\\d{2}:\\d{2}>, got <11:14>" 32 | failsWithErrorMessage(message) { 33 | expect("11:14").toNot(match("\\d{2}:\\d{2}")) 34 | } 35 | } 36 | 37 | func testMatchNils() { 38 | failsWithErrorMessageForNil("expected to match <\\d{2}:\\d{2}>, got ") { 39 | expect(nil as String?).to(match("\\d{2}:\\d{2}")) 40 | } 41 | 42 | failsWithErrorMessageForNil("expected to not match <\\d{2}:\\d{2}>, got ") { 43 | expect(nil as String?).toNot(match("\\d{2}:\\d{2}")) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCAsyncTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "NimbleSpecHelper.h" 4 | 5 | @interface ObjCAsyncTest : XCTestCase 6 | 7 | @end 8 | 9 | @implementation ObjCAsyncTest 10 | 11 | - (void)testAsync { 12 | __block id obj = @1; 13 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 14 | obj = nil; 15 | }); 16 | expect(obj).toEventually(beNil()); 17 | } 18 | 19 | 20 | - (void)testAsyncWithCustomTimeout { 21 | __block id obj = nil; 22 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 23 | obj = @1; 24 | }); 25 | expect(obj).withTimeout(5).toEventuallyNot(beNil()); 26 | } 27 | 28 | - (void)testAsyncCallback { 29 | waitUntil(^(void (^done)(void)){ 30 | done(); 31 | }); 32 | 33 | expectFailureMessage(@"Waited more than 1.0 second", ^{ 34 | waitUntil(^(void (^done)(void)){ /* ... */ }); 35 | }); 36 | 37 | expectFailureMessage(@"Waited more than 0.01 seconds", ^{ 38 | waitUntilTimeout(0.01, ^(void (^done)(void)){ 39 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 40 | [NSThread sleepForTimeInterval:0.1]; 41 | done(); 42 | }); 43 | }); 44 | }); 45 | 46 | expectFailureMessage(@"expected to equal , got ", ^{ 47 | waitUntil(^(void (^done)(void)){ 48 | [NSThread sleepForTimeInterval:0.1]; 49 | expect(@"hello").to(equal(@"goodbye")); 50 | done(); 51 | }); 52 | }); 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeGreaterThanOrEqualToTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeGreaterThanOrEqualToTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeGreaterThanOrEqualToTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@2).to(beGreaterThanOrEqualTo(@2)); 12 | expect(@2).toNot(beGreaterThanOrEqualTo(@3)); 13 | expect(2).to(beGreaterThanOrEqualTo(0)); 14 | expect(2).to(beGreaterThanOrEqualTo(2)); 15 | expect(2).toNot(beGreaterThanOrEqualTo(3)); 16 | expect(2.5).to(beGreaterThanOrEqualTo(2)); 17 | expect(2.5).to(beGreaterThanOrEqualTo(2.5)); 18 | } 19 | 20 | - (void)testNegativeMatches { 21 | expectFailureMessage(@"expected to be greater than or equal to <0>, got <-1>", ^{ 22 | expect(@(-1)).to(beGreaterThanOrEqualTo(@0)); 23 | }); 24 | expectFailureMessage(@"expected to not be greater than or equal to <1>, got <2>", ^{ 25 | expect(@2).toNot(beGreaterThanOrEqualTo(@(1))); 26 | }); 27 | expectFailureMessage(@"expected to be greater than or equal to <0>, got <-1>", ^{ 28 | expect(-1).to(beGreaterThanOrEqualTo(0)); 29 | }); 30 | expectFailureMessage(@"expected to not be greater than or equal to <1>, got <2>", ^{ 31 | expect(2).toNot(beGreaterThanOrEqualTo(1)); 32 | }); 33 | } 34 | 35 | - (void)testNilMatches { 36 | expectNilFailureMessage(@"expected to be greater than or equal to <-1>, got ", ^{ 37 | expect(nil).to(beGreaterThanOrEqualTo(@(-1))); 38 | }); 39 | expectNilFailureMessage(@"expected to not be greater than or equal to <1>, got ", ^{ 40 | expect(nil).toNot(beGreaterThanOrEqualTo(@(1))); 41 | }); 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeFalsyTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeFalsyTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeFalsyTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@NO).to(beFalsy()); 12 | expect(@YES).toNot(beFalsy()); 13 | expect(nil).to(beFalsy()); 14 | 15 | expect(true).toNot(beFalsy()); 16 | expect(false).to(beFalsy()); 17 | 18 | expect(YES).toNot(beFalsy()); 19 | expect(NO).to(beFalsy()); 20 | 21 | expect(10).toNot(beFalsy()); 22 | expect(0).to(beFalsy()); 23 | } 24 | 25 | - (void)testNegativeMatches { 26 | expectFailureMessage(@"expected to not be falsy, got ", ^{ 27 | expect(nil).toNot(beFalsy()); 28 | }); 29 | expectFailureMessage(@"expected to be falsy, got <1>", ^{ 30 | expect(@1).to(beFalsy()); 31 | }); 32 | expectFailureMessage(@"expected to not be falsy, got <0>", ^{ 33 | expect(@NO).toNot(beFalsy()); 34 | }); 35 | 36 | expectFailureMessage(@"expected to be falsy, got <1>", ^{ 37 | expect(true).to(beFalsy()); 38 | }); 39 | expectFailureMessage(@"expected to not be falsy, got <0>", ^{ 40 | expect(false).toNot(beFalsy()); 41 | }); 42 | 43 | expectFailureMessage(@"expected to be falsy, got <1>", ^{ 44 | expect(YES).to(beFalsy()); 45 | }); 46 | expectFailureMessage(@"expected to not be falsy, got <0>", ^{ 47 | expect(NO).toNot(beFalsy()); 48 | }); 49 | 50 | expectFailureMessage(@"expected to be falsy, got <10>", ^{ 51 | expect(10).to(beFalsy()); 52 | }); 53 | expectFailureMessage(@"expected to not be falsy, got <0>", ^{ 54 | expect(0).toNot(beFalsy()); 55 | }); 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeTruthyTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeTruthyTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeTruthyTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@YES).to(beTruthy()); 12 | expect(@NO).toNot(beTruthy()); 13 | expect(nil).toNot(beTruthy()); 14 | 15 | expect(true).to(beTruthy()); 16 | expect(false).toNot(beTruthy()); 17 | 18 | expect(YES).to(beTruthy()); 19 | expect(NO).toNot(beTruthy()); 20 | 21 | expect(10).to(beTruthy()); 22 | expect(0).toNot(beTruthy()); 23 | } 24 | 25 | - (void)testNegativeMatches { 26 | expectFailureMessage(@"expected to be truthy, got ", ^{ 27 | expect(nil).to(beTruthy()); 28 | }); 29 | expectFailureMessage(@"expected to not be truthy, got <1>", ^{ 30 | expect(@1).toNot(beTruthy()); 31 | }); 32 | expectFailureMessage(@"expected to be truthy, got <0>", ^{ 33 | expect(@NO).to(beTruthy()); 34 | }); 35 | expectFailureMessage(@"expected to be truthy, got <0>", ^{ 36 | expect(false).to(beTruthy()); 37 | }); 38 | expectFailureMessage(@"expected to not be truthy, got <1>", ^{ 39 | expect(true).toNot(beTruthy()); 40 | }); 41 | expectFailureMessage(@"expected to be truthy, got <0>", ^{ 42 | expect(NO).to(beTruthy()); 43 | }); 44 | expectFailureMessage(@"expected to not be truthy, got <1>", ^{ 45 | expect(YES).toNot(beTruthy()); 46 | }); 47 | expectFailureMessage(@"expected to not be truthy, got <10>", ^{ 48 | expect(10).toNot(beTruthy()); 49 | }); 50 | expectFailureMessage(@"expected to be truthy, got <0>", ^{ 51 | expect(0).to(beTruthy()); 52 | }); 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCAllPassTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCAllPassTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCAllPassTest 9 | 10 | - (void)testPositiveMatches { 11 | expect(@[@1, @2, @3,@4]).to(allPass(beLessThan(@5))); 12 | expect(@[@1, @2, @3,@4]).toNot(allPass(beGreaterThan(@5))); 13 | 14 | expect([NSSet setWithArray:@[@1, @2, @3,@4]]).to(allPass(beLessThan(@5))); 15 | expect([NSSet setWithArray:@[@1, @2, @3,@4]]).toNot(allPass(beGreaterThan(@5))); 16 | } 17 | 18 | - (void)testNegativeMatches { 19 | expectFailureMessage(@"expected to all be less than <3>, but failed first at element" 20 | " <3> in <[1, 2, 3, 4]>", ^{ 21 | expect(@[@1, @2, @3, @4]).to(allPass(beLessThan(@3))); 22 | }); 23 | expectFailureMessage(@"expected to not all be less than <5>", ^{ 24 | expect(@[@1, @2, @3, @4]).toNot(allPass(beLessThan(@5))); 25 | }); 26 | expectFailureMessage(@"expected to not all be less than <5>", ^{ 27 | expect([NSSet setWithArray:@[@1, @2, @3, @4]]).toNot(allPass(beLessThan(@5))); 28 | }); 29 | expectFailureMessage(@"allPass can only be used with types which implement NSFastEnumeration " 30 | "(NSArray, NSSet, ...), and whose elements subclass NSObject, got <3>", ^{ 31 | expect(@3).to(allPass(beLessThan(@5))); 32 | }); 33 | expectFailureMessage(@"allPass can only be used with types which implement NSFastEnumeration " 34 | "(NSArray, NSSet, ...), and whose elements subclass NSObject, got <3>", ^{ 35 | expect(@3).toNot(allPass(beLessThan(@5))); 36 | }); 37 | } 38 | @end 39 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/BeIdenticalTo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is the same instance 4 | /// as the expected instance. 5 | public func beIdenticalTo(_ expected: Any?) -> Predicate { 6 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 7 | #if os(Linux) 8 | let actual = try actualExpression.evaluate() as? AnyObject 9 | #else 10 | let actual = try actualExpression.evaluate() as AnyObject? 11 | #endif 12 | failureMessage.actualValue = "\(identityAsString(actual))" 13 | failureMessage.postfixMessage = "be identical to \(identityAsString(expected))" 14 | #if os(Linux) 15 | return actual === (expected as? AnyObject) && actual !== nil 16 | #else 17 | return actual === (expected as AnyObject?) && actual !== nil 18 | #endif 19 | }.requireNonNil 20 | } 21 | 22 | public func === (lhs: Expectation, rhs: Any?) { 23 | lhs.to(beIdenticalTo(rhs)) 24 | } 25 | public func !== (lhs: Expectation, rhs: Any?) { 26 | lhs.toNot(beIdenticalTo(rhs)) 27 | } 28 | 29 | /// A Nimble matcher that succeeds when the actual value is the same instance 30 | /// as the expected instance. 31 | /// 32 | /// Alias for "beIdenticalTo". 33 | public func be(_ expected: Any?) -> Predicate { 34 | return beIdenticalTo(expected) 35 | } 36 | 37 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 38 | extension NMBObjCMatcher { 39 | @objc public class func beIdenticalToMatcher(_ expected: NSObject?) -> NMBObjCMatcher { 40 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 41 | let aExpr = actualExpression.cast { $0 as Any? } 42 | return try! beIdenticalTo(expected).matches(aExpr, failureMessage: failureMessage) 43 | } 44 | } 45 | } 46 | #endif 47 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UICollectionViewExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UICollectionViewExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 6/7/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UICollectionView 12 | { 13 | public func targetCenteredContentOffset(proposedContentOffset offset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint 14 | { 15 | let cvBounds = self.bounds 16 | let halfWidth = cvBounds.size.width * 0.5 17 | let proposedContentOffsetCenterX = offset.x + halfWidth 18 | 19 | guard let attributesForVisibleCells = self.collectionViewLayout.layoutAttributesForElements(in: cvBounds) else { return offset } 20 | 21 | var candidateAttributes: UICollectionViewLayoutAttributes? 22 | 23 | for attributes in attributesForVisibleCells { 24 | 25 | guard let candAttrs = candidateAttributes else { 26 | candidateAttributes = attributes 27 | continue 28 | } 29 | 30 | let a = attributes.center.x - proposedContentOffsetCenterX 31 | let b = candAttrs.center.x - proposedContentOffsetCenterX 32 | 33 | if fabsf(Float(a)) < fabsf(Float(b)) { 34 | candidateAttributes = attributes 35 | } 36 | } 37 | 38 | return CGPoint(x: round(candidateAttributes!.center.x - halfWidth), y: offset.y) 39 | } 40 | } 41 | 42 | extension UICollectionView 43 | { 44 | public func indexPathForItemAtCenter() -> IndexPath? 45 | { 46 | let point = CGPoint( 47 | x: self.center.x + self.contentOffset.x, 48 | y: self.center.y + self.contentOffset.y 49 | ) 50 | 51 | return self.indexPathForItem(at: point) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/BeLessThan.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is less than the expected value. 4 | public func beLessThan(_ expectedValue: T?) -> Predicate { 5 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 6 | failureMessage.postfixMessage = "be less than <\(stringify(expectedValue))>" 7 | if let actual = try actualExpression.evaluate(), let expected = expectedValue { 8 | return actual < expected 9 | } 10 | return false 11 | }.requireNonNil 12 | } 13 | 14 | /// A Nimble matcher that succeeds when the actual value is less than the expected value. 15 | public func beLessThan(_ expectedValue: NMBComparable?) -> Predicate { 16 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 17 | failureMessage.postfixMessage = "be less than <\(stringify(expectedValue))>" 18 | let actualValue = try actualExpression.evaluate() 19 | let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) == ComparisonResult.orderedAscending 20 | return matches 21 | }.requireNonNil 22 | } 23 | 24 | public func <(lhs: Expectation, rhs: T) { 25 | lhs.to(beLessThan(rhs)) 26 | } 27 | 28 | public func < (lhs: Expectation, rhs: NMBComparable?) { 29 | lhs.to(beLessThan(rhs)) 30 | } 31 | 32 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 33 | extension NMBObjCMatcher { 34 | @objc public class func beLessThanMatcher(_ expected: NMBComparable?) -> NMBObjCMatcher { 35 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 36 | let expr = actualExpression.cast { $0 as? NMBComparable } 37 | return try! beLessThan(expected).matches(expr, failureMessage: failureMessage) 38 | } 39 | } 40 | } 41 | #endif 42 | -------------------------------------------------------------------------------- /Swiftility/Sources/Type Safety/UITableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 1/29/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UITableViewCell 12 | { 13 | open class var defaultHeight: CGFloat { return 44 } 14 | } 15 | 16 | extension UITableView 17 | { 18 | // MARK: - Register 19 | 20 | public func register(_ nibCell: T.Type) where T: UITableViewCell, T: FromNib 21 | { 22 | self.register(nibCell.ownNib.nib, forCellReuseIdentifier: String(describing: nibCell)) 23 | } 24 | 25 | public func register(_ classCell: T.Type) 26 | { 27 | self.register(T.self, forCellReuseIdentifier: String(describing: T.self)) 28 | } 29 | 30 | // MARK: - Dequeue 31 | 32 | public func dequeueReusableCell() -> T 33 | { 34 | guard let cell = self.dequeueReusableCell(withIdentifier: String(describing: T.self)) as? T else { 35 | fatalError("\(String(describing: T.self)) cell could not be instantiated because it was not found on the tableView(\(self))") 36 | } 37 | 38 | return cell 39 | } 40 | 41 | public func dequeueReusableCell(for indexPath: IndexPath) -> T 42 | { 43 | var cell: UITableViewCell? = nil 44 | 45 | do { 46 | try ObjC.catchException { 47 | cell = self.dequeueReusableCell(withIdentifier: String(describing: T.self), for: indexPath) 48 | } 49 | } catch { 50 | cell = nil 51 | } 52 | 53 | guard let typedCell = cell as? T else { 54 | fatalError("\(String(describing: T.self)) cell could not be instantiated because it was not found on the tableView(\(self))") 55 | } 56 | 57 | return typedCell 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/BeGreaterThan.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is greater than the expected value. 4 | public func beGreaterThan(_ expectedValue: T?) -> Predicate { 5 | let errorMessage = "be greater than <\(stringify(expectedValue))>" 6 | return Predicate.simple(errorMessage) { actualExpression in 7 | if let actual = try actualExpression.evaluate(), let expected = expectedValue { 8 | return PredicateStatus(bool: actual > expected) 9 | } 10 | return .fail 11 | } 12 | } 13 | 14 | /// A Nimble matcher that succeeds when the actual value is greater than the expected value. 15 | public func beGreaterThan(_ expectedValue: NMBComparable?) -> Predicate { 16 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 17 | failureMessage.postfixMessage = "be greater than <\(stringify(expectedValue))>" 18 | let actualValue = try actualExpression.evaluate() 19 | let matches = actualValue != nil 20 | && actualValue!.NMB_compare(expectedValue) == ComparisonResult.orderedDescending 21 | return matches 22 | }.requireNonNil 23 | } 24 | 25 | public func >(lhs: Expectation, rhs: T) { 26 | lhs.to(beGreaterThan(rhs)) 27 | } 28 | 29 | public func > (lhs: Expectation, rhs: NMBComparable?) { 30 | lhs.to(beGreaterThan(rhs)) 31 | } 32 | 33 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 34 | extension NMBObjCMatcher { 35 | @objc public class func beGreaterThanMatcher(_ expected: NMBComparable?) -> NMBObjCMatcher { 36 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 37 | let expr = actualExpression.cast { $0 as? NMBComparable } 38 | return try! beGreaterThan(expected).matches(expr, failureMessage: failureMessage) 39 | } 40 | } 41 | } 42 | #endif 43 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Utils/Errors.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // Generic 4 | 5 | internal func setFailureMessageForError( 6 | _ failureMessage: FailureMessage, 7 | postfixMessageVerb: String = "throw", 8 | actualError: Error?, 9 | error: T? = nil, 10 | errorType: T.Type? = nil, 11 | closure: ((T) -> Void)? = nil) { 12 | failureMessage.postfixMessage = "\(postfixMessageVerb) error" 13 | 14 | if let error = error { 15 | failureMessage.postfixMessage += " <\(error)>" 16 | } else if errorType != nil || closure != nil { 17 | failureMessage.postfixMessage += " from type <\(T.self)>" 18 | } 19 | if closure != nil { 20 | failureMessage.postfixMessage += " that satisfies block" 21 | } 22 | if error == nil && errorType == nil && closure == nil { 23 | failureMessage.postfixMessage = "\(postfixMessageVerb) any error" 24 | } 25 | 26 | if let actualError = actualError { 27 | failureMessage.actualValue = "<\(actualError)>" 28 | } else { 29 | failureMessage.actualValue = "no error" 30 | } 31 | } 32 | 33 | internal func errorMatchesExpectedError( 34 | _ actualError: Error, 35 | expectedError: T) -> Bool { 36 | return actualError._domain == expectedError._domain 37 | && actualError._code == expectedError._code 38 | } 39 | 40 | // Non-generic 41 | 42 | internal func setFailureMessageForError( 43 | _ failureMessage: FailureMessage, 44 | actualError: Error?, 45 | closure: ((Error) -> Void)?) { 46 | failureMessage.postfixMessage = "throw error" 47 | 48 | if closure != nil { 49 | failureMessage.postfixMessage += " that satisfies block" 50 | } else { 51 | failureMessage.postfixMessage = "throw any error" 52 | } 53 | 54 | if let actualError = actualError { 55 | failureMessage.actualValue = "<\(actualError)>" 56 | } else { 57 | failureMessage.actualValue = "no error" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/BeGreaterThanTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | import Nimble 4 | 5 | final class BeGreaterThanTest: XCTestCase, XCTestCaseProvider { 6 | static var allTests: [(String, (BeGreaterThanTest) -> () throws -> Void)] { 7 | return [ 8 | ("testGreaterThan", testGreaterThan), 9 | ("testGreaterThanOperator", testGreaterThanOperator), 10 | ] 11 | } 12 | 13 | func testGreaterThan() { 14 | expect(10).to(beGreaterThan(2)) 15 | expect(1).toNot(beGreaterThan(2)) 16 | #if SUPPORT_IMPLICIT_BRIDGING_CONVERSION 17 | expect(NSNumber(value:3)).to(beGreaterThan(2)) 18 | #else 19 | expect(NSNumber(value:3)).to(beGreaterThan(2 as NSNumber)) 20 | #endif 21 | expect(NSNumber(value:1)).toNot(beGreaterThan(NSNumber(value:2))) 22 | 23 | failsWithErrorMessage("expected to be greater than <2>, got <0>") { 24 | expect(0).to(beGreaterThan(2)) 25 | } 26 | failsWithErrorMessage("expected to not be greater than <0>, got <1>") { 27 | expect(1).toNot(beGreaterThan(0)) 28 | } 29 | failsWithErrorMessageForNil("expected to be greater than <-2>, got ") { 30 | expect(nil as Int?).to(beGreaterThan(-2)) 31 | } 32 | failsWithErrorMessageForNil("expected to not be greater than <0>, got ") { 33 | expect(nil as Int?).toNot(beGreaterThan(0)) 34 | } 35 | } 36 | 37 | func testGreaterThanOperator() { 38 | expect(1) > 0 39 | expect(NSNumber(value:1)) > NSNumber(value:0) 40 | #if SUPPORT_IMPLICIT_BRIDGING_CONVERSION 41 | expect(NSNumber(value:1)) > 0 42 | #else 43 | expect(NSNumber(value:1)) > 0 as NSNumber 44 | #endif 45 | expect(2.5) > 1.5 46 | expect(Float(2.5)) > Float(1.5) 47 | 48 | failsWithErrorMessage("expected to be greater than <2>, got <1>") { 49 | expect(1) > 2 50 | return 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/BeLessThanOrEqual.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is less than 4 | /// or equal to the expected value. 5 | public func beLessThanOrEqualTo(_ expectedValue: T?) -> Predicate { 6 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 7 | failureMessage.postfixMessage = "be less than or equal to <\(stringify(expectedValue))>" 8 | if let actual = try actualExpression.evaluate(), let expected = expectedValue { 9 | return actual <= expected 10 | } 11 | return false 12 | }.requireNonNil 13 | } 14 | 15 | /// A Nimble matcher that succeeds when the actual value is less than 16 | /// or equal to the expected value. 17 | public func beLessThanOrEqualTo(_ expectedValue: T?) -> Predicate { 18 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 19 | failureMessage.postfixMessage = "be less than or equal to <\(stringify(expectedValue))>" 20 | let actualValue = try actualExpression.evaluate() 21 | return actualValue != nil && actualValue!.NMB_compare(expectedValue) != ComparisonResult.orderedDescending 22 | }.requireNonNil 23 | } 24 | 25 | public func <=(lhs: Expectation, rhs: T) { 26 | lhs.to(beLessThanOrEqualTo(rhs)) 27 | } 28 | 29 | public func <=(lhs: Expectation, rhs: T) { 30 | lhs.to(beLessThanOrEqualTo(rhs)) 31 | } 32 | 33 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 34 | extension NMBObjCMatcher { 35 | @objc public class func beLessThanOrEqualToMatcher(_ expected: NMBComparable?) -> NMBObjCMatcher { 36 | return NMBObjCMatcher(canMatchNil:false) { actualExpression, failureMessage in 37 | let expr = actualExpression.cast { $0 as? NMBComparable } 38 | return try! beLessThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage) 39 | } 40 | } 41 | } 42 | #endif 43 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Helpers/XCTestCaseProvider.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | // XCTestCaseProvider should be adopted by all XCTestCase subclasses. It provides a 5 | // mechanism for us to fail tests in Xcode which haven't been included in the `allTests` 6 | // list for swift-corelibs-xctest which is unable to dynamically discover tests. Note 7 | // that only `static var allTests` needs to be explicitly implemented, as `allTestNames` 8 | // has a default implementation provided by a protocol extension. 9 | 10 | // Implementation note: This is broken down into two separate protocols because we need a 11 | // protocol with no Self references to which we can cast XCTestCase instances in a non-generic context. 12 | 13 | public protocol XCTestCaseProviderStatic { 14 | // This should be explicitly implemented by XCTestCase subclasses 15 | static var allTests: [(String, (Self) -> () throws -> Void)] { get } 16 | } 17 | 18 | public protocol XCTestCaseNameProvider { 19 | // This does not need to be explicitly implemented because of the protocol extension below 20 | var allTestNames: [String] { get } 21 | } 22 | 23 | public protocol XCTestCaseProvider: XCTestCaseProviderStatic, XCTestCaseNameProvider {} 24 | 25 | extension XCTestCaseProvider { 26 | var allTestNames: [String] { 27 | return type(of: self).allTests.map({ name, _ in 28 | return name 29 | }) 30 | } 31 | } 32 | 33 | #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) 34 | 35 | extension XCTestCase { 36 | override open func tearDown() { 37 | if let provider = self as? XCTestCaseNameProvider { 38 | provider.assertContainsTest(invocation!.selector.description) 39 | } 40 | 41 | super.tearDown() 42 | } 43 | } 44 | 45 | extension XCTestCaseNameProvider { 46 | fileprivate func assertContainsTest(_ name: String) { 47 | let contains = self.allTestNames.contains(name) 48 | XCTAssert(contains, "Test '\(name)' is missing from the allTests array") 49 | } 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /Swiftility/Sources/Type Safety/Storyboard.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Storyboard.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 10/21/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | // MARK: - Storyboard 13 | 14 | extension UIStoryboard 15 | { 16 | public struct Name 17 | { 18 | var name: String 19 | var bundle: Bundle? 20 | 21 | public init(name: String, bundle: Bundle? = nil) 22 | { 23 | self.name = name 24 | self.bundle = bundle 25 | } 26 | } 27 | } 28 | 29 | extension UIStoryboard 30 | { 31 | public convenience init(name: UIStoryboard.Name) 32 | { 33 | self.init(name: name.name, bundle: name.bundle) 34 | } 35 | } 36 | 37 | // MARK: - FromStoryboard 38 | 39 | public protocol FromStoryboard 40 | { 41 | static var storyboardName: UIStoryboard.Name { get } 42 | } 43 | 44 | // MARK: - Type safe instantiate view controller 45 | 46 | extension UIStoryboard 47 | { 48 | public func instantiateInitialViewController() -> T 49 | { 50 | guard let vc = self.instantiateInitialViewController() as? T else { 51 | fatalError("\(String(describing: T.self)) could not be instantiated because it was not found in storyboard: \(self)") 52 | } 53 | 54 | return vc 55 | } 56 | 57 | public func instantiateViewController() -> T 58 | { 59 | var vc: UIViewController? = nil 60 | 61 | do { 62 | try ObjC.catchException { 63 | vc = self.instantiateViewController(withIdentifier: String(describing: T.self)) 64 | } 65 | } catch { 66 | vc = nil 67 | } 68 | 69 | guard let typedVc = vc as? T else { 70 | fatalError("\(String(describing: T.self)) could not be instantiated because it was not found in storyboard: \(self)") 71 | } 72 | 73 | return typedVc 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/BeLessThanOrEqualToTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | import Nimble 4 | 5 | final class BeLessThanOrEqualToTest: XCTestCase, XCTestCaseProvider { 6 | static var allTests: [(String, (BeLessThanOrEqualToTest) -> () throws -> Void)] { 7 | return [ 8 | ("testLessThanOrEqualTo", testLessThanOrEqualTo), 9 | ("testLessThanOrEqualToOperator", testLessThanOrEqualToOperator), 10 | ] 11 | } 12 | 13 | func testLessThanOrEqualTo() { 14 | expect(10).to(beLessThanOrEqualTo(10)) 15 | expect(2).to(beLessThanOrEqualTo(10)) 16 | expect(2).toNot(beLessThanOrEqualTo(1)) 17 | 18 | expect(NSNumber(value:2)).to(beLessThanOrEqualTo(10)) 19 | expect(NSNumber(value:2)).toNot(beLessThanOrEqualTo(1)) 20 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 21 | expect(2).to(beLessThanOrEqualTo(NSNumber(value:10))) 22 | expect(2).toNot(beLessThanOrEqualTo(NSNumber(value:1))) 23 | #endif 24 | 25 | failsWithErrorMessage("expected to be less than or equal to <0>, got <2>") { 26 | expect(2).to(beLessThanOrEqualTo(0)) 27 | return 28 | } 29 | failsWithErrorMessage("expected to not be less than or equal to <0>, got <0>") { 30 | expect(0).toNot(beLessThanOrEqualTo(0)) 31 | return 32 | } 33 | failsWithErrorMessageForNil("expected to be less than or equal to <2>, got ") { 34 | expect(nil as Int?).to(beLessThanOrEqualTo(2)) 35 | return 36 | } 37 | failsWithErrorMessageForNil("expected to not be less than or equal to <-2>, got ") { 38 | expect(nil as Int?).toNot(beLessThanOrEqualTo(-2)) 39 | return 40 | } 41 | } 42 | 43 | func testLessThanOrEqualToOperator() { 44 | expect(0) <= 1 45 | expect(1) <= 1 46 | 47 | failsWithErrorMessage("expected to be less than or equal to <1>, got <2>") { 48 | expect(2) <= 1 49 | return 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Nimble/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (2.3.5) 5 | activesupport (4.2.8) 6 | i18n (~> 0.7) 7 | minitest (~> 5.1) 8 | thread_safe (~> 0.3, >= 0.3.4) 9 | tzinfo (~> 1.1) 10 | claide (1.0.1) 11 | cocoapods (1.2.0) 12 | activesupport (>= 4.0.2, < 5) 13 | claide (>= 1.0.1, < 2.0) 14 | cocoapods-core (= 1.2.0) 15 | cocoapods-deintegrate (>= 1.0.1, < 2.0) 16 | cocoapods-downloader (>= 1.1.3, < 2.0) 17 | cocoapods-plugins (>= 1.0.0, < 2.0) 18 | cocoapods-search (>= 1.0.0, < 2.0) 19 | cocoapods-stats (>= 1.0.0, < 2.0) 20 | cocoapods-trunk (>= 1.1.2, < 2.0) 21 | cocoapods-try (>= 1.1.0, < 2.0) 22 | colored (~> 1.2) 23 | escape (~> 0.0.4) 24 | fourflusher (~> 2.0.1) 25 | gh_inspector (~> 1.0) 26 | molinillo (~> 0.5.5) 27 | nap (~> 1.0) 28 | ruby-macho (~> 0.2.5) 29 | xcodeproj (>= 1.4.1, < 2.0) 30 | cocoapods-core (1.2.0) 31 | activesupport (>= 4.0.2, < 5) 32 | fuzzy_match (~> 2.0.4) 33 | nap (~> 1.0) 34 | cocoapods-deintegrate (1.0.1) 35 | cocoapods-downloader (1.1.3) 36 | cocoapods-plugins (1.0.0) 37 | nap 38 | cocoapods-search (1.0.0) 39 | cocoapods-stats (1.0.0) 40 | cocoapods-trunk (1.1.2) 41 | nap (>= 0.8, < 2.0) 42 | netrc (= 0.7.8) 43 | cocoapods-try (1.1.0) 44 | colored (1.2) 45 | escape (0.0.4) 46 | fourflusher (2.0.1) 47 | fuzzy_match (2.0.4) 48 | gh_inspector (1.0.3) 49 | i18n (0.8.1) 50 | minitest (5.10.1) 51 | molinillo (0.5.6) 52 | nanaimo (0.2.3) 53 | nap (1.1.0) 54 | netrc (0.7.8) 55 | ruby-macho (0.2.6) 56 | thread_safe (0.3.6) 57 | tzinfo (1.2.2) 58 | thread_safe (~> 0.1) 59 | xcodeproj (1.4.2) 60 | CFPropertyList (~> 2.3.3) 61 | activesupport (>= 3) 62 | claide (>= 1.0.1, < 2.0) 63 | colored (~> 1.2) 64 | nanaimo (~> 0.2.3) 65 | 66 | PLATFORMS 67 | ruby 68 | 69 | DEPENDENCIES 70 | cocoapods (= 1.2.0) 71 | 72 | BUNDLED WITH 73 | 1.14.5 74 | -------------------------------------------------------------------------------- /SwiftilityTests/RegexTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RegexTests.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 12/16/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Swiftility 11 | 12 | class RegexTests: XCTestCase 13 | { 14 | func testMatch() 15 | { 16 | let emailRegEx = "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$" 17 | 18 | XCTAssert("allan.bto+test34@allan.com" =~ emailRegEx, "regex doesn't validate email") 19 | XCTAssert(!("allan.bto+test34@" =~ emailRegEx), "regex validates wrong email") 20 | 21 | XCTAssert("allan.bto+test34@allan.com".match(pattern: emailRegEx), "regex doesn't validate email") 22 | 23 | do { 24 | let regex = try Regex(pattern: emailRegEx) 25 | XCTAssert("allan.bto+test34@allan.com".match(regex: regex), "regex doesn't validate email") 26 | } catch { 27 | XCTAssert(false, "Regex fails to instantiate") 28 | } 29 | } 30 | 31 | func testReplace() 32 | { 33 | XCTAssertEqual("I am a developer fixing bugs".replace(pattern: "fixing bugs", template: "implementing features"), 34 | "I am a developer implementing features", 35 | "regex doesn't replace correctly") 36 | 37 | do { 38 | let regex = try Regex(pattern:"fixing bugs") 39 | XCTAssertEqual("I am a developer fixing bugs".replace(regex: regex, template: "implementing features"), 40 | "I am a developer implementing features", 41 | "regex doesn't replace correctly") 42 | } catch { 43 | XCTAssert(false, "Regex fails to instantiate") 44 | } 45 | 46 | XCTAssertEqual("I am a developer doing stuff".replace(pattern: "<[a-z]+>([a-z]+)", template: "normal $1"), 47 | "I am a developer doing normal stuff", 48 | "regex doesn't replace correctly") 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/ThrowAssertionTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | import Nimble 4 | 5 | #if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE 6 | 7 | final class ThrowAssertionTest: XCTestCase, XCTestCaseProvider { 8 | static var allTests: [(String, (ThrowAssertionTest) -> () throws -> Void)] { 9 | return [ 10 | ("testPositiveMatch", testPositiveMatch), 11 | ("testErrorThrown", testErrorThrown), 12 | ("testPostAssertionCodeNotRun", testPostAssertionCodeNotRun), 13 | ("testNegativeMatch", testNegativeMatch), 14 | ("testPositiveMessage", testPositiveMessage), 15 | ("testNegativeMessage", testNegativeMessage), 16 | ] 17 | } 18 | 19 | func testPositiveMatch() { 20 | expect { () -> Void in fatalError() }.to(throwAssertion()) 21 | } 22 | 23 | func testErrorThrown() { 24 | expect { throw NSError(domain: "test", code: 0, userInfo: nil) }.toNot(throwAssertion()) 25 | } 26 | 27 | func testPostAssertionCodeNotRun() { 28 | var reachedPoint1 = false 29 | var reachedPoint2 = false 30 | 31 | expect { 32 | reachedPoint1 = true 33 | precondition(false, "condition message") 34 | reachedPoint2 = true 35 | }.to(throwAssertion()) 36 | 37 | expect(reachedPoint1) == true 38 | expect(reachedPoint2) == false 39 | } 40 | 41 | func testNegativeMatch() { 42 | var reachedPoint1 = false 43 | 44 | expect { reachedPoint1 = true }.toNot(throwAssertion()) 45 | 46 | expect(reachedPoint1) == true 47 | } 48 | 49 | func testPositiveMessage() { 50 | failsWithErrorMessage("expected to throw an assertion") { 51 | expect { () -> Void? in return }.to(throwAssertion()) 52 | } 53 | } 54 | 55 | func testNegativeMessage() { 56 | failsWithErrorMessage("expected to not throw an assertion") { 57 | expect { () -> Void in fatalError() }.toNot(throwAssertion()) 58 | } 59 | } 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/BeGreaterThanOrEqualTo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is greater than 4 | /// or equal to the expected value. 5 | public func beGreaterThanOrEqualTo(_ expectedValue: T?) -> Predicate { 6 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 7 | failureMessage.postfixMessage = "be greater than or equal to <\(stringify(expectedValue))>" 8 | let actualValue = try actualExpression.evaluate() 9 | if let actual = actualValue, let expected = expectedValue { 10 | return actual >= expected 11 | } 12 | return false 13 | }.requireNonNil 14 | } 15 | 16 | /// A Nimble matcher that succeeds when the actual value is greater than 17 | /// or equal to the expected value. 18 | public func beGreaterThanOrEqualTo(_ expectedValue: T?) -> Predicate { 19 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 20 | failureMessage.postfixMessage = "be greater than or equal to <\(stringify(expectedValue))>" 21 | let actualValue = try actualExpression.evaluate() 22 | let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) != ComparisonResult.orderedAscending 23 | return matches 24 | }.requireNonNil 25 | } 26 | 27 | public func >=(lhs: Expectation, rhs: T) { 28 | lhs.to(beGreaterThanOrEqualTo(rhs)) 29 | } 30 | 31 | public func >=(lhs: Expectation, rhs: T) { 32 | lhs.to(beGreaterThanOrEqualTo(rhs)) 33 | } 34 | 35 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 36 | extension NMBObjCMatcher { 37 | @objc public class func beGreaterThanOrEqualToMatcher(_ expected: NMBComparable?) -> NMBObjCMatcher { 38 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 39 | let expr = actualExpression.cast { $0 as? NMBComparable } 40 | return try! beGreaterThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage) 41 | } 42 | } 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/BeLessThanTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | import Nimble 4 | 5 | final class BeLessThanTest: XCTestCase, XCTestCaseProvider { 6 | static var allTests: [(String, (BeLessThanTest) -> () throws -> Void)] { 7 | return [ 8 | ("testLessThan", testLessThan), 9 | ("testLessThanOperator", testLessThanOperator), 10 | ] 11 | } 12 | 13 | func testLessThan() { 14 | expect(2).to(beLessThan(10)) 15 | expect(2).toNot(beLessThan(1)) 16 | #if SUPPORT_IMPLICIT_BRIDGING_CONVERSION 17 | expect(NSNumber(value:2)).to(beLessThan(10)) 18 | expect(NSNumber(value:2)).toNot(beLessThan(1)) 19 | 20 | expect(2).to(beLessThan(NSNumber(value:10))) 21 | expect(2).toNot(beLessThan(NSNumber(value:1))) 22 | #else 23 | expect(NSNumber(value:2)).to(beLessThan(10 as NSNumber)) 24 | expect(NSNumber(value:2)).toNot(beLessThan(1 as NSNumber)) 25 | 26 | expect(2 as NSNumber).to(beLessThan(NSNumber(value:10))) 27 | expect(2 as NSNumber).toNot(beLessThan(NSNumber(value:1))) 28 | #endif 29 | 30 | failsWithErrorMessage("expected to be less than <0>, got <2>") { 31 | expect(2).to(beLessThan(0)) 32 | } 33 | failsWithErrorMessage("expected to not be less than <1>, got <0>") { 34 | expect(0).toNot(beLessThan(1)) 35 | } 36 | 37 | failsWithErrorMessageForNil("expected to be less than <2>, got ") { 38 | expect(nil as Int?).to(beLessThan(2)) 39 | } 40 | failsWithErrorMessageForNil("expected to not be less than <-1>, got ") { 41 | expect(nil as Int?).toNot(beLessThan(-1)) 42 | } 43 | } 44 | 45 | func testLessThanOperator() { 46 | expect(0) < 1 47 | #if SUPPORT_IMPLICIT_BRIDGING_CONVERSION 48 | expect(NSNumber(value:0)) < 1 49 | #else 50 | expect(NSNumber(value:0)) < 1 as NSNumber 51 | #endif 52 | failsWithErrorMessage("expected to be less than <1>, got <2>") { 53 | expect(2) < 1 54 | return 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/BeginWithTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | import Nimble 4 | 5 | final class BeginWithTest: XCTestCase, XCTestCaseProvider { 6 | static var allTests: [(String, (BeginWithTest) -> () throws -> Void)] { 7 | return [ 8 | ("testPositiveMatches", testPositiveMatches), 9 | ("testNegativeMatches", testNegativeMatches), 10 | ] 11 | } 12 | 13 | func testPositiveMatches() { 14 | expect([1, 2, 3]).to(beginWith(1)) 15 | expect([1, 2, 3]).toNot(beginWith(2)) 16 | 17 | expect("foobar").to(beginWith("foo")) 18 | expect("foobar").toNot(beginWith("oo")) 19 | 20 | expect("foobarfoo").to(beginWith("foo")) 21 | 22 | expect(NSString(string: "foobar").description).to(beginWith("foo")) 23 | expect(NSString(string: "foobar").description).toNot(beginWith("oo")) 24 | 25 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 26 | expect(NSArray(array: ["a", "b"])).to(beginWith("a")) 27 | expect(NSArray(array: ["a", "b"])).toNot(beginWith("b")) 28 | #endif 29 | } 30 | 31 | func testNegativeMatches() { 32 | failsWithErrorMessageForNil("expected to begin with , got ") { 33 | expect(nil as NSArray?).to(beginWith(NSString(string: "b"))) 34 | } 35 | failsWithErrorMessageForNil("expected to not begin with , got ") { 36 | expect(nil as NSArray?).toNot(beginWith(NSString(string: "b"))) 37 | } 38 | 39 | failsWithErrorMessage("expected to begin with <2>, got <[1, 2, 3]>") { 40 | expect([1, 2, 3]).to(beginWith(2)) 41 | } 42 | failsWithErrorMessage("expected to not begin with <1>, got <[1, 2, 3]>") { 43 | expect([1, 2, 3]).toNot(beginWith(1)) 44 | } 45 | failsWithErrorMessage("expected to begin with , got ") { 46 | expect("batman").to(beginWith("atm")) 47 | } 48 | failsWithErrorMessage("expected to not begin with , got ") { 49 | expect("batman").toNot(beginWith("bat")) 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCUserDescriptionTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCUserDescriptionTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCUserDescriptionTest 9 | 10 | - (void)testToWithDescription { 11 | expectFailureMessage(@"These are equal!\n" 12 | "expected to equal <2>, got <1>", ^{ 13 | expect(@1).toWithDescription(equal(@2), @"These are equal!"); 14 | }); 15 | } 16 | 17 | - (void)testToNotWithDescription { 18 | expectFailureMessage(@"These aren't equal!\n" 19 | "expected to not equal <1>, got <1>", ^{ 20 | expect(@1).toNotWithDescription(equal(@1), @"These aren't equal!"); 21 | }); 22 | } 23 | 24 | - (void)testNotToWithDescription { 25 | expectFailureMessage(@"These aren't equal!\n" 26 | "expected to not equal <1>, got <1>", ^{ 27 | expect(@1).notToWithDescription(equal(@1), @"These aren't equal!"); 28 | }); 29 | } 30 | 31 | - (void)testToEventuallyWithDescription { 32 | expectFailureMessage(@"These are equal!\n" 33 | "expected to eventually equal <2>, got <1>", ^{ 34 | expect(@1).toEventuallyWithDescription(equal(@2), @"These are equal!"); 35 | }); 36 | } 37 | 38 | - (void)testToEventuallyNotWithDescription { 39 | expectFailureMessage(@"These aren't equal!\n" 40 | "expected to eventually not equal <1>, got <1>", ^{ 41 | expect(@1).toEventuallyNotWithDescription(equal(@1), @"These aren't equal!"); 42 | }); 43 | } 44 | 45 | - (void)testToNotEventuallyWithDescription { 46 | expectFailureMessage(@"These aren't equal!\n" 47 | "expected to eventually not equal <1>, got <1>", ^{ 48 | expect(@1).toNotEventuallyWithDescription(equal(@1), @"These aren't equal!"); 49 | }); 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /SwiftilityTests/Extensions/StringExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringExtensionsTests.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 3/24/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import Swiftility 12 | 13 | class StringExtensionsTests: XCTestCase 14 | { 15 | func testSubscript() 16 | { 17 | let str = "012345" 18 | let char: Character = str[0] 19 | 20 | XCTAssert(char == Character("0")) 21 | XCTAssert(str[0] == "0") 22 | 23 | XCTAssert(str[0..<2] == "01") 24 | XCTAssert(str[0..<3] == "012") 25 | XCTAssert(str[2..<5] == "234") 26 | } 27 | 28 | func testTrim() 29 | { 30 | let str = " t es t " 31 | 32 | XCTAssert(str.trimmed() == "t es t") 33 | XCTAssert("test".trimmed() == "test") 34 | } 35 | 36 | func testWords() 37 | { 38 | XCTAssert("".words.isEmpty) 39 | XCTAssert("Hello".words == ["Hello"]) 40 | XCTAssert("Hello World".words == ["Hello", "World"]) 41 | XCTAssert(" %^& +)) Hello World! #$%^&<>? ".words == ["Hello", "World"]) 42 | XCTAssert(" 😀 Hello 😀😬🙏☝🏼👂🏿👽 World! 😀 ".words == ["Hello", "World"]) 43 | } 44 | 45 | func testUrlEncoded() 46 | { 47 | XCTAssert(";?/:#&=+$, %<>~%".urlEncoded() == "%3B%3F%2F%3A%23%26%3D%2B%24%2C%20%25%3C%3E%7E%25") 48 | XCTAssert("https://www.toto.co.uk/toto/tutu?hello=titi&asasas=tre".urlEncoded() == "https%3A%2F%2Fwww.toto.co.uk%2Ftoto%2Ftutu%3Fhello%3Dtiti%26asasas%3Dtre") 49 | } 50 | 51 | func testTruncated() 52 | { 53 | XCTAssert("toto".truncated(-1) == "toto") 54 | XCTAssert("toto".truncated(0) == "") 55 | XCTAssert("toto".truncated(1) == "t") 56 | XCTAssert("toto".truncated(2) == "to") 57 | XCTAssert("toto".truncated(3) == "tot") 58 | XCTAssert("toto".truncated(4) == "toto") 59 | XCTAssert("toto".truncated(50) == "toto") 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Swiftility/Sources/Type Safety/Nib.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Nib.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 1/29/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // MARK: - NibConvertible 12 | 13 | public protocol NibConvertible 14 | { 15 | var nibName: String { get } 16 | var bundle: Bundle? { get } 17 | } 18 | 19 | extension NibConvertible 20 | { 21 | public var bundle: Bundle? { 22 | return nil 23 | } 24 | 25 | public var nib: UINib { 26 | return UINib(nibName: self.nibName, bundle: self.bundle) 27 | } 28 | } 29 | 30 | // MARK: - From nib 31 | 32 | public protocol FromNib 33 | { 34 | static var ownNib: NibConvertible { get } 35 | } 36 | 37 | extension FromNib 38 | { 39 | public static func instantiateFromNib(_ nib: NibConvertible? = nil, owner: Any? = nil, options: [AnyHashable: Any]? = nil) -> Self 40 | { 41 | let nibName: String = nib?.nibName ?? self.ownNib.nibName 42 | let bundle: Bundle = nib?.bundle ?? self.ownNib.bundle ?? Bundle.main 43 | 44 | guard let view = bundle.loadNibNamed(nibName, owner: owner, options: options)?.first as? Self else { 45 | fatalError("\(String(describing: self)) could not be instantiated because it was not found on this bundle or the nib (\(nibName)) did not contain \(String(describing: self))") 46 | } 47 | 48 | return view 49 | } 50 | } 51 | 52 | // MARK: - SelfNibConvertible 53 | 54 | public protocol SelfNibConvertible {} 55 | 56 | extension SelfNibConvertible 57 | { 58 | public static var ownNib: NibConvertible { 59 | return NibContainer(String(describing: Self.self)) 60 | } 61 | } 62 | 63 | public struct NibContainer: NibConvertible 64 | { 65 | fileprivate var _name: String 66 | fileprivate var _bundle: Bundle? 67 | 68 | public init(_ name: String, bundle: Bundle? = nil) 69 | { 70 | _name = name 71 | _bundle = bundle 72 | } 73 | 74 | public var nibName: String { 75 | return _name 76 | } 77 | 78 | public var bundle: Bundle? { 79 | return _bundle 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /SwiftilityTests/Type Safe UIKIt/StoryboardTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StoryboardTests.swift 3 | // SwiftilityTests 4 | // 5 | // Created by Allan Barbato on 12/14/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import Nimble 11 | @testable import Swiftility 12 | 13 | class StoryboardTests: XCTestCase 14 | { 15 | let storyboard = UIStoryboard(name: "MainStoryboard", bundle: Bundle(for: StoryboardTests.self)) 16 | 17 | func testStoryboardSafeTypeInstantiation() 18 | { 19 | // Test view controller that doesn't exist 20 | expect { 21 | _ = self.storyboard.instantiateViewController() as TestNonExistingVC 22 | }.to(throwAssertion()) 23 | 24 | // Test view controller that does exist 25 | let existingVC: TestVC = storyboard.instantiateViewController() 26 | 27 | XCTAssert(true, "existingVC(\(existingVC)) instantiation should not crash") 28 | } 29 | 30 | func testStoryboardName() 31 | { 32 | // Define default storyboard convertible type 33 | let sbc: UIStoryboard.Name = .mainDefault 34 | 35 | XCTAssert(sbc.name == "MainStoryboard") 36 | XCTAssert(sbc.bundle == nil) 37 | 38 | // Define test storyboard convertible type 39 | let sbc2: UIStoryboard.Name = .mainTests 40 | 41 | XCTAssert(sbc2.name == "MainStoryboard") 42 | XCTAssert(sbc2.bundle != nil) 43 | 44 | let storyboard = UIStoryboard(name: sbc2) 45 | 46 | XCTAssert(true, "storyboard(\(storyboard)) instantiation should not crash") 47 | } 48 | 49 | func testInitialViewController() 50 | { 51 | // Test initial view controller that doesn't exist 52 | expect { 53 | _ = self.storyboard.instantiateInitialViewController() as TestNonExistingVC 54 | }.to(throwAssertion()) 55 | 56 | // Test initial view controller that does exist 57 | let existingVC: TestVC = storyboard.instantiateInitialViewController() 58 | 59 | XCTAssert(true, "existingVC(\(existingVC)) instantiation should not crash") 60 | } 61 | } 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/Foundation/WeakTimer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeakTimer.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/23/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Timer 12 | { 13 | /** 14 | A factory for Timer instances that invoke closures, thereby allowing a weak reference to its context 15 | 16 | - parameter timeInterval: Interval 17 | - parameter userInfo: =nil; userInfo object 18 | - parameter repeats: =false; Should repeat or called only once 19 | - parameter callback: callback called instead of NSTimer target's selector 20 | 21 | - returns: new scheduled timer. More info, see: Timer.scheduledTimer(:_) 22 | */ 23 | public static func scheduledTimer( 24 | timeInterval: TimeInterval, 25 | userInfo: Any? = nil, 26 | repeats: Bool = false, 27 | callback: @escaping () -> Void) -> Timer 28 | { 29 | return WeakTimer( 30 | timeInterval: timeInterval, 31 | userInfo: userInfo, 32 | repeats: repeats, 33 | callback: callback 34 | ).timer 35 | } 36 | } 37 | 38 | private extension Selector 39 | { 40 | static let invokeCallback = #selector(WeakTimer.invokeCallback) 41 | } 42 | 43 | private final class WeakTimer: NSObject 44 | { 45 | // MARK: - Properties 46 | 47 | fileprivate var timer: Timer! 48 | fileprivate let callback: () -> Void 49 | 50 | // MARK: - Life cycle 51 | 52 | fileprivate init(timeInterval: TimeInterval, 53 | userInfo: Any?, 54 | repeats: Bool, 55 | callback: @escaping () -> Void) 56 | { 57 | self.callback = callback 58 | 59 | super.init() 60 | 61 | self.timer = Timer.scheduledTimer( 62 | timeInterval: timeInterval, 63 | target: self, 64 | selector: .invokeCallback, 65 | userInfo: userInfo, 66 | repeats: repeats 67 | ) 68 | } 69 | 70 | // MARK: - Actions 71 | 72 | @objc func invokeCallback() 73 | { 74 | callback() 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/UIKit/UINavigationControllerExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UINavigationControllerExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/17/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public enum CATransitionStyle 12 | { 13 | case fade, moveIn, push, reveal 14 | 15 | public var CATransitionValue: String { 16 | switch self { 17 | case .fade: 18 | return kCATransitionFade 19 | case .moveIn: 20 | return kCATransitionMoveIn 21 | case .push: 22 | return kCATransitionPush 23 | case .reveal: 24 | return kCATransitionReveal 25 | } 26 | } 27 | 28 | public func transition(withDuration duration: CFTimeInterval) -> CATransition 29 | { 30 | let transition = CATransition() 31 | 32 | transition.duration = duration 33 | transition.type = self.CATransitionValue 34 | 35 | return transition 36 | } 37 | } 38 | 39 | extension UINavigationController 40 | { 41 | // MARK: - Animation 42 | 43 | public func pushViewController(_ vc: UIViewController, animationType: CATransitionStyle, duration: CFTimeInterval = 0.2) 44 | { 45 | self._addAnimation(animationType, duration: duration) 46 | return self.pushViewController(vc, animated: false) 47 | } 48 | 49 | public func popViewController(animationType: CATransitionStyle, duration: CFTimeInterval = 0.2) -> UIViewController? 50 | { 51 | self._addAnimation(animationType, duration: duration) 52 | return self.popViewController(animated: false) 53 | } 54 | 55 | public func popToRootViewController(animationType: CATransitionStyle, duration: CFTimeInterval = 0.2) -> [UIViewController]? 56 | { 57 | self._addAnimation(animationType, duration: duration) 58 | return self.popToRootViewController(animated: false) 59 | } 60 | 61 | private func _addAnimation(_ transitionType: CATransitionStyle, duration: CFTimeInterval) 62 | { 63 | self.view.layer.add(transitionType.transition(withDuration: duration), forKey: nil) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/HaveCountTest.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Nimble 3 | 4 | final class HaveCountTest: XCTestCase, XCTestCaseProvider { 5 | static var allTests: [(String, (HaveCountTest) -> () throws -> Void)] { 6 | return [ 7 | ("testHaveCountForArray", testHaveCountForArray), 8 | ("testHaveCountForDictionary", testHaveCountForDictionary), 9 | ("testHaveCountForSet", testHaveCountForSet), 10 | ] 11 | } 12 | 13 | func testHaveCountForArray() { 14 | expect([1, 2, 3]).to(haveCount(3)) 15 | expect([1, 2, 3]).notTo(haveCount(1)) 16 | 17 | failsWithErrorMessage("expected to have Array with count 1, got 3\nActual Value: [1, 2, 3]") { 18 | expect([1, 2, 3]).to(haveCount(1)) 19 | } 20 | 21 | failsWithErrorMessage("expected to not have Array with count 3, got 3\nActual Value: [1, 2, 3]") { 22 | expect([1, 2, 3]).notTo(haveCount(3)) 23 | } 24 | } 25 | 26 | func testHaveCountForDictionary() { 27 | let dictionary = ["1": 1, "2": 2, "3": 3] 28 | expect(dictionary).to(haveCount(3)) 29 | expect(dictionary).notTo(haveCount(1)) 30 | 31 | failsWithErrorMessage("expected to have Dictionary with count 1, got 3\nActual Value: \(stringify(dictionary))") { 32 | expect(dictionary).to(haveCount(1)) 33 | } 34 | 35 | failsWithErrorMessage("expected to not have Dictionary with count 3, got 3" + 36 | "\nActual Value: \(stringify(dictionary))") { 37 | expect(dictionary).notTo(haveCount(3)) 38 | } 39 | } 40 | 41 | func testHaveCountForSet() { 42 | let set = Set([1, 2, 3]) 43 | expect(set).to(haveCount(3)) 44 | expect(set).notTo(haveCount(1)) 45 | 46 | failsWithErrorMessage("expected to have Set with count 1, got 3" + 47 | "\nActual Value: \(stringify(set))") { 48 | expect(set).to(haveCount(1)) 49 | } 50 | 51 | failsWithErrorMessage("expected to not have Set with count 3, got 3" + 52 | "\nActual Value: \(stringify(set))") { 53 | expect(set).notTo(haveCount(3)) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/EndWithTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | import Nimble 4 | 5 | final class EndWithTest: XCTestCase, XCTestCaseProvider { 6 | static var allTests: [(String, (EndWithTest) -> () throws -> Void)] { 7 | return [ 8 | ("testEndWithPositives", testEndWithPositives), 9 | ("testEndWithNegatives", testEndWithNegatives), 10 | ] 11 | } 12 | 13 | func testEndWithPositives() { 14 | expect([1, 2, 3]).to(endWith(3)) 15 | expect([1, 2, 3]).toNot(endWith(2)) 16 | expect([]).toNot(endWith(1)) 17 | expect(["a", "b", "a"]).to(endWith("a")) 18 | 19 | expect("foobar").to(endWith("bar")) 20 | expect("foobar").toNot(endWith("oo")) 21 | expect("foobarfoo").to(endWith("foo")) 22 | 23 | expect(NSString(string: "foobar").description).to(endWith("bar")) 24 | expect(NSString(string: "foobar").description).toNot(endWith("oo")) 25 | 26 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 27 | expect(NSArray(array: ["a", "b"])).to(endWith("b")) 28 | expect(NSArray(array: ["a", "b"])).toNot(endWith("a")) 29 | expect(NSArray(array: [])).toNot(endWith("a")) 30 | expect(NSArray(array: ["a", "b", "a"])).to(endWith("a")) 31 | #endif 32 | } 33 | 34 | func testEndWithNegatives() { 35 | failsWithErrorMessageForNil("expected to end with <2>, got ") { 36 | expect(nil as [Int]?).to(endWith(2)) 37 | } 38 | failsWithErrorMessageForNil("expected to not end with <2>, got ") { 39 | expect(nil as [Int]?).toNot(endWith(2)) 40 | } 41 | 42 | failsWithErrorMessage("expected to end with <2>, got <[1, 2, 3]>") { 43 | expect([1, 2, 3]).to(endWith(2)) 44 | } 45 | failsWithErrorMessage("expected to not end with <3>, got <[1, 2, 3]>") { 46 | expect([1, 2, 3]).toNot(endWith(3)) 47 | } 48 | failsWithErrorMessage("expected to end with , got ") { 49 | expect("batman").to(endWith("atm")) 50 | } 51 | failsWithErrorMessage("expected to not end with , got ") { 52 | expect("batman").toNot(endWith("man")) 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Swiftility/Sources/Extensions/Foundation/DateExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateExtensions.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 9/17/15. 6 | // Copyright © 2015 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension TimeZone { 12 | public static var gmt: TimeZone { return TimeZone(secondsFromGMT: 0)! } 13 | } 14 | 15 | extension Date { 16 | 17 | // MARK: - Convenience 18 | 19 | public static func from(_ date: String, format: String, locale: Locale = .current, timeZone: TimeZone = .current) -> Date? { 20 | let formatter = DateFormatter() 21 | 22 | formatter.dateFormat = format 23 | formatter.locale = locale 24 | formatter.timeZone = timeZone 25 | 26 | return formatter.date(from: date) 27 | } 28 | 29 | public func format(_ format: String, locale: Locale = .current, timeZone: TimeZone = .current) -> String { 30 | let formatter = DateFormatter() 31 | 32 | formatter.dateFormat = format 33 | formatter.locale = locale 34 | formatter.timeZone = timeZone 35 | 36 | return formatter.string(from: self) 37 | } 38 | 39 | public func date(byAdding value: Int, _ component: Calendar.Component, calendar: Calendar = .current) -> Date? { 40 | return calendar.date(byAdding: component, value: value, to: self) 41 | } 42 | 43 | public func date(bySetting component: Calendar.Component, to value: Int, calendar: Calendar = .current) -> Date? { 44 | return calendar.date(bySetting: component, value: value, of: self) 45 | } 46 | 47 | public func component(_ component: Calendar.Component, calendar: Calendar = .current) -> Int { 48 | return calendar.component(component, from: self) 49 | } 50 | 51 | // MARK: - String representation 52 | 53 | /// Easier to read string representation of date 54 | public var relativeValue: String { 55 | let formatter = DateFormatter() 56 | 57 | formatter.timeStyle = .short 58 | formatter.dateStyle = .short 59 | formatter.doesRelativeDateFormatting = true 60 | 61 | return formatter.string(from: self) 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/BeGreaterThanOrEqualToTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | import Nimble 4 | 5 | final class BeGreaterThanOrEqualToTest: XCTestCase, XCTestCaseProvider { 6 | static var allTests: [(String, (BeGreaterThanOrEqualToTest) -> () throws -> Void)] { 7 | return [ 8 | ("testGreaterThanOrEqualTo", testGreaterThanOrEqualTo), 9 | ("testGreaterThanOrEqualToOperator", testGreaterThanOrEqualToOperator), 10 | ] 11 | } 12 | 13 | func testGreaterThanOrEqualTo() { 14 | expect(10).to(beGreaterThanOrEqualTo(10)) 15 | expect(10).to(beGreaterThanOrEqualTo(2)) 16 | expect(1).toNot(beGreaterThanOrEqualTo(2)) 17 | expect(NSNumber(value:1)).toNot(beGreaterThanOrEqualTo(2)) 18 | expect(NSNumber(value:2)).to(beGreaterThanOrEqualTo(NSNumber(value:2))) 19 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 20 | expect(1).to(beGreaterThanOrEqualTo(NSNumber(value:0))) 21 | #endif 22 | 23 | failsWithErrorMessage("expected to be greater than or equal to <2>, got <0>") { 24 | expect(0).to(beGreaterThanOrEqualTo(2)) 25 | return 26 | } 27 | failsWithErrorMessage("expected to not be greater than or equal to <1>, got <1>") { 28 | expect(1).toNot(beGreaterThanOrEqualTo(1)) 29 | return 30 | } 31 | failsWithErrorMessageForNil("expected to be greater than or equal to <-2>, got ") { 32 | expect(nil as Int?).to(beGreaterThanOrEqualTo(-2)) 33 | } 34 | failsWithErrorMessageForNil("expected to not be greater than or equal to <1>, got ") { 35 | expect(nil as Int?).toNot(beGreaterThanOrEqualTo(1)) 36 | } 37 | } 38 | 39 | func testGreaterThanOrEqualToOperator() { 40 | expect(0) >= 0 41 | expect(1) >= 0 42 | expect(NSNumber(value:1)) >= 1 43 | expect(NSNumber(value:1)) >= NSNumber(value:1) 44 | expect(2.5) >= 2.5 45 | expect(2.5) >= 2 46 | expect(Float(2.5)) >= Float(2.5) 47 | expect(Float(2.5)) >= 2 48 | 49 | failsWithErrorMessage("expected to be greater than or equal to <2>, got <1>") { 50 | expect(1) >= 2 51 | return 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCContainTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCContainTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCContainTest 9 | 10 | - (void)testPositiveMatches { 11 | NSArray *array = @[@1, @2]; 12 | expect(array).to(contain(@1)); 13 | expect(array).toNot(contain(@"HI")); 14 | expect(@"String").to(contain(@"Str")); 15 | expect(@"Other").toNot(contain(@"Str")); 16 | } 17 | 18 | - (void)testNegativeMatches { 19 | expectFailureMessage(@"expected to contain <3>, got <(1, 2)>", ^{ 20 | expect((@[@1, @2])).to(contain(@3)); 21 | }); 22 | expectFailureMessage(@"expected to not contain <2>, got <(1, 2)>", ^{ 23 | expect((@[@1, @2])).toNot(contain(@2)); 24 | }); 25 | 26 | expectFailureMessage(@"expected to contain , got ", ^{ 27 | expect(@"la").to(contain(@"hi")); 28 | }); 29 | expectFailureMessage(@"expected to not contain , got ", ^{ 30 | expect(@"hihihi").toNot(contain(@"hi")); 31 | }); 32 | } 33 | 34 | - (void)testNilMatches { 35 | expectNilFailureMessage(@"expected to contain <3>, got ", ^{ 36 | expect(nil).to(contain(@3)); 37 | }); 38 | expectNilFailureMessage(@"expected to not contain <3>, got ", ^{ 39 | expect(nil).toNot(contain(@3)); 40 | }); 41 | 42 | expectNilFailureMessage(@"expected to contain , got ", ^{ 43 | expect(nil).to(contain(@"hi")); 44 | }); 45 | expectNilFailureMessage(@"expected to not contain , got ", ^{ 46 | expect(nil).toNot(contain(@"hi")); 47 | }); 48 | } 49 | 50 | - (void)testVariadicArguments { 51 | NSArray *array = @[@1, @2]; 52 | expect(array).to(contain(@1, @2)); 53 | expect(array).toNot(contain(@"HI", @"whale")); 54 | expect(@"String").to(contain(@"Str", @"ng")); 55 | expect(@"Other").toNot(contain(@"Str", @"Oth")); 56 | 57 | 58 | expectFailureMessage(@"expected to contain , got <(a, b, c)>", ^{ 59 | expect(@[@"a", @"b", @"c"]).to(contain(@"a", @"bar")); 60 | }); 61 | 62 | expectFailureMessage(@"expected to not contain , got <(a, b, c)>", ^{ 63 | expect(@[@"a", @"b", @"c"]).toNot(contain(@"a", @"b")); 64 | }); 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCBeIdenticalToTest.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCBeIdenticalToTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCBeIdenticalToTest 9 | 10 | - (void)testPositiveMatches { 11 | NSNull *obj = [NSNull null]; 12 | expect(obj).to(beIdenticalTo([NSNull null])); 13 | expect(@2).toNot(beIdenticalTo(@3)); 14 | } 15 | 16 | - (void)testNegativeMatches { 17 | NSNull *obj = [NSNull null]; 18 | expectFailureMessage(([NSString stringWithFormat:@"expected to be identical to <%p>, got <%p>", obj, @2]), ^{ 19 | expect(@2).to(beIdenticalTo(obj)); 20 | }); 21 | expectFailureMessage(([NSString stringWithFormat:@"expected to not be identical to <%p>, got <%p>", obj, obj]), ^{ 22 | expect(obj).toNot(beIdenticalTo(obj)); 23 | }); 24 | } 25 | 26 | - (void)testNilMatches { 27 | NSNull *obj = [NSNull null]; 28 | #pragma clang diagnostic push 29 | #pragma clang diagnostic ignored "-Wnonnull" 30 | expectNilFailureMessage(@"expected to be identical to nil, got nil", ^{ 31 | expect(nil).to(beIdenticalTo(nil)); 32 | }); 33 | #pragma clang diagnostic pop 34 | expectNilFailureMessage(([NSString stringWithFormat:@"expected to not be identical to <%p>, got nil", obj]), ^{ 35 | expect(nil).toNot(beIdenticalTo(obj)); 36 | }); 37 | } 38 | 39 | - (void)testAliasPositiveMatches { 40 | NSNull *obj = [NSNull null]; 41 | expect(obj).to(be([NSNull null])); 42 | expect(@2).toNot(be(@3)); 43 | } 44 | 45 | - (void)testAliasNegativeMatches { 46 | NSNull *obj = [NSNull null]; 47 | expectFailureMessage(([NSString stringWithFormat:@"expected to be identical to <%p>, got <%p>", obj, @2]), ^{ 48 | expect(@2).to(be(obj)); 49 | }); 50 | expectFailureMessage(([NSString stringWithFormat:@"expected to not be identical to <%p>, got <%p>", obj, obj]), ^{ 51 | expect(obj).toNot(be(obj)); 52 | }); 53 | } 54 | 55 | - (void)testAliasNilMatches { 56 | NSNull *obj = [NSNull null]; 57 | #pragma clang diagnostic push 58 | #pragma clang diagnostic ignored "-Wnonnull" 59 | expectNilFailureMessage(@"expected to be identical to nil, got nil", ^{ 60 | expect(nil).to(be(nil)); 61 | }); 62 | #pragma clang diagnostic pop 63 | expectNilFailureMessage(([NSString stringWithFormat:@"expected to not be identical to <%p>, got nil", obj]), ^{ 64 | expect(nil).toNot(be(obj)); 65 | }); 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/MatchError.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual expression evaluates to an 4 | /// error from the specified case. 5 | /// 6 | /// Errors are tried to be compared by their implementation of Equatable, 7 | /// otherwise they fallback to comparison by _domain and _code. 8 | public func matchError(_ error: T) -> Predicate { 9 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 10 | let actualError: Error? = try actualExpression.evaluate() 11 | 12 | setFailureMessageForError(failureMessage, postfixMessageVerb: "match", actualError: actualError, error: error) 13 | var matches = false 14 | if let actualError = actualError, errorMatchesExpectedError(actualError, expectedError: error) { 15 | matches = true 16 | } 17 | return matches 18 | }.requireNonNil 19 | } 20 | 21 | /// A Nimble matcher that succeeds when the actual expression evaluates to an 22 | /// error from the specified case. 23 | /// 24 | /// Errors are tried to be compared by their implementation of Equatable, 25 | /// otherwise they fallback to comparision by _domain and _code. 26 | public func matchError(_ error: T) -> Predicate { 27 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 28 | let actualError: Error? = try actualExpression.evaluate() 29 | 30 | setFailureMessageForError(failureMessage, postfixMessageVerb: "match", actualError: actualError, error: error) 31 | 32 | var matches = false 33 | if let actualError = actualError as? T, error == actualError { 34 | matches = true 35 | } 36 | return matches 37 | }.requireNonNil 38 | } 39 | 40 | /// A Nimble matcher that succeeds when the actual expression evaluates to an 41 | /// error of the specified type 42 | public func matchError(_ errorType: T.Type) -> Predicate { 43 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 44 | let actualError: Error? = try actualExpression.evaluate() 45 | 46 | setFailureMessageForError( 47 | failureMessage, 48 | postfixMessageVerb: "match", 49 | actualError: actualError, 50 | errorType: errorType 51 | ) 52 | var matches = false 53 | if actualError as? T != nil { 54 | matches = true 55 | } 56 | return matches 57 | }.requireNonNil 58 | } 59 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/ContainElementSatisfying.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func containElementSatisfying(_ predicate: @escaping ((T) -> Bool), _ predicateDescription: String = "") -> Predicate where S.Iterator.Element == T { 4 | 5 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 6 | failureMessage.actualValue = nil 7 | 8 | if predicateDescription == "" { 9 | failureMessage.postfixMessage = "find object in collection that satisfies predicate" 10 | } else { 11 | failureMessage.postfixMessage = "find object in collection \(predicateDescription)" 12 | } 13 | 14 | if let sequence = try actualExpression.evaluate() { 15 | for object in sequence { 16 | if predicate(object) { 17 | return true 18 | } 19 | } 20 | 21 | return false 22 | } 23 | 24 | return false 25 | }.requireNonNil 26 | } 27 | 28 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 29 | extension NMBObjCMatcher { 30 | @objc public class func containElementSatisfyingMatcher(_ predicate: @escaping ((NSObject) -> Bool)) -> NMBObjCMatcher { 31 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 32 | let value = try! actualExpression.evaluate() 33 | guard let enumeration = value as? NSFastEnumeration else { 34 | // swiftlint:disable:next line_length 35 | failureMessage.postfixMessage = "containElementSatisfying must be provided an NSFastEnumeration object" 36 | failureMessage.actualValue = nil 37 | failureMessage.expected = "" 38 | failureMessage.to = "" 39 | return false 40 | } 41 | 42 | var iterator = NSFastEnumerationIterator(enumeration) 43 | while let item = iterator.next() { 44 | guard let object = item as? NSObject else { 45 | continue 46 | } 47 | 48 | if predicate(object) { 49 | return true 50 | } 51 | } 52 | 53 | failureMessage.actualValue = nil 54 | failureMessage.postfixMessage = "" 55 | failureMessage.to = "to find object in collection that satisfies predicate" 56 | return false 57 | } 58 | } 59 | } 60 | #endif 61 | -------------------------------------------------------------------------------- /SwiftilityTests/Type Safe UIKIt/UITableViewTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UITableViewTests.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 1/31/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import Nimble 11 | @testable import Swiftility 12 | 13 | class UITableViewTests: XCTestCase 14 | { 15 | func testDefaultHeight() 16 | { 17 | XCTAssert(UITableViewCell.defaultHeight > 0, "UITableViewCell.DefaultHeight should be greater than 0") 18 | } 19 | 20 | func testDequeueCell() 21 | { 22 | let tableView = UITableView(frame: .zero, style: .grouped) 23 | 24 | tableView.register(TestCell.self) 25 | 26 | XCTAssert(true, "registerCell should not crash") 27 | 28 | // Dequeue cell that doesn't exists 29 | 30 | expect { 31 | _ = tableView.dequeueReusableCell() as TestNonExistingCell 32 | }.to(throwAssertion()) 33 | 34 | // Dequeue cell that exists 35 | 36 | _ = tableView.dequeueReusableCell() as TestCell 37 | XCTAssert(true, "dequeueReusableCell should not crash") 38 | 39 | // Register and dequeue class cell (non nib) 40 | 41 | tableView.register(TestCellClass.self) 42 | 43 | _ = tableView.dequeueReusableCell() as TestCellClass 44 | 45 | XCTAssert(true, "dequeueReusableCell should not crash") 46 | } 47 | 48 | func testDequeueCellOnViewController() 49 | { 50 | let tableVC = TestTableVC.instantiateFromStoryboard() 51 | 52 | XCTAssert(true, "tableVC instatiation should not crash") 53 | 54 | // Dequeue cell that doesn't exists 55 | 56 | expect { 57 | _ = tableVC.tableView.dequeueReusableCell() as TestNonExistingCell 58 | }.to(throwAssertion()) 59 | 60 | // Dequeue cell that exists 61 | 62 | _ = tableVC.tableView.dequeueReusableCell() as TestCell 63 | XCTAssert(true, "dequeueReusableCell should not crash") 64 | 65 | // Dequeue cell that doesn't exists forIndexPath 66 | 67 | expect { 68 | _ = tableVC.tableView.dequeueReusableCell(for: IndexPath(row: 0, section: 0)) as TestNonExistingCell 69 | }.to(throwAssertion()) 70 | 71 | // Dequeue cell that exists forIndexPath 72 | 73 | _ = tableVC.tableView.dequeueReusableCell(for: IndexPath(row: 0, section: 0)) as TestCell 74 | XCTAssert(true, "dequeueReusableCell should not crash") 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/BeAnInstanceOf.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is an _exact_ instance of the given class. 4 | public func beAnInstanceOf(_ expectedType: T.Type) -> Predicate { 5 | let errorMessage = "be an instance of \(String(describing: expectedType))" 6 | return Predicate.define { actualExpression in 7 | let instance = try actualExpression.evaluate() 8 | guard let validInstance = instance else { 9 | return PredicateResult( 10 | status: .doesNotMatch, 11 | message: .expectedActualValueTo(errorMessage) 12 | ) 13 | } 14 | 15 | let actualString = "<\(String(describing: type(of: validInstance))) instance>" 16 | 17 | return PredicateResult( 18 | status: PredicateStatus(bool: type(of: validInstance) == expectedType), 19 | message: .expectedCustomValueTo(errorMessage, actualString) 20 | ) 21 | } 22 | } 23 | 24 | /// A Nimble matcher that succeeds when the actual value is an instance of the given class. 25 | /// @see beAKindOf if you want to match against subclasses 26 | public func beAnInstanceOf(_ expectedClass: AnyClass) -> Predicate { 27 | let errorMessage = "be an instance of \(String(describing: expectedClass))" 28 | return Predicate.define { actualExpression in 29 | let instance = try actualExpression.evaluate() 30 | let actualString: String 31 | if let validInstance = instance { 32 | actualString = "<\(String(describing: type(of: validInstance))) instance>" 33 | } else { 34 | actualString = "" 35 | } 36 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 37 | let matches = instance != nil && instance!.isMember(of: expectedClass) 38 | #else 39 | let matches = instance != nil && type(of: instance!) == expectedClass 40 | #endif 41 | return PredicateResult( 42 | status: PredicateStatus(bool: matches), 43 | message: .expectedCustomValueTo(errorMessage, actualString) 44 | ) 45 | } 46 | } 47 | 48 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 49 | extension NMBObjCMatcher { 50 | @objc public class func beAnInstanceOfMatcher(_ expected: AnyClass) -> NMBMatcher { 51 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 52 | return try! beAnInstanceOf(expected).matches(actualExpression, failureMessage: failureMessage) 53 | } 54 | } 55 | } 56 | #endif 57 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/objc/ObjCContainElementSatisfying.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NimbleSpecHelper.h" 3 | 4 | @interface ObjCContainElementSatisfyingTest : XCTestCase 5 | 6 | @end 7 | 8 | @implementation ObjCContainElementSatisfyingTest 9 | 10 | - (void)testPassingMatches { 11 | NSArray *orderIndifferentArray = @[@1, @2, @3]; 12 | expect(orderIndifferentArray).to(containElementSatisfying(^BOOL(id object) { 13 | return [object isEqualToNumber:@1]; 14 | })); 15 | expect(orderIndifferentArray).to(containElementSatisfying(^BOOL(id object) { 16 | return [object isEqualToNumber:@2]; 17 | })); 18 | expect(orderIndifferentArray).to(containElementSatisfying(^BOOL(id object) { 19 | return [object isEqualToNumber:@3]; 20 | })); 21 | 22 | orderIndifferentArray = @[@3, @1, @2]; 23 | expect(orderIndifferentArray).to(containElementSatisfying(^BOOL(id object) { 24 | return [object isEqualToNumber:@1]; 25 | })); 26 | expect(orderIndifferentArray).to(containElementSatisfying(^BOOL(id object) { 27 | return [object isEqualToNumber:@2]; 28 | })); 29 | expect(orderIndifferentArray).to(containElementSatisfying(^BOOL(id object) { 30 | return [object isEqualToNumber:@3]; 31 | })); 32 | 33 | NSSet *orderIndifferentSet = [NSSet setWithObjects:@"turtle test", @"turtle assessment", nil]; 34 | expect(orderIndifferentSet).to(containElementSatisfying(^BOOL(id object) { 35 | return [object isEqualToString:@"turtle assessment"]; 36 | })); 37 | } 38 | 39 | - (void)testFailingMatches { 40 | expectFailureMessage(@"expected to find object in collection that satisfies predicate", ^{ 41 | expect(@[@1]).to(containElementSatisfying(^BOOL(id object) { 42 | return [object isEqualToNumber:@2]; 43 | })); 44 | }); 45 | expectFailureMessage(@"containElementSatisfying must be provided an NSFastEnumeration object", ^{ 46 | expect((nil)).to(containElementSatisfying(^BOOL(id object) { 47 | return [object isEqualToNumber:@3]; 48 | })); 49 | }); 50 | expectFailureMessage(@"containElementSatisfying must be provided an NSFastEnumeration object", ^{ 51 | expect((@3)).to(containElementSatisfying(^BOOL(id object) { 52 | return [object isEqualToNumber:@3]; 53 | })); 54 | }); 55 | } 56 | 57 | - (void)testNegativeCases { 58 | NSArray *orderIndifferentArray = @[@"puppies", @"kittens", @"turtles"]; 59 | expect(orderIndifferentArray).toNot(containElementSatisfying(^BOOL(id object) { 60 | return [object isEqualToString:@"armadillos"]; 61 | })); 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Nimble/Nimble.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Nimble" 3 | s.version = "7.0.1" 4 | s.summary = "A Matcher Framework for Swift and Objective-C" 5 | s.description = <<-DESC 6 | Use Nimble to express the expected outcomes of Swift or Objective-C expressions. Inspired by Cedar. 7 | DESC 8 | s.homepage = "https://github.com/Quick/Nimble" 9 | s.license = { :type => "Apache 2.0", :file => "LICENSE" } 10 | s.author = "Quick Contributors" 11 | s.ios.deployment_target = "8.0" 12 | s.osx.deployment_target = "10.10" 13 | s.tvos.deployment_target = "9.0" 14 | s.source = { :git => "https://github.com/Quick/Nimble.git", 15 | :tag => "v#{s.version}" } 16 | 17 | s.source_files = "Sources/**/*.{swift,h,m,c}" 18 | 19 | s.osx.exclude_files = [ 20 | "Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/CwlCatchBadInstructionPosix.swift", 21 | "Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/Posix/CwlPreconditionTesting.h", 22 | ] 23 | s.ios.exclude_files = [ 24 | "Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/CwlCatchBadInstructionPOSIX.swift", 25 | "Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/Posix/CwlPreconditionTesting.h", 26 | ] 27 | s.tvos.exclude_files = [ 28 | "Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/Mach/CwlPreconditionTesting.h", 29 | "Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/CwlCatchBadInstruction.swift", 30 | "Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/CwlCatchBadInstruction.m", 31 | "Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/CwlBadInstructionException.swift", 32 | "Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/CwlDarwinDefinitions.swift", 33 | "Sources/Lib/CwlPreconditionTesting/CwlCatchException/CwlCatchException.swift", 34 | "Sources/Lib/CwlPreconditionTesting/CwlCatchExceptionSupport/CwlCatchException.m", 35 | "Sources/Lib/CwlPreconditionTesting/CwlCatchExceptionSupport/include/CwlCatchException.h", 36 | ] 37 | 38 | s.private_header_files = "Sources/NimbleObjectiveC/CurrentTestCaseTracker.h" 39 | 40 | s.exclude_files = "Sources/Nimble/Adapters/NonObjectiveC/*.swift" 41 | s.weak_framework = "XCTest" 42 | s.requires_arc = true 43 | s.compiler_flags = '-DPRODUCT_NAME=Nimble/Nimble' 44 | s.pod_target_xcconfig = { 45 | 'ENABLE_BITCODE' => 'NO', 46 | 'OTHER_LDFLAGS' => '-weak-lswiftXCTest', 47 | 'OTHER_SWIFT_FLAGS' => '$(inherited) -suppress-warnings', 48 | 'FRAMEWORK_SEARCH_PATHS' => '$(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"', 49 | } 50 | end 51 | -------------------------------------------------------------------------------- /Swiftility/Sources/Type Safety/UICollectionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UICollectionView.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 1/29/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension UICollectionView 12 | { 13 | // MARK: - Cell 14 | 15 | public func register(_ nibCell: T.Type) where T: UICollectionViewCell, T: FromNib 16 | { 17 | self.register(nibCell.ownNib.nib, forCellWithReuseIdentifier: nibCell.ownNib.nibName) 18 | } 19 | 20 | public func register(_ classCell: T.Type) 21 | { 22 | self.register(T.self, forCellWithReuseIdentifier: String(describing: T.self)) 23 | } 24 | 25 | // MARK: - Supplementary view 26 | 27 | public func register(_ nibView: T.Type, forSupplementaryViewOfKind elementKind: String) where T: UICollectionReusableView, T: FromNib 28 | { 29 | self.register(nibView.ownNib.nib, forSupplementaryViewOfKind: elementKind, withReuseIdentifier: nibView.ownNib.nibName) 30 | } 31 | 32 | public func register(_ classView: T.Type, forSupplementaryViewOfKind elementKind: String) 33 | { 34 | self.register(T.self, forSupplementaryViewOfKind: elementKind, withReuseIdentifier: String(describing: T.self)) 35 | } 36 | 37 | // MARK: - Dequeue 38 | 39 | public func dequeueReusableCell(for indexPath: IndexPath) -> T 40 | { 41 | var cell: UICollectionViewCell? = nil 42 | 43 | do { 44 | try ObjC.catchException { 45 | cell = self.dequeueReusableCell(withReuseIdentifier: String(describing: T.self), for: indexPath) 46 | } 47 | } catch { 48 | cell = nil 49 | } 50 | 51 | guard let typedCell = cell as? T else { 52 | fatalError("\(String(describing: T.self)) cell could not be instantiated because it was not found on the collectionView(\(self))") 53 | } 54 | 55 | return typedCell 56 | } 57 | 58 | public func dequeueReusableSupplementaryView(ofKind elementKind: String, for indexPath: IndexPath) -> T 59 | { 60 | guard let view = self.dequeueReusableSupplementaryView(ofKind: elementKind, withReuseIdentifier: String(describing: T.self), for: indexPath) as? T else { 61 | fatalError("\(String(describing: T.self)) supplementary view of kind \(elementKind) could not be instantiated because it was not found on the collectionView(\(self))") 62 | } 63 | 64 | return view 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /SwiftilityTests/Type Safe UIKIt/UICollectionViewTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UICollectionViewTests.swift 3 | // Swiftility 4 | // 5 | // Created by Allan Barbato on 1/31/16. 6 | // Copyright © 2016 Allan Barbato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import Nimble 11 | @testable import Swiftility 12 | 13 | class UICollectionViewTests: XCTestCase 14 | { 15 | // let collectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: UICollectionViewFlowLayout()) 16 | let collectionVC = TestCollectionViewVC.instantiateFromStoryboard() 17 | 18 | func testDequeueCell() 19 | { 20 | let collectionView = self.collectionVC.collectionView 21 | 22 | XCTAssert(collectionView != nil) 23 | 24 | // Dequeue storyboard cell 25 | 26 | _ = collectionView!.dequeueReusableCell(for: IndexPath(row: 0, section: 0)) as TestCollectionViewStoryboardCell 27 | 28 | XCTAssert(true, "dequeueReusableCell should not crash") 29 | 30 | // Register and dequeue nib cell 31 | 32 | collectionView!.register(TestCollectionViewCell.self) 33 | 34 | XCTAssert(true, "registerCell should not crash") 35 | 36 | _ = collectionView!.dequeueReusableCell(for: IndexPath(row: 0, section: 0)) as TestCollectionViewCell 37 | 38 | XCTAssert(true, "dequeueReusableCell should not crash") 39 | 40 | // Register and dequeue class cell 41 | 42 | collectionView!.register(TestCollectionViewCellClass.self) 43 | 44 | XCTAssert(true, "registerCell should not crash") 45 | 46 | _ = collectionView!.dequeueReusableCell(for: IndexPath(row: 1, section: 0)) as TestCollectionViewCellClass 47 | 48 | XCTAssert(true, "dequeueReusableCell should not crash") 49 | 50 | // Dequeue non existing cell 51 | 52 | expect { 53 | _ = collectionView!.dequeueReusableCell(for: IndexPath(row: 1, section: 0)) as TestNonExistingCollectionViewCell 54 | }.to(throwAssertion()) 55 | } 56 | 57 | // TODO: Add test for reusableSupplementaryView 58 | // func testDequeueView() 59 | // { 60 | // let collectionView = self.collectionVC.collectionView 61 | // 62 | // expect(collectionView!.registerSupplementaryView(TestCollectionViewView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader)).toNot(raiseException()) 63 | // 64 | // expect(collectionView!.dequeueReusableSupplementaryView(kind: UICollectionElementKindSectionHeader, type: TestCollectionViewView.self, forIndexPath: NSIndexPath(forRow: 0, inSection: 0))).to(beTruthy()) 65 | // } 66 | } 67 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/DSL.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Make an expectation on a given actual value. The value given is lazily evaluated. 4 | public func expect(_ expression: @autoclosure @escaping () throws -> T?, file: FileString = #file, line: UInt = #line) -> Expectation { 5 | return Expectation( 6 | expression: Expression( 7 | expression: expression, 8 | location: SourceLocation(file: file, line: line), 9 | isClosure: true)) 10 | } 11 | 12 | /// Make an expectation on a given actual value. The closure is lazily invoked. 13 | public func expect(_ file: FileString = #file, line: UInt = #line, expression: @escaping () throws -> T?) -> Expectation { 14 | return Expectation( 15 | expression: Expression( 16 | expression: expression, 17 | location: SourceLocation(file: file, line: line), 18 | isClosure: true)) 19 | } 20 | 21 | /// Always fails the test with a message and a specified location. 22 | public func fail(_ message: String, location: SourceLocation) { 23 | let handler = NimbleEnvironment.activeInstance.assertionHandler 24 | handler.assert(false, message: FailureMessage(stringValue: message), location: location) 25 | } 26 | 27 | /// Always fails the test with a message. 28 | public func fail(_ message: String, file: FileString = #file, line: UInt = #line) { 29 | fail(message, location: SourceLocation(file: file, line: line)) 30 | } 31 | 32 | /// Always fails the test. 33 | public func fail(_ file: FileString = #file, line: UInt = #line) { 34 | fail("fail() always fails", file: file, line: line) 35 | } 36 | 37 | /// Like Swift's precondition(), but raises NSExceptions instead of sigaborts 38 | internal func nimblePrecondition( 39 | _ expr: @autoclosure() -> Bool, 40 | _ name: @autoclosure() -> String, 41 | _ message: @autoclosure() -> String, 42 | file: StaticString = #file, 43 | line: UInt = #line) { 44 | let result = expr() 45 | if !result { 46 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 47 | let e = NSException( 48 | name: NSExceptionName(name()), 49 | reason: message(), 50 | userInfo: nil) 51 | e.raise() 52 | #else 53 | preconditionFailure("\(name()) - \(message())", file: file, line: line) 54 | #endif 55 | } 56 | } 57 | 58 | internal func internalError(_ msg: String, file: FileString = #file, line: UInt = #line) -> Never { 59 | fatalError( 60 | "Nimble Bug Found: \(msg) at \(file):\(line).\n" + 61 | "Please file a bug to Nimble: https://github.com/Quick/Nimble/issues with the " + 62 | "code snippet that caused this error." 63 | ) 64 | } 65 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/PostNotification.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal class NotificationCollector { 4 | private(set) var observedNotifications: [Notification] 5 | private let notificationCenter: NotificationCenter 6 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 7 | private var token: AnyObject? 8 | #else 9 | private var token: NSObjectProtocol? 10 | #endif 11 | 12 | required init(notificationCenter: NotificationCenter) { 13 | self.notificationCenter = notificationCenter 14 | self.observedNotifications = [] 15 | } 16 | 17 | func startObserving() { 18 | self.token = self.notificationCenter.addObserver(forName: nil, object: nil, queue: nil) { [weak self] n in 19 | // linux-swift gets confused by .append(n) 20 | self?.observedNotifications.append(n) 21 | } 22 | } 23 | 24 | deinit { 25 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 26 | if let token = self.token { 27 | self.notificationCenter.removeObserver(token) 28 | } 29 | #else 30 | if let token = self.token as? AnyObject { 31 | self.notificationCenter.removeObserver(token) 32 | } 33 | #endif 34 | } 35 | } 36 | 37 | private let mainThread = pthread_self() 38 | 39 | public func postNotifications( 40 | _ notificationsMatcher: T, 41 | fromNotificationCenter center: NotificationCenter = .default) 42 | -> Predicate 43 | where T: Matcher, T.ValueType == [Notification] 44 | { 45 | _ = mainThread // Force lazy-loading of this value 46 | let collector = NotificationCollector(notificationCenter: center) 47 | collector.startObserving() 48 | var once: Bool = false 49 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 50 | let collectorNotificationsExpression = Expression(memoizedExpression: { _ in 51 | return collector.observedNotifications 52 | }, location: actualExpression.location, withoutCaching: true) 53 | 54 | assert(pthread_equal(mainThread, pthread_self()) != 0, "Only expecting closure to be evaluated on main thread.") 55 | if !once { 56 | once = true 57 | _ = try actualExpression.evaluate() 58 | } 59 | 60 | let match = try notificationsMatcher.matches(collectorNotificationsExpression, failureMessage: failureMessage) 61 | if collector.observedNotifications.isEmpty { 62 | failureMessage.actualValue = "no notifications" 63 | } else { 64 | failureMessage.actualValue = "<\(stringify(collector.observedNotifications))>" 65 | } 66 | return match 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Nimble/Sources/Lib/CwlPreconditionTesting/CwlPreconditionTesting/CwlDarwinDefinitions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CwlDarwinDefinitions.swift 3 | // CwlPreconditionTesting 4 | // 5 | // Created by Matt Gallagher on 2016/01/10. 6 | // Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved. 7 | // 8 | // Permission to use, copy, modify, and/or distribute this software for any 9 | // purpose with or without fee is hereby granted, provided that the above 10 | // copyright notice and this permission notice appear in all copies. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 15 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 18 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | // 20 | 21 | import Darwin 22 | 23 | #if arch(x86_64) 24 | 25 | // From /usr/include/mach/message.h 26 | // #define MACH_MSG_TYPE_MAKE_SEND 20 /* Must hold receive right */ 27 | // #define MACH_MSGH_BITS_REMOTE(bits) \ 28 | // ((bits) & MACH_MSGH_BITS_REMOTE_MASK) 29 | // #define MACH_MSGH_BITS(remote, local) /* legacy */ \ 30 | // ((remote) | ((local) << 8)) 31 | public let MACH_MSG_TYPE_MAKE_SEND: UInt32 = 20 32 | public func MACH_MSGH_BITS_REMOTE(_ bits: UInt32) -> UInt32 { return bits & UInt32(MACH_MSGH_BITS_REMOTE_MASK) } 33 | public func MACH_MSGH_BITS(_ remote: UInt32, _ local: UInt32) -> UInt32 { return ((remote) | ((local) << 8)) } 34 | 35 | // From /usr/include/mach/exception_types.h 36 | // #define EXC_BAD_INSTRUCTION 2 /* Instruction failed */ 37 | // #define EXC_MASK_BAD_INSTRUCTION (1 << EXC_BAD_INSTRUCTION) 38 | public let EXC_BAD_INSTRUCTION: UInt32 = 2 39 | public let EXC_MASK_BAD_INSTRUCTION: UInt32 = 1 << EXC_BAD_INSTRUCTION 40 | 41 | // From /usr/include/mach/i386/thread_status.h 42 | // #define x86_THREAD_STATE64_COUNT ((mach_msg_type_number_t) \ 43 | // ( sizeof (x86_thread_state64_t) / sizeof (int) )) 44 | public let x86_THREAD_STATE64_COUNT = UInt32(MemoryLayout.size / MemoryLayout.size) 45 | 46 | public let EXC_TYPES_COUNT = 14 47 | public struct execTypesCountTuple { 48 | // From /usr/include/mach/i386/exception.h 49 | // #define EXC_TYPES_COUNT 14 /* incl. illegal exception 0 */ 50 | public var value: (T, T, T, T, T, T, T, T, T, T, T, T, T, T) = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 51 | public init() { 52 | } 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/SatisfyAnyOfTest.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Nimble 3 | import Foundation 4 | 5 | final class SatisfyAnyOfTest: XCTestCase, XCTestCaseProvider { 6 | static var allTests: [(String, (SatisfyAnyOfTest) -> () throws -> Void)] { 7 | return [ 8 | ("testSatisfyAnyOf", testSatisfyAnyOf), 9 | ("testOperatorOr", testOperatorOr), 10 | ] 11 | } 12 | 13 | func testSatisfyAnyOf() { 14 | expect(2).to(satisfyAnyOf(equal(2), equal(3))) 15 | #if SUPPORT_IMPLICIT_BRIDGING_CONVERSION 16 | expect(2).toNot(satisfyAnyOf(equal(3), equal("turtles"))) 17 | #else 18 | expect(2 as NSNumber).toNot(satisfyAnyOf(equal(3 as NSNumber), equal("turtles" as NSString))) 19 | #endif 20 | expect([1, 2, 3]).to(satisfyAnyOf(equal([1, 2, 3]), allPass({$0 < 4}), haveCount(3))) 21 | expect("turtle").toNot(satisfyAnyOf(contain("a"), endWith("magic"))) 22 | expect(82.0).toNot(satisfyAnyOf(beLessThan(10.5), beGreaterThan(100.75), beCloseTo(50.1))) 23 | expect(false).to(satisfyAnyOf(beTrue(), beFalse())) 24 | expect(true).to(satisfyAnyOf(beTruthy(), beFalsy())) 25 | 26 | failsWithErrorMessage( 27 | "expected to match one of: {equal <3>}, or {equal <4>}, or {equal <5>}, got 2") { 28 | expect(2).to(satisfyAnyOf(equal(3), equal(4), equal(5))) 29 | } 30 | failsWithErrorMessage( 31 | "expected to match one of: {all be less than 4, but failed first at element <5> in <[5, 6, 7]>}, or {equal <[1, 2, 3, 4]>}, got [5, 6, 7]") { 32 | expect([5, 6, 7]).to(satisfyAnyOf(allPass("be less than 4", {$0 < 4}), equal([1, 2, 3, 4]))) 33 | } 34 | failsWithErrorMessage( 35 | "expected to match one of: {be true}, got false") { 36 | expect(false).to(satisfyAnyOf(beTrue())) 37 | } 38 | failsWithErrorMessage( 39 | "expected to not match one of: {be less than <10.5>}, or {be greater than <100.75>}, or {be close to <50.1> (within 0.0001)}, got 50.10001") { 40 | expect(50.10001).toNot(satisfyAnyOf(beLessThan(10.5), beGreaterThan(100.75), beCloseTo(50.1))) 41 | } 42 | } 43 | 44 | func testOperatorOr() { 45 | expect(2).to(equal(2) || equal(3)) 46 | #if SUPPORT_IMPLICIT_BRIDGING_CONVERSION 47 | expect(2).toNot(equal(3) || equal("turtles")) 48 | #else 49 | expect(2 as NSNumber).toNot(equal(3 as NSNumber) || equal("turtles" as NSString)) 50 | #endif 51 | expect("turtle").toNot(contain("a") || endWith("magic")) 52 | expect(82.0).toNot(beLessThan(10.5) || beGreaterThan(100.75)) 53 | expect(false).to(beTrue() || beFalse()) 54 | expect(true).to(beTruthy() || beFalsy()) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/BeAKindOf.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | private func matcherMessage(forType expectedType: T.Type) -> String { 4 | return "be a kind of \(String(describing: expectedType))" 5 | } 6 | private func matcherMessage(forClass expectedClass: AnyClass) -> String { 7 | return "be a kind of \(String(describing: expectedClass))" 8 | } 9 | 10 | /// A Nimble matcher that succeeds when the actual value is an instance of the given class. 11 | public func beAKindOf(_ expectedType: T.Type) -> Predicate { 12 | return Predicate.define { actualExpression in 13 | let message: ExpectationMessage 14 | 15 | let instance = try actualExpression.evaluate() 16 | guard let validInstance = instance else { 17 | message = .expectedCustomValueTo(matcherMessage(forType: expectedType), "") 18 | return PredicateResult(status: .fail, message: message) 19 | } 20 | message = .expectedCustomValueTo( 21 | "be a kind of \(String(describing: expectedType))", 22 | "<\(String(describing: type(of: validInstance))) instance>" 23 | ) 24 | 25 | return PredicateResult( 26 | bool: validInstance is T, 27 | message: message 28 | ) 29 | } 30 | } 31 | 32 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 33 | 34 | /// A Nimble matcher that succeeds when the actual value is an instance of the given class. 35 | /// @see beAnInstanceOf if you want to match against the exact class 36 | public func beAKindOf(_ expectedClass: AnyClass) -> Predicate { 37 | return Predicate.define { actualExpression in 38 | let message: ExpectationMessage 39 | let status: PredicateStatus 40 | 41 | let instance = try actualExpression.evaluate() 42 | if let validInstance = instance { 43 | status = PredicateStatus(bool: instance != nil && instance!.isKind(of: expectedClass)) 44 | message = .expectedCustomValueTo( 45 | matcherMessage(forClass: expectedClass), 46 | "<\(String(describing: type(of: validInstance))) instance>" 47 | ) 48 | } else { 49 | status = .fail 50 | message = .expectedCustomValueTo( 51 | matcherMessage(forClass: expectedClass), 52 | "" 53 | ) 54 | } 55 | 56 | return PredicateResult(status: status, message: message) 57 | } 58 | } 59 | 60 | extension NMBObjCMatcher { 61 | @objc public class func beAKindOfMatcher(_ expected: AnyClass) -> NMBMatcher { 62 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 63 | return try! beAKindOf(expected).matches(actualExpression, failureMessage: failureMessage) 64 | } 65 | } 66 | } 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/BeIdenticalToTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | @testable import Nimble 4 | 5 | final class BeIdenticalToTest: XCTestCase, XCTestCaseProvider { 6 | static var allTests: [(String, (BeIdenticalToTest) -> () throws -> Void)] { 7 | return [ 8 | ("testBeIdenticalToPositive", testBeIdenticalToPositive), 9 | ("testBeIdenticalToNegative", testBeIdenticalToNegative), 10 | ("testBeIdenticalToPositiveMessage", testBeIdenticalToPositiveMessage), 11 | ("testBeIdenticalToNegativeMessage", testBeIdenticalToNegativeMessage), 12 | ("testOperators", testOperators), 13 | ("testBeAlias", testBeAlias), 14 | ] 15 | } 16 | 17 | func testBeIdenticalToPositive() { 18 | let value = NSDate() 19 | expect(value).to(beIdenticalTo(value)) 20 | } 21 | 22 | func testBeIdenticalToNegative() { 23 | expect(NSNumber(value:1)).toNot(beIdenticalTo(NSString(string: "yo"))) 24 | expect(NSArray(array: [NSNumber(value: 1)])).toNot(beIdenticalTo(NSArray(array: [NSNumber(value: 1)]))) 25 | } 26 | 27 | func testBeIdenticalToPositiveMessage() { 28 | let num1 = NSNumber(value:1) 29 | let num2 = NSNumber(value:2) 30 | let message = "expected to be identical to \(identityAsString(num2)), got \(identityAsString(num1))" 31 | failsWithErrorMessage(message) { 32 | expect(num1).to(beIdenticalTo(num2)) 33 | } 34 | } 35 | 36 | func testBeIdenticalToNegativeMessage() { 37 | let value1 = NSArray(array: []) 38 | let value2 = value1 39 | let message = "expected to not be identical to \(identityAsString(value2)), got \(identityAsString(value1))" 40 | failsWithErrorMessage(message) { 41 | expect(value1).toNot(beIdenticalTo(value2)) 42 | } 43 | } 44 | 45 | func testOperators() { 46 | let value = NSDate() 47 | expect(value) === value 48 | expect(NSNumber(value:1)) !== NSNumber(value:2) 49 | } 50 | 51 | func testBeAlias() { 52 | let value = NSDate() 53 | expect(value).to(be(value)) 54 | expect(NSNumber(value:1)).toNot(be(NSString(string: "turtles"))) 55 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 56 | expect([1]).toNot(be([1])) 57 | #else 58 | expect(NSArray(array: [NSNumber(value: 1)])).toNot(beIdenticalTo(NSArray(array: [NSNumber(value: 1)]))) 59 | #endif 60 | 61 | let value1 = NSArray(array: []) 62 | let value2 = value1 63 | let message = "expected to not be identical to \(identityAsString(value1)), got \(identityAsString(value2))" 64 | failsWithErrorMessage(message) { 65 | expect(value1).toNot(be(value2)) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/ThrowAssertion.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func throwAssertion() -> Predicate { 4 | return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in 5 | #if arch(x86_64) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE 6 | failureMessage.postfixMessage = "throw an assertion" 7 | failureMessage.actualValue = nil 8 | 9 | var succeeded = true 10 | 11 | let caughtException: BadInstructionException? = catchBadInstruction { 12 | #if os(tvOS) 13 | if !NimbleEnvironment.activeInstance.suppressTVOSAssertionWarning { 14 | print() 15 | print("[Nimble Warning]: If you're getting stuck on a debugger breakpoint for a " + 16 | "fatal error while using throwAssertion(), please disable 'Debug Executable' " + 17 | "in your scheme. Go to 'Edit Scheme > Test > Info' and uncheck " + 18 | "'Debug Executable'. If you've already done that, suppress this warning " + 19 | "by setting `NimbleEnvironment.activeInstance.suppressTVOSAssertionWarning = true`. " + 20 | "This is required because the standard methods of catching assertions " + 21 | "(mach APIs) are unavailable for tvOS. Instead, the same mechanism the " + 22 | "debugger uses is the fallback method for tvOS." 23 | ) 24 | print() 25 | NimbleEnvironment.activeInstance.suppressTVOSAssertionWarning = true 26 | } 27 | #endif 28 | do { 29 | try actualExpression.evaluate() 30 | } catch let error { 31 | succeeded = false 32 | failureMessage.postfixMessage += "; threw error instead <\(error)>" 33 | } 34 | } 35 | 36 | if !succeeded { 37 | return false 38 | } 39 | 40 | if caughtException == nil { 41 | return false 42 | } 43 | 44 | return true 45 | #elseif SWIFT_PACKAGE 46 | fatalError("The throwAssertion Nimble matcher does not currently support Swift CLI." + 47 | " You can silence this error by placing the test case inside an #if !SWIFT_PACKAGE" + 48 | " conditional statement") 49 | #else 50 | fatalError("The throwAssertion Nimble matcher can only run on x86_64 platforms with " + 51 | "Objective-C (e.g. Mac, iPhone 5s or later simulators). You can silence this error " + 52 | "by placing the test case inside an #if arch(x86_64) or (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) conditional statement") 53 | // swiftlint:disable:previous line_length 54 | #endif 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/BeIdenticalToObjectTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | import Nimble 4 | 5 | final class BeIdenticalToObjectTest: XCTestCase, XCTestCaseProvider { 6 | static var allTests: [(String, (BeIdenticalToObjectTest) -> () throws -> Void)] { 7 | return [ 8 | ("testBeIdenticalToPositive", testBeIdenticalToPositive), 9 | ("testBeIdenticalToNegative", testBeIdenticalToNegative), 10 | ("testBeIdenticalToPositiveMessage", testBeIdenticalToPositiveMessage), 11 | ("testBeIdenticalToNegativeMessage", testBeIdenticalToNegativeMessage), 12 | ("testFailsOnNils", testFailsOnNils), 13 | ("testOperators", testOperators), 14 | ] 15 | } 16 | 17 | private class BeIdenticalToObjectTester {} 18 | private let testObjectA = BeIdenticalToObjectTester() 19 | private let testObjectB = BeIdenticalToObjectTester() 20 | 21 | func testBeIdenticalToPositive() { 22 | expect(self.testObjectA).to(beIdenticalTo(testObjectA)) 23 | } 24 | 25 | func testBeIdenticalToNegative() { 26 | expect(self.testObjectA).toNot(beIdenticalTo(testObjectB)) 27 | } 28 | 29 | func testBeIdenticalToPositiveMessage() { 30 | let message = String(describing: NSString(format: "expected to be identical to <%p>, got <%p>", 31 | unsafeBitCast(testObjectB, to: Int.self), unsafeBitCast(testObjectA, to: Int.self))) 32 | failsWithErrorMessage(message) { 33 | expect(self.testObjectA).to(beIdenticalTo(self.testObjectB)) 34 | } 35 | } 36 | 37 | func testBeIdenticalToNegativeMessage() { 38 | let message = String(describing: NSString(format: "expected to not be identical to <%p>, got <%p>", 39 | unsafeBitCast(testObjectA, to: Int.self), unsafeBitCast(testObjectA, to: Int.self))) 40 | failsWithErrorMessage(message) { 41 | expect(self.testObjectA).toNot(beIdenticalTo(self.testObjectA)) 42 | } 43 | } 44 | 45 | func testFailsOnNils() { 46 | let message1 = String(describing: NSString(format: "expected to be identical to <%p>, got nil", 47 | unsafeBitCast(testObjectA, to: Int.self))) 48 | failsWithErrorMessageForNil(message1) { 49 | expect(nil as BeIdenticalToObjectTester?).to(beIdenticalTo(self.testObjectA)) 50 | } 51 | 52 | let message2 = String(describing: NSString(format: "expected to not be identical to <%p>, got nil", 53 | unsafeBitCast(testObjectA, to: Int.self))) 54 | failsWithErrorMessageForNil(message2) { 55 | expect(nil as BeIdenticalToObjectTester?).toNot(beIdenticalTo(self.testObjectA)) 56 | } 57 | } 58 | 59 | func testOperators() { 60 | expect(self.testObjectA) === testObjectA 61 | expect(self.testObjectA) !== testObjectB 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/UserDescriptionTest.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Nimble 3 | 4 | final class UserDescriptionTest: XCTestCase, XCTestCaseProvider { 5 | static var allTests: [(String, (UserDescriptionTest) -> () throws -> Void)] { 6 | return [ 7 | ("testToMatcher_CustomFailureMessage", testToMatcher_CustomFailureMessage), 8 | ("testNotToMatcher_CustomFailureMessage", testNotToMatcher_CustomFailureMessage), 9 | ("testToNotMatcher_CustomFailureMessage", testToNotMatcher_CustomFailureMessage), 10 | ("testToEventuallyMatch_CustomFailureMessage", testToEventuallyMatch_CustomFailureMessage), 11 | ("testToEventuallyNotMatch_CustomFailureMessage", testToEventuallyNotMatch_CustomFailureMessage), 12 | ("testToNotEventuallyMatch_CustomFailureMessage", testToNotEventuallyMatch_CustomFailureMessage), 13 | ] 14 | } 15 | 16 | func testToMatcher_CustomFailureMessage() { 17 | failsWithErrorMessage( 18 | "These aren't equal!\n" + 19 | "expected to match, got <1>") { 20 | expect(1).to(MatcherFunc { _, _ in false }, description: "These aren't equal!") 21 | } 22 | } 23 | 24 | func testNotToMatcher_CustomFailureMessage() { 25 | failsWithErrorMessage( 26 | "These aren't equal!\n" + 27 | "expected to not match, got <1>") { 28 | expect(1).notTo(MatcherFunc { _, _ in true }, description: "These aren't equal!") 29 | } 30 | } 31 | 32 | func testToNotMatcher_CustomFailureMessage() { 33 | failsWithErrorMessage( 34 | "These aren't equal!\n" + 35 | "expected to not match, got <1>") { 36 | expect(1).toNot(MatcherFunc { _, _ in true }, description: "These aren't equal!") 37 | } 38 | } 39 | 40 | func testToEventuallyMatch_CustomFailureMessage() { 41 | failsWithErrorMessage( 42 | "These aren't eventually equal!\n" + 43 | "expected to eventually equal <1>, got <0>") { 44 | expect { 0 }.toEventually(equal(1), description: "These aren't eventually equal!") 45 | } 46 | } 47 | 48 | func testToEventuallyNotMatch_CustomFailureMessage() { 49 | failsWithErrorMessage( 50 | "These are eventually equal!\n" + 51 | "expected to eventually not equal <1>, got <1>") { 52 | expect { 1 }.toEventuallyNot(equal(1), description: "These are eventually equal!") 53 | } 54 | } 55 | 56 | func testToNotEventuallyMatch_CustomFailureMessage() { 57 | failsWithErrorMessage( 58 | "These are eventually equal!\n" + 59 | "expected to eventually not equal <1>, got <1>") { 60 | expect { 1 }.toEventuallyNot(equal(1), description: "These are eventually equal!") 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /Nimble/Sources/Lib/CwlPreconditionTesting/CwlMachBadInstructionHandler/include/CwlMachBadInstructionHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // CwlMachBadExceptionHandler.h 3 | // CwlPreconditionTesting 4 | // 5 | // Created by Matt Gallagher on 2016/01/10. 6 | // Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved. 7 | // 8 | // Permission to use, copy, modify, and/or distribute this software for any 9 | // purpose with or without fee is hereby granted, provided that the above 10 | // copyright notice and this permission notice appear in all copies. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 15 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 18 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | // 20 | 21 | #import 22 | #import 23 | 24 | NS_ASSUME_NONNULL_BEGIN 25 | 26 | extern boolean_t mach_exc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); 27 | 28 | // The request_mach_exception_raise_t struct is passed to mach_msg which assumes its exact layout. To avoid problems with different layouts, we keep the definition in C rather than Swift. 29 | typedef struct 30 | { 31 | mach_msg_header_t Head; 32 | /* start of the kernel processed data */ 33 | mach_msg_body_t msgh_body; 34 | mach_msg_port_descriptor_t thread; 35 | mach_msg_port_descriptor_t task; 36 | /* end of the kernel processed data */ 37 | NDR_record_t NDR; 38 | exception_type_t exception; 39 | mach_msg_type_number_t codeCnt; 40 | int64_t code[2]; 41 | int flavor; 42 | mach_msg_type_number_t old_stateCnt; 43 | natural_t old_state[224]; 44 | } request_mach_exception_raise_t; 45 | 46 | // The reply_mach_exception_raise_state_t struct is passed to mach_msg which assumes its exact layout. To avoid problems with different layouts, we keep the definition in C rather than Swift. 47 | typedef struct 48 | { 49 | mach_msg_header_t Head; 50 | NDR_record_t NDR; 51 | kern_return_t RetCode; 52 | int flavor; 53 | mach_msg_type_number_t new_stateCnt; 54 | natural_t new_state[224]; 55 | } reply_mach_exception_raise_state_t; 56 | 57 | typedef struct 58 | { 59 | mach_port_t exception_port; 60 | exception_type_t exception; 61 | mach_exception_data_type_t const * _Nullable code; 62 | mach_msg_type_number_t codeCnt; 63 | int32_t * _Nullable flavor; 64 | natural_t const * _Nullable old_state; 65 | mach_msg_type_number_t old_stateCnt; 66 | thread_state_t _Nullable new_state; 67 | mach_msg_type_number_t * _Nullable new_stateCnt; 68 | } bad_instruction_exception_reply_t; 69 | 70 | NS_ASSUME_NONNULL_END 71 | -------------------------------------------------------------------------------- /Nimble/Sources/Nimble/Matchers/BeginWith.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual sequence's first element 4 | /// is equal to the expected value. 5 | public func beginWith(_ startingElement: T) -> Predicate 6 | where S.Iterator.Element == T { 7 | return Predicate.simple("begin with <\(startingElement)>") { actualExpression in 8 | if let actualValue = try actualExpression.evaluate() { 9 | var actualGenerator = actualValue.makeIterator() 10 | return PredicateStatus(bool: actualGenerator.next() == startingElement) 11 | } 12 | return .fail 13 | } 14 | } 15 | 16 | /// A Nimble matcher that succeeds when the actual collection's first element 17 | /// is equal to the expected object. 18 | public func beginWith(_ startingElement: Any) -> Predicate { 19 | return Predicate.simple("begin with <\(startingElement)>") { actualExpression in 20 | guard let collection = try actualExpression.evaluate() else { return .fail } 21 | guard collection.count > 0 else { return .doesNotMatch } 22 | #if os(Linux) 23 | guard let collectionValue = collection.object(at: 0) as? NSObject else { 24 | return .fail 25 | } 26 | #else 27 | let collectionValue = collection.object(at: 0) as AnyObject 28 | #endif 29 | return PredicateStatus(bool: collectionValue.isEqual(startingElement)) 30 | } 31 | } 32 | 33 | /// A Nimble matcher that succeeds when the actual string contains expected substring 34 | /// where the expected substring's location is zero. 35 | public func beginWith(_ startingSubstring: String) -> Predicate { 36 | return Predicate.simple("begin with <\(startingSubstring)>") { actualExpression in 37 | if let actual = try actualExpression.evaluate() { 38 | let range = actual.range(of: startingSubstring) 39 | return PredicateStatus(bool: range != nil && range!.lowerBound == actual.startIndex) 40 | } 41 | return .fail 42 | } 43 | } 44 | 45 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 46 | extension NMBObjCMatcher { 47 | @objc public class func beginWithMatcher(_ expected: Any) -> NMBObjCMatcher { 48 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 49 | let actual = try! actualExpression.evaluate() 50 | if (actual as? String) != nil { 51 | let expr = actualExpression.cast { $0 as? String } 52 | return try! beginWith(expected as! String).matches(expr, failureMessage: failureMessage) 53 | } else { 54 | let expr = actualExpression.cast { $0 as? NMBOrderedCollection } 55 | return try! beginWith(expected).matches(expr, failureMessage: failureMessage) 56 | } 57 | } 58 | } 59 | } 60 | #endif 61 | -------------------------------------------------------------------------------- /Nimble/Tests/NimbleTests/Matchers/BeEmptyTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | import Nimble 4 | 5 | final class BeEmptyTest: XCTestCase, XCTestCaseProvider { 6 | static var allTests: [(String, (BeEmptyTest) -> () throws -> Void)] { 7 | return [ 8 | ("testBeEmptyPositive", testBeEmptyPositive), 9 | ("testBeEmptyNegative", testBeEmptyNegative), 10 | ] 11 | } 12 | 13 | func testBeEmptyPositive() { 14 | expect([] as [Int]).to(beEmpty()) 15 | expect([1]).toNot(beEmpty()) 16 | 17 | expect([] as [CInt]).to(beEmpty()) 18 | expect([1] as [CInt]).toNot(beEmpty()) 19 | 20 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 21 | expect(NSDictionary() as? [Int:Int]).to(beEmpty()) 22 | expect(NSDictionary(object: 1, forKey: 1 as NSNumber) as? [Int:Int]).toNot(beEmpty()) 23 | #endif 24 | 25 | expect([Int: Int]()).to(beEmpty()) 26 | expect(["hi": 1]).toNot(beEmpty()) 27 | 28 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 29 | expect(NSArray() as? [Int]).to(beEmpty()) 30 | expect(NSArray(array: [1]) as? [Int]).toNot(beEmpty()) 31 | #endif 32 | 33 | expect(NSSet()).to(beEmpty()) 34 | expect(NSSet(array: [NSNumber(value: 1)])).toNot(beEmpty()) 35 | 36 | expect(NSIndexSet()).to(beEmpty()) 37 | expect(NSIndexSet(index: 1)).toNot(beEmpty()) 38 | 39 | expect(NSString()).to(beEmpty()) 40 | expect(NSString(string: "hello")).toNot(beEmpty()) 41 | 42 | expect("").to(beEmpty()) 43 | expect("foo").toNot(beEmpty()) 44 | } 45 | 46 | func testBeEmptyNegative() { 47 | failsWithErrorMessageForNil("expected to be empty, got ") { 48 | expect(nil as NSString?).to(beEmpty()) 49 | } 50 | failsWithErrorMessageForNil("expected to not be empty, got ") { 51 | expect(nil as [CInt]?).toNot(beEmpty()) 52 | } 53 | 54 | failsWithErrorMessage("expected to not be empty, got <()>") { 55 | expect(NSArray()).toNot(beEmpty()) 56 | } 57 | failsWithErrorMessage("expected to be empty, got <[1]>") { 58 | expect([1]).to(beEmpty()) 59 | } 60 | 61 | failsWithErrorMessage("expected to not be empty, got <{()}>") { 62 | expect(NSSet()).toNot(beEmpty()) 63 | } 64 | failsWithErrorMessage("expected to be empty, got <{(1)}>") { 65 | expect(NSSet(object: NSNumber(value: 1))).to(beEmpty()) 66 | } 67 | 68 | failsWithErrorMessage("expected to not be empty, got <()>") { 69 | expect(NSIndexSet()).toNot(beEmpty()) 70 | } 71 | failsWithErrorMessage("expected to be empty, got <(1)>") { 72 | expect(NSIndexSet(index: 1)).to(beEmpty()) 73 | } 74 | 75 | failsWithErrorMessage("expected to not be empty, got <>") { 76 | expect("").toNot(beEmpty()) 77 | } 78 | failsWithErrorMessage("expected to be empty, got ") { 79 | expect("foo").to(beEmpty()) 80 | } 81 | } 82 | } 83 | --------------------------------------------------------------------------------