1 dnl PSPP - a program for statistical analysis.
2 dnl Copyright (C) 2017, 2020, 2021 Free Software Foundation, Inc.
4 dnl This program is free software: you can redistribute it and/or modify
5 dnl it under the terms of the GNU General Public License as published by
6 dnl the Free Software Foundation, either version 3 of the License, or
7 dnl (at your option) any later version.
9 dnl This program is distributed in the hope that it will be useful,
10 dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
11 dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 dnl GNU General Public License for more details.
14 dnl You should have received a copy of the GNU General Public License
15 dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
17 AT_BANNER([Perl module tests])
19 m4_divert_push([PREPARE_TESTS])
20 # Find the Address Sanitizer library that PSPP is linked against, if any.
21 # If it exists, it needs to be preloaded when we run Perl.
22 asan_lib=$("$abs_top_builddir/libtool" --mode=execute ldd \
23 "$abs_top_builddir/src/ui/terminal/pspp" 2>/dev/null \
26 if test ! -e "$asan_lib"; then
30 dnl This command can be used to run with the PSPP Perl module after it has been
31 dnl built (with "make") but before it has been installed. The -I options are
32 dnl equivalent to "use ExtUtils::testlib;" inside the Perl program, but it does
33 dnl not need to be run with the perl-module build directory as the current
34 dnl working directory.
36 LD_PRELOAD="$asan_lib":"$LD_PRELOAD" \
37 LD_LIBRARY_PATH="$abs_top_builddir/src/.libs" \
38 DYLD_LIBRARY_PATH="$abs_top_builddir/src/.libs" \
39 ASAN_OPTIONS="$ASAN_OPTIONS detect_leaks=false" \
40 $PERL -I"$abs_top_builddir/perl-module/blib/arch" \
41 -I"$abs_top_builddir/perl-module/blib/lib" "$@"
43 m4_divert_pop([PREPARE_TESTS])
45 AT_SETUP([Perl create system file])
46 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
52 my $d = PSPP::Dict->new();
53 die "dictionary creation" if !ref $d;
54 die if $d->get_var_cnt () != 0;
56 $d->set_label ("My Dictionary");
57 $d->set_documents ("These Documents");
59 # Tests for variable creation
61 my $var0 = PSPP::Var->new ($d, "le");
62 die "trap illegal variable name" if ref $var0;
63 die if $d->get_var_cnt () != 0;
65 $var0 = PSPP::Var->new ($d, "legal");
66 die "accept legal variable name" if !ref $var0;
67 die if $d->get_var_cnt () != 1;
69 my $var1 = PSPP::Var->new ($d, "money",
70 (fmt=>PSPP::Fmt::DOLLAR,
71 width=>4, decimals=>2) );
72 die "cappet valid format" if !ref $var1;
73 die if $d->get_var_cnt () != 2;
75 $d->set_weight ($var1);
77 my $sysfile = PSPP::Sysfile->new ('testfile.sav', $d);
78 die "create sysfile object" if !ref $sysfile;
82 AT_CHECK([run_perl_module test.pl])
83 AT_DATA([dump-dict.sps],
84 [GET FILE='testfile.sav'.
90 AT_CHECK([pspp -O format=csv dump-dict.sps], [0], [dnl
98 Name,Position,Measurement Level,Role,Width,Alignment,Print Format,Write Format
99 legal,1,Scale,Input,8,Right,F9.2,F9.2
100 money,2,Scale,Input,8,Right,DOLLAR6.2,DOLLAR6.2
102 dump-dict.sps:5: note: SHOW: WEIGHT is money.
106 AT_SETUP([Perl writing cases to system files])
107 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
113 my $d = PSPP::Dict->new();
114 PSPP::Var->new ($d, "id",
122 PSPP::Var->new ($d, "name",
129 $d->set_documents ("This should not appear");
130 $d->clear_documents ();
131 $d->add_document ("This is a document line");
133 $d->set_label ("This is the file label");
135 # Check that we can write cases to system files.
136 my $sysfile = PSPP::Sysfile->new ("testfile.sav", $d);
137 my $res = $sysfile->append_case ( [34, "frederick"]);
138 die "append case" if !$res;
140 $res = $sysfile->append_case ( [34, "frederick", "extra"]);
141 die "append case with too many variables" if $res;
144 # Check that sysfiles are closed properly automaticallly in the destructor.
145 my $sysfile2 = PSPP::Sysfile->new ("testfile2.sav", $d);
146 $res = $sysfile2->append_case ( [21, "wheelbarrow"]);
147 die "append case 2" if !$res;
149 $res = $sysfile->append_case ( [34, "frederick", "extra"]);
150 die "append case with too many variables" if $res;
152 # Don't close. We want to test that the destructor does that.
154 AT_CHECK([run_perl_module test.pl])
155 AT_DATA([dump-dicts.sps],
156 [GET FILE='testfile.sav'.
162 GET FILE='testfile2.sav'.
168 AT_CHECK([pspp -O format=csv dump-dicts.sps], [0], [dnl
170 Name,Position,Measurement Level,Role,Width,Alignment,Print Format,Write Format
171 id,1,Scale,Input,8,Right,F2.0,F2.0
172 name,2,Nominal,Input,20,Left,A20,A20
175 Label,This is the file label
178 This is a document line
185 Name,Position,Measurement Level,Role,Width,Alignment,Print Format,Write Format
186 id,1,Scale,Input,8,Right,F2.0,F2.0
187 name,2,Nominal,Input,20,Left,A20,A20
190 Label,This is the file label
193 This is a document line
201 AT_SETUP([Perl write variable parameters])
202 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
208 my $dict = PSPP::Dict->new();
209 die "dictionary creation" if !ref $dict;
211 my $int = PSPP::Var->new ($dict, "integer",
212 (width=>8, decimals=>0) );
214 $int->set_label ("My Integer");
216 $int->add_value_label (99, "Silly");
217 $int->clear_value_labels ();
218 $int->add_value_label (0, "Zero");
219 $int->add_value_label (1, "Unity");
220 $int->add_value_label (2, "Duality");
222 my $str = PSPP::Var->new ($dict, "string",
223 (fmt=>PSPP::Fmt::A, width=>8) );
226 $str->set_label ("My String");
227 $str->add_value_label ("xx", "foo");
228 $str->add_value_label ("yy", "bar");
230 $str->set_missing_values ("this", "that");
232 my $longstr = PSPP::Var->new ($dict, "longstring",
233 (fmt=>PSPP::Fmt::A, width=>9) );
236 $longstr->set_label ("My Long String");
237 my $re = $longstr->add_value_label ("xxx", "xfoo");
239 $int->set_missing_values (9, 99);
241 my $sysfile = PSPP::Sysfile->new ("testfile.sav", $dict);
246 AT_CHECK([run_perl_module test.pl], [0], [], [stderr])
248 AT_DATA([dump-dict.sps],
249 [GET FILE='testfile.sav'.
252 AT_CHECK([pspp -O format=csv dump-dict.sps], [0], [dnl
254 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
255 integer,1,My Integer,Scale,Input,8,Right,F8.0,F8.0,9; 99
256 string,2,My String,Nominal,Input,8,Left,A8,A8,"""this ""; ""that """
257 longstring,3,My Long String,Nominal,Input,9,Left,A9,A9,
260 Variable Value,,Label
266 My Long String,xxx,xfoo
270 AT_SETUP([Perl dictionary survives system file])
271 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
280 my $d = PSPP::Dict->new();
282 PSPP::Var->new ($d, "id",
290 $sysfile = PSPP::Sysfile->new ("testfile.sav", $d);
293 my $res = $sysfile->append_case ([3]);
294 print "Dictionary survives sysfile\n" if $res;
296 AT_CHECK([run_perl_module test.pl], [0],
297 [Dictionary survives sysfile
301 m4_define([PERL_GENERATE_SYSFILE],
302 [AT_DATA([sample.sps],
303 [[data list notable list /string (a8) longstring (a12) numeric (f10) date (date11) dollar (dollar8.2) datetime (datetime17)
305 1111 One 1 1/1/1 1 1/1/1+01:01
306 2222 Two 2 2/2/2 2 2/2/2+02:02
307 3333 Three 3 3/3/3 3 3/3/3+03:03
309 5555 Five 5 5/5/5 5 5/5/5+05:05
313 variable labels string 'A Short String Variable'
314 /longstring 'A Long String Variable'
315 /numeric 'A Numeric Variable'
316 /date 'A Date Variable'
317 /dollar 'A Dollar Variable'
318 /datetime 'A Datetime Variable'.
321 missing values numeric (9, 5, 999).
323 missing values string ("3333").
326 /string '1111' 'ones' '2222' 'twos' '3333' 'threes'
327 /numeric 1 'Unity' 2 'Duality' 3 'Thripality'.
331 attribute=colour[1]('blue') colour[2]('pink') colour[3]('violet')
332 attribute=size('large') nationality('foreign').
335 save outfile='sample.sav'.
337 AT_CHECK([pspp -O format=csv sample.sps])])
339 AT_SETUP([Perl read system file])
340 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
341 PERL_GENERATE_SYSFILE
347 my $sf = PSPP::Reader->open ("sample.sav");
349 my $dict = $sf->get_dict ();
351 for (my $v = 0 ; $v < $dict->get_var_cnt() ; $v++)
353 my $var = $dict->get_var ($v);
354 my $name = $var->get_name ();
355 my $label = $var->get_label ();
357 print "Variable $v is \"$name\", label is \"$label\"\n";
359 my $vl = $var->get_value_labels ();
361 print "Value Labels:\n";
362 print "$_ => $vl->{$_}\n" for sort (keys %$vl);
365 while (my @c = $sf->get_next_case () )
367 for (my $v = 0; $v < $dict->get_var_cnt(); $v++)
369 print "val$v: \"$c[$v]\"\n";
374 AT_CHECK([run_perl_module test.pl], [0],
375 [Variable 0 is "string", label is "A Short String Variable"
380 Variable 1 is "longstring", label is "A Long String Variable"
382 Variable 2 is "numeric", label is "A Numeric Variable"
387 Variable 3 is "date", label is "A Date Variable"
389 Variable 4 is "dollar", label is "A Dollar Variable"
391 Variable 5 is "datetime", label is "A Datetime Variable"
431 AT_SETUP([Perl copying system files])
432 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
433 PERL_GENERATE_SYSFILE
439 my $input = PSPP::Reader->open ("sample.sav");
441 my $dict = $input->get_dict ();
443 my $output = PSPP::Sysfile->new ("copy.sav", $dict);
445 while (my (@c) = $input->get_next_case () )
447 $output->append_case (\@c);
452 AT_CHECK([run_perl_module test.pl])
453 AT_DATA([dump-dicts.sps],
454 [GET FILE='sample.sav'.
464 AT_CHECK([pspp -O format=csv dump-dicts.sps], [0],
466 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
467 string,1,A Short String Variable,Nominal,Input,8,Left,A8,A8,"""3333 """
468 longstring,2,A Long String Variable,Nominal,Input,12,Left,A12,A12,
469 numeric,3,A Numeric Variable,Scale,Input,8,Right,F10.0,F10.0,9; 5; 999
470 date,4,A Date Variable,Scale,Input,8,Right,DATE11,DATE11,
471 dollar,5,A Dollar Variable,Scale,Input,8,Right,DOLLAR11.2,DOLLAR11.2,
472 datetime,6,A Datetime Variable,Scale,Input,8,Right,DATETIME17.0,DATETIME17.0,
475 Variable Value,,Label
476 A Short String Variable,1111,ones
479 A Numeric Variable,1,Unity
482 Footnote: a. User-missing value
484 Table: Variable and Dataset Attributes
485 Variable and Name,,Value
486 A Numeric Variable,colour[1],blue
493 string,longstring,numeric,date,dollar,datetime
494 1111,One,1,01-JAN-2001,$1.00,01-JAN-2001 01:01
495 2222,Two,2,02-FEB-2002,$2.00,02-FEB-2002 02:02
496 3333,Three,3,03-MAR-2003,$3.00,03-MAR-2003 03:03
498 5555,Five,5,05-MAY-2005,$5.00,05-MAY-2005 05:05
501 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
502 string,1,A Short String Variable,Nominal,Input,8,Left,A8,A8,"""3333 """
503 longstring,2,A Long String Variable,Nominal,Input,12,Left,A12,A12,
504 numeric,3,A Numeric Variable,Scale,Input,8,Right,F10.0,F10.0,9; 5; 999
505 date,4,A Date Variable,Scale,Input,8,Right,DATE11,DATE11,
506 dollar,5,A Dollar Variable,Scale,Input,8,Right,DOLLAR11.2,DOLLAR11.2,
507 datetime,6,A Datetime Variable,Scale,Input,8,Right,DATETIME17.0,DATETIME17.0,
510 Variable Value,,Label
511 A Short String Variable,1111,ones
514 A Numeric Variable,1,Unity
517 Footnote: a. User-missing value
519 Table: Variable and Dataset Attributes
520 Variable and Name,,Value
521 A Numeric Variable,colour[1],blue
528 string,longstring,numeric,date,dollar,datetime
529 1111,One,1,01-JAN-2001,$1.00,01-JAN-2001 01:01
530 2222,Two,2,02-FEB-2002,$2.00,02-FEB-2002 02:02
531 3333,Three,3,03-MAR-2003,$3.00,03-MAR-2003 03:03
533 5555,Five,5,05-MAY-2005,$5.00,05-MAY-2005 05:05
537 AT_SETUP([Perl value formatting])
538 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
540 [DATA LIST LIST /d (DATETIME17).
545 SAVE OUTFILE='dd.sav'.
547 AT_CHECK([pspp -O format=csv dd.sps], [0],
548 [Table: Reading free-form data from INLINE.
557 my $sf = PSPP::Reader->open ("dd.sav");
559 my $dict = $sf->get_dict ();
561 my (@c) = $sf->get_next_case ();
563 my $var = $dict->get_var (0);
565 my $formatted = PSPP::format_value ($val, $var);
566 my $str = gmtime ($val - PSPP::PERL_EPOCH);
567 print "Formatted string is \"$formatted\"\n";
568 print "Perl representation is \"$str\"\n";
570 AT_CHECK([run_perl_module test.pl], [0],
571 [[Formatted string is "11-SEP-2001 08:20"
572 Perl representation is "Tue Sep 11 08:20:00 2001"
576 AT_SETUP([Perl opening nonexistent file])
577 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
583 my $sf = PSPP::Reader->open ("no-such-file.sav");
585 die "Returns undef on opening failure" if ref $sf;
586 print $PSPP::errstr, "\n";
588 AT_CHECK([run_perl_module test.pl], [0],
589 [[An error occurred while opening `no-such-file.sav': No such file or directory.
591 [[Name "PSPP::errstr" used only once: possible typo at test.pl line 8.
595 AT_SETUP([Perl missing values])
596 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
597 PERL_GENERATE_SYSFILE
603 my $sf = PSPP::Reader->open ("sample.sav");
605 my $dict = $sf->get_dict ();
607 my (@c) = $sf->get_next_case ();
609 my $stringvar = $dict->get_var (0);
610 my $numericvar = $dict->get_var (2);
613 die "Missing Value Negative String"
614 if PSPP::value_is_missing ($val, $stringvar);
618 die "Missing Value Negative Num"
619 if PSPP::value_is_missing ($val, $numericvar);
621 @c = $sf->get_next_case ();
622 @c = $sf->get_next_case ();
625 die "Missing Value Positive"
626 if !PSPP::value_is_missing ($val, $stringvar);
628 @c = $sf->get_next_case ();
630 die "Missing Value Positive SYS"
631 if !PSPP::value_is_missing ($val, $numericvar);
633 @c = $sf->get_next_case ();
635 die "Missing Value Positive Num"
636 if !PSPP::value_is_missing ($val, $numericvar);
638 AT_CHECK([run_perl_module test.pl])
641 AT_SETUP([Perl custom attributes])
642 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
643 PERL_GENERATE_SYSFILE
649 my $sf = PSPP::Reader->open ("sample.sav");
651 my $dict = $sf->get_dict ();
653 my $var = $dict->get_var_by_name ("numeric");
655 my $attr = $var->get_attributes ();
657 foreach my $k (sort (keys (%$attr)))
659 my $ll = $attr->{$k};
661 print map "$_\n", join ', ', @$ll;
664 AT_CHECK([run_perl_module test.pl], [0],
666 colour =>blue, pink, violet
667 nationality =>foreign
672 AT_SETUP([Perl Pspp.t])
674 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
675 # Skip this test if Perl's Text::Diff module is not installed.
676 AT_CHECK([perl -MText::Diff -e '' || exit 77])
677 # Skip this test if Perl's Memory::Usage module is not installed.
678 AT_CHECK([perl -MMemory::Usage -e '' || exit 77])
679 AT_CHECK([run_perl_module "$abs_top_builddir/perl-module/t/Pspp.t"], [0],
682 ok 2 - Dictionary Creation
684 ok 4 - Trap illegal variable name
686 ok 6 - Accept legal variable name
688 ok 8 - Trap duplicate variable name
690 ok 10 - Accept valid format
692 ok 12 - Create sysfile object
693 ok 13 - Write system file
695 ok 15 - Appending Case with too many variables
697 ok 17 - Append Case 2
700 ok 20 - Dictionary Creation 2
701 ok 21 - Value label for short string
702 ok 22 - Value label for long string
703 ok 23 - Check output 2
704 ok 24 - Dictionary survives sysfile
705 ok 25 - Basic reader operation
706 ok 26 - Streaming of files
707 Formatted string is "11-SEP-2001 08:20"
708 ok 27 - format_value function
709 ok 28 - Perl representation of time
710 ok 29 - Returns undef on opening failure
711 ok 30 - Error string on open failure
712 ok 31 - Missing Value Negative String
713 ok 32 - Missing Value Negative Num
714 ok 33 - Missing Value Positive
715 ok 34 - Missing Value Positive SYS
716 ok 35 - Missing Value Positive Num
717 ok 36 - Custom Attributes
719 ok 38 - Memory management of append_case