cuke_sniffer 0.0.5 → 0.0.6
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.
- data/bin/cuke_sniffer +85 -63
- data/lib/cuke_sniffer.rb +23 -16
- data/lib/cuke_sniffer/cli.rb +269 -523
- data/lib/cuke_sniffer/constants.rb +5 -2
- data/lib/cuke_sniffer/cuke_sniffer_helper.rb +165 -0
- data/lib/cuke_sniffer/dead_steps_helper.rb +54 -0
- data/lib/cuke_sniffer/feature.rb +13 -81
- data/lib/cuke_sniffer/feature_rules_evaluator.rb +56 -115
- data/lib/cuke_sniffer/formatter.rb +142 -0
- data/lib/cuke_sniffer/hook.rb +77 -160
- data/lib/cuke_sniffer/report/dead_steps.html.erb +36 -0
- data/lib/cuke_sniffer/report/features.html.erb +60 -0
- data/lib/cuke_sniffer/report/hooks.html.erb +49 -0
- data/lib/cuke_sniffer/report/improvement_list.html.erb +18 -0
- data/lib/cuke_sniffer/report/legend.html.erb +167 -0
- data/lib/cuke_sniffer/report/min_template.html.erb +125 -0
- data/lib/cuke_sniffer/report/rules.html.erb +9 -0
- data/lib/cuke_sniffer/report/standard_template.html.erb +137 -0
- data/lib/cuke_sniffer/report/step_definitions.html.erb +49 -0
- data/lib/cuke_sniffer/report/sub_rules.html.erb +24 -0
- data/lib/cuke_sniffer/report/summary.html.erb +71 -0
- data/lib/cuke_sniffer/rule.rb +28 -0
- data/lib/cuke_sniffer/rule_config.rb +241 -48
- data/lib/cuke_sniffer/rule_target.rb +62 -0
- data/lib/cuke_sniffer/rules_evaluator.rb +65 -70
- data/lib/cuke_sniffer/scenario.rb +102 -238
- data/lib/cuke_sniffer/step_definition.rb +163 -239
- data/lib/cuke_sniffer/summary_helper.rb +91 -0
- data/lib/cuke_sniffer/summary_node.rb +19 -0
- metadata +23 -5
- data/lib/cuke_sniffer/report/markup.rhtml +0 -353
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module CukeSniffer
|
4
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
5
|
+
# Copyright:: Copyright (C) 2013 Robert Cochran
|
6
|
+
# License:: Distributes under the MIT License
|
7
|
+
# Mixins: CukeSniffer::Constants
|
8
|
+
# Static class used to generate output for the CukeSniffer::CLI object.
|
9
|
+
class Formatter
|
10
|
+
include CukeSniffer::Constants
|
11
|
+
|
12
|
+
# Prints out a summary of the results and the list of improvements to be made
|
13
|
+
def self.output_console(cuke_sniffer)
|
14
|
+
summary = cuke_sniffer.summary
|
15
|
+
output = "Suite Summary" +
|
16
|
+
" Total Score: #{summary[:total_score]}\n" +
|
17
|
+
get_output_summary_nodes(cuke_sniffer) +
|
18
|
+
console_improvement_list(summary[:improvement_list])
|
19
|
+
|
20
|
+
puts output
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns a string of formatted output for all the object sections of summary
|
24
|
+
def self.get_output_summary_nodes(cuke_sniffer)
|
25
|
+
output = ""
|
26
|
+
[:features, :scenarios, :step_definitions, :hooks].each do |summary_section|
|
27
|
+
output += console_summary(summary_section.to_s.gsub("_", " ").capitalize, cuke_sniffer.summary[summary_section])
|
28
|
+
end
|
29
|
+
output
|
30
|
+
end
|
31
|
+
|
32
|
+
# Formats the section data for a summary object
|
33
|
+
def self.console_summary(name, summary)
|
34
|
+
" #{name}\n" +
|
35
|
+
" Min: #{summary[:min]} (#{summary[:min_file]})\n" +
|
36
|
+
" Max: #{summary[:max]} (#{summary[:max_file]})\n" +
|
37
|
+
" Average: #{summary[:average]}\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Formats the improvement list data for summary
|
41
|
+
def self.console_improvement_list(improvement_list)
|
42
|
+
output = " Improvements to make:\n"
|
43
|
+
improvement_list.each do |improvement, count|
|
44
|
+
output << " (#{count}) #{improvement}\n"
|
45
|
+
end
|
46
|
+
output
|
47
|
+
end
|
48
|
+
|
49
|
+
# Creates a html file with the collected project details
|
50
|
+
# file_name defaults to "cuke_sniffer_results.html" unless specified
|
51
|
+
# Second parameter used for passing into the markup.
|
52
|
+
# cuke_sniffer.output_html
|
53
|
+
# Or
|
54
|
+
# cuke_sniffer.output_html("results01-01-0001.html")
|
55
|
+
def self.output_html(cuke_sniffer, file_name = DEFAULT_OUTPUT_FILE_NAME, template_name = "standard_template")
|
56
|
+
cuke_sniffer = sort_cuke_sniffer_lists(cuke_sniffer)
|
57
|
+
output = ERB.new(extract_markup("#{template_name}.html.erb")).result(binding)
|
58
|
+
File.open(format_html_file_name(file_name), 'w') do |f| f.write(output) end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns an ERB page built up for the passed file name
|
62
|
+
def self.build_page(cuke_sniffer, erb_file)
|
63
|
+
ERB.new(extract_markup(erb_file)).result(binding)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Assigns an html extension if one is not provided for the passed file name
|
67
|
+
def self.format_html_file_name(file_name)
|
68
|
+
if file_name =~ /\.html$/
|
69
|
+
file_name
|
70
|
+
else
|
71
|
+
file_name + ".html"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Creates a html file with minimum information: Summary, Rules, Improvement List.
|
76
|
+
# file_name defaults to "cuke_sniffer_results.html" unless specified
|
77
|
+
# Second parameter used for passing into the markup.
|
78
|
+
# cuke_sniffer.output_min_html
|
79
|
+
# Or
|
80
|
+
# cuke_sniffer.output_min_html("results01-01-0001.html")
|
81
|
+
def self.output_min_html(cuke_sniffer, file_name = DEFAULT_OUTPUT_FILE_NAME)
|
82
|
+
output_html(cuke_sniffer, file_name, "min_template")
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns the Rules erb page that utilizes sub page sections of enabled and disabled rules
|
86
|
+
def self.rules_template(cuke_sniffer)
|
87
|
+
enabled_rules = sub_rules_template(cuke_sniffer, true, "Enabled Rules")
|
88
|
+
disabled_rules = sub_rules_template(cuke_sniffer, false, "Disabled Rules")
|
89
|
+
ERB.new(extract_markup("rules.html.erb")).result(binding)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns the sub rules erb page for enabled status of a rule
|
93
|
+
def self.sub_rules_template(cuke_sniffer, state, heading)
|
94
|
+
ERB.new(extract_markup("sub_rules.html.erb")).result(binding)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Creates a xml file with the collected project details
|
98
|
+
# file_name defaults to "cuke_sniffer.xml" unless specified
|
99
|
+
# cuke_sniffer.output_xml
|
100
|
+
# Or
|
101
|
+
# cuke_sniffer.output_xml("cuke_sniffer01-01-0001.xml")
|
102
|
+
def self.output_xml(cuke_sniffer, file_name = DEFAULT_OUTPUT_FILE_NAME)
|
103
|
+
file_name = file_name + ".xml" unless file_name =~ /\.xml$/
|
104
|
+
|
105
|
+
doc = Nokogiri::XML::Document.new
|
106
|
+
doc.root = cuke_sniffer.to_xml
|
107
|
+
open(file_name, "w") do |file|
|
108
|
+
file << doc.serialize
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Formats a list of rule conditions into a compact string of 5 or less elements per row.
|
113
|
+
def self.convert_array_condition_into_list_of_strings(condition_list)
|
114
|
+
result = []
|
115
|
+
while condition_list.size > 0
|
116
|
+
five_words = condition_list.slice!(0, 5)
|
117
|
+
result << five_words.join(", ")
|
118
|
+
end
|
119
|
+
result
|
120
|
+
end
|
121
|
+
|
122
|
+
# Sorts all of the lists on a cuke_sniffer object to be in descending order for each objects score.
|
123
|
+
def self.sort_cuke_sniffer_lists(cuke_sniffer)
|
124
|
+
cuke_sniffer.features = cuke_sniffer.features.sort_by { |feature| feature.total_score }.reverse
|
125
|
+
cuke_sniffer.step_definitions = cuke_sniffer.step_definitions.sort_by { |step_definition| step_definition.score }.reverse
|
126
|
+
cuke_sniffer.hooks = cuke_sniffer.hooks.sort_by { |hook| hook.score }.reverse
|
127
|
+
cuke_sniffer.rules = cuke_sniffer.rules.sort_by { |rule| rule.score }.reverse
|
128
|
+
cuke_sniffer
|
129
|
+
end
|
130
|
+
|
131
|
+
# Returns the markup for a desired erb file.
|
132
|
+
def self.extract_markup(template_name = "markup.html.erb", markup_source = MARKUP_SOURCE)
|
133
|
+
markup_location = "#{markup_source}/#{template_name}"
|
134
|
+
markup = ""
|
135
|
+
File.open(markup_location).lines.each do |line|
|
136
|
+
markup << line
|
137
|
+
end
|
138
|
+
markup
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
data/lib/cuke_sniffer/hook.rb
CHANGED
@@ -1,160 +1,77 @@
|
|
1
|
-
require 'roxml'
|
2
|
-
module CukeSniffer
|
3
|
-
|
4
|
-
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
5
|
-
# Copyright:: Copyright (C) 2013 Robert Cochran
|
6
|
-
# License:: Distributes under the MIT License
|
7
|
-
# Cucumber Hook class used for evaluating rules
|
8
|
-
# Extends CukeSniffer::RulesEvaluator
|
9
|
-
class Hook <
|
10
|
-
|
11
|
-
xml_accessor :start_line
|
12
|
-
xml_accessor :type
|
13
|
-
xml_accessor :tags, :as => [], :in => "tags"
|
14
|
-
xml_accessor :parameters, :as => [], :in => "parameters"
|
15
|
-
xml_accessor :code, :as => [], :in => "code"
|
16
|
-
|
17
|
-
# The type of the hook: AfterConfiguration, After, AfterStep, Around, Before, at_exit
|
18
|
-
attr_accessor :type
|
19
|
-
|
20
|
-
# The list of tags used as a filter for the hook
|
21
|
-
attr_accessor :tags
|
22
|
-
|
23
|
-
# The parameters that are declared on the hook
|
24
|
-
attr_accessor :parameters
|
25
|
-
|
26
|
-
# Integer of the line in which the hook was found
|
27
|
-
attr_accessor :start_line
|
28
|
-
|
29
|
-
# Array of strings that contain the code kept in the hook
|
30
|
-
attr_accessor :code
|
31
|
-
|
32
|
-
|
33
|
-
# location must be in the format of "file_path\file_name.rb:line_number"
|
34
|
-
# raw_code is an array of strings that represents the step definition
|
35
|
-
# must contain the hook declaration line and the pairing end
|
36
|
-
def initialize(location,
|
37
|
-
super(location)
|
38
|
-
|
39
|
-
|
40
|
-
@
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
rule_around_hook_no_block_call
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def rule_empty_hook
|
83
|
-
rule = RULES[:empty_hook]
|
84
|
-
store_rule(rule) if @code == []
|
85
|
-
end
|
86
|
-
|
87
|
-
def rule_hook_not_in_hooks_file
|
88
|
-
rule = RULES[:hook_not_in_hooks_file]
|
89
|
-
store_rule(rule) unless @location.include?(rule[:file])
|
90
|
-
end
|
91
|
-
|
92
|
-
def rule_around_hook_without_2_parameters
|
93
|
-
rule = RULES[:around_hook_without_2_parameters]
|
94
|
-
store_rule(rule) unless @parameters.count == 2
|
95
|
-
end
|
96
|
-
|
97
|
-
def rule_around_hook_no_block_call
|
98
|
-
return if rule_stored?(:around_hook_without_2_parameters)
|
99
|
-
rule = RULES[:around_hook_no_block_call]
|
100
|
-
block_call = "#{@parameters[1]}.call"
|
101
|
-
@code.each do |line|
|
102
|
-
return if line.include?(block_call)
|
103
|
-
end
|
104
|
-
store_rule(rule)
|
105
|
-
end
|
106
|
-
|
107
|
-
def rule_stored?(rule_symbol)
|
108
|
-
@rules_hash.keys.include?(RULES[rule_symbol][:phrase])
|
109
|
-
end
|
110
|
-
|
111
|
-
def rule_no_debugging
|
112
|
-
return if rule_stored?(:empty_hook)
|
113
|
-
rule = RULES[:hook_no_debugging]
|
114
|
-
begin_found = false
|
115
|
-
rescue_found = false
|
116
|
-
@code.each do |line|
|
117
|
-
begin_found = true if line.include?("begin")
|
118
|
-
rescue_found = true if line.include?("rescue")
|
119
|
-
break if begin_found and rescue_found
|
120
|
-
end
|
121
|
-
store_rule(rule) unless begin_found and rescue_found
|
122
|
-
end
|
123
|
-
|
124
|
-
def rule_all_comments
|
125
|
-
rule = RULES[:hook_all_comments]
|
126
|
-
@code.each do |line|
|
127
|
-
return unless is_comment?(line)
|
128
|
-
end
|
129
|
-
store_rule(rule)
|
130
|
-
end
|
131
|
-
|
132
|
-
def rule_conflicting_tags
|
133
|
-
rule = RULES[:hook_conflicting_tags]
|
134
|
-
all_tags = flatten_tags
|
135
|
-
|
136
|
-
all_tags.each do |single_tag|
|
137
|
-
tag = single_tag.gsub("~", "")
|
138
|
-
if all_tags.include?(tag) and all_tags.include?("~#{tag}")
|
139
|
-
store_rule(rule)
|
140
|
-
return
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def flatten_tags
|
146
|
-
all_tags = []
|
147
|
-
@tags.each { |single_tag| all_tags << single_tag.split(',') }
|
148
|
-
all_tags.flatten
|
149
|
-
end
|
150
|
-
|
151
|
-
def rule_duplicate_tags
|
152
|
-
rule = RULES[:hook_duplicate_tags]
|
153
|
-
all_tags = flatten_tags
|
154
|
-
unique_tags = all_tags.uniq
|
155
|
-
|
156
|
-
store_rule(rule) unless all_tags == unique_tags
|
157
|
-
end
|
158
|
-
|
159
|
-
end
|
160
|
-
end
|
1
|
+
require 'roxml'
|
2
|
+
module CukeSniffer
|
3
|
+
|
4
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
5
|
+
# Copyright:: Copyright (C) 2013 Robert Cochran
|
6
|
+
# License:: Distributes under the MIT License
|
7
|
+
# Cucumber Hook class used for evaluating rules
|
8
|
+
# Extends CukeSniffer::RulesEvaluator
|
9
|
+
class Hook < RuleTarget
|
10
|
+
|
11
|
+
xml_accessor :start_line
|
12
|
+
xml_accessor :type
|
13
|
+
xml_accessor :tags, :as => [], :in => "tags"
|
14
|
+
xml_accessor :parameters, :as => [], :in => "parameters"
|
15
|
+
xml_accessor :code, :as => [], :in => "code"
|
16
|
+
|
17
|
+
# The type of the hook: AfterConfiguration, After, AfterStep, Around, Before, at_exit
|
18
|
+
attr_accessor :type
|
19
|
+
|
20
|
+
# The list of tags used as a filter for the hook
|
21
|
+
attr_accessor :tags
|
22
|
+
|
23
|
+
# The parameters that are declared on the hook
|
24
|
+
attr_accessor :parameters
|
25
|
+
|
26
|
+
# Integer of the line in which the hook was found
|
27
|
+
attr_accessor :start_line
|
28
|
+
|
29
|
+
# Array of strings that contain the code kept in the hook
|
30
|
+
attr_accessor :code
|
31
|
+
|
32
|
+
|
33
|
+
# location must be in the format of "file_path\file_name.rb:line_number"
|
34
|
+
# raw_code is an array of strings that represents the step definition
|
35
|
+
# must contain the hook declaration line and the pairing end
|
36
|
+
def initialize(location, hook_block)
|
37
|
+
super(location)
|
38
|
+
@start_line = location.match(/:(?<line>\d*)$/)[:line].to_i
|
39
|
+
end_match_index = (hook_block.size - 1) - hook_block.reverse.index("end")
|
40
|
+
@code = hook_block[1...end_match_index]
|
41
|
+
initialize_hook_signature(hook_block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def ==(comparison_object) # :nodoc:
|
45
|
+
super(comparison_object) &&
|
46
|
+
comparison_object.type == type &&
|
47
|
+
comparison_object.tags == tags &&
|
48
|
+
comparison_object.parameters == parameters &&
|
49
|
+
comparison_object.code == code
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def initialize_hook_signature(hook_block)
|
55
|
+
@type = nil
|
56
|
+
@tags = []
|
57
|
+
@parameters = []
|
58
|
+
|
59
|
+
hook_signature = extract_hook_signature(hook_block)
|
60
|
+
matches = HOOK_REGEX.match(hook_signature)
|
61
|
+
@type = matches[:type]
|
62
|
+
initialize_tags(matches[:tags]) if matches[:tags]
|
63
|
+
@parameters = matches[:parameters].split(/,\s*/) if matches[:parameters]
|
64
|
+
end
|
65
|
+
|
66
|
+
def extract_hook_signature(hook_block)
|
67
|
+
hook_block.each do |line|
|
68
|
+
return line if line =~ HOOK_REGEX
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize_tags(tag_list)
|
73
|
+
hook_tag_regexp = /["']([^"']*)["']/
|
74
|
+
tag_list.scan(hook_tag_regexp).each { |tag| @tags << tag[0] }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<div class="title" onclick="toggleById('dead_steps_data', this)">
|
2
|
+
Dead Steps +
|
3
|
+
</div>
|
4
|
+
<div class="shrink_section" id="dead_steps_data">
|
5
|
+
<% dead_steps = cuke_sniffer.get_dead_steps %>
|
6
|
+
<% dead_steps.delete(:total) %>
|
7
|
+
<% dead_step_count = dead_steps.values.flatten.count %>
|
8
|
+
<% if dead_step_count == 0 %>
|
9
|
+
<div class="empty_set_message">No dead steps found!</div>
|
10
|
+
<% elsif dead_step_count == 1 %>
|
11
|
+
<div class="empty_set_message" style="color: red"><%= dead_step_count %> Dead Step found.</div>
|
12
|
+
<% else %>
|
13
|
+
<div class="empty_set_message" style="color: red"><%= dead_step_count %> Dead Steps found.</div>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<table style="width: 100%">
|
17
|
+
<% dead_steps.each_key do |file_name| %>
|
18
|
+
<tr>
|
19
|
+
<td>
|
20
|
+
<div style="text-indent: 2%;font-weight: bold;"><%= file_name.gsub(cuke_sniffer.step_definitions_location, "") %>
|
21
|
+
.rb
|
22
|
+
</div>
|
23
|
+
<table style="width: 100%; padding-left: 3%;">
|
24
|
+
<% dead_steps[file_name].each do |regex| %>
|
25
|
+
<tr>
|
26
|
+
<td style="width: 3%"><%= regex.match(/(?<line>\d+):/)[:line] %></td>
|
27
|
+
<td><%= regex.match(/:(?<regex>.*)/)[:regex] %></td>
|
28
|
+
</tr>
|
29
|
+
<% end %>
|
30
|
+
</table>
|
31
|
+
</td>
|
32
|
+
</tr>
|
33
|
+
<% end %>
|
34
|
+
</table>
|
35
|
+
</div>
|
36
|
+
<br style="clear:both">
|
@@ -0,0 +1,60 @@
|
|
1
|
+
<div class="title" onclick="toggleById('features_data', this)">
|
2
|
+
Features +
|
3
|
+
</div>
|
4
|
+
<div class="shrink_section" id="features_data">
|
5
|
+
<% if cuke_sniffer.features.count == 0 %>
|
6
|
+
<div class="empty_set_message">There were no Features to sniff in '<%= cuke_sniffer.features_location %>'!</div>
|
7
|
+
<% elsif cuke_sniffer.features.count >= 1 && cuke_sniffer.scenarios.count >=1 && cuke_sniffer.summary[:features][:total_score] ==0 && cuke_sniffer.summary[:scenarios][:total_score] ==0 %>
|
8
|
+
<div class="empty_set_message">Excellent! No smells found for Features and Scenarios!</div>
|
9
|
+
<% end %>
|
10
|
+
<% index = 0 %>
|
11
|
+
<% cuke_sniffer.features.each do |feature| %>
|
12
|
+
<% next if feature.total_score <= 0 %>
|
13
|
+
<div style="cursor: pointer; padding-top: 3px" onclick="updateDisplayStatus(document.getElementById('feature_<%=index%>'))">
|
14
|
+
<div class="red_number" style="float:left"><%= feature.total_score + feature.scenarios_score %></div>
|
15
|
+
<div class="notes"><%= feature.name %></div>
|
16
|
+
</div>
|
17
|
+
<div id="feature_<%= index %>" class="sub_section">
|
18
|
+
<div style="text-indent: 4%; float: left; width: 45%; border-right: 2px solid #add8e6; padding-bottom: 4px">
|
19
|
+
<% if feature.rules_hash.empty? %>
|
20
|
+
<pre style="margin: 0;"> </pre>
|
21
|
+
<% end %>
|
22
|
+
<% feature.rules_hash.each_key do |rule| %>
|
23
|
+
<pre style="margin: 0;"><%= rule %></pre>
|
24
|
+
<% end %>
|
25
|
+
</div>
|
26
|
+
<div style="text-indent: 1%; padding-bottom: 4px">
|
27
|
+
<%= feature.location.gsub(cuke_sniffer.features_location, "") %>
|
28
|
+
</div>
|
29
|
+
<br style="clear:both">
|
30
|
+
|
31
|
+
<div>
|
32
|
+
<% unless feature.background.nil? or feature.background.score > 0 %>
|
33
|
+
<div class="red_number" style="float:left; padding-left: 1%"><%= feature.background.score %></div>
|
34
|
+
<div style="float: left; width: 45%;"><%= feature.background.type + ": " + feature.background.name %></div>
|
35
|
+
<div style="margin-left:1%;float: left; border-left: 2px solid #90ee90; border-top: 2px solid #90ee90;text-indent: 1%;">
|
36
|
+
<% feature.background.rules_hash.each_key do |rule| %>
|
37
|
+
<pre style="margin: 0; text_indent: 3%;"><%= rule %></pre>
|
38
|
+
<% end %>
|
39
|
+
</div>
|
40
|
+
<br style="clear:both">
|
41
|
+
<% end %>
|
42
|
+
</div>
|
43
|
+
<div>
|
44
|
+
<% feature.scenarios.each do |scenario| %>
|
45
|
+
<% next if scenario.score <= 0 %>
|
46
|
+
<div class="red_number" style="float:left; padding-left: 1%"><%= scenario.score %></div>
|
47
|
+
<div style="float: left; width: 45%;"><%= scenario.type + ": " + scenario.name %></div>
|
48
|
+
<div style="margin-left:1%;float: left; border-left: 2px solid #90ee90; border-top: 2px solid #90ee90; text-indent: 1%">
|
49
|
+
<% scenario.rules_hash.each_key do |rule| %>
|
50
|
+
<pre style="margin: 0; text_indent: 3%;"><%= rule %></pre>
|
51
|
+
<% end %>
|
52
|
+
</div>
|
53
|
+
<br style="clear:both">
|
54
|
+
<% end %>
|
55
|
+
</div>
|
56
|
+
</div>
|
57
|
+
<% index += 1 %>
|
58
|
+
<% end %>
|
59
|
+
</div>
|
60
|
+
<br style="clear:both">
|