cucumber-core 0.1.0

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.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.rspec +1 -0
  4. data/.ruby-gemset +1 -0
  5. data/.travis.yml +16 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE +20 -0
  8. data/README.md +9 -0
  9. data/Rakefile +24 -0
  10. data/cucumber-core.gemspec +32 -0
  11. data/lib/cucumber/core.rb +37 -0
  12. data/lib/cucumber/core/ast.rb +13 -0
  13. data/lib/cucumber/core/ast/background.rb +33 -0
  14. data/lib/cucumber/core/ast/comment.rb +17 -0
  15. data/lib/cucumber/core/ast/data_table.rb +326 -0
  16. data/lib/cucumber/core/ast/describes_itself.rb +16 -0
  17. data/lib/cucumber/core/ast/doc_string.rb +83 -0
  18. data/lib/cucumber/core/ast/empty_background.rb +12 -0
  19. data/lib/cucumber/core/ast/examples_table.rb +95 -0
  20. data/lib/cucumber/core/ast/feature.rb +62 -0
  21. data/lib/cucumber/core/ast/location.rb +140 -0
  22. data/lib/cucumber/core/ast/multiline_argument.rb +33 -0
  23. data/lib/cucumber/core/ast/names.rb +19 -0
  24. data/lib/cucumber/core/ast/outline_step.rb +51 -0
  25. data/lib/cucumber/core/ast/scenario.rb +43 -0
  26. data/lib/cucumber/core/ast/scenario_outline.rb +44 -0
  27. data/lib/cucumber/core/ast/step.rb +38 -0
  28. data/lib/cucumber/core/ast/tag.rb +14 -0
  29. data/lib/cucumber/core/compiler.rb +136 -0
  30. data/lib/cucumber/core/gherkin/ast_builder.rb +315 -0
  31. data/lib/cucumber/core/gherkin/document.rb +20 -0
  32. data/lib/cucumber/core/gherkin/parser.rb +45 -0
  33. data/lib/cucumber/core/gherkin/writer.rb +220 -0
  34. data/lib/cucumber/core/gherkin/writer/helpers.rb +178 -0
  35. data/lib/cucumber/core/platform.rb +30 -0
  36. data/lib/cucumber/core/test/case.rb +143 -0
  37. data/lib/cucumber/core/test/filters.rb +48 -0
  38. data/lib/cucumber/core/test/filters/tag_filter.rb +110 -0
  39. data/lib/cucumber/core/test/hook_compiler.rb +109 -0
  40. data/lib/cucumber/core/test/mapper.rb +56 -0
  41. data/lib/cucumber/core/test/mapping.rb +67 -0
  42. data/lib/cucumber/core/test/result.rb +191 -0
  43. data/lib/cucumber/core/test/runner.rb +149 -0
  44. data/lib/cucumber/core/test/step.rb +69 -0
  45. data/lib/cucumber/core/test/timer.rb +31 -0
  46. data/lib/cucumber/core/version.rb +9 -0
  47. data/lib/cucumber/initializer.rb +18 -0
  48. data/spec/capture_warnings.rb +68 -0
  49. data/spec/coverage.rb +10 -0
  50. data/spec/cucumber/core/ast/data_table_spec.rb +139 -0
  51. data/spec/cucumber/core/ast/doc_string_spec.rb +77 -0
  52. data/spec/cucumber/core/ast/examples_table_spec.rb +87 -0
  53. data/spec/cucumber/core/ast/location_spec.rb +105 -0
  54. data/spec/cucumber/core/ast/outline_step_spec.rb +77 -0
  55. data/spec/cucumber/core/ast/step_spec.rb +44 -0
  56. data/spec/cucumber/core/compiler_spec.rb +249 -0
  57. data/spec/cucumber/core/gherkin/parser_spec.rb +182 -0
  58. data/spec/cucumber/core/gherkin/writer_spec.rb +332 -0
  59. data/spec/cucumber/core/test/case_spec.rb +416 -0
  60. data/spec/cucumber/core/test/hook_compiler_spec.rb +78 -0
  61. data/spec/cucumber/core/test/mapper_spec.rb +68 -0
  62. data/spec/cucumber/core/test/mapping_spec.rb +103 -0
  63. data/spec/cucumber/core/test/result_spec.rb +178 -0
  64. data/spec/cucumber/core/test/runner_spec.rb +265 -0
  65. data/spec/cucumber/core/test/step_spec.rb +58 -0
  66. data/spec/cucumber/core/test/timer_spec.rb +13 -0
  67. data/spec/cucumber/core_spec.rb +419 -0
  68. data/spec/cucumber/initializer_spec.rb +49 -0
  69. metadata +221 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ea9227a0b067303f1aa77c9f4f05e75a73a74da6
