Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save karthikAdaptavant/0ba16932cd5b3f85f8ed9d38767e1e4e to your computer and use it in GitHub Desktop.
Save karthikAdaptavant/0ba16932cd5b3f85f8ed9d38767e1e4e to your computer and use it in GitHub Desktop.
This code is deprecated. You can use https://github.com/mattgallagher/CwlPreconditionTesting instead.
//
// ProgrammerAssertions.swift
// Assertions
//
// Created by Mohamed Afifi on 12/20/15.
// Copyright © 2015 mohamede1945. All rights reserved.
//
import Foundation
/// ### IMPORTANT HOW TO USE ###
/// 1. Drop `ProgrammerAssertions.swift` to the target of your app or framework under test. Just besides your source code.
/// 2. Drop `XCTestCase+ProgrammerAssertions.swift` to your test target. Just besides your test cases.
/// 3. Use `assert`, `assertionFailure`, `precondition`, `preconditionFailure` and `fatalError` normally as you always do.
/// 4. Unit test them with the new methods `expectAssert`, `expectAssertionFailure`, `expectPrecondition`, `expectPreconditionFailure` and `expectFatalError`.
///
/// This file is an overriden implementation of Swift assertions functions.
/// For a complete project example see <https://github.com/mohamede1945/AssertionsTestingExample>
/// drop-in replacements
public func assert(@autoclosure condition: () -> Bool, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
Assertions.assertClosure(condition(), message(), file, line)
}
public func assertionFailure(@autoclosure message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
Assertions.assertionFailureClosure(message(), file, line)
}
public func precondition(@autoclosure condition: () -> Bool, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
Assertions.preconditionClosure(condition(), message(), file, line)
}
@noreturn public func preconditionFailure(@autoclosure message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
Assertions.preconditionFailureClosure(message(), file, line)
runForever()
}
@noreturn public func fatalError(@autoclosure message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
Assertions.fatalErrorClosure(message(), file, line)
runForever()
}
/// Stores custom assertions closures, by default it points to Swift functions. But test target can override them.
public class Assertions {
public static var assertClosure = swiftAssertClosure
public static var assertionFailureClosure = swiftAssertionFailureClosure
public static var preconditionClosure = swiftPreconditionClosure
public static var preconditionFailureClosure = swiftPreconditionFailureClosure
public static var fatalErrorClosure = swiftFatalErrorClosure
public static let swiftAssertClosure = { Swift.assert($0, $1, file: $2, line: $3) }
public static let swiftAssertionFailureClosure = { Swift.assertionFailure($0, file: $1, line: $2) }
public static let swiftPreconditionClosure = { Swift.precondition($0, $1, file: $2, line: $3) }
public static let swiftPreconditionFailureClosure = { Swift.preconditionFailure($0, file: $1, line: $2) }
public static let swiftFatalErrorClosure = { Swift.fatalError($0, file: $1, line: $2) }
}
/// This is a `noreturn` function that runs forever and doesn't return.
/// Used by assertions with `@noreturn`.
@noreturn private func runForever() {
repeat {
NSRunLoop.currentRunLoop().run()
} while (true)
}
//
// ProgrammerAssertionsExampleDivide.swift
// Assertions
//
// Created by Mohamed Afifi on 12/20/15.
// Copyright © 2015 mohamede1945. All rights reserved.
//
import UIKit
/// ### IMPORTANT HOW TO USE ###
/// 1. Drop `ProgrammerAssertions.swift` to the target of your app or framework under test. Just besides your source code.
/// 2. Drop `XCTestCase+ProgrammerAssertions.swift` to your test target. Just besides your test cases.
/// 3. Use `assert`, `assertionFailure`, `precondition`, `preconditionFailure` and `fatalError` normally as you always do.
/// 4. Unit test them with the new methods `expectAssert`, `expectAssertionFailure`, `expectPrecondition`, `expectPreconditionFailure` and `expectFatalError`.
///
/// This file is just an example of how to use the functions. Normally as you would do previously.
/// For a complete project example see <https://github.com/mohamede1945/AssertionsTestingExample>
func divideAssert(x: Float, by y: Float) -> Float {
assert(y != 0, "Zero division")
return x / y
}
func divideAssertionFailure(x: Float, by y: Float) -> Float {
guard y != 0 else {
assertionFailure("Zero division")
return Float.infinity
}
return x / y
}
func dividePrecondition(x: Float, by y: Float) -> Float {
precondition(y != 0, "Zero division")
return x / y
}
func dividePreconditionFailure(x: Float, by y: Float) -> Float {
guard y != 0 else {
preconditionFailure("Zero division")
}
return x / y
}
func divideFatalError(x: Float, by y: Float) -> Float {
guard y != 0 else {
fatalError("Zero division")
}
return x / y
}
//
// ProgrammerAssertionsExampleTests.swift
// AssertionsTests
//
// Created by Mohamed Afifi on 12/20/15.
// Copyright © 2015 mohamede1945. All rights reserved.
//
import XCTest
@testable import Assertions
/// ### IMPORTANT HOW TO USE ###
/// 1. Drop `ProgrammerAssertions.swift` to the target of your app or framework under test. Just besides your source code.
/// 2. Drop `XCTestCase+ProgrammerAssertions.swift` to your test target. Just besides your test cases.
/// 3. Use `assert`, `assertionFailure`, `precondition`, `preconditionFailure` and `fatalError` normally as you always do.
/// 4. Unit test them with the new methods `expectAssert`, `expectAssertionFailure`, `expectPrecondition`, `expectPreconditionFailure` and `expectFatalError`.
///
/// This file is just an example of how to unit test the functions.
/// When you run tests, you should expect many of them to fail. This is normally, because the test cases tests the error message produced by expectXXX methods.
/// For a complete project example see <https://github.com/mohamede1945/AssertionsTestingExample>
class AssertionsTestsExample: XCTestCase {
// assert tests
func testAssertNotCalled() {
expectAssert("Zero division") {
}
}
func testAssertTrueCondition() {
expectAssert("Zero division") {
divideAssert(1, by: 1)
}
}
func testAssertNoMessage() {
expectAssert() {
divideAssert(1, by: 0)
}
}
func testAssertErrorIncorrectMessage() {
expectAssert("Invalid") {
divideAssert(1, by: 0)
}
}
func testAssertCorrectMessage() {
expectAssert("Zero division") {
divideAssert(1, by: 0)
}
}
// expectionFailure tests
func testAssertionFailureNotCalled() {
expectAssertionFailure("Zero division") {
divideAssertionFailure(1, by: 1)
}
}
func testAssertionFailureNoMessage() {
expectAssertionFailure() {
divideAssertionFailure(1, by: 0)
}
}
func testAssertionFailureErrorIncorrectMessage() {
expectAssertionFailure("Invalid") {
divideAssertionFailure(1, by: 0)
}
}
func testAssertionFailureCorrectMessage() {
expectAssertionFailure("Zero division") {
divideAssertionFailure(1, by: 0)
}
}
// precondition tests
func testPreconditionNotCalled() {
expectPrecondition("Zero division") {
}
}
func testPreconditionTrueCondition() {
expectPrecondition("Zero division") {
dividePrecondition(1, by: 1)
}
}
func testPreconditionNoMessage() {
expectPrecondition() {
dividePrecondition(1, by: 0)
}
}
func testPreconditionErrorIncorrectMessage() {
expectPrecondition("Invalid") {
dividePrecondition(1, by: 0)
}
}
func testPreconditionCorrectMessage() {
expectPrecondition("Zero division") {
dividePrecondition(1, by: 0)
}
}
// preconditionFailure tests
func testPreconditionFailureNotCalled() {
expectPreconditionFailure("Zero division") {
dividePreconditionFailure(1, by: 1)
}
}
func testPreconditionFailureNoMessage() {
expectPreconditionFailure() {
dividePreconditionFailure(1, by: 0)
}
}
func testPreconditionFailureErrorIncorrectMessage() {
expectPreconditionFailure("Invalid") {
dividePreconditionFailure(1, by: 0)
}
}
func testPreconditionFailureCorrectMessage() {
expectPreconditionFailure("Zero division") {
dividePreconditionFailure(1, by: 0)
}
}
// fatalError tests
func testFatalErrorNotCalled() {
expectFatalError("Zero division!") {
divideFatalError(1, by: 1)
}
}
func testFatalErrorNoMessage() {
expectFatalError() {
divideFatalError(1, by: 0)
}
}
func testFatalErrorIncorrectMessage() {
expectFatalError("Invalid") {
divideFatalError(1, by: 0)
}
}
func testFatalCorrectMessage() {
expectFatalError("Zero division") {
divideFatalError(1, by: 0)
}
}
}
//
// XCTestCase+ProgrammerAssertions.swift
// Assertions
//
// Created by Mohamed Afifi on 12/20/15.
// Copyright © 2015 mohamede1945. All rights reserved.
//
/// ### IMPORTANT HOW TO USE ###
/// 1. Drop `ProgrammerAssertions.swift` to the target of your app or framework under test. Just besides your source code.
/// 2. Drop `XCTestCase+ProgrammerAssertions.swift` to your test target. Just besides your test cases.
/// 3. Use `assert`, `assertionFailure`, `precondition`, `preconditionFailure` and `fatalError` normally as you always do.
/// 4. Unit test them with the new methods `expectAssert`, `expectAssertionFailure`, `expectPrecondition`, `expectPreconditionFailure` and `expectFatalError`.
///
/// This file is the unit test assertions.
/// For a complete project example see <https://github.com/mohamede1945/AssertionsTestingExample>
import Foundation
import XCTest
@testable import Assertions
private let noReturnFailureWaitTime = 0.1
public extension XCTestCase {
/**
Expects an `assert` to be called with a false condition.
If `assert` not called or the assert's condition is true, the test case will fail.
- parameter expectedMessage: The expected message to be asserted to the one passed to the `assert`. If nil, then ignored.
- parameter file: The file name that called the method.
- parameter line: The line number that called the method.
- parameter testCase: The test case to be executed that expected to fire the assertion method.
*/
public func expectAssert(
expectedMessage: String? = nil,
file: StaticString = __FILE__,
line: UInt = __LINE__,
testCase: () -> Void
) {
expectAssertionReturnFunction("assert", file: file, line: line, function: { (caller) -> () in
Assertions.assertClosure = { condition, message, _, _ in
caller(condition, message)
}
}, expectedMessage: expectedMessage, testCase: testCase) { () -> () in
Assertions.assertClosure = Assertions.swiftAssertClosure
}
}
/**
Expects an `assertionFailure` to be called.
If `assertionFailure` not called, the test case will fail.
- parameter expectedMessage: The expected message to be asserted to the one passed to the `assertionFailure`. If nil, then ignored.
- parameter file: The file name that called the method.
- parameter line: The line number that called the method.
- parameter testCase: The test case to be executed that expected to fire the assertion method.
*/
public func expectAssertionFailure(
expectedMessage: String? = nil,
file: StaticString = __FILE__,
line: UInt = __LINE__,
testCase: () -> Void
) {
expectAssertionReturnFunction("assertionFailure", file: file, line: line, function: { (caller) -> () in
Assertions.assertionFailureClosure = { message, _, _ in
caller(false, message)
}
}, expectedMessage: expectedMessage, testCase: testCase) { () -> () in
Assertions.assertionFailureClosure = Assertions.swiftAssertionFailureClosure
}
}
/**
Expects an `precondition` to be called with a false condition.
If `precondition` not called or the precondition's condition is true, the test case will fail.
- parameter expectedMessage: The expected message to be asserted to the one passed to the `precondition`. If nil, then ignored.
- parameter file: The file name that called the method.
- parameter line: The line number that called the method.
- parameter testCase: The test case to be executed that expected to fire the assertion method.
*/
public func expectPrecondition(
expectedMessage: String? = nil,
file: StaticString = __FILE__,
line: UInt = __LINE__,
testCase: () -> Void
) {
expectAssertionReturnFunction("precondition", file: file, line: line, function: { (caller) -> () in
Assertions.preconditionClosure = { condition, message, _, _ in
caller(condition, message)
}
}, expectedMessage: expectedMessage, testCase: testCase) { () -> () in
Assertions.preconditionClosure = Assertions.swiftPreconditionClosure
}
}
/**
Expects an `preconditionFailure` to be called.
If `preconditionFailure` not called, the test case will fail.
- parameter expectedMessage: The expected message to be asserted to the one passed to the `preconditionFailure`. If nil, then ignored.
- parameter file: The file name that called the method.
- parameter line: The line number that called the method.
- parameter testCase: The test case to be executed that expected to fire the assertion method.
*/
public func expectPreconditionFailure(
expectedMessage: String? = nil,
file: StaticString = __FILE__,
line: UInt = __LINE__,
testCase: () -> Void
) {
expectAssertionNoReturnFunction("preconditionFailure", file: file, line: line, function: { (caller) -> () in
Assertions.preconditionFailureClosure = { message, _, _ in
caller(message)
}
}, expectedMessage: expectedMessage, testCase: testCase) { () -> () in
Assertions.preconditionFailureClosure = Assertions.swiftPreconditionFailureClosure
}
}
/**
Expects an `fatalError` to be called.
If `fatalError` not called, the test case will fail.
- parameter expectedMessage: The expected message to be asserted to the one passed to the `fatalError`. If nil, then ignored.
- parameter file: The file name that called the method.
- parameter line: The line number that called the method.
- parameter testCase: The test case to be executed that expected to fire the assertion method.
*/
public func expectFatalError(
expectedMessage: String? = nil,
file: StaticString = __FILE__,
line: UInt = __LINE__,
testCase: () -> Void) {
expectAssertionNoReturnFunction("fatalError", file: file, line: line, function: { (caller) -> () in
Assertions.fatalErrorClosure = { message, _, _ in
caller(message)
}
}, expectedMessage: expectedMessage, testCase: testCase) { () -> () in
Assertions.fatalErrorClosure = Assertions.swiftFatalErrorClosure
}
}
// MARK:- Private Methods
private func expectAssertionReturnFunction(
functionName: String,
file: StaticString,
line: UInt,
function: (caller: (Bool, String) -> Void) -> Void,
expectedMessage: String? = nil,
testCase: () -> Void,
cleanUp: () -> ()
) {
let expectation = expectationWithDescription(functionName + "-Expectation")
var assertion: (condition: Bool, message: String)? = nil
function { (condition, message) -> Void in
assertion = (condition, message)
expectation.fulfill()
}
// perform on the same thread since it will return
testCase()
waitForExpectationsWithTimeout(0) { _ in
defer {
// clean up
cleanUp()
}
guard let assertion = assertion else {
XCTFail(functionName + " is expected to be called.", file: file.stringValue, line: line)
return
}
XCTAssertFalse(assertion.condition, functionName + " condition expected to be false", file: file.stringValue, line: line)
if let expectedMessage = expectedMessage {
// assert only if not nil
XCTAssertEqual(assertion.message, expectedMessage, functionName + " called with incorrect message.", file: file.stringValue, line: line)
}
}
}
private func expectAssertionNoReturnFunction(
functionName: String,
file: StaticString,
line: UInt,
function: (caller: (String) -> Void) -> Void,
expectedMessage: String? = nil,
testCase: () -> Void,
cleanUp: () -> ()
) {
let expectation = expectationWithDescription(functionName + "-Expectation")
var assertionMessage: String? = nil
function { (message) -> Void in
assertionMessage = message
expectation.fulfill()
}
// act, perform on separate thead because a call to function runs forever
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), testCase)
waitForExpectationsWithTimeout(noReturnFailureWaitTime) { _ in
defer {
// clean up
cleanUp()
}
guard let assertionMessage = assertionMessage else {
XCTFail(functionName + " is expected to be called.", file: file.stringValue, line: line)
return
}
if let expectedMessage = expectedMessage {
// assert only if not nil
XCTAssertEqual(assertionMessage, expectedMessage, functionName + " called with incorrect message.", file: file.stringValue, line: line)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment