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

* lib/csv.rb: Import the FasterCSV source as the new CSV class.

* test/csv/*:  Added all applicable tests from FasterCSV.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@14646 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
jeg2 2007-12-25 02:46:26 +00:00
parent 0d570142ba
commit 29ba327bd1
13 changed files with 3946 additions and 0 deletions

View file

@ -1,3 +1,9 @@
Tue Dec 25 11:45:34 2007 James Edward Gray II <jeg2@ruby-lang.org>
* lib/csv.rb: Import the FasterCSV source as the new CSV class.
* test/csv/*: Added all applicable tests from FasterCSV.
Tue Dec 25 11:33:52 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* error.c (report_bug): uses ruby_description.

1892
lib/csv.rb Normal file

File diff suppressed because it is too large Load diff

BIN
test/csv/line_endings.gz Normal file

Binary file not shown.

164
test/csv/tc_csv_parsing.rb Normal file
View file

@ -0,0 +1,164 @@
#!/usr/local/bin/ruby -w
# tc_csv_parsing.rb
#
# Created by James Edward Gray II on 2005-10-31.
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
# under the terms of Ruby's license.
require "test/unit"
require "csv"
#
# Following tests are my interpretation of the
# {CSV RCF}[http://www.ietf.org/rfc/rfc4180.txt]. I only deviate from that
# document in one place (intentionally) and that is to make the default row
# separator <tt>$/</tt>.
#
class TestCSVParsing < Test::Unit::TestCase
def test_mastering_regex_example
ex = %Q{Ten Thousand,10000, 2710 ,,"10,000","It's ""10 Grand"", baby",10K}
assert_equal( [ "Ten Thousand", "10000", " 2710 ", nil, "10,000",
"It's \"10 Grand\", baby", "10K" ],
CSV.parse_line(ex) )
end
# Old Ruby 1.8 CSV library tests.
def test_std_lib_csv
[ ["\t", ["\t"]],
["foo,\"\"\"\"\"\",baz", ["foo", "\"\"", "baz"]],
["foo,\"\"\"bar\"\"\",baz", ["foo", "\"bar\"", "baz"]],
["\"\"\"\n\",\"\"\"\n\"", ["\"\n", "\"\n"]],
["foo,\"\r\n\",baz", ["foo", "\r\n", "baz"]],
["\"\"", [""]],
["foo,\"\"\"\",baz", ["foo", "\"", "baz"]],
["foo,\"\r.\n\",baz", ["foo", "\r.\n", "baz"]],
["foo,\"\r\",baz", ["foo", "\r", "baz"]],
["foo,\"\",baz", ["foo", "", "baz"]],
["\",\"", [","]],
["foo", ["foo"]],
[",,", [nil, nil, nil]],
[",", [nil, nil]],
["foo,\"\n\",baz", ["foo", "\n", "baz"]],
["foo,,baz", ["foo", nil, "baz"]],
["\"\"\"\r\",\"\"\"\r\"", ["\"\r", "\"\r"]],
["\",\",\",\"", [",", ","]],
["foo,bar,", ["foo", "bar", nil]],
[",foo,bar", [nil, "foo", "bar"]],
["foo,bar", ["foo", "bar"]],
[";", [";"]],
["\t,\t", ["\t", "\t"]],
["foo,\"\r\n\r\",baz", ["foo", "\r\n\r", "baz"]],
["foo,\"\r\n\n\",baz", ["foo", "\r\n\n", "baz"]],
["foo,\"foo,bar\",baz", ["foo", "foo,bar", "baz"]],
[";,;", [";", ";"]] ].each do |csv_test|
assert_equal(csv_test.last, CSV.parse_line(csv_test.first))
end
[ ["foo,\"\"\"\"\"\",baz", ["foo", "\"\"", "baz"]],
["foo,\"\"\"bar\"\"\",baz", ["foo", "\"bar\"", "baz"]],
["foo,\"\r\n\",baz", ["foo", "\r\n", "baz"]],
["\"\"", [""]],
["foo,\"\"\"\",baz", ["foo", "\"", "baz"]],
["foo,\"\r.\n\",baz", ["foo", "\r.\n", "baz"]],
["foo,\"\r\",baz", ["foo", "\r", "baz"]],
["foo,\"\",baz", ["foo", "", "baz"]],
["foo", ["foo"]],
[",,", [nil, nil, nil]],
[",", [nil, nil]],
["foo,\"\n\",baz", ["foo", "\n", "baz"]],
["foo,,baz", ["foo", nil, "baz"]],
["foo,bar", ["foo", "bar"]],
["foo,\"\r\n\n\",baz", ["foo", "\r\n\n", "baz"]],
["foo,\"foo,bar\",baz", ["foo", "foo,bar", "baz"]] ].each do |csv_test|
assert_equal(csv_test.last, CSV.parse_line(csv_test.first))
end
end
# From: http://ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-core/6496
def test_aras_edge_cases
[ [%Q{a,b}, ["a", "b"]],
[%Q{a,"""b"""}, ["a", "\"b\""]],
[%Q{a,"""b"}, ["a", "\"b"]],
[%Q{a,"b"""}, ["a", "b\""]],
[%Q{a,"\nb"""}, ["a", "\nb\""]],
[%Q{a,"""\nb"}, ["a", "\"\nb"]],
[%Q{a,"""\nb\n"""}, ["a", "\"\nb\n\""]],
[%Q{a,"""\nb\n""",\nc}, ["a", "\"\nb\n\"", nil]],
[%Q{a,,,}, ["a", nil, nil, nil]],
[%Q{,}, [nil, nil]],
[%Q{"",""}, ["", ""]],
[%Q{""""}, ["\""]],
[%Q{"""",""}, ["\"",""]],
[%Q{,""}, [nil,""]],
[%Q{,"\r"}, [nil,"\r"]],
[%Q{"\r\n,"}, ["\r\n,"]],
[%Q{"\r\n,",}, ["\r\n,", nil]] ].each do |edge_case|
assert_equal(edge_case.last, CSV.parse_line(edge_case.first))
end
end
def test_james_edge_cases
# A read at eof? should return nil.
assert_equal(nil, CSV.parse_line(""))
#
# With Ruby 1.8 CSV it's impossible to tell an empty line from a line
# containing a single +nil+ field. The old CSV library returns
# <tt>[nil]</tt> in these cases, but <tt>Array.new</tt> makes more sense to
# me.
#
assert_equal(Array.new, CSV.parse_line("\n1,2,3\n"))
end
def test_malformed_csv
assert_raise(CSV::MalformedCSVError) do
CSV.parse_line("1,2\r,3", :row_sep => "\n")
end
bad_data = <<-END_DATA.gsub(/^ +/, "")
line,1,abc
line,2,"def\nghi"
line,4,some\rjunk
line,5,jkl
END_DATA
lines = bad_data.to_a
assert_equal(6, lines.size)
assert_match(/\Aline,4/, lines.find { |l| l =~ /some\rjunk/ })
csv = CSV.new(bad_data)
begin
loop do
assert_not_nil(csv.shift)
assert_send([csv.lineno, :<, 4])
end
rescue CSV::MalformedCSVError
assert_equal( "Unquoted fields do not allow \\r or \\n (line 4).",
$!.message )
end
assert_raise(CSV::MalformedCSVError) { CSV.parse_line('1,2,"3...') }
bad_data = <<-END_DATA.gsub(/^ +/, "")
line,1,abc
line,2,"def\nghi"
line,4,8'10"
line,5,jkl
END_DATA
lines = bad_data.to_a
assert_equal(6, lines.size)
assert_match(/\Aline,4/, lines.find { |l| l =~ /8'10"/ })
csv = CSV.new(bad_data)
begin
loop do
assert_not_nil(csv.shift)
assert_send([csv.lineno, :<, 4])
end
rescue CSV::MalformedCSVError
assert_equal("Unclosed quoted field on line 4.", $!.message)
end
end
end

View file

@ -0,0 +1,96 @@
#!/usr/local/bin/ruby -w
# tc_csv_writing.rb
#
# Created by James Edward Gray II on 2005-10-31.
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
# under the terms of Ruby's license.
require "test/unit"
require "csv"
class TestCSVWriting < Test::Unit::TestCase
def test_writing
[ ["\t", ["\t"]],
["foo,\"\"\"\"\"\",baz", ["foo", "\"\"", "baz"]],
["foo,\"\"\"bar\"\"\",baz", ["foo", "\"bar\"", "baz"]],
["\"\"\"\n\",\"\"\"\n\"", ["\"\n", "\"\n"]],
["foo,\"\r\n\",baz", ["foo", "\r\n", "baz"]],
["\"\"", [""]],
["foo,\"\"\"\",baz", ["foo", "\"", "baz"]],
["foo,\"\r.\n\",baz", ["foo", "\r.\n", "baz"]],
["foo,\"\r\",baz", ["foo", "\r", "baz"]],
["foo,\"\",baz", ["foo", "", "baz"]],
["\",\"", [","]],
["foo", ["foo"]],
[",,", [nil, nil, nil]],
[",", [nil, nil]],
["foo,\"\n\",baz", ["foo", "\n", "baz"]],
["foo,,baz", ["foo", nil, "baz"]],
["\"\"\"\r\",\"\"\"\r\"", ["\"\r", "\"\r"]],
["\",\",\",\"", [",", ","]],
["foo,bar,", ["foo", "bar", nil]],
[",foo,bar", [nil, "foo", "bar"]],
["foo,bar", ["foo", "bar"]],
[";", [";"]],
["\t,\t", ["\t", "\t"]],
["foo,\"\r\n\r\",baz", ["foo", "\r\n\r", "baz"]],
["foo,\"\r\n\n\",baz", ["foo", "\r\n\n", "baz"]],
["foo,\"foo,bar\",baz", ["foo", "foo,bar", "baz"]],
[";,;", [";", ";"]],
["foo,\"\"\"\"\"\",baz", ["foo", "\"\"", "baz"]],
["foo,\"\"\"bar\"\"\",baz", ["foo", "\"bar\"", "baz"]],
["foo,\"\r\n\",baz", ["foo", "\r\n", "baz"]],
["\"\"", [""]],
["foo,\"\"\"\",baz", ["foo", "\"", "baz"]],
["foo,\"\r.\n\",baz", ["foo", "\r.\n", "baz"]],
["foo,\"\r\",baz", ["foo", "\r", "baz"]],
["foo,\"\",baz", ["foo", "", "baz"]],
["foo", ["foo"]],
[",,", [nil, nil, nil]],
[",", [nil, nil]],
["foo,\"\n\",baz", ["foo", "\n", "baz"]],
["foo,,baz", ["foo", nil, "baz"]],
["foo,bar", ["foo", "bar"]],
["foo,\"\r\n\n\",baz", ["foo", "\r\n\n", "baz"]],
["foo,\"foo,bar\",baz", ["foo", "foo,bar", "baz"]],
[%Q{a,b}, ["a", "b"]],
[%Q{a,"""b"""}, ["a", "\"b\""]],
[%Q{a,"""b"}, ["a", "\"b"]],
[%Q{a,"b"""}, ["a", "b\""]],
[%Q{a,"\nb"""}, ["a", "\nb\""]],
[%Q{a,"""\nb"}, ["a", "\"\nb"]],
[%Q{a,"""\nb\n"""}, ["a", "\"\nb\n\""]],
[%Q{a,"""\nb\n""",}, ["a", "\"\nb\n\"", nil]],
[%Q{a,,,}, ["a", nil, nil, nil]],
[%Q{,}, [nil, nil]],
[%Q{"",""}, ["", ""]],
[%Q{""""}, ["\""]],
[%Q{"""",""}, ["\"",""]],
[%Q{,""}, [nil,""]],
[%Q{,"\r"}, [nil,"\r"]],
[%Q{"\r\n,"}, ["\r\n,"]],
[%Q{"\r\n,",}, ["\r\n,", nil]] ].each do |test_case|
assert_equal(test_case.first + $/, CSV.generate_line(test_case.last))
end
end
def test_col_sep
assert_equal( "a;b;;c\n", CSV.generate_line( ["a", "b", nil, "c"],
:col_sep => ";" ) )
assert_equal( "a\tb\t\tc\n", CSV.generate_line( ["a", "b", nil, "c"],
:col_sep => "\t" ) )
end
def test_row_sep
assert_equal( "a,b,,c\r\n", CSV.generate_line( ["a", "b", nil, "c"],
:row_sep => "\r\n" ) )
end
def test_force_quotes
assert_equal( %Q{"1","b","","already ""quoted"""\n},
CSV.generate_line( [1, "b", nil, %Q{already "quoted"}],
:force_quotes => true ) )
end
end

View file

@ -0,0 +1,260 @@
#!/usr/local/bin/ruby -w
# tc_data_converters.rb
#
# Created by James Edward Gray II on 2005-10-31.
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
# under the terms of Ruby's license.
require "test/unit"
require "csv"
class TestDataConverters < Test::Unit::TestCase
def setup
@data = "Numbers,:integer,1,:float,3.015"
@parser = CSV.new(@data)
@custom = lambda { |field| field =~ /\A:(\S.*?)\s*\Z/ ? $1.to_sym : field }
@win_safe_time_str = Time.now.strftime("%a %b %d %H:%M:%S %Y")
end
def test_builtin_integer_converter
# does convert
[-5, 1, 10000000000].each do |n|
assert_equal(n, CSV::Converters[:integer][n.to_s])
end
# does not convert
(%w{junk 1.0} + [""]).each do |str|
assert_equal(str, CSV::Converters[:integer][str])
end
end
def test_builtin_float_converter
# does convert
[-5.1234, 0, 2.3e-11].each do |n|
assert_equal(n, CSV::Converters[:float][n.to_s])
end
# does not convert
(%w{junk 1..0 .015F} + [""]).each do |str|
assert_equal(str, CSV::Converters[:float][str])
end
end
def test_builtin_date_converter
# does convert
assert_instance_of(
Date,
CSV::Converters[:date][@win_safe_time_str.sub(/\d+:\d+:\d+ /, "")]
)
# does not convert
assert_instance_of(String, CSV::Converters[:date]["junk"])
end
def test_builtin_date_time_converter
# does convert
assert_instance_of( DateTime,
CSV::Converters[:date_time][@win_safe_time_str] )
# does not convert
assert_instance_of(String, CSV::Converters[:date_time]["junk"])
end
def test_convert_with_builtin
# setup parser...
assert(@parser.respond_to?(:convert))
assert_nothing_raised(Exception) { @parser.convert(:integer) }
# and use
assert_equal(["Numbers", ":integer", 1, ":float", "3.015"], @parser.shift)
setup # reset
# setup parser...
assert_nothing_raised(Exception) { @parser.convert(:float) }
# and use
assert_equal(["Numbers", ":integer", 1.0, ":float", 3.015], @parser.shift)
end
def test_convert_order
# floats first, then integers...
assert_nothing_raised(Exception) do
@parser.convert(:float)
@parser.convert(:integer)
end
# gets us nothing but floats
assert_equal( [String, String, Float, String, Float],
@parser.shift.map { |field| field.class } )
setup # reset
# integers have precendance...
assert_nothing_raised(Exception) do
@parser.convert(:integer)
@parser.convert(:float)
end
# gives us proper number conversion
assert_equal( [String, String, Fixnum, String, Float],
@parser.shift.map { |field| field.class } )
end
def test_builtin_numeric_combo_converter
# setup parser...
assert_nothing_raised(Exception) { @parser.convert(:numeric) }
# and use
assert_equal( [String, String, Fixnum, String, Float],
@parser.shift.map { |field| field.class } )
end
def test_builtin_all_nested_combo_converter
# setup parser...
@data << ",#{@win_safe_time_str}" # add a DateTime field
@parser = CSV.new(@data) # reset parser
assert_nothing_raised(Exception) { @parser.convert(:all) }
# and use
assert_equal( [String, String, Fixnum, String, Float, DateTime],
@parser.shift.map { |field| field.class } )
end
def test_convert_with_custom_code
# define custom converter...
assert_nothing_raised(Exception) do
@parser.convert { |field| field =~ /\A:(\S.*?)\s*\Z/ ? $1.to_sym : field }
end
# and use
assert_equal(["Numbers", :integer, "1", :float, "3.015"], @parser.shift)
setup # reset
# mix built-in and custom...
assert_nothing_raised(Exception) { @parser.convert(:numeric) }
assert_nothing_raised(Exception) { @parser.convert(&@custom) }
# and use
assert_equal(["Numbers", :integer, 1, :float, 3.015], @parser.shift)
end
def test_convert_with_custom_code_using_field_info
# define custom converter that uses field information...
assert_nothing_raised(Exception) do
@parser.convert do |field, info|
assert_equal(1, info.line)
info.index == 4 ? Float(field).floor : field
end
end
# and use
assert_equal(["Numbers", ":integer", "1", ":float", 3], @parser.shift)
end
def test_convert_with_custom_code_using_field_info_header
@parser = CSV.new(@data, :headers => %w{one two three four five})
# define custom converter that uses field header information...
assert_nothing_raised(Exception) do
@parser.convert do |field, info|
info.header == "three" ? Integer(field) * 100 : field
end
end
# and use
assert_equal( ["Numbers", ":integer", 100, ":float", "3.015"],
@parser.shift.fields )
end
def test_shortcut_interface
assert_equal( ["Numbers", ":integer", 1, ":float", 3.015],
CSV.parse_line(@data, :converters => :numeric) )
assert_equal( ["Numbers", ":integer", 1, ":float", 3.015],
CSV.parse_line(@data, :converters => [:integer, :float]) )
assert_equal( ["Numbers", :integer, 1, :float, 3.015],
CSV.parse_line(@data, :converters => [:numeric, @custom]) )
end
def test_unconverted_fields
[ [ @data,
["Numbers", :integer, 1, :float, 3.015],
%w{Numbers :integer 1 :float 3.015} ],
["\n", Array.new, Array.new] ].each do |test, fields, unconverted|
row = nil
assert_nothing_raised(Exception) do
row = CSV.parse_line( test,
:converters => [:numeric, @custom],
:unconverted_fields => true )
end
assert_not_nil(row)
assert_equal(fields, row)
assert_respond_to(row, :unconverted_fields)
assert_equal(unconverted, row.unconverted_fields)
end
data = <<-END_CSV.gsub(/^\s+/, "")
first,second,third
1,2,3
END_CSV
row = nil
assert_nothing_raised(Exception) do
row = CSV.parse_line( data,
:converters => :numeric,
:unconverted_fields => true,
:headers => :first_row )
end
assert_not_nil(row)
assert_equal([["first", 1], ["second", 2], ["third", 3]], row.to_a)
assert_respond_to(row, :unconverted_fields)
assert_equal(%w{1 2 3}, row.unconverted_fields)
assert_nothing_raised(Exception) do
row = CSV.parse_line( data,
:converters => :numeric,
:unconverted_fields => true,
:headers => :first_row,
:return_headers => true )
end
assert_not_nil(row)
assert_equal( [%w{first first}, %w{second second}, %w{third third}],
row.to_a )
assert_respond_to(row, :unconverted_fields)
assert_equal(%w{first second third}, row.unconverted_fields)
assert_nothing_raised(Exception) do
row = CSV.parse_line( data,
:converters => :numeric,
:unconverted_fields => true,
:headers => :first_row,
:return_headers => true,
:header_converters => :symbol )
end
assert_not_nil(row)
assert_equal( [[:first, "first"], [:second, "second"], [:third, "third"]],
row.to_a )
assert_respond_to(row, :unconverted_fields)
assert_equal(%w{first second third}, row.unconverted_fields)
assert_nothing_raised(Exception) do
row = CSV.parse_line( data,
:converters => :numeric,
:unconverted_fields => true,
:headers => %w{my new headers},
:return_headers => true,
:header_converters => :symbol )
end
assert_not_nil(row)
assert_equal( [[:my, "my"], [:new, "new"], [:headers, "headers"]],
row.to_a )
assert_respond_to(row, :unconverted_fields)
assert_equal(Array.new, row.unconverted_fields)
end
end

177
test/csv/tc_features.rb Normal file
View file

@ -0,0 +1,177 @@
#!/usr/local/bin/ruby -w
# tc_features.rb
#
# Created by James Edward Gray II on 2005-10-31.
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
# under the terms of Ruby's license.
require "test/unit"
require "zlib"
require "csv"
class TestCSVFeatures < Test::Unit::TestCase
TEST_CASES = [ [%Q{a,b}, ["a", "b"]],
[%Q{a,"""b"""}, ["a", "\"b\""]],
[%Q{a,"""b"}, ["a", "\"b"]],
[%Q{a,"b"""}, ["a", "b\""]],
[%Q{a,"\nb"""}, ["a", "\nb\""]],
[%Q{a,"""\nb"}, ["a", "\"\nb"]],
[%Q{a,"""\nb\n"""}, ["a", "\"\nb\n\""]],
[%Q{a,"""\nb\n""",\nc}, ["a", "\"\nb\n\"", nil]],
[%Q{a,,,}, ["a", nil, nil, nil]],
[%Q{,}, [nil, nil]],
[%Q{"",""}, ["", ""]],
[%Q{""""}, ["\""]],
[%Q{"""",""}, ["\"",""]],
[%Q{,""}, [nil,""]],
[%Q{,"\r"}, [nil,"\r"]],
[%Q{"\r\n,"}, ["\r\n,"]],
[%Q{"\r\n,",}, ["\r\n,", nil]] ]
def setup
@sample_data = <<-END_DATA.gsub(/^ +/, "")
line,1,abc
line,2,"def\nghi"
line,4,jkl
END_DATA
@csv = CSV.new(@sample_data)
end
def test_col_sep
[";", "\t"].each do |sep|
TEST_CASES.each do |test_case|
assert_equal( test_case.last.map { |t| t.tr(",", sep) unless t.nil? },
CSV.parse_line( test_case.first.tr(",", sep),
:col_sep => sep ) )
end
end
assert_equal([",,,", nil], CSV.parse_line(",,,;", :col_sep => ";"))
end
def test_row_sep
assert_raise(CSV::MalformedCSVError) do
CSV.parse_line("1,2,3\n,4,5\r\n", :row_sep => "\r\n")
end
assert_equal( ["1", "2", "3\n", "4", "5"],
CSV.parse_line(%Q{1,2,"3\n",4,5\r\n}, :row_sep => "\r\n"))
end
def test_quote_char
TEST_CASES.each do |test_case|
assert_equal( test_case.last.map { |t| t.tr('"', "'") unless t.nil? },
CSV.parse_line( test_case.first.tr('"', "'"),
:quote_char => "'" ) )
end
end
def test_row_sep_auto_discovery
["\r\n", "\n", "\r"].each do |line_end|
data = "1,2,3#{line_end}4,5#{line_end}"
discovered = CSV.new(data).instance_eval { @row_sep }
assert_equal(line_end, discovered)
end
assert_equal("\n", CSV.new("\n\r\n\r").instance_eval { @row_sep })
assert_equal($/, CSV.new("").instance_eval { @row_sep })
assert_equal($/, CSV.new(STDERR).instance_eval { @row_sep })
end
def test_lineno
assert_equal(5, @sample_data.to_a.size)
4.times do |line_count|
assert_equal(line_count, @csv.lineno)
assert_not_nil(@csv.shift)
assert_equal(line_count + 1, @csv.lineno)
end
assert_nil(@csv.shift)
end
def test_readline
test_lineno
@csv.rewind
test_lineno
end
def test_unknown_options
assert_raise(ArgumentError) { CSV.new(String.new, :unknown => :error) }
end
def test_skip_blanks
assert_equal(4, @csv.to_a.size)
@csv = CSV.new(@sample_data, :skip_blanks => true)
count = 0
@csv.each do |row|
count += 1
assert_equal("line", row.first)
end
assert_equal(3, count)
end
# reported by Kev Jackson
def test_failing_to_escape_col_sep_bug_fix
assert_nothing_raised(Exception) { CSV.new(String.new, :col_sep => "|") }
end
# reported by Chris Roos
def test_failing_to_reset_headers_in_rewind_bug_fix
csv = CSV.new("forename,surname", :headers => true, :return_headers => true)
csv.each { |row| assert row.header_row? }
csv.rewind
csv.each { |row| assert row.header_row? }
end
# reported by Dave Burt
def test_leading_empty_fields_with_multibyte_col_sep_bug_fix
data = <<-END_DATA.gsub(/^\s+/, "")
<=><=>A<=>B<=>C
1<=>2<=>3
END_DATA
parsed = CSV.parse(data, :col_sep => "<=>")
assert_equal([[nil, nil, "A", "B", "C"], ["1", "2", "3"]], parsed)
end
def test_gzip_reader_bug_fix
zipped = nil
assert_nothing_raised(NoMethodError) do
zipped = CSV.new(
Zlib::GzipReader.open(
File.join(File.dirname(__FILE__), "line_endings.gz")
)
)
end
assert_equal("\r\n", zipped.instance_eval { @row_sep })
end
def test_gzip_writer_bug_fix
file = File.join(File.dirname(__FILE__), "temp.gz")
zipped = nil
assert_nothing_raised(NoMethodError) do
zipped = CSV.new(Zlib::GzipWriter.open(file))
end
zipped << %w[one two three]
zipped << [1, 2, 3]
zipped.close
assert( Zlib::GzipReader.open(file) { |f| f.read }.
include?($INPUT_RECORD_SEPARATOR),
"@row_sep did not default" )
File.unlink(file)
end
def test_version
assert_not_nil(CSV::VERSION)
assert_instance_of(String, CSV::VERSION)
assert(CSV::VERSION.frozen?)
assert_match(/\A\d\.\d\.\d\Z/, CSV::VERSION)
end
end

261
test/csv/tc_headers.rb Normal file
View file

@ -0,0 +1,261 @@
#!/usr/local/bin/ruby -w
# tc_headers.rb
#
# Created by James Edward Gray II on 2005-10-31.
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
# under the terms of Ruby's license.
require "test/unit"
require "csv"
class TestCSVHeaders < Test::Unit::TestCase
def setup
@data = <<-END_CSV.gsub(/^\s+/, "")
first,second,third
A,B,C
1,2,3
END_CSV
end
def test_first_row
[:first_row, true].each do |setting| # two names for the same setting
# activate headers
csv = nil
assert_nothing_raised(Exception) do
csv = CSV.parse(@data, :headers => setting)
end
# first data row - skipping headers
row = csv[0]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([%w{first A}, %w{second B}, %w{third C}], row.to_a)
# second data row
row = csv[1]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([%w{first 1}, %w{second 2}, %w{third 3}], row.to_a)
# empty
assert_nil(csv[2])
end
end
def test_array_of_headers
# activate headers
csv = nil
assert_nothing_raised(Exception) do
csv = CSV.parse(@data, :headers => [:my, :new, :headers])
end
# first data row - skipping headers
row = csv[0]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal( [[:my, "first"], [:new, "second"], [:headers, "third"]],
row.to_a )
# second data row
row = csv[1]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([[:my, "A"], [:new, "B"], [:headers, "C"]], row.to_a)
# third data row
row = csv[2]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([[:my, "1"], [:new, "2"], [:headers, "3"]], row.to_a)
# empty
assert_nil(csv[3])
# with return and convert
assert_nothing_raised(Exception) do
csv = CSV.parse(@data, :headers => [:my, :new, :headers],
:return_headers => true,
:header_converters => lambda { |h| h.to_s } )
end
row = csv[0]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([["my", :my], ["new", :new], ["headers", :headers]], row.to_a)
assert(row.header_row?)
assert(!row.field_row?)
end
def test_csv_header_string
# activate headers
csv = nil
assert_nothing_raised(Exception) do
csv = CSV.parse(@data, :headers => "my,new,headers")
end
# first data row - skipping headers
row = csv[0]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([%w{my first}, %w{new second}, %w{headers third}], row.to_a)
# second data row
row = csv[1]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([%w{my A}, %w{new B}, %w{headers C}], row.to_a)
# third data row
row = csv[2]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([%w{my 1}, %w{new 2}, %w{headers 3}], row.to_a)
# empty
assert_nil(csv[3])
# with return and convert
assert_nothing_raised(Exception) do
csv = CSV.parse(@data, :headers => "my,new,headers",
:return_headers => true,
:header_converters => :symbol )
end
row = csv[0]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([[:my, "my"], [:new, "new"], [:headers, "headers"]], row.to_a)
assert(row.header_row?)
assert(!row.field_row?)
end
def test_return_headers
# activate headers and request they are returned
csv = nil
assert_nothing_raised(Exception) do
csv = CSV.parse(@data, :headers => true, :return_headers => true)
end
# header row
row = csv[0]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal( [%w{first first}, %w{second second}, %w{third third}],
row.to_a )
assert(row.header_row?)
assert(!row.field_row?)
# first data row - skipping headers
row = csv[1]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([%w{first A}, %w{second B}, %w{third C}], row.to_a)
assert(!row.header_row?)
assert(row.field_row?)
# second data row
row = csv[2]
assert_not_nil(row)
assert_instance_of(CSV::Row, row)
assert_equal([%w{first 1}, %w{second 2}, %w{third 3}], row.to_a)
assert(!row.header_row?)
assert(row.field_row?)
# empty
assert_nil(csv[3])
end
def test_converters
# create test data where headers and fields look alike
data = <<-END_MATCHING_CSV.gsub(/^\s+/, "")
1,2,3
1,2,3
END_MATCHING_CSV
# normal converters do not affect headers
csv = CSV.parse( data, :headers => true,
:return_headers => true,
:converters => :numeric )
assert_equal([%w{1 1}, %w{2 2}, %w{3 3}], csv[0].to_a)
assert_equal([["1", 1], ["2", 2], ["3", 3]], csv[1].to_a)
assert_nil(csv[2])
# header converters do affect headers (only)
assert_nothing_raised(Exception) do
csv = CSV.parse( data, :headers => true,
:return_headers => true,
:converters => :numeric,
:header_converters => :symbol )
end
assert_equal([[:"1", "1"], [:"2", "2"], [:"3", "3"]], csv[0].to_a)
assert_equal([[:"1", 1], [:"2", 2], [:"3", 3]], csv[1].to_a)
assert_nil(csv[2])
end
def test_builtin_downcase_converter
csv = CSV.parse( "One,TWO Three", :headers => true,
:return_headers => true,
:header_converters => :downcase )
assert_equal(%w{one two\ three}, csv.headers)
end
def test_builtin_symbol_converter
csv = CSV.parse( "One,TWO Three", :headers => true,
:return_headers => true,
:header_converters => :symbol )
assert_equal([:one, :two_three], csv.headers)
end
def test_custom_converter
converter = lambda { |header| header.tr(" ", "_") }
csv = CSV.parse( "One,TWO Three",
:headers => true,
:return_headers => true,
:header_converters => converter )
assert_equal(%w{One TWO_Three}, csv.headers)
end
def test_table_support
csv = nil
assert_nothing_raised(Exception) do
csv = CSV.parse(@data, :headers => true)
end
assert_instance_of(CSV::Table, csv)
end
def test_skip_blanks
@data = <<-END_CSV.gsub(/^ +/, "")
A,B,C
1,2,3
END_CSV
expected = [%w[1 2 3]]
CSV.parse(@data, :headers => true, :skip_blanks => true) do |row|
assert_equal(expected.shift, row.fields)
end
expected = [%w[A B C], %w[1 2 3]]
CSV.parse( @data,
:headers => true,
:return_headers => true,
:skip_blanks => true ) do |row|
assert_equal(expected.shift, row.fields)
end
end
def test_blank_row_bug_fix
@data += "\n#{@data}" # add a blank row
# ensure that everything returned is a Row object
CSV.parse(@data, :headers => true) do |row|
assert_instance_of(CSV::Row, row)
end
end
end

235
test/csv/tc_interface.rb Normal file
View file

@ -0,0 +1,235 @@
#!/usr/local/bin/ruby -w
# tc_interface.rb
#
# Created by James Edward Gray II on 2005-10-31.
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
# under the terms of Ruby's license.
require "test/unit"
require "csv"
class TestCSVInterface < Test::Unit::TestCase
def setup
@path = File.join(File.dirname(__FILE__), "temp_test_data.csv")
File.open(@path, "w") do |file|
file << "1\t2\t3\r\n"
file << "4\t5\r\n"
end
@expected = [%w{1 2 3}, %w{4 5}]
end
def teardown
File.unlink(@path)
end
### Test Read Interface ###
def test_foreach
CSV.foreach(@path, :col_sep => "\t", :row_sep => "\r\n") do |row|
assert_equal(@expected.shift, row)
end
end
def test_open_and_close
csv = CSV.open(@path, "r+", :col_sep => "\t", :row_sep => "\r\n")
assert_not_nil(csv)
assert_instance_of(CSV, csv)
assert_equal(false, csv.closed?)
csv.close
assert(csv.closed?)
ret = CSV.open(@path) do |csv|
assert_instance_of(CSV, csv)
"Return value."
end
assert(csv.closed?)
assert_equal("Return value.", ret)
end
def test_parse
data = File.read(@path)
assert_equal( @expected,
CSV.parse(data, :col_sep => "\t", :row_sep => "\r\n") )
CSV.parse(data, :col_sep => "\t", :row_sep => "\r\n") do |row|
assert_equal(@expected.shift, row)
end
end
def test_parse_line
row = CSV.parse_line("1;2;3", :col_sep => ";")
assert_not_nil(row)
assert_instance_of(Array, row)
assert_equal(%w{1 2 3}, row)
# shortcut interface
row = "1;2;3".parse_csv(:col_sep => ";")
assert_not_nil(row)
assert_instance_of(Array, row)
assert_equal(%w{1 2 3}, row)
end
def test_read_and_readlines
assert_equal( @expected,
CSV.read(@path, :col_sep => "\t", :row_sep => "\r\n") )
assert_equal( @expected,
CSV.readlines(@path, :col_sep => "\t", :row_sep => "\r\n") )
data = CSV.open(@path, :col_sep => "\t", :row_sep => "\r\n") do |csv|
csv.read
end
assert_equal(@expected, data)
data = CSV.open(@path, :col_sep => "\t", :row_sep => "\r\n") do |csv|
csv.readlines
end
assert_equal(@expected, data)
end
def test_table
table = CSV.table(@path, :col_sep => "\t", :row_sep => "\r\n")
assert_instance_of(CSV::Table, table)
assert_equal([[:"1", :"2", :"3"], [4, 5, nil]], table.to_a)
end
def test_shift # aliased as gets() and readline()
CSV.open(@path, "r+", :col_sep => "\t", :row_sep => "\r\n") do |csv|
assert_equal(@expected.shift, csv.shift)
assert_equal(@expected.shift, csv.shift)
assert_equal(nil, csv.shift)
end
end
### Test Write Interface ###
def test_generate
str = CSV.generate do |csv| # default empty String
assert_instance_of(CSV, csv)
assert_equal(csv, csv << [1, 2, 3])
assert_equal(csv, csv << [4, nil, 5])
end
assert_not_nil(str)
assert_instance_of(String, str)
assert_equal("1,2,3\n4,,5\n", str)
CSV.generate(str) do |csv| # appending to a String
assert_equal(csv, csv << ["last", %Q{"row"}])
end
assert_equal(%Q{1,2,3\n4,,5\nlast,"""row"""\n}, str)
end
def test_generate_line
line = CSV.generate_line(%w{1 2 3}, :col_sep => ";")
assert_not_nil(line)
assert_instance_of(String, line)
assert_equal("1;2;3\n", line)
# shortcut interface
line = %w{1 2 3}.to_csv(:col_sep => ";")
assert_not_nil(line)
assert_instance_of(String, line)
assert_equal("1;2;3\n", line)
end
def test_write_header_detection
File.unlink(@path)
headers = %w{a b c}
CSV.open(@path, "w", :headers => true) do |csv|
csv << headers
csv << %w{1 2 3}
assert_equal(headers, csv.instance_variable_get(:@headers))
end
end
def test_write_lineno
File.unlink(@path)
CSV.open(@path, "w") do |csv|
lines = 20
lines.times { csv << %w{a b c} }
assert_equal(lines, csv.lineno)
end
end
def test_write_hash
File.unlink(@path)
lines = [{:a => 1, :b => 2, :c => 3}, {:a => 4, :b => 5, :c => 6}]
CSV.open( @path, "w", :headers => true,
:converters => :all,
:header_converters => :symbol ) do |csv|
csv << lines.first.keys
lines.each { |line| csv << line }
end
CSV.open( @path, "w", :headers => true,
:converters => :all,
:header_converters => :symbol ) do |csv|
csv.each { |line| assert_equal(lines.shift, line.to_hash) }
end
end
def test_append # aliased add_row() and puts()
File.unlink(@path)
CSV.open(@path, "w", :col_sep => "\t", :row_sep => "\r\n") do |csv|
@expected.each { |row| csv << row }
end
test_shift
# same thing using CSV::Row objects
File.unlink(@path)
CSV.open(@path, "w", :col_sep => "\t", :row_sep => "\r\n") do |csv|
@expected.each { |row| csv << CSV::Row.new(Array.new, row) }
end
test_shift
end
### Test Read and Write Interface ###
def test_filter
assert_respond_to(CSV, :filter)
expected = [[1, 2, 3], [4, 5]]
CSV.filter( "1;2;3\n4;5\n", (result = String.new),
:in_col_sep => ";", :out_col_sep => ",",
:converters => :all ) do |row|
assert_equal(row, expected.shift)
row.map! { |n| n * 2 }
row << "Added\r"
end
assert_equal("2,4,6,\"Added\r\"\n8,10,\"Added\r\"\n", result)
end
def test_instance
csv = String.new
first = nil
assert_nothing_raised(Exception) do
first = CSV.instance(csv, :col_sep => ";")
first << %w{a b c}
end
assert_equal("a;b;c\n", csv)
second = nil
assert_nothing_raised(Exception) do
second = CSV.instance(csv, :col_sep => ";")
second << [1, 2, 3]
end
assert_equal(first.object_id, second.object_id)
assert_equal("a;b;c\n1;2;3\n", csv)
# shortcuts
assert_equal(STDOUT, CSV.instance.instance_eval { @io })
assert_equal(STDOUT, CSV { |csv| csv.instance_eval { @io } })
end
end

289
test/csv/tc_row.rb Normal file
View file

@ -0,0 +1,289 @@
#!/usr/local/bin/ruby -w
# tc_row.rb
#
# Created by James Edward Gray II on 2005-10-31.
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
# under the terms of Ruby's license.
require "test/unit"
require "csv"
class TestCSVRow < Test::Unit::TestCase
def setup
@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(!row.header_row?)
assert(row.field_row?)
row = CSV::Row.new(%w{A B C}, [1, 2, 3], false) # explicit
assert(!row.header_row?)
assert(row.field_row?)
# header row
row = CSV::Row.new(%w{A B C}, [1, 2, 3], true)
assert(row.header_row?)
assert(!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))
# 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_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"))
# using a block
assert_equal(@row, @row.delete_if { |h, f| h == "A" and not f.nil? })
assert_equal([["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
# headers
assert(@row.header?("A"))
assert(@row.header?("C"))
assert(!@row.header?("Z"))
assert(@row.include?("A")) # alias
# 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 { })
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, (header, 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
assert_equal({"A" => nil, "B" => 2, "C" => 3}, @row.to_hash)
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(!@row.empty?, "Row was empty.")
assert_equal([@row.headers.size, @row.fields.size].max, @row.size)
end
end

View file

@ -0,0 +1,155 @@
#!/usr/local/bin/ruby -w
# tc_serialization.rb
#
# Created by James Edward Gray II on 2005-10-31.
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
# under the terms of Ruby's license.
require "test/unit"
require "csv"
# An example of how to provide custom CSV serialization.
class Hash
def self.csv_load( meta, headers, fields )
self[*headers.zip(fields).flatten.map { |e| eval(e) }]
end
def csv_headers
keys.map { |key| key.inspect }
end
def csv_dump( headers )
headers.map { |header| fetch(eval(header)).inspect }
end
end
class TestSerialization < Test::Unit::TestCase
### Classes Used to Test Serialization ###
class ReadOnlyName
def initialize( first, last )
@first, @last = first, last
end
attr_reader :first, :last
def ==( other )
%w{first last}.all? { |att| send(att) == other.send(att) }
end
end
Name = Struct.new(:first, :last)
class FullName < Name
def initialize( first, last, suffix = nil )
super(first, last)
@suffix = suffix
end
attr_accessor :suffix
def ==( other )
%w{first last suffix}.all? { |att| send(att) == other.send(att) }
end
end
### Tests ###
def test_class_dump
@names = [ %w{James Gray},
%w{Dana Gray},
%w{Greg Brown} ].map do |first, last|
ReadOnlyName.new(first, last)
end
assert_nothing_raised(Exception) do
@data = CSV.dump(@names)
end
assert_equal(<<-END_CLASS_DUMP.gsub(/^\s*/, ""), @data)
class,TestSerialization::ReadOnlyName
@first,@last
James,Gray
Dana,Gray
Greg,Brown
END_CLASS_DUMP
end
def test_struct_dump
@names = [ %w{James Gray},
%w{Dana Gray},
%w{Greg Brown} ].map do |first, last|
Name.new(first, last)
end
assert_nothing_raised(Exception) do
@data = CSV.dump(@names)
end
assert_equal(<<-END_STRUCT_DUMP.gsub(/^\s*/, ""), @data)
class,TestSerialization::Name
first=,last=
James,Gray
Dana,Gray
Greg,Brown
END_STRUCT_DUMP
end
def test_inherited_struct_dump
@names = [ %w{James Gray II},
%w{Dana Gray},
%w{Greg Brown} ].map do |first, last, suffix|
FullName.new(first, last, suffix)
end
assert_nothing_raised(Exception) do
@data = CSV.dump(@names)
end
assert_equal(<<-END_STRUCT_DUMP.gsub(/^\s*/, ""), @data)
class,TestSerialization::FullName
@suffix,first=,last=
II,James,Gray
,Dana,Gray
,Greg,Brown
END_STRUCT_DUMP
end
def test_load
%w{ test_class_dump
test_struct_dump
test_inherited_struct_dump }.each do |test|
send(test)
CSV.load(@data).each do |loaded|
assert_instance_of(@names.first.class, loaded)
assert_equal(@names.shift, loaded)
end
end
end
def test_io
test_class_dump
data_file = File.join(File.dirname(__FILE__), "temp_test_data.csv")
CSV.dump(@names, File.open(data_file, "w"))
assert(File.exist?(data_file))
assert_equal(<<-END_IO_DUMP.gsub(/^\s*/, ""), File.read(data_file))
class,TestSerialization::ReadOnlyName
@first,@last
James,Gray
Dana,Gray
Greg,Brown
END_IO_DUMP
assert_equal(@names, CSV.load(File.open(data_file)))
File.unlink(data_file)
end
def test_custom_dump_and_load
obj = {1 => "simple", :test => Hash}
assert_equal(obj, CSV.load(CSV.dump([obj])).first)
end
end

