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

Builds a `MixAffected.TestMap` inside the consuming project's VM, the way
`mix test` loads tests but without running any: the project must already
be compiled (and its apps started, as `mix test` does) by the caller.

  1. `ExUnit.start(autorun: false)`, then each test path's
     `test_helper.exs` is required (a failing helper is reported and
     skipped: tracing only needs the test modules to compile)
  2. every test file is required in parallel with
     `MixAffected.TestMap.Tracer` registered as a compiler tracer
  3. files that did not finish (an error, or the parallel compiler stopping
     on someone else's error) are retried one at a time
  4. a file that still fails gets its references from its AST
     (`MixAffected.TestMap.Ast`, mode `:ast`); one that does not parse
     either is `:always`
  5. every file's `:reads` (repo files it reads itself) come from its AST,
     anchored at the entries of the root (`MixAffected.TestMap.Ast.reads/3`)
  6. an `affected_by` glob `MixAffected.Config.validate_glob/2` rejects
     (malformed, not in normal form, or naming a directory) is dropped and its file is
     `:always`, with a warning in the stats: the edge it declared cannot be
     honoured, so the test runs whenever anything is affected

Referenced modules are mapped to their source file: the test file that
defined them, else `module_info(:compile)[:source]`. Sources outside the
root, or under an `:exclude` dir (deps, `_build`), are dropped.

A referenced Mox mock (a loaded module exporting `__mock_for__/0`) also
references the behaviours it mocks; mocks are defined by `test_helper.exs`,
which is required before the test files are traced.

Protocol impls among the project's `:modules` are recorded with the file
of the type they are for (`nil` when that type is not a project module).

# `stats`

```elixir
@type stats() :: %{
  tracer: non_neg_integer(),
  ast: non_neg_integer(),
  always: non_neg_integer(),
  helper_errors: [String.t()],
  glob_warnings: [String.t()]
}
```

# `build`

```elixir
@spec build(Path.t(), MixAffected.Config.t(), keyword()) ::
  {MixAffected.TestMap.t(), stats()}
```

Options: `:exclude` - absolute dirs whose sources are never refs;
`:modules` - the project's compiled modules, searched for protocol impls
(`TestMap` `:impls`). `root` is the absolute project root.

# `test_files`

```elixir
@spec test_files(Path.t(), MixAffected.Config.t()) :: [Path.t()]
```

Every test file of the project, absolute, sorted (as `mix test` finds them).

---

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