gherkin 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/.gitattributes +1 -0
  2. data/History.txt +18 -0
  3. data/README.rdoc +4 -1
  4. data/Rakefile +4 -2
  5. data/VERSION.yml +1 -1
  6. data/bin/gherkin +1 -1
  7. data/dotnet/.gitignore +13 -0
  8. data/features/feature_parser.feature +22 -2
  9. data/features/native_lexer.feature +1 -1
  10. data/features/parser_with_native_lexer.feature +1 -1
  11. data/features/step_definitions/gherkin_steps.rb +2 -6
  12. data/features/step_definitions/pretty_printer_steps.rb +2 -3
  13. data/features/steps_parser.feature +1 -1
  14. data/gherkin.gemspec +53 -24
  15. data/java/Gherkin.iml +2 -4
  16. data/java/build.xml +3 -0
  17. data/java/src/gherkin/FixJava.java +6 -3
  18. data/java/src/gherkin/I18nLexer.java +48 -0
  19. data/java/src/gherkin/Listener.java +3 -1
  20. data/java/src/gherkin/Main.java +17 -0
  21. data/java/src/gherkin/Parser.java +9 -3
  22. data/java/src/gherkin/formatter/Argument.java +39 -0
  23. data/java/src/gherkin/formatter/ArgumentFormat.java +17 -0
  24. data/java/src/gherkin/formatter/Colors.java +7 -0
  25. data/java/src/gherkin/formatter/Formatter.java +15 -0
  26. data/java/src/gherkin/formatter/PrettyFormatter.java +219 -0
  27. data/java/src/gherkin/parser/StateMachineReader.java +8 -3
  28. data/java/test/gherkin/formatter/ArgumentTest.java +17 -0
  29. data/lib/gherkin/csharp_lexer.rb +15 -0
  30. data/lib/gherkin/format/argument.rb +35 -0
  31. data/lib/gherkin/format/monochrome_format.rb +9 -0
  32. data/lib/gherkin/i18n.rb +22 -0
  33. data/lib/gherkin/i18n.yml +34 -20
  34. data/lib/gherkin/i18n_lexer.rb +57 -13
  35. data/lib/gherkin/lexer.rb +9 -18
  36. data/lib/gherkin/parser.rb +3 -3
  37. data/lib/gherkin/parser/meta.txt +5 -4
  38. data/lib/gherkin/parser/root.txt +11 -9
  39. data/lib/gherkin/parser/steps.txt +4 -3
  40. data/lib/gherkin/rb_parser.rb +13 -5
  41. data/lib/gherkin/tools/colors.rb +119 -0
  42. data/lib/gherkin/tools/files.rb +6 -1
  43. data/lib/gherkin/tools/pretty_listener.rb +115 -23
  44. data/ragel/lexer.c.rl.erb +67 -51
  45. data/ragel/lexer.csharp.rl.erb +240 -0
  46. data/ragel/lexer.java.rl.erb +27 -18
  47. data/ragel/lexer.rb.rl.erb +17 -17
  48. data/ragel/lexer_common.rl.erb +8 -8
  49. data/spec/gherkin/c_lexer_spec.rb +4 -4
  50. data/spec/gherkin/csharp_lexer_spec.rb +20 -0
  51. data/spec/gherkin/fixtures/comments_in_table.feature +9 -0
  52. data/spec/gherkin/fixtures/complex.feature +2 -0
  53. data/spec/gherkin/fixtures/dos_line_endings.feature +45 -0
  54. data/spec/gherkin/fixtures/i18n_fr.feature +1 -0
  55. data/spec/gherkin/fixtures/i18n_no.feature +1 -0
  56. data/spec/gherkin/fixtures/i18n_zh-CN.feature +1 -0
  57. data/spec/gherkin/format/argument_spec.rb +28 -0
  58. data/spec/gherkin/i18n_lexer_spec.rb +4 -4
  59. data/spec/gherkin/i18n_spec.rb +31 -23
  60. data/spec/gherkin/java_lexer_spec.rb +4 -3
  61. data/spec/gherkin/parser_spec.rb +5 -0
  62. data/spec/gherkin/rb_lexer_spec.rb +4 -2
  63. data/spec/gherkin/sexp_recorder.rb +1 -1
  64. data/spec/gherkin/shared/lexer_spec.rb +169 -60
  65. data/spec/gherkin/shared/py_string_spec.rb +6 -0
  66. data/spec/gherkin/shared/row_spec.rb +107 -0
  67. data/spec/gherkin/shared/tags_spec.rb +1 -1
  68. data/spec/gherkin/tools/colors_spec.rb +19 -0
  69. data/spec/gherkin/tools/pretty_listener_spec.rb +147 -0
  70. data/spec/spec_helper.rb +31 -7
  71. data/tasks/compile.rake +81 -7
  72. data/tasks/ragel_task.rb +6 -4
  73. data/tasks/rspec.rake +2 -2
  74. metadata +104 -41
  75. data/lib/gherkin/java_lexer.rb +0 -10
  76. data/spec/gherkin/shared/table_spec.rb +0 -97
