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