testdict.c 11 KB

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