fbuf: New data structure for buffered file I/O.
[pspp] / tests / perl-module.at
1 dnl PSPP - a program for statistical analysis.
2 dnl Copyright (C) 2017 Free Software Foundation, Inc.
3 dnl 
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.
8 dnl 
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.
13 dnl 
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/>.
16 dnl
17 AT_BANNER([Perl module tests])
18
19 dnl This command can be used to run with the PSPP Perl module after it has been
20 dnl built (with "make") but before it has been installed.  The -I options are
21 dnl equivalent to "use ExtUtils::testlib;" inside the Perl program, but it does
22 dnl not need to be run with the perl-module build directory as the current
23 dnl working directory.
24 dnl
25 dnl XXX "libtool --mode=execute" is probably better than setting
26 dnl LD_LIBRARY_PATH.
27 m4_define([RUN_PERL_MODULE],
28   [LD_LIBRARY_PATH=$abs_top_builddir/src/.libs \
29    DYLD_LIBRARY_PATH=$abs_top_builddir/src/.libs \
30    $PERL -I$abs_top_builddir/perl-module/blib/arch \
31          -I$abs_top_builddir/perl-module/blib/lib])
32
33 AT_SETUP([Perl create system file])
34 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
35 AT_DATA([test.pl],
36   [use warnings;
37    use strict;
38    use PSPP;
39
40    my $d = PSPP::Dict->new();
41    die "dictionary creation" if !ref $d;
42    die if $d->get_var_cnt () != 0;
43
44    $d->set_label ("My Dictionary");
45    $d->set_documents ("These Documents");
46
47    # Tests for variable creation
48
49    my $var0 = PSPP::Var->new ($d, "le");
50    die "trap illegal variable name" if ref $var0;
51    die if $d->get_var_cnt () != 0;
52
53    $var0 = PSPP::Var->new ($d, "legal");
54    die "accept legal variable name" if !ref $var0;
55    die if $d->get_var_cnt () != 1;
56
57    my $var1 = PSPP::Var->new ($d, "money", 
58                               (fmt=>PSPP::Fmt::DOLLAR,
59                                width=>4, decimals=>2) );
60    die "cappet valid format" if !ref $var1;
61    die if $d->get_var_cnt () != 2;
62
63    $d->set_weight ($var1);
64
65    my $sysfile = PSPP::Sysfile->new ('testfile.sav', $d);
66    die "create sysfile object" if !ref $sysfile;
67
68    $sysfile->close ();
69 ])
70 AT_CHECK([RUN_PERL_MODULE test.pl])
71 AT_DATA([dump-dict.sps],
72   [GET FILE='testfile.sav'.
73 DISPLAY FILE LABEL.
74 DISPLAY DOCUMENTS.
75 DISPLAY DICTIONARY.
76 SHOW WEIGHT.
77 ])
78 AT_CHECK([pspp -O format=csv dump-dict.sps], [0],
79   [File label: My Dictionary
80
81 Documents in the active dataset:
82
83 These Documents
84
85 Variable,Description,Position
86 legal,Format: F9.2,1
87 money,Format: DOLLAR6.2,2
88
89 dump-dict.sps:5: note: SHOW: WEIGHT is money.
90 ])
91 AT_CLEANUP
92
93 AT_SETUP([Perl writing cases to system files])
94 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
95 AT_DATA([test.pl],
96   [[use warnings;
97     use strict;
98     use PSPP;
99
100     my $d = PSPP::Dict->new();
101     PSPP::Var->new ($d, "id",
102                     (
103                      fmt=>PSPP::Fmt::F, 
104                      width=>2, 
105                      decimals=>0
106                      )
107                     );
108
109     PSPP::Var->new ($d, "name",
110                            (
111                             fmt=>PSPP::Fmt::A, 
112                             width=>20, 
113                             )
114                            );
115
116     $d->set_documents ("This should not appear");
117     $d->clear_documents ();
118     $d->add_document ("This is a document line");
119
120     $d->set_label ("This is the file label");
121
122     # Check that we can write cases to system files.
123     my $sysfile = PSPP::Sysfile->new ("testfile.sav", $d);
124     my $res = $sysfile->append_case ( [34, "frederick"]);
125     die "append case" if !$res;
126
127     $res = $sysfile->append_case ( [34, "frederick", "extra"]);
128     die "append case with too many variables" if $res;
129     $sysfile->close ();
130
131     # Check that sysfiles are closed properly automaticallly in the destructor.
132     my $sysfile2 = PSPP::Sysfile->new ("testfile2.sav", $d);
133     $res = $sysfile2->append_case ( [21, "wheelbarrow"]);
134     die "append case 2" if !$res;
135
136     $res = $sysfile->append_case ( [34, "frederick", "extra"]);
137     die "append case with too many variables" if $res;
138
139     # Don't close.  We want to test that the destructor does that.
140 ]])
141 AT_CHECK([RUN_PERL_MODULE test.pl])
142 AT_DATA([dump-dicts.sps],
143   [GET FILE='testfile.sav'.
144 DISPLAY DICTIONARY.
145 DISPLAY FILE LABEL.
146 DISPLAY DOCUMENTS.
147 LIST.
148
149 GET FILE='testfile2.sav'.
150 DISPLAY DICTIONARY.
151 DISPLAY FILE LABEL.
152 DISPLAY DOCUMENTS.
153 LIST.
154 ])
155 AT_CHECK([pspp -O format=csv dump-dicts.sps], [0],
156   [Variable,Description,Position
157 id,Format: F2.0,1
158 name,Format: A20,2
159
160 File label: This is the file label
161
162 Documents in the active dataset:
163
164 This is a document line
165
166 Table: Data List
167 id,name
168 34,frederick           @&t@
169
170 Variable,Description,Position
171 id,Format: F2.0,1
172 name,Format: A20,2
173
174 File label: This is the file label
175
176 Documents in the active dataset:
177
178 This is a document line
179
180 Table: Data List
181 id,name
182 21,wheelbarrow         @&t@
183 ])
184 AT_CLEANUP
185
186 AT_SETUP([Perl write variable parameters])
187 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
188 AT_DATA([test.pl],
189   [[use warnings;
190     use strict;
191     use PSPP;
192
193     my $dict = PSPP::Dict->new();
194     die "dictionary creation" if !ref $dict;
195
196     my $int = PSPP::Var->new ($dict, "integer", 
197                               (width=>8, decimals=>0) );
198
199     $int->set_label ("My Integer");
200
201     $int->add_value_label (99, "Silly");
202     $int->clear_value_labels ();
203     $int->add_value_label (0, "Zero");
204     $int->add_value_label (1, "Unity");
205     $int->add_value_label (2, "Duality");
206
207     my $str = PSPP::Var->new ($dict, "string", 
208                               (fmt=>PSPP::Fmt::A, width=>8) );
209
210
211     $str->set_label ("My String");
212     $str->add_value_label ("xx", "foo");
213     $str->add_value_label ("yy", "bar");
214
215     $str->set_missing_values ("this", "that");
216
217     my $longstr = PSPP::Var->new ($dict, "longstring", 
218                               (fmt=>PSPP::Fmt::A, width=>9) );
219
220
221     $longstr->set_label ("My Long String");
222     my $re = $longstr->add_value_label ("xxx", "xfoo");
223
224     $int->set_missing_values (9, 99);
225
226     my $sysfile = PSPP::Sysfile->new ("testfile.sav", $dict);
227
228
229     $sysfile->close ();
230 ]])
231 AT_CHECK([RUN_PERL_MODULE test.pl])
232 AT_DATA([dump-dict.sps],
233   [GET FILE='testfile.sav'.
234 DISPLAY DICTIONARY.
235 ])
236 AT_CHECK([pspp -O format=csv dump-dict.sps], [0],
237   [Variable,Description,Position
238 integer,"Label: My Integer
239 Format: F8.0
240 Missing Values: 9; 99
241
242 Value,Label
243 0,Zero
244 1,Unity
245 2,Duality",1
246 string,"Label: My String
247 Format: A8
248 Missing Values: ""this    ""; ""that    ""
249
250 Value,Label
251 xx      ,foo
252 yy      ,bar",2
253 longstring,"Label: My Long String
254 Format: A9
255
256 Value,Label
257 xxx      ,xfoo",3
258 ])
259 AT_CLEANUP
260
261 AT_SETUP([Perl dictionary survives system file])
262 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
263 AT_DATA([test.pl],
264   [[use warnings;
265 use strict;
266 use PSPP;
267
268 my $sysfile ;
269
270     {
271         my $d = PSPP::Dict->new();
272
273         PSPP::Var->new ($d, "id",
274                         (
275                          fmt=>PSPP::Fmt::F, 
276                          width=>2, 
277                          decimals=>0
278                          )
279                         );
280
281         $sysfile = PSPP::Sysfile->new ("testfile.sav", $d);
282     }
283
284     my $res = $sysfile->append_case ([3]);
285     print "Dictionary survives sysfile\n" if $res;
286 ]])
287 AT_CHECK([RUN_PERL_MODULE test.pl], [0],
288   [Dictionary survives sysfile
289 ])
290 AT_CLEANUP
291
292 m4_define([PERL_GENERATE_SYSFILE],
293   [AT_DATA([sample.sps],
294     [[data list notable list /string (a8) longstring (a12) numeric (f10) date (date11) dollar (dollar8.2) datetime (datetime17)
295 begin data.
296 1111 One   1 1/1/1 1   1/1/1+01:01
297 2222 Two   2 2/2/2 2   2/2/2+02:02
298 3333 Three 3 3/3/3 3   3/3/3+03:03
299 .    .     . .     .   .
300 5555 Five  5 5/5/5 5   5/5/5+05:05
301 end data.
302
303
304 variable labels string 'A Short String Variable'
305   /longstring 'A Long String Variable'
306   /numeric 'A Numeric Variable'
307   /date 'A Date Variable'
308   /dollar 'A Dollar Variable'
309   /datetime 'A Datetime Variable'.
310
311
312 missing values numeric (9, 5, 999).
313
314 missing values string ("3333").
315
316 add value labels
317   /string '1111' 'ones' '2222' 'twos' '3333' 'threes'
318   /numeric 1 'Unity' 2 'Duality' 3 'Thripality'.
319
320 variable attribute
321     variables = numeric
322     attribute=colour[1]('blue') colour[2]('pink') colour[3]('violet')
323     attribute=size('large') nationality('foreign').
324
325
326 save outfile='sample.sav'.
327 ]])
328    AT_CHECK([pspp -O format=csv sample.sps])])
329
330 AT_SETUP([Perl read system file])
331 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
332 PERL_GENERATE_SYSFILE
333 AT_DATA([test.pl],
334   [[use warnings;
335     use strict;
336     use PSPP;
337
338     my $sf = PSPP::Reader->open ("sample.sav");
339
340     my $dict = $sf->get_dict ();
341
342     for (my $v = 0 ; $v < $dict->get_var_cnt() ; $v++)
343     {
344        my $var = $dict->get_var ($v);
345        my $name = $var->get_name ();
346        my $label = $var->get_label ();
347
348        print "Variable $v is \"$name\", label is \"$label\"\n";
349
350        my $vl = $var->get_value_labels ();
351
352        print "Value Labels:\n";
353        print "$_ => $vl->{$_}\n" for sort (keys %$vl);
354     }
355
356     while (my @c = $sf->get_next_case () )
357     {
358        for (my $v = 0; $v < $dict->get_var_cnt(); $v++)
359        {
360            print "val$v: \"$c[$v]\"\n";
361        }
362        print "\n";
363     }
364 ]])
365 AT_CHECK([RUN_PERL_MODULE test.pl], [0],
366   [Variable 0 is "string", label is "A Short String Variable"
367 Value Labels:
368 1111     => ones
369 2222     => twos
370 3333     => threes
371 Variable 1 is "longstring", label is "A Long String Variable"
372 Value Labels:
373 Variable 2 is "numeric", label is "A Numeric Variable"
374 Value Labels:
375 1 => Unity
376 2 => Duality
377 3 => Thripality
378 Variable 3 is "date", label is "A Date Variable"
379 Value Labels:
380 Variable 4 is "dollar", label is "A Dollar Variable"
381 Value Labels:
382 Variable 5 is "datetime", label is "A Datetime Variable"
383 Value Labels:
384 val0: "1111    "
385 val1: "One         "
386 val2: "1"
387 val3: "13197686400"
388 val4: "1"
389 val5: "13197690060"
390
391 val0: "2222    "
392 val1: "Two         "
393 val2: "2"
394 val3: "13231987200"
395 val4: "2"
396 val5: "13231994520"
397
398 val0: "3333    "
399 val1: "Three       "
400 val2: "3"
401 val3: "13266028800"
402 val4: "3"
403 val5: "13266039780"
404
405 val0: ".       "
406 val1: ".           "
407 val2: ""
408 val3: ""
409 val4: ""
410 val5: ""
411
412 val0: "5555    "
413 val1: "Five        "
414 val2: "5"
415 val3: "13334630400"
416 val4: "5"
417 val5: "13334648700"
418
419 ])
420 AT_CLEANUP
421
422 AT_SETUP([Perl copying system files])
423 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
424 PERL_GENERATE_SYSFILE
425 AT_DATA([test.pl],
426   [[use warnings;
427     use strict;
428     use PSPP;
429
430     my $input = PSPP::Reader->open ("sample.sav");
431
432     my $dict = $input->get_dict ();
433
434     my $output = PSPP::Sysfile->new ("copy.sav", $dict);
435
436     while (my (@c) = $input->get_next_case () )
437     {
438       $output->append_case (\@c);
439     }
440
441     $output->close ();
442 ]])
443 AT_CHECK([RUN_PERL_MODULE test.pl])
444 AT_DATA([dump-dicts.sps],
445   [GET FILE='sample.sav'.
446 DISPLAY DICTIONARY.
447 LIST.
448
449 GET FILE='copy.sav'.
450 DISPLAY DICTIONARY.
451 LIST.
452 ])
453 AT_CHECK([pspp -O format=csv dump-dicts.sps], [0],
454   [[Variable,Description,Position
455 string,"Label: A Short String Variable
456 Format: A8
457 Missing Values: ""3333    ""
458
459 Value,Label
460 1111    ,ones
461 2222    ,twos
462 3333    ,threes",1
463 longstring,"Label: A Long String Variable
464 Format: A12",2
465 numeric,"Label: A Numeric Variable
466 Format: F10.0
467 Missing Values: 9; 5; 999
468
469 Value,Label
470 1,Unity
471 2,Duality
472 3,Thripality
473
474 Attribute,Value
475 colour[1],blue
476 colour[2],pink
477 colour[3],violet
478 nationality,foreign
479 size,large",3
480 date,"Label: A Date Variable
481 Format: DATE11",4
482 dollar,"Label: A Dollar Variable
483 Format: DOLLAR11.2",5
484 datetime,"Label: A Datetime Variable
485 Format: DATETIME17.0",6
486
487 Table: Data List
488 string,longstring,numeric,date,dollar,datetime
489 1111    ,One         ,1,01-JAN-2001,$1.00,01-JAN-2001 01:01
490 2222    ,Two         ,2,02-FEB-2002,$2.00,02-FEB-2002 02:02
491 3333    ,Three       ,3,03-MAR-2003,$3.00,03-MAR-2003 03:03
492 .       ,.           ,.,.,.  ,.
493 5555    ,Five        ,5,05-MAY-2005,$5.00,05-MAY-2005 05:05
494
495 Variable,Description,Position
496 string,"Label: A Short String Variable
497 Format: A8
498 Missing Values: ""3333    ""
499
500 Value,Label
501 1111    ,ones
502 2222    ,twos
503 3333    ,threes",1
504 longstring,"Label: A Long String Variable
505 Format: A12",2
506 numeric,"Label: A Numeric Variable
507 Format: F10.0
508 Missing Values: 9; 5; 999
509
510 Value,Label
511 1,Unity
512 2,Duality
513 3,Thripality
514
515 Attribute,Value
516 colour[1],blue
517 colour[2],pink
518 colour[3],violet
519 nationality,foreign
520 size,large",3
521 date,"Label: A Date Variable
522 Format: DATE11",4
523 dollar,"Label: A Dollar Variable
524 Format: DOLLAR11.2",5
525 datetime,"Label: A Datetime Variable
526 Format: DATETIME17.0",6
527
528 Table: Data List
529 string,longstring,numeric,date,dollar,datetime
530 1111    ,One         ,1,01-JAN-2001,$1.00,01-JAN-2001 01:01
531 2222    ,Two         ,2,02-FEB-2002,$2.00,02-FEB-2002 02:02
532 3333    ,Three       ,3,03-MAR-2003,$3.00,03-MAR-2003 03:03
533 .       ,.           ,.,.,.  ,.
534 5555    ,Five        ,5,05-MAY-2005,$5.00,05-MAY-2005 05:05
535 ]])
536 AT_CLEANUP
537
538 AT_SETUP([Perl value formatting])
539 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
540 AT_DATA([dd.sps],
541   [DATA LIST LIST /d (DATETIME17).
542 BEGIN DATA.
543 11/9/2001+08:20
544 END DATA.
545
546 SAVE OUTFILE='dd.sav'.
547 ])
548 AT_CHECK([pspp -O format=csv dd.sps], [0],
549   [Table: Reading free-form data from INLINE.
550 Variable,Format
551 d,DATETIME17.0
552 ])
553 AT_DATA([test.pl],
554   [[use warnings;
555     use strict;
556     use PSPP;
557
558     my $sf = PSPP::Reader->open ("dd.sav");
559
560     my $dict = $sf->get_dict ();
561
562     my (@c) = $sf->get_next_case ();
563
564     my $var = $dict->get_var (0);
565     my $val = $c[0];
566     my $formatted = PSPP::format_value ($val, $var);
567     my $str = gmtime ($val - PSPP::PERL_EPOCH);
568     print "Formatted string is \"$formatted\"\n";
569     print "Perl representation is \"$str\"\n";
570 ]])
571 AT_CHECK([RUN_PERL_MODULE test.pl], [0],
572   [[Formatted string is "11-SEP-2001 08:20"
573 Perl representation is "Tue Sep 11 08:20:00 2001"
574 ]])
575 AT_CLEANUP
576
577 AT_SETUP([Perl opening nonexistent file])
578 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
579 AT_DATA([test.pl],
580   [[use warnings;
581     use strict;
582     use PSPP;
583
584     my $sf = PSPP::Reader->open ("no-such-file.sav");
585
586     die "Returns undef on opening failure" if ref $sf;
587     print $PSPP::errstr, "\n";
588 ]])
589 AT_CHECK([RUN_PERL_MODULE test.pl], [0],
590   [[An error occurred while opening `no-such-file.sav': No such file or directory.
591 ]],
592   [[Name "PSPP::errstr" used only once: possible typo at test.pl line 8.
593 ]])
594 AT_CLEANUP
595
596 AT_SETUP([Perl missing values])
597 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
598 PERL_GENERATE_SYSFILE
599 AT_DATA([test.pl],
600   [[use warnings;
601     use strict;
602     use PSPP;
603
604     my $sf = PSPP::Reader->open ("sample.sav");
605
606     my $dict = $sf->get_dict ();
607
608     my (@c) = $sf->get_next_case ();
609
610     my $stringvar = $dict->get_var (0);
611     my $numericvar = $dict->get_var (2);
612     my $val = $c[0];
613
614     die "Missing Value Negative String"
615         if PSPP::value_is_missing ($val, $stringvar);
616
617     $val = $c[2];
618
619     die "Missing Value Negative Num"
620         if PSPP::value_is_missing ($val, $numericvar);
621
622     @c = $sf->get_next_case (); 
623     @c = $sf->get_next_case (); 
624
625     $val = $c[0];
626     die "Missing Value Positive"
627         if !PSPP::value_is_missing ($val, $stringvar);
628
629     @c = $sf->get_next_case (); 
630     $val = $c[2];
631     die "Missing Value Positive SYS"
632         if !PSPP::value_is_missing ($val, $numericvar);
633
634     @c = $sf->get_next_case (); 
635     $val = $c[2];
636     die "Missing Value Positive Num"
637         if !PSPP::value_is_missing ($val, $numericvar);
638 ]])
639 AT_CHECK([RUN_PERL_MODULE test.pl])
640 AT_CLEANUP
641
642 AT_SETUP([Perl custom attributes])
643 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
644 PERL_GENERATE_SYSFILE
645 AT_DATA([test.pl],
646   [[use warnings;
647     use strict;
648     use PSPP;
649
650     my $sf = PSPP::Reader->open ("sample.sav");
651
652     my $dict = $sf->get_dict ();
653
654     my $var = $dict->get_var_by_name ("numeric");
655
656     my $attr = $var->get_attributes ();
657
658     foreach my $k (sort (keys (%$attr)))
659     {
660         my $ll = $attr->{$k};
661         print "$k =>";
662         print map "$_\n", join ', ', @$ll;
663     }
664 ]])
665 AT_CHECK([RUN_PERL_MODULE test.pl], [0],
666   [[$@Role =>0
667 colour =>blue, pink, violet
668 nationality =>foreign
669 size =>large
670 ]])
671 AT_CLEANUP
672
673 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 AT_CHECK([RUN_PERL_MODULE $abs_top_builddir/perl-module/t/Pspp.t], [0],
678   [[1..37
679 ok 1 - use PSPP;
680 ok 2 - Dictionary Creation
681 ok 3
682 ok 4 - Trap illegal variable name
683 ok 5
684 ok 6 - Accept legal variable name
685 ok 7
686 ok 8 - Trap duplicate variable name
687 ok 9
688 ok 10 - Accept valid format
689 ok 11
690 ok 12 - Create sysfile object
691 ok 13 - Write system file
692 ok 14 - Append Case
693 ok 15 - Appending Case with too many variables
694 ok 16 - existance
695 ok 17 - Append Case 2
696 ok 18 - existance2
697 ok 19 - Check output
698 ok 20 - Dictionary Creation 2
699 ok 21 - Value label for short string
700 ok 22 - Value label for long string
701 ok 23 - Check output 2
702 ok 24 - Dictionary survives sysfile
703 ok 25 - Basic reader operation
704 ok 26 - Streaming of files
705 Formatted string is "11-SEP-2001 08:20"
706 ok 27 - format_value function
707 ok 28 - Perl representation of time
708 ok 29 - Returns undef on opening failure
709 ok 30 - Error string on open failure
710 ok 31 - Missing Value Negative String
711 ok 32 - Missing Value Negative Num
712 ok 33 - Missing Value Positive
713 ok 34 - Missing Value Positive SYS
714 ok 35 - Missing Value Positive Num
715 ok 36 - Custom Attributes
716 ok 37 - Case count
717 ]],[ignore])
718 AT_CLEANUP