cuke_linter 0.6.0 → 0.7.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -1
  3. data/cuke_linter.gemspec +1 -0
  4. data/lib/cuke_linter.rb +24 -3
  5. data/lib/cuke_linter/linters/element_with_too_many_tags_linter.rb +41 -0
  6. data/lib/cuke_linter/linters/feature_without_name_linter.rb +20 -0
  7. data/lib/cuke_linter/linters/test_with_no_action_step_linter.rb +23 -0
  8. data/lib/cuke_linter/linters/test_with_no_name_linter.rb +20 -0
  9. data/lib/cuke_linter/linters/test_with_no_verification_step_linter.rb +23 -0
  10. data/lib/cuke_linter/linters/test_with_too_many_steps_linter.rb +1 -1
  11. data/lib/cuke_linter/version.rb +1 -1
  12. data/testing/cucumber/features/command_line.feature +6 -4
  13. data/testing/cucumber/features/configuration/configuring_linters.feature +36 -0
  14. data/testing/cucumber/features/linters/{background_does_more_than_setup_linter.feature → background_does_more_than_setup.feature} +2 -2
  15. data/testing/cucumber/features/linters/custom_linters.feature +3 -3
  16. data/testing/cucumber/features/linters/default_linters.feature +5 -1
  17. data/testing/cucumber/features/linters/element_with_too_many_tags.feature +70 -0
  18. data/testing/cucumber/features/linters/example_without_name.feature +6 -1
  19. data/testing/cucumber/features/linters/feature_without_description.feature +1 -1
  20. data/testing/cucumber/features/linters/feature_without_name.feature +18 -0
  21. data/testing/cucumber/features/linters/feature_without_scenarios.feature +1 -1
  22. data/testing/cucumber/features/linters/outline_with_single_example_row.feature +1 -1
  23. data/testing/cucumber/features/linters/{single_test_background_linter.feature → single_test_background.feature} +1 -1
  24. data/testing/cucumber/features/linters/step_too_long.feature +3 -3
  25. data/testing/cucumber/features/linters/step_with_end_period.feature +1 -1
  26. data/testing/cucumber/features/linters/test_with_no_action_step.feature +30 -0
  27. data/testing/cucumber/features/linters/test_with_no_name.feature +23 -0
  28. data/testing/cucumber/features/linters/test_with_no_verification_step.feature +31 -0
  29. data/testing/cucumber/features/linters/test_with_too_many_steps.feature +6 -6
  30. data/testing/cucumber/step_definitions/setup_steps.rb +24 -0
  31. data/testing/cucumber/step_definitions/verification_steps.rb +5 -1
  32. data/testing/model_factory.rb +1 -0
  33. data/testing/rspec/spec/integration/cli_integration_spec.rb +16 -11
  34. data/testing/rspec/spec/integration/cuke_linter_integration_spec.rb +37 -0
  35. data/testing/rspec/spec/integration/linters/element_with_too_many_tags_linter_integration_spec.rb +8 -0
  36. data/testing/rspec/spec/integration/linters/feature_without_name_linter_integration_spec.rb +8 -0
  37. data/testing/rspec/spec/integration/linters/test_with_no_action_step_integration_spec.rb +8 -0
  38. data/testing/rspec/spec/integration/linters/test_with_no_name_integration_spec.rb +8 -0
  39. data/testing/rspec/spec/integration/linters/test_with_no_verification_step_integration_spec.rb +8 -0
  40. data/testing/rspec/spec/unit/linters/element_with_too_many_tags_linter_unit_spec.rb +333 -0
  41. data/testing/rspec/spec/unit/linters/feature_without_name_linter_unit_spec.rb +112 -0
  42. data/testing/rspec/spec/unit/linters/step_with_too_many_characters_linter_unit_spec.rb +53 -52
  43. data/testing/rspec/spec/unit/linters/test_with_no_action_step_linter_unit_spec.rb +217 -0
  44. data/testing/rspec/spec/unit/linters/test_with_no_name_linter_unit_spec.rb +115 -0
  45. data/testing/rspec/spec/unit/linters/test_with_no_verification_step_linter_unit_spec.rb +217 -0
  46. data/testing/rspec/spec/unit/linters/test_with_too_many_steps_linter_unit_spec.rb +2 -2
  47. metadata +24 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b5619ded0f8f0a4db213f7c2505b8868865ea4f5a40991515bf8324c474d5b4
