cuke_sniffer 0.0.8 → 1.0.0

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,96 +1,131 @@
1
- <div class="title" onclick="toggleById('summary_data', this)">
2
- Summary -
3
- </div>
4
- <div class="shrink_section" style="display: block;" id="summary_data">
5
- <% data_symbols = [:features, :scenarios, :step_definitions, :hooks] %>
6
- <table style="padding-left:2px; width: 100%;" class="notes" border="0" cellspacing="0">
7
- <tr class="divide_row">
8
- <td class="table_top"></td>
9
- <td class="table_top">Features</td>
10
- <td class="table_top">Scenarios</td>
11
- <td class="table_top">Step Definitions</td>
12
- <td class="table_top">Hooks</td>
13
- </tr>
14
- <tr class="blue_row">
15
- <td>
16
- Total Score
17
- <a title="Total Points for a section." class="help">(?)</a>
18
- </td>
19
- <% data_symbols.each do |symbol| %>
20
- <td>
21
- <%= cuke_sniffer.summary[symbol][:total_score] %>
22
- </td>
23
- <% end %>
24
- </tr>
25
- <tr>
26
- <td>
27
- Count
28
- <a title="Total Number of objects found in the project." class="help" class="help">(?)</a>
29
- </td>
30
- <% data_symbols.each do |symbol| %>
31
- <td><%= cuke_sniffer.summary[symbol][:total].inspect %></td>
32
- <% end %>
33
- </tr>
34
- <tr/>
35
- <tr class="blue_row">
36
- <td>
37
- Lowest Score
38
- <a title="Score of the best object found." class="help">(?)</a>
39
- </td>
40
- <% data_symbols.each do |symbol| %>
41
- <td><%= cuke_sniffer.summary[symbol][:min] %></td>
42
- <% end %>
43
- </tr>
44
- <tr>
45
- <td>
46
- Highest Score
47
- <a title="Score of the object with the most to improve on." class="help">(?)</a>
48
- </td>
49
- <% data_symbols.each do |symbol| %>
50
- <td><%= cuke_sniffer.summary[symbol][:max] %></td>
51
- <% end %>
52
- </tr>
53
- <tr class="blue_row">
54
- <td>
55
- Average Score
56
- <a title="Average score of a section." class="help">(?)</a>
57
- </td>
58
- <% data_symbols.each do |symbol| %>
59
- <td><%= cuke_sniffer.summary[symbol][:average] %></td>
60
- <% end %>
61
- </tr>
62
- <tr/>
63
- <tr>
64
- <td>
65
- Threshold
66
- <a title="The maximum score an object can have to be considered good." class="help">(?)</a>
67
- </td>
68
- <% data_symbols.each do |symbol| %>
69
- <td><%= cuke_sniffer.summary[symbol][:threshold] %></td>
70
- <% end %>
71
- </tr>
72
- <tr class="blue_row">
73
- <td>
74
- Good
75
- <a title="Percentage of the objects that can be considered good in the project." class="help">(?)</a>
76
- </td>
77
- <% data_symbols.each do |symbol| %>
78
- <td><%= ((cuke_sniffer.summary[symbol][:good].to_f/cuke_sniffer.summary[symbol][:total].to_f) * 100).round(2) %>
79
- %
80
- </td>
81
- <% end %>
82
- </tr>
83
- <tr>
84
- <td>
85
- Bad
86
- <a title="Percentage of the objects that can be considered bad in the project." class="help">(?)</a>
87
- </td>
88
- <% data_symbols.each do |symbol| %>
89
- <td><%= ((cuke_sniffer.summary[symbol][:bad].to_f/cuke_sniffer.summary[symbol][:total].to_f) * 100).round(2) %>
90
- %
91
- </td>
92
- <% end %>
93
- </tr>
94
- </table>
95
- </div>
96
- <br style="clear:both">
1
+ <div class="row">
2
+ <div id="summaryPanel" class="panel panel-default">
3
+ <div class="panel-heading panel-title" data-toggle="collapse" data-target="#summaryTable">
4
+ Summary <span class="glyphicon glyphicon-menu-up"></span>
5
+ </div>
6
+ <% data_symbols = [:features, :scenarios, :step_definitions, :hooks] %>
7
+ <table id="summaryTable" class="table table-responsive table-striped collapse in">
8
+ <tr>
9
+ <td></td>
10
+ <td>
11
+ <span class="full-page">Features</span>
12
+ <span class="small-page" title="Features">F</span>
13
+ </td>
14
+ <td>
15
+ <span class="full-page">Scenarios</span>
16
+ <span class="small-page" title="Scenarios">S</span>
17
+ </td>
18
+ <td>
19
+ <span class="full-page">Step Definitions</span>
20
+ <span class="small-page" title="Step Definitions">S.D.</span>
21
+ </td>
22
+ <td>
23
+ <span class="full-page">Hooks</span>
24
+ <span class="small-page" title="Hooks">H</span>
25
+ </td>
26
+ </tr>
27
+ <tr>
28
+ <td>
29
+ Total Score
30
+ <span title="Total Points for a section." class="glyphicon glyphicon-question-sign"
31
+ data-toggle="tooltip" data-placement="right"></span>
32
+ </td>
33
+ <% data_symbols.each do |symbol| %>
34
+ <td>
35
+ <%= cuke_sniffer.summary[symbol][:total_score] %>
36
+ </td>
37
+ <% end %>
38
+ </tr>
39
+ <tr>
40
+ <td>
41
+ Count
42
+ <span title="Total Number of objects found in the project." class="glyphicon glyphicon-question-sign"
43
+ data-toggle="tooltip" data-placement="right"></span>
44
+ </td>
45
+ <% data_symbols.each do |symbol| %>
46
+ <td><%= cuke_sniffer.summary[symbol][:total].inspect %></td>
47
+ <% end %>
48
+ </tr>
49
+ <tr>
50
+ <td>
51
+ Lowest Score
52
+ <span title="Score of the best object found." class="glyphicon glyphicon-question-sign"
53
+ data-toggle="tooltip" data-placement="right"></span>
54
+ </td>
55
+ <% data_symbols.each do |symbol| %>
56
+ <td><%= cuke_sniffer.summary[symbol][:min] %></td>
57
+ <% end %>
58
+ </tr>
59
+ <tr>
60
+ <td>
61
+ Highest Score
62
+ <span title="Score of the object with the most to improve on." class="glyphicon glyphicon-question-sign"
63
+ data-toggle="tooltip" data-placement="right"></span>
64
+ </td>
65
+ <% data_symbols.each do |symbol| %>
66
+ <td><%= cuke_sniffer.summary[symbol][:max] %></td>
67
+ <% end %>
68
+ </tr>
69
+ <tr>
70
+ <td>
71
+ Average Score
72
+ <span title="Average score of a section." class="glyphicon glyphicon-question-sign"
73
+ data-toggle="tooltip" data-placement="right"></span>
74
+ </td>
75
+ <% data_symbols.each do |symbol| %>
76
+ <td>
77
+ <% if cuke_sniffer.summary[symbol][:average].nan?%>
78
+ 0
79
+ <% else %>
80
+ <%= cuke_sniffer.summary[symbol][:average] %>
81
+ <% end %>
82
+ </td>
83
+ <% end %>
84
+ </tr>
85
+ <tr>
86
+ <td>
87
+ Threshold
88
+ <span title="The maximum score an object can have to be considered good." class="glyphicon glyphicon-question-sign"
89
+ data-toggle="tooltip" data-placement="right"></span>
90
+ </td>
91
+ <% data_symbols.each do |symbol| %>
92
+ <td><%= cuke_sniffer.summary[symbol][:threshold] %></td>
93
+ <% end %>
94
+ </tr>
95
+ <tr>
96
+ <td>
97
+ Good
98
+ <span title="Percentage of the objects that can be considered good in the project."
99
+ class="glyphicon glyphicon-question-sign" data-toggle="tooltip" data-placement="right"></span>
100
+ </td>
101
+ <% data_symbols.each do |symbol| %>
102
+ <td>
103
+ <% if cuke_sniffer.summary[symbol][:good] == 0 %>
104
+ 0
105
+ <% else %>
106
+ <%= ((cuke_sniffer.summary[symbol][:good].to_f/cuke_sniffer.summary[symbol][:total].to_f) * 100).round(2) %>
107
+ <% end %>
108
+ %
109
+ </td>
110
+ <% end %>
111
+ </tr>
112
+ <tr>
113
+ <td>
114
+ Bad
115
+ <span title="Percentage of the objects that can be considered bad in the project."
116
+ class="glyphicon glyphicon-question-sign" data-toggle="tooltip" data-placement="right"></span>
117
+ </td>
118
+ <% data_symbols.each do |symbol| %>
119
+ <td>
120
+ <% if cuke_sniffer.summary[symbol][:bad] == 0 %>
121
+ 0
122
+ <% else %>
123
+ <%= ((cuke_sniffer.summary[symbol][:bad].to_f/cuke_sniffer.summary[symbol][:total].to_f) * 100).round(2) %>
124
+ <% end %>
125
+ %
126
+ </td>
127
+ <% end %>
128
+ </tr>
129
+ </table>
130
+ </div>
131
+ </div>
@@ -1,9 +1,13 @@
1
- <div style="font-family: Arial; float: left; color: #509f50; font-size: 20px; font-weight: bold; padding-bottom: 1px;">
2
- Cuke Sniffer
3
- </div>
4
- <br style="clear:both">
5
- <div style="border-top: 2px solid #509f50; text-align: right;">
6
- <div style="font-family: Arial;border-bottom-left-radius: 15px; border-bottom-right-radius: 15px;float: right; background-color:#509f50; color:white;padding-left:40px;font-size:11pt;font-weight:bold;padding-right:10px;">
7
- Score: <%= cuke_sniffer.summary[:total_score] %></div>
8
- </div>
9
- <br style="clear:both">
1
+ <div class="row">
2
+ <div class="page-header">
3
+ <h1>
4
+ Cuke Sniffer <a class="black" target="_blank" href="https://github.com/r-cochran/cuke_sniffer"><span class="fa fa-github"></span></a>
5
+ <% if Gem.loaded_specs["cuke_sniffer"] %>
6
+ <small><%= Gem.loaded_specs["cuke_sniffer"].version %></small>
7
+ <% end %>
8
+ </h1>
9
+ <div>Score:
10
+ <span class="score"><%= cuke_sniffer.summary[:total_score] %></span>
11
+ </div>
12
+ </div>
13
+ </div>
@@ -7,6 +7,7 @@ module CukeSniffer
7
7
  # Mixins: ROXML
