You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
444 lines
11 KiB
444 lines
11 KiB
#include <string.h> |
|
#include <libxml/parser.h> |
|
#include <libxml/dict.h> |
|
|
|
/* #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); |
|
}
|
|
|