4
- data.tar.gz: 93c3214e99988dcfd03d6ce2eb15d291b8a1bbbc04a9af0f5c6f280a6fdccd6d
3
+ metadata.gz: 58a53b185027cee980dfa4801a9e2cb3ca7efdbd2cc0db2119a04636e494ef87
4
+ data.tar.gz: f71c950b3132a8141e401f2ec385c0f3ed895385ca8309be636960a34d51c2ec
5
5
  SHA512:
6
- metadata.gz: 325b5aadbcf822a5e00ffd1ca7db7c26c4e7c6d63673c509247c49364cd09a365b6c5bcb9e42d4a01ebfe12f8bd85378bc639bb41356bca5766c96334a934046
7
- data.tar.gz: 6ba5e64086bc5f79716408d6383b281ef468e63dc405423f216c05d6b3a342c0fedf3d2fee9bc4ba8b896a6db8004a40852fb0ed245c8b89328ba4df52bf7402
6
+ metadata.gz: 16060efd013a6f783514efedd830db6a9ce431f786a630ed5a521c99863202ad500a72aaae8c08870d38ef22cc4b7edcba21a2f36e01512e79b7d6f6bad8b597
7
+ data.tar.gz: cdb8c1250a9e5bf5b6406ed05c74c4cdf97b46d3927e6bb0b4640ef966961afab29eb712667e8110aa92c610336c3a0edb9c134805c0e2beb2eb5c60a7c600b7
data/CHANGELOG.md CHANGED
@@ -8,6 +8,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
 
9
9
  Nothing yet...
10
10
 
11
+
12
+ ## [0.7.0] - 2019-07-12
13
+
14
+ ### Added
15
+ - Linters can now be configured en masse instead of having to configure the same property for all of them individually.
16
+
17
+ - New linters
18
+ - ElementWithTooManyTagsLinter
19
+ - FeatureWithoutNameLinter
20
+ - TestWithNoActionStepLinter
21
+ - TestWithNoNameLinter
22
+ - TestWithNoVerificationStepLinter
23
+
11
24
  ## [0.6.0] - 2019-06-25
12
25
 
13
26
  ### Added
@@ -65,7 +78,8 @@ Nothing yet...
65
78
  - Custom linters, formatters, and command line usability
66
79
 
67
80
 
68
- [Unreleased]: https://github.com/enkessler/cuke_linter/compare/v0.6.0...HEAD
81
+ [Unreleased]: https://github.com/enkessler/cuke_linter/compare/v0.7.0...HEAD
82
+ [0.6.0]: https://github.com/enkessler/cuke_linter/compare/v0.6.0...v0.7.0
69
83
  [0.6.0]: https://github.com/enkessler/cuke_linter/compare/v0.5.0...v0.6.0
70
84
  [0.5.0]: https://github.com/enkessler/cuke_linter/compare/v0.4.0...v0.5.0
71
85
  [0.4.0]: https://github.com/enkessler/cuke_linter/compare/v0.3.1...v0.4.0
data/cuke_linter.gemspec CHANGED
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.license = "MIT"
15
15
 
16
16
 
17
+ # TODO: don't just include everything in the gem
17
18
  # Specify which files should be added to the gem when it is released.
18
19
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
20
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
data/lib/cuke_linter.rb CHANGED
@@ -5,13 +5,18 @@ require "cuke_linter/version"
5
5
  require 'cuke_linter/formatters/pretty_formatter'
6
6
  require 'cuke_linter/linters/linter'
7
7
  require 'cuke_linter/linters/background_does_more_than_setup_linter'
8
+ require 'cuke_linter/linters/element_with_too_many_tags_linter'
8
9
  require 'cuke_linter/linters/example_without_name_linter'
