Class: Henitai::Operator
- Inherits:
-
Object
- Object
- Henitai::Operator
- Defined in:
- lib/henitai/operator.rb,
sig/henitai.rbs
Overview
Base class for all mutation operators.
An Operator receives an AST node and produces zero or more Mutant objects. Operator names follow the Stryker-compatible naming convention so that the JSON report is compatible with stryker-dashboard filters and HTML reports.
Built-in operators (light set):
ArithmeticOperator, EqualityOperator, LogicalOperator, BooleanLiteral,
ConditionalExpression, StringLiteral, ReturnValue
Additional operators (full set):
ArrayDeclaration, HashLiteral, RangeLiteral, SafeNavigation,
PatternMatch, BlockStatement, MethodExpression, AssignmentExpression,
UnaryOperator, UpdateOperator, RegexMutator, MethodChainUnwrap,
EqualityIdentityOperator
Each operator subclass must implement:
- .node_types → Array<Symbol> AST node types this operator handles
- #mutate(node, subject:) → Array<Mutant>
Direct Known Subclasses
Henitai::Operators::ArithmeticOperator, Henitai::Operators::ArrayDeclaration, Henitai::Operators::AssignmentExpression, Henitai::Operators::BlockStatement, Henitai::Operators::BooleanLiteral, Henitai::Operators::ConditionalExpression, Henitai::Operators::EqualityIdentityOperator, Henitai::Operators::EqualityOperator, Henitai::Operators::HashKeyType, Henitai::Operators::HashLiteral, Henitai::Operators::LogicalOperator, Henitai::Operators::MethodChainUnwrap, Henitai::Operators::MethodExpression, Henitai::Operators::PatternMatch, Henitai::Operators::RangeLiteral, Henitai::Operators::RegexMutator, Henitai::Operators::ReturnValue, Henitai::Operators::SafeNavigation, Henitai::Operators::StringLiteral, Henitai::Operators::UnaryOperator, Henitai::Operators::UpdateOperator
Constant Summary collapse
- LIGHT_SET =
%w[ ArithmeticOperator EqualityOperator LogicalOperator BooleanLiteral ConditionalExpression StringLiteral ReturnValue ].freeze
- FULL_SET =
(LIGHT_SET + %w[ ArrayDeclaration HashLiteral MethodChainUnwrap RangeLiteral RegexMutator SafeNavigation PatternMatch BlockStatement MethodExpression AssignmentExpression UnaryOperator UpdateOperator ]).freeze
- HARD_SET =
Usually-unkillable operators on top of full: mutations whose survival rarely indicates a test gap (framework key normalization, the ==/eql?/equal? pairing). Opt in when hunting the last survivors (ADR-12).
(FULL_SET + %w[ EqualityIdentityOperator HashKeyType ]).freeze
- SETS =
{ light: LIGHT_SET, full: FULL_SET, hard: HARD_SET }.freeze
Class Method Summary collapse
-
.for_set(set) ⇒ Array<Operator>
Operator instances for the given set.
-
.node_types ⇒ Array[Symbol]
Subclasses must declare which AST node types they handle.
Instance Method Summary collapse
- #build_mutant(subject:, original_node:, mutated_node:, description:) ⇒ Mutant
- #mutate(node, subject:) ⇒ Array<Mutant>
-
#name ⇒ String
Operator name as used in the Stryker JSON schema.
- #node_location(node) ⇒ Hash[Symbol, untyped]
Class Method Details
.for_set(set) ⇒ Array<Operator>
Returns operator instances for the given set.
62 63 64 65 |
# File 'lib/henitai/operator.rb', line 62 def self.for_set(set) names = SETS.fetch(set.to_sym, LIGHT_SET) names.map { |name| Henitai::Operators.const_get(name).new } end |
.node_types ⇒ Array[Symbol]
Subclasses must declare which AST node types they handle.
68 69 70 |
# File 'lib/henitai/operator.rb', line 68 def self.node_types raise NotImplementedError, "#{name}.node_types must be defined" end |
Instance Method Details
#build_mutant(subject:, original_node:, mutated_node:, description:) ⇒ Mutant
86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/henitai/operator.rb', line 86 def build_mutant(subject:, original_node:, mutated_node:, description:) loc = node_location(original_node) Mutant.new( subject:, operator: name, nodes: { original: original_node, mutated: mutated_node }, description:, location: loc ) end |
#mutate(node, subject:) ⇒ Array<Mutant>
75 76 77 |
# File 'lib/henitai/operator.rb', line 75 def mutate(node, subject:) raise NotImplementedError, "#{self.class}#mutate must be implemented" end |
#name ⇒ String
Operator name as used in the Stryker JSON schema.
80 81 82 |
# File 'lib/henitai/operator.rb', line 80 def name self.class.name.split("::").last end |
#node_location(node) ⇒ Hash[Symbol, untyped]
100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/henitai/operator.rb', line 100 def node_location(node) exp = node.location.expression return {} unless exp { file: exp.source_buffer.name, start_line: exp.line, end_line: exp.last_line, start_col: exp.column, end_col: exp.last_column } end |