summaryrefslogtreecommitdiff
path: root/jni/ruby/test/csv
diff options
context:
space:
mode:
authorJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-16 18:49:26 +0900
committerJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-30 00:39:06 +0900
commitfcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch)
tree64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/test/csv
Fresh start
Diffstat (limited to 'jni/ruby/test/csv')
-rw-r--r--jni/ruby/test/csv/base.rb8
-rw-r--r--jni/ruby/test/csv/line_endings.gzbin0 -> 59 bytes
-rwxr-xr-xjni/ruby/test/csv/test_csv_parsing.rb221
-rwxr-xr-xjni/ruby/test/csv/test_csv_writing.rb97
-rwxr-xr-xjni/ruby/test/csv/test_data_converters.rb263
-rwxr-xr-xjni/ruby/test/csv/test_encodings.rb337
-rwxr-xr-xjni/ruby/test/csv/test_features.rb327
-rwxr-xr-xjni/ruby/test/csv/test_headers.rb297
-rwxr-xr-xjni/ruby/test/csv/test_interface.rb368
-rwxr-xr-xjni/ruby/test/csv/test_row.rb355
-rwxr-xr-xjni/ruby/test/csv/test_table.rb434
-rw-r--r--jni/ruby/test/csv/ts_all.rb20
12 files changed, 2727 insertions, 0 deletions
diff --git a/jni/ruby/test/csv/base.rb b/jni/ruby/test/csv/base.rb
new file mode 100644
index 0000000..621569e
--- /dev/null
+++ b/jni/ruby/test/csv/base.rb
@@ -0,0 +1,8 @@
+require "test/unit"
+
+require "csv"
+
+require_relative "../lib/with_different_ofs.rb"
+
+class TestCSV < Test::Unit::TestCase
+end
diff --git a/jni/ruby/test/csv/line_endings.gz b/jni/ruby/test/csv/line_endings.gz
new file mode 100644
index 0000000..39e1729
--- /dev/null
+++ b/jni/ruby/test/csv/line_endings.gz
Binary files differ
diff --git a/jni/ruby/test/csv/test_csv_parsing.rb b/jni/ruby/test/csv/test_csv_parsing.rb
new file mode 100755
index 0000000..319f3f3
--- /dev/null
+++ b/jni/ruby/test/csv/test_csv_parsing.rb
@@ -0,0 +1,221 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+
+# 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 "timeout"
+
+require_relative "base"
+
+#
+# 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 TestCSV::Parsing < TestCSV
+ extend DifferentOFS
+
+ BIG_DATA = "123456789\n" * 1024
+
+ 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_rob_edge_cases
+ [ [%Q{"a\nb"}, ["a\nb"]],
+ [%Q{"\n\n\n"}, ["\n\n\n"]],
+ [%Q{a,"b\n\nc"}, ['a', "b\n\nc"]],
+ [%Q{,"\r\n"}, [nil,"\r\n"]],
+ [%Q{,"\r\n."}, [nil,"\r\n."]],
+ [%Q{"a\na","one newline"}, ["a\na", 'one newline']],
+ [%Q{"a\n\na","two newlines"}, ["a\n\na", 'two newlines']],
+ [%Q{"a\r\na","one CRLF"}, ["a\r\na", 'one CRLF']],
+ [%Q{"a\r\n\r\na","two CRLFs"}, ["a\r\n\r\na", 'two CRLFs']],
+ [%Q{with blank,"start\n\nfinish"\n}, ['with blank', "start\n\nfinish"]],
+ ].each do |edge_case|
+ assert_equal(edge_case.last, CSV.parse_line(edge_case.first))
+ end
+ end
+
+ def test_non_regex_edge_cases
+ # An early version of the non-regex parser fails this test
+ [ [ "foo,\"foo,bar,baz,foo\",\"foo\"",
+ ["foo", "foo,bar,baz,foo", "foo"] ] ].each do |edge_case|
+ assert_equal(edge_case.last, CSV.parse_line(edge_case.first))
+ end
+
+ assert_raise(CSV::MalformedCSVError) do
+ CSV.parse_line("1,\"23\"4\"5\", 6")
+ end
+ 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.lines.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.lines.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("Illegal quoting in line 4.", $!.message)
+ end
+ end
+
+ def test_the_parse_fails_fast_when_it_can_for_unquoted_fields
+ assert_parse_errors_out('valid,fields,bad start"' + BIG_DATA)
+ end
+
+ def test_the_parse_fails_fast_when_it_can_for_unescaped_quotes
+ assert_parse_errors_out('valid,fields,"bad start"unescaped' + BIG_DATA)
+ end
+
+ def test_field_size_limit_controls_lookahead
+ assert_parse_errors_out( 'valid,fields,"' + BIG_DATA + '"',
+ field_size_limit: 2048 )
+ end
+
+ private
+
+ def assert_parse_errors_out(*args)
+ assert_raise(CSV::MalformedCSVError) do
+ Timeout.timeout(0.2) do
+ CSV.parse(*args)
+ fail("Parse didn't error out")
+ end
+ end
+ end
+end
diff --git a/jni/ruby/test/csv/test_csv_writing.rb b/jni/ruby/test/csv/test_csv_writing.rb
new file mode 100755
index 0000000..704c1d7
--- /dev/null
+++ b/jni/ruby/test/csv/test_csv_writing.rb
@@ -0,0 +1,97 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+
+# 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_relative "base"
+
+class TestCSV::Writing < TestCSV
+ extend DifferentOFS
+
+ 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
diff --git a/jni/ruby/test/csv/test_data_converters.rb b/jni/ruby/test/csv/test_data_converters.rb
new file mode 100755
index 0000000..89b6dd1
--- /dev/null
+++ b/jni/ruby/test/csv/test_data_converters.rb
@@ -0,0 +1,263 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+
+# 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_relative "base"
+
+class TestCSV::DataConverters < TestCSV
+ extend DifferentOFS
+
+ def setup
+ super
+ @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_integer
+ # setup parser...
+ assert_respond_to(@parser, :convert)
+ assert_nothing_raised(Exception) { @parser.convert(:integer) }
+
+ # and use
+ assert_equal(["Numbers", ":integer", 1, ":float", "3.015"], @parser.shift)
+ end
+
+ def test_convert_with_builtin_float
+ # setup parser...
+ assert_respond_to(@parser, :convert)
+ 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_float_integer
+ # 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 } )
+ end
+
+ def test_convert_order_integer_float
+ # 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)
+ end
+
+ def test_convert_with_custom_code_mix
+ # 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
diff --git a/jni/ruby/test/csv/test_encodings.rb b/jni/ruby/test/csv/test_encodings.rb
new file mode 100755
index 0000000..dc45692
--- /dev/null
+++ b/jni/ruby/test/csv/test_encodings.rb
@@ -0,0 +1,337 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+
+# tc_encodings.rb
+#
+# Created by James Edward Gray II on 2008-09-13.
+# Copyright 2008 James Edward Gray II. You can redistribute or modify this code
+# under the terms of Ruby's license.
+
+require_relative "base"
+
+class TestCSV::Encodings < TestCSV
+ extend DifferentOFS
+
+ def setup
+ super
+ require 'tempfile'
+ @temp_csv_file = Tempfile.new(%w"test_csv. .csv")
+ @temp_csv_path = @temp_csv_file.path
+ @temp_csv_file.close
+ end
+
+ def teardown
+ @temp_csv_file.close!
+ super
+ end
+
+ ########################################
+ ### Hand Test Some Popular Encodings ###
+ ########################################
+
+ def test_parses_utf8_encoding
+ assert_parses( [ %w[ one two … ],
+ %w[ 1 … 3 ],
+ %w[ … 5 6 ] ], "UTF-8" )
+ end
+
+ def test_parses_latin1_encoding
+ assert_parses( [ %w[ one two Résumé ],
+ %w[ 1 Résumé 3 ],
+ %w[ Résumé 5 6 ] ], "ISO-8859-1" )
+ end
+
+ def test_parses_utf16be_encoding
+ assert_parses( [ %w[ one two … ],
+ %w[ 1 … 3 ],
+ %w[ … 5 6 ] ], "UTF-16BE" )
+ end
+
+ def test_parses_shift_jis_encoding
+ assert_parses( [ %w[ 一 二 三 ],
+ %w[ 四 五 六 ],
+ %w[ 七 八 九 ] ], "Shift_JIS" )
+ end
+
+ ###########################################################
+ ### Try Simple Reading for All Non-dummy Ruby Encodings ###
+ ###########################################################
+
+ def test_reading_with_most_encodings
+ each_encoding do |encoding|
+ begin
+ assert_parses( [ %w[ abc def ],
+ %w[ ghi jkl ] ], encoding )
+ rescue Encoding::ConverterNotFoundError
+ fail("Failed to support #{encoding.name}.")
+ end
+ end
+ end
+
+ def test_regular_expression_escaping
+ each_encoding do |encoding|
+ begin
+ assert_parses( [ %w[ abc def ],
+ %w[ ghi jkl ] ], encoding, col_sep: "|" )
+ rescue Encoding::ConverterNotFoundError
+ fail("Failed to properly escape #{encoding.name}.")
+ end
+ end
+ end
+
+ def test_read_with_default_encoding
+ data = "abc"
+ default_external = Encoding.default_external
+ each_encoding do |encoding|
+ File.open(@temp_csv_path, "wb", encoding: encoding) {|f| f << data}
+ begin
+ no_warnings do
+ Encoding.default_external = encoding
+ end
+ result = CSV.read(@temp_csv_path)[0][0]
+ ensure
+ no_warnings do
+ Encoding.default_external = default_external
+ end
+ end
+ assert_equal(encoding, result.encoding)
+ end
+ end
+
+ #######################################################################
+ ### Stress Test ASCII Compatible and Non-ASCII Compatible Encodings ###
+ #######################################################################
+
+ def test_auto_line_ending_detection
+ # arrange data to place a \r at the end of CSV's read ahead point
+ encode_for_tests([["a" * 509]], row_sep: "\r\n") do |data|
+ assert_equal("\r\n".encode(data.encoding), CSV.new(data).row_sep)
+ end
+ end
+
+ def test_csv_chars_are_transcoded
+ encode_for_tests([%w[abc def]]) do |data|
+ %w[col_sep row_sep quote_char].each do |csv_char|
+ assert_equal( "|".encode(data.encoding),
+ CSV.new(data, csv_char.to_sym => "|").send(csv_char) )
+ end
+ end
+ end
+
+ def test_parser_works_with_encoded_headers
+ encode_for_tests([%w[one two three], %w[1 2 3]]) do |data|
+ parsed = CSV.parse(data, headers: true)
+ assert_all?(parsed.headers, "Wrong data encoding.") {|h| h.encoding == data.encoding}
+ parsed.each do |row|
+ assert_all?(row.fields, "Wrong data encoding.") {|f| f.encoding == data.encoding}
+ end
+ end
+ end
+
+ def test_built_in_converters_transcode_to_utf_8_then_convert
+ encode_for_tests([%w[one two three], %w[1 2 3]]) do |data|
+ parsed = CSV.parse(data, converters: :integer)
+ assert_all?(parsed[0], "Wrong data encoding.") {|f| f.encoding == data.encoding}
+ assert_equal([1, 2, 3], parsed[1])
+ end
+ end
+
+ def test_built_in_header_converters_transcode_to_utf_8_then_convert
+ encode_for_tests([%w[one two three], %w[1 2 3]]) do |data|
+ parsed = CSV.parse( data, headers: true,
+ header_converters: :downcase )
+ assert_all?(parsed.headers, "Wrong data encoding.") {|h| h.encoding.name == "UTF-8"}
+ assert_all?(parsed[0].fields, "Wrong data encoding.") {|f| f.encoding == data.encoding}
+ end
+ end
+
+ def test_open_allows_you_to_set_encodings
+ encode_for_tests([%w[abc def]]) do |data|
+ # read and write in encoding
+ File.open(@temp_csv_path, "wb:#{data.encoding.name}") { |f| f << data }
+ CSV.open(@temp_csv_path, "rb:#{data.encoding.name}") do |csv|
+ csv.each do |row|
+ assert_all?(row, "Wrong data encoding.") {|f| f.encoding == data.encoding}
+ end
+ end
+
+ # read and write with transcoding
+ File.open(@temp_csv_path, "wb:UTF-32BE:#{data.encoding.name}") do |f|
+ f << data
+ end
+ CSV.open(@temp_csv_path, "rb:UTF-32BE:#{data.encoding.name}") do |csv|
+ csv.each do |row|
+ assert_all?(row, "Wrong data encoding.") {|f| f.encoding == data.encoding}
+ end
+ end
+ end
+ end
+
+ def test_foreach_allows_you_to_set_encodings
+ encode_for_tests([%w[abc def]]) do |data|
+ # read and write in encoding
+ File.open(@temp_csv_path, "wb", encoding: data.encoding) { |f| f << data }
+ CSV.foreach(@temp_csv_path, encoding: data.encoding) do |row|
+ row.each {|f| assert_equal(f.encoding, data.encoding)}
+ end
+
+ # read and write with transcoding
+ File.open(@temp_csv_path, "wb:UTF-32BE:#{data.encoding.name}") do |f|
+ f << data
+ end
+ CSV.foreach( @temp_csv_path,
+ encoding: "UTF-32BE:#{data.encoding.name}" ) do |row|
+ assert_all?(row, "Wrong data encoding.") {|f| f.encoding == data.encoding}
+ end
+ end
+ end
+
+ def test_read_allows_you_to_set_encodings
+ encode_for_tests([%w[abc def]]) do |data|
+ # read and write in encoding
+ File.open(@temp_csv_path, "wb:#{data.encoding.name}") { |f| f << data }
+ rows = CSV.read(@temp_csv_path, encoding: data.encoding.name)
+ assert_all?(rows.flatten, "Wrong data encoding.") {|f| f.encoding == data.encoding}
+
+ # read and write with transcoding
+ File.open(@temp_csv_path, "wb:UTF-32BE:#{data.encoding.name}") do |f|
+ f << data
+ end
+ rows = CSV.read( @temp_csv_path,
+ encoding: "UTF-32BE:#{data.encoding.name}" )
+ assert_all?(rows.flatten, "Wrong data encoding.") {|f| f.encoding == data.encoding}
+ end
+ end
+
+ #################################
+ ### Write CSV in any Encoding ###
+ #################################
+
+ def test_can_write_csv_in_any_encoding
+ each_encoding do |encoding|
+ # test generate_line with encoding hint
+ begin
+ csv = %w[abc d|ef].map { |f| f.encode(encoding) }.
+ to_csv(col_sep: "|", encoding: encoding.name)
+ rescue Encoding::ConverterNotFoundError
+ next
+ end
+ assert_equal(encoding, csv.encoding)
+
+ # test generate_line with encoding guessing from fields
+ csv = %w[abc d|ef].map { |f| f.encode(encoding) }.to_csv(col_sep: "|")
+ assert_equal(encoding, csv.encoding)
+
+ # writing to files
+ data = encode_ary([%w[abc d,ef], %w[123 456 ]], encoding)
+ CSV.open(@temp_csv_path, "wb:#{encoding.name}") do |f|
+ data.each { |row| f << row }
+ end
+ assert_equal(data, CSV.read(@temp_csv_path, encoding: encoding.name))
+ end
+ end
+
+ def test_encoding_is_upgraded_during_writing_as_needed
+ data = ["foo".force_encoding("US-ASCII"), "\u3042"]
+ assert_equal("US-ASCII", data.first.encoding.name)
+ assert_equal("UTF-8", data.last.encoding.name)
+ assert_equal("UTF-8", data.join('').encoding.name)
+ assert_equal("UTF-8", data.to_csv.encoding.name)
+ end
+
+ def test_encoding_is_upgraded_for_ascii_content_during_writing_as_needed
+ data = ["foo".force_encoding("ISO-8859-1"), "\u3042"]
+ assert_equal("ISO-8859-1", data.first.encoding.name)
+ assert_equal("UTF-8", data.last.encoding.name)
+ assert_equal("UTF-8", data.join('').encoding.name)
+ assert_equal("UTF-8", data.to_csv.encoding.name)
+ end
+
+ def test_explicit_encoding
+ bug9766 = '[ruby-core:62113] [Bug #9766]'
+ s = CSV.generate(encoding: "Windows-31J") do |csv|
+ csv << ["foo".force_encoding("ISO-8859-1"), "\u3042"]
+ end
+ assert_equal(["foo,\u3042\n".encode(Encoding::Windows_31J), Encoding::Windows_31J], [s, s.encoding], bug9766)
+ end
+
+ private
+
+ def assert_parses(fields, encoding, options = { })
+ encoding = Encoding.find(encoding) unless encoding.is_a? Encoding
+ orig_fields = fields
+ fields = encode_ary(fields, encoding)
+ data = ary_to_data(fields, options)
+ parsed = CSV.parse(data, options)
+ assert_equal(fields, parsed)
+ parsed.flatten.each_with_index do |field, i|
+ assert_equal(encoding, field.encoding, "Field[#{i + 1}] was transcoded.")
+ end
+ File.open(@temp_csv_path, "wb") {|f| f.print(data)}
+ CSV.open(@temp_csv_path, "rb:#{encoding}", options) do |csv|
+ csv.each_with_index do |row, i|
+ assert_equal(fields[i], row)
+ end
+ end
+ begin
+ CSV.open(@temp_csv_path, "rb:#{encoding}:#{__ENCODING__}", options) do |csv|
+ csv.each_with_index do |row, i|
+ assert_equal(orig_fields[i], row)
+ end
+ end unless encoding == __ENCODING__
+ rescue Encoding::ConverterNotFoundError
+ end
+ options[:encoding] = encoding.name
+ CSV.open(@temp_csv_path, options) do |csv|
+ csv.each_with_index do |row, i|
+ assert_equal(fields[i], row)
+ end
+ end
+ options.delete(:encoding)
+ options[:external_encoding] = encoding.name
+ options[:internal_encoding] = __ENCODING__.name
+ begin
+ CSV.open(@temp_csv_path, options) do |csv|
+ csv.each_with_index do |row, i|
+ assert_equal(orig_fields[i], row)
+ end
+ end unless encoding == __ENCODING__
+ rescue Encoding::ConverterNotFoundError
+ end
+ end
+
+ def encode_ary(ary, encoding)
+ ary.map { |row| row.map { |field| field.encode(encoding) } }
+ end
+
+ def ary_to_data(ary, options = { })
+ encoding = ary.flatten.first.encoding
+ quote_char = (options[:quote_char] || '"').encode(encoding)
+ col_sep = (options[:col_sep] || ",").encode(encoding)
+ row_sep = (options[:row_sep] || "\n").encode(encoding)
+ ary.map { |row|
+ row.map { |field|
+ [quote_char, field.encode(encoding), quote_char].join('')
+ }.join(col_sep) + row_sep
+ }.join('').encode(encoding)
+ end
+
+ def encode_for_tests(data, options = { })
+ yield ary_to_data(encode_ary(data, "UTF-8"), options)
+ yield ary_to_data(encode_ary(data, "UTF-16BE"), options)
+ end
+
+ def each_encoding
+ Encoding.list.each do |encoding|
+ next if encoding.dummy? # skip "dummy" encodings
+ yield encoding
+ end
+ end
+
+ def no_warnings
+ old_verbose, $VERBOSE = $VERBOSE, nil
+ yield
+ ensure
+ $VERBOSE = old_verbose
+ end
+end
diff --git a/jni/ruby/test/csv/test_features.rb b/jni/ruby/test/csv/test_features.rb
new file mode 100755
index 0000000..e314657
--- /dev/null
+++ b/jni/ruby/test/csv/test_features.rb
@@ -0,0 +1,327 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+
+# 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.
+
+begin
+ require "zlib"
+rescue LoadError
+end
+
+require_relative "base"
+require "tempfile"
+
+class TestCSV::Features < TestCSV
+ extend DifferentOFS
+
+ 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
+ super
+ @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_bug_8405
+ 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_csv_char_readers
+ %w[col_sep row_sep quote_char].each do |reader|
+ csv = CSV.new("abc,def", reader.to_sym => "|")
+ assert_equal("|", csv.send(reader))
+ 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).row_sep
+ assert_equal(line_end, discovered)
+ end
+
+ assert_equal("\n", CSV.new("\n\r\n\r").row_sep)
+
+ assert_equal($/, CSV.new("").row_sep)
+
+ assert_equal($/, CSV.new(STDERR).row_sep)
+ end
+
+ def test_lineno
+ assert_equal(5, @sample_data.lines.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_with_message(ArgumentError, /unknown/) {
+ CSV.new(@sample_data, 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
+
+ def test_csv_behavior_readers
+ %w[ unconverted_fields return_headers write_headers
+ skip_blanks force_quotes ].each do |behavior|
+ assert_not_predicate(CSV.new("abc,def"), "#{behavior}?", "Behavior defaulted to on.")
+ csv = CSV.new("abc,def", behavior.to_sym => true)
+ assert_predicate(csv, "#{behavior}?", "Behavior change now registered.")
+ end
+ end
+
+ def test_converters_reader
+ # no change
+ assert_equal( [:integer],
+ CSV.new("abc,def", converters: [:integer]).converters )
+
+ # just one
+ assert_equal( [:integer],
+ CSV.new("abc,def", converters: :integer).converters )
+
+ # expanded
+ assert_equal( [:integer, :float],
+ CSV.new("abc,def", converters: :numeric).converters )
+
+ # custom
+ csv = CSV.new("abc,def", converters: [:integer, lambda { }])
+ assert_equal(2, csv.converters.size)
+ assert_equal(:integer, csv.converters.first)
+ assert_instance_of(Proc, csv.converters.last)
+ end
+
+ def test_header_converters_reader
+ # no change
+ hc = :header_converters
+ assert_equal([:downcase], CSV.new("abc,def", hc => [:downcase]).send(hc))
+
+ # just one
+ assert_equal([:downcase], CSV.new("abc,def", hc => :downcase).send(hc))
+
+ # custom
+ csv = CSV.new("abc,def", hc => [:symbol, lambda { }])
+ assert_equal(2, csv.send(hc).size)
+ assert_equal(:symbol, csv.send(hc).first)
+ assert_instance_of(Proc, csv.send(hc).last)
+ 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_predicate row, :header_row?}
+ csv.rewind
+ csv.each {|row| assert_predicate 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.row_sep)
+ ensure
+ zipped.close
+ end if defined?(Zlib::GzipReader)
+
+ def test_gzip_writer_bug_fix
+ Tempfile.create(%w"temp .gz") {|tempfile|
+ tempfile.close
+ file = tempfile.path
+ 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_include(Zlib::GzipReader.open(file) {|f| f.read},
+ $INPUT_RECORD_SEPARATOR, "@row_sep did not default")
+ }
+ end if defined?(Zlib::GzipWriter)
+
+ def test_inspect_is_smart_about_io_types
+ str = CSV.new("string,data").inspect
+ assert_include(str, "io_type:StringIO", "IO type not detected.")
+
+ str = CSV.new($stderr).inspect
+ assert_include(str, "io_type:$stderr", "IO type not detected.")
+
+ Tempfile.create(%w"temp .csv") {|tempfile|
+ tempfile.close
+ path = tempfile.path
+ File.open(path, "w") { |csv| csv << "one,two,three\n1,2,3\n" }
+ str = CSV.open(path) { |csv| csv.inspect }
+ assert_include(str, "io_type:File", "IO type not detected.")
+ }
+ end
+
+ def test_inspect_shows_key_attributes
+ str = @csv.inspect
+ %w[lineno col_sep row_sep quote_char].each do |attr_name|
+ assert_match(/\b#{attr_name}:[^\s>]+/, str)
+ end
+ end
+
+ def test_inspect_shows_headers_when_available
+ CSV.new("one,two,three\n1,2,3\n", headers: true) do |csv|
+ assert_include(csv.inspect, "headers:true", "Header hint not shown.")
+ csv.shift # load headers
+ assert_match(/headers:\[[^\]]+\]/, csv.inspect)
+ end
+ end
+
+ def test_inspect_encoding_is_ascii_compatible
+ CSV.new("one,two,three\n1,2,3\n".encode("UTF-16BE")) do |csv|
+ assert_send([Encoding, :compatible?,
+ Encoding.find("US-ASCII"), csv.inspect.encoding],
+ "inspect() was not ASCII compatible.")
+ end
+ end
+
+ def test_version
+ assert_not_nil(CSV::VERSION)
+ assert_instance_of(String, CSV::VERSION)
+ assert_predicate(CSV::VERSION, :frozen?)
+ assert_match(/\A\d\.\d\.\d\Z/, CSV::VERSION)
+ end
+
+ def test_accepts_comment_skip_lines_option
+ assert_nothing_raised(ArgumentError) do
+ CSV.new(@sample_data, :skip_lines => /\A\s*#/)
+ end
+ end
+
+ def test_accepts_comment_defaults_to_nil
+ c = CSV.new(@sample_data)
+ assert_nil(c.skip_lines)
+ end
+
+ class RegexStub
+ end
+
+ def test_requires_skip_lines_to_call_match
+ regex_stub = RegexStub.new
+ assert_raise_with_message(ArgumentError, /skip_lines/) do
+ CSV.new(@sample_data, :skip_lines => regex_stub)
+ end
+ end
+
+ def test_comment_rows_are_ignored
+ sample_data = "line,1,a\n#not,a,line\nline,2,b\n #also,no,line"
+ c = CSV.new sample_data, :skip_lines => /\A\s*#/
+ assert_equal [["line", "1", "a"], ["line", "2", "b"]], c.each.to_a
+ end
+
+ def test_quoted_skip_line_markers_are_ignored
+ sample_data = "line,1,a\n\"#not\",a,line\nline,2,b"
+ c = CSV.new sample_data, :skip_lines => /\A\s*#/
+ assert_equal [["line", "1", "a"], ["#not", "a", "line"], ["line", "2", "b"]], c.each.to_a
+ end
+
+ def test_string_works_like_a_regexp
+ sample_data = "line,1,a\n#(not,a,line\nline,2,b\n also,#no,line"
+ c = CSV.new sample_data, :skip_lines => "#"
+ assert_equal [["line", "1", "a"], ["line", "2", "b"]], c.each.to_a
+ end
+
+end
diff --git a/jni/ruby/test/csv/test_headers.rb b/jni/ruby/test/csv/test_headers.rb
new file mode 100755
index 0000000..79ccd20
--- /dev/null
+++ b/jni/ruby/test/csv/test_headers.rb
@@ -0,0 +1,297 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+
+# 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_relative "base"
+
+class TestCSV::Headers < TestCSV
+ extend DifferentOFS
+
+ def setup
+ super
+ @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_predicate(row, :header_row?)
+ assert_not_predicate(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_predicate(row, :header_row?)
+ assert_not_predicate(row, :field_row?)
+ end
+
+ def test_csv_header_string_inherits_separators
+ # parse with custom col_sep
+ csv = nil
+ assert_nothing_raised(Exception) do
+ csv = CSV.parse( @data.tr(",", "|"), col_sep: "|",
+ headers: "my|new|headers" )
+ end
+
+ # verify headers were recognized
+ 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)
+ 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_predicate(row, :header_row?)
+ assert_not_predicate(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_not_predicate(row, :header_row?)
+ assert_predicate(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_not_predicate(row, :header_row?)
+ assert_predicate(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
+ # Note that the trailing space is intentional
+ csv = CSV.parse( "One,TWO Three ", headers: true,
+ return_headers: true,
+ header_converters: :symbol )
+ assert_equal([:one, :two_three], csv.headers)
+ end
+
+ def test_builtin_converters_with_blank_header
+ csv = CSV.parse( "one,,three", headers: true,
+ return_headers: true,
+ header_converters: [:downcase, :symbol] )
+ assert_equal([:one, nil, :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_headers_reader
+ # no headers
+ assert_nil(CSV.new(@data).headers)
+
+ # headers
+ csv = CSV.new(@data, headers: true)
+ assert_equal(true, csv.headers) # before headers are read
+ csv.shift # set headers
+ assert_equal(%w[first second third], csv.headers) # after headers are read
+ 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
diff --git a/jni/ruby/test/csv/test_interface.rb b/jni/ruby/test/csv/test_interface.rb
new file mode 100755
index 0000000..d6bf470
--- /dev/null
+++ b/jni/ruby/test/csv/test_interface.rb
@@ -0,0 +1,368 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+
+# 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_relative "base"
+require "tempfile"
+
+class TestCSV::Interface < TestCSV
+ extend DifferentOFS
+
+ def setup
+ super
+ @tempfile = Tempfile.new(%w"temp .csv")
+ @tempfile.close
+ @path = @tempfile.path
+
+ File.open(@path, "wb") 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
+ @tempfile.close(true)
+ super
+ 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_foreach_enum
+ CSV.foreach(@path, col_sep: "\t", row_sep: "\r\n").zip(@expected) do |row, exp|
+ assert_equal(exp, 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_not_predicate(csv, :closed?)
+ csv.close
+ assert_predicate(csv, :closed?)
+
+ ret = CSV.open(@path) do |new_csv|
+ csv = new_csv
+ assert_instance_of(CSV, new_csv)
+ "Return value."
+ end
+ assert_predicate(csv, :closed?)
+ assert_equal("Return value.", ret)
+ end
+
+ def test_parse
+ data = File.binread(@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_parse_line_with_empty_lines
+ assert_equal(nil, CSV.parse_line("")) # to signal eof
+ assert_equal(Array.new, CSV.parse_line("\n1,2,3"))
+ 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, "rb+", 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
+
+ def test_enumerators_are_supported
+ CSV.open(@path, col_sep: "\t", row_sep: "\r\n") do |csv|
+ enum = csv.each
+ assert_instance_of(Enumerator, enum)
+ assert_equal(@expected.shift, enum.next)
+ end
+ end
+
+ def test_nil_is_not_acceptable
+ assert_raise_with_message ArgumentError, "Cannot parse nil as CSV" do
+ CSV.new(nil)
+ 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, "wb", headers: true,
+ header_converters: :symbol ) do |csv|
+ csv << lines.first.keys
+ lines.each { |line| csv << line }
+ end
+ CSV.open( @path, "rb", headers: true,
+ converters: :all,
+ header_converters: :symbol ) do |csv|
+ csv.each { |line| assert_equal(lines.shift, line.to_hash) }
+ end
+ end
+
+ def test_write_hash_with_string_keys
+ File.unlink(@path)
+
+ lines = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}]
+ CSV.open( @path, "wb", headers: true ) do |csv|
+ csv << lines.first.keys
+ lines.each { |line| csv << line }
+ end
+ CSV.open( @path, "rb", headers: true ) do |csv|
+ csv.each do |line|
+ csv.headers.each_with_index do |header, h|
+ keys = line.to_hash.keys
+ assert_instance_of(String, keys[h])
+ assert_same(header, keys[h])
+ end
+ end
+ end
+ end
+
+ def test_write_hash_with_headers_array
+ File.unlink(@path)
+
+ lines = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}]
+ CSV.open(@path, "wb", headers: [:b, :a, :c]) do |csv|
+ lines.each { |line| csv << line }
+ end
+
+ # test writing fields in the correct order
+ File.open(@path, "rb") do |f|
+ assert_equal("2,1,3", f.gets.strip)
+ assert_equal("5,4,6", f.gets.strip)
+ end
+
+ # test reading CSV with headers
+ CSV.open( @path, "rb", headers: [:b, :a, :c],
+ converters: :all ) do |csv|
+ csv.each { |line| assert_equal(lines.shift, line.to_hash) }
+ end
+ end
+
+ def test_write_hash_with_headers_string
+ File.unlink(@path)
+
+ lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}]
+ CSV.open(@path, "wb", headers: "b|a|c", col_sep: "|") do |csv|
+ lines.each { |line| csv << line }
+ end
+
+ # test writing fields in the correct order
+ File.open(@path, "rb") do |f|
+ assert_equal("2|1|3", f.gets.strip)
+ assert_equal("5|4|6", f.gets.strip)
+ end
+
+ # test reading CSV with headers
+ CSV.open( @path, "rb", headers: "b|a|c",
+ col_sep: "|",
+ converters: :all ) do |csv|
+ csv.each { |line| assert_equal(lines.shift, line.to_hash) }
+ end
+ end
+
+ def test_write_headers
+ File.unlink(@path)
+
+ lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}]
+ CSV.open( @path, "wb", headers: "b|a|c",
+ write_headers: true,
+ col_sep: "|" ) do |csv|
+ lines.each { |line| csv << line }
+ end
+
+ # test writing fields in the correct order
+ File.open(@path, "rb") do |f|
+ assert_equal("b|a|c", f.gets.strip)
+ assert_equal("2|1|3", f.gets.strip)
+ assert_equal("5|4|6", f.gets.strip)
+ end
+
+ # test reading CSV with headers
+ CSV.open( @path, "rb", headers: true,
+ col_sep: "|",
+ converters: :all ) 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, "wb", 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, "wb", 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 { |new_csv| new_csv.instance_eval { @io } })
+ end
+
+ def test_options_are_not_modified
+ opt = {}.freeze
+ assert_nothing_raised { CSV.foreach(@path, opt) }
+ assert_nothing_raised { CSV.open(@path, opt){} }
+ assert_nothing_raised { CSV.parse("", opt) }
+ assert_nothing_raised { CSV.parse_line("", opt) }
+ assert_nothing_raised { CSV.read(@path, opt) }
+ assert_nothing_raised { CSV.readlines(@path, opt) }
+ assert_nothing_raised { CSV.table(@path, opt) }
+ assert_nothing_raised { CSV.generate(opt){} }
+ assert_nothing_raised { CSV.generate_line([], opt) }
+ assert_nothing_raised { CSV.filter("", "", opt){} }
+ assert_nothing_raised { CSV.instance("", opt) }
+ end
+end
diff --git a/jni/ruby/test/csv/test_row.rb b/jni/ruby/test/csv/test_row.rb
new file mode 100755
index 0000000..3acceea
--- /dev/null
+++ b/jni/ruby/test/csv/test_row.rb
@@ -0,0 +1,355 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+
+# 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_relative "base"
+
+class TestCSV::Row < TestCSV
+ 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))
+
+ # 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'))
+ 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_send([@row, :header?, "A"])
+ assert_send([@row, :header?, "C"])
+ assert_not_send([@row, :header?, "Z"])
+ assert_send([@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, (_, 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" => nil, "B" => 2, "C" => 3}, 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
+end
diff --git a/jni/ruby/test/csv/test_table.rb b/jni/ruby/test/csv/test_table.rb
new file mode 100755
index 0000000..44e9d4a
--- /dev/null
+++ b/jni/ruby/test/csv/test_table.rb
@@ -0,0 +1,434 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+
+# 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_relative "base"
+
+class TestCSV::Table < TestCSV
+ extend DifferentOFS
+
+ def setup
+ super
+ @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_headers_empty
+ t = CSV::Table.new([])
+ assert_equal Array.new, t.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_set_by_col_with_header_row
+ r = [ CSV::Row.new(%w{X Y Z}, [97, 98, 99], true) ]
+ t = CSV::Table.new(r)
+ t.by_col!
+ t['A'] = [42]
+ assert_equal(['A'], t['A'])
+ 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") )
+ assert_equal( csv.lines.to_a[1..-1].join(''),
+ @table.to_csv(:write_headers => false) )
+
+ # 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
+ ##################
+ ### 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
+ end
+
+ def test_delete_column
+ ###################
+ ### Column Mode ###
+ ###################
+ @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
+ end
+
+ def test_delete_row
+ ################
+ ### Row Mode ###
+ ################
+ @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_with_blank_rows
+ data = "col1,col2\nra1,ra2\n\nrb1,rb2"
+ table = CSV.parse(data, :headers => true)
+ assert_equal(["ra2", nil, "rb2"], table.delete("col2"))
+ end
+
+ def test_delete_if_row
+ ######################
+ ### 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
+ end
+
+ def test_delete_if_column
+ ###################
+ ### Column Mode ###
+ ###################
+ @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_not_empty(@table, "Table was empty.")
+
+ assert_equal(@rows.size, @table.size)
+ end
+
+ def test_inspect_shows_current_mode
+ str = @table.inspect
+ assert_include(str, "mode:#{@table.mode}", "Mode not shown.")
+
+ @table.by_col!
+ str = @table.inspect
+ assert_include(str, "mode:#{@table.mode}", "Mode not shown.")
+ end
+
+ def test_inspect_encoding_is_ascii_compatible
+ assert_send([Encoding, :compatible?,
+ Encoding.find("US-ASCII"),
+ @table.inspect.encoding],
+ "inspect() was not ASCII compatible." )
+ end
+end
diff --git a/jni/ruby/test/csv/ts_all.rb b/jni/ruby/test/csv/ts_all.rb
new file mode 100644
index 0000000..3893841
--- /dev/null
+++ b/jni/ruby/test/csv/ts_all.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+
+# 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 "test_csv_parsing"
+require "test_features"
+require "test_interface"
+require "test_csv_writing"
+require "test_data_converters"
+require "test_row"
+require "test_table"
+require "test_headers"
+require "test_encodings"