Using plain char instead of unsigned char in my tests.
[yaz-moved-to-github.git] / test / nfatest1.c
1 /*  Copyright (C) 2006, Index Data ApS
2  *  See the file LICENSE for details.
3  *
4  *  $Id: nfatest1.c,v 1.8 2006-10-09 14:22:44 heikki Exp $
5  *
6  */
7
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <yaz/nfa.h>
12 #include <yaz/nmem.h>
13 #include <yaz/test.h>
14
15
16 char *printfunc(void *result) {
17     static char buf[200];
18     sprintf(buf, "\"%s\"", (char*) result);
19     return buf;
20 }
21
22 char *printfunc2(void *result) {
23     static char buf[200];
24     sprintf(buf,"(%p)",  result);
25     return buf;
26 }
27
28 void test_match(yaz_nfa *n, 
29         yaz_nfa_char *buf, size_t buflen, 
30         int expcode, char *expstr) {
31     yaz_nfa_char *c = buf;
32     yaz_nfa_char *cp1, *cp2;
33     void *resptr = 0;
34     int i, bi;
35     size_t buflen2 = buflen;
36     i = yaz_nfa_match(n,&c, &buflen2,&resptr);
37     if (yaz_test_get_verbosity()>3)
38         printf("\n'%s' returned %d. Moved c by %ld, and resulted in '%s'\n",
39             expstr, i, (long)(c-buf),(char*)resptr);
40     YAZ_CHECK_EQ(buflen-buflen2, c-buf);
41     YAZ_CHECK_EQ(i, expcode);
42     if (i==0)
43         YAZ_CHECK_EQ(strcmp(expstr,(char*)resptr), 0);
44     i = 0;
45     bi = 0;
46     while((bi!=2) && (yaz_test_get_verbosity()>3)){
47         bi = yaz_nfa_get_backref(n, i,&cp1,&cp2);
48         if (bi==0 && ( cp1 || cp2 ) ) {
49             printf("  got backref %d of %ld chars (%p to %p): '",
50                     i, (long)(cp2-cp1+1), cp1, cp2);
51             while (cp2-cp1 >= 0 )
52                 printf("%c", *cp1++);
53             printf("'\n");
54         }
55         i++;
56     }
57 }
58
59 void construction_test(void) {
60     yaz_nfa* n= yaz_nfa_init();
61     yaz_nfa_char *cp, *cp1, *cp2;
62     yaz_nfa_state *s, *s0, *s1, *s2, *s3, *s4, *s5;
63     int i;
64     yaz_nfa_char seq1[]={'p', 'r', 'e', 'f', 'i', 'x', 0};
65     yaz_nfa_char seq2[]={'p', 'r', 'e', 'l', 'i', 'm', 0};
66     yaz_nfa_char tst1[]={'c', 0};
67     yaz_nfa_char tst2[]={'c', 'k', 0};
68     yaz_nfa_char tst3[]={'c', 'x', 0};
69     yaz_nfa_char tst4[]={'z', 'k', 0};
70     yaz_nfa_char tst5[]={'y', 'k', 'l', 'k', 'k', 'l', 'k', 'd', 0};
71     yaz_nfa_char tst6[]={'x', 'z', 'k', 'a', 'b', 0};
72     void *p;
73     size_t sz;
74
75     YAZ_CHECK(n);
76
77     s = yaz_nfa_get_first(n);
78     YAZ_CHECK(!s);
79
80     s0 = yaz_nfa_add_state(n);
81
82     s = yaz_nfa_get_first(n);
83     YAZ_CHECK(s);
84     s = yaz_nfa_get_next(n, s);
85     YAZ_CHECK(!s);
86
87     s1 = yaz_nfa_add_state(n);
88     i = yaz_nfa_set_result(n, s1, "first");
89     YAZ_CHECK_EQ(i, 0);
90
91     i = yaz_nfa_set_result(n, s1, "DUPLICATE");
92     YAZ_CHECK_EQ(i, YAZ_NFA_ALREADY);
93
94     p = yaz_nfa_get_result(n, s1);
95     YAZ_CHECK(p);
96     YAZ_CHECK( strcmp((char*)p, "first")==0 );
97
98     i = yaz_nfa_set_result(n, s1, 0);
99     YAZ_CHECK_EQ(i, 0);
100     p = yaz_nfa_get_result(n, s1);
101     YAZ_CHECK(!p);
102     i = yaz_nfa_set_result(n, s1, "first");
103     YAZ_CHECK_EQ(i, 0);
104     
105     s2 = yaz_nfa_add_state(n);
106     s3 = yaz_nfa_add_state(n);
107     yaz_nfa_set_result(n, s3, "a-k, x-z");
108
109     s = yaz_nfa_get_first(n);
110     YAZ_CHECK(s);
111     s = yaz_nfa_get_next(n, s);
112     YAZ_CHECK(s);
113
114     
115     yaz_nfa_add_transition(n, s0, s1, 'a', 'k');
116     yaz_nfa_add_transition(n, s1, s1, 'k', 'k');
117     yaz_nfa_add_transition(n, s0, s2, 'p', 'p');
118     yaz_nfa_add_transition(n, s1, s3, 'x', 'z');
119
120     s = yaz_nfa_add_range(n, 0, 'k', 's' );
121     yaz_nfa_set_result(n, s, "K-S");
122
123     s4 = yaz_nfa_add_range(n, s2, 'l', 'r' );
124     s5 = yaz_nfa_add_range(n, s2, 'l', 'r' );
125     YAZ_CHECK((s4==s5));
126     s = yaz_nfa_add_range(n, 0, 'c', 'c' );
127
128     s = yaz_nfa_add_range(n, 0, 'z', 'z' );
129     yaz_nfa_add_empty_transition(n, s, s);
130     yaz_nfa_set_result(n, s, "loop");
131
132     s = yaz_nfa_add_range(n, 0, 'y', 'y' );
133     yaz_nfa_set_backref_point(n, s, 1, 1);
134     s1 = yaz_nfa_add_state(n);
135     yaz_nfa_add_empty_transition(n, s, s1);
136     s = s1;
137     yaz_nfa_add_transition(n, s, s, 'k', 'l');
138     s = yaz_nfa_add_range(n, s, 'd', 'd' );
139     yaz_nfa_set_result(n, s, "y k+ d");
140     yaz_nfa_set_backref_point(n, s, 1, 0);
141
142     s = yaz_nfa_add_sequence(n, 0, seq1,6 ); 
143     yaz_nfa_set_result(n, s, "PREFIX");
144     s = yaz_nfa_add_sequence(n, 0, seq2,6 ); 
145     yaz_nfa_set_result(n, s, "PRELIM");
146
147     s = yaz_nfa_add_range(n, 0, 'x', 'x' );
148     i=yaz_nfa_set_backref_point(n, s, 2, 0);
149     YAZ_CHECK_EQ(i,YAZ_NFA_NOSTART);
150     i=yaz_nfa_set_backref_point(n, s, 2, 1);
151     YAZ_CHECK_EQ(i,YAZ_NFA_SUCCESS);
152     i=yaz_nfa_set_backref_point(n, s, 2, 1);
153     YAZ_CHECK_EQ(i,YAZ_NFA_ALREADY);
154     s1 = yaz_nfa_add_sequence(n, s, tst4,2);
155     yaz_nfa_set_backref_point(n, s1, 2, 0);
156     yaz_nfa_set_result(n, s1, "xzk");
157
158     /* check return codes before doing any matches */
159     i = yaz_nfa_get_backref(n, 0, &cp1, &cp2 );
160     YAZ_CHECK_EQ(i, YAZ_NFA_NOMATCH);
161     i = yaz_nfa_get_backref(n, 3, &cp1, &cp2 );
162     YAZ_CHECK_EQ(i, YAZ_NFA_NOSUCHBACKREF );
163     i = yaz_nfa_get_backref(n, 1, &cp1, &cp2 );
164     YAZ_CHECK_EQ(i, YAZ_NFA_NOMATCH );
165
166     
167     if (yaz_test_get_verbosity()>3)
168         yaz_nfa_dump(0, n, printfunc);
169
170     test_match(n, seq2, 3, YAZ_NFA_OVERRUN, "K-S");
171     test_match(n, seq2, 6, YAZ_NFA_SUCCESS, "PRELIM");
172     test_match(n, tst1, 3, YAZ_NFA_SUCCESS, "first");
173     test_match(n, tst2, 3, YAZ_NFA_SUCCESS, "first");
174     test_match(n, tst3, 3, YAZ_NFA_SUCCESS, "a-k, x-z");
175     test_match(n, tst4, 9, YAZ_NFA_LOOP, "loop");
176     test_match(n, tst5, 9, YAZ_NFA_SUCCESS, "y k+ d");
177
178     cp = tst6;  /* xzkab */
179     sz = 8;
180     i = yaz_nfa_match(n, &cp, &sz, &p);
181     YAZ_CHECK_EQ(i, YAZ_NFA_SUCCESS); 
182     i = yaz_nfa_get_backref(n, 2, &cp1, &cp2 );
183     YAZ_CHECK_EQ(i, 0);
184     YAZ_CHECK_EQ(cp2-cp1+1,2); 
185     YAZ_CHECK_EQ(*cp1, 'z' );
186     YAZ_CHECK_EQ(*cp2, 'k' );
187     if (yaz_test_get_verbosity()>3)
188         printf("backref from %p '%c' to %p '%c' is %ld long. sz is now %ld\n",
189             cp1, *cp1,  cp2, *cp2,  (long)(cp2-cp1+1), (long)sz );
190
191     yaz_nfa_destroy(n);
192 }
193
194 void converter_test(void) {
195     yaz_nfa* n= yaz_nfa_init();
196     yaz_nfa_converter *c1, *c2, *c3;
197     yaz_nfa_char str1[]={'a','b','c'};
198     yaz_nfa_char seq1[]={'A','B','C'};
199     yaz_nfa_char seq2[]={'k','m','n','m','x','P','Q','X',0};
200     yaz_nfa_char outbuf[1024];
201     yaz_nfa_char *outp, *cp, *cp1, *cp2;
202     yaz_nfa_state *s, *s2;
203     void *vp;
204     int i;
205     size_t sz;
206
207     c1=yaz_nfa_create_string_converter(n,str1,3);
208
209     for(i=0;i<1024;i++)
210         outbuf[i]=10000+i;
211     outp=outbuf;
212     sz=1;
213     i=yaz_nfa_run_converters(n, c1, &outp, &sz);
214     YAZ_CHECK_EQ(i,4); /* overrun */
215     YAZ_CHECK_EQ(outbuf[0],'a');
216     YAZ_CHECK_EQ(outbuf[1],10000+1);
217
218     for(i=0;i<1024;i++)
219         outbuf[i]=10000+i;
220     outp=outbuf;
221     sz=3;
222     i=yaz_nfa_run_converters(n, c1, &outp, &sz);
223     YAZ_CHECK_EQ(i,0); 
224     YAZ_CHECK_EQ(outbuf[0],'a');
225     YAZ_CHECK_EQ(outbuf[1],'b');
226     YAZ_CHECK_EQ(outbuf[2],'c');
227     YAZ_CHECK_EQ(outbuf[3],10000+3);
228     YAZ_CHECK_EQ(sz,0);
229     
230     c2=yaz_nfa_create_string_converter(n,str1,2);
231     yaz_nfa_append_converter(n,c1,c2);
232
233     for(i=0;i<1024;i++)
234         outbuf[i]=10000+i;
235     outp=outbuf;
236     sz=10;
237     i=yaz_nfa_run_converters(n, c1, &outp, &sz);
238     YAZ_CHECK_EQ(i,0); 
239     YAZ_CHECK_EQ(outbuf[0],'a');
240     YAZ_CHECK_EQ(outbuf[1],'b');
241     YAZ_CHECK_EQ(outbuf[2],'c');
242     YAZ_CHECK_EQ(outbuf[3],'a');
243     YAZ_CHECK_EQ(outbuf[4],'b');
244     YAZ_CHECK_EQ(outbuf[5],10000+5);
245     YAZ_CHECK_EQ(sz,5);
246     
247     /* ABC -> abcab */
248     (void) yaz_nfa_add_state(n);/* start state */
249     s=yaz_nfa_add_state(n);
250     yaz_nfa_add_empty_transition(n,0,s);
251     yaz_nfa_set_backref_point(n,s,1,1);
252     s=yaz_nfa_add_sequence(n, s, seq1,3 ); 
253     yaz_nfa_set_result(n,s,c1);
254     yaz_nfa_set_backref_point(n,s,1,0);
255
256     /* ([k-o][m-n]*)x -> \1 */
257     s=yaz_nfa_add_state(n);
258     yaz_nfa_add_empty_transition(n,0,s);
259     yaz_nfa_set_backref_point(n,s,2,1);
260     s2=yaz_nfa_add_state(n);
261     yaz_nfa_add_transition(n,s,s2,'k','o');
262     yaz_nfa_add_transition(n,s2,s2,'m','n');
263     s=yaz_nfa_add_state(n);
264     yaz_nfa_add_transition(n,s2,s,'x','x');
265     yaz_nfa_set_backref_point(n,s,2,0);
266
267     c1=yaz_nfa_create_backref_converter(n,2);
268     yaz_nfa_set_result(n,s,c1);
269
270     if (yaz_test_get_verbosity()>3)
271         yaz_nfa_dump(0,n, printfunc2);
272
273     cp=seq2;
274     sz=18;
275     i=yaz_nfa_match(n,&cp,&sz,&vp);
276     c2=vp;
277     YAZ_CHECK_EQ(i,YAZ_NFA_SUCCESS); 
278     i=yaz_nfa_get_backref(n, 2, &cp1, &cp2 );
279     if (yaz_test_get_verbosity()>3)
280         printf("backref from %p '%c' to %p '%c' is %ld long. sz is now %ld\n",
281             cp1, *cp1,  cp2, *cp2,  (long)(cp2-cp1+1), (long)sz );
282     YAZ_CHECK_EQ(i,0);
283     /*YAZ_CHECK_EQ((int)c1,(int)c2);*/  /* got our pointer back from nfa */
284     YAZ_CHECK(c1==c2);  /* got our pointer back from nfa */
285     for(i=0;i<1024;i++)
286         outbuf[i]=10000+i;
287     outp=outbuf;
288     sz=11;
289     i=yaz_nfa_run_converters(n, c2, &outp, &sz);
290     YAZ_CHECK_EQ(i,0); 
291     YAZ_CHECK_EQ(outbuf[0],'k');
292     YAZ_CHECK_EQ(outbuf[1],'m');
293     YAZ_CHECK_EQ(outbuf[2],'n');
294     YAZ_CHECK_EQ(outbuf[3],'m');
295     YAZ_CHECK_EQ(outbuf[4],'x');
296     YAZ_CHECK_EQ(outbuf[5],10000+5);
297     YAZ_CHECK_EQ(sz,11-5);
298
299     c3=yaz_nfa_create_range_converter(n,2, 'a', 'A' );
300     for(i=0;i<1024;i++)
301         outbuf[i]=10000+i;
302     outp=outbuf;
303     sz=11;
304     i=yaz_nfa_run_converters(n, c3, &outp, &sz);
305     YAZ_CHECK_EQ(i,0); 
306     YAZ_CHECK_EQ(outbuf[0],'K');
307     YAZ_CHECK_EQ(outbuf[1],'M');
308     YAZ_CHECK_EQ(outbuf[2],'N');
309     YAZ_CHECK_EQ(outbuf[3],'M');
310     YAZ_CHECK_EQ(outbuf[4],'X');
311     YAZ_CHECK_EQ(outbuf[5],10000+5);
312     YAZ_CHECK_EQ(sz,11-5);
313
314     yaz_nfa_destroy(n);
315 }
316
317 yaz_nfa_char *makebuff(NMEM nmem, char *in) {
318     yaz_nfa_char *buff = nmem_malloc(nmem, strlen(in)*sizeof(yaz_nfa_char));
319     yaz_nfa_char *op=buff;
320     while ( (*op++ = *in++) )
321         ;
322     return buff;
323 }
324
325 void dumpbuff(char *msg, yaz_nfa_char *start, yaz_nfa_char *end) {
326     if (yaz_test_get_verbosity()>3) {
327         printf("%s\"",msg);
328         while (start!=end)
329             printf("%c",*start++);
330         printf("\"\n");
331     }
332 }
333
334 void chkbuff( yaz_nfa_char *start, yaz_nfa_char *end, char *exp) {
335     char *orig_exp=exp;
336     while (start!=end)
337         if ( *start++ != *exp++ ) {
338             if (yaz_test_get_verbosity()>3) {
339                 start--;
340                 exp--;
341                 printf ("chkbuff: unexpected conversion '%c' != '%c' \n"
342                         "\"%s\"\n", *start, *exp, orig_exp );
343             }
344             YAZ_CHECK(!"conversion differs! ");
345             return;
346         }
347
348 }
349
350 void high_level_test(void) {
351     NMEM nmem=nmem_create();
352     yaz_nfa_char from1[] = {'f','o','o','b','a','r'};
353     yaz_nfa_char to1[] = {'f','u','b','a','r'};
354     yaz_nfa_char tospace[] = {' '};
355     yaz_nfa_char todot[] = {'.'};
356     char *fromtext =
357             "It was a Dark and Rainy Night, when alpha and beta "
358             "fixme - FIND better names ?? !! ##  - "
359             "went out to fix the foobar "
360             "that was all foo.";
361     char *expected = 
362             "IT WAS A DARK AND RAINY NIGHT. WHEN ALPHA AND b "
363             "to-be-fixed-later . FIND BETTER NAMES .. .. ..  . "
364             "WENT OUT TO (fix) THE fubar "
365             "THAT WAS ALL FOO.";
366     yaz_nfa_char *from3 = makebuff(nmem,fromtext);
367     yaz_nfa_char *to3 = nmem_malloc(nmem, 1024*sizeof(yaz_nfa_char));
368     yaz_nfa_char *fromp=from3;
369     yaz_nfa_char *top=to3;
370     size_t insize=strlen(fromtext);
371     size_t outsize=1024;
372     size_t prev_insize=0;
373
374     yaz_nfa *n = yaz_nfa_init();
375     int i;
376     i = yaz_nfa_add_string_rule(n, from1, 6, to1, 5);
377     YAZ_CHECK_EQ(i,0);
378     i = yaz_nfa_add_string_rule(n, from1, 6, to1, 5);
379     YAZ_CHECK_EQ(i,YAZ_NFA_ALREADY);
380     i = yaz_nfa_add_ascii_string_rule(n,"beta","b");
381     YAZ_CHECK_EQ(i,0);
382     i = yaz_nfa_add_ascii_string_rule(n,"fixme","to-be-fixed-later");
383     YAZ_CHECK_EQ(i,0);
384     i = yaz_nfa_add_ascii_string_rule(n,"fix","(fix)");
385     YAZ_CHECK_EQ(i,0);
386     i = yaz_nfa_add_char_range_rule(n, 'a','z','A');
387     YAZ_CHECK_EQ(i,0);
388     i = yaz_nfa_add_char_string_rule(n, 0,' ', tospace,1);
389     YAZ_CHECK_EQ(i,0);
390     i = yaz_nfa_add_char_string_rule(n, '!','/', todot,1);
391     YAZ_CHECK_EQ(i,0);
392     i = yaz_nfa_add_char_string_rule(n, ':','?', todot,1);
393     YAZ_CHECK_EQ(i,0);
394     if (yaz_test_get_verbosity()>3)
395         yaz_nfa_dump(0,n, printfunc2);
396
397     YAZ_CHECK_EQ( *from3, 'I' ); /* just to be sure my copy func works */
398     for (i=0;i<100;i++)
399         to3[i]=10000+i;
400     i=yaz_nfa_convert_slice(n, &fromp, &insize, &top, &outsize);
401     YAZ_CHECK_EQ(i,YAZ_NFA_SUCCESS);
402     YAZ_CHECK_EQ(*to3,'I');
403     YAZ_CHECK_EQ(insize, strlen(fromtext)-1);
404     YAZ_CHECK_EQ(outsize, 1024-1);
405
406     while ( (i==YAZ_NFA_SUCCESS) && (insize > 0) && (prev_insize!=insize) ) {
407         prev_insize=insize; /* detect dead loops if something goes wrong */
408         i=yaz_nfa_convert_slice(n, &fromp, &insize, &top, &outsize);
409     }
410     YAZ_CHECK_EQ(i,YAZ_NFA_SUCCESS);
411     YAZ_CHECK_EQ(insize,0);
412     YAZ_CHECK(prev_insize != insize); /* the loop would have been endless */
413
414     dumpbuff("Original text: ",from3, fromp);
415     dumpbuff("Converted text: ",to3, top);
416
417     chkbuff(to3, top, expected);
418
419     yaz_nfa_destroy(n);
420     nmem_destroy(nmem);
421 }
422
423 int main(int argc, char **argv)
424 {
425     YAZ_CHECK_INIT(argc, argv);
426     nmem_init ();
427     construction_test(); 
428     converter_test();
429     high_level_test();
430     nmem_exit ();
431     YAZ_CHECK_TERM;
432 }
433
434
435 /* 
436  * Local variables:
437  * c-basic-offset: 4
438  * indent-tabs-mode: nil
439  * End:
440  * vim: shiftwidth=4 tabstop=8 expandtab
441  */