10
+ require 'cuke_linter/linters/feature_without_name_linter'
9
11
  require 'cuke_linter/linters/feature_without_description_linter'
10
12
  require 'cuke_linter/linters/feature_without_scenarios_linter'
11
13
  require 'cuke_linter/linters/outline_with_single_example_row_linter'
12
14
  require 'cuke_linter/linters/single_test_background_linter'
13
15
  require 'cuke_linter/linters/step_with_end_period_linter'
14
16
  require 'cuke_linter/linters/step_with_too_many_characters_linter'
17
+ require 'cuke_linter/linters/test_with_no_action_step_linter'
18
+ require 'cuke_linter/linters/test_with_no_name_linter'
19
+ require 'cuke_linter/linters/test_with_no_verification_step_linter'
15
20
  require 'cuke_linter/linters/test_with_too_many_steps_linter'
16
21
 
17
22
 
@@ -20,12 +25,17 @@ require 'cuke_linter/linters/test_with_too_many_steps_linter'
20
25
  module CukeLinter
21
26
 
22
27
  @original_linters = { 'BackgroundDoesMoreThanSetupLinter' => BackgroundDoesMoreThanSetupLinter.new,
28
+ 'ElementWithTooManyTagsLinter' => ElementWithTooManyTagsLinter.new,
23
29
  'ExampleWithoutNameLinter' => ExampleWithoutNameLinter.new,
24
30
  'FeatureWithoutDescriptionLinter' => FeatureWithoutDescriptionLinter.new,
31
+ 'FeatureWithoutNameLinter' => FeatureWithoutNameLinter.new,
25
32
  'FeatureWithoutScenariosLinter' => FeatureWithoutScenariosLinter.new,
26
33
  'OutlineWithSingleExampleRowLinter' => OutlineWithSingleExampleRowLinter.new,
27
34
  'SingleTestBackgroundLinter' => SingleTestBackgroundLinter.new,
28
35
  'StepWithEndPeriodLinter' => StepWithEndPeriodLinter.new,
36
+ 'TestWithNoActionStepLinter' => TestWithNoActionStepLinter.new,
37
+ 'TestWithNoNameLinter' => TestWithNoNameLinter.new,
38
+ 'TestWithNoVerificationStepLinter' => TestWithNoVerificationStepLinter.new,
29
39
  'StepWithTooManyCharactersLinter' => StepWithTooManyCharactersLinter.new,
30
40
  'TestWithTooManyStepsLinter' => TestWithTooManyStepsLinter.new }
31
41
 
@@ -41,11 +51,22 @@ module CukeLinter
41
51
 
42
52
  config = config || YAML.load_file(config_file_path)
43
53
 
44
- config.each_pair do |linter_name, options|
45
- unregister_linter(linter_name) if options.key?('Enabled') && !options['Enabled']
54
+ common_config = config['AllLinters'] || {}
55
+ to_delete = []
46
56
 
47
- registered_linters[linter_name].configure(options) if registered_linters[linter_name] && registered_linters[linter_name].respond_to?(:configure)
57
+ registered_linters.each_pair do |name, linter|
58
+ linter_config = config[name] || {}
59
+ final_config = common_config.merge(linter_config)
60
+
61
+ disabled = (final_config.key?('Enabled') && !final_config['Enabled'])
62
+
63
+ # Just save it for afterwards because modifying a collection while iterating through it is not a good idea
64
+ to_delete << name if disabled
65
+
66
+ linter.configure(final_config) if linter.respond_to?(:configure)
48
67
  end
68
+
69
+ to_delete.each { |linter_name| unregister_linter(linter_name) }
49
70
  end
50
71
 
51
72
  # Returns the registered linters to their default state
