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.

631 lines
21KB

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