v
Зеркало из https://github.com/vlang/v
1/*
2csv reader 1.0 alpha
3
4Copyright (c) 2023 Dario Deledda. All rights reserved.
5Use of this source code is governed by an MIT license
6that can be found in the LICENSE file.
7
8This file contains tests
9
10Known limitations:
11*/
12import encoding.csv
13import strings
14import os
15
16/******************************************************************************
17*
18* Test Data
19*
20******************************************************************************/
21// dataset 1
22const txt1 = '
23
24#
25# pippo
26#
27a,b,c,d,e,f,g
280,dario,.2,3.2e-2,4,"pero5",6
29# first comment, test @# again
301,2,3,4,5,6,7
312,3,4,5,6,7,8
323,4,5,6,7,8,9
33
34a,"b,c,d",0,#,3,"pippo"
35
36# last comment
37'
38
39const target_header_list = [
40csv.HeaderItem{
41label: 'a'
42column: 0
43htype: .int
44},
45csv.HeaderItem{
46label: 'b'
47column: 1
48htype: .string
49},
50csv.HeaderItem{
51label: 'c'
52column: 2
53htype: .f32
54},
55csv.HeaderItem{
56label: 'd'
57column: 3
58htype: .f32
59},
60csv.HeaderItem{
61label: 'e'
62column: 4
63htype: .int
64},
65csv.HeaderItem{
66label: 'f'
67column: 5
68htype: .string
69},
70csv.HeaderItem{
71label: 'g'
72column: 6
73htype: .int
74},
75]
76
77const target_data = [
78['a', 'b', 'c', 'd', 'e', 'f', 'g'],
79['0', 'dario', '.2', '3.2e-2', '4', '"pero5"', '6'],
80['1', '2', '3', '4', '5', '6', '7'],
81['2', '3', '4', '5', '6', '7', '8'],
82['3', '4', '5', '6', '7', '8', '9'],
83['a', '"b,c,d"', '0', '#', '3', '"pippo"'], // 6 columns for test purpose
84]
85
86// dataset 2 crlf string from windows
87const txt2 = '
88
89#
90# pippo
91#
92a,b,c,d,e,f,g
930,dario,.2,3.2e-2,4,"pero5",6
94# first comment, test @# again
951,2,3,4,5,6,7
962,3,4,5,6,7,8
973,4,5,6,7,8,9
98
99a,"b,c,d",,#,3,"pippo"
100
101# last comment
102'
103
104// dataset 3/4
105const txt3 = 'a,b,c,d\r\n0,1,2,3\r\n4,5,6,7\r\n'
106const txt4 = 'a,b,c,d\n0,1,2,3\n4,5,6,7\n'
107/******************************************************************************
108*
109* Test Sequential Functions
110*
111******************************************************************************/
112fn test_csv_sequential() {
113mut csvr := csv.csv_sequential_reader(scr_buf: txt1.str, scr_buf_len: txt1.len)!
114mut data := [][]string{}
115for csvr.has_data() > 1 {
116data << csvr.get_next_row()!
117}
118csvr.dispose_csv_reader()
119assert data[0][0] == 'a', 'test_csv_sequential1 reading failed!'
120// there is a final empty row in txt1
121assert data[data.len - 2][0] == 'a', 'test_csv_sequential2 reading failed!'
122assert data[data.len - 2][1] == 'b,c,d', 'test_csv_sequential3 reading failed!'
123
124csvr = csv.csv_sequential_reader(scr_buf: txt2.str, scr_buf_len: txt2.len)!
125csvr.empty_cell = '####'
126data = [][]string{}
127for csvr.has_data() > 1 {
128data << csvr.get_next_row()!
129}
130csvr.dispose_csv_reader()
131assert data[data.len - 2][2] == '####', 'test_csv_sequential4 reading failed!'
132assert data[data.len - 2][5] == 'pippo', 'test_csv_sequential5 reading failed!'
133
134// create a temp file to test csv parsing from file
135file_path_str := os.join_path(os.temp_dir(), 'test_csv.csv')
136// println("file_path_str: ${file_path_str}")
137
138// test Windows confguration
139mut tmp_txt1 := txt1.replace('\n', '\r\n')
140
141mut f := os.open_file(file_path_str, 'wb')!
142unsafe {
143f.write_ptr(tmp_txt1.str, tmp_txt1.len)
144}
145// f.write_string(tmp_txt1)!
146f.close()
147
148csvr = csv.csv_sequential_reader(
149file_path: file_path_str
150mem_buf_size: 64
151end_line_len: csv.endline_crlf_len
152)!
153data = [][]string{}
154for csvr.has_data() > 1 {
155data << csvr.get_next_row()!
156}
157csvr.dispose_csv_reader()
158
159assert data[0][0] == 'a', 'test_csv_sequential1 reading failed!'
160// there is a final empty row in txt1
161assert data[data.len - 2][0] == 'a', 'test_csv_sequential2 reading failed!'
162assert data[data.len - 2][1] == 'b,c,d', 'test_csv_sequential3 reading failed!'
163
164// remove the temp file
165os.rm(file_path_str)!
166}
167
168/******************************************************************************
169*
170* Test Random Access Functions
171*
172******************************************************************************/
173fn perform_test(mut csvr csv.RandomAccessReader) ! {
174csvr.build_header_dict(csv.GetHeaderConf{})!
175
176// test the Header reader
177// println("csvr.header_list: ${csvr.header_list}")
178assert csvr.header_list == target_header_list, 'header_list not matched!'
179
180/*
181println("--------------------------------")
182for x in csvr.csv_map#[..5] {
183println(x.len)
184println(x)
185}
186println("--------------------------------")
187*/
188
189// test the data reading
190mut data := [][]string{len: csvr.csv_map.len}
191for x in 0 .. csvr.csv_map.len {
192data[x] = csvr.get_row(x)!
193// if x % 10000 == 0 {
194// println("#${x:-6d}")
195//}
196}
197
198/*
199// debug print
200println("---------------")
201for x in 0..csvr.csv_map.len {
202println(csvr.get_row(x)!)
203}
204*/
205
206// test if we have the same amount of data rows
207assert data.len == csvr.csv_map.len, 'data len not equal'
208
209// test the data retriever
210for row_count, row in target_data {
211// println("${data[row_count]} ${row}")
212assert data[row_count] == row, ''
213}
214
215// test lfcr cr
216assert csvr.get_cell(x: 6, y: 4)! == '9'
217
218// test the get cell behaviour
219assert csvr.get_cell(x: csvr.header_map['b'], y: 1)! == 'dario', 'get_cell failed 1'
220assert csvr.get_cell(x: csvr.header_map['g'], y: 5)! == csvr.default_cell, 'get_cell out of data failed 2'
221assert csvr.get_cellt(x: 0, y: 1)! == csv.CellValue(0), 'get_cellt [int] failed'
222assert csvr.get_cellt(x: 1, y: 1)! == csv.CellValue('dario'), 'get_cellt [string] failed'
223assert csvr.get_cellt(x: 2, y: 1)! == csv.CellValue(f32(.2)), 'get_cell [f32] failed'
224
225// test the filter quote flag
226csvr.quote_remove = true
227assert csvr.get_cell(x: 1, y: 5)! == 'b,c,d', 'get_cell filer quote flag failed'
228}
229
230fn perform_test2(mut csvr csv.RandomAccessReader) ! {
231csvr.build_header_dict(csv.GetHeaderConf{})!
232// test the empty cells
233assert csvr.get_cell(x: csvr.header_map['c'], y: 5)! == csvr.empty_cell, 'get_cell empty_cell failed 2'
234}
235
236fn perform_test3(mut csvr csv.RandomAccessReader) ! {
237csvr.build_header_dict(csv.GetHeaderConf{})!
238/*
239// debug print
240println("---------------")
241for x in 0..csvr.csv_map.len {
242println(csvr.get_row(x)!)
243}
244*/
245assert csvr.get_cell(x: csvr.header_map['d'], y: 2)! == '7', 'test \n \r\n failed'
246}
247
248fn test_csv_string() {
249// test the csv parsing from RAM
250mut csvr := csv.csv_reader_from_string(txt1)!
251perform_test(mut csvr)!
252csvr.dispose_csv_reader()
253
254// create a temp file to test csv parsing from file
255file_path_str := os.join_path(os.temp_dir(), 'test_csv.csv')
256// println("file_path_str: ${file_path_str}")
257
258// test Windows confguration
259mut tmp_txt1 := txt1.replace('\n', '\r\n')
260
261mut f := os.open_file(file_path_str, 'wb')!
262unsafe {
263f.write_ptr(tmp_txt1.str, tmp_txt1.len)
264}
265// f.write_string(tmp_txt1)!
266f.close()
267
268// parse the temp file
269csvr = csv.csv_reader(
270file_path: file_path_str
271mem_buf_size: 32
272end_line_len: csv.endline_crlf_len
273)!
274perform_test(mut csvr)!
275csvr.dispose_csv_reader()
276
277// remove the temp file
278os.rm(file_path_str)!
279
280csvr = csv.csv_reader_from_string(txt2)!
281perform_test2(mut csvr)!
282csvr.dispose_csv_reader()
283
284// test crlf endline
285csvr = csv.csv_reader(
286scr_buf: txt3.str
287scr_buf_len: txt3.len
288end_line_len: csv.endline_crlf_len
289)!
290perform_test3(mut csvr)!
291csvr.dispose_csv_reader()
292
293// test cr endline
294csvr = csv.csv_reader(scr_buf: txt4.str, scr_buf_len: txt4.len, end_line_len: csv.endline_cr_len)!
295perform_test3(mut csvr)!
296csvr.dispose_csv_reader()
297}
298
299fn test_coherence() {
300file_path_str := os.join_path(os.temp_dir(), 'test_csv.csv')
301mut f := os.open_file(file_path_str, 'w')!
302mut b := strings.new_builder(64536)
303mut i := u64(0)
304mut sum := u64(0)
305for rows in 0 .. 1000 {
306for col in 0 .. 1000 {
307if col > 0 {
308b.write_u8(`,`)
309}
310b.write_string(i.str())
311i++
312sum += i
313}
314b.write_string('\n')
315}
316f.write_string(b.str())!
317f.close()
318
319sum -= i
320// println('sum: ${sum}')
321
322// parse the temp file
323mut csvr := csv.csv_reader(
324file_path: file_path_str
325mem_buf_size: 32
326end_line_len: csv.endline_cr_len
327)!
328
329mut sum1 := u64(0)
330for row_index in 0 .. csvr.csv_map.len {
331row := csvr.get_row(row_index)!
332for x in row {
333sum1 += u64(x.int())
334}
335}
336// println('sum: ${sum1}')
337
338csvr.dispose_csv_reader()
339
340// remove the temp file
341os.rm(file_path_str)!
342
343assert sum == sum1, 'csv coherence test failed'
344}
345
346// Debug code
347fn main() {
348test_csv_string()
349}
350