cuke_linter 1.3.0 → 1.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 +4 -4
- data/CHANGELOG.md +217 -211
- data/LICENSE.txt +21 -21
- data/README.md +160 -160
- data/cuke_linter.gemspec +59 -58
- data/exe/cuke_linter +112 -112
- data/lib/cuke_linter/configuration.rb +45 -45
- data/lib/cuke_linter/default_linters.rb +32 -32
- data/lib/cuke_linter/formatters/pretty_formatter.rb +84 -84
- data/lib/cuke_linter/gherkin.rb +10 -10
- data/lib/cuke_linter/linter_registration.rb +32 -32
- data/lib/cuke_linter/linters/background_does_more_than_setup_linter.rb +35 -35
- data/lib/cuke_linter/linters/element_with_common_tags_linter.rb +49 -49
- data/lib/cuke_linter/linters/element_with_duplicate_tags_linter.rb +48 -48
- data/lib/cuke_linter/linters/element_with_too_many_tags_linter.rb +46 -46
- data/lib/cuke_linter/linters/example_without_name_linter.rb +19 -19
- data/lib/cuke_linter/linters/feature_file_with_invalid_name_linter.rb +20 -20
- data/lib/cuke_linter/linters/feature_file_with_mismatched_name_linter.rb +25 -25
- data/lib/cuke_linter/linters/feature_with_too_many_different_tags_linter.rb +35 -35
- data/lib/cuke_linter/linters/feature_without_description_linter.rb +19 -19
- data/lib/cuke_linter/linters/feature_without_name_linter.rb +19 -19
- data/lib/cuke_linter/linters/feature_without_scenarios_linter.rb +23 -23
- data/lib/cuke_linter/linters/linter.rb +42 -42
- data/lib/cuke_linter/linters/outline_with_single_example_row_linter.rb +22 -22
- data/lib/cuke_linter/linters/single_test_background_linter.rb +19 -19
- data/lib/cuke_linter/linters/step_with_end_period_linter.rb +19 -19
- data/lib/cuke_linter/linters/step_with_too_many_characters_linter.rb +38 -38
- data/lib/cuke_linter/linters/test_name_with_too_many_characters_linter.rb +38 -38
- data/lib/cuke_linter/linters/test_should_use_background_linter.rb +80 -80
- data/lib/cuke_linter/linters/test_with_action_step_as_final_step_linter.rb +33 -33
- data/lib/cuke_linter/linters/test_with_bad_name_linter.rb +23 -23
- data/lib/cuke_linter/linters/test_with_no_action_step_linter.rb +33 -33
- data/lib/cuke_linter/linters/test_with_no_name_linter.rb +19 -19
- data/lib/cuke_linter/linters/test_with_no_verification_step_linter.rb +33 -33
- data/lib/cuke_linter/linters/test_with_setup_step_after_action_step_linter.rb +46 -46
- data/lib/cuke_linter/linters/test_with_setup_step_after_verification_step_linter.rb +46 -46
- data/lib/cuke_linter/linters/test_with_setup_step_as_final_step_linter.rb +33 -33
- data/lib/cuke_linter/linters/test_with_too_many_steps_linter.rb +27 -27
- data/lib/cuke_linter/version.rb +4 -4
- data/lib/cuke_linter.rb +196 -196
- data/testing/cucumber/features/command_line.feature +202 -202
- data/testing/cucumber/features/configuration/configuring_linters.feature +58 -58
- data/testing/cucumber/features/configuration/locally_scoping_linters.feature +55 -55
- data/testing/cucumber/features/configuration/using_configurations.feature +41 -41
- data/testing/cucumber/features/custom_linters.feature +56 -56
- data/testing/cucumber/features/default_linters.feature +57 -57
- data/testing/cucumber/features/formatters/pretty_formatter.feature +26 -26
- data/testing/cucumber/features/linters/background_does_more_than_setup.feature +84 -84
- data/testing/cucumber/features/linters/element_with_common_tags.feature +28 -28
- data/testing/cucumber/features/linters/element_with_duplicate_tags.feature +71 -71
- data/testing/cucumber/features/linters/element_with_too_many_tags.feature +70 -70
- data/testing/cucumber/features/linters/example_without_name.feature +34 -34
- data/testing/cucumber/features/linters/feature_file_with_invalid_name.feature +20 -20
- data/testing/cucumber/features/linters/feature_file_with_mismatched_name.feature +32 -32
- data/testing/cucumber/features/linters/feature_with_too_many_different_tags.feature +56 -56
- data/testing/cucumber/features/linters/feature_without_description.feature +17 -17
- data/testing/cucumber/features/linters/feature_without_name.feature +18 -18
- data/testing/cucumber/features/linters/feature_without_scenarios.feature +39 -39
- data/testing/cucumber/features/linters/outline_with_single_example_row.feature +23 -23
- data/testing/cucumber/features/linters/single_test_background.feature +24 -24
- data/testing/cucumber/features/linters/step_too_long.feature +43 -43
- data/testing/cucumber/features/linters/step_with_end_period.feature +21 -21
- data/testing/cucumber/features/linters/test_name_too_long.feature +41 -41
- data/testing/cucumber/features/linters/test_should_use_background.feature +29 -29
- data/testing/cucumber/features/linters/test_with_action_as_final_step.feature +50 -50
- data/testing/cucumber/features/linters/test_with_bad_name.feature +29 -29
- data/testing/cucumber/features/linters/test_with_no_action_step.feature +56 -56
- data/testing/cucumber/features/linters/test_with_no_name.feature +23 -23
- data/testing/cucumber/features/linters/test_with_no_verification_step.feature +58 -58
- data/testing/cucumber/features/linters/test_with_setup_step_after_action_step.feature +57 -57
- data/testing/cucumber/features/linters/test_with_setup_step_after_verification_step.feature +57 -57
- data/testing/cucumber/features/linters/test_with_setup_step_as_final_step.feature +50 -50
- data/testing/cucumber/features/linters/test_with_too_many_steps.feature +61 -61
- metadata +21 -25
- data/testing/cucumber/features/linters/rule_without_name.feature +0 -18
data/exe/cuke_linter
CHANGED
|
@@ -1,112 +1,112 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require 'cuke_linter'
|
|
4
|
-
require 'optparse'
|
|
5
|
-
|
|
6
|
-
params = {}
|
|
7
|
-
params[:paths] = []
|
|
8
|
-
params[:formatters] = []
|
|
9
|
-
params[:outs] = []
|
|
10
|
-
params[:requires] = []
|
|
11
|
-
|
|
12
|
-
# rubocop:disable Metrics/BlockLength
|
|
13
|
-
parser = OptionParser.new do |options|
|
|
14
|
-
|
|
15
|
-
options.set_summary_width(30)
|
|
16
|
-
|
|
17
|
-
options.on('-p', '--path PATH', String,
|
|
18
|
-
'The file path that should be linted. Can be a file or directory.',
|
|
19
|
-
'This option can be specified multiple times in order to lint',
|
|
20
|
-
'multiple, unconnected locations.') do |path|
|
|
21
|
-
params[:paths] << path
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
options.on('-f', '--formatter FORMATTER', String,
|
|
25
|
-
'The formatter used for generating linting output. This option',
|
|
26
|
-
'can be specified multiple times in order to use more than one',
|
|
27
|
-
'formatter. Formatters must be specified using their fully',
|
|
28
|
-
'qualified class name (e.g CukeLinter::PrettyFormatter). Uses',
|
|
29
|
-
'the default formatter if none are specified.') do |format|
|
|
30
|
-
params[:formatters] << format
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
options.on('-o', '--out OUT', String,
|
|
34
|
-
'The file path to which linting results are output. Can be specified',
|
|
35
|
-
'multiple times. Specified files are matched to formatters in the',
|
|
36
|
-
'same order that the formatters are specified. Any formatter without',
|
|
37
|
-
'a corresponding file path will output to STDOUT instead.') do |out|
|
|
38
|
-
params[:outs] << out
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
options.on('-r', '--require FILEPATH', String,
|
|
42
|
-
'A file that will be required before further processing. Likely',
|
|
43
|
-
'needed when using custom linters or formatters in order to ensure',
|
|
44
|
-
'that the specified classes have been read into memory. This option',
|
|
45
|
-
'can be specified multiple times in order to load more than one file.') do |file_path|
|
|
46
|
-
params[:requires] << file_path
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
options.on('-c', '--config FILEPATH', String,
|
|
50
|
-
'The configuration file that will be used. Will use the default',
|
|
51
|
-
'configuration file (if present) if this option is not specified.') do |file_path|
|
|
52
|
-
|
|
53
|
-
if params[:config]
|
|
54
|
-
puts 'Cannot specify more than one configuration file!'
|
|
55
|
-
exit(2)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
params[:config] = file_path
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
options.on('-h', '--help', 'Display the help that you are reading now.') do
|
|
62
|
-
puts options.help
|
|
63
|
-
exit
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
options.on('-v', '--version', 'Display the version of the gem being used.') do
|
|
67
|
-
puts CukeLinter::VERSION
|
|
68
|
-
exit
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
end
|
|
72
|
-
# rubocop:enable Metrics/BlockLength
|
|
73
|
-
|
|
74
|
-
begin
|
|
75
|
-
parser.parse!
|
|
76
|
-
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
|
|
77
|
-
puts e.message
|
|
78
|
-
puts parser.help
|
|
79
|
-
|
|
80
|
-
exit(2)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
require_files = params[:requires]
|
|
85
|
-
|
|
86
|
-
require_files.each do |file|
|
|
87
|
-
require file
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
file_paths = params[:paths]
|
|
91
|
-
formatters = params[:formatters].map { |formatter| Kernel.const_get(formatter).new }
|
|
92
|
-
output_paths = params[:outs]
|
|
93
|
-
|
|
94
|
-
bundled_formatters = [].tap do |formatter_output_pairs|
|
|
95
|
-
[formatters.count, output_paths.count].max.times do |count|
|
|
96
|
-
formatter_output_pairs << [formatters[count] || CukeLinter::PrettyFormatter.new, output_paths[count]]
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
options = {}
|
|
101
|
-
options[:formatters] = bundled_formatters unless bundled_formatters.empty?
|
|
102
|
-
options[:file_paths] = file_paths
|
|
103
|
-
|
|
104
|
-
if params[:config]
|
|
105
|
-
CukeLinter.load_configuration(config_file_path: params[:config])
|
|
106
|
-
elsif File.exist?("#{Dir.pwd}/.cuke_linter")
|
|
107
|
-
CukeLinter.load_configuration
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
results = CukeLinter.lint(**options)
|
|
111
|
-
|
|
112
|
-
exit(1) unless results.empty?
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'cuke_linter'
|
|
4
|
+
require 'optparse'
|
|
5
|
+
|
|
6
|
+
params = {}
|
|
7
|
+
params[:paths] = []
|
|
8
|
+
params[:formatters] = []
|
|
9
|
+
params[:outs] = []
|
|
10
|
+
params[:requires] = []
|
|
11
|
+
|
|
12
|
+
# rubocop:disable Metrics/BlockLength
|
|
13
|
+
parser = OptionParser.new do |options|
|
|
14
|
+
|
|
15
|
+
options.set_summary_width(30)
|
|
16
|
+
|
|
17
|
+
options.on('-p', '--path PATH', String,
|
|
18
|
+
'The file path that should be linted. Can be a file or directory.',
|
|
19
|
+
'This option can be specified multiple times in order to lint',
|
|
20
|
+
'multiple, unconnected locations.') do |path|
|
|
21
|
+
params[:paths] << path
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
options.on('-f', '--formatter FORMATTER', String,
|
|
25
|
+
'The formatter used for generating linting output. This option',
|
|
26
|
+
'can be specified multiple times in order to use more than one',
|
|
27
|
+
'formatter. Formatters must be specified using their fully',
|
|
28
|
+
'qualified class name (e.g CukeLinter::PrettyFormatter). Uses',
|
|
29
|
+
'the default formatter if none are specified.') do |format|
|
|
30
|
+
params[:formatters] << format
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
options.on('-o', '--out OUT', String,
|
|
34
|
+
'The file path to which linting results are output. Can be specified',
|
|
35
|
+
'multiple times. Specified files are matched to formatters in the',
|
|
36
|
+
'same order that the formatters are specified. Any formatter without',
|
|
37
|
+
'a corresponding file path will output to STDOUT instead.') do |out|
|
|
38
|
+
params[:outs] << out
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
options.on('-r', '--require FILEPATH', String,
|
|
42
|
+
'A file that will be required before further processing. Likely',
|
|
43
|
+
'needed when using custom linters or formatters in order to ensure',
|
|
44
|
+
'that the specified classes have been read into memory. This option',
|
|
45
|
+
'can be specified multiple times in order to load more than one file.') do |file_path|
|
|
46
|
+
params[:requires] << file_path
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
options.on('-c', '--config FILEPATH', String,
|
|
50
|
+
'The configuration file that will be used. Will use the default',
|
|
51
|
+
'configuration file (if present) if this option is not specified.') do |file_path|
|
|
52
|
+
|
|
53
|
+
if params[:config]
|
|
54
|
+
puts 'Cannot specify more than one configuration file!'
|
|
55
|
+
exit(2)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
params[:config] = file_path
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
options.on('-h', '--help', 'Display the help that you are reading now.') do
|
|
62
|
+
puts options.help
|
|
63
|
+
exit
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
options.on('-v', '--version', 'Display the version of the gem being used.') do
|
|
67
|
+
puts CukeLinter::VERSION
|
|
68
|
+
exit
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
# rubocop:enable Metrics/BlockLength
|
|
73
|
+
|
|
74
|
+
begin
|
|
75
|
+
parser.parse!
|
|
76
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
|
|
77
|
+
puts e.message
|
|
78
|
+
puts parser.help
|
|
79
|
+
|
|
80
|
+
exit(2)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
require_files = params[:requires]
|
|
85
|
+
|
|
86
|
+
require_files.each do |file|
|
|
87
|
+
require file
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
file_paths = params[:paths]
|
|
91
|
+
formatters = params[:formatters].map { |formatter| Kernel.const_get(formatter).new }
|
|
92
|
+
output_paths = params[:outs]
|
|
93
|
+
|
|
94
|
+
bundled_formatters = [].tap do |formatter_output_pairs|
|
|
95
|
+
[formatters.count, output_paths.count].max.times do |count|
|
|
96
|
+
formatter_output_pairs << [formatters[count] || CukeLinter::PrettyFormatter.new, output_paths[count]]
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
options = {}
|
|
101
|
+
options[:formatters] = bundled_formatters unless bundled_formatters.empty?
|
|
102
|
+
options[:file_paths] = file_paths
|
|
103
|
+
|
|
104
|
+
if params[:config]
|
|
105
|
+
CukeLinter.load_configuration(config_file_path: params[:config])
|
|
106
|
+
elsif File.exist?("#{Dir.pwd}/.cuke_linter")
|
|
107
|
+
CukeLinter.load_configuration
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
results = CukeLinter.lint(**options)
|
|
111
|
+
|
|
112
|
+
exit(1) unless results.empty?
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
module CukeLinter
|
|
2
|
-
|
|
3
|
-
# Mix-in module containing methods related to configuring linters
|
|
4
|
-
module Configuration
|
|
5
|
-
|
|
6
|
-
# Configures linters based on the given options
|
|
7
|
-
def load_configuration(config_file_path: nil, config: nil)
|
|
8
|
-
# TODO: define what happens if both a configuration file and a configuration are
|
|
9
|
-
# provided. Merge them or have direct config take precedence? Both?
|
|
10
|
-
|
|
11
|
-
unless config || config_file_path
|
|
12
|
-
config_file_path = "#{Dir.pwd}/.cuke_linter"
|
|
13
|
-
message = 'No configuration or configuration file given and no .cuke_linter file found'
|
|
14
|
-
raise message unless File.exist?(config_file_path)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
config ||= YAML.load_file(config_file_path)
|
|
18
|
-
configure_linters(config, registered_linters)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
private
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def configure_linters(configuration, linters)
|
|
26
|
-
common_config = configuration['AllLinters'] || {}
|
|
27
|
-
to_delete = []
|
|
28
|
-
|
|
29
|
-
linters.each_pair do |name, linter|
|
|
30
|
-
linter_config = configuration[name] || {}
|
|
31
|
-
final_config = common_config.merge(linter_config)
|
|
32
|
-
|
|
33
|
-
disabled =
|
|
34
|
-
|
|
35
|
-
# Just save it for afterwards because modifying a collection while iterating through it is not a good idea
|
|
36
|
-
to_delete << name if disabled
|
|
37
|
-
|
|
38
|
-
linter.configure(final_config) if linter.respond_to?(:configure)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
to_delete.each { |linter_name| unregister_linter(linter_name) }
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
end
|
|
45
|
-
end
|
|
1
|
+
module CukeLinter
|
|
2
|
+
|
|
3
|
+
# Mix-in module containing methods related to configuring linters
|
|
4
|
+
module Configuration
|
|
5
|
+
|
|
6
|
+
# Configures linters based on the given options
|
|
7
|
+
def load_configuration(config_file_path: nil, config: nil)
|
|
8
|
+
# TODO: define what happens if both a configuration file and a configuration are
|
|
9
|
+
# provided. Merge them or have direct config take precedence? Both?
|
|
10
|
+
|
|
11
|
+
unless config || config_file_path
|
|
12
|
+
config_file_path = "#{Dir.pwd}/.cuke_linter"
|
|
13
|
+
message = 'No configuration or configuration file given and no .cuke_linter file found'
|
|
14
|
+
raise message unless File.exist?(config_file_path)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
config ||= YAML.load_file(config_file_path)
|
|
18
|
+
configure_linters(config, registered_linters)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def configure_linters(configuration, linters) # rubocop:disable Metrics/CyclomaticComplexity -- Maybe I'll revisit this later
|
|
26
|
+
common_config = configuration['AllLinters'] || {}
|
|
27
|
+
to_delete = []
|
|
28
|
+
|
|
29
|
+
linters.each_pair do |name, linter|
|
|
30
|
+
linter_config = configuration[name] || {}
|
|
31
|
+
final_config = common_config.merge(linter_config)
|
|
32
|
+
|
|
33
|
+
disabled = final_config.key?('Enabled') && !final_config['Enabled']
|
|
34
|
+
|
|
35
|
+
# Just save it for afterwards because modifying a collection while iterating through it is not a good idea
|
|
36
|
+
to_delete << name if disabled
|
|
37
|
+
|
|
38
|
+
linter.configure(final_config) if linter.respond_to?(:configure)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
to_delete.each { |linter_name| unregister_linter(linter_name) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
module CukeLinter # rubocop:disable Style/Documentation
|
|
2
|
-
|
|
3
|
-
# Long names inherently result in long lines
|
|
4
|
-
# rubocop:disable
|
|
5
|
-
@original_linters = { 'BackgroundDoesMoreThanSetupLinter' => BackgroundDoesMoreThanSetupLinter.new,
|
|
6
|
-
'ElementWithCommonTagsLinter' => ElementWithCommonTagsLinter.new,
|
|
7
|
-
'ElementWithDuplicateTagsLinter' => ElementWithDuplicateTagsLinter.new,
|
|
8
|
-
'ElementWithTooManyTagsLinter' => ElementWithTooManyTagsLinter.new,
|
|
9
|
-
'ExampleWithoutNameLinter' => ExampleWithoutNameLinter.new,
|
|
10
|
-
'FeatureFileWithInvalidNameLinter' => FeatureFileWithInvalidNameLinter.new,
|
|
11
|
-
'FeatureFileWithMismatchedNameLinter' => FeatureFileWithMismatchedNameLinter.new,
|
|
12
|
-
'FeatureWithTooManyDifferentTagsLinter' => FeatureWithTooManyDifferentTagsLinter.new,
|
|
13
|
-
'FeatureWithoutDescriptionLinter' => FeatureWithoutDescriptionLinter.new,
|
|
14
|
-
'FeatureWithoutNameLinter' => FeatureWithoutNameLinter.new,
|
|
15
|
-
'FeatureWithoutScenariosLinter' => FeatureWithoutScenariosLinter.new,
|
|
16
|
-
'OutlineWithSingleExampleRowLinter' => OutlineWithSingleExampleRowLinter.new,
|
|
17
|
-
'SingleTestBackgroundLinter' => SingleTestBackgroundLinter.new,
|
|
18
|
-
'StepWithEndPeriodLinter' => StepWithEndPeriodLinter.new,
|
|
19
|
-
'StepWithTooManyCharactersLinter' => StepWithTooManyCharactersLinter.new,
|
|
20
|
-
'TestShouldUseBackgroundLinter' => TestShouldUseBackgroundLinter.new,
|
|
21
|
-
'TestWithActionStepAsFinalStepLinter' => TestWithActionStepAsFinalStepLinter.new,
|
|
22
|
-
'TestWithBadNameLinter' => TestWithBadNameLinter.new,
|
|
23
|
-
'TestWithNoActionStepLinter' => TestWithNoActionStepLinter.new,
|
|
24
|
-
'TestWithNoNameLinter' => TestWithNoNameLinter.new,
|
|
25
|
-
'TestWithNoVerificationStepLinter' => TestWithNoVerificationStepLinter.new,
|
|
26
|
-
'TestWithSetupStepAfterActionStepLinter' => TestWithSetupStepAfterActionStepLinter.new,
|
|
27
|
-
'TestWithSetupStepAfterVerificationStepLinter' => TestWithSetupStepAfterVerificationStepLinter.new,
|
|
28
|
-
'TestWithSetupStepAsFinalStepLinter' => TestWithSetupStepAsFinalStepLinter.new,
|
|
29
|
-
'TestWithTooManyStepsLinter' => TestWithTooManyStepsLinter.new }
|
|
30
|
-
# rubocop:enable
|
|
31
|
-
|
|
32
|
-
end
|
|
1
|
+
module CukeLinter # rubocop:disable Style/Documentation
|
|
2
|
+
|
|
3
|
+
# Long names inherently result in long lines
|
|
4
|
+
# rubocop:disable Layout/LineLength
|
|
5
|
+
@original_linters = { 'BackgroundDoesMoreThanSetupLinter' => BackgroundDoesMoreThanSetupLinter.new,
|
|
6
|
+
'ElementWithCommonTagsLinter' => ElementWithCommonTagsLinter.new,
|
|
7
|
+
'ElementWithDuplicateTagsLinter' => ElementWithDuplicateTagsLinter.new,
|
|
8
|
+
'ElementWithTooManyTagsLinter' => ElementWithTooManyTagsLinter.new,
|
|
9
|
+
'ExampleWithoutNameLinter' => ExampleWithoutNameLinter.new,
|
|
10
|
+
'FeatureFileWithInvalidNameLinter' => FeatureFileWithInvalidNameLinter.new,
|
|
11
|
+
'FeatureFileWithMismatchedNameLinter' => FeatureFileWithMismatchedNameLinter.new,
|
|
12
|
+
'FeatureWithTooManyDifferentTagsLinter' => FeatureWithTooManyDifferentTagsLinter.new,
|
|
13
|
+
'FeatureWithoutDescriptionLinter' => FeatureWithoutDescriptionLinter.new,
|
|
14
|
+
'FeatureWithoutNameLinter' => FeatureWithoutNameLinter.new,
|
|
15
|
+
'FeatureWithoutScenariosLinter' => FeatureWithoutScenariosLinter.new,
|
|
16
|
+
'OutlineWithSingleExampleRowLinter' => OutlineWithSingleExampleRowLinter.new,
|
|
17
|
+
'SingleTestBackgroundLinter' => SingleTestBackgroundLinter.new,
|
|
18
|
+
'StepWithEndPeriodLinter' => StepWithEndPeriodLinter.new,
|
|
19
|
+
'StepWithTooManyCharactersLinter' => StepWithTooManyCharactersLinter.new,
|
|
20
|
+
'TestShouldUseBackgroundLinter' => TestShouldUseBackgroundLinter.new,
|
|
21
|
+
'TestWithActionStepAsFinalStepLinter' => TestWithActionStepAsFinalStepLinter.new,
|
|
22
|
+
'TestWithBadNameLinter' => TestWithBadNameLinter.new,
|
|
23
|
+
'TestWithNoActionStepLinter' => TestWithNoActionStepLinter.new,
|
|
24
|
+
'TestWithNoNameLinter' => TestWithNoNameLinter.new,
|
|
25
|
+
'TestWithNoVerificationStepLinter' => TestWithNoVerificationStepLinter.new,
|
|
26
|
+
'TestWithSetupStepAfterActionStepLinter' => TestWithSetupStepAfterActionStepLinter.new,
|
|
27
|
+
'TestWithSetupStepAfterVerificationStepLinter' => TestWithSetupStepAfterVerificationStepLinter.new,
|
|
28
|
+
'TestWithSetupStepAsFinalStepLinter' => TestWithSetupStepAsFinalStepLinter.new,
|
|
29
|
+
'TestWithTooManyStepsLinter' => TestWithTooManyStepsLinter.new }
|
|
30
|
+
# rubocop:enable Layout/LineLength
|
|
31
|
+
|
|
32
|
+
end
|
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
module CukeLinter
|
|
2
|
-
|
|
3
|
-
# Formats linting data into organized, user readable text
|
|
4
|
-
class PrettyFormatter
|
|
5
|
-
|
|
6
|
-
# Formats the given linting data
|
|
7
|
-
def format(data)
|
|
8
|
-
format_data(categorize_problems(data), data.count)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def categorize_problems(data)
|
|
16
|
-
{}.tap do |categorized_problems|
|
|
17
|
-
data.each do |lint_item|
|
|
18
|
-
categorized_problems[lint_item[:linter]] ||= {}
|
|
19
|
-
categorized_problems[lint_item[:linter]][lint_item[:problem]] ||= []
|
|
20
|
-
categorized_problems[lint_item[:linter]][lint_item[:problem]] << lint_item[:location]
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def format_data(problem_data, problem_count)
|
|
26
|
-
''.tap do |formatted_data|
|
|
27
|
-
problem_data.each_pair do |linter, problems|
|
|
28
|
-
formatted_data << "#{linter}\n"
|
|
29
|
-
|
|
30
|
-
problems.each_pair do |problem, locations|
|
|
31
|
-
formatted_data << " #{problem}\n"
|
|
32
|
-
|
|
33
|
-
sort_locations(locations).each do |location|
|
|
34
|
-
formatted_data << " #{location}\n"
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
formatted_data << "\n" unless problem_count.zero?
|
|
40
|
-
formatted_data << "#{problem_count} issues found"
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def sort_locations(locations)
|
|
45
|
-
locations.sort do |a, b|
|
|
46
|
-
file_name_1 = a.match(/(.*?)(?::\d+)?$/)[1]
|
|
47
|
-
line_number_1 = a =~ /:\d+$/ ? a.match(/:(\d+)$/)[1].to_i : 0
|
|
48
|
-
file_name_2 = b.match(/(.*?)(?::\d+)?$/)[1]
|
|
49
|
-
line_number_2 = b =~ /:\d+$/ ? b.match(/:(\d+)$/)[1].to_i : 0
|
|
50
|
-
|
|
51
|
-
compare_locations(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def compare_locations(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
56
|
-
if earlier_file(file_name_1, file_name_2) ||
|
|
57
|
-
same_file_earlier_line(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
58
|
-
-1
|
|
59
|
-
elsif later_file(file_name_1, file_name_2) ||
|
|
60
|
-
same_file_later_line(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
61
|
-
1
|
|
62
|
-
else
|
|
63
|
-
0
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def earlier_file(file_name_1, file_name_2)
|
|
68
|
-
(file_name_1 < file_name_2)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def same_file_earlier_line(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
72
|
-
(file_name_1 == file_name_2) && (line_number_1 < line_number_2)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def later_file(file_name_1, file_name_2)
|
|
76
|
-
(file_name_1 > file_name_2)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def same_file_later_line(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
80
|
-
(file_name_1 == file_name_2) && (line_number_1 > line_number_2)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
end
|
|
84
|
-
end
|
|
1
|
+
module CukeLinter
|
|
2
|
+
|
|
3
|
+
# Formats linting data into organized, user readable text
|
|
4
|
+
class PrettyFormatter
|
|
5
|
+
|
|
6
|
+
# Formats the given linting data
|
|
7
|
+
def format(data)
|
|
8
|
+
format_data(categorize_problems(data), data.count)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def categorize_problems(data)
|
|
16
|
+
{}.tap do |categorized_problems|
|
|
17
|
+
data.each do |lint_item|
|
|
18
|
+
categorized_problems[lint_item[:linter]] ||= {}
|
|
19
|
+
categorized_problems[lint_item[:linter]][lint_item[:problem]] ||= []
|
|
20
|
+
categorized_problems[lint_item[:linter]][lint_item[:problem]] << lint_item[:location]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def format_data(problem_data, problem_count)
|
|
26
|
+
''.tap do |formatted_data|
|
|
27
|
+
problem_data.each_pair do |linter, problems|
|
|
28
|
+
formatted_data << "#{linter}\n"
|
|
29
|
+
|
|
30
|
+
problems.each_pair do |problem, locations|
|
|
31
|
+
formatted_data << " #{problem}\n"
|
|
32
|
+
|
|
33
|
+
sort_locations(locations).each do |location|
|
|
34
|
+
formatted_data << " #{location}\n"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
formatted_data << "\n" unless problem_count.zero?
|
|
40
|
+
formatted_data << "#{problem_count} issues found"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def sort_locations(locations)
|
|
45
|
+
locations.sort do |a, b|
|
|
46
|
+
file_name_1 = a.match(/(.*?)(?::\d+)?$/)[1]
|
|
47
|
+
line_number_1 = a =~ /:\d+$/ ? a.match(/:(\d+)$/)[1].to_i : 0
|
|
48
|
+
file_name_2 = b.match(/(.*?)(?::\d+)?$/)[1]
|
|
49
|
+
line_number_2 = b =~ /:\d+$/ ? b.match(/:(\d+)$/)[1].to_i : 0
|
|
50
|
+
|
|
51
|
+
compare_locations(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def compare_locations(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
56
|
+
if earlier_file(file_name_1, file_name_2) ||
|
|
57
|
+
same_file_earlier_line(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
58
|
+
-1
|
|
59
|
+
elsif later_file(file_name_1, file_name_2) ||
|
|
60
|
+
same_file_later_line(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
61
|
+
1
|
|
62
|
+
else
|
|
63
|
+
0
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def earlier_file(file_name_1, file_name_2)
|
|
68
|
+
(file_name_1 < file_name_2)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def same_file_earlier_line(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
72
|
+
(file_name_1 == file_name_2) && (line_number_1 < line_number_2)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def later_file(file_name_1, file_name_2)
|
|
76
|
+
(file_name_1 > file_name_2)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def same_file_later_line(file_name_1, file_name_2, line_number_1, line_number_2)
|
|
80
|
+
(file_name_1 == file_name_2) && (line_number_1 > line_number_2)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
end
|
data/lib/cuke_linter/gherkin.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
module CukeLinter
|
|
2
|
-
|
|
3
|
-
# The default keyword that is considered a 'Given' keyword
|
|
4
|
-
DEFAULT_GIVEN_KEYWORD = 'Given'.freeze
|
|
5
|
-
# The default keyword that is considered a 'When' keyword
|
|
6
|
-
DEFAULT_WHEN_KEYWORD = 'When'.freeze
|
|
7
|
-
# The default keyword that is considered a 'Then' keyword
|
|
8
|
-
DEFAULT_THEN_KEYWORD = 'Then'.freeze
|
|
9
|
-
|
|
10
|
-
end
|
|
1
|
+
module CukeLinter
|
|
2
|
+
|
|
3
|
+
# The default keyword that is considered a 'Given' keyword
|
|
4
|
+
DEFAULT_GIVEN_KEYWORD = 'Given'.freeze
|
|
5
|
+
# The default keyword that is considered a 'When' keyword
|
|
6
|
+
DEFAULT_WHEN_KEYWORD = 'When'.freeze
|
|
7
|
+
# The default keyword that is considered a 'Then' keyword
|
|
8
|
+
DEFAULT_THEN_KEYWORD = 'Then'.freeze
|
|
9
|
+
|
|
10
|
+
end
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
module CukeLinter
|
|
2
|
-
|
|
3
|
-
# Mix-in module containing methods related to registering linters
|
|
4
|
-
module LinterRegistration
|
|
5
|
-
|
|
6
|
-
# Returns the registered linters to their default state
|
|
7
|
-
def reset_linters
|
|
8
|
-
@registered_linters = nil
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
# Registers for linting use the given linter object, tracked by the given name
|
|
12
|
-
def register_linter(linter:, name:)
|
|
13
|
-
registered_linters[name] = linter
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Unregisters the linter object tracked by the given name so that it is not used for linting
|
|
17
|
-
def unregister_linter(name)
|
|
18
|
-
registered_linters.delete(name)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Lists the names of the currently registered linting objects
|
|
22
|
-
def registered_linters
|
|
23
|
-
@registered_linters ||= Marshal.load(Marshal.dump(@original_linters))
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Unregisters all currently registered linting objects
|
|
27
|
-
def clear_registered_linters
|
|
28
|
-
registered_linters.clear
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
end
|
|
32
|
-
end
|
|
1
|
+
module CukeLinter
|
|
2
|
+
|
|
3
|
+
# Mix-in module containing methods related to registering linters
|
|
4
|
+
module LinterRegistration
|
|
5
|
+
|
|
6
|
+
# Returns the registered linters to their default state
|
|
7
|
+
def reset_linters
|
|
8
|
+
@registered_linters = nil
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Registers for linting use the given linter object, tracked by the given name
|
|
12
|
+
def register_linter(linter:, name:)
|
|
13
|
+
registered_linters[name] = linter
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Unregisters the linter object tracked by the given name so that it is not used for linting
|
|
17
|
+
def unregister_linter(name)
|
|
18
|
+
registered_linters.delete(name)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Lists the names of the currently registered linting objects
|
|
22
|
+
def registered_linters
|
|
23
|
+
@registered_linters ||= Marshal.load(Marshal.dump(@original_linters))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Unregisters all currently registered linting objects
|
|
27
|
+
def clear_registered_linters
|
|
28
|
+
registered_linters.clear
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end
|