cuke_linter 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 499570d540f5b32c4774f299e4733b932c32c2b14f3b52d47f4bec6e99854edd
4
- data.tar.gz: 8e4361c1f2cd7c7f11f503dbc1ba9deaa073f89a220fbcf8cd1ef1cc63ff1265
3
+ metadata.gz: 5bc43845a692a99b982b4a41b56c877bc41231bf931e04defd9d70aad2193f04
4
+ data.tar.gz: 6b8e365c8eda00b38728d02fd88caad4b04fc601c94caeb03dc760bc374ebac9
5
5
  SHA512:
6
- metadata.gz: 37d73b22eb4be9d13b98339b14605c6d5b99c4c3584bc03f8baada3f88035787d4427980b0308855277ceccd5aa846468cecb34e03ad6e5c20b936426dfc62ab
7
- data.tar.gz: e678c2ee1ac758234b4fd461c4c46acc555e5752d886203189b155a451a294b74d40b971b5aa8415af3239fa402ead4f9352bc6188a245d9dede6b720e1d5a1c
6
+ metadata.gz: 650f8900dc73461011250fc3d487c0c14f85e7064c7bed6b65316fedaeac167dd368127ee900774058d6109e6a4ea397994eeeffa9b6295fec223ae5c5344cf4
7
+ data.tar.gz: 9ee27f5bc99953d7b830dd4ffcdec2fd47b6fe51f1b4f9fce2cdb1380495705325fa10be710afdf88268c1c4113a36803e8a71bcc5c1d1932749c0784f151bc2
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.3.0] - 2019-04-07
12
+
13
+ ### Added
14
+ - Linter configuration: linters can now be configured (turned on/off, conditions changed, etc.) instead of having to always use the default settings
15
+
11
16
  ## [0.2.0] - 2019-03-19
12
17
 
13
18
  ### Added
@@ -23,6 +28,7 @@ Nothing yet...
23
28
  - Custom linters, formatters, and command line usability
24
29
 
25
30
 
26
- [Unreleased]: https://github.com/enkessler/cuke_linter/compare/v0.2.0...HEAD
31
+ [Unreleased]: https://github.com/enkessler/cuke_linter/compare/v0.3.0...HEAD
32
+ [0.3.0]: https://github.com/enkessler/cuke_linter/compare/v0.2.0...v0.3.0
27
33
  [0.2.0]: https://github.com/enkessler/cuke_linter/compare/v0.1.0...v0.2.0
28
34
  [0.1.0]: https://github.com/enkessler/cuke_linter/compare/2bbd3f29f4eb45b6e9ea7d47c5bb47182bf4fde7...v0.1.0
data/Rakefile CHANGED
@@ -1,8 +1,9 @@
1
1
  require 'rake'
2
2
  require 'racatt'
3
3
  require 'coveralls/rake/task'
4
- require 'colorize'
4
+ require 'rainbow'
5
5
 
6
+ Rainbow.enabled = true
6
7
 
7
8
  namespace 'racatt' do
8
9
  Racatt.create_tasks
@@ -19,20 +20,20 @@ namespace 'cuke_linter' do
19
20
 
20
21
  desc 'Check documentation with RDoc'
21
22
  task :check_documentation do
22
- output = `rdoc lib`
23
+ output = `rdoc lib -C`
23
24
  puts output
24
25
 
25
26
  if output =~ /100.00% documented/
26
- puts 'All code documented'.green
27
+ puts Rainbow('All code documented').green
27
28
  else
28
- raise 'Parts of the gem are undocumented'.red
29
+ raise Rainbow('Parts of the gem are undocumented').red
29
30
  end
30
31
  end
31
32
 
32
33
  desc 'Run all of the tests'
33
34
  task :test_everything => [:clear_coverage] do