392
test/csv/tc_table.rb Normal file
View file

@ -0,0 +1,392 @@
#!/usr/local/bin/ruby -w
# tc_table.rb
#
# Created by James Edward Gray II on 2005-10-31.
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
# under the terms of Ruby's license.
require "test/unit"
require "csv"
class TestCSVTable < Test::Unit::TestCase
def setup
@rows = [ CSV::Row.new(%w{A B C}, [1, 2, 3]),
CSV::Row.new(%w{A B C}, [4, 5, 6]),
CSV::Row.new(%w{A B C}, [7, 8, 9]) ]
@table = CSV::Table.new(@rows)
@header_table = CSV::Table.new(
[CSV::Row.new(%w{A B C}, %w{A B C}, true)] + @rows
)
end
def test_initialze
assert_not_nil(@table)
assert_instance_of(CSV::Table, @table)
end
def test_modes
assert_equal(:col_or_row, @table.mode)
# non-destructive changes, intended for one shot calls
cols = @table.by_col
assert_equal(:col_or_row, @table.mode)
assert_equal(:col, cols.mode)
assert_equal(@table, cols)
rows = @table.by_row
assert_equal(:col_or_row, @table.mode)
assert_equal(:row, rows.mode)
assert_equal(@table, rows)
# destructive mode changing calls
assert_equal(@table, @table.by_row!)
assert_equal(:row, @table.mode)
assert_equal(@table, @table.by_col_or_row!)
assert_equal(:col_or_row, @table.mode)
end
def test_headers
assert_equal(@rows.first.headers, @table.headers)
end
def test_index
##################
### Mixed Mode ###
##################
# by row
@rows.each_index { |i| assert_equal(@rows[i], @table[i]) }
assert_equal(nil, @table[100]) # empty row
# by col
@rows.first.headers.each do |header|
assert_equal(@rows.map { |row| row[header] }, @table[header])
end
assert_equal([nil] * @rows.size, @table["Z"]) # empty col
# by cell, row then col
assert_equal(2, @table[0][1])
assert_equal(6, @table[1]["C"])
# by cell, col then row
assert_equal(5, @table["B"][1])
assert_equal(9, @table["C"][2])
# with headers (by col)
assert_equal(["B", 2, 5, 8], @header_table["B"])
###################
### Column Mode ###
###################
@table.by_col!
assert_equal([2, 5, 8], @table[1])
assert_equal([2, 5, 8], @table["B"])
################
### Row Mode ###
################
@table.by_row!
assert_equal(@rows[1], @table[1])
assert_raise(TypeError) { @table["B"] }
############################
### One Shot Mode Change ###
############################
assert_equal(@rows[1], @table[1])
assert_equal([2, 5, 8], @table.by_col[1])
assert_equal(@rows[1], @table[1])
end
def test_set_row_or_column
##################
### Mixed Mode ###
##################
# set row
@table[2] = [10, 11, 12]
assert_equal([%w[A B C], [1, 2, 3], [4, 5, 6], [10, 11, 12]], @table.to_a)
@table[3] = CSV::Row.new(%w[A B C], [13, 14, 15])
assert_equal( [%w[A B C], [1, 2, 3], [4, 5, 6], [10, 11, 12], [13, 14, 15]],
@table.to_a )
# set col
@table["Type"] = "data"
assert_equal( [ %w[A B C Type],
[1, 2, 3, "data"],
[4, 5, 6, "data"],
[10, 11, 12, "data"],
[13, 14, 15, "data"] ],
@table.to_a )
@table["Index"] = [1, 2, 3]
assert_equal( [ %w[A B C Type Index],
[1, 2, 3, "data", 1],
[4, 5, 6, "data", 2],
[10, 11, 12, "data", 3],
[13, 14, 15, "data", nil] ],
@table.to_a )
@table["B"] = [100, 200]
assert_equal( [ %w[A B C Type Index],
[1, 100, 3, "data", 1],
[4, 200, 6, "data", 2],
[10, nil, 12, "data", 3],
[13, nil, 15, "data", nil] ],
@table.to_a )
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
A,B,C,Type,Index
1,100,3,data,1
4,200,6,data,2
10,,12,data,3
13,,15,data,
END_RESULT
# with headers
@header_table["Type"] = "data"
assert_equal(%w[Type data data data], @header_table["Type"])
###################
### Column Mode ###
###################
@table.by_col!
@table[1] = [2, 5, 11, 14]
assert_equal( [ %w[A B C Type Index],
[1, 2, 3, "data", 1],
[4, 5, 6, "data", 2],
[10, 11, 12, "data", 3],
[13, 14, 15, "data", nil] ],
@table.to_a )
@table["Extra"] = "new stuff"
assert_equal( [ %w[A B C Type Index Extra],
[1, 2, 3, "data", 1, "new stuff"],
[4, 5, 6, "data", 2, "new stuff"],
[10, 11, 12, "data", 3, "new stuff"],
[13, 14, 15, "data", nil, "new stuff"] ],
@table.to_a )
################
### Row Mode ###
################
@table.by_row!
@table[1] = (1..6).to_a
assert_equal( [ %w[A B C Type Index Extra],
[1, 2, 3, "data", 1, "new stuff"],
[1, 2, 3, 4, 5, 6],
[10, 11, 12, "data", 3, "new stuff"],
[13, 14, 15, "data", nil, "new stuff"] ],
@table.to_a )
assert_raise(TypeError) { @table["Extra"] = nil }
end
def test_each
######################
### Mixed/Row Mode ###
######################
i = 0
@table.each do |row|
assert_equal(@rows[i], row)
i += 1
end
# verify that we can chain the call
assert_equal(@table, @table.each { })
###################
### Column Mode ###
###################
@table.by_col!
headers = @table.headers
@table.each do |header, column|
assert_equal(headers.shift, header)
assert_equal(@table[header], column)
end
############################
### One Shot Mode Change ###
############################
@table.by_col_or_row!
@table.each { |row| assert_instance_of(CSV::Row, row) }
@table.by_col.each { |tuple| assert_instance_of(Array, tuple) }
@table.each { |row| assert_instance_of(CSV::Row, row) }
end
def test_enumerable
assert_equal( @rows.values_at(0, 2),
@table.select { |row| (row["B"] % 2).zero? } )
assert_equal(@rows[1], @table.find { |row| row["C"] > 5 })
end
def test_to_a
assert_equal([%w[A B C], [1, 2, 3], [4, 5, 6], [7, 8, 9]], @table.to_a)
# with headers
assert_equal( [%w[A B C], [1, 2, 3], [4, 5, 6], [7, 8, 9]],
@header_table.to_a )
end
def test_to_csv
csv = <<-END_CSV.gsub(/^\s+/, "")
A,B,C
1,2,3
4,5,6
7,8,9
END_CSV
# normal conversion
assert_equal(csv, @table.to_csv)
assert_equal(csv, @table.to_s) # alias
# with options
assert_equal( csv.gsub(",", "|").gsub("\n", "\r\n"),
@table.to_csv(:col_sep => "|", :row_sep => "\r\n") )
# with headers
assert_equal(csv, @header_table.to_csv)
end
def test_append
# verify that we can chain the call
assert_equal(@table, @table << [10, 11, 12])
# Array append
assert_equal(CSV::Row.new(%w[A B C], [10, 11, 12]), @table[-1])
# Row append
assert_equal(@table, @table << CSV::Row.new(%w[A B C], [13, 14, 15]))
assert_equal(CSV::Row.new(%w[A B C], [13, 14, 15]), @table[-1])
end
def test_delete
##################
### Mixed Mode ###
##################
# delete a row
assert_equal(@rows[1], @table.delete(1))
# delete a col
assert_equal(@rows.map { |row| row["A"] }, @table.delete("A"))
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
B,C
2,3
8,9
END_RESULT
###################
### Column Mode ###
###################
setup
@table.by_col!
assert_equal(@rows.map { |row| row[0] }, @table.delete(0))
assert_equal(@rows.map { |row| row["C"] }, @table.delete("C"))
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
B
2
5
8
END_RESULT
################
### Row Mode ###
################
setup
@table.by_row!
assert_equal(@rows[1], @table.delete(1))
assert_raise(TypeError) { @table.delete("C") }
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
A,B,C
1,2,3
7,8,9
END_RESULT
end
def test_delete_if
######################
### Mixed/Row Mode ###
######################
# verify that we can chain the call
assert_equal(@table, @table.delete_if { |row| (row["B"] % 2).zero? })
# verify resulting table
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
A,B,C
4,5,6
END_RESULT
###################
### Column Mode ###
###################
setup
@table.by_col!
assert_equal(@table, @table.delete_if { |h, v| h > "A" })
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
A
1
4
7
END_RESULT
end
def test_values_at
##################
### Mixed Mode ###
##################
# rows
assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
assert_equal(@rows.values_at(1..2), @table.values_at(1..2))
# cols
assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at("A", "C"))
assert_equal([[2, 3], [5, 6], [8, 9]], @table.values_at("B".."C"))
###################
### Column Mode ###
###################
@table.by_col!
assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at(0, 2))
assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at("A", "C"))
################
### Row Mode ###
################
@table.by_row!
assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
assert_raise(TypeError) { @table.values_at("A", "C") }
############################
### One Shot Mode Change ###
############################
assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
assert_equal([[1, 3], [4, 6], [7, 9]], @table.by_col.values_at(0, 2))
assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
end
def test_array_delegation
assert(!@table.empty?, "Table was empty.")
assert_equal(@rows.size, @table.size)
end
end

19
test/csv/ts_all.rb Normal file
View file

@ -0,0 +1,19 @@
#!/usr/local/bin/ruby -w
# ts_all.rb
#
# Created by James Edward Gray II on 2005-10-31.
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
# under the terms of Ruby's license.
require "test/unit"
require "tc_csv_parsing"
require "tc_features"
require "tc_interface"
require "tc_csv_writing"
require "tc_data_converters"
require "tc_row"
require "tc_table"
require "tc_headers"
require "tc_serialization"