# -*- 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