cuke_linter 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/CHANGELOG.md +7 -1
- data/lib/cuke_linter.rb +71 -1
- data/lib/cuke_linter/version.rb +1 -1
- data/testing/cucumber/features/configuration/locally_scoping_linters.feature +50 -0
- data/testing/cucumber/features/{linters/custom_linters.feature → custom_linters.feature} +0 -0
- data/testing/cucumber/features/{linters/default_linters.feature → default_linters.feature} +0 -0
- data/testing/cucumber/step_definitions/setup_steps.rb +13 -0
- data/testing/cucumber/step_definitions/verification_steps.rb +18 -0
- data/testing/linter_factory.rb +28 -0
- data/testing/rspec/spec/integration/configuration_spec.rb +764 -73
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 064456ffb63c27969a361497f8c1d6c9f9b96f5a59f488506db5611faa695f0f
|
4
|
+
data.tar.gz: b31161d84e3bda65527caa854bdcfcb2e1bdaca8a0f94b4dc540d00274d54bdf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b83fad28c5cd56da418697695f4333659f8cd16f750e4be51cd796e62a979c125413aa7b9d443ef56a832e1585b7247e9eb07512acb62e9071a074ed3593e079
|
7
|
+
data.tar.gz: 414f730e30415505687acc8abc8a197ba7d49e1bdb6ff9337d079d4450e928cb88d3582f85124b047bd554d13a0f2cf6fbb13f6c43e6a58db26b8ffb41e36d8a
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
8
8
|
|
9
9
|
Nothing yet...
|
10
10
|
|
11
|
+
## [0.9.0] - 2019-09-11
|
12
|
+
|
13
|
+
### Added
|
14
|
+
- Linters can now be temporarily enabled/disabled within arbitrary portions of a feature file, in order to allow for exceptions to the otherwise blanket set of linting rules.
|
15
|
+
|
11
16
|
## [0.8.0] - 2019-09-07
|
12
17
|
|
13
18
|
### Changed
|
@@ -85,7 +90,8 @@ Nothing yet...
|
|
85
90
|
- Custom linters, formatters, and command line usability
|
86
91
|
|
87
92
|
|
88
|
-
[Unreleased]: https://github.com/enkessler/cuke_linter/compare/v0.
|
93
|
+
[Unreleased]: https://github.com/enkessler/cuke_linter/compare/v0.9.0...HEAD
|
94
|
+
[0.9.0]: https://github.com/enkessler/cuke_linter/compare/v0.8.0...v0.9.0
|
89
95
|
[0.8.0]: https://github.com/enkessler/cuke_linter/compare/v0.7.0...v0.8.0
|
90
96
|
[0.7.0]: https://github.com/enkessler/cuke_linter/compare/v0.6.0...v0.7.0
|
91
97
|
[0.6.0]: https://github.com/enkessler/cuke_linter/compare/v0.5.0...v0.6.0
|
data/lib/cuke_linter.rb
CHANGED
@@ -115,7 +115,8 @@ module CukeLinter
|
|
115
115
|
|
116
116
|
model_sets.each do |model_tree|
|
117
117
|
model_tree.each_model do |model|
|
118
|
-
linters
|
118
|
+
applicable_linters = relevant_linters_for_model(linters, model)
|
119
|
+
applicable_linters.each do |linter|
|
119
120
|
# TODO: have linters lint only certain types of models
|
120
121
|
# linting_data.concat(linter.lint(model)) if relevant_model?(linter, model)
|
121
122
|
|
@@ -147,6 +148,75 @@ module CukeLinter
|
|
147
148
|
end
|
148
149
|
|
149
150
|
|
151
|
+
def self.relevant_linters_for_model(base_linters, model)
|
152
|
+
feature_file_model = model.get_ancestor(:feature_file)
|
153
|
+
|
154
|
+
# Linter directives are not applicable for directory and feature file models. Every other model type should have a feature file ancestor from which to grab linter directive comments.
|
155
|
+
return base_linters if feature_file_model.nil?
|
156
|
+
|
157
|
+
linter_modifications_for_model = {}
|
158
|
+
|
159
|
+
linter_directives_for_feature_file(feature_file_model).each do |directive|
|
160
|
+
# Assuming that the directives are in the same order that they appear in the file
|
161
|
+
break if directive[:source_line] > model.source_line
|
162
|
+
|
163
|
+
linter_modifications_for_model[directive[:linter_class]] = directive[:enabled_status]
|
164
|
+
end
|
165
|
+
|
166
|
+
disabled_linter_classes = linter_modifications_for_model.reject { |_name, status| status }.keys
|
167
|
+
enabled_linter_classes = linter_modifications_for_model.select { |_name, status| status }.keys
|
168
|
+
|
169
|
+
final_linters = base_linters.reject { |linter| disabled_linter_classes.include?(linter.class) }
|
170
|
+
enabled_linter_classes.each do |clazz|
|
171
|
+
final_linters << dynamic_linters[clazz] unless final_linters.map(&:class).include?(clazz)
|
172
|
+
end
|
173
|
+
|
174
|
+
final_linters
|
175
|
+
end
|
176
|
+
|
177
|
+
private_class_method(:relevant_linters_for_model)
|
178
|
+
|
179
|
+
|
180
|
+
def self.linter_directives_for_feature_file(feature_file_model)
|
181
|
+
# IMPORTANT ASSUMPTION: Models never change during the life of the program, so data only has to be gathered once
|
182
|
+
@directives_for_feature_file ||= {}
|
183
|
+
return @directives_for_feature_file[feature_file_model.object_id] if @directives_for_feature_file[feature_file_model.object_id]
|
184
|
+
|
185
|
+
|
186
|
+
@directives_for_feature_file[feature_file_model.object_id] = []
|
187
|
+
|
188
|
+
feature_file_model.comments.each do |comment|
|
189
|
+
pieces = comment.text.match(/#\s*cuke_linter:(disable|enable)\s+(.*)/)
|
190
|
+
next unless pieces # Skipping non-directive file comments
|
191
|
+
|
192
|
+
linter_classes = pieces[2].gsub(',', ' ').split(' ')
|
193
|
+
linter_classes.each do |clazz|
|
194
|
+
@directives_for_feature_file[feature_file_model.object_id] << { linter_class: Kernel.const_get(clazz),
|
195
|
+
enabled_status: pieces[1] != 'disable',
|
196
|
+
source_line: comment.source_line }
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Make sure that the directives are in the same order as they appear in the source file
|
201
|
+
@directives_for_feature_file[feature_file_model.object_id] = @directives_for_feature_file[feature_file_model.object_id].sort { |a, b| a[:source_line] <=> b[:source_line] }
|
202
|
+
|
203
|
+
|
204
|
+
@directives_for_feature_file[feature_file_model.object_id]
|
205
|
+
end
|
206
|
+
|
207
|
+
private_class_method(:linter_directives_for_feature_file)
|
208
|
+
|
209
|
+
def self.dynamic_linters
|
210
|
+
# No need to keep making new ones over and over...
|
211
|
+
@dynamic_linters ||= Hash.new { |hash, key| hash[key] = key.new }
|
212
|
+
# return @dynamic_linters if @dynamic_linters
|
213
|
+
#
|
214
|
+
# @dynamic_linters = {}
|
215
|
+
end
|
216
|
+
|
217
|
+
private_class_method(:dynamic_linters)
|
218
|
+
|
219
|
+
|
150
220
|
# # def self.relevant_model?(linter, model)
|
151
221
|
# # model_classes = linter.class.target_model_types.map { |type| CukeModeler.const_get(type.to_s.capitalize.chop) }
|
152
222
|
# # model_classes.any? { |clazz| model.is_a?(clazz) }
|
data/lib/cuke_linter/version.rb
CHANGED
@@ -0,0 +1,50 @@
|
|
1
|
+
Feature: Locally scoping linters
|
2
|
+
|
3
|
+
As a writer of documentation
|
4
|
+
I want to be able to limit the scope of linters for certain portions of the documentation
|
5
|
+
So that exceptions to rules can be made
|
6
|
+
|
7
|
+
In addition to using configurations to change whether or not a given linter is used when linting, linters can be enabled/disabled for specific portions of a `.feature` file. To enable/disable one (or more) linters, add a comment line before the portion of the file where the change should apply. Add a comment with the opposite change at the point in the file when the default behavior should resume. Unless so countermanded, changes remain in effect for the remainder of the feature file.
|
8
|
+
|
9
|
+
|
10
|
+
Scenario: Enabling/disabling a linter within a feature file
|
11
|
+
|
12
|
+
Note: This example disables linters that are enabled by default but enabling a linter that is disabled by default works in the same manner
|
13
|
+
|
14
|
+
Given the default linters are being used
|
15
|
+
And a feature file model based on the following text:
|
16
|
+
"""
|
17
|
+
# The comma is optional when listing linters. The following two lines are equivalent (although the second line is redundant in this case).
|
18
|
+
# cuke_linter:disable CukeLinter::TestWithNoNameLinter, CukeLinter::FeatureWithoutDescriptionLinter
|
19
|
+
# cuke_linter:disable CukeLinter::TestWithNoNameLinter CukeLinter::FeatureWithoutDescriptionLinter
|
20
|
+
|
21
|
+
Feature: Feature with no description
|
22
|
+
|
23
|
+
# cuke_linter:disable CukeLinter::ElementWithTooManyTagsLinter
|
24
|
+
@tag_1 @tag_2 @tag_3 @tag_4 @tag_5 @tag_one_too_many
|
25
|
+
Scenario:
|
26
|
+
This scenario has no name and too many tags
|
27
|
+
|
28
|
+
Given a step
|
29
|
+
When a step
|
30
|
+
Then a step
|
31
|
+
# cuke_linter:enable CukeLinter::ElementWithTooManyTagsLinter
|
32
|
+
|
33
|
+
@tag_1 @tag_2 @tag_3 @tag_4 @tag_5 @tag_one_too_many
|
34
|
+
Scenario:
|
35
|
+
This scenario also has no name and too many tags
|
36
|
+
|
37
|
+
Given a step
|
38
|
+
When a step
|
39
|
+
Then a step
|
40
|
+
"""
|
41
|
+
When the feature is linted
|
42
|
+
Then the following problems are reported:
|
43
|
+
| linter | problem | location |
|
44
|
+
| ElementWithTooManyTagsLinter | Scenario has too many tags. 6 tags found (max 5). | <path_to_file>:18 |
|
45
|
+
And the following problems are not reported:
|
46
|
+
| linter | problem | location |
|
47
|
+
| FeatureWithoutDescriptionLinter | Feature has no description | <path_to_file>:5 |
|
48
|
+
| TestWithNoNameLinter | Test does not have a name. | <path_to_file>:9 |
|
49
|
+
| TestWithNoNameLinter | Test does not have a name. | <path_to_file>:18 |
|
50
|
+
| ElementWithTooManyTagsLinter | Scenario has too many tags. 6 tags found (max 5). | <path_to_file>:9 |
|
File without changes
|
File without changes
|
@@ -148,3 +148,16 @@ Given(/^the following(?: feature)? file "([^"]*)":$/) do |file_path, text|
|
|
148
148
|
@created_files ||= []
|
149
149
|
@created_files << CukeLinter::FileHelper.create_file(directory: @root_test_directory, name: path, extension: ".#{extension}", text: text)
|
150
150
|
end
|
151
|
+
|
152
|
+
Given(/^the default linters are being used$/) do
|
153
|
+
CukeLinter.reset_linters
|
154
|
+
end
|
155
|
+
|
156
|
+
And(/^a feature file model based on the following text:$/) do |text|
|
157
|
+
file_path = CukeLinter::FileHelper.create_file(directory: @root_test_directory, extension: '.feature', text: text)
|
158
|
+
|
159
|
+
@created_files ||= []
|
160
|
+
@created_files << file_path
|
161
|
+
|
162
|
+
@model = CukeModeler::FeatureFile.new(file_path)
|
163
|
+
end
|
@@ -22,6 +22,24 @@ Then(/^an error is reported:$/) do |table|
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
Then(/^the following problems are( not)? reported:$/) do |exclude, table|
|
26
|
+
assertion_method = exclude ? :to_not : :to
|
27
|
+
|
28
|
+
if @model.is_a?(CukeModeler::FeatureFile)
|
29
|
+
feature_file_model = @model
|
30
|
+
source_line = ''
|
31
|
+
else
|
32
|
+
feature_file_model = @model.get_ancestor(:feature_file)
|
33
|
+
source_line = @model.source_line.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
table.hashes.each do |error_record|
|
37
|
+
expect(@results).send(assertion_method, include({ linter: error_record['linter'],
|
38
|
+
problem: error_record['problem'],
|
39
|
+
location: error_record['location'].sub('<path_to_file>', feature_file_model.path).sub('<model_line_number>', source_line) }))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
25
43
|
Then(/^the following linters are registered(?: by default)?$/) do |linter_names|
|
26
44
|
expect(CukeLinter.registered_linters.keys).to match_array(linter_names.raw.flatten)
|
27
45
|
end
|
data/testing/linter_factory.rb
CHANGED
@@ -28,5 +28,33 @@ module CukeLinter
|
|
28
28
|
linter
|
29
29
|
end
|
30
30
|
|
31
|
+
def self.generate_fake_linter_class(module_name: nil, class_name: 'FakeLinter', name: 'Some Name', finds_problems: true)
|
32
|
+
|
33
|
+
if module_name
|
34
|
+
parent_module = Kernel.const_defined?(module_name) ? Kernel.const_get(module_name) : Kernel.const_set(module_name, Module.new)
|
35
|
+
end
|
36
|
+
|
37
|
+
(parent_module || Kernel).const_set(class_name, Class.new do
|
38
|
+
|
39
|
+
define_method('lint') do |model|
|
40
|
+
location = model.respond_to?(:source_line) ? "#{model.get_ancestor(:feature_file).path}:#{model.source_line}" : model.path
|
41
|
+
problem = @problem || "#{name} problem"
|
42
|
+
|
43
|
+
if finds_problems
|
44
|
+
{ problem: problem,
|
45
|
+
location: location }
|
46
|
+
else
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
define_method('name') do
|
52
|
+
name
|
53
|
+
end
|
54
|
+
|
55
|
+
end)
|
56
|
+
|
57
|
+
end
|
58
|
+
|
31
59
|
end
|
32
60
|
end
|
@@ -4,115 +4,806 @@ RSpec.describe CukeLinter do
|
|
4
4
|
|
5
5
|
describe 'configuration' do
|
6
6
|
|
7
|
-
|
8
|
-
let(:test_linters) { [CukeLinter::LinterFactory.generate_fake_linter] }
|
9
|
-
let(:test_formatters) { [[CukeLinter::FormatterFactory.generate_fake_formatter, "#{CukeLinter::FileHelper::create_directory}/junk_output_file.txt"]] }
|
10
|
-
let(:linting_options) { { model_trees: [test_model_tree], linters: test_linters, formatters: test_formatters } }
|
7
|
+
describe 'blanket linters' do
|
11
8
|
|
9
|
+
let(:test_model_tree) { CukeLinter::ModelFactory.generate_lintable_model }
|
10
|
+
let(:test_linters) { [CukeLinter::LinterFactory.generate_fake_linter] }
|
11
|
+
let(:test_formatters) { [[CukeLinter::FormatterFactory.generate_fake_formatter, "#{CukeLinter::FileHelper::create_directory}/junk_output_file.txt"]] }
|
12
|
+
let(:linting_options) { { model_trees: [test_model_tree], linters: test_linters, formatters: test_formatters } }
|
12
13
|
|
13
|
-
it 'unregisters disabled linters' do
|
14
|
-
config = { 'FakeLinter1' => { 'Enabled' => false } }
|
15
|
-
configuration_file = CukeLinter::FileHelper.create_file(name: '.cuke_linter', extension: '', text: config.to_yaml)
|
16
14
|
|
17
|
-
|
18
|
-
|
15
|
+
it 'unregisters disabled linters' do
|
16
|
+
config = { 'FakeLinter1' => { 'Enabled' => false } }
|
17
|
+
configuration_file = CukeLinter::FileHelper.create_file(name: '.cuke_linter', extension: '', text: config.to_yaml)
|
19
18
|
|
20
|
-
|
19
|
+
CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter1'), name: 'FakeLinter1')
|
20
|
+
expect(subject.registered_linters['FakeLinter1']).to_not be nil
|
21
21
|
|
22
|
-
|
23
|
-
end
|
22
|
+
subject.load_configuration(config_file_path: configuration_file)
|
24
23
|
|
25
|
-
|
26
|
-
|
24
|
+
expect(subject.registered_linters['FakeLinter1']).to be nil
|
25
|
+
end
|
27
26
|
|
28
|
-
|
29
|
-
|
27
|
+
it 'can apply a property to all linters' do
|
28
|
+
configuration = { 'AllLinters' => { 'Enabled' => false } }
|
30
29
|
|
31
|
-
|
32
|
-
|
30
|
+
# Restore the default linters
|
31
|
+
CukeLinter.reset_linters
|
33
32
|
|
33
|
+
# Also add some custom ones
|
34
|
+
CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter, name: 'Foo')
|
34
35
|
|
35
|
-
subject.load_configuration(config: configuration)
|
36
36
|
|
37
|
-
|
38
|
-
end
|
37
|
+
subject.load_configuration(config: configuration)
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
'FakeLinter1' => { 'Enabled' => true } }
|
39
|
+
expect(subject.registered_linters).to be_empty
|
40
|
+
end
|
43
41
|
|
44
|
-
|
45
|
-
|
42
|
+
it 'uses linter specific properties over general properties' do
|
43
|
+
configuration = { 'AllLinters' => { 'Enabled' => false },
|
44
|
+
'FakeLinter1' => { 'Enabled' => true } }
|
46
45
|
|
47
|
-
|
46
|
+
CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter, name: 'FakeLinter1')
|
47
|
+
expect(subject.registered_linters['FakeLinter1']).to_not be nil
|
48
48
|
|
49
|
-
|
50
|
-
end
|
49
|
+
subject.load_configuration(config: configuration)
|
51
50
|
|
52
|
-
|
53
|
-
|
54
|
-
configuration_file = CukeLinter::FileHelper.create_file(name: '.cuke_linter', extension: '', text: config.to_yaml)
|
55
|
-
non_configurable_linter = CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter')
|
56
|
-
non_configurable_linter.instance_eval('undef :configure')
|
51
|
+
expect(subject.registered_linters['FakeLinter1']).to_not be nil
|
52
|
+
end
|
57
53
|
|
58
|
-
|
59
|
-
|
54
|
+
it 'even unregisters non-configurable disabled linters' do
|
55
|
+
config = { 'FakeLinter' => { 'Enabled' => false } }
|
56
|
+
configuration_file = CukeLinter::FileHelper.create_file(name: '.cuke_linter', extension: '', text: config.to_yaml)
|
57
|
+
non_configurable_linter = CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter')
|
58
|
+
non_configurable_linter.instance_eval('undef :configure')
|
60
59
|
|
61
|
-
|
60
|
+
CukeLinter.register_linter(linter: non_configurable_linter, name: 'FakeLinter')
|
61
|
+
expect(subject.registered_linters['FakeLinter']).to_not be nil
|
62
62
|
|
63
|
-
|
64
|
-
end
|
63
|
+
subject.load_configuration(config_file_path: configuration_file)
|
65
64
|
|
66
|
-
|
67
|
-
|
68
|
-
configuration_file = CukeLinter::FileHelper.create_file(name: '.cuke_linter', extension: '', text: config.to_yaml)
|
65
|
+
expect(subject.registered_linters['FakeLinter']).to be nil
|
66
|
+
end
|
69
67
|
|
70
|
-
|
71
|
-
|
68
|
+
it 'uses the default configuration file in the current directory if no configuration file is provided' do
|
69
|
+
config = { 'FakeLinter1' => { 'Enabled' => false } }
|
70
|
+
configuration_file = CukeLinter::FileHelper.create_file(name: '.cuke_linter', extension: '', text: config.to_yaml)
|
72
71
|
|
73
|
-
|
74
|
-
subject.
|
72
|
+
CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter1'), name: 'FakeLinter1')
|
73
|
+
expect(subject.registered_linters['FakeLinter1']).to_not be nil
|
74
|
+
|
75
|
+
Dir.chdir(File.dirname(configuration_file)) do
|
76
|
+
subject.load_configuration
|
77
|
+
end
|
78
|
+
|
79
|
+
expect(subject.registered_linters['FakeLinter1']).to be nil
|
75
80
|
end
|
76
81
|
|
77
|
-
|
78
|
-
|
82
|
+
it 'raises an exception if no default configuration file is found and no configuration or file is provided' do
|
83
|
+
some_empty_directory = CukeLinter::FileHelper.create_directory
|
84
|
+
|
85
|
+
Dir.chdir(File.dirname(some_empty_directory)) do
|
86
|
+
expect { subject.load_configuration }.to raise_error('No configuration or configuration file given and no .cuke_linter file found')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'configures every linter for which it has a configuration' do
|
91
|
+
config = { 'FakeLinter1' => { 'Problem' => 'My custom message for FakeLinter1' },
|
92
|
+
'FakeLinter2' => { 'Problem' => 'My custom message for FakeLinter2' } }
|
93
|
+
|
94
|
+
CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter1'), name: 'FakeLinter1')
|
95
|
+
CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter2'), name: 'FakeLinter2')
|
96
|
+
linting_options.delete(:linters)
|
79
97
|
|
80
|
-
|
81
|
-
|
98
|
+
subject.load_configuration(config: config)
|
99
|
+
results = subject.lint(linting_options)
|
82
100
|
|
83
|
-
|
84
|
-
|
101
|
+
expect(results).to match_array([{ linter: 'FakeLinter1', location: 'path_to_file:1', problem: 'My custom message for FakeLinter1' },
|
102
|
+
{ linter: 'FakeLinter2', location: 'path_to_file:1', problem: 'My custom message for FakeLinter2' }])
|
85
103
|
end
|
86
|
-
end
|
87
104
|
|
88
|
-
|
89
|
-
|
90
|
-
|
105
|
+
it "does not try to configure linters that don't know how to be configured" do
|
106
|
+
config = { 'FakeLinter' => { 'Problem' => 'My custom message for FakeLinter' } }
|
107
|
+
non_configurable_linter = CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter')
|
108
|
+
non_configurable_linter.instance_eval('undef :configure')
|
109
|
+
|
110
|
+
CukeLinter.clear_registered_linters
|
111
|
+
CukeLinter.register_linter(linter: non_configurable_linter, name: 'FakeLinter')
|
112
|
+
linting_options.delete(:linters)
|
91
113
|
|
92
|
-
|
93
|
-
|
94
|
-
linting_options.delete(:linters)
|
114
|
+
subject.load_configuration(config: config)
|
115
|
+
results = subject.lint(linting_options)
|
95
116
|
|
96
|
-
|
97
|
-
|
117
|
+
expect(results).to match_array([{ linter: 'FakeLinter', location: 'path_to_file:1', problem: 'FakeLinter problem' }])
|
118
|
+
end
|
98
119
|
|
99
|
-
expect(results).to match_array([{ linter: 'FakeLinter1', location: 'path_to_file:1', problem: 'My custom message for FakeLinter1' },
|
100
|
-
{ linter: 'FakeLinter2', location: 'path_to_file:1', problem: 'My custom message for FakeLinter2' }])
|
101
120
|
end
|
102
121
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
122
|
+
describe 'targeted linters' do
|
123
|
+
|
124
|
+
before(:all) do
|
125
|
+
@targeted_linter_class = CukeLinter::LinterFactory.generate_fake_linter_class(class_name: 'ATargetedLinterClass', name: 'ATargetedLinter')
|
126
|
+
@another_targeted_linter_class = CukeLinter::LinterFactory.generate_fake_linter_class(class_name: 'AnotherTargetedLinterClass', name: 'AnotherTargetedLinter')
|
127
|
+
@yet_another_targeted_linter_class = CukeLinter::LinterFactory.generate_fake_linter_class(class_name: 'YetAnotherTargetedLinterClass', name: 'YetAnotherTargetedLinter')
|
128
|
+
|
129
|
+
@a_non_nested_targeted_linter_class = CukeLinter::LinterFactory.generate_fake_linter_class(module_name: nil, class_name: 'ANonNestedTargetedLinterClass', name: 'ANonNestedTargetedLinter')
|
130
|
+
@another_non_nested_targeted_linter_class = CukeLinter::LinterFactory.generate_fake_linter_class(module_name: nil, class_name: 'AnotherNonNestedTargetedLinterClass', name: 'AnotherNonNestedTargetedLinter')
|
131
|
+
|
132
|
+
@a_nested_targeted_linter_class = CukeLinter::LinterFactory.generate_fake_linter_class(module_name: 'Foo', class_name: 'ANestedTargetedLinterClass', name: 'ANestedTargetedLinter')
|
133
|
+
@another_nested_targeted_linter_class = CukeLinter::LinterFactory.generate_fake_linter_class(module_name: 'Foo', class_name: 'AnotherNestedTargetedLinterClass', name: 'AnotherNestedTargetedLinter')
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
let(:linter_name) { 'ATargetedLinter' }
|
138
|
+
let(:another_linter_name) { 'AnotherTargetedLinter' }
|
139
|
+
let(:yet_another_linter_name) { 'YetAnotherTargetedLinter' }
|
140
|
+
|
141
|
+
let(:non_nested_linter_name) { 'ANonNestedTargetedLinter' }
|
142
|
+
let(:another_non_nested_linter_name) { 'AnotherNonNestedTargetedLinter' }
|
143
|
+
let(:nested_linter_name) { 'ANestedTargetedLinter' }
|
144
|
+
let(:another_nested_linter_name) { 'AnotherNestedTargetedLinter' }
|
145
|
+
|
146
|
+
let(:linter_class_name) { 'ATargetedLinterClass' }
|
147
|
+
let(:another_linter_class_name) { 'AnotherTargetedLinterClass' }
|
148
|
+
let(:yet_another_linter_class_name) { 'YetAnotherTargetedLinterClass' }
|
149
|
+
let(:non_nested_linter_class_name) { 'ANonNestedTargetedLinterClass' }
|
150
|
+
let(:another_non_nested_linter_class_name) { 'AnotherNonNestedTargetedLinterClass' }
|
151
|
+
let(:nested_linter_class_name) { 'Foo::ANestedTargetedLinterClass' }
|
152
|
+
let(:another_nested_linter_class_name) { 'Foo::AnotherNestedTargetedLinterClass' }
|
153
|
+
|
154
|
+
let(:targeted_linter) { @targeted_linter_class.new }
|
155
|
+
let(:another_targeted_linter) { @another_targeted_linter_class.new }
|
156
|
+
let(:yet_another_targeted_linter) { @yet_another_targeted_linter_class.new }
|
157
|
+
let(:non_nested_targeted_linter) { @a_non_nested_targeted_linter_class.new }
|
158
|
+
let(:nested_targeted_linter) { @a_nested_targeted_linter_class.new }
|
159
|
+
|
160
|
+
let(:test_linters) { [targeted_linter] }
|
161
|
+
let(:test_linter_names) { [linter_name] }
|
162
|
+
let(:test_formatters) { [[CukeLinter::FormatterFactory.generate_fake_formatter, "#{CukeLinter::FileHelper::create_directory}/junk_output_file.txt"]] }
|
163
|
+
let(:test_model_trees) { [CukeModeler::FeatureFile.new(linted_file)] }
|
164
|
+
|
165
|
+
let(:test_directory) { CukeLinter::FileHelper.create_directory }
|
166
|
+
let(:linted_file) { CukeLinter::FileHelper.create_file(directory: test_directory,
|
167
|
+
extension: '.feature',
|
168
|
+
text: file_text) }
|
169
|
+
|
170
|
+
|
171
|
+
[:provided, :registered].each do |linter_type|
|
172
|
+
|
173
|
+
context "using #{linter_type} linters" do
|
174
|
+
|
175
|
+
if linter_type == :provided
|
176
|
+
let(:linting_options) { { model_trees: test_model_trees, linters: test_linters, formatters: test_formatters } }
|
177
|
+
else
|
178
|
+
let(:linting_options) { { model_trees: test_model_trees, formatters: test_formatters } }
|
179
|
+
|
180
|
+
before(:each) do
|
181
|
+
subject.clear_registered_linters
|
182
|
+
|
183
|
+
test_linters.each_with_index { |linter, index| subject.register_linter(linter: linter, name: test_linter_names[index]) }
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
context 'with non-nested class names' do
|
189
|
+
|
190
|
+
let(:test_linters) { [non_nested_targeted_linter] }
|
191
|
+
let(:test_linter_names) { [non_nested_linter_name] }
|
192
|
+
|
193
|
+
let(:file_text) { "Feature:
|
194
|
+
|
195
|
+
# cuke_linter:disable #{non_nested_linter_class_name}
|
196
|
+
# cuke_linter:enable #{another_non_nested_linter_class_name}
|
197
|
+
Scenario:" }
|
198
|
+
|
199
|
+
|
200
|
+
it 'handles the directives correctly' do
|
201
|
+
results = subject.lint(linting_options)
|
202
|
+
|
203
|
+
expect(results).to match_array([{ linter: non_nested_linter_name, location: linted_file, problem: "#{non_nested_linter_name} problem" },
|
204
|
+
{ linter: non_nested_linter_name, location: "#{linted_file}:1", problem: "#{non_nested_linter_name} problem" },
|
205
|
+
{ linter: another_non_nested_linter_name, location: "#{linted_file}:5", problem: "#{another_non_nested_linter_name} problem" }])
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
context 'with nested class names' do
|
211
|
+
|
212
|
+
let(:test_linters) { [nested_targeted_linter] }
|
213
|
+
let(:test_linter_names) { [nested_linter_name] }
|
214
|
+
|
215
|
+
let(:file_text) { "Feature:
|
216
|
+
|
217
|
+
# cuke_linter:disable #{nested_linter_class_name}
|
218
|
+
# cuke_linter:enable #{another_nested_linter_class_name}
|
219
|
+
Scenario:" }
|
220
|
+
|
221
|
+
|
222
|
+
it 'handles the directives correctly' do
|
223
|
+
results = subject.lint(linting_options)
|
224
|
+
|
225
|
+
expect(results).to match_array([{ linter: nested_linter_name, location: linted_file, problem: "#{nested_linter_name} problem" },
|
226
|
+
{ linter: nested_linter_name, location: "#{linted_file}:1", problem: "#{nested_linter_name} problem" },
|
227
|
+
{ linter: another_nested_linter_name, location: "#{linted_file}:5", problem: "#{another_nested_linter_name} problem" }])
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
context 'with multiple linters in the directive' do
|
233
|
+
|
234
|
+
let(:commas_text) { "Feature:
|
235
|
+
|
236
|
+
# cuke_linter:disable #{linter_class_name}, #{another_linter_class_name}, #{yet_another_linter_class_name}
|
237
|
+
Scenario:" }
|
238
|
+
let(:commas_file) { CukeLinter::FileHelper.create_file(directory: test_directory,
|
239
|
+
extension: '.feature',
|
240
|
+
text: commas_text,
|
241
|
+
name: 'commas_text') }
|
242
|
+
|
243
|
+
let(:spaces_text) { "Feature:
|
244
|
+
|
245
|
+
# cuke_linter:disable #{linter_class_name} #{another_linter_class_name} #{yet_another_linter_class_name}
|
246
|
+
Scenario:" }
|
247
|
+
let(:spaces_file) { CukeLinter::FileHelper.create_file(directory: test_directory,
|
248
|
+
extension: '.feature',
|
249
|
+
text: spaces_text,
|
250
|
+
name: 'spaces_text') }
|
251
|
+
|
252
|
+
let(:test_model_trees) { [CukeModeler::FeatureFile.new(commas_file),
|
253
|
+
CukeModeler::FeatureFile.new(spaces_file)] }
|
254
|
+
|
255
|
+
let(:test_linters) { [targeted_linter, another_targeted_linter, yet_another_targeted_linter] }
|
256
|
+
let(:test_linter_names) { [linter_name, another_linter_name, yet_another_linter_name] }
|
257
|
+
|
258
|
+
|
259
|
+
it 'handles the directives correctly' do
|
260
|
+
results = subject.lint(linting_options)
|
261
|
+
|
262
|
+
expect(results).to match_array([{ linter: linter_name, location: spaces_file, problem: "#{linter_name} problem" },
|
263
|
+
{ linter: linter_name, location: "#{spaces_file}:1", problem: "#{linter_name} problem" },
|
264
|
+
{ linter: another_linter_name, location: spaces_file, problem: "#{another_linter_name} problem" },
|
265
|
+
{ linter: another_linter_name, location: "#{spaces_file}:1", problem: "#{another_linter_name} problem" },
|
266
|
+
{ linter: yet_another_linter_name, location: spaces_file, problem: "#{yet_another_linter_name} problem" },
|
267
|
+
{ linter: yet_another_linter_name, location: "#{spaces_file}:1", problem: "#{yet_another_linter_name} problem" },
|
268
|
+
|
269
|
+
{ linter: linter_name, location: commas_file, problem: "#{linter_name} problem" },
|
270
|
+
{ linter: linter_name, location: "#{commas_file}:1", problem: "#{linter_name} problem" },
|
271
|
+
{ linter: another_linter_name, location: commas_file, problem: "#{another_linter_name} problem" },
|
272
|
+
{ linter: another_linter_name, location: "#{commas_file}:1", problem: "#{another_linter_name} problem" },
|
273
|
+
{ linter: yet_another_linter_name, location: commas_file, problem: "#{yet_another_linter_name} problem" },
|
274
|
+
{ linter: yet_another_linter_name, location: "#{commas_file}:1", problem: "#{yet_another_linter_name} problem" }])
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
|
279
|
+
context 'with multiple files' do
|
280
|
+
|
281
|
+
let(:modified_text) { "Feature:
|
282
|
+
|
283
|
+
# cuke_linter:disable #{linter_class_name}
|
284
|
+
Scenario:" }
|
285
|
+
let(:modified_file) { CukeLinter::FileHelper.create_file(directory: test_directory,
|
286
|
+
extension: '.feature',
|
287
|
+
text: modified_text) }
|
288
|
+
let(:unmodified_text) { "Feature:
|
289
|
+
|
290
|
+
Scenario:" }
|
291
|
+
let(:unmodified_file) { CukeLinter::FileHelper.create_file(directory: test_directory,
|
292
|
+
extension: '.feature',
|
293
|
+
text: unmodified_text) }
|
294
|
+
|
295
|
+
let(:test_model_trees) { [CukeModeler::FeatureFile.new(modified_file),
|
296
|
+
CukeModeler::FeatureFile.new(unmodified_file)] }
|
297
|
+
|
298
|
+
it 'does not use targeted linting changes outside of the file in which they occur' do
|
299
|
+
results = subject.lint(linting_options)
|
300
|
+
|
301
|
+
expect(results).to match_array([{ linter: linter_name, location: modified_file, problem: "#{linter_name} problem" },
|
302
|
+
{ linter: linter_name, location: "#{modified_file}:1", problem: "#{linter_name} problem" },
|
303
|
+
{ linter: linter_name, location: unmodified_file, problem: "#{linter_name} problem" },
|
304
|
+
{ linter: linter_name, location: "#{unmodified_file}:1", problem: "#{linter_name} problem" },
|
305
|
+
{ linter: linter_name, location: "#{unmodified_file}:3", problem: "#{linter_name} problem" }])
|
306
|
+
end
|
307
|
+
|
308
|
+
end
|
309
|
+
|
310
|
+
context 'with other comments in the file' do
|
311
|
+
|
312
|
+
let(:file_text) { "# I'm just a comment
|
313
|
+
Feature:
|
314
|
+
|
315
|
+
# cuke_linter:disable #{linter_class_name}
|
316
|
+
#Me too
|
317
|
+
Scenario:" }
|
318
|
+
|
319
|
+
|
320
|
+
it 'handles the directive correctly' do
|
321
|
+
results = subject.lint(linting_options)
|
322
|
+
|
323
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
324
|
+
{ linter: linter_name, location: "#{linted_file}:2", problem: "#{linter_name} problem" }])
|
325
|
+
end
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
context 'with varying whitespace' do
|
330
|
+
|
331
|
+
let(:extra_whitespace_text) { "Feature:
|
332
|
+
|
333
|
+
# cuke_linter:disable #{linter_class_name}
|
334
|
+
Scenario:" }
|
335
|
+
let(:extra_whitespace_file) { CukeLinter::FileHelper.create_file(directory: test_directory,
|
336
|
+
extension: '.feature',
|
337
|
+
text: extra_whitespace_text) }
|
338
|
+
let(:minimal_whitespace_text) { "Feature:
|
339
|
+
|
340
|
+
#cuke_linter:disable #{linter_class_name}
|
341
|
+
Scenario:" }
|
342
|
+
let(:minimal_whitespace_file) { CukeLinter::FileHelper.create_file(directory: test_directory,
|
343
|
+
extension: '.feature',
|
344
|
+
text: minimal_whitespace_text) }
|
345
|
+
|
346
|
+
let(:test_model_trees) { [CukeModeler::FeatureFile.new(extra_whitespace_file),
|
347
|
+
CukeModeler::FeatureFile.new(minimal_whitespace_file)] }
|
348
|
+
|
349
|
+
|
350
|
+
it 'handles the directives correctly' do
|
351
|
+
results = subject.lint(linting_options)
|
352
|
+
|
353
|
+
expect(results).to match_array([{ linter: linter_name, location: extra_whitespace_file, problem: "#{linter_name} problem" },
|
354
|
+
{ linter: linter_name, location: "#{extra_whitespace_file}:1", problem: "#{linter_name} problem" },
|
355
|
+
{ linter: linter_name, location: minimal_whitespace_file, problem: "#{linter_name} problem" },
|
356
|
+
{ linter: linter_name, location: "#{minimal_whitespace_file}:1", problem: "#{linter_name} problem" }])
|
357
|
+
end
|
358
|
+
|
359
|
+
|
360
|
+
context 'and multiple targeted linters' do
|
361
|
+
|
362
|
+
let(:spaced_commas_text) { "Feature:
|
363
|
+
|
364
|
+
# cuke_linter:disable #{linter_class_name} , #{another_linter_class_name} , #{yet_another_linter_class_name}
|
365
|
+
Scenario:" }
|
366
|
+
let(:spaced_commas_file) { CukeLinter::FileHelper.create_file(directory: test_directory,
|
367
|
+
extension: '.feature',
|
368
|
+
text: spaced_commas_text,
|
369
|
+
name: 'spaced_commas_text') }
|
370
|
+
|
371
|
+
let(:compact_commas_text) { "Feature:
|
372
|
+
|
373
|
+
# cuke_linter:disable #{linter_class_name},#{another_linter_class_name},#{yet_another_linter_class_name}
|
374
|
+
Scenario:" }
|
375
|
+
let(:compact_commas_file) { CukeLinter::FileHelper.create_file(directory: test_directory,
|
376
|
+
extension: '.feature',
|
377
|
+
text: compact_commas_text,
|
378
|
+
name: 'compact_commas_text') }
|
379
|
+
|
380
|
+
let(:spaced_space_text) { "Feature:
|
381
|
+
|
382
|
+
# cuke_linter:disable #{linter_class_name} #{another_linter_class_name} #{yet_another_linter_class_name}
|
383
|
+
Scenario:" }
|
384
|
+
let(:spaced_space_file) { CukeLinter::FileHelper.create_file(directory: test_directory,
|
385
|
+
extension: '.feature',
|
386
|
+
text: spaced_space_text,
|
387
|
+
name: 'spaced_space_text') }
|
388
|
+
|
389
|
+
let(:compact_space_text) { "Feature:
|
390
|
+
|
391
|
+
# cuke_linter:disable #{linter_class_name} #{another_linter_class_name} #{yet_another_linter_class_name}
|
392
|
+
Scenario:" }
|
393
|
+
let(:compact_space_file) { CukeLinter::FileHelper.create_file(directory: test_directory,
|
394
|
+
extension: '.feature',
|
395
|
+
text: compact_space_text,
|
396
|
+
name: 'compact_space_text') }
|
397
|
+
|
398
|
+
let(:test_model_trees) { [CukeModeler::FeatureFile.new(spaced_commas_file),
|
399
|
+
CukeModeler::FeatureFile.new(compact_commas_file),
|
400
|
+
CukeModeler::FeatureFile.new(spaced_space_file),
|
401
|
+
CukeModeler::FeatureFile.new(compact_space_file)] }
|
402
|
+
|
403
|
+
let(:test_linters) { [targeted_linter, another_targeted_linter, yet_another_targeted_linter] }
|
404
|
+
let(:test_linter_names) { [linter_name, another_linter_name, yet_another_linter_name] }
|
405
|
+
|
406
|
+
|
407
|
+
it 'handles the directives correctly' do
|
408
|
+
results = subject.lint(linting_options)
|
409
|
+
|
410
|
+
expect(results).to match_array([{ linter: linter_name, location: spaced_commas_file, problem: "#{linter_name} problem" },
|
411
|
+
{ linter: linter_name, location: "#{spaced_commas_file}:1", problem: "#{linter_name} problem" },
|
412
|
+
{ linter: another_linter_name, location: spaced_commas_file, problem: "#{another_linter_name} problem" },
|
413
|
+
{ linter: another_linter_name, location: "#{spaced_commas_file}:1", problem: "#{another_linter_name} problem" },
|
414
|
+
{ linter: yet_another_linter_name, location: spaced_commas_file, problem: "#{yet_another_linter_name} problem" },
|
415
|
+
{ linter: yet_another_linter_name, location: "#{spaced_commas_file}:1", problem: "#{yet_another_linter_name} problem" },
|
416
|
+
|
417
|
+
{ linter: linter_name, location: compact_commas_file, problem: "#{linter_name} problem" },
|
418
|
+
{ linter: linter_name, location: "#{compact_commas_file}:1", problem: "#{linter_name} problem" },
|
419
|
+
{ linter: another_linter_name, location: compact_commas_file, problem: "#{another_linter_name} problem" },
|
420
|
+
{ linter: another_linter_name, location: "#{compact_commas_file}:1", problem: "#{another_linter_name} problem" },
|
421
|
+
{ linter: yet_another_linter_name, location: compact_commas_file, problem: "#{yet_another_linter_name} problem" },
|
422
|
+
{ linter: yet_another_linter_name, location: "#{compact_commas_file}:1", problem: "#{yet_another_linter_name} problem" },
|
423
|
+
|
424
|
+
{ linter: linter_name, location: spaced_space_file, problem: "#{linter_name} problem" },
|
425
|
+
{ linter: linter_name, location: "#{spaced_space_file}:1", problem: "#{linter_name} problem" },
|
426
|
+
{ linter: another_linter_name, location: spaced_space_file, problem: "#{another_linter_name} problem" },
|
427
|
+
{ linter: another_linter_name, location: "#{spaced_space_file}:1", problem: "#{another_linter_name} problem" },
|
428
|
+
{ linter: yet_another_linter_name, location: spaced_space_file, problem: "#{yet_another_linter_name} problem" },
|
429
|
+
{ linter: yet_another_linter_name, location: "#{spaced_space_file}:1", problem: "#{yet_another_linter_name} problem" },
|
430
|
+
|
431
|
+
{ linter: linter_name, location: compact_space_file, problem: "#{linter_name} problem" },
|
432
|
+
{ linter: linter_name, location: "#{compact_space_file}:1", problem: "#{linter_name} problem" },
|
433
|
+
{ linter: another_linter_name, location: compact_space_file, problem: "#{another_linter_name} problem" },
|
434
|
+
{ linter: another_linter_name, location: "#{compact_space_file}:1", problem: "#{another_linter_name} problem" },
|
435
|
+
{ linter: yet_another_linter_name, location: compact_space_file, problem: "#{yet_another_linter_name} problem" },
|
436
|
+
{ linter: yet_another_linter_name, location: "#{compact_space_file}:1", problem: "#{yet_another_linter_name} problem" }])
|
437
|
+
end
|
438
|
+
|
439
|
+
end
|
440
|
+
|
441
|
+
end
|
442
|
+
|
443
|
+
context 'with a disabled(i.e. unregistered)/not provided linter' do
|
444
|
+
|
445
|
+
if linter_type == :provided
|
446
|
+
before(:each) do
|
447
|
+
test_linters.delete(targeted_linter)
|
448
|
+
end
|
449
|
+
else
|
450
|
+
before(:each) do
|
451
|
+
subject.unregister_linter(linter_name)
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
|
456
|
+
context 'that is explicitly disabled' do
|
457
|
+
|
458
|
+
# Used so that the linting process is not entirely bypassed due to no other linters being registered/provided
|
459
|
+
let(:baseline_linter_name) { 'BaselineLinter' }
|
460
|
+
let(:baseline_linter) { CukeLinter::LinterFactory.generate_fake_linter(name: baseline_linter_name) }
|
461
|
+
|
462
|
+
let(:test_linters) { [baseline_linter, targeted_linter] }
|
463
|
+
let(:test_linter_names) { [baseline_linter_name, linter_name] }
|
464
|
+
|
465
|
+
|
466
|
+
let(:file_text) { "Feature:
|
467
|
+
|
468
|
+
# cuke_linter:disable #{linter_class_name}
|
469
|
+
Scenario:" }
|
470
|
+
|
471
|
+
let(:baseline_linter_results) { [{ linter: baseline_linter_name, location: linted_file, problem: "#{baseline_linter_name} problem" },
|
472
|
+
{ linter: baseline_linter_name, location: "#{linted_file}:1", problem: "#{baseline_linter_name} problem" },
|
473
|
+
{ linter: baseline_linter_name, location: "#{linted_file}:4", problem: "#{baseline_linter_name} problem" }] }
|
107
474
|
|
108
|
-
CukeLinter.clear_registered_linters
|
109
|
-
CukeLinter.register_linter(linter: non_configurable_linter, name: 'FakeLinter')
|
110
|
-
linting_options.delete(:linters)
|
111
475
|
|
112
|
-
|
113
|
-
|
476
|
+
it 'does not use the linter' do
|
477
|
+
results = subject.lint(linting_options)
|
478
|
+
|
479
|
+
expect(results).to match_array(baseline_linter_results + [])
|
480
|
+
end
|
481
|
+
|
482
|
+
|
483
|
+
context 'multiple times' do
|
484
|
+
|
485
|
+
context 'with separate targetings' do
|
486
|
+
|
487
|
+
let(:file_text) { "Feature:
|
488
|
+
# cuke_linter:disable #{linter_class_name}
|
489
|
+
# cuke_linter:disable #{linter_class_name}
|
490
|
+
Scenario:" }
|
491
|
+
|
492
|
+
|
493
|
+
it 'does not use the linter' do
|
494
|
+
results = subject.lint(linting_options)
|
495
|
+
|
496
|
+
expect(results).to match_array(baseline_linter_results + [])
|
497
|
+
end
|
498
|
+
|
499
|
+
end
|
500
|
+
|
501
|
+
context 'with the same targeting' do
|
502
|
+
|
503
|
+
let(:file_text) { "Feature:
|
504
|
+
|
505
|
+
# cuke_linter:disable #{linter_class_name}, #{linter_class_name}
|
506
|
+
Scenario:" }
|
507
|
+
|
508
|
+
it 'does not use the linter' do
|
509
|
+
results = subject.lint(linting_options)
|
510
|
+
|
511
|
+
expect(results).to match_array(baseline_linter_results + [])
|
512
|
+
end
|
513
|
+
|
514
|
+
end
|
515
|
+
|
516
|
+
end
|
517
|
+
|
518
|
+
end
|
519
|
+
|
520
|
+
context 'that is explicitly enabled' do
|
521
|
+
|
522
|
+
let(:file_text) { "Feature:
|
523
|
+
|
524
|
+
# cuke_linter:enable #{linter_class_name}
|
525
|
+
Scenario:" }
|
526
|
+
|
527
|
+
it 'uses the linter' do
|
528
|
+
results = subject.lint(linting_options)
|
529
|
+
|
530
|
+
expect(results).to match_array([{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
531
|
+
end
|
532
|
+
|
533
|
+
context 'multiple times' do
|
534
|
+
|
535
|
+
context 'with separate targetings' do
|
536
|
+
|
537
|
+
let(:file_text) { "Feature:
|
538
|
+
# cuke_linter:enable #{linter_class_name}
|
539
|
+
# cuke_linter:enable #{linter_class_name}
|
540
|
+
Scenario:" }
|
541
|
+
|
542
|
+
it 'uses the linter' do
|
543
|
+
results = subject.lint(linting_options)
|
544
|
+
|
545
|
+
expect(results).to match_array([{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
546
|
+
end
|
547
|
+
|
548
|
+
it 'does not include redundant linting results' do
|
549
|
+
results = subject.lint(linting_options)
|
550
|
+
|
551
|
+
expect(results).to match_array([{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
552
|
+
end
|
553
|
+
|
554
|
+
end
|
555
|
+
|
556
|
+
context 'with the same targeting' do
|
557
|
+
|
558
|
+
let(:file_text) { "Feature:
|
559
|
+
|
560
|
+
# cuke_linter:enable #{linter_class_name}, #{linter_class_name}
|
561
|
+
Scenario:" }
|
562
|
+
|
563
|
+
it 'uses the linter' do
|
564
|
+
results = subject.lint(linting_options)
|
565
|
+
|
566
|
+
expect(results).to match_array([{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
567
|
+
end
|
568
|
+
|
569
|
+
it 'does not include redundant linting results' do
|
570
|
+
results = subject.lint(linting_options)
|
571
|
+
|
572
|
+
expect(results).to match_array([{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
573
|
+
end
|
574
|
+
|
575
|
+
end
|
576
|
+
|
577
|
+
end
|
578
|
+
|
579
|
+
context 'and then re-disabled' do
|
580
|
+
|
581
|
+
let(:file_text) { "Feature:
|
582
|
+
|
583
|
+
# cuke_linter:enable #{linter_class_name}
|
584
|
+
Scenario:
|
585
|
+
# cuke_linter:disable #{linter_class_name}
|
586
|
+
Scenario:" }
|
587
|
+
|
588
|
+
it 'ceases using the linter' do
|
589
|
+
results = subject.lint(linting_options)
|
590
|
+
|
591
|
+
expect(results).to match_array([{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
592
|
+
end
|
593
|
+
|
594
|
+
end
|
595
|
+
|
596
|
+
end
|
597
|
+
|
598
|
+
end
|
599
|
+
|
600
|
+
context 'with an enabled(i.e. registered)/provided linter' do
|
601
|
+
|
602
|
+
if linter_type == :provided
|
603
|
+
before(:each) do
|
604
|
+
test_linters << targeted_linter unless test_linters.include?(targeted_linter)
|
605
|
+
end
|
606
|
+
else
|
607
|
+
before(:each) do
|
608
|
+
subject.register_linter(linter: targeted_linter, name: linter_name)
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
|
613
|
+
context 'that is explicitly disabled' do
|
614
|
+
|
615
|
+
let(:file_text) { "Feature:
|
616
|
+
|
617
|
+
# cuke_linter:disable #{linter_class_name}
|
618
|
+
Scenario:" }
|
619
|
+
|
620
|
+
|
621
|
+
it 'does not use the linter' do
|
622
|
+
results = subject.lint(linting_options)
|
623
|
+
|
624
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
625
|
+
{ linter: linter_name, location: "#{linted_file}:1", problem: "#{linter_name} problem" }])
|
626
|
+
end
|
627
|
+
|
628
|
+
context 'multiple times' do
|
629
|
+
|
630
|
+
context 'with separate targetings' do
|
631
|
+
|
632
|
+
let(:file_text) { "Feature:
|
633
|
+
# cuke_linter:disable #{linter_class_name}
|
634
|
+
# cuke_linter:disable #{linter_class_name}
|
635
|
+
Scenario:" }
|
636
|
+
|
637
|
+
|
638
|
+
it 'does not use the linter' do
|
639
|
+
results = subject.lint(linting_options)
|
640
|
+
|
641
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
642
|
+
{ linter: linter_name, location: "#{linted_file}:1", problem: "#{linter_name} problem" }])
|
643
|
+
end
|
644
|
+
|
645
|
+
end
|
646
|
+
|
647
|
+
context 'with the same targeting' do
|
648
|
+
|
649
|
+
let(:file_text) { "Feature:
|
650
|
+
|
651
|
+
# cuke_linter:disable #{linter_class_name}, #{linter_class_name}
|
652
|
+
Scenario:" }
|
653
|
+
|
654
|
+
it 'does not use the linter' do
|
655
|
+
results = subject.lint(linting_options)
|
656
|
+
|
657
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
658
|
+
{ linter: linter_name, location: "#{linted_file}:1", problem: "#{linter_name} problem" }])
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
end
|
663
|
+
|
664
|
+
context 'and then re-enabled' do
|
665
|
+
|
666
|
+
let(:file_text) { "Feature:
|
667
|
+
|
668
|
+
# cuke_linter:disable #{linter_class_name}
|
669
|
+
Scenario:
|
670
|
+
# cuke_linter:enable #{linter_class_name}
|
671
|
+
Scenario:" }
|
672
|
+
|
673
|
+
|
674
|
+
it 'resumes using the linter' do
|
675
|
+
results = subject.lint(linting_options)
|
676
|
+
|
677
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
678
|
+
{ linter: linter_name, location: "#{linted_file}:1", problem: "#{linter_name} problem" },
|
679
|
+
{ linter: linter_name, location: "#{linted_file}:6", problem: "#{linter_name} problem" }])
|
680
|
+
end
|
681
|
+
|
682
|
+
it 'does not include redundant linting results' do
|
683
|
+
results = subject.lint(linting_options)
|
684
|
+
|
685
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
686
|
+
{ linter: linter_name, location: "#{linted_file}:1", problem: "#{linter_name} problem" },
|
687
|
+
{ linter: linter_name, location: "#{linted_file}:6", problem: "#{linter_name} problem" }])
|
688
|
+
end
|
689
|
+
|
690
|
+
end
|
691
|
+
|
692
|
+
end
|
693
|
+
|
694
|
+
context 'that is explicitly enabled' do
|
695
|
+
|
696
|
+
let(:file_text) { "Feature:
|
697
|
+
|
698
|
+
# cuke_linter:enable #{linter_class_name}
|
699
|
+
Scenario:" }
|
700
|
+
|
701
|
+
|
702
|
+
it 'uses the linter' do
|
703
|
+
results = subject.lint(linting_options)
|
704
|
+
|
705
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
706
|
+
{ linter: linter_name, location: "#{linted_file}:1", problem: "#{linter_name} problem" },
|
707
|
+
{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
708
|
+
end
|
709
|
+
|
710
|
+
it 'does not include redundant linting results' do
|
711
|
+
results = subject.lint(linting_options)
|
712
|
+
|
713
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
714
|
+
{ linter: linter_name, location: "#{linted_file}:1", problem: "#{linter_name} problem" },
|
715
|
+
{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
716
|
+
end
|
717
|
+
|
718
|
+
it 'prefers the provided (or registered) linter over having to make a new one' do
|
719
|
+
|
720
|
+
# Tweaking the linter objects that will already exist so that any linter created from the same class will be noticeably different
|
721
|
+
provided_linter = test_linters.find { |linter| linter.is_a?(Kernel.const_get(linter_class_name)) }
|
722
|
+
registered_linter = CukeLinter.registered_linters.values.find { |linter| linter.is_a?(Kernel.const_get(linter_class_name)) }
|
723
|
+
|
724
|
+
if provided_linter
|
725
|
+
def provided_linter.name
|
726
|
+
'Pre-existing Linter'
|
727
|
+
end
|
728
|
+
end
|
729
|
+
|
730
|
+
if registered_linter
|
731
|
+
def registered_linter.name
|
732
|
+
'Pre-existing Linter'
|
733
|
+
end
|
734
|
+
end
|
735
|
+
|
736
|
+
|
737
|
+
results = subject.lint(linting_options)
|
738
|
+
|
739
|
+
expect(results).to match_array([{ linter: 'Pre-existing Linter', location: linted_file, problem: "#{linter_name} problem" },
|
740
|
+
{ linter: 'Pre-existing Linter', location: "#{linted_file}:1", problem: "#{linter_name} problem" },
|
741
|
+
{ linter: 'Pre-existing Linter', location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
742
|
+
end
|
743
|
+
|
744
|
+
|
745
|
+
context 'multiple times' do
|
746
|
+
|
747
|
+
context 'with separate targetings' do
|
748
|
+
|
749
|
+
let(:file_text) { "Feature:
|
750
|
+
# cuke_linter:enable #{linter_class_name}
|
751
|
+
# cuke_linter:enable #{linter_class_name}
|
752
|
+
Scenario:" }
|
753
|
+
|
754
|
+
it 'uses the linter' do
|
755
|
+
results = subject.lint(linting_options)
|
756
|
+
|
757
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
758
|
+
{ linter: linter_name, location: "#{linted_file}:1", problem: "#{linter_name} problem" },
|
759
|
+
{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
760
|
+
end
|
761
|
+
|
762
|
+
it 'does not include redundant linting results' do
|
763
|
+
results = subject.lint(linting_options)
|
764
|
+
|
765
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
766
|
+
{ linter: linter_name, location: "#{linted_file}:1", problem: "#{linter_name} problem" },
|
767
|
+
{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
768
|
+
end
|
769
|
+
|
770
|
+
end
|
771
|
+
|
772
|
+
context 'with the same targeting' do
|
773
|
+
|
774
|
+
let(:file_text) { "Feature:
|
775
|
+
|
776
|
+
# cuke_linter:enable #{linter_class_name}, #{linter_class_name}
|
777
|
+
Scenario:" }
|
778
|
+
|
779
|
+
it 'uses the linter' do
|
780
|
+
results = subject.lint(linting_options)
|
781
|
+
|
782
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
783
|
+
{ linter: linter_name, location: "#{linted_file}:1", problem: "#{linter_name} problem" },
|
784
|
+
{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
785
|
+
end
|
786
|
+
|
787
|
+
it 'does not include redundant linting results' do
|
788
|
+
results = subject.lint(linting_options)
|
789
|
+
|
790
|
+
expect(results).to match_array([{ linter: linter_name, location: linted_file, problem: "#{linter_name} problem" },
|
791
|
+
{ linter: linter_name, location: "#{linted_file}:1", problem: "#{linter_name} problem" },
|
792
|
+
{ linter: linter_name, location: "#{linted_file}:4", problem: "#{linter_name} problem" }])
|
793
|
+
end
|
794
|
+
|
795
|
+
end
|
796
|
+
|
797
|
+
end
|
798
|
+
|
799
|
+
end
|
800
|
+
|
801
|
+
end
|
802
|
+
|
803
|
+
end
|
804
|
+
|
805
|
+
end
|
114
806
|
|
115
|
-
expect(results).to match_array([{ linter: 'FakeLinter', location: 'path_to_file:1', problem: 'FakeLinter problem' }])
|
116
807
|
end
|
117
808
|
|
118
809
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cuke_linter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Kessler
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-09-
|
11
|
+
date: 2019-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cuke_modeler
|
@@ -194,11 +194,12 @@ files:
|
|
194
194
|
- lib/cuke_linter/version.rb
|
195
195
|
- testing/cucumber/features/command_line.feature
|
196
196
|
- testing/cucumber/features/configuration/configuring_linters.feature
|
197
|
+
- testing/cucumber/features/configuration/locally_scoping_linters.feature
|
197
198
|
- testing/cucumber/features/configuration/using_configurations.feature
|
199
|
+
- testing/cucumber/features/custom_linters.feature
|
200
|
+
- testing/cucumber/features/default_linters.feature
|
198
201
|
- testing/cucumber/features/formatters/pretty_formatter.feature
|
199
202
|
- testing/cucumber/features/linters/background_does_more_than_setup.feature
|
200
|
-
- testing/cucumber/features/linters/custom_linters.feature
|
201
|
-
- testing/cucumber/features/linters/default_linters.feature
|
202
203
|
- testing/cucumber/features/linters/element_with_too_many_tags.feature
|
203
204
|
- testing/cucumber/features/linters/example_without_name.feature
|
204
205
|
- testing/cucumber/features/linters/feature_without_description.feature
|