tc_interface.rb 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. #!/usr/local/bin/ruby -w
  2. # tc_interface.rb
  3. #
  4. # Created by James Edward Gray II on 2005-11-14.
  5. # Copyright 2012 Gray Productions. All rights reserved.
  6. require "test/unit"
  7. require "faster_csv"
  8. class TestFasterCSVInterface < Test::Unit::TestCase
  9. def setup
  10. @path = File.join(File.dirname(__FILE__), "temp_test_data.csv")
  11. File.open(@path, "w") do |file|
  12. file << "1\t2\t3\r\n"
  13. file << "4\t5\r\n"
  14. end
  15. @expected = [%w{1 2 3}, %w{4 5}]
  16. end
  17. def teardown
  18. File.unlink(@path)
  19. end
  20. ### Test Read Interface ###
  21. def test_foreach
  22. FasterCSV.foreach(@path, :col_sep => "\t", :row_sep => "\r\n") do |row|
  23. assert_equal(@expected.shift, row)
  24. end
  25. end
  26. def test_open_and_close
  27. csv = FasterCSV.open(@path, "r+", :col_sep => "\t", :row_sep => "\r\n")
  28. assert_not_nil(csv)
  29. assert_instance_of(FasterCSV, csv)
  30. assert_equal(false, csv.closed?)
  31. csv.close
  32. assert(csv.closed?)
  33. ret = FasterCSV.open(@path) do |csv|
  34. assert_instance_of(FasterCSV, csv)
  35. "Return value."
  36. end
  37. assert(csv.closed?)
  38. assert_equal("Return value.", ret)
  39. end
  40. def test_parse
  41. data = File.read(@path)
  42. assert_equal( @expected,
  43. FasterCSV.parse(data, :col_sep => "\t", :row_sep => "\r\n") )
  44. FasterCSV.parse(data, :col_sep => "\t", :row_sep => "\r\n") do |row|
  45. assert_equal(@expected.shift, row)
  46. end
  47. end
  48. def test_parse_line
  49. row = FasterCSV.parse_line("1;2;3", :col_sep => ";")
  50. assert_not_nil(row)
  51. assert_instance_of(Array, row)
  52. assert_equal(%w{1 2 3}, row)
  53. # shortcut interface
  54. row = "1;2;3".parse_csv(:col_sep => ";")
  55. assert_not_nil(row)
  56. assert_instance_of(Array, row)
  57. assert_equal(%w{1 2 3}, row)
  58. end
  59. def test_parse_line_with_empty_lines
  60. assert_equal(nil, FasterCSV.parse_line("")) # to signal eof
  61. assert_equal(Array.new, FasterCSV.parse_line("\n1,2,3"))
  62. end
  63. def test_read_and_readlines
  64. assert_equal( @expected,
  65. FasterCSV.read(@path, :col_sep => "\t", :row_sep => "\r\n") )
  66. assert_equal( @expected,
  67. FasterCSV.readlines( @path,
  68. :col_sep => "\t", :row_sep => "\r\n") )
  69. data = FasterCSV.open(@path, :col_sep => "\t", :row_sep => "\r\n") do |csv|
  70. csv.read
  71. end
  72. assert_equal(@expected, data)
  73. data = FasterCSV.open(@path, :col_sep => "\t", :row_sep => "\r\n") do |csv|
  74. csv.readlines
  75. end
  76. assert_equal(@expected, data)
  77. end
  78. def test_table
  79. table = FasterCSV.table(@path, :col_sep => "\t", :row_sep => "\r\n")
  80. assert_instance_of(FasterCSV::Table, table)
  81. assert_equal([[:"1", :"2", :"3"], [4, 5, nil]], table.to_a)
  82. end
  83. def test_shift # aliased as gets() and readline()
  84. FasterCSV.open(@path, "r+", :col_sep => "\t", :row_sep => "\r\n") do |csv|
  85. assert_equal(@expected.shift, csv.shift)
  86. assert_equal(@expected.shift, csv.shift)
  87. assert_equal(nil, csv.shift)
  88. end
  89. end
  90. def test_long_line # ruby's regex parser may have problems with long rows
  91. File.unlink(@path)
  92. long_field_length = 2800
  93. File.open(@path, "w") do |file|
  94. file << "1\t2\t#{'3' * long_field_length}\r\n"
  95. end
  96. @expected = [%w{1 2} + ['3' * long_field_length]]
  97. test_shift
  98. end
  99. ### Test Write Interface ###
  100. def test_generate
  101. str = FasterCSV.generate do |csv| # default empty String
  102. assert_instance_of(FasterCSV, csv)
  103. assert_equal(csv, csv << [1, 2, 3])
  104. assert_equal(csv, csv << [4, nil, 5])
  105. end
  106. assert_not_nil(str)
  107. assert_instance_of(String, str)
  108. assert_equal("1,2,3\n4,,5\n", str)
  109. FasterCSV.generate(str) do |csv| # appending to a String
  110. assert_equal(csv, csv << ["last", %Q{"row"}])
  111. end
  112. assert_equal(%Q{1,2,3\n4,,5\nlast,"""row"""\n}, str)
  113. end
  114. def test_generate_line
  115. line = FasterCSV.generate_line(%w{1 2 3}, :col_sep => ";")
  116. assert_not_nil(line)
  117. assert_instance_of(String, line)
  118. assert_equal("1;2;3\n", line)
  119. # shortcut interface
  120. line = %w{1 2 3}.to_csv(:col_sep => ";")
  121. assert_not_nil(line)
  122. assert_instance_of(String, line)
  123. assert_equal("1;2;3\n", line)
  124. end
  125. def test_write_header_detection
  126. File.unlink(@path)
  127. headers = %w{a b c}
  128. FasterCSV.open(@path, "w", :headers => true) do |csv|
  129. csv << headers
  130. csv << %w{1 2 3}
  131. assert_equal(headers, csv.instance_variable_get(:@headers))
  132. end
  133. end
  134. def test_write_lineno
  135. File.unlink(@path)
  136. FasterCSV.open(@path, "w") do |csv|
  137. lines = 20
  138. lines.times { csv << %w{a b c} }
  139. assert_equal(lines, csv.lineno)
  140. end
  141. end
  142. def test_write_hash
  143. File.unlink(@path)
  144. lines = [{:a => 1, :b => 2, :c => 3}, {:a => 4, :b => 5, :c => 6}]
  145. FasterCSV.open( @path, "w", :headers => true,
  146. :header_converters => :symbol ) do |csv|
  147. csv << lines.first.keys
  148. lines.each { |line| csv << line }
  149. end
  150. FasterCSV.open( @path, "r", :headers => true,
  151. :converters => :all,
  152. :header_converters => :symbol ) do |csv|
  153. csv.each { |line| assert_equal(lines.shift, line.to_hash) }
  154. end
  155. end
  156. def test_write_hash_with_headers_array
  157. File.unlink(@path)
  158. lines = [{:a => 1, :b => 2, :c => 3}, {:a => 4, :b => 5, :c => 6}]
  159. FasterCSV.open(@path, "w", :headers => [:b, :a, :c]) do |csv|
  160. lines.each { |line| csv << line }
  161. end
  162. # test writing fields in the correct order
  163. File.open(@path, "r") do |f|
  164. assert_equal("2,1,3", f.gets.strip)
  165. assert_equal("5,4,6", f.gets.strip)
  166. end
  167. # test reading CSV with headers
  168. FasterCSV.open( @path, "r", :headers => [:b, :a, :c],
  169. :converters => :all ) do |csv|
  170. csv.each { |line| assert_equal(lines.shift, line.to_hash) }
  171. end
  172. end
  173. def test_write_hash_with_headers_string
  174. File.unlink(@path)
  175. lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}]
  176. FasterCSV.open( @path, "w", :headers => "b|a|c",
  177. :col_sep => "|" ) do |csv|
  178. lines.each { |line| csv << line }
  179. end
  180. # test writing fields in the correct order
  181. File.open(@path, "r") do |f|
  182. assert_equal("2|1|3", f.gets.strip)
  183. assert_equal("5|4|6", f.gets.strip)
  184. end
  185. # test reading CSV with headers
  186. FasterCSV.open( @path, "r", :headers => "b|a|c",
  187. :col_sep => "|",
  188. :converters => :all ) do |csv|
  189. csv.each { |line| assert_equal(lines.shift, line.to_hash) }
  190. end
  191. end
  192. def test_write_headers
  193. File.unlink(@path)
  194. lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}]
  195. FasterCSV.open( @path, "w", :headers => "b|a|c",
  196. :write_headers => true,
  197. :col_sep => "|" ) do |csv|
  198. lines.each { |line| csv << line }
  199. end
  200. # test writing fields in the correct order
  201. File.open(@path, "r") do |f|
  202. assert_equal("b|a|c", f.gets.strip)
  203. assert_equal("2|1|3", f.gets.strip)
  204. assert_equal("5|4|6", f.gets.strip)
  205. end
  206. # test reading CSV with headers
  207. FasterCSV.open( @path, "r", :headers => true,
  208. :col_sep => "|",
  209. :converters => :all ) do |csv|
  210. csv.each { |line| assert_equal(lines.shift, line.to_hash) }
  211. end
  212. end
  213. def test_append # aliased add_row() and puts()
  214. File.unlink(@path)
  215. FasterCSV.open(@path, "w", :col_sep => "\t", :row_sep => "\r\n") do |csv|
  216. @expected.each { |row| csv << row }
  217. end
  218. test_shift
  219. # same thing using FasterCSV::Row objects
  220. File.unlink(@path)
  221. FasterCSV.open(@path, "w", :col_sep => "\t", :row_sep => "\r\n") do |csv|
  222. @expected.each { |row| csv << FasterCSV::Row.new(Array.new, row) }
  223. end
  224. test_shift
  225. end
  226. ### Test Read and Write Interface ###
  227. def test_filter
  228. assert_respond_to(FasterCSV, :filter)
  229. expected = [[1, 2, 3], [4, 5]]
  230. FasterCSV.filter( "1;2;3\n4;5\n", (result = String.new),
  231. :in_col_sep => ";", :out_col_sep => ",",
  232. :converters => :all ) do |row|
  233. assert_equal(row, expected.shift)
  234. row.map! { |n| n * 2 }
  235. row << "Added\r"
  236. end
  237. assert_equal("2,4,6,\"Added\r\"\n8,10,\"Added\r\"\n", result)
  238. end
  239. def test_instance
  240. csv = String.new
  241. first = nil
  242. assert_nothing_raised(Exception) do
  243. first = FasterCSV.instance(csv, :col_sep => ";")
  244. first << %w{a b c}
  245. end
  246. assert_equal("a;b;c\n", csv)
  247. second = nil
  248. assert_nothing_raised(Exception) do
  249. second = FasterCSV.instance(csv, :col_sep => ";")
  250. second << [1, 2, 3]
  251. end
  252. assert_equal(first.object_id, second.object_id)
  253. assert_equal("a;b;c\n1;2;3\n", csv)
  254. # shortcuts
  255. assert_equal(STDOUT, FasterCSV.instance.instance_eval { @io })
  256. assert_equal(STDOUT, FasterCSV { |csv| csv.instance_eval { @io } })
  257. assert_equal(STDOUT, FCSV.instance.instance_eval { @io })
  258. assert_equal(STDOUT, FCSV { |csv| csv.instance_eval { @io } })
  259. end
  260. ### Test Alternate Interface ###
  261. def test_csv_interface
  262. require "csv"
  263. data = ["Number", 42, "Tricky Field", 'This has embedded "quotes"!']
  264. data_file = File.join(File.dirname(__FILE__), "temp_csv_data.csv")
  265. CSV.open(data_file, "w") { |f| 10.times { f << data } }
  266. csv = CSV.generate_line(data)
  267. tests = { :foreach => Array.new,
  268. :generate_line => csv,
  269. :open => Array.new,
  270. :parse => CSV.parse(csv),
  271. :parse_w_block => Array.new,
  272. :parse_line => CSV.parse_line(csv),
  273. :readlines => CSV.readlines(data_file) }
  274. CSV.foreach(data_file) { |row| tests[:foreach] << row }
  275. CSV.open(data_file, "r") { |row| tests[:open] << row }
  276. CSV.parse(([csv] * 3).join("\n")) { |row| tests[:parse_w_block] << row }
  277. Object.send(:remove_const, :CSV)
  278. assert_nothing_raised(Exception) do
  279. FasterCSV.build_csv_interface
  280. end
  281. %w{ foreach
  282. generate_line
  283. open
  284. parse
  285. parse_line
  286. readlines }.each do |meth|
  287. assert_respond_to(::CSV, meth)
  288. end
  289. faster_csv = Array.new
  290. CSV.foreach(data_file) { |row| faster_csv << row }
  291. assert_equal(tests[:foreach], faster_csv)
  292. assert_equal(tests[:generate_line], CSV.generate_line(data))
  293. faster_csv.clear
  294. CSV.open(data_file, "r") { |row| faster_csv << row }
  295. assert_equal(tests[:open], faster_csv)
  296. comp_file = data_file.sub("_csv_data", "_faster_csv_data")
  297. CSV.open(comp_file, "w") { |f| 10.times { f << data } }
  298. assert_equal(File.read(data_file), File.read(comp_file))
  299. assert_equal(tests[:parse], CSV.parse(csv))
  300. faster_csv.clear
  301. CSV.parse(([csv] * 3).join("\n")) { |row| faster_csv << row }
  302. assert_equal(tests[:parse_w_block], faster_csv)
  303. assert_equal(tests[:parse_line], CSV.parse_line(csv))
  304. assert_equal(tests[:readlines], CSV.readlines(data_file))
  305. Object.send(:remove_const, :CSV)
  306. load "csv.rb"
  307. [data_file, comp_file].each { |file| File.unlink(file) }
  308. end
  309. end