Audio plugin host https://kx.studio/carla
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.

serd_test.c 22KB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. /*
  2. Copyright 2011-2016 David Robillard <http://drobilla.net>
  3. Permission to use, copy, modify, and/or distribute this software for any
  4. purpose with or without fee is hereby granted, provided that the above
  5. copyright notice and this permission notice appear in all copies.
  6. THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  7. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  8. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  9. ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  10. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  11. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  12. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  13. */
  14. #include <float.h>
  15. #include <math.h>
  16. #include <stdarg.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include "serd/serd.h"
  21. #define USTR(s) ((const uint8_t*)(s))
  22. #ifndef INFINITY
  23. # define INFINITY (DBL_MAX + DBL_MAX)
  24. #endif
  25. #ifndef NAN
  26. # define NAN (INFINITY - INFINITY)
  27. #endif
  28. static int
  29. failure(const char* fmt, ...)
  30. {
  31. va_list args;
  32. va_start(args, fmt);
  33. fprintf(stderr, "error: ");
  34. vfprintf(stderr, fmt, args);
  35. va_end(args);
  36. return 1;
  37. }
  38. static bool
  39. test_strtod(double dbl, double max_delta)
  40. {
  41. char buf[1024];
  42. snprintf(buf, sizeof(buf), "%f", dbl);
  43. char* endptr = NULL;
  44. const double out = serd_strtod(buf, &endptr);
  45. const double diff = fabs(out - dbl);
  46. if (diff > max_delta) {
  47. return !failure("Parsed %lf != %lf (delta %lf)\n", dbl, out, diff);
  48. }
  49. return true;
  50. }
  51. static SerdStatus
  52. count_prefixes(void* handle, const SerdNode* name, const SerdNode* uri)
  53. {
  54. ++*(int*)handle;
  55. return SERD_SUCCESS;
  56. }
  57. typedef struct {
  58. int n_statements;
  59. const SerdNode* graph;
  60. } ReaderTest;
  61. static SerdStatus
  62. test_sink(void* handle,
  63. SerdStatementFlags flags,
  64. const SerdNode* graph,
  65. const SerdNode* subject,
  66. const SerdNode* predicate,
  67. const SerdNode* object,
  68. const SerdNode* object_datatype,
  69. const SerdNode* object_lang)
  70. {
  71. ReaderTest* rt = (ReaderTest*)handle;
  72. ++rt->n_statements;
  73. rt->graph = graph;
  74. return SERD_SUCCESS;
  75. }
  76. int
  77. main(void)
  78. {
  79. #define MAX 1000000
  80. #define NUM_TESTS 1000
  81. for (int i = 0; i < NUM_TESTS; ++i) {
  82. double dbl = rand() % MAX;
  83. dbl += (rand() % MAX) / (double)MAX;
  84. if (!test_strtod(dbl, 1 / (double)MAX)) {
  85. return 1;
  86. }
  87. }
  88. const double expt_test_nums[] = {
  89. 2.0E18, -5e19, +8e20, 2e+24, -5e-5, 8e0, 9e-0, 2e+0
  90. };
  91. const char* expt_test_strs[] = {
  92. "02e18", "-5e019", "+8e20", "2E+24", "-5E-5", "8E0", "9e-0", " 2e+0"
  93. };
  94. for (unsigned i = 0; i < sizeof(expt_test_nums) / sizeof(double); ++i) {
  95. const double num = serd_strtod(expt_test_strs[i], NULL);
  96. const double delta = fabs(num - expt_test_nums[i]);
  97. if (delta > DBL_EPSILON) {
  98. return failure("Parsed `%s' %lf != %lf (delta %lf)\n",
  99. expt_test_strs[i], num, expt_test_nums[i], delta);
  100. }
  101. }
  102. // Test serd_node_new_decimal
  103. const double dbl_test_nums[] = {
  104. 0.0, 9.0, 10.0, .01, 2.05, -16.00001, 5.000000005, 0.0000000001, NAN, INFINITY
  105. };
  106. const char* dbl_test_strs[] = {
  107. "0.0", "9.0", "10.0", "0.01", "2.05", "-16.00001", "5.00000001", "0.0", NULL, NULL
  108. };
  109. for (unsigned i = 0; i < sizeof(dbl_test_nums) / sizeof(double); ++i) {
  110. SerdNode node = serd_node_new_decimal(dbl_test_nums[i], 8);
  111. const bool pass = (node.buf && dbl_test_strs[i])
  112. ? !strcmp((const char*)node.buf, (const char*)dbl_test_strs[i])
  113. : ((const char*)node.buf == dbl_test_strs[i]);
  114. if (!pass) {
  115. return failure("Serialised `%s' != %s\n",
  116. node.buf, dbl_test_strs[i]);
  117. }
  118. const size_t len = node.buf ? strlen((const char*)node.buf) : 0;
  119. if (node.n_bytes != len || node.n_chars != len) {
  120. return failure("Length %zu,%zu != %zu\n",
  121. node.n_bytes, node.n_chars, len);
  122. }
  123. serd_node_free(&node);
  124. }
  125. // Test serd_node_new_integer
  126. const long int_test_nums[] = {
  127. 0, -0, -23, 23, -12340, 1000, -1000
  128. };
  129. const char* int_test_strs[] = {
  130. "0", "0", "-23", "23", "-12340", "1000", "-1000"
  131. };
  132. for (unsigned i = 0; i < sizeof(int_test_nums) / sizeof(double); ++i) {
  133. SerdNode node = serd_node_new_integer(int_test_nums[i]);
  134. if (strcmp((const char*)node.buf, (const char*)int_test_strs[i])) {
  135. return failure("Serialised `%s' != %s\n",
  136. node.buf, int_test_strs[i]);
  137. }
  138. const size_t len = strlen((const char*)node.buf);
  139. if (node.n_bytes != len || node.n_chars != len) {
  140. return failure("Length %zu,%zu != %zu\n",
  141. node.n_bytes, node.n_chars, len);
  142. }
  143. serd_node_free(&node);
  144. }
  145. // Test serd_node_new_blob
  146. for (size_t size = 0; size < 256; ++size) {
  147. uint8_t* data = (uint8_t*)malloc(size);
  148. for (size_t i = 0; i < size; ++i) {
  149. data[i] = (uint8_t)(rand() % 256);
  150. }
  151. SerdNode blob = serd_node_new_blob(data, size, size % 5);
  152. if (blob.n_bytes != blob.n_chars) {
  153. return failure("Blob %zu bytes != %zu chars\n",
  154. blob.n_bytes, blob.n_chars);
  155. }
  156. size_t out_size;
  157. uint8_t* out = (uint8_t*)serd_base64_decode(
  158. blob.buf, blob.n_bytes, &out_size);
  159. if (out_size != size) {
  160. return failure("Blob size %zu != %zu\n", out_size, size);
  161. }
  162. for (size_t i = 0; i < size; ++i) {
  163. if (out[i] != data[i]) {
  164. return failure("Corrupt blob at byte %zu\n", i);
  165. }
  166. }
  167. serd_node_free(&blob);
  168. free(out);
  169. free(data);
  170. }
  171. // Test serd_strlen
  172. const uint8_t str[] = { '"', '5', 0xE2, 0x82, 0xAC, '"', '\n', 0 };
  173. size_t n_bytes;
  174. SerdNodeFlags flags;
  175. size_t len = serd_strlen(str, &n_bytes, &flags);
  176. if (len != 5 || n_bytes != 7
  177. || flags != (SERD_HAS_QUOTE|SERD_HAS_NEWLINE)) {
  178. return failure("Bad serd_strlen(%s) len=%zu n_bytes=%zu flags=%u\n",
  179. str, len, n_bytes, flags);
  180. }
  181. len = serd_strlen(str, NULL, &flags);
  182. if (len != 5) {
  183. return failure("Bad serd_strlen(%s) len=%zu flags=%u\n",
  184. str, len, flags);
  185. }
  186. // Test serd_strerror
  187. const uint8_t* msg = NULL;
  188. if (strcmp((const char*)(msg = serd_strerror(SERD_SUCCESS)), "Success")) {
  189. return failure("Bad message `%s' for SERD_SUCCESS\n", msg);
  190. }
  191. for (int i = SERD_FAILURE; i <= SERD_ERR_INTERNAL; ++i) {
  192. msg = serd_strerror((SerdStatus)i);
  193. if (!strcmp((const char*)msg, "Success")) {
  194. return failure("Bad message `%s' for (SerdStatus)%d\n", msg, i);
  195. }
  196. }
  197. msg = serd_strerror((SerdStatus)-1);
  198. // Test serd_uri_to_path
  199. const uint8_t* uri = (const uint8_t*)"file:///home/user/foo.ttl";
  200. if (strcmp((const char*)serd_uri_to_path(uri), "/home/user/foo.ttl")) {
  201. return failure("Bad path %s for %s\n", serd_uri_to_path(uri), uri);
  202. }
  203. uri = (const uint8_t*)"file://localhost/home/user/foo.ttl";
  204. if (strcmp((const char*)serd_uri_to_path(uri), "/home/user/foo.ttl")) {
  205. return failure("Bad path %s for %s\n", serd_uri_to_path(uri), uri);
  206. }
  207. uri = (const uint8_t*)"file:illegal/file/uri";
  208. if (serd_uri_to_path(uri)) {
  209. return failure("Converted invalid URI `%s' to path `%s'\n",
  210. uri, serd_uri_to_path(uri));
  211. }
  212. uri = (const uint8_t*)"file:///c:/awful/system";
  213. if (strcmp((const char*)serd_uri_to_path(uri), "c:/awful/system")) {
  214. return failure("Bad path %s for %s\n", serd_uri_to_path(uri), uri);
  215. }
  216. uri = (const uint8_t*)"file:///c:awful/system";
  217. if (strcmp((const char*)serd_uri_to_path(uri), "/c:awful/system")) {
  218. return failure("Bad path %s for %s\n", serd_uri_to_path(uri), uri);
  219. }
  220. uri = (const uint8_t*)"file:///0/1";
  221. if (strcmp((const char*)serd_uri_to_path(uri), "/0/1")) {
  222. return failure("Bad path %s for %s\n", serd_uri_to_path(uri), uri);
  223. }
  224. uri = (const uint8_t*)"C:\\Windows\\Sucks";
  225. if (strcmp((const char*)serd_uri_to_path(uri), "C:\\Windows\\Sucks")) {
  226. return failure("Bad path %s for %s\n", serd_uri_to_path(uri), uri);
  227. }
  228. uri = (const uint8_t*)"C|/Windows/Sucks";
  229. if (strcmp((const char*)serd_uri_to_path(uri), "C|/Windows/Sucks")) {
  230. return failure("Bad path %s for %s\n", serd_uri_to_path(uri), uri);
  231. }
  232. // Test serd_node_new_file_uri and serd_file_uri_parse
  233. SerdURI furi;
  234. const uint8_t* path_str = USTR("C:/My 100%");
  235. SerdNode file_node = serd_node_new_file_uri(path_str, 0, &furi, true);
  236. uint8_t* hostname = NULL;
  237. uint8_t* out_path = serd_file_uri_parse(file_node.buf, &hostname);
  238. if (strcmp((const char*)file_node.buf, "file:///C:/My%20100%%")) {
  239. return failure("Bad URI %s\n", file_node.buf);
  240. } else if (hostname) {
  241. return failure("hostname `%s' shouldn't exist\n", hostname);
  242. } else if (strcmp((const char*)path_str, (const char*)out_path)) {
  243. return failure("path=>URI=>path failure %s => %s => %s\n",
  244. path_str, file_node.buf, out_path);
  245. }
  246. free(out_path);
  247. serd_node_free(&file_node);
  248. path_str = USTR("C:\\Pointless Space");
  249. file_node = serd_node_new_file_uri(path_str, USTR("pwned"), 0, true);
  250. hostname = NULL;
  251. out_path = serd_file_uri_parse(file_node.buf, &hostname);
  252. if (strcmp((const char*)file_node.buf, "file://pwned/C:/Pointless%20Space")) {
  253. return failure("Bad URI %s\n", file_node.buf);
  254. } else if (!hostname || strcmp((const char*)hostname, "pwned")) {
  255. return failure("Bad hostname `%s'\n", hostname);
  256. } else if (strcmp((const char*)out_path, "C:/Pointless Space")) {
  257. return failure("path=>URI=>path failure %s => %s => %s\n",
  258. path_str, file_node.buf, out_path);
  259. }
  260. free(hostname);
  261. free(out_path);
  262. serd_node_free(&file_node);
  263. path_str = USTR("/foo/bar");
  264. file_node = serd_node_new_file_uri(path_str, 0, 0, true);
  265. hostname = NULL;
  266. out_path = serd_file_uri_parse(file_node.buf, &hostname);
  267. if (strcmp((const char*)file_node.buf, "file:///foo/bar")) {
  268. return failure("Bad URI %s\n", file_node.buf);
  269. } else if (hostname) {
  270. return failure("hostname `%s' shouldn't exist\n", hostname);
  271. } else if (strcmp((const char*)path_str, (const char*)out_path)) {
  272. return failure("path=>URI=>path failure %s => %s => %s\n",
  273. path_str, file_node.buf, out_path);
  274. }
  275. free(out_path);
  276. serd_node_free(&file_node);
  277. path_str = USTR("/foo/bar");
  278. file_node = serd_node_new_file_uri(path_str, USTR("localhost"), 0, true);
  279. out_path = serd_file_uri_parse(file_node.buf, &hostname);
  280. if (strcmp((const char*)file_node.buf, "file://localhost/foo/bar")) {
  281. return failure("Bad URI %s\n", file_node.buf);
  282. } else if (strcmp((const char*)hostname, "localhost")) {
  283. return failure("incorrect hostname `%s'\n", hostname);
  284. } else if (strcmp((const char*)path_str, (const char*)out_path)) {
  285. return failure("path=>URI=>path failure %s => %s => %s\n",
  286. path_str, file_node.buf, out_path);
  287. }
  288. free(hostname);
  289. free(out_path);
  290. serd_node_free(&file_node);
  291. path_str = USTR("a/relative path");
  292. file_node = serd_node_new_file_uri(path_str, 0, 0, false);
  293. out_path = serd_file_uri_parse(file_node.buf, &hostname);
  294. if (strcmp((const char*)file_node.buf, "a/relative path")) {
  295. return failure("Bad URI %s\n", file_node.buf);
  296. } else if (hostname) {
  297. return failure("hostname `%s' shouldn't exist\n", hostname);
  298. } else if (strcmp((const char*)path_str, (const char*)out_path)) {
  299. return failure("path=>URI=>path failure %s => %s => %s\n",
  300. path_str, file_node.buf, out_path);
  301. }
  302. free(hostname);
  303. free(out_path);
  304. serd_node_free(&file_node);
  305. if (serd_file_uri_parse(USTR("file://invalid"), NULL)) {
  306. return failure("successfully parsed bogus URI <file://invalid>\n");
  307. }
  308. out_path = serd_file_uri_parse(USTR("file://host/foo/%XYbar"), NULL);
  309. if (strcmp((const char*)out_path, "/foo/bar")) {
  310. return failure("bad tolerance of junk escape: `%s'\n", out_path);
  311. }
  312. free(out_path);
  313. out_path = serd_file_uri_parse(USTR("file://host/foo/%0Abar"), NULL);
  314. if (strcmp((const char*)out_path, "/foo/bar")) {
  315. return failure("bad tolerance of junk escape: `%s'\n", out_path);
  316. }
  317. free(out_path);
  318. // Test serd_node_equals
  319. const uint8_t replacement_char_str[] = { 0xEF, 0xBF, 0xBD, 0 };
  320. SerdNode lhs = serd_node_from_string(SERD_LITERAL, replacement_char_str);
  321. SerdNode rhs = serd_node_from_string(SERD_LITERAL, USTR("123"));
  322. if (serd_node_equals(&lhs, &rhs)) {
  323. return failure("%s == %s\n", lhs.buf, rhs.buf);
  324. }
  325. SerdNode qnode = serd_node_from_string(SERD_CURIE, USTR("foo:bar"));
  326. if (serd_node_equals(&lhs, &qnode)) {
  327. return failure("%s == %s\n", lhs.buf, qnode.buf);
  328. }
  329. if (!serd_node_equals(&lhs, &lhs)) {
  330. return failure("%s != %s\n", lhs.buf, lhs.buf);
  331. }
  332. SerdNode null_copy = serd_node_copy(&SERD_NODE_NULL);
  333. if (!serd_node_equals(&SERD_NODE_NULL, &null_copy)) {
  334. return failure("copy of null node != null node\n");
  335. }
  336. // Test serd_node_from_string
  337. SerdNode node = serd_node_from_string(SERD_LITERAL, (const uint8_t*)"hello\"");
  338. if (node.n_bytes != 6 || node.n_chars != 6 || node.flags != SERD_HAS_QUOTE
  339. || strcmp((const char*)node.buf, "hello\"")) {
  340. return failure("Bad node %s %zu %zu %d %d\n",
  341. node.buf, node.n_bytes, node.n_chars, node.flags, node.type);
  342. }
  343. node = serd_node_from_string(SERD_URI, NULL);
  344. if (!serd_node_equals(&node, &SERD_NODE_NULL)) {
  345. return failure("Creating node from NULL string failed\n");
  346. }
  347. // Test serd_node_new_uri_from_string
  348. SerdNode nonsense = serd_node_new_uri_from_string(NULL, NULL, NULL);
  349. if (nonsense.type != SERD_NOTHING) {
  350. return failure("Successfully created NULL URI\n");
  351. }
  352. SerdURI base_uri;
  353. SerdNode base = serd_node_new_uri_from_string(USTR("http://example.org/"),
  354. NULL, &base_uri);
  355. SerdNode nil = serd_node_new_uri_from_string(NULL, &base_uri, NULL);
  356. SerdNode nil2 = serd_node_new_uri_from_string(USTR(""), &base_uri, NULL);
  357. if (nil.type != SERD_URI || strcmp((const char*)nil.buf, (const char*)base.buf) ||
  358. nil2.type != SERD_URI || strcmp((const char*)nil2.buf, (const char*)base.buf)) {
  359. return failure("URI %s != base %s\n", nil.buf, base.buf);
  360. }
  361. serd_node_free(&nil);
  362. serd_node_free(&nil2);
  363. // Test serd_node_new_relative_uri
  364. SerdNode abs = serd_node_from_string(SERD_URI, USTR("http://example.org/foo/bar"));
  365. SerdURI abs_uri;
  366. serd_uri_parse(abs.buf, &abs_uri);
  367. SerdURI rel_uri;
  368. SerdNode rel = serd_node_new_relative_uri(&abs_uri, &base_uri, NULL, &rel_uri);
  369. if (strcmp((const char*)rel.buf, "/foo/bar")) {
  370. return failure("Bad relative URI %s (expected '/foo/bar')\n", rel.buf);
  371. }
  372. serd_node_free(&rel);
  373. serd_node_free(&base);
  374. // Test SerdEnv
  375. SerdNode u = serd_node_from_string(SERD_URI, USTR("http://example.org/foo"));
  376. SerdNode b = serd_node_from_string(SERD_CURIE, USTR("invalid"));
  377. SerdNode c = serd_node_from_string(SERD_CURIE, USTR("eg.2:b"));
  378. SerdEnv* env = serd_env_new(NULL);
  379. serd_env_set_prefix_from_strings(env, USTR("eg.2"), USTR("http://example.org/"));
  380. if (!serd_env_set_base_uri(env, NULL)) {
  381. return failure("Successfully set NULL base URI\n");
  382. }
  383. if (!serd_env_set_base_uri(env, &node)) {
  384. return failure("Set base URI to %s\n", node.buf);
  385. }
  386. if (!serd_node_equals(serd_env_get_base_uri(env, NULL), &node)) {
  387. return failure("Base URI mismatch\n");
  388. }
  389. SerdChunk prefix, suffix;
  390. if (!serd_env_expand(env, &b, &prefix, &suffix)) {
  391. return failure("Expanded invalid curie %s\n", b.buf);
  392. }
  393. SerdNode xnode = serd_env_expand_node(env, &node);
  394. if (!serd_node_equals(&xnode, &SERD_NODE_NULL)) {
  395. return failure("Expanded %s to %s\n", c.buf, xnode.buf);
  396. }
  397. SerdNode xu = serd_env_expand_node(env, &u);
  398. if (strcmp((const char*)xu.buf, "http://example.org/foo")) {
  399. return failure("Expanded %s to %s\n", c.buf, xu.buf);
  400. }
  401. serd_node_free(&xu);
  402. SerdNode badpre = serd_node_from_string(SERD_CURIE, USTR("hm:what"));
  403. SerdNode xbadpre = serd_env_expand_node(env, &badpre);
  404. if (!serd_node_equals(&xbadpre, &SERD_NODE_NULL)) {
  405. return failure("Expanded invalid curie %s\n", badpre.buf);
  406. }
  407. SerdNode xc = serd_env_expand_node(env, &c);
  408. if (strcmp((const char*)xc.buf, "http://example.org/b")) {
  409. return failure("Expanded %s to %s\n", c.buf, xc.buf);
  410. }
  411. serd_node_free(&xc);
  412. if (!serd_env_set_prefix(env, &SERD_NODE_NULL, &SERD_NODE_NULL)) {
  413. return failure("Set NULL prefix\n");
  414. }
  415. const SerdNode lit = serd_node_from_string(SERD_LITERAL, USTR("hello"));
  416. if (!serd_env_set_prefix(env, &b, &lit)) {
  417. return failure("Set prefix to literal\n");
  418. }
  419. int n_prefixes = 0;
  420. serd_env_set_prefix_from_strings(env, USTR("eg.2"), USTR("http://example.org/"));
  421. serd_env_foreach(env, count_prefixes, &n_prefixes);
  422. if (n_prefixes != 1) {
  423. return failure("Bad prefix count %d\n", n_prefixes);
  424. }
  425. SerdNode shorter_uri = serd_node_from_string(SERD_URI, USTR("urn:foo"));
  426. SerdNode prefix_name;
  427. if (serd_env_qualify(env, &shorter_uri, &prefix_name, &suffix)) {
  428. return failure("Qualified %s\n", shorter_uri.buf);
  429. }
  430. // Test SerdReader and SerdWriter
  431. const char* path = "serd_test.ttl";
  432. FILE* fd = fopen(path, "w");
  433. if (!fd) {
  434. return failure("Failed to open file %s\n", path);
  435. }
  436. SerdWriter* writer = serd_writer_new(
  437. SERD_TURTLE, (SerdStyle)0, env, NULL, serd_file_sink, fd);
  438. if (!writer) {
  439. return failure("Failed to create writer\n");
  440. }
  441. serd_writer_chop_blank_prefix(writer, USTR("tmp"));
  442. serd_writer_chop_blank_prefix(writer, NULL);
  443. if (!serd_writer_set_base_uri(writer, &lit)) {
  444. return failure("Set base URI to %s\n", lit.buf);
  445. }
  446. if (!serd_writer_set_prefix(writer, &lit, &lit)) {
  447. return failure("Set prefix %s to %s\n", lit.buf, lit.buf);
  448. }
  449. if (!serd_writer_end_anon(writer, NULL)) {
  450. return failure("Ended non-existent anonymous node\n");
  451. }
  452. if (serd_writer_get_env(writer) != env) {
  453. return failure("Writer has incorrect env\n");
  454. }
  455. uint8_t buf[] = { 0x80, 0, 0, 0, 0 };
  456. SerdNode s = serd_node_from_string(SERD_URI, USTR(""));
  457. SerdNode p = serd_node_from_string(SERD_URI, USTR("http://example.org/pred"));
  458. SerdNode o = serd_node_from_string(SERD_LITERAL, buf);
  459. // Write 3 invalid statements (should write nothing)
  460. const SerdNode* junk[][5] = { { &s, &p, NULL, NULL, NULL },
  461. { &s, NULL, &o, NULL, NULL },
  462. { NULL, &p, &o, NULL, NULL },
  463. { &s, &p, &SERD_NODE_NULL, NULL, NULL },
  464. { &s, &SERD_NODE_NULL, &o, NULL, NULL },
  465. { &SERD_NODE_NULL, &p, &o, NULL, NULL },
  466. { &s, &o, &o, NULL, NULL },
  467. { &o, &p, &o, NULL, NULL },
  468. { NULL, NULL, NULL, NULL, NULL } };
  469. for (unsigned i = 0; i < sizeof(junk) / (sizeof(SerdNode*) * 5); ++i) {
  470. if (!serd_writer_write_statement(
  471. writer, 0, NULL,
  472. junk[i][0], junk[i][1], junk[i][2], junk[i][3], junk[i][4])) {
  473. return failure("Successfully wrote junk statement %d\n", i);
  474. }
  475. }
  476. const SerdNode t = serd_node_from_string(SERD_URI, USTR("urn:Type"));
  477. const SerdNode l = serd_node_from_string(SERD_LITERAL, USTR("en"));
  478. const SerdNode* good[][5] = { { &s, &p, &o, NULL, NULL },
  479. { &s, &p, &o, &SERD_NODE_NULL, &SERD_NODE_NULL },
  480. { &s, &p, &o, &t, NULL },
  481. { &s, &p, &o, NULL, &l },
  482. { &s, &p, &o, &t, &l },
  483. { &s, &p, &o, &t, &SERD_NODE_NULL },
  484. { &s, &p, &o, &SERD_NODE_NULL, &l },
  485. { &s, &p, &o, NULL, &SERD_NODE_NULL },
  486. { &s, &p, &o, &SERD_NODE_NULL, NULL },
  487. { &s, &p, &o, &SERD_NODE_NULL, NULL } };
  488. for (unsigned i = 0; i < sizeof(good) / (sizeof(SerdNode*) * 5); ++i) {
  489. if (serd_writer_write_statement(
  490. writer, 0, NULL,
  491. good[i][0], good[i][1], good[i][2], good[i][3], good[i][4])) {
  492. return failure("Failed to write good statement %d\n", i);
  493. }
  494. }
  495. // Write 1 statement with bad UTF-8 (should be replaced)
  496. if (serd_writer_write_statement(writer, 0, NULL,
  497. &s, &p, &o, NULL, NULL)) {
  498. return failure("Failed to write junk UTF-8\n");
  499. }
  500. // Write 1 valid statement
  501. o = serd_node_from_string(SERD_LITERAL, USTR("hello"));
  502. if (serd_writer_write_statement(writer, 0, NULL,
  503. &s, &p, &o, NULL, NULL)) {
  504. return failure("Failed to write valid statement\n");
  505. }
  506. serd_writer_free(writer);
  507. // Test chunk sink
  508. SerdChunk chunk = { NULL, 0 };
  509. writer = serd_writer_new(
  510. SERD_TURTLE, (SerdStyle)0, env, NULL, serd_chunk_sink, &chunk);
  511. o = serd_node_from_string(SERD_URI, USTR("http://example.org/base"));
  512. if (serd_writer_set_base_uri(writer, &o)) {
  513. return failure("Failed to write to chunk sink\n");
  514. }
  515. serd_writer_free(writer);
  516. uint8_t* out = serd_chunk_sink_finish(&chunk);
  517. if (strcmp((const char*)out, "@base <http://example.org/base> .\n")) {
  518. return failure("Incorrect chunk output:\n%s\n", chunk.buf);
  519. }
  520. free(out);
  521. // Rewind and test reader
  522. fseek(fd, 0, SEEK_SET);
  523. ReaderTest* rt = (ReaderTest*)calloc(1, sizeof(ReaderTest));
  524. SerdReader* reader = serd_reader_new(
  525. SERD_TURTLE, rt, free,
  526. NULL, NULL, test_sink, NULL);
  527. if (!reader) {
  528. return failure("Failed to create reader\n");
  529. }
  530. if (serd_reader_get_handle(reader) != rt) {
  531. return failure("Corrupt reader handle\n");
  532. }
  533. SerdNode g = serd_node_from_string(SERD_URI, USTR("http://example.org/"));
  534. serd_reader_set_default_graph(reader, &g);
  535. serd_reader_add_blank_prefix(reader, USTR("tmp"));
  536. serd_reader_add_blank_prefix(reader, NULL);
  537. if (!serd_reader_read_file(reader, USTR("http://notafile"))) {
  538. return failure("Apparently read an http URI\n");
  539. }
  540. if (!serd_reader_read_file(reader, USTR("file:///better/not/exist"))) {
  541. return failure("Apparently read a non-existent file\n");
  542. }
  543. if (!serd_reader_read_file(reader, USTR("file://"))) {
  544. return failure("Apparently read a file with no path\n");
  545. }
  546. SerdStatus st = serd_reader_read_file(reader, USTR(path));
  547. if (st) {
  548. return failure("Error reading file (%s)\n", serd_strerror(st));
  549. }
  550. if (rt->n_statements != 12) {
  551. return failure("Bad statement count %d\n", rt->n_statements);
  552. } else if (!rt->graph || !rt->graph->buf ||
  553. strcmp((const char*)rt->graph->buf, "http://example.org/")) {
  554. return failure("Bad graph %p\n", rt->graph);
  555. }
  556. if (!serd_reader_read_string(reader, USTR("This isn't Turtle at all."))) {
  557. return failure("Parsed invalid string successfully.\n");
  558. }
  559. serd_reader_free(reader);
  560. fclose(fd);
  561. serd_env_free(env);
  562. printf("Success\n");
  563. return 0;
  564. }