PageRenderTime 95ms CodeModel.GetById 2ms RepoModel.GetById 1ms app.codeStats 0ms

/test/csv/test_table.rb

http://github.com/ruby/ruby
Ruby | 620 lines | 387 code | 115 blank | 118 comment | 0 complexity | d3cb2a5c979131e246cba5351821c32b MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, AGPL-3.0
  1. # -*- coding: utf-8 -*-
  2. # frozen_string_literal: false
  3. require_relative "helper"
  4. class TestCSVTable < Test::Unit::TestCase
  5. extend DifferentOFS
  6. def setup
  7. super
  8. @rows = [ CSV::Row.new(%w{A B C}, [1, 2, 3]),
  9. CSV::Row.new(%w{A B C}, [4, 5, 6]),
  10. CSV::Row.new(%w{A B C}, [7, 8, 9]) ]
  11. @table = CSV::Table.new(@rows)
  12. @header_table = CSV::Table.new(
  13. [CSV::Row.new(%w{A B C}, %w{A B C}, true)] + @rows
  14. )
  15. @header_only_table = CSV::Table.new([], headers: %w{A B C})
  16. end
  17. def test_initialze
  18. assert_not_nil(@table)
  19. assert_instance_of(CSV::Table, @table)
  20. end
  21. def test_modes
  22. assert_equal(:col_or_row, @table.mode)
  23. # non-destructive changes, intended for one shot calls
  24. cols = @table.by_col
  25. assert_equal(:col_or_row, @table.mode)
  26. assert_equal(:col, cols.mode)
  27. assert_equal(@table, cols)
  28. rows = @table.by_row
  29. assert_equal(:col_or_row, @table.mode)
  30. assert_equal(:row, rows.mode)
  31. assert_equal(@table, rows)
  32. col_or_row = rows.by_col_or_row
  33. assert_equal(:row, rows.mode)
  34. assert_equal(:col_or_row, col_or_row.mode)
  35. assert_equal(@table, col_or_row)
  36. # destructive mode changing calls
  37. assert_equal(@table, @table.by_row!)
  38. assert_equal(:row, @table.mode)
  39. assert_equal(@table, @table.by_col_or_row!)
  40. assert_equal(:col_or_row, @table.mode)
  41. end
  42. def test_headers
  43. assert_equal(@rows.first.headers, @table.headers)
  44. end
  45. def test_headers_empty
  46. t = CSV::Table.new([])
  47. assert_equal Array.new, t.headers
  48. end
  49. def test_headers_only
  50. assert_equal(%w[A B C], @header_only_table.headers)
  51. end
  52. def test_headers_modified_by_row
  53. table = CSV::Table.new([], headers: ["A", "B"])
  54. table << ["a", "b"]
  55. table.first << {"C" => "c"}
  56. assert_equal(["A", "B", "C"], table.headers)
  57. end
  58. def test_index
  59. ##################
  60. ### Mixed Mode ###
  61. ##################
  62. # by row
  63. @rows.each_index { |i| assert_equal(@rows[i], @table[i]) }
  64. assert_equal(nil, @table[100]) # empty row
  65. # by row with Range
  66. assert_equal([@table[1], @table[2]], @table[1..2])
  67. # by col
  68. @rows.first.headers.each do |header|
  69. assert_equal(@rows.map { |row| row[header] }, @table[header])
  70. end
  71. assert_equal([nil] * @rows.size, @table["Z"]) # empty col
  72. # by cell, row then col
  73. assert_equal(2, @table[0][1])
  74. assert_equal(6, @table[1]["C"])
  75. # by cell, col then row
  76. assert_equal(5, @table["B"][1])
  77. assert_equal(9, @table["C"][2])
  78. # with headers (by col)
  79. assert_equal(["B", 2, 5, 8], @header_table["B"])
  80. ###################
  81. ### Column Mode ###
  82. ###################
  83. @table.by_col!
  84. assert_equal([2, 5, 8], @table[1])
  85. assert_equal([2, 5, 8], @table["B"])
  86. ################
  87. ### Row Mode ###
  88. ################
  89. @table.by_row!
  90. assert_equal(@rows[1], @table[1])
  91. assert_raise(TypeError) { @table["B"] }
  92. ############################
  93. ### One Shot Mode Change ###
  94. ############################
  95. assert_equal(@rows[1], @table[1])
  96. assert_equal([2, 5, 8], @table.by_col[1])
  97. assert_equal(@rows[1], @table[1])
  98. end
  99. def test_set_row_or_column
  100. ##################
  101. ### Mixed Mode ###
  102. ##################
  103. # set row
  104. @table[2] = [10, 11, 12]
  105. assert_equal([%w[A B C], [1, 2, 3], [4, 5, 6], [10, 11, 12]], @table.to_a)
  106. @table[3] = CSV::Row.new(%w[A B C], [13, 14, 15])
  107. assert_equal( [%w[A B C], [1, 2, 3], [4, 5, 6], [10, 11, 12], [13, 14, 15]],
  108. @table.to_a )
  109. # set col
  110. @table["Type"] = "data"
  111. assert_equal( [ %w[A B C Type],
  112. [1, 2, 3, "data"],
  113. [4, 5, 6, "data"],
  114. [10, 11, 12, "data"],
  115. [13, 14, 15, "data"] ],
  116. @table.to_a )
  117. @table["Index"] = [1, 2, 3]
  118. assert_equal( [ %w[A B C Type Index],
  119. [1, 2, 3, "data", 1],
  120. [4, 5, 6, "data", 2],
  121. [10, 11, 12, "data", 3],
  122. [13, 14, 15, "data", nil] ],
  123. @table.to_a )
  124. @table["B"] = [100, 200]
  125. assert_equal( [ %w[A B C Type Index],
  126. [1, 100, 3, "data", 1],
  127. [4, 200, 6, "data", 2],
  128. [10, nil, 12, "data", 3],
  129. [13, nil, 15, "data", nil] ],
  130. @table.to_a )
  131. # verify resulting table
  132. assert_equal(<<-CSV, @table.to_csv)
  133. A,B,C,Type,Index
  134. 1,100,3,data,1
  135. 4,200,6,data,2
  136. 10,,12,data,3
  137. 13,,15,data,
  138. CSV
  139. # with headers
  140. @header_table["Type"] = "data"
  141. assert_equal(%w[Type data data data], @header_table["Type"])
  142. ###################
  143. ### Column Mode ###
  144. ###################
  145. @table.by_col!
  146. @table[1] = [2, 5, 11, 14]
  147. assert_equal( [ %w[A B C Type Index],
  148. [1, 2, 3, "data", 1],
  149. [4, 5, 6, "data", 2],
  150. [10, 11, 12, "data", 3],
  151. [13, 14, 15, "data", nil] ],
  152. @table.to_a )
  153. @table["Extra"] = "new stuff"
  154. assert_equal( [ %w[A B C Type Index Extra],
  155. [1, 2, 3, "data", 1, "new stuff"],
  156. [4, 5, 6, "data", 2, "new stuff"],
  157. [10, 11, 12, "data", 3, "new stuff"],
  158. [13, 14, 15, "data", nil, "new stuff"] ],
  159. @table.to_a )
  160. ################
  161. ### Row Mode ###
  162. ################
  163. @table.by_row!
  164. @table[1] = (1..6).to_a
  165. assert_equal( [ %w[A B C Type Index Extra],
  166. [1, 2, 3, "data", 1, "new stuff"],
  167. [1, 2, 3, 4, 5, 6],
  168. [10, 11, 12, "data", 3, "new stuff"],
  169. [13, 14, 15, "data", nil, "new stuff"] ],
  170. @table.to_a )
  171. assert_raise(TypeError) { @table["Extra"] = nil }
  172. end
  173. def test_set_by_col_with_header_row
  174. r = [ CSV::Row.new(%w{X Y Z}, [97, 98, 99], true) ]
  175. t = CSV::Table.new(r)
  176. t.by_col!
  177. t['A'] = [42]
  178. assert_equal(['A'], t['A'])
  179. end
  180. def test_each
  181. ######################
  182. ### Mixed/Row Mode ###
  183. ######################
  184. i = 0
  185. @table.each do |row|
  186. assert_equal(@rows[i], row)
  187. i += 1
  188. end
  189. # verify that we can chain the call
  190. assert_equal(@table, @table.each { })
  191. # without block
  192. enum = @table.each
  193. assert_instance_of(Enumerator, enum)
  194. assert_equal(@table.size, enum.size)
  195. i = 0
  196. enum.each do |row|
  197. assert_equal(@rows[i], row)
  198. i += 1
  199. end
  200. ###################
  201. ### Column Mode ###
  202. ###################
  203. @table.by_col!
  204. headers = @table.headers
  205. @table.each do |header, column|
  206. assert_equal(headers.shift, header)
  207. assert_equal(@table[header], column)
  208. end
  209. # without block
  210. enum = @table.each
  211. assert_instance_of(Enumerator, enum)
  212. assert_equal(@table.headers.size, enum.size)
  213. headers = @table.headers
  214. enum.each do |header, column|
  215. assert_equal(headers.shift, header)
  216. assert_equal(@table[header], column)
  217. end
  218. ############################
  219. ### One Shot Mode Change ###
  220. ############################
  221. @table.by_col_or_row!
  222. @table.each { |row| assert_instance_of(CSV::Row, row) }
  223. @table.by_col.each { |tuple| assert_instance_of(Array, tuple) }
  224. @table.each { |row| assert_instance_of(CSV::Row, row) }
  225. end
  226. def test_each_split
  227. yielded_values = []
  228. @table.each do |column1, column2, column3|
  229. yielded_values << [column1, column2, column3]
  230. end
  231. assert_equal(@rows.collect(&:to_a),
  232. yielded_values)
  233. end
  234. def test_enumerable
  235. assert_equal( @rows.values_at(0, 2),
  236. @table.select { |row| (row["B"] % 2).zero? } )
  237. assert_equal(@rows[1], @table.find { |row| row["C"] > 5 })
  238. end
  239. def test_to_a
  240. assert_equal([%w[A B C], [1, 2, 3], [4, 5, 6], [7, 8, 9]], @table.to_a)
  241. # with headers
  242. assert_equal( [%w[A B C], [1, 2, 3], [4, 5, 6], [7, 8, 9]],
  243. @header_table.to_a )
  244. end
  245. def test_to_csv
  246. csv = <<-CSV
  247. A,B,C
  248. 1,2,3
  249. 4,5,6
  250. 7,8,9
  251. CSV
  252. # normal conversion
  253. assert_equal(csv, @table.to_csv)
  254. assert_equal(csv, @table.to_s) # alias
  255. # with options
  256. assert_equal( csv.gsub(",", "|").gsub("\n", "\r\n"),
  257. @table.to_csv(col_sep: "|", row_sep: "\r\n") )
  258. assert_equal( csv.lines.to_a[1..-1].join(''),
  259. @table.to_csv(:write_headers => false) )
  260. # with headers
  261. assert_equal(csv, @header_table.to_csv)
  262. end
  263. def test_append
  264. # verify that we can chain the call
  265. assert_equal(@table, @table << [10, 11, 12])
  266. # Array append
  267. assert_equal(CSV::Row.new(%w[A B C], [10, 11, 12]), @table[-1])
  268. # Row append
  269. assert_equal(@table, @table << CSV::Row.new(%w[A B C], [13, 14, 15]))
  270. assert_equal(CSV::Row.new(%w[A B C], [13, 14, 15]), @table[-1])
  271. end
  272. def test_delete_mixed_one
  273. ##################
  274. ### Mixed Mode ###
  275. ##################
  276. # delete a row
  277. assert_equal(@rows[1], @table.delete(1))
  278. # delete a col
  279. assert_equal(@rows.map { |row| row["A"] }, @table.delete("A"))
  280. # verify resulting table
  281. assert_equal(<<-CSV, @table.to_csv)
  282. B,C
  283. 2,3
  284. 8,9
  285. CSV
  286. end
  287. def test_delete_mixed_multiple
  288. ##################
  289. ### Mixed Mode ###
  290. ##################
  291. # delete row and col
  292. second_row = @rows[1]
  293. a_col = @rows.map { |row| row["A"] }
  294. a_col_without_second_row = a_col[0..0] + a_col[2..-1]
  295. assert_equal([
  296. second_row,
  297. a_col_without_second_row,
  298. ],
  299. @table.delete(1, "A"))
  300. # verify resulting table
  301. assert_equal(<<-CSV, @table.to_csv)
  302. B,C
  303. 2,3
  304. 8,9
  305. CSV
  306. end
  307. def test_delete_column
  308. ###################
  309. ### Column Mode ###
  310. ###################
  311. @table.by_col!
  312. assert_equal(@rows.map { |row| row[0] }, @table.delete(0))
  313. assert_equal(@rows.map { |row| row["C"] }, @table.delete("C"))
  314. # verify resulting table
  315. assert_equal(<<-CSV, @table.to_csv)
  316. B
  317. 2
  318. 5
  319. 8
  320. CSV
  321. end
  322. def test_delete_row
  323. ################
  324. ### Row Mode ###
  325. ################
  326. @table.by_row!
  327. assert_equal(@rows[1], @table.delete(1))
  328. assert_raise(TypeError) { @table.delete("C") }
  329. # verify resulting table
  330. assert_equal(<<-CSV, @table.to_csv)
  331. A,B,C
  332. 1,2,3
  333. 7,8,9
  334. CSV
  335. end
  336. def test_delete_with_blank_rows
  337. data = "col1,col2\nra1,ra2\n\nrb1,rb2"
  338. table = CSV.parse(data, :headers => true)
  339. assert_equal(["ra2", nil, "rb2"], table.delete("col2"))
  340. end
  341. def test_delete_if_row
  342. ######################
  343. ### Mixed/Row Mode ###
  344. ######################
  345. # verify that we can chain the call
  346. assert_equal(@table, @table.delete_if { |row| (row["B"] % 2).zero? })
  347. # verify resulting table
  348. assert_equal(<<-CSV, @table.to_csv)
  349. A,B,C
  350. 4,5,6
  351. CSV
  352. end
  353. def test_delete_if_row_without_block
  354. ######################
  355. ### Mixed/Row Mode ###
  356. ######################
  357. enum = @table.delete_if
  358. assert_instance_of(Enumerator, enum)
  359. assert_equal(@table.size, enum.size)
  360. # verify that we can chain the call
  361. assert_equal(@table, enum.each { |row| (row["B"] % 2).zero? })
  362. # verify resulting table
  363. assert_equal(<<-CSV, @table.to_csv)
  364. A,B,C
  365. 4,5,6
  366. CSV
  367. end
  368. def test_delete_if_column
  369. ###################
  370. ### Column Mode ###
  371. ###################
  372. @table.by_col!
  373. assert_equal(@table, @table.delete_if { |h, v| h > "A" })
  374. assert_equal(<<-CSV, @table.to_csv)
  375. A
  376. 1
  377. 4
  378. 7
  379. CSV
  380. end
  381. def test_delete_if_column_without_block
  382. ###################
  383. ### Column Mode ###
  384. ###################
  385. @table.by_col!
  386. enum = @table.delete_if
  387. assert_instance_of(Enumerator, enum)
  388. assert_equal(@table.headers.size, enum.size)
  389. assert_equal(@table, enum.each { |h, v| h > "A" })
  390. assert_equal(<<-CSV, @table.to_csv)
  391. A
  392. 1
  393. 4
  394. 7
  395. CSV
  396. end
  397. def test_delete_headers_only
  398. ###################
  399. ### Column Mode ###
  400. ###################
  401. @header_only_table.by_col!
  402. # delete by index
  403. assert_equal([], @header_only_table.delete(0))
  404. assert_equal(%w[B C], @header_only_table.headers)
  405. # delete by header
  406. assert_equal([], @header_only_table.delete("C"))
  407. assert_equal(%w[B], @header_only_table.headers)
  408. end
  409. def test_values_at
  410. ##################
  411. ### Mixed Mode ###
  412. ##################
  413. # rows
  414. assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
  415. assert_equal(@rows.values_at(1..2), @table.values_at(1..2))
  416. # cols
  417. assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at("A", "C"))
  418. assert_equal([[2, 3], [5, 6], [8, 9]], @table.values_at("B".."C"))
  419. ###################
  420. ### Column Mode ###
  421. ###################
  422. @table.by_col!
  423. assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at(0, 2))
  424. assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at("A", "C"))
  425. ################
  426. ### Row Mode ###
  427. ################
  428. @table.by_row!
  429. assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
  430. assert_raise(TypeError) { @table.values_at("A", "C") }
  431. ############################
  432. ### One Shot Mode Change ###
  433. ############################
  434. assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
  435. assert_equal([[1, 3], [4, 6], [7, 9]], @table.by_col.values_at(0, 2))
  436. assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
  437. end
  438. def test_array_delegation
  439. assert_not_empty(@table, "Table was empty.")
  440. assert_equal(@rows.size, @table.size)
  441. end
  442. def test_inspect_shows_current_mode
  443. str = @table.inspect
  444. assert_include(str, "mode:#{@table.mode}", "Mode not shown.")
  445. @table.by_col!
  446. str = @table.inspect
  447. assert_include(str, "mode:#{@table.mode}", "Mode not shown.")
  448. end
  449. def test_inspect_encoding_is_ascii_compatible
  450. assert_send([Encoding, :compatible?,
  451. Encoding.find("US-ASCII"),
  452. @table.inspect.encoding],
  453. "inspect() was not ASCII compatible." )
  454. end
  455. def test_dig_mixed
  456. # by row
  457. assert_equal(@rows[0], @table.dig(0))
  458. assert_nil(@table.dig(100)) # empty row
  459. # by col
  460. assert_equal([2, 5, 8], @table.dig("B"))
  461. assert_equal([nil] * @rows.size, @table.dig("Z")) # empty col
  462. # by row then col
  463. assert_equal(2, @table.dig(0, 1))
  464. assert_equal(6, @table.dig(1, "C"))
  465. # by col then row
  466. assert_equal(5, @table.dig("B", 1))
  467. assert_equal(9, @table.dig("C", 2))
  468. end
  469. def test_dig_by_column
  470. @table.by_col!
  471. assert_equal([2, 5, 8], @table.dig(1))
  472. assert_equal([2, 5, 8], @table.dig("B"))
  473. # by col then row
  474. assert_equal(5, @table.dig("B", 1))
  475. assert_equal(9, @table.dig("C", 2))
  476. end
  477. def test_dig_by_row
  478. @table.by_row!
  479. assert_equal(@rows[1], @table.dig(1))
  480. assert_raise(TypeError) { @table.dig("B") }
  481. # by row then col
  482. assert_equal(2, @table.dig(0, 1))
  483. assert_equal(6, @table.dig(1, "C"))
  484. end
  485. def test_dig_cell
  486. table = CSV::Table.new([CSV::Row.new(["A"], [["foo", ["bar", ["baz"]]]])])
  487. # by row, col then cell
  488. assert_equal("foo", table.dig(0, "A", 0))
  489. assert_equal(["baz"], table.dig(0, "A", 1, 1))
  490. # by col, row then cell
  491. assert_equal("foo", table.dig("A", 0, 0))
  492. assert_equal(["baz"], table.dig("A", 0, 1, 1))
  493. end
  494. def test_dig_cell_no_dig
  495. table = CSV::Table.new([CSV::Row.new(["A"], ["foo"])])
  496. # by row, col then cell
  497. assert_raise(TypeError) do
  498. table.dig(0, "A", 0)
  499. end
  500. # by col, row then cell
  501. assert_raise(TypeError) do
  502. table.dig("A", 0, 0)
  503. end
  504. end
  505. end