chutney 2.0.3.1 → 3.0.0.beta.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/chutney.svg)](https://badge.fury.io/rb/chutney)
|
15
|
+
[![Downloads](https://img.shields.io/gem/dt/chutney)](https://rubygems.org/gems/chutney)
|
15
16
|
![CircleCI branch](https://img.shields.io/circleci/project/github/BillyRuffian/chutney/master.svg?style=flat-square)
|
16
17
|
[![CodeFactor](https://www.codefactor.io/repository/github/billyruffian/chutney/badge?style=flat-square)](https://www.codefactor.io/repository/github/billyruffian/chutney)
|
17
18
|
![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/BillyRuffian/chutney.svg?style=flat-square)
|
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
|