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
@@ -21,7 +21,12 @@ Feature: Example without name linter
21
21
  | value |
22
22
  """
23
23
  When it is linted
24
- Then an error is reported
24
+ Then an error is reported:
25
25
  | linter | problem | location |
26
26
  | ExampleWithoutNameLinter | Example has no name | <path_to_file>:5 |
27
27
  | ExampleWithoutNameLinter | Example has no name | <path_to_file>:8 |
28
+
29
+ @wip
30
+ Scenario: Configuration
31
+
32
+ Ideas: Configure whether or not the linter triggers on outline with only one Example set?
@@ -12,6 +12,6 @@ Feature: Feature without description linter
12
12
  Feature: Features must have a description
13
13
  """
14
14
  When it is linted
15
- Then an error is reported
15
+ Then an error is reported:
16
16
  | linter | problem | location |
17
17
  | FeatureWithoutDescriptionLinter | Feature has no description | <path_to_file>:1 |
@@ -0,0 +1,18 @@
1
+ Feature: Feature without name linter
2
+
3
+ As a reader of documentation
4
+ I want every feature to have a name
5
+ So that I can get an idea of what the feature is about without having to read every use case
6
+
7
+
8
+ Scenario: Linting
9
+ Given a linter for features without a name
10
+ And the following feature:
11
+ """
12
+ Feature:
13
+ This feature does not have a name
14
+ """
15
+ When it is linted
16
+ Then an error is reported:
17
+ | linter | problem | location |
18
+ | FeatureWithoutNameLinter | Feature does not have a name. | <path_to_file>:1 |
@@ -12,6 +12,6 @@ Feature: Feature without scenarios linter
12
12
  Feature:
13
13
  """
14
14
  When it is linted
15
- Then an error is reported
15
+ Then an error is reported:
16
16
  | linter | problem | location |
17
17
  | FeatureWithoutScenariosLinter | Feature has no scenarios | <path_to_file>:1 |
@@ -18,6 +18,6 @@ Feature: Outline with single example row linter
18
18
  | value |
19
19
  """
20
20
  When it is linted
21
- Then an error is reported
21
+ Then an error is reported:
22
22
  | linter | problem | location |
23
23
  | OutlineWithSingleExampleRowLinter | Outline has only one example row | <path_to_file>:3 |
@@ -19,6 +19,6 @@ Feature: Single test background linter
19
19
  * a step
20
20
  """
21
21
  When it is linted
22
- Then an error is reported
22
+ Then an error is reported:
23
23
  | linter | problem | location |
24
24
  | SingleTestBackgroundLinter | Background used with only one test | <path_to_file>:3 |
@@ -16,13 +16,13 @@ Feature: Test step with too many characters
16
16
  * tea exists and teapots exist and so do cups and saucers and there might be milk in the milk jug together with sugar cubes
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
  | StepWithTooManyCharactersLinter | Step is too long. 121 characters found (max 80) | <path_to_file>:4 |
22
22
 
23
23
 
24
24
  Scenario: Configuration of step count threshold
25
-
25
+
26
26
  Given a linter for test steps with too many characters has been registered
27
27
  And the following configuration file:
28
28
  """
@@ -38,6 +38,6 @@ Feature: Test step with too many characters
38
38
  """
39
39
  When the configuration file is loaded
40
40
  And the feature is linted
41
- Then an error is reported
41
+ Then an error is reported:
42
42
  | linter | problem | location |
43
43
  | StepWithTooManyCharactersLinter | Step is too long. 56 characters found (max 55) | <path_to_file>:4 |
@@ -16,6 +16,6 @@ Feature: Step that ends with a period linter
16
16
  * a bad step.
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
  | StepWithEndPeriodLinter | Step ends with a period | <path_to_file>:5 |
@@ -0,0 +1,30 @@
1
+ Feature: Test with no action step linter
2
+
3
+ As a tester
4
+ I want tests to have at least one action step
5
+ So that I know what is triggering the behavior that is being checked
6
+
7
+
8
+ Scenario: Linting
9
+
10
+ Note: Also works on outlines. Also includes steps inherited from backgrounds.
11
+
12
+ Given a linter for tests with no action step
13
+ And the following feature:
14
+ """
15
+ Feature:
16
+
17
+ Scenario:
18
+ Given some setup step
19
+ Then that's the end of the test
20
+ """
21
+ When it is linted
22
+ Then an error is reported:
23
+ | linter | problem | location |
24
+ | TestWithNoActionStepLinter | Test does not have a 'When' step. | <path_to_file>:3 |
25
+
26
+ @wip
27
+ Scenario: Configuration
28
+
29
+ Ideas: Configure whether or not the linter triggers on tests with no steps at all?
30
+ Configure the keyword(s) that count as an action step?
@@ -0,0 +1,23 @@
1
+ Feature: Test with no name linter
2
+
3
+ As a reader of documentation
4
+ I want every scenario to have a name
5
+ So that I can understand the significance of the use case
6
+
7
+
8
+ Scenario: Linting
9
+
10
+ Note: Also works on outlines.
11
+
12
+ Given a linter for tests with no name
13
+ And the following feature:
14
+ """
15
+ Feature:
16
+
17
+ Scenario:
18
+ This scenario has no name
19
+ """
20
+ When it is linted
21
+ Then an error is reported:
22
+ | linter | problem | location |
23
+ | TestWithNoNameLinter | Test does not have a name. | <path_to_file>:3 |
@@ -0,0 +1,31 @@
1
+ Feature: Test with no verification step linter
2
+
3
+ As a tester
4
+ I want tests to have at least one verification step
5
+ So that I know that something is being checked
6
+
7
+
8
+ Scenario: Linting
9
+
10
+ Note: Also works on outlines. Also includes steps inherited from backgrounds.
11
+
12
+ Given a linter for tests with no verification step
13
+ And the following feature:
14
+ """
15
+ Feature:
16
+
17
+ Scenario:
18
+ Given some setup step
19
+ When an action is taken
20
+ And that's the end of the test
21
+ """
22
+ When it is linted
23
+ Then an error is reported:
24
+ | linter | problem | location |
25
+ | TestWithNoVerificationStepLinter | Test does not have a 'Then' step. | <path_to_file>:3 |
26
+
27
+ @wip
28
+ Scenario: Configuration
29
+
30
+ Ideas: Configure whether or not the linter triggers on tests with no steps at all?
31
+ Configure the keyword(s) that count as a verification step?
@@ -28,9 +28,9 @@ Feature: Test with too many steps linter
28
28
  * step one too many...
29
29
  """
30
30
  When it is linted
31
- Then an error is reported
32
- | linter | problem | location |
33
- | TestWithTooManyStepsLinter | Test has too many steps. 11 steps found (max 10) | <path_to_file>:3 |
31
+ Then an error is reported:
32
+ | linter | problem | location |
33
+ | TestWithTooManyStepsLinter | Test has too many steps. 11 steps found (max 10). | <path_to_file>:3 |
34
34
 
35
35
  Scenario: Configuration of step count threshold
36
36
  Given a linter for tests with too many steps has been registered
