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