cucumber_lint 0.0.3
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 +7 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +22 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +63 -0
- data/LICENSE +22 -0
- data/README.md +62 -0
- data/Rakefile +24 -0
- data/bin/cucumber_lint +7 -0
- data/cucumber.yml +3 -0
- data/cucumber_lint.gemspec +20 -0
- data/features/cucumber_lint/cli_fix.feature +51 -0
- data/features/cucumber_lint/cli_lint.feature +55 -0
- data/features/cucumber_lint/feature_formatter.feature +106 -0
- data/features/cucumber_lint/steps_formatter.feature +30 -0
- data/features/cucumber_lint/table_formatter.feature +45 -0
- data/features/step_definitions/cli_steps.rb +31 -0
- data/features/step_definitions/env.rb +20 -0
- data/features/step_definitions/feature_formatter_steps.rb +15 -0
- data/features/step_definitions/fixtures/formatted.feature.example +9 -0
- data/features/step_definitions/fixtures/unformatted.feature.example +9 -0
- data/features/step_definitions/steps_formatter_steps.rb +15 -0
- data/features/step_definitions/support/run_helpers.rb +12 -0
- data/features/step_definitions/table_formatter_steps.rb +15 -0
- data/lib/core_ext/array.rb +22 -0
- data/lib/cucumber_lint.rb +7 -0
- data/lib/cucumber_lint/cli.rb +85 -0
- data/lib/cucumber_lint/feature_formatter.rb +48 -0
- data/lib/cucumber_lint/steps_formatter.rb +50 -0
- data/lib/cucumber_lint/table_formatter.rb +65 -0
- data/lib/cucumber_lint/version.rb +3 -0
- data/spec/core_ext/array_spec.rb +19 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d357226ed5d21c9e3b55736ba03019f023dce69e
|
4
|
+
data.tar.gz: 4b0998c48b5d3e4df9ac658b979ac543dc032811
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 851e8c5aaa639c14fb2185cec529f03f29bce5b9ccaa8c6177da58257b93f85bf77d69ab54dfc4ed1c59645b4944961c844d736c3cad8008fa2742cf79febc65
|
7
|
+
data.tar.gz: c769b2952189beb4f574a01bfec1479f6716de886280ee239696b4d4328313dec4adc013d314d25606b9a5f2c737f2768ad8492d7303e730b01d1243725ce328
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Metrics/LineLength:
|
2
|
+
Max: 100
|
3
|
+
|
4
|
+
|
5
|
+
Metrics/MethodLength:
|
6
|
+
Max: 11
|
7
|
+
|
8
|
+
|
9
|
+
Style/Documentation:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
|
13
|
+
Style/EmptyLines:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
|
17
|
+
Style/EmptyLinesAroundClassBody:
|
18
|
+
EnforcedStyle: empty_lines
|
19
|
+
|
20
|
+
|
21
|
+
Style/MethodDefParentheses:
|
22
|
+
EnforcedStyle: require_no_parentheses
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
cucumber_lint (0.0.3)
|
5
|
+
colorize (~> 0.7.5)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
ast (2.0.0)
|
11
|
+
astrolabe (1.3.0)
|
12
|
+
parser (>= 2.2.0.pre.3, < 3.0)
|
13
|
+
builder (3.2.2)
|
14
|
+
colorize (0.7.5)
|
15
|
+
cucumber (1.3.18)
|
16
|
+
builder (>= 2.1.2)
|
17
|
+
diff-lcs (>= 1.1.3)
|
18
|
+
gherkin (~> 2.12)
|
19
|
+
multi_json (>= 1.7.5, < 2.0)
|
20
|
+
multi_test (>= 0.1.1)
|
21
|
+
diff-lcs (1.2.5)
|
22
|
+
gherkin (2.12.2)
|
23
|
+
multi_json (~> 1.3)
|
24
|
+
multi_json (1.10.1)
|
25
|
+
multi_test (0.1.1)
|
26
|
+
open4 (1.3.4)
|
27
|
+
parser (2.2.0.1)
|
28
|
+
ast (>= 1.1, < 3.0)
|
29
|
+
slop (~> 3.4, >= 3.4.5)
|
30
|
+
powerpack (0.0.9)
|
31
|
+
rainbow (2.0.0)
|
32
|
+
rake (10.4.2)
|
33
|
+
rspec (3.1.0)
|
34
|
+
rspec-core (~> 3.1.0)
|
35
|
+
rspec-expectations (~> 3.1.0)
|
36
|
+
rspec-mocks (~> 3.1.0)
|
37
|
+
rspec-core (3.1.7)
|
38
|
+
rspec-support (~> 3.1.0)
|
39
|
+
rspec-expectations (3.1.2)
|
40
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
+
rspec-support (~> 3.1.0)
|
42
|
+
rspec-mocks (3.1.3)
|
43
|
+
rspec-support (~> 3.1.0)
|
44
|
+
rspec-support (3.1.2)
|
45
|
+
rubocop (0.28.0)
|
46
|
+
astrolabe (~> 1.3)
|
47
|
+
parser (>= 2.2.0.pre.7, < 3.0)
|
48
|
+
powerpack (~> 0.0.6)
|
49
|
+
rainbow (>= 1.99.1, < 3.0)
|
50
|
+
ruby-progressbar (~> 1.4)
|
51
|
+
ruby-progressbar (1.7.1)
|
52
|
+
slop (3.6.0)
|
53
|
+
|
54
|
+
PLATFORMS
|
55
|
+
ruby
|
56
|
+
|
57
|
+
DEPENDENCIES
|
58
|
+
cucumber
|
59
|
+
cucumber_lint!
|
60
|
+
open4
|
61
|
+
rake
|
62
|
+
rspec
|
63
|
+
rubocop
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Charlie Rudolph
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# cucumber_lint
|
2
|
+
|
3
|
+
A command line linter and formatter for cucumber features
|
4
|
+
|
5
|
+
### Installation
|
6
|
+
|
7
|
+
```
|
8
|
+
gem install cucumber_lint
|
9
|
+
```
|
10
|
+
|
11
|
+
### Usage
|
12
|
+
|
13
|
+
```
|
14
|
+
cucumber_lint # Lints (exits with status 1 on failure, 0 on success)
|
15
|
+
cucumber_lint --fix # Fixes all lint errors
|
16
|
+
```
|
17
|
+
|
18
|
+
### Tables
|
19
|
+
* requires at a space leading and trailing cell content
|
20
|
+
* requires pipes to be aligned
|
21
|
+
|
22
|
+
Bad
|
23
|
+
````
|
24
|
+
|header_column1|header_column2|
|
25
|
+
|row1_column1|row1_column2|
|
26
|
+
|row2_column1|row2_column2|
|
27
|
+
|row3_column1|row3_column2|
|
28
|
+
```
|
29
|
+
Bad
|
30
|
+
```
|
31
|
+
| header_column1 | header_column2 |
|
32
|
+
| row1_column1 | row1_column2 |
|
33
|
+
| row2_column1 | row2_column2 |
|
34
|
+
| row3_column1 | row3_column2 |
|
35
|
+
```
|
36
|
+
Good
|
37
|
+
```
|
38
|
+
| header_column1 | header_column2 |
|
39
|
+
| row1_column1 | row1_column2 |
|
40
|
+
| row2_column1 | row2_column2 |
|
41
|
+
| row3_column1 | row3_column2 |
|
42
|
+
```
|
43
|
+
|
44
|
+
### Steps
|
45
|
+
* Use `And` instead of repeating `Given`, `When`, or `Then`
|
46
|
+
|
47
|
+
Bad
|
48
|
+
```
|
49
|
+
Given A
|
50
|
+
Given B
|
51
|
+
When C
|
52
|
+
Then D
|
53
|
+
Then E
|
54
|
+
```
|
55
|
+
Good
|
56
|
+
```
|
57
|
+
Given A
|
58
|
+
And B
|
59
|
+
When C
|
60
|
+
Then D
|
61
|
+
And E
|
62
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
desc 'Run all linters and specs'
|
2
|
+
task default: %w(lint spec features)
|
3
|
+
|
4
|
+
|
5
|
+
desc 'Run linters'
|
6
|
+
task :lint do
|
7
|
+
sh 'bundle exec rubocop'
|
8
|
+
end
|
9
|
+
|
10
|
+
desc 'Run specs'
|
11
|
+
task :spec do
|
12
|
+
sh 'bundle exec rspec'
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Run features'
|
16
|
+
task :features do
|
17
|
+
sh 'bundle exec cucumber'
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
desc 'Build the gem'
|
22
|
+
task build: :default do
|
23
|
+
sh 'gem build cucumber_lint.gemspec'
|
24
|
+
end
|
data/bin/cucumber_lint
ADDED
data/cucumber.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cucumber_lint/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'cucumber_lint'
|
8
|
+
spec.version = CucumberLint::VERSION
|
9
|
+
spec.authors = ['charlierudolph']
|
10
|
+
spec.email = ['charles.w.rudolph@gmail.com']
|
11
|
+
spec.summary = 'A command line interface for linting and formatting cucumber features'
|
12
|
+
spec.homepage = 'https://github.com/charlierudolph/cucumber_lint'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
|
15
|
+
spec.add_runtime_dependency 'colorize', '~> 0.7.5'
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split("\n")
|
18
|
+
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
Feature: cli format
|
2
|
+
|
3
|
+
Scenario: no files
|
4
|
+
Given I have no files
|
5
|
+
When I run `cucumber_lint --fix`
|
6
|
+
Then I see the output
|
7
|
+
"""
|
8
|
+
|
9
|
+
|
10
|
+
0 files inspected (0 written)
|
11
|
+
"""
|
12
|
+
And it exits with status 0
|
13
|
+
|
14
|
+
|
15
|
+
Scenario: formatted file
|
16
|
+
Given I have a formatted file at "features/formatted.feature"
|
17
|
+
When I run `cucumber_lint --fix`
|
18
|
+
Then I see the output
|
19
|
+
"""
|
20
|
+
.
|
21
|
+
|
22
|
+
1 file inspected (0 written)
|
23
|
+
"""
|
24
|
+
And it exits with status 0
|
25
|
+
|
26
|
+
|
27
|
+
Scenario: unformatted file
|
28
|
+
Given I have an unformatted file at "features/unformatted.feature"
|
29
|
+
When I run `cucumber_lint --fix`
|
30
|
+
Then I see the output
|
31
|
+
"""
|
32
|
+
W
|
33
|
+
|
34
|
+
1 file inspected (1 written)
|
35
|
+
"""
|
36
|
+
And it exits with status 0
|
37
|
+
And the file "features/unformatted.feature" in now formatted
|
38
|
+
|
39
|
+
|
40
|
+
Scenario: formatted file and unformatted file
|
41
|
+
Given I have an formatted file at "features/formatted.feature"
|
42
|
+
And I have an unformatted file at "features/unformatted.feature"
|
43
|
+
When I run `cucumber_lint --fix`
|
44
|
+
Then I see the output
|
45
|
+
"""
|
46
|
+
.W
|
47
|
+
|
48
|
+
2 files inspected (1 written)
|
49
|
+
"""
|
50
|
+
And it exits with status 0
|
51
|
+
And the file "features/unformatted.feature" in now formatted
|
@@ -0,0 +1,55 @@
|
|
1
|
+
Feature: cli lint
|
2
|
+
|
3
|
+
Scenario: no files
|
4
|
+
Given I have no files
|
5
|
+
When I run `cucumber_lint`
|
6
|
+
Then I see the output
|
7
|
+
"""
|
8
|
+
|
9
|
+
|
10
|
+
0 files inspected (0 passed)
|
11
|
+
"""
|
12
|
+
And it exits with status 0
|
13
|
+
|
14
|
+
|
15
|
+
Scenario: formatted file
|
16
|
+
Given I have a formatted file at "features/formatted.feature"
|
17
|
+
When I run `cucumber_lint`
|
18
|
+
Then I see the output
|
19
|
+
"""
|
20
|
+
.
|
21
|
+
|
22
|
+
1 file inspected (1 passed)
|
23
|
+
"""
|
24
|
+
And it exits with status 0
|
25
|
+
|
26
|
+
|
27
|
+
Scenario: unformatted file
|
28
|
+
Given I have an unformatted file at "features/unformatted.feature"
|
29
|
+
When I run `cucumber_lint`
|
30
|
+
Then I see the output
|
31
|
+
"""
|
32
|
+
F
|
33
|
+
|
34
|
+
Files with errors:
|
35
|
+
./features/unformatted.feature
|
36
|
+
|
37
|
+
1 file inspected (0 passed, 1 failed)
|
38
|
+
"""
|
39
|
+
And it exits with status 1
|
40
|
+
|
41
|
+
|
42
|
+
Scenario: formatted file and unformatted file
|
43
|
+
Given I have an formatted file at "features/formatted.feature"
|
44
|
+
And I have an unformatted file at "features/unformatted.feature"
|
45
|
+
When I run `cucumber_lint`
|
46
|
+
Then I see the output
|
47
|
+
"""
|
48
|
+
.F
|
49
|
+
|
50
|
+
Files with errors:
|
51
|
+
./features/unformatted.feature
|
52
|
+
|
53
|
+
2 files inspected (1 passed, 1 failed)
|
54
|
+
"""
|
55
|
+
And it exits with status 1
|
@@ -0,0 +1,106 @@
|
|
1
|
+
Feature: feature formatter
|
2
|
+
|
3
|
+
Scenario: feature with single unformatted table
|
4
|
+
Given feature content
|
5
|
+
"""
|
6
|
+
Feature: Test Feature
|
7
|
+
|
8
|
+
Scenario: Test Scenario
|
9
|
+
Given a table
|
10
|
+
|header_column1|header_column2|
|
11
|
+
|row1_column1|row1_column2|
|
12
|
+
|row2_column1|row2_column2|
|
13
|
+
|row3_column1|row3_column2|
|
14
|
+
Given other stuff
|
15
|
+
When I do things
|
16
|
+
Then my tests pass
|
17
|
+
Then I am happy
|
18
|
+
"""
|
19
|
+
Then the formatted feature content is
|
20
|
+
"""
|
21
|
+
Feature: Test Feature
|
22
|
+
|
23
|
+
Scenario: Test Scenario
|
24
|
+
Given a table
|
25
|
+
| header_column1 | header_column2 |
|
26
|
+
| row1_column1 | row1_column2 |
|
27
|
+
| row2_column1 | row2_column2 |
|
28
|
+
| row3_column1 | row3_column2 |
|
29
|
+
And other stuff
|
30
|
+
When I do things
|
31
|
+
Then my tests pass
|
32
|
+
And I am happy
|
33
|
+
"""
|
34
|
+
|
35
|
+
|
36
|
+
Scenario: feature with mutliple unformatted tables
|
37
|
+
Given feature content
|
38
|
+
"""
|
39
|
+
Feature: Test Feature
|
40
|
+
|
41
|
+
Scenario: Test Scenario
|
42
|
+
Given a table
|
43
|
+
|header_column1|header_column2|
|
44
|
+
|row1_column1|row1_column2|
|
45
|
+
|row2_column1|row2_column2|
|
46
|
+
|row3_column1|row3_column2|
|
47
|
+
Then my tests pass
|
48
|
+
|
49
|
+
Scenario Outline: Test Scenario Outline
|
50
|
+
Given <a> and <b>
|
51
|
+
Then I expect <c>
|
52
|
+
|
53
|
+
Examples:
|
54
|
+
|a | b | c |
|
55
|
+
|a1 | b1| c1 |
|
56
|
+
|a2 | b2 | c2 |
|
57
|
+
|a3 | b3 | c3 |
|
58
|
+
"""
|
59
|
+
Then the formatted feature content is
|
60
|
+
"""
|
61
|
+
Feature: Test Feature
|
62
|
+
|
63
|
+
Scenario: Test Scenario
|
64
|
+
Given a table
|
65
|
+
| header_column1 | header_column2 |
|
66
|
+
| row1_column1 | row1_column2 |
|
67
|
+
| row2_column1 | row2_column2 |
|
68
|
+
| row3_column1 | row3_column2 |
|
69
|
+
Then my tests pass
|
70
|
+
|
71
|
+
Scenario Outline: Test Scenario Outline
|
72
|
+
Given <a> and <b>
|
73
|
+
Then I expect <c>
|
74
|
+
|
75
|
+
Examples:
|
76
|
+
| a | b | c |
|
77
|
+
| a1 | b1 | c1 |
|
78
|
+
| a2 | b2 | c2 |
|
79
|
+
| a3 | b3 | c3 |
|
80
|
+
"""
|
81
|
+
|
82
|
+
|
83
|
+
Scenario: feature with formatted tables
|
84
|
+
Given feature content
|
85
|
+
"""
|
86
|
+
Feature: Test Feature
|
87
|
+
|
88
|
+
Scenario: Test Scenario
|
89
|
+
Given a table
|
90
|
+
| header_column1 | header_column2 |
|
91
|
+
| row1_column1 | row1_column2 |
|
92
|
+
| row2_column1 | row2_column2 |
|
93
|
+
| row3_column1 | row3_column2 |
|
94
|
+
Then my tests pass
|
95
|
+
|
96
|
+
Scenario Outline: Test Scenario Outline
|
97
|
+
Given <a> and <b>
|
98
|
+
Then I expect <c>
|
99
|
+
|
100
|
+
Examples:
|
101
|
+
| a | b | c |
|
102
|
+
| a1 | b1 | c1 |
|
103
|
+
| a2 | b2 | c2 |
|
104
|
+
| a3 | b3 | c3 |
|
105
|
+
"""
|
106
|
+
Then the feature is formatted
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Feature: table formatter
|
2
|
+
|
3
|
+
Scenario: unformatted steps
|
4
|
+
Given steps
|
5
|
+
"""
|
6
|
+
Given A
|
7
|
+
Given B
|
8
|
+
When C
|
9
|
+
Then D
|
10
|
+
Then E
|
11
|
+
"""
|
12
|
+
Then the formatted steps are
|
13
|
+
"""
|
14
|
+
Given A
|
15
|
+
And B
|
16
|
+
When C
|
17
|
+
Then D
|
18
|
+
And E
|
19
|
+
"""
|
20
|
+
|
21
|
+
Scenario: formatted steps
|
22
|
+
Given steps
|
23
|
+
"""
|
24
|
+
Given A
|
25
|
+
And B
|
26
|
+
When C
|
27
|
+
Then D
|
28
|
+
And E
|
29
|
+
"""
|
30
|
+
Then the steps are formatted
|
@@ -0,0 +1,45 @@
|
|
1
|
+
Feature: table formatter
|
2
|
+
|
3
|
+
Scenario: minimal table
|
4
|
+
Given table lines
|
5
|
+
"""
|
6
|
+
|header_column1|header_column2|
|
7
|
+
|row1_column1|row1_column2|
|
8
|
+
|row2_column1|row2_column2|
|
9
|
+
|row3_column1|row3_column2|
|
10
|
+
"""
|
11
|
+
Then the formatted table lines are
|
12
|
+
"""
|
13
|
+
| header_column1 | header_column2 |
|
14
|
+
| row1_column1 | row1_column2 |
|
15
|
+
| row2_column1 | row2_column2 |
|
16
|
+
| row3_column1 | row3_column2 |
|
17
|
+
"""
|
18
|
+
|
19
|
+
|
20
|
+
Scenario: misaligned spacing in table
|
21
|
+
Given table lines
|
22
|
+
"""
|
23
|
+
| header_column1 | header_column2 |
|
24
|
+
| row1_column1 | row1_column2 |
|
25
|
+
| row2_column1 | row2_column2 |
|
26
|
+
| row3_column1 | row3_column2 |
|
27
|
+
"""
|
28
|
+
Then the formatted table lines are
|
29
|
+
"""
|
30
|
+
| header_column1 | header_column2 |
|
31
|
+
| row1_column1 | row1_column2 |
|
32
|
+
| row2_column1 | row2_column2 |
|
33
|
+
| row3_column1 | row3_column2 |
|
34
|
+
"""
|
35
|
+
|
36
|
+
|
37
|
+
Scenario: formatted table
|
38
|
+
Given table lines
|
39
|
+
"""
|
40
|
+
| header_column1 | header_column2 |
|
41
|
+
| row1_column1 | row1_column2 |
|
42
|
+
| row2_column1 | row2_column2 |
|
43
|
+
| row3_column1 | row3_column2 |
|
44
|
+
"""
|
45
|
+
Then the table is formatted
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Given(/^I have no files$/) do
|
2
|
+
# Empty step for readability
|
3
|
+
end
|
4
|
+
|
5
|
+
|
6
|
+
Given(/^I have an? (.+?) file at "features\/(.+?)"$/) do |filetype, filename|
|
7
|
+
content = IO.read("#{FIXTURES_PATH}/#{filetype}.feature.example")
|
8
|
+
IO.write "#{TMP_DIR}/features/#{filename}", content
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
When(/^I run `(.+?)`$/) do |command|
|
13
|
+
@last_run = run command
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
Then(/^I see the output$/) do |output|
|
18
|
+
expect(@last_run.out.uncolorize).to eql "#{output}\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
Then(/^it exits with status (\d+)$/) do |status|
|
23
|
+
expect(@last_run.exit_status).to eql status.to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
Then(/^the file "features\/(.+?)" in now formatted$/) do |filename|
|
28
|
+
expected = IO.read "#{FIXTURES_PATH}/formatted.feature.example"
|
29
|
+
actual = IO.read "#{TMP_DIR}/features/#{filename}"
|
30
|
+
expect(actual).to eql expected
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'cucumber_lint'
|
2
|
+
require 'open4'
|
3
|
+
require 'rspec'
|
4
|
+
|
5
|
+
|
6
|
+
BIN_PATH = "#{File.dirname(__FILE__)}/../../bin"
|
7
|
+
FIXTURES_PATH = "#{File.dirname(__FILE__)}/fixtures"
|
8
|
+
TMP_DIR = '/tmp'
|
9
|
+
|
10
|
+
|
11
|
+
Before do
|
12
|
+
Dir.chdir TMP_DIR
|
13
|
+
FileUtils.rm_rf 'features'
|
14
|
+
Dir.mkdir 'features'
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
at_exit do
|
19
|
+
FileUtils.rm_rf TMP_DIR
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Given(/^feature content$/) do |content|
|
2
|
+
@content = content
|
3
|
+
end
|
4
|
+
|
5
|
+
|
6
|
+
Then(/^the formatted feature content is$/) do |content|
|
7
|
+
expected = content
|
8
|
+
actual = CucumberLint::FeatureFormatter.new(@content).formatted_content
|
9
|
+
expect(actual).to eql expected
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
Then(/^the feature is formatted$/) do
|
14
|
+
expect(CucumberLint::FeatureFormatter.new(@content)).to be_formatted
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Given(/^steps$/) do |steps|
|
2
|
+
@steps = steps.split("\n", -1)
|
3
|
+
end
|
4
|
+
|
5
|
+
|
6
|
+
Then(/^the formatted steps are$/) do |steps|
|
7
|
+
expected = steps.split("\n", -1)
|
8
|
+
actual = CucumberLint::StepsFormatter.new(@steps).formatted_content
|
9
|
+
expect(actual).to eql expected
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
Then(/^the steps are formatted$/) do
|
14
|
+
expect(CucumberLint::StepsFormatter.new(@steps)).to be_formatted
|
15
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
def run command
|
2
|
+
result = OpenStruct.new
|
3
|
+
command = "PATH=#{BIN_PATH}:$PATH; #{command} 2>&1"
|
4
|
+
|
5
|
+
status = Open4.popen4(command) do |_pid, stdin, stdout, _stderr|
|
6
|
+
stdin.close
|
7
|
+
result.out = stdout.read
|
8
|
+
end
|
9
|
+
|
10
|
+
result.exit_status = status.exitstatus
|
11
|
+
result
|
12
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Given(/^table lines$/) do |lines|
|
2
|
+
@lines = lines.split("\n", -1)
|
3
|
+
end
|
4
|
+
|
5
|
+
|
6
|
+
Then(/^the formatted table lines are$/) do |lines|
|
7
|
+
expected = lines.split("\n", -1)
|
8
|
+
actual = CucumberLint::TableFormatter.new(@lines).formatted_content
|
9
|
+
expect(actual).to eql expected
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
Then(/^the table is formatted$/) do
|
14
|
+
expect(CucumberLint::TableFormatter.new(@lines)).to be_formatted
|
15
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Monkey-patching Array
|
2
|
+
class Array
|
3
|
+
|
4
|
+
def group
|
5
|
+
groups = []
|
6
|
+
last_group = { passing: true, values: [] }
|
7
|
+
|
8
|
+
each do |element|
|
9
|
+
passing = yield element
|
10
|
+
|
11
|
+
if passing != last_group[:passing]
|
12
|
+
groups << last_group unless last_group[:values].empty?
|
13
|
+
last_group = { passing: passing, values: [] }
|
14
|
+
end
|
15
|
+
|
16
|
+
last_group[:values] << element
|
17
|
+
end
|
18
|
+
|
19
|
+
groups + [last_group]
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'colorize'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module CucumberLint
|
5
|
+
# A class that takes in the content that make up a cucumber feature
|
6
|
+
# and can determine if it is formatted and output the formatted content
|
7
|
+
class Cli
|
8
|
+
|
9
|
+
def self.execute args
|
10
|
+
new(args).execute!
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def initialize args, out: STDOUT
|
15
|
+
@out = out
|
16
|
+
@lint = args[0] != '--fix'
|
17
|
+
@results = OpenStruct.new(formatted: 0, unformatted: 0, unformatted_files: [])
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def execute!
|
22
|
+
Dir.glob('./features/**/*.feature').each do |filename|
|
23
|
+
formatter = FeatureFormatter.new IO.read(filename)
|
24
|
+
|
25
|
+
if formatter.formatted?
|
26
|
+
file_formatted
|
27
|
+
else
|
28
|
+
file_unformatted filename, formatter.formatted_content
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
output_results
|
33
|
+
exit 1 unless @results.unformatted_files.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
def output_results
|
37
|
+
output_failures if @lint && !@results.unformatted_files.empty?
|
38
|
+
total = @results.formatted + @results.unformatted
|
39
|
+
@out.print "\n\n#{total} file#{'s' if total != 1} inspected ("
|
40
|
+
if @lint
|
41
|
+
output_inspect_results
|
42
|
+
else
|
43
|
+
output_write_results
|
44
|
+
end
|
45
|
+
@out.puts ')'
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def output_inspect_results
|
50
|
+
@out.print "#{@results.formatted} passed".green
|
51
|
+
@out.print ', ' + "#{@results.unformatted} failed".red if @results.unformatted > 0
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def output_write_results
|
56
|
+
@out.print "#{@results.unformatted} written".yellow
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def output_failures
|
61
|
+
@out.puts "\n\nFiles with errors:".red
|
62
|
+
@out.print @results.unformatted_files.join("\n").red
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def file_formatted
|
67
|
+
@results.formatted += 1
|
68
|
+
@out.print '.'.green
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def file_unformatted filename, content
|
73
|
+
@results.unformatted += 1
|
74
|
+
|
75
|
+
if @lint
|
76
|
+
@results.unformatted_files << filename
|
77
|
+
@out.print 'F'.red
|
78
|
+
else
|
79
|
+
IO.write filename, content
|
80
|
+
@out.print 'W'.yellow
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'core_ext/array'
|
2
|
+
|
3
|
+
module CucumberLint
|
4
|
+
# A class that takes in the content that make up a cucumber feature
|
5
|
+
# and can determine if it is formatted and output the formatted content
|
6
|
+
class FeatureFormatter
|
7
|
+
|
8
|
+
attr_reader :formatted_content
|
9
|
+
|
10
|
+
def initialize content
|
11
|
+
@content = content
|
12
|
+
@formatted_content = format
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def formatted?
|
17
|
+
@content == @formatted_content
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
|
24
|
+
def format
|
25
|
+
lines = format_steps @content.split("\n", -1)
|
26
|
+
groupings = lines.group { |line| line =~ /^\s*\|/ }
|
27
|
+
|
28
|
+
groupings.map do |group|
|
29
|
+
if group[:passing]
|
30
|
+
format_table group[:values]
|
31
|
+
else
|
32
|
+
group[:values]
|
33
|
+
end
|
34
|
+
end.flatten.join("\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def format_table lines
|
39
|
+
TableFormatter.new(lines).formatted_content
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def format_steps steps
|
44
|
+
StepsFormatter.new(steps).formatted_content
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module CucumberLint
|
2
|
+
# A class that takes in the lines of a cucumber feature
|
3
|
+
# and can determine if the steps are formatted and output the formatted steps
|
4
|
+
class StepsFormatter
|
5
|
+
|
6
|
+
attr_reader :formatted_content
|
7
|
+
|
8
|
+
def initialize lines
|
9
|
+
@lines = lines
|
10
|
+
@formatted_content = format
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def formatted?
|
15
|
+
@lines == @formatted_content
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
RESET_KEYWORDS = %w(Background Scenario)
|
21
|
+
STEP_TYPES = %w(Given When Then)
|
22
|
+
|
23
|
+
def format
|
24
|
+
@lines.map { |line| format_line line }
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def format_line line
|
29
|
+
@previous_step_type = nil if should_reset_previous_step_type? line
|
30
|
+
|
31
|
+
step_type = line.split(' ', -1)[0]
|
32
|
+
|
33
|
+
if STEP_TYPES.include?(step_type)
|
34
|
+
if @previous_step_type == step_type
|
35
|
+
line.sub! step_type, 'And'
|
36
|
+
else
|
37
|
+
@previous_step_type = step_type
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
line
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def should_reset_previous_step_type? line
|
46
|
+
RESET_KEYWORDS.any? { |keyword| line.start_with? keyword }
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module CucumberLint
|
2
|
+
# A class that takes in the lines that make up a cucumber table
|
3
|
+
# and can determine if it is formatted and output the formatted table
|
4
|
+
class TableFormatter
|
5
|
+
|
6
|
+
attr_reader :formatted_content
|
7
|
+
|
8
|
+
def initialize lines
|
9
|
+
@lines = lines
|
10
|
+
@column_widths = column_widths
|
11
|
+
@formatted_content = format
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def formatted?
|
16
|
+
@lines == @formatted_content
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
|
23
|
+
def column_widths
|
24
|
+
widths_by_line = @lines.map { |line| line_column_widths line }
|
25
|
+
grouped_widths = widths_by_line[0].zip(*widths_by_line[1..-1])
|
26
|
+
grouped_widths.each_with_index.map do |width, i|
|
27
|
+
i == 0 ? width.min : width.max
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def format
|
33
|
+
@lines.each_with_index.map do |line|
|
34
|
+
line.split('|', -1).each_with_index.map do |piece, index|
|
35
|
+
format_piece piece, index
|
36
|
+
end.join('|')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def format_piece piece, index
|
42
|
+
if index == 0
|
43
|
+
' ' * column_widths[index]
|
44
|
+
elsif index == column_widths.length - 1
|
45
|
+
piece
|
46
|
+
else
|
47
|
+
" #{piece.strip} ".ljust column_widths[index]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def line_column_widths line
|
53
|
+
pieces = line.split('|', -1)
|
54
|
+
pieces.each_with_index.map do |piece, index|
|
55
|
+
if index == 0 || index == pieces.length - 1
|
56
|
+
piece.length
|
57
|
+
else
|
58
|
+
piece.strip!
|
59
|
+
piece.length + 2 # one space padding on each side
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'core_ext/array'
|
2
|
+
|
3
|
+
describe Array do
|
4
|
+
describe '#group' do
|
5
|
+
it 'returns elements grouped by whether of not they pass the given block' do
|
6
|
+
array = [1, 1, 2, 3, 5, 8, 13, 21, 34]
|
7
|
+
expected = array.group(&:odd?)
|
8
|
+
actual = [
|
9
|
+
{ passing: true, values: [1, 1] },
|
10
|
+
{ passing: false, values: [2] },
|
11
|
+
{ passing: true, values: [3, 5] },
|
12
|
+
{ passing: false, values: [8] },
|
13
|
+
{ passing: true, values: [13, 21] },
|
14
|
+
{ passing: false, values: [34] }
|
15
|
+
]
|
16
|
+
expect(expected).to eql actual
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cucumber_lint
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- charlierudolph
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: colorize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.7.5
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.7.5
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- charles.w.rudolph@gmail.com
|
30
|
+
executables:
|
31
|
+
- cucumber_lint
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".gitignore"
|
36
|
+
- ".rubocop.yml"
|
37
|
+
- Gemfile
|
38
|
+
- Gemfile.lock
|
39
|
+
- LICENSE
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- bin/cucumber_lint
|
43
|
+
- cucumber.yml
|
44
|
+
- cucumber_lint.gemspec
|
45
|
+
- features/cucumber_lint/cli_fix.feature
|
46
|
+
- features/cucumber_lint/cli_lint.feature
|
47
|
+
- features/cucumber_lint/feature_formatter.feature
|
48
|
+
- features/cucumber_lint/steps_formatter.feature
|
49
|
+
- features/cucumber_lint/table_formatter.feature
|
50
|
+
- features/step_definitions/cli_steps.rb
|
51
|
+
- features/step_definitions/env.rb
|
52
|
+
- features/step_definitions/feature_formatter_steps.rb
|
53
|
+
- features/step_definitions/fixtures/formatted.feature.example
|
54
|
+
- features/step_definitions/fixtures/unformatted.feature.example
|
55
|
+
- features/step_definitions/steps_formatter_steps.rb
|
56
|
+
- features/step_definitions/support/run_helpers.rb
|
57
|
+
- features/step_definitions/table_formatter_steps.rb
|
58
|
+
- lib/core_ext/array.rb
|
59
|
+
- lib/cucumber_lint.rb
|
60
|
+
- lib/cucumber_lint/cli.rb
|
61
|
+
- lib/cucumber_lint/feature_formatter.rb
|
62
|
+
- lib/cucumber_lint/steps_formatter.rb
|
63
|
+
- lib/cucumber_lint/table_formatter.rb
|
64
|
+
- lib/cucumber_lint/version.rb
|
65
|
+
- spec/core_ext/array_spec.rb
|
66
|
+
homepage: https://github.com/charlierudolph/cucumber_lint
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 2.4.5
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: A command line interface for linting and formatting cucumber features
|
90
|
+
test_files: []
|