aboutsummaryrefslogtreecommitdiffstats
path: root/test/test_reader_writer.c
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2023-04-09 11:54:11 -0400
committerDavid Robillard <d@drobilla.net>2023-04-16 22:17:56 -0400
commita6cd7dd91d93015ec118286b868c3fd43133f3ac (patch)
treeb10d88ca099c0d0986c2e48ccca62023a0ac1614 /test/test_reader_writer.c
parent1d8cdcef2cc4aaf2e45cfab01a390d6eab56d525 (diff)
downloadserd-a6cd7dd91d93015ec118286b868c3fd43133f3ac.tar.gz
serd-a6cd7dd91d93015ec118286b868c3fd43133f3ac.tar.bz2
serd-a6cd7dd91d93015ec118286b868c3fd43133f3ac.zip
Gracefully handle errors when writing text
Diffstat (limited to 'test/test_reader_writer.c')
-rw-r--r--test/test_reader_writer.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c
index 32367bf7..83ee7b2f 100644
--- a/test/test_reader_writer.c
+++ b/test/test_reader_writer.c
@@ -10,6 +10,7 @@
#endif
#include <assert.h>
+#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@@ -19,6 +20,11 @@
#define USTR(s) ((const uint8_t*)(s))
typedef struct {
+ size_t n_written;
+ size_t error_offset;
+} ErrorContext;
+
+typedef struct {
int n_base;
int n_prefix;
int n_statement;
@@ -26,6 +32,29 @@ typedef struct {
const SerdNode* graph;
} ReaderTest;
+static const char* const doc_string =
+ "@base <http://drobilla.net/> .\n"
+ "@prefix eg: <http://example.org/> .\n"
+ "eg:g {\n"
+ "<http://example.com/s> eg:p \"l\\n\\\"it\" ,\n"
+ " \"\"\"long\"\"\" ,\n"
+ " \"lang\"@en ;\n"
+ " eg:p <http://example.com/o> .\n"
+ "}\n"
+ "eg:s\n"
+ " <http://example.org/p> [\n"
+ " eg:p 3.0 ,\n"
+ " 4 ,\n"
+ " \"lit\" ,\n"
+ " _:n42 ,\n"
+ " \"t\"^^eg:T\n"
+ " ] ;\n"
+ " eg:p () ;\n"
+ " eg:p\\!q (\"s\" 1 2.0 \"l\"@en eg:o) .\n"
+ "[] eg:p eg:o .\n"
+ "[ eg:p eg:o ] eg:q eg:r .\n"
+ "( eg:o ) eg:t eg:u .\n";
+
static SerdStatus
test_base_sink(void* handle, const SerdNode* uri)
{
@@ -250,6 +279,73 @@ test_read_string(void)
serd_reader_free(reader);
}
+static size_t
+faulty_sink(const void* const buf, const size_t len, void* const stream)
+{
+ (void)buf;
+ (void)len;
+
+ ErrorContext* const ctx = (ErrorContext*)stream;
+ const size_t new_n_written = ctx->n_written + len;
+ if (new_n_written >= ctx->error_offset) {
+ errno = EINVAL;
+ return 0U;
+ }
+
+ ctx->n_written += len;
+ errno = 0;
+ return len;
+}
+
+static SerdStatus
+quiet_error_sink(void* const handle, const SerdError* const e)
+{
+ (void)handle;
+ (void)e;
+ return SERD_SUCCESS;
+}
+
+static void
+test_write_errors(void)
+{
+ ErrorContext ctx = {0U, 0U};
+ const SerdStyle style = (SerdStyle)(SERD_STYLE_STRICT | SERD_STYLE_CURIED);
+
+ const size_t max_offsets[] = {0, 386, 1911, 2003, 386};
+
+ // Test errors at different offsets to hit different code paths
+ for (unsigned s = 1; s <= (unsigned)SERD_TRIG; ++s) {
+ const SerdSyntax syntax = (SerdSyntax)s;
+ for (size_t o = 0; o < max_offsets[s]; ++o) {
+ ctx.n_written = 0;
+ ctx.error_offset = o;
+
+ SerdEnv* const env = serd_env_new(NULL);
+ SerdWriter* const writer =
+ serd_writer_new(syntax, style, env, NULL, faulty_sink, &ctx);
+
+ SerdReader* const reader =
+ serd_reader_new(SERD_TRIG,
+ writer,
+ NULL,
+ (SerdBaseSink)serd_writer_set_base_uri,
+ (SerdPrefixSink)serd_writer_set_prefix,
+ (SerdStatementSink)serd_writer_write_statement,
+ (SerdEndSink)serd_writer_end_anon);
+
+ serd_reader_set_error_sink(reader, quiet_error_sink, NULL);
+ serd_writer_set_error_sink(writer, quiet_error_sink, NULL);
+
+ const SerdStatus st = serd_reader_read_string(reader, USTR(doc_string));
+ assert(st == SERD_ERR_BAD_WRITE);
+
+ serd_reader_free(reader);
+ serd_writer_free(writer);
+ serd_env_free(env);
+ }
+ }
+}
+
static void
test_writer(const char* const path)
{
@@ -470,6 +566,7 @@ main(void)
test_read_chunks(path);
test_read_string();
+ test_write_errors();
test_writer(path);
test_reader(path);