# `Mix.Statifier.Corpus.PositionExpectation`
[🔗](https://github.com/riddler/statifier-ex/blob/v2.15.0/lib/mix/statifier/corpus/position_expectation.ex#L1)

The position a corpus step's `expect_position` states (ADR-0076): what
`Statifier.Position.export/1` answers for the chart's state after that
step, with the fields a conforming implementation need not share left
out, rendered as the JSON value a case writes.

The rendering is a map with string keys and exactly these seven members:

- `configuration`, `entered_states` and `states_to_invoke`: each set of
  state ids as an array sorted ascending.
- `history_values`: an object from each history state's id to its
  recorded state ids, as an array sorted ascending.
- `active_invocations`: one object per active invocation, `state` (the id
  of the state that owns the `<invoke>`) and `index` (the `<invoke>`'s
  ordinal among that state's own), sorted by `state` and then by `index`;
  the invocation's id is left out.
- `running`: the export's boolean as it is.
- `datamodel`: the export's datamodel with `_event`, `_ioprocessors` and
  `_sessionid` removed, and `_name` removed as well unless the document's
  `<scxml>` element carries a `name` attribute: spec 5.10 binds `_name`
  to that attribute's value, so every conforming implementation holds the
  same one, while an unset `_name` is each implementation's own spelling.
  A string, a number, a boolean and `nil` are written as they are,
  `:undefined` as `nil` (JSON `null`), a list as an array and a map with
  string keys as an object, member by member; any other value has no JSON
  form and is refused, naming its variable.

The export's other members (`identity`, `invoke_counter`, `send_counter`,
`timer_counter`, `status`, `macrostep`, `microstep`, `round`, `trace` and
`max_macrostep_rounds`) are not rendered. ADR-0076 gives the reason for
each.

A case that carries an `expect_position` on any step needs every state of
its document to carry an id (`named/1`), because the export refuses a
position that holds a state it cannot name.

# `compare`

```elixir
@spec compare(
  expected :: map(),
  machine_state :: Statifier.MachineState.t(),
  step :: {pos_integer(), String.t()}
) :: :ok | {:disagree, String.t()}
```

Compares `expected`, a step's `expect_position`, with the rendering of
`machine_state`. `step` names the step in a disagreement: its one-based
number and its event's name. Each member that differs is named, with
both values as JSON.

Values compare as JSON values: two numbers agree when they are equal
in value, so a float `2.0` the chart holds agrees with an expected
`2`; an array compares element by element in order, an object member
by member; a string, a boolean and `null` agree only with themselves.

# `expected?`

```elixir
@spec expected?(corpus_case :: map()) :: boolean()
```

Whether any of `corpus_case`'s steps carries an `expect_position`.

# `named`

```elixir
@spec named(machine :: Statifier.Machine.t()) :: :ok | {:disagree, String.t()}
```

Answers `:ok` when every state of `machine` but the root carries an id,
and a disagreement naming the count of states without one otherwise.

# `render`

```elixir
@spec render(machine_state :: Statifier.MachineState.t()) ::
  {:ok, map()} | {:error, String.t()}
```

Renders `machine_state`'s exported position in the expectation's JSON
form, or answers why it cannot: the export's own refusal, or a datamodel
value with no JSON form.

---

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