mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
08e70126ae
This PR adds `invalid: :replace` for `CSV.open`. It is a PR similar to #129. https://github.com/ruby/csv/commit/5bf687341c
339 lines
8.5 KiB
Ruby
339 lines
8.5 KiB
Ruby
# frozen_string_literal: false
|
|
|
|
require_relative "../helper"
|
|
|
|
class TestCSVInterfaceRead < Test::Unit::TestCase
|
|
extend DifferentOFS
|
|
|
|
def setup
|
|
super
|
|
@data = ""
|
|
@data << "1\t2\t3\r\n"
|
|
@data << "4\t5\r\n"
|
|
@input = Tempfile.new(["interface-read", ".csv"], binmode: true)
|
|
@input << @data
|
|
@input.rewind
|
|
@rows = [
|
|
["1", "2", "3"],
|
|
["4", "5"],
|
|
]
|
|
end
|
|
|
|
def teardown
|
|
@input.close(true)
|
|
super
|
|
end
|
|
|
|
def test_foreach
|
|
rows = []
|
|
CSV.foreach(@input.path, col_sep: "\t", row_sep: "\r\n").each do |row|
|
|
rows << row
|
|
end
|
|
assert_equal(@rows, rows)
|
|
end
|
|
|
|
def test_foreach_mode
|
|
rows = []
|
|
CSV.foreach(@input.path, "r", col_sep: "\t", row_sep: "\r\n").each do |row|
|
|
rows << row
|
|
end
|
|
assert_equal(@rows, rows)
|
|
end
|
|
|
|
def test_foreach_enumurator
|
|
rows = CSV.foreach(@input.path, col_sep: "\t", row_sep: "\r\n").to_a
|
|
assert_equal(@rows, rows)
|
|
end
|
|
|
|
def test_closed?
|
|
csv = CSV.open(@input.path, "r+", col_sep: "\t", row_sep: "\r\n")
|
|
assert_not_predicate(csv, :closed?)
|
|
csv.close
|
|
assert_predicate(csv, :closed?)
|
|
end
|
|
|
|
def test_open_auto_close
|
|
csv = nil
|
|
CSV.open(@input.path) do |_csv|
|
|
csv = _csv
|
|
end
|
|
assert_predicate(csv, :closed?)
|
|
end
|
|
|
|
def test_open_closed
|
|
csv = nil
|
|
CSV.open(@input.path) do |_csv|
|
|
csv = _csv
|
|
csv.close
|
|
end
|
|
assert_predicate(csv, :closed?)
|
|
end
|
|
|
|
def test_open_block_return_value
|
|
return_value = CSV.open(@input.path) do
|
|
"Return value."
|
|
end
|
|
assert_equal("Return value.", return_value)
|
|
end
|
|
|
|
def test_open_encoding_valid
|
|
# U+1F600 GRINNING FACE
|
|
# U+1F601 GRINNING FACE WITH SMILING EYES
|
|
File.open(@input.path, "w") do |file|
|
|
file << "\u{1F600},\u{1F601}"
|
|
end
|
|
CSV.open(@input.path, encoding: "utf-8") do |csv|
|
|
assert_equal([["\u{1F600}", "\u{1F601}"]],
|
|
csv.to_a)
|
|
end
|
|
end
|
|
|
|
def test_open_encoding_invalid
|
|
# U+1F600 GRINNING FACE
|
|
# U+1F601 GRINNING FACE WITH SMILING EYES
|
|
File.open(@input.path, "w") do |file|
|
|
file << "\u{1F600},\u{1F601}"
|
|
end
|
|
CSV.open(@input.path, encoding: "EUC-JP") do |csv|
|
|
error = assert_raise(CSV::MalformedCSVError) do
|
|
csv.shift
|
|
end
|
|
assert_equal("Invalid byte sequence in EUC-JP in line 1.",
|
|
error.message)
|
|
end
|
|
end
|
|
|
|
def test_open_encoding_nonexistent
|
|
_output, error = capture_output do
|
|
CSV.open(@input.path, encoding: "nonexistent") do
|
|
end
|
|
end
|
|
assert_equal("path:0: warning: Unsupported encoding nonexistent ignored\n",
|
|
error.gsub(/\A.+:\d+: /, "path:0: "))
|
|
end
|
|
|
|
def test_open_encoding_utf_8_with_bom
|
|
# U+FEFF ZERO WIDTH NO-BREAK SPACE, BOM
|
|
# U+1F600 GRINNING FACE
|
|
# U+1F601 GRINNING FACE WITH SMILING EYES
|
|
File.open(@input.path, "w") do |file|
|
|
file << "\u{FEFF}\u{1F600},\u{1F601}"
|
|
end
|
|
CSV.open(@input.path, encoding: "bom|utf-8") do |csv|
|
|
assert_equal([["\u{1F600}", "\u{1F601}"]],
|
|
csv.to_a)
|
|
end
|
|
end
|
|
|
|
def test_open_invalid_byte_sequence_in_utf_8
|
|
CSV.open(@input.path, "w", encoding: Encoding::CP932) do |rows|
|
|
error = assert_raise(Encoding::InvalidByteSequenceError) do
|
|
rows << ["\x82\xa0"]
|
|
end
|
|
assert_equal('"\x82" on UTF-8',
|
|
error.message)
|
|
end
|
|
end
|
|
|
|
def test_open_with_invalid_nil
|
|
CSV.open(@input.path, "w", encoding: Encoding::CP932, invalid: nil) do |rows|
|
|
error = assert_raise(Encoding::InvalidByteSequenceError) do
|
|
rows << ["\x82\xa0"]
|
|
end
|
|
assert_equal('"\x82" on UTF-8',
|
|
error.message)
|
|
end
|
|
end
|
|
|
|
def test_open_with_invalid_replace
|
|
CSV.open(@input.path, "w", encoding: Encoding::CP932, invalid: :replace) do |rows|
|
|
rows << ["\x82\xa0".force_encoding(Encoding::UTF_8)]
|
|
end
|
|
CSV.open(@input.path, encoding: Encoding::CP932) do |csv|
|
|
assert_equal([["??"]],
|
|
csv.to_a)
|
|
end
|
|
end
|
|
|
|
def test_open_with_invalid_replace_and_replace_string
|
|
CSV.open(@input.path, "w", encoding: Encoding::CP932, invalid: :replace, replace: "X") do |rows|
|
|
rows << ["\x82\xa0".force_encoding(Encoding::UTF_8)]
|
|
end
|
|
CSV.open(@input.path, encoding: Encoding::CP932) do |csv|
|
|
assert_equal([["XX"]],
|
|
csv.to_a)
|
|
end
|
|
end
|
|
|
|
def test_open_with_undef_replace
|
|
# U+00B7 Middle Dot
|
|
CSV.open(@input.path, "w", encoding: Encoding::CP932, undef: :replace) do |rows|
|
|
rows << ["\u00B7"]
|
|
end
|
|
CSV.open(@input.path, encoding: Encoding::CP932) do |csv|
|
|
assert_equal([["?"]],
|
|
csv.to_a)
|
|
end
|
|
end
|
|
|
|
def test_open_with_undef_replace_and_replace_string
|
|
# U+00B7 Middle Dot
|
|
CSV.open(@input.path, "w", encoding: Encoding::CP932, undef: :replace, replace: "X") do |rows|
|
|
rows << ["\u00B7"]
|
|
end
|
|
CSV.open(@input.path, encoding: Encoding::CP932) do |csv|
|
|
assert_equal([["X"]],
|
|
csv.to_a)
|
|
end
|
|
end
|
|
|
|
def test_parse
|
|
assert_equal(@rows,
|
|
CSV.parse(@data, col_sep: "\t", row_sep: "\r\n"))
|
|
end
|
|
|
|
def test_parse_block
|
|
rows = []
|
|
CSV.parse(@data, col_sep: "\t", row_sep: "\r\n") do |row|
|
|
rows << row
|
|
end
|
|
assert_equal(@rows, rows)
|
|
end
|
|
|
|
def test_parse_enumerator
|
|
rows = CSV.parse(@data, col_sep: "\t", row_sep: "\r\n").to_a
|
|
assert_equal(@rows, rows)
|
|
end
|
|
|
|
def test_parse_headers_only
|
|
table = CSV.parse("a,b,c", headers: true)
|
|
assert_equal([
|
|
["a", "b", "c"],
|
|
[],
|
|
],
|
|
[
|
|
table.headers,
|
|
table.each.to_a,
|
|
])
|
|
end
|
|
|
|
def test_parse_line
|
|
assert_equal(["1", "2", "3"],
|
|
CSV.parse_line("1;2;3", col_sep: ";"))
|
|
end
|
|
|
|
def test_parse_line_shortcut
|
|
assert_equal(["1", "2", "3"],
|
|
"1;2;3".parse_csv(col_sep: ";"))
|
|
end
|
|
|
|
def test_parse_line_empty
|
|
assert_equal(nil, CSV.parse_line("")) # to signal eof
|
|
end
|
|
|
|
def test_parse_line_empty_line
|
|
assert_equal([], CSV.parse_line("\n1,2,3"))
|
|
end
|
|
|
|
def test_read
|
|
assert_equal(@rows,
|
|
CSV.read(@input.path, col_sep: "\t", row_sep: "\r\n"))
|
|
end
|
|
|
|
def test_readlines
|
|
assert_equal(@rows,
|
|
CSV.readlines(@input.path, col_sep: "\t", row_sep: "\r\n"))
|
|
end
|
|
|
|
def test_open_read
|
|
rows = CSV.open(@input.path, col_sep: "\t", row_sep: "\r\n") do |csv|
|
|
csv.read
|
|
end
|
|
assert_equal(@rows, rows)
|
|
end
|
|
|
|
def test_open_readlines
|
|
rows = CSV.open(@input.path, col_sep: "\t", row_sep: "\r\n") do |csv|
|
|
csv.readlines
|
|
end
|
|
assert_equal(@rows, rows)
|
|
end
|
|
|
|
def test_table
|
|
table = CSV.table(@input.path, col_sep: "\t", row_sep: "\r\n")
|
|
assert_equal(CSV::Table.new([
|
|
CSV::Row.new([:"1", :"2", :"3"], [4, 5, nil]),
|
|
]),
|
|
table)
|
|
end
|
|
|
|
def test_shift # aliased as gets() and readline()
|
|
CSV.open(@input.path, "rb+", col_sep: "\t", row_sep: "\r\n") do |csv|
|
|
rows = [
|
|
csv.shift,
|
|
csv.shift,
|
|
csv.shift,
|
|
]
|
|
assert_equal(@rows + [nil],
|
|
rows)
|
|
end
|
|
end
|
|
|
|
def test_enumerator
|
|
CSV.open(@input.path, col_sep: "\t", row_sep: "\r\n") do |csv|
|
|
assert_equal(@rows, csv.each.to_a)
|
|
end
|
|
end
|
|
|
|
def test_shift_and_each
|
|
CSV.open(@input.path, col_sep: "\t", row_sep: "\r\n") do |csv|
|
|
rows = []
|
|
rows << csv.shift
|
|
rows.concat(csv.each.to_a)
|
|
assert_equal(@rows, rows)
|
|
end
|
|
end
|
|
|
|
def test_each_twice
|
|
CSV.open(@input.path, col_sep: "\t", row_sep: "\r\n") do |csv|
|
|
assert_equal([
|
|
@rows,
|
|
[],
|
|
],
|
|
[
|
|
csv.each.to_a,
|
|
csv.each.to_a,
|
|
])
|
|
end
|
|
end
|
|
|
|
def test_eof?
|
|
eofs = []
|
|
CSV.open(@input.path, col_sep: "\t", row_sep: "\r\n") do |csv|
|
|
eofs << csv.eof?
|
|
csv.shift
|
|
eofs << csv.eof?
|
|
csv.shift
|
|
eofs << csv.eof?
|
|
end
|
|
assert_equal([false, false, true],
|
|
eofs)
|
|
end
|
|
|
|
def test_new_nil
|
|
assert_raise_with_message ArgumentError, "Cannot parse nil as CSV" do
|
|
CSV.new(nil)
|
|
end
|
|
end
|
|
|
|
def test_options_not_modified
|
|
options = {}.freeze
|
|
CSV.foreach(@input.path, **options)
|
|
CSV.open(@input.path, **options) {}
|
|
CSV.parse("", **options)
|
|
CSV.parse_line("", **options)
|
|
CSV.read(@input.path, **options)
|
|
CSV.readlines(@input.path, **options)
|
|
CSV.table(@input.path, **options)
|
|
end
|
|
end
|