StephanZ-fastercsv 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,154 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # tc_serialization.rb
4
+ #
5
+ # Created by James Edward Gray II on 2006-03-28.
6
+ # Copyright 2006 Gray Productions. All rights reserved.
7
+
8
+ require "test/unit"
9
+
10
+ require "faster_csv"
11
+
12
+ # An example of how to provide custom CSV serialization.
13
+ class Hash
14
+ def self.csv_load( meta, headers, fields )
15
+ self[*headers.zip(fields).flatten.map { |e| eval(e) }]
16
+ end
17
+
18
+ def csv_headers
19
+ keys.map { |key| key.inspect }
20
+ end
21
+
22
+ def csv_dump( headers )
23
+ headers.map { |header| fetch(eval(header)).inspect }
24
+ end
25
+ end
26
+
27
+ class TestSerialization < Test::Unit::TestCase
28
+
29
+ ### Classes Used to Test Serialization ###
30
+
31
+ class ReadOnlyName
32
+ def initialize( first, last )
33
+ @first, @last = first, last
34
+ end
35
+
36
+ attr_reader :first, :last
37
+
38
+ def ==( other )
39
+ %w{first last}.all? { |att| send(att) == other.send(att) }
40
+ end
41
+ end
42
+
43
+ Name = Struct.new(:first, :last)
44
+
45
+ class FullName < Name
46
+ def initialize( first, last, suffix = nil )
47
+ super(first, last)
48
+
49
+ @suffix = suffix
50
+ end
51
+
52
+ attr_accessor :suffix
53
+
54
+ def ==( other )
55
+ %w{first last suffix}.all? { |att| send(att) == other.send(att) }
56
+ end
57
+ end
58
+
59
+ ### Tests ###
60
+
61
+ def test_class_dump
62
+ @names = [ %w{James Gray},
63
+ %w{Dana Gray},
64
+ %w{Greg Brown} ].map do |first, last|
65
+ ReadOnlyName.new(first, last)
66
+ end
67
+
68
+ assert_nothing_raised(Exception) do
69
+ @data = FasterCSV.dump(@names)
70
+ end
71
+ assert_equal(<<-END_CLASS_DUMP.gsub(/^\s*/, ""), @data)
72
+ class,TestSerialization::ReadOnlyName
73
+ @first,@last
74
+ James,Gray
75
+ Dana,Gray
76
+ Greg,Brown
77
+ END_CLASS_DUMP
78
+ end
79
+
80
+ def test_struct_dump
81
+ @names = [ %w{James Gray},
82
+ %w{Dana Gray},
83
+ %w{Greg Brown} ].map do |first, last|
84
+ Name.new(first, last)
85
+ end
86
+
87
+ assert_nothing_raised(Exception) do
88
+ @data = FasterCSV.dump(@names)
89
+ end
90
+ assert_equal(<<-END_STRUCT_DUMP.gsub(/^\s*/, ""), @data)
91
+ class,TestSerialization::Name
92
+ first=,last=
93
+ James,Gray
94
+ Dana,Gray
95
+ Greg,Brown
96
+ END_STRUCT_DUMP
97
+ end
98
+
99
+ def test_inherited_struct_dump
100
+ @names = [ %w{James Gray II},
101
+ %w{Dana Gray},
102
+ %w{Greg Brown} ].map do |first, last, suffix|
103
+ FullName.new(first, last, suffix)
104
+ end
105
+
106
+ assert_nothing_raised(Exception) do
107
+ @data = FasterCSV.dump(@names)
108
+ end
109
+ assert_equal(<<-END_STRUCT_DUMP.gsub(/^\s*/, ""), @data)
110
+ class,TestSerialization::FullName
111
+ @suffix,first=,last=
112
+ II,James,Gray
113
+ ,Dana,Gray
114
+ ,Greg,Brown
115
+ END_STRUCT_DUMP
116
+ end
117
+
118
+ def test_load
119
+ %w{ test_class_dump
120
+ test_struct_dump
121
+ test_inherited_struct_dump }.each do |test|
122
+ send(test)
123
+ FasterCSV.load(@data).each do |loaded|
124
+ assert_instance_of(@names.first.class, loaded)
125
+ assert_equal(@names.shift, loaded)
126
+ end
127
+ end
128
+ end
129
+
130
+ def test_io
131
+ test_class_dump
132
+
133
+ data_file = File.join(File.dirname(__FILE__), "temp_test_data.csv")
134
+ FasterCSV.dump(@names, File.open(data_file, "w"))
135
+
136
+ assert(File.exist?(data_file))
137
+ assert_equal(<<-END_IO_DUMP.gsub(/^\s*/, ""), File.read(data_file))
138
+ class,TestSerialization::ReadOnlyName
139
+ @first,@last
140
+ James,Gray
141
+ Dana,Gray
142
+ Greg,Brown
143
+ END_IO_DUMP
144
+
145
+ assert_equal(@names, FasterCSV.load(File.open(data_file)))
146
+
147
+ File.unlink(data_file)
148
+ end
149
+
150
+ def test_custom_dump_and_load
151
+ obj = {1 => "simple", :test => Hash}
152
+ assert_equal(obj, FasterCSV.load(FasterCSV.dump([obj])).first)
153
+ end
154
+ end
data/test/tc_speed.rb ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # tc_speed.rb
4
+ #
5
+ # Created by James Edward Gray II on 2005-11-14.
6
+ # Copyright 2005 Gray Productions. All rights reserved.
7
+
8
+ require "test/unit"
9
+ require "timeout"
10
+
11
+ require "faster_csv"
12
+ require "csv"
13
+
14
+ class TestFasterCSVSpeed < Test::Unit::TestCase
15
+ PATH = File.join(File.dirname(__FILE__), "test_data.csv")
16
+ BIG_DATA = "123456789\n" * 1024
17
+
18
+ def test_that_we_are_doing_the_same_work
19
+ FasterCSV.open(PATH) do |csv|
20
+ CSV.foreach(PATH) do |row|
21
+ assert_equal(row, csv.shift)
22
+ end
23
+ end
24
+ end
25
+
26
+ def test_speed_vs_csv
27
+ csv_time = Time.now
28
+ CSV.foreach(PATH) do |row|
29
+ # do nothing, we're just timing a read...
30
+ end
31
+ csv_time = Time.now - csv_time
32
+
33
+ faster_csv_time = Time.now
34
+ FasterCSV.foreach(PATH) do |row|
35
+ # do nothing, we're just timing a read...
36
+ end
37
+ faster_csv_time = Time.now - faster_csv_time
38
+
39
+ assert(faster_csv_time < csv_time / 3)
40
+ end
41
+
42
+ def test_the_parse_fails_fast_when_it_can_for_unquoted_fields
43
+ assert_parse_errors_out('valid,fields,bad start"' + BIG_DATA)
44
+ end
45
+
46
+ def test_the_parse_fails_fast_when_it_can_for_unescaped_quotes
47
+ assert_parse_errors_out('valid,fields,"bad start"unescaped' + BIG_DATA)
48
+ end
49
+
50
+ def test_field_size_limit_controls_lookahead
51
+ assert_parse_errors_out( 'valid,fields,"' + BIG_DATA + '"',
52
+ :field_size_limit => 2048 )
53
+ end
54
+
55
+ private
56
+
57
+ def assert_parse_errors_out(*args)
58
+ assert_raise(FasterCSV::MalformedCSVError) do
59
+ Timeout.timeout(0.2) do
60
+ FasterCSV.parse(*args)
61
+ fail("Parse didn't error out")
62
+ end
63
+ end
64
+ end
65
+ end
data/test/tc_table.rb ADDED
@@ -0,0 +1,400 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # tc_table.rb
4
+ #
5
+ # Created by James Edward Gray II on 2006-02-24.
6
+ # Copyright 2006 Gray Productions. All rights reserved.
7
+
8
+ require "test/unit"
9
+
10
+ require "faster_csv"
11
+
12
+ class TestFasterCSVTable < Test::Unit::TestCase
13
+ def setup
14
+ @rows = [ FasterCSV::Row.new(%w{A B C}, [1, 2, 3]),
15
+ FasterCSV::Row.new(%w{A B C}, [4, 5, 6]),
16
+ FasterCSV::Row.new(%w{A B C}, [7, 8, 9]) ]
17
+ @table = FasterCSV::Table.new(@rows)
18
+
19
+ @header_table = FasterCSV::Table.new(
20
+ [FasterCSV::Row.new(%w{A B C}, %w{A B C}, true)] + @rows
21
+ )
22
+ end
23
+
24
+ def test_initialze
25
+ assert_not_nil(@table)
26
+ assert_instance_of(FasterCSV::Table, @table)
27
+ end
28
+
29
+ def test_modes
30
+ assert_equal(:col_or_row, @table.mode)
31
+
32
+ # non-destructive changes, intended for one shot calls
33
+ cols = @table.by_col
34
+ assert_equal(:col_or_row, @table.mode)
35
+ assert_equal(:col, cols.mode)
36
+ assert_equal(@table, cols)
37
+
38
+ rows = @table.by_row
39
+ assert_equal(:col_or_row, @table.mode)
40
+ assert_equal(:row, rows.mode)
41
+ assert_equal(@table, rows)
42
+
43
+ # destructive mode changing calls
44
+ assert_equal(@table, @table.by_row!)
45
+ assert_equal(:row, @table.mode)
46
+ assert_equal(@table, @table.by_col_or_row!)
47
+ assert_equal(:col_or_row, @table.mode)
48
+ end
49
+
50
+ def test_headers
51
+ assert_equal(@rows.first.headers, @table.headers)
52
+ end
53
+
54
+ def test_index
55
+ ##################
56
+ ### Mixed Mode ###
57
+ ##################
58
+ # by row
59
+ @rows.each_index { |i| assert_equal(@rows[i], @table[i]) }
60
+ assert_equal(nil, @table[100]) # empty row
61
+
62
+ # by col
63
+ @rows.first.headers.each do |header|
64
+ assert_equal(@rows.map { |row| row[header] }, @table[header])
65
+ end
66
+ assert_equal([nil] * @rows.size, @table["Z"]) # empty col
67
+
68
+ # by cell, row then col
69
+ assert_equal(2, @table[0][1])
70
+ assert_equal(6, @table[1]["C"])
71
+
72
+ # by cell, col then row
73
+ assert_equal(5, @table["B"][1])
74
+ assert_equal(9, @table["C"][2])
75
+
76
+ # with headers (by col)
77
+ assert_equal(["B", 2, 5, 8], @header_table["B"])
78
+
79
+ ###################
80
+ ### Column Mode ###
81
+ ###################
82
+ @table.by_col!
83
+
84
+ assert_equal([2, 5, 8], @table[1])
85
+ assert_equal([2, 5, 8], @table["B"])
86
+
87
+ ################
88
+ ### Row Mode ###
89
+ ################
90
+ @table.by_row!
91
+
92
+ assert_equal(@rows[1], @table[1])
93
+ assert_raise(TypeError) { @table["B"] }
94
+
95
+ ############################
96
+ ### One Shot Mode Change ###
97
+ ############################
98
+ assert_equal(@rows[1], @table[1])
99
+ assert_equal([2, 5, 8], @table.by_col[1])
100
+ assert_equal(@rows[1], @table[1])
101
+ end
102
+
103
+ def test_set_row_or_column
104
+ ##################
105
+ ### Mixed Mode ###
106
+ ##################
107
+ # set row
108
+ @table[2] = [10, 11, 12]
109
+ assert_equal([%w[A B C], [1, 2, 3], [4, 5, 6], [10, 11, 12]], @table.to_a)
110
+
111
+ @table[3] = FasterCSV::Row.new(%w[A B C], [13, 14, 15])
112
+ assert_equal( [%w[A B C], [1, 2, 3], [4, 5, 6], [10, 11, 12], [13, 14, 15]],
113
+ @table.to_a )
114
+
115
+ # set col
116
+ @table["Type"] = "data"
117
+ assert_equal( [ %w[A B C Type],
118
+ [1, 2, 3, "data"],
119
+ [4, 5, 6, "data"],
120
+ [10, 11, 12, "data"],
121
+ [13, 14, 15, "data"] ],
122
+ @table.to_a )
123
+
124
+ @table["Index"] = [1, 2, 3]
125
+ assert_equal( [ %w[A B C Type Index],
126
+ [1, 2, 3, "data", 1],
127
+ [4, 5, 6, "data", 2],
128
+ [10, 11, 12, "data", 3],
129
+ [13, 14, 15, "data", nil] ],
130
+ @table.to_a )
131
+
132
+ @table["B"] = [100, 200]
133
+ assert_equal( [ %w[A B C Type Index],
134
+ [1, 100, 3, "data", 1],
135
+ [4, 200, 6, "data", 2],
136
+ [10, nil, 12, "data", 3],
137
+ [13, nil, 15, "data", nil] ],
138
+ @table.to_a )
139
+
140
+ # verify resulting table
141
+ assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
142
+ A,B,C,Type,Index
143
+ 1,100,3,data,1
144
+ 4,200,6,data,2
145
+ 10,,12,data,3
146
+ 13,,15,data,
147
+ END_RESULT
148
+
149
+ # with headers
150
+ @header_table["Type"] = "data"
151
+ assert_equal(%w[Type data data data], @header_table["Type"])
152
+
153
+ ###################
154
+ ### Column Mode ###
155
+ ###################
156
+ @table.by_col!
157
+
158
+ @table[1] = [2, 5, 11, 14]
159
+ assert_equal( [ %w[A B C Type Index],
160
+ [1, 2, 3, "data", 1],
161
+ [4, 5, 6, "data", 2],
162
+ [10, 11, 12, "data", 3],
163
+ [13, 14, 15, "data", nil] ],
164
+ @table.to_a )
165
+
166
+ @table["Extra"] = "new stuff"
167
+ assert_equal( [ %w[A B C Type Index Extra],
168
+ [1, 2, 3, "data", 1, "new stuff"],
169
+ [4, 5, 6, "data", 2, "new stuff"],
170
+ [10, 11, 12, "data", 3, "new stuff"],
171
+ [13, 14, 15, "data", nil, "new stuff"] ],
172
+ @table.to_a )
173
+
174
+ ################
175
+ ### Row Mode ###
176
+ ################
177
+ @table.by_row!
178
+
179
+ @table[1] = (1..6).to_a
180
+ assert_equal( [ %w[A B C Type Index Extra],
181
+ [1, 2, 3, "data", 1, "new stuff"],
182
+ [1, 2, 3, 4, 5, 6],
183
+ [10, 11, 12, "data", 3, "new stuff"],
184
+ [13, 14, 15, "data", nil, "new stuff"] ],
185
+ @table.to_a )
186
+
187
+ assert_raise(TypeError) { @table["Extra"] = nil }
188
+ end
189
+
190
+ def test_each
191
+ ######################
192
+ ### Mixed/Row Mode ###
193
+ ######################
194
+ i = 0
195
+ @table.each do |row|
196
+ assert_equal(@rows[i], row)
197
+ i += 1
198
+ end
199
+
200
+ # verify that we can chain the call
201
+ assert_equal(@table, @table.each { })
202
+
203
+ ###################
204
+ ### Column Mode ###
205
+ ###################
206
+ @table.by_col!
207
+
208
+ headers = @table.headers
209
+ @table.each do |header, column|
210
+ assert_equal(headers.shift, header)
211
+ assert_equal(@table[header], column)
212
+ end
213
+
214
+ ############################
215
+ ### One Shot Mode Change ###
216
+ ############################
217
+ @table.by_col_or_row!
218
+
219
+ @table.each { |row| assert_instance_of(FasterCSV::Row, row) }
220
+ @table.by_col.each { |tuple| assert_instance_of(Array, tuple) }
221
+ @table.each { |row| assert_instance_of(FasterCSV::Row, row) }
222
+ end
223
+
224
+ def test_enumerable
225
+ assert_equal( @rows.values_at(0, 2),
226
+ @table.select { |row| (row["B"] % 2).zero? } )
227
+
228
+ assert_equal(@rows[1], @table.find { |row| row["C"] > 5 })
229
+ end
230
+
231
+ def test_to_a
232
+ assert_equal([%w[A B C], [1, 2, 3], [4, 5, 6], [7, 8, 9]], @table.to_a)
233
+
234
+ # with headers
235
+ assert_equal( [%w[A B C], [1, 2, 3], [4, 5, 6], [7, 8, 9]],
236
+ @header_table.to_a )
237
+ end
238
+
239
+ def test_to_csv
240
+ csv = <<-END_CSV.gsub(/^\s+/, "")
241
+ A,B,C
242
+ 1,2,3
243
+ 4,5,6
244
+ 7,8,9
245
+ END_CSV
246
+
247
+ # normal conversion
248
+ assert_equal(csv, @table.to_csv)
249
+ assert_equal(csv, @table.to_s) # alias
250
+
251
+ # with options
252
+ assert_equal( csv.gsub(",", "|").gsub("\n", "\r\n"),
253
+ @table.to_csv(:col_sep => "|", :row_sep => "\r\n") )
254
+
255
+ # with headers
256
+ assert_equal(csv, @header_table.to_csv)
257
+ end
258
+
259
+ def test_append
260
+ # verify that we can chain the call
261
+ assert_equal(@table, @table << [10, 11, 12])
262
+
263
+ # Array append
264
+ assert_equal(FasterCSV::Row.new(%w[A B C], [10, 11, 12]), @table[-1])
265
+
266
+ # Row append
267
+ assert_equal(@table, @table << FasterCSV::Row.new(%w[A B C], [13, 14, 15]))
268
+ assert_equal(FasterCSV::Row.new(%w[A B C], [13, 14, 15]), @table[-1])
269
+ end
270
+
271
+ def test_delete
272
+ ##################
273
+ ### Mixed Mode ###
274
+ ##################
275
+ # delete a row
276
+ assert_equal(@rows[1], @table.delete(1))
277
+
278
+ # delete a col
279
+ assert_equal(@rows.map { |row| row["A"] }, @table.delete("A"))
280
+
281
+ # verify resulting table
282
+ assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
283
+ B,C
284
+ 2,3
285
+ 8,9
286
+ END_RESULT
287
+
288
+ ###################
289
+ ### Column Mode ###
290
+ ###################
291
+ setup
292
+ @table.by_col!
293
+
294
+ assert_equal(@rows.map { |row| row[0] }, @table.delete(0))
295
+ assert_equal(@rows.map { |row| row["C"] }, @table.delete("C"))
296
+
297
+ # verify resulting table
298
+ assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
299
+ B
300
+ 2
301
+ 5
302
+ 8
303
+ END_RESULT
304
+
305
+ ################
306
+ ### Row Mode ###
307
+ ################
308
+ setup
309
+ @table.by_row!
310
+
311
+ assert_equal(@rows[1], @table.delete(1))
312
+ assert_raise(TypeError) { @table.delete("C") }
313
+
314
+ # verify resulting table
315
+ assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
316
+ A,B,C
317
+ 1,2,3
318
+ 7,8,9
319
+ END_RESULT
320
+ end
321
+
322
+ def test_delete_if
323
+ ######################
324
+ ### Mixed/Row Mode ###
325
+ ######################
326
+ # verify that we can chain the call
327
+ assert_equal(@table, @table.delete_if { |row| (row["B"] % 2).zero? })
328
+
329
+ # verify resulting table
330
+ assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
331
+ A,B,C
332
+ 4,5,6
333
+ END_RESULT
334
+
335
+ ###################
336
+ ### Column Mode ###
337
+ ###################
338
+ setup
339
+ @table.by_col!
340
+
341
+ assert_equal(@table, @table.delete_if { |h, v| h > "A" })
342
+ assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
343
+ A
344
+ 1
345
+ 4
346
+ 7
347
+ END_RESULT
348
+ end
349
+
350
+ def test_values_at
351
+ ##################
352
+ ### Mixed Mode ###
353
+ ##################
354
+ # rows
355
+ assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
356
+ assert_equal(@rows.values_at(1..2), @table.values_at(1..2))
357
+
358
+ # cols
359
+ assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at("A", "C"))
360
+ assert_equal([[2, 3], [5, 6], [8, 9]], @table.values_at("B".."C"))
361
+
362
+ ###################
363
+ ### Column Mode ###
364
+ ###################
365
+ @table.by_col!
366
+
367
+ assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at(0, 2))
368
+ assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at("A", "C"))
369
+
370
+ ################
371
+ ### Row Mode ###
372
+ ################
373
+ @table.by_row!
374
+
375
+ assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
376
+ assert_raise(TypeError) { @table.values_at("A", "C") }
377
+
378
+ ############################
379
+ ### One Shot Mode Change ###
380
+ ############################
381
+ assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
382
+ assert_equal([[1, 3], [4, 6], [7, 9]], @table.by_col.values_at(0, 2))
383
+ assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
384
+ end
385
+
386
+ def test_array_delegation
387
+ assert(!@table.empty?, "Table was empty.")
388
+
389
+ assert_equal(@rows.size, @table.size)
390
+ end
391
+
392
+ def test_inspect_shows_current_mode
393
+ str = @table.inspect
394
+ assert(str.include?("mode:#{@table.mode}"), "Mode not shown.")
395
+
396
+ @table.by_col!
397
+ str = @table.inspect
398
+ assert(str.include?("mode:#{@table.mode}"), "Mode not shown.")
399
+ end
400
+ end