Files
ThreadSafe/Tests/ThreadSafeTests/ThreadSafeTests.swift

69 lines
2.3 KiB
Swift

import Testing
import Foundation
@testable import ThreadSafe
class ThreadSafetyTest: @unchecked Sendable {
class Obj {
let id = UUID().uuidString
}
// If @ThreadSafe is removed, the test would crash instantly
@ThreadSafe var obj = Obj()
@Test func testThreadSafe() async throws {
let coreCount = ProcessInfo.processInfo.activeProcessorCount
for _ in 0 ..< coreCount / 2 {
Thread { // write thread
while true {
self.obj = .init()
}
}.start()
}
for _ in 0 ..< coreCount / 2{
Thread { // read thread
while self.obj.id.count != 0 {}
}.start()
}
// If it doesn't crash after 10s, consider it passed.
// I think it's good enough as the possibility for a false positive is microscopic.
// Can't think of a way to definitively prove it's thread safe
try? await Task.sleep(for: .seconds(10))
}
}
@Test func TestCopyBehaviour() async throws {
struct Example {
// valueTypeCopyOnWrite enabled by default
@ThreadSafe var string: String = "Hello"
// valueTypeCopyOnWrite disabled
@ThreadSafe(valueTypeCopyOnWrite: false) var anotherString: String = "Hello"
// won't do anything as NSMutableString is a class
@ThreadSafe(valueTypeCopyOnWrite: true) var nsString: NSMutableString = "Hello"
// same as above
@ThreadSafe(valueTypeCopyOnWrite: false) var anotherNSString: NSMutableString = "Hello"
}
let original = Example()
var copy = original
copy.string.append(", World!")
#expect(original.string == "Hello") // copy on write triggered, original not affected
#expect(copy.string == "Hello, World!")
copy.anotherString.append(", World!")
#expect(original.anotherString == "Hello, World!") // valueTypeCopyOnWrite == false, underlying box not copied
#expect(copy.anotherString == "Hello, World!")
copy.nsString.append(", World!")
#expect(original.nsString == "Hello, World!")
#expect(copy.nsString == "Hello, World!")
copy.anotherNSString.append(", World!")
#expect(original.anotherNSString == "Hello, World!")
#expect(copy.anotherNSString == "Hello, World!")
}