@@ -0,0 +1,41 @@
1
+ module CukeLinter
2
+
3
+ # A linter that detects taggable Gherkin elements that have too many tags
4
+
5
+ class ElementWithTooManyTagsLinter < Linter
6
+
7
+ # Changes the linting settings on the linter using the provided configuration
8
+ def configure(options)
9
+ @tag_threshold = options['TagCountThreshold']
10
+ @tag_inheritance = options['CountInheritedTags']
11
+ end
12
+
13
+ # The rule used to determine if a model has a problem
14
+ def rule(model)
15
+ return false unless model.is_a?(CukeModeler::Feature) ||
16
+ model.is_a?(CukeModeler::Scenario) ||
17
+ model.is_a?(CukeModeler::Outline) ||
18
+ model.is_a?(CukeModeler::Example)
19
+
20
+
21
+ @linted_model_class = model.class
22
+ @linted_tag_threshold = @tag_threshold || 5
23
+
24
+ if @tag_inheritance
25
+ @linted_tag_count = model.all_tags.count
26
+ else
27
+ @linted_tag_count = model.tags.nil? ? 0 : model.tags.count
28
+ end
29
+
30
+ @linted_tag_count > @linted_tag_threshold
31
+ end
32
+
33
+ # The message used to describe the problem that has been found
34
+ def message
35
+ class_name = @linted_model_class.name.split('::').last
36
+
37
+ "#{class_name} has too many tags. #{@linted_tag_count} tags found (max #{@linted_tag_threshold})."
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,20 @@
1
+ module CukeLinter
2
+
3
+ # A linter that detects features that don't have a name
4
+
5
+ class FeatureWithoutNameLinter < Linter
6
+
7
+ # The rule used to determine if a model has a problem
8
+ def rule(model)
9
+ return false unless model.is_a?(CukeModeler::Feature)
10
+
11
+ model.name.nil? || model.name.empty?
12
+ end
13
+
14
+ # The message used to describe the problem that has been found
15
+ def message
16
+ 'Feature does not have a name.'
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ module CukeLinter
2
+
3
+ # A linter that detects scenarios and outlines that do not have an action (i.e. 'When') step
4
+
5
+ class TestWithNoActionStepLinter < Linter
6
+
7
+ # The rule used to determine if a model has a problem
8
+ def rule(model)
9
+ return false unless model.is_a?(CukeModeler::Scenario) || model.is_a?(CukeModeler::Outline)
10
+
11
+ model_steps = model.steps || []
12
+ background_steps = model.parent_model.has_background? ? model.parent_model.background.steps || [] : []
13
+ all_steps = model_steps + background_steps
14
+ all_steps.none? { |step| step.keyword == 'When' }
15
+ end
16
+
17
+ # The message used to describe the problem that has been found
18
+ def message
19
+ "Test does not have a 'When' step."
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ module CukeLinter
2
+
3
+ # A linter that detects scenarios and outlines that do not have a name
4
+
5
+ class TestWithNoNameLinter < Linter
6
+
7
+ # The rule used to determine if a model has a problem
8
+ def rule(model)
9
+ return false unless model.is_a?(CukeModeler::Scenario) || model.is_a?(CukeModeler::Outline)
10
+
11
+ model.name.nil? || model.name.empty?
12
+ end
13
+
14
+ # The message used to describe the problem that has been found
15
+ def message
16
+ 'Test does not have a name.'
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ module CukeLinter
2
+
3
+ # A linter that detects scenarios and outlines that do not have a verification (i.e. 'Then') step
4
+
5
+ class TestWithNoVerificationStepLinter < Linter
6
+
7
+ # The rule used to determine if a model has a problem
8
+ def rule(model)
9
+ return false unless model.is_a?(CukeModeler::Scenario) || model.is_a?(CukeModeler::Outline)
10
+
11
+ model_steps = model.steps || []
12
+ background_steps = model.parent_model.has_background? ? model.parent_model.background.steps || [] : []
13
+ all_steps = model_steps + background_steps
14
+ all_steps.none? { |step| step.keyword == 'Then' }
15
+ end
16
+
17
+ # The message used to describe the problem that has been found
18
+ def message
19
+ "Test does not have a 'Then' step."
20
+ end
21
+
22
+ end
23
+ end
@@ -21,7 +21,7 @@ module CukeLinter
21
21
 
22
22
  # The message used to describe the problem that has been found
23
23
  def message
