5

Based on answers to this question, I feel happy with the simplicity and ease of use of the following two methods for synchronization:

func synchronized(lock: AnyObject, closure: () -> Void) {
    objc_sync_enter(lock)
    closure()
    objc_sync_exit(lock)
}

func synchronized<T>(lock: AnyObject, closure: () -> T) -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    return closure()
}

But to be sure they're actually doing what I want, I want to wrap these in piles of unit tests. How can I write unit tests that will effectively test these methods (and show they are actually synchronizing the code)?

Ideally, I'd also like these unit tests to be as simple and as clear as possible. Presumably, this test should be code that, if run outside the synchronization block, would give one set of results, but give an entirely separate set of results inside these synchronized blocks.

Community
  • 1
  • 1
nhgrif
  • 61,578
  • 25
  • 134
  • 173
  • Are you trying to write a test to test that the synchronized block synchronizes in the general case, or are you trying to test that your code that relies on the synchronized block is being synchronized? – Will M. Feb 10 '16 at 22:27
  • @WillM.I am interested in the general case. I want a unit test that verifies that it is synchronizing any code run through it. – nhgrif Feb 11 '16 at 01:15
  • Ok, I threw something together that should demonstrate that. – Will M. Feb 11 '16 at 02:39
  • let me know if that was or was not what you had in mind – Will M. Feb 11 '16 at 02:51

1 Answers1

1

Here is a runnable XCTest that verifies the synchronization. If you synchronize delayedAddToArray, it will work, otherwise it will fail.

class DelayedArray:NSObject {
    func synchronized(lock: AnyObject, closure: () -> Void) {
        objc_sync_enter(lock)
        closure()
        objc_sync_exit(lock)
    }

    private var array = [String]()
    func delayedAddToArray(expectation:XCTestExpectation) {
        synchronized(self) {
            let arrayCount = self.array.count
            self.array.append("hi")
            sleep(5)
            XCTAssert(self.array.count == arrayCount + 1)
            expectation.fulfill()
        }
    }
}

func testExample() {
    let expectation = self.expectationWithDescription("desc")
    let expectation2 = self.expectationWithDescription("desc2")

    let delayedArray:DelayedArray = DelayedArray()
    // This is an example of a functional test case.
    let thread = NSThread(target: delayedArray, selector: "delayedAddToArray:", object: expectation)
    let secondThread = NSThread(target: delayedArray, selector: "delayedAddToArray:", object: expectation2)
    thread.start()
    sleep(1)
    secondThread.start()

    self.waitForExpectationsWithTimeout(15, handler: nil)
}
Will M.
  • 1,864
  • 17
  • 28