1 /* ------------------------------------------------------------------------
2 @NAME : simple_test.c
3 @INPUT :
4 @OUTPUT :
5 @RETURNS :
6 @DESCRIPTION: Run some basic tests on some simple data. The .bib files
7 processed here are all free of errors, and use just the basic
8 BibTeX syntax. This is just to make sure the parser and
9 library are working in the crudest sense; more elaborate
10 tests will someday performed elsewhere (I hope).
11 @GLOBALS :
12 @CALLS :
13 @CALLERS :
14 @CREATED : 1997/07/29, Greg Ward
15 @MODIFIED :
16 @VERSION : $Id: simple_test.c 714 2003-10-09 02:37:15Z greg $
17 @COPYRIGHT : Copyright (c) 1996-97 by Gregory P. Ward. All rights reserved.
18
19 This file is part of the btparse distribution (but not part
20 of the library itself). This is free software; you can
21 redistribute it and/or modify it under the terms of the GNU
22 General Public License as published by the Free Software
23 Foundation; either version 2 of the License, or (at your
24 option) any later version.
25 -------------------------------------------------------------------------- */
26
27 #include "bt_config.h"
28 #include <stdlib.h>
29 #include <string.h>
30 #include "btparse.h"
31 #include "testlib.h"
32 #include "my_dmalloc.h"
33
34 int test_num = 0;
35
36
37 typedef enum { single, multiple, wholefile } test_mode;
38
39 typedef struct
40 {
41 int num_fields;
42 char **fields;
43 int num_values;
44 char **values;
45 bt_nodetype * ntypes;
46 } test_data;
47
48 typedef boolean (*tester) (AST *, test_data *);
49
50 typedef struct
51 {
52 char * desc;
53 char * filename;
54 ushort options;
55 tester test_func;
56 test_data * data;
57 } test;
58
59 /* prototypes needed for defining the tests[] array */
60 boolean eviltest_regular (AST *entry, test_data *data);
61 boolean eviltest_macro (AST *entry, test_data *data);
62 boolean eviltest_comment (AST *entry, test_data *data);
63 boolean eviltest_preamble (AST *entry, test_data *data);
64 boolean goodtest_regular (AST *entry, test_data *data);
65 boolean goodtest_macro (AST *entry, test_data *data);
66 boolean goodtest_comment (AST *entry, test_data *data);
67 boolean goodtest_preamble (AST *entry, test_data *data);
68
69 /* and prototypes to keep "gcc -Wall" from whining */
70 boolean test_multiple (FILE *, char *, ushort, ushort, int, test *);
71 boolean test_wholefile (char *, ushort, ushort, int, test *);
72
73
74 /* a priori knowledge about the entry in "regular.bib" (used for both tests) */
75 char * regular_fields[] = { "title", "editor", "publisher", "year" };
76 char * regular_values[] =
77 { "A ", "Book", " John Q. Random", "junk", "Foo Bar \\& Sons", "1922" };
78 char * regular_values_proc[] =
79 { "A Book", "John Q. Random", "Foo Bar \\& Sons", "1922" };
80 bt_nodetype regular_ntypes[] =
81 { BTAST_STRING, BTAST_STRING, BTAST_STRING, BTAST_MACRO, BTAST_STRING, BTAST_NUMBER };
82 bt_nodetype regular_ntypes_proc[] =
83 { BTAST_STRING, BTAST_STRING, BTAST_STRING, BTAST_STRING };
84
85 /* likewise for "macro.bib" */
86 char * macro_macros[] = { "macro", "foo" };
87 char * macro_values[] =
88 { "macro text ", "blah blah ", " ding dong " };
89 char * macro_values_proc[] =
90 { "macro text", "blah blah ding dong" };
91 bt_nodetype macro_ntypes[] = { BTAST_STRING, BTAST_STRING, BTAST_STRING };
92
93 /* and for "comment.bib" */
94 char * comment_value = "this is a comment entry, anything at all can go in it (as long as parentheses are balanced), even {braces}";
95 char * comment_value_proc = "this is a comment entry, anything at all can go in it (as long as parentheses are balanced), even {braces}";
96
97 /* and for "preamble.bib" */
98 char * preamble_values[] =
99 { " This is a preamble",
100 "---the concatenation of several strings" };
101 char * preamble_value_proc =
102 "This is a preamble---the concatenation of several strings";
103
104 test_data regular_unproc_data =
105 { 4, regular_fields, 6, regular_values, regular_ntypes };
106 test_data regular_proc_data =
107 { 4, regular_fields, 4, regular_values_proc, regular_ntypes_proc };
108 test_data macro_unproc_data =
109 { 2, macro_macros, 3, macro_values, macro_ntypes };
110 test_data macro_proc_data =
111 { 2, macro_macros, 2, macro_values_proc, macro_ntypes };
112 test_data comment_unproc_data =
113 { 0, NULL, 1, &comment_value, NULL };
114 test_data comment_proc_data =
115 { 0, NULL, 1, &comment_value_proc, NULL };
116 test_data preamble_unproc_data =
117 { 0, NULL, 2, preamble_values, NULL };
118 test_data preamble_proc_data =
119 { 0, NULL, 1, &preamble_value_proc, NULL };
120
121
122 test tests[] =
123 {
124 { "regular entry (unprocessed, low-level scan)",
125 "regular.bib", BTO_MINIMAL,
126 eviltest_regular, ®ular_unproc_data
127 },
128 { "macro entry (unprocessed, low-level scan)",
129 "macro.bib", BTO_MINIMAL,
130 eviltest_macro, ¯o_unproc_data
131 },
132 { "comment entry (unprocessed, low-level scan)",
133 "comment.bib", BTO_MINIMAL,
134 eviltest_comment, &comment_unproc_data
135 },
136 { "preamble entry (unprocessed, low-level scan)",
137 "preamble.bib", BTO_MINIMAL,
138 eviltest_preamble, &preamble_unproc_data
139 },
140 { "regular entry (unprocessed, high-level scan)",
141 "regular.bib", BTO_MINIMAL,
142 goodtest_regular, ®ular_unproc_data
143 },
144 { "macro entry (unprocessed, high-level scan)",
145 "macro.bib", BTO_MINIMAL,
146 goodtest_macro, ¯o_unproc_data
147 },
148 { "comment entry (unprocessed, high-level scan)",
149 "comment.bib", BTO_MINIMAL,
150 goodtest_comment, &comment_unproc_data
151 },
152 { "preamble entry (unprocessed, high-level scan)",
153 "preamble.bib", BTO_MINIMAL,
154 goodtest_preamble, &preamble_unproc_data
155 },
156 { "regular entry (processed, low-level scan)",
157 "regular.bib", BTO_FULL,
158 eviltest_regular, ®ular_proc_data
159 },
160 { "macro entry (processed, low-level scan)",
161 "macro.bib", BTO_FULL,
162 eviltest_macro, ¯o_proc_data
163 },
164 { "comment entry (processed, low-level scan)",
165 "comment.bib", BTO_FULL,
166 eviltest_comment, &comment_proc_data
167 },
168 { "preamble entry (processed, low-level scan)",
169 "preamble.bib", BTO_FULL,
170 eviltest_preamble, &preamble_proc_data
171 },
172 { "regular entry (processed, high-level scan)",
173 "regular.bib", BTO_FULL,
174 goodtest_regular, ®ular_proc_data
175 },
176 { "macro entry (processed, high-level scan)",
177 "macro.bib", BTO_FULL,
178 goodtest_macro, ¯o_proc_data
179 },
180 { "comment entry (processed, high-level scan)",
181 "comment.bib", BTO_FULL,
182 goodtest_comment, &comment_proc_data
183 },
184 { "preamble entry (processed, high-level scan)",
185 "preamble.bib", BTO_FULL,
186 goodtest_preamble, &preamble_proc_data
187 },
188 };
189
190
191 #define NUM_TESTS sizeof (tests) / sizeof (tests[0])
192
193
eviltest_regular(AST * entry,test_data * data)194 boolean eviltest_regular (AST * entry, test_data * data)
195 {
196 boolean ok = TRUE;
197 AST * key;
198 AST * field;
199 AST * value;
200 int field_num;
201 int value_num;
202
203 CHECK_ESCAPE (entry != NULL, return FALSE, "entry")
204 CHECK (entry->nodetype == BTAST_ENTRY)
205 CHECK (entry->metatype == BTE_REGULAR)
206 CHECK (strcmp (entry->text, "book") == 0)
207
208 key = entry->down;
209 CHECK_ESCAPE (key != NULL, return FALSE, "entry")
210 CHECK (key->nodetype == BTAST_KEY)
211 CHECK (key->metatype == BTE_UNKNOWN)
212 CHECK (strcmp (key->text, "abook") == 0)
213
214 field = key;
215 field_num = 0;
216 value_num = 0;
217
218 while ((field = field->right))
219 {
220 CHECK_ESCAPE (field_num < data->num_fields, break, "entry")
221 CHECK (field->nodetype == BTAST_FIELD)
222 CHECK (field->metatype == BTE_UNKNOWN)
223 CHECK (strcmp (field->text, data->fields[field_num++]) == 0)
224
225 value = field->down;
226 while (value)
227 {
228 CHECK_ESCAPE (value_num < data->num_values, break, "field")
229 CHECK (value->nodetype == data->ntypes[value_num])
230 CHECK (strcmp (value->text, data->values[value_num]) == 0)
231 value = value->right;
232 value_num++;
233 }
234 }
235 CHECK (field_num == data->num_fields)
236 CHECK (value_num == data->num_values)
237
238 return ok;
239
240 } /* eviltest_regular () */
241
242
eviltest_macro(AST * entry,test_data * data)243 boolean eviltest_macro (AST * entry, test_data * data)
244 {
245 boolean ok = TRUE;
246 AST * macro;
247 AST * value;
248 int macro_num;
249 int value_num;
250
251 CHECK (entry != NULL)
252 CHECK (entry->nodetype == BTAST_ENTRY)
253 CHECK (entry->metatype == BTE_MACRODEF)
254 CHECK (strcmp (entry->text, "string") == 0)
255
256 macro_num = 0;
257 value_num = 0;
258 macro = entry->down;
259
260 while (macro)
261 {
262 CHECK_ESCAPE (macro_num < data->num_fields, break, "entry")
263 CHECK (macro->nodetype == BTAST_FIELD)
264 CHECK (macro->metatype == BTE_UNKNOWN)
265 CHECK (strcmp (macro->text, data->fields[macro_num++]) == 0)
266
267 value = macro->down;
268 while (value)
269 {
270 CHECK_ESCAPE (value_num < data->num_values, break, "macro")
271 CHECK (value->nodetype == data->ntypes[value_num])
272 CHECK (strcmp (value->text, data->values[value_num]) == 0)
273 value = value->right;
274 value_num++;
275 }
276 macro = macro->right;
277 }
278 CHECK (macro_num == data->num_fields)
279 CHECK (value_num == data->num_values)
280
281 return ok;
282
283 } /* eviltest_macro () */
284
285
eviltest_comment(AST * entry,test_data * data)286 boolean eviltest_comment (AST * entry, test_data * data)
287 {
288 boolean ok = TRUE;
289 AST * value;
290
291 CHECK_ESCAPE (entry != NULL, return FALSE, "entry");
292 CHECK (strcmp (entry->text, "comment") == 0);
293
294 value = entry->down;
295 CHECK_ESCAPE (value != NULL, return FALSE, "entry");
296 CHECK (strcmp (value->text, data->values[0]) == 0);
297 CHECK (value->right == NULL);
298 CHECK (value->down == NULL);
299
300 return ok;
301 } /* eviltest_comment () */
302
303
eviltest_preamble(AST * entry,test_data * data)304 boolean eviltest_preamble (AST * entry, test_data * data)
305 {
306 boolean ok = TRUE;
307 AST * value;
308 int value_num;
309
310 CHECK_ESCAPE (entry != NULL, return FALSE, "entry");
311 CHECK (strcmp (entry->text, "preamble") == 0);
312
313 value_num = 0;
314 value = entry->down;
315 while (value)
316 {
317 CHECK_ESCAPE (value_num < data->num_values, break, "entry");
318 CHECK (value->nodetype == BTAST_STRING);
319 CHECK (strcmp (value->text, data->values[value_num]) == 0);
320
321 value = value->right;
322 value_num++;
323 }
324
325 CHECK (value_num == data->num_values);
326 return ok;
327
328 } /* eviltest_preamble () */
329
330
goodtest_regular(AST * entry,test_data * data)331 boolean goodtest_regular (AST * entry, test_data * data)
332 {
333 boolean ok = TRUE;
334 AST * field;
335 AST * value;
336 char * field_name;
337 char * value_text;
338 bt_nodetype
339 value_nodetype;
340 int field_num;
341 int value_num;
342
343 CHECK (bt_entry_metatype (entry) == BTE_REGULAR);
344 CHECK (strcmp (bt_entry_type (entry), "book") == 0);
345 CHECK (strcmp (bt_entry_key (entry), "abook") == 0);
346
347 field = NULL;
348 field_num = 0;
349 value_num = 0;
350
351 while ((field = bt_next_field (entry, field, &field_name)))
352 {
353 CHECK_ESCAPE (field_num < data->num_fields, break, "entry");
354 CHECK (strcmp (field_name, data->fields[field_num++]) == 0);
355
356 value = NULL;
357 while ((value = bt_next_value (field,value,&value_nodetype,&value_text)))
358 {
359 CHECK_ESCAPE (value_num < data->num_values, break, "field");
360 CHECK (value_nodetype == data->ntypes[value_num]);
361 CHECK (strcmp (value_text, data->values[value_num++]) == 0);
362 }
363 }
364
365 CHECK (field_num == data->num_fields);
366 CHECK (value_num == data->num_values);
367
368 return ok;
369
370 }
371
372
goodtest_macro(AST * entry,test_data * data)373 boolean goodtest_macro (AST * entry, test_data * data)
374 {
375 boolean ok = TRUE;
376 AST * macro;
377 AST * value;
378 char * macro_name;
379 char * value_text;
380 bt_nodetype
381 value_nodetype;
382 int macro_num;
383 int value_num;
384
385 CHECK (bt_entry_metatype (entry) == BTE_MACRODEF);
386 CHECK (strcmp (bt_entry_type (entry), "string") == 0);
387 CHECK (bt_entry_key (entry) == NULL);
388
389 macro = NULL;
390 macro_num = 0;
391 value_num = 0;
392
393 while ((macro = bt_next_macro (entry, macro, ¯o_name)))
394 {
395 CHECK_ESCAPE (macro_num < data->num_fields, break, "entry");
396 CHECK (strcmp (macro_name, data->fields[macro_num++]) == 0);
397
398 value = NULL;
399 while ((value = bt_next_value (macro,value,&value_nodetype,&value_text)))
400 {
401 CHECK_ESCAPE (value_num < data->num_values, break, "macro");
402 CHECK (value_nodetype == data->ntypes[value_num]);
403 CHECK (strcmp (value_text, data->values[value_num++]) == 0);
404 }
405 }
406
407 CHECK (macro_num == data->num_fields);
408 CHECK (value_num == data->num_values);
409
410 return ok;
411
412 }
413
414
goodtest_comment(AST * entry,test_data * data)415 boolean goodtest_comment (AST * entry, test_data * data)
416 {
417 boolean ok = TRUE;
418 AST * value;
419 char * text;
420
421 CHECK (bt_entry_metatype (entry) == BTE_COMMENT);
422 CHECK (strcmp (bt_entry_type (entry), "comment") == 0);
423
424 value = bt_next_value (entry, NULL, NULL, &text);
425 CHECK (strcmp (text, data->values[0]) == 0);
426
427 return ok;
428 }
429
430
goodtest_preamble(AST * entry,test_data * data)431 boolean goodtest_preamble (AST * entry, test_data * data)
432 {
433 boolean ok = TRUE;
434 AST * value;
435 char * value_text;
436 bt_nodetype
437 value_nodetype;
438 int value_num;
439
440 CHECK (bt_entry_metatype (entry) == BTE_PREAMBLE);
441 CHECK (strcmp (bt_entry_type (entry), "preamble") == 0);
442
443 value = NULL;
444 value_num = 0;
445 while ((value = bt_next_value (entry, value, &value_nodetype, &value_text)))
446 {
447 CHECK_ESCAPE (value_num < data->num_values, break, "entry");
448 CHECK (value_nodetype == BTAST_STRING);
449 CHECK (strcmp (value_text, data->values[value_num++]) == 0);
450 }
451
452 CHECK (value_num == data->num_values);
453 return ok;
454 }
455
456
test_multiple(FILE * file,char * filename,ushort string_opts,ushort other_opts,int num_entries,test * tests)457 boolean test_multiple (FILE * file,
458 char * filename,
459 ushort string_opts,
460 ushort other_opts,
461 int num_entries,
462 test * tests)
463 {
464 boolean entry_ok;
465 boolean ok;
466 int entry_num;
467 AST * entry;
468
469 ok = TRUE;
470 entry_num = 0;
471
472 printf ("multiple entries in one file, read individually:\n");
473 set_all_stringopts (string_opts);
474
475 while (1)
476 {
477 entry = bt_parse_entry (file, filename, other_opts, &entry_ok);
478 if (!entry) break; /* at eof? */
479
480 CHECK_ESCAPE (entry_num < num_entries, break, "file");
481
482 entry_ok &= tests[entry_num].test_func (entry, tests[entry_num].data);
483 printf (" %s: %s\n",
484 tests[entry_num].desc,
485 entry_ok ? "ok" : "not ok");
486 entry_num++;
487 bt_free_ast (entry);
488
489 ok &= entry_ok;
490 }
491
492 CHECK (entry_num == num_entries);
493 printf ("...%s\n", ok ? "all ok" : "not all ok");
494 return ok;
495
496 }
497
498
test_wholefile(char * filename,ushort string_opts,ushort other_opts,int num_entries,test * tests)499 boolean test_wholefile (char * filename,
500 ushort string_opts,
501 ushort other_opts,
502 int num_entries,
503 test * tests)
504 {
505 boolean entry_ok;
506 boolean ok;
507 int entry_num;
508 AST * entries,
509 * entry;
510
511 ok = TRUE;
512 entry_num = 0;
513
514 printf ("multiple entries in one file, read together:\n");
515 set_all_stringopts (string_opts);
516 entries = bt_parse_file (filename, other_opts, &entry_ok);
517 CHECK (entry_ok);
518
519 entry = NULL;
520 while ((entry = bt_next_entry (entries, entry)))
521 {
522 CHECK_ESCAPE (entry_num < num_entries, break, "file");
523
524 entry_ok = tests[entry_num].test_func (entry, tests[entry_num].data);
525 printf (" %s: %s\n",
526 tests[entry_num].desc,
527 entry_ok ? "ok" : "not ok");
528 entry_num++;
529
530 ok &= entry_ok;
531 }
532
533 CHECK (entry_num == num_entries);
534 bt_free_ast (entries);
535 printf ("...%s\n", ok ? "all ok" : "not all ok");
536 return ok;
537
538 }
539
540
main(void)541 int main (void)
542 {
543 unsigned i;
544 char filename[256];
545 FILE * infile;
546 AST * entry;
547 ushort options = 0; /* use default non-string options */
548 boolean ok;
549 int num_failures = 0;
550
551 bt_initialize ();
552
553 for (i = 0; i < NUM_TESTS; i++)
554 {
555 infile = open_file (tests[i].filename, DATA_DIR, filename);
556
557 /* Override string-processing options for all entry metatypes */
558 set_all_stringopts (tests[i].options);
559
560 entry = bt_parse_entry (infile, filename, options, &ok);
561 ok &= tests[i].test_func (entry, tests[i].data);
562 bt_free_ast (entry);
563 entry = bt_parse_entry (infile, filename, options, NULL);
564 CHECK ((entry == NULL));
565 CHECK (feof (infile));
566 fclose (infile);
567
568 printf ("%s: %s\n", tests[i].desc, ok ? "ok" : "not ok");
569 if (!ok) num_failures++;
570 } /* for i */
571
572 infile = open_file ("simple.bib", DATA_DIR, filename);
573 if (! test_multiple (infile, filename, BTO_MINIMAL, options, 4, tests+4))
574 num_failures++;
575 rewind (infile);
576 if (! test_multiple (infile, filename, BTO_FULL, options, 4, tests+12))
577 num_failures++;
578
579 fclose (infile);
580
581 if (! test_wholefile (DATA_DIR "/" "simple.bib",
582 BTO_MINIMAL, options, 4, tests+4))
583 num_failures++;
584 if (! test_wholefile (DATA_DIR "/" "simple.bib",
585 BTO_FULL, options, 4, tests+12))
586 num_failures++;
587
588 bt_cleanup ();
589
590 if (num_failures == 0)
591 printf ("All tests successful\n");
592 else
593 printf ("%d failed tests\n", num_failures);
594
595 return (num_failures > 0);
596 }
597