cucumber 2.0.0.beta.2 → 2.0.0.beta.3

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +25 -7
  3. data/cucumber.gemspec +1 -1
  4. data/features/docs/defining_steps/nested_steps.feature +0 -1
  5. data/features/docs/defining_steps/printing_messages.feature +1 -0
  6. data/features/docs/defining_steps/table_diffing.feature +9 -4
  7. data/features/docs/exception_in_after_step_hook.feature +1 -0
  8. data/features/docs/formatters/json_formatter.feature +51 -4
  9. data/features/docs/formatters/junit_formatter.feature +1 -0
  10. data/features/docs/gherkin/outlines.feature +4 -0
  11. data/features/docs/output_from_hooks.feature +128 -0
  12. data/features/docs/wire_protocol_table_diffing.feature +6 -2
  13. data/features/docs/writing_support_code/after_hooks.feature +56 -0
  14. data/lib/cucumber/cli/configuration.rb +0 -4
  15. data/lib/cucumber/cli/main.rb +0 -1
  16. data/lib/cucumber/cli/options.rb +0 -3
  17. data/lib/cucumber/formatter/console.rb +3 -1
  18. data/lib/cucumber/formatter/debug.rb +4 -0
  19. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +26 -3
  20. data/lib/cucumber/formatter/html.rb +6 -2
  21. data/lib/cucumber/formatter/usage.rb +1 -58
  22. data/lib/cucumber/mappings.rb +25 -7
  23. data/lib/cucumber/multiline_argument.rb +40 -82
  24. data/lib/cucumber/multiline_argument/data_table.rb +719 -0
  25. data/lib/cucumber/multiline_argument/doc_string.rb +10 -0
  26. data/lib/cucumber/platform.rb +1 -1
  27. data/lib/cucumber/rb_support/rb_world.rb +2 -4
  28. data/lib/cucumber/reports/legacy_formatter.rb +69 -22
  29. data/lib/cucumber/runtime.rb +0 -39
  30. data/lib/cucumber/runtime/for_programming_languages.rb +12 -10
  31. data/lib/cucumber/runtime/support_code.rb +11 -4
  32. data/lib/cucumber/wire_support/wire_protocol/requests.rb +2 -2
  33. data/spec/cucumber/formatter/pretty_spec.rb +5 -5
  34. data/spec/cucumber/mappings_spec.rb +137 -8
  35. data/spec/cucumber/multiline_argument/data_table_spec.rb +508 -0
  36. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +3 -3
  37. data/spec/cucumber/rb_support/snippet_spec.rb +1 -1
  38. data/spec/cucumber/runtime/for_programming_languages_spec.rb +16 -12
  39. metadata +13 -6
  40. data/lib/cucumber/runtime/features_loader.rb +0 -62
