Skip to content

GenerateMutants produces non-unique mutant IDs #2

Description

@mcgoughprogress

Summary

Engine.GenerateMutants does not produce unique mutant IDs. The same ID is handed to different mutants of the same file, pervasively — 87 of this repository's own 123 source files generate at least one repeated ID, 4530 duplicates across 21754 mutants.

Detail

internal/mutation/engine.go:137:

for i := range mutants {
    mutants[i].FilePath = filePath
    mutants[i].ID = fmt.Sprintf("%s_%d", filePath, len(allMutants)+i)

    // Only add mutant if it passes type check
    if typeChecker == nil || typeChecker.IsValidMutation(node, mutants[i]) {
        allMutants = append(allMutants, mutants[i])
    }
}

The ID combines len(allMutants) — re-evaluated on every iteration, and growing as the loop appends — with i, the candidate index within the same loop. Each accepted mutant is thus counted twice, so numbering advances in steps of two within a batch and then repeats values once the next batch resumes from the true slice length.

Type-check rejections skew it in the other direction: a rejected candidate still consumes an i without growing allMutants.

Minimal example — a nine-line file yields three collisions:

duplicate mutant ID test.go_3:  4:2 "n == 0"->"false" and 4:5 "=="->"!="
duplicate mutant ID test.go_9:  4:5 "=="->">"         and 4:12 "{...}"->"{}"
duplicate mutant ID test.go_11: 4:5 "=="->">="        and 8:2 "false"->"true"

Impact

Nothing in gomu currently keys off the ID — history is keyed by file path and gated on file and test hashes (internal/history/store.go), and the report prints position, not ID. So this is a data-quality bug rather than a behavioural one:

Suggested fix

Assign the ID after the type check, from the number of mutants kept so far, so the number is unique and gapless per file. Since nothing reads the ID, no history or report compatibility handling is needed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions