1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Import CSV 3.0.8

This includes performance improvements and backward incompatibility
fixes.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67560 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
kou 2019-04-14 21:01:51 +00:00
parent fb96811d15
commit e3b6c7c7eb
23 changed files with 1534 additions and 650 deletions

View file

@ -0,0 +1,47 @@
# frozen_string_literal: false
require_relative "../helper"
class TestCSVInterfaceDelegation < Test::Unit::TestCase
class TestStringIO < self
def setup
@csv = CSV.new("h1,h2")
end
def test_flock
assert_raise(NotImplementedError) do
@csv.flock(File::LOCK_EX)
end
end
def test_ioctl
assert_raise(NotImplementedError) do
@csv.ioctl(0)
end
end
def test_stat
assert_raise(NotImplementedError) do
@csv.stat
end
end
def test_to_i
assert_raise(NotImplementedError) do
@csv.to_i
end
end
def test_binmode?
assert_equal(false, @csv.binmode?)
end
def test_path
assert_equal(nil, @csv.path)
end
def test_to_io
assert_instance_of(StringIO, @csv.to_io)
end
end
end

View file

@ -0,0 +1,277 @@
# 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"], options: {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_io 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_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

View file

@ -0,0 +1,51 @@
# frozen_string_literal: false
require_relative "../helper"
class TestCSVInterfaceReadWrite < Test::Unit::TestCase
extend DifferentOFS
def test_filter
rows = [[1, 2, 3], [4, 5]]
input = <<-CSV
1;2;3
4;5
CSV
output = ""
CSV.filter(input, output,
in_col_sep: ";",
out_col_sep: ",",
converters: :all) do |row|
row.map! {|n| n * 2}
row << "Added\r"
end
assert_equal(<<-CSV, output)
2,4,6,"Added\r"
8,10,"Added\r"
CSV
end
def test_instance_same
data = ""
assert_equal(CSV.instance(data, col_sep: ";").object_id,
CSV.instance(data, col_sep: ";").object_id)
end
def test_instance_append
output = ""
CSV.instance(output, col_sep: ";") << ["a", "b", "c"]
assert_equal(<<-CSV, output)
a;b;c
CSV
CSV.instance(output, col_sep: ";") << [1, 2, 3]
assert_equal(<<-CSV, output)
a;b;c
1;2;3
CSV
end
def test_instance_shortcut
assert_equal(CSV.instance,
CSV {|csv| csv})
end
end

View file

@ -0,0 +1,174 @@
# frozen_string_literal: false
require_relative "../helper"
class TestCSVInterfaceWrite < Test::Unit::TestCase
extend DifferentOFS
def setup
super
@output = Tempfile.new(["interface-write", ".csv"])
end
def teardown
@output.close(true)
super
end
def test_generate_default
csv_text = CSV.generate do |csv|
csv << [1, 2, 3] << [4, nil, 5]
end
assert_equal(<<-CSV, csv_text)
1,2,3
4,,5
CSV
end
def test_generate_append
csv_text = <<-CSV
1,2,3
4,,5
CSV
CSV.generate(csv_text) do |csv|
csv << ["last", %Q{"row"}]
end
assert_equal(<<-CSV, csv_text)
1,2,3
4,,5
last,"""row"""
CSV
end
def test_generate_no_new_line
csv_text = CSV.generate("test") do |csv|
csv << ["row"]
end
assert_equal(<<-CSV, csv_text)
testrow
CSV
end
def test_generate_line_col_sep
line = CSV.generate_line(["1", "2", "3"], col_sep: ";")
assert_equal(<<-LINE, line)
1;2;3
LINE
end
def test_generate_line_row_sep
line = CSV.generate_line(["1", "2"], row_sep: nil)
assert_equal(<<-LINE.chomp, line)
1,2
LINE
end
def test_generate_line_shortcut
line = ["1", "2", "3"].to_csv(col_sep: ";")
assert_equal(<<-LINE, line)
1;2;3
LINE
end
def test_headers_detection
headers = ["a", "b", "c"]
CSV.open(@output.path, "w", headers: true) do |csv|
csv << headers
csv << ["1", "2", "3"]
assert_equal(headers, csv.headers)
end
end
def test_lineno
CSV.open(@output.path, "w") do |csv|
n_lines = 20
n_lines.times do
csv << ["a", "b", "c"]
end
assert_equal(n_lines, csv.lineno)
end
end
def test_append_row
CSV.open(@output.path, "wb") do |csv|
csv <<
CSV::Row.new([], ["1", "2", "3"]) <<
CSV::Row.new([], ["a", "b", "c"])
end
assert_equal(<<-CSV, File.read(@output.path, mode: "rb"))
1,2,3
a,b,c
CSV
end
def test_append_hash
CSV.open(@output.path, "wb", headers: true) do |csv|
csv << [:a, :b, :c]
csv << {a: 1, b: 2, c: 3}
csv << {a: 4, b: 5, c: 6}
end
assert_equal(<<-CSV, File.read(@output.path, mode: "rb"))
a,b,c
1,2,3
4,5,6
CSV
end
def test_append_hash_headers_array
CSV.open(@output.path, "wb", headers: [:b, :a, :c]) do |csv|
csv << {a: 1, b: 2, c: 3}
csv << {a: 4, b: 5, c: 6}
end
assert_equal(<<-CSV, File.read(@output.path, mode: "rb"))
2,1,3
5,4,6
CSV
end
def test_append_hash_headers_string
CSV.open(@output.path, "wb", headers: "b|a|c", col_sep: "|") do |csv|
csv << {"a" => 1, "b" => 2, "c" => 3}
csv << {"a" => 4, "b" => 5, "c" => 6}
end
assert_equal(<<-CSV, File.read(@output.path, mode: "rb"))
2|1|3
5|4|6
CSV
end
def test_write_headers
CSV.open(@output.path,
"wb",
headers: "b|a|c",
write_headers: true,
col_sep: "|" ) do |csv|
csv << {"a" => 1, "b" => 2, "c" => 3}
csv << {"a" => 4, "b" => 5, "c" => 6}
end
assert_equal(<<-CSV, File.read(@output.path, mode: "rb"))
b|a|c
2|1|3
5|4|6
CSV
end
def test_write_headers_empty
CSV.open(@output.path,
"wb",
headers: "b|a|c",
write_headers: true,
col_sep: "|" ) do |csv|
end
assert_equal(<<-CSV, File.read(@output.path, mode: "rb"))
b|a|c
CSV
end
def test_options_not_modified
options = {}.freeze
CSV.generate(options) {}
CSV.generate_line([], options)
CSV.filter("", "", options)
CSV.instance("", options)
end
end