Add random access to casefiles, for use in GUI.
[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/case.h>
23
24 #include <gsl/gsl_randist.h>
25 #include <gsl/gsl_rng.h>
26 #include <stdarg.h>
27 #include <language/command.h>
28 #include <language/lexer/lexer.h>
29
30 #include "xalloc.h"
31
32 static void test_casefile (int pattern, size_t value_cnt, size_t case_cnt);
33 static void get_random_case (struct ccase *, size_t value_cnt,
34                              size_t case_idx);
35 static void write_random_case (struct casefile *cf, size_t case_idx);
36 static void read_and_verify_random_case (struct casefile *cf,
37                                          struct casereader *reader,
38                                          size_t case_idx);
39 static void fail_test (const char *message, ...);
40
41 int
42 cmd_debug_casefile (void) 
43 {
44   static const size_t sizes[] =
45     {
46       1, 2, 3, 4, 5, 6, 7, 14, 15, 16, 17, 31, 55, 73,
47       100, 137, 257, 521, 1031, 2053
48     };
49   int size_max;
50   int case_max;
51   int pattern;
52
53   size_max = sizeof sizes / sizeof *sizes;
54   if (lex_match_id ("SMALL")) 
55     {
56       size_max -= 4;
57       case_max = 511; 
58     }
59   else
60     case_max = 4095;
61   if (token != '.')
62     return lex_end_of_command ();
63     
64   for (pattern = 0; pattern < 6; pattern++) 
65     {
66       const size_t *size;
67
68       for (size = sizes; size < sizes + size_max; size++) 
69         {
70           size_t case_cnt;
71
72           for (case_cnt = 0; case_cnt <= case_max;
73                case_cnt = (case_cnt * 2) + 1)
74             test_casefile (pattern, *size, case_cnt);
75         }
76     }
77   printf ("Casefile tests succeeded.\n");
78   return CMD_SUCCESS;
79 }
80
81 static void
82 test_casefile (int pattern, size_t value_cnt, size_t case_cnt) 
83 {
84   struct casefile *cf;
85   struct casereader *r1, *r2;
86   struct ccase c;
87   gsl_rng *rng;
88   size_t i, j;
89
90   rng = gsl_rng_alloc (gsl_rng_mt19937);
91   cf = casefile_create (value_cnt);
92   if (pattern == 5)
93     casefile_to_disk (cf);
94   for (i = 0; i < case_cnt; i++)
95     write_random_case (cf, i);
96   if (pattern == 5)
97     casefile_sleep (cf);
98   r1 = casefile_get_reader (cf);
99   r2 = casefile_get_reader (cf);
100   switch (pattern) 
101     {
102     case 0:
103     case 5:
104       for (i = 0; i < case_cnt; i++) 
105         {
106           read_and_verify_random_case (cf, r1, i);
107           read_and_verify_random_case (cf, r2, i);
108         } 
109       break;
110     case 1:
111       for (i = 0; i < case_cnt; i++)
112         read_and_verify_random_case (cf, r1, i);
113       for (i = 0; i < case_cnt; i++) 
114         read_and_verify_random_case (cf, r2, i);
115       break;
116     case 2:
117     case 3:
118     case 4:
119       for (i = j = 0; i < case_cnt; i++) 
120         {
121           read_and_verify_random_case (cf, r1, i);
122           if (gsl_rng_get (rng) % pattern == 0) 
123             read_and_verify_random_case (cf, r2, j++); 
124           if (i == case_cnt / 2)
125             casefile_to_disk (cf);
126         }
127       for (; j < case_cnt; j++) 
128         read_and_verify_random_case (cf, r2, j);
129       break;
130     }
131   if (casereader_read (r1, &c))
132     fail_test ("Casereader 1 not at end of file.");
133   if (casereader_read (r2, &c))
134     fail_test ("Casereader 2 not at end of file.");
135   if (pattern != 1)
136     casereader_destroy (r1);
137   if (pattern != 2)
138     casereader_destroy (r2);
139   if (pattern > 3) 
140     {
141       int *order;
142       r1 = casefile_get_random_reader (cf);
143       order = xmalloc (sizeof *order * case_cnt);
144       for (i = 0; i < case_cnt; i++)
145         order[i] = i;
146       if (case_cnt > 0)
147         gsl_ran_shuffle (rng, order, case_cnt, sizeof *order);
148       for (i = 0; i < case_cnt; i++)
149         {
150           int case_idx = order[i];
151           casereader_seek (r1, case_idx);
152           read_and_verify_random_case (cf, r1, case_idx);
153         }
154       casereader_destroy (r1);
155       free (order);
156     }
157   if (pattern > 2) 
158     {
159       r1 = casefile_get_destructive_reader (cf);
160       for (i = 0; i < case_cnt; i++) 
161         {
162           struct ccase read_case, expected_case;
163           
164           get_random_case (&expected_case, value_cnt, i);
165           if (!casereader_read_xfer (r1, &read_case)) 
166             fail_test ("Premature end of casefile.");
167           for (j = 0; j < value_cnt; j++) 
168             {
169               double a = case_num (&read_case, j);
170               double b = case_num (&expected_case, j);
171               if (a != b)
172                 fail_test ("Case %lu fails comparison.", (unsigned long) i); 
173             }
174           case_destroy (&expected_case);
175           case_destroy (&read_case);
176         }
177       casereader_destroy (r1);
178     }
179   casefile_destroy (cf);
180   gsl_rng_free (rng);
181 }
182
183 static void
184 get_random_case (struct ccase *c, size_t value_cnt, size_t case_idx) 
185 {
186   int i;
187   case_create (c, value_cnt);
188   for (i = 0; i < value_cnt; i++)
189     case_data_rw (c, i)->f = case_idx % 257 + i;
190 }
191
192 static void
193 write_random_case (struct casefile *cf, size_t case_idx) 
194 {
195   struct ccase c;
196   get_random_case (&c, casefile_get_value_cnt (cf), case_idx);
197   casefile_append_xfer (cf, &c);
198 }
199
200 static void
201 read_and_verify_random_case (struct casefile *cf,
202                              struct casereader *reader, size_t case_idx) 
203 {
204   struct ccase read_case, expected_case;
205   size_t value_cnt;
206   size_t i;
207   
208   value_cnt = casefile_get_value_cnt (cf);
209   get_random_case (&expected_case, value_cnt, case_idx);
210   if (!casereader_read (reader, &read_case)) 
211     fail_test ("Premature end of casefile.");
212   for (i = 0; i < value_cnt; i++) 
213     {
214       double a = case_num (&read_case, i);
215       double b = case_num (&expected_case, i);
216       if (a != b)
217         fail_test ("Case %lu fails comparison.", (unsigned long) case_idx); 
218     }
219   case_destroy (&read_case);
220   case_destroy (&expected_case);
221 }
222
223 static void
224 fail_test (const char *message, ...) 
225 {
226   va_list args;
227
228   va_start (args, message);
229   vprintf (message, args);
230   putchar ('\n');
231   va_end (args);
232   
233   exit (1);
234 }