Class: Henitai::EquivalenceDetector

Inherits:
Object
  • Object
show all
Defined in:
lib/henitai/equivalence_detector.rb,
lib/henitai/equivalence_detector/operand_predicates.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.

Defined Under Namespace

Classes: OperandPredicates

Instance Method Summary collapse

Constructor Details

#initializeEquivalenceDetector

Returns a new instance of EquivalenceDetector.



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

def initialize: () -> void

Instance Method Details

#additive_equivalent?(original, mutated) ⇒ Boolean

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Boolean)


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

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)


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

def additive_operator?(operator) = operand_predicates.additive_operator?(operator)

#analyze(mutant) ⇒ Mutant

Parameters:

Returns:



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

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

  mutant.status = :equivalent
  mutant
end

#binary_send?(node) ⇒ Boolean

Parameters:

  • (Object)

Returns:

  • (Boolean)


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

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)


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

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)


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

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)


118
# File 'lib/henitai/equivalence_detector.rb', line 118

def multiplicative_operator?(operator) = operand_predicates.multiplicative_operator?(operator)

#numeric_operand?Boolean

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Boolean)


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

def numeric_operand?: (untyped, untyped) -> bool

#one_operand?(node) ⇒ Boolean

Parameters:

  • (Object)

Returns:

  • (Boolean)


122
# File 'lib/henitai/equivalence_detector.rb', line 122

def one_operand?(node) = operand_predicates.one_operand?(node)

#same_node?(left, right) ⇒ Boolean

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Boolean)


235
236
237
# File 'lib/henitai/equivalence_detector.rb', line 235

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

#same_receiver?(original, mutated) ⇒ Boolean

Parameters:

  • (Object)
  • (Object)

Returns:

  • (Boolean)


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

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

#zero_operand?(node) ⇒ Boolean

Parameters:

  • (Object)

Returns:

  • (Boolean)


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

def zero_operand?(node) = operand_predicates.zero_operand?(node)