// RUN: %target-run-simple-swift // REQUIRES: executable_test // REQUIRES: objc_interop import Foundation import StdlibUnittest // rdar://problem/18884272 // Make sure that NSObject conforms to NSObjectProtocol. This // particular bug is ridiculously hard to trigger without a complete // SDK, so it sits here. let objcProtocol: NSObjectProtocol = NSObject() var FoundationTestSuite = TestSuite("Foundation") func asNSString(_ s: String) -> NSString { return s as NSString } func asString(_ ns: NSString) -> String { return ns as String } //===----------------------------------------------------------------------===// // Strings //===----------------------------------------------------------------------===// FoundationTestSuite.test("NSString") { var str = "Hello" var nsStr = str as NSString assert(nsStr.compare(str).rawValue == ComparisonResult.orderedSame.rawValue) assert(nsStr.compare(str) == ComparisonResult.orderedSame) nsStr = "World" str = nsStr as String // FIXME: Shouldn't need coercion here to resolve ambiguity. assert(str == asString(nsStr)) } //===----------------------------------------------------------------------===// // Numbers //===----------------------------------------------------------------------===// FoundationTestSuite.test("NSNumber") { var i = 17 var d = 3.14159 var b = true // Implicit boxing/explicit unboxing var nsNum: NSNumber = i as NSNumber expectEqual(i, Int(nsNum)) nsNum = d as NSNumber expectEqual(d, Double(nsNum)) nsNum = b as NSNumber expectEqual(b, Bool(nsNum)) // Literals nsNum = 42 expectEqual(42, Int(nsNum)) nsNum = 3.14159 expectEqual(3.14159, Double(nsNum)) nsNum = false expectEqual(false, Bool(nsNum)) } //===----------------------------------------------------------------------===// // Arrays //===----------------------------------------------------------------------===// FoundationTestSuite.test("NSArray") { // Literals var nsArr: NSArray = [1, 2.5, "Hello"] assert(nsArr.count == 3) // Subscripting expectEqual(1, Int(nsArr[0] as! NSNumber)) expectEqual(2.5, Double(nsArr[1] as! NSNumber)) expectTrue((nsArr[2] as! NSString).isEqual("Hello")) // Iteration var result = [String]() for x: Any in nsArr { result.append((x as! NSObject).description) } expectEqualSequence(["1", "2.5", "Hello"], result) } FoundationTestSuite.test("NSMutableArray") { let nsMutableArr: NSMutableArray = ["Constant", "Moon"] nsMutableArr[0] = "Inconstant" expectEqual(2, nsMutableArr.count) expectEqual("Inconstant", nsMutableArr[0] as! NSString) expectEqual("Moon", nsMutableArr[1] as! NSString) } FoundationTestSuite.test("NSArrayVariadicInit") { let variadicArray = NSArray(objects: "A", "B", "C") expectEqual(3, variadicArray.count) } FoundationTestSuite.test("arrayConversions") { var nsa = NSArray() var aoa: Array = [] nsa as Array var nsa2 = NSArray() var aoa2 = nsa2 as Array var nsaoa = aoa as NSArray func nsArrayToAnyObjectArray(_ nsa: NSArray) -> [AnyObject] { return nsa as [AnyObject] } nsArrayToAnyObjectArray(nsa) nsArrayToAnyObjectArray(aoa as NSArray) } //===----------------------------------------------------------------------===// // Dictionaries //===----------------------------------------------------------------------===// FoundationTestSuite.test("NSDictionary") { var nsDict : NSDictionary = [1 : "Hello", 2 : "World"] assert((nsDict[1]! as! NSString).isEqual("Hello")) assert((nsDict[2]! as! NSString).isEqual("World")) let nsMutableDict: NSMutableDictionary = ["Hello" : 1, "World" : 2 as NSNumber] assert((nsMutableDict["Hello"]! as AnyObject).isEqual(1)) assert((nsMutableDict["World"]! as AnyObject).isEqual(2)) } //===----------------------------------------------------------------------===// // Ranges //===----------------------------------------------------------------------===// FoundationTestSuite.test("NSRange") { let nsRange = NSRange(1..<5) expectEqual("{1, 4}", String(NSStringFromRange(nsRange))) } FoundationTestSuite.test("RangeConversion") { let i: Int8 = 10 let j: Int8 = 20 let nsrFromInt8 = NSRange(i..>.self, &r) var r8 = Range(nsrFromInt8) expectNotNil(r8 != nil) expectEqual(r8?.lowerBound, 10) expectEqual(r8?.upperBound, 20) expectType(Optional>.self, &r8) var nsrFromPartial = NSRange(..<5) expectEqual("{0, 5}", NSStringFromRange(nsrFromPartial)) let s = "Hello, 🌎!" let b = s.firstIndex(of: ",")! let e = s.firstIndex(of: "!")! let nsr = NSRange(b.. Bool { switch input { case a, b: return true default: return false } } FoundationTestSuite.test("patternMatching") { var one, two, three, oneAgain : NSNumber one = NSNumber(value: 1) two = NSNumber(value: 2) three = NSNumber(value: 3) oneAgain = NSNumber(value: 1) expectFalse(matchesEither(one, two, three)) expectTrue(matchesEither(one, oneAgain, three)) expectTrue(matchesEither(one, two, oneAgain)) } //===----------------------------------------------------------------------===// // Miscellaneous //===----------------------------------------------------------------------===// // // Type checker used to crash on this. class ClassWithDtor : NSObject { deinit { let noteCenter = NotificationCenter.default noteCenter.removeObserver(self, name: Notification.Name(rawValue: "ReceivedContentNotification"), object: nil) } } FoundationTestSuite.test("rdar://17584531") { // // Type checker used to be confused by this. var dict: NSDictionary = ["status": 200, "people": [["id": 255, "name": ["first": "John", "last": "Appleseed"] as NSDictionary] as NSDictionary] as NSArray] var dict2 = dict["people"].flatMap { $0 as? NSArray }?[0] as! NSDictionary expectEqual("Optional(255)", String(describing: dict2["id" as NSString])) } FoundationTestSuite.test("DarwinBoolean smoke test") { expectFalse(CFEqual("abc" as NSString as CFString, "def" as NSString as CFString)) let _: CFArrayEqualCallBack = { DarwinBoolean($0 == $1) } } #if os(macOS) FoundationTestSuite.test("NSRectEdge/constants") { // Check that the following constants have the correct type and value. // // It is valid to hardcode the value in the test. The way they are currently // defined in the SDK makes them ABI for Objective-C code. expectEqual(0, CGRectEdge(rectEdge: NSRectEdge.minX).rawValue) expectEqual(0, NSRectEdge(rectEdge: CGRectEdge.minXEdge).rawValue) expectEqual(1, CGRectEdge(rectEdge: NSRectEdge.minY).rawValue) expectEqual(1, NSRectEdge(rectEdge: CGRectEdge.minYEdge).rawValue) expectEqual(2, CGRectEdge(rectEdge: NSRectEdge.maxX).rawValue) expectEqual(2, NSRectEdge(rectEdge: CGRectEdge.maxXEdge).rawValue) expectEqual(3, CGRectEdge(rectEdge: NSRectEdge.maxY).rawValue) expectEqual(3, NSRectEdge(rectEdge: CGRectEdge.maxYEdge).rawValue) } #endif if #available(OSX 10.11, iOS 9.0, *) { FoundationTestSuite.test("UndoManager/ObjCClass") { let UM = UndoManager() // Confirm with an ObjC class. class ObjCClass : NSObject { var someProperty: String = "" } let f = ObjCClass() UM.registerUndo(withTarget: f) { target in target.someProperty = "expected" } UM.undo() expectEqual(f.someProperty, "expected") } FoundationTestSuite.test("UndoManager/SwiftClass") { let UM = UndoManager() // Confirm with a Swift class. class SwiftClass { var someOtherProperty: String = "" } var b = SwiftClass() UM.registerUndo(withTarget:b) { target in target.someOtherProperty = "expected" } UM.undo() expectEqual(b.someOtherProperty, "expected") } } private let KEY = "some-key" private func createTestArchive() -> NSData { let mutableData = NSMutableData() let KA = NSKeyedArchiver(forWritingWith: mutableData) // Set up some fake data. let obj = NSPredicate(value: true) KA.encode(obj, forKey: KEY) KA.encode(obj, forKey: NSKeyedArchiveRootObjectKey) KA.finishEncoding() return mutableData } FoundationTestSuite.test("NSKeyedUnarchiver/decodeObjectOfClass(_:forKey:)") { let obj = NSPredicate(value: true) let data = createTestArchive() var KU = NSKeyedUnarchiver(forReadingWith: data as Data) var missing = KU.decodeObject(of: NSPredicate.self, forKey: "Not there") expectNil(missing) expectType((NSPredicate?).self, &missing) var decoded = KU.decodeObject(of: NSPredicate.self, forKey: KEY) expectNotNil(decoded) expectType((NSPredicate?).self, &decoded) var wrongType = KU.decodeObject(of: DateFormatter.self, forKey: KEY) expectNil(missing) KU.finishDecoding() } if #available(OSX 10.11, iOS 9.0, *) { FoundationTestSuite.test("NSKeyedUnarchiver/decodeTopLevel*") { let obj = NSPredicate(value: true) let data = createTestArchive() // first confirm .decodeObjectWithClasses overlay requires an array of classes var KU = NSKeyedUnarchiver(forReadingWith: data as Data) var nonTopLevelResult = KU.decodeObject(of: [NSPredicate.self], forKey: KEY) expectTrue(nonTopLevelResult != nil) KU.finishDecoding() KU = NSKeyedUnarchiver(forReadingWith: data as Data) do { // decodeObjectForKey(_:) throws let decoded1 = try KU.decodeTopLevelObject(forKey: KEY) as? NSPredicate let missing1 = try KU.decodeTopLevelObject(forKey:"Not there") expectTrue(decoded1 != nil) expectEqual(obj, decoded1) expectTrue(missing1 == nil) KU.finishDecoding() // recreate so we can do the rest securely KU = NSKeyedUnarchiver(forReadingWith: data as Data) KU.requiresSecureCoding = true // decodeObjectOfClass(_:,forKey:) throws let decoded2 = try KU.decodeTopLevelObject(of: NSPredicate.self, forKey: KEY) let missing2 = try KU.decodeTopLevelObject(of: NSPredicate.self, forKey: "Not there") expectTrue(decoded2 != nil) expectEqual(obj, decoded2) expectTrue(missing2 == nil) let classes: [AnyClass] = [NSPredicate.self] let decoded3 = try KU.decodeTopLevelObject(of: classes, forKey: KEY) as? NSPredicate let missing3 = try KU.decodeTopLevelObject(of: classes, forKey: "Not there") expectTrue(decoded3 != nil) expectEqual(obj, decoded3) expectTrue(missing3 == nil) } catch { expectTrue(false) // should have no errors } KU.finishDecoding() KU = NSKeyedUnarchiver(forReadingWith: data as Data) KU.requiresSecureCoding = true do { // recreate so we avoid caches from above let wrong = try KU.decodeTopLevelObject(of: DateFormatter.self, forKey: KEY) expectUnreachable() // should have error } catch { // expected } KU.finishDecoding() KU = NSKeyedUnarchiver(forReadingWith: data as Data) KU.requiresSecureCoding = true do { let wrongClasses: [AnyClass] = [DateFormatter.self] let wrong = try KU.decodeTopLevelObject(of: wrongClasses, forKey: KEY) expectUnreachable() // should have error } catch { // expected } KU.finishDecoding() // confirm the that class function works do { let decoded = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data as Data) as? NSPredicate expectEqual(obj, decoded) } catch { expectUnreachableCatch(error) } } FoundationTestSuite.test("NSKeyedUnarchiver/decodeTopLevelObjectOfClass(_:forKey:)/trap") { let obj = NSPredicate(value: true) let data = createTestArchive() var KU = NSKeyedUnarchiver(forReadingWith: data as Data) // Even though we're doing non-secure coding, this should still be checked // in Swift. do { var wrongType = try KU.decodeTopLevelObject(of: DateFormatter.self, forKey: KEY) expectType((DateFormatter?).self, &wrongType) } catch { expectUnreachableCatch(error) } KU.finishDecoding() } FoundationTestSuite.test("NSKeyedUnarchiver/CycleWithConvenienceInit") { @objc(HasACyclicReference) class HasACyclicReference: NSObject, NSCoding { var ref: AnyObject? override init() { super.init() ref = self } required convenience init?(coder: NSCoder) { let decodedRef = coder.decodeObject(forKey: "ref") as AnyObject? self.init(ref: decodedRef) } @objc init(ref: AnyObject?) { self.ref = ref super.init() } func encode(with coder: NSCoder) { coder.encode(ref, forKey: "ref") } } let data = NSKeyedArchiver.archivedData(withRootObject: HasACyclicReference()) let decodedObj = NSKeyedUnarchiver.unarchiveObject(with: data) as! HasACyclicReference expectEqual(ObjectIdentifier(decodedObj), ObjectIdentifier(decodedObj.ref!), "cycle was not preserved (due to object replacement?)") } } FoundationTestSuite.test("NotificationCenter/addObserver(_:selector:name:object:)") { let obj: AnyObject = "Hello" as NSString NotificationCenter.default.addObserver(obj, selector: Selector("blah:"), name: nil, object: nil) let name = "hello" NotificationCenter.default.addObserver(obj, selector: Selector("blarg:"), name: Notification.Name(name), object: nil) } runAllTests()