Class: CucumberCharacteristics::ProfileData

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

Constant Summary collapse

STATUS_ORDER =
{passed: 0, failed: 2000, skipped: 1000, undefined: 500}
STATUS =
STATUS_ORDER.keys

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(runtime, features) ⇒ ProfileData

Returns a new instance of ProfileData.



14
15
16
17
18
# File 'lib/cucumber_characteristics/profile_data.rb', line 14

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

Instance Attribute Details

#durationObject (readonly)

Returns the value of attribute duration.



8
9
10
# File 'lib/cucumber_characteristics/profile_data.rb', line 8

def duration
  @duration
end

Instance Method Details

#ambiguous?(step) ⇒ Boolean

Returns:

  • (Boolean)


102
103
104
# File 'lib/cucumber_characteristics/profile_data.rb', line 102

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

#ambiguous_countObject



20
21
22
# File 'lib/cucumber_characteristics/profile_data.rb', line 20

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

#feature_profilesObject



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/cucumber_characteristics/profile_data.rb', line 36

def feature_profiles
  feature_profiles = { }
  @runtime.scenarios.each do |f|
    if f.is_a?(Cucumber::Ast::OutlineTable::ExampleRow)
      feature_id = f.scenario_outline.file_colon_line
      feature_profiles[feature_id] ||= {name: f.scenario_outline.name, total_duration: 0, step_count: 0, example_count: 0, examples: {} }
      example_id = f.name
      feature_profiles[feature_id][:examples][example_id] ||= {total_duration: 0, step_count: 0}
      feature_profiles[feature_id][:examples][example_id][:total_duration] = f.step_invocations.select{|s| s.status == :passed}.map{|s| s.step_match.duration}.inject(&:+)
      feature_profiles[feature_id][:examples][example_id][:step_count] = f.step_invocations.count
      feature_profiles[feature_id][:examples][example_id][:status] = f.status
    else
      feature_id = f.file_colon_line
      feature_profiles[feature_id] = {name: f.name, total_duration: 0, step_count: 0}
      feature_profiles[feature_id][:total_duration] = f.steps.select{|s| s.status == :passed}.map{|s| s.step_match.duration}.inject(&:+)
      feature_profiles[feature_id][:step_count] = f.steps.count
      feature_profiles[feature_id][:status] = f.status
    end
  end
  with_feature_calculations(feature_profiles)
end

#has_unmatched_steps?Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/cucumber_characteristics/profile_data.rb', line 32

def has_unmatched_steps?
  unmatched_steps.count > 0
end

#nonstep_durationObject



140
141
142
# File 'lib/cucumber_characteristics/profile_data.rb', line 140

def nonstep_duration
  duration - step_duration
end

#scenario_count_by_statusObject



157
158
159
160
161
162
163
164
# File 'lib/cucumber_characteristics/profile_data.rb', line 157

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



153
154
155
# File 'lib/cucumber_characteristics/profile_data.rb', line 153

def step_count(status)
  step_count_by_status[status]
end

#step_count_by_statusObject



144
145
146
147
148
149
150
151
# File 'lib/cucumber_characteristics/profile_data.rb', line 144

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

#step_durationObject



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

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(:+)
end

#step_profilesObject



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/cucumber_characteristics/profile_data.rb', line 79

def step_profiles
  step_profiles = {}
  @runtime.steps.each do |s|
    unless 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] ||= []
      if 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
    end
  end
  with_step_calculations(step_profiles)
end

#unmatched_stepsObject



24
25
26
27
28
29
30
# File 'lib/cucumber_characteristics/profile_data.rb', line 24

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

#with_feature_calculations(feature_profiles) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/cucumber_characteristics/profile_data.rb', line 58

def with_feature_calculations(feature_profiles)
  feature_profiles.each do |feature, meta|
    if meta[:examples]
      feature_profiles[feature][:example_count] = meta[:examples].keys.count
      feature_profiles[feature][:total_duration] = meta[:examples].map{|e,m| m[:total_duration]}.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
  end
  feature_profiles.sort_by{|k, v| (STATUS_ORDER[v[:status]]||0)+(v[:total_duration] || 0)}.reverse
end

#with_step_calculations(step_profiles) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/cucumber_characteristics/profile_data.rb', line 106

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