mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
b219cd5ac3
* 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
435 lines
11 KiB
Ruby
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
|