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
33 dnl This command can be used to run with the PSPP Perl module after it has been
34 dnl built (with "make") but before it has been installed. The -I options are
35 dnl equivalent to "use ExtUtils::testlib;" inside the Perl program, but it does
36 dnl not need to be run with the perl-module build directory as the current
37 dnl working directory.
39 LD_PRELOAD="$asan_lib":"$LD_PRELOAD" \
40 LD_LIBRARY_PATH="$abs_top_builddir/src/.libs" \
41 DYLD_LIBRARY_PATH="$abs_top_builddir/src/.libs" \
42 ASAN_OPTIONS="$ASAN_OPTIONS detect_leaks=false" \
43 $PERL -I"$abs_top_builddir/perl-module/blib/arch" \
44 -I"$abs_top_builddir/perl-module/blib/lib" "$@"
46 m4_divert_pop([PREPARE_TESTS])
48 AT_SETUP([Perl create system file])
49 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
55 my $d = PSPP::Dict->new();
56 die "dictionary creation" if !ref $d;
57 die if $d->get_var_cnt () != 0;
59 $d->set_label ("My Dictionary");
60 $d->set_documents ("These Documents");
62 # Tests for variable creation
64 my $var0 = PSPP::Var->new ($d, "le");
65 die "trap illegal variable name" if ref $var0;
66 die if $d->get_var_cnt () != 0;
68 $var0 = PSPP::Var->new ($d, "legal");
69 die "accept legal variable name" if !ref $var0;
70 die if $d->get_var_cnt () != 1;
72 my $var1 = PSPP::Var->new ($d, "money",
73 (fmt=>PSPP::Fmt::DOLLAR,
74 width=>4, decimals=>2) );
75 die "cappet valid format" if !ref $var1;
76 die if $d->get_var_cnt () != 2;
78 $d->set_weight ($var1);
80 my $sysfile = PSPP::Sysfile->new ('testfile.sav', $d);
81 die "create sysfile object" if !ref $sysfile;
85 AT_CHECK([run_perl_module test.pl])
86 AT_DATA([dump-dict.sps],
87 [GET FILE='testfile.sav'.
93 AT_CHECK([pspp -O format=csv dump-dict.sps], [0], [dnl
101 Name,Position,Measurement Level,Role,Width,Alignment,Print Format,Write Format
102 legal,1,Scale,Input,8,Right,F9.2,F9.2
103 money,2,Scale,Input,8,Right,DOLLAR6.2,DOLLAR6.2
110 AT_SETUP([Perl writing cases to system files])
111 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
117 my $d = PSPP::Dict->new();
118 PSPP::Var->new ($d, "id",
126 PSPP::Var->new ($d, "name",
133 $d->set_documents ("This should not appear");
134 $d->clear_documents ();
135 $d->add_document ("This is a document line");
137 $d->set_label ("This is the file label");
139 # Check that we can write cases to system files.
140 my $sysfile = PSPP::Sysfile->new ("testfile.sav", $d);
141 my $res = $sysfile->append_case ( [34, "frederick"]);
142 die "append case" if !$res;
144 $res = $sysfile->append_case ( [34, "frederick", "extra"]);
145 die "append case with too many variables" if $res;
148 # Check that sysfiles are closed properly automaticallly in the destructor.
149 my $sysfile2 = PSPP::Sysfile->new ("testfile2.sav", $d);
150 $res = $sysfile2->append_case ( [21, "wheelbarrow"]);
151 die "append case 2" if !$res;
153 $res = $sysfile->append_case ( [34, "frederick", "extra"]);
154 die "append case with too many variables" if $res;
156 # Don't close. We want to test that the destructor does that.
158 AT_CHECK([run_perl_module test.pl])
159 AT_DATA([dump-dicts.sps],
160 [GET FILE='testfile.sav'.
166 GET FILE='testfile2.sav'.
172 AT_CHECK([pspp -O format=csv dump-dicts.sps], [0], [dnl
174 Name,Position,Measurement Level,Role,Width,Alignment,Print Format,Write Format
175 id,1,Scale,Input,8,Right,F2.0,F2.0
176 name,2,Nominal,Input,20,Left,A20,A20
179 Label,This is the file label
182 This is a document line
189 Name,Position,Measurement Level,Role,Width,Alignment,Print Format,Write Format
190 id,1,Scale,Input,8,Right,F2.0,F2.0
191 name,2,Nominal,Input,20,Left,A20,A20
194 Label,This is the file label
197 This is a document line
205 AT_SETUP([Perl write variable parameters])
206 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
212 my $dict = PSPP::Dict->new();
213 die "dictionary creation" if !ref $dict;
215 my $int = PSPP::Var->new ($dict, "integer",
216 (width=>8, decimals=>0) );
218 $int->set_label ("My Integer");
220 $int->add_value_label (99, "Silly");
221 $int->clear_value_labels ();
222 $int->add_value_label (0, "Zero");
223 $int->add_value_label (1, "Unity");
224 $int->add_value_label (2, "Duality");
226 my $str = PSPP::Var->new ($dict, "string",
227 (fmt=>PSPP::Fmt::A, width=>8) );
230 $str->set_label ("My String");
231 $str->add_value_label ("xx", "foo");
232 $str->add_value_label ("yy", "bar");
234 $str->set_missing_values ("this", "that");
236 my $longstr = PSPP::Var->new ($dict, "longstring",
237 (fmt=>PSPP::Fmt::A, width=>9) );
240 $longstr->set_label ("My Long String");
241 my $re = $longstr->add_value_label ("xxx", "xfoo");
243 $int->set_missing_values (9, 99);
245 my $sysfile = PSPP::Sysfile->new ("testfile.sav", $dict);
250 AT_CHECK([run_perl_module test.pl], [0], [], [stderr])
252 AT_DATA([dump-dict.sps],
253 [GET FILE='testfile.sav'.
256 AT_CHECK([pspp -O format=csv dump-dict.sps], [0], [dnl
258 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
259 integer,1,My Integer,Scale,Input,8,Right,F8.0,F8.0,9; 99
260 string,2,My String,Nominal,Input,8,Left,A8,A8,"""this ""; ""that """
261 longstring,3,My Long String,Nominal,Input,9,Left,A9,A9,
264 Variable Value,,Label
270 My Long String,xxx,xfoo
274 AT_SETUP([Perl dictionary survives system file])
275 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
284 my $d = PSPP::Dict->new();
286 PSPP::Var->new ($d, "id",
294 $sysfile = PSPP::Sysfile->new ("testfile.sav", $d);
297 my $res = $sysfile->append_case ([3]);
298 print "Dictionary survives sysfile\n" if $res;
300 AT_CHECK([run_perl_module test.pl], [0],
301 [Dictionary survives sysfile
305 m4_define([PERL_GENERATE_SYSFILE],
306 [AT_DATA([sample.sps],
307 [[data list notable list /string (a8) longstring (a12) numeric (f10) date (date11) dollar (dollar8.2) datetime (datetime17)
309 1111 One 1 1/1/1 1 1/1/1+01:01
310 2222 Two 2 2/2/2 2 2/2/2+02:02
311 3333 Three 3 3/3/3 3 3/3/3+03:03
313 5555 Five 5 5/5/5 5 5/5/5+05:05
317 variable labels string 'A Short String Variable'
318 /longstring 'A Long String Variable'
319 /numeric 'A Numeric Variable'
320 /date 'A Date Variable'
321 /dollar 'A Dollar Variable'
322 /datetime 'A Datetime Variable'.
325 missing values numeric (9, 5, 999).
327 missing values string ("3333").
330 /string '1111' 'ones' '2222' 'twos' '3333' 'threes'
331 /numeric 1 'Unity' 2 'Duality' 3 'Thripality'.
335 attribute=colour[1]('blue') colour[2]('pink') colour[3]('violet')
336 attribute=size('large') nationality('foreign').
339 save outfile='sample.sav'.
341 AT_CHECK([pspp -O format=csv sample.sps])])
343 AT_SETUP([Perl read system file])
344 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
345 PERL_GENERATE_SYSFILE
351 my $sf = PSPP::Reader->open ("sample.sav");
353 my $dict = $sf->get_dict ();
355 for (my $v = 0 ; $v < $dict->get_var_cnt() ; $v++)
357 my $var = $dict->get_var ($v);
358 my $name = $var->get_name ();
359 my $label = $var->get_label ();
361 print "Variable $v is \"$name\", label is \"$label\"\n";
363 my $vl = $var->get_value_labels ();
365 print "Value Labels:\n";
366 print "$_ => $vl->{$_}\n" for sort (keys %$vl);
369 while (my @c = $sf->get_next_case () )
371 for (my $v = 0; $v < $dict->get_var_cnt(); $v++)
373 print "val$v: \"$c[$v]\"\n";
378 AT_CHECK([run_perl_module test.pl], [0],
379 [Variable 0 is "string", label is "A Short String Variable"
384 Variable 1 is "longstring", label is "A Long String Variable"
386 Variable 2 is "numeric", label is "A Numeric Variable"
391 Variable 3 is "date", label is "A Date Variable"
393 Variable 4 is "dollar", label is "A Dollar Variable"
395 Variable 5 is "datetime", label is "A Datetime Variable"
435 AT_SETUP([Perl copying system files])
436 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
437 PERL_GENERATE_SYSFILE
443 my $input = PSPP::Reader->open ("sample.sav");
445 my $dict = $input->get_dict ();
447 my $output = PSPP::Sysfile->new ("copy.sav", $dict);
449 while (my (@c) = $input->get_next_case () )
451 $output->append_case (\@c);
456 AT_CHECK([run_perl_module test.pl])
457 AT_DATA([dump-dicts.sps],
458 [GET FILE='sample.sav'.
468 AT_CHECK([pspp -O format=csv dump-dicts.sps], [0],
470 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
471 string,1,A Short String Variable,Nominal,Input,8,Left,A8,A8,"""3333 """
472 longstring,2,A Long String Variable,Nominal,Input,12,Left,A12,A12,
473 numeric,3,A Numeric Variable,Nominal,Input,8,Right,F10.0,F10.0,9; 5; 999
474 date,4,A Date Variable,Scale,Input,8,Right,DATE11,DATE11,
475 dollar,5,A Dollar Variable,Scale,Input,8,Right,DOLLAR11.2,DOLLAR11.2,
476 datetime,6,A Datetime Variable,Scale,Input,8,Right,DATETIME17.0,DATETIME17.0,
479 Variable Value,,Label
480 A Short String Variable,1111,ones
483 A Numeric Variable,1,Unity
486 Footnote: a. User-missing value
488 Table: Variable and Dataset Attributes
489 Variable and Name,,Value
490 A Numeric Variable,colour[1],blue
497 string,longstring,numeric,date,dollar,datetime
498 1111,One,1,01-JAN-2001,$1.00,01-JAN-2001 01:01
499 2222,Two,2,02-FEB-2002,$2.00,02-FEB-2002 02:02
500 3333,Three,3,03-MAR-2003,$3.00,03-MAR-2003 03:03
502 5555,Five,5,05-MAY-2005,$5.00,05-MAY-2005 05:05
505 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
506 string,1,A Short String Variable,Nominal,Input,8,Left,A8,A8,"""3333 """
507 longstring,2,A Long String Variable,Nominal,Input,12,Left,A12,A12,
508 numeric,3,A Numeric Variable,Nominal,Input,8,Right,F10.0,F10.0,9; 5; 999
509 date,4,A Date Variable,Scale,Input,8,Right,DATE11,DATE11,
510 dollar,5,A Dollar Variable,Scale,Input,8,Right,DOLLAR11.2,DOLLAR11.2,
511 datetime,6,A Datetime Variable,Scale,Input,8,Right,DATETIME17.0,DATETIME17.0,
514 Variable Value,,Label
515 A Short String Variable,1111,ones
518 A Numeric Variable,1,Unity
521 Footnote: a. User-missing value
523 Table: Variable and Dataset Attributes
524 Variable and Name,,Value
525 A Numeric Variable,colour[1],blue
532 string,longstring,numeric,date,dollar,datetime
533 1111,One,1,01-JAN-2001,$1.00,01-JAN-2001 01:01
534 2222,Two,2,02-FEB-2002,$2.00,02-FEB-2002 02:02
535 3333,Three,3,03-MAR-2003,$3.00,03-MAR-2003 03:03
537 5555,Five,5,05-MAY-2005,$5.00,05-MAY-2005 05:05
541 AT_SETUP([Perl value formatting])
542 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
544 [DATA LIST LIST /d (DATETIME17).
549 SAVE OUTFILE='dd.sav'.
551 AT_CHECK([pspp -O format=csv dd.sps], [0],
552 [Table: Reading free-form data from INLINE.
561 my $sf = PSPP::Reader->open ("dd.sav");
563 my $dict = $sf->get_dict ();
565 my (@c) = $sf->get_next_case ();
567 my $var = $dict->get_var (0);
569 my $formatted = PSPP::format_value ($val, $var);
570 my $str = gmtime ($val - PSPP::PERL_EPOCH);
571 print "Formatted string is \"$formatted\"\n";
572 print "Perl representation is \"$str\"\n";
574 AT_CHECK([run_perl_module test.pl], [0],
575 [[Formatted string is "11-SEP-2001 08:20"
576 Perl representation is "Tue Sep 11 08:20:00 2001"
580 AT_SETUP([Perl opening nonexistent file])
581 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
587 my $sf = PSPP::Reader->open ("no-such-file.sav");
589 die "Returns undef on opening failure" if ref $sf;
590 print $PSPP::errstr, "\n";
592 AT_CHECK([run_perl_module test.pl], [0],
593 [[An error occurred while opening `no-such-file.sav': No such file or directory.
595 [[Name "PSPP::errstr" used only once: possible typo at test.pl line 8.
599 AT_SETUP([Perl missing values])
600 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
601 PERL_GENERATE_SYSFILE
607 my $sf = PSPP::Reader->open ("sample.sav");
609 my $dict = $sf->get_dict ();
611 my (@c) = $sf->get_next_case ();
613 my $stringvar = $dict->get_var (0);
614 my $numericvar = $dict->get_var (2);
617 die "Missing Value Negative String"
618 if PSPP::value_is_missing ($val, $stringvar);
622 die "Missing Value Negative Num"
623 if PSPP::value_is_missing ($val, $numericvar);
625 @c = $sf->get_next_case ();
626 @c = $sf->get_next_case ();
629 die "Missing Value Positive"
630 if !PSPP::value_is_missing ($val, $stringvar);
632 @c = $sf->get_next_case ();
634 die "Missing Value Positive SYS"
635 if !PSPP::value_is_missing ($val, $numericvar);
637 @c = $sf->get_next_case ();
639 die "Missing Value Positive Num"
640 if !PSPP::value_is_missing ($val, $numericvar);
642 AT_CHECK([run_perl_module test.pl])
645 AT_SETUP([Perl custom attributes])
646 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
647 PERL_GENERATE_SYSFILE
653 my $sf = PSPP::Reader->open ("sample.sav");
655 my $dict = $sf->get_dict ();
657 my $var = $dict->get_var_by_name ("numeric");
659 my $attr = $var->get_attributes ();
661 foreach my $k (sort (keys (%$attr)))
663 my $ll = $attr->{$k};
665 print map "$_\n", join ', ', @$ll;
668 AT_CHECK([run_perl_module test.pl], [0],
670 colour =>blue, pink, violet
671 nationality =>foreign
676 AT_SETUP([Perl Pspp.t])
678 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
679 # Skip this test if Perl's Text::Diff module is not installed.
680 AT_CHECK([perl -MText::Diff -e '' || exit 77])
681 # Skip this test if Perl's Test::More module is not installed.
682 AT_CHECK([perl -MTest::More -e '' || exit 77])
683 AT_CHECK([run_perl_module "$abs_top_builddir/perl-module/t/Pspp.t"], [0],
686 ok 2 - Dictionary Creation
688 ok 4 - Trap illegal variable name
690 ok 6 - Accept legal variable name
692 ok 8 - Trap duplicate variable name
694 ok 10 - Accept valid format
696 ok 12 - Create sysfile object
697 ok 13 - Write system file
699 ok 15 - Appending Case with too many variables
701 ok 17 - Append Case 2
704 ok 20 - Dictionary Creation 2
705 ok 21 - Value label for short string
706 ok 22 - Value label for long string
707 ok 23 - Check output 2
708 ok 24 - Dictionary survives sysfile
709 ok 25 - Basic reader operation
710 ok 26 - Streaming of files
711 Formatted string is "11-SEP-2001 08:20"
712 ok 27 - format_value function
713 ok 28 - Perl representation of time
714 ok 29 - Returns undef on opening failure
715 ok 30 - Error string on open failure
716 ok 31 - Missing Value Negative String
717 ok 32 - Missing Value Negative Num
718 ok 33 - Missing Value Positive
719 ok 34 - Missing Value Positive SYS
720 ok 35 - Missing Value Positive Num
721 ok 36 - Custom Attributes