cuke_sniffer 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,35 +1,22 @@
1
- module CukeSniffer
2
- module Constants
3
- FILE_IGNORE_LIST = %w(. .. .svn)
4
- DATE_REGEX = /(?<date>\d{2}\/\d{2}\/\d{4})/
5
- COMMENT_REGEX = /#?.*/
6
-
7
- FEATURE_NAME_REGEX = /Feature:\s*(?<name>.*)/
8
- TAG_REGEX = /(?<tag>@\S*)/
9
- SCENARIO_TITLE_STYLES = /(?<type>Background|Scenario|Scenario Outline|Scenario Template):\s*/
10
- SCENARIO_TITLE_REGEX = /#{COMMENT_REGEX}#{SCENARIO_TITLE_STYLES}(?<name>.*)/
11
-
12
- STEP_STYLES = /(?<style>Given|When|Then|And|Or|But|Transform|\*)\s/
13
- STEP_REGEX = /^#{COMMENT_REGEX}#{STEP_STYLES}(?<step_string>.*)/
14
- STEP_DEFINITION_REGEX = /^#{STEP_STYLES}\/(?<step>.+)\/\sdo\s?(\|(?<parameters>.*)\|)?$/
15
-
16
- SIMPLE_NESTED_STEP_REGEX = /steps\s"#{STEP_STYLES}(?<step_string>.*)"/
17
- SAME_LINE_COMPLEX_STEP_REGEX = /^steps\s%Q?{#{STEP_STYLES}(?<step_string>.*)}/
18
- START_COMPLEX_STEP_REGEX = /steps\s%Q?\{\s*/
19
- END_COMPLEX_STEP_REGEX = /}/
20
- START_COMPLEX_WITH_STEP_REGEX = /steps\s%Q?\{#{STEP_STYLES}(?<step_string>.*)/
21
- END_COMPLEX_WITH_STEP_REGEX = /#{STEP_STYLES}(?<step_string>.*)}/
22
-
23
- HELP_CMD_TEXT = "Welcome to CukeSniffer!
24
- Calling CukeSniffer with no arguments will run it against the current directory.
25
- Other Options for Running include:
26
- <feature_file_path>, <step_def_file_path> : Runs CukeSniffer against the
27
- specified paths.
28
- -o, --out html (name) : Runs CukeSniffer then outputs an
29
- html file in the current
30
- directory (with optional name).
31
- -h, --help : You get this lovely document."
32
-
33
-
34
- end
35
- end
1
+ module CukeSniffer
2
+ module Constants
3
+ FILE_IGNORE_LIST = %w(. .. .svn)
4
+ DATE_REGEX = /(?<date>\d{2}\/\d{2}\/\d{4})/
5
+ COMMENT_REGEX = /#?\s*/
6
+
7
+ TAG_REGEX = /(?<tag>@\S*)/
8
+
9
+ SCENARIO_TITLE_STYLES = /(?<type>Background|Scenario|Scenario Outline|Scenario Template):\s*/
10
+
11
+ STEP_STYLES = /(?<style>Given|When|Then|And|Or|But|Transform|\*)\s/
12
+ STEP_REGEX = /^#{COMMENT_REGEX}#{STEP_STYLES}(?<step_string>.*)/
13
+ STEP_DEFINITION_REGEX = /^#{STEP_STYLES}\/(?<step>.+)\/\sdo\s?(\|(?<parameters>.*)\|)?$/
14
+
15
+ THRESHOLDS = {
16
+ "Project" => 1000,
17
+ "Feature" => 30,
18
+ "Scenario" => 30,
19
+ "StepDefinition" => 20
20
+ }
21
+ end
22
+ end
@@ -1,116 +1,107 @@
1
- require 'cuke_sniffer/constants'
2
- require 'cuke_sniffer/rule_config'
3
- require 'cuke_sniffer/feature_rules_evaluator'
4
- require 'cuke_sniffer/scenario'
5
-
6
- module CukeSniffer
7
- class Feature < FeatureRulesEvaluator
8
- include CukeSniffer::Constants
9
- include CukeSniffer::RuleConfig
10
-
11
- attr_accessor :background, :scenarios, :feature_rules_hash
12
-
13
- def initialize(file_name)
14
- super(file_name)
15
- @scenarios = []
16
- @feature_rules_hash = {}
17
- split_feature(file_name)
18
- evaluate_score
19
- end
20
-
21
- def split_feature(file_name)
22
- feature_lines = []
23
-
24
- feature_file = File.open(file_name)
25
- feature_file.each_line { |line| feature_lines << line }
26
- feature_file.close
27
-
28
- index = 0
29
- until feature_lines[index].match FEATURE_NAME_REGEX
30
- update_tag_list(feature_lines[index])
31
- index += 1
32
- end
33
-
34
- until index >= feature_lines.length or feature_lines[index].match TAG_REGEX or feature_lines[index].match SCENARIO_TITLE_REGEX
35
- create_name(feature_lines[index], "Feature:")
36
- index += 1
37
- end
38
-
39
- scenario_title_found = false
40
- index_of_title = nil
41
- code_block = []
42
- until index >= feature_lines.length
43
- if scenario_title_found and (feature_lines[index].match TAG_REGEX or feature_lines[index].match SCENARIO_TITLE_REGEX)
44
- add_scenario_to_feature(code_block, index_of_title)
45
- scenario_title_found = false
46
- code_block = []
47
- end
48
- code_block << feature_lines[index].strip
49
- if feature_lines[index].match SCENARIO_TITLE_REGEX
50
- scenario_title_found = true
51
- index_of_title = "#{file_name}:#{index + 1}"
52
- end
53
- index += 1
54
- end
55
- #TODO - Last scenario falling through above logic, needs a fix (code_block related)
56
- add_scenario_to_feature(code_block, index_of_title) unless code_block==[]
57
- end
58
-
59
- def add_scenario_to_feature(code_block, index_of_title)
60
- scenario = CukeSniffer::Scenario.new(index_of_title, code_block)
61
- if scenario.type == "Background"
62
- @background = scenario
63
- else
64
- @scenarios << scenario
65
- end
66
- end
67
-
68
- def ==(comparison_object)
69
- super(comparison_object)
70
- comparison_object.scenarios == scenarios
71
- end
72
-
73
- def evaluate_score
74
- super
75
- rule_no_scenarios
76
- rule_too_many_scenarios
77
- rule_background_with_no_scenarios
78
- rule_background_with_one_scenario
79
- @feature_rules_hash = @rules_hash.clone
80
- include_sub_scores(@background) unless @background.nil?
81
- include_scenario_scores
82
- end
83
-
84
- def include_sub_scores(sub_class)
85
- @score += sub_class.score
86
- sub_class.rules_hash.each_key do |rule_descriptor|
87
- rules_hash[rule_descriptor] ||= 0
88
- rules_hash[rule_descriptor] += sub_class.rules_hash[rule_descriptor]
89
- end
90
- end
91
-
92
- def include_scenario_scores
93
- scenarios.each do |scenario|
94
- include_sub_scores(scenario)
95
- end
96
- end
97
-
98
- def rule_no_scenarios
99
- store_rule(FEATURE_RULES[:no_scenarios]) if @scenarios.empty?
100
- end
101
-
102
- def rule_too_many_scenarios
103
- rule = FEATURE_RULES[:too_many_scenarios]
104
- store_rule(rule) if @scenarios.size >= rule[:max]
105
- end
106
-
107
- def rule_background_with_no_scenarios
108
- store_rule( FEATURE_RULES[:background_with_no_scenarios]) if @scenarios.empty? and !@background.nil?
109
- end
110
-
111
- def rule_background_with_one_scenario
112
- store_rule(FEATURE_RULES[:background_with_one_scenario]) if @scenarios.size == 1 and !@background.nil?
113
- end
114
-
115
- end
116
- end
1
+ module CukeSniffer
2
+ class Feature < FeatureRulesEvaluator
3
+ include CukeSniffer::Constants
4
+ include CukeSniffer::RuleConfig
5
+
6
+ SCENARIO_TITLE_REGEX = /#{COMMENT_REGEX}#{SCENARIO_TITLE_STYLES}(?<name>.*)/
7
+
8
+ attr_accessor :background, :scenarios, :scenarios_score, :total_score
9
+
10
+ def initialize(file_name)
11
+ super(file_name)
12
+ @scenarios = []
13
+ @feature_rules_hash = {}
14
+ @scenarios_score = 0
15
+ @total_score = 0
16
+ split_feature(file_name)
17
+ evaluate_score
18
+ end
19
+
20
+ def split_feature(file_name)
21
+ feature_lines = []
22
+
23
+ feature_file = File.open(file_name)
24
+ feature_file.each_line { |line| feature_lines << line }
25
+ feature_file.close
26
+
27
+ index = 0
28
+ until feature_lines[index].match /Feature:\s*(?<name>.*)/
29
+ update_tag_list(feature_lines[index])
30
+ index += 1
31
+ end
32
+
33
+ until index >= feature_lines.length or feature_lines[index].match TAG_REGEX or feature_lines[index].match SCENARIO_TITLE_REGEX
34
+ create_name(feature_lines[index], "Feature:")
35
+ index += 1
36
+ end
37
+
38
+ scenario_title_found = false
39
+ index_of_title = nil
40
+ code_block = []
41
+ until index >= feature_lines.length
42
+ if scenario_title_found and (feature_lines[index].match TAG_REGEX or feature_lines[index].match SCENARIO_TITLE_REGEX)
43
+ add_scenario_to_feature(code_block, index_of_title)
44
+ scenario_title_found = false
45
+ code_block = []
46
+ end
47
+ code_block << feature_lines[index].strip
48
+ if feature_lines[index].match SCENARIO_TITLE_REGEX
49
+ scenario_title_found = true
50
+ index_of_title = "#{file_name}:#{index + 1}"
51
+ end
52
+ index += 1
53
+ end
54
+ #TODO - Last scenario falling through above logic, needs a fix (code_block related)
55
+ add_scenario_to_feature(code_block, index_of_title) unless code_block==[]
56
+ end
57
+
58
+ def add_scenario_to_feature(code_block, index_of_title)
59
+ scenario = CukeSniffer::Scenario.new(index_of_title, code_block)
60
+ if scenario.type == "Background"
61
+ @background = scenario
62
+ else
63
+ @scenarios << scenario
64
+ end
65
+ end
66
+
67
+ def ==(comparison_object)
68
+ super(comparison_object)
69
+ comparison_object.scenarios == scenarios
70
+ end
71
+
72
+ def evaluate_score
73
+ super
74
+ rule_no_scenarios
75
+ rule_too_many_scenarios
76
+ rule_background_with_no_scenarios
77
+ rule_background_with_one_scenario
78
+ get_scenarios_score
79
+ @total_score = score + @scenarios_score
80
+ end
81
+
82
+ def get_scenarios_score
83
+ @scenarios_score += @background.score unless @background.nil?
84
+ @scenarios.each do |scenario|
85
+ @scenarios_score += scenario.score
86
+ end
87
+ end
88
+
89
+ def rule_no_scenarios
90
+ store_rule(FEATURE_RULES[:no_scenarios]) if @scenarios.empty?
91
+ end
92
+
93
+ def rule_too_many_scenarios
94
+ rule = FEATURE_RULES[:too_many_scenarios]
95
+ store_rule(rule) if @scenarios.size >= rule[:max]
96
+ end
97
+
98
+ def rule_background_with_no_scenarios
99
+ store_rule( FEATURE_RULES[:background_with_no_scenarios]) if @scenarios.empty? and !@background.nil?
100
+ end
101
+
102
+ def rule_background_with_one_scenario
103
+ store_rule(FEATURE_RULES[:background_with_one_scenario]) if @scenarios.size == 1 and !@background.nil?
104
+ end
105
+
106
+ end
107
+ end
@@ -1,311 +1,386 @@
1
- <script>
2
- function toggle(item, off) {
3
- updateDisplayStatus(item.getElementsByTagName("div")[off]);
4
- }
5
- function toggleById(item, link) {
6
- updateDisplayStatus(document.getElementById(item));
7
- toggleText(link)
8
- }
9
- function updateDisplayStatus(object) {
10
- object.style.display = (object.style.display == "block") ? 'none' : "block";
11
- }
12
- function toggleText(link) {
13
- var char_result = link.innerHTML.indexOf("+") > -1 ? "-" : "+";
14
- link.innerHTML = link.innerHTML.replace(/(\+|\-)/, char_result)
15
- }
16
-
17
- </script>
18
- <style>
19
- body {
20
- font-size: 12pt;
21
- font-family: arial;
22
- }
23
-
24
- .padded {
25
- padding-left: 3%;
26
- }
27
-
28
- .sections {
29
- border: 2px solid #90ee90;
30
- }
31
-
32
- .shrink_section {
33
- display: none;
34
- }
35
-
36
- .sub_title {
37
- font-weight: bold;
38
- font-size: 13pt;
39
- padding: 1%;
40
- }
41
-
42
- .scenarios, .steps, {
43
- border-top: 1px solid #bbb;
44
- padding: 4px;
45
- padding-left: 90px;
46
- }
47
-
48
- .scenarios, .steps {
49
- border-top: 1px solid #bbb;
50
- padding: 4px;
51
- padding-left: 90px;
52
- }
53
-
54
- .title {
55
- padding-left: 2%;
56
- width: 25%;
57
- background-color: green;
58
- color: white;
59
- border-top: 0;
60
- border-bottom: 0;
61
- padding-top: 4px;
62
- font-weight: bold;
63
- font-size: 15pt;
64
- padding-bottom: 1%;
65
- }
66
-
67
- .rule {
68
- background-color: #ffaaaa;
69
- padding: 3px;
70
- font-size: 13px;
71
- }
72
-
73
- span {
74
- font-size: 20pt;
75
- font-weight: bold;
76
- width: 100%;
77
- border-left: 2px solid #fff;
78
- padding-bottom: 3px;
79
- padding-left: 30px;
80
- padding-top: 4px
81
- }
82
-
83
- .even {
84
- background-color: #eeeeff;
85
- border-bottom: 1px solid #ccc;
86
- }
87
-
88
- .odd {
89
- border-bottom: 1px solid #ddd;
90
- }
91
- </style>
92
- <div style="float:left; color: green; font-weight: bold; padding-left:10px;">
93
- Cuke Sniffer
94
- </div>
95
- <br style="clear:both">
96
- <div style="border-top: 2px solid lightgreen;">
97
- <div style="float:right;border-right: 2px solid lightgreen;">
98
- <div style="background-color:green;border-right:2px solid #fff; color:white;padding:4px; padding-left:40px;font-size:11pt;font-weight:bold;padding-right:10px;">
99
- <%= summary[:total_score] %> Total Score
100
- </div>
101
- </div>
102
- </div>
103
- <br style="clear:both">
104
- <div style="float:left;" class="title">
105
- <a href=#summary style="color: white;font-style: normal;">
106
- <span style="border-left-color:green;cursor: hand;" onclick="toggleById('summary',this)">- Summary</span>
107
- </a>
108
- </div>
109
- <br style="clear:both">
110
-
111
- <div class="sections">
112
- <div name="summary" class="shrink_section" id="summary" style="display:block">
113
- <%
114
- feature_results = cuke_sniffer.summary[:features]
115
- step_definition_results = cuke_sniffer.summary[:step_definitions]
116
- %>
117
- <br>
118
-
119
- <div><span class="sub_title">Features</span><br></div>
120
- <div class="padded">Min: <%= feature_results[:min] %> (<%= feature_results[:min_file] %>)<br>
121
- Max: <%= feature_results[:max] %> (<%= feature_results[:max_file] %>)<br>
122
- Average: <%= feature_results[:average] %>
123
- </div>
124
- <br>
125
-
126
- <div><span class="sub_title">Step Definitions</span><br></div>
127
- <div class="padded">Min: <%= step_definition_results[:min] %> (<%= step_definition_results[:min_file] %>)<br>
128
- Max: <%= step_definition_results[:max] %> (<%= step_definition_results[:max_file] %>)<br>
129
- Average: <%= step_definition_results[:average] %> </div>
130
- <br>
131
-
132
- <% list = summary[:improvement_list] %>
133
- <div><span class="sub_title">Improvements to make: <%= list.size %></span><br></div>
134
- <div class="padded">
135
- <% list.each_key do |improvement| %>
136
- (<%= list[improvement] %>) <%= improvement %>
137
- <br>
138
- <% end %>
139
- <br>
140
- </div>
141
- <% dead_steps_list = cuke_sniffer.get_dead_steps %>
142
- <div><span class="sub_title">Dead Steps: <%= dead_steps_list.size %></span><br></div>
143
- <div class="padded">
144
- <% dead_steps_list.each do |dead_step| %>
145
- <table>
146
- <tr>
147
- <td style="width:300px">
148
- /<%= dead_step.regex.to_s.match(/\(\?\-mix\:(?<regex>.*)\)/)[:regex] %>/
149
- </td>
150
- <td style="width:600px">
151
- <%= dead_step.location %>
152
- </td>
153
- </tr>
154
- </table>
155
- <% end %>
156
- <br>
157
- </div>
158
- </div>
159
- </div>
160
- <br><br>
161
- <div style="float:left;" class="title">
162
- <a href=#feature_details style="color: white;font-style: normal;">
163
- <span style="border-left-color:green;cursor: hand;" onclick="toggleById('feature_details',this)">+ Features</span>
164
- </a>
165
- </div>
166
- <div class="links" style="float:right"></div>
167
- <br style="clear:both">
168
- <div class="sections">
169
- <div name="feature_details" class="shrink_section" id="feature_details">
170
- <% i=0 %>
171
- <% cuke_sniffer.features.each do |feature| %>
172
- <% next if feature.score == 0 %>
173
- <div style="cursor: hand;" onclick="toggle(this,3)" class="feature <%= i%2==0 ? "even" : "odd" %>">
174
- <div style="float:left;padding:4px;font-weight:bold;color:red; width:3%"><%= feature.score %></div>
175
-
176
- <div style=" float:left;">
177
- <font class="featurename"><%= feature.location[feature.location.rindex("/")..-1] %></font></div>
178
- <div style="width:60%;padding:4px; float:right">
179
- <font class="featurepath"><%= feature.location[0..feature.location.rindex("/")] %></font></div>
180
- <br style="clear:both;">
181
-
182
- <div class="scenarios" style="display:none;">
183
-
184
- <table>
185
- <tr>
186
- <td style="width: 600px;vertical-align:top;">
187
- <b style="text-indent:5px">Feature: <%= feature.name %></b>
188
- <br>
189
- <b style="text-indent:5px">Scenarios: <%= feature.scenarios.size %></b>
190
- </td>
191
- <td style="width: 600px;vertical-align:top;">
192
- <% unless feature.feature_rules_hash.empty? %>
193
- <b>Feature Improvements:</b>
194
-
195
- <div style="padding: 1%">
196
- <% feature.feature_rules_hash.each_key do |rule| %>
197
- <%= rule %>
198
- <br>
199
- <% end %>
200
- </div>
201
- <% end %>
202
- </td>
203
- </tr>
204
- </table>
205
- <br>
206
- <% feature.scenarios = [feature.background, feature.scenarios].flatten unless feature.background.nil? %>
207
- <table style="border-bottom:2px solid lightgreen">
208
- <% feature.scenarios.each do |scenario| %>
209
- <% next if scenario.rules_hash.empty? %>
210
- <tr>
211
- <td style="border-top:2px solid lightblue;width: 600px;vertical-align:top;">
212
- <b style="padding:1%;"><%= scenario.type %>: <%= scenario.name %></b>
213
- <br>
214
- <% scenario.steps.each do |step| %>
215
- <div style="text-indent:15px">
216
- <%= step %>
217
- </div>
218
- <% end %>
219
- <br>
220
- </td>
221
- <td style="border-top:2px solid lightblue;width: 600px;vertical-align:top;">
222
- <b>Score: <%= scenario.score %></b>
223
- <br>
224
- <%= scenario.location %>
225
- <br>
226
- <b>Scenario Improvements:</b>
227
- <br>
228
- <% scenario.rules_hash.each_key do |rule| %>
229
- <div style="text-indent:15px">
230
- <%= rule %>
231
- </div>
232
- <% end %>
233
- </td>
234
- </tr>
235
- <% end %>
236
- </table>
237
- </div>
238
- </div>
239
- <% i+=1 %>
240
- <% end %>
241
- </div>
242
- </div>
243
- <br><br>
244
- <div style="float:left;" class="title">
245
- <a href=#step_definitions style="color: white;font-style: normal;">
246
- <span style="border-left-color:green;cursor: hand;" onclick="toggleById('step_definitions',this)">+ Step Definitions</span>
247
- </a>
248
- </div>
249
- <div class="links" style="float:right"></div>
250
- <br style="clear:both">
251
- <div class="sections">
252
- <div name="step_definitions" class="shrink_section" id="step_definitions">
253
- <% i=0 %>
254
- <% cuke_sniffer.step_definitions.each do |step_definition| %>
255
- <div style="cursor: hand;" onclick="toggle(this,4)" class="feature <%= i%2==0 ? "even" : "odd" %>">
256
- <% next if step_definition.score <= 0 and !step_definition.calls.empty? %>
257
- <div style="float:left;padding:4px;font-weight:bold;color:red;"><%= step_definition.score %></div>
258
- <div style="width:55%;padding:4px; float:left;">
259
-
260
- <% parameters = "" %>
261
- <% step_definition.parameters.each do |param| %>
262
- <% if param == step_definition.parameters.first %>
263
- <% parameters << "| " %>
264
- <% end %>
265
- <% parameters << param %>
266
-
267
- <% if param == step_definition.parameters.last %>
268
- <% parameters << " |" %>
269
- <% else %>
270
- <% parameters << ", " %>
271
- <% end %>
272
- <% end %>
273
- <font class="featurename"><%= "/" + step_definition.regex.to_s.match(/\(\?\-mix\:(?<regex>.*)\)/)[:regex] + "/ do " + parameters %></font>
274
- </div>
275
- <% if step_definition.calls.empty? %>
276
- <div style="float:left; width:10%;padding:4px;"><span class="rule"><b>Dead step!</b></span></div>
277
- <% else %>
278
- <div style="float:left; width:10%;padding:4px;">&nbsp;</div>
279
- <% end %>
280
- <div style="width:30%;padding:4px; float:left;">
281
- <font class="featurepath"><%= step_definition.location[step_definition.location.rindex("/")..-1] %></font>
282
- </div>
283
- <br style="clear:both;">
284
-
285
- <div class="steps" style="display:none;">
286
- <table>
287
- <tr>
288
- <td style="width: 600px;vertical-align:top;">
289
- <b>Calls: <%= step_definition.calls.size %></b>
290
- <% step_definition.calls.each_key do |call| %>
291
- <div style="text-indent: 15px;"><%= step_definition.calls[call] %></div>
292
- <div style="text-indent: 30px;"><%= call %></div>
293
- <% end %>
294
- </td>
295
- <td style="width: 600px;vertical-align:top;">
296
- <b>Step Definition improvements:</b>
297
- <br>
298
- <% step_definition.rules_hash.each_key do |improvement| %>
299
- <div style="text-indent: 15px;">
300
- (<%= step_definition.rules_hash[improvement] %>) <%= improvement %>
301
- </div>
302
- <% end %>
303
- </td>
304
- </tr>
305
- </table>
306
- </div>
307
- </div>
308
- <% i+=1 %>
309
- <% end %>
310
- </div>
1
+ <script>
2
+ function toggle(item, off) {
3
+ updateDisplayStatus(item.getElementsByTagName("div")[off]);
4
+ }
5
+ function toggleById(item, link) {
6
+ updateDisplayStatus(document.getElementById(item));
7
+ toggleText(link)
8
+ }
9
+ function updateDisplayStatus(object) {
10
+ object.style.display = (object.style.display == "block") ? 'none' : "block";
11
+ }
12
+ function toggleText(link) {
13
+ var char_result = link.innerHTML.indexOf("+") > -1 ? "-" : "+";
14
+ link.innerHTML = link.innerHTML.replace(/(\+|\-)/, char_result)
15
+ }
16
+
17
+ </script>
18
+ <style>
19
+ body {
20
+ font-size: 12pt;
21
+ font-family: arial;
22
+ }
23
+
24
+ .sections {
25
+ border: 2px solid #90ee90;
26
+ }
27
+
28
+ .shrink_section {
29
+ display: none;
30
+ }
31
+
32
+ .scenarios, .steps, {
33
+ border-top: 1px solid #bbb;
34
+ padding: 4px;
35
+ padding-left: 90px;
36
+ }
37
+
38
+ .scenarios, .steps {
39
+ border-top: 1px solid #bbb;
40
+ padding: 4px;
41
+ padding-left: 90px;
42
+ }
43
+
44
+ .title {
45
+ padding-left: 2%;
46
+ width: 25%;
47
+ background-color: green;
48
+ color: white;
49
+ border-top: 0;
50
+ border-bottom: 0;
51
+ padding-top: 4px;
52
+ font-weight: bold;
53
+ font-size: 15pt;
54
+ padding-bottom: 1%;
55
+ }
56
+
57
+ .rule {
58
+ background-color: #ffaaaa;
59
+ padding: 3px;
60
+ font-size: 13px;
61
+ }
62
+
63
+ .summary_col {
64
+ width: 20%;
65
+ font-size: 14pt;
66
+ }
67
+
68
+ .major_summary_col {
69
+ width: 20%;
70
+ font-size: 14pt;
71
+ padding: 0%;
72
+ border-bottom: solid lightgreen 3px;
73
+ padding-bottom: 3%;
74
+ }
75
+
76
+ span {
77
+ font-size: 20pt;
78
+ font-weight: bold;
79
+ width: 100%;
80
+ border-left: 2px solid #fff;
81
+ padding-bottom: 3px;
82
+ padding-left: 30px;
83
+ padding-top: 4px
84
+ }
85
+
86
+ </style>
87
+ <div style="float:left; color: green; font-weight: bold; padding-left:10px;">
88
+ Cuke Sniffer
89
+ </div>
90
+ <br style="clear:both">
91
+ <div style="border-top: 2px solid lightgreen;">
92
+ <div style="float:right;border-right: 2px solid lightgreen;">
93
+ <div style="background-color:green;border-right:2px solid #fff; color:white;padding:4px; padding-left:40px;font-size:11pt;font-weight:bold;padding-right:10px;">
94
+ <%= summary[:total_score] %> Total Score
95
+ </div>
96
+ </div>
97
+ </div>
98
+ <br style="clear:both">
99
+ <div style="float:left;" class="title">
100
+ <a href=#summary style="color: white;font-style: normal;">
101
+ <span style="border-left-color:green;cursor: hand;" onclick="toggleById('summary',this)">- Summary</span>
102
+ </a>
103
+ </div>
104
+ <br style="clear:both">
105
+
106
+ <div class="sections">
107
+ <div name="summary" class="shrink_section" id="summary" style="display:block">
108
+ <%
109
+ feature_results = cuke_sniffer.summary[:features]
110
+ scenario_results = cuke_sniffer.summary[:scenarios]
111
+ step_definition_results = cuke_sniffer.summary[:step_definitions]
112
+ %>
113
+ <br>
114
+ <table style="padding-left: 3%;">
115
+ <tr>
116
+ <td class="major_summary_col"></td>
117
+ <td class="major_summary_col">Features</td>
118
+ <td class="major_summary_col">Scenarios</td>
119
+ <td class="major_summary_col">Step Definitions</td>
120
+ </tr>
121
+ <tr>
122
+ <td class="summary_col">Total Score</td>
123
+ <td class="summary_col"><%= feature_results[:total_score] %></td>
124
+ <td class="summary_col"><%= scenario_results[:total_score] %></td>
125
+ <td class="summary_col"><%= step_definition_results[:total_score] %></td>
126
+ </tr>
127
+ <tr>
128
+ <td class="major_summary_col">Count</td>
129
+ <td class="major_summary_col"><%= cuke_sniffer.features.count %></td>
130
+ <td class="major_summary_col"><%= cuke_sniffer.scenarios.count %></td>
131
+ <td class="major_summary_col"><%= cuke_sniffer.step_definitions.count %></td>
132
+ </tr>
133
+ <tr>
134
+ <td class="summary_col">Lowest Score</td>
135
+ <td class="summary_col"><%= feature_results[:min] %></td>
136
+ <td class="summary_col"><%= scenario_results[:min] %></td>
137
+ <td class="summary_col"><%= step_definition_results[:min] %></td>
138
+ </tr>
139
+ <tr>
140
+ <td class="summary_col">Highest Score</td>
141
+ <td class="summary_col"><%= feature_results[:max] %></td>
142
+ <td class="summary_col"><%= scenario_results[:max] %></td>
143
+ <td class="summary_col"><%= step_definition_results[:max] %></td>
144
+ </tr>
145
+ <tr>
146
+ <td class="major_summary_col">Average Score</td>
147
+ <td class="major_summary_col"><%= feature_results[:average] %></td>
148
+ <td class="major_summary_col"><%= scenario_results[:average] %></td>
149
+ <td class="major_summary_col"><%= step_definition_results[:average] %></td>
150
+ </tr>
151
+ <tr>
152
+ <td class="summary_col">Threshold</td>
153
+ <td class="summary_col"><%= feature_results[:threshold] %></td>
154
+ <td class="summary_col"><%= scenario_results[:threshold] %></td>
155
+ <td class="summary_col"><%= step_definition_results[:threshold] %></td>
156
+ </tr>
157
+ <tr>
158
+ <td class="summary_col">Good</td>
159
+ <td class="summary_col"><%= (feature_results[:good].to_f/feature_results[:total].to_f*100).round(2) %>%</td>
160
+ <td class="summary_col"><%= (scenario_results[:good].to_f/scenario_results[:total].to_f*100).round(2) %>%</td>
161
+ <td class="summary_col"><%= (step_definition_results[:good].to_f/step_definition_results[:total].to_f*100).round(2) %>
162
+ %
163
+ </td>
164
+ </tr>
165
+ <tr>
166
+ <td class="summary_col">Bad</td>
167
+ <td class="summary_col"><%= (feature_results[:bad].to_f/feature_results[:total].to_f*100).round(2) %>%</td>
168
+ <td class="summary_col"><%= (scenario_results[:bad].to_f/scenario_results[:total].to_f*100).round(2) %>%</td>
169
+ <td class="summary_col"><%= (step_definition_results[:bad].to_f/step_definition_results[:total].to_f*100).round(2) %>
170
+ %
171
+ </td>
172
+ </tr>
173
+ </table>
174
+ </div>
175
+ <br><br>
176
+
177
+ <div style="float:left;" class="title">
178
+ <a href=#improvement_list style="color: white;font-style: normal;">
179
+ <span style="border-left-color:green;cursor: hand;" onclick="toggleById('improvement_list',this)">+ Improvement List</span>
180
+ </a>
181
+ </div>
182
+ <div class="links" style="float:right"></div>
183
+ <br style="clear:both">
184
+
185
+ <div class="sections">
186
+ <div name="improvement_list" class="shrink_section" id="improvement_list">
187
+ <div style="padding-left:3%;font:bold;font-size:14pt;">Types of
188
+ improvements: <%= cuke_sniffer.summary[:improvement_list].keys.count %></div>
189
+ <table style="padding-left: 5%;font-size:14pt;">
190
+ <% cuke_sniffer.summary[:improvement_list].each do |improvement, count| %>
191
+ <tr>
192
+ <td style="width: 20px"><%= count %></td>
193
+ <td style="width: 400px"><%= improvement %></td>
194
+ </tr>
195
+ <% end %>
196
+ </table>
197
+ <br>
198
+ </div>
199
+ </div>
200
+ <br><br>
201
+
202
+ <div style="float:left;" class="title">
203
+ <a href=#dead_steps style="color: white;font-style: normal;">
204
+ <span style="border-left-color:green;cursor: hand;" onclick="toggleById('dead_steps',this)">+ Dead Steps</span>
205
+ </a>
206
+ </div>
207
+ <div class="links" style="float:right"></div>
208
+ <br style="clear:both">
209
+
210
+ <div class="sections">
211
+ <div name="dead_steps" class="shrink_section" id="dead_steps">
212
+ <div style="font:bold;padding-left:3%;font:bold;font-size:14pt;">Total Dead
213
+ Steps: <%= cuke_sniffer.get_dead_steps.count %></div>
214
+ <% cuke_sniffer.get_dead_steps.each do |dead_step| %>
215
+ <div style="font:14pt;padding-left:5%;padding-bottom: 1%;">
216
+ <div><%= "/" + dead_step.regex.to_s.match(/\(\?\-mix\:(?<regex>.*)\)/)[:regex] + "/" %></div>
217
+ <div style="padding-left:1%"><%= dead_step.location %></div>
218
+ </div>
219
+ <% end %>
220
+ </div>
221
+ </div>
222
+ <br><br>
223
+
224
+
225
+ <div style="float:left;" class="title">
226
+ <a href=#feature_details style="color: white;font-style: normal;">
227
+ <span style="border-left-color:green;cursor: hand;" onclick="toggleById('feature_details',this)">+ Features</span>
228
+ </a>
229
+ </div>
230
+ <div class="links" style="float:right"></div>
231
+ <br style="clear:both">
232
+
233
+ <div class="sections">
234
+ <div name="feature_details" class="shrink_section" id="feature_details">
235
+ <% i=0 %>
236
+ <% cuke_sniffer.features.each do |feature| %>
237
+ <% next if feature.score == 0 and feature.scenarios_score == 0 %>
238
+ <div style="cursor: hand;" onclick="toggle(this,3)" class="feature <%= i%2==0 ? "even" : "odd" %>">
239
+ <div style="float:left;padding:4px;font-weight:bold;color:red; width:3%"><%= feature.score + feature.scenarios_score %></div>
240
+
241
+ <div style=" float:left;">
242
+ <font class="featurename"><%= feature.name %></font></div>
243
+ <div style="width:60%;padding:4px; float:right">
244
+ <font class="featurepath"></font></div>
245
+ <br style="clear:both;">
246
+
247
+ <div class="scenarios" style="display:none;">
248
+ <b style="text-indent:5px"><%= feature.location.gsub(cuke_sniffer.features_location, "") %></b>
249
+ <table>
250
+ <tr>
251
+ <td style="width: 600px;vertical-align:top;">
252
+ <b style="text-indent:5px">Scenarios: <%= feature.scenarios.size %></b>
253
+ </td>
254
+ <td style="width: 600px;vertical-align:top;">
255
+ <b style="text-indent:5px">Score: <%= feature.score %></b>
256
+ <br>
257
+ <% unless feature.rules_hash.empty? %>
258
+ <b>Feature Improvements:</b>
259
+
260
+ <div style="padding: 1%">
261
+ <% feature.rules_hash.each_key do |rule| %>
262
+ <%= rule %>
263
+ <br>
264
+ <% end %>
265
+ </div>
266
+ <% end %>
267
+ </td>
268
+ </tr>
269
+ </table>
270
+ <br>
271
+ <% feature.scenarios = [feature.background, feature.scenarios].flatten unless feature.background.nil? %>
272
+ <table style="border-bottom:2px solid lightgreen">
273
+ <% feature.scenarios.each do |scenario| %>
274
+ <% next if scenario.rules_hash.empty? %>
275
+ <tr>
276
+ <td style="border-top:2px solid lightblue;width: 600px;vertical-align:top;">
277
+ <b style="padding:1%;"><%= scenario.type %>: <%= scenario.name %></b>
278
+ <br>
279
+ <% scenario.steps.each do |step| %>
280
+ <div style="text-indent:15px">
281
+ <%= step %>
282
+ </div>
283
+ <% end %>
284
+ <br>
285
+ </td>
286
+ <td style="border-top:2px solid lightblue;width: 600px;vertical-align:top;">
287
+ <b>Score: <%= scenario.score %></b>
288
+ <br>
289
+ <b>Line: <%= scenario.start_line %></b>
290
+ <br>
291
+ <b>Scenario Improvements:</b>
292
+ <br>
293
+ <% scenario.rules_hash.each_key do |rule| %>
294
+ <div style="text-indent:15px">
295
+ <%= rule %>
296
+ </div>
297
+ <% end %>
298
+ </td>
299
+ </tr>
300
+ <% end %>
301
+ </table>
302
+ </div>
303
+ </div>
304
+ <% i+=1 %>
305
+ <% end %>
306
+ </div>
307
+ </div>
308
+ <br><br>
309
+
310
+ <div style="float:left;" class="title">
311
+ <a href=#step_definitions style="color: white;font-style: normal;">
312
+ <span style="border-left-color:green;cursor: hand;" onclick="toggleById('step_definitions',this)">+ Step Definitions</span>
313
+ </a>
314
+ </div>
315
+ <div class="links" style="float:right"></div>
316
+ <br style="clear:both">
317
+
318
+ <div class="sections">
319
+ <div name="step_definitions" class="shrink_section" id="step_definitions">
320
+ <% i=0 %>
321
+ <% cuke_sniffer.step_definitions.each do |step_definition| %>
322
+ <div style="cursor: hand;" onclick="toggle(this,4)" class="feature <%= i%2==0 ? "even" : "odd" %>">
323
+ <% next if step_definition.score <= 0 and !step_definition.calls.empty? %>
324
+ <div style="float:left;padding:4px;font-weight:bold;color:red;"><%= step_definition.score %></div>
325
+ <div style="width:55%;padding:4px; float:left;">
326
+
327
+ <% parameters = "" %>
328
+ <% step_definition.parameters.each do |param| %>
329
+ <% if param == step_definition.parameters.first %>
330
+ <% parameters << "| " %>
331
+ <% end %>
332
+ <% parameters << param %>
333
+
334
+ <% if param == step_definition.parameters.last %>
335
+ <% parameters << " |" %>
336
+ <% else %>
337
+ <% parameters << ", " %>
338
+ <% end %>
339
+ <% end %>
340
+ <font class="featurename"><%= "/" + step_definition.regex.to_s.match(/\(\?\-mix\:(?<regex>.*)\)/)[:regex] + "/ do " + parameters %></font>
341
+ </div>
342
+ <% if step_definition.calls.empty? %>
343
+ <div style="float:left; width:10%;padding:4px;"><span class="rule"><b>Dead step!</b></span></div>
344
+ <% else %>
345
+ <div style="float:left; width:10%;padding:4px;">Calls: <%= step_definition.calls.size %></div>
346
+ <% end %>
347
+ <div style="width:30%;padding:4px; float:left;">
348
+
349
+ </div>
350
+ <br style="clear:both;">
351
+
352
+ <div class="steps" style="display:none;">
353
+ <b class="featurepath"><%= step_definition.location.gsub(cuke_sniffer.step_definitions_location, "") %></b>
354
+ <br>
355
+ <table>
356
+ <tr>
357
+ <td style="width: 600px;vertical-align:top;">
358
+ <% unless step_definition.parameters.empty? %>
359
+ <% calls = step_definition.condensed_call_list %>
360
+ <% calls.each_key do |step_string| %>
361
+ <div style="text-indent: 15px;"><%= step_string %></div>
362
+ <% calls[step_string].each do |call| %>
363
+ <div style="text-indent: 30px;"><%= call %></div>
364
+ <% end %>
365
+ <br>
366
+ <% end %>
367
+ <% end %>
368
+ </td>
369
+ <td style="width: 600px;vertical-align:top;">
370
+ <b>Step Definition improvements:</b>
371
+ <br>
372
+ <% step_definition.rules_hash.each_key do |improvement| %>
373
+ <div style="text-indent: 15px;">
374
+ (<%= step_definition.rules_hash[improvement] %>) <%= improvement %>
375
+ </div>
376
+ <% end %>
377
+ </td>
378
+ </tr>
379
+ </table>
380
+ </div>
381
+ </div>
382
+ <% i+=1 %>
383
+ <% end %>
384
+ </div>
385
+ </div>
311
386
  </div>