cuke_sniffer 0.0.7 → 0.0.8
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/lib/cuke_sniffer.rb +8 -23
- data/lib/cuke_sniffer/cli.rb +38 -5
- data/lib/cuke_sniffer/constants.rb +1 -1
- data/lib/cuke_sniffer/cuke_sniffer_helper.rb +1 -1
- data/lib/cuke_sniffer/dead_steps_helper.rb +1 -1
- data/lib/cuke_sniffer/feature.rb +109 -104
- data/lib/cuke_sniffer/feature_rules_evaluator.rb +55 -56
- data/lib/cuke_sniffer/formatter.rb +1 -1
- data/lib/cuke_sniffer/hook.rb +103 -77
- data/lib/cuke_sniffer/report/rules.html.erb +0 -5
- data/lib/cuke_sniffer/rule.rb +26 -27
- data/lib/cuke_sniffer/rule_config.rb +114 -128
- data/lib/cuke_sniffer/rule_target.rb +78 -62
- data/lib/cuke_sniffer/rules_evaluator.rb +52 -64
- data/lib/cuke_sniffer/scenario.rb +123 -102
- data/lib/cuke_sniffer/step_definition.rb +176 -163
- data/lib/cuke_sniffer/summary_helper.rb +1 -1
- data/lib/cuke_sniffer/summary_node.rb +17 -18
- metadata +2 -2
@@ -1,62 +1,78 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
class
|
10
|
-
|
11
|
-
|
12
|
-
include
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
attr_accessor :
|
22
|
-
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
#
|
44
|
-
# Return:
|
45
|
-
def
|
46
|
-
score
|
47
|
-
end
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
1
|
+
require 'cuke_sniffer/constants'
|
2
|
+
require 'cuke_sniffer/rule_config'
|
3
|
+
|
4
|
+
module CukeSniffer
|
5
|
+
|
6
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
7
|
+
# Copyright:: Copyright (C) 2014 Robert Cochran
|
8
|
+
# License:: Distributes under the MIT License
|
9
|
+
# Parent class for all objects that have rules executed against it
|
10
|
+
# Mixins: CukeSniffer::Constants, CukeSniffer::RuleConfig, ROXML
|
11
|
+
class RuleTarget
|
12
|
+
include CukeSniffer::Constants
|
13
|
+
include CukeSniffer::RuleConfig
|
14
|
+
include ROXML
|
15
|
+
|
16
|
+
xml_accessor :score, :location
|
17
|
+
xml_accessor :rules_hash, :as => {:key => "phrase", :value => "score"}, :in => "rules", :from => "rule"
|
18
|
+
xml_accessor :type
|
19
|
+
|
20
|
+
# int: Sum of the rules fired
|
21
|
+
attr_accessor :score
|
22
|
+
|
23
|
+
# string: Location in which the object was found
|
24
|
+
attr_accessor :location
|
25
|
+
|
26
|
+
# hash: Contains the phrase every rule fired against the object and times it fired
|
27
|
+
# * Key: string
|
28
|
+
# * Value: int
|
29
|
+
attr_accessor :rules_hash
|
30
|
+
|
31
|
+
# string: Type of the object being evaluated
|
32
|
+
attr_accessor :type
|
33
|
+
|
34
|
+
# Location must be in the format of "file_path\file_name.rb:line_number"
|
35
|
+
def initialize(location)
|
36
|
+
@location = location
|
37
|
+
@score = 0
|
38
|
+
@rules_hash = {}
|
39
|
+
@class_type = self.class.to_s.gsub(/.*::/, "")
|
40
|
+
end
|
41
|
+
|
42
|
+
# Compares the score against the objects threshold
|
43
|
+
# If a score is below the threshold it is good and returns true
|
44
|
+
# Return: Boolean
|
45
|
+
def good?
|
46
|
+
score <= Constants::THRESHOLDS[@class_type]
|
47
|
+
end
|
48
|
+
|
49
|
+
# Calculates the score to threshold percentage of an object
|
50
|
+
# Return: Float
|
51
|
+
def problem_percentage
|
52
|
+
score.to_f / Constants::THRESHOLDS[@class_type].to_f
|
53
|
+
end
|
54
|
+
|
55
|
+
def == (comparison_object) # :nodoc:
|
56
|
+
comparison_object.location == location &&
|
57
|
+
comparison_object.score == score &&
|
58
|
+
comparison_object.rules_hash == rules_hash
|
59
|
+
end
|
60
|
+
|
61
|
+
#TODO Abstraction needed for this regex matcher (constants?)
|
62
|
+
def is_comment?(line)
|
63
|
+
true if line =~ /^\#.*$/
|
64
|
+
end
|
65
|
+
|
66
|
+
def store_rule(rule, phrase = rule.phrase)
|
67
|
+
@score += rule.score
|
68
|
+
@rules_hash[phrase] ||= 0
|
69
|
+
@rules_hash[phrase] += 1
|
70
|
+
end
|
71
|
+
|
72
|
+
def store_rule_many_times(rule, count, phrase = rule.phrase)
|
73
|
+
count.times do
|
74
|
+
store_rule(rule, phrase)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -1,65 +1,53 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
def store_rule(object, rule, phrase = rule.phrase)
|
56
|
-
object.score += rule.score
|
57
|
-
object.rules_hash[phrase] ||= 0
|
58
|
-
object.rules_hash[phrase] += 1
|
59
|
-
end
|
60
|
-
|
61
|
-
def is_comment?(line)
|
62
|
-
true if line =~ /^\#.*$/
|
63
|
-
end
|
64
|
-
end
|
1
|
+
module CukeSniffer
|
2
|
+
|
3
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
4
|
+
# Copyright:: Copyright (C) 2014 Robert Cochran
|
5
|
+
# License:: Distributes under the MIT License
|
6
|
+
# Evaluates all cucumber components found in CukeSniffer with the passed rules
|
7
|
+
class RulesEvaluator
|
8
|
+
include CukeSniffer::Constants
|
9
|
+
attr_accessor :rules
|
10
|
+
|
11
|
+
def initialize(cli, rules)
|
12
|
+
raise "A CLI must be provided for evaluation." if cli.nil?
|
13
|
+
raise "Rules must be provided for evaluation." if rules.nil? or rules.empty?
|
14
|
+
@rules = rules
|
15
|
+
judge_features(cli.features)
|
16
|
+
judge_objects(cli.step_definitions, "StepDefinition")
|
17
|
+
judge_objects(cli.hooks, "Hook")
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def judge_features(features)
|
23
|
+
features.each do |feature|
|
24
|
+
judge_feature(feature)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def judge_feature(feature)
|
29
|
+
judge_object(feature, "Feature")
|
30
|
+
judge_object(feature.background, "Background") unless feature.background.nil?
|
31
|
+
judge_objects(feature.scenarios, "Scenario")
|
32
|
+
feature.total_score += feature.update_score
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def judge_objects(objects, type)
|
37
|
+
objects.each do | object |
|
38
|
+
judge_object(object, type)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def judge_object(object, type)
|
43
|
+
@rules.each do |rule|
|
44
|
+
fail "No targets for rule: #{rule.phrase}" if rule.targets.nil? or rule.targets.empty?
|
45
|
+
next unless rule.targets.include? type and rule.enabled
|
46
|
+
if rule.reason.(object, rule) == true
|
47
|
+
phrase = rule.phrase.gsub("{class}", type)
|
48
|
+
object.store_rule(rule, phrase)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
65
53
|
end
|
@@ -1,102 +1,123 @@
|
|
1
|
-
module CukeSniffer
|
2
|
-
|
3
|
-
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
4
|
-
# Copyright:: Copyright (C)
|
5
|
-
# License:: Distributes under the MIT License
|
6
|
-
# This class is a representation of the cucumber objects
|
7
|
-
# Background, Scenario, Scenario Outline
|
8
|
-
#
|
9
|
-
# Extends CukeSniffer::FeatureRulesEvaluator
|
10
|
-
class Scenario < FeatureRuleTarget
|
11
|
-
|
12
|
-
xml_accessor :start_line
|
13
|
-
xml_accessor :steps, :as => [], :in => "steps"
|
14
|
-
xml_accessor :examples_table, :as => [], :in => "examples"
|
15
|
-
|
16
|
-
# int: Line on which the scenario begins
|
17
|
-
attr_accessor :start_line
|
18
|
-
|
19
|
-
# string: The type of scenario
|
20
|
-
# Background, Scenario, Scenario Outline
|
21
|
-
attr_accessor :type
|
22
|
-
|
23
|
-
# string array: List of each step call in a scenario
|
24
|
-
attr_accessor :steps
|
25
|
-
|
26
|
-
# hash: Keeps each location and content of an inline table
|
27
|
-
# * Key: Step string the inline table is attached to
|
28
|
-
# * Value: Array of all of the lines in the table
|
29
|
-
attr_accessor :inline_tables
|
30
|
-
|
31
|
-
# string array: List of each example row in a scenario outline
|
32
|
-
attr_accessor :examples_table
|
33
|
-
|
34
|
-
# Location must be in the format of "file_path\file_name.rb:line_number"
|
35
|
-
# Scenario must be a string array containing everything from the first tag to the last example table
|
36
|
-
# where applicable.
|
37
|
-
def initialize(location, scenario)
|
38
|
-
super(location)
|
39
|
-
@start_line = location.match(/:(?<line>\d*)$/)[:line].to_i
|
40
|
-
@steps = []
|
41
|
-
@inline_tables = {}
|
42
|
-
@examples_table = []
|
43
|
-
split_scenario(scenario)
|
44
|
-
end
|
45
|
-
|
46
|
-
def ==(comparison_object) # :nodoc:
|
47
|
-
super(comparison_object) &&
|
48
|
-
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
def get_step_order
|
53
|
-
order = []
|
54
|
-
@steps.each do |line|
|
55
|
-
next if is_comment?(line)
|
56
|
-
match = line.match(STEP_REGEX)
|
57
|
-
order << match[:style] unless match.nil?
|
58
|
-
end
|
59
|
-
order
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
1
|
+
module CukeSniffer
|
2
|
+
|
3
|
+
# Author:: Robert Cochran (mailto:cochrarj@miamioh.edu)
|
4
|
+
# Copyright:: Copyright (C) 2014 Robert Cochran
|
5
|
+
# License:: Distributes under the MIT License
|
6
|
+
# This class is a representation of the cucumber objects
|
7
|
+
# Background, Scenario, Scenario Outline
|
8
|
+
#
|
9
|
+
# Extends CukeSniffer::FeatureRulesEvaluator
|
10
|
+
class Scenario < FeatureRuleTarget
|
11
|
+
|
12
|
+
xml_accessor :start_line
|
13
|
+
xml_accessor :steps, :as => [], :in => "steps"
|
14
|
+
xml_accessor :examples_table, :as => [], :in => "examples"
|
15
|
+
|
16
|
+
# int: Line on which the scenario begins
|
17
|
+
attr_accessor :start_line
|
18
|
+
|
19
|
+
# string: The type of scenario
|
20
|
+
# Background, Scenario, Scenario Outline
|
21
|
+
attr_accessor :type
|
22
|
+
|
23
|
+
# string array: List of each step call in a scenario
|
24
|
+
attr_accessor :steps
|
25
|
+
|
26
|
+
# hash: Keeps each location and content of an inline table
|
27
|
+
# * Key: Step string the inline table is attached to
|
28
|
+
# * Value: Array of all of the lines in the table
|
29
|
+
attr_accessor :inline_tables
|
30
|
+
|
31
|
+
# string array: List of each example row in a scenario outline
|
32
|
+
attr_accessor :examples_table
|
33
|
+
|
34
|
+
# Location must be in the format of "file_path\file_name.rb:line_number"
|
35
|
+
# Scenario must be a string array containing everything from the first tag to the last example table
|
36
|
+
# where applicable.
|
37
|
+
def initialize(location, scenario)
|
38
|
+
super(location)
|
39
|
+
@start_line = location.match(/:(?<line>\d*)$/)[:line].to_i
|
40
|
+
@steps = []
|
41
|
+
@inline_tables = {}
|
42
|
+
@examples_table = []
|
43
|
+
split_scenario(scenario)
|
44
|
+
end
|
45
|
+
|
46
|
+
def ==(comparison_object) # :nodoc:
|
47
|
+
super(comparison_object) &&
|
48
|
+
comparison_object.steps == steps &&
|
49
|
+
comparison_object.examples_table == examples_table
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_step_order
|
53
|
+
order = []
|
54
|
+
@steps.each do |line|
|
55
|
+
next if is_comment?(line)
|
56
|
+
match = line.match(STEP_REGEX)
|
57
|
+
order << match[:style] unless match.nil?
|
58
|
+
end
|
59
|
+
order
|
60
|
+
end
|
61
|
+
|
62
|
+
def outline?
|
63
|
+
type === 'Scenario Outline'
|
64
|
+
end
|
65
|
+
|
66
|
+
def commented_examples
|
67
|
+
@examples_table.select do |example|
|
68
|
+
is_comment?(example)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_steps(step_start)
|
73
|
+
if step_start != "*"
|
74
|
+
regex = /^\s*#{step_start}/
|
75
|
+
else
|
76
|
+
regex = /^\s*[*]/
|
77
|
+
end
|
78
|
+
@steps.select do |step|
|
79
|
+
step =~ regex
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def split_scenario(scenario)
|
86
|
+
index = 0
|
87
|
+
until index >= scenario.length or scenario[index] =~ SCENARIO_TITLE_STYLES
|
88
|
+
update_tag_list(scenario[index])
|
89
|
+
index += 1
|
90
|
+
end
|
91
|
+
|
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
|
97
|
+
end
|
98
|
+
|
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]
|
105
|
+
index += 1
|
106
|
+
end
|
107
|
+
else
|
108
|
+
@steps << scenario[index] if scenario[index] =~ STEP_REGEX
|
109
|
+
index += 1
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
if index < scenario.length and scenario[index].include?("Examples:")
|
114
|
+
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
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|