Class: Henitai::EquivalenceDetector

Inherits:
Object
  • Object
show all
Defined in:
lib/henitai/equivalence_detector.rb,
sig/henitai.rbs

Overview

Detects obvious equivalent mutants before execution.

The detector is intentionally conservative: it only marks mutations as equivalent when the AST shape and the operand literals make the equivalence obvious enough to be useful.

Instance Method Summary collapse

Constructor Details

#initializeEquivalenceDetector

Returns a new instance of EquivalenceDetector.



571
# File 'sig/henitai.rbs', line 571

def initialize: () -> void

Instance Method Details

#additive_equivalent?(original, mutated) ⇒ Boolean

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Boolean)


46
47
48
49
50
51
# File 'lib/henitai/equivalence_detector.rb', line 46

def additive_equivalent?(original, mutated)
  additive_operator?(original.children[1]) &&
    additive_operator?(mutated.children[1]) &&
    zero_operand?(original) &&
    zero_operand?(mutated)
end

#additive_operator?(operator) ⇒ Boolean

Parameters:

  • (Object)

Returns:

  • (Boolean)


115
116
117
# File 'lib/henitai/equivalence_detector.rb', line 115

def additive_operator?(operator)
  %i[+ -].include?(operator)
end

#analyze(mutant) ⇒ Mutant

Parameters:

Returns:



12
13
14
15
16
17
# File 'lib/henitai/equivalence_detector.rb', line 12

def analyze(mutant)
  return mutant unless equivalent_mutation?(mutant)

  mutant.status = :equivalent
  mutant
end

#binary_send?(node) ⇒ Boolean

Parameters:

  • (Object)

Returns:

  • (Boolean)


38
39
40
# File 'lib/henitai/equivalence_detector.rb', line 38

def binary_send?(node)
  node.is_a?(Parser::AST::Node) && node.type == :send && node.children.size >= 3
end

#equivalent_arithmetic_mutation?(mutant) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


28
29
30
31
32
33
34
35
36
# File 'lib/henitai/equivalence_detector.rb', line 28

def equivalent_arithmetic_mutation?(mutant)
  original = mutant.original_node
  mutated = mutant.mutated_node
  return false unless binary_send?(original) && binary_send?(mutated)
  return false unless same_receiver?(original, mutated)

  additive_equivalent?(original, mutated) ||
    multiplicative_equivalent?(original, mutated)
end

#multiplicative_equivalent?(original, mutated) ⇒ Boolean

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Boolean)


53
54
55
56
57
58
# File 'lib/henitai/equivalence_detector.rb', line 53

def multiplicative_equivalent?(original, mutated)
  multiplicative_operator?(original.children[1]) &&
    multiplicative_operator?(mutated.children[1]) &&
    one_operand?(original) &&
    one_operand?(mutated)
end

#multiplicative_operator?(operator) ⇒ Boolean

Parameters:

  • (Object)

Returns:

  • (Boolean)


119
120
121
# File 'lib/henitai/equivalence_detector.rb', line 119

def multiplicative_operator?(operator)
  %i[* / **].include?(operator)
end

#numeric_operand?(node, value) ⇒ Boolean

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Boolean)


131
132
133
134
135
136
137
138
139
140
141
# File 'lib/henitai/equivalence_detector.rb', line 131

def numeric_operand?(node, value)
  operand = node.children[2]
  return false unless operand.is_a?(Parser::AST::Node)

  case operand.type
  when :int, :float
    operand.children.first == value || operand.children.first == value.to_i
  else
    false
  end
end

#one_operand?(node) ⇒ Boolean

Parameters:

  • (Object)

Returns:

  • (Boolean)


127
128
129
# File 'lib/henitai/equivalence_detector.rb', line 127

def one_operand?(node)
  numeric_operand?(node, 1)
end

#same_node?(left, right) ⇒ Boolean

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Boolean)


252
253
254
# File 'lib/henitai/equivalence_detector.rb', line 252

def same_node?(left, right)
  left == right
end

#same_receiver?(original, mutated) ⇒ Boolean

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Boolean)


42
43
44
# File 'lib/henitai/equivalence_detector.rb', line 42

def same_receiver?(original, mutated)
  same_node?(original.children[0], mutated.children[0])
end

#zero_operand?(node) ⇒ Boolean

Parameters:

  • (Object)

Returns:

  • (Boolean)


123
124
125
# File 'lib/henitai/equivalence_detector.rb', line 123

def zero_operand?(node)
  numeric_operand?(node, 0)
end