@@ -50,6 +50,7 @@ EOS
50
50
  @lexer.scan ps("A\n\nB")
51
51
  @listener.to_sexp.should == [
52
52
  [:py_string, "A\n\nB", 1],
53
+ [:eof]
53
54
  ]
54
55
  end
55
56
 
@@ -119,6 +120,11 @@ EOS
119
120
  @listener.should_receive(:py_string).with("PyString text\n\n",1)
120
121
  @lexer.scan(str)
121
122
  end
123
+
124
+ it "should preserve CRLFs within py_strings" do
125
+ @listener.should_receive(:py_string).with("Line one\r\nLine two\r\n", 1)
126
+ @lexer.scan("\"\"\"\r\nLine one\r\nLine two\r\n\r\n\"\"\"")
127
+ end
122
128
  end
123
129
  end
124
130
  end
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
3
+
4
+ module Gherkin
5
+ module Lexer
6
+ shared_examples_for "a Gherkin lexer lexing rows" do
7
+ rows = {
8
+ "|a|b|\n" => %w{a b},
9
+ "|a|b|c|\n" => %w{a b c},
10
+ }
11
+
12
+ rows.each do |text, expected|
13
+ it "should parse #{text}" do
14
+ @listener.should_receive(:row).with(r(expected), 1)
15
+ @lexer.scan(text.dup)
16
+ end
17
+ end
18
+
19
+ it "should parse a row with many cells" do
20
+ @listener.should_receive(:row).with(r(%w{a b c d e f g h i j k l m n o p}), 1)
21
+ @lexer.scan("|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|\n")
22
+ end
23
+
24
+ it "should parse multicharacter cell content" do
25
+ @listener.should_receive(:row).with(r(%w{foo bar}), 1)
26
+ @lexer.scan("| foo | bar |\n")
27
+ end
28
+
29
+ it "should parse cells with spaces within the content" do
30
+ @listener.should_receive(:row).with(r(["Dill pickle", "Valencia orange"]), 1)
31
+ @lexer.scan("| Dill pickle | Valencia orange |\n")
32
+ end
33
+
34
+ it "should allow utf-8" do
35
+ # Fails in 1.9.1!
36
+ # 'Gherkin::Lexer::Table should allow utf-8 with using == to evaluate' FAILED
37
+ # expected: [[:row, [["ůﻚ", "2"]], 1]],
38
+ # got: [[:row, [["\xC5\xAF\xEF\xBB\x9A", "2"]], 1]] (using ==)
39
+ # BUT, simply running:
40
+ # [[:row, [["ůﻚ", "2"]], 1]].should == [[:row, [["\xC5\xAF\xEF\xBB\x9A", "2"]], 1]]
41
+ # passes
42
+ #
43
+ @lexer.scan(" | ůﻚ | 2 | \n")
44
+ @listener.to_sexp.should == [
45
+ [:row, ["ůﻚ", "2"], 1],
46
+ [:eof]
47
+ ]
48
+ end
49
+
50
+ it "should allow utf-8 using should_receive" do
51
+ @listener.should_receive(:row).with(r(['繁體中文 而且','並且','繁體中文 而且','並且']), 1)
52
+ @lexer.scan("| 繁體中文 而且|並且| 繁體中文 而且|並且|\n")
53
+ end
54
+
55
+ it "should parse a 2x2 table" do
56
+ @listener.should_receive(:row).with(r(%w{1 2}), 1)
57
+ @listener.should_receive(:row).with(r(%w{3 4}), 2)
58
+ @lexer.scan("| 1 | 2 |\n| 3 | 4 |\n")
59
+ end
60
+
61
+ it "should parse a 2x2 table with empty cells" do
62
+ @listener.should_receive(:row).with(r(['1', '']), 1)
63
+ @listener.should_receive(:row).with(r(['', '4']), 2)
64
+ @lexer.scan("| 1 | |\n|| 4 |\n")
65
+ end
66
+
67
+ it "should parse a row with empty cells" do
68
+ @listener.should_receive(:row).with(r(['1', '']), 1).twice
69
+ @lexer.scan("| 1 | |\n")
70
+ @lexer.scan("|1||\n")
71
+ end
72
+
73
+ it "should parse a 1x2 table that does not end in a newline" do
74
+ @listener.should_receive(:row).with(r(%w{1 2}), 1)
75
+ @lexer.scan("| 1 | 2 |")
76
+ end
77
+
78
+ it "should parse a row without spaces and with a newline" do
79
+ @listener.should_receive(:row).with(r(%w{1 2}), 1)
80
+ @lexer.scan("|1|2|\n")
81
+ end
82
+
83
+ it "should parse a row with whitespace after the rows" do
84
+ @listener.should_receive(:row).with(r(%w{1 2}), 1)
85
+ @lexer.scan("| 1 | 2 | \n ")
86
+ end
87
+
88
+ it "should parse a row with lots of whitespace" do
89
+ @listener.should_receive(:row).with(r(["abc", "123"]), 1)
90
+ @lexer.scan(" \t| \t abc\t| \t123\t \t\t| \t\t \t \t\n ")
91
+ end
92
+
93
+ it "should parse a table with a commented-out row" do
94
+ @listener.should_receive(:row).with(r(["abc"]), 1)
95
+ @listener.should_receive(:comment).with("#|123|", 2)
96
+ @listener.should_receive(:row).with(r(["def"]), 3)
97
+ @lexer.scan("|abc|\n#|123|\n|def|\n")
98
+ end
99
+
100
+ it "should raise LexingError for rows that aren't closed" do
101
+ lambda {
102
+ @lexer.scan("|| oh hello \n")
103
+ }.should raise_error(/Parsing error on line 1: '|| oh hello/)
104
+ end
105
+ end
106
+ end
107
+ end
@@ -1,4 +1,4 @@
1
- #encoding: utf-8
1
+ # encoding: utf-8
2
2
  require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
3
3
 
4
4
  module Gherkin
@@ -0,0 +1,19 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'gherkin/tools/pretty_listener'
3
+
4
+
5
+ module Gherkin
6
+ module Tools
7
+ describe Colors do
8
+ include Colors
9
+
10
+ it "should colour stuff red" do
11
+ failed("hello").should == "\e[31mhello\e[0m"
12
+ end
13
+
14
+ it "should be possible to specify no colouring" do
15
+ failed("hello", true).should == "hello"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,147 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
3
+ require 'gherkin/tools/pretty_listener'
4
+ require 'gherkin/format/argument'
5
+ require 'stringio'
6
+
7
+ module Gherkin
8
+ module Tools
9
+ describe PrettyListener do
10
+ def assert_io(s)
11
+ @io.rewind
12
+ actual = @io.read
13
+ actual.should == s
14
+ end
15
+
16
+ def assert_pretty(text)
17
+ io = StringIO.new
18
+ l = PrettyListener.new(io, true)
19
+ parser = Gherkin::Parser.new(l, true, "root")
20
+ lexer = Gherkin::I18nLexer.new(parser, true)
21
+ lexer.scan(text)
22
+ io.rewind
23
+ actual = io.read
24
+ actual.should == text
25
+ end
26
+
27
+ before do
28
+ @io = StringIO.new
29
+ @l = PrettyListener.new(@io, true)
30
+ end
31
+
32
+ it "should print comments when scenario is longer" do
33
+ @l.feature("Feature", "Hello\nWorld", 1)
34
+ @l.steps([
35
+ ['Given ', 'some stuff'],
36
+ ['When ', 'foo']
37
+ ])
38
+ @l.scenario("Scenario", "The scenario", 4, "features/foo.feature:4")
39
+ @l.step("Given ", "some stuff", 5, nil, nil, "features/step_definitions/bar.rb:56")
40
+ @l.step("When ", "foo", 6, nil, nil, "features/step_definitions/bar.rb:96")
41
+
42
+ assert_io(%{Feature: Hello
43
+ World
44
+
45
+ Scenario: The scenario # features/foo.feature:4
46
+ Given some stuff # features/step_definitions/bar.rb:56
47
+ When foo # features/step_definitions/bar.rb:96
48
+ })
49
+ end
50
+
51
+ it "should print comments when step is longer" do
52
+ @l.feature("Feature", "Hello\nWorld", 1)
53
+ @l.steps([
54
+ ['Given ', 'some stuff that is longer']
55
+ ])
56
+ @l.scenario("Scenario", "The scenario", 4, "features/foo.feature:4")
57
+ @l.step("Given ", "some stuff that is longer", 5, nil, nil, "features/step_definitions/bar.rb:56")
58
+
59
+ assert_io(%{Feature: Hello
60
+ World
61
+
62
+ Scenario: The scenario # features/foo.feature:4
63
+ Given some stuff that is longer # features/step_definitions/bar.rb:56
64
+ })
65
+ end
66
+
67
+ it "should print ANSI coloured steps" do
68
+ @l.feature("Feature", "Hello\nWorld", 1)
69
+ @l.steps([
70
+ ['Given ', 'some stuff that is longer']
71
+ ])
72
+ @l.scenario("Scenario", "The scenario", 4, "features/foo.feature:4")
73
+ @l.step("Given ", "some stuff that is longer", 5, nil, nil, "features/step_definitions/bar.rb:56")
74
+
75
+ assert_io(%{Feature: Hello
76
+ World
77
+
78
+ Scenario: The scenario # features/foo.feature:4
79
+ Given some stuff that is longer # features/step_definitions/bar.rb:56
80
+ })
81
+ end
82
+
83
+ it "should prettify a whole table with padding (typically ANSI)" do
84
+ @l.row(%w(a bb), 1)
85
+ @l.row(%w(ccc d), 2)
86
+ @l.row(%w(ee ffff), 3)
87
+ @l.flush_table
88
+
89
+ assert_io(
90
+ " | a | bb |\n" +
91
+ " | ccc | d |\n" +
92
+ " | ee | ffff |\n"
93
+ )
94
+ end
95
+
96
+ it "should highlight arguments for regular steps" do
97
+ passed = defined?(JRUBY_VERSION) ? 'passed' : :passed
98
+ @l.step("Given ", "I have 999 cukes in my belly", 3, passed, [Gherkin::Format::Argument.new(7, '999')], nil)
99
+ assert_io(" Given I have 999 cukes in my belly\n")
100
+ end
101
+
102
+ it "should prettify scenario" do
103
+ assert_pretty(%{Feature: Feature Description
104
+ Some preamble
105
+
106
+ Scenario: Scenario Description
107
+ Given there is a step
108
+ """
109
+ with
110
+ pystrings
111
+ """
112
+ And there is another step
113
+ | æ | o |
114
+ | a | ø |
115
+ Then we will see steps
116
+ })
117
+ end
118
+
119
+
120
+ it "should prettify scenario outline with table" do
121
+ assert_pretty(%{# A feature comment
122
+ @foo
123
+ Feature: Feature Description
124
+ Some preamble
125
+
126
+ # A Scenario Outline comment
127
+ @bar
128
+ Scenario Outline: Scenario Ouline Description
129
+ Given there is a
130
+ """
131
+ string with <foo>
132
+ """
133
+ And a table with
134
+ | <bar> |
135
+ | <baz> |
136
+
137
+ @zap @boing
138
+ Examples: Examples Description
139
+ | foo | bar | baz |
140
+ | Banana | I | am hungry |
141
+ | Beer | You | are thirsty |
142
+ | Bed | They | are tired |
143
+ })
144
+ end
145
+ end
146
+ end
147
+ end
@@ -2,6 +2,7 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'spec/gherkin'))
4
4
  require 'gherkin'
