summaryrefslogtreecommitdiffstats
path: root/t/02-csv.t
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-26 14:40:05 -0300
committerMurilo Ijanc <[email protected]>2026-07-26 14:40:05 -0300
commit0bc578d6d334c7f1ccaf329cd61bb8bce76b7f59 (patch)
tree86f73108f0432fd8330edcaab8b8ae7018322dee /t/02-csv.t
downloadperl-0.1.0.tar.gz
Initial importv0.1.0
Diffstat (limited to 't/02-csv.t')
-rw-r--r--t/02-csv.t105
1 files changed, 105 insertions, 0 deletions
diff --git a/t/02-csv.t b/t/02-csv.t
new file mode 100644
index 0000000..8850620
--- /dev/null
+++ b/t/02-csv.t
@@ -0,0 +1,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();