/ libxml2 / testdict.c
testdict.c
  1  #include <string.h>
  2  #include <libxml/parser.h>
  3  #include <libxml/dict.h>
  4  
  5  /* #define WITH_PRINT */
  6  
  7  static const char *seeds1[] = {
  8     "a", "b", "c",
  9     "d", "e", "f",
 10     "g", "h", "i",
 11     "j", "k", "l",
 12  
 13     NULL
 14  };
 15  
 16  static const char *seeds2[] = {
 17     "m", "n", "o",
 18     "p", "q", "r",
 19     "s", "t", "u",
 20     "v", "w", "x",
 21  
 22     NULL
 23  };
 24  
 25  #define NB_STRINGS_NS 100
 26  #define NB_STRINGS_MAX 10000
 27  #define NB_STRINGS_MIN 10
 28  
 29  static xmlChar *strings1[NB_STRINGS_MAX];
 30  static xmlChar *strings2[NB_STRINGS_MAX];
 31  static const xmlChar *test1[NB_STRINGS_MAX];
 32  static const xmlChar *test2[NB_STRINGS_MAX];
 33  static int nbErrors = 0;
 34  
 35  static void fill_strings(void) {
 36      int i, j, k;
 37  
 38      /*
 39       * That's a bit nasty but the output is fine and it doesn't take hours
 40       * there is a small but sufficient number of duplicates, and we have
 41       * ":xxx" and full QNames in the last NB_STRINGS_NS values
 42       */
 43      for (i = 0; seeds1[i] != NULL; i++) {
 44          strings1[i] = xmlStrdup((const xmlChar *) seeds1[i]);
 45  	if (strings1[i] == NULL) {
 46  	    fprintf(stderr, "Out of memory while generating strings1\n");
 47  	    exit(1);
 48  	}
 49      }
 50      for (j = 0, k = 0;i < NB_STRINGS_MAX - NB_STRINGS_NS;i++,j++) {
 51          strings1[i] = xmlStrncatNew(strings1[j], strings1[k], -1);
 52  	if (strings1[i] == NULL) {
 53  	    fprintf(stderr, "Out of memory while generating strings1\n");
 54  	    exit(1);
 55  	}
 56  	if (j >= 50) {
 57  	    j = 0;
 58  	    k++;
 59  	}
 60      }
 61      for (j = 0; (j < 50) && (i < NB_STRINGS_MAX); i++, j+=2) {
 62          strings1[i] = xmlStrncatNew(strings1[j], (const xmlChar *) ":", -1);
 63  	if (strings1[i] == NULL) {
 64  	    fprintf(stderr, "Out of memory while generating strings1\n");
 65  	    exit(1);
 66  	}
 67      }
 68      for (j = NB_STRINGS_MAX - NB_STRINGS_NS, k = 0;
 69           i < NB_STRINGS_MAX;i++,j++) {
 70          strings1[i] = xmlStrncatNew(strings1[j], strings1[k], -1);
 71  	if (strings1[i] == NULL) {
 72  	    fprintf(stderr, "Out of memory while generating strings1\n");
 73  	    exit(1);
 74  	}
 75  	k += 3;
 76  	if (k >= 50) k = 0;
 77      }
 78  
 79      /*
 80       * Now do the same with the second pool of strings
 81       */
 82      for (i = 0; seeds2[i] != NULL; i++) {
 83          strings2[i] = xmlStrdup((const xmlChar *) seeds2[i]);
 84  	if (strings2[i] == NULL) {
 85  	    fprintf(stderr, "Out of memory while generating strings2\n");
 86  	    exit(1);
 87  	}
 88      }
 89      for (j = 0, k = 0;i < NB_STRINGS_MAX - NB_STRINGS_NS;i++,j++) {
 90          strings2[i] = xmlStrncatNew(strings2[j], strings2[k], -1);
 91  	if (strings2[i] == NULL) {
 92  	    fprintf(stderr, "Out of memory while generating strings2\n");
 93  	    exit(1);
 94  	}
 95  	if (j >= 50) {
 96  	    j = 0;
 97  	    k++;
 98  	}
 99      }
100      for (j = 0; (j < 50) && (i < NB_STRINGS_MAX); i++, j+=2) {
101          strings2[i] = xmlStrncatNew(strings2[j], (const xmlChar *) ":", -1);
102  	if (strings2[i] == NULL) {
103  	    fprintf(stderr, "Out of memory while generating strings2\n");
104  	    exit(1);
105  	}
106      }
107      for (j = NB_STRINGS_MAX - NB_STRINGS_NS, k = 0;
108           i < NB_STRINGS_MAX;i++,j++) {
109          strings2[i] = xmlStrncatNew(strings2[j], strings2[k], -1);
110  	if (strings2[i] == NULL) {
111  	    fprintf(stderr, "Out of memory while generating strings2\n");
112  	    exit(1);
113  	}
114  	k += 3;
115  	if (k >= 50) k = 0;
116      }
117  
118  }
119  
120  #ifdef WITH_PRINT
121  static void print_strings(void) {
122      int i;
123  
124      for (i = 0; i < NB_STRINGS_MAX;i++) {
125          printf("%s\n", strings1[i]);
126      }
127      for (i = 0; i < NB_STRINGS_MAX;i++) {
128          printf("%s\n", strings2[i]);
129      }
130  }
131  #endif
132  
133  static void clean_strings(void) {
134      int i;
135  
136      for (i = 0; i < NB_STRINGS_MAX; i++) {
137          if (strings1[i] != NULL) /* really should not happen */
138  	    xmlFree(strings1[i]);
139      }
140      for (i = 0; i < NB_STRINGS_MAX; i++) {
141          if (strings2[i] != NULL) /* really should not happen */
142  	    xmlFree(strings2[i]);
143      }
144  }
145  
146  /*
147   * This tests the sub-dictionary support
148   */
149  static int run_test2(xmlDictPtr parent) {
150      int i, j;
151      xmlDictPtr dict;
152      int ret = 0;
153      xmlChar prefix[40];
154      xmlChar *cur, *pref;
155      const xmlChar *tmp;
156  
157      dict = xmlDictCreateSub(parent);
158      if (dict == NULL) {
159  	fprintf(stderr, "Out of memory while creating sub-dictionary\n");
160  	exit(1);
161      }
162      memset(test2, 0, sizeof(test2));
163  
164      /*
165       * Fill in NB_STRINGS_MIN, at this point the dictionary should not grow
166       * and we allocate all those doing the fast key computations
167       * All the strings are based on a different seeds subset so we know
168       * they are allocated in the main dictionary, not coming from the parent
169       */
170      for (i = 0;i < NB_STRINGS_MIN;i++) {
171          test2[i] = xmlDictLookup(dict, strings2[i], -1);
172  	if (test2[i] == NULL) {
173  	    fprintf(stderr, "Failed lookup for '%s'\n", strings2[i]);
174  	    ret = 1;
175  	    nbErrors++;
176  	}
177      }
178      j = NB_STRINGS_MAX - NB_STRINGS_NS;
179      /* ":foo" like strings2 */
180      for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
181          test2[j] = xmlDictLookup(dict, strings2[j], xmlStrlen(strings2[j]));
182  	if (test2[j] == NULL) {
183  	    fprintf(stderr, "Failed lookup for '%s'\n", strings2[j]);
184  	    ret = 1;
185  	    nbErrors++;
186  	}
187      }
188      /* "a:foo" like strings2 */
189      j = NB_STRINGS_MAX - NB_STRINGS_MIN;
190      for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
191          test2[j] = xmlDictLookup(dict, strings2[j], xmlStrlen(strings2[j]));
192  	if (test2[j] == NULL) {
193  	    fprintf(stderr, "Failed lookup for '%s'\n", strings2[j]);
194  	    ret = 1;
195  	    nbErrors++;
196  	}
197      }
198  
199      /*
200       * At this point allocate all the strings
201       * the dictionary will grow in the process, reallocate more string tables
202       * and switch to the better key generator
203       */
204      for (i = 0;i < NB_STRINGS_MAX;i++) {
205          if (test2[i] != NULL)
206  	    continue;
207  	test2[i] = xmlDictLookup(dict, strings2[i], -1);
208  	if (test2[i] == NULL) {
209  	    fprintf(stderr, "Failed lookup for '%s'\n", strings2[i]);
210  	    ret = 1;
211  	    nbErrors++;
212  	}
213      }
214  
215      /*
216       * Now we can start to test things, first that all strings2 belongs to
217       * the dict, and that none of them was actually allocated in the parent
218       */
219      for (i = 0;i < NB_STRINGS_MAX;i++) {
220          if (!xmlDictOwns(dict, test2[i])) {
221  	    fprintf(stderr, "Failed ownership failure for '%s'\n",
222  	            strings2[i]);
223  	    ret = 1;
224  	    nbErrors++;
225  	}
226          if (xmlDictOwns(parent, test2[i])) {
227  	    fprintf(stderr, "Failed parent ownership failure for '%s'\n",
228  	            strings2[i]);
229  	    ret = 1;
230  	    nbErrors++;
231  	}
232      }
233  
234      /*
235       * Also verify that all strings from the parent are seen from the subdict
236       */
237      for (i = 0;i < NB_STRINGS_MAX;i++) {
238          if (!xmlDictOwns(dict, test1[i])) {
239  	    fprintf(stderr, "Failed sub-ownership failure for '%s'\n",
240  	            strings1[i]);
241  	    ret = 1;
242  	    nbErrors++;
243  	}
244      }
245  
246      /*
247       * Then that another lookup to the string in sub will return the same
248       */
249      for (i = 0;i < NB_STRINGS_MAX;i++) {
250          if (xmlDictLookup(dict, strings2[i], -1) != test2[i]) {
251  	    fprintf(stderr, "Failed re-lookup check for %d, '%s'\n",
252  	            i, strings2[i]);
253  	    ret = 1;
254  	    nbErrors++;
255  	}
256      }
257      /*
258       * But also that any lookup for a string in the parent will be provided
259       * as in the parent
260       */
261      for (i = 0;i < NB_STRINGS_MAX;i++) {
262          if (xmlDictLookup(dict, strings1[i], -1) != test1[i]) {
263  	    fprintf(stderr, "Failed parent string lookup check for %d, '%s'\n",
264  	            i, strings1[i]);
265  	    ret = 1;
266  	    nbErrors++;
267  	}
268      }
269  
270      /*
271       * check the QName lookups
272       */
273      for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) {
274          cur = strings2[i];
275  	pref = &prefix[0];
276  	while (*cur != ':') *pref++ = *cur++;
277  	cur++;
278  	*pref = 0;
279  	tmp = xmlDictQLookup(dict, &prefix[0], cur);
280  	if (tmp != test2[i]) {
281  	    fprintf(stderr, "Failed lookup check for '%s':'%s'\n",
282  	            &prefix[0], cur);
283              ret = 1;
284  	    nbErrors++;
285  	}
286      }
287      /*
288       * check the QName lookups for strings from the parent
289       */
290      for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) {
291          cur = strings1[i];
292  	pref = &prefix[0];
293  	while (*cur != ':') *pref++ = *cur++;
294  	cur++;
295  	*pref = 0;
296  	tmp = xmlDictQLookup(dict, &prefix[0], cur);
297  	if (xmlDictQLookup(dict, &prefix[0], cur) != test1[i]) {
298  	    fprintf(stderr, "Failed parent lookup check for '%s':'%s'\n",
299  	            &prefix[0], cur);
300              ret = 1;
301  	    nbErrors++;
302  	}
303      }
304  
305      xmlDictFree(dict);
306      return(ret);
307  }
308  
309  /*
310   * Test a single dictionary
311   */
312  static int run_test1(void) {
313      int i, j;
314      xmlDictPtr dict;
315      int ret = 0;
316      xmlChar prefix[40];
317      xmlChar *cur, *pref;
318      const xmlChar *tmp;
319  
320      dict = xmlDictCreate();
321      if (dict == NULL) {
322  	fprintf(stderr, "Out of memory while creating dictionary\n");
323  	exit(1);
324      }
325      memset(test1, 0, sizeof(test1));
326  
327      /*
328       * Fill in NB_STRINGS_MIN, at this point the dictionary should not grow
329       * and we allocate all those doing the fast key computations
330       */
331      for (i = 0;i < NB_STRINGS_MIN;i++) {
332          test1[i] = xmlDictLookup(dict, strings1[i], -1);
333  	if (test1[i] == NULL) {
334  	    fprintf(stderr, "Failed lookup for '%s'\n", strings1[i]);
335  	    ret = 1;
336  	    nbErrors++;
337  	}
338      }
339      j = NB_STRINGS_MAX - NB_STRINGS_NS;
340      /* ":foo" like strings1 */
341      for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
342          test1[j] = xmlDictLookup(dict, strings1[j], xmlStrlen(strings1[j]));
343  	if (test1[j] == NULL) {
344  	    fprintf(stderr, "Failed lookup for '%s'\n", strings1[j]);
345  	    ret = 1;
346  	    nbErrors++;
347  	}
348      }
349      /* "a:foo" like strings1 */
350      j = NB_STRINGS_MAX - NB_STRINGS_MIN;
351      for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
352          test1[j] = xmlDictLookup(dict, strings1[j], xmlStrlen(strings1[j]));
353  	if (test1[j] == NULL) {
354  	    fprintf(stderr, "Failed lookup for '%s'\n", strings1[j]);
355  	    ret = 1;
356  	    nbErrors++;
357  	}
358      }
359  
360      /*
361       * At this point allocate all the strings
362       * the dictionary will grow in the process, reallocate more string tables
363       * and switch to the better key generator
364       */
365      for (i = 0;i < NB_STRINGS_MAX;i++) {
366          if (test1[i] != NULL)
367  	    continue;
368  	test1[i] = xmlDictLookup(dict, strings1[i], -1);
369  	if (test1[i] == NULL) {
370  	    fprintf(stderr, "Failed lookup for '%s'\n", strings1[i]);
371  	    ret = 1;
372  	    nbErrors++;
373  	}
374      }
375  
376      /*
377       * Now we can start to test things, first that all strings1 belongs to
378       * the dict
379       */
380      for (i = 0;i < NB_STRINGS_MAX;i++) {
381          if (!xmlDictOwns(dict, test1[i])) {
382  	    fprintf(stderr, "Failed ownership failure for '%s'\n",
383  	            strings1[i]);
384  	    ret = 1;
385  	    nbErrors++;
386  	}
387      }
388  
389      /*
390       * Then that another lookup to the string will return the same
391       */
392      for (i = 0;i < NB_STRINGS_MAX;i++) {
393          if (xmlDictLookup(dict, strings1[i], -1) != test1[i]) {
394  	    fprintf(stderr, "Failed re-lookup check for %d, '%s'\n",
395  	            i, strings1[i]);
396  	    ret = 1;
397  	    nbErrors++;
398  	}
399      }
400  
401      /*
402       * More complex, check the QName lookups
403       */
404      for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) {
405          cur = strings1[i];
406  	pref = &prefix[0];
407  	while (*cur != ':') *pref++ = *cur++;
408  	cur++;
409  	*pref = 0;
410  	tmp = xmlDictQLookup(dict, &prefix[0], cur);
411  	if (tmp != test1[i]) {
412  	    fprintf(stderr, "Failed lookup check for '%s':'%s'\n",
413  	            &prefix[0], cur);
414              ret = 1;
415  	    nbErrors++;
416  	}
417      }
418  
419      run_test2(dict);
420  
421      xmlDictFree(dict);
422      return(ret);
423  }
424  
425  int main(void)
426  {
427      int ret;
428  
429      LIBXML_TEST_VERSION
430      fill_strings();
431  #ifdef WITH_PRINT
432      print_strings();
433  #endif
434      ret = run_test1();
435      if (ret == 0) {
436          printf("dictionary tests succeeded %d strings\n", 2 * NB_STRINGS_MAX);
437      } else {
438          printf("dictionary tests failed with %d errors\n", nbErrors);
439      }
440      clean_strings();
441      xmlCleanupParser();
442      xmlMemoryDump();
443      return(ret);
444  }