gherkin_lint 0.3.1 → 0.4.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.
- checksums.yaml +7 -0
- data/.rubocop.yml +12 -6
- data/Gemfile +1 -1
- data/Rakefile +2 -2
- data/gherkin_lint.gemspec +3 -3
- data/lib/gherkin_lint.rb +8 -13
- data/lib/gherkin_lint/linter.rb +39 -34
- data/lib/gherkin_lint/linter/avoid_outline_for_single_example.rb +4 -4
- data/lib/gherkin_lint/linter/avoid_period.rb +3 -3
- data/lib/gherkin_lint/linter/avoid_scripting.rb +4 -4
- data/lib/gherkin_lint/linter/background_does_more_than_setup.rb +2 -2
- data/lib/gherkin_lint/linter/background_requires_multiple_scenarios.rb +1 -1
- data/lib/gherkin_lint/linter/bad_scenario_name.rb +2 -2
- data/lib/gherkin_lint/linter/be_declarative.rb +2 -2
- data/lib/gherkin_lint/linter/file_name_differs_feature_name.rb +2 -2
- data/lib/gherkin_lint/linter/invalid_step_flow.rb +5 -5
- data/lib/gherkin_lint/linter/missing_example_name.rb +4 -4
- data/lib/gherkin_lint/linter/missing_feature_description.rb +1 -1
- data/lib/gherkin_lint/linter/missing_feature_name.rb +1 -1
- data/lib/gherkin_lint/linter/missing_scenario_name.rb +1 -1
- data/lib/gherkin_lint/linter/missing_test_action.rb +1 -1
- data/lib/gherkin_lint/linter/missing_verification.rb +1 -1
- data/lib/gherkin_lint/linter/same_tag_for_all_scenarios.rb +12 -12
- data/lib/gherkin_lint/linter/too_clumsy.rb +1 -1
- data/lib/gherkin_lint/linter/too_long_step.rb +2 -2
- data/lib/gherkin_lint/linter/too_many_different_tags.rb +2 -2
- data/lib/gherkin_lint/linter/too_many_steps.rb +2 -2
- data/lib/gherkin_lint/linter/unique_scenario_names.rb +2 -2
- data/lib/gherkin_lint/linter/unknown_variable.rb +13 -8
- data/lib/gherkin_lint/linter/unused_variable.rb +12 -11
- data/lib/gherkin_lint/linter/use_background.rb +17 -15
- data/lib/gherkin_lint/linter/use_outline.rb +5 -5
- metadata +21 -33
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5e776cabb83c6f00b485d9e88b7193bfd421ab79
|
4
|
+
data.tar.gz: 63e15be6fb1920e3a587b75163af5d18b959f3d3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 03ccf86a4b33104ba1cb5f65d98df1a72a660ebb27a53997be9c38b95a1271ea2ced2c55522e10dbd2a25c57e4d141ebcca647d6ffd1617885b9b6ddf5ae1e65
|
7
|
+
data.tar.gz: 31f0d3b395b1e4661d5d0705429c4a057008c719a0fcebffecf68b423e73778279d37d2f77cccdc0f7978787f48005e24dc0a566aa61820d46d5099db71b30fb
|
data/.rubocop.yml
CHANGED
@@ -1,24 +1,30 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on 2016-
|
3
|
+
# on 2016-08-11 02:27:52 +0200 using RuboCop version 0.42.0.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
8
|
|
9
|
+
# Offense count: 1
|
10
|
+
Metrics/AbcSize:
|
11
|
+
Max: 16
|
12
|
+
|
9
13
|
# Offense count: 1
|
10
14
|
# Configuration parameters: CountComments.
|
11
15
|
Metrics/ClassLength:
|
12
|
-
Max:
|
16
|
+
Max: 121
|
13
17
|
|
14
|
-
# Offense count:
|
18
|
+
# Offense count: 33
|
15
19
|
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
|
16
20
|
# URISchemes: http, https
|
17
21
|
Metrics/LineLength:
|
18
|
-
Max:
|
22
|
+
Max: 116
|
19
23
|
|
20
24
|
# Offense count: 1
|
21
25
|
# Cop supports --auto-correct.
|
22
|
-
|
26
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
27
|
+
# SupportedStyles: predicate, comparison
|
28
|
+
Style/NumericPredicate:
|
23
29
|
Exclude:
|
24
|
-
- 'lib/gherkin_lint/linter/
|
30
|
+
- 'lib/gherkin_lint/linter/file_name_differs_feature_name.rb'
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -11,12 +11,12 @@ end
|
|
11
11
|
|
12
12
|
desc 'Publishes the Gem'
|
13
13
|
task :push do
|
14
|
-
sh 'gem push gherkin_lint-0.
|
14
|
+
sh 'gem push gherkin_lint-0.4.0.gem'
|
15
15
|
end
|
16
16
|
|
17
17
|
desc 'Checks ruby style'
|
18
18
|
task :rubocop do
|
19
|
-
|
19
|
+
sh 'rubocop'
|
20
20
|
end
|
21
21
|
|
22
22
|
task test: :rubocop
|
data/gherkin_lint.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'gherkin_lint'
|
3
|
-
s.version = '0.
|
4
|
-
s.date = '2016-
|
3
|
+
s.version = '0.4.0'
|
4
|
+
s.date = '2016-08-11'
|
5
5
|
s.summary = 'Gherkin Lint'
|
6
6
|
s.description = 'Lint Gherkin Files'
|
7
7
|
s.authors = ['Stefan Rohe']
|
8
8
|
s.homepage = 'http://github.com/funkwerk/gherkin_lint/'
|
9
9
|
s.files = `git ls-files`.split("\n")
|
10
10
|
s.executables = s.files.grep(%r{^bin/}) { |file| File.basename(file) }
|
11
|
-
s.add_runtime_dependency 'gherkin', ['
|
11
|
+
s.add_runtime_dependency 'gherkin', ['>= 4.0.0']
|
12
12
|
s.add_runtime_dependency 'term-ansicolor', ['>= 1.3.2']
|
13
13
|
s.add_runtime_dependency 'amatch', ['>= 0.3.0']
|
14
14
|
s.add_runtime_dependency 'engtagger', ['>=0.2.0']
|
data/lib/gherkin_lint.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
gem 'gherkin', '
|
1
|
+
gem 'gherkin', '>=4.0.0'
|
2
2
|
|
3
|
-
require 'gherkin/
|
4
|
-
require 'gherkin/parser/parser'
|
3
|
+
require 'gherkin/parser'
|
5
4
|
require 'gherkin_lint/linter/avoid_outline_for_single_example'
|
6
5
|
require 'gherkin_lint/linter/avoid_period'
|
7
6
|
require 'gherkin_lint/linter/avoid_scripting'
|
@@ -29,7 +28,6 @@ require 'gherkin_lint/linter/unknown_variable'
|
|
29
28
|
require 'gherkin_lint/linter/unused_variable'
|
30
29
|
require 'gherkin_lint/linter/use_background'
|
31
30
|
require 'gherkin_lint/linter/use_outline'
|
32
|
-
require 'stringio'
|
33
31
|
require 'multi_json'
|
34
32
|
require 'set'
|
35
33
|
|
@@ -102,8 +100,7 @@ module GherkinLint
|
|
102
100
|
end
|
103
101
|
|
104
102
|
def parse(file)
|
105
|
-
|
106
|
-
to_json(content, file)
|
103
|
+
to_json File.read(file)
|
107
104
|
end
|
108
105
|
|
109
106
|
def report
|
@@ -122,13 +119,11 @@ module GherkinLint
|
|
122
119
|
LINTER.map { |lint| "disable#{lint.new.class.name.split('::').last}" }
|
123
120
|
end
|
124
121
|
|
125
|
-
def to_json(input
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
parser.parse(
|
130
|
-
formatter.done
|
131
|
-
MultiJson.load io.string
|
122
|
+
def to_json(input)
|
123
|
+
parser = Gherkin::Parser.new
|
124
|
+
scanner = Gherkin::TokenScanner.new input
|
125
|
+
|
126
|
+
parser.parse(scanner)
|
132
127
|
end
|
133
128
|
|
134
129
|
def print(issues)
|
data/lib/gherkin_lint/linter.rb
CHANGED
@@ -13,9 +13,9 @@ module GherkinLint
|
|
13
13
|
|
14
14
|
def features
|
15
15
|
@files.each do |file, content|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
feature = content[:feature]
|
17
|
+
|
18
|
+
yield(file, feature)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -25,39 +25,40 @@ module GherkinLint
|
|
25
25
|
|
26
26
|
def scenarios
|
27
27
|
elements do |file, feature, scenario|
|
28
|
-
next if scenario[
|
28
|
+
next if scenario[:type] == :Background
|
29
29
|
yield(file, feature, scenario)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
def filled_scenarios
|
34
34
|
scenarios do |file, feature, scenario|
|
35
|
-
next unless scenario.include?
|
35
|
+
next unless scenario.include? :steps
|
36
36
|
yield(file, feature, scenario)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
def steps
|
41
41
|
elements do |file, feature, scenario|
|
42
|
-
next unless scenario.include?
|
43
|
-
scenario[
|
42
|
+
next unless scenario.include? :steps
|
43
|
+
scenario[:steps].each { |step| yield(file, feature, scenario, step) }
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
def backgrounds
|
48
48
|
elements do |file, feature, scenario|
|
49
|
-
next unless scenario[
|
49
|
+
next unless scenario[:type] == :Background
|
50
50
|
yield(file, feature, scenario)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
54
|
def elements
|
55
55
|
@files.each do |file, content|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
56
|
+
feature = content[:feature]
|
57
|
+
|
58
|
+
next if feature.nil?
|
59
|
+
next unless feature.key? :children
|
60
|
+
feature[:children].each do |scenario|
|
61
|
+
yield(file, feature, scenario)
|
61
62
|
end
|
62
63
|
end
|
63
64
|
end
|
@@ -75,7 +76,8 @@ module GherkinLint
|
|
75
76
|
|
76
77
|
def filter_tag(data, tag)
|
77
78
|
return data.select { |item| !tag?(item, tag) }.map { |item| filter_tag(item, tag) } if data.class == Array
|
78
|
-
return
|
79
|
+
return {} if (data.class == Hash) && (data.include? :feature) && tag?(data[:feature], tag)
|
80
|
+
return data unless data.respond_to? :each_pair
|
79
81
|
result = {}
|
80
82
|
|
81
83
|
data.each_pair { |key, value| result[key] = filter_tag(value, tag) }
|
@@ -84,8 +86,8 @@ module GherkinLint
|
|
84
86
|
|
85
87
|
def tag?(data, tag)
|
86
88
|
return false if data.class != Hash
|
87
|
-
return false unless data.
|
88
|
-
data[
|
89
|
+
return false unless data.include? :tags
|
90
|
+
data[:tags].map { |item| item[:name] }.include? "@#{tag}"
|
89
91
|
end
|
90
92
|
|
91
93
|
def suppress_tags(data, tags)
|
@@ -94,7 +96,7 @@ module GherkinLint
|
|
94
96
|
result = {}
|
95
97
|
|
96
98
|
data.each_pair do |key, value|
|
97
|
-
value = suppress(value, tags) if key ==
|
99
|
+
value = suppress(value, tags) if key == :tags
|
98
100
|
|
99
101
|
result[key] = suppress_tags(value, tags)
|
100
102
|
end
|
@@ -102,7 +104,7 @@ module GherkinLint
|
|
102
104
|
end
|
103
105
|
|
104
106
|
def suppress(data, tags)
|
105
|
-
data.select { |item| !tags.map { |tag| "@#{tag}" }.include? item[
|
107
|
+
data.select { |item| !tags.map { |tag| "@#{tag}" }.include? item[:name] }
|
106
108
|
end
|
107
109
|
|
108
110
|
def lint
|
@@ -110,17 +112,17 @@ module GherkinLint
|
|
110
112
|
end
|
111
113
|
|
112
114
|
def reference(file, feature = nil, scenario = nil, step = nil)
|
113
|
-
return file if feature.nil? || feature[
|
114
|
-
result = "#{file} (#{line(feature, scenario, step)}): #{feature[
|
115
|
-
result += ".#{scenario[
|
116
|
-
result += " step: #{step[
|
115
|
+
return file if feature.nil? || feature[:name].empty?
|
116
|
+
result = "#{file} (#{line(feature, scenario, step)}): #{feature[:name]}"
|
117
|
+
result += ".#{scenario[:name]}" unless scenario.nil? || scenario[:name].empty?
|
118
|
+
result += " step: #{step[:text]}" unless step.nil?
|
117
119
|
result
|
118
120
|
end
|
119
121
|
|
120
122
|
def line(feature, scenario, step)
|
121
|
-
line = feature.nil? ? nil : feature[
|
122
|
-
line = scenario[
|
123
|
-
line = step[
|
123
|
+
line = feature.nil? ? nil : feature[:location][:line]
|
124
|
+
line = scenario[:location][:line] unless scenario.nil?
|
125
|
+
line = step[:location][:line] unless step.nil?
|
124
126
|
line
|
125
127
|
end
|
126
128
|
|
@@ -133,19 +135,22 @@ module GherkinLint
|
|
133
135
|
end
|
134
136
|
|
135
137
|
def gather_tags(element)
|
136
|
-
return [] unless element.include?
|
137
|
-
element[
|
138
|
+
return [] unless element.include? :tags
|
139
|
+
element[:tags].map { |tag| tag[:name][1..-1] }
|
138
140
|
end
|
139
141
|
|
140
142
|
def render_step(step)
|
141
|
-
value = "#{step[
|
142
|
-
value +=
|
143
|
-
if step.include? 'rows'
|
144
|
-
value += step['rows'].map do |row|
|
145
|
-
row['cells'].join '|'
|
146
|
-
end.join "|\n"
|
147
|
-
end
|
143
|
+
value = "#{step[:keyword]}#{step[:text]}"
|
144
|
+
value += render_step_argument step[:argument] if step.include? :argument
|
148
145
|
value
|
149
146
|
end
|
147
|
+
|
148
|
+
def render_step_argument(argument)
|
149
|
+
return "\n#{argument[:content]}" if argument[:type] == :DocString
|
150
|
+
result = argument[:rows].map do |row|
|
151
|
+
"|#{row[:cells].map { |cell| cell[:value] }.join '|'}|"
|
152
|
+
end.join "\n"
|
153
|
+
"\n#{result}"
|
154
|
+
end
|
150
155
|
end
|
151
156
|
end
|
@@ -5,11 +5,11 @@ module GherkinLint
|
|
5
5
|
class AvoidOutlineForSingleExample < Linter
|
6
6
|
def lint
|
7
7
|
scenarios do |file, feature, scenario|
|
8
|
-
next unless scenario[
|
8
|
+
next unless scenario[:type] == :ScenarioOutline
|
9
9
|
|
10
|
-
next unless scenario.key?
|
11
|
-
next if scenario[
|
12
|
-
next if scenario[
|
10
|
+
next unless scenario.key? :examples
|
11
|
+
next if scenario[:examples].length > 1
|
12
|
+
next if scenario[:examples].first[:tableBody].length > 1
|
13
13
|
|
14
14
|
references = [reference(file, feature, scenario)]
|
15
15
|
add_error(references, 'Better write a scenario')
|
@@ -5,11 +5,11 @@ module GherkinLint
|
|
5
5
|
class AvoidPeriod < Linter
|
6
6
|
def lint
|
7
7
|
scenarios do |file, feature, scenario|
|
8
|
-
next unless scenario.key?
|
8
|
+
next unless scenario.key? :steps
|
9
9
|
|
10
|
-
scenario[
|
10
|
+
scenario[:steps].each do |step|
|
11
11
|
references = [reference(file, feature, scenario, step)]
|
12
|
-
add_error(references) if step[
|
12
|
+
add_error(references) if step[:text].strip.end_with? '.'
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -5,7 +5,7 @@ module GherkinLint
|
|
5
5
|
class AvoidScripting < Linter
|
6
6
|
def lint
|
7
7
|
filled_scenarios do |file, feature, scenario|
|
8
|
-
steps = filter_when_steps scenario[
|
8
|
+
steps = filter_when_steps scenario[:steps]
|
9
9
|
|
10
10
|
next if steps.length <= 1
|
11
11
|
references = [reference(file, feature, scenario)]
|
@@ -14,9 +14,9 @@ module GherkinLint
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def filter_when_steps(steps)
|
17
|
-
steps = steps.drop_while { |step| step[
|
18
|
-
steps = steps.reverse.drop_while { |step| step[
|
19
|
-
steps.select { |step| step[
|
17
|
+
steps = steps.drop_while { |step| step[:keyword] != 'When ' }
|
18
|
+
steps = steps.reverse.drop_while { |step| step[:keyword] != 'Then ' }.reverse
|
19
|
+
steps.select { |step| step[:keyword] != 'Then ' }
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -5,8 +5,8 @@ module GherkinLint
|
|
5
5
|
class BackgroundDoesMoreThanSetup < Linter
|
6
6
|
def lint
|
7
7
|
backgrounds do |file, feature, background|
|
8
|
-
next unless background.key?
|
9
|
-
invalid_steps = background[
|
8
|
+
next unless background.key? :steps
|
9
|
+
invalid_steps = background[:steps].select { |step| step[:keyword] == 'When ' || step[:keyword] == 'Then ' }
|
10
10
|
next if invalid_steps.empty?
|
11
11
|
references = [reference(file, feature, background, invalid_steps[0])]
|
12
12
|
add_error(references, 'Just Given Steps allowed')
|
@@ -5,7 +5,7 @@ module GherkinLint
|
|
5
5
|
class BackgroundRequiresMultipleScenarios < Linter
|
6
6
|
def lint
|
7
7
|
backgrounds do |file, feature, background|
|
8
|
-
scenarios = feature[
|
8
|
+
scenarios = feature[:children].select { |element| element[:type] != :Background }
|
9
9
|
next if scenarios.length >= 2
|
10
10
|
|
11
11
|
references = [reference(file, feature, background)]
|
@@ -5,12 +5,12 @@ module GherkinLint
|
|
5
5
|
class BadScenarioName < Linter
|
6
6
|
def lint
|
7
7
|
scenarios do |file, feature, scenario|
|
8
|
-
next if scenario[
|
8
|
+
next if scenario[:name].empty?
|
9
9
|
references = [reference(file, feature, scenario)]
|
10
10
|
description = 'Prefer to rely just on Given and When steps when name your scenario to keep it stable'
|
11
11
|
bad_words = %w(test verif check)
|
12
12
|
bad_words.each do |bad_word|
|
13
|
-
add_error(references, description) if scenario[
|
13
|
+
add_error(references, description) if scenario[:name].downcase.include? bad_word
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -10,7 +10,7 @@ module GherkinLint
|
|
10
10
|
|
11
11
|
def lint
|
12
12
|
filled_scenarios do |file, feature, scenario|
|
13
|
-
scenario[
|
13
|
+
scenario[:steps].each do |step|
|
14
14
|
references = [reference(file, feature, scenario, step)]
|
15
15
|
add_warning(references, 'no verb') unless verb? step
|
16
16
|
end
|
@@ -18,7 +18,7 @@ module GherkinLint
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def verb?(step)
|
21
|
-
tagged = tagger.add_tags step[
|
21
|
+
tagged = tagger.add_tags step[:text]
|
22
22
|
step_verbs = verbs tagged
|
23
23
|
|
24
24
|
!step_verbs.empty?
|
@@ -5,9 +5,9 @@ module GherkinLint
|
|
5
5
|
class FileNameDiffersFeatureName < Linter
|
6
6
|
def lint
|
7
7
|
features do |file, feature|
|
8
|
-
next unless feature.include?
|
8
|
+
next unless feature.include? :name
|
9
9
|
expected_feature_name = title_case file
|
10
|
-
next if feature[
|
10
|
+
next if feature[:name].casecmp(expected_feature_name) == 0
|
11
11
|
references = [reference(file, feature)]
|
12
12
|
add_error(references, "Feature name should be '#{expected_feature_name}'")
|
13
13
|
end
|
@@ -5,7 +5,7 @@ module GherkinLint
|
|
5
5
|
class InvalidStepFlow < Linter
|
6
6
|
def lint
|
7
7
|
filled_scenarios do |file, feature, scenario|
|
8
|
-
steps = scenario[
|
8
|
+
steps = scenario[:steps].select { |step| step[:keyword] != 'And ' && step[:keyword] != 'But ' }
|
9
9
|
last_step_is_an_action(file, feature, scenario, steps)
|
10
10
|
given_after_non_given(file, feature, scenario, steps)
|
11
11
|
verification_before_action(file, feature, scenario, steps)
|
@@ -14,7 +14,7 @@ module GherkinLint
|
|
14
14
|
|
15
15
|
def last_step_is_an_action(file, feature, scenario, steps)
|
16
16
|
references = [reference(file, feature, scenario, steps.last)]
|
17
|
-
add_error(references, 'Last step is an action') if steps.last[
|
17
|
+
add_error(references, 'Last step is an action') if steps.last[:keyword] == 'When '
|
18
18
|
end
|
19
19
|
|
20
20
|
def given_after_non_given(file, feature, scenario, steps)
|
@@ -22,16 +22,16 @@ module GherkinLint
|
|
22
22
|
steps.each do |step|
|
23
23
|
references = [reference(file, feature, scenario, step)]
|
24
24
|
description = 'Given after Action or Verification'
|
25
|
-
add_error(references, description) if step[
|
25
|
+
add_error(references, description) if step[:keyword] == 'Given ' && last_step[:keyword] != 'Given '
|
26
26
|
last_step = step
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
def verification_before_action(file, feature, scenario, steps)
|
31
31
|
steps.each do |step|
|
32
|
-
break if step[
|
32
|
+
break if step[:keyword] == 'When '
|
33
33
|
references = [reference(file, feature, scenario, step)]
|
34
|
-
add_error(references, 'Missing Action') if step[
|
34
|
+
add_error(references, 'Missing Action') if step[:keyword] == 'Then '
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -5,10 +5,10 @@ module GherkinLint
|
|
5
5
|
class MissingExampleName < Linter
|
6
6
|
def lint
|
7
7
|
scenarios do |file, feature, scenario|
|
8
|
-
next unless scenario.key?
|
9
|
-
next unless scenario[
|
10
|
-
scenario[
|
11
|
-
name = example.key?(
|
8
|
+
next unless scenario.key? :examples
|
9
|
+
next unless scenario[:examples].length > 1
|
10
|
+
scenario[:examples].each do |example|
|
11
|
+
name = example.key?(:name) ? example[:name].strip : ''
|
12
12
|
next unless name.empty?
|
13
13
|
references = [reference(file, feature, scenario)]
|
14
14
|
add_error(references, 'No Example Name')
|
@@ -5,7 +5,7 @@ module GherkinLint
|
|
5
5
|
class MissingFeatureDescription < Linter
|
6
6
|
def lint
|
7
7
|
features do |file, feature|
|
8
|
-
name = feature.key?(
|
8
|
+
name = feature.key?(:description) ? feature[:description].strip : ''
|
9
9
|
next unless name.empty?
|
10
10
|
references = [reference(file, feature)]
|
11
11
|
add_error(references, 'Favor a user story as description')
|
@@ -5,7 +5,7 @@ module GherkinLint
|
|
5
5
|
class MissingFeatureName < Linter
|
6
6
|
def lint
|
7
7
|
features do |file, feature|
|
8
|
-
name = feature.key?(
|
8
|
+
name = feature.key?(:name) ? feature[:name].strip : ''
|
9
9
|
next unless name.empty?
|
10
10
|
references = [reference(file, feature)]
|
11
11
|
add_error(references, 'No Feature Name')
|
@@ -5,7 +5,7 @@ module GherkinLint
|
|
5
5
|
class MissingScenarioName < Linter
|
6
6
|
def lint
|
7
7
|
scenarios do |file, feature, scenario|
|
8
|
-
name = scenario.key?(
|
8
|
+
name = scenario.key?(:name) ? scenario[:name].strip : ''
|
9
9
|
references = [reference(file, feature, scenario)]
|
10
10
|
next unless name.empty?
|
11
11
|
add_error(references, 'No Scenario Name')
|
@@ -5,7 +5,7 @@ module GherkinLint
|
|
5
5
|
class MissingTestAction < Linter
|
6
6
|
def lint
|
7
7
|
filled_scenarios do |file, feature, scenario|
|
8
|
-
when_steps = scenario[
|
8
|
+
when_steps = scenario[:steps].select { |step| step[:keyword] == 'When ' }
|
9
9
|
next unless when_steps.empty?
|
10
10
|
references = [reference(file, feature, scenario)]
|
11
11
|
add_error(references, 'No \'When\'-Step')
|
@@ -5,7 +5,7 @@ module GherkinLint
|
|
5
5
|
class MissingVerification < Linter
|
6
6
|
def lint
|
7
7
|
filled_scenarios do |file, feature, scenario|
|
8
|
-
then_steps = scenario[
|
8
|
+
then_steps = scenario[:steps].select { |step| step[:keyword] == 'Then ' }
|
9
9
|
next unless then_steps.empty?
|
10
10
|
references = [reference(file, feature, scenario)]
|
11
11
|
add_error(references, 'No verification step')
|
@@ -5,7 +5,7 @@ module GherkinLint
|
|
5
5
|
class SameTagForAllScenarios < Linter
|
6
6
|
def lint
|
7
7
|
features do |file, feature|
|
8
|
-
next unless feature.include?
|
8
|
+
next unless feature.include? :children
|
9
9
|
|
10
10
|
lint_scenarios file, feature
|
11
11
|
lint_examples file, feature
|
@@ -16,7 +16,7 @@ module GherkinLint
|
|
16
16
|
tags = gather_same_tags feature
|
17
17
|
return if tags.nil?
|
18
18
|
return if tags.empty?
|
19
|
-
return unless feature[
|
19
|
+
return unless feature[:children].length > 1
|
20
20
|
references = [reference(file, feature)]
|
21
21
|
tags.each do |tag|
|
22
22
|
next if tag == '@skip'
|
@@ -26,10 +26,10 @@ module GherkinLint
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def lint_examples(file, feature)
|
29
|
-
feature[
|
29
|
+
feature[:children].each do |scenario|
|
30
30
|
tags = gather_same_tags_for_outline scenario
|
31
31
|
next if tags.nil? || tags.empty?
|
32
|
-
next unless scenario[
|
32
|
+
next unless scenario[:examples].length > 1
|
33
33
|
references = [reference(file, feature, scenario)]
|
34
34
|
tags.each do |tag|
|
35
35
|
next if tag == '@skip'
|
@@ -41,10 +41,10 @@ module GherkinLint
|
|
41
41
|
|
42
42
|
def gather_same_tags(feature)
|
43
43
|
result = nil
|
44
|
-
feature[
|
45
|
-
next if scenario[
|
46
|
-
return nil unless scenario.include?
|
47
|
-
tags = scenario[
|
44
|
+
feature[:children].each do |scenario|
|
45
|
+
next if scenario[:type] == :Background
|
46
|
+
return nil unless scenario.include? :tags
|
47
|
+
tags = scenario[:tags].map { |tag| tag[:name] }
|
48
48
|
result = tags if result.nil?
|
49
49
|
result &= tags
|
50
50
|
end
|
@@ -53,10 +53,10 @@ module GherkinLint
|
|
53
53
|
|
54
54
|
def gather_same_tags_for_outline(scenario)
|
55
55
|
result = nil
|
56
|
-
return result unless scenario.include?
|
57
|
-
scenario[
|
58
|
-
return nil unless example.include?
|
59
|
-
tags = example[
|
56
|
+
return result unless scenario.include? :examples
|
57
|
+
scenario[:examples].each do |example|
|
58
|
+
return nil unless example.include? :tags
|
59
|
+
tags = example[:tags].map { |tag| tag[:name] }
|
60
60
|
result = tags if result.nil?
|
61
61
|
result &= tags
|
62
62
|
end
|
@@ -5,7 +5,7 @@ module GherkinLint
|
|
5
5
|
class TooClumsy < Linter
|
6
6
|
def lint
|
7
7
|
filled_scenarios do |file, feature, scenario|
|
8
|
-
characters = scenario[
|
8
|
+
characters = scenario[:steps].map { |step| step[:text].length }.inject(0, :+)
|
9
9
|
next if characters < 400
|
10
10
|
references = [reference(file, feature, scenario)]
|
11
11
|
add_error(references, "Used #{characters} Characters")
|
@@ -5,9 +5,9 @@ module GherkinLint
|
|
5
5
|
class TooLongStep < Linter
|
6
6
|
def lint
|
7
7
|
steps do |file, feature, scenario, step|
|
8
|
-
next if step[
|
8
|
+
next if step[:text].length < 80
|
9
9
|
references = [reference(file, feature, scenario, step)]
|
10
|
-
add_error(references, "Used #{step[
|
10
|
+
add_error(references, "Used #{step[:text].length} characters")
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -31,8 +31,8 @@ module GherkinLint
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def tags_for_feature(feature)
|
34
|
-
return [] unless feature.include?
|
35
|
-
gather_tags(feature) + feature[
|
34
|
+
return [] unless feature.include? :children
|
35
|
+
gather_tags(feature) + feature[:children].map { |scenario| gather_tags(scenario) }.flatten
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -5,9 +5,9 @@ module GherkinLint
|
|
5
5
|
class TooManySteps < Linter
|
6
6
|
def lint
|
7
7
|
filled_scenarios do |file, feature, scenario|
|
8
|
-
next if scenario[
|
8
|
+
next if scenario[:steps].length < 10
|
9
9
|
references = [reference(file, feature, scenario)]
|
10
|
-
add_error(references, "Used #{scenario[
|
10
|
+
add_error(references, "Used #{scenario[:steps].length} Steps")
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -6,8 +6,8 @@ module GherkinLint
|
|
6
6
|
def lint
|
7
7
|
references_by_name = Hash.new []
|
8
8
|
scenarios do |file, feature, scenario|
|
9
|
-
next unless scenario.key?
|
10
|
-
scenario_name = "#{feature[
|
9
|
+
next unless scenario.key? :name
|
10
|
+
scenario_name = "#{feature[:name]}.#{scenario[:name]}"
|
11
11
|
references_by_name[scenario_name] = references_by_name[scenario_name] + [reference(file, feature, scenario)]
|
12
12
|
end
|
13
13
|
references_by_name.each do |name, references|
|
@@ -6,7 +6,7 @@ module GherkinLint
|
|
6
6
|
def lint
|
7
7
|
filled_scenarios do |file, feature, scenario|
|
8
8
|
known_vars = Set.new known_variables scenario
|
9
|
-
scenario[
|
9
|
+
scenario[:steps].each do |step|
|
10
10
|
step_vars(step).each do |used_var|
|
11
11
|
next if known_vars.include? used_var
|
12
12
|
references = [reference(file, feature, scenario)]
|
@@ -17,10 +17,15 @@ module GherkinLint
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def step_vars(step)
|
20
|
-
vars = gather_vars step[
|
21
|
-
vars
|
22
|
-
vars + (step[
|
23
|
-
|
20
|
+
vars = gather_vars step[:text]
|
21
|
+
return vars unless step.include? :argument
|
22
|
+
vars + gather_vars_from_argument(step[:argument])
|
23
|
+
end
|
24
|
+
|
25
|
+
def gather_vars_from_argument(argument)
|
26
|
+
return gather_vars argument[:content] if argument[:type] == :DocString
|
27
|
+
(argument[:rows] || []).map do |row|
|
28
|
+
row[:cells].map { |value| gather_vars value[:value] }.flatten
|
24
29
|
end.flatten
|
25
30
|
end
|
26
31
|
|
@@ -29,9 +34,9 @@ module GherkinLint
|
|
29
34
|
end
|
30
35
|
|
31
36
|
def known_variables(scenario)
|
32
|
-
(scenario[
|
33
|
-
next unless example.key?
|
34
|
-
example[
|
37
|
+
(scenario[:examples] || []).map do |example|
|
38
|
+
next unless example.key? :tableHeader
|
39
|
+
example[:tableHeader][:cells].map { |cell| cell[:value].strip }
|
35
40
|
end.flatten
|
36
41
|
end
|
37
42
|
end
|
@@ -5,10 +5,10 @@ module GherkinLint
|
|
5
5
|
class UnusedVariable < Linter
|
6
6
|
def lint
|
7
7
|
scenarios do |file, feature, scenario|
|
8
|
-
next unless scenario.key?
|
9
|
-
scenario[
|
10
|
-
next unless example.key?
|
11
|
-
example[
|
8
|
+
next unless scenario.key? :examples
|
9
|
+
scenario[:examples].each do |example|
|
10
|
+
next unless example.key? :tableHeader
|
11
|
+
example[:tableHeader][:cells].map { |cell| cell[:value] }.each do |variable|
|
12
12
|
references = [reference(file, feature, scenario)]
|
13
13
|
add_error(references, "'<#{variable}>' is unused") unless used?(variable, scenario)
|
14
14
|
end
|
@@ -18,9 +18,10 @@ module GherkinLint
|
|
18
18
|
|
19
19
|
def used?(variable, scenario)
|
20
20
|
variable = "<#{variable}>"
|
21
|
-
return false unless scenario.key?
|
22
|
-
scenario[
|
23
|
-
return true if step[
|
21
|
+
return false unless scenario.key? :steps
|
22
|
+
scenario[:steps].each do |step|
|
23
|
+
return true if step[:text].include? variable
|
24
|
+
next unless step.include? :argument
|
24
25
|
return true if used_in_docstring?(variable, step)
|
25
26
|
return true if used_in_table?(variable, step)
|
26
27
|
end
|
@@ -28,13 +29,13 @@ module GherkinLint
|
|
28
29
|
end
|
29
30
|
|
30
31
|
def used_in_docstring?(variable, step)
|
31
|
-
step
|
32
|
+
step[:argument][:type] == :DocString && step[:argument][:content].include?(variable)
|
32
33
|
end
|
33
34
|
|
34
35
|
def used_in_table?(variable, step)
|
35
|
-
return false unless step
|
36
|
-
step[
|
37
|
-
row[
|
36
|
+
return false unless step[:argument][:type] == :DataTable
|
37
|
+
step[:argument][:rows].each do |row|
|
38
|
+
row[:cells].each { |value| return true if value[:value].include?(variable) }
|
38
39
|
end
|
39
40
|
false
|
40
41
|
end
|
@@ -17,20 +17,20 @@ module GherkinLint
|
|
17
17
|
|
18
18
|
def scenarios_with_steps(feature)
|
19
19
|
scenarios = 0
|
20
|
-
return 0 unless feature.key?
|
21
|
-
feature[
|
22
|
-
next unless scenario.include?
|
20
|
+
return 0 unless feature.key? :children
|
21
|
+
feature[:children].each do |scenario|
|
22
|
+
next unless scenario.include? :steps
|
23
23
|
scenarios += 1
|
24
24
|
end
|
25
25
|
scenarios
|
26
26
|
end
|
27
27
|
|
28
28
|
def gather_givens(feature)
|
29
|
-
return unless feature.include?
|
29
|
+
return unless feature.include? :children
|
30
30
|
has_non_given_step = false
|
31
|
-
feature[
|
32
|
-
next unless scenario.include?
|
33
|
-
has_non_given_step = true unless scenario[
|
31
|
+
feature[:children].each do |scenario|
|
32
|
+
next unless scenario.include? :steps
|
33
|
+
has_non_given_step = true unless scenario[:steps].first[:keyword] == 'Given '
|
34
34
|
end
|
35
35
|
return if has_non_given_step
|
36
36
|
|
@@ -40,11 +40,11 @@ module GherkinLint
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def expanded_steps(feature)
|
43
|
-
feature[
|
44
|
-
next unless scenario[
|
45
|
-
next unless scenario.include?
|
46
|
-
prototypes = [render_step(scenario[
|
47
|
-
prototypes = expand_examples(scenario[
|
43
|
+
feature[:children].each do |scenario|
|
44
|
+
next unless scenario[:type] != :Background
|
45
|
+
next unless scenario.include? :steps
|
46
|
+
prototypes = [render_step(scenario[:steps].first)]
|
47
|
+
prototypes = expand_examples(scenario[:examples], prototypes) if scenario.key? :examples
|
48
48
|
prototypes.each { |prototype| yield prototype }
|
49
49
|
end
|
50
50
|
end
|
@@ -58,10 +58,12 @@ module GherkinLint
|
|
58
58
|
|
59
59
|
def expand_outlines(sentence, example)
|
60
60
|
result = []
|
61
|
-
headers = example[
|
62
|
-
example[
|
61
|
+
headers = example[:tableHeader][:cells].map { |cell| cell[:value] }
|
62
|
+
example[:tableBody].each do |row| # .slice(1, example[:tableBody].length).each do |row|
|
63
63
|
modified_sentence = sentence.dup
|
64
|
-
headers.zip(row[
|
64
|
+
headers.zip(row[:cells].map { |cell| cell[:value] }).map do |key, value|
|
65
|
+
modified_sentence.gsub!("<#{key}>", value)
|
66
|
+
end
|
65
67
|
result.push modified_sentence
|
66
68
|
end
|
67
69
|
result
|
@@ -28,10 +28,10 @@ module GherkinLint
|
|
28
28
|
|
29
29
|
def gather_scenarios(file, feature)
|
30
30
|
scenarios = []
|
31
|
-
return scenarios unless feature.include?
|
32
|
-
feature[
|
33
|
-
next unless scenario[
|
34
|
-
next unless scenario.include?
|
31
|
+
return scenarios unless feature.include? :children
|
32
|
+
feature[:children].each do |scenario|
|
33
|
+
next unless scenario[:type] == :Scenario
|
34
|
+
next unless scenario.include? :steps
|
35
35
|
scenarios.push generate_reference(file, feature, scenario)
|
36
36
|
end
|
37
37
|
scenarios
|
@@ -40,7 +40,7 @@ module GherkinLint
|
|
40
40
|
def generate_reference(file, feature, scenario)
|
41
41
|
reference = {}
|
42
42
|
reference[:reference] = reference(file, feature, scenario)
|
43
|
-
reference[:text] = scenario[
|
43
|
+
reference[:text] = scenario[:steps].map { |step| render_step(step) }.join ' '
|
44
44
|
reference
|
45
45
|
end
|
46
46
|
end
|
metadata
CHANGED
@@ -1,94 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gherkin_lint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.4.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Stefan Rohe
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2016-
|
11
|
+
date: 2016-08-11 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: gherkin
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
19
|
+
version: 4.0.0
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
26
|
+
version: 4.0.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: term-ansicolor
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: 1.3.2
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 1.3.2
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: amatch
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: 0.3.0
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 0.3.0
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: engtagger
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - ">="
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: 0.2.0
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - ">="
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: 0.2.0
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: aruba
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - ">="
|
84
74
|
- !ruby/object:Gem::Version
|
85
75
|
version: 0.6.2
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - ">="
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: 0.6.2
|
94
83
|
description: Lint Gherkin Files
|
@@ -98,8 +87,8 @@ executables:
|
|
98
87
|
extensions: []
|
99
88
|
extra_rdoc_files: []
|
100
89
|
files:
|
101
|
-
- .rubocop.yml
|
102
|
-
- .travis.yml
|
90
|
+
- ".rubocop.yml"
|
91
|
+
- ".travis.yml"
|
103
92
|
- Dockerfile
|
104
93
|
- Gemfile
|
105
94
|
- Guardfile
|
@@ -169,26 +158,25 @@ files:
|
|
169
158
|
- lib/gherkin_lint/linter/use_outline.rb
|
170
159
|
homepage: http://github.com/funkwerk/gherkin_lint/
|
171
160
|
licenses: []
|
161
|
+
metadata: {}
|
172
162
|
post_install_message:
|
173
163
|
rdoc_options: []
|
174
164
|
require_paths:
|
175
165
|
- lib
|
176
166
|
required_ruby_version: !ruby/object:Gem::Requirement
|
177
|
-
none: false
|
178
167
|
requirements:
|
179
|
-
- -
|
168
|
+
- - ">="
|
180
169
|
- !ruby/object:Gem::Version
|
181
170
|
version: '0'
|
182
171
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
|
-
none: false
|
184
172
|
requirements:
|
185
|
-
- -
|
173
|
+
- - ">="
|
186
174
|
- !ruby/object:Gem::Version
|
187
175
|
version: '0'
|
188
176
|
requirements: []
|
189
177
|
rubyforge_project:
|
190
|
-
rubygems_version:
|
178
|
+
rubygems_version: 2.2.2
|
191
179
|
signing_key:
|
192
|
-
specification_version:
|
180
|
+
specification_version: 4
|
193
181
|
summary: Gherkin Lint
|
194
182
|
test_files: []
|