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); |
+} |