Structural Mutators
Relevant source files
The following files were used as context for generating this wiki page:
Structural mutators modify the logic and execution flow of Ruby programs by altering the composition of statements, method calls, and control structures. Unlike literal or arithmetic mutators that change values, structural mutators test the necessity and correctness of the code's architecture by removing or forcing specific execution paths.
These mutators are organized into different tiers. Some, like statement_removal, belong to the default "Tier 1" set used in standard runs, while others like chain_link or condition_forcing are specialized "Tier 2" mutators.
Sources: lib/mutineer.rb:14-34, lib/mutineer/mutator_registry.rb:48-64
Core Structural Mutators
Mutineer provides several classes specifically designed to manipulate the structure of Ruby source code. The following table summarizes the primary structural mutators and their effects:
| Mutator Name | Operator ID | Tier | Effect |
|---|---|---|---|
StatementRemoval | statement_removal | 1 | Removes an entire statement or line of code. |
ReturnNil | return_nil | 2 | Appends ` |
ChainLink | chain_link | 2 | Removes intermediate method calls in a chain. |
ConditionTrue | condition_true | 2 | Forces a conditional expression to always be true. |
ConditionFalse | condition_false | 2 | Forces a conditional expression to always be false. |
Sources: lib/mutineer/mutator_registry.rb:11-30, lib/mutineer/mutators/statement_removal.rb:5, lib/mutineer/mutators/return_nil.rb:5, lib/mutineer/mutators/chain_link.rb:5, lib/mutineer/mutators/condition_forcing.rb:5
Statement Removal
The StatementRemoval mutator identifies statements within a method or block and replaces them with an empty string. It specifically avoids mutating certain structures like def (method definitions) or alias statements to ensure the resulting code remains syntactically valid for the test runner.
The diagram above illustrates the logic used by the Statement Removal mutator to decide which code segments to delete.
Sources: lib/mutineer/mutators/statement_removal.rb:5-24
Return Nil
The ReturnNil mutator alters expressions by appending || nil. This forces the expression to evaluate to nil if it was previously falsey, or tests if the surrounding code handles nil return values correctly. It ignores specific assignments (like local or instance variables) to prevent breaking basic variable scoping.
Sources: lib/mutineer/mutators/return_nil.rb:5-18
Chain Link Manipulation
The ChainLink mutator targets method call chains, such as user.account.owner.name. It removes intermediate links while preserving the receiver and the final call. For example, it might mutate the chain to user.owner.name or user.account.name.
Certain "equivalent" links are skipped to avoid generating redundant mutants. These include:
to_s,to_a,to_hdup,clone,freezeitself,new
Sources: lib/mutineer/mutators/chain_link.rb:5-30, test/mutators/chain_link_test.rb:55-60
Condition Forcing
The ConditionTrue and ConditionFalse mutators target conditional logic within if, unless, while, and until statements. They replace the entire conditional expression with a boolean literal.
This diagram shows how conditional expressions are mapped to forced boolean outcomes.
Sources: lib/mutineer/mutators/condition_forcing.rb:5-25
Supported Conditional Nodes
Condition forcing applies to several types of Ruby nodes:
IfNodeUnlessNodeWhileNodeUntilNodeConditionalWriteNode(e.g.,||=or&&=)
Sources: lib/mutineer/mutators/condition_forcing.rb:14-22
Execution Flow in Mutators
Structural mutators inherit from a base mutator class and implement a visitor pattern to traverse the AST (Abstract Syntax Tree). When a relevant node is encountered, the mutator generates a Mutation object containing the byte offsets and the replacement text.
The sequence diagram details the interaction between the registry, the mutator, and the source code AST during the mutation generation phase.
Sources: lib/mutineer/mutators/statement_removal.rb:9-15, lib/mutineer/mutators/chain_link.rb:9-15, lib/mutineer/mutator_registry.rb:48-55
Summary
Structural mutators provide a critical layer of mutation testing by verifying that the code's structure—such as method chains and conditional paths—is actually necessary for passing tests. By removing statements or forcing conditions, Mutineer ensures that tests are sensitive to the logic flow of the application, rather than just simple value changes.