#include #include #include /* #define WITH_PRINT */ static const char *seeds1[] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", NULL }; static const char *seeds2[] = { "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", NULL }; #define NB_STRINGS_NS 100 #define NB_STRINGS_MAX 10000 #define NB_STRINGS_MIN 10 static xmlChar *strings1[NB_STRINGS_MAX]; static xmlChar *strings2[NB_STRINGS_MAX]; static const xmlChar *test1[NB_STRINGS_MAX]; static const xmlChar *test2[NB_STRINGS_MAX]; static int nbErrors = 0; static void fill_strings(void) { int i, j, k; /* * That's a bit nasty but the output is fine and it doesn't take hours * there is a small but sufficient number of duplicates, and we have * ":xxx" and full QNames in the last NB_STRINGS_NS values */ for (i = 0; seeds1[i] != NULL; i++) { strings1[i] = xmlStrdup((const xmlChar *) seeds1[i]); if (strings1[i] == NULL) { fprintf(stderr, "Out of memory while generating strings1\n"); exit(1); } } for (j = 0, k = 0;i < NB_STRINGS_MAX - NB_STRINGS_NS;i++,j++) { strings1[i] = xmlStrncatNew(strings1[j], strings1[k], -1); if (strings1[i] == NULL) { fprintf(stderr, "Out of memory while generating strings1\n"); exit(1); } if (j >= 50) { j = 0; k++; } } for (j = 0; (j < 50) && (i < NB_STRINGS_MAX); i++, j+=2) { strings1[i] = xmlStrncatNew(strings1[j], (const xmlChar *) ":", -1); if (strings1[i] == NULL) { fprintf(stderr, "Out of memory while generating strings1\n"); exit(1); } } for (j = NB_STRINGS_MAX - NB_STRINGS_NS, k = 0; i < NB_STRINGS_MAX;i++,j++) { strings1[i] = xmlStrncatNew(strings1[j], strings1[k], -1); if (strings1[i] == NULL) { fprintf(stderr, "Out of memory while generating strings1\n"); exit(1); } k += 3; if (k >= 50) k = 0; } /* * Now do the same with the second pool of strings */ for (i = 0; seeds2[i] != NULL; i++) { strings2[i] = xmlStrdup((const xmlChar *) seeds2[i]); if (strings2[i] == NULL) { fprintf(stderr, "Out of memory while generating strings2\n"); exit(1); } } for (j = 0, k = 0;i < NB_STRINGS_MAX - NB_STRINGS_NS;i++,j++) { strings2[i] = xmlStrncatNew(strings2[j], strings2[k], -1); if (strings2[i] == NULL) { fprintf(stderr, "Out of memory while generating strings2\n"); exit(1); } if (j >= 50) { j = 0; k++; } } for (j = 0; (j < 50) && (i < NB_STRINGS_MAX); i++, j+=2) { strings2[i] = xmlStrncatNew(strings2[j], (const xmlChar *) ":", -1); if (strings2[i] == NULL) { fprintf(stderr, "Out of memory while generating strings2\n"); exit(1); } } for (j = NB_STRINGS_MAX - NB_STRINGS_NS, k = 0; i < NB_STRINGS_MAX;i++,j++) { strings2[i] = xmlStrncatNew(strings2[j], strings2[k], -1); if (strings2[i] == NULL) { fprintf(stderr, "Out of memory while generating strings2\n"); exit(1); } k += 3; if (k >= 50) k = 0; } } #ifdef WITH_PRINT static void print_strings(void) { int i; for (i = 0; i < NB_STRINGS_MAX;i++) { printf("%s\n", strings1[i]); } for (i = 0; i < NB_STRINGS_MAX;i++) { printf("%s\n", strings2[i]); } } #endif static void clean_strings(void) { int i; for (i = 0; i < NB_STRINGS_MAX; i++) { if (strings1[i] != NULL) /* really should not happen */ xmlFree(strings1[i]); } for (i = 0; i < NB_STRINGS_MAX; i++) { if (strings2[i] != NULL) /* really should not happen */ xmlFree(strings2[i]); } } /* * This tests the sub-dictionary support */ static int run_test2(xmlDictPtr parent) { int i, j; xmlDictPtr dict; int ret = 0; xmlChar prefix[40]; xmlChar *cur, *pref; const xmlChar *tmp; dict = xmlDictCreateSub(parent); if (dict == NULL) { fprintf(stderr, "Out of memory while creating sub-dictionary\n"); exit(1); } memset(test2, 0, sizeof(test2)); /* * Fill in NB_STRINGS_MIN, at this point the dictionary should not grow * and we allocate all those doing the fast key computations * All the strings are based on a different seeds subset so we know * they are allocated in the main dictionary, not coming from the parent */ for (i = 0;i < NB_STRINGS_MIN;i++) { test2[i] = xmlDictLookup(dict, strings2[i], -1); if (test2[i] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings2[i]); ret = 1; nbErrors++; } } j = NB_STRINGS_MAX - NB_STRINGS_NS; /* ":foo" like strings2 */ for (i = 0;i < NB_STRINGS_MIN;i++, j++) { test2[j] = xmlDictLookup(dict, strings2[j], xmlStrlen(strings2[j])); if (test2[j] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings2[j]); ret = 1; nbErrors++; } } /* "a:foo" like strings2 */ j = NB_STRINGS_MAX - NB_STRINGS_MIN; for (i = 0;i < NB_STRINGS_MIN;i++, j++) { test2[j] = xmlDictLookup(dict, strings2[j], xmlStrlen(strings2[j])); if (test2[j] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings2[j]); ret = 1; nbErrors++; } } /* * At this point allocate all the strings * the dictionary will grow in the process, reallocate more string tables * and switch to the better key generator */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (test2[i] != NULL) continue; test2[i] = xmlDictLookup(dict, strings2[i], -1); if (test2[i] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings2[i]); ret = 1; nbErrors++; } } /* * Now we can start to test things, first that all strings2 belongs to * the dict, and that none of them was actually allocated in the parent */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (!xmlDictOwns(dict, test2[i])) { fprintf(stderr, "Failed ownership failure for '%s'\n", strings2[i]); ret = 1; nbErrors++; } if (xmlDictOwns(parent, test2[i])) { fprintf(stderr, "Failed parent ownership failure for '%s'\n", strings2[i]); ret = 1; nbErrors++; } } /* * Also verify that all strings from the parent are seen from the subdict */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (!xmlDictOwns(dict, test1[i])) { fprintf(stderr, "Failed sub-ownership failure for '%s'\n", strings1[i]); ret = 1; nbErrors++; } } /* * Then that another lookup to the string in sub will return the same */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (xmlDictLookup(dict, strings2[i], -1) != test2[i]) { fprintf(stderr, "Failed re-lookup check for %d, '%s'\n", i, strings2[i]); ret = 1; nbErrors++; } } /* * But also that any lookup for a string in the parent will be provided * as in the parent */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (xmlDictLookup(dict, strings1[i], -1) != test1[i]) { fprintf(stderr, "Failed parent string lookup check for %d, '%s'\n", i, strings1[i]); ret = 1; nbErrors++; } } /* * check the QName lookups */ for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) { cur = strings2[i]; pref = &prefix[0]; while (*cur != ':') *pref++ = *cur++; cur++; *pref = 0; tmp = xmlDictQLookup(dict, &prefix[0], cur); if (tmp != test2[i]) { fprintf(stderr, "Failed lookup check for '%s':'%s'\n", &prefix[0], cur); ret = 1; nbErrors++; } } /* * check the QName lookups for strings from the parent */ for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) { cur = strings1[i]; pref = &prefix[0]; while (*cur != ':') *pref++ = *cur++; cur++; *pref = 0; tmp = xmlDictQLookup(dict, &prefix[0], cur); if (xmlDictQLookup(dict, &prefix[0], cur) != test1[i]) { fprintf(stderr, "Failed parent lookup check for '%s':'%s'\n", &prefix[0], cur); ret = 1; nbErrors++; } } xmlDictFree(dict); return(ret); } /* * Test a single dictionary */ static int run_test1(void) { int i, j; xmlDictPtr dict; int ret = 0; xmlChar prefix[40]; xmlChar *cur, *pref; const xmlChar *tmp; dict = xmlDictCreate(); if (dict == NULL) { fprintf(stderr, "Out of memory while creating dictionary\n"); exit(1); } memset(test1, 0, sizeof(test1)); /* * Fill in NB_STRINGS_MIN, at this point the dictionary should not grow * and we allocate all those doing the fast key computations */ for (i = 0;i < NB_STRINGS_MIN;i++) { test1[i] = xmlDictLookup(dict, strings1[i], -1); if (test1[i] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings1[i]); ret = 1; nbErrors++; } } j = NB_STRINGS_MAX - NB_STRINGS_NS; /* ":foo" like strings1 */ for (i = 0;i < NB_STRINGS_MIN;i++, j++) { test1[j] = xmlDictLookup(dict, strings1[j], xmlStrlen(strings1[j])); if (test1[j] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings1[j]); ret = 1; nbErrors++; } } /* "a:foo" like strings1 */ j = NB_STRINGS_MAX - NB_STRINGS_MIN; for (i = 0;i < NB_STRINGS_MIN;i++, j++) { test1[j] = xmlDictLookup(dict, strings1[j], xmlStrlen(strings1[j])); if (test1[j] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings1[j]); ret = 1; nbErrors++; } } /* * At this point allocate all the strings * the dictionary will grow in the process, reallocate more string tables * and switch to the better key generator */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (test1[i] != NULL) continue; test1[i] = xmlDictLookup(dict, strings1[i], -1); if (test1[i] == NULL) { fprintf(stderr, "Failed lookup for '%s'\n", strings1[i]); ret = 1; nbErrors++; } } /* * Now we can start to test things, first that all strings1 belongs to * the dict */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (!xmlDictOwns(dict, test1[i])) { fprintf(stderr, "Failed ownership failure for '%s'\n", strings1[i]); ret = 1; nbErrors++; } } /* * Then that another lookup to the string will return the same */ for (i = 0;i < NB_STRINGS_MAX;i++) { if (xmlDictLookup(dict, strings1[i], -1) != test1[i]) { fprintf(stderr, "Failed re-lookup check for %d, '%s'\n", i, strings1[i]); ret = 1; nbErrors++; } } /* * More complex, check the QName lookups */ for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) { cur = strings1[i]; pref = &prefix[0]; while (*cur != ':') *pref++ = *cur++; cur++; *pref = 0; tmp = xmlDictQLookup(dict, &prefix[0], cur); if (tmp != test1[i]) { fprintf(stderr, "Failed lookup check for '%s':'%s'\n", &prefix[0], cur); ret = 1; nbErrors++; } } run_test2(dict); xmlDictFree(dict); return(ret); } int main(void) { int ret; LIBXML_TEST_VERSION fill_strings(); #ifdef WITH_PRINT print_strings(); #endif ret = run_test1(); if (ret == 0) { printf("dictionary tests succeeded %d strings\n", 2 * NB_STRINGS_MAX); } else { printf("dictionary tests failed with %d errors\n", nbErrors); } clean_strings(); xmlCleanupParser(); xmlMemoryDump(); return(ret); }