@@ -0,0 +1,508 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'cucumber/multiline_argument/data_table'
4
+
5
+ module Cucumber
6
+ module MultilineArgument
7
+ describe DataTable do
8
+ before do
9
+ @table = DataTable.new([
10
+ %w{one four seven},
11
+ %w{4444 55555 666666}
12
+ ])
13
+ end
14
+
15
+ it "should have rows" do
16
+ expect( @table.cells_rows[0].map{|cell| cell.value} ).to eq %w{one four seven}
17
+ end
18
+
19
+ it "should have columns" do
20
+ expect( @table.columns[1].map{|cell| cell.value} ).to eq %w{four 55555}
21
+ end
22
+
23
+ it "should have same cell objects in rows and columns" do
24
+ # 666666
25
+ expect( @table.cells_rows[1][2] ).to equal(@table.columns[2][1])
26
+ end
27
+
28
+ it "should be convertible to an array of hashes" do
29
+ expect( @table.hashes ).to eq [
30
+ {'one' => '4444', 'four' => '55555', 'seven' => '666666'}
31
+ ]
32
+ end
33
+
34
+ it "should accept symbols as keys for the hashes" do
35
+ expect( @table.hashes.first[:one] ).to eq '4444'
36
+ end
37
+
38
+ it "should return the row values in order" do
39
+ expect( @table.rows.first ).to eq %w{4444 55555 666666}
40
+ end
41
+
42
+ describe '#map_column!' do
43
+ it "should allow mapping columns" do
44
+ @table.map_column!('one') { |v| v.to_i }
45
+ expect( @table.hashes.first['one'] ).to eq 4444
46
+ end
47
+
48
+ it "applies the block once to each value" do
49
+ headers = ['header']
50
+ rows = ['value']
51
+ table = DataTable.new [headers, rows]
52
+ count = 0
53
+ table.map_column!('header') { |value| count +=1 }
54
+ table.rows
55
+ expect( count ).to eq rows.size
56
+ end
57
+
58
+ it "should allow mapping columns and take a symbol as the column name" do
59
+ @table.map_column!(:one) { |v| v.to_i }
60
+ expect( @table.hashes.first['one'] ).to eq 4444
61
+ end
62
+
63
+ it "should allow mapping columns and modify the rows as well" do
64
+ @table.map_column!(:one) { |v| v.to_i }
65
+ expect( @table.rows.first ).to include(4444)
66
+ expect( @table.rows.first ).to_not include('4444')
67
+ end
68
+
69
+ it "should pass silently if a mapped column does not exist in non-strict mode" do
70
+ expect {
71
+ @table.map_column!('two', false) { |v| v.to_i }
72
+ @table.hashes
73
+ }.not_to raise_error
74
+ end
75
+
76
+ it "should fail if a mapped column does not exist in strict mode" do
77
+ expect {
78
+ @table.map_column!('two', true) { |v| v.to_i }
79
+ @table.hashes
80
+ }.to raise_error('The column named "two" does not exist')
81
+ end
82
+
83
+ it "should return the table" do
84
+ expect( (@table.map_column!(:one) { |v| v.to_i }) ).to eq @table
85
+ end
86
+ end
87
+
88
+ describe '#map_column' do
89
+ it "should allow mapping columns" do
90
+ new_table = @table.map_column('one') { |v| v.to_i }
91
+ expect( new_table.hashes.first['one'] ).to eq 4444
92
+ end
93
+
94
+ it "applies the block once to each value" do
95
+ headers = ['header']
96
+ rows = ['value']
97
+ table = DataTable.new [headers, rows]
98
+ count = 0
99
+ new_table = table.map_column('header') { |value| count +=1 }
100
+ new_table.rows
101
+ expect( count ).to eq rows.size
102
+ end
103
+
104
+ it "should allow mapping columns and take a symbol as the column name" do
105
+ new_table = @table.map_column(:one) { |v| v.to_i }
106
+ expect( new_table.hashes.first['one'] ).to eq 4444
107
+ end
108
+
109
+ it "should allow mapping columns and modify the rows as well" do
110
+ new_table = @table.map_column(:one) { |v| v.to_i }
111
+ expect( new_table.rows.first ).to include(4444)
112
+ expect( new_table.rows.first ).to_not include('4444')
113
+ end
114
+
115
+ it "should pass silently if a mapped column does not exist in non-strict mode" do
116
+ expect {
117
+ new_table = @table.map_column('two', false) { |v| v.to_i }
118
+ new_table.hashes
119
+ }.not_to raise_error
120
+ end
121
+
122
+ it "should fail if a mapped column does not exist in strict mode" do
123
+ expect {
124
+ new_table = @table.map_column('two', true) { |v| v.to_i }
125
+ new_table.hashes
126
+ }.to raise_error('The column named "two" does not exist')
127
+ end
128
+
129
+ it "should return a new table" do
130
+ expect( (@table.map_column(:one) { |v| v.to_i }) ).to_not eq @table
131
+ end
132
+ end
133
+
134
+ describe "#match" do
135
+ before(:each) do
136
+ @table = DataTable.new([
137
+ %w{one four seven},
138
+ %w{4444 55555 666666}
139
+ ])
140
+ end
141
+
142
+ it "returns nil if headers do not match" do
143
+ expect( @table.match('does,not,match') ).to be_nil
144
+ end
145
+ it "requires a table: prefix on match" do
146
+ expect( @table.match('table:one,four,seven') ).to_not be_nil
147
+ end
148
+ it "does not match if no table: prefix on match" do
149
+ expect( @table.match('one,four,seven') ).to be_nil
150
+ end
151
+ end
152
+
153
+ describe "#transpose" do
154
+ before(:each) do
155
+ @table = DataTable.new([
156
+ %w{one 1111},
157
+ %w{two 22222}
158
+ ])
159
+ end
160
+
161
+ it "should be convertible in to an array where each row is a hash" do
162
+ expect( @table.transpose.hashes[0] ).to eq('one' => '1111', 'two' => '22222')
163
+ end
164
+ end
165
+
166
+ describe "#rows_hash" do
167
+
168
+ it "should return a hash of the rows" do
169
+ table = DataTable.new([
170
+ %w{one 1111},
171
+ %w{two 22222}
172
+ ])
173
+ expect( table.rows_hash ).to eq( 'one' => '1111', 'two' => '22222' )
174
+ end
175
+
176
+ it "should fail if the table doesn't have two columns" do
177
+ faulty_table = DataTable.new([
178
+ %w{one 1111 abc},
179
+ %w{two 22222 def}
180
+ ])
181
+ expect {
182
+ faulty_table.rows_hash
183
+ }.to raise_error('The table must have exactly 2 columns')
184
+ end
185
+
186
+ it "should support header and column mapping" do
187
+ table = DataTable.new([
188
+ %w{one 1111},
189
+ %w{two 22222}
190
+ ])
191
+ t2 = table.map_headers({ 'two' => 'Two' }) { |header| header.upcase }.
192
+ map_column('two', false) { |val| val.to_i }
193
+ expect( t2.rows_hash ).to eq( 'ONE' => '1111', 'Two' => 22222 )
194
+ end
195
+ end
196
+
197
+ describe '#map_headers!' do
198
+ let(:table) do
199
+ DataTable.new([
200
+ %w{HELLO WORLD},
201
+ %w{4444 55555}
202
+ ])
203
+ end
204
+
205
+ it "renames the columns to the specified values in the provided hash" do
206
+ @table.map_headers!('one' => :three)
207
+ expect( @table.hashes.first[:three] ).to eq '4444'
208
+ end
209
+
210
+ it "allows renaming columns using regexp" do
211
+ @table.map_headers!(/one|uno/ => :three)
212
+ expect( @table.hashes.first[:three] ).to eq '4444'
213
+ end
214
+
215
+ it "copies column mappings" do
216
+ @table.map_column!('one') { |v| v.to_i }
217
+ @table.map_headers!('one' => 'three')
218
+ expect( @table.hashes.first['three'] ).to eq 4444
219
+ end
220
+
221
+ it "takes a block and operates on all the headers with it" do
222
+ table.map_headers! do |header|
223
+ header.downcase
224
+ end
225
+ expect( table.hashes.first.keys ).to match %w[hello world]
226
+ end
227
+
228
+ it "treats the mappings in the provided hash as overrides when used with a block" do
229
+ table.map_headers!('WORLD' => 'foo') do |header|
230
+ header.downcase
231
+ end
232
+
233
+ expect( table.hashes.first.keys ).to match %w[hello foo]
234
+ end
235
+ end
236
+
237
+ describe '#map_headers' do
238
+ let(:table) do
239
+ DataTable.new([
240
+ %w{HELLO WORLD},
241
+ %w{4444 55555}
242
+ ])
243
+ end
244
+
245
+ it "renames the columns to the specified values in the provided hash" do
246
+ table2 = @table.map_headers('one' => :three)
247
+ expect( table2.hashes.first[:three] ).to eq '4444'
248
+ end
249
+
250
+ it "allows renaming columns using regexp" do
251
+ table2 = @table.map_headers(/one|uno/ => :three)
252
+ expect( table2.hashes.first[:three] ).to eq '4444'
253
+ end
254
+
255
+ it "copies column mappings" do
256
+ @table.map_column!('one') { |v| v.to_i }
257
+ table2 = @table.map_headers('one' => 'three')
258
+ expect( table2.hashes.first['three'] ).to eq 4444
259
+ end
260
+
261
+ it "takes a block and operates on all the headers with it" do
262
+ table2 = table.map_headers do |header|
263
+ header.downcase
264
+ end
265
+
266
+ expect( table2.hashes.first.keys ).to match %w[hello world]
267
+ end
268
+
269
+ it "treats the mappings in the provided hash as overrides when used with a block" do
270
+ table2 = table.map_headers('WORLD' => 'foo') do |header|
271
+ header.downcase
272
+ end
273
+
274
+ expect( table2.hashes.first.keys ).to match %w[hello foo]
275
+ end
276
+ end
277
+
278
+ describe "diff!" do
279
+ it "should detect a complex diff" do
280
+ t1 = table(%{
281
+ | 1 | 22 | 333 | 4444 |
282
+ | 55555 | 666666 | 7777777 | 88888888 |
283
+ | 999999999 | 0000000000 | 01010101010 | 121212121212 |
284
+ | 4000 | ABC | DEF | 50000 |
285
+ }, __FILE__, __LINE__)
286
+
287
+ t2 = table(%{
288
+ | a | 4444 | 1 |
289
+ | bb | 88888888 | 55555 |
290
+ | ccc | xxxxxxxx | 999999999 |
291
+ | dddd | 4000 | 300 |
292
+ | e | 50000 | 4000 |
293
+ }, __FILE__, __LINE__)
294
+ expect { t1.diff!(t2) }.to raise_error
295
+ expect( t1.to_s(:indent => 12, :color => false) ).to eq %{
296
+ | 1 | (-) 22 | (-) 333 | 4444 | (+) a |
297
+ | 55555 | (-) 666666 | (-) 7777777 | 88888888 | (+) bb |
298
+ | (-) 999999999 | (-) 0000000000 | (-) 01010101010 | (-) 121212121212 | (+) |
299
+ | (+) 999999999 | (+) | (+) | (+) xxxxxxxx | (+) ccc |
300
+ | (+) 300 | (+) | (+) | (+) 4000 | (+) dddd |
301
+ | 4000 | (-) ABC | (-) DEF | 50000 | (+) e |
302
+ }
303
+ end
304
+
305
+ it "should not change table when diffed with identical" do
306
+ t = table(%{
307
+ |a|b|c|
308
+ |d|e|f|
309
+ |g|h|i|
310
+ }, __FILE__, __LINE__)
311
+ t.diff!(t.dup)
312
+ expect( t.to_s(:indent => 12, :color => false) ).to eq %{
313
+ | a | b | c |
314
+ | d | e | f |
315
+ | g | h | i |
316
+ }
317
+ end
318
+
319
+ it "should inspect missing and surplus cells" do
320
+ t1 = DataTable.new([
321
+ ['name', 'male', 'lastname', 'swedish'],
322
+ ['aslak', 'true', 'hellesøy', 'false']
323
+ ])
324
+ t2 = DataTable.new([
325
+ ['name', 'male', 'lastname', 'swedish'],
326
+ ['aslak', true, 'hellesøy', false]
327
+ ])
328
+ expect { t1.diff!(t2) }.to raise_error
329
+
330
+ expect( t1.to_s(:indent => 12, :color => false) ).to eq %{
331
+ | name | male | lastname | swedish |
332
+ | (-) aslak | (-) (i) "true" | (-) hellesøy | (-) (i) "false" |
333
+ | (+) aslak | (+) (i) true | (+) hellesøy | (+) (i) false |
334
+ }
335
+ end
336
+
337
+ it "should allow column mapping of target before diffing" do
338
+ t1 = DataTable.new([
339
+ ['name', 'male'],
340
+ ['aslak', 'true']
341
+ ])
342
+ t1.map_column!('male') { |m| m == 'true' }
343
+ t2 = DataTable.new([
344
+ ['name', 'male'],
345
+ ['aslak', true]
346
+ ])
347
+ t1.diff!(t2)
348
+ expect( t1.to_s(:indent => 12, :color => false) ).to eq %{
349
+ | name | male |
350
+ | aslak | true |
351
+ }
352
+ end
353
+
354
+ it "should allow column mapping of argument before diffing" do
355
+ t1 = DataTable.new([
356
+ ['name', 'male'],
357
+ ['aslak', true]
358
+ ])
359
+ t1.map_column!('male') {
360
+ 'true'
361
+ }
362
+ t2 = DataTable.new([
363
+ ['name', 'male'],
364
+ ['aslak', 'true']
365
+ ])
366
+ t2.diff!(t1)
367
+ expect( t1.to_s(:indent => 12, :color => false) ).to eq %{
368
+ | name | male |
369
+ | aslak | true |
370
+ }
371
+ end
372
+
373
+ it "should allow header mapping before diffing" do
374
+ t1 = DataTable.new([
375
+ ['Name', 'Male'],
376
+ ['aslak', 'true']
377
+ ])
378
+ t1.map_headers!('Name' => 'name', 'Male' => 'male')
379
+ t1.map_column!('male') { |m| m == 'true' }
380
+ t2 = DataTable.new([
381
+ ['name', 'male'],
382
+ ['aslak', true]
383
+ ])
384
+ t1.diff!(t2)
385
+ expect( t1.to_s(:indent => 12, :color => false) ).to eq %{
386
+ | name | male |
387
+ | aslak | true |
388
+ }
389
+ end
390
+
391
+ it "should detect seemingly identical tables as different" do
392
+ t1 = DataTable.new([
393
+ ['X', 'Y'],
394
+ ['2', '1']
395
+ ])
396
+ t2 = DataTable.new([
397
+ ['X', 'Y'],
398
+ [2, 1]
399
+ ])
400
+ expect { t1.diff!(t2) }.to raise_error
401
+ expect( t1.to_s(:indent => 12, :color => false) ).to eq %{
402
+ | X | Y |
403
+ | (-) (i) "2" | (-) (i) "1" |
404
+ | (+) (i) 2 | (+) (i) 1 |
405
+ }
406
+ end
407
+
408
+ it "should not allow mappings that match more than 1 column" do
409
+ t1 = DataTable.new([
410
+ ['Cuke', 'Duke'],
411
+ ['Foo', 'Bar']
412
+ ])
413
+ expect do
414
+ t1.map_headers!(/uk/ => 'u')
415
+ t1.hashes
416
+ end.to raise_error(%{2 headers matched /uk/: ["Cuke", "Duke"]})
417
+ end
418
+
419
+ describe "raising" do
420
+ before do
421
+ @t = table(%{
422
+ | a | b |
423
+ | c | d |
424
+ }, __FILE__, __LINE__)
425
+ expect( @t ).not_to eq nil
426
+ end
427
+
428
+ it "should raise on missing rows" do
429
+ t = table(%{
430
+ | a | b |
431
+ }, __FILE__, __LINE__)
432
+ expect( lambda { @t.dup.diff!(t) } ).to raise_error
433
+ expect { @t.dup.diff!(t, :missing_row => false) }.not_to raise_error
434
+ end
435
+
436
+ it "should not raise on surplus rows when surplus is at the end" do
437
+ t = table(%{
438
+ | a | b |
439
+ | c | d |
440
+ | e | f |
441
+ }, __FILE__, __LINE__)
442
+ expect { @t.dup.diff!(t) }.to raise_error
443
+ expect { @t.dup.diff!(t, :surplus_row => false) }.not_to raise_error
444
+ end
445
+
446
+ it "should not raise on surplus rows when surplus is interleaved" do
447
+ t1 = table(%{
448
+ | row_1 | row_2 |
449
+ | four | 4 |
450
+ }, __FILE__, __LINE__)
451
+ t2 = table(%{
452
+ | row_1 | row_2 |
453
+ | one | 1 |
454
+ | two | 2 |
455
+ | three | 3 |
456
+ | four | 4 |
457
+ | five | 5 |
458
+ }, __FILE__, __LINE__)
459
+ expect { t1.dup.diff!(t2) }.to raise_error
460
+
461
+ expect { t1.dup.diff!(t2, :surplus_row => false) }.not_to raise_error
462
+ end
463
+
464
+ it "should raise on missing columns" do
465
+ t = table(%{
466
+ | a |
467
+ | c |
468
+ }, __FILE__, __LINE__)
469
+ expect { @t.dup.diff!(t) }.to raise_error
470
+ expect { @t.dup.diff!(t, :missing_col => false) }.not_to raise_error
471
+ end
472
+
473
+ it "should not raise on surplus columns" do
474
+ t = table(%{
475
+ | a | b | x |
476
+ | c | d | y |
477
+ }, __FILE__, __LINE__)
478
+ expect { @t.dup.diff!(t) }.not_to raise_error
479
+ expect { @t.dup.diff!(t, :surplus_col => true) }.to raise_error
480
+ end
481
+
482
+ it "should not raise on misplaced columns" do
483
+ t = table(%{
484
+ | b | a |
485
+ | d | c |
486
+ }, __FILE__, __LINE__)
487
+ expect { @t.dup.diff!(t) }.not_to raise_error
488
+ expect { @t.dup.diff!(t, :misplaced_col => true) }.to raise_error
489
+ end
490
+ end
491
+
492
+ def table(text, file, offset)
493
+ DataTable.parse(text, file, offset)
494
+ end
495
+ end
496
+
497
+ describe "#new" do
498
+ it "should allow Array of Hash" do
499
+ t1 = DataTable.new([{'name' => 'aslak', 'male' => 'true'}])
500
+ expect( t1.to_s(:indent => 12, :color => false) ).to eq %{
501
+ | male | name |
502
+ | true | aslak |
503
+ }
504
+ end
505
+ end
506
+ end
507
+ end
508
+ end