# `MixAffected.TestMap`
[🔗](https://github.com/mnox/mix_affected/blob/v0.1.0/lib/mix_affected/test_map.ex#L1)

Which source files each test file references, built by `mix affected.map`
(see `MixAffected.TestMap.Builder`) and stored as an ETF file, by default at
`_build/test/mix_affected/test_map.etf`.

Each test file has an entry:

  * `:mode` - how its references were found: `:tracer` (compiler tracer
    while requiring the file), `:ast` (the file failed to require; module
    references read from its AST, which misses what `use` injects, so the
    test runs whenever anything is affected), or `:always` (it does not
    parse either, or an `affected_by` glob was rejected: same)
  * `:refs` - root-relative source files of every module it references,
    including other test files that define modules it uses
  * `:hashes` - `%{path => hash/1}` of the test file and of every file in
    `:refs`, as they were when the map was built. An entry whose files
    changed since is `stale/2`: its references may be out of date (a map
    prebuilt on another commit, a test edited after the local map was
    built), so selecting it is a full run (see `MixAffected.Run`).
  * `:unresolved` - names of traced modules no file defines and none can
    be loaded (typically defined by a file deleted or edited before the map
    was built); any seed selects every test with any
  * `:affected_by` - its literal `@moduletag affected_by: [globs]` and
    `@affected_by [globs]`, minus any `MixAffected.Config.validate_glob/2`
    rejects (which make the entry `:always`)
  * `:reads` - globs of the repo files it reads itself (`File.read!/1`,
    `Path.wildcard/1`, ...: a guard scanning `lib/**`, a doc test), `["**"]`
    when they cannot be pinned down, `[]` when it reads none
    (`MixAffected.TestMap.Ast.reads/3`)

`:impls` lists the project's protocol implementations as
`{impl_file, for_file}`: protocol dispatch is a runtime lookup no xref edge
records, so selection treats the `for:` type's file as depending on the
impl file (`for_file` equals `impl_file` for an impl in its type's own file or
from `@derive`). `for_file` is `nil` when the type is not defined in the project
(`Integer`, `Any`, a dependency's struct): then nothing in the project can
vouch for who dispatches to it.

# `entry`

```elixir
@type entry() :: %{
  mode: mode(),
  refs: [path()],
  affected_by: [String.t()],
  hashes: %{optional(path()) =&gt; binary()},
  unresolved: [String.t()],
  reads: [String.t()]
}
```

# `impl`

```elixir
@type impl() :: {impl_file :: path(), for_file :: path() | nil}
```

# `mode`

```elixir
@type mode() :: :tracer | :ast | :always
```

# `path`

```elixir
@type path() :: MixAffected.Graph.path()
```

# `t`

```elixir
@type t() :: %MixAffected.TestMap{
  impls: [impl()],
  tests: %{optional(path()) =&gt; entry()}
}
```

# `default_path`

```elixir
@spec default_path(Path.t()) :: Path.t()
```

The default map path under a build path such as `_build/test`.

# `hash`

```elixir
@spec hash(binary()) :: binary()
```

The content hash the map stores for a file's `content`.

# `mark_stale`

```elixir
@spec mark_stale(t(), [path()]) :: t()
```

Marks the entries of the `stale` test files `:always`, so selection
selects them whenever anything is affected instead of trusting their
references.

# `new`

```elixir
@spec new(%{optional(path()) =&gt; entry()}, [impl()]) :: t()
```

A map from `%{test_file => entry}` and the project's protocol impls.

# `read`

```elixir
@spec read(Path.t()) :: {:ok, t()} | {:error, String.t()}
```

Reads a map written by `write!/2` by the same map format version.

# `stale`

```elixir
@spec stale(t(), Path.t()) :: [path()]
```

The test files, sorted, whose entry's recorded `:hashes` no longer match
the files under `root` (changed or missing): their references may be out
of date.

# `write!`

```elixir
@spec write!(t(), Path.t()) :: :ok
```

Writes `map` to `path`, creating its directory.

---

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