gherkin 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/History.txt +12 -0
  2. data/LICENSE +1 -1
  3. data/README.rdoc +2 -2
  4. data/Rakefile +2 -2
  5. data/VERSION.yml +2 -2
  6. data/features/json_formatter.feature +3 -41
  7. data/features/step_definitions/gherkin_steps.rb +5 -6
  8. data/features/step_definitions/json_formatter_steps.rb +3 -2
  9. data/features/step_definitions/json_lexer_steps.rb +5 -5
  10. data/features/step_definitions/pretty_formatter_steps.rb +9 -13
  11. data/features/support/env.rb +1 -1
  12. data/lib/gherkin/formatter/argument.rb +1 -0
  13. data/lib/gherkin/formatter/filter_formatter.rb +149 -0
  14. data/lib/gherkin/formatter/json_formatter.rb +35 -45
  15. data/lib/gherkin/formatter/line_filter.rb +26 -0
  16. data/lib/gherkin/formatter/model.rb +85 -0
  17. data/lib/gherkin/formatter/pretty_formatter.rb +36 -39
  18. data/lib/gherkin/formatter/regexp_filter.rb +17 -0
  19. data/lib/gherkin/formatter/tag_count_formatter.rb +44 -0
  20. data/lib/gherkin/i18n.rb +5 -5
  21. data/lib/gherkin/i18n.yml +13 -0
  22. data/lib/gherkin/i18n_lexer.rb +2 -2
  23. data/lib/gherkin/{json_lexer.rb → json_parser.rb} +17 -5
  24. data/lib/gherkin/{parser → listener}/event.rb +1 -1
  25. data/lib/gherkin/{parser → listener}/formatter_listener.rb +30 -23
  26. data/lib/gherkin/native/java.rb +9 -1
  27. data/lib/gherkin/parser/parser.rb +27 -14
  28. data/lib/gherkin/rubify.rb +5 -1
  29. data/lib/gherkin/tag_expression.rb +62 -0
  30. data/lib/gherkin/tools/files.rb +3 -4
  31. data/lib/gherkin/tools/reformat.rb +2 -2
  32. data/lib/gherkin/tools/stats.rb +3 -4
  33. data/lib/gherkin/tools/stats_listener.rb +1 -1
  34. data/ragel/lexer.c.rl.erb +2 -3
  35. data/ragel/lexer.java.rl.erb +1 -2
  36. data/ragel/lexer.rb.rl.erb +1 -2
  37. data/spec/gherkin/fixtures/complex_for_filtering.feature +60 -0
  38. data/spec/gherkin/fixtures/complex_with_tags.feature +61 -0
  39. data/spec/gherkin/fixtures/hantu_pisang.feature +35 -0
  40. data/spec/gherkin/formatter/filter_formatter_spec.rb +156 -0
  41. data/spec/gherkin/formatter/model_spec.rb +15 -0
  42. data/spec/gherkin/formatter/pretty_formatter_spec.rb +17 -16
  43. data/spec/gherkin/formatter/tag_count_formatter_spec.rb +31 -0
  44. data/spec/gherkin/i18n_lexer_spec.rb +3 -3
  45. data/spec/gherkin/i18n_spec.rb +2 -4
  46. data/spec/gherkin/{json_lexer_spec.rb → json_parser_spec.rb} +13 -8
  47. data/spec/gherkin/sexp_recorder.rb +10 -4
  48. data/spec/gherkin/shared/lexer_group.rb +0 -40
  49. data/spec/gherkin/shared/py_string_group.rb +0 -1
  50. data/spec/gherkin/shared/row_group.rb +1 -2
  51. data/spec/gherkin/tag_expression_spec.rb +137 -0
  52. data/spec/spec_helper.rb +5 -1
  53. data/tasks/bench.rake +5 -9
  54. metadata +35 -25
  55. data/lib/gherkin/parser/filter_listener.rb +0 -203
  56. data/lib/gherkin/parser/row.rb +0 -15
  57. data/lib/gherkin/parser/tag_expression.rb +0 -50
  58. data/spec/gherkin/parser/filter_listener_spec.rb +0 -397
  59. data/spec/gherkin/parser/formatter_listener_spec.rb +0 -134
  60. data/spec/gherkin/parser/parser_spec.rb +0 -50
  61. data/spec/gherkin/parser/tag_expression_spec.rb +0 -116
