Class: Mutineer::Mutators::RangeLiteral
- Defined in:
- lib/mutineer/mutators/range_literal.rb
Overview
Range mutator (Tier-2).
Swaps .. with ... and ... with .., one mutation per range. The
.. -> ... mutant survives when no test checks the last element.
Flip-flops are FlipFlopNode, not RangeNode, so this mutator skips them.
Endless ranges (1.., 1..nil) are skipped. (1..) and (1...) give
the same result for slicing, include?, ===, size and patterns, so
the mutant is equivalent and no normal test can kill it.
Constant Summary collapse
- SWAPS =
Maps each range operator to its opposite.
{ ".." => "...", "..." => ".." }.freeze
Instance Method Summary collapse
-
#emit(node) ⇒ void
private
Emits the mutation that swaps the range operator.
-
#endless?(node) ⇒ Boolean
private
Whether the range has no end:
1..or1..nil. -
#visit_range_node(node) ⇒ void
Visits range nodes and emits range mutations.
Methods inherited from Base
Instance Method Details
#emit(node) ⇒ void (private)
This method returns an undefined value.
Emits the mutation that swaps the range operator.
43 44 45 46 47 48 49 50 51 |
# File 'lib/mutineer/mutators/range_literal.rb', line 43 def emit(node) loc = node.operator_loc @mutations << Mutation.new( start_offset: loc.start_offset, end_offset: loc.end_offset, replacement: SWAPS.fetch(loc.slice), operator: :range ) end |
#endless?(node) ⇒ Boolean (private)
Whether the range has no end: 1.. or 1..nil.
35 36 37 |
# File 'lib/mutineer/mutators/range_literal.rb', line 35 def endless?(node) node.right.nil? || node.right.is_a?(Prism::NilNode) end |
#visit_range_node(node) ⇒ void
This method returns an undefined value.
Visits range nodes and emits range mutations.
24 25 26 27 |
# File 'lib/mutineer/mutators/range_literal.rb', line 24 def visit_range_node(node) emit(node) unless endless?(node) super # nested ranges ((1..2)...(3..4)) each get their own mutation end |