| Index: third_party/libxml/src/testdict.c
|
| diff --git a/third_party/libxml/src/testdict.c b/third_party/libxml/src/testdict.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..4e8581f85c3e7fef8488de1089140f3ae6db35d5
|
| --- /dev/null
|
| +++ b/third_party/libxml/src/testdict.c
|
| @@ -0,0 +1,444 @@
|
| +#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 (xmlDictQLookup(dict, &prefix[0], cur) != 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 (xmlDictQLookup(dict, &prefix[0], cur) != 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);
|
| +}
|
|
|