1 /*************************************************************************************************
2 * Test cases of Odeum
3 * Copyright (C) 2000-2007 Mikio Hirabayashi
4 * This file is part of QDBM, Quick Database Manager.
5 * QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * Lesser General Public License as published by the Free Software Foundation; either version
7 * 2.1 of the License or any later version. QDBM is distributed in the hope that it will be
8 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
10 * details.
11 * You should have received a copy of the GNU Lesser General Public License along with QDBM; if
12 * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
13 * 02111-1307 USA.
14 *************************************************************************************************/
15
16
17 #include <depot.h>
18 #include <cabin.h>
19 #include <odeum.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <limits.h>
25 #include <time.h>
26
27 #undef TRUE
28 #define TRUE 1 /* boolean true */
29 #undef FALSE
30 #define FALSE 0 /* boolean false */
31
32 #define DOCBUFSIZ 256 /* buffer for documents */
33
34
35 /* for RISC OS */
36 #if defined(__riscos__) || defined(__riscos)
37 #include <unixlib/local.h>
38 int __riscosify_control = __RISCOSIFY_NO_PROCESS;
39 #endif
40
41
42 /* global variables */
43 const char *progname; /* program name */
44
45
46 /* function prototypes */
47 int main(int argc, char **argv);
48 void usage(void);
49 int runwrite(int argc, char **argv);
50 int runread(int argc, char **argv);
51 int runcombo(int argc, char **argv);
52 int runwicked(int argc, char **argv);
53 int printfflush(const char *format, ...);
54 void pdperror(const char *name);
55 int myrand(void);
56 ODDOC *makedoc(int id, int wnum, int pnum);
57 int dowrite(const char *name, int dnum, int wnum, int pnum,
58 int ibnum, int idnum, int cbnum, int csiz);
59 int doread(const char *name);
60 int docombo(const char *name);
61 int dowicked(const char *name, int dnum);
62
63
64 /* main routine */
main(int argc,char ** argv)65 int main(int argc, char **argv){
66 char *env;
67 int rv;
68 cbstdiobin();
69 if((env = getenv("QDBMDBGFD")) != NULL) dpdbgfd = atoi(env);
70 progname = argv[0];
71 if(argc < 2) usage();
72 rv = 0;
73 if(!strcmp(argv[1], "write")){
74 rv = runwrite(argc, argv);
75 } else if(!strcmp(argv[1], "read")){
76 rv = runread(argc, argv);
77 } else if(!strcmp(argv[1], "combo")){
78 rv = runcombo(argc, argv);
79 } else if(!strcmp(argv[1], "wicked")){
80 rv = runwicked(argc, argv);
81 } else {
82 usage();
83 }
84 return 0;
85 }
86
87
88 /* print the usage and exit */
usage(void)89 void usage(void){
90 fprintf(stderr, "%s: test cases for Odeum\n", progname);
91 fprintf(stderr, "\n");
92 fprintf(stderr, "usage:\n");
93 fprintf(stderr, " %s write [-tune ibnum idnum cbnum csiz] name dnum wnum pnum\n", progname);
94 fprintf(stderr, " %s read name\n", progname);
95 fprintf(stderr, " %s combo name\n", progname);
96 fprintf(stderr, " %s wicked name dnum\n", progname);
97 fprintf(stderr, "\n");
98 exit(1);
99 }
100
101
102 /* parse arguments of write command */
runwrite(int argc,char ** argv)103 int runwrite(int argc, char **argv){
104 char *name, *dstr, *wstr, *pstr;
105 int i, dnum, wnum, pnum, ibnum, idnum, cbnum, csiz, rv;
106 name = NULL;
107 dstr = NULL;
108 wstr = NULL;
109 pstr = NULL;
110 dnum = 0;
111 wnum = 0;
112 pnum = 0;
113 ibnum = -1;
114 idnum = -1;
115 cbnum = -1;
116 csiz = -1;
117 for(i = 2; i < argc; i++){
118 if(!name && argv[i][0] == '-'){
119 if(!strcmp(argv[i], "-tune")){
120 if(++i >= argc) usage();
121 ibnum = atoi(argv[i]);
122 if(++i >= argc) usage();
123 idnum = atoi(argv[i]);
124 if(++i >= argc) usage();
125 cbnum = atoi(argv[i]);
126 if(++i >= argc) usage();
127 csiz = atoi(argv[i]);
128 } else {
129 usage();
130 }
131 } else if(!name){
132 name = argv[i];
133 } else if(!dstr){
134 dstr = argv[i];
135 } else if(!wstr){
136 wstr = argv[i];
137 } else if(!pstr){
138 pstr = argv[i];
139 } else {
140 usage();
141 }
142 }
143 if(!name || !dstr || !wstr || !pstr) usage();
144 dnum = atoi(dstr);
145 wnum = atoi(wstr);
146 pnum = atoi(pstr);
147 if(dnum < 1 || wnum < 1 || pnum < 1) usage();
148 rv = dowrite(name, dnum, wnum, pnum, ibnum, idnum, cbnum, csiz);
149 return rv;
150 }
151
152
153 /* parse arguments of read command */
runread(int argc,char ** argv)154 int runread(int argc, char **argv){
155 char *name;
156 int i, rv;
157 name = NULL;
158 for(i = 2; i < argc; i++){
159 if(!name && argv[i][0] == '-'){
160 usage();
161 } else if(!name){
162 name = argv[i];
163 } else {
164 usage();
165 }
166 }
167 if(!name) usage();
168 rv = doread(name);
169 return rv;
170 }
171
172
173 /* parse arguments of combo command */
runcombo(int argc,char ** argv)174 int runcombo(int argc, char **argv){
175 char *name;
176 int i, rv;
177 name = NULL;
178 for(i = 2; i < argc; i++){
179 if(!name && argv[i][0] == '-'){
180 usage();
181 } else if(!name){
182 name = argv[i];
183 } else {
184 usage();
185 }
186 }
187 if(!name) usage();
188 rv = docombo(name);
189 return rv;
190 }
191
192
193 /* parse arguments of wicked command */
runwicked(int argc,char ** argv)194 int runwicked(int argc, char **argv){
195 char *name, *dstr;
196 int i, dnum, rv;
197 name = NULL;
198 dstr = NULL;
199 for(i = 2; i < argc; i++){
200 if(!name && argv[i][0] == '-'){
201 usage();
202 } else if(!name){
203 name = argv[i];
204 } else if(!dstr){
205 dstr = argv[i];
206 } else {
207 usage();
208 }
209 }
210 if(!name || !dstr) usage();
211 dnum = atoi(dstr);
212 if(dnum < 1) usage();
213 rv = dowicked(name, dnum);
214 return rv;
215 }
216
217
218 /* print formatted string and flush the buffer */
printfflush(const char * format,...)219 int printfflush(const char *format, ...){
220 va_list ap;
221 int rv;
222 va_start(ap, format);
223 rv = vprintf(format, ap);
224 if(fflush(stdout) == EOF) rv = -1;
225 va_end(ap);
226 return rv;
227 }
228
229
230 /* print an error message */
pdperror(const char * name)231 void pdperror(const char *name){
232 fprintf(stderr, "%s: %s: %s\n", progname, name, dperrmsg(dpecode));
233 }
234
235
236 /* pseudo random number generator */
myrand(void)237 int myrand(void){
238 static int cnt = 0;
239 if(cnt == 0) srand(time(NULL));
240 return (rand() * rand() + (rand() >> (sizeof(int) * 4)) + (cnt++)) & INT_MAX;
241 }
242
243
244 /* create a document */
makedoc(int id,int wnum,int pnum)245 ODDOC *makedoc(int id, int wnum, int pnum){
246 ODDOC *doc;
247 char buf[DOCBUFSIZ];
248 int i;
249 sprintf(buf, "%08d", id);
250 doc = oddocopen(buf);
251 oddocaddattr(doc, "title", buf);
252 oddocaddattr(doc, "author", buf);
253 oddocaddattr(doc, "date", buf);
254 for(i = 0; i < wnum; i++){
255 sprintf(buf, "%08d", myrand() % pnum);
256 oddocaddword(doc, buf, buf);
257 }
258 return doc;
259 }
260
261
262 /* perform write command */
dowrite(const char * name,int dnum,int wnum,int pnum,int ibnum,int idnum,int cbnum,int csiz)263 int dowrite(const char *name, int dnum, int wnum, int pnum,
264 int ibnum, int idnum, int cbnum, int csiz){
265 ODEUM *odeum;
266 ODDOC *doc;
267 int i, err;
268 printfflush("<Writing Test>\n name=%s dnum=%d wnum=%d pnum=%d"
269 " ibnum=%d idnum=%d cbnum=%d csiz=%d\n\n",
270 name, dnum, wnum, pnum, ibnum, idnum, cbnum, csiz);
271 /* open a database */
272 if(ibnum > 0) odsettuning(ibnum, idnum, cbnum, csiz);
273 if(!(odeum = odopen(name, OD_OWRITER | OD_OCREAT | OD_OTRUNC))){
274 pdperror(name);
275 return 1;
276 }
277 err = FALSE;
278 /* loop for each document */
279 for(i = 1; i <= dnum; i++){
280 /* store a document */
281 doc = makedoc(i, wnum, pnum);
282 if(!odput(odeum, doc, -1, FALSE)){
283 pdperror(name);
284 oddocclose(doc);
285 err = TRUE;
286 break;
287 }
288 oddocclose(doc);
289 /* print progression */
290 if(dnum > 250 && i % (dnum / 250) == 0){
291 putchar('.');
292 fflush(stdout);
293 if(i == dnum || i % (dnum / 10) == 0){
294 printfflush(" (%08d)\n", i);
295 }
296 }
297 }
298 /* close the database */
299 if(!odclose(odeum)){
300 pdperror(name);
301 return 1;
302 }
303 if(!err) printfflush("ok\n\n");
304 return err ? 1 : 0;
305 }
306
307
308 /* perform read command */
doread(const char * name)309 int doread(const char *name){
310 ODEUM *odeum;
311 ODDOC *doc;
312 char buf[DOCBUFSIZ];
313 int i, dnum, err;
314 printfflush("<Reading Test>\n name=%s\n\n", name);
315 /* open a database */
316 if(!(odeum = odopen(name, OD_OREADER))){
317 pdperror(name);
318 return 1;
319 }
320 /* get the number of documents */
321 dnum = oddnum(odeum);
322 err = FALSE;
323 /* loop for each document */
324 for(i = 1; i <= dnum; i++){
325 /* retrieve a document */
326 sprintf(buf, "%08d", i);
327 if(!(doc = odget(odeum, buf))){
328 pdperror(name);
329 err = TRUE;
330 break;
331 }
332 oddocclose(doc);
333 /* print progression */
334 if(dnum > 250 && i % (dnum / 250) == 0){
335 putchar('.');
336 fflush(stdout);
337 if(i == dnum || i % (dnum / 10) == 0){
338 printfflush(" (%08d)\n", i);
339 }
340 }
341 }
342 /* close the database */
343 if(!odclose(odeum)){
344 pdperror(name);
345 return 1;
346 }
347 if(!err) printfflush("ok\n\n");
348 return err ? 1 : 0;
349 }
350
351
352 /* perform combo command */
docombo(const char * name)353 int docombo(const char *name){
354 ODEUM *odeum;
355 ODDOC *doc;
356 const CBLIST *nwords, *awords;
357 CBLIST *tawords, *tnwords, *oawords;
358 ODPAIR *pairs;
359 const char *asis;
360 char buf[DOCBUFSIZ], *normal;
361 int i, j, pnum;
362 printfflush("<Combination Test>\n name=%s\n\n", name);
363 printfflush("Creating a database with ... ");
364 if(!(odeum = odopen(name, OD_OWRITER | OD_OCREAT | OD_OTRUNC))){
365 pdperror(name);
366 return 1;
367 }
368 printfflush("ok\n");
369 printfflush("Adding 20 documents including about 200 words ... ");
370 for(i = 1; i <= 20; i++){
371 sprintf(buf, "%08d", i);
372 doc = makedoc(i, 120 + myrand() % 160, myrand() % 500 + 500);
373 if(!odput(odeum, doc, 180 + myrand() % 40, FALSE)){
374 pdperror(name);
375 oddocclose(doc);
376 odclose(odeum);
377 return 1;
378 }
379 oddocclose(doc);
380 }
381 printfflush("ok\n");
382 printfflush("Checking documents ... ");
383 for(i = 1; i <= 20; i++){
384 sprintf(buf, "%08d", i);
385 if(!(doc = odget(odeum, buf))){
386 pdperror(name);
387 return 1;
388 }
389 nwords = oddocnwords(doc);
390 awords = oddocawords(doc);
391 if(!oddocuri(doc) || !oddocgetattr(doc, "title") || cblistnum(nwords) != cblistnum(awords)){
392 fprintf(stderr, "%s: %s: invalid document\n", progname, name);
393 oddocclose(doc);
394 odclose(odeum);
395 return 1;
396 }
397 for(j = 0; j < cblistnum(nwords); j++){
398 if(strcmp(cblistval(nwords, j, NULL), cblistval(nwords, j, NULL))){
399 fprintf(stderr, "%s: %s: invalid words\n", progname, name);
400 oddocclose(doc);
401 odclose(odeum);
402 return 1;
403 }
404 }
405 oddocclose(doc);
406 }
407 printfflush("ok\n");
408 printfflush("Syncing the database ... ");
409 if(!odsync(odeum)){
410 pdperror(name);
411 odclose(odeum);
412 return 1;
413 }
414 printfflush("ok\n");
415 printfflush("Overwriting 1 - 10 documents ... ");
416 for(i = 1; i <= 10; i++){
417 sprintf(buf, "%08d", i);
418 doc = makedoc(i, 120 + myrand() % 160, myrand() % 500 + 500);
419 if(!odput(odeum, doc, 180 + myrand() % 40, TRUE)){
420 pdperror(name);
421 oddocclose(doc);
422 odclose(odeum);
423 return 1;
424 }
425 oddocclose(doc);
426 }
427 printfflush("ok\n");
428 printfflush("Deleting 11 - 20 documents ... ");
429 for(i = 11; i <= 20; i++){
430 sprintf(buf, "%08d", i);
431 if(!odout(odeum, buf)){
432 pdperror(name);
433 odclose(odeum);
434 return 1;
435 }
436 }
437 printfflush("ok\n");
438 printfflush("Checking documents ... ");
439 for(i = 1; i <= 10; i++){
440 sprintf(buf, "%08d", i);
441 if(!(doc = odget(odeum, buf))){
442 pdperror(name);
443 return 1;
444 }
445 nwords = oddocnwords(doc);
446 awords = oddocawords(doc);
447 if(!oddocuri(doc) || !oddocgetattr(doc, "title") || cblistnum(nwords) != cblistnum(awords)){
448 fprintf(stderr, "%s: %s: invalid document\n", progname, name);
449 oddocclose(doc);
450 odclose(odeum);
451 return 1;
452 }
453 for(j = 0; j < cblistnum(nwords); j++){
454 if(strcmp(cblistval(nwords, j, NULL), cblistval(nwords, j, NULL))){
455 fprintf(stderr, "%s: %s: invalid words\n", progname, name);
456 oddocclose(doc);
457 odclose(odeum);
458 return 1;
459 }
460 }
461 oddocclose(doc);
462 }
463 if(oddnum(odeum) != 10){
464 fprintf(stderr, "%s: %s: invalid document number\n", progname, name);
465 odclose(odeum);
466 return 1;
467 }
468 printfflush("ok\n");
469 printfflush("Optimizing the database ... ");
470 if(!odoptimize(odeum)){
471 pdperror(name);
472 odclose(odeum);
473 return 1;
474 }
475 printfflush("ok\n");
476 printfflush("Adding 10 documents including about 200 words ... ");
477 for(i = 11; i <= 20; i++){
478 sprintf(buf, "%08d", i);
479 doc = makedoc(i, 120 + myrand() % 160, myrand() % 500 + 500);
480 if(!odput(odeum, doc, 180 + myrand() % 40, FALSE)){
481 pdperror(name);
482 oddocclose(doc);
483 odclose(odeum);
484 return 1;
485 }
486 oddocclose(doc);
487 }
488 printfflush("ok\n");
489 printfflush("Deleting 6 - 15 documents ... ");
490 for(i = 6; i <= 15; i++){
491 sprintf(buf, "%08d", i);
492 if(!odout(odeum, buf)){
493 pdperror(name);
494 odclose(odeum);
495 return 1;
496 }
497 }
498 printfflush("ok\n");
499 printfflush("Retrieving documents 100 times ... ");
500 for(i = 1; i <= 100; i++){
501 sprintf(buf, "%08d", myrand() % 1000 + 1);
502 if((pairs = odsearch(odeum, buf, -1, &pnum)) != NULL){
503 for(j = 0; j < pnum; j++){
504 if((doc = odgetbyid(odeum, pairs[j].id)) != NULL){
505 oddocclose(doc);
506 } else if(dpecode != DP_ENOITEM){
507 pdperror(name);
508 odclose(odeum);
509 return 1;
510 }
511 }
512 free(pairs);
513 } else if(dpecode != DP_ENOITEM){
514 pdperror(name);
515 odclose(odeum);
516 return 1;
517 }
518 }
519 printfflush("ok\n");
520 printfflush("Analyzing text ... ");
521 tawords = cblistopen();
522 tnwords = cblistopen();
523 odanalyzetext(odeum, "I'd like to ++see++ Mr. X-men tomorrow.", tawords, tnwords);
524 odanalyzetext(odeum, "=== :-) SMILE . @ . SAD :-< ===", tawords, tnwords);
525 for(i = 0; i < DOCBUFSIZ - 1; i++){
526 buf[i] = myrand() % 255 + 1;
527 }
528 buf[DOCBUFSIZ-1] = '\0';
529 cblistclose(tnwords);
530 cblistclose(tawords);
531 for(i = 0; i < 1000; i++){
532 for(j = 0; j < DOCBUFSIZ - 1; j++){
533 if((j + 1) % 32 == 0){
534 buf[j] = ' ';
535 } else {
536 buf[j] = myrand() % 255 + 1;
537 }
538 }
539 buf[DOCBUFSIZ-1] = '\0';
540 tawords = cblistopen();
541 tnwords = cblistopen();
542 odanalyzetext(odeum, buf, tawords, tnwords);
543 oawords = odbreaktext(buf);
544 if(cblistnum(tawords) != cblistnum(oawords) || cblistnum(tnwords) != cblistnum(oawords)){
545 fprintf(stderr, "%s: %s: invalid analyzing\n", progname, name);
546 cblistclose(oawords);
547 cblistclose(tnwords);
548 cblistclose(tawords);
549 odclose(odeum);
550 return 1;
551 }
552 for(j = 0; j < cblistnum(oawords); j++){
553 asis = cblistval(oawords, j, NULL);
554 normal = odnormalizeword(asis);
555 if(strcmp(asis, cblistval(oawords, j, NULL)) || strcmp(normal, cblistval(tnwords, j, NULL))){
556 fprintf(stderr, "%s: %s: invalid analyzing\n", progname, name);
557 free(normal);
558 cblistclose(oawords);
559 cblistclose(tnwords);
560 cblistclose(tawords);
561 odclose(odeum);
562 return 1;
563 }
564 free(normal);
565 }
566 cblistclose(oawords);
567 cblistclose(tnwords);
568 cblistclose(tawords);
569 }
570 printfflush("ok\n");
571 printfflush("Closing the database ... ");
572 if(!odclose(odeum)){
573 pdperror(name);
574 return 1;
575 }
576 printfflush("ok\n");
577 printfflush("all ok\n\n");
578 return 0;
579 }
580
581
582 /* perform wicked command */
dowicked(const char * name,int dnum)583 int dowicked(const char *name, int dnum){
584 ODEUM *odeum;
585 ODDOC *doc;
586 ODPAIR *pairs;
587 char buf[DOCBUFSIZ];
588 int i, j, pnum, err;
589 printfflush("<Wicked Writing Test>\n name=%s dnum=%d\n\n", name, dnum);
590 err = FALSE;
591 if(!(odeum = odopen(name, OD_OWRITER | OD_OCREAT | OD_OTRUNC))){
592 pdperror(name);
593 return 1;
594 }
595 for(i = 1; i <= dnum; i++){
596 switch(myrand() % 8){
597 case 1:
598 putchar('K');
599 doc = makedoc(myrand() % dnum + 1, myrand() % 10 + 10, myrand() % dnum + 500);
600 if(!odput(odeum, doc, 5, FALSE) && dpecode != DP_EKEEP) err = TRUE;
601 oddocclose(doc);
602 break;
603 case 3:
604 putchar('D');
605 if(!odoutbyid(odeum, myrand() % dnum + 1) && dpecode != DP_ENOITEM) err = TRUE;
606 break;
607 case 4:
608 putchar('R');
609 sprintf(buf, "%08d", myrand() % (dnum + 500) + 1);
610 if((pairs = odsearch(odeum, buf, 5, &pnum)) != NULL){
611 if(myrand() % 5 == 0){
612 for(j = 0; j < pnum; j++){
613 if((doc = odgetbyid(odeum, pairs[j].id)) != NULL){
614 oddocclose(doc);
615 } else if(dpecode != DP_ENOITEM){
616 err = TRUE;
617 break;
618 }
619 }
620 }
621 free(pairs);
622 } else if(dpecode != DP_ENOITEM){
623 err = TRUE;
624 }
625 break;
626 default:
627 putchar('O');
628 doc = makedoc(myrand() % dnum + 1, myrand() % 10 + 10, myrand() % dnum + 500);
629 if(!odput(odeum, doc, 5, TRUE)) err = TRUE;
630 oddocclose(doc);
631 break;
632 }
633 if(i % 50 == 0) printfflush(" (%08d)\n", i);
634 if(err){
635 pdperror(name);
636 break;
637 }
638 }
639 if(!odoptimize(odeum)){
640 pdperror(name);
641 err = TRUE;
642 }
643 for(i = 1; i <= dnum; i++){
644 doc = makedoc(i, 5, 5);
645 if(!odput(odeum, doc, 5, FALSE) && dpecode != DP_EKEEP){
646 pdperror(name);
647 oddocclose(doc);
648 err = TRUE;
649 break;
650 }
651 oddocclose(doc);
652 putchar(':');
653 if(i % 50 == 0) printfflush(" (%08d)\n", i);
654 }
655 if(!odoptimize(odeum)){
656 pdperror(name);
657 err = TRUE;
658 }
659 for(i = 1; i <= dnum; i++){
660 sprintf(buf, "%08d", i);
661 if(!(doc = odget(odeum, buf))){
662 pdperror(name);
663 err = TRUE;
664 break;
665 }
666 oddocclose(doc);
667 putchar('=');
668 if(i % 50 == 0) printfflush(" (%08d)\n", i);
669 }
670 if(!oditerinit(odeum)){
671 pdperror(name);
672 err = TRUE;
673 }
674 for(i = 1; i <= dnum; i++){
675 if(!(doc = oditernext(odeum))){
676 pdperror(name);
677 err = TRUE;
678 break;
679 }
680 oddocclose(doc);
681 putchar('@');
682 if(i % 50 == 0) printfflush(" (%08d)\n", i);
683 }
684 if(!odclose(odeum)){
685 pdperror(name);
686 return 1;
687 }
688 if(!err) printfflush("ok\n\n");
689 return 0;
690 }
691
692
693
694 /* END OF FILE */
695