blob: 7cd76b30ff9994a49beee7759f596cbf41d5f319 [file] [log] [blame]
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// RUN: %target-run-simple-swift
// REQUIRES: executable_test
// REQUIRES: objc_interop
import Foundation
#if FOUNDATION_XCTEST
import XCTest
class TestUserInfoSuper : XCTestCase { }
#else
import StdlibUnittest
class TestUserInfoSuper : NSObject { }
#endif
struct SubStruct: Equatable {
var i: Int
var str: String
static func ==(lhs: SubStruct, rhs: SubStruct) -> Bool {
return lhs.i == rhs.i &&
lhs.str == rhs.str
}
}
struct SomeStructure: Hashable {
var i: Int
var str: String
var sub: SubStruct
static func ==(lhs: SomeStructure, rhs: SomeStructure) -> Bool {
return lhs.i == rhs.i &&
lhs.str == rhs.str &&
lhs.sub == rhs.sub
}
// FIXME: we don't care about this, but Any only finds == on Hashables
func hash(into hasher: inout Hasher) {
hasher.combine(i)
hasher.combine(str)
hasher.combine(sub.i)
hasher.combine(sub.str)
}
}
/*
Notification and potentially other structures require a representation of a
userInfo dictionary. The Objective-C counterparts are represented via
NSDictionary which can only store a hashable key (actually
NSObject<NSCopying> *) and a value of AnyObject (actually NSObject *). However
it is desired in swift to store Any in the value. These structure expositions
in swift have an adapter that allows them to pass a specialized NSDictionary
subclass to the Objective-C layer that can round trip the stored Any types back
out into Swift.
In this case NSNotification -> Notification bridging is suitable to verify that
behavior.
*/
class TestUserInfo : TestUserInfoSuper {
var posted: Notification?
func validate(_ testStructure: SomeStructure, _ value: SomeStructure) {
expectEqual(testStructure.i, value.i)
expectEqual(testStructure.str, value.str)
expectEqual(testStructure.sub.i, value.sub.i)
expectEqual(testStructure.sub.str, value.sub.str)
}
func test_userInfoPost() {
let userInfoKey = "userInfoKey"
let notifName = Notification.Name(rawValue: "TestSwiftNotification")
let testStructure = SomeStructure(i: 5, str: "10", sub: SubStruct(i: 6, str: "11"))
let info: [AnyHashable : Any] = [
AnyHashable(userInfoKey) : testStructure
]
let note = Notification(name: notifName, userInfo: info)
expectNotNil(note.userInfo)
let nc = NotificationCenter.default
nc.addObserver(self, selector: #selector(TestUserInfo.notification(_:)), name: notifName, object: nil)
nc.post(note)
expectNotNil(posted)
if let notification = posted {
let postedInfo = notification.userInfo
expectNotNil(postedInfo)
if let userInfo = postedInfo {
let postedValue = userInfo[AnyHashable(userInfoKey)] as? SomeStructure
expectNotNil(postedValue)
if let value = postedValue {
validate(testStructure, value)
}
}
}
}
func test_equality() {
let userInfoKey = "userInfoKey"
let notifName = Notification.Name(rawValue: "TestSwiftNotification")
let testStructure = SomeStructure(i: 5, str: "10", sub: SubStruct(i: 6, str: "11"))
let testStructure2 = SomeStructure(i: 6, str: "10", sub: SubStruct(i: 6, str: "11"))
let info1: [AnyHashable : Any] = [
AnyHashable(userInfoKey) : testStructure
]
let info2: [AnyHashable : Any] = [
AnyHashable(userInfoKey) : "this can convert"
]
let info3: [AnyHashable : Any] = [
AnyHashable(userInfoKey) : testStructure2
]
let note1 = Notification(name: notifName, userInfo: info1)
let note2 = Notification(name: notifName, userInfo: info1)
expectEqual(note1, note2)
let note3 = Notification(name: notifName, userInfo: info2)
let note4 = Notification(name: notifName, userInfo: info2)
expectEqual(note3, note4)
let note5 = Notification(name: notifName, userInfo: info3)
expectNotEqual(note1, note5)
}
@objc func notification(_ notif: Notification) {
posted = notif
}
// MARK: -
func test_classForCoder() {
// confirm internal bridged impl types are not exposed to archival machinery
// we have to be circuitous here, as bridging makes it very difficult to confirm this
//
// Gated on the availability of NSKeyedArchiver.archivedData(withRootObject:).
if #available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *) {
let note = Notification(name: Notification.Name(rawValue: "TestSwiftNotification"), userInfo: [AnyHashable("key"):"value"])
let archivedNote = NSKeyedArchiver.archivedData(withRootObject: note)
let noteAsPlist = try! PropertyListSerialization.propertyList(from: archivedNote, options: [], format: nil)
let plistAsData = try! PropertyListSerialization.data(fromPropertyList: noteAsPlist, format: .xml, options: 0)
let xml = NSString(data: plistAsData, encoding: String.Encoding.utf8.rawValue)!
expectEqual(xml.range(of: "_NSUserInfoDictionary").location, NSNotFound)
}
}
func test_AnyHashableContainingNotification() {
let values: [Notification] = [
Notification(name: Notification.Name(rawValue: "TestSwiftNotification")),
Notification(name: Notification.Name(rawValue: "TestOtherSwiftNotification")),
Notification(name: Notification.Name(rawValue: "TestOtherSwiftNotification")),
]
let anyHashables = values.map(AnyHashable.init)
expectEqual(Notification.self, type(of: anyHashables[0].base))
expectEqual(Notification.self, type(of: anyHashables[1].base))
expectEqual(Notification.self, type(of: anyHashables[2].base))
expectNotEqual(anyHashables[0], anyHashables[1])
expectEqual(anyHashables[1], anyHashables[2])
}
func test_AnyHashableCreatedFromNSNotification() {
let values: [NSNotification] = [
NSNotification(name: Notification.Name(rawValue: "TestSwiftNotification"), object: nil),
NSNotification(name: Notification.Name(rawValue: "TestOtherSwiftNotification"), object: nil),
NSNotification(name: Notification.Name(rawValue: "TestOtherSwiftNotification"), object: nil),
]
let anyHashables = values.map(AnyHashable.init)
expectEqual(Notification.self, type(of: anyHashables[0].base))
expectEqual(Notification.self, type(of: anyHashables[1].base))
expectEqual(Notification.self, type(of: anyHashables[2].base))
expectNotEqual(anyHashables[0], anyHashables[1])
expectEqual(anyHashables[1], anyHashables[2])
}
}
#if !FOUNDATION_XCTEST
var UserInfoTests = TestSuite("UserInfo")
UserInfoTests.test("test_userInfoPost") { TestUserInfo().test_userInfoPost() }
UserInfoTests.test("test_equality") { TestUserInfo().test_equality() }
UserInfoTests.test("test_classForCoder") { TestUserInfo().test_classForCoder() }
UserInfoTests.test("test_AnyHashableContainingNotification") { TestUserInfo().test_AnyHashableContainingNotification() }
UserInfoTests.test("test_AnyHashableCreatedFromNSNotification") { TestUserInfo().test_AnyHashableCreatedFromNSNotification() }
runAllTests()
#endif