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:
parent
fb96811d15
commit
e3b6c7c7eb
23 changed files with 1534 additions and 650 deletions
47
test/csv/interface/test_delegation.rb
Normal file
47
test/csv/interface/test_delegation.rb
Normal 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
|
||||
277
test/csv/interface/test_read.rb
Normal file
277
test/csv/interface/test_read.rb
Normal 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
|
||||
51
test/csv/interface/test_read_write.rb
Normal file
51
test/csv/interface/test_read_write.rb
Normal 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
|
||||
174
test/csv/interface/test_write.rb
Normal file
174
test/csv/interface/test_write.rb
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue