|
- # frozen_string_literal: true
-
- require 'spec_helper'
- require 'cucumber/multiline_argument/data_table'
-
- module Cucumber
- module MultilineArgument
- describe DataTable do
- before do
- @table = DataTable.from([
- %w[one four seven],
- %w[4444 55555 666666]
- ])
- end
-
- it 'should have rows' do
- expect(@table.cells_rows[0].map(&:value)).to eq %w[one four seven]
- end
-
- it 'should have columns' do
- expect(@table.columns[1].map(&:value)).to eq %w[four 55555]
- end
-
- it 'should have same cell objects in rows and columns' do
- # 666666
- expect(@table.cells_rows[1][2]).to equal(@table.columns[2][1])
- end
-
- it 'should be convertible to an array of hashes' do
- expect(@table.hashes).to eq [
- { 'one' => '4444', 'four' => '55555', 'seven' => '666666' }
- ]
- end
-
- it 'should accept symbols as keys for the hashes' do
- expect(@table.hashes.first[:one]).to eq '4444'
- end
-
- it 'should return the row values in order' do
- expect(@table.rows.first).to eq %w[4444 55555 666666]
- end
-
- describe '#symbolic_hashes' do
- it 'should covert data table to an array of hashes with symbols as keys' do
- ast_table = Cucumber::Core::Test::DataTable.new([['foo', 'Bar', 'Foo Bar'], %w[1 22 333]])
- data_table = DataTable.new(ast_table)
- expect(data_table.symbolic_hashes).to eq([{ foo: '1', bar: '22', foo_bar: '333' }])
- end
-
- it 'should be able to be accessed multiple times' do
- @table.symbolic_hashes
- expect { @table.symbolic_hashes }.to_not raise_error
- end
-
- it 'should not interfere with use of #hashes' do
- @table.symbolic_hashes
- expect { @table.hashes }.to_not raise_error
- end
- end
-
- describe '#map_column' do
- it 'should allow mapping columns' do
- new_table = @table.map_column('one', &:to_i)
- expect(new_table.hashes.first['one']).to eq 4444
- end
-
- it 'applies the block once to each value' do
- headers = ['header']
- rows = ['value']
- table = DataTable.from [headers, rows]
- count = 0
- new_table = table.map_column('header') { |_value| count += 1 }
- new_table.rows
- expect(count).to eq rows.size
- end
-
- it 'should allow mapping columns and take a symbol as the column name' do
- new_table = @table.map_column(:one, &:to_i)
- expect(new_table.hashes.first['one']).to eq 4444
- end
-
- it 'should allow mapping columns and modify the rows as well' do
- new_table = @table.map_column(:one, &:to_i)
- expect(new_table.rows.first).to include(4444)
- expect(new_table.rows.first).to_not include('4444')
- end
-
- it 'should pass silently if a mapped column does not exist in non-strict mode' do
- expect do
- new_table = @table.map_column('two', strict: false, &:to_i)
- new_table.hashes
- end.not_to raise_error
- end
-
- it 'should fail if a mapped column does not exist in strict mode' do
- expect do
- new_table = @table.map_column('two', strict: true, &:to_i)
- new_table.hashes
- end.to raise_error('The column named "two" does not exist')
- end
-
- it 'should return a new table' do
- expect(@table.map_column(:one, &:to_i)).to_not eq @table
- end
- end
-
- describe '#match' do
- before(:each) do
- @table = DataTable.from([
- %w[one four seven],
- %w[4444 55555 666666]
- ])
- end
-
- it 'returns nil if headers do not match' do
- expect(@table.match('does,not,match')).to be_nil
- end
- it 'requires a table: prefix on match' do
- expect(@table.match('table:one,four,seven')).to_not be_nil
- end
- it 'does not match if no table: prefix on match' do
- expect(@table.match('one,four,seven')).to be_nil
- end
- end
-
- describe '#transpose' do
- before(:each) do
- @table = DataTable.from([
- %w[one 1111],
- %w[two 22222]
- ])
- end
-
- it 'should be convertible in to an array where each row is a hash' do
- expect(@table.transpose.hashes[0]).to eq('one' => '1111', 'two' => '22222')
- end
- end
-
- describe '#rows_hash' do
- it 'should return a hash of the rows' do
- table = DataTable.from([
- %w[one 1111],
- %w[two 22222]
- ])
- expect(table.rows_hash).to eq('one' => '1111', 'two' => '22222')
- end
-
- it "should fail if the table doesn't have two columns" do
- faulty_table = DataTable.from([
- %w[one 1111 abc],
- %w[two 22222 def]
- ])
- expect do
- faulty_table.rows_hash
- end.to raise_error('The table must have exactly 2 columns')
- end
-
- it 'should support header and column mapping' do
- table = DataTable.from([
- %w[one 1111],
- %w[two 22222]
- ])
- t2 = table.map_headers({ 'two' => 'Two' }, &:upcase)
- .map_column('two', strict: false, &:to_i)
- expect(t2.rows_hash).to eq('ONE' => '1111', 'Two' => 22_222)
- end
- end
-
- describe '#map_headers' do
- let(:table) do
- DataTable.from([
- %w[ANT ANTEATER],
- %w[4444 55555]
- ])
- end
-
- it 'renames the columns to the specified values in the provided hash' do
- table2 = @table.map_headers('one' => :three)
- expect(table2.hashes.first[:three]).to eq '4444'
- end
-
- it 'allows renaming columns using regexp' do
- table2 = @table.map_headers(/one|uno/ => :three)
- expect(table2.hashes.first[:three]).to eq '4444'
- end
-
- it 'copies column mappings' do
- table = @table.map_column('one', &:to_i)
- table2 = table.map_headers('one' => 'three')
- expect(table2.hashes.first['three']).to eq 4444
- end
-
- it 'takes a block and operates on all the headers with it' do
- table2 = table.map_headers(&:downcase)
-
- expect(table2.hashes.first.keys).to match %w[ant anteater]
- end
-
- it 'treats the mappings in the provided hash as overrides when used with a block' do
- table2 = table.map_headers('ANT' => 'foo', &:downcase)
-
- expect(table2.hashes.first.keys).to match %w[foo anteater]
- end
- end
-
- describe 'diff!' do
- it 'should detect a complex diff' do
- t1 = DataTable.from(%(
- | 1 | 22 | 333 | 4444 |
- | 55555 | 666666 | 7777777 | 88888888 |
- | 999999999 | 0000000000 | 01010101010 | 121212121212 |
- | 4000 | ABC | DEF | 50000 |
- ))
-
- t2 = DataTable.from(%(
- | a | 4444 | 1 |
- | bb | 88888888 | 55555 |
- | ccc | xxxxxxxx | 999999999 |
- | dddd | 4000 | 300 |
- | e | 50000 | 4000 |
- ))
- expect { t1.diff!(t2) }.to raise_error(DataTable::Different) do |error|
- expect(error.table.to_s(indent: 14, color: false)).to eq %{
- | 1 | (-) 22 | (-) 333 | 4444 | (+) a |
- | 55555 | (-) 666666 | (-) 7777777 | 88888888 | (+) bb |
- | (-) 999999999 | (-) 0000000000 | (-) 01010101010 | (-) 121212121212 | (+) |
- | (+) 999999999 | (+) | (+) | (+) xxxxxxxx | (+) ccc |
- | (+) 300 | (+) | (+) | (+) 4000 | (+) dddd |
- | 4000 | (-) ABC | (-) DEF | 50000 | (+) e |
- }
- end
- end
-
- it 'should not change table when diffed with identical' do
- t = DataTable.from(%(
- |a|b|c|
- |d|e|f|
- |g|h|i|
- ))
- t.diff!(t.dup)
- expect(t.to_s(indent: 12, color: false)).to eq %(
- | a | b | c |
- | d | e | f |
- | g | h | i |
- )
- end
-
- context 'with empty tables' do
- it 'should allow diffing empty tables' do
- t1 = DataTable.from([[]])
- t2 = DataTable.from([[]])
- expect { t1.diff!(t2) }.not_to raise_error
- end
-
- it 'should be able to diff when the right table is empty' do
- t1 = DataTable.from(%(
- |a|b|c|
- |d|e|f|
- |g|h|i|
- ))
- t2 = DataTable.from([[]])
- expect { t1.diff!(t2) }.to raise_error(DataTable::Different) do |error|
- expect(error.table.to_s(indent: 16, color: false)).to eq %{
- | (-) a | (-) b | (-) c |
- | (-) d | (-) e | (-) f |
- | (-) g | (-) h | (-) i |
- }
- end
- end
-
- it 'should be able to diff when the left table is empty' do
- t1 = DataTable.from([[]])
- t2 = DataTable.from(%(
- |a|b|c|
- |d|e|f|
- |g|h|i|
- ))
- expect { t1.diff!(t2) }.to raise_error(DataTable::Different) do |error|
- expect(error.table.to_s(indent: 16, color: false)).to eq %{
- | (+) a | (+) b | (+) c |
- | (+) d | (+) e | (+) f |
- | (+) g | (+) h | (+) i |
- }
- end
- end
- end
-
- context 'in case of duplicate header values' do
- it 'raises no error for two identical tables' do
- t = DataTable.from(%(
- |a|a|c|
- |d|e|f|
- |g|h|i|
- ))
- t.diff!(t.dup)
- expect(t.to_s(indent: 12, color: false)).to eq %(
- | a | a | c |
- | d | e | f |
- | g | h | i |
- )
- end
-
- it 'detects a diff in one cell' do
- t1 = DataTable.from(%(
- |a|a|c|
- |d|e|f|
- |g|h|i|
- ))
- t2 = DataTable.from(%(
- |a|a|c|
- |d|oops|f|
- |g|h|i|
- ))
- expect { t1.diff!(t2) }.to raise_error(DataTable::Different) do |error|
- expect(error.table.to_s(indent: 16, color: false)).to eq %{
- | a | a | c |
- | (-) d | (-) e | (-) f |
- | (+) d | (+) oops | (+) f |
- | g | h | i |
- }
- end
- end
-
- it 'detects missing columns' do
- t1 = DataTable.from(%(
- |a|a|b|c|
- |d|d|e|f|
- |g|g|h|i|
- ))
- t2 = DataTable.from(%(
- |a|b|c|
- |d|e|f|
- |g|h|i|
- ))
- expect { t1.diff!(t2) }.to raise_error(DataTable::Different) do |error|
- expect(error.table.to_s(indent: 16, color: false)).to eq %{
- | a | (-) a | b | c |
- | d | (-) d | e | f |
- | g | (-) g | h | i |
- }
- end
- end
-
- it 'detects surplus columns' do
- t1 = DataTable.from(%(
- |a|b|c|
- |d|e|f|
- |g|h|i|
- ))
- t2 = DataTable.from(%(
- |a|b|a|c|
- |d|e|d|f|
- |g|h|g|i|
- ))
- expect { t1.diff!(t2, surplus_col: true) }.to raise_error(DataTable::Different) do |error|
- expect(error.table.to_s(indent: 16, color: false)).to eq %{
- | a | b | c | (+) a |
- | d | e | f | (+) d |
- | g | h | i | (+) g |
- }
- end
- end
- end
-
- it 'should inspect missing and surplus cells' do
- t1 = DataTable.from([
- %w[name male lastname swedish],
- %w[aslak true hellesøy false]
- ])
- t2 = DataTable.from([
- %w[name male lastname swedish],
- ['aslak', true, 'hellesøy', false]
- ])
- expect { t1.diff!(t2) }.to raise_error(DataTable::Different) do |error|
- expect(error.table.to_s(indent: 14, color: false)).to eq %{
- | name | male | lastname | swedish |
- | (-) aslak | (-) (i) "true" | (-) hellesøy | (-) (i) "false" |
- | (+) aslak | (+) (i) true | (+) hellesøy | (+) (i) false |
- }
- end
- end
-
- it 'should allow column mapping of target before diffing' do
- t1 = DataTable.from([
- %w[name male],
- %w[aslak true]
- ])
- t2 = DataTable.from([
- %w[name male],
- ['aslak', true]
- ])
- t1.map_column('male') { |m| m == 'true' }.diff!(t2)
- expect(t1.to_s(indent: 12, color: false)).to eq %(
- | name | male |
- | aslak | true |
- )
- end
-
- it 'should allow column mapping of argument before diffing' do
- t1 = DataTable.from([
- %w[name male],
- ['aslak', true]
- ])
- t2 = DataTable.from([
- %w[name male],
- %w[aslak true]
- ])
- t2.diff!(t1.map_column('male') { 'true' })
- expect(t1.to_s(indent: 12, color: false)).to eq %(
- | name | male |
- | aslak | true |
- )
- end
-
- it 'should allow header mapping before diffing' do
- t1 = DataTable.from([
- %w[Name Male],
- %w[aslak true]
- ])
- t1 = t1.map_headers('Name' => 'name', 'Male' => 'male')
- t1 = t1.map_column('male') { |m| m == 'true' }
-
- t2 = DataTable.from([
- %w[name male],
- ['aslak', true]
- ])
- t1.diff!(t2)
- expect(t1.to_s(indent: 12, color: false)).to eq %(
- | name | male |
- | aslak | true |
- )
- end
-
- it 'should detect seemingly identical tables as different' do
- t1 = DataTable.from([
- %w[X Y],
- %w[2 1]
- ])
- t2 = DataTable.from([
- %w[X Y],
- [2, 1]
- ])
- expect { t1.diff!(t2) }.to raise_error(DataTable::Different) do |error|
- expect(error.table.to_s(indent: 14, color: false)).to eq %{
- | X | Y |
- | (-) (i) "2" | (-) (i) "1" |
- | (+) (i) 2 | (+) (i) 1 |
- }
- end
- end
-
- it 'should not allow mappings that match more than 1 column' do
- t1 = DataTable.from([
- %w[Cuke Duke],
- %w[Foo Bar]
- ])
- expect do
- t1 = t1.map_headers(/uk/ => 'u')
- t1.hashes
- end.to raise_error(%(2 headers matched /uk/: ["Cuke", "Duke"]))
- end
-
- describe 'raising' do
- before do
- @t = DataTable.from(%(
- | a | b |
- | c | d |
- ))
- expect(@t).not_to eq nil
- end
-
- it 'should raise on missing rows' do
- t = DataTable.from(%(
- | a | b |
- ))
- expect { @t.dup.diff!(t) }.to raise_error(DataTable::Different)
- expect { @t.dup.diff!(t, missing_row: false) }.not_to raise_error
- end
-
- it 'should not raise on surplus rows when surplus is at the end' do
- t = DataTable.from(%(
- | a | b |
- | c | d |
- | e | f |
- ))
- expect { @t.dup.diff!(t) }.to raise_error(DataTable::Different)
- expect { @t.dup.diff!(t, surplus_row: false) }.not_to raise_error
- end
-
- it 'should not raise on surplus rows when surplus is interleaved' do
- t1 = DataTable.from(%(
- | row_1 | row_2 |
- | four | 4 |
- ))
- t2 = DataTable.from(%(
- | row_1 | row_2 |
- | one | 1 |
- | two | 2 |
- | three | 3 |
- | four | 4 |
- | five | 5 |
- ))
- expect { t1.dup.diff!(t2) }.to raise_error(DataTable::Different)
- expect { t1.dup.diff!(t2, surplus_row: false) }.not_to raise_error
- end
-
- it 'should raise on missing columns' do
- t = DataTable.from(%(
- | a |
- | c |
- ))
- expect { @t.dup.diff!(t) }.to raise_error(DataTable::Different)
- expect { @t.dup.diff!(t, missing_col: false) }.not_to raise_error
- end
-
- it 'should not raise on surplus columns' do
- t = DataTable.from(%(
- | a | b | x |
- | c | d | y |
- ))
- expect { @t.dup.diff!(t) }.not_to raise_error
- expect { @t.dup.diff!(t, surplus_col: true) }.to raise_error(DataTable::Different)
- end
-
- it 'should not raise on misplaced columns' do
- t = DataTable.from(%(
- | b | a |
- | d | c |
- ))
- expect { @t.dup.diff!(t) }.not_to raise_error
- expect { @t.dup.diff!(t, misplaced_col: true) }.to raise_error(DataTable::Different)
- end
- end
-
- it 'can compare to an Array' do
- t = DataTable.from(%(
- | b | a |
- | d | c |
- ))
- other = [%w[b a], %w[d c]]
-
- expect { t.diff!(other) }.not_to raise_error
- end
- end
-
- describe '#from' do
- it 'should allow Array of Hash' do
- t1 = DataTable.from([{ 'name' => 'aslak', 'male' => 'true' }])
- expect(t1.to_s(indent: 12, color: false)).to eq %(
- | male | name |
- | true | aslak |
- )
- end
- end
- end
- end
- end
|