Module: AbideDevUtils::XCCDF::Diff::BenchmarkPropertyDiff

Included in:
BenchmarkDiff
Defined in:
lib/abide_dev_utils/xccdf/diff/benchmark/property.rb

Overview

Diffs benchmark properties.

Constant Summary collapse

DEFAULT_PROPERTY_DIFF_OPTS =
{
  rule_properties_for_similarity: %i[title description rationale fixtext],
  rule_properties_for_confidence: %i[description rationale fixtext],
  rule_confidence_property_threshold: 0.7,
  rule_confidence_total_threshold: 0.5,
  digest_similarity_threshold: 0.75,
  digest_similarity_label_weights: {
    'title' => 4.0,
  },
  digest_similarity_only_labels: %w[title description fixtext rationale],
  digest_top_x_similarities: 10,
}.freeze

Instance Method Summary collapse

Instance Method Details

#add_other_rule_val(rule, prop, val) ⇒ Object



48
49
50
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 48

def add_other_rule_val(rule, prop, val)
  add_rule_val(rule, prop, val, container: other_rule_vals)
end

#add_rule_val(rule, prop, val, container: nil) ⇒ Object

Raises:

  • (ArgumentError)


35
36
37
38
39
40
41
42
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 35

def add_rule_val(rule, prop, val, container: nil)
  raise ArgumentError, 'container must not be nil' if container.nil?

  return unless container.dig(rule, prop).nil?

  container[rule] ||= {}
  container[rule][prop] = val
end

#add_self_rule_val(rule, prop, val) ⇒ Object



44
45
46
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 44

def add_self_rule_val(rule, prop, val)
  add_rule_val(rule, prop, val, container: self_rule_vals)
end

#find_most_similar(children, other_children) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 113

def find_most_similar(children, other_children)
  children.each_with_object({}) do |benchmark_child, h|
    maxed_similarities = maxed_digest_similarities(benchmark_child, other_children)
    next if maxed_similarities.empty?

    best = most_similar(benchmark_child, maxed_similarities)
    next if best.nil? || best.empty?

    h[benchmark_child] = best
  end
end

#max_digest_similarities(digest_similarities) ⇒ Object



75
76
77
78
79
80
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 75

def max_digest_similarities(digest_similarities)
  digest_similarities.reject! { |s| s[0] < opts[:digest_similarity_threshold] }
  return digest_similarities if digest_similarities.empty?

  digest_similarities.max_by(opts[:digest_top_x_similarities]) { |s| s[0] }
end

#maxed_digest_similarities(child, other_children) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 60

def maxed_digest_similarities(child, other_children)
  similarities = other_children.each_with_object([]) do |other_child, ary|
    if other_child.digest_equal? child
      ary << [1.0, other_child]
      next
    end

    d_sim = child.digest_similarity(other_child,
                                    only_labels: opts[:digest_similarity_only_labels],
                                    label_weights: opts[:digest_similarity_label_weights])
    ary << [d_sim, other_child]
  end
  max_digest_similarities(similarities)
end

#most_similar(child, maxed_digest_similarities) ⇒ Object



102
103
104
105
106
107
108
109
110
111
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 102

def most_similar(child, maxed_digest_similarities)
  most_similar_map = maxed_digest_similarities.each_with_object({}) do |similarity, h|
    prop_similarities = rule_property_similarity(child, similarity[1])
    if child.title.to_s == similarity[1].title.to_s
      prop_similarities[:total] = 99.0 # magic number denoting a title match
    end
    h[prop_similarities[:total]] = { self: child, other: similarity[1] }.merge(prop_similarities)
  end
  most_similar_map[most_similar_map.keys.max]
end

#other_rule_valsObject



31
32
33
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 31

def other_rule_vals
  @other_rule_vals ||= {}
end

#rule_property_similarity(rule1, rule2) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 82

def rule_property_similarity(rule1, rule2)
  prop_similarities = {}
  prop_diff = {}
  opts[:rule_properties_for_similarity].each do |prop|
    add_self_rule_val(rule1, prop, safe_rule_prop(rule1, prop).to_s)
    add_other_rule_val(rule2, prop, safe_rule_prop(rule2, prop).to_s)
    prop_similarities[prop] = self_rule_vals[rule1][prop].levenshtein_similar(other_rule_vals[rule2][prop])
    if prop_similarities[prop] < 1.0
      prop_diff[prop] = { self: self_rule_vals[rule1][prop], other: other_rule_vals[rule2][prop] }
    end
  end
  total = prop_similarities.values.sum / opts[:rule_properties_for_similarity].length
  {
    total: total,
    prop_similarities: prop_similarities,
    prop_diff: prop_diff,
    confident_same: same_rule?(prop_similarities),
  }
end

#safe_rule_prop(rule, prop) ⇒ Object



23
24
25
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 23

def safe_rule_prop(rule, prop)
  rule.respond_to?(prop) ? rule.send(prop).to_s : :none
end

#same_rule?(prop_similarities) ⇒ Boolean

Returns:

  • (Boolean)


52
53
54
55
56
57
58
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 52

def same_rule?(prop_similarities)
  confidence_indicator = 0.0
  opts[:rule_properties_for_confidence].each do |prop|
    confidence_indicator += 1.0 if prop_similarities[prop] >= opts[:rule_confidence_property_threshold]
  end
  (confidence_indicator / opts[:rule_properties_for_confidence].length) >= opts[:rule_confidence_total_threshold]
end

#self_rule_valsObject



27
28
29
# File 'lib/abide_dev_utils/xccdf/diff/benchmark/property.rb', line 27

def self_rule_vals
  @self_rule_vals ||= {}
end