Class: CucumberCharacteristics::ProfileData

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/cucumber_characteristics/profile_data.rb

Constant Summary collapse

CUCUMBER_VERSION =
Gem::Version.new(Cucumber::VERSION)
STATUS_ORDER =
{ passed: 0, failed: 2000, skipped: 1000, undefined: 500 }.freeze
STATUS =
STATUS_ORDER.keys

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(runtime, features) ⇒ ProfileData

Returns a new instance of ProfileData.



16
17
18
19
20
# File 'lib/cucumber_characteristics/profile_data.rb', line 16

def initialize(runtime, features)
  @runtime = runtime
  @duration = features.duration
  @features = features
end

Instance Attribute Details

#durationObject (readonly)

Returns the value of attribute duration.



10
11
12
# File 'lib/cucumber_characteristics/profile_data.rb', line 10

def duration
  @duration
end

Instance Method Details

#ambiguous?(step) ⇒ Boolean

Returns:

  • (Boolean)


86
87
88
# File 'lib/cucumber_characteristics/profile_data.rb', line 86

def ambiguous?(step)
  step.status == :failed && step.step_match.step_definition.nil?
end

#ambiguous_countObject



22
23
24
# File 'lib/cucumber_characteristics/profile_data.rb', line 22

def ambiguous_count
  @runtime.steps.count { |s| ambiguous?(s) }
end

#feature_profilesObject



39
40
41
42
43
# File 'lib/cucumber_characteristics/profile_data.rb', line 39

def feature_profiles
  return @feature_profiles if @feature_profiles
  feature_profiles = @runtime.scenario_profiles
  @feature_profiles = with_feature_calculations(feature_profiles)
end

#nonstep_durationObject



124
125
126
# File 'lib/cucumber_characteristics/profile_data.rb', line 124

def nonstep_duration
  duration - step_duration
end

#scenario_count_by_statusObject



141
142
143
144
145
146
147
148
# File 'lib/cucumber_characteristics/profile_data.rb', line 141

def scenario_count_by_status
  status = {}
  @runtime.scenarios.each do |s|
    status[s.status] ||= 0
    status[s.status] += 1
  end
  status
end

#step_count(status) ⇒ Object



137
138
139
# File 'lib/cucumber_characteristics/profile_data.rb', line 137

def step_count(status)
  step_count_by_status[status]
end

#step_count_by_statusObject



128
129
130
131
132
133
134
135
# File 'lib/cucumber_characteristics/profile_data.rb', line 128

def step_count_by_status
  status = {}
  @runtime.steps.each do |s|
    status[s.status] ||= 0
    status[s.status] += 1
  end
  status
end

#step_durationObject



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/cucumber_characteristics/profile_data.rb', line 112

def step_duration
  step_duration = []
  step_profiles.each do |_step, meta|
    STATUS.each do |status|
      meta[status][:feature_location].each do |_location, timings|
        step_duration << timings
      end
    end
  end
  step_duration.flatten.compact.inject(:+) || 0
end

#step_profilesObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/cucumber_characteristics/profile_data.rb', line 65

def step_profiles
  step_profiles = {}
  @runtime.steps.each do |s|
    next if ambiguous?(s)
    step_name = s.status == :undefined ? s.name : s.step_match.step_definition.file_colon_line
    # Initialize data structure
    step_profiles[step_name] ||= { total_count: 0 }
    STATUS.each { |status| step_profiles[step_name][status] ||= { count: 0, feature_location: {} } }
    feature_location = s.file_colon_line
    step_profiles[step_name][s.status][:count] += 1
    step_profiles[step_name][:total_count] += 1
    step_profiles[step_name][s.status][:feature_location][feature_location] ||= []
    next unless s.status != :undefined
    step_profiles[step_name][:regexp] = s.step_match.step_definition.regexp_source
    if s.status == :passed
      step_profiles[step_name][s.status][:feature_location][feature_location] << s.step_match.duration
    end
  end
  with_step_calculations(step_profiles)
end

#unmatched_stepsObject



26
27
28
29
30
31
32
33
# File 'lib/cucumber_characteristics/profile_data.rb', line 26

def unmatched_steps
  unmatched = {}
  @runtime.unmatched_step_definitions.each do |u|
    location = u.file_colon_line
    unmatched[location] = u.regexp_source
  end
  unmatched.sort
end

#unmatched_steps?Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/cucumber_characteristics/profile_data.rb', line 35

def unmatched_steps?
  unmatched_steps.count > 0
end

#with_feature_calculations(feature_profiles) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/cucumber_characteristics/profile_data.rb', line 45

def with_feature_calculations(feature_profiles)
  feature_profiles.each do |feature, meta|
    next unless meta[:examples]
    feature_profiles[feature][:example_count] = meta[:examples].keys.count
    feature_profiles[feature][:total_duration] = meta[:examples].map { |_e, m| m[:total_duration] || 0 }.inject(&:+)
    feature_profiles[feature][:step_count] = meta[:examples].map { |_e, m| m[:step_count] }.inject(&:+)
    feature_profiles[feature][:examples] = feature_profiles[feature][:examples].sort_by { |_k, v| v[:total_duration] }.reverse
    feature_profiles[feature][:status] = if meta[:examples].all? { |_e, m| m[:status] == :passed }
                                           :passed
                                         elsif meta[:examples].any? { |_e, m| m[:status] == :failed }
                                           :failed
                                         elsif meta[:examples].any? { |_e, m| m[:status] == :skipped }
                                           :skipped
                                         else
                                           :unknown
                                         end
  end
  feature_profiles.sort_by { |_k, v| (STATUS_ORDER[v[:status]] || 0) + (v[:total_duration] || 0) }.reverse
end

#with_step_calculations(step_profiles) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/cucumber_characteristics/profile_data.rb', line 90

def with_step_calculations(step_profiles)
  step_profiles.each do |step, meta|
    meta.merge!(fastest: nil, slowest: nil, average: nil, total_duration: nil, standard_deviation: nil, variation: nil)
    next unless meta[:passed][:count] > 0
    timings = []
    STATUS.each do |status|
      timings << meta[status][:feature_location].values
    end
    timings = timings.flatten.compact

    step_profiles[step][:fastest] = timings.min
    step_profiles[step][:slowest] = timings.max
    step_profiles[step][:variation] = step_profiles[step][:slowest] - step_profiles[step][:fastest]
    step_profiles[step][:total_duration] = timings.inject(:+)
    step_profiles[step][:average] = step_profiles[step][:total_duration] / meta[:passed][:count]
    sum = timings.inject(0) { |accum, i| accum + (i - step_profiles[step][:average])**2 }
    step_profiles[step][:variance] = sum / timings.length.to_f
    step_profiles[step][:standard_deviation] = Math.sqrt(step_profiles[step][:variance])
  end
  step_profiles.sort_by { |_k, v| v[:total_duration] || 0 }.reverse
end