diff options
author | David Robillard <d@drobilla.net> | 2025-02-25 08:57:57 -0500 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2025-03-16 20:22:36 -0400 |
commit | 5ecac71066475b2bb55758ae138afeebeaa5b948 (patch) | |
tree | 2bbf63c80c713420d846105ac9eae0753e39fc4e | |
parent | eb7e973b25a8e5556b2f1175d8375e5e513ba664 (diff) | |
download | serd-5ecac71066475b2bb55758ae138afeebeaa5b948.tar.gz serd-5ecac71066475b2bb55758ae138afeebeaa5b948.tar.bz2 serd-5ecac71066475b2bb55758ae138afeebeaa5b948.zip |
Refuse to write incoherent statements
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | src/writer.c | 17 | ||||
-rw-r--r-- | test/test_reader_writer.c | 15 | ||||
-rw-r--r-- | test/test_writer.c | 72 |
4 files changed, 87 insertions, 20 deletions
@@ -2,9 +2,10 @@ serd (0.32.5) unstable; urgency=medium * Fix handling of some invalid EOF cases in lax mode * Fix invalid characters in error messages + * Refuse to write incoherent statements * Remove project and version number from man page OS field - -- David Robillard <d@drobilla.net> Thu, 30 Jan 2025 20:28:00 +0000 + -- David Robillard <d@drobilla.net> Tue, 25 Feb 2025 14:22:43 +0000 serd (0.32.4) stable; urgency=medium diff --git a/src/writer.c b/src/writer.c index f0a9ad16..ab237099 100644 --- a/src/writer.c +++ b/src/writer.c @@ -1,4 +1,4 @@ -// Copyright 2011-2023 David Robillard <d@drobilla.net> +// Copyright 2011-2025 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #include "attributes.h" @@ -926,10 +926,6 @@ serd_writer_write_statement(SerdWriter* const writer, SerdStatus st = SERD_SUCCESS; - if (!is_resource(subject) || !is_resource(predicate) || !object->buf) { - return SERD_ERR_BAD_ARG; - } - if ((flags & SERD_LIST_O_BEGIN) && !strcmp((const char*)object->buf, NS_RDF "nil")) { /* Tolerate LIST_O_BEGIN for "()" objects, even though it doesn't make @@ -938,6 +934,17 @@ serd_writer_write_statement(SerdWriter* const writer, flags &= (SerdStatementFlags)~SERD_LIST_O_BEGIN; } + // Refuse to write incoherent statements + if (!is_resource(subject) || !is_resource(predicate) || + object->type == SERD_NOTHING || !object->buf || + (datatype && datatype->buf && lang && lang->buf) || + ((flags & SERD_ANON_S_BEGIN) && (flags & SERD_LIST_S_BEGIN)) || + ((flags & SERD_EMPTY_S) && (flags & SERD_LIST_S_BEGIN)) || + ((flags & SERD_ANON_O_BEGIN) && (flags & SERD_LIST_O_BEGIN)) || + ((flags & SERD_EMPTY_O) && (flags & SERD_LIST_O_BEGIN))) { + return SERD_ERR_BAD_ARG; + } + // Simple case: write a line of NTriples or NQuads if (writer->syntax == SERD_NTRIPLES || writer->syntax == SERD_NQUADS) { TRY(st, write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags)); diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c index 61874bc7..829caff5 100644 --- a/test/test_reader_writer.c +++ b/test/test_reader_writer.c @@ -168,15 +168,19 @@ test_writer(const char* const path) const uint8_t buf[] = {0x80, 0, 0, 0, 0}; - SerdNode s = serd_node_from_string(SERD_URI, USTR("")); - SerdNode p = serd_node_from_string(SERD_URI, USTR("http://example.org/pred")); - SerdNode o = serd_node_from_string(SERD_LITERAL, buf); + const SerdNode s = serd_node_from_string(SERD_URI, USTR("")); + const SerdNode p = + serd_node_from_string(SERD_URI, USTR("http://example.org/pred")); + const SerdNode o = serd_node_from_string(SERD_LITERAL, buf); + const SerdNode t = serd_node_from_string(SERD_URI, USTR("urn:Type")); + const SerdNode l = serd_node_from_string(SERD_LITERAL, USTR("en")); // Attempt to write invalid statements (should write nothing) const SerdNode* junk[][5] = {{&s, &p, &SERD_NODE_NULL, NULL, NULL}, {&s, &SERD_NODE_NULL, &o, NULL, NULL}, {&SERD_NODE_NULL, &p, &o, NULL, NULL}, {&s, &o, &o, NULL, NULL}, + {&s, &o, &o, &t, &l}, {&o, &p, &o, NULL, NULL}, {&s, &p, &SERD_NODE_NULL, NULL, NULL}}; for (size_t i = 0; i < sizeof(junk) / (sizeof(SerdNode*) * 5); ++i) { @@ -191,14 +195,11 @@ test_writer(const char* const path) } // Write some valid statements - const SerdNode t = serd_node_from_string(SERD_URI, USTR("urn:Type")); - const SerdNode l = serd_node_from_string(SERD_LITERAL, USTR("en")); const SerdNode* good[][5] = {{&s, &p, &o, NULL, NULL}, {&s, &p, &lit, NULL, NULL}, {&s, &p, &o, &SERD_NODE_NULL, &SERD_NODE_NULL}, {&s, &p, &o, &t, NULL}, {&s, &p, &o, NULL, &l}, - {&s, &p, &o, &t, &l}, {&s, &p, &o, &t, &SERD_NODE_NULL}, {&s, &p, &o, &SERD_NODE_NULL, &l}, {&s, &p, &o, NULL, &SERD_NODE_NULL}, @@ -260,7 +261,7 @@ test_reader(const char* const path) const SerdStatus st = serd_reader_read_file(reader, USTR(path)); assert(!st); - assert(rt->n_statement == 13); + assert(rt->n_statement == 12); assert(rt->graph && rt->graph->buf && !strcmp((const char*)rt->graph->buf, "http://example.org/")); diff --git a/test/test_writer.c b/test/test_writer.c index 27ce6138..7f8d2f94 100644 --- a/test/test_writer.c +++ b/test/test_writer.c @@ -309,17 +309,74 @@ test_write_nothing_node(void) SerdNode s = serd_node_from_string(SERD_URI, USTR("")); SerdNode p = serd_node_from_string(SERD_URI, USTR("http://example.org/pred")); SerdNode o = serd_node_from_string(SERD_NOTHING, USTR("")); - assert(!serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL)); - - assert( - !strncmp((const char*)chunk.buf, "<>\n\t<http://example.org/pred> ", 30)); + assert(serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL) == + SERD_ERR_BAD_ARG); + assert(!chunk.buf); serd_writer_free(writer); + serd_env_free(env); +} - uint8_t* const out = serd_chunk_sink_finish(&chunk); - assert(!strcmp((const char*)out, "<>\n\t<http://example.org/pred> .\n")); - serd_free(out); +static void +test_write_bad_statement(void) +{ + SerdEnv* const env = serd_env_new(NULL); + assert(env); + SerdChunk chunk = {NULL, 0}; + SerdWriter* const writer = serd_writer_new( + SERD_TURTLE, (SerdStyle)0, env, NULL, serd_chunk_sink, &chunk); + assert(writer); + + SerdNode s = serd_node_from_string(SERD_URI, USTR("http://example.org/s")); + SerdNode p = serd_node_from_string(SERD_URI, USTR("http://example.org/p")); + SerdNode o = serd_node_from_string(SERD_URI, USTR("http://example.org/o")); + SerdNode l = serd_node_from_string(SERD_LITERAL, USTR("lang")); + + assert(serd_writer_write_statement( + writer, + (SerdStatementFlags)(SERD_ANON_S_BEGIN | SERD_LIST_S_BEGIN), + NULL, + &s, + &p, + &o, + NULL, + NULL) == SERD_ERR_BAD_ARG); + + assert(serd_writer_write_statement( + writer, + (SerdStatementFlags)(SERD_EMPTY_S | SERD_LIST_S_BEGIN), + NULL, + &s, + &p, + &o, + NULL, + NULL) == SERD_ERR_BAD_ARG); + + assert(serd_writer_write_statement( + writer, + (SerdStatementFlags)(SERD_ANON_O_BEGIN | SERD_LIST_O_BEGIN), + NULL, + &s, + &p, + &o, + NULL, + NULL) == SERD_ERR_BAD_ARG); + + assert(serd_writer_write_statement( + writer, + (SerdStatementFlags)(SERD_EMPTY_O | SERD_LIST_O_BEGIN), + NULL, + &s, + &p, + &o, + NULL, + NULL) == SERD_ERR_BAD_ARG); + + assert(serd_writer_write_statement(writer, 0U, NULL, &s, &p, &o, &o, &l) == + SERD_ERR_BAD_ARG); + + serd_writer_free(writer); serd_env_free(env); } @@ -334,6 +391,7 @@ main(void) test_write_error(); test_chunk_sink(); test_write_nothing_node(); + test_write_bad_statement(); return 0; } |