chutney 1.6.3 → 2.0.0.rc1

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.rubocop.yml +3 -3
  4. data/README.md +44 -30
  5. data/Rakefile +10 -24
  6. data/chutney.gemspec +13 -10
  7. data/config/{default.yml → chutney.yml} +6 -3
  8. data/docs/.keep +0 -0
  9. data/exe/chutney +28 -22
  10. data/img/chutney.svg +852 -0
  11. data/img/formatters.png +0 -0
  12. data/lib/chutney.rb +61 -85
  13. data/lib/chutney/configuration.rb +6 -7
  14. data/lib/chutney/formatter.rb +21 -0
  15. data/lib/chutney/formatter/json_formatter.rb +8 -0
  16. data/lib/chutney/formatter/pie_formatter.rb +78 -0
  17. data/lib/chutney/formatter/rainbow_formatter.rb +47 -0
  18. data/lib/chutney/linter.rb +145 -113
  19. data/lib/chutney/linter/avoid_full_stop.rb +12 -0
  20. data/lib/chutney/linter/avoid_outline_for_single_example.rb +3 -6
  21. data/lib/chutney/linter/avoid_scripting.rb +10 -15
  22. data/lib/chutney/linter/background_does_more_than_setup.rb +7 -10
  23. data/lib/chutney/linter/background_requires_multiple_scenarios.rb +2 -3
  24. data/lib/chutney/linter/bad_scenario_name.rb +4 -11
  25. data/lib/chutney/linter/file_name_differs_feature_name.rb +5 -10
  26. data/lib/chutney/linter/givens_after_background.rb +17 -0
  27. data/lib/chutney/linter/invalid_file_name.rb +14 -6
  28. data/lib/chutney/linter/invalid_step_flow.rb +18 -18
  29. data/lib/chutney/linter/missing_example_name.rb +13 -11
  30. data/lib/chutney/linter/missing_feature_description.rb +2 -9
  31. data/lib/chutney/linter/missing_feature_name.rb +3 -12
  32. data/lib/chutney/linter/missing_scenario_name.rb +3 -7
  33. data/lib/chutney/linter/missing_test_action.rb +3 -6
  34. data/lib/chutney/linter/missing_verification.rb +3 -4
  35. data/lib/chutney/linter/required_tags_starts_with.rb +20 -5
  36. data/lib/chutney/linter/same_tag_for_all_scenarios.rb +24 -28
  37. data/lib/chutney/linter/scenario_names_match.rb +6 -8
  38. data/lib/chutney/linter/tag_used_multiple_times.rb +6 -13
  39. data/lib/chutney/linter/too_clumsy.rb +4 -4
  40. data/lib/chutney/linter/too_long_step.rb +8 -18
  41. data/lib/chutney/linter/too_many_different_tags.rb +13 -34
  42. data/lib/chutney/linter/too_many_steps.rb +10 -6
  43. data/lib/chutney/linter/too_many_tags.rb +11 -10
  44. data/lib/chutney/linter/unique_scenario_names.rb +19 -13
  45. data/lib/chutney/linter/unknown_variable.rb +5 -6
  46. data/lib/chutney/linter/unused_variable.rb +6 -7
  47. data/lib/chutney/linter/use_background.rb +11 -29
  48. data/lib/chutney/linter/use_outline.rb +21 -15
  49. data/lib/chutney/version.rb +1 -1
  50. data/lib/config/locales/en.yml +93 -0
  51. data/spec/chutney_spec.rb +54 -62
  52. data/spec/spec_helper.rb +103 -0
  53. metadata +75 -44
  54. data/Guardfile +0 -3
  55. data/lib/chutney/linter/avoid_period.rb +0 -19
  56. data/lib/chutney/linter/be_declarative.rb +0 -49
  57. data/lib/chutney/linter/tag_collector.rb +0 -10
  58. data/lib/chutney/linter/tag_constraint.rb +0 -35
  59. data/spec/configuration_spec.rb +0 -58
  60. data/spec/required_tags_starts_with_spec.rb +0 -74
  61. data/spec/shared_contexts/file_exists.rb +0 -12
  62. data/spec/shared_contexts/gherkin_linter.rb +0 -14
