Files
UUVPN/iOS-SwiftUI-Code/GRDB.swift-6.29.3/Tests/GRDBTests/PoolTests.swift
T
2025-01-28 12:28:03 +08:00

270 lines
7.6 KiB
Swift

import XCTest
@testable import GRDB
class PoolTests: XCTestCase {
/// Returns a Pool whose elements are incremented integers: 1, 2, 3...
private func makeCounterPool(maximumCount: Int) -> Pool<Int> {
let count = ReadWriteBox(wrappedValue: 0)
return Pool(maximumCount: maximumCount, makeElement: count.increment)
}
func testElementsAreReused() throws {
let pool = makeCounterPool(maximumCount: 2)
// Get and release element
let first = try pool.get()
XCTAssertEqual(first.element, 1)
first.release(.reuse)
// Get recycled element
let second = try pool.get()
XCTAssertEqual(second.element, 1)
// Get new element
let third = try pool.get()
XCTAssertEqual(third.element, 2)
// Reuse elements
second.release(.reuse)
third.release(.reuse)
// Get and release recycled elements
let fourth = try pool.get()
XCTAssertEqual(fourth.element, 1)
let fifth = try pool.get()
XCTAssertEqual(fifth.element, 2)
fourth.release(.reuse)
fifth.release(.reuse)
}
func testElementsCanBeDiscarded() throws {
let pool = makeCounterPool(maximumCount: 2)
// Get and release element
let first = try pool.get()
XCTAssertEqual(first.element, 1)
first.release(.reuse)
// Get recycled element
let second = try pool.get()
XCTAssertEqual(second.element, 1)
// Get new element
let third = try pool.get()
XCTAssertEqual(third.element, 2)
// Reuse second, discard third
second.release(.reuse)
third.release(.discard)
// Get and release recycled elements
let fourth = try pool.get()
XCTAssertEqual(fourth.element, 1)
let fifth = try pool.get()
XCTAssertEqual(fifth.element, 3)
fourth.release(.reuse)
fifth.release(.reuse)
}
func testRemoveAll() throws {
let pool = makeCounterPool(maximumCount: 2)
// Get elements
let first = try pool.get()
XCTAssertEqual(first.element, 1)
let second = try pool.get()
XCTAssertEqual(second.element, 2)
// removeAll is not locked by used elements
pool.removeAll()
// Reuse elements
first.release(.reuse)
second.release(.reuse)
// Get and release new elements
let third = try pool.get()
XCTAssertEqual(third.element, 3)
let fourth = try pool.get()
XCTAssertEqual(fourth.element, 4)
third.release(.reuse)
fourth.release(.reuse)
}
func testBarrierLocksElements() throws {
let expectation = self.expectation(description: "lock")
expectation.isInverted = true
let pool = makeCounterPool(maximumCount: 1)
var element: Int?
let s1 = DispatchSemaphore(value: 0)
let s2 = DispatchSemaphore(value: 0)
let s3 = DispatchSemaphore(value: 0)
DispatchQueue.global().async {
pool.barrier {
s1.signal()
s2.wait()
}
}
DispatchQueue.global().async {
// Wait for barrier to start
s1.wait()
let first = try! pool.get()
element = first.element
first.release(.reuse)
expectation.fulfill()
s3.signal()
}
// Assert that get() is blocked
waitForExpectations(timeout: 1)
// Reuse barrier
s2.signal()
// Wait for get() to complete
s3.wait()
XCTAssertEqual(element, 1)
}
func testBarrierIsLockedByOneUsedElementOutOfOne() throws {
let expectation = self.expectation(description: "lock")
expectation.isInverted = true
let pool = makeCounterPool(maximumCount: 1)
// Get element
let first = try pool.get()
XCTAssertEqual(first.element, 1)
let s = DispatchSemaphore(value: 0)
DispatchQueue.global().async {
pool.barrier { }
expectation.fulfill()
s.signal()
}
// Assert that barrier is blocked
waitForExpectations(timeout: 1)
// Reuse element
first.release(.reuse)
// Wait for barrier to complete
s.wait()
// Get and release recycled element
let second = try pool.get()
XCTAssertEqual(second.element, 1)
second.release(.reuse)
}
func testBarrierIsLockedByOneUsedElementOutOfTwo() throws {
let expectation = self.expectation(description: "lock")
expectation.isInverted = true
let pool = makeCounterPool(maximumCount: 2)
// Get elements
let first = try pool.get()
XCTAssertEqual(first.element, 1)
let second = try pool.get()
XCTAssertEqual(second.element, 2)
// Reuse first element
first.release(.reuse)
let s = DispatchSemaphore(value: 0)
DispatchQueue.global().async {
pool.barrier { }
expectation.fulfill()
s.signal()
}
// Assert that barrier is blocked
waitForExpectations(timeout: 1)
// Reuse second element
second.release(.reuse)
// Wait for barrier to complete
s.wait()
// Get and release recycled element
let third = try pool.get()
XCTAssertEqual(third.element, 1)
third.release(.reuse)
}
func testBarrierIsLockedByTwoUsedElementsOutOfTwo() throws {
let expectation = self.expectation(description: "lock")
expectation.isInverted = true
let pool = makeCounterPool(maximumCount: 2)
// Get elements
let first = try pool.get()
XCTAssertEqual(first.element, 1)
let second = try pool.get()
XCTAssertEqual(second.element, 2)
let s = DispatchSemaphore(value: 0)
DispatchQueue.global().async {
pool.barrier { }
expectation.fulfill()
s.signal()
}
// Assert that barrier is blocked
waitForExpectations(timeout: 1)
// Reuse elements
first.release(.reuse)
second.release(.reuse)
// Wait for barrier to complete
s.wait()
// Get and release recycled element
let third = try pool.get()
XCTAssertEqual(third.element, 1)
third.release(.reuse)
}
func testBarrierRemoveAll() throws {
let expectation = self.expectation(description: "lock")
expectation.isInverted = true
let pool = makeCounterPool(maximumCount: 1)
// Get element
let first = try pool.get()
XCTAssertEqual(first.element, 1)
let s = DispatchSemaphore(value: 0)
DispatchQueue.global().async {
// No deadlock
pool.barrier { pool.removeAll() }
expectation.fulfill()
s.signal()
}
// Assert that barrier is blocked
waitForExpectations(timeout: 1)
// Reuse element
first.release(.reuse)
// Wait for barrier to complete
s.wait()
// Get and release new element
let second = try pool.get()
XCTAssertEqual(second.element, 2)
second.release(.reuse)
}
}