FakeSeam
A test double for Seam with test-driver helpers for state mutation, frame delivery, and outgoing-frame inspection.
Defaults make FakeSeam() a ready-to-use, single-peer, SeamState.Woven seam in one line:
val seam = FakeSeam()
seam.deliver(PeerId("alice"), byteArrayOf(1, 2, 3))
val frame = seam.incoming.first()For wired two-peer scenarios, prefer fakeSeamPair which cross-wires broadcast delivery between two seams.
Send semantics (matching the Seam contract):
broadcast while SeamState.Weaving or SeamState.Woven with no other peers: no-op, but the payload is still recorded in broadcasts.
sendTo to a peer not in peers: throws PeerNotConnected.
Either send while SeamState.Torn: throws IllegalStateException.
The inbound buffer is bounded via policy (default DeliveryPolicy.Reliable). Unbounded delivery is structurally unrepresentable — pass a custom policy to change capacity or overflow behaviour.
initialPeers must contain selfId — in every state, as Seam.peers requires from construction onward. peers.value.size > 1 is the contract's sentinel for "at least one remote is connected", so a roster without selfId under-counts by one and a seam holding one remote reads as alone. Passing one throws IllegalArgumentException.
That obligation is an invariant, not a construction-time snapshot (#2546). Two doors used to reach the identical state the require refuses: removePeer applied to selfId now throws rather than holing the roster, and initialPeers is copied rather than retained, so a caller holding a MutableSet reference cannot edit the seam's roster out from under it after construction.
Constructing one already Torn is allowed, but only in the shape a real seam reaches: initialPeers must be setOf(selfId) (the default), because Seam.peers requires a torn seam's roster to be exactly that. Anything else throws IllegalArgumentException — see the init block. A seam constructed Torn also starts with incoming already completed, as tear leaves it.
Torn is terminal here too: weave refuses once torn rather than silently un-tearing, so a test cannot drive this fake through a transition no real seam performs. See weave for why that arm throws while tear is a silent no-op.
Constructors
Properties
All payloads passed to broadcast, in call order. Each read returns a fresh defensive snapshot; two reads may observe different snapshots if a broadcast lands between them.
Functions
Transition state to SeamState.Torn with reason, collapsing peers to { selfId } and completing incoming. Idempotent.
Transition state from SeamState.Weaving to SeamState.Woven. Re-asserting SeamState.Woven on an already-woven seam is a harmless no-op.