data/Guardfile DELETED
@@ -1,3 +0,0 @@
1
- guard 'rake', task: :default do
2
- watch(%r{^src/.*$})
3
- end
@@ -1,19 +0,0 @@
1
- require 'chutney/linter'
2
-
3
- module Chutney
4
- # service class to lint for avoiding periods
5
- class AvoidPeriod < Linter
6
- MESSAGE = 'Avoid using a period (full-stop) in steps so that it is easier to re-use them'.freeze
7
-
8
- def lint
9
- scenarios do |file, feature, scenario|
10
- next unless scenario.key? :steps
11
-
12
- scenario[:steps].each do |step|
13
- references = [reference(file, feature, scenario, step)]
14
- add_error(references, MESSAGE) if step[:text].strip.end_with? '.'
15
- end
16
- end
17
- end
18
- end
19
- end
@@ -1,49 +0,0 @@
1
- require 'chutney/linter'
2
- require 'engtagger'
3
-
4
- module Chutney
5
- # service class to lint for avoiding periods
6
- class BeDeclarative < Linter
7
- MESSAGE = 'This step does not contain a verb'.freeze
8
-
9
- def initialize
10
- super
11
- end
12
-
13
- def lint
14
- filled_scenarios do |file, feature, scenario|
15
- scenario[:steps].each do |step|
16
- references = [reference(file, feature, scenario, step)]
17
- add_warning(references, MESSAGE) unless verb? step
18
- end
19
- end
20
- end
21
-
22
- def verb?(step)
23
- tagged = tagger.add_tags step[:text]
24
- step_verbs = verbs tagged
25
-
26
- !step_verbs.empty?
27
- end
28
-
29
- def verbs(tagged_text)
30
- verbs =
31
- %i[
32
- get_infinitive_verbs
33
- get_past_tense_verbs
34
- get_gerund_verbs
35
- get_passive_verbs
36
- get_present_verbs
37
- get_base_present_verbs
38
- ]
39
-
40
- verbs.map { |verb| tagger.send(verb, tagged_text).keys }.flatten
41
- end
42
-
43
- def tagger
44
- @tagger = EngTagger.new unless instance_variable_defined? :@tagger
45
-
46
- @tagger
47
- end
48
- end
49
- end
@@ -1,10 +0,0 @@
1
- module Chutney
2
- # Mixin to lint for tags based on their relationship to eachother
3
- module TagCollector
4
- def gather_tags(element)
5
- return [] unless element.include? :tags
6
-
7
- element[:tags].map { |tag| tag[:name][1..-1] }
8
- end
9
- end
10
- end
@@ -1,35 +0,0 @@
1
- module Chutney
2
- # Mixin to lint for tags that have certain string contraints
3
- module TagConstraint
4
- def lint
5
- scenarios do |file, feature, scenario|
6
- next if match_pattern? tags(feature)
7
- next if match_pattern? tags(scenario)
8
-
9
- references = [reference(file, feature, scenario)]
10
- add_error(references, 'Required Tag not found')
11
- end
12
- end
13
-
14
- def tags(element)
15
- return [] unless element.include? :tags
16
-
17
- element[:tags].map { |a| a[:name] }
18
- end
19
-
20
- def matcher(pattern)
21
- @pattern = pattern
22
- validate_input
23
- end
24
-
25
- def match_pattern?(_tags)
26
- raise NoMethodError, 'This is an abstraction that must be implemented by the includer'
27
- end
28
-
29
- def validate_input
30
- raise 'No Tags provided in the YAML' if @pattern.nil?
31
-
32
- warn 'Required Tags matcher has no value' if @pattern.empty?
33
- end
34
- end
35
- end
@@ -1,58 +0,0 @@
1
- require 'rspec'
2
- require 'chutney/configuration'
3
- require 'shared_contexts/file_exists'
4
-
5
- describe Chutney::Configuration do
6
- subject { Chutney::Configuration.new file }
7
- let(:file) { 'default.yml' }
8
-
9
- it 'should do something' do
10
- expect(subject.config).to eq('')
11
- end
12
-
13
- it 'should have a default config path' do
14
- expect(subject.configuration_path).not_to be nil
15
- end
16
- context 'when a empty config file is present' do
17
- include_context 'a file exists'
18
- let(:file_content) { '---' }
19
- it 'should load a file from the config path' do
20
- expect(subject.config).to eq ''
21
- end
22
- end
23
-
24
- context 'when a non-YAML config file is present' do
25
- include_context 'a file exists'
26
- let(:file_content) do
27
- <<-CONTENT
28
- foo: [
29
- ‘bar’, {
30
- baz: 42
31
- }
32
- ]'
33
- CONTENT
34
- end
35
-
36
- it 'should load a file from the config path but fail to parse' do
37
- expect { subject.load_configuration }.to raise_error Psych::SyntaxError
38
- expect { subject.config }.to raise_error Psych::SyntaxError
39
- end
40
- end
41
- context 'when a valid YAML file is present' do
42
- include_context 'a file exists'
43
- let(:file_content) do
44
- <<-CONTENT
45
- ---
46
- :parent_key: parent_value
47
- :child_key: child_value
48
- CONTENT
49
- end
50
- before :each do
51
- subject.load_configuration
52
- end
53
-
54
- it 'should load the values from the config file' do
55
- expect(subject.config).to eq(parent_key: 'parent_value', child_key: 'child_value')
56
- end
57
- end
58
- end
@@ -1,74 +0,0 @@
1
- require 'rspec'
2
- require 'chutney/linter/required_tags_starts_with'
3
- require 'chutney'
4
- require 'shared_contexts/gherkin_linter'
5
-
6
- describe Chutney::RequiredTagsStartsWith do
7
- let(:linter) { Chutney::ChutneyLint.new }
8
- let(:file) { 'lint.feature' }
9
- let(:pattern) { %w[MCC PB] }
10
- describe '#matcher' do
11
- it 'should raise an error when pattern is nil' do
12
- expect { subject.matcher(nil) }.to raise_error('No Tags provided in the YAML')
13
- end
14
- it 'should raise an error when pattern is empty' do
15
- expect { subject.matcher('') }.to output("Required Tags matcher has no value\n").to_stderr
16
- end
17
- end
18
-
19
- describe '#issues' do
20
- context 'before linting' do
21
- it 'should have no issue' do
22
- expect(subject.issues.size).to eq(0)
23
- end
24
- end
25
-
26
- context 'after linting a feature file with valid PB tag at the feature level' do
27
- include_context 'a gherkin linter'
28
-
29
- let(:file_content) do
30
- <<-CONTENT
31
- @PB
32
- Feature: Test
33
- @scenario_tag
34
- Scenario: A
35
- CONTENT
36
- end
37
- it 'should have no issues' do
38
- expect(subject.issues.size).to eq(0)
39
- end
40
- end
41
-
42
- context 'after linting a file with a MCC tag at the scenario level' do
43
- include_context 'a gherkin linter'
44
- let(:file_content) do
45
- <<-CONTENT
46
- @feature_tag
47
- Feature: Test
48
- @MCC
49
- Scenario: A
50
- CONTENT
51
- end
52
-
53
- it 'should have no issues' do
54
- expect(subject.issues.size).to eq(0)
55
- end
56
- end
57
-
58
- context 'after linting a file with no required tags' do
59
- include_context 'a gherkin linter'
60
- let(:file_content) do
61
- <<-CONTENT
62
- @feature_tag
63
- Feature: Test
64
- @scenario_tag
65
- Scenario: A
66
- CONTENT
67
- end
68
-
69
- it 'should have issues after linting a file without PB or MCC tags' do
70
- expect(subject.issues[0].name).to eq(subject.class.name.split('::').last)
71
- end
72
- end
73
- end
74
- end
@@ -1,12 +0,0 @@
1
- # needs file and file_content defined
2
- shared_context 'a file exists' do
3
- before :each do
4
- File.open(file, 'w') do |f|
5
- f.write file_content
6
- end
7
- end
8
-
9
- after :each do
10
- File.delete(file) if File.exist?(file)
11
- end
12
- end
@@ -1,14 +0,0 @@
1
- require 'rspec'
2
- require_relative 'file_exists'
3
-
4
- shared_context 'a gherkin linter' do
5
- include_context 'a file exists'
6
-
7
- let(:files) { linter.analyze file }
8
- let(:disable_tags) { linter.disable_tags }
9
-
10
- before :each do
11
- subject.instance_variable_set(:@pattern, pattern)
12
- subject.lint_files({ file: files }, disable_tags)
13
- end
14
- end