@@ -142,8 +142,7 @@ public class <%= @i18n.underscored_iso_code.upcase %> implements Lexer {
142
142
 
143
143
  %% write data noerror;
144
144
 
145
- public void scan(String source, String uri, int offset) {
146
- listener.location(uri, offset);
145
+ public void scan(String source) {
147
146
  String input = source + "\n%_FEATURE_END_%";
148
147
  byte[] data = null;
149
148
  try {
@@ -127,8 +127,7 @@ module Gherkin
127
127
  %% write data;
128
128
  end
129
129
 
130
- def scan(data, uri, offset)
131
- @listener.location(uri, offset)
130
+ def scan(data)
132
131
  data = (data + "\n%_FEATURE_END_%").unpack("c*") # Explicit EOF simplifies things considerably
133
132
  eof = pe = data.length
134
133
 
@@ -0,0 +1,60 @@
1
+ #Comment on line 1
2
+ #Comment on line 2
3
+ @tag1 @tag2
4
+ Feature: Feature Text
5
+ In order to test multiline forms
6
+ As a ragel writer
7
+ I need to check for complex combinations
8
+
9
+ #Comment on line 9
10
+ #Comment on line 11
11
+ Background:
12
+ Given this is a background step
13
+ And this is another one
14
+
15
+ @tag3 @tag4
16
+ Scenario: Reading a Scenario
17
+ Given there is a step
18
+ But not another step
19
+
20
+ @tag3
21
+ Scenario: Reading a second scenario
22
+ With two lines of text
23
+
24
+ #Comment on line 24
25
+ Given a third step with a table
26
+ | a | b |
27
+ | c | d |
28
+ | e | f |
29
+ And I am still testing things
30
+ And I am done testing these tables
31
+ #Comment on line 29
32
+ Then I am happy
33
+ | g | h |
34
+ | e | r |
35
+ | k | i |
36
+ | n | |
37
+
38
+ Scenario: Hammerzeit XX
39
+ Given All work and no play
40
+ Then crazy
41
+ """
42
+ Makes Homer something something
43
+ And something else
44
+ """
45
+
46
+ @more
47
+ Scenario Outline: More
48
+ Given Some <whaaa>
49
+
50
+ @neat
51
+ Examples: Neato XX
52
+ | whaa |
53
+ | neat |
54
+ | beat |
55
+
56
+ @hamster
57
+ Examples: Rodents
58
+ | whaa |
59
+ | hammy |
60
+ | mousy |
@@ -0,0 +1,61 @@
1
+ #Comment on line 1
2
+ #Comment on line 2
3
+ @tag1 @tag2
4
+ Feature: Feature Text
5
+ In order to test multiline forms
6
+ As a ragel writer
7
+ I need to check for complex combinations
8
+
9
+ #Comment on line 9
10
+
11
+ #Comment on line 11
12
+
13
+ Background:
14
+ Given this is a background step
15
+ And this is another one
16
+
17
+ @tag3 @tag4
18
+ Scenario: Reading a Scenario
19
+ Given there is a step
20
+ But not another step
21
+
22
+ @tag3
23
+ Scenario: Reading a second scenario
24
+ With two lines of text
25
+ #Comment on line 24
26
+ Given a third step with a table
27
+ |a|b|
28
+ |c|d|
29
+ |e|f|
30
+ And I am still testing things
31
+ |g|h|
32
+ |e|r|
33
+ |k|i|
34
+ |n||
35
+ And I am done testing these tables
36
+ #Comment on line 29
37
+ Then I am happy
38
+
39
+ Scenario: Hammerzeit
40
+ Given All work and no play
41
+ """
42
+ Makes Homer something something
43
+ And something else
44
+ """
45
+ Then crazy
46
+
47
+ @more
48
+ Scenario Outline: More
49
+ Given Some <whaaa>
50
+
51
+ @neat
52
+ Examples: Neato
53
+ |whaa|
54
+ |neat|
55
+ |beat|
56
+
57
+ @hamster
58
+ Examples: Rodents
59
+ |whaa|
60
+ |hammy|
61
+ |mousy|
@@ -0,0 +1,35 @@
1
+ Feature: search examples
2
+
3
+ Background: The background
4
+ Given passing without a table
5
+
6
+ Scenario: should match Hantu Pisang
7
+ Given passing without a table
8
+
9
+ Scenario: Ignore me
10
+ Given failing without a table
11
+
12
+ Scenario Outline: Ignore me
13
+ Given <state> without a table
14
+
15
+ Examples:
16
+ | state |
17
+ | 1111111 |
18
+
19
+ Scenario Outline: Hantu Pisang match
20
+ Given <state> without a table
21
+
22
+ Examples:
23
+ | state |
24
+ | 2222222 |
25
+
26
+ Scenario Outline: no match in name but in examples
27
+ Given <state> without a table
28
+
29
+ Examples: Hantu Pisang
30
+ | state |
31
+ | 3333333 |
32
+
33
+ Examples: Ignore me
34
+ | state |
35
+ | 4444444 |
@@ -0,0 +1,156 @@
1
+ # encoding: utf-8
2
+ require 'stringio'
3
+ require 'spec_helper'
4
+ require 'gherkin/i18n_lexer'
5
+ require 'gherkin/listener/formatter_listener'
6
+ require 'gherkin/formatter/filter_formatter'
7
+ require 'gherkin/formatter/pretty_formatter'
8
+
9
+ module Gherkin
10
+ module Formatter
11
+ describe FilterFormatter do
12
+ attr_accessor :file
13
+
14
+ before do
15
+ self.file = 'complex_for_filtering.feature'
16
+ end
17
+
18
+ def verify_filter(filters, *line_ranges)
19
+ io = StringIO.new
20
+ pretty_formatter = Gherkin::Formatter::PrettyFormatter.new(io, true)
21
+ filter_formatter = Gherkin::Formatter::FilterFormatter.new(pretty_formatter, filters)
22
+ parser = Gherkin::Parser::Parser.new(filter_formatter)
23
+
24
+ path = File.dirname(__FILE__) + "/../fixtures/" + file
25
+ source = File.new(path).read + "# __EOF__"
26
+ parser.parse(source, path, 0)
27
+
28
+ source_lines = source.split("\n")
29
+ expected = (line_ranges.map do |line_range|
30
+ source_lines[(line_range.first-1..line_range.last-1)]
31
+ end.flatten).join("\n").gsub(/# __EOF__/, '')
32
+ io.string.should == expected
33
+ end
34
+
35
+ context "tags" do
36
+ it "should filter on feature tag" do
37
+ verify_filter(['@tag1'], 1..61)
38
+ end
39
+
40
+ it "should filter on scenario tag" do
41
+ verify_filter(['@tag4'], 1..19)
42
+ end
43
+
44
+ it "should filter on abother scenario tag" do
45
+ verify_filter(['@tag3'], 1..37)
46
+ end
47
+
48
+ it "should filter on scenario outline tag" do
49
+ verify_filter(['@more'], 1..14, 46..61)
50
+ end
51
+
52
+ it "should filter on first examples tag" do
53
+ verify_filter(['@neat'], 1..14, 46..55)
54
+ end
55
+
56
+ it "should filter on second examples tag" do
57
+ verify_filter(['@hamster'], 1..14, 46..49, 56..61)
58
+ end
59
+ end
60
+
61
+ context "names" do
62
+ it "should filter on scenario name" do
63
+ verify_filter([/Reading a Scenario/], 1..19)
64
+ end
65
+
66
+ it "should filter on scenario outline name" do
67
+ verify_filter([/More/], 1..14, 46..61)
68
+ end
69
+
70
+ it "should filter on first examples name" do
71
+ verify_filter([/Neato/], 1..14, 46..55)
72
+ end
73
+
74
+ it "should filter on second examples name" do
75
+ verify_filter([/Rodents/], 1..14, 46..49, 56..61)
76
+ end
77
+
78
+ it "should filter on various names" do
79
+ self.file = 'hantu_pisang.feature'
80
+ verify_filter([/Pisang/], 1..8, 19..32)
81
+ end
82
+
83
+ it "should filter on background name" do
84
+ self.file = 'hantu_pisang.feature'
85
+ verify_filter([/The background/], 1..5)
86
+ end
87
+ end
88
+
89
+ context "lines" do
90
+ context "on the same line as feature element keyword" do
91
+ it "should filter on scenario line" do
92
+ verify_filter([16], 1..19)
93
+ end
94
+
95
+ it "should filter on scenario outline line" do
96
+ verify_filter([47], 1..14, 46..61)
97
+ end
98
+
99
+ it "should filter on first examples line" do
100
+ verify_filter([51], 1..14, 46..55)
101
+ end
102
+
103
+ it "should filter on second examples line" do
104
+ verify_filter([57], 1..14, 46..49, 56..61)
105
+ end
106
+ end
107
+
108
+ context "on the same line as step keyword" do
109
+ it "should filter on step line" do
110
+ verify_filter([17], 1..19)
111
+ end
112
+
113
+ it "should filter on scenario outline line" do
114
+ verify_filter([48], 1..14, 46..61)
115
+ end
116
+ end
117
+
118
+ context "on examples header line" do
119
+ it "should filter on first table" do
120
+ verify_filter([52], 1..14, 46..55)
121
+ end
122
+
123
+ it "should filter on second table" do
124
+ verify_filter([58], 1..14, 46..49, 56..61)
125
+ end
126
+ end
127
+
128
+ context "on examples example line" do
129
+ it "should filter on first table" do
130
+ verify_filter([53], 1..14, 46..53, 55..55)
131
+ end
132
+ end
133
+
134
+ context "on tag line" do
135
+ it "should filter on first tag" do
136
+ verify_filter([15], 1..19)
137
+ end
138
+ end
139
+
140
+ context "multiline argument" do
141
+ it "should filter on table line" do
142
+ verify_filter([36], 1..14, 20..37)
143
+ end
144
+
145
+ it "should filter on first pystring quote" do
146
+ verify_filter([41], 1..14, 38..45)
147
+ end
148
+
149
+ it "should filter on last pystring quote" do
150
+ verify_filter([44], 1..14, 38..45)
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ require 'gherkin/formatter/model'
3
+
4
+ module Gherkin
5
+ module Formatter
6
+ module Model
7
+ describe Tag do
8
+ it "should be equal when name is equal" do
9
+ tags = [Tag.new('@x', 1), Tag.new('@y', 2), Tag.new('@x', 3)]
10
+ tags.uniq.length.should == 2
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -2,8 +2,8 @@
2
2
  require 'spec_helper'
3
3
  require 'gherkin/formatter/pretty_formatter'
4
4
  require 'gherkin/formatter/argument'
5
- require 'gherkin/parser/formatter_listener'
6
- require 'gherkin/parser/row'
5
+ require 'gherkin/formatter/model'
6
+ require 'gherkin/listener/formatter_listener'
7
7
  require 'stringio'
8
8
 
9
9
  module Gherkin
@@ -18,29 +18,31 @@ module Gherkin
18
18
  [true, false].each do |force_ruby|
19
19
  io = StringIO.new
20
20
  pf = Gherkin::Formatter::PrettyFormatter.new(io, true)
21
- l = Gherkin::Parser::FormatterListener.new(pf)
22
- parser = Gherkin::Parser::Parser.new(l, true, "root")
23
- lexer = Gherkin::I18nLexer.new(parser, force_ruby)
24
- lexer.scan(input, "test.feature", 0)
21
+ parser = Gherkin::Parser::Parser.new(pf, true, "root", force_ruby)
22
+ parser.parse(input, "test.feature", 0)
25
23
  actual = io.string
26
24
  actual.should == output
27
25
  end
28
26
  end
29
27
 
28
+ def result(status, error_message, arguments, stepdef_location)
29
+ Model::Result.new(status, error_message, arguments, stepdef_location)
30
+ end
31
+
30
32
  before do
31
33
  @io = StringIO.new
32
34
  @l = Gherkin::Formatter::PrettyFormatter.new(@io, true)
33
35
  end
34
36
 
35
37
  it "should print comments when scenario is longer" do
36
- @l.feature([], [], "Feature", "Hello", "World", "features/foo.feature")
38
+ @l.feature(Model::Statement.new([], [], "Feature", "Hello", "World", 1), "features/foo.feature")
37
39
  @l.steps([
38
40
  ['Given ', 'some stuff'],
39
41
  ['When ', 'foo']
40
42
  ])
41
- @l.scenario([], [], "Scenario", "The scenario", "", 4)
42
- @l.step([], "Given ", "some stuff", 5, nil, nil, nil, nil, "features/step_definitions/bar.rb:56")
43
- @l.step([], "When ", "foo", 6, nil, nil, nil, nil, "features/step_definitions/bar.rb:96")
43
+ @l.scenario(Model::Statement.new([], [], "Scenario", "The scenario", "", 4))
44
+ @l.step(Model::Statement.new([], [], "Given ", "some stuff", "", 5), nil, result('passed', nil, nil, "features/step_definitions/bar.rb:56"))
45
+ @l.step(Model::Statement.new([], [], "When ", "foo", "", 6), nil, result('passed', nil, nil, "features/step_definitions/bar.rb:96"))
44
46
 
45
47
  assert_io(%{Feature: Hello
46
48
  World
@@ -52,12 +54,12 @@ module Gherkin
52
54
  end
53
55
 
54
56
  it "should print comments when step is longer" do
55
- @l.feature([], [], "Feature", "Hello", "World", "features/foo.feature")
57
+ @l.feature(Model::Statement.new([], [], "Feature", "Hello", "World", 1), "features/foo.feature")
56
58
  @l.steps([
57
59
  ['Given ', 'some stuff that is longer']
58
60
  ])
59
- @l.scenario([], [], "Scenario", "The scenario", "", 4)
60
- @l.step([], "Given ", "some stuff that is longer", 5, nil, nil, nil, nil, "features/step_definitions/bar.rb:56")
61
+ @l.scenario(Model::Statement.new([], [], "Scenario", "The scenario", "", 4))
62
+ @l.step(Model::Statement.new([], [], "Given ", "some stuff that is longer", "", 5), nil, result('passed', nil, nil, "features/step_definitions/bar.rb:56"))
61
63
 
62
64
  assert_io(%{Feature: Hello
63
65
  World
@@ -68,8 +70,7 @@ module Gherkin
68
70
  end
69
71
 
70
72
  it "should highlight arguments for regular steps" do
71
- passed = defined?(JRUBY_VERSION) ? 'passed' : :passed
72
- @l.step([], "Given ", "I have 999 cukes in my belly", 3, nil, passed, nil, [Gherkin::Formatter::Argument.new(7, '999')], nil)
73
+ @l.step(Model::Statement.new([], [], "Given ", "I have 999 cukes in my belly", "", 3), nil, result('passed', nil, [Gherkin::Formatter::Argument.new(7, '999')], nil))
73
74
  assert_io(" Given I have 999 cukes in my belly\n")
74
75
  end
75
76
 
@@ -128,7 +129,7 @@ Feature: Feature Description
128
129
  it "should escape backslashes and pipes" do
129
130
  io = StringIO.new
130
131
  l = Gherkin::Formatter::PrettyFormatter.new(io, true)
131
- l.__send__(:table, [Gherkin::Parser::Row.new(['|', '\\'], [], nil)])
132
+ l.__send__(:table, [Gherkin::Formatter::Model::Row.new([], ['|', '\\'], nil)])
132
133
  io.string.should == ' | \\| | \\\\ |' + "\n"
133
134
  end
134
135
  end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'gherkin/i18n_lexer'
4
+ require 'gherkin/listener/formatter_listener'
5
+ require 'gherkin/formatter/tag_count_formatter'
6
+
7
+ module Gherkin
8
+ module Formatter
9
+ describe TagCountFormatter do
10
+ it "should count tags" do
11
+ tag_counts = {}
12
+ dummy = Gherkin::SexpRecorder.new
13
+ formatter = Gherkin::Formatter::TagCountFormatter.new(dummy, tag_counts)
14
+ parser = Gherkin::Parser::Parser.new(formatter)
15
+
16
+ f = File.new(File.dirname(__FILE__) + "/../fixtures/complex_with_tags.feature").read
17
+ parser.parse(f, 'f.feature', 0)
18
+
19
+ tag_counts.should == {
20
+ "@hamster" => ["f.feature:58"],
21
+ "@tag1" => ["f.feature:18","f.feature:23","f.feature:39","f.feature:52","f.feature:58"],
22
+ "@tag2" => ["f.feature:18","f.feature:23","f.feature:39","f.feature:52","f.feature:58"],
23
+ "@tag3" => ["f.feature:18", "f.feature:23"],
24
+ "@tag4" => ["f.feature:18"],
25
+ "@neat" => ["f.feature:52"],
26
+ "@more" => ["f.feature:52", "f.feature:58"]
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end