8
8
  class Rule
9
9
  include ROXML
10
+ xml_accessor :symbol
10
11
  xml_accessor :enabled
11
12
  xml_accessor :phrase
12
13
  xml_accessor :score
@@ -275,12 +275,12 @@ module CukeSniffer
275
275
  },
276
276
  :feature_same_tag => {
277
277
  :enabled => true,
278
- :phrase => "Same tag appears on Feature.",
278
+ :phrase => "Same tag appears on both Feature and Scenario",
279
279
  :score => WARNING,
280
280
  :targets => ["Feature"],
281
281
  :reason => lambda { |feature, rule| if(feature.scenarios.count >= 2)
282
282
  feature.scenarios[1..-1].each do |scenario|
283
- feature.scenarios.first.tags.each do |tag|
283
+ feature.tags.each do |tag|
284
284
  feature.store_rule(rule) if scenario.tags.include?(tag)
285
285
  end
286
286
  end
@@ -29,8 +29,7 @@ module CukeSniffer
29
29
  judge_object(feature, "Feature")
30
30
  judge_object(feature.background, "Background") unless feature.background.nil?
31
31
  judge_objects(feature.scenarios, "Scenario")
32
- feature.total_score += feature.update_score
33
-
32
+ feature.update_score
34
33
  end
35
34
 
36
35
  def judge_objects(objects, type)
@@ -83,41 +83,85 @@ module CukeSniffer
83
83
  private
84
84
 
85
85
  def split_scenario(scenario)
86
+ ranges = define_ranges(scenario)
87
+ split_tag_list(ranges[:tags])
88
+ split_name_and_type(ranges[:name].join(" "))
89
+ split_scenario_body(ranges[:body])
90
+ split_examples(ranges[:examples]) unless ranges[:examples].nil?
91
+ end
92
+
93
+ def define_ranges(scenario)
94
+ ranges = {}
86
95
  index = 0
87
- until index >= scenario.length or scenario[index] =~ SCENARIO_TITLE_STYLES
88
- update_tag_list(scenario[index])
89
- index += 1
96
+ index += 1 until index >= scenario.length or scenario[index] =~ SCENARIO_TITLE_STYLES
97
+ ranges[:tags] = scenario[0...index]
98
+
99
+ start_index = index
100
+ index += 1 until index >= scenario.length or scenario[index].match STEP_REGEX or scenario[index].include?("Examples:")
101
+ ranges[:name] = scenario[start_index...index]
102
+
103
+ start_index = index
104
+ index += 1 until index >= scenario.length or scenario[index].include?("Examples:")
105
+ ranges[:body] = scenario[start_index...index]
106
+
107
+ ranges[:examples] = scenario[index + 1..scenario.size] if index < scenario.length and scenario[index].include?("Examples:")
108
+ ranges
109
+ end
110
+
111
+ def split_tag_list(list_of_tag_lines)
112
+ list_of_tag_lines.each do |line|
113
+ update_tag_list(line)
90
114
  end
115
+ end
91
116
 
92
- until index >= scenario.length or scenario[index].match STEP_REGEX or scenario[index].include?("Examples:")
93
- match = scenario[index].match(SCENARIO_TITLE_STYLES)
94
- @type = match[:type] unless match.nil?
95
- create_name(scenario[index], SCENARIO_TITLE_STYLES)
96
- index += 1
117
+ def split_name_and_type(name_section)
118
+ match = name_section.match(SCENARIO_TITLE_STYLES)
119
+ @type = match[:type] unless match.nil?
120
+ create_name(name_section, SCENARIO_TITLE_STYLES)
121
+ end
122
+
123
+ def split_scenario_body(scenario_body)
124
+ extract_steps(scenario_body)
125
+ extract_inline_tables(scenario_body)
126
+ end
127
+
128
+ def extract_steps(scenario_body)
129
+ scenario_body.each do |line|
130
+ next if line =~ /^\|.*\|/ or line.empty? or line.match(STEP_REGEX).nil?
131
+ @steps << line
97
132
  end
133
+ end
98
134
 
99
- until index >= scenario.length or scenario[index].include?("Examples:")
100
- if scenario[index] =~ /^\|.*\|/
101
- step = scenario[index - 1]
102
- @inline_tables[step] = []
103
- until index >= scenario.length or scenario[index] =~ /(#{STEP_REGEX}|^\s*Examples:)/
104
- @inline_tables[step] << scenario[index]
135
+ def extract_inline_tables(scenario_body)
136
+ index = 0
137
+ while index < scenario_body.size
138
+ if scenario_body[index] =~ /^\|.*\|/
139
+ start_index = index
140
+ while index < scenario_body.size and scenario_body[index] =~ /^\|.*\|/
105
141
  index += 1
106
142
  end
107
- else
108
- @steps << scenario[index] if scenario[index] =~ STEP_REGEX
109
- index += 1
143
+ @inline_tables[scenario_body[start_index-1]] = scenario_body[start_index..index]
110
144
  end
145
+ index += 1
111
146
  end
147
+ end
112
148
 
113
- if index < scenario.length and scenario[index].include?("Examples:")
149
+ def split_examples(examples_section)
150
+ remove_examples_declaration(examples_section).each do |line|
151
+ next if line.include?("Examples:")
152
+ @examples_table << line if line =~ /#{COMMENT_REGEX}\|.*\|/
153
+ end
154
+ end
155
+
156
+ def remove_examples_declaration(examples_section)
157
+ return_section = []
158
+ index = 0
159
+ while index < examples_section.size
160
+ index += 2 if(examples_section[index].include?("Examples:"))
161
+ return_section << examples_section[index]
114
162
  index += 1
115
- until index >= scenario.length
116
- index += 2 if scenario[index].include?("Examples:")
117
- @examples_table << scenario[index] if scenario[index] =~ /#{COMMENT_REGEX}\|.*\|/
118
- index += 1
119
- end
120
163
  end
164
+ return_section
121
165
  end
122
166
  end
123
167
  end
@@ -1,91 +1,91 @@
1
- module CukeSniffer
2
- # Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
3
- # Copyright:: Copyright (C) 2014 Robert Cochran
4
- # License:: Distributes under the MIT License
5
- # Mixins: CukeSniffer::Constants
6
- # A static class used to help with handling summary data for CukeSniffer::CLI
7
- class SummaryHelper
8
- include CukeSniffer::Constants
9
-
10
- # Sorts the list of improvements in descending order of times found.
11
- def self.sort_improvement_list(improvement_list)
12
- sorted_array = improvement_list.sort_by { |improvement, occurrence| occurrence }.reverse
13
- sorted_improvement_list = {}
14
- sorted_array.each { |node|
15
- sorted_improvement_list[node[0]] = node[1]
16
- }
17
- sorted_improvement_list
18
- end
19
-
20
- # Builds a default assessment hash.
21
- def self.make_assessment_hash
22
- {
23
- :total => 0,
24
- :total_score => 0,
25
- :min => nil,
26
- :min_file => nil,
27
- :max => nil,
28
- :max_file => nil,
29
- :average => 0,
30
- :threshold => nil,
31
- :good => 0,
32
- :bad => 0,
33
- :improvement_list => {}
34
- }
35
- end
36
-
37
- # Initializes an assessment hash for the rule target list
38
- def self.initialize_assessment_hash(rule_target_list, type)
39
- assessment_hash = make_assessment_hash
40
- assessment_hash[:total] = rule_target_list.count
41
- assessment_hash[:threshold] = THRESHOLDS[type]
42
-
43
- unless rule_target_list.empty?
44
- score = rule_target_list.first.score
45
- location = rule_target_list.first.location
46
- assessment_hash[:min] = score
47
- assessment_hash[:min_file] = location
48
- assessment_hash[:max] = score
49
- assessment_hash[:max_file] = location
50
- end
51
- assessment_hash
52
- end
53
-
54
- # Returns a summary hash for the rule_target_list
55
- def self.assess_rule_target_list(rule_target_list, type)
56
- assessment_hash = initialize_assessment_hash(rule_target_list, type)
57
- rule_target_list.each do |rule_target|
58
- score = rule_target.score
59
- assessment_hash[:total_score] += score
60
- assessment_hash[rule_target.good? ? :good : :bad] += 1
61
- if score < assessment_hash[:min]
62
- assessment_hash[:min] = score
63
- assessment_hash[:min_file] = rule_target.location
64
- end
65
- if score > assessment_hash[:max]
66
- assessment_hash[:max] = score
67
- assessment_hash[:max_file] = rule_target.location
68
- end
69
- rule_target.rules_hash.each_key do |key|
70
- assessment_hash[:improvement_list][key] ||= 0
71
- assessment_hash[:improvement_list][key] += rule_target.rules_hash[key]
72
- end
73
- end
74
- assessment_hash[:average] = (assessment_hash[:total_score].to_f/rule_target_list.count.to_f).round(2)
75
- assessment_hash
76
- end
77
-
78
- # Returns a CukeSniffer::SummaryNode object for the passed hash
79
- def self.load_summary_data(summary_hash)
80
- summary_node = SummaryNode.new
81
- summary_node.count = summary_hash[:total]
82
- summary_node.score = summary_hash[:total_score]
83
- summary_node.average = summary_hash[:average]
84
- summary_node.threshold = summary_hash[:threshold]
85
- summary_node.good = summary_hash[:good]
86
- summary_node.bad = summary_hash[:bad]
87
- summary_node
88
- end
89
-
90
- end
1
+ module CukeSniffer
2
+ # Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
3
+ # Copyright:: Copyright (C) 2014 Robert Cochran
4
+ # License:: Distributes under the MIT License
5
+ # Mixins: CukeSniffer::Constants
6
+ # A static class used to help with handling summary data for CukeSniffer::CLI
7
+ class SummaryHelper
8
+ include CukeSniffer::Constants
9
+
10
+ # Sorts the list of improvements in descending order of times found.
11
+ def self.sort_improvement_list(improvement_list)
12
+ sorted_array = improvement_list.sort_by { |improvement, occurrence| occurrence }.reverse
13
+ sorted_improvement_list = {}
14
+ sorted_array.each { |node|
15
+ sorted_improvement_list[node[0]] = node[1]
16
+ }
17
+ sorted_improvement_list
18
+ end
19
+
20
+ # Builds a default assessment hash.
21
+ def self.make_assessment_hash
22
+ {
23
+ :total => 0,
24
+ :total_score => 0,
25
+ :min => nil,
26
+ :min_file => nil,
27
+ :max => nil,
28
+ :max_file => nil,
29
+ :average => 0,
30
+ :threshold => nil,
31
+ :good => 0,
32
+ :bad => 0,
33
+ :improvement_list => {}
34
+ }
35
+ end
36
+
37
+ # Initializes an assessment hash for the rule target list
38
+ def self.initialize_assessment_hash(rule_target_list, type)
39
+ assessment_hash = make_assessment_hash
40
+ assessment_hash[:total] = rule_target_list.count
41
+ assessment_hash[:threshold] = THRESHOLDS[type]
42
+
43
+ unless rule_target_list.empty?
44
+ score = rule_target_list.first.score
45
+ location = rule_target_list.first.location
46
+ assessment_hash[:min] = score
47
+ assessment_hash[:min_file] = location
48
+ assessment_hash[:max] = score
49
+ assessment_hash[:max_file] = location
50
+ end
51
+ assessment_hash
52
+ end
53
+
54
+ # Returns a summary hash for the rule_target_list
55
+ def self.assess_rule_target_list(rule_target_list, type)
56
+ assessment_hash = initialize_assessment_hash(rule_target_list, type)
57
+ rule_target_list.each do |rule_target|
58
+ score = rule_target.score
59
+ assessment_hash[:total_score] += score
60
+ assessment_hash[rule_target.good? ? :good : :bad] += 1
61
+ if score < assessment_hash[:min]
62
+ assessment_hash[:min] = score
63
+ assessment_hash[:min_file] = rule_target.location
64
+ end
65
+ if score > assessment_hash[:max]
66
+ assessment_hash[:max] = score
67
+ assessment_hash[:max_file] = rule_target.location
68
+ end
69
+ rule_target.rules_hash.each_key do |key|
70
+ assessment_hash[:improvement_list][key] ||= 0
71
+ assessment_hash[:improvement_list][key] += rule_target.rules_hash[key]
72
+ end
73
+ end
74
+ assessment_hash[:average] = (assessment_hash[:total_score].to_f/rule_target_list.count.to_f).round(2)
75
+ assessment_hash
76
+ end
77
+
78
+ # Returns a CukeSniffer::SummaryNode object for the passed hash
79
+ def self.load_summary_data(summary_hash)
80
+ summary_node = SummaryNode.new
81
+ summary_node.count = summary_hash[:total]
82
+ summary_node.score = summary_hash[:total_score]
83
+ summary_node.average = summary_hash[:average]
84
+ summary_node.threshold = summary_hash[:threshold]
85
+ summary_node.good = summary_hash[:good]
86
+ summary_node.bad = summary_hash[:bad]
87
+ summary_node
88
+ end
89
+
90
+ end
91
91
  end