3 ## PSPP - a program for statistical analysis.
4 ## Copyright (C) 2019, 2020 Free Software Foundation, Inc.
6 ## This program is free software: you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation, either version 3 of the License, or
9 ## (at your option) any later version.
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ## GNU General Public License for more details.
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # Before `make install' is performed this script should be runnable
20 # with `make test' as long as libpspp-core-$VERSION.so is in
21 # LD_LIBRARY_PATH. After `make install' it should work as `perl
24 #########################
26 # change 'tests => 1' to 'tests => last_test_to_print';
28 use Test::More tests => 37;
30 use File::Temp qw/ tempfile tempdir /;
32 BEGIN { use_ok('PSPP') };
34 #########################
40 return ! diff ("$file", \$pattern);
43 my $pspp_cmd = $ENV{PSPP_TEST_CMD};
55 my $syntaxfile = "$tempdir/foo.sps";
57 open (FH, ">$syntaxfile");
61 system ("cd $tempdir; $pspp_cmd -o pspp.csv $syntaxfile");
64 sub run_pspp_syntax_cmp
71 run_pspp_syntax ($tempdir, $syntax);
73 my $diff = diff ("$tempdir/pspp.csv", \$result);
84 # Insert your test code below, the Test::More module is used here so read
85 # its man page ( perldoc Test::More ) for help writing this test script.
88 my $d = PSPP::Dict->new();
89 ok (ref $d, "Dictionary Creation");
90 ok ($d->get_var_cnt () == 0);
92 $d->set_label ("My Dictionary");
93 $d->add_document ("These Documents");
95 # Tests for variable creation
97 my $var0 = PSPP::Var->new ($d, "le");
98 ok (!ref $var0, "Trap illegal variable name");
99 ok ($d->get_var_cnt () == 0);
101 $var0 = PSPP::Var->new ($d, "legal");
102 ok (ref $var0, "Accept legal variable name");
103 ok ($d->get_var_cnt () == 1);
105 my $var1 = PSPP::Var->new ($d, "legal");
106 ok (!ref $var1, "Trap duplicate variable name");
107 ok ($d->get_var_cnt () == 1);
109 $var1 = PSPP::Var->new ($d, "money",
110 (fmt=>PSPP::Fmt::DOLLAR,
111 width=>4, decimals=>2) );
112 ok (ref $var1, "Accept valid format");
113 ok ($d->get_var_cnt () == 2);
115 $d->set_weight ($var1);
118 # Tests for system file creation
119 # Make sure a system file can be created
121 my $tempdir = tempdir( CLEANUP => 1 );
122 my $tempfile = "$tempdir/testfile.sav";
123 my $syntaxfile = "$tempdir/syntax.sps";
124 my $sysfile = PSPP::Sysfile->new ("$tempfile", $d);
125 ok (ref $sysfile, "Create sysfile object");
128 ok (-s "$tempfile", "Write system file");
133 # Make sure we can write cases to a file
135 my $d = PSPP::Dict->new();
136 PSPP::Var->new ($d, "id",
144 PSPP::Var->new ($d, "name",
151 $d->add_document ("This should not appear");
152 $d->clear_documents ();
153 $d->add_document ("This is a document line");
155 $d->set_label ("This is the file label");
157 # Check that we can write system files
159 my $tempdir = tempdir( CLEANUP => 1 );
160 my $tempfile = "$tempdir/testfile.sav";
161 my $sysfile = PSPP::Sysfile->new ("$tempfile", $d);
163 my $res = $sysfile->append_case ( [34, "frederick"]);
164 ok ($res, "Append Case");
166 $res = $sysfile->append_case ( [34, "frederick", "extra"]);
167 ok (!$res, "Appending Case with too many variables");
170 ok (-s "$tempfile", "existance");
173 # Check that sysfiles are closed properly
175 my $tempdir = tempdir( CLEANUP => 1 );
176 my $tempfile = "$tempdir/testfile.sav";
178 my $sysfile = PSPP::Sysfile->new ("$tempfile", $d);
180 my $res = $sysfile->append_case ( [21, "wheelbarrow"]);
181 ok ($res, "Append Case 2");
183 # Don't close. We want to test that the destructor does that
186 ok (-s "$tempfile", "existance2");
188 ok (run_pspp_syntax_cmp ($tempdir, <<SYNTAX, <<RESULT), "Check output");
190 GET FILE='$tempfile'.
197 Name,Position,Measurement Level,Role,Width,Alignment,Print Format,Write Format
198 id,1,Scale,Input,8,Right,F2.0,F2.0
199 name,2,Nominal,Input,20,Left,A20,A20
202 Label,This is the file label
205 This is a document line
215 # Now do some tests to make sure all the variable parameters
216 # can be written properly.
219 my $tempdir = tempdir( CLEANUP => 1 );
220 my $tempfile = "$tempdir/testfile.sav";
221 my $dict = PSPP::Dict->new();
222 ok (ref $dict, "Dictionary Creation 2");
224 my $int = PSPP::Var->new ($dict, "integer",
225 (width=>8, decimals=>0) );
227 $int->set_label ("My Integer");
229 $int->add_value_label (99, "Silly");
230 $int->clear_value_labels ();
231 $int->add_value_label (0, "Zero");
232 $int->add_value_label (1, "Unity");
233 $int->add_value_label (2, "Duality");
235 my $str = PSPP::Var->new ($dict, "string",
236 (fmt=>PSPP::Fmt::A, width=>8) );
239 $str->set_label ("My String");
240 ok ($str->add_value_label ("xx", "foo"), "Value label for short string");
241 diag ($PSPP::errstr);
242 $str->add_value_label ("yy", "bar");
244 $str->set_missing_values ("this", "that");
246 my $longstr = PSPP::Var->new ($dict, "longstring",
247 (fmt=>PSPP::Fmt::A, width=>9) );
250 $longstr->set_label ("My Long String");
251 my $re = $longstr->add_value_label ("xxx", "xfoo");
252 ok ($re, "Value label for long string");
254 $int->set_missing_values (9, 99);
256 my $sysfile = PSPP::Sysfile->new ("$tempfile", $dict);
261 ok (run_pspp_syntax_cmp ($tempdir, <<SYNTAX, <<RESULT), "Check output 2");
262 GET FILE='$tempfile'.
266 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
267 integer,1,My Integer,Scale,Input,8,Right,F8.0,F8.0,9; 99
268 string,2,My String,Nominal,Input,8,Left,A8,A8,"""this ""; ""that """
269 longstring,3,My Long String,Nominal,Input,9,Left,A9,A9,
272 Variable Value,,Label
278 My Long String,xxx,xfoo
285 sub generate_sav_file
287 my $filename = shift;
290 run_pspp_syntax_cmp ($tempdir, <<SYNTAX, <<RESULT);
291 data list notable list /string (a8) longstring (a12) numeric (f10) date (date11) dollar (dollar8.2) datetime (datetime17)
293 1111 One 1 1/1/1 1 1/1/1+01:01
294 2222 Two 2 2/2/2 2 2/2/2+02:02
295 3333 Three 3 3/3/3 3 3/3/3+03:03
297 5555 Five 5 5/5/5 5 5/5/5+05:05
301 variable labels string 'A Short String Variable'
302 /longstring 'A Long String Variable'
303 /numeric 'A Numeric Variable'
304 /date 'A Date Variable'
305 /dollar 'A Dollar Variable'
306 /datetime 'A Datetime Variable'.
309 missing values numeric (9, 5, 999).
311 missing values string ("3333").
314 /string '1111' 'ones' '2222' 'twos' '3333' 'threes'
315 /numeric 1 'Unity' 2 'Duality' 3 'Thripality'.
319 attribute=colour[1]('blue') colour[2]('pink') colour[3]('violet')
320 attribute=size('large') nationality('foreign').
323 save outfile='$filename'.
331 # Test to make sure that the dictionary survives the sysfile.
332 # Thanks to Rob Messer for reporting this problem
334 my $tempdir = tempdir( CLEANUP => 1 );
335 my $tempfile = "$tempdir/testfile.sav";
339 my $d = PSPP::Dict->new();
341 PSPP::Var->new ($d, "id",
349 $sysfile = PSPP::Sysfile->new ("$tempfile", $d);
352 my $res = $sysfile->append_case ([3]);
354 ok ($res, "Dictionary survives sysfile");
360 my $tempdir = tempdir( CLEANUP => 1 );
362 generate_sav_file ("$tempdir/in.sav", "$tempdir");
364 my $sf = PSPP::Reader->open ("$tempdir/in.sav");
366 my $dict = $sf->get_dict ();
368 open (MYFILE, ">$tempdir/out.txt");
369 for ($v = 0 ; $v < $dict->get_var_cnt() ; $v++)
371 my $var = $dict->get_var ($v);
372 my $name = $var->get_name ();
373 my $label = $var->get_label ();
375 print MYFILE "Variable $v is \"$name\", label is \"$label\"\n";
377 my $vl = $var->get_value_labels ();
379 print MYFILE "Value Labels:\n";
380 print MYFILE "$_ => $vl->{$_}\n" for (sort keys %$vl);
383 while (my @c = $sf->get_next_case () )
385 for ($v = 0; $v < $dict->get_var_cnt(); $v++)
387 print MYFILE "val$v: \"$c[$v]\"\n";
394 ok (compare ("$tempdir/out.txt", <<EOF), "Basic reader operation");
395 Variable 0 is "string", label is "A Short String Variable"
400 Variable 1 is "longstring", label is "A Long String Variable"
402 Variable 2 is "numeric", label is "A Numeric Variable"
407 Variable 3 is "date", label is "A Date Variable"
409 Variable 4 is "dollar", label is "A Dollar Variable"
411 Variable 5 is "datetime", label is "A Datetime Variable"
453 # Check that we can stream one file into another
455 my $tempdir = tempdir( CLEANUP => 1 );
457 generate_sav_file ("$tempdir/in.sav", "$tempdir");
459 my $input = PSPP::Reader->open ("$tempdir/in.sav");
461 my $dict = $input->get_dict ();
463 my $output = PSPP::Sysfile->new ("$tempdir/out.sav", $dict);
465 while (my (@c) = $input->get_next_case () )
467 $output->append_case (\@c);
473 #Check the two files are the same (except for metadata)
475 run_pspp_syntax ($tempdir, <<SYNTAX);
476 get file='$tempdir/in.sav'.
482 system ("cp $tempdir/pspp.csv $tempdir/in.txt");
484 run_pspp_syntax ($tempdir, <<SYNTAX);
485 get file='$tempdir/out.sav'.
491 ok (! diff ("$tempdir/pspp.csv", "$tempdir/in.txt"), "Streaming of files");
496 # Check that the format_value function works properly
498 my $tempdir = tempdir( CLEANUP => 1 );
500 run_pspp_syntax ($tempdir, <<SYNTAX);
502 data list list /d (datetime17).
507 save outfile='$tempdir/dd.sav'.
511 my $sf = PSPP::Reader->open ("$tempdir/dd.sav");
513 my $dict = $sf->get_dict ();
515 my (@c) = $sf->get_next_case ();
517 my $var = $dict->get_var (0);
519 my $formatted = PSPP::format_value ($val, $var);
520 my $str = gmtime ($val - PSPP::PERL_EPOCH);
521 print "Formatted string is \"$formatted\"\n";
522 ok ( $formatted eq "11-SEP-2001 08:20", "format_value function");
523 ok ( $str eq "Tue Sep 11 08:20:00 2001", "Perl representation of time");
527 # Check that attempting to open a non-existent file results in an error
529 my $tempdir = tempdir( CLEANUP => 1 );
531 unlink ("$tempdir/no-such-file.sav");
533 my $sf = PSPP::Reader->open ("$tempdir/no-such-file.sav");
535 ok ( !ref $sf, "Returns undef on opening failure");
537 ok ("$PSPP::errstr" eq "An error occurred while opening `$tempdir/no-such-file.sav': No such file or directory.",
538 "Error string on open failure");
542 # Missing value tests.
544 my $tempdir = tempdir( CLEANUP => 1 );
546 generate_sav_file ("$tempdir/in.sav", "$tempdir");
548 my $sf = PSPP::Reader->open ("$tempdir/in.sav");
550 my $dict = $sf->get_dict ();
553 my (@c) = $sf->get_next_case ();
555 my $stringvar = $dict->get_var (0);
556 my $numericvar = $dict->get_var (2);
559 ok ( !PSPP::value_is_missing ($val, $stringvar), "Missing Value Negative String");
563 ok ( !PSPP::value_is_missing ($val, $numericvar), "Missing Value Negative Num");
565 @c = $sf->get_next_case ();
566 @c = $sf->get_next_case ();
569 ok ( PSPP::value_is_missing ($val, $stringvar), "Missing Value Positive");
571 @c = $sf->get_next_case ();
573 ok ( PSPP::value_is_missing ($val, $numericvar), "Missing Value Positive SYS");
575 @c = $sf->get_next_case ();
577 ok ( PSPP::value_is_missing ($val, $numericvar), "Missing Value Positive Num");
581 #Test reading of custom attributes
583 my $tempdir = tempdir( CLEANUP => 1 );
585 generate_sav_file ("$tempdir/in.sav", "$tempdir");
587 my $sf = PSPP::Reader->open ("$tempdir/in.sav");
589 my $dict = $sf->get_dict ();
591 my $var = $dict->get_var_by_name ("numeric");
593 my $attr = $var->get_attributes ();
595 open (MYFILE, ">$tempdir/out.txt");
597 foreach $k (sort (keys (%$attr)))
599 my $ll = $attr->{$k};
600 print MYFILE "$k =>";
601 print MYFILE map "$_\n", join ', ', @$ll;
606 ok (compare ("$tempdir/out.txt", <<'EOF'), "Custom Attributes");
608 colour =>blue, pink, violet
609 nationality =>foreign
615 # Test of the get_case_cnt function
617 my $tempdir = tempdir( CLEANUP => 1 );
619 generate_sav_file ("$tempdir/in.sav", "$tempdir");
621 my $sf = PSPP::Reader->open ("$tempdir/in.sav");
623 my $n = $sf->get_case_cnt ();
625 ok ($n == 5, "Case count");