mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The problem is fixed, so these tests should pass in optimized mode again.
This reverts commit bdd8626374.
380 lines
10 KiB
Plaintext
380 lines
10 KiB
Plaintext
// RUN: %target-run-simple-swiftgyb
|
|
// REQUIRES: executable_test
|
|
|
|
import StdlibUnittest
|
|
import StdlibCollectionUnittest
|
|
|
|
let CopyToNativeArrayBufferTests = TestSuite("CopyToNativeArrayBufferTests")
|
|
|
|
CopyToNativeArrayBufferTests.test("Sequence._copyToContiguousArray()") {
|
|
do {
|
|
// Call from a static context.
|
|
let s =
|
|
MinimalSequence(elements: LifetimeTracked(10)..<LifetimeTracked(27))
|
|
|
|
expectEqual(0, s.timesMakeIteratorCalled.value)
|
|
let copy = s._copyToContiguousArray()
|
|
expectEqual(1, s.timesMakeIteratorCalled.value)
|
|
expectEqualSequence(
|
|
Array(10..<27),
|
|
copy.map { $0.value })
|
|
}
|
|
do {
|
|
// Call from a generic context.
|
|
let wrapped = MinimalSequence(elements: LifetimeTracked(10)..<LifetimeTracked(27))
|
|
let s = LoggingSequence(wrapping: wrapped)
|
|
|
|
expectEqual(0, wrapped.timesMakeIteratorCalled.value)
|
|
let copy = s._copyToContiguousArray()
|
|
expectEqual(1, wrapped.timesMakeIteratorCalled.value)
|
|
expectEqualSequence(
|
|
Array(10..<27),
|
|
copy.map { $0.value })
|
|
}
|
|
}
|
|
|
|
CopyToNativeArrayBufferTests.test("Collection._copyToContiguousArray()") {
|
|
// Check that collections are handled with the collection-specific API. This
|
|
// means that we are calling the right default implementation (one for
|
|
// collections, not the one for sequences).
|
|
|
|
do {
|
|
// Call from a static context.
|
|
let c =
|
|
DefaultedCollection(elements: LifetimeTracked(10)..<LifetimeTracked(27))
|
|
|
|
expectEqual(0, c.timesMakeIteratorCalled.value)
|
|
expectEqual(0, c.timesStartIndexCalled.value)
|
|
let copy = c._copyToContiguousArray()
|
|
expectEqual(0, c.timesMakeIteratorCalled.value)
|
|
expectNotEqual(0, c.timesStartIndexCalled.value)
|
|
expectEqualSequence(
|
|
Array(10..<27),
|
|
copy.map { $0.value })
|
|
}
|
|
do {
|
|
// Call from a generic context.
|
|
let wrapped =
|
|
DefaultedCollection(elements: LifetimeTracked(10)..<LifetimeTracked(27))
|
|
let s = LoggingSequence(wrapping: wrapped)
|
|
expectEqual(0, wrapped.timesMakeIteratorCalled.value)
|
|
expectEqual(0, wrapped.timesStartIndexCalled.value)
|
|
let copy = s._copyToContiguousArray()
|
|
expectEqual(0, wrapped.timesMakeIteratorCalled.value)
|
|
expectNotEqual(0, wrapped.timesStartIndexCalled.value)
|
|
|
|
expectEqualSequence(
|
|
Array(10..<27),
|
|
copy.map { $0.value })
|
|
}
|
|
}
|
|
|
|
%{
|
|
all_array_types = ['ContiguousArray', 'ArraySlice', 'Array']
|
|
}%
|
|
|
|
var ArrayTestSuite = TestSuite("Array")
|
|
|
|
ArrayTestSuite.test("sizeof") {
|
|
var a = [ 10, 20, 30 ]
|
|
#if arch(i386) || arch(arm)
|
|
expectEqual(4, MemoryLayout.size(ofValue: a))
|
|
#else
|
|
expectEqual(8, MemoryLayout.size(ofValue: a))
|
|
#endif
|
|
}
|
|
|
|
ArrayTestSuite.test("valueDestruction") {
|
|
var a = [LifetimeTracked]()
|
|
for i in 100...110 {
|
|
a.append(LifetimeTracked(i))
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Native array tests
|
|
// FIXME: incomplete.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ArrayTestSuite.test("Native/count/empty") {
|
|
let a = [LifetimeTracked]()
|
|
expectEqual(0, a.count)
|
|
}
|
|
|
|
ArrayTestSuite.test("Native/count") {
|
|
let a = [ LifetimeTracked(10), LifetimeTracked(20), LifetimeTracked(30) ]
|
|
expectEqual(3, a.count)
|
|
}
|
|
|
|
ArrayTestSuite.test("Native/isEmpty/empty") {
|
|
let a = [LifetimeTracked]()
|
|
expectTrue(a.isEmpty)
|
|
}
|
|
|
|
ArrayTestSuite.test("Native/isEmpty") {
|
|
let a = [ LifetimeTracked(10), LifetimeTracked(20), LifetimeTracked(30) ]
|
|
expectFalse(a.isEmpty)
|
|
}
|
|
|
|
% for Kind in ['Array', 'ContiguousArray']:
|
|
ArrayTestSuite.test("${Kind}/popLast") {
|
|
// Empty
|
|
do {
|
|
var a = ${Kind}<Int>()
|
|
let popped = a.popLast()
|
|
expectNil(popped)
|
|
expectTrue(a.isEmpty)
|
|
}
|
|
|
|
do {
|
|
var popped = [Int]()
|
|
var a: ${Kind}<Int> = [1010, 2020, 3030]
|
|
while let element = a.popLast() {
|
|
popped.append(element)
|
|
}
|
|
expectEqualSequence([1010, 2020, 3030], popped.reversed())
|
|
expectTrue(a.isEmpty)
|
|
}
|
|
}
|
|
% end
|
|
|
|
// Check how removeFirst() affects indices.
|
|
% for Kind in ['Array', 'ContiguousArray']:
|
|
ArrayTestSuite.test("${Kind}/removeFirst") {
|
|
do {
|
|
var a: ${Kind}<OpaqueValue<Int>> = ${Kind}([ 1 ].map(OpaqueValue.init))
|
|
a.removeFirst()
|
|
expectEqual(0, a.startIndex)
|
|
}
|
|
do {
|
|
var a: ${Kind}<OpaqueValue<Int>> = ${Kind}([ 1, 2 ].map(OpaqueValue.init))
|
|
a.removeFirst()
|
|
expectEqual(0, a.startIndex)
|
|
}
|
|
}
|
|
% end
|
|
|
|
ArrayTestSuite.test("ArraySlice/removeFirst") {
|
|
do {
|
|
let a: [OpaqueValue<Int>] = [ 99, 1010, 99 ].map(OpaqueValue.init)
|
|
var s = a[1..<2]
|
|
expectEqual(1, s.startIndex)
|
|
s.removeFirst()
|
|
expectEqual(2, s.startIndex)
|
|
}
|
|
do {
|
|
let a: [OpaqueValue<Int>] = [ 99, 1010, 2020, 99 ].map(OpaqueValue.init)
|
|
var s = a[1..<2]
|
|
expectEqual(1, s.startIndex)
|
|
s.removeFirst()
|
|
expectEqual(2, s.startIndex)
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Array and EvilCollection that changes its size while we are not looking
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
let evilBoundsError = "EvilCollection: index out of range"
|
|
|
|
final class EvilSequence : Sequence {
|
|
init(_ growth: Int) {
|
|
self.growth = growth
|
|
}
|
|
|
|
var growth: Int
|
|
var _count: Int = 20
|
|
|
|
var underestimatedCount: Int {
|
|
defer { _count += growth }
|
|
return _count
|
|
}
|
|
|
|
func makeIterator() -> AnyIterator<LifetimeTracked> {
|
|
var i = 0
|
|
return AnyIterator {
|
|
if i >= self._count { return nil }
|
|
let result = LifetimeTracked(i)
|
|
i += 1
|
|
return result
|
|
}
|
|
}
|
|
}
|
|
|
|
final class EvilCollection : Collection {
|
|
func index(after i: Int) -> Int {
|
|
return i + 1
|
|
}
|
|
|
|
init(_ growth: Int, boundsChecked: Bool) {
|
|
self.growth = growth
|
|
self.boundsChecked = boundsChecked
|
|
}
|
|
|
|
var growth: Int
|
|
var _count: Int = 20
|
|
var boundsChecked: Bool
|
|
|
|
var startIndex : Int {
|
|
_count += growth
|
|
return 0
|
|
}
|
|
|
|
var endIndex : Int {
|
|
return _count
|
|
}
|
|
|
|
subscript(i: Int) -> LifetimeTracked {
|
|
if boundsChecked {
|
|
precondition(i >= 0 && i < _count, evilBoundsError)
|
|
}
|
|
return LifetimeTracked(i)
|
|
}
|
|
|
|
// Default implementation will call _failEarlyRangeCheck,
|
|
// passing in a startIndex that will grow _count faster than
|
|
// necessary.
|
|
func formIndex(after i: inout Int) {
|
|
i += 1
|
|
}
|
|
}
|
|
|
|
for (step, evilBoundsCheck) in [ (1, true), (-1, false), (-1, true) ] {
|
|
|
|
let message = step < 0 && evilBoundsCheck
|
|
? evilBoundsError
|
|
: "invalid Collection: count differed in successive traversals"
|
|
|
|
let constructionMessage =
|
|
/*_isStdlibInternalChecksEnabled() && !evilBoundsCheck && step <= 0
|
|
? "_UnsafePartiallyInitializedContiguousArrayBuffer has no more capacity"
|
|
:*/ message
|
|
|
|
// The invalid Collection error is a _debugPreconditon that will only fire
|
|
// in a Debug assert configuration.
|
|
let expectedToFail = (step < 0 && evilBoundsCheck) ||
|
|
_isDebugAssertConfiguration()
|
|
|
|
let natureOfEvil = step > 0 ? "Growth" : "Shrinkage"
|
|
let boundsChecked = evilBoundsCheck ? "BoundsChecked" : "NoBoundsCheck"
|
|
let testPrefix = "MemorySafety/\(boundsChecked)/Evil\(natureOfEvil)"
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/Infrastructure/EvilSequence") {
|
|
let evil = EvilSequence(step)
|
|
let count0 = evil.underestimatedCount
|
|
let count1 = evil.underestimatedCount
|
|
expectNotEqual(count0, count1)
|
|
if step > 0 {
|
|
expectLE(count0, count1)
|
|
}
|
|
else {
|
|
expectGE(count0, count1)
|
|
}
|
|
}
|
|
|
|
let t1 = ArrayTestSuite.test("\(testPrefix)/Infrastructure/EvilCollection")
|
|
(evilBoundsCheck && _isDebugAssertConfiguration()
|
|
? t1.crashOutputMatches(evilBoundsError) : t1)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
let count0 = evil.count
|
|
let count1 = evil.count
|
|
expectNotEqual(count0, count1)
|
|
if step > 0 {
|
|
expectLE(count0, count1)
|
|
}
|
|
else {
|
|
expectGE(count0, count1)
|
|
}
|
|
if evilBoundsCheck {
|
|
expectCrashLater()
|
|
}
|
|
let x = evil[-1]
|
|
_blackHole(x)
|
|
}
|
|
|
|
let t2 = ArrayTestSuite.test("\(testPrefix)/Construction")
|
|
(_isDebugAssertConfiguration() && expectedToFail
|
|
? t2.crashOutputMatches(constructionMessage) : t2)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
|
|
let a = Array(evil)
|
|
_blackHole(a)
|
|
}
|
|
|
|
for (op, rangeMax) in ["Grow":0, "Shrink":200] {
|
|
let t3 = ArrayTestSuite.test("\(testPrefix)/replaceSubrange/\(op)Unique")
|
|
(_isDebugAssertConfiguration() ? t3.crashOutputMatches(message) : t3)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
var a = Array((0..<200).lazy.map { LifetimeTracked($0) })
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
a.replaceSubrange(0..<rangeMax, with: evil)
|
|
}
|
|
|
|
let t4 = ArrayTestSuite.test("\(testPrefix)/replaceSubrange/\(op)NonUnique")
|
|
(_isDebugAssertConfiguration() ? t4.crashOutputMatches(message) : t4)
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
var a = Array((0..<200).lazy.map { LifetimeTracked($0) })
|
|
var b = a
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
a.replaceSubrange(0..<rangeMax, with: evil)
|
|
_fixLifetime(b)
|
|
}
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/SequenceMap")
|
|
.skip(.custom(
|
|
{ _isFastAssertConfiguration() },
|
|
reason: "this trap is not guaranteed to happen in -Ounchecked"))
|
|
.code {
|
|
let evil = EvilSequence(step)
|
|
|
|
if step < 0 {
|
|
expectCrashLater()
|
|
}
|
|
let a = evil.map { $0 }
|
|
_blackHole(a)
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/CollectionMap")
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
if expectedToFail {
|
|
expectCrashLater()
|
|
}
|
|
|
|
let a = evil.map { $0 }
|
|
_blackHole(a)
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/FilterAll")
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
let a = evil.filter { _ in true }
|
|
_blackHole(a)
|
|
}
|
|
|
|
ArrayTestSuite.test("\(testPrefix)/FilterNone")
|
|
.code {
|
|
let evil = EvilCollection(step, boundsChecked: evilBoundsCheck)
|
|
|
|
let a = evil.filter { _ in false }
|
|
_blackHole(a)
|
|
}
|
|
}
|
|
|
|
runAllTests()
|