Mutant ids
Every mutant has an id, m and eight hex digits, such as mb2f8ae57. It’s how you name a mutant to
mutastic: mutastic verify <id> checks that one, mutastic run --only=<id> runs only it, and
mutastic explain <id> shows what it is. Scripts, CI jobs, ignores and coding agents keep ids, so an
id has to keep naming the same mutant while you work.
What an id is made of
Section titled “What an id is made of”An id is the start of a SHA-256 over what the mutant is. There’s no line number and no file name in
it, so code moving around a mutant doesn’t change it. The fingerprint in --format=jsonl is the
same hash, longer.
- the class, with its package;
- the method’s name, and its parameter and return types;
- which site of its kind in the method it is, counted in bytecode order: calls are counted apart from arithmetic, branches and returns;
- the change, and for most operators the operator’s id.
- the crate’s name;
- the path of the function it’s in, such as
pricing::Pricing::discount; - the operator, such as
mutastic/boundary; - the code it changes, and what it changes it to, with each run of whitespace and comments squeezed to one space;
- and, when the same change can be made more than once in that function, which one it is, counted from the top.
What keeps an id
Section titled “What keeps an id”- Code moving. Lines added or removed above it, or the method moved within its class.
- Line breaks, spaces and comments, which the class file doesn’t have.
- Changes later in the method, and changes earlier in it that add or remove no site of the mutant’s kind.
- Other operators. A new operator only adds ids, never changes the others’.
- Code moving. Lines added or removed above it, or the function moved within its file.
- Line breaks and comments. A long condition broken over two lines, a comment added inside
it, or more spaces where there were some: each run of them counts as one space. Spaces added
where there were none (
a<btoa < b) are a change, thoughrustfmt’d code rarely has any to add. - Other changes in the function, unless they add or remove the same change earlier in it.
- Other operators. An id doesn’t depend on which operators a run uses, or which mutants it
shows: an id shown by an
--operators=extendedrun works withverifyon its own, without naming the set again, and so does one from inside unsafe code. - A new version of mutastic. Ids are a promise: the Rust edition’s tests hold every mutant of every fixture to a kept list, and fail if an id goes or comes to name another mutant. A new operator only adds ids.
What changes an id
Section titled “What changes an id”- A different change. A mutant whose change is different is a different mutant, with a new id.
- The method’s name or types. Renaming the method, its class or its package, or changing its parameter or return types.
- A site of the same kind added or removed earlier in the method. The count moves: a new condition above a mutant’s moves the ids of the arithmetic, branches and returns below it, and a new call moves the calls’. Run again to see the ids as they are now.
- The change itself. Edit the line so the code at the site differs (
total >= 100tototal >= 120), and its mutants are new ones, with new ids. - The function’s path. Renaming the function, moving it to another module, or renaming the
type of an
implit’s in. - The crate’s name.
- The same change made earlier in the function. A second
total >= 100added above the first takes the first one’s place in the count: the new one gets the old one’s ids, and the old one gets new ones. - The same change deleted earlier in the function. Identical lines are told apart by their
place in the count, not by their line number. With four
i = i + 1;lines in one function, deleting the second moves the third and fourth up the count: the third takes the second’s ids, the fourth takes the third’s, and the fourth’s old ids name nothing. An id you kept for one of them may now name the line below it, so run again to see which is which.
Each of the identical lines still has ids of its own, its own card, and its own verify: a test
that catches the third line’s change verifies the third line’s ids, and no other’s. Only deleting
or adding one of them earlier in the function moves the count.
When an id you kept names no mutant of the project, mutastic says so. An id belongs to the project its run was on, so name the project’s directory as that run did.
mutastic 1.1.0 · reading the Cargo package…mutastic: m00000000 isn't a mutant of pricing: run `mutastic run fixtures/pricing` to see its mutantsIds in the two editions
Section titled “Ids in the two editions”Both editions make an id from what the mutant is, and the operator ids are shared:
mutastic/boundary means the same change in both. The Rust edition hashes its own name in first,
so a Rust id never names a Java mutant.