33b15cb6eb00ef0eb93e7ae312859b79c458e576
[pspp-builds.git] / src / language / tests / casefile-test.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2004 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include <data/casefile.h>
22 #include <data/fastfile.h>
23
24 #include <data/case.h>
25
26 #include <gsl/gsl_randist.h>
27 #include <gsl/gsl_rng.h>
28 #include <stdarg.h>
29 #include <language/command.h>
30 #include <language/lexer/lexer.h>
31 #include <libpspp/assertion.h>
32
33 #include "xalloc.h"
34
35 static void test_casefile (int pattern, size_t value_cnt, size_t case_cnt);
36 static void get_random_case (struct ccase *, size_t value_cnt,
37                              size_t case_idx);
38 static void write_random_case (struct casefile *cf, size_t case_idx);
39 static void read_and_verify_random_case (struct casefile *cf,
40                                          struct casereader *reader,
41                                          size_t case_idx);
42 static void test_casereader_clone (struct casereader *reader1, size_t case_cnt);
43                                  
44
45 static void fail_test (const char *message, ...);
46
47 int
48 cmd_debug_casefile (struct lexer *lexer, struct dataset *ds UNUSED) 
49 {
50   static const size_t sizes[] =
51     {
52       1, 2, 3, 4, 5, 6, 7, 14, 15, 16, 17, 31, 55, 73,
53       100, 137, 257, 521, 1031, 2053
54     };
55   int size_max;
56   int case_max;
57   int pattern;
58
59   size_max = sizeof sizes / sizeof *sizes;
60   if (lex_match_id (lexer, "SMALL")) 
61     {
62       size_max -= 4;
63       case_max = 511; 
64     }
65   else
66     case_max = 4095;
67   if (lex_token (lexer) != '.')
68     return lex_end_of_command (lexer);
69     
70   for (pattern = 0; pattern < 7; pattern++) 
71     {
72       const size_t *size;
73
74       for (size = sizes; size < sizes + size_max; size++) 
75         {
76           size_t case_cnt;
77
78           for (case_cnt = 0; case_cnt <= case_max;
79                case_cnt = (case_cnt * 2) + 1)
80             test_casefile (pattern, *size, case_cnt);
81         }
82     }
83   printf ("Casefile tests succeeded.\n");
84   return CMD_SUCCESS;
85 }
86
87 static void
88 test_casefile (int pattern, size_t value_cnt, size_t case_cnt) 
89 {
90   struct casefile *cf;
91   struct casereader *r1, *r2;
92   struct ccase c;
93   gsl_rng *rng;
94   size_t i, j;
95
96   rng = gsl_rng_alloc (gsl_rng_mt19937);
97   cf = fastfile_create (value_cnt);
98   if (pattern == 5)
99     casefile_to_disk (cf);
100   for (i = 0; i < case_cnt; i++)
101     write_random_case (cf, i);
102   if (pattern == 5)
103     casefile_sleep (cf);
104   r1 = casefile_get_reader (cf, NULL);
105   r2 = casefile_get_reader (cf, NULL);
106   switch (pattern) 
107     {
108     case 0:
109     case 5:
110       for (i = 0; i < case_cnt; i++) 
111         {
112           read_and_verify_random_case (cf, r1, i);
113           read_and_verify_random_case (cf, r2, i);
114         } 
115       break;
116     case 1:
117       for (i = 0; i < case_cnt; i++)
118         read_and_verify_random_case (cf, r1, i);
119       for (i = 0; i < case_cnt; i++) 
120         read_and_verify_random_case (cf, r2, i);
121       break;
122     case 2:
123     case 3:
124     case 4:
125       for (i = j = 0; i < case_cnt; i++) 
126         {
127           read_and_verify_random_case (cf, r1, i);
128           if (gsl_rng_get (rng) % pattern == 0) 
129             read_and_verify_random_case (cf, r2, j++); 
130           if (i == case_cnt / 2)
131             casefile_to_disk (cf);
132         }
133       for (; j < case_cnt; j++) 
134         read_and_verify_random_case (cf, r2, j);
135       break;
136     case 6:
137       test_casereader_clone (r1, case_cnt);
138       test_casereader_clone (r2, case_cnt);
139       break;
140     default:
141       NOT_REACHED ();
142     }
143   if (casereader_read (r1, &c))
144     fail_test ("Casereader 1 not at end of file.");
145   if (casereader_read (r2, &c))
146     fail_test ("Casereader 2 not at end of file.");
147   if (pattern != 1)
148     casereader_destroy (r1);
149   if (pattern != 2)
150     casereader_destroy (r2);
151   if (pattern > 2) 
152     {
153       r1 = casefile_get_destructive_reader (cf);
154       for (i = 0; i < case_cnt; i++) 
155         {
156           struct ccase read_case, expected_case;
157           
158           get_random_case (&expected_case, value_cnt, i);
159           if (!casereader_read_xfer (r1, &read_case)) 
160             fail_test ("Premature end of casefile.");
161           for (j = 0; j < value_cnt; j++) 
162             {
163               double a = case_num_idx (&read_case, j);
164               double b = case_num_idx (&expected_case, j);
165               if (a != b)
166                 fail_test ("Case %lu fails comparison.", (unsigned long) i); 
167             }
168           case_destroy (&expected_case);
169           case_destroy (&read_case);
170         }
171       casereader_destroy (r1);
172     }
173   casefile_destroy (cf);
174   gsl_rng_free (rng);
175 }
176
177 static void
178 get_random_case (struct ccase *c, size_t value_cnt, size_t case_idx) 
179 {
180   int i;
181   case_create (c, value_cnt);
182   for (i = 0; i < value_cnt; i++)
183     case_data_rw_idx (c, i)->f = case_idx % 257 + i;
184 }
185
186 static void
187 write_random_case (struct casefile *cf, size_t case_idx) 
188 {
189   struct ccase c;
190   get_random_case (&c, casefile_get_value_cnt (cf), case_idx);
191   casefile_append_xfer (cf, &c);
192 }
193
194 static void
195 read_and_verify_random_case (struct casefile *cf,
196                              struct casereader *reader, size_t case_idx) 
197 {
198   struct ccase read_case, expected_case;
199   size_t value_cnt;
200   size_t i;
201   
202   value_cnt = casefile_get_value_cnt (cf);
203   get_random_case (&expected_case, value_cnt, case_idx);
204   if (!casereader_read (reader, &read_case)) 
205     fail_test ("Premature end of casefile.");
206   for (i = 0; i < value_cnt; i++) 
207     {
208       double a = case_num_idx (&read_case, i);
209       double b = case_num_idx (&expected_case, i);
210       if (a != b)
211         fail_test ("Case %lu fails comparison.", (unsigned long) case_idx); 
212     }
213   case_destroy (&read_case);
214   case_destroy (&expected_case);
215 }
216
217 static void
218 test_casereader_clone (struct casereader *reader1, size_t case_cnt)
219 {
220   size_t i;
221   size_t cases = 0;
222   struct ccase c1;
223   struct ccase c2;
224   struct casefile *src = casereader_get_casefile (reader1);
225   struct casereader *clone = NULL;
226
227   size_t value_cnt = casefile_get_value_cnt (src);
228
229   struct casefile *newfile = fastfile_create (value_cnt);
230   struct casereader *newreader;
231
232
233   /* Read a 3rd of the cases */
234   for ( i = 0 ; i < case_cnt / 3 ; ++i ) 
235     {
236       casereader_read (reader1, &c1);
237       case_destroy (&c1);
238     }
239
240   clone = casereader_clone (reader1);
241
242   /* Copy all the cases into a new file */
243   while( casereader_read (reader1, &c1))
244     { 
245       casefile_append_xfer (newfile, &c1);
246       cases ++;
247     }
248
249   newreader = casefile_get_reader (newfile, NULL);
250
251   /* Make sure that the new file's are identical to those returned from 
252      the cloned reader */
253   while( casereader_read (clone, &c1))
254     { 
255       const union value *v1;
256       const union value *v2;
257       cases --;
258
259       if ( ! casereader_read_xfer (newreader, &c2) ) 
260         {
261           case_destroy (&c1);
262           break; 
263         }
264       
265       v1 = case_data_all (&c1) ;
266       v2 = case_data_all (&c2) ;
267
268       if ( 0 != memcmp (v1, v2, value_cnt * MAX_SHORT_STRING))
269         fail_test ("Cloned reader read different value at case %ld", cases);
270
271       case_destroy (&c1);
272       case_destroy (&c2);
273     }
274
275   if ( cases > 0 ) 
276     fail_test ("Cloned reader reads different number of cases.");
277
278 }
279
280 static void
281 fail_test (const char *message, ...) 
282 {
283   va_list args;
284
285   va_start (args, message);
286   vprintf (message, args);
287   putchar ('\n');
288   va_end (args);
289   
290   exit (1);
291 }