diff options
author | David Robillard <d@drobilla.net> | 2023-04-09 11:54:11 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2023-04-16 22:17:56 -0400 |
commit | a6cd7dd91d93015ec118286b868c3fd43133f3ac (patch) | |
tree | b10d88ca099c0d0986c2e48ccca62023a0ac1614 /test/test_reader_writer.c | |
parent | 1d8cdcef2cc4aaf2e45cfab01a390d6eab56d525 (diff) | |
download | serd-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.c | 97 |
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); |