lean4-htt/tests/elab/sync_channel.lean
Garmelon 08eb78a5b2
chore: switch to new test/bench suite (#12590)
This PR sets up the new integrated test/bench suite. It then migrates
all benchmarks and some related tests to the new suite. There's also
some documentation and some linting.

For now, a lot of the old tests are left alone so this PR doesn't become
even larger than it already is. Eventually, all tests should be migrated
to the new suite though so there isn't a confusing mix of two systems.
2026-02-25 13:51:53 +00:00

150 lines
5.4 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Std.Sync
open Std
def assertBEq [BEq α] [ToString α] (is should : α) : IO Unit := do
if is != should then
throw <| .userError s!"{is} should be {should}"
def closeClose (ch : CloseableChannel Nat) : IO Unit := do
assertBEq (← ch.isClosed) false
assertBEq ((← EIO.toBaseIO ch.close) matches .ok ()) true
assertBEq (← ch.isClosed) true
assertBEq ((← EIO.toBaseIO ch.close) matches .error .alreadyClosed) true
assertBEq (← ch.isClosed) true
def paired (ch : CloseableChannel Nat) : IO Unit := do
let sendTask ← ch.send 37
let recvTask ← ch.recv
assertBEq ((← IO.wait sendTask) matches .ok ()) true
assertBEq (← IO.wait recvTask) (some 37)
def syncPaired (ch : CloseableChannel.Sync Nat) : IO Unit := do
let sendTask ← IO.asTask (prio := .dedicated) (EIO.toBaseIO (ch.send 37))
let recvTask ← IO.asTask (prio := .dedicated) (ch.recv)
assertBEq ((← IO.ofExcept (← IO.wait sendTask)) matches .ok ()) true
assertBEq (← IO.ofExcept (← IO.wait recvTask)) (some 37)
def trySend (ch : CloseableChannel Nat) (capacity : Option Nat) : IO Unit := do
-- ready a receiver ahead of time
let recvTask ← ch.recv
assertBEq (← ch.trySend 37) true
assertBEq (← IO.wait recvTask) (some 37)
-- the unbounded CloseableChannel cannot go out of space so it is pointless to fill it up
let some capacity := capacity | return ()
for i in *...capacity do
assertBEq (← ch.trySend i) true
assertBEq (← ch.trySend (capacity + 1)) false
def tryRecv (ch : CloseableChannel Nat) : IO Unit := do
assertBEq (← ch.tryRecv) none
let sendTask ← ch.send 37
assertBEq (← ch.tryRecv) (some 37)
assertBEq ((← IO.wait sendTask) matches .ok ()) true
def sendRecvClose (ch : CloseableChannel Nat) : IO Unit := do
let sendTask ← ch.send 37
assertBEq ((← EIO.toBaseIO ch.close) matches .ok ()) true
let recvTask ← ch.recv
assertBEq ((← IO.wait sendTask) matches .ok ()) true
assertBEq (← IO.wait recvTask) (some 37)
let sendTask ← ch.send 37
assertBEq ((← IO.wait sendTask) matches .error .closed) true
let recvTask ← ch.recv
assertBEq (← IO.wait recvTask) none
assertBEq (← ch.trySend 37) false
assertBEq (← ch.tryRecv) none
def sendIt (ch : CloseableChannel Nat) (messages : List Nat) : BaseIO (Task (Option Unit)) := do
match messages with
| [] => return .pure <| some ()
| msg :: messages =>
BaseIO.bindTask (← ch.send msg) fun
| .error .. =>
return .pure <| none
| .ok .. =>
sendIt ch messages
partial def recvIt (ch : CloseableChannel Nat) (messages : List Nat) : BaseIO (Task (List Nat)) := do
BaseIO.bindTask (← ch.recv) fun
| none => return .pure messages.reverse
| some msg => recvIt ch (msg :: messages)
def sendLots (ch : CloseableChannel Nat) : IO Unit := do
let messages := List.range 1000
let sendTask ← sendIt ch messages
let recvTask ← recvIt ch []
assertBEq (← IO.wait sendTask) (some ())
discard <| ch.close
assertBEq (← IO.wait recvTask) messages
def sendItSync (ch : CloseableChannel.Sync Nat) (messages : List Nat) : IO Unit := do
for msg in messages do
ch.send msg
return ()
def recvItSync (ch : CloseableChannel.Sync Nat) : IO (List Nat) := do
let mut messages := []
for msg in ch do
messages := msg :: messages
return messages.reverse
def sendLotsSync (ch : CloseableChannel.Sync Nat) : IO Unit := do
let messages := List.range 1000
let sendTask ← IO.asTask (prio := .dedicated) (sendItSync ch messages)
let recvTask ← IO.asTask (prio := .dedicated) (recvItSync ch)
IO.ofExcept (← IO.wait sendTask)
discard <| ch.close
assertBEq (← IO.ofExcept (← IO.wait recvTask)) messages
partial def sendLotsMulti (ch : CloseableChannel Nat) : IO Unit := do
let messages := List.range 1000
let sendTask1 ← sendIt ch messages
let sendTask2 ← sendIt ch messages
let recvTask1 ← recvIt ch []
let recvTask2 ← recvIt ch []
assertBEq (← IO.wait sendTask1) (some ())
assertBEq (← IO.wait sendTask2) (some ())
discard <| ch.close
let msg1 ← IO.wait recvTask1
let msg2 ← IO.wait recvTask2
assertBEq (msg1.sum + msg2.sum) (2 * messages.sum)
partial def sendLotsMultiSync (ch : CloseableChannel.Sync Nat) : IO Unit := do
let messages := List.range 1000
let sendTask1 ← IO.asTask (prio := .dedicated) (sendItSync ch messages)
let sendTask2 ← IO.asTask (prio := .dedicated) (sendItSync ch messages)
let recvTask1 ← IO.asTask (prio := .dedicated) (recvItSync ch)
let recvTask2 ← IO.asTask (prio := .dedicated) (recvItSync ch)
IO.ofExcept (← IO.wait sendTask1)
IO.ofExcept (← IO.wait sendTask2)
discard <| ch.close
let msg1 ← IO.ofExcept (← IO.wait recvTask1)
let msg2 ← IO.ofExcept (← IO.wait recvTask2)
assertBEq (msg1.sum + msg2.sum) (2 * messages.sum)
def testIt (capacity : Option Nat) : IO Unit := do
paired (← CloseableChannel.new capacity)
syncPaired (← CloseableChannel.new capacity).sync
closeClose (← CloseableChannel.new capacity)
trySend (← CloseableChannel.new capacity) capacity
tryRecv (← CloseableChannel.new capacity)
sendRecvClose (← CloseableChannel.new capacity)
sendLots (← CloseableChannel.new capacity)
sendLotsSync (← CloseableChannel.new capacity).sync
sendLotsMulti (← CloseableChannel.new capacity)
sendLotsMultiSync (← CloseableChannel.new capacity).sync
def suite : IO Unit := do
testIt none
testIt (some 0)
testIt (some 1)
testIt (some 8)
testIt (some 128)
#eval suite