24
- "Test has too many steps. #{@linted_step_count} steps found (max #{@linted_step_threshold})"
24
+ "Test has too many steps. #{@linted_step_count} steps found (max #{@linted_step_threshold})."
25
25
  end
26
26
 
27
27
  end
@@ -1,4 +1,4 @@
1
1
  module CukeLinter
2
2
  # The release version of this gem
3
- VERSION = "0.6.0"
3
+ VERSION = "0.7.0"
4
4
  end
@@ -59,15 +59,17 @@ Feature: Using cuke_linter on the command line
59
59
  Scenario: Specifying directories and files to lint
60
60
  Given the following feature file "some.feature":
61
61
  """
62
- Feature:
62
+ Feature: Some feature
63
63
  Scenario: A scenario
64
- * a step
64
+ When a step
65
+ Then a step
65
66
  """
66
67
  And the following feature file "a_directory/with_a.feature":
67
68
  """
68
- Feature:
69
+ Feature: Some feature
69
70
  Scenario: A scenario
70
- * a step
71
+ When a step
72
+ Then a step
71
73
  """
72
74
  When the following command is executed:
73
75
  """
@@ -17,3 +17,39 @@ Feature: Configuration of linters
17
17
  When the configuration file is used
18
18
  And the feature is linted
19
19
  Then no error is reported
20
+
21
+ Scenario: Setting a common configuration for all linters
22
+
23
+ Note: Any property could be set for all linters, but disabling them (and then re-enabling a select few) is one of the few things that you are likely to want to do to all linters.
24
+
25
+ Given a linter registered as "AlwaysFindsAProblem"
26
+ And the following configuration file:
27
+ """
28
+ AllLinters:
29
+ Enabled: false
30
+ """
31
+ And the following feature:
32
+ """
33
+ Feature: Something in which a problem could exist
34
+ """
35
+ When the configuration file is used
36
+ And the feature is linted
37
+ Then no error is reported
38
+
39
+ Scenario: Overriding a common configuration
40
+ Given a linter registered as "AlwaysFindsAProblem"
41
+ And the following configuration file:
42
+ """
43
+ AllLinters:
44
+ Enabled: false
45
+
46
+ AlwaysFindsAProblem:
47
+ Enabled: true
48
+ """
49
+ And the following feature:
50
+ """
51
+ Feature: Something in which a problem could exist
52
+ """
53
+ When the configuration file is used
54
+ And the feature is linted
55
+ Then an error is reported
@@ -16,7 +16,7 @@ Feature: Background does more than setup linter
16
16
  When some action
17
17
  """
18
18
  When it is linted
19
- Then an error is reported
19
+ Then an error is reported:
20
20
  | linter | problem | location |
21
21
  | BackgroundDoesMoreThanSetupLinter | Background has non-setup steps | <path_to_file>:3 |
22
22
 
@@ -31,7 +31,7 @@ Feature: Background does more than setup linter
31
31
  Then some verification
32
32
  """
33
33
  When it is linted
34
- Then an error is reported
34
+ Then an error is reported:
35
35
  | linter | problem | location |
36
36
  | BackgroundDoesMoreThanSetupLinter | Background has non-setup steps | <path_to_file>:3 |
37
37
 
@@ -1,6 +1,6 @@
1
1
  Feature: Custom linters
2
2
 
3
- In addition to the linters provided by CukeSlicer, custom linters can be used. A linter is essentially any object that provides a few needed methods. In order to simplify the creation of custom linters, a base linter class is available that provides these needed methods.
3
+ In addition to the linters provided by CukeLinter, custom linters can be used. A linter is essentially any object that provides a few needed methods. In order to simplify the creation of custom linters, a base linter class is available that provides these needed methods.
4
4
 
5
5
 
6
6
  Scenario: Creating a custom linter object
@@ -19,7 +19,7 @@ Feature: Custom linters
19
19
  """
20
20
  And a model to lint
21
21
  When the model is linted
22
- Then an error is reported
22
+ Then an error is reported:
23
23
  | linter | problem | location |
24
24
  | MyCustomLinter | My custom message | <path_to_file>:<model_line_number> |
25
25
 
@@ -49,6 +49,6 @@ Feature: Custom linters
49
49
  """
50
50
  And a model to lint
51
51
  When the model is linted
52
- Then an error is reported
52
+ Then an error is reported:
53
53
  | linter | problem | location |
54
54
  | MyCustomLinter | My custom message | <path_to_file>:<model_line_number> |
@@ -9,17 +9,21 @@ Feature: Default Linters
9
9
  Given no other linters have been registered or unregistered
10
10
  Then the following linters are registered by default
11
11
  | BackgroundDoesMoreThanSetupLinter |
12
+ | ElementWithTooManyTagsLinter |
12
13
  | ExampleWithoutNameLinter |
13
14
  | FeatureWithoutDescriptionLinter |
15
+ | FeatureWithoutNameLinter |
14
16
  | FeatureWithoutScenariosLinter |
15
17
  | OutlineWithSingleExampleRowLinter |
16
18
  | SingleTestBackgroundLinter |
17
19
  | StepWithEndPeriodLinter |
18
20
  | StepWithTooManyCharactersLinter |
21
+ | TestWithNoActionStepLinter |
22
+ | TestWithNoNameLinter |
23
+ | TestWithNoVerificationStepLinter |
19
24
  | TestWithTooManyStepsLinter |
20
25
 
21
26
 
22
-
23
27
  Scenario: Registering new linters
24
28
  Given no linters are currently registered
25
29
  When the following code is used:
@@ -0,0 +1,70 @@
1
+ Feature: Element with too many tags linter
2
+
3
+ As a reader of documentation
4
+ I want taggable elements to not have an overabundance of tags
5
+ So that I can concentrate on the content of the scenario
6
+
7
+
8
+ Scenario: Linting
9
+
10
+ Note: Also works on outlines, features, and examples
11
+ Note: Tags inherited from other elements are not counted by default (see configuration options below)
12
+
13
+ Given a linter for elements with too many tags
14
+ And the following feature:
15
+ """
16
+ @this_tag_not_counted
17
+ Feature:
18
+
19
+ @tag_1 @tag_2 @tag_3 @tag_4 @tag_5 @tag_one_too_many
20
+ Scenario:
21
+ * a step
22
+ """
23
+ When it is linted
24
+ Then an error is reported:
25
+ | linter | problem | location |
26
+ | ElementWithTooManyTagsLinter | Scenario has too many tags. 6 tags found (max 5). | <path_to_file>:5 |
27
+
28
+
29
+ Scenario: Configuration of tag count threshold
30
+ Given a linter for elements with too many tags has been registered
31
+ And the following configuration file:
32
+ """
33
+ ElementWithTooManyTagsLinter:
34
+ TagCountThreshold: 3
35
+ """
36
+ And the following feature:
37
+ """
38
+ Feature:
39
+
40
+ @tag_1 @tag_2 @tag_3 @tag_one_too_many
41
+ Scenario:
42
+ * a step
43
+ """
44
+ When the configuration file is loaded
45
+ And it is linted
46
+ Then an error is reported:
47
+ | linter | problem | location |
48
+ | ElementWithTooManyTagsLinter | Scenario has too many tags. 4 tags found (max 3). | <path_to_file>:4 |
49
+
50
+ Scenario: Configuration of indirect tag count
51
+ Given a linter for elements with too many tags has been registered
52
+ And the following configuration file:
53
+ """
54
+ ElementWithTooManyTagsLinter:
55
+ CountInheritedTags: true
56
+ """
57
+ And the following feature:
58
+ """
59
+ @this_tag_is_also_counted
60
+ Feature:
61
+
62
+ @tag_1 @tag_2 @tag_3 @tag_4 @tag_one_too_many
63
+ Scenario:
64
+ * a step
65
+ """
66
+ When the configuration file is loaded
67
+ And it is linted
68
+ Then an error is reported:
69
+ | linter | problem | location |
70
+ | ElementWithTooManyTagsLinter | Scenario has too many tags. 6 tags found (max 5). | <path_to_file>:5 |