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

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