5
+ require 'stringio'
5
6
  require 'gherkin/sexp_recorder'
6
7
  require 'rubygems'
7
8
  require 'spec'
@@ -9,7 +10,30 @@ require 'spec/autorun'
9
10
  require 'shared/lexer_spec'
10
11
  require 'shared/tags_spec'
11
12
  require 'shared/py_string_spec'
12
- require 'shared/table_spec'
13
+ require 'shared/row_spec'
14
+
15
+ if defined?(JRUBY_VERSION)
16
+ class OutputStreamStringIO < java.io.ByteArrayOutputStream
17
+ def rewind
18
+ end
19
+
20
+ def read
21
+ toString("UTF-8")
22
+ end
23
+ end
24
+ end
25
+
26
+ class StringIO
27
+ class << self
28
+ def new
29
+ if defined?(JRUBY_VERSION)
30
+ OutputStreamStringIO.new
31
+ else
32
+ super
33
+ end
34
+ end
35
+ end
36
+ end
13
37
 
14
38
  module GherkinSpecHelper
15
39
  def scan_file(file)
@@ -21,13 +45,13 @@ Spec::Runner.configure do |c|
21
45
  c.include(GherkinSpecHelper)
22
46
  end
23
47
 
24
- # Allows comparison of Java List with Ruby Array (tables)
25
- Spec::Matchers.define :t do |expected|
26
- match do |table|
27
- def table.inspect
28
- "t " + self.map{|row| row.map{|cell| cell}}.inspect
48
+ # Allows comparison of Java List with Ruby Array (rows)
49
+ Spec::Matchers.define :r do |expected|
50
+ match do |row|
51
+ def row.inspect
52
+ "r " + self.map{|cell| cell}.inspect
29
53
  end
