cuke_sniffer 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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>