gherkin-ruby 0.0.1
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.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +11 -0
- data/Readme.md +57 -0
- data/gherkin-ruby.gemspec +23 -0
- data/lib/gherkin/ast.rb +83 -0
- data/lib/gherkin/parser.rb +40 -0
- data/lib/gherkin/transform.rb +49 -0
- data/lib/gherkin/version.rb +3 -0
- data/lib/gherkin.rb +15 -0
- data/test/gherkin/ast_test.rb +102 -0
- data/test/gherkin/parser_test.rb +156 -0
- data/test/gherkin/transform_test.rb +65 -0
- data/test/test_helper.rb +4 -0
- metadata +87 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
data/Readme.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# gherkin-ruby
|
2
|
+
Gherkin-ruby is a pure Ruby implementation of a [Gherkin](http://github.com/cucumber/gherkin) parser, using [Parslet](http://github.com/kschiess/parslet).
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
You can easily implement your own visitors to traverse the Abstract Syntax Tree. The following example just prints the step names to standard output:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
class MyVisitor
|
9
|
+
def visit(ast)
|
10
|
+
ast.accept(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def visit_Feature(feature)
|
14
|
+
# Do something nasty with the feature
|
15
|
+
# Set whatever state you want:
|
16
|
+
# @current_feature = feature
|
17
|
+
# etc etc
|
18
|
+
# And keep visiting its children:
|
19
|
+
|
20
|
+
feature.each { |scenario| scenario.accept(self) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def visit_Scenario(scenario)
|
24
|
+
# Do something nasty with the scenario
|
25
|
+
# Set whatever state you want:
|
26
|
+
# @current_scenario = scenario
|
27
|
+
# etc etc
|
28
|
+
# And keep visiting its children:
|
29
|
+
|
30
|
+
scenario.each { |step| step.accept(self) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def visit_Background(background)
|
34
|
+
# Do something nasty with the background
|
35
|
+
# And keep visiting its children:
|
36
|
+
|
37
|
+
background.each { |step| step.accept(self) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def visit_Tag(tag)
|
41
|
+
# Do something nasty with the tag
|
42
|
+
end
|
43
|
+
|
44
|
+
def visit_Step(step)
|
45
|
+
# Finally, print the step name.
|
46
|
+
puts "STEP: #{step.name}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
ast = Gherkin.parse(File.read('some.feature'))
|
51
|
+
visitor = MyVisitor.new
|
52
|
+
visitor.visit(ast)
|
53
|
+
```
|
54
|
+
|
55
|
+
## Todo
|
56
|
+
|
57
|
+
* Some optimization
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "gherkin/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "gherkin-ruby"
|
7
|
+
s.version = Gherkin::VERSION
|
8
|
+
s.authors = ["Marc Divins", "Josep M. Bach"]
|
9
|
+
s.email = ["marcdivc@gmail.com", "josep.m.bach@gmail.com"]
|
10
|
+
s.homepage = "http://github.com/codegram/gherkin"
|
11
|
+
s.summary = %q{Gherkin-ruby is a Gherkin parser in pure Ruby using Parslet}
|
12
|
+
s.description = %q{Gherkin-ruby is a Gherkin parser in pure Ruby using Parslet}
|
13
|
+
|
14
|
+
s.rubyforge_project = "gherkin-ruby"
|
15
|
+
|
16
|
+
s.add_runtime_dependency 'parslet'
|
17
|
+
s.add_development_dependency 'minitest'
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
end
|
data/lib/gherkin/ast.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module Gherkin
|
2
|
+
module AST
|
3
|
+
class Node
|
4
|
+
attr_reader :line, :column
|
5
|
+
|
6
|
+
def accept(visitor)
|
7
|
+
name = self.class.name.split('::').last
|
8
|
+
visitor.send("visit_#{name}".to_sym, self)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Feature < Node
|
13
|
+
attr_reader :name, :background, :scenarios
|
14
|
+
|
15
|
+
include Enumerable
|
16
|
+
|
17
|
+
def initialize(name, scenarios=[], background=nil)
|
18
|
+
@line, @column = name.line_and_column
|
19
|
+
|
20
|
+
@name = name.to_s
|
21
|
+
@background = background
|
22
|
+
@scenarios = scenarios
|
23
|
+
end
|
24
|
+
|
25
|
+
def each
|
26
|
+
@scenarios.each
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Background < Node
|
31
|
+
attr_reader :steps
|
32
|
+
|
33
|
+
include Enumerable
|
34
|
+
|
35
|
+
def initialize(steps=[])
|
36
|
+
@line = steps.first.line - 1
|
37
|
+
@column = 3
|
38
|
+
|
39
|
+
@steps = steps
|
40
|
+
end
|
41
|
+
|
42
|
+
def each
|
43
|
+
@steps.each
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Scenario < Node
|
48
|
+
attr_reader :name, :steps, :tags
|
49
|
+
|
50
|
+
include Enumerable
|
51
|
+
|
52
|
+
def initialize(name, steps=[], tags=[])
|
53
|
+
@line, @column = name.line_and_column
|
54
|
+
|
55
|
+
@name = name.to_s
|
56
|
+
@steps = steps
|
57
|
+
@tags = tags
|
58
|
+
end
|
59
|
+
|
60
|
+
def each
|
61
|
+
@steps.each
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Step < Node
|
66
|
+
attr_reader :name
|
67
|
+
def initialize(name)
|
68
|
+
@line, @column = name.line_and_column
|
69
|
+
|
70
|
+
@name = name.to_s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Tag < Node
|
75
|
+
attr_reader :name
|
76
|
+
def initialize(name)
|
77
|
+
@line, @column = name.line_and_column
|
78
|
+
|
79
|
+
@name = name.to_s
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
module Gherkin
|
4
|
+
class Parser < Parslet::Parser
|
5
|
+
def indent(num=2)
|
6
|
+
str(' ' * num)
|
7
|
+
end
|
8
|
+
|
9
|
+
rule(:space) { match('\s').repeat }
|
10
|
+
rule(:space?) { space.maybe }
|
11
|
+
rule(:newline) { match('\n').repeat }
|
12
|
+
rule(:text) { match('[^\n]').repeat }
|
13
|
+
rule(:identifier) { match('\w').repeat }
|
14
|
+
|
15
|
+
rule(:feature_line) { str('Feature:') >> space? >> text.as(:name) }
|
16
|
+
rule(:scenario_line) { indent(2) >> str('Scenario:') >> space? >> text.as(:name) }
|
17
|
+
rule(:background_line) { indent(2) >> str('Background:') }
|
18
|
+
|
19
|
+
rule(:step_keyword) { str('Given') | str('When') | str('Then') | str('And') | str('But') }
|
20
|
+
|
21
|
+
rule(:comment) { str('#') >> text.as(:comment) }
|
22
|
+
rule(:description) { indent(2) >> text.as(:description) }
|
23
|
+
|
24
|
+
rule(:step) { indent(4) >> step_keyword >> space? >> text.as(:name) }
|
25
|
+
rule(:steps) { (step.as(:step) >> newline.maybe).repeat }
|
26
|
+
|
27
|
+
rule(:tags) { indent(2) >> (str('@') >> identifier.as(:tag) >> str(' ').maybe).repeat(1) }
|
28
|
+
|
29
|
+
rule(:scenario) { (tags.as(:tags) >> newline).maybe >> scenario_line >> newline >> steps.as(:steps) }
|
30
|
+
rule(:scenarios) { (scenario.as(:scenario) >> newline.maybe).repeat }
|
31
|
+
|
32
|
+
rule(:background) { background_line >> newline >> steps.as(:steps) }
|
33
|
+
|
34
|
+
rule(:feature) { feature_line >> newline >> background.as(:background).maybe >> scenarios.as(:scenarios) }
|
35
|
+
|
36
|
+
rule(:main) { feature.as(:feature) }
|
37
|
+
|
38
|
+
root :main
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Gherkin
|
2
|
+
class Transform < Parslet::Transform
|
3
|
+
# Match feature with background
|
4
|
+
rule(
|
5
|
+
feature: {
|
6
|
+
name: simple(:name),
|
7
|
+
background: {
|
8
|
+
steps: subtree(:background_steps)
|
9
|
+
},
|
10
|
+
scenarios: subtree(:scenarios)
|
11
|
+
}
|
12
|
+
) { AST::Feature.new(name, scenarios, AST::Background.new(background_steps)) }
|
13
|
+
|
14
|
+
# Match feature without background
|
15
|
+
rule(
|
16
|
+
feature: {
|
17
|
+
name: simple(:name),
|
18
|
+
scenarios: subtree(:scenarios)
|
19
|
+
}
|
20
|
+
) { AST::Feature.new(name, scenarios, AST::Background.new([])) }
|
21
|
+
|
22
|
+
# Match scenarios without tags
|
23
|
+
rule(
|
24
|
+
scenario: {
|
25
|
+
name: simple(:name),
|
26
|
+
steps: subtree(:steps)
|
27
|
+
}
|
28
|
+
) { AST::Scenario.new(name, steps, []) }
|
29
|
+
|
30
|
+
# Match scenarios with tags
|
31
|
+
rule(
|
32
|
+
scenario: {
|
33
|
+
name: simple(:name),
|
34
|
+
steps: subtree(:steps),
|
35
|
+
tags: subtree(:tags)
|
36
|
+
}
|
37
|
+
) { AST::Scenario.new(name, steps, tags) }
|
38
|
+
|
39
|
+
rule(
|
40
|
+
step: {
|
41
|
+
name: simple(:name),
|
42
|
+
}
|
43
|
+
) { AST::Step.new(name) }
|
44
|
+
|
45
|
+
rule(
|
46
|
+
tag: simple(:name)
|
47
|
+
) { AST::Tag.new(name) }
|
48
|
+
end
|
49
|
+
end
|
data/lib/gherkin.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
require_relative "gherkin/version"
|
3
|
+
require_relative 'gherkin/ast'
|
4
|
+
require_relative 'gherkin/parser'
|
5
|
+
require_relative 'gherkin/transform'
|
6
|
+
|
7
|
+
module Gherkin
|
8
|
+
def self.parse(input)
|
9
|
+
parser = Parser.new
|
10
|
+
transform = Transform.new
|
11
|
+
|
12
|
+
parsed = parser.parse input
|
13
|
+
transform.apply(parsed)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
class MyVisitor
|
5
|
+
def visit_MyNode(my_node)
|
6
|
+
my_node.elements
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class MyNode < Gherkin::AST::Node
|
11
|
+
attr_reader :elements
|
12
|
+
def initialize(name, elements)
|
13
|
+
@name = name
|
14
|
+
@elements = elements
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module Gherkin
|
19
|
+
module AST
|
20
|
+
describe Node do
|
21
|
+
it 'is visitable' do
|
22
|
+
my_node = MyNode.new('My Node', ['foo', 'bar', 'baz'])
|
23
|
+
visitor = MyVisitor.new
|
24
|
+
|
25
|
+
my_node.accept(visitor).must_equal ['foo', 'bar', 'baz']
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
[Feature, Scenario, Step, Tag].each do |node|
|
30
|
+
describe node do
|
31
|
+
it 'is a Node' do
|
32
|
+
node.ancestors.must_include Node
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'has a line and column' do
|
36
|
+
name = OpenStruct.new(line_and_column: [2, 13])
|
37
|
+
def name.to_s; 'Name'; end
|
38
|
+
|
39
|
+
instance = node.new(name)
|
40
|
+
instance.name.must_equal 'Name'
|
41
|
+
instance.line.must_equal 2
|
42
|
+
instance.column.must_equal 13
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe Feature do
|
48
|
+
it 'is Enumerable' do
|
49
|
+
name = OpenStruct.new(line_and_column: [2, 13])
|
50
|
+
def name.to_s; 'Name'; end
|
51
|
+
|
52
|
+
background = ['foo', 'bar']
|
53
|
+
elements = ['+foo', '+bar']
|
54
|
+
|
55
|
+
instance = Feature.new(name, elements, background )
|
56
|
+
instance.background.each.to_a.must_equal ['foo', 'bar']
|
57
|
+
instance.each.to_a.must_equal ['+foo', '+bar']
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe Scenario do
|
62
|
+
it 'is Enumerable' do
|
63
|
+
name = OpenStruct.new(line_and_column: [2, 13])
|
64
|
+
def name.to_s; 'Name'; end
|
65
|
+
|
66
|
+
elements = ['foo', 'bar']
|
67
|
+
|
68
|
+
instance = Scenario.new(name, elements)
|
69
|
+
instance.each.to_a.must_equal ['foo', 'bar']
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'has tags' do
|
73
|
+
name = OpenStruct.new(line_and_column: [2, 13])
|
74
|
+
def name.to_s; 'Name'; end
|
75
|
+
|
76
|
+
steps = ['foo', 'bar']
|
77
|
+
tags = ['javascript', 'wip']
|
78
|
+
|
79
|
+
instance = Scenario.new(name, steps, tags)
|
80
|
+
instance.tags.must_equal tags
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe Background do
|
85
|
+
it 'is a Node' do
|
86
|
+
Background.ancestors.must_include Node
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'is Enumerable' do
|
90
|
+
steps = [
|
91
|
+
OpenStruct.new(line: 4),
|
92
|
+
OpenStruct.new(line: 5),
|
93
|
+
]
|
94
|
+
|
95
|
+
instance = Background.new(steps)
|
96
|
+
instance.line.must_equal 3
|
97
|
+
instance.column.must_equal 3
|
98
|
+
instance.each.to_a.must_equal steps
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require 'parslet'
|
3
|
+
|
4
|
+
def p(rule, input, tag=nil)
|
5
|
+
tag ||= rule
|
6
|
+
parser = Gherkin::Parser.new
|
7
|
+
parser.send(rule).parse(input)[tag]
|
8
|
+
end
|
9
|
+
|
10
|
+
module Gherkin
|
11
|
+
describe 'Feature parsing' do
|
12
|
+
it 'parses the Feature name' do
|
13
|
+
p(:feature_line, "Feature: Test how Gherkin works", :name).must_equal "Test how Gherkin works"
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'parses the Scenario name' do
|
17
|
+
p(:scenario_line, " Scenario: Formal greeting", :name).must_equal "Formal greeting"
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'Steps' do
|
21
|
+
it 'parses a Given step' do
|
22
|
+
p(:step, " Given I have an empty array", :name).must_equal "I have an empty array"
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'parses a When step' do
|
26
|
+
p(:step, " When I have an empty array", :name).must_equal "I have an empty array"
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'parses a Then step' do
|
30
|
+
p(:step, " Then I have an empty array", :name).must_equal "I have an empty array"
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'parses an And step' do
|
34
|
+
p(:step, " And I have an empty array", :name).must_equal "I have an empty array"
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'parses a But step' do
|
38
|
+
p(:step, " But I have an empty array", :name).must_equal "I have an empty array"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'Comment parsing' do
|
44
|
+
it 'parses a comment ignoring its content' do
|
45
|
+
p(:comment, "# My comment").size.must_be :>, 0
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'Description parsing' do
|
50
|
+
it 'parses descriptions ignoring their content' do
|
51
|
+
p(:description, " In order to know what the heck is Gherkin").size.must_be :>, 0
|
52
|
+
p(:description, " As a developer").size.must_be :>, 0
|
53
|
+
p(:description, " I want it to behave in an expected way").size.must_be :>, 0
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'Tags parsing' do
|
58
|
+
it 'parses many tags' do
|
59
|
+
javascript = p(:tags, " @javascript @wip", 0)
|
60
|
+
wip = p(:tags, " @javascript @wip", 1)
|
61
|
+
javascript[:tag].must_equal 'javascript'
|
62
|
+
wip[:tag].must_equal 'wip'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'parses one tag' do
|
66
|
+
p(:tags, " @javascript", 0)[:tag].must_equal 'javascript'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'Background parsing' do
|
71
|
+
it 'parses a background' do
|
72
|
+
background = " Background:\n When I do something\n Then blah"
|
73
|
+
steps = p(:background, background, :steps)
|
74
|
+
steps.first[:step][:name].must_equal 'I do something'
|
75
|
+
steps.last[:step][:name].must_equal 'blah'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'Parses scenario objects' do
|
80
|
+
it 'parses a Scenario' do
|
81
|
+
parser = Gherkin::Parser.new
|
82
|
+
scenario = " Scenario: Parse a scenario\n Given something happens\n Then something cooler happens"
|
83
|
+
result = parser.scenario.parse(scenario)
|
84
|
+
|
85
|
+
result[:name].must_equal 'Parse a scenario'
|
86
|
+
result[:steps][0][:step][:name].must_equal 'something happens'
|
87
|
+
result[:steps][1][:step][:name].must_equal 'something cooler happens'
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'parses a Scenario with a tag' do
|
91
|
+
parser = Gherkin::Parser.new
|
92
|
+
scenario = " @javascript\n Scenario: Parse a scenario\n Given something happens\n Then something cooler happens"
|
93
|
+
result = parser.scenario.parse(scenario)
|
94
|
+
|
95
|
+
result[:tags].first[:tag].must_equal 'javascript'
|
96
|
+
result[:name].must_equal 'Parse a scenario'
|
97
|
+
result[:steps][0][:step][:name].must_equal 'something happens'
|
98
|
+
result[:steps][1][:step][:name].must_equal 'something cooler happens'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'Parses feature objects without background' do
|
103
|
+
it 'parses a Feature' do
|
104
|
+
parser = Gherkin::Parser.new
|
105
|
+
scenario = """Feature: My Feature
|
106
|
+
@javascript @wip
|
107
|
+
Scenario: something happens
|
108
|
+
Given something happens
|
109
|
+
Then something cooler happens
|
110
|
+
|
111
|
+
Scenario: something else happens
|
112
|
+
Given foo
|
113
|
+
Then bar
|
114
|
+
"""
|
115
|
+
result = parser.parse(scenario)
|
116
|
+
|
117
|
+
result[:feature][:name].must_equal 'My Feature'
|
118
|
+
|
119
|
+
result[:feature][:scenarios][0][:scenario][:tags].first[:tag].must_equal 'javascript'
|
120
|
+
result[:feature][:scenarios][0][:scenario][:tags].last[:tag].must_equal 'wip'
|
121
|
+
result[:feature][:scenarios][0][:scenario][:name].must_equal 'something happens'
|
122
|
+
result[:feature][:scenarios][0][:scenario][:steps][0][:step][:name].must_equal 'something happens'
|
123
|
+
result[:feature][:scenarios][0][:scenario][:steps][1][:step][:name].must_equal 'something cooler happens'
|
124
|
+
|
125
|
+
result[:feature][:scenarios][1][:scenario][:name].must_equal 'something else happens'
|
126
|
+
result[:feature][:scenarios][1][:scenario][:steps][0][:step][:name].must_equal 'foo'
|
127
|
+
result[:feature][:scenarios][1][:scenario][:steps][1][:step][:name].must_equal 'bar'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'Parses feature objects with background' do
|
132
|
+
it 'parses a Feature' do
|
133
|
+
parser = Gherkin::Parser.new
|
134
|
+
scenario = """Feature: My Feature
|
135
|
+
|
136
|
+
Background:
|
137
|
+
Given something happens
|
138
|
+
And something cooler happens
|
139
|
+
|
140
|
+
Scenario: something else happens
|
141
|
+
Given foo
|
142
|
+
Then bar
|
143
|
+
"""
|
144
|
+
result = parser.parse(scenario)
|
145
|
+
|
146
|
+
result[:feature][:name].must_equal 'My Feature'
|
147
|
+
|
148
|
+
result[:feature][:background][:steps][0][:step][:name].must_equal 'something happens'
|
149
|
+
result[:feature][:background][:steps][1][:step][:name].must_equal 'something cooler happens'
|
150
|
+
|
151
|
+
result[:feature][:scenarios][0][:scenario][:name].must_equal 'something else happens'
|
152
|
+
result[:feature][:scenarios][0][:scenario][:steps][0][:step][:name].must_equal 'foo'
|
153
|
+
result[:feature][:scenarios][0][:scenario][:steps][1][:step][:name].must_equal 'bar'
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require 'parslet'
|
3
|
+
|
4
|
+
module Gherkin
|
5
|
+
describe 'Feature parsing' do
|
6
|
+
before do
|
7
|
+
@scenario = """Feature: My Feature
|
8
|
+
|
9
|
+
Background:
|
10
|
+
Given something happens before anything else happens
|
11
|
+
And more things happens before anything else happens
|
12
|
+
|
13
|
+
Scenario: something happens
|
14
|
+
Given something happens
|
15
|
+
Then something cooler happens
|
16
|
+
|
17
|
+
@javascript @wip
|
18
|
+
Scenario: something else happens
|
19
|
+
Given foo
|
20
|
+
Then bar
|
21
|
+
"""
|
22
|
+
|
23
|
+
parser = Gherkin::Parser.new
|
24
|
+
result = parser.parse(@scenario)
|
25
|
+
transform = Gherkin::Transform.new
|
26
|
+
@result = transform.apply(result)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'generates a nice tree' do
|
30
|
+
@result.must_be_kind_of AST::Feature
|
31
|
+
@result.line.must_equal 1
|
32
|
+
|
33
|
+
background = @result.background
|
34
|
+
background.must_be_kind_of AST::Background
|
35
|
+
background.line.must_equal 3
|
36
|
+
background.column.must_equal 3
|
37
|
+
background.steps.first.name.must_equal 'something happens before anything else happens'
|
38
|
+
background.steps.first.line.must_equal 4
|
39
|
+
background.steps.last.name.must_equal 'more things happens before anything else happens'
|
40
|
+
background.steps.last.line.must_equal 5
|
41
|
+
|
42
|
+
first_scenario = @result.scenarios.first
|
43
|
+
first_scenario.must_be_kind_of AST::Scenario
|
44
|
+
first_scenario.line.must_equal 7
|
45
|
+
first_scenario.name.must_equal 'something happens'
|
46
|
+
first_scenario.steps.first.name.must_equal 'something happens'
|
47
|
+
first_scenario.steps.first.line.must_equal 8
|
48
|
+
first_scenario.steps.last.name.must_equal 'something cooler happens'
|
49
|
+
first_scenario.steps.last.line.must_equal 9
|
50
|
+
|
51
|
+
last_scenario = @result.scenarios.last
|
52
|
+
last_scenario.must_be_kind_of AST::Scenario
|
53
|
+
last_scenario.line.must_equal 12
|
54
|
+
last_scenario.name.must_equal 'something else happens'
|
55
|
+
|
56
|
+
last_scenario.tags.first.name.must_equal 'javascript'
|
57
|
+
last_scenario.tags.last.name.must_equal 'wip'
|
58
|
+
|
59
|
+
last_scenario.steps.first.name.must_equal 'foo'
|
60
|
+
last_scenario.steps.first.line.must_equal 13
|
61
|
+
last_scenario.steps.last.name.must_equal 'bar'
|
62
|
+
last_scenario.steps.last.line.must_equal 14
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gherkin-ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Marc Divins
|
9
|
+
- Josep M. Bach
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2011-11-09 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: parslet
|
17
|
+
requirement: &2160498080 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2160498080
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: minitest
|
28
|
+
requirement: &2160497620 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *2160497620
|
37
|
+
description: Gherkin-ruby is a Gherkin parser in pure Ruby using Parslet
|
38
|
+
email:
|
39
|
+
- marcdivc@gmail.com
|
40
|
+
- josep.m.bach@gmail.com
|
41
|
+
executables: []
|
42
|
+
extensions: []
|
43
|
+
extra_rdoc_files: []
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- Gemfile
|
47
|
+
- Rakefile
|
48
|
+
- Readme.md
|
49
|
+
- gherkin-ruby.gemspec
|
50
|
+
- lib/gherkin.rb
|
51
|
+
- lib/gherkin/ast.rb
|
52
|
+
- lib/gherkin/parser.rb
|
53
|
+
- lib/gherkin/transform.rb
|
54
|
+
- lib/gherkin/version.rb
|
55
|
+
- test/gherkin/ast_test.rb
|
56
|
+
- test/gherkin/parser_test.rb
|
57
|
+
- test/gherkin/transform_test.rb
|
58
|
+
- test/test_helper.rb
|
59
|
+
homepage: http://github.com/codegram/gherkin
|
60
|
+
licenses: []
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project: gherkin-ruby
|
79
|
+
rubygems_version: 1.8.10
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Gherkin-ruby is a Gherkin parser in pure Ruby using Parslet
|
83
|
+
test_files:
|
84
|
+
- test/gherkin/ast_test.rb
|
85
|
+
- test/gherkin/parser_test.rb
|
86
|
+
- test/gherkin/transform_test.rb
|
87
|
+
- test/test_helper.rb
|