mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[test] renaming test/1_stdlib to just test/stdlib
This commit is contained in:
473
test/stdlib/ArrayBridge.swift.gyb
Normal file
473
test/stdlib/ArrayBridge.swift.gyb
Normal file
@@ -0,0 +1,473 @@
|
||||
//===--- ArrayBridge.swift - Tests of Array casting and bridging ----------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir -p %t
|
||||
//
|
||||
// RUN: %gyb %s -o %t/ArrayBridge.swift
|
||||
// RUN: %target-clang %S/Inputs/ArrayBridge/ArrayBridge.m -c -o %t/ArrayBridgeObjC.o -g
|
||||
// RUN: %line-directive %t/ArrayBridge.swift -- %target-build-swift %t/ArrayBridge.swift -I %S/Inputs/ArrayBridge/ -Xlinker %t/ArrayBridgeObjC.o -o %t/ArrayBridge --
|
||||
|
||||
// RUN: %target-run %t/ArrayBridge
|
||||
// REQUIRES: executable_test
|
||||
// REQUIRES: objc_interop
|
||||
|
||||
import Foundation
|
||||
import ArrayBridgeObjC
|
||||
import StdlibUnittest
|
||||
let tests = TestSuite("ArrayBridge")
|
||||
|
||||
var trackedCount = 0
|
||||
var nextBaseSerialNumber = 0
|
||||
|
||||
@objc protocol Fooable {
|
||||
func foo()
|
||||
}
|
||||
|
||||
@objc protocol Barable {
|
||||
func bar()
|
||||
}
|
||||
|
||||
@objc protocol Bazable {
|
||||
func baz()
|
||||
}
|
||||
|
||||
/// A type that will be bridged verbatim to Objective-C
|
||||
class Base : NSObject, Fooable {
|
||||
func foo() { }
|
||||
|
||||
required init(_ value: Int) {
|
||||
trackedCount += 1
|
||||
nextBaseSerialNumber += 1
|
||||
serialNumber = nextBaseSerialNumber
|
||||
self.value = value
|
||||
}
|
||||
|
||||
deinit {
|
||||
assert(serialNumber > 0, "double destruction!")
|
||||
trackedCount -= 1
|
||||
serialNumber = -serialNumber
|
||||
}
|
||||
|
||||
override func isEqual(_ other: Any?) -> Bool {
|
||||
return (other as? Base)?.value == self.value
|
||||
}
|
||||
|
||||
var value: Int
|
||||
var serialNumber: Int
|
||||
}
|
||||
|
||||
class Subclass : Base, Barable {
|
||||
func bar() { }
|
||||
}
|
||||
|
||||
var bridgeFromOperationCount = 0
|
||||
var bridgeToOperationCount = 0
|
||||
|
||||
/// A value type that's bridged using _ObjectiveCBridgeable
|
||||
struct BridgeableValue : _ObjectiveCBridgeable, Equatable {
|
||||
func _bridgeToObjectiveC() -> Subclass {
|
||||
bridgeToOperationCount += 1
|
||||
return Subclass(trak.value)
|
||||
}
|
||||
|
||||
static func _forceBridgeFromObjectiveC(
|
||||
_ x: Subclass,
|
||||
result: inout BridgeableValue?
|
||||
) {
|
||||
assert(x.value >= 0, "not bridged")
|
||||
bridgeFromOperationCount += 1
|
||||
result = BridgeableValue(x.value)
|
||||
}
|
||||
|
||||
static func _conditionallyBridgeFromObjectiveC(
|
||||
_ x: Subclass,
|
||||
result: inout BridgeableValue?
|
||||
) -> Bool {
|
||||
if x.value >= 0 {
|
||||
result = BridgeableValue(x.value)
|
||||
return true
|
||||
}
|
||||
|
||||
result = nil
|
||||
return false
|
||||
}
|
||||
|
||||
static func _unconditionallyBridgeFromObjectiveC(_ source: Subclass?)
|
||||
-> BridgeableValue {
|
||||
var result: BridgeableValue? = nil
|
||||
_forceBridgeFromObjectiveC(source!, result: &result)
|
||||
return result!
|
||||
}
|
||||
|
||||
init(_ value: Int) {
|
||||
self.trak = Base(value)
|
||||
}
|
||||
|
||||
static func resetStats() {
|
||||
bridgeFromOperationCount = 0
|
||||
bridgeToOperationCount = 0
|
||||
}
|
||||
|
||||
var trak: Base
|
||||
}
|
||||
|
||||
func == (lhs: BridgeableValue, rhs: BridgeableValue) -> Bool {
|
||||
return lhs.trak.value == rhs.trak.value
|
||||
}
|
||||
|
||||
// A class used to test various Objective-C thunks.
|
||||
class Thunks : NSObject {
|
||||
func createSubclass(_ value: Int) -> AnyObject {
|
||||
return Subclass(value)
|
||||
}
|
||||
|
||||
@objc func acceptSubclassArray(
|
||||
_ x: [Subclass],
|
||||
expecting expected: NSArray
|
||||
) {
|
||||
expectEqualSequence(
|
||||
expected.lazy.map { ObjectIdentifier($0 as AnyObject) },
|
||||
x.lazy.map { ObjectIdentifier($0 as AnyObject) }
|
||||
)
|
||||
}
|
||||
|
||||
@objc func produceSubclassArray(
|
||||
_ expectations: NSMutableArray
|
||||
) -> [Subclass] {
|
||||
var array: [Subclass] = []
|
||||
for i in 0..<5 {
|
||||
array.append(Subclass(i))
|
||||
expectations.add(array[i])
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
@objc func checkProducedSubclassArray(
|
||||
_ produced: NSArray, expecting expected: NSArray
|
||||
) {
|
||||
expectEqualSequence(
|
||||
expected.lazy.map { ObjectIdentifier($0 as AnyObject) },
|
||||
produced.lazy.map { ObjectIdentifier($0 as AnyObject) }
|
||||
)
|
||||
}
|
||||
|
||||
@objc func acceptBridgeableValueArray(_ raw: NSArray) {
|
||||
let x = raw as! [BridgeableValue]
|
||||
expectEqualSequence(
|
||||
raw.lazy.map { $0 as! BridgeableValue },
|
||||
x
|
||||
)
|
||||
}
|
||||
|
||||
@objc func produceBridgeableValueArray() -> NSArray {
|
||||
var array: [BridgeableValue] = []
|
||||
for i in 0..<5 {
|
||||
array.append(BridgeableValue(i))
|
||||
}
|
||||
return array as NSArray
|
||||
}
|
||||
|
||||
@objc func checkProducedBridgeableValueArray(_ produced: NSArray) {
|
||||
expectEqualSequence(
|
||||
0..<5,
|
||||
produced.lazy.map { ($0 as! Subclass).value })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===--- Bridged Verbatim -------------------------------------------------===//
|
||||
// Base is "bridged verbatim"
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
tests.test("testBridgedVerbatim") {
|
||||
nextBaseSerialNumber = 0
|
||||
let bases: [Base] = [Base(100), Base(200), Base(300)]
|
||||
|
||||
//===--- Implicit conversion to/from NSArray ------------------------------===//
|
||||
|
||||
let basesConvertedToNSArray = bases as NSArray
|
||||
let firstBase = basesConvertedToNSArray.object(at: 0) as! Base
|
||||
expectEqual(100, firstBase.value)
|
||||
expectEqual(1, firstBase.serialNumber)
|
||||
|
||||
// Verify that NSArray class methods are inherited by a Swift bridging class.
|
||||
let className = String(reflecting: type(of: basesConvertedToNSArray))
|
||||
expectTrue(className.hasPrefix("Swift._ContiguousArrayStorage"))
|
||||
expectTrue(type(of: basesConvertedToNSArray).supportsSecureCoding)
|
||||
|
||||
//===--- Up- and Down-casts -----------------------------------------------===//
|
||||
var subclass: [Subclass] = [Subclass(11), Subclass(22)]
|
||||
let subclass0 = subclass
|
||||
|
||||
// upcast is implicit
|
||||
let subclassAsBases: [Base] = subclass
|
||||
expectEqual(subclass.count, subclassAsBases.count)
|
||||
for (x, y) in zip(subclass, subclassAsBases) {
|
||||
expectTrue(x === y)
|
||||
}
|
||||
|
||||
// Arrays are logically distinct after upcast
|
||||
subclass[0] = Subclass(33)
|
||||
|
||||
expectEqual([Subclass(33), Subclass(22)], subclass)
|
||||
expectEqual([Subclass(11), Subclass(22)], subclassAsBases)
|
||||
|
||||
expectEqual(subclass0, subclassAsBases as! [Subclass])
|
||||
|
||||
}
|
||||
|
||||
% for Any in 'Any', 'AnyObject':
|
||||
|
||||
tests.test("Another/${Any}") {
|
||||
// Create an ordinary NSArray, not a native one
|
||||
let nsArrayOfBase: NSArray = NSArray(object: Base(42))
|
||||
|
||||
// NSArray can be unconditionally cast to [${Any}]...
|
||||
|
||||
let nsArrayOfBaseConvertedToAnyArray = nsArrayOfBase
|
||||
% if Any == 'Any':
|
||||
// FIXME: nsArrayOfBase as [Any] doesn't
|
||||
// typecheck.
|
||||
as [AnyObject]
|
||||
% end
|
||||
as [${Any}]
|
||||
|
||||
// Capture the representation of the first element
|
||||
let base42: ObjectIdentifier
|
||||
do {
|
||||
let b = nsArrayOfBase.object(at: 0) as! Base
|
||||
expectEqual(42, b.value)
|
||||
base42 = ObjectIdentifier(b)
|
||||
}
|
||||
|
||||
// ...with the same elements
|
||||
expectEqual(
|
||||
base42,
|
||||
ObjectIdentifier(nsArrayOfBaseConvertedToAnyArray[0] as! Base))
|
||||
|
||||
let subclassInBaseBuffer: [Base] = [Subclass(44), Subclass(55)]
|
||||
let subclass2 = subclassInBaseBuffer
|
||||
|
||||
// Explicit downcast-ability is based on element type, not buffer type
|
||||
expectNotEmpty(subclassInBaseBuffer as? [Subclass])
|
||||
|
||||
// We can up-cast to array of Any
|
||||
let subclassAsAnyArray: [${Any}] = subclassInBaseBuffer
|
||||
expectEqual(subclass2, subclassAsAnyArray.map { $0 as! Base })
|
||||
|
||||
let downcastBackToBase = subclassAsAnyArray as? [Base]
|
||||
expectNotEmpty(downcastBackToBase)
|
||||
|
||||
if let downcastBackToSubclass = expectNotEmpty(subclassAsAnyArray as? [Subclass]) {
|
||||
expectEqual(subclass2, downcastBackToSubclass)
|
||||
}
|
||||
|
||||
if let downcastToProtocols = expectNotEmpty(subclassAsAnyArray as? [Fooable]) {
|
||||
expectEqual(subclass2, downcastToProtocols.map { $0 as! Subclass })
|
||||
}
|
||||
|
||||
if let downcastToProtocols = expectNotEmpty(subclassAsAnyArray as? [Barable]) {
|
||||
expectEqual(subclass2, downcastToProtocols.map { $0 as! Subclass })
|
||||
}
|
||||
|
||||
if let downcastToProtocols = expectNotEmpty(subclassAsAnyArray as? [Barable & Fooable]) {
|
||||
expectEqual(subclass2, downcastToProtocols.map { $0 as! Subclass })
|
||||
}
|
||||
|
||||
expectEmpty(subclassAsAnyArray as? [Barable & Bazable])
|
||||
}
|
||||
|
||||
//===--- Explicitly Bridged -----------------------------------------------===//
|
||||
// BridgeableValue conforms to _ObjectiveCBridgeable
|
||||
//===----------------------------------------------------------------------===//
|
||||
tests.test("testExplicitlyBridged/${Any}") {
|
||||
|
||||
let bridgeableValues = [BridgeableValue(42), BridgeableValue(17)]
|
||||
|
||||
let bridgeableValuesAsNSArray = bridgeableValues as NSArray
|
||||
expectEqual(2, bridgeableValuesAsNSArray.count)
|
||||
expectEqual(42, (bridgeableValuesAsNSArray[0] as AnyObject).value)
|
||||
expectEqual(17, (bridgeableValuesAsNSArray[1] as AnyObject).value)
|
||||
|
||||
// Make sure we can bridge back.
|
||||
let roundTrippedValues = Swift._forceBridgeFromObjectiveC(
|
||||
bridgeableValuesAsNSArray, [BridgeableValue].self)
|
||||
|
||||
// Expect equal values...
|
||||
expectEqualSequence(bridgeableValues, roundTrippedValues)
|
||||
// ...with the same identity for some reason? FIXME: understand why.
|
||||
expectFalse(
|
||||
zip(bridgeableValues, roundTrippedValues).contains { $0.trak !== $1.trak })
|
||||
|
||||
// Make a real Cocoa NSArray of these...
|
||||
let cocoaBridgeableValues = NSArray(
|
||||
array: bridgeableValuesAsNSArray
|
||||
%if Any == 'Any':
|
||||
// FIXME: should just be "as [Any]" but the typechecker doesn't allow it
|
||||
// yet.
|
||||
as [AnyObject] as [Any] as [AnyObject]
|
||||
%else:
|
||||
as [${Any}]
|
||||
%end
|
||||
)
|
||||
|
||||
// ...and bridge *that* back
|
||||
let bridgedBackSwifts = Swift._forceBridgeFromObjectiveC(
|
||||
cocoaBridgeableValues, [BridgeableValue].self)
|
||||
|
||||
// Expect equal, but distinctly created instances
|
||||
expectEqualSequence(bridgeableValues, bridgedBackSwifts)
|
||||
expectFalse(
|
||||
zip(bridgedBackSwifts, roundTrippedValues).contains { $0.trak === $1.trak })
|
||||
expectFalse(
|
||||
zip(bridgedBackSwifts, bridgeableValues).contains { $0.trak === $1.trak })
|
||||
|
||||
let expectedSubclasses = [Subclass(42), Subclass(17)]
|
||||
let expectedBases = expectedSubclasses.lazy.map { $0 as Base }
|
||||
|
||||
// Up-casts.
|
||||
let bridgeableValuesAsSubclasses = bridgeableValues as [Subclass]
|
||||
expectEqualSequence(expectedSubclasses, bridgeableValuesAsSubclasses)
|
||||
|
||||
let bridgeableValuesAsBases = bridgeableValues as [Base]
|
||||
expectEqualSequence(expectedBases, bridgeableValuesAsBases)
|
||||
|
||||
let bridgeableValuesAsAnys = bridgeableValues as [Any]
|
||||
expectEqualSequence(
|
||||
expectedBases,
|
||||
bridgeableValuesAsAnys.lazy.map { $0 as! Base })
|
||||
|
||||
// Downcasts of non-verbatim bridged value types to objects.
|
||||
do {
|
||||
let downcasted = bridgeableValues as [Subclass]
|
||||
expectEqualSequence(expectedSubclasses, downcasted)
|
||||
}
|
||||
|
||||
do {
|
||||
let downcasted = bridgeableValues as [Base]
|
||||
expectEqualSequence(expectedBases, downcasted)
|
||||
}
|
||||
|
||||
do {
|
||||
let downcasted = bridgeableValues as [${Any}]
|
||||
expectEqualSequence(expectedBases, downcasted.map { $0 as! Base })
|
||||
}
|
||||
|
||||
// Downcasts of up-casted arrays.
|
||||
if let downcasted = expectNotEmpty(
|
||||
bridgeableValuesAsAnys as? [Subclass]
|
||||
) {
|
||||
expectEqualSequence(expectedSubclasses, downcasted)
|
||||
}
|
||||
|
||||
if let downcasted = bridgeableValuesAsAnys as? [Base] {
|
||||
expectEqualSequence(expectedBases, downcasted)
|
||||
}
|
||||
|
||||
// Downcast of Cocoa array to an array of classes.
|
||||
let wrappedCocoaBridgeableValues = cocoaBridgeableValues
|
||||
%if Any == 'Any':
|
||||
// FIXME: should just be "as [Any]" but typechecker doesn't allow it
|
||||
// yet.
|
||||
as [AnyObject]
|
||||
%end
|
||||
as [${Any}]
|
||||
|
||||
if let downcasted = wrappedCocoaBridgeableValues as? [Subclass] {
|
||||
expectEqualSequence(expectedSubclasses, downcasted)
|
||||
}
|
||||
|
||||
// Downcast of Cocoa array to an array of values.
|
||||
if let downcasted = wrappedCocoaBridgeableValues as? [BridgeableValue] {
|
||||
expectEqualSequence(bridgeableValues, downcasted)
|
||||
}
|
||||
|
||||
// Downcast of Cocoa array to an array of strings (which should fail)
|
||||
expectEmpty(wrappedCocoaBridgeableValues as? [String])
|
||||
|
||||
// Downcast from an implicitly unwrapped optional array of Anys.
|
||||
var wrappedCocoaBridgeableValuesIUO: [${Any}]! = wrappedCocoaBridgeableValues
|
||||
if let downcasted = wrappedCocoaBridgeableValuesIUO as? [BridgeableValue] {
|
||||
expectEqualSequence(bridgeableValues, downcasted)
|
||||
}
|
||||
|
||||
// Downcast from a nil implicitly unwrapped optional array of Anys.
|
||||
wrappedCocoaBridgeableValuesIUO = nil
|
||||
expectEmpty(wrappedCocoaBridgeableValuesIUO as? [BridgeableValue])
|
||||
|
||||
// Downcast from an optional array of Anys.
|
||||
var wrappedCocoaBridgeableValuesOpt: [${Any}]? = wrappedCocoaBridgeableValues
|
||||
if let downcasted = wrappedCocoaBridgeableValuesOpt as? [BridgeableValue] {
|
||||
expectEqualSequence(bridgeableValues, downcasted)
|
||||
}
|
||||
|
||||
// Downcast from a nil optional array of Anys.
|
||||
wrappedCocoaBridgeableValuesOpt = nil
|
||||
expectEmpty(wrappedCocoaBridgeableValuesOpt as? [BridgeableValue])
|
||||
}
|
||||
% end
|
||||
|
||||
tests.test("testThunks") {
|
||||
testSubclass(Thunks())
|
||||
testBridgeableValue(Thunks())
|
||||
}
|
||||
|
||||
|
||||
tests.test("testRoundTrip") {
|
||||
class Test : NSObject {
|
||||
@objc dynamic func call(_ array: NSArray) -> NSArray {
|
||||
|
||||
let result = array as! [BridgeableValue]
|
||||
expectEqual(0, bridgeFromOperationCount)
|
||||
expectEqual(0, bridgeToOperationCount)
|
||||
|
||||
// Clear out the stats before returning array
|
||||
BridgeableValue.resetStats()
|
||||
return result as NSArray
|
||||
}
|
||||
}
|
||||
|
||||
let test = Test()
|
||||
|
||||
let array = [
|
||||
BridgeableValue(10), BridgeableValue(20), BridgeableValue(30),
|
||||
BridgeableValue(40), BridgeableValue(50) ]
|
||||
|
||||
BridgeableValue.resetStats()
|
||||
_ = test.call(array as NSArray)
|
||||
|
||||
expectEqual(0, bridgeFromOperationCount)
|
||||
expectEqual(0, bridgeToOperationCount)
|
||||
}
|
||||
|
||||
//===--- Non-bridging -----------------------------------------------------===//
|
||||
// X is not bridged to Objective-C
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct X {}
|
||||
|
||||
tests.test("testMutableArray") {
|
||||
let m = NSMutableArray(array: ["fu", "bar", "buzz"])
|
||||
let a = m as NSArray as! [NSString]
|
||||
|
||||
// Create distinct array storage with a copy of the elements in a
|
||||
let aCopy = a.map { $0 }
|
||||
|
||||
// Modify the original mutable array
|
||||
m.add("goop")
|
||||
|
||||
// Check that our [NSString] is unaffected
|
||||
expectEqualSequence(aCopy, a)
|
||||
}
|
||||
|
||||
runAllTests()
|
||||
Reference in New Issue
Block a user