1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/test/csv/test_row.rb
Jim Kane b219cd5ac3
[ruby/csv] Make CSV::Row#dup return a usable Row (#108)
* Make CSV::Row#dup return a usable Row

Previously, calling `dup` on a `CSV::Row` object yielded an object whose
copy was too shallow. Changing the clone's fields would also change the
fields on the source. This change makes the clone more distinct from the
source, so that changes can be made to its fields without affecting the
source.

* Simplify

https://github.com/ruby/csv/commit/64a1ea06fc
2020-07-20 02:32:49 +09:00

435 lines
11 KiB
Ruby

# -*- coding: utf-8 -*-
# frozen_string_literal: false
require_relative "helper"
class TestCSVRow < Test::Unit::TestCase
extend DifferentOFS
def setup
super
@row = CSV::Row.new(%w{A B C A A}, [1, 2, 3, 4])
end
def test_initialize
# basic
row = CSV::Row.new(%w{A B C}, [1, 2, 3])
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([["A", 1], ["B", 2], ["C", 3]], row.to_a)
# missing headers
row = CSV::Row.new(%w{A}, [1, 2, 3])
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([["A", 1], [nil, 2], [nil, 3]], row.to_a)
# missing fields
row = CSV::Row.new(%w{A B C}, [1, 2])
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([["A", 1], ["B", 2], ["C", nil]], row.to_a)
end
def test_row_type
# field rows
row = CSV::Row.new(%w{A B C}, [1, 2, 3]) # implicit
assert_not_predicate(row, :header_row?)
assert_predicate(row, :field_row?)
row = CSV::Row.new(%w{A B C}, [1, 2, 3], false) # explicit
assert_not_predicate(row, :header_row?)
assert_predicate(row, :field_row?)
# header row
row = CSV::Row.new(%w{A B C}, [1, 2, 3], true)
assert_predicate(row, :header_row?)
assert_not_predicate(row, :field_row?)
end
def test_headers
assert_equal(%w{A B C A A}, @row.headers)
end
def test_field
# by name
assert_equal(2, @row.field("B"))
assert_equal(2, @row["B"]) # alias
# by index
assert_equal(3, @row.field(2))
# by range
assert_equal([2,3], @row.field(1..2))
# missing
assert_nil(@row.field("Missing"))
assert_nil(@row.field(10))
# minimum index
assert_equal(1, @row.field("A"))
assert_equal(1, @row.field("A", 0))
assert_equal(4, @row.field("A", 1))
assert_equal(4, @row.field("A", 2))
assert_equal(4, @row.field("A", 3))
assert_equal(nil, @row.field("A", 4))
assert_equal(nil, @row.field("A", 5))
end
def test_fetch
# only by name
assert_equal(2, @row.fetch('B'))
# missing header raises KeyError
assert_raise KeyError do
@row.fetch('foo')
end
# missing header yields itself to block
assert_equal 'bar', @row.fetch('foo') { |header|
header == 'foo' ? 'bar' : false }
# missing header returns the given default value
assert_equal 'bar', @row.fetch('foo', 'bar')
# more than one vararg raises ArgumentError
assert_raise ArgumentError do
@row.fetch('foo', 'bar', 'baz')
end
end
def test_has_key?
assert_equal(true, @row.has_key?('B'))
assert_equal(false, @row.has_key?('foo'))
# aliases
assert_equal(true, @row.header?('B'))
assert_equal(false, @row.header?('foo'))
assert_equal(true, @row.include?('B'))
assert_equal(false, @row.include?('foo'))
assert_equal(true, @row.member?('B'))
assert_equal(false, @row.member?('foo'))
assert_equal(true, @row.key?('B'))
assert_equal(false, @row.key?('foo'))
end
def test_set_field
# set field by name
assert_equal(100, @row["A"] = 100)
# set field by index
assert_equal(300, @row[3] = 300)
# set field by name and minimum index
assert_equal([:a, :b, :c], @row["A", 4] = [:a, :b, :c])
# verify the changes
assert_equal( [ ["A", 100],
["B", 2],
["C", 3],
["A", 300],
["A", [:a, :b, :c]] ], @row.to_a )
# assigning an index past the end
assert_equal("End", @row[10] = "End")
assert_equal( [ ["A", 100],
["B", 2],
["C", 3],
["A", 300],
["A", [:a, :b, :c]],
[nil, nil],
[nil, nil],
[nil, nil],
[nil, nil],
[nil, nil],
[nil, "End"] ], @row.to_a )
# assigning a new field by header
assert_equal("New", @row[:new] = "New")
assert_equal( [ ["A", 100],
["B", 2],
["C", 3],
["A", 300],
["A", [:a, :b, :c]],
[nil, nil],
[nil, nil],
[nil, nil],
[nil, nil],
[nil, nil],
[nil, "End"],
[:new, "New"] ], @row.to_a )
end
def test_append
# add a value
assert_equal(@row, @row << "Value")
assert_equal( [ ["A", 1],
["B", 2],
["C", 3],
["A", 4],
["A", nil],
[nil, "Value"] ], @row.to_a )
# add a pair
assert_equal(@row, @row << %w{Header Field})
assert_equal( [ ["A", 1],
["B", 2],
["C", 3],
["A", 4],
["A", nil],
[nil, "Value"],
%w{Header Field} ], @row.to_a )
# a pair with Hash syntax
assert_equal(@row, @row << {key: :value})
assert_equal( [ ["A", 1],
["B", 2],
["C", 3],
["A", 4],
["A", nil],
[nil, "Value"],
%w{Header Field},
[:key, :value] ], @row.to_a )
# multiple fields at once
assert_equal(@row, @row.push(100, 200, [:last, 300]))
assert_equal( [ ["A", 1],
["B", 2],
["C", 3],
["A", 4],
["A", nil],
[nil, "Value"],
%w{Header Field},
[:key, :value],
[nil, 100],
[nil, 200],
[:last, 300] ], @row.to_a )
end
def test_delete
# by index
assert_equal(["B", 2], @row.delete(1))
# by header
assert_equal(["C", 3], @row.delete("C"))
end
def test_delete_if
assert_equal(@row, @row.delete_if { |h, f| h == "A" and not f.nil? })
assert_equal([["B", 2], ["C", 3], ["A", nil]], @row.to_a)
end
def test_delete_if_without_block
enum = @row.delete_if
assert_instance_of(Enumerator, enum)
assert_equal(@row.size, enum.size)
assert_equal(@row, enum.each { |h, f| h == "A" and not f.nil? })
assert_equal([["B", 2], ["C", 3], ["A", nil]], @row.to_a)
end
def test_fields
# all fields
assert_equal([1, 2, 3, 4, nil], @row.fields)
# by header
assert_equal([1, 3], @row.fields("A", "C"))
# by index
assert_equal([2, 3, nil], @row.fields(1, 2, 10))
# by both
assert_equal([2, 3, 4], @row.fields("B", "C", 3))
# with minimum indices
assert_equal([2, 3, 4], @row.fields("B", "C", ["A", 3]))
# by header range
assert_equal([2, 3], @row.values_at("B".."C"))
end
def test_index
# basic usage
assert_equal(0, @row.index("A"))
assert_equal(1, @row.index("B"))
assert_equal(2, @row.index("C"))
assert_equal(nil, @row.index("Z"))
# with minimum index
assert_equal(0, @row.index("A"))
assert_equal(0, @row.index("A", 0))
assert_equal(3, @row.index("A", 1))
assert_equal(3, @row.index("A", 2))
assert_equal(3, @row.index("A", 3))
assert_equal(4, @row.index("A", 4))
assert_equal(nil, @row.index("A", 5))
end
def test_queries
# fields
assert(@row.field?(4))
assert(@row.field?(nil))
assert(!@row.field?(10))
end
def test_each
# array style
ary = @row.to_a
@row.each do |pair|
assert_equal(ary.first.first, pair.first)
assert_equal(ary.shift.last, pair.last)
end
# hash style
ary = @row.to_a
@row.each do |header, field|
assert_equal(ary.first.first, header)
assert_equal(ary.shift.last, field)
end
# verify that we can chain the call
assert_equal(@row, @row.each { })
# without block
ary = @row.to_a
enum = @row.each
assert_instance_of(Enumerator, enum)
assert_equal(@row.size, enum.size)
enum.each do |pair|
assert_equal(ary.first.first, pair.first)
assert_equal(ary.shift.last, pair.last)
end
end
def test_each_pair
assert_equal([
["A", 1],
["B", 2],
["C", 3],
["A", 4],
["A", nil],
],
@row.each_pair.to_a)
end
def test_enumerable
assert_equal( [["A", 1], ["A", 4], ["A", nil]],
@row.select { |pair| pair.first == "A" } )
assert_equal(10, @row.inject(0) { |sum, (_, n)| sum + (n || 0) })
end
def test_to_a
row = CSV::Row.new(%w{A B C}, [1, 2, 3]).to_a
assert_instance_of(Array, row)
row.each do |pair|
assert_instance_of(Array, pair)
assert_equal(2, pair.size)
end
assert_equal([["A", 1], ["B", 2], ["C", 3]], row)
end
def test_to_hash
hash = @row.to_hash
assert_equal({"A" => @row["A"], "B" => @row["B"], "C" => @row["C"]}, hash)
hash.keys.each_with_index do |string_key, h|
assert_predicate(string_key, :frozen?)
assert_same(string_key, @row.headers[h])
end
end
def test_to_csv
# normal conversion
assert_equal("1,2,3,4,\n", @row.to_csv)
assert_equal("1,2,3,4,\n", @row.to_s) # alias
# with options
assert_equal( "1|2|3|4|\r\n",
@row.to_csv(col_sep: "|", row_sep: "\r\n") )
end
def test_array_delegation
assert_not_empty(@row, "Row was empty.")
assert_equal([@row.headers.size, @row.fields.size].max, @row.size)
end
def test_inspect_shows_header_field_pairs
str = @row.inspect
@row.each do |header, field|
assert_include(str, "#{header.inspect}:#{field.inspect}",
"Header field pair not found.")
end
end
def test_inspect_encoding_is_ascii_compatible
assert_send([Encoding, :compatible?,
Encoding.find("US-ASCII"),
@row.inspect.encoding],
"inspect() was not ASCII compatible.")
end
def test_inspect_shows_symbol_headers_as_bare_attributes
str = CSV::Row.new(@row.headers.map { |h| h.to_sym }, @row.fields).inspect
@row.each do |header, field|
assert_include(str, "#{header}:#{field.inspect}",
"Header field pair not found.")
end
end
def test_can_be_compared_with_other_classes
assert_not_nil(CSV::Row.new([ ], [ ]), "The row was nil")
end
def test_can_be_compared_when_not_a_row
r = @row == []
assert_equal false, r
end
def test_dig_by_index
assert_equal(2, @row.dig(1))
assert_nil(@row.dig(100))
end
def test_dig_by_header
assert_equal(2, @row.dig("B"))
assert_nil(@row.dig("Missing"))
end
def test_dig_cell
row = CSV::Row.new(%w{A}, [["foo", ["bar", ["baz"]]]])
assert_equal("foo", row.dig(0, 0))
assert_equal("bar", row.dig(0, 1, 0))
assert_equal("foo", row.dig("A", 0))
assert_equal("bar", row.dig("A", 1, 0))
end
def test_dig_cell_no_dig
row = CSV::Row.new(%w{A}, ["foo"])
assert_raise(TypeError) do
row.dig(0, 0)
end
assert_raise(TypeError) do
row.dig("A", 0)
end
end
def test_dup
row = CSV::Row.new(["A"], ["foo"])
dupped_row = row.dup
dupped_row["A"] = "bar"
assert_equal(["foo", "bar"],
[row["A"], dupped_row["A"]])
dupped_row.delete("A")
assert_equal(["foo", nil],
[row["A"], dupped_row["A"]])
end
end