# `Flezha.SDK.TaskletTestHarness`
[🔗](https://github.com/flezha/flezha_elixir_sdk/blob/v0.1.0/lib/flezha/sdk/tasklet_test_harness.ex#L1)

Run one tasklet as the dispatcher runs it, with no controller and no relay.

    h = TaskletTestHarness.new(Counter)
    {%{result: :ok, outputs: ["a=3"]}, h} = TaskletTestHarness.feed(h, "a:3")
    assert TaskletTestHarness.state(h) == %{value: 3}
    assert TaskletTestHarness.replay_equals(h) == :ok

Each call takes the harness and answers the next one beside what the
invocation produced: a `Flezha.SDK.TaskletTestHarness.Outcome`. An invocation
that fails changes nothing, as a live one is discarded.

`now/1` is `feed/3`'s `now:` when given, else what the declared clock reads:
the input's `event_time/1`, the change count under `logical_clock`, `0`
otherwise; inside a firing it is the scheduled time. The harness keeps the
pending timers as one set per kind, as the core does; it does not judge them
(the cap and the clock rule are the core's, when an item settles). An
`effect/4` name is judged by the core: an over-long one answers
`effect.bad_name`; a well-formed one answers `effect.outside_invocation`,
since keeping an outside call's result needs a live activation
(`Flezha.SDK.Local` runs one).

# `t`

```elixir
@type t() :: %Flezha.SDK.TaskletTestHarness{
  cell_key: term(),
  initial: term(),
  log: term(),
  module: term(),
  state: term(),
  timers: term()
}
```

# `advance_event_time`

```elixir
@spec advance_event_time(t(), non_neg_integer()) ::
  {[Flezha.SDK.TaskletTestHarness.Outcome.t()], t()}
```

Fire each pending event-time timer at or before `to`, earliest first; what a
firing registers or cancels counts, as it does live.

# `feed`

```elixir
@spec feed(t(), term(), keyword()) :: {Flezha.SDK.TaskletTestHarness.Outcome.t(), t()}
```

Run `run/3` against `value`. Options: `now:` (the clock's value for this
input) and `replay: true` (the input is replayed).

# `fire_timer`

```elixir
@spec fire_timer(t(), Flezha.SDK.TimerFiring.kind(), non_neg_integer()) ::
  {Flezha.SDK.TaskletTestHarness.Outcome.t(), t()}
```

Fire the `kind` timer scheduled at `at`, pending or not, through
`on_timer/3`; a tasklet without it answers the non-retryable error a live
firing parks with.

# `new`

```elixir
@spec new(module(), keyword()) :: t()
```

A harness for the tasklet `module` on one Cell. Options: `cell_key:` (default
nil, a Single Cell) and `state:` (default `init_state/1` of the key).

# `replay_equals`

```elixir
@spec replay_equals(t()) :: :ok | {:mismatch, term(), term()}
```

Fold every recorded change through `apply_change/2` from the initial state:
`:ok` when it rebuilds the live state, else `{:mismatch, live, replayed}`.
A mismatch is an `apply_change/2` that is not a pure fold, or a state
changed without a recorded change.

# `state`

```elixir
@spec state(t()) :: term()
```

The Cell's state, as the recorded invocations left it.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
