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