// Copyright 2011-2023 David Robillard // SPDX-License-Identifier: ISC #undef NDEBUG #include "serd/buffer.h" #include "serd/env.h" #include "serd/memory.h" #include "serd/node.h" #include "serd/statement.h" #include "serd/status.h" #include "serd/syntax.h" #include "serd/writer.h" #include #include #include #include static void test_write_long_literal(void) { SerdEnv* env = serd_env_new(NULL); SerdBuffer buffer = {NULL, 0}; SerdWriter* writer = serd_writer_new(SERD_TURTLE, 0U, env, NULL, serd_buffer_sink, &buffer); assert(writer); SerdNode s = serd_node_from_string(SERD_URI, "http://example.org/s"); SerdNode p = serd_node_from_string(SERD_URI, "http://example.org/p"); SerdNode o = serd_node_from_string(SERD_LITERAL, "hello \"\"\"world\"\"\"!"); assert(!serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL)); serd_writer_free(writer); serd_env_free(env); char* out = serd_buffer_sink_finish(&buffer); static const char* const expected = "\n" "\t \"\"\"hello \"\"\\\"world\"\"\\\"!\"\"\" .\n"; assert(!strcmp((char*)out, expected)); serd_free(out); } static size_t null_sink(const void* const buf, const size_t len, void* const stream) { (void)buf; (void)stream; return len; } static void test_writer_cleanup(void) { SerdStatus st = SERD_SUCCESS; SerdEnv* env = serd_env_new(NULL); SerdWriter* writer = serd_writer_new(SERD_TURTLE, 0U, env, NULL, null_sink, NULL); SerdNode s = serd_node_from_string(SERD_URI, "http://example.org/s"); SerdNode p = serd_node_from_string(SERD_URI, "http://example.org/p"); SerdNode o = serd_node_from_string(SERD_BLANK, "http://example.org/o"); st = serd_writer_write_statement( writer, SERD_ANON_O_BEGIN, NULL, &s, &p, &o, NULL, NULL); assert(!st); // Write the start of several nested anonymous objects for (unsigned i = 0U; !st && i < 8U; ++i) { char buf[12] = {0}; snprintf(buf, sizeof(buf), "b%u", i); SerdNode next_o = serd_node_from_string(SERD_BLANK, buf); st = serd_writer_write_statement( writer, SERD_ANON_O_BEGIN, NULL, &o, &p, &next_o, NULL, NULL); o = next_o; } // Finish writing without terminating nodes assert(!(st = serd_writer_finish(writer))); // Set the base to an empty URI assert(!(st = serd_writer_set_base_uri(writer, NULL))); // Free (which could leak if the writer doesn't clean up the stack properly) serd_writer_free(writer); serd_env_free(env); } static void test_strict_write(void) { const char* const path = "serd_strict_write_test.ttl"; FILE* const fd = fopen(path, "wb"); assert(fd); SerdEnv* const env = serd_env_new(NULL); SerdWriter* const writer = serd_writer_new( SERD_TURTLE, (SerdWriterFlags)SERD_WRITE_STRICT, env, NULL, null_sink, fd); assert(writer); const uint8_t bad_str[] = {0xFF, 0x90, 'h', 'i', 0}; SerdNode s = serd_node_from_string(SERD_URI, "http://example.org/s"); SerdNode p = serd_node_from_string(SERD_URI, "http://example.org/p"); SerdNode bad_lit = serd_node_from_string(SERD_LITERAL, (const char*)bad_str); SerdNode bad_uri = serd_node_from_string(SERD_URI, (const char*)bad_str); assert(serd_writer_write_statement( writer, 0, NULL, &s, &p, &bad_lit, NULL, NULL) == SERD_BAD_TEXT); assert(serd_writer_write_statement( writer, 0, NULL, &s, &p, &bad_uri, NULL, NULL) == SERD_BAD_TEXT); serd_writer_free(writer); serd_env_free(env); fclose(fd); remove(path); } // Produce a write error without setting errno static size_t error_sink(const void* const buf, const size_t len, void* const stream) { (void)buf; (void)len; (void)stream; return 0U; } static void test_write_error(void) { SerdEnv* const env = serd_env_new(NULL); SerdWriter* writer = NULL; SerdStatus st = SERD_SUCCESS; SerdNode u = serd_node_from_string(SERD_URI, "http://example.com/u"); writer = serd_writer_new( SERD_TURTLE, (SerdWriterFlags)0, env, NULL, error_sink, NULL); assert(writer); st = serd_writer_write_statement(writer, 0U, NULL, &u, &u, &u, NULL, NULL); assert(st == SERD_BAD_WRITE); serd_writer_free(writer); serd_env_free(env); } int main(void) { test_write_long_literal(); test_writer_cleanup(); test_strict_write(); test_write_error(); return 0; }