4
+ data.tar.gz: 5ec7e76b3ec7fe9e093e5091a0e7e80156153aea
5
+ SHA512:
6
+ metadata.gz: 9b8b2ce54523d97a6107b334342578af32f865281ceccb891f035cd55d0df119f267f510713e3e893ed6cb4a6be4af278648f22f3c77364ec0cc5d7e4ab15635
7
+ data.tar.gz: faae23fd3346d6957260ea77836ec6162e15d562017723d6328e5f386eecc3c4628fbe54513d579febcf97118303ece2d2ef9de505f5cab2752a897683c62b9a
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1 @@
1
+ cucumber
@@ -0,0 +1,16 @@
1
+ rvm:
2
+ - 2.1.0
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - jruby
6
+
7
+ # whitelist
8
+ branches:
9
+ only:
10
+ - master
11
+
12
+ notifications:
13
+ email:
14
+ - cukes-devs@googlegroups.com
15
+ irc:
16
+ - "irc.freenode.org#cucumber"
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (C) 2013 The Cucumber Organisation
2
+
3
+ MIT License (Expat)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ 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, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,9 @@
1
+ cucumber-ruby-core
2
+ ==================
3
+
4
+ [![Build Status](https://secure.travis-ci.org/cucumber/cucumber-ruby-core.png)](http://travis-ci.org/cucumber/cucumber-ruby-core)
5
+ [![Code
6
+ Climate](https://codeclimate.com/github/cucumber/cucumber-ruby-core.png)](https://codeclimate.com/github/cucumber/cucumber-ruby-core)
7
+ [![Coverage Status](https://coveralls.io/repos/cucumber/cucumber-ruby-core/badge.png?branch=master)](https://coveralls.io/r/cucumber/cucumber-ruby-core?branch=master)
8
+
9
+ Core library for the Ruby flavour of Cucumber
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ $:.unshift File.expand_path("../lib", __FILE__)
7
+
8
+ require "rspec/core/rake_task"
9
+ RSpec::Core::RakeTask.new(:spec) do |t|
10
+ t.ruby_opts = %w[-r./spec/coverage -w]
11
+ t.rspec_opts = %w[--color]
12
+ end
13
+
14
+ require_relative 'spec/capture_warnings'
15
+ include CaptureWarnings
16
+ namespace :spec do
17
+ task :warnings do
18
+ report_warnings do
19
+ Rake::Task['spec'].invoke
20
+ end
21
+ end
22
+ end
23
+
24
+ task default: ['spec:warnings']
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
3
+ require "cucumber/core/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'cucumber-core'
7
+ s.version = Cucumber::Core::Version
8
+ s.authors = ["Aslak Hellesøy", "Matt Wynne", "Steve Tooke", "Oleg Sukhodolsky", "Tom Brand"]
9
+ s.description = 'Core library for the Cucumber BDD app'
10
+ s.summary = "cucumber-core-#{s.version}"
11
+ s.email = 'cukes@googlegroups.com'
12
+ s.homepage = "http://cukes.info"
13
+ s.platform = Gem::Platform::RUBY
14
+ s.license = "MIT"
15
+ s.required_ruby_version = ">= 1.9.3"
16
+
17
+ s.add_dependency 'gherkin', '~> 2.12.0'
18
+
19
+ s.add_development_dependency 'bundler', '>= 1.3.5'
20
+ s.add_development_dependency 'rake', '>= 0.9.2'
21
+ s.add_development_dependency 'rspec', '>= 2.13'
22
+ s.add_development_dependency 'unindent', '>= 1.0'
23
+
24
+ # For coverage reports
25
+ s.add_development_dependency 'coveralls', '~> 0.7'
26
+
27
+ s.rubygems_version = ">= 1.6.1"
28
+ s.files = `git ls-files`.split("\n").reject {|path| path =~ /\.gitignore$/ }
29
+ s.test_files = `git ls-files -- spec/*`.split("\n")
30
+ s.rdoc_options = ["--charset=UTF-8"]
31
+ s.require_path = "lib"
32
+ end
@@ -0,0 +1,37 @@
1
+ require 'cucumber/core/gherkin/parser'
2
+ require 'cucumber/core/compiler'
3
+ require 'cucumber/core/test/runner'
4
+ require 'cucumber/core/test/mapper'
5
+ require 'cucumber/core/test/hook_compiler'
6
+
7
+ module Cucumber
8
+ module Core
9
+
10
+ def parse(gherkin_documents, compiler)
11
+ parser = Core::Gherkin::Parser.new(compiler)
12
+ gherkin_documents.each do |document|
13
+ parser.document document
14
+ end
15
+ parser.done
16
+ self
17
+ end
18
+
19
+ def compile(gherkin_documents, last_receiver, filters = [])
20
+ first_receiver = filters.reduce(last_receiver) do |receiver, (filter_type, args)|
21
+ filter_type.new(*args + [receiver])
22
+ end
23
+ compiler = Compiler.new(first_receiver)
24
+ parse gherkin_documents, compiler
25
+ self
26
+ end
27
+
28
+ def execute(gherkin_documents, mappings, report, filters = [], run_options = {})
29
+ receiver = Test::Runner.new(report, run_options)
30
+ filters << [Test::HookCompiler, [mappings]]
31
+ filters << [Test::Mapper, [mappings]]
32
+ compile gherkin_documents, receiver, filters
33
+ self
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,13 @@
1
+ require 'cucumber/core/ast/comment'
2
+ require 'cucumber/core/ast/tag'
3
+ require 'cucumber/core/ast/feature'
4
+ require 'cucumber/core/ast/empty_background'
5
+ require 'cucumber/core/ast/background'
6
+ require 'cucumber/core/ast/scenario'
7
+ require 'cucumber/core/ast/step'
8
+ require 'cucumber/core/ast/multiline_argument'
9
+ require 'cucumber/core/ast/doc_string'
10
+ require 'cucumber/core/ast/data_table'
11
+ require 'cucumber/core/ast/scenario_outline'
12
+ require 'cucumber/core/ast/outline_step'
13
+ require 'cucumber/core/ast/examples_table'
@@ -0,0 +1,33 @@
1
+ require 'cucumber/initializer'
2
+ require 'cucumber/core/ast/names'
3
+ require 'cucumber/core/ast/location'
4
+ require 'cucumber/core/ast/describes_itself'
5
+
6
+ module Cucumber
7
+ module Core
8
+ module Ast
9
+ class Background
10
+ include Names
11
+ include HasLocation
12
+ include DescribesItself
13
+
14
+ include Cucumber.initializer(:gherkin_statement, :language, :location, :comments, :keyword, :title, :description, :raw_steps)
15
+
16
+ attr_accessor :feature
17
+ attr_accessor :comments, :keyword, :location
18
+ attr_reader :gherkin_statement
19
+
20
+ def children
21
+ raw_steps
22
+ end
23
+
24
+ private
25
+
26
+ def description_for_visitors
27
+ :background
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ require 'cucumber/initializer'
2
+ require 'cucumber/core/ast/location'
3
+
4
+ module Cucumber
5
+ module Core
6
+ module Ast
7
+ class Comment
8
+ include HasLocation
9
+ include Cucumber.initializer :location, :value
10
+
11
+ def to_s
12
+ value
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,326 @@
1
+ require 'gherkin/rubify'
2
+ require 'gherkin/lexer/i18n_lexer'
3
+ require 'gherkin/formatter/escaping'
4
+ require 'cucumber/core/ast/describes_itself'
5
+ require 'cucumber/core/ast/location'
6
+
7
+ module Cucumber
8
+ module Core
9
+ module Ast
10
+ # Step Definitions that match a plain text Step with a multiline argument table
11
+ # will receive it as an instance of DataTable. A DataTable object holds the data of a
12
+ # table parsed from a feature file and lets you access and manipulate the data
13
+ # in different ways.
14
+ #
15
+ # For example:
16
+ #
17
+ # Given I have:
18
+ # | a | b |
19
+ # | c | d |
20
+ #
21
+ # And a matching StepDefinition:
22
+ #
23
+ # Given /I have:/ do |table|
24
+ # data = table.raw
25
+ # end
26
+ #
27
+ # This will store <tt>[['a', 'b'], ['c', 'd']]</tt> in the <tt>data</tt> variable.
28
+ #
29
+ class DataTable
30
+ include DescribesItself
31
+ include HasLocation
32
+
33
+ class Builder
34
+ attr_reader :rows
35
+
36
+ def initialize
37
+ @rows = []
38
+ end
39
+
40
+ def row(row, line_number)
41
+ @rows << row
42
+ end
43
+
44
+ def eof
45
+ end
46
+ end
47
+
48
+ include ::Gherkin::Rubify
49
+
50
+ NULL_CONVERSIONS = Hash.new({ :strict => false, :proc => lambda{ |cell_value| cell_value } }).freeze
51
+
52
+ attr_accessor :file
53
+
54
+ def self.default_arg_name #:nodoc:
55
+ "table"
56
+ end
57
+
58
+ def self.parse(text, uri, location)
59
+ builder = Builder.new
60
+ lexer = ::Gherkin::Lexer::I18nLexer.new(builder)
61
+ lexer.scan(text)
62
+ new(builder.rows, location)
63
+ end
64
+
65
+ # Creates a new instance. +raw+ should be an Array of Array of String
66
+ # or an Array of Hash
67
+ # You don't typically create your own DataTable objects - Cucumber will do
68
+ # it internally and pass them to your Step Definitions.
69
+ #
70
+ def initialize(raw, location)
71
+ @cells_class = Cells
72
+ @cell_class = Cell
73
+ raw = ensure_array_of_array(rubify(raw))
74
+ # Verify that it's square
75
+ raw.transpose
76
+ create_cell_matrix(raw)
77
+ @location = location
78
+ end
79
+
80
+ def to_step_definition_arg
81
+ dup
82
+ end
83
+
84
+ # Creates a copy of this table
85
+ #
86
+ def dup
87
+ self.class.new(raw.dup, location)
88
+ end
89
+
90
+ # Returns a new, transposed table. Example:
91
+ #
92
+ # | a | 7 | 4 |
93
+ # | b | 9 | 2 |
94
+ #
95
+ # Gets converted into the following:
96
+ #
97
+ # | a | b |
98
+ # | 7 | 9 |
99
+ # | 4 | 2 |
100
+ #
101
+ def transpose
102
+ self.class.new(raw.transpose, location)
103
+ end
104
+
105
+ def map(&block)
106
+ new_raw = raw.map do |row|
107
+ row.map(&block)
108
+ end
109
+
110
+ self.class.new(new_raw, location)
111
+ end
112
+
113
+ # Converts this table into an Array of Hash where the keys of each
114
+ # Hash are the headers in the table. For example, a DataTable built from
115
+ # the following plain text:
116
+ #
117
+ # | a | b | sum |
118
+ # | 2 | 3 | 5 |
119
+ # | 7 | 9 | 16 |
120
+ #
121
+ # Gets converted into the following:
122
+ #
123
+ # [{'a' => '2', 'b' => '3', 'sum' => '5'}, {'a' => '7', 'b' => '9', 'sum' => '16'}]
124
+ #
125
+ def hashes
126
+ build_hashes
127
+ end
128
+
129
+ # Converts this table into a Hash where the first column is
130
+ # used as keys and the second column is used as values
131
+ #
132
+ # | a | 2 |
133
+ # | b | 3 |
134
+ #
135
+ # Gets converted into the following:
136
+ #
137
+ # {'a' => '2', 'b' => '3'}
138
+ #
139
+ # The table must be exactly two columns wide
140
+ #
141
+ def rows_hash
142
+ verify_table_width(2)
143
+ self.transpose.hashes[0]
144
+ end
145
+
146
+ # Gets the raw data of this table. For example, a DataTable built from
147
+ # the following plain text:
148
+ #
149
+ # | a | b |
150
+ # | c | d |
151
+ #
152
+ # gets converted into the following:
153
+ #
154
+ # [['a', 'b'], ['c', 'd']]
155
+ #
156
+ def raw
157
+ cell_matrix.map do |row|
158
+ row.map do |cell|
159
+ cell.value
160
+ end
161
+ end
162
+ end
163
+
164
+ def column_names #:nodoc:
165
+ cell_matrix[0].map { |cell| cell.value }
166
+ end
167
+
168
+ def rows
169
+ hashes.map do |hash|
170
+ hash.values_at(*headers)
171
+ end
172
+ end
173
+
174
+ # For testing only
175
+ def to_sexp #:nodoc:
176
+ [:table, *cells_rows.map{|row| row.to_sexp}]
177
+ end
178
+
179
+ def to_hash(cells) #:nodoc:
180
+ hash = Hash.new do |the_hash, key|
181
+ the_hash[key.to_s] if key.is_a?(Symbol)
182
+ end
183
+ column_names.each_with_index do |column_name, column_index|
184
+ hash[column_name] = cells.value(column_index)
185
+ end
186
+ hash
187
+ end
188
+
189
+ def verify_table_width(width) #:nodoc:
190
+ raise %{The table must have exactly #{width} columns} unless raw[0].size == width
191
+ end
192
+
193
+ def cells_rows #:nodoc:
194
+ cell_matrix.map do |cell_row|
195
+ @cells_class.new(self, cell_row)
196
+ end
197
+ end
198
+
199
+ def headers #:nodoc:
200
+ raw.first
201
+ end
202
+
203
+ def cell_matrix #:nodoc:
204
+ @cell_matrix
205
+ end
206
+
207
+ def col_width(col) #:nodoc:
208
+ columns[col].__send__(:width)
209
+ end
210
+
211
+ def ==(other)
212
+ other.class == self.class && raw == other.raw
213
+ end
214
+
215
+ def inspect
216
+ raw.inspect
217
+ end
218
+
219
+ private
220
+
221
+ TO_S_PREFIXES = Hash.new(' ')
222
+ TO_S_PREFIXES[:comment] = '(+) '
223
+ TO_S_PREFIXES[:undefined] = '(-) '
224
+
225
+ def build_hashes
226
+ cells_rows[1..-1].map do |row|
227
+ row.to_hash
228
+ end
229
+ end
230
+
231
+ def create_cell_matrix(raw) #:nodoc:
232
+ @cell_matrix = raw.map do |raw_row|
233
+ line = raw_row.line rescue -1
234
+ raw_row.map do |raw_cell|
235
+ new_cell(raw_cell, line)
236
+ end
237
+ end
238
+ end
239
+
240
+ def columns #:nodoc:
241
+ cell_matrix.transpose.map do |cell_row|
242
+ @cells_class.new(self, cell_row)
243
+ end
244
+ end
245
+
246
+ def new_cell(raw_cell, line) #:nodoc:
247
+ @cell_class.new(raw_cell, self, line)
248
+ end
249
+
250
+ def ensure_array_of_array(array)
251
+ Hash === array[0] ? hashes_to_array(array) : array
252
+ end
253
+
254
+ def hashes_to_array(hashes) #:nodoc:
255
+ header = hashes[0].keys.sort
256
+ [header] + hashes.map{|hash| header.map{|key| hash[key]}}
257
+ end
258
+
259
+ def description_for_visitors
260
+ :table
261
+ end
262
+
263
+ # Represents a row of cells or columns of cells
264
+ class Cells #:nodoc:
265
+ include Enumerable
266
+ include Gherkin::Formatter::Escaping
267
+
268
+ attr_reader :exception
269
+
270
+ def initialize(table, cells)
271
+ @table, @cells = table, cells
272
+ end
273
+
274
+ # For testing only
275
+ def to_sexp #:nodoc:
276
+ [:row, line, *@cells.map{|cell| cell.to_sexp}]
277
+ end
278
+
279
+ def to_hash #:nodoc:
280
+ @to_hash ||= @table.to_hash(self)
281
+ end
282
+
283
+ def value(n) #:nodoc:
284
+ self[n].value
285
+ end
286
+
287
+ def [](n)
288
+ @cells[n]
289
+ end
290
+
291
+ def line
292
+ @cells[0].line
293
+ end
294
+
295
+ private
296
+
297
+ def width
298
+ map{|cell| cell.value ? escape_cell(cell.value.to_s).unpack('U*').length : 0}.max
299
+ end
300
+
301
+ def each(&proc)
302
+ @cells.each(&proc)
303
+ end
304
+ end
305
+
306
+ class Cell #:nodoc:
307
+ attr_reader :line, :table
308
+ attr_accessor :status, :value
309
+
310
+ def initialize(value, table, line)
311
+ @value, @table, @line = value, table, line
312
+ end
313
+
314
+ def inspect!
315
+ @value = "(i) #{value.inspect}"
316
+ end
317
+
318
+ # For testing only
319
+ def to_sexp #:nodoc:
320
+ [:cell, @value]
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end