A Mutare extension for Gettext macro expansion and argument
routing. It configures the built-in mutators to mutate runtime arguments in a use Gettext
module while preserving the literals required to compile the metamutant.
It produces no mutations, occupies no mutator slot, and does not appear in reports.
List it under :extensions (in .mutare.exs or Mutare.run/2):
# .mutare.exs
[extensions: [Mutare.Gettext]]What it does
The extension implements two capability behaviours (see Mutare.Extension):
Mutare.UseExpansion.expand_use/3— suppliesimport Gettext.Macrosdirectly for everyuse Gettextduring Mutare's scan. Gettext (>= 0.26) compilesuse Gettext, backend: MyApp.Gettextby mutating the caller module to register the backend, which raises when Mutare expands it in the scan process (the caller is already compiled), soimportis not recovered and the baregettext/ngettextcalls remain unresolved. (Thebackend:value is a module alias, not a compile-time literal, so Mutare's requirement for static-literal options would prevent expansion regardless.) Supplying the import directly allows Mutare to resolve and route those calls.Mutare.CallRouting.call_routes/0— routes each Gettext macro's arguments. The compile-time literal positions — message id, plural id, domain, context, backend — must never be mutated: inserting a mutation selector there causes a macro expansion error and prevents compilation. The runtime positions — thengettextpluralcountand the interpolationbindings— are mutated, so mutation testing can check whether tests detect changes to plural counts and interpolation values.
This is expressed as a whole-module :raw baseline ({Gettext.Macros, :*, :raw} — every
argument of every macro left untouched, the safe default) plus a per-position override for each
arity with a count or bindings argument, routing just those trailing positions :expression
(a more specific route takes precedence; see Mutare.CallRouting). For example ngettext/4
routes [:raw, :raw, :expression, :expression] — the two message ids remain unchanged, while
the count and bindings are mutated. The overrides are derived from the Gettext macro families;
the test suite cross-checks every one against the Gettext.Macros exports.
Targets Gettext >= 0.26, which introduced Gettext.Macros. On older versions, the injected
import Gettext.Macros refers to a module that isn't loaded. Mutare leaves unresolved calls
unchanged, so the extension has no effect.