@@ -51,6 +51,6 @@ Feature: Test with too many steps linter
51
51
  """
52
52
  When the configuration file is loaded
53
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 |
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 |
@@ -57,6 +57,26 @@ Given("a linter for test steps with too many characters") do
57
57
  @linter = CukeLinter::StepWithTooManyCharactersLinter.new
58
58
  end
59
59
 
60
+ Given(/^a linter for tests with no action step$/) do
61
+ @linter = CukeLinter::TestWithNoActionStepLinter.new
62
+ end
63
+
64
+ Given(/^a linter for tests with no verification step$/) do
65
+ @linter = CukeLinter::TestWithNoVerificationStepLinter.new
66
+ end
67
+
68
+ Given(/^a linter for features without a name$/) do
69
+ @linter = CukeLinter::FeatureWithoutNameLinter.new
70
+ end
71
+
72
+ Given(/^a linter for elements with too many tags$/) do
73
+ @linter = CukeLinter::ElementWithTooManyTagsLinter.new
74
+ end
75
+
76
+ Given(/^a linter for elements with too many tags has been registered$/) do
77
+ CukeLinter.register_linter(linter: CukeLinter::ElementWithTooManyTagsLinter.new, name: 'ElementWithTooManyTagsLinter')
78
+ end
79
+
60
80
  Given(/^a linter for tests with too many steps has been registered$/) do
61
81
  CukeLinter.register_linter(linter: CukeLinter::TestWithTooManyStepsLinter.new, name: 'TestWithTooManyStepsLinter')
62
82
  end
@@ -65,6 +85,10 @@ Given("a linter for features without a description") do
65
85
  @linter = CukeLinter::FeatureWithoutDescriptionLinter.new
66
86
  end
67
87
 
88
+ Given(/^a linter for tests with no name$/) do
89
+ @linter = CukeLinter::TestWithNoNameLinter.new
90
+ end
91
+
68
92
  Given(/^a linter for test steps with too many characters has been registered$/) do
69
93
  CukeLinter.register_linter(linter: CukeLinter::StepWithTooManyCharactersLinter.new, name: 'StepWithTooManyCharactersLinter')
70
94
  end
@@ -14,7 +14,7 @@ Then(/^the resulting output will include the following:$/) do |text|
14
14
  expect(@results.chomp).to include(text)
15
15
  end
16
16
 
17
- Then(/^an error is reported$/) do |table|
17
+ Then(/^an error is reported:$/) do |table|
18
18
  table.hashes.each do |error_record|
19
19
  expect(@results).to include({ linter: error_record['linter'],
20
20
  problem: error_record['problem'],
@@ -26,6 +26,10 @@ Then(/^the following linters are registered(?: by default)?$/) do |linter_names|
26
26
  expect(CukeLinter.registered_linters.keys).to match_array(linter_names.raw.flatten)
27
27
  end
28
28
 
29
+ Then(/^an error is reported$/) do
30
+ expect(@results).to_not be_empty
31
+ end
32
+
29
33
  Then(/^no error is reported$/) do
30
34
  expect(@results).to be_empty
31
35
  end
@@ -5,6 +5,7 @@ module CukeLinter
5
5
  class TestModel < CukeModeler::Model
6
6
 
7
7
  include CukeModeler::Sourceable
8
+ include CukeModeler::Taggable
8
9
 
9
10
  end
10
11
  end
@@ -11,7 +11,8 @@ RSpec.describe 'the Command Line Interface' do
11
11
  extension: '.feature',
12
12
  text: 'Feature:
13
13
  Scenario: A scenario
14
- * a step') }
14
+ When a step
15
+ Then a step') }
15
16
 
16
17
  # Stuff that is not always needed and so can be lazy instantiated
17
18
  let(:executable_directory) { "#{PROJECT_ROOT}/exe" }
@@ -61,7 +62,7 @@ RSpec.describe 'the Command Line Interface' do
61
62
  CukeLinter::FileHelper.create_file(directory: test_directory,
62
63
  name: '.cuke_linter',
63
64
  extension: '',
64
- text: 'FeatureWithoutDescriptionLinter:
65
+ text: 'AllLinters:
65
66
  Enabled: false')
66
67
  end
67
68
 
@@ -100,15 +101,17 @@ RSpec.describe 'the Command Line Interface' do
100
101
  let(:file_1) { CukeLinter::FileHelper.create_file(directory: test_directory,
101
102
  name: 'some',
102
103
  extension: '.feature',
103
- text: 'Feature:
104
+ text: 'Feature: Some feature
104
105
  Scenario: A scenario
105
- * a step') }
106
+ When a step
107
+ Then a step') }
106
108
  let(:file_2) { CukeLinter::FileHelper.create_file(directory: test_directory,
107
109
  name: 'a_directory/with_a',
108
110
  extension: '.feature',
109
- text: 'Feature:
111
+ text: 'Feature: Some feature
110
112
  Scenario: A scenario
111
- * a step') }
113
+ When a step
114
+ Then a step') }
112
115
  let(:file_1_path) { file_1 }
113
116
  let(:file_2_directory) { File.dirname(file_2) }
114
117
  let(:command) { "bundle exec ruby #{executable_path} #{flag} #{file_1_path} #{flag} #{file_2_directory}" }
@@ -159,9 +162,10 @@ RSpec.describe 'the Command Line Interface' do
159
162
  context 'with formatter arguments' do
160
163
  let(:linted_file) { CukeLinter::FileHelper.create_file(name: 'some',
161
164
  extension: '.feature',
162
- text: 'Feature:
165
+ text: 'Feature: Some feature
163
166
  Scenario: A scenario
164
- * a step') }
167
+ When a step
168
+ Then a step') }
165
169
  let(:formatter_class) { 'AFakeFormatter' }
166
170
  let(:formatter_class_in_module) { 'CukeLinter::AnotherFakeFormatter' }
167
171
  let(:formatter_class_file) { CukeLinter::FileHelper.create_file(extension: '.rb',
@@ -224,9 +228,10 @@ RSpec.describe 'the Command Line Interface' do
224
228
  let(:other_output_location) { "#{CukeLinter::FileHelper.create_directory}/other_output.txt" }
225
229
  let(:linted_file) { CukeLinter::FileHelper.create_file(name: 'some',
226
230
  extension: '.feature',
227
- text: 'Feature:
231
+ text: 'Feature: Some feature
228
232
  Scenario: A scenario
229
- * a step') }
233
+ When a step
234
+ Then a step') }
230
235
  let(:formatter_class_1) { 'AFakeFormatter' }
231
236
  let(:formatter_class_2) { 'AnotherFakeFormatter' }
232
237
  let(:formatter_class_file) { CukeLinter::FileHelper.create_file(extension: '.rb',
@@ -386,7 +391,7 @@ RSpec.describe 'the Command Line Interface' do
386
391
 
387
392
  let(:config_file) { CukeLinter::FileHelper.create_file(name: 'my_config_file',
388
393
  extension: '.yml',
389
- text: 'FeatureWithoutDescriptionLinter:
394
+ text: 'AllLinters:
390
395
  Enabled: false') }
391
396
  let(:command) { "bundle exec ruby #{executable_path} #{flag} #{config_file}" }
392
397
 
@@ -176,10 +176,14 @@ RSpec.describe CukeLinter do
176
176
  it 'has a default set of registered linters' do
177
177
  expect(subject.registered_linters.keys).to include('BackgroundDoesMoreThanSetupLinter')
178
178
  expect(subject.registered_linters['BackgroundDoesMoreThanSetupLinter']).to be_a(CukeLinter::BackgroundDoesMoreThanSetupLinter)
179
+ expect(subject.registered_linters.keys).to include('ElementWithTooManyTagsLinter')
180
+ expect(subject.registered_linters['ElementWithTooManyTagsLinter']).to be_a(CukeLinter::ElementWithTooManyTagsLinter)
179
181
  expect(subject.registered_linters.keys).to include('ExampleWithoutNameLinter')
180
182
  expect(subject.registered_linters['ExampleWithoutNameLinter']).to be_a(CukeLinter::ExampleWithoutNameLinter)
181
183
  expect(subject.registered_linters.keys).to include('FeatureWithoutDescriptionLinter')
182
184
  expect(subject.registered_linters['FeatureWithoutDescriptionLinter']).to be_a(CukeLinter::FeatureWithoutDescriptionLinter)
185
+ expect(subject.registered_linters.keys).to include('FeatureWithoutNameLinter')
186
+ expect(subject.registered_linters['FeatureWithoutNameLinter']).to be_a(CukeLinter::FeatureWithoutNameLinter)
183
187
  expect(subject.registered_linters.keys).to include('FeatureWithoutScenariosLinter')
184
188
  expect(subject.registered_linters['FeatureWithoutScenariosLinter']).to be_a(CukeLinter::FeatureWithoutScenariosLinter)
185
189
  expect(subject.registered_linters.keys).to include('OutlineWithSingleExampleRowLinter')
@@ -190,6 +194,12 @@ RSpec.describe CukeLinter do
190
194
  expect(subject.registered_linters['StepWithEndPeriodLinter']).to be_a(CukeLinter::StepWithEndPeriodLinter)
191
195
  expect(subject.registered_linters.keys).to include('StepWithTooManyCharactersLinter')
192
196
  expect(subject.registered_linters['StepWithTooManyCharactersLinter']).to be_a(CukeLinter::StepWithTooManyCharactersLinter)
197
+ expect(subject.registered_linters.keys).to include('TestWithNoActionStepLinter')
198
+ expect(subject.registered_linters['TestWithNoActionStepLinter']).to be_a(CukeLinter::TestWithNoActionStepLinter)
199
+ expect(subject.registered_linters.keys).to include('TestWithNoNameLinter')
200
+ expect(subject.registered_linters['TestWithNoNameLinter']).to be_a(CukeLinter::TestWithNoNameLinter)
201
+ expect(subject.registered_linters.keys).to include('TestWithNoVerificationStepLinter')
202
+ expect(subject.registered_linters['TestWithNoVerificationStepLinter']).to be_a(CukeLinter::TestWithNoVerificationStepLinter)
193
203
  expect(subject.registered_linters.keys).to include('TestWithTooManyStepsLinter')
194
204
  expect(subject.registered_linters['TestWithTooManyStepsLinter']).to be_a(CukeLinter::TestWithTooManyStepsLinter)
195
205
  end
@@ -236,6 +246,33 @@ RSpec.describe CukeLinter do
236
246
  expect(subject.registered_linters['FakeLinter1']).to be nil
237
247
  end
238
248
 
249
+ it 'can apply a property to all linters' do
250
+ configuration = { 'AllLinters' => { 'Enabled' => false } }
251
+
252
+ # Restore the default linters
253
+ CukeLinter.reset_linters
254
+
255
+ # Also add some custom ones
256
+ CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter, name: 'Foo')
257
+
258
+
259
+ subject.load_configuration(config: configuration)
260
+
261
+ expect(subject.registered_linters).to be_empty
262
+ end
263
+
264
+ it 'uses linter specific properties over general properties' do
265
+ configuration = { 'AllLinters' => { 'Enabled' => false },
266
+ 'FakeLinter1' => { 'Enabled' => true } }
267
+
268
+ CukeLinter.register_linter(linter: CukeLinter::LinterFactory.generate_fake_linter, name: 'FakeLinter1')
269
+ expect(subject.registered_linters['FakeLinter1']).to_not be nil
270
+
271
+ subject.load_configuration(config: configuration)
272
+
273
+ expect(subject.registered_linters['FakeLinter1']).to_not be nil
274
+ end
275
+
239
276
  it 'even unregisters non-configurable disabled linters' do
240
277
  config = { 'FakeLinter' => { 'Enabled' => false } }
241
278
  configuration_file = CukeLinter::FileHelper.create_file(name: '.cuke_linter', extension: '', text: config.to_yaml)
@@ -0,0 +1,8 @@
1
+ require_relative '../../../../../environments/rspec_env'
2
+
3
+
4
+ RSpec.describe CukeLinter::ElementWithTooManyTagsLinter do
5
+
6
+ it_should_behave_like 'a linter at the integration level'
7
+
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative '../../../../../environments/rspec_env'
2
+
3
+
4
+ RSpec.describe CukeLinter::FeatureWithoutNameLinter do
5
+
6
+ it_should_behave_like 'a linter at the integration level'
7
+
8
+ end
@@ -0,0 +1,8 @@
1
+ require_relative '../../../../../environments/rspec_env'
2
+
3
+
4
+ RSpec.describe CukeLinter::TestWithNoActionStepLinter do
5
+
6
+ it_should_behave_like 'a linter at the integration level'
7
+
8
+ end