30
- table.map{|row| row.map{|cell| cell}}.should == expected
54
+ row.map{|cell| cell}.should == expected
31
55
  end
32
56
  end
33
57
 
@@ -8,7 +8,10 @@ CLEAN.include [
8
8
  'ragel/i18n/*.rl',
9
9
  'lib/gherkin/rb_lexer/*.rb',
10
10
  'ext/**/*.c',
11
- 'java/src/gherkin/lexer/*.java'
11
+ 'java/src/gherkin/lexer/*.java',
12
+ 'dotnet/Gherkin/Lexer',
13
+ 'dotnet/Gherkin/obj',
14
+ 'dotnet/Gherkin/bin'
12
15
  ]
13
16
 
14
17
  desc "Compile the Java extensions"
@@ -16,12 +19,83 @@ task :jar do
16
19
  sh("ant -f java/build.xml")
17
20
  end
18
21
 
19
- Gherkin::I18n.all.each do |i18n|
20
- java = RagelTask.new('java', i18n)
21
- rb = RagelTask.new('rb', i18n)
22
+ namespace :dotnet do
23
+ require 'albacore'
22
24
 
23
- task :jar => java.target
24
- task :jar => rb.target
25
+ FileList['lib/gherkin/parser/*'].each do |src|
26
+ dst = "dotnet/Gherkin/StateMachine/#{File.basename(src)}"
27
+ file dst => src do
28
+ cp src, dst, :verbose => true
29
+ end
30
+ task :compile => dst
31
+ end
32
+
33
+ task :compile => :lexer
34
+
35
+ if (`which mono` rescue "") =~ /mono/
36
+ xbuild :compile do |msb|
37
+ msb.properties :configuration => :Release
38
+ msb.targets :Build
39
+ msb.solution = 'dotnet/Gherkin.sln'
40
+ end
41
+
42
+ require 'rake/xunittask'
43
+ class XUnitTestRunner
44
+ def execute
45
+ system("mono dotnet/lib/xunit/xunit.console.exe dotnet/Gherkin.Tests/bin/Release/Gherkin.Tests.dll")
46
+ exit 1 if $? != 0
47
+ end
48
+ end
49
+ else
50
+ msbuild :compile do |msb|
51
+ msb.properties :configuration => :Release
52
+ msb.targets :Build
53
+ msb.solution = 'dotnet/Gherkin.sln'
54
+ end
55
+ end
56
+
57
+ xunit :test => :compile do |xunit|
58
+ xunit.path_to_command = "dotnet/lib/xunit/xunit.console.exe"
59
+ xunit.assembly = "dotnet/Gherkin.Tests/bin/Release/Gherkin.Tests.dll"
60
+ end
61
+
62
+ task :package => :test do
63
+ cp 'dotnet/Gherkin/bin/Release/Gherkin.dll', 'lib/Gherkin.dll'
64
+ end
65
+ end
66
+
67
+ desc "Compile and package the .NET extensions"
68
+ task :dotnet => ['dotnet:package']
69
+
70
+ class CSharpSByteFixTask
71
+ def initialize(source)
72
+ @source = source
73
+ define_tasks
74
+ end
75
+
76
+ def define_tasks
77
+ directory File.dirname(target)
78
+ file target => [File.dirname(target), @source] do
79
+ sh "cat #{@source} | sed ""s/sbyte/short/g"" > #{target}"
80
+ end
81
+ end
82
+
83
+ def target
84
+ "dotnet/Gherkin/Lexer/#{File.basename(@source)}"
85
+ end
86
+ end
87
+
88
+ rl_langs = ENV['RL_LANGS'] ? ENV['RL_LANGS'].split(',') : []
89
+ langs = Gherkin::I18n.all.select { |lang| rl_langs.empty? || rl_langs.include?(lang.key) }
90
+
91
+ langs.each do |i18n|
92
+ java = RagelTask.new('java', i18n)
93
+ rb = RagelTask.new('rb', i18n)
94
+ csharp_tmp = RagelTask.new('csharp', i18n)
95
+ csharp = CSharpSByteFixTask.new(csharp_tmp.target)
96
+
97
+ task :jar => [java.target, rb.target]
98
+ task 'dotnet:lexer' => csharp.target
25
99
 
26
100
  begin
27
101
  unless defined?(JRUBY_VERSION)
@@ -67,4 +141,4 @@ EOF
67
141
  task :compile # no-op
68
142
  end
69
143
  end
70
- end
144
+ end