34
- rspec_args = '--pattern "testing/rspec/spec/**/*_spec.rb"'
35
- cucumber_args = "testing/cucumber/features -r environments/cucumber_env.rb -f progress -t 'not @wip'"
35
+ rspec_args = '--pattern "testing/rspec/spec/**/*_spec.rb" --force-color'
36
+ cucumber_args = "testing/cucumber/features -r environments/cucumber_env.rb -f progress -t 'not @wip' --color"
36
37
 
37
38
  Rake::Task['racatt:test_everything'].invoke(rspec_args, cucumber_args)
38
39
  end
@@ -42,6 +43,20 @@ namespace 'cuke_linter' do
42
43
 
43
44
  desc 'The task that CI will run. Do not run locally.'
44
45
  task :ci_build => ['cuke_linter:test_everything', 'coveralls:push']
46
+
47
+ desc 'Check that things look good before trying to release'
48
+ task :prerelease_check do
49
+ begin
50
+ Rake::Task['cuke_linter:test_everything'].invoke
51
+ Rake::Task['cuke_linter:check_documentation'].invoke
52
+ rescue => e
53
+ puts Rainbow("Something isn't right!").red
54
+ raise e
55
+ end
56
+
57
+ puts Rainbow('All is well. :)').green
58
+ end
59
+
45
60
  end
46
61
 
47
62
 
data/cuke_linter.gemspec CHANGED
@@ -33,5 +33,5 @@ Gem::Specification.new do |spec|
33
33
  spec.add_development_dependency "rspec", "~> 3.0"
34
34
  spec.add_development_dependency 'simplecov', '< 1.0.0'
35
35
  spec.add_development_dependency 'coveralls', '< 1.0.0'
36
- spec.add_development_dependency 'colorize', '< 1.0.0'
36
+ spec.add_development_dependency 'rainbow', '< 4.0.0'
37
37
  end
@@ -7,6 +7,14 @@ require 'cucumber'
7
7
  require_all 'testing/cucumber/step_definitions'
8
8
 
9
9
 
10
+ Before do
11
+ CukeLinter.clear_registered_linters
12
+ end
13
+
14
+ Before do
15
+ @root_test_directory = CukeLinter::FileHelper.create_directory
16
+ end
17
+
10
18
  at_exit do
11
19
  CukeLinter::FileHelper.created_directories.each do |dir_path|
12
20
  FileUtils.remove_entry(dir_path, true)
@@ -4,8 +4,10 @@ SimpleCov.command_name('rspec_tests')
4
4
  require_relative 'common_env'
5
5
  require 'rspec'
6
6
  require 'rubygems/mock_gem_ui'
7
+ require 'yaml'
7
8
 
8
9
  require_relative '../testing/rspec/spec/unit/formatters/formatter_unit_specs'
10
+ require_relative '../testing/rspec/spec/unit/linters/configurable_linter_unit_specs'
9
11
  require_relative '../testing/rspec/spec/unit/linters/linter_unit_specs'
10
12
  require_relative '../testing/rspec/spec/integration/formatters/formatter_integration_specs'
11
13
  require_relative '../testing/rspec/spec/integration/linters/linter_integration_specs'
data/lib/cuke_linter.rb CHANGED
@@ -12,33 +12,56 @@ require 'cuke_linter/linters/test_with_too_many_steps_linter'
12
12
 
13
13
  module CukeLinter
14
14
 
15
- @registered_linters = { 'FeatureWithoutScenariosLinter' => FeatureWithoutScenariosLinter.new,
16
- 'ExampleWithoutNameLinter' => ExampleWithoutNameLinter.new,
17
- 'OutlineWithSingleExampleRowLinter' => OutlineWithSingleExampleRowLinter.new,
18
- 'TestWithTooManyStepsLinter' => TestWithTooManyStepsLinter.new }
15
+ @original_linters = { 'FeatureWithoutScenariosLinter' => FeatureWithoutScenariosLinter.new,
16
+ 'ExampleWithoutNameLinter' => ExampleWithoutNameLinter.new,
17
+ 'OutlineWithSingleExampleRowLinter' => OutlineWithSingleExampleRowLinter.new,
18
+ 'TestWithTooManyStepsLinter' => TestWithTooManyStepsLinter.new }
19
+
20
+ # Configures linters based on the given options
21
+ def self.load_configuration(config_file_path: nil, config: nil)
22
+ # TODO: define what happens if both a configuration file and a configuration are provided. Merge them or have direct config take precedence? Both?
23
+
24
+ unless config || config_file_path
25
+ config_file_path = "#{Dir.pwd}/.cuke_linter"
26
+ raise 'No configuration or configuration file given and no .cuke_linter file found' unless File.exist?(config_file_path)
27
+ end
28
+
29
+ config = config || YAML.load_file(config_file_path)
30
+
31
+ config.each_pair do |linter_name, options|
32
+ unregister_linter(linter_name) if options.key?('Enabled') && !options['Enabled']
33
+
34
+ registered_linters[linter_name].configure(options) if registered_linters[linter_name]
35
+ end
36
+ end
37
+
38
+ # Returns the registered linters to their default state
39
+ def self.reset_linters
40
+ @registered_linters = nil
41
+ end
19
42
 
20
43
  # Registers for linting use the given linter object, tracked by the given name
21
44
  def self.register_linter(linter:, name:)
22
- @registered_linters[name] = linter
45
+ self.registered_linters[name] = linter
23
46
  end
24
47
 
25
48
  # Unregisters the linter object tracked by the given name so that it is not used for linting
26
49
  def self.unregister_linter(name)
27
- @registered_linters.delete(name)
50
+ self.registered_linters.delete(name)
28
51
  end
29
52
 
30
53
  # Lists the names of the currently registered linting objects
31
54
  def self.registered_linters
32
- @registered_linters
55
+ @registered_linters ||= Marshal.load(Marshal.dump(@original_linters))
33
56
  end
34
57
 
35
58
  # Unregisters all currently registered linting objects
36
59
  def self.clear_registered_linters
37
- @registered_linters.clear
60
+ self.registered_linters.clear
38
61
  end
39
62
 
40
63
  # Lints the tree of model objects rooted at the given model using the given linting objects and formatting the results with the given formatters and their respective output locations
41
- def self.lint(model_tree: CukeModeler::Directory.new(Dir.pwd), linters: @registered_linters.values, formatters: [[CukeLinter::PrettyFormatter.new]])
64
+ def self.lint(model_tree: CukeModeler::Directory.new(Dir.pwd), linters: self.registered_linters.values, formatters: [[CukeLinter::PrettyFormatter.new]])
42
65
  # puts "model tree: #{model_tree}"
43
66
  # puts "linters: #{linters}"
44
67
  # puts "formatters: #{formatters}"
@@ -9,14 +9,20 @@ module CukeLinter
9
9
  'TestWithTooManyStepsLinter'
10
10
  end
11
11
 
12
+ # Changes the linting settings on the linter using the provided configuration
13
+ def configure(options)
14
+ @step_threshold = options['StepThreshold'] if options['StepThreshold']
15
+ end
16
+
12
17
  # Lints the given model and returns linting data about said model
13
18
  def lint(model)
14
19
  return [] unless model.is_a?(CukeModeler::Scenario) || model.is_a?(CukeModeler::Outline)
15
20
 
16
- step_count = model.steps.nil? ? 0 : model.steps.count
21
+ step_count = model.steps.nil? ? 0 : model.steps.count
22
+ step_threshold = @step_threshold || 10
17
23
 
18
- if step_count > 10
19
- [{ problem: "Test has too many steps. #{step_count} steps found (max 10)", location: "#{model.get_ancestor(:feature_file).path}:#{model.source_line}" }]
24
+ if step_count > step_threshold
25
+ [{ problem: "Test has too many steps. #{step_count} steps found (max #{step_threshold})", location: "#{model.get_ancestor(:feature_file).path}:#{model.source_line}" }]
20
26
  else
21
27
  []
22
28
  end
@@ -1,4 +1,4 @@
1
1
  module CukeLinter
2
2
  # The release version of this gem
3
- VERSION = "0.2.0"
3
+ VERSION = "0.3.0"
4
4
  end
@@ -0,0 +1,19 @@
1
+ Feature: Configuration of linters
2
+
3
+ Instead of having to modify the linting object directly in a script at runtime, a configuration file can be used so that specific linters can be configured in a more convenient, static manner. Some configurable properties are available across all linters while some are linter specific.
4
+
5
+
6
+ Scenario: Disabling a linter
7
+ Given a linter registered as "AlwaysFindsAProblem"
8
+ And the following configuration file:
9
+ """
10
+ AlwaysFindsAProblem:
11
+ Enabled: false
12
+ """
13
+ And the following feature:
14
+ """
15
+ Feature: Something in which a problem could exist
16
+ """
17
+ When the configuration file is used
18
+ And the feature is linted
19
+ Then no error is reported
@@ -0,0 +1,46 @@
1
+ Feature: Using a configuration
2
+
3
+ Configuration can be done during a script or through a configuration file. This file can be explicitly provided or a default configuration file will be used.
4
+
5
+
6
+ Scenario: Providing a configuration directly
7
+ Given a linter registered as "SomeLinter"
8
+ When the following code is used:
9
+ """
10
+ CukeLinter.load_configuration(config: { 'SomeLinter' => { 'Enabled' => false } })
11
+ """
12
+ Then the linter "SomeLinter" is no longer registered
13
+
14
+ Scenario: Loading a configuration from a file
15
+ Given a linter registered as "SomeLinter"
16
+ And the following configuration file "my_config.file":
17
+ """
18
+ SomeLinter:
19
+ Enabled: false
20
+ """
21
+ When the following code is used:
22
+ """
23
+ CukeLinter.load_configuration(config_file_path: '<path_to>/my_config.file')
24
+ """
25
+ Then the linter "SomeLinter" is no longer registered
26
+
27
+ Scenario: Using the default configuration file
28
+ Given a directory "test_directory"
29
+ And the following configuration file "test_directory/.cuke_linter":
30
+ """
31
+ SomeLinter:
32
+ Enabled: false
33
+ """
34
+ And a linter registered as "SomeLinter"
35
+ When "test_directory" is the current directory
36
+ And the following code is used:
37
+ """
38
+ CukeLinter.load_configuration
39
+ """
40
+ Then the linter "SomeLinter" is no longer registered
41
+
42
+ @wip
43
+ Scenario: Configuring from the command line
44
+
45
+ @wip
46
+ Scenario: Using the default configuration file from the command line
@@ -6,7 +6,7 @@ Feature: Default Linters
6
6
 
7
7
 
8
8
  Scenario: Using the default linters
9
- Given no other linters have been registered
9
+ Given no other linters have been registered or unregistered
10
10
  Then the following linters are registered by default
11
11
  | ExampleWithoutNameLinter |
12
12
  | FeatureWithoutScenariosLinter |
@@ -31,3 +31,26 @@ Feature: Test with too many steps linter
31
31
  Then an error is reported
32
32
  | linter | problem | location |
33
33
  | TestWithTooManyStepsLinter | Test has too many steps. 11 steps found (max 10) | <path_to_file>:3 |
34
+
35
+ Scenario: Configuration of step count threshold
36
+ Given a linter for tests with too many steps has been registered
37
+ And the following configuration file:
38
+ """
39
+ TestWithTooManyStepsLinter:
40
+ StepThreshold: 3
41
+ """
42
+ And the following feature:
43
+ """
44
+ Feature:
45
+
46
+ Scenario:
47
+ * step 1
48
+ * step 2
49
+ * step 3
50
+ * step one too many...
51
+ """
52
+ When the configuration file is loaded
53
+ And the feature is linted
54
+ Then an error is reported
55
+ | linter | problem | location |
56
+ | TestWithTooManyStepsLinter | Test has too many steps. 4 steps found (max 3) | <path_to_file>:3 |
@@ -8,10 +8,30 @@ When(/^it is formatted by the "([^"]*)" formatter$/) do |linter_name|
8
8
  @results = CukeLinter.const_get("#{linter_name.capitalize}Formatter").new.format(@linter_data)
9
9
  end
10
10
 
11
- When(/^it is linted$/) do
12
- options = { model_tree: @model,
13
- linters: [@linter],
14
- formatters: [[CukeLinter::FormatterFactory.generate_fake_formatter, "#{CukeLinter::FileHelper::create_directory}/junk_output_file.txt"]] }
11
+ When(/^(?:the feature|it) is linted$/) do
12
+ options = { model_tree: @model,
13
+ formatters: [[CukeLinter::FormatterFactory.generate_fake_formatter, "#{CukeLinter::FileHelper::create_directory}/junk_output_file.txt"]] }
14
+ options[:linters] = [@linter] if @linter
15
15
 
16
16
  @results = CukeLinter.lint(options)
17
17
  end
18
+
19
+ When(/^the configuration file is (?:used|loaded)$/) do
20
+ CukeLinter.load_configuration(config_file_path: @configuration_file_path)
21
+ end
22
+
23
+ And(/^the following code is used:$/) do |code|
24
+ code.sub!('<path_to>', @root_test_directory)
25
+
26
+ if @working_directory
27
+ Dir.chdir(@working_directory) do
28
+ eval(code)
29
+ end
30
+ else
31
+ eval(code)
32
+ end
33
+ end
34
+
35
+ When(/^"([^"]*)" is the current directory$/) do |directory|
36
+ @working_directory = "#{@root_test_directory}/#{directory}"
37
+ end
@@ -25,8 +25,8 @@ Given(/^a linter for features without scenarios$/) do
25
25
  @linter = CukeLinter::FeatureWithoutScenariosLinter.new
26
26
  end
27
27
 
28
- Given(/^no other linters have been registered$/) do
29
- # There is no way to 'reset' the linters, so just assume that no changes have been made
28
+ Given(/^no other linters have been registered or unregistered$/) do
29
+ CukeLinter.reset_linters
30
30
  end
31
31
 
32
32
  Given(/^a linter for examples without names$/) do
@@ -40,3 +40,25 @@ end
40
40
  Given(/^a linter for tests with too many steps$/) do
41
41
  @linter = CukeLinter::TestWithTooManyStepsLinter.new
42
42
  end
43
+
44
+ Given(/^a linter for tests with too many steps has been registered$/) do
45
+ CukeLinter.register_linter(linter: CukeLinter::TestWithTooManyStepsLinter.new, name: 'TestWithTooManyStepsLinter')
46
+ end
47
+
48
+ Given(/^the following configuration file(?: "([^"]*)")?:$/) do |file_name, text|
49
+ file_name ||= '.cuke_linter'
50
+
51
+ @configuration_file_path = CukeLinter::FileHelper.create_file(directory: @root_test_directory, name: file_name, extension: '', text: text)
52
+ end
53
+
54
+ Given(/^a linter "([^"]*)"$/) do |linter_class|
55
+ @linter = CukeLinter.const_get(linter_class).new
56
+ end
57
+
58
+ Given(/^a linter registered as "([^"]*)"$/) do |linter_name|
59
+ CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: linter_name), name: linter_name)
60
+ end
61
+
62
+ Given(/^a directory "([^"]*)"$/) do |directory_name|
63
+ @test_directory = CukeLinter::FileHelper.create_directory(directory: @root_test_directory, name: directory_name)
64
+ end
@@ -17,3 +17,11 @@ end
17
17
  Then(/^the following linters are registered by default$/) do |linter_names|
18
18
  expect(CukeLinter.registered_linters.keys).to match_array(linter_names.raw.flatten)
19
19
  end
20
+
21
+ Then(/^no error is reported$/) do
22
+ expect(@results).to be_empty
23
+ end
24
+
25
+ Then(/^the linter "([^"]*)" is no longer registered$/) do |linter_name|
26
+ expect(CukeLinter.registered_linters).to_not have_key(linter_name)
27
+ end
@@ -22,6 +22,18 @@ module CukeLinter
22
22
  path
23
23
  end
24
24
 
25
+ def create_file(options = {})
26
+ options[:text] ||= ''
27
+ options[:name] ||= 'test_file'
28
+ options[:extension] ||= '.txt'
29
+ options[:directory] ||= create_directory
30
+
31
+ file_path = "#{options[:directory]}/#{options[:name]}#{options[:extension]}"
32
+ File.write(file_path, options[:text])
33
+
34
+ file_path
35
+ end
36
+
25
37
  end
26
38
 
27
39
  end
@@ -5,9 +5,10 @@ module CukeLinter
5
5
  linter = Object.new
6
6
 
7
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",
8
+ location = model.respond_to?(:source_line) ? "#{model.get_ancestor(:feature_file).path}:#{model.source_line}" : model.path
9
+ problem = @problem || "#{name} problem"
10
+
11
+ [{ problem: problem,
11
12
  location: location }]
12
13
  end
13
14
 
@@ -15,6 +16,11 @@ module CukeLinter
15
16
  name
16
17
  end
17
18
 
19
+ linter.define_singleton_method('configure') do |options|
20
+ @problem = options['Problem'] if options['Problem']
21
+ end
22
+
23
+
18
24
  linter
19
25
  end
20
26
 
@@ -115,4 +115,79 @@ RSpec.describe CukeLinter do
115
115
  expect(subject.registered_linters['TestWithTooManyStepsLinter']).to be_a(CukeLinter::TestWithTooManyStepsLinter)
116
116
  end
117
117
 
118
+ it 'returns to its default set of linters after being reset' do
119
+ original_names = CukeLinter.registered_linters.keys
120
+ original_linter_types = CukeLinter.registered_linters.values.map(&:class)
121
+ new_linter = CukeLinter::LinterFactory.generate_fake_linter
122
+
123
+ CukeLinter.register_linter(linter: new_linter, name: 'FakeLinter')
124
+ CukeLinter.reset_linters
125
+
126
+ expect(CukeLinter.registered_linters.keys).to eq(original_names)
127
+ expect(CukeLinter.registered_linters.values.map(&:class)).to eq(original_linter_types)
128
+ end
129
+
130
+ # To protect against someone modifying them
131
+ it 'does not reuse the old linting objects when resetting to the default linters' do
132
+ original_linter_ids = CukeLinter.registered_linters.values.map(&:object_id)
133
+
134
+ CukeLinter.reset_linters
135
+
136
+ expect(CukeLinter.registered_linters.values.map(&:object_id)).to_not match_array(original_linter_ids)
137
+ end
138
+
139
+
140
+ describe 'configuration' do
141
+
142
+ it 'unregisters disabled linters' do
143
+ config = { 'FakeLinter1' => { 'Enabled' => false } }
144
+ configuration_file = CukeLinter::FileHelper.create_file(name: '.cuke_linter', extension: '', text: config.to_yaml)
145
+
146
+ CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter1'), name: 'FakeLinter1')
147
+ expect(subject.registered_linters['FakeLinter1']).to_not be nil
148
+
149
+ subject.load_configuration(config_file_path: configuration_file)
150
+
151
+ expect(subject.registered_linters['FakeLinter1']).to be nil
152
+ end
153
+
154
+ it 'uses the default configuration file in the current directory if no configuration file is provided' do
155
+ config = { 'FakeLinter1' => { 'Enabled' => false } }
156
+ configuration_file = CukeLinter::FileHelper.create_file(name: '.cuke_linter', extension: '', text: config.to_yaml)
157
+
158
+ CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter1'), name: 'FakeLinter1')
159
+ expect(subject.registered_linters['FakeLinter1']).to_not be nil
160
+
161
+ Dir.chdir(File.dirname(configuration_file)) do
162
+ subject.load_configuration
163
+ end
164
+
165
+ expect(subject.registered_linters['FakeLinter1']).to be nil
166
+ end
167
+
168
+ it 'raises an exception if no default configuration file is found and no configuration or file is provided' do
169
+ some_empty_directory = CukeLinter::FileHelper.create_directory
170
+
171
+ Dir.chdir(File.dirname(some_empty_directory)) do
172
+ expect { subject.load_configuration }.to raise_error('No configuration or configuration file given and no .cuke_linter file found')
173
+ end
174
+ end
175
+
176
+ it 'configures every linter for which it has a configuration' do
177
+ config = { 'FakeLinter1' => { 'Problem' => 'My custom message for FakeLinter1' },
178
+ 'FakeLinter2' => { 'Problem' => 'My custom message for FakeLinter2' } }
179
+
180
+ CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter1'), name: 'FakeLinter1')
181
+ CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter(name: 'FakeLinter2'), name: 'FakeLinter2')
182
+ linting_options.delete(:linters)
183
+
184
+ subject.load_configuration(config: config)
185
+ results = subject.lint(linting_options)
186
+
187
+ expect(results).to match_array([{ linter: 'FakeLinter1', location: 'path_to_file:1', problem: 'My custom message for FakeLinter1' },
188
+ { linter: 'FakeLinter2', location: 'path_to_file:1', problem: 'My custom message for FakeLinter2' }])
189
+ end
190
+
191
+ end
192
+
118
193
  end
@@ -80,4 +80,22 @@ RSpec.describe CukeLinter do
80
80
  expect(CukeLinter.registered_linters).to eq({})
81
81
  end
82
82
 
83
+ it 'can reset to its default set of linters' do
84
+ expect(CukeLinter).to respond_to(:reset_linters)
85
+ end
86
+
87
+ describe 'configuration' do
88
+
89
+ it 'can load a configuration' do
90
+ expect(CukeLinter).to respond_to(:load_configuration)
91
+ end
92
+
93
+ it 'is configured optionally via a file or a directly provided configuration' do
94
+ expect(CukeLinter.method(:load_configuration).arity).to eq(-1)
95
+ expect(CukeLinter.method(:load_configuration).parameters).to match_array([[:key, :config_file_path],
96
+ [:key, :config]])
97
+ end
98
+
99
+ end
100
+
83
101
  end
@@ -0,0 +1,11 @@
1
+ shared_examples_for 'a configurable linter at the unit level' do
2
+
3
+ it 'is configurable' do
4
+ expect(subject).to respond_to(:configure)
5
+ end
6
+
7
+ it 'is configured via a set of options' do
8
+ expect(subject.method(:configure).arity).to eq(1)
9
+ end
10
+
11
+ end
@@ -29,6 +29,7 @@ RSpec.describe CukeLinter::TestWithTooManyStepsLinter do
29
29
 
30
30
 
31
31
  it_should_behave_like 'a linter at the unit level'
32
+ it_should_behave_like 'a configurable linter at the unit level'
32
33
 
33
34
 
34
35
  it 'has a name' do
@@ -139,6 +140,78 @@ RSpec.describe CukeLinter::TestWithTooManyStepsLinter do
139
140
 
140
141
  end
141
142
 
143
+
144
+ describe 'configuration' do
145
+
146
+ context 'with no configuration' do
147
+
148
+ let(:default_step_threshhold) { 10 }
149
+
150
+ context 'because configuration never happened' do
151
+
152
+ let(:unconfigured_test_model) do
153
+ model = CukeLinter::ModelFactory.send("generate_#{model_type}_model")
154
+ model.steps = []
155
+ (default_step_threshhold + 1).times { model.steps << :a_step }
156
+
157
+ model
158
+ end
159
+
160
+ it 'defaults to a step threshold of 10 steps' do
161
+ results = subject.lint(unconfigured_test_model)
162
+
163
+ expect(results.first[:problem]).to match(/^Test has too many steps. #{unconfigured_test_model.steps.count} steps found \(max 10\)/)
164
+ end
165
+
166
+ end
167
+
168
+ context 'because configuration did not set a step threshold' do
169
+ let(:configuration) { {} }
170
+ let(:configured_test_model) do
171
+ model = CukeLinter::ModelFactory.send("generate_#{model_type}_model")
172
+ model.steps = []
173
+ (default_step_threshhold + 1).times { model.steps << :a_step }
174
+
175
+ subject.configure(configuration)
176
+
177
+ model
178
+ end
179
+
180
+ it 'defaults to a step threshold of 10 steps' do
181
+ results = subject.lint(configured_test_model)
182
+
183
+ expect(results.first[:problem]).to match(/^Test has too many steps. #{configured_test_model.steps.count} steps found \(max 10\)/)
184
+ end
185
+
186
+ end
187
+
188
+ end
189
+
190
+
191
+ context 'with configuration' do
192
+
193
+ let(:step_threshhold) { 3 }
194
+ let(:configuration) { { 'StepThreshold' => step_threshhold } }
195
+ let(:configured_test_model) do
196
+ model = CukeLinter::ModelFactory.send("generate_#{model_type}_model")
197
+ model.steps = []
198
+ (step_threshhold + 1).times { model.steps << :a_step }
199
+
200
+ subject.configure(configuration)
201
+
202
+ model
203
+ end
204
+
205
+ it 'the step threshold used is the configured value' do
206
+ results = subject.lint(configured_test_model)
207
+
208
+ expect(results.first[:problem]).to match(/^Test has too many steps. #{configured_test_model.steps.count} steps found \(max #{step_threshhold}\)/)
209
+ end
210
+
211
+ end
212
+
213
+ end
214
+
142
215
  end
143
216
 
144
217
  context 'a non-test model' do
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.2.0
4
+ version: 0.3.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-03-20 00:00:00.000000000 Z
11
+ date: 2019-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cuke_modeler
@@ -137,19 +137,19 @@ dependencies:
137
137
  - !ruby/object:Gem::Version
138
138
  version: 1.0.0
139
139
  - !ruby/object:Gem::Dependency
140
- name: colorize
140
+ name: rainbow
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "<"
144
144
  - !ruby/object:Gem::Version
145
- version: 1.0.0
145
+ version: 4.0.0
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "<"
151
151
  - !ruby/object:Gem::Version
152
- version: 1.0.0
152
+ version: 4.0.0
153
153
  description:
154
154
  email:
155
155
  - morrow748@gmail.com
@@ -182,6 +182,8 @@ files:
182
182
  - lib/cuke_linter/linters/test_with_too_many_steps_linter.rb
183
183
  - lib/cuke_linter/version.rb
184
184
  - testing/cucumber/features/command_line.feature
185
+ - testing/cucumber/features/configuration/configuring_linters.feature
186
+ - testing/cucumber/features/configuration/using_configurations.feature
185
187
  - testing/cucumber/features/formatters/pretty_formatter.feature
186
188
  - testing/cucumber/features/linters/default_linters.feature
187
189
  - testing/cucumber/features/linters/example_without_name.feature
@@ -206,6 +208,7 @@ files:
206
208
  - testing/rspec/spec/unit/cuke_linter_unit_spec.rb
207
209
  - testing/rspec/spec/unit/formatters/formatter_unit_specs.rb
208
210
  - testing/rspec/spec/unit/formatters/pretty_formatter_unit_spec.rb
211
+ - testing/rspec/spec/unit/linters/configurable_linter_unit_specs.rb
209
212
  - testing/rspec/spec/unit/linters/example_without_name_linter_unit_spec.rb
210
213
  - testing/rspec/spec/unit/linters/feature_without_scenarios_linter_unit_spec.rb
211
214
  - testing/rspec/spec/unit/linters/linter_unit_specs.rb