How can one use XCTAssertNil with optional structs?

i0S Swift Issue

Question or problem in the Swift programming language:

Update 3/23/2016 I just tested my original sample code below and it all compiles fine in XCode 7.3. Looks like XCTAssertNil was updated along the way to take an expression of type () throws -> Any? Therefore this question and answer may be no longer needed (except for a while with older versions of the compiler.)

I’m writing my first unit tests in XCode with XCTest. I’m unsure how one can take advantage of XCTAssertNil as it seems to only compile when using certain types. It appears it will work with optionals made from classes and built-in primitives, but not structs. How would one go about using this method?

For structs the compiler gives the following error (assuming ‘SimpleStruct’ is the name of your type):

'SimpleStruct' is not identical to 'AnyObject'

Here’s a simple test class to illustrate some of the types that compile okay and other’s that don’t.

import Cocoa
import XCTest

struct SimpleStruct {
}

class SimpleClass {
}

class Tests: XCTestCase {

    func testl() {
        var simpleStruct:SimpleStruct? = nil;
        var simpleClass:SimpleClass? = nil;
        var i:Int? = nil;
        var s:String? = nil;
        var tuple:(Int,String)? = nil;

        XCTAssertNil(simpleStruct); // compile error
        XCTAssertNil(simpleClass); // OK
        XCTAssertNil(i); // OK
        XCTAssertNil(s); // OK
        XCTAssertNil(tuple); // compile error
    }

}

How to solve the problem:

Update 3/23/2016 Updated for XCode 7.3 (however if you see my edit to the question, it would appear this workaround is no longer needed)

Here is a workaround. I created my own generic function:

func AssertNil(@autoclosure expression: () -> T?, message: String = "",
               file: StaticString = #file, line: UInt = #line) {

    if (expression() != nil) {
        XCTFail(message, file:file, line:line)
    }
}

Doesn’t seem like this should be necessary. Is this just a result of XCTest originally targeting Objective-C and not being updated/bridged enough for Swift yet?

Edit: I’ve done enough research to see that AnyObject can be used to represent any class but not structs. However, that then doesn’t explain why the code in my original post compiles for Int types and String types. (I read somewhere else that Xcode may auto convert these to NSNumber and NSString for you which might explain why. See http://www.scottlogic.com/blog/2014/09/24/swift-anyobject.html and http://www.drewag.me/posts/swift-s-weird-handling-of-basic-value-types-and-anyobject. I’ll try removing my import of Cocoa which imports Foundation to see what happens)

Edit2: XCTest also imports Foundation so I can’t test what I wanted to. I could create my own methods and test this. For now, I assume that the auto-conversions are what are allowing the int and string optionals to compile. Seems like XCTest isn’t quite ready for prime time with Swift.

Update 8/13/2015: Edited the function to be compatible with XCode 7 beta

Hope this helps!