Module: RSpec::Risky::Evaluation

Defined in:
lib/rspec/risky/evaluation.rb,
sig/rspec/risky.rbs

Class Method Summary collapse

Class Method Details

.assertion_density(dynamic_payload) ⇒ Hash[Symbol, untyped]

Parameters:

  • dynamic_payload (Hash[String, untyped])

Returns:

  • (Hash[Symbol, untyped])


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/rspec/risky/evaluation.rb', line 22

def assertion_density(dynamic_payload)
  counts = dynamic_payload.fetch("examples", []).map do |example|
    example.fetch("expectation_count", 0) +
      example.fetch("mock_expectation_count", 0) +
      example.fetch("custom_expectation_count", 0)
  end
  return {} if counts.empty?

  sorted = counts.sort
  {
    average: counts.sum.fdiv(counts.length),
    max: sorted.last,
    min: sorted.first,
    p50: percentile(sorted, 0.50),
    p90: percentile(sorted, 0.90)
  }
end

.compare(static_findings:, dynamic_payload:) ⇒ Hash[Symbol, untyped]

Parameters:

  • static_findings: (Array[untyped])
  • dynamic_payload: (Hash[String, untyped])

Returns:

  • (Hash[Symbol, untyped])


9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/rspec/risky/evaluation.rb', line 9

def compare(static_findings:, dynamic_payload:)
  static = static_findings.map { |finding| normalize_static(finding) }
  dynamic = dynamic_payload.fetch("examples", []).flat_map { |example| normalize_dynamic(example) }

  {
    dynamic_only: dynamic - static,
    dynamic_total: dynamic.length,
    overlap: dynamic & static,
    static_only: static - dynamic,
    static_total: static.length
  }
end

.label_template(dynamic_payload) ⇒ Array[Hash[Symbol, untyped]]

Parameters:

  • dynamic_payload (Hash[String, untyped])

Returns:

  • (Array[Hash[Symbol, untyped]])


40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/rspec/risky/evaluation.rb', line 40

def label_template(dynamic_payload)
  dynamic_payload.fetch("examples", []).flat_map do |example|
    example.fetch("verdicts", []).map do |verdict|
      {
        location: example.fetch("location"),
        rule: verdict.fetch("rule").to_s,
        label: nil,
        allowed_labels: %w[intentional_smoke true_missing_oracle false_positive],
        description: example["description"]
      }
    end
  end
end

.mutation_study(dynamic_payload, mutation_payload = nil) ⇒ Hash[Symbol, untyped]

Parameters:

  • dynamic_payload (Hash[String, untyped])
  • mutation_payload (Hash[String, untyped], nil) (defaults to: nil)

Returns:

  • (Hash[Symbol, untyped])


54
55
56
57
58
59
60
61
62
63
64
# File 'lib/rspec/risky/evaluation.rb', line 54

def mutation_study(dynamic_payload, mutation_payload = nil)
  density = assertion_density(dynamic_payload)
  scores = mutation_payload ? mutation_scores(dynamic_payload, mutation_payload) : []
  return { assertion_density: density, mutation_correlation: nil, mutation_samples: 0 } if scores.empty?

  {
    assertion_density: density,
    mutation_correlation: pearson(scores.map(&:first), scores.map(&:last)),
    mutation_samples: scores.length
  }
end

.precision(labels_payload) ⇒ Hash[Symbol, untyped]

Parameters:

  • labels_payload (Hash[String, untyped])

Returns:

  • (Hash[Symbol, untyped])


66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/rspec/risky/evaluation.rb', line 66

def precision(labels_payload)
  labels = labels_payload.fetch("labels", labels_payload)
  total = labels.length
  return { total: 0, precision: nil } if total.zero?

  false_positives = labels.count { |label| label.fetch("label", label[:label]) == "false_positive" }
  true_positives = total - false_positives
  {
    false_positives: false_positives,
    precision: true_positives.fdiv(total),
    total: total,
    true_positives: true_positives
  }
end