Skip to content

Make NSPredicate expectation constructor API accept nil object #219

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Sources/XCTest/Private/XCPredicateExpectation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@

internal class XCPredicateExpectation: XCTestExpectation {
internal let predicate: NSPredicate
internal let object: AnyObject
internal let object: Any?
internal var timer: Timer?
internal let handler: XCPredicateExpectationHandler?
private let evaluationInterval = 0.01

internal init(predicate: NSPredicate, object: AnyObject, description: String, file: StaticString, line: Int, testCase: XCTestCase, handler: XCPredicateExpectationHandler? = nil) {
internal init(predicate: NSPredicate, object: Any? = nil, file: StaticString, line: Int, testCase: XCTestCase, handler: XCPredicateExpectationHandler? = nil) {
self.predicate = predicate
self.object = object
self.handler = handler
self.timer = nil
let description = "Expect predicate `\(predicate)`" + (object.map { " for object \($0)" } ?? "")
super.init(description: description, file: file, line: line, testCase: testCase)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public extension XCTestCase {
/// - Parameter predicate: The predicate that will be used to evaluate the
/// object.
/// - Parameter object: The object that is evaluated against the conditions
/// specified by the predicate.
/// specified by the predicate, if any. Default is nil.
/// - Parameter file: The file name to use in the error message if
/// this expectation is not waited for. Default is the file
/// containing the call to this method. It is rare to provide this
Expand All @@ -33,11 +33,10 @@ public extension XCTestCase {
/// first successful evaluation will fulfill the expectation. If provided,
/// the handler can override that behavior which leaves the caller
/// responsible for fulfilling the expectation.
@discardableResult func expectation(for predicate: NSPredicate, evaluatedWith object: AnyObject, file: StaticString = #file, line: Int = #line, handler: XCPredicateExpectationHandler? = nil) -> XCTestExpectation {
@discardableResult func expectation(for predicate: NSPredicate, evaluatedWith object: Any? = nil, file: StaticString = #file, line: Int = #line, handler: XCPredicateExpectationHandler? = nil) -> XCTestExpectation {
let expectation = XCPredicateExpectation(
predicate: predicate,
object: object,
description: "Expect `\(predicate)` for object \(object)",
file: file,
line: line,
testCase: self,
Expand Down
86 changes: 60 additions & 26 deletions Tests/Functional/Asynchronous/Predicates/Expectations/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,66 +13,100 @@

// CHECK: Test Suite 'PredicateExpectationsTestCase' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
class PredicateExpectationsTestCase: XCTestCase {
// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyTruePredicateAndObject_passes' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyTruePredicateAndObject_passes' passed \(\d+\.\d+ seconds\)
func test_immediatelyTruePredicateAndObject_passes() {
// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyTruePredicate_passes' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyTruePredicate_passes' passed \(\d+\.\d+ seconds\)
func test_immediatelyTruePredicate_passes() {
let predicate = NSPredicate(value: true)
let object = NSObject()
expectation(for: predicate, evaluatedWith: object)
expectation(for: predicate)
waitForExpectations(timeout: 0.1)
}

// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyFalsePredicateAndObject_fails' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: .*/Tests/Functional/Asynchronous/Predicates/Expectations/main.swift:[[@LINE+6]]: error: PredicateExpectationsTestCase.test_immediatelyFalsePredicateAndObject_fails : Asynchronous wait failed - Exceeded timeout of 0.1 seconds, with unfulfilled expectations: Expect `<NSPredicate: 0x[0-9A-Fa-f]{1,16}>` for object <NSObject: 0x[0-9A-Fa-f]{1,16}>
// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyFalsePredicateAndObject_fails' failed \(\d+\.\d+ seconds\)
func test_immediatelyFalsePredicateAndObject_fails() {
// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyFalsePredicate_fails' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: .*/Tests/Functional/Asynchronous/Predicates/Expectations/main.swift:[[@LINE+5]]: error: PredicateExpectationsTestCase.test_immediatelyFalsePredicate_fails : Asynchronous wait failed - Exceeded timeout of 0.1 seconds, with unfulfilled expectations: Expect predicate `<NSPredicate: 0x[0-9A-Fa-f]{1,16}>`
// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyFalsePredicate_fails' failed \(\d+\.\d+ seconds\)
func test_immediatelyFalsePredicate_fails() {
let predicate = NSPredicate(value: false)
let object = NSObject()
expectation(for: predicate, evaluatedWith: object)
expectation(for: predicate)
waitForExpectations(timeout: 0.1)
}

// CHECK: Test Case 'PredicateExpectationsTestCase.test_delayedTruePredicateAndObject_passes' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: Test Case 'PredicateExpectationsTestCase.test_delayedTruePredicateAndObject_passes' passed \(\d+\.\d+ seconds\)
func test_delayedTruePredicateAndObject_passes() {
// CHECK: Test Case 'PredicateExpectationsTestCase.test_delayedTruePredicate_passes' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: Test Case 'PredicateExpectationsTestCase.test_delayedTruePredicate_passes' passed \(\d+\.\d+ seconds\)
func test_delayedTruePredicate_passes() {
var didEvaluate = false
let predicate = NSPredicate(block: { evaluatedObject, bindings in
XCTAssertNil(evaluatedObject)
defer { didEvaluate = true }
return didEvaluate
})
expectation(for: predicate, evaluatedWith: NSObject())
expectation(for: predicate)
waitForExpectations(timeout: 0.1)
}

// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyTrueDelayedFalsePredicateAndObject_passes' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyTrueDelayedFalsePredicateAndObject_passes' passed \(\d+\.\d+ seconds\)
func test_immediatelyTrueDelayedFalsePredicateAndObject_passes() {
// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyTrueDelayedFalsePredicate_passes' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: Test Case 'PredicateExpectationsTestCase.test_immediatelyTrueDelayedFalsePredicate_passes' passed \(\d+\.\d+ seconds\)
func test_immediatelyTrueDelayedFalsePredicate_passes() {
var didEvaluate = false
let predicate = NSPredicate(block: { evaluatedObject, bindings in
XCTAssertNil(evaluatedObject)
defer { didEvaluate = true }
return !didEvaluate
})
expectation(for: predicate, evaluatedWith: NSObject())
expectation(for: predicate)
XCTAssertTrue(didEvaluate)

waitForExpectations(timeout: 0.1)
}

// CHECK: Test Case 'PredicateExpectationsTestCase.test_blockPredicateWithNilObject_passes' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: Test Case 'PredicateExpectationsTestCase.test_blockPredicateWithNilObject_passes' passed \(\d+\.\d+ seconds\)
func test_blockPredicateWithNilObject_passes() {
var flag = false
let predicate = NSPredicate(block: { _, _ in
return flag
})
expectation(for: predicate, evaluatedWith: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
flag = true
}
waitForExpectations(timeout: 1)
XCTAssertTrue(flag)
}

// CHECK: Test Case 'PredicateExpectationsTestCase.test_blockPredicateWithObject_passes' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: Test Case 'PredicateExpectationsTestCase.test_blockPredicateWithObject_passes' passed \(\d+\.\d+ seconds\)
func test_blockPredicateWithObject_passes() {
class Foo { var x = false }
let foo = Foo()
let predicate = NSPredicate(block: { evaluatedObject, _ in
guard let object = evaluatedObject as? Foo else { return false }
return object.x
})
expectation(for: predicate, evaluatedWith: foo)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
foo.x = true
}
waitForExpectations(timeout: 1)
XCTAssertTrue(foo.x)
}

static var allTests = {
return [
("test_immediatelyTruePredicateAndObject_passes", test_immediatelyTruePredicateAndObject_passes),
("test_immediatelyFalsePredicateAndObject_fails", test_immediatelyFalsePredicateAndObject_fails),
("test_delayedTruePredicateAndObject_passes", test_delayedTruePredicateAndObject_passes),
("test_immediatelyTrueDelayedFalsePredicateAndObject_passes", test_immediatelyTrueDelayedFalsePredicateAndObject_passes),
("test_immediatelyTruePredicate_passes", test_immediatelyTruePredicate_passes),
("test_immediatelyFalsePredicate_fails", test_immediatelyFalsePredicate_fails),
("test_delayedTruePredicate_passes", test_delayedTruePredicate_passes),
("test_immediatelyTrueDelayedFalsePredicate_passes", test_immediatelyTrueDelayedFalsePredicate_passes),
("test_blockPredicateWithNilObject_passes", test_blockPredicateWithNilObject_passes),
("test_blockPredicateWithObject_passes", test_blockPredicateWithObject_passes),
]
}()
}

// CHECK: Test Suite 'PredicateExpectationsTestCase' failed at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: \t Executed 4 tests, with 1 failure \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds
// CHECK: \t Executed 6 tests, with 1 failure \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds
XCTMain([testCase(PredicateExpectationsTestCase.allTests)])

// CHECK: Test Suite '.*\.xctest' failed at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: \t Executed 4 tests, with 1 failure \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds
// CHECK: \t Executed 6 tests, with 1 failure \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds
// CHECK: Test Suite 'All tests' failed at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: \t Executed 4 tests, with 1 failure \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds
// CHECK: \t Executed 6 tests, with 1 failure \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds
4 changes: 2 additions & 2 deletions Tests/Functional/Asynchronous/Predicates/Handler/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class PredicateHandlerTestCase: XCTestCase {
waitForExpectations(timeout: 0.1)
}
// CHECK: Test Case 'PredicateHandlerTestCase.test_predicateIsTrue_handlerReturnsFalse_fails' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: .*/Tests/Functional/Asynchronous/Predicates/Handler/main.swift:[[@LINE+8]]: error: PredicateHandlerTestCase.test_predicateIsTrue_handlerReturnsFalse_fails : Asynchronous wait failed - Exceeded timeout of 0.1 seconds, with unfulfilled expectations: Expect `<NSPredicate: 0x[0-9a-fA-F]{1,16}>` for object <NSObject: 0x[0-9a-fA-F]{1,16}>
// CHECK: .*/Tests/Functional/Asynchronous/Predicates/Handler/main.swift:[[@LINE+8]]: error: PredicateHandlerTestCase.test_predicateIsTrue_handlerReturnsFalse_fails : Asynchronous wait failed - Exceeded timeout of 0.1 seconds, with unfulfilled expectations: Expect predicate `<NSPredicate: 0x[0-9a-fA-F]{1,16}>` for object <NSObject: 0x[0-9a-fA-F]{1,16}>
// CHECK: Test Case 'PredicateHandlerTestCase.test_predicateIsTrue_handlerReturnsFalse_fails' failed \(\d+\.\d+ seconds\)
func test_predicateIsTrue_handlerReturnsFalse_fails() {
let predicate = NSPredicate(value: true)
Expand All @@ -36,7 +36,7 @@ class PredicateHandlerTestCase: XCTestCase {
}

// CHECK: Test Case 'PredicateHandlerTestCase.test_predicateIsTrueAfterTimeout_handlerIsNotCalled_fails' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
// CHECK: .*/Tests/Functional/Asynchronous/Predicates/Handler/main.swift:[[@LINE+14]]: error: PredicateHandlerTestCase.test_predicateIsTrueAfterTimeout_handlerIsNotCalled_fails : Asynchronous wait failed - Exceeded timeout of 0.1 seconds, with unfulfilled expectations: Expect `<NSPredicate: 0x[0-9a-fA-F]{1,16}>` for object \d{4}-\d{2}-\d{2} \d+:\d+:\d+ \+\d+
// CHECK: .*/Tests/Functional/Asynchronous/Predicates/Handler/main.swift:[[@LINE+14]]: error: PredicateHandlerTestCase.test_predicateIsTrueAfterTimeout_handlerIsNotCalled_fails : Asynchronous wait failed - Exceeded timeout of 0.1 seconds, with unfulfilled expectations: Expect predicate `<NSPredicate: 0x[0-9a-fA-F]{1,16}>` for object \d{4}-\d{2}-\d{2} \d+:\d+:\d+ \+\d+
// CHECK: Test Case 'PredicateHandlerTestCase.test_predicateIsTrueAfterTimeout_handlerIsNotCalled_fails' failed \(\d+\.\d+ seconds\)
func test_predicateIsTrueAfterTimeout_handlerIsNotCalled_fails() {
let halfSecLaterDate = NSDate(timeIntervalSinceNow: 0.2)
Expand Down