cuke_linter 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +14 -0
- data/CHANGELOG.md +19 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +148 -0
- data/Rakefile +23 -0
- data/appveyor.yml +24 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/cuke_linter.gemspec +34 -0
- data/environments/common_env.rb +11 -0
- data/environments/cucumber_env.rb +4 -0
- data/environments/rspec_env.rb +41 -0
- data/exe/cuke_linter +6 -0
- data/lib/cuke_linter/formatters/pretty_formatter.rb +48 -0
- data/lib/cuke_linter/linters/feature_without_scenarios_linter.rb +22 -0
- data/lib/cuke_linter/version.rb +3 -0
- data/lib/cuke_linter.rb +71 -0
- data/testing/cucumber/features/command_line.feature +12 -0
- data/testing/cucumber/features/formatters/pretty_formatter.feature +24 -0
- data/testing/cucumber/features/linters/default_linters.feature +7 -0
- data/testing/cucumber/features/linters/feature_without_scenarios.feature +12 -0
- data/testing/cucumber/step_definitions/action_steps.rb +13 -0
- data/testing/cucumber/step_definitions/setup_steps.rb +30 -0
- data/testing/cucumber/step_definitions/verification_steps.rb +18 -0
- data/testing/file_helper.rb +28 -0
- data/testing/formatter_factory.rb +15 -0
- data/testing/linter_factory.rb +22 -0
- data/testing/model_factory.rb +39 -0
- data/testing/rspec/spec/integration/cuke_linter_integration_spec.rb +112 -0
- data/testing/rspec/spec/integration/formatters/formatter_integration_specs.rb +5 -0
- data/testing/rspec/spec/integration/formatters/pretty_formatter_integration_spec.rb +8 -0
- data/testing/rspec/spec/integration/linters/feature_without_scenarios_linter_integration_spec.rb +8 -0
- data/testing/rspec/spec/integration/linters/linter_integration_specs.rb +7 -0
- data/testing/rspec/spec/unit/cuke_linter_unit_spec.rb +83 -0
- data/testing/rspec/spec/unit/formatters/formatter_unit_specs.rb +11 -0
- data/testing/rspec/spec/unit/formatters/pretty_formatter_unit_spec.rb +75 -0
- data/testing/rspec/spec/unit/linters/feature_without_scenarios_linter_unit_spec.rb +72 -0
- data/testing/rspec/spec/unit/linters/linter_unit_specs.rb +38 -0
- metadata +183 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
Then(/^a linting report will be made for all features$/) do
|
2
|
+
expect(@output).to match(/\d+ issues found/)
|
3
|
+
end
|
4
|
+
|
5
|
+
Then(/^the resulting output is the following:$/) do |text|
|
6
|
+
expect(@results).to eq(text)
|
7
|
+
end
|
8
|
+
|
9
|
+
Then(/^an error is reported$/) do |table|
|
10
|
+
table.hashes.each do |error_record|
|
11
|
+
expect(@results).to include({ problem: error_record['problem'],
|
12
|
+
location: error_record['location'].sub('<path_to_file>', @model.get_ancestor(:feature_file).path) })
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Then(/^the following linters are registered by default$/) do |linter_names|
|
17
|
+
expect(CukeLinter.registered_linters.keys).to eq(linter_names.raw.flatten)
|
18
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
|
4
|
+
module CukeLinter
|
5
|
+
module FileHelper
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def created_directories
|
10
|
+
@created_directories ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_directory(options = {})
|
14
|
+
options[:name] ||= 'test_directory'
|
15
|
+
options[:directory] ||= Dir.mktmpdir
|
16
|
+
|
17
|
+
path = "#{options[:directory]}/#{options[:name]}"
|
18
|
+
|
19
|
+
Dir::mkdir(path)
|
20
|
+
created_directories << options[:directory]
|
21
|
+
|
22
|
+
path
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CukeLinter
|
2
|
+
module FormatterFactory
|
3
|
+
|
4
|
+
def self.generate_fake_formatter(name: 'FakeFormater')
|
5
|
+
formatter = Object.new
|
6
|
+
|
7
|
+
formatter.define_singleton_method('format') do |data|
|
8
|
+
data.reduce("#{name}: ") { |final, lint_error| final << "#{lint_error[:problem]}: #{lint_error[:location]}\n" }
|
9
|
+
end
|
10
|
+
|
11
|
+
formatter
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module CukeLinter
|
2
|
+
module LinterFactory
|
3
|
+
|
4
|
+
def self.generate_fake_linter(name: 'FakeLinter')
|
5
|
+
linter = Object.new
|
6
|
+
|
7
|
+
linter.define_singleton_method('lint') do |model|
|
8
|
+
location = model.respond_to?(:source_line) ? "#{model.get_ancestor(:feature_file).path}:#{model.source_line}" :
|
9
|
+
model.path
|
10
|
+
[{ problem: "#{name} problem",
|
11
|
+
location: location }]
|
12
|
+
end
|
13
|
+
|
14
|
+
linter.define_singleton_method('name') do
|
15
|
+
name
|
16
|
+
end
|
17
|
+
|
18
|
+
linter
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module CukeLinter
|
2
|
+
class TestModel < CukeModeler::Model
|
3
|
+
|
4
|
+
include CukeModeler::Sourceable
|
5
|
+
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
module CukeLinter
|
11
|
+
module ModelFactory
|
12
|
+
|
13
|
+
def self.generate_feature_model(source_text: 'Feature:', parent_file_path: 'path_to_file')
|
14
|
+
fake_file_model = CukeModeler::FeatureFile.new
|
15
|
+
fake_file_model.path = parent_file_path
|
16
|
+
|
17
|
+
model = CukeModeler::Feature.new(source_text)
|
18
|
+
model.parent_model = fake_file_model
|
19
|
+
|
20
|
+
model
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.generate_lintable_model(parent_file_path: 'path_to_file', source_line: '1', children: [])
|
24
|
+
fake_file_model = CukeModeler::FeatureFile.new
|
25
|
+
fake_file_model.path = parent_file_path
|
26
|
+
|
27
|
+
model = CukeLinter::TestModel.new
|
28
|
+
model.parent_model = fake_file_model
|
29
|
+
model.source_line = source_line
|
30
|
+
|
31
|
+
model.define_singleton_method('children') do
|
32
|
+
children
|
33
|
+
end
|
34
|
+
|
35
|
+
model
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require_relative '../../../../environments/rspec_env'
|
2
|
+
|
3
|
+
RSpec.describe CukeLinter do
|
4
|
+
|
5
|
+
let(:test_model_tree) { CukeLinter::ModelFactory.generate_lintable_model }
|
6
|
+
let(:test_linters) { [CukeLinter::LinterFactory.generate_fake_linter] }
|
7
|
+
let(:test_formatters) { [[CukeLinter::FormatterFactory.generate_fake_formatter, "#{CukeLinter::FileHelper::create_directory}/junk_output_file.txt"]] }
|
8
|
+
let(:linting_options) { { model_tree: test_model_tree, linters: test_linters, formatters: test_formatters } }
|
9
|
+
|
10
|
+
|
11
|
+
it 'returns the un-formatted linting data when linting' do
|
12
|
+
results = subject.lint(linting_options)
|
13
|
+
|
14
|
+
expect(results).to eq([{ linter: 'FakeLinter', location: 'path_to_file:1', problem: 'FakeLinter problem' }])
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'uses evey formatter provided' do
|
18
|
+
linting_options[:formatters] = [[CukeLinter::FormatterFactory.generate_fake_formatter(name: 'Formatter1')],
|
19
|
+
[CukeLinter::FormatterFactory.generate_fake_formatter(name: 'Formatter2')]]
|
20
|
+
|
21
|
+
expect { subject.lint(linting_options) }.to output("Formatter1: FakeLinter problem: path_to_file:1\nFormatter2: FakeLinter problem: path_to_file:1\n").to_stdout
|
22
|
+
end
|
23
|
+
|
24
|
+
it "uses the 'pretty' formatter if none are provided" do
|
25
|
+
linting_options.delete(:formatters)
|
26
|
+
|
27
|
+
expect { subject.lint(linting_options) }.to output(['FakeLinter',
|
28
|
+
' FakeLinter problem',
|
29
|
+
' path_to_file:1',
|
30
|
+
'',
|
31
|
+
'1 issues found',
|
32
|
+
''].join("\n")).to_stdout
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'outputs formatted linting data to the provided output location' do
|
36
|
+
output_path = "#{CukeLinter::FileHelper::create_directory}/output.txt"
|
37
|
+
linting_options[:formatters] = [[CukeLinter::FormatterFactory.generate_fake_formatter(name: 'Formatter1'),
|
38
|
+
output_path]]
|
39
|
+
|
40
|
+
expect { subject.lint(linting_options) }.to_not output.to_stdout
|
41
|
+
expect(File.read(output_path)).to eq("Formatter1: FakeLinter problem: path_to_file:1\n")
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'outputs formatted data to STDOUT if not location is provided' do
|
45
|
+
linting_options[:formatters] = [[CukeLinter::FormatterFactory.generate_fake_formatter(name: 'Formatter1')]]
|
46
|
+
|
47
|
+
expect { subject.lint(linting_options) }.to output("Formatter1: FakeLinter problem: path_to_file:1\n").to_stdout
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'lints every model in the model tree' do
|
51
|
+
child_model = CukeLinter::ModelFactory.generate_lintable_model(source_line: 3)
|
52
|
+
parent_model = CukeLinter::ModelFactory.generate_lintable_model(source_line: 5, children: [child_model])
|
53
|
+
linting_options[:model_tree] = parent_model
|
54
|
+
|
55
|
+
results = subject.lint(linting_options)
|
56
|
+
|
57
|
+
expect(results).to match_array([{ linter: 'FakeLinter', location: 'path_to_file:3', problem: 'FakeLinter problem' },
|
58
|
+
{ linter: 'FakeLinter', location: 'path_to_file:5', problem: 'FakeLinter problem' }])
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'models the current directory if a model tree is not provided' do
|
62
|
+
test_dir = CukeLinter::FileHelper::create_directory
|
63
|
+
File.write("#{test_dir}/test_feature.feature", "Feature:")
|
64
|
+
linting_options.delete(:model_tree)
|
65
|
+
|
66
|
+
Dir.chdir(test_dir) do
|
67
|
+
@results = subject.lint(linting_options)
|
68
|
+
end
|
69
|
+
|
70
|
+
# There should be 3 models to lint: the directory, the file, and the feature
|
71
|
+
expect(@results.count).to eq(3)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'uses evey linter provided' do
|
75
|
+
linting_options[:linters] = [CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter1'),
|
76
|
+
CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter2')]
|
77
|
+
|
78
|
+
results = subject.lint(linting_options)
|
79
|
+
|
80
|
+
expect(results).to match_array([{ linter: 'FakeLinter1', location: 'path_to_file:1', problem: 'FakeLinter1 problem' },
|
81
|
+
{ linter: 'FakeLinter2', location: 'path_to_file:1', problem: 'FakeLinter2 problem' }])
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'uses all registered linters if none are provided', :linter_registration do
|
85
|
+
CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter1'), name: 'FakeLinter1')
|
86
|
+
CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter2'), name: 'FakeLinter2')
|
87
|
+
CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter3'), name: 'FakeLinter3')
|
88
|
+
linting_options.delete(:linters)
|
89
|
+
|
90
|
+
results = subject.lint(linting_options)
|
91
|
+
|
92
|
+
expect(results).to match_array([{ linter: 'FakeLinter1', location: 'path_to_file:1', problem: 'FakeLinter1 problem' },
|
93
|
+
{ linter: 'FakeLinter2', location: 'path_to_file:1', problem: 'FakeLinter2 problem' },
|
94
|
+
{ linter: 'FakeLinter3', location: 'path_to_file:1', problem: 'FakeLinter3 problem' }])
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'includes the name of the linter in the linting data' do
|
98
|
+
linting_options[:linters] = [CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter1'),
|
99
|
+
CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter2')]
|
100
|
+
|
101
|
+
results = subject.lint(linting_options)
|
102
|
+
|
103
|
+
expect(results).to match_array([{ linter: 'FakeLinter1', location: 'path_to_file:1', problem: 'FakeLinter1 problem' },
|
104
|
+
{ linter: 'FakeLinter2', location: 'path_to_file:1', problem: 'FakeLinter2 problem' }])
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'has a default set of registered linters' do
|
108
|
+
expect(subject.registered_linters.keys).to include('FeatureWithoutScenariosLinter')
|
109
|
+
expect(subject.registered_linters['FeatureWithoutScenariosLinter']).to be_a(CukeLinter::FeatureWithoutScenariosLinter)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative '../../../../environments/rspec_env'
|
2
|
+
|
3
|
+
|
4
|
+
RSpec.describe 'the gem' do
|
5
|
+
|
6
|
+
let(:gemspec) { eval(File.read "#{__dir__}/../../../../cuke_linter.gemspec") }
|
7
|
+
|
8
|
+
it 'has an executable' do
|
9
|
+
expect(gemspec.executables).to include('cuke_linter')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'validates cleanly' do
|
13
|
+
mock_ui = Gem::MockGemUi.new
|
14
|
+
Gem::DefaultUserInteraction.use_ui(mock_ui) { gemspec.validate }
|
15
|
+
|
16
|
+
expect(mock_ui.error).to_not match(/warn/i)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
RSpec.describe CukeLinter do
|
23
|
+
|
24
|
+
it "has a version number" do
|
25
|
+
expect(CukeLinter::VERSION).not_to be nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can lint' do
|
29
|
+
expect(CukeLinter).to respond_to(:lint)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'lints the (optionally) given model tree using the (optionally) provided set of linters and formats the output with the (optionally) provided formatters' do
|
33
|
+
expect(CukeLinter.method(:lint).arity).to eq(-1)
|
34
|
+
expect(CukeLinter.method(:lint).parameters).to match_array([[:key, :model_tree],
|
35
|
+
[:key, :linters],
|
36
|
+
[:key, :formatters]])
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'can register a linter' do
|
40
|
+
expect(CukeLinter).to respond_to(:register_linter)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'can unregister a linter' do
|
44
|
+
expect(CukeLinter).to respond_to(:unregister_linter)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'registers a linter by name' do
|
48
|
+
expect(CukeLinter.method(:register_linter).arity).to eq(1)
|
49
|
+
expect(CukeLinter.method(:register_linter).parameters).to match_array([[:keyreq, :linter],
|
50
|
+
[:keyreq, :name]])
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'unregisters a linter by name' do
|
54
|
+
expect(CukeLinter.method(:unregister_linter).arity).to eq(1)
|
55
|
+
expect(CukeLinter.method(:unregister_linter).parameters).to match_array([[:req, :name]])
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'knows its currently registered linters' do
|
59
|
+
expect(CukeLinter).to respond_to(:registered_linters)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'correctly registers, unregisters, and tracks linters', :linter_registration do
|
63
|
+
CukeLinter.clear_registered_linters
|
64
|
+
CukeLinter.register_linter(name: 'foo', linter: :linter_1)
|
65
|
+
CukeLinter.register_linter(name: 'bar', linter: :linter_2)
|
66
|
+
CukeLinter.register_linter(name: 'baz', linter: :linter_3)
|
67
|
+
|
68
|
+
CukeLinter.unregister_linter('bar')
|
69
|
+
|
70
|
+
expect(CukeLinter.registered_linters).to eq({ 'foo' => :linter_1,
|
71
|
+
'baz' => :linter_3, })
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'can clear all of its currently registered linters', :linter_registration do
|
75
|
+
expect(CukeLinter).to respond_to(:clear_registered_linters)
|
76
|
+
|
77
|
+
CukeLinter.register_linter(name: 'some_linter', linter: :the_linter)
|
78
|
+
CukeLinter.clear_registered_linters
|
79
|
+
|
80
|
+
expect(CukeLinter.registered_linters).to eq({})
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require_relative '../../../../../environments/rspec_env'
|
2
|
+
|
3
|
+
|
4
|
+
RSpec.describe CukeLinter::PrettyFormatter do
|
5
|
+
|
6
|
+
it_should_behave_like 'a formatter at the unit level'
|
7
|
+
|
8
|
+
|
9
|
+
it 'formats linting data as pretty text' do
|
10
|
+
linting_data = [{ linter: 'SomeLinter',
|
11
|
+
problem: 'Some problem',
|
12
|
+
location: 'path/to/the_file:1' },
|
13
|
+
{ linter: 'SomeOtherLinter',
|
14
|
+
problem: 'Some other problem',
|
15
|
+
location: 'path/to/the_file:1' }]
|
16
|
+
|
17
|
+
results = subject.format(linting_data)
|
18
|
+
|
19
|
+
expect(results).to eq(['SomeLinter',
|
20
|
+
' Some problem',
|
21
|
+
' path/to/the_file:1',
|
22
|
+
'SomeOtherLinter',
|
23
|
+
' Some other problem',
|
24
|
+
' path/to/the_file:1',
|
25
|
+
'',
|
26
|
+
'2 issues found'].join("\n"))
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'groups data by linter and problem' do
|
30
|
+
linting_data = [{ linter: 'SomeLinter',
|
31
|
+
problem: 'Some problem',
|
32
|
+
location: 'path/to/the_file:1' },
|
33
|
+
{ linter: 'SomeOtherLinter',
|
34
|
+
problem: 'Some other problem',
|
35
|
+
location: 'path/to/the_file:1' },
|
36
|
+
{ linter: 'SomeLinter',
|
37
|
+
problem: 'Some problem',
|
38
|
+
location: 'path/to/the_file:11' }]
|
39
|
+
|
40
|
+
results = subject.format(linting_data)
|
41
|
+
|
42
|
+
expect(results).to eq(['SomeLinter',
|
43
|
+
' Some problem',
|
44
|
+
' path/to/the_file:1',
|
45
|
+
' path/to/the_file:11',
|
46
|
+
'SomeOtherLinter',
|
47
|
+
' Some other problem',
|
48
|
+
' path/to/the_file:1',
|
49
|
+
'',
|
50
|
+
'3 issues found'].join("\n"))
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'orders violations by line number' do
|
54
|
+
linting_data = [{ linter: 'SomeLinter',
|
55
|
+
problem: 'Some problem',
|
56
|
+
location: 'path/to/the_file:2' },
|
57
|
+
{ linter: 'SomeLinter',
|
58
|
+
problem: 'Some problem',
|
59
|
+
location: 'path/to/the_file:3' },
|
60
|
+
{ linter: 'SomeLinter',
|
61
|
+
problem: 'Some problem',
|
62
|
+
location: 'path/to/the_file:1' }]
|
63
|
+
|
64
|
+
results = subject.format(linting_data)
|
65
|
+
|
66
|
+
expect(results).to eq(['SomeLinter',
|
67
|
+
' Some problem',
|
68
|
+
' path/to/the_file:1',
|
69
|
+
' path/to/the_file:2',
|
70
|
+
' path/to/the_file:3',
|
71
|
+
'',
|
72
|
+
'3 issues found'].join("\n"))
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require_relative '../../../../../environments/rspec_env'
|
2
|
+
|
3
|
+
|
4
|
+
RSpec.describe CukeLinter::FeatureWithoutScenariosLinter do
|
5
|
+
|
6
|
+
let(:good_data) do
|
7
|
+
model = CukeLinter::ModelFactory.generate_feature_model
|
8
|
+
model.tests = ['totally_a_test']
|
9
|
+
|
10
|
+
model
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:bad_data) do
|
14
|
+
model = CukeLinter::ModelFactory.generate_feature_model
|
15
|
+
model.tests = []
|
16
|
+
|
17
|
+
model
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
it_should_behave_like 'a linter at the unit level'
|
22
|
+
|
23
|
+
|
24
|
+
it 'has a name' do
|
25
|
+
expect(subject.name).to eq('FeatureWithoutScenariosLinter')
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'linting' do
|
29
|
+
|
30
|
+
context 'a feature with no scenarios' do
|
31
|
+
|
32
|
+
let(:test_model) do
|
33
|
+
model = CukeLinter::ModelFactory.generate_feature_model(parent_file_path: 'path_to_file')
|
34
|
+
model.tests = []
|
35
|
+
|
36
|
+
model
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'records a problem' do
|
40
|
+
results = subject.lint(test_model)
|
41
|
+
|
42
|
+
expect(results.first[:problem]).to eq('Feature has no scenarios')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'records the location of the problem' do
|
46
|
+
model_1 = CukeLinter::ModelFactory.generate_feature_model(parent_file_path: 'path_to_file')
|
47
|
+
model_1.tests = []
|
48
|
+
model_1.source_line = 1
|
49
|
+
model_2 = CukeLinter::ModelFactory.generate_feature_model(parent_file_path: 'path_to_file')
|
50
|
+
model_2.tests = []
|
51
|
+
model_2.source_line = 3
|
52
|
+
|
53
|
+
results = subject.lint(model_1)
|
54
|
+
expect(results.first[:location]).to eq('path_to_file:1')
|
55
|
+
|
56
|
+
results = subject.lint(model_2)
|
57
|
+
expect(results.first[:location]).to eq('path_to_file:3')
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'a non-feature model' do
|
63
|
+
|
64
|
+
it 'returns an empty set of results' do
|
65
|
+
results = subject.lint(CukeModeler::Model.new)
|
66
|
+
|
67
|
+
expect(results).to eq([])
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
shared_examples_for 'a linter at the unit level' do
|
2
|
+
|
3
|
+
it 'is named' do
|
4
|
+
expect(subject).to respond_to(:name)
|
5
|
+
expect(subject.name).to be_a_kind_of(String)
|
6
|
+
expect(subject.name).to_not be_empty
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'can lint' do
|
10
|
+
expect(subject).to respond_to(:lint)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'lints a model' do
|
14
|
+
expect(subject.method(:lint).arity).to eq(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with good data' do
|
18
|
+
|
19
|
+
it 'returns an empty set of results' do
|
20
|
+
expect(subject.lint(good_data)).to eq([])
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with bad data' do
|
26
|
+
|
27
|
+
it 'returns a set of detected problems' do
|
28
|
+
expect(subject.lint(bad_data)).to_not be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'includes the problems and their locations in its results' do
|
32
|
+
results = subject.lint(bad_data)
|
33
|
+
|
34
|
+
results.each { |result| expect(result.keys).to match_array([:problem, :location]) }
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|