cuke_linter 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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 |