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