cuke_linter 0.2.0 → 0.3.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 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