diff options
author | David Robillard <d@drobilla.net> | 2018-06-03 19:24:59 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2023-12-02 18:49:07 -0500 |
commit | 40534e6c42daabb6cc8ec2d49785bec088d1d3a8 (patch) | |
tree | 593e37de3e9bce98e291ec098a7081e6e26240b0 | |
parent | 38f85ad8c53c618033e3d0b7cb1fe782c38cf0a3 (diff) | |
download | serd-40534e6c42daabb6cc8ec2d49785bec088d1d3a8.tar.gz serd-40534e6c42daabb6cc8ec2d49785bec088d1d3a8.tar.bz2 serd-40534e6c42daabb6cc8ec2d49785bec088d1d3a8.zip |
Add SerdStatement
-rw-r--r-- | doc/conf.py.in | 1 | ||||
-rw-r--r-- | include/serd/sink.h | 16 | ||||
-rw-r--r-- | include/serd/statement.h | 83 | ||||
-rw-r--r-- | meson.build | 2 | ||||
-rw-r--r-- | src/node.h | 8 | ||||
-rw-r--r-- | src/reader.c | 8 | ||||
-rw-r--r-- | src/sink.c | 17 | ||||
-rw-r--r-- | src/statement.c | 142 | ||||
-rw-r--r-- | src/statement.h | 24 | ||||
-rw-r--r-- | src/writer.c | 15 | ||||
-rw-r--r-- | test/meson.build | 1 | ||||
-rw-r--r-- | test/test_reader_writer.c | 14 | ||||
-rw-r--r-- | test/test_sink.c | 44 | ||||
-rw-r--r-- | test/test_statement.c | 142 |
14 files changed, 463 insertions, 54 deletions
diff --git a/doc/conf.py.in b/doc/conf.py.in index 9b1cdc70..e3e7f1ad 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -32,6 +32,7 @@ _opaque = [ "SerdNodeImpl", "SerdReaderImpl", "SerdSinkImpl", + "SerdStatementImpl", "SerdWorldImpl", "SerdWriterImpl", "int64_t", diff --git a/include/serd/sink.h b/include/serd/sink.h index f24db683..95979b50 100644 --- a/include/serd/sink.h +++ b/include/serd/sink.h @@ -39,12 +39,10 @@ typedef SerdStatus (*SerdPrefixFunc)(void* SERD_NULLABLE handle, Called for every RDF statement in the serialisation. */ -typedef SerdStatus (*SerdStatementFunc)(void* SERD_NULLABLE handle, - SerdStatementFlags flags, - const SerdNode* SERD_NULLABLE graph, - const SerdNode* SERD_NONNULL subject, - const SerdNode* SERD_NONNULL predicate, - const SerdNode* SERD_NONNULL object); +typedef SerdStatus (*SerdStatementFunc)(void* SERD_NULLABLE handle, + SerdStatementFlags flags, + const SerdStatement* SERD_NONNULL + statement); /** Sink function for anonymous node end markers. @@ -110,6 +108,12 @@ serd_sink_write_prefix(const SerdSink* SERD_NONNULL sink, const SerdNode* SERD_NONNULL name, const SerdNode* SERD_NONNULL uri); +/// Write a statement +SERD_API SerdStatus +serd_sink_write_statement(const SerdSink* SERD_NONNULL sink, + SerdStatementFlags flags, + const SerdStatement* SERD_NONNULL statement); + /// Write a statement from individual nodes SERD_API SerdStatus serd_sink_write(const SerdSink* SERD_NONNULL sink, diff --git a/include/serd/statement.h b/include/serd/statement.h index 33911c41..eff7b796 100644 --- a/include/serd/statement.h +++ b/include/serd/statement.h @@ -5,7 +5,10 @@ #define SERD_STATEMENT_H #include "serd/attributes.h" +#include "serd/caret.h" +#include "serd/node.h" +#include <stdbool.h> #include <stdint.h> SERD_BEGIN_DECLS @@ -39,6 +42,86 @@ typedef enum { /// Bitwise OR of SerdStatementFlag values typedef uint32_t SerdStatementFlags; +/// A subject, predicate, and object, with optional graph context +typedef struct SerdStatementImpl SerdStatement; + +/** + Create a new statement. + + Note that, to minimise model overhead, statements do not own their nodes, so + they must have a longer lifetime than the statement for it to be valid. For + statements in models, this is the lifetime of the model. For user-created + statements, the simplest way to handle this is to use `SerdNodes`. + + @param s The subject + @param p The predicate ("key") + @param o The object ("value") + @param g The graph ("context") + @param caret Optional caret at the origin of this statement + @return A new statement that must be freed with serd_statement_free() +*/ +SERD_API SerdStatement* SERD_ALLOCATED +serd_statement_new(const SerdNode* SERD_NONNULL s, + const SerdNode* SERD_NONNULL p, + const SerdNode* SERD_NONNULL o, + const SerdNode* SERD_NULLABLE g, + const SerdCaret* SERD_NULLABLE caret); + +/// Return a copy of `statement` +SERD_API SerdStatement* SERD_ALLOCATED +serd_statement_copy(const SerdStatement* SERD_NULLABLE statement); + +/// Free `statement` +SERD_API void +serd_statement_free(SerdStatement* SERD_NULLABLE statement); + +/// Return the given node of the statement +SERD_PURE_API const SerdNode* SERD_NULLABLE +serd_statement_node(const SerdStatement* SERD_NONNULL statement, + SerdField field); + +/// Return the subject of the statement +SERD_PURE_API const SerdNode* SERD_NONNULL +serd_statement_subject(const SerdStatement* SERD_NONNULL statement); + +/// Return the predicate of the statement +SERD_PURE_API const SerdNode* SERD_NONNULL +serd_statement_predicate(const SerdStatement* SERD_NONNULL statement); + +/// Return the object of the statement +SERD_PURE_API const SerdNode* SERD_NONNULL +serd_statement_object(const SerdStatement* SERD_NONNULL statement); + +/// Return the graph of the statement +SERD_PURE_API const SerdNode* SERD_NULLABLE +serd_statement_graph(const SerdStatement* SERD_NONNULL statement); + +/// Return the source location where the statement originated, or NULL +SERD_PURE_API const SerdCaret* SERD_NULLABLE +serd_statement_caret(const SerdStatement* SERD_NONNULL statement); + +/** + Return true iff `a` is equal to `b`, ignoring statement caret metadata. + + Only returns true if nodes are equivalent, does not perform wildcard + matching. +*/ +SERD_PURE_API bool +serd_statement_equals(const SerdStatement* SERD_NULLABLE a, + const SerdStatement* SERD_NULLABLE b); + +/** + Return true iff the statement matches the given pattern. + + Nodes match if they are equivalent, or if one of them is NULL. The + statement matches if every node matches. +*/ +SERD_PURE_API bool +serd_statement_matches(const SerdStatement* SERD_NONNULL statement, + const SerdNode* SERD_NULLABLE subject, + const SerdNode* SERD_NULLABLE predicate, + const SerdNode* SERD_NULLABLE object, + const SerdNode* SERD_NULLABLE graph); /** @} */ diff --git a/meson.build b/meson.build index 8b4652b1..5cacf693 100644 --- a/meson.build +++ b/meson.build @@ -150,6 +150,8 @@ sources = files( 'src/node.c', 'src/reader.c', 'src/sink.c', + 'src/statement.c', + 'src/statement.c', 'src/string.c', 'src/syntax.c', 'src/system.c', @@ -10,6 +10,7 @@ #include "serd/string_view.h" #include "serd/uri.h" +#include <stdbool.h> #include <stddef.h> #include <stdint.h> @@ -39,6 +40,13 @@ serd_node_string_i(const SerdNode* const SERD_NONNULL node) return (const char*)(node + 1); } +static inline bool +serd_node_pattern_match(const SerdNode* SERD_NULLABLE a, + const SerdNode* SERD_NULLABLE b) +{ + return !a || !b || serd_node_equals(a, b); +} + SerdNode* SERD_ALLOCATED serd_node_malloc(size_t length, SerdNodeFlags flags, SerdNodeType type); diff --git a/src/reader.c b/src/reader.c index a9c483c0..3c80c491 100644 --- a/src/reader.c +++ b/src/reader.c @@ -7,6 +7,7 @@ #include "node.h" #include "serd_internal.h" #include "stack.h" +#include "statement.h" #include "system.h" #include "world.h" @@ -118,8 +119,11 @@ emit_statement(SerdReader* const reader, (subject and predicate) were already zeroed by subsequent pushes. */ serd_node_zero_pad(o); - const SerdStatus st = serd_sink_write( - reader->sink, *ctx.flags, ctx.subject, ctx.predicate, o, ctx.graph); + const SerdStatement statement = {{ctx.subject, ctx.predicate, o, ctx.graph}, + &reader->source.caret}; + + const SerdStatus st = + serd_sink_write_statement(reader->sink, *ctx.flags, &statement); *ctx.flags &= SERD_ANON_CONT | SERD_LIST_CONT; // Preserve only cont flags return st; @@ -3,6 +3,8 @@ #include "sink.h" +#include "statement.h" + #include "serd/node.h" #include "serd/sink.h" #include "serd/statement.h" @@ -77,6 +79,15 @@ serd_sink_write_prefix(const SerdSink* sink, } SerdStatus +serd_sink_write_statement(const SerdSink* sink, + const SerdStatementFlags flags, + const SerdStatement* statement) +{ + return sink->statement ? sink->statement(sink->handle, flags, statement) + : SERD_SUCCESS; +} + +SerdStatus serd_sink_write(const SerdSink* sink, const SerdStatementFlags flags, const SerdNode* subject, @@ -89,10 +100,8 @@ serd_sink_write(const SerdSink* sink, assert(predicate); assert(object); - return sink->statement - ? sink->statement( - sink->handle, flags, graph, subject, predicate, object) - : SERD_SUCCESS; + const SerdStatement statement = {{subject, predicate, object, graph}, NULL}; + return serd_sink_write_statement(sink, flags, &statement); } SerdStatus diff --git a/src/statement.c b/src/statement.c new file mode 100644 index 00000000..430194b7 --- /dev/null +++ b/src/statement.c @@ -0,0 +1,142 @@ +// Copyright 2011-2020 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#include "statement.h" + +#include "caret.h" +#include "node.h" + +#include "serd/statement.h" + +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +static bool +is_resource(const SerdNode* const node) +{ + const SerdNodeType type = node ? serd_node_type(node) : (SerdNodeType)0; + return type == SERD_URI || type == SERD_CURIE || type == SERD_BLANK; +} + +bool +serd_statement_is_valid(const SerdNode* const subject, + const SerdNode* const predicate, + const SerdNode* const object, + const SerdNode* const graph) +{ + return is_resource(subject) && is_resource(predicate) && object && + serd_node_type(predicate) != SERD_BLANK && + (!graph || is_resource(graph)); +} + +SerdStatement* +serd_statement_new(const SerdNode* const s, + const SerdNode* const p, + const SerdNode* const o, + const SerdNode* const g, + const SerdCaret* const caret) +{ + assert(s); + assert(p); + assert(o); + + if (!serd_statement_is_valid(s, p, o, g)) { + return NULL; + } + + SerdStatement* statement = (SerdStatement*)malloc(sizeof(SerdStatement)); + if (statement) { + statement->nodes[0] = s; + statement->nodes[1] = p; + statement->nodes[2] = o; + statement->nodes[3] = g; + statement->caret = serd_caret_copy(caret); + } + return statement; +} + +SerdStatement* +serd_statement_copy(const SerdStatement* const statement) +{ + if (!statement) { + return NULL; + } + + SerdStatement* copy = (SerdStatement*)malloc(sizeof(SerdStatement)); + memcpy(copy, statement, sizeof(SerdStatement)); + if (statement->caret) { + copy->caret = (SerdCaret*)malloc(sizeof(SerdCaret)); + memcpy(copy->caret, statement->caret, sizeof(SerdCaret)); + } + return copy; +} + +void +serd_statement_free(SerdStatement* const statement) +{ + if (statement) { + free(statement->caret); + free(statement); + } +} + +const SerdNode* +serd_statement_node(const SerdStatement* const statement, const SerdField field) +{ + return statement->nodes[field]; +} + +const SerdNode* +serd_statement_subject(const SerdStatement* const statement) +{ + return statement->nodes[SERD_SUBJECT]; +} + +const SerdNode* +serd_statement_predicate(const SerdStatement* const statement) +{ + return statement->nodes[SERD_PREDICATE]; +} + +const SerdNode* +serd_statement_object(const SerdStatement* const statement) +{ + return statement->nodes[SERD_OBJECT]; +} + +const SerdNode* +serd_statement_graph(const SerdStatement* const statement) +{ + return statement->nodes[SERD_GRAPH]; +} + +const SerdCaret* +serd_statement_caret(const SerdStatement* const statement) +{ + return statement->caret; +} + +bool +serd_statement_equals(const SerdStatement* const a, + const SerdStatement* const b) +{ + return (a == b || (a && b && serd_node_equals(a->nodes[0], b->nodes[0]) && + serd_node_equals(a->nodes[1], b->nodes[1]) && + serd_node_equals(a->nodes[2], b->nodes[2]) && + serd_node_equals(a->nodes[3], b->nodes[3]))); +} + +bool +serd_statement_matches(const SerdStatement* const statement, + const SerdNode* const subject, + const SerdNode* const predicate, + const SerdNode* const object, + const SerdNode* const graph) +{ + return (serd_node_pattern_match(statement->nodes[0], subject) && + serd_node_pattern_match(statement->nodes[1], predicate) && + serd_node_pattern_match(statement->nodes[2], object) && + serd_node_pattern_match(statement->nodes[3], graph)); +} diff --git a/src/statement.h b/src/statement.h new file mode 100644 index 00000000..d4a64da5 --- /dev/null +++ b/src/statement.h @@ -0,0 +1,24 @@ +// Copyright 2011-2020 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#ifndef SERD_SRC_STATEMENT_H +#define SERD_SRC_STATEMENT_H + +#include "serd/attributes.h" +#include "serd/caret.h" +#include "serd/node.h" + +#include <stdbool.h> + +struct SerdStatementImpl { + const SerdNode* SERD_NULLABLE nodes[4]; + SerdCaret* SERD_NULLABLE caret; +}; + +SERD_PURE_FUNC bool +serd_statement_is_valid(const SerdNode* SERD_NULLABLE subject, + const SerdNode* SERD_NULLABLE predicate, + const SerdNode* SERD_NULLABLE object, + const SerdNode* SERD_NULLABLE graph); + +#endif // SERD_SRC_STATEMENT_H diff --git a/src/writer.c b/src/writer.c index 5419e565..376becf1 100644 --- a/src/writer.c +++ b/src/writer.c @@ -961,14 +961,15 @@ terminate_context(SerdWriter* writer) } static SerdStatus -serd_writer_write_statement(SerdWriter* const writer, - const SerdStatementFlags flags, - const SerdNode* const graph, - const SerdNode* const subject, - const SerdNode* const predicate, - const SerdNode* const object) +serd_writer_write_statement(SerdWriter* const writer, + const SerdStatementFlags flags, + const SerdStatement* const statement) { - SerdStatus st = SERD_SUCCESS; + SerdStatus st = SERD_SUCCESS; + const SerdNode* const subject = serd_statement_subject(statement); + const SerdNode* const predicate = serd_statement_predicate(statement); + const SerdNode* const object = serd_statement_object(statement); + const SerdNode* const graph = serd_statement_graph(statement); if (!is_resource(subject) || !is_resource(predicate) || !object) { return SERD_BAD_ARG; diff --git a/test/meson.build b/test/meson.build index c3f29637..3e24fea0 100644 --- a/test/meson.build +++ b/test/meson.build @@ -126,6 +126,7 @@ unit_tests = [ 'overflow', 'reader_writer', 'sink', + 'statement', 'string', 'syntax', 'uri', diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c index 39bde443..e792f2dc 100644 --- a/test/test_reader_writer.c +++ b/test/test_reader_writer.c @@ -86,18 +86,12 @@ test_prefix_sink(void* handle, const SerdNode* name, const SerdNode* uri) } static SerdStatus -test_statement_sink(void* handle, - SerdStatementFlags flags, - const SerdNode* graph, - const SerdNode* subject, - const SerdNode* predicate, - const SerdNode* object) +test_statement_sink(void* handle, + const SerdStatementFlags flags, + const SerdStatement* statement) { - (void)graph; (void)flags; - (void)subject; - (void)predicate; - (void)object; + (void)statement; ReaderTest* rt = (ReaderTest*)handle; ++rt->n_statement; diff --git a/test/test_sink.c b/test/test_sink.c index 944dea1a..4b9a2eb2 100644 --- a/test/test_sink.c +++ b/test/test_sink.c @@ -18,15 +18,12 @@ #define NS_EG "http://example.org/" typedef struct { - const SerdNode* last_base; - const SerdNode* last_name; - const SerdNode* last_namespace; - const SerdNode* last_end; - const SerdNode* last_subject; - const SerdNode* last_predicate; - const SerdNode* last_object; - const SerdNode* last_graph; - SerdStatus return_status; + const SerdNode* last_base; + const SerdNode* last_name; + const SerdNode* last_namespace; + const SerdNode* last_end; + const SerdStatement* last_statement; + SerdStatus return_status; } State; static SerdStatus @@ -49,21 +46,15 @@ on_prefix(void* handle, const SerdNode* name, const SerdNode* uri) } static SerdStatus -on_statement(void* handle, - SerdStatementFlags flags, - const SerdNode* const graph, - const SerdNode* const subject, - const SerdNode* const predicate, - const SerdNode* const object) +on_statement(void* handle, + SerdStatementFlags flags, + const SerdStatement* const statement) { (void)flags; State* state = (State*)handle; - state->last_subject = subject; - state->last_predicate = predicate; - state->last_object = object; - state->last_graph = graph; + state->last_statement = statement; return state->return_status; } @@ -85,13 +76,17 @@ test_callbacks(void) SerdNode* const uri = serd_new_uri(serd_string(NS_EG "uri")); SerdNode* const blank = serd_new_blank(serd_string("b1")); SerdEnv* env = serd_env_new(serd_node_string_view(base)); - State state = {0, 0, 0, 0, 0, 0, 0, 0, SERD_SUCCESS}; + State state = {0, 0, 0, 0, 0, SERD_SUCCESS}; + + SerdStatement* const statement = + serd_statement_new(base, uri, blank, NULL, NULL); // Call functions on a sink with no functions set SerdSink* null_sink = serd_sink_new(&state, NULL); assert(!serd_sink_write_base(null_sink, base)); assert(!serd_sink_write_prefix(null_sink, name, uri)); + assert(!serd_sink_write_statement(null_sink, 0, statement)); assert(!serd_sink_write(null_sink, 0, base, uri, blank, NULL)); assert(!serd_sink_write_end(null_sink, blank)); serd_sink_free(null_sink); @@ -111,16 +106,15 @@ test_callbacks(void) assert(serd_node_equals(state.last_name, name)); assert(serd_node_equals(state.last_namespace, uri)); - assert(!serd_sink_write(sink, 0, base, uri, blank, NULL)); - assert(serd_node_equals(state.last_subject, base)); - assert(serd_node_equals(state.last_predicate, uri)); - assert(serd_node_equals(state.last_object, blank)); - assert(!state.last_graph); + assert(!serd_sink_write_statement(sink, 0, statement)); + assert(serd_statement_equals(state.last_statement, statement)); assert(!serd_sink_write_end(sink, blank)); assert(serd_node_equals(state.last_end, blank)); serd_sink_free(sink); + + serd_statement_free(statement); serd_env_free(env); serd_node_free(blank); serd_node_free(uri); diff --git a/test/test_statement.c b/test/test_statement.c new file mode 100644 index 00000000..844955f8 --- /dev/null +++ b/test/test_statement.c @@ -0,0 +1,142 @@ +// Copyright 2011-2020 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#undef NDEBUG + +#include "serd/caret.h" +#include "serd/node.h" +#include "serd/statement.h" +#include "serd/string_view.h" + +#include <assert.h> +#include <stddef.h> + +#define NS_EG "http://example.org/" + +static void +test_new(void) +{ + SerdNode* const u = serd_new_uri(serd_string(NS_EG "s")); + SerdNode* const c = serd_new_curie(serd_string("eg:c")); + SerdNode* const b = serd_new_blank(serd_string("b0")); + SerdNode* const l = serd_new_string(serd_string("str")); + + assert(!serd_statement_new(c, b, u, NULL, NULL)); + assert(!serd_statement_new(l, c, u, NULL, NULL)); + assert(!serd_statement_new(l, u, c, u, NULL)); + assert(!serd_statement_new(u, l, c, NULL, NULL)); + assert(!serd_statement_new(u, l, u, u, NULL)); + assert(!serd_statement_new(u, l, u, u, NULL)); + + serd_node_free(l); + serd_node_free(b); + serd_node_free(u); + serd_node_free(c); +} + +static void +test_copy(void) +{ + assert(!serd_statement_copy(NULL)); + + SerdNode* const f = serd_new_string(serd_string("file")); + SerdNode* const s = serd_new_uri(serd_string(NS_EG "s")); + SerdNode* const p = serd_new_uri(serd_string(NS_EG "p")); + SerdNode* const o = serd_new_uri(serd_string(NS_EG "o")); + SerdNode* const g = serd_new_uri(serd_string(NS_EG "g")); + + SerdCaret* const caret = serd_caret_new(f, 1, 1); + SerdStatement* const statement = serd_statement_new(s, p, o, g, caret); + SerdStatement* const copy = serd_statement_copy(statement); + + assert(serd_statement_equals(copy, statement)); + assert(serd_caret_equals(serd_statement_caret(copy), caret)); + + serd_statement_free(copy); + serd_caret_free(caret); + serd_statement_free(statement); + serd_node_free(g); + serd_node_free(o); + serd_node_free(p); + serd_node_free(s); + serd_node_free(f); +} + +static void +test_free(void) +{ + serd_statement_free(NULL); +} + +static void +test_fields(void) +{ + SerdNode* const f = serd_new_string(serd_string("file")); + SerdNode* const s = serd_new_uri(serd_string(NS_EG "s")); + SerdNode* const p = serd_new_uri(serd_string(NS_EG "p")); + SerdNode* const o = serd_new_uri(serd_string(NS_EG "o")); + SerdNode* const g = serd_new_uri(serd_string(NS_EG "g")); + + SerdCaret* const caret = serd_caret_new(f, 1, 1); + SerdStatement* const statement = serd_statement_new(s, p, o, g, caret); + + assert(serd_statement_equals(statement, statement)); + assert(!serd_statement_equals(statement, NULL)); + assert(!serd_statement_equals(NULL, statement)); + + assert(serd_statement_node(statement, SERD_SUBJECT) == s); + assert(serd_statement_node(statement, SERD_PREDICATE) == p); + assert(serd_statement_node(statement, SERD_OBJECT) == o); + assert(serd_statement_node(statement, SERD_GRAPH) == g); + + assert(serd_statement_subject(statement) == s); + assert(serd_statement_predicate(statement) == p); + assert(serd_statement_object(statement) == o); + assert(serd_statement_graph(statement) == g); + assert(serd_statement_caret(statement) != caret); + assert(serd_caret_equals(serd_statement_caret(statement), caret)); + assert(serd_statement_matches(statement, s, p, o, g)); + assert(serd_statement_matches(statement, NULL, p, o, g)); + assert(serd_statement_matches(statement, s, NULL, o, g)); + assert(serd_statement_matches(statement, s, p, NULL, g)); + assert(serd_statement_matches(statement, s, p, o, NULL)); + assert(!serd_statement_matches(statement, o, NULL, NULL, NULL)); + assert(!serd_statement_matches(statement, NULL, o, NULL, NULL)); + assert(!serd_statement_matches(statement, NULL, NULL, s, NULL)); + assert(!serd_statement_matches(statement, NULL, NULL, NULL, s)); + + SerdStatement* const diff_s = serd_statement_new(o, p, o, g, caret); + assert(!serd_statement_equals(statement, diff_s)); + serd_statement_free(diff_s); + + SerdStatement* const diff_p = serd_statement_new(s, o, o, g, caret); + assert(!serd_statement_equals(statement, diff_p)); + serd_statement_free(diff_p); + + SerdStatement* const diff_o = serd_statement_new(s, p, s, g, caret); + assert(!serd_statement_equals(statement, diff_o)); + serd_statement_free(diff_o); + + SerdStatement* const diff_g = serd_statement_new(s, p, o, s, caret); + assert(!serd_statement_equals(statement, diff_g)); + serd_statement_free(diff_g); + + serd_statement_free(statement); + serd_caret_free(caret); + serd_node_free(g); + serd_node_free(o); + serd_node_free(p); + serd_node_free(s); + serd_node_free(f); +} + +int +main(void) +{ + test_new(); + test_copy(); + test_free(); + test_fields(); + + return 0; +} |