chutney 2.0.3.1 → 3.0.0.beta.2
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 +4 -4
- data/.rubocop.yml +7 -1
- data/.rufo +1 -0
- data/Gemfile +2 -0
- data/README.md +6 -1
- data/Rakefile +2 -0
- data/chutney.gemspec +14 -6
- data/config/chutney.yml +4 -0
- data/config/cucumber.yml +1 -0
- data/docs/usage/rules.md +7 -1
- data/exe/chutney +20 -0
- data/lib/chutney.rb +20 -20
- data/lib/chutney/configuration.rb +7 -1
- data/lib/chutney/formatter.rb +2 -0
- data/lib/chutney/formatter/json_formatter.rb +2 -0
- data/lib/chutney/formatter/pie_formatter.rb +2 -0
- data/lib/chutney/formatter/rainbow_formatter.rb +6 -3
- data/lib/chutney/issue.rb +2 -0
- data/lib/chutney/linter.rb +65 -61
- data/lib/chutney/linter/avoid_full_stop.rb +3 -1
- data/lib/chutney/linter/avoid_outline_for_single_example.rb +8 -6
- data/lib/chutney/linter/avoid_scripting.rb +6 -4
- data/lib/chutney/linter/avoid_typographers_quotes.rb +39 -0
- data/lib/chutney/linter/background_does_more_than_setup.rb +8 -6
- data/lib/chutney/linter/background_requires_multiple_scenarios.rb +6 -3
- data/lib/chutney/linter/bad_scenario_name.rb +4 -2
- data/lib/chutney/linter/empty_feature_file.rb +10 -0
- data/lib/chutney/linter/file_name_differs_feature_name.rb +4 -2
- data/lib/chutney/linter/givens_after_background.rb +5 -6
- data/lib/chutney/linter/invalid_file_name.rb +2 -0
- data/lib/chutney/linter/invalid_step_flow.rb +7 -7
- data/lib/chutney/linter/missing_example_name.rb +7 -5
- data/lib/chutney/linter/missing_feature_description.rb +6 -3
- data/lib/chutney/linter/missing_feature_name.rb +5 -2
- data/lib/chutney/linter/missing_scenario_name.rb +3 -4
- data/lib/chutney/linter/missing_test_action.rb +3 -1
- data/lib/chutney/linter/missing_verification.rb +3 -1
- data/lib/chutney/linter/required_tags_starts_with.rb +2 -0
- data/lib/chutney/linter/same_tag_for_all_scenarios.rb +11 -10
- data/lib/chutney/linter/scenario_names_match.rb +4 -3
- data/lib/chutney/linter/tag_used_multiple_times.rb +2 -0
- data/lib/chutney/linter/too_clumsy.rb +3 -1
- data/lib/chutney/linter/too_long_step.rb +4 -2
- data/lib/chutney/linter/too_many_different_tags.rb +4 -2
- data/lib/chutney/linter/too_many_steps.rb +4 -2
- data/lib/chutney/linter/too_many_tags.rb +2 -0
- data/lib/chutney/linter/unique_scenario_names.rb +3 -3
- data/lib/chutney/linter/unknown_variable.rb +13 -13
- data/lib/chutney/linter/unused_variable.rb +13 -13
- data/lib/chutney/linter/use_background.rb +17 -16
- data/lib/chutney/linter/use_outline.rb +8 -7
- data/lib/chutney/version.rb +3 -1
- data/lib/config/locales/en.yml +6 -0
- data/spec/chutney_spec.rb +2 -0
- data/spec/spec_helper.rb +2 -0
- metadata +37 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c99f32f7cba016b8d419d1867c5005b448e05939565afff74db238c68222f2d9
|
4
|
+
data.tar.gz: 9f21a905656a69d4bbfc7288b7abcec37e36e3fb5950c852aa8c6e4183e52cd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a4339e31214900e809bdbdaf968a2d21af9bc7526365cd2f00a17745b10272947114c018e6b182c6679769636ffc127d6880d69dbbbb8dc66f0d5f5762a410d
|
7
|
+
data.tar.gz: b755781258f1781e4586a77f639682b7ebb0a584d50aa0c001a7eca5c5e8b0c16487b2d1dd1978e97744c5f7ec163ea169ae8d9c6114e1ed22cda716e3173a34
|
data/.rubocop.yml
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
|
9
9
|
# Offense count: 1
|
10
10
|
Metrics/AbcSize:
|
11
|
-
|
11
|
+
Enabled: false
|
12
12
|
|
13
13
|
# Offense count: 1
|
14
14
|
# Configuration parameters: CountComments.
|
@@ -55,4 +55,10 @@ Layout/TrailingWhitespace:
|
|
55
55
|
Enabled: false
|
56
56
|
|
57
57
|
Style/FrozenStringLiteralComment:
|
58
|
+
Enabled: true
|
59
|
+
|
60
|
+
Style/StringConcatenation:
|
58
61
|
Enabled: false
|
62
|
+
|
63
|
+
AllCops:
|
64
|
+
NewCops: enable
|
data/.rufo
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
quote_style :single
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -12,10 +12,15 @@
|
|
12
12
|
<div align="center">
|
13
13
|
|
14
14
|
[](https://badge.fury.io/rb/chutney)
|
15
|
+
[](https://rubygems.org/gems/chutney)
|
15
16
|

|
16
17
|
[](https://www.codefactor.io/repository/github/billyruffian/chutney)
|
17
18
|

|
18
19
|
|
19
20
|
</div>
|
20
21
|
|
21
|
-
Read the documentation [here](https://billyruffian.github.io/chutney/).
|
22
|
+
Read the documentation [here](https://billyruffian.github.io/chutney/).
|
23
|
+
|
24
|
+
## Notes
|
25
|
+
|
26
|
+
Chutney 3+ (in beta) has replaced its direct dependency on Cucumber and instead uses the excellent [cuke_modeller](https://github.com/enkessler/cuke_modeler) to parse your feature files.
|
data/Rakefile
CHANGED
data/chutney.gemspec
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Disable rubocop checks for the .gemspec
|
2
4
|
# I'll take the output from 'bundle gem new' to be authoritative
|
3
5
|
# rubocop:disable all
|
@@ -12,9 +14,13 @@ Gem::Specification.new do |spec|
|
|
12
14
|
spec.authors = ['Nigel Brookes-Thomas', 'Stefan Rohe', 'Nishtha Argawal', 'John Gluck']
|
13
15
|
spec.email = ['nigel@brookes-thomas.co.uk']
|
14
16
|
|
15
|
-
spec.summary = 'A linter for
|
16
|
-
spec.description = 'A linter for your Cucumber features. '
|
17
|
-
|
17
|
+
spec.summary = 'A linter for multi-lingual Gherkin'
|
18
|
+
spec.description = 'A linter for your Cucumber features. ' \
|
19
|
+
'Making sure you have nice, expressible Gherkin is ' \
|
20
|
+
'essential is making sure you have a readable test-base. ' \
|
21
|
+
'Chutney is designed to sniff out smells in your feature ' \
|
22
|
+
'files. ' \
|
23
|
+
'It supports any spoken language Cucumber supports.'
|
18
24
|
|
19
25
|
spec.homepage = 'https://billyruffian.github.io/chutney/'
|
20
26
|
spec.license = 'MIT'
|
@@ -43,18 +49,20 @@ Gem::Specification.new do |spec|
|
|
43
49
|
spec.require_paths = ['lib']
|
44
50
|
|
45
51
|
spec.add_runtime_dependency 'amatch', '~> 0.4.0'
|
46
|
-
spec.add_runtime_dependency '
|
52
|
+
spec.add_runtime_dependency 'cuke_modeler', '~> 3.3'
|
47
53
|
spec.add_runtime_dependency 'i18n', '~> 1.8.2'
|
48
54
|
spec.add_runtime_dependency 'pastel', '~> 0.7'
|
49
55
|
spec.add_runtime_dependency 'tty-pie', '~> 0.3'
|
50
56
|
|
51
57
|
|
52
58
|
spec.add_development_dependency 'coveralls', '~> 0.8'
|
53
|
-
spec.add_development_dependency 'cucumber', '~>
|
59
|
+
spec.add_development_dependency 'cucumber', '~> 5.1'
|
60
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.0'
|
54
61
|
spec.add_development_dependency 'rake', '~> 13.0'
|
55
62
|
spec.add_development_dependency 'rerun', '~> 0.13'
|
56
63
|
spec.add_development_dependency 'rspec-expectations', '~> 3.0'
|
57
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
64
|
+
spec.add_development_dependency 'rubocop', '~> 0.89.0'
|
58
65
|
spec.add_development_dependency 'rspec', '~> 3.8'
|
59
66
|
|
67
|
+
spec.required_ruby_version = '~> 2.6'
|
60
68
|
end
|
data/config/chutney.yml
CHANGED
@@ -4,12 +4,16 @@ AvoidFullStop:
|
|
4
4
|
Enabled: true
|
5
5
|
AvoidScripting:
|
6
6
|
Enabled: true
|
7
|
+
AvoidTypographersQuotes:
|
8
|
+
Enabled: true
|
7
9
|
BackgroundDoesMoreThanSetup:
|
8
10
|
Enabled: true
|
9
11
|
BackgroundRequiresMultipleScenarios:
|
10
12
|
Enabled: true
|
11
13
|
BadScenarioName:
|
12
14
|
Enabled: true
|
15
|
+
EmptyFeatureFile:
|
16
|
+
Enabled: true
|
13
17
|
FileNameDiffersFeatureName:
|
14
18
|
Enabled: true
|
15
19
|
GivensAfterBackground:
|
data/config/cucumber.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
default: --publish-quiet
|
data/docs/usage/rules.md
CHANGED
@@ -18,6 +18,9 @@ Chutney enforces its rules with the linters. These are:
|
|
18
18
|
[AvoidScripting](https://github.com/BillyRuffian/chutney/blob/master/features/avoid_scripting.feature)
|
19
19
|
: You have a lot of steps, are you sure you're not scripting the scenario when you should be specifying the behaviour of the system?
|
20
20
|
|
21
|
+
[AvoidTypographersQuotes](https://github.com/BillyRuffian/chutney/blob/master/features/avoid_typographers_quotes.feature)
|
22
|
+
: Cutting and pasting from Word documents? Is that pasting in curly-quotes instead of neutral ones you would type on a keyboard? Are you sure that's what you want?
|
23
|
+
|
21
24
|
[BackgroundDoesMoreThanSetup](https://github.com/BillyRuffian/chutney/blob/master/features/background_does_more_than_setup.feature)
|
22
25
|
: Background in feature files should only do setup activity and so they should only contain `Given` steps.
|
23
26
|
|
@@ -27,6 +30,9 @@ Chutney enforces its rules with the linters. These are:
|
|
27
30
|
[BadScenarioName](https://github.com/BillyRuffian/chutney/blob/master/features/bad_scenario_name.feature)
|
28
31
|
: You should avoid using words like 'test' or 'check' in your scenario names, instead you should define the behaviour of your system.
|
29
32
|
|
33
|
+
[EmptyFeatureFile](https://github.com/BillyRuffian/chutney/blob/master/features/empty_feature_file.feature)
|
34
|
+
: The feature should have content and should avoid committing empty features to repositories.
|
35
|
+
|
30
36
|
[FileNameDiffersFeatureName](https://github.com/BillyRuffian/chutney/blob/master/features/file_name_differs_feature_name.feature)
|
31
37
|
: The feature should have a name that follows the file name.
|
32
38
|
|
@@ -76,7 +82,7 @@ Chutney enforces its rules with the linters. These are:
|
|
76
82
|
: This is a very long step. Consider writing it more concisely.
|
77
83
|
|
78
84
|
[TooManyDifferentTags](https://github.com/BillyRuffian/chutney/blob/master/features/too_many_different_tags.feature)
|
79
|
-
: This feature has a lot of
|
85
|
+
: This feature has a lot of different tags.
|
80
86
|
|
81
87
|
[TooManySteps](https://github.com/BillyRuffian/chutney/blob/master/features/too_many_steps.feature)
|
82
88
|
: This feature has a lot of steps. Consider writing it more concisely.
|
data/exe/chutney
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require 'chutney'
|
3
5
|
require 'chutney/formatter'
|
4
6
|
require 'chutney/formatter/json_formatter'
|
@@ -17,6 +19,24 @@ OptionParser.new do |opts|
|
|
17
19
|
|
18
20
|
formatters << formatter
|
19
21
|
end
|
22
|
+
|
23
|
+
opts.on('-l',
|
24
|
+
'--linters',
|
25
|
+
'List the linter status by this configuration and exit') do
|
26
|
+
pastel = Pastel.new
|
27
|
+
chutney_config = Chutney::ChutneyLint.new.configuration
|
28
|
+
max_name_length = chutney_config.keys.map(&:length).max + 1
|
29
|
+
chutney_config.each do |linter, value|
|
30
|
+
print pastel.cyan(linter.ljust(max_name_length))
|
31
|
+
|
32
|
+
if value['Enabled']
|
33
|
+
puts pastel.green('enabled')
|
34
|
+
else
|
35
|
+
puts pastel.red('disabled')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
exit
|
39
|
+
end
|
20
40
|
end.parse!
|
21
41
|
|
22
42
|
formatters << 'RainbowFormatter' if formatters.empty?
|
data/lib/chutney.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'amatch'
|
4
|
+
|
2
5
|
require 'chutney/configuration'
|
3
6
|
require 'chutney/linter'
|
4
7
|
require 'chutney/linter/avoid_full_stop'
|
5
8
|
require 'chutney/linter/avoid_outline_for_single_example'
|
6
9
|
require 'chutney/linter/avoid_scripting'
|
10
|
+
require 'chutney/linter/avoid_typographers_quotes'
|
7
11
|
require 'chutney/linter/background_does_more_than_setup'
|
8
12
|
require 'chutney/linter/background_requires_multiple_scenarios'
|
9
13
|
require 'chutney/linter/bad_scenario_name'
|
14
|
+
require 'chutney/linter/empty_feature_file'
|
10
15
|
require 'chutney/linter/file_name_differs_feature_name'
|
11
16
|
require 'chutney/linter/givens_after_background'
|
12
17
|
require 'chutney/linter/invalid_file_name'
|
@@ -31,9 +36,11 @@ require 'chutney/linter/unknown_variable'
|
|
31
36
|
require 'chutney/linter/unused_variable'
|
32
37
|
require 'chutney/linter/use_background'
|
33
38
|
require 'chutney/linter/use_outline'
|
39
|
+
|
40
|
+
require 'cuke_modeler'
|
34
41
|
require 'forwardable'
|
35
|
-
require 'gherkin/dialect'
|
36
|
-
require 'gherkin/parser'
|
42
|
+
# require 'gherkin/dialect'
|
43
|
+
# require 'gherkin/parser'
|
37
44
|
require 'i18n'
|
38
45
|
require 'set'
|
39
46
|
require 'yaml'
|
@@ -43,9 +50,8 @@ module Chutney
|
|
43
50
|
class ChutneyLint
|
44
51
|
extend Forwardable
|
45
52
|
attr_accessor :verbose
|
46
|
-
attr_reader :files
|
47
|
-
|
48
|
-
|
53
|
+
attr_reader :files, :results
|
54
|
+
|
49
55
|
def_delegators :@files, :<<, :clear, :delete, :include?
|
50
56
|
|
51
57
|
def initialize(*files)
|
@@ -54,9 +60,9 @@ module Chutney
|
|
54
60
|
i18n_paths = Dir[File.expand_path(File.join(__dir__, 'config/locales')) + '/*.yml']
|
55
61
|
return if I18n.load_path.include?(i18n_paths)
|
56
62
|
|
57
|
-
I18n.load_path
|
63
|
+
I18n.load_path += i18n_paths
|
58
64
|
end
|
59
|
-
|
65
|
+
|
60
66
|
def configuration
|
61
67
|
unless @config
|
62
68
|
default_file = [File.expand_path('..', __dir__), '**/config', 'chutney.yml']
|
@@ -65,11 +71,11 @@ module Chutney
|
|
65
71
|
end
|
66
72
|
@config
|
67
73
|
end
|
68
|
-
|
74
|
+
|
69
75
|
def configuration=(config)
|
70
76
|
@config = config
|
71
77
|
end
|
72
|
-
|
78
|
+
|
73
79
|
def analyse
|
74
80
|
files.each do |f|
|
75
81
|
lint(f)
|
@@ -79,25 +85,19 @@ module Chutney
|
|
79
85
|
# alias for non-british English
|
80
86
|
# https://dictionary.cambridge.org/dictionary/english/analyse
|
81
87
|
alias analyze analyse
|
82
|
-
|
88
|
+
|
83
89
|
def linters
|
84
90
|
@linters ||= Linter.descendants.filter { |l| configuration.dig(l.linter_name, 'Enabled') }
|
85
91
|
end
|
86
|
-
|
92
|
+
|
87
93
|
def linters=(*linters)
|
88
94
|
@linters = linters
|
89
95
|
end
|
90
|
-
|
96
|
+
|
91
97
|
private
|
92
|
-
|
93
|
-
def parse(text)
|
94
|
-
@parser ||= Gherkin::Parser.new
|
95
|
-
scanner = Gherkin::TokenScanner.new(text)
|
96
|
-
@parser.parse(scanner)
|
97
|
-
end
|
98
|
-
|
98
|
+
|
99
99
|
def lint(file)
|
100
|
-
parsed =
|
100
|
+
parsed = CukeModeler::FeatureFile.new(file)
|
101
101
|
linters.each do |linter_class|
|
102
102
|
linter = linter_class.new(file, parsed, configuration[linter_class.linter_name])
|
103
103
|
linter.lint
|
@@ -1,4 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'delegate'
|
3
|
+
|
2
4
|
module Chutney
|
3
5
|
# gherkin_lint configuration object
|
4
6
|
class Configuration < SimpleDelegator
|
@@ -18,7 +20,11 @@ module Chutney
|
|
18
20
|
end
|
19
21
|
|
20
22
|
def load_user_configuration
|
21
|
-
|
23
|
+
config_files = ['chutney.yml', '.chutney.yml'].map do |fname|
|
24
|
+
Dir.glob(File.join(Dir.pwd, '**', fname))
|
25
|
+
end.flatten
|
26
|
+
|
27
|
+
config_file = config_files.first
|
22
28
|
merge_config(config_file) if !config_file.nil? && File.exist?(config_file)
|
23
29
|
end
|
24
30
|
|
data/lib/chutney/formatter.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'pastel'
|
2
4
|
|
3
5
|
module Chutney
|
@@ -16,7 +18,7 @@ module Chutney
|
|
16
18
|
linter.filter { |l| !l[:issues].empty? }.each do |linter_with_issues|
|
17
19
|
|
18
20
|
put_linter(linter_with_issues)
|
19
|
-
linter_with_issues[:issues].each { |i| put_issue(i) }
|
21
|
+
linter_with_issues[:issues].each { |i| put_issue(file, i) }
|
20
22
|
end
|
21
23
|
end
|
22
24
|
put_summary
|
@@ -30,8 +32,9 @@ module Chutney
|
|
30
32
|
puts @pastel.red(" #{linter[:linter]}")
|
31
33
|
end
|
32
34
|
|
33
|
-
def put_issue(issue)
|
34
|
-
puts " #{
|
35
|
+
def put_issue(file, issue)
|
36
|
+
puts " #{issue[:message]}"
|
37
|
+
puts " #{@pastel.dim file.to_s}:#{@pastel.dim(issue.dig(:location, :line))}"
|
35
38
|
end
|
36
39
|
|
37
40
|
def put_summary
|
data/lib/chutney/issue.rb
CHANGED
data/lib/chutney/linter.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# gherkin utilities
|
4
|
+
|
2
5
|
module Chutney
|
3
6
|
# base class for all linters
|
4
7
|
class Linter
|
5
8
|
attr_accessor :issues
|
6
|
-
attr_reader :filename
|
7
|
-
attr_reader :configuration
|
9
|
+
attr_reader :filename, :configuration
|
8
10
|
|
9
11
|
Lint = Struct.new(:message, :gherkin_type, :location, :feature, :scenario, :step, keyword_init: true)
|
10
12
|
|
@@ -17,8 +19,8 @@ module Chutney
|
|
17
19
|
@filename = filename
|
18
20
|
@issues = []
|
19
21
|
@configuration = configuration
|
20
|
-
language = @content.dig(:feature, :language) || 'en'
|
21
|
-
@dialect = Gherkin::Dialect.for(language)
|
22
|
+
# language = @content.dig(:feature, :language) || 'en'
|
23
|
+
# @dialect = Gherkin::Dialect.for(language)
|
22
24
|
end
|
23
25
|
|
24
26
|
def lint
|
@@ -26,63 +28,71 @@ module Chutney
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def and_word?(word)
|
29
|
-
|
31
|
+
dialect_word(:and).include?(word)
|
30
32
|
end
|
31
33
|
|
32
34
|
def background_word?(word)
|
33
|
-
|
35
|
+
dialect_word(:background).include?(word)
|
34
36
|
end
|
35
37
|
|
36
38
|
def but_word?(word)
|
37
|
-
|
39
|
+
dialect_word(:but).include?(word)
|
38
40
|
end
|
39
41
|
|
40
42
|
def examples_word?(word)
|
41
|
-
|
43
|
+
dialect_word(:examples).include?(word)
|
42
44
|
end
|
43
45
|
|
44
46
|
def feature_word?(word)
|
45
|
-
|
47
|
+
dialect_word(:feature).include?(word)
|
46
48
|
end
|
47
49
|
|
48
50
|
def given_word?(word)
|
49
|
-
|
51
|
+
dialect_word(:given).include?(word)
|
50
52
|
end
|
51
53
|
|
52
54
|
def scenario_outline_word?(word)
|
53
|
-
|
55
|
+
dialect_word(:scenarioOutline).include?(word)
|
54
56
|
end
|
55
57
|
|
56
58
|
def then_word?(word)
|
57
|
-
|
59
|
+
dialect_word(:then).include?(word)
|
58
60
|
end
|
59
61
|
|
60
62
|
def when_word?(word)
|
61
|
-
|
63
|
+
dialect_word(:when).include?(word)
|
64
|
+
end
|
65
|
+
|
66
|
+
def dialect_word(word)
|
67
|
+
CukeModeler::Parsing.dialects[dialect][word.to_s].map(&:strip)
|
68
|
+
end
|
69
|
+
|
70
|
+
def dialect
|
71
|
+
@content.feature&.parsing_data&.dig(:language) || 'en'
|
62
72
|
end
|
63
73
|
|
64
74
|
def tags_for(element)
|
65
|
-
|
66
|
-
|
67
|
-
element[:tags].map { |tag| tag[:name][1..-1] }
|
75
|
+
element.tags.map { |tag| tag.name[1..-1] }
|
68
76
|
end
|
69
77
|
|
70
|
-
def add_issue(message, feature, scenario = nil,
|
78
|
+
def add_issue(message, feature = nil, scenario = nil, item = nil)
|
71
79
|
issues << Lint.new(
|
72
80
|
message: message,
|
73
|
-
gherkin_type: type(feature, scenario,
|
74
|
-
location: location(feature, scenario,
|
75
|
-
feature: feature
|
76
|
-
scenario: scenario
|
77
|
-
step:
|
81
|
+
gherkin_type: type(feature, scenario, item),
|
82
|
+
location: location(feature, scenario, item),
|
83
|
+
feature: feature&.name,
|
84
|
+
scenario: scenario&.name,
|
85
|
+
step: item&.parsing_data&.dig(:name)
|
78
86
|
).to_h
|
79
87
|
end
|
80
88
|
|
81
89
|
def location(feature, scenario, step)
|
82
90
|
if step
|
83
|
-
step[:location]
|
84
|
-
|
85
|
-
scenario
|
91
|
+
step.parsing_data[:location]
|
92
|
+
elsif scenario
|
93
|
+
scenario.parsing_data.dig(:scenario, :location) || scenario.parsing_data.dig(:background, :location)
|
94
|
+
else
|
95
|
+
feature ? feature.parsing_data[:location] : 0
|
86
96
|
end
|
87
97
|
end
|
88
98
|
|
@@ -96,77 +106,71 @@ module Chutney
|
|
96
106
|
|
97
107
|
def feature
|
98
108
|
if block_given?
|
99
|
-
yield(@content
|
109
|
+
yield(@content.feature) if @content.feature
|
100
110
|
else
|
101
|
-
@content
|
111
|
+
@content.feature
|
102
112
|
end
|
103
113
|
end
|
104
114
|
|
105
|
-
def elements
|
115
|
+
def elements
|
116
|
+
return [] unless feature
|
117
|
+
|
106
118
|
if block_given?
|
107
|
-
feature
|
119
|
+
feature.children.each do |child|
|
108
120
|
next if off_switch?(child)
|
109
121
|
|
110
122
|
yield(feature, child)
|
111
123
|
end
|
112
124
|
else
|
113
|
-
feature
|
125
|
+
feature.children
|
114
126
|
end
|
115
127
|
end
|
116
|
-
|
128
|
+
|
117
129
|
def off_switch?(element = feature)
|
118
|
-
off_switch = element
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
130
|
+
off_switch = element.tags
|
131
|
+
.then { |tags| tags || [] }
|
132
|
+
.filter { |tag| tag[:type] == :Tag }
|
133
|
+
.filter { |tag| tag[:name] == "@disable#{linter_name}" }
|
134
|
+
.count
|
135
|
+
.positive?
|
124
136
|
off_switch ||= off_switch?(feature) unless element == feature
|
125
137
|
off_switch
|
126
138
|
end
|
127
139
|
|
128
140
|
def background
|
129
|
-
if block_given?
|
130
|
-
|
131
|
-
next unless child[:type] == :Background
|
132
|
-
|
133
|
-
yield(feature, child)
|
134
|
-
end
|
141
|
+
if block_given?
|
142
|
+
yield(feature, feature&.background)
|
135
143
|
else
|
136
|
-
|
144
|
+
feature&.background
|
137
145
|
end
|
138
146
|
end
|
139
147
|
|
140
148
|
def scenarios
|
141
149
|
if block_given?
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
yield(feature, child)
|
150
|
+
feature&.tests&.each do |test|
|
151
|
+
yield(feature, test)
|
146
152
|
end
|
153
|
+
|
147
154
|
else
|
148
|
-
|
155
|
+
feature&.tests
|
149
156
|
end
|
150
157
|
end
|
151
158
|
|
152
159
|
def filled_scenarios
|
153
160
|
if block_given?
|
154
161
|
scenarios do |feature, scenario|
|
155
|
-
next
|
156
|
-
next if scenario[:steps].empty?
|
162
|
+
next if scenario.steps.empty?
|
157
163
|
|
158
164
|
yield(feature, scenario)
|
159
165
|
end
|
160
166
|
else
|
161
|
-
scenarios.filter { |s| !s
|
167
|
+
scenarios ? scenarios.filter { |s| !s.steps.empty? } : []
|
162
168
|
end
|
163
169
|
end
|
164
170
|
|
165
171
|
def steps
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
child[:steps].each { |step| yield(feature, child, step) }
|
172
|
+
feature&.tests&.each do |t|
|
173
|
+
t.steps.each { |s| yield(feature, t, s) }
|
170
174
|
end
|
171
175
|
end
|
172
176
|
|
@@ -179,16 +183,16 @@ module Chutney
|
|
179
183
|
end
|
180
184
|
|
181
185
|
def render_step(step)
|
182
|
-
value = "#{step
|
183
|
-
value += render_step_argument
|
186
|
+
value = "#{step.keyword} #{step.text}"
|
187
|
+
value += render_step_argument(step.block) if step.block
|
184
188
|
value
|
185
189
|
end
|
186
190
|
|
187
191
|
def render_step_argument(argument)
|
188
|
-
return "\n#{argument
|
192
|
+
return "\n#{argument.content}" if argument.is_a?(CukeModeler::DocString)
|
189
193
|
|
190
|
-
result = argument
|
191
|
-
"|#{row
|
194
|
+
result = argument.rows.map do |row|
|
195
|
+
"|#{row.cells.map(&:value).join '|'}|"
|
192
196
|
end.join "\n"
|
193
197
|
"\n#{result}"
|
194
198
|
end
|