import XCTest @testable import LChatCore // 🤖 The refresh gate's contract: overlapping calls collapse into exactly // one trailing rerun (not zero — a frame that arrives mid-pass must still // produce a fresh pass; not N — the stampede was the bug); sequential // calls each run; and a mid-pass caller resumes only after a pass that // STARTED after its call (createChat reads `threads` right after run()). @MainActor final class CoalescedRunnerTests: XCTestCase { func testSequentialCallsEachRun() async { let runner = CoalescedRunner() var passes = 0 await runner.run { passes += 1 } await runner.run { passes += 1 } XCTAssertEqual(passes, 2) } func testOverlappingCallsCollapseToOneTrailingRerunAndAwaitIt() async { let runner = CoalescedRunner() var passes = 0 var blocked = false var release: CheckedContinuation? // First pass blocks inside the runner so the overlapping calls below // genuinely arrive mid-pass; the trailing rerun (same closure) must // not block again. let first = Task { @MainActor in await runner.run { passes += 1 if !blocked { blocked = true await withCheckedContinuation { release = $0 } } } } while release == nil { await Task.yield() } // Three callers while the pass is running: none may run a pass of // their own, and none may RESUME until the trailing rerun has // covered them. var resumed = 0 let waiters = (0..<3).map { _ in Task { @MainActor in await runner.run { passes += 1 } resumed += 1 } } for _ in 0..<20 { await Task.yield() } // let the waiters park in run() XCTAssertEqual(passes, 1, "mid-pass calls must not run a pass themselves") XCTAssertEqual(resumed, 0, "mid-pass callers wait for their covering pass") release?.resume() _ = await first.value for w in waiters { _ = await w.value } XCTAssertEqual(passes, 2, "exactly one trailing rerun after the pass ends") XCTAssertEqual(resumed, 3, "every waiter resumed once the rerun landed") } func testCallAfterCompletionRunsFresh() async { // The current-task handle must be cleared by the time any awaiter // resumes — a later call must start a fresh pass, never attach to a // finished task and return passless. let runner = CoalescedRunner() var passes = 0 await runner.run { passes += 1 } await runner.run { passes += 1 } await runner.run { passes += 1 } XCTAssertEqual(passes, 3) } }