Class: Henitai::Result

Inherits:
Object
  • Object
show all
Includes:
UnparseHelper
Defined in:
lib/henitai/result.rb

Overview

Aggregates the outcome of a complete mutation testing run.

Provides metrics and the serialised Stryker mutation-testing-report-schema JSON payload. The schema version follows stryker-mutator/mutation-testing-elements.

Constant Summary collapse

SCHEMA_VERSION =
"1.0"
DEFAULT_THRESHOLDS =
{ high: 80, low: 60 }.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mutants:, started_at:, finished_at:, thresholds: nil) ⇒ Result

Returns a new instance of Result.



18
19
20
21
22
23
# File 'lib/henitai/result.rb', line 18

def initialize(mutants:, started_at:, finished_at:, thresholds: nil)
  @mutants     = mutants
  @started_at  = started_at
  @finished_at = finished_at
  @thresholds  = DEFAULT_THRESHOLDS.merge(thresholds || {})
end

Instance Attribute Details

#finished_atObject (readonly)

Returns the value of attribute finished_at.



16
17
18
# File 'lib/henitai/result.rb', line 16

def finished_at
  @finished_at
end

#mutantsObject (readonly)

Returns the value of attribute mutants.



16
17
18
# File 'lib/henitai/result.rb', line 16

def mutants
  @mutants
end

#started_atObject (readonly)

Returns the value of attribute started_at.



16
17
18
# File 'lib/henitai/result.rb', line 16

def started_at
  @started_at
end

#thresholdsObject (readonly)

Returns the value of attribute thresholds.



16
17
18
# File 'lib/henitai/result.rb', line 16

def thresholds
  @thresholds
end

Instance Method Details

#detectedInteger

Detected = killed + timeout + runtime_error (alle Zustände die einen Fehler beweisen)

Returns:

  • (Integer)


36
37
38
# File 'lib/henitai/result.rb', line 36

def detected
  mutants.count { |m| %i[killed timeout runtime_error].include?(m.status) }
end

#durationFloat

Returns duration in seconds.

Returns:

  • (Float)

    duration in seconds



84
85
86
# File 'lib/henitai/result.rb', line 84

def duration
  finished_at - started_at
end

#equivalentInteger

Returns number of confirmed equivalent mutants (excluded from MS).

Returns:

  • (Integer)

    number of confirmed equivalent mutants (excluded from MS)



32
# File 'lib/henitai/result.rb', line 32

def equivalent = mutants.count(&:equivalent?)

#killedInteger

Returns number of killed mutants.

Returns:

  • (Integer)

    number of killed mutants



26
# File 'lib/henitai/result.rb', line 26

def killed   = mutants.count(&:killed?)

#mutation_scoreFloat?

Mutation Score (MS) — Architektur-Formel aus Abschnitt 6.1:

MS = detected / (total  ignored  no_coverage  compile_error  equivalent)

Confirmed equivalent mutants werden aus BEIDEN Seiten der Gleichung entfernt: Sie sind weder im Zähler (nicht detektierbar) noch im Nenner (nicht testbar). Das ist der entscheidende Unterschied zum MSI.

Returns:

  • (Float, nil)

    0.0–100.0, nil wenn kein valider Mutant vorhanden



49
50
51
52
53
54
55
# File 'lib/henitai/result.rb', line 49

def mutation_score
  excluded = %i[ignored no_coverage compile_error equivalent]
  valid = mutants.reject { |m| excluded.include?(m.status) }
  return nil if valid.empty?

  ((detected.to_f / valid.count) * 100.0).round(2).to_f
end

#mutation_score_indicatorFloat?

Mutation Score Indicator (MSI) — naive Berechnung ohne Äquivalenz-Bereinigung:

MSI = killed / all_mutants

MSI ist immer ≤ MS. Der Unterschied kommuniziert die Äquivalenz-Unsicherheit. Beide Werte MÜSSEN im Report zusammen ausgewiesen werden (Anti-Pattern: nur MS).

Returns:

  • (Float, nil)


65
66
67
68
69
# File 'lib/henitai/result.rb', line 65

def mutation_score_indicator
  return nil if mutants.empty?

  ((killed.to_f / mutants.count) * 100.0).round(2).to_f
end

#scoring_summaryObject

Compact public summary for reporters. The uncertainty note is intentionally qualitative: equivalent mutants are a known gray area, so the terminal report should communicate that uncertainty instead of pretending to be precise.



75
76
77
78
79
80
81
# File 'lib/henitai/result.rb', line 75

def scoring_summary
  {
    mutation_score: mutation_score,
    mutation_score_indicator: mutation_score_indicator,
    equivalence_uncertainty: equivalence_uncertainty
  }
end

#survivedInteger

Returns number of survived mutants.

Returns:

  • (Integer)

    number of survived mutants



29
# File 'lib/henitai/result.rb', line 29

def survived = mutants.count(&:survived?)

#to_stryker_schemaHash

Serialise to Stryker mutation-testing-report-schema JSON (schema 1.0).

Returns:

  • (Hash)


90
91
92
93
94
95
96
# File 'lib/henitai/result.rb', line 90

def to_stryker_schema
  {
    schemaVersion: SCHEMA_VERSION,
    thresholds: thresholds,
    files: build_files_section
  }
end