1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
use strict;
use warnings;
use utf8;
use Test::More;
use Cepis::CSV;
binmode Test::More->builder->output, ':encoding(UTF-8)';
binmode Test::More->builder->failure_output, ':encoding(UTF-8)';
is_deeply( Cepis::CSV::parse_rows(''), [], 'empty input yields no rows' );
is_deeply(
Cepis::CSV::parse_rows("a,b,c\n1,2,3\n"),
[ [qw(a b c)], [qw(1 2 3)] ],
'plain rows'
);
is_deeply(
Cepis::CSV::parse_rows("a,b\r\n1,2\r\n"),
[ [qw(a b)], [qw(1 2)] ],
'CRLF line endings'
);
is_deeply(
Cepis::CSV::parse_rows("a,b\n1,2"),
[ [qw(a b)], [qw(1 2)] ],
'a missing final newline still closes the row'
);
is_deeply(
Cepis::CSV::parse_rows(qq{a,b\n"um, dois",3\n}),
[ [qw(a b)], [ 'um, dois', '3' ] ],
'a quoted field may hold a comma'
);
is_deeply(
Cepis::CSV::parse_rows(qq{a\n"he said ""hi"""\n}),
[ ['a'], ['he said "hi"'] ],
'a doubled quote is an escaped quote'
);
is_deeply(
Cepis::CSV::parse_rows(qq{a,b\n"line\none",2\n}),
[ [qw(a b)], [ "line\none", '2' ] ],
'a quoted field may hold a newline'
);
is_deeply(
Cepis::CSV::parse_rows(qq{a,b,c\n,,\n}),
[ [qw(a b c)], [ '', '', '' ] ],
'empty fields survive'
);
is_deeply(
Cepis::CSV::parse_rows(qq{a,b\n"",""\n}),
[ [qw(a b)], [ '', '' ] ],
'explicitly quoted empty fields survive'
);
is_deeply(
Cepis::CSV::parse_rows("\x{FEFF}a,b\n1,2\n"),
[ [qw(a b)], [qw(1 2)] ],
'a byte order mark is stripped'
);
is_deeply(
Cepis::CSV::parse_rows("a,b\n1,2\n\n\n"),
[ [qw(a b)], [qw(1 2)] ],
'blank lines are skipped'
);
is_deeply(
Cepis::CSV::parse_rows("cep,localidade\n01001000,São Paulo\n"),
[ [qw(cep localidade)], [ '01001000', 'São Paulo' ] ],
'non-ASCII characters survive'
);
my ( $header, $records )
= Cepis::CSV::parse_hashes("cep,localidade,uf\n01001000,São Paulo,SP\n99999999,,\n");
is_deeply( $header, [qw(cep localidade uf)], 'the header row comes back' );
is_deeply(
$records,
[ { cep => '01001000', localidade => 'São Paulo', uf => 'SP' },
{ cep => '99999999', localidade => '', uf => '' },
],
'records are keyed by column name'
);
( $header, $records ) = Cepis::CSV::parse_hashes("a,b,c\n1\n");
is_deeply(
$records,
[ { a => '1', b => '', c => '' } ],
'a short row is filled with empty strings'
);
( $header, $records ) = Cepis::CSV::parse_hashes("a\n1,2,3\n");
is_deeply( $records, [ { a => '1' } ], 'fields beyond the header are dropped' );
( $header, $records ) = Cepis::CSV::parse_hashes('');
is_deeply( [ $header, $records ], [ [], [] ], 'empty input yields nothing' );
done_testing();
|