From 248a874d7425749d29cf900a1c3783c624ea8d8c Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 10 Sep 2023 15:06:42 -0400 Subject: Add support for custom allocators This makes it explicit in the API where memory is allocated, and allows the user to provide a custom allocator to avoid the use of the default system allocator for whatever reason. --- test/test_reader.c | 144 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 111 insertions(+), 33 deletions(-) (limited to 'test/test_reader.c') diff --git a/test/test_reader.c b/test/test_reader.c index f1ec1d35..a0eaee5c 100644 --- a/test/test_reader.c +++ b/test/test_reader.c @@ -3,6 +3,8 @@ #undef NDEBUG +#include "failing_allocator.h" + #include "serd/caret.h" #include "serd/env.h" #include "serd/event.h" @@ -60,6 +62,81 @@ test_sink(void* handle, const SerdEvent* event) return SERD_SUCCESS; } +static void +test_new_failed_alloc(void) +{ + SerdFailingAllocator allocator = serd_failing_allocator(); + + SerdWorld* const world = serd_world_new(&allocator.base); + SerdEnv* const env = serd_env_new(&allocator.base, serd_empty_string()); + size_t ignored = 0U; + SerdSink* const sink = + serd_sink_new(&allocator.base, &ignored, test_sink, NULL); + + // Successfully allocate a reader to count the number of allocations + const size_t n_world_allocs = allocator.n_allocations; + SerdReader* reader = serd_reader_new(world, SERD_TURTLE, 0U, env, sink); + assert(reader); + + // Test that each allocation failing is handled gracefully + const size_t n_new_allocs = allocator.n_allocations - n_world_allocs; + for (size_t i = 0; i < n_new_allocs; ++i) { + allocator.n_remaining = i; + assert(!serd_reader_new(world, SERD_TURTLE, 0U, env, sink)); + } + + serd_reader_free(reader); + serd_env_free(env); + serd_sink_free(sink); + serd_world_free(world); +} + +static void +test_start_failed_alloc(const char* const path) +{ + SerdFailingAllocator allocator = serd_failing_allocator(); + + FILE* const f = fopen(path, "w+b"); + assert(f); + + fprintf(f, "_:s _:o .\n"); + fflush(f); + fseek(f, 0L, SEEK_SET); + + SerdWorld* world = serd_world_new(&allocator.base); + SerdEnv* env = serd_env_new(&allocator.base, serd_empty_string()); + size_t ignored = 0U; + SerdSink* sink = serd_sink_new(&allocator.base, &ignored, test_sink, NULL); + SerdReader* reader = serd_reader_new(world, SERD_TURTLE, 0U, env, sink); + assert(reader); + + SerdInputStream in = + serd_open_input_stream((SerdReadFunc)fread, (SerdErrorFunc)ferror, NULL, f); + + // Successfully start a new read to count the number of allocations + const size_t n_setup_allocs = allocator.n_allocations; + assert(serd_reader_start(reader, &in, NULL, 4096) == SERD_SUCCESS); + + // Test that each allocation failing is handled gracefully + const size_t n_new_allocs = allocator.n_allocations - n_setup_allocs; + assert(!serd_reader_finish(reader)); + for (size_t i = 0; i < n_new_allocs; ++i) { + allocator.n_remaining = i; + + in = serd_open_input_stream( + (SerdReadFunc)fread, (SerdErrorFunc)ferror, NULL, f); + + SerdStatus st = serd_reader_start(reader, &in, NULL, 4096); + assert(st == SERD_BAD_ALLOC); + } + + serd_reader_free(reader); + serd_env_free(env); + serd_sink_free(sink); + serd_world_free(world); + fclose(f); +} + ZIX_PURE_FUNC static size_t prepare_test_read(void* buf, size_t size, size_t nmemb, void* stream) { @@ -84,7 +161,7 @@ prepare_test_error(void* stream) static void test_prepare_error(const char* const path) { - SerdWorld* const world = serd_world_new(); + SerdWorld* const world = serd_world_new(NULL); ReaderTest rt = {0, 0, 0, 0}; FILE* const f = fopen(path, "w+b"); @@ -94,12 +171,11 @@ test_prepare_error(const char* const path) fflush(f); fseek(f, 0L, SEEK_SET); - SerdSink* const sink = serd_sink_new(&rt, test_sink, NULL); + SerdSink* const sink = serd_sink_new(NULL, &rt, test_sink, NULL); assert(sink); - SerdEnv* const env = serd_env_new(serd_empty_string()); + SerdEnv* const env = serd_env_new(NULL, serd_empty_string()); SerdReader* const reader = serd_reader_new(world, SERD_TURTLE, 0, env, sink); - assert(reader); SerdInputStream in = @@ -124,14 +200,13 @@ test_prepare_error(const char* const path) static void test_read_string(void) { - SerdWorld* world = serd_world_new(); + SerdWorld* world = serd_world_new(NULL); ReaderTest rt = {0, 0, 0, 0}; - SerdSink* sink = serd_sink_new(&rt, test_sink, NULL); + SerdSink* sink = serd_sink_new(NULL, &rt, test_sink, NULL); assert(sink); - SerdEnv* const env = serd_env_new(serd_empty_string()); + SerdEnv* const env = serd_env_new(NULL, serd_empty_string()); SerdReader* const reader = serd_reader_new(world, SERD_TURTLE, 0U, env, sink); - assert(reader); static const char* const string1 = @@ -228,11 +303,12 @@ test_read_eof_by_page(const char* const path) fflush(f); fseek(f, 0L, SEEK_SET); - SerdWorld* world = serd_world_new(); - ReaderTest ignored = {0, 0, 0, 0}; - SerdSink* sink = serd_sink_new(&ignored, test_sink, NULL); - SerdEnv* env = serd_env_new(serd_empty_string()); - SerdReader* reader = serd_reader_new(world, SERD_TURTLE, 0U, env, sink); + SerdWorld* const world = serd_world_new(NULL); + ReaderTest rt = {0, 0, 0, 0}; + SerdSink* const sink = serd_sink_new(NULL, &rt, test_sink, NULL); + SerdEnv* const env = serd_env_new(NULL, serd_empty_string()); + SerdReader* reader = serd_reader_new(world, SERD_TURTLE, 0U, env, sink); + SerdInputStream in = serd_open_input_stream((SerdReadFunc)fread, (SerdErrorFunc)ferror, NULL, f); @@ -255,11 +331,11 @@ test_read_eof_by_page(const char* const path) static void test_read_eof_by_byte(void) { - SerdWorld* world = serd_world_new(); - ReaderTest ignored = {0, 0, 0, 0}; - SerdSink* sink = serd_sink_new(&ignored, test_sink, NULL); - SerdEnv* env = serd_env_new(serd_empty_string()); - SerdReader* reader = serd_reader_new(world, SERD_TURTLE, 0U, env, sink); + SerdWorld* const world = serd_world_new(NULL); + ReaderTest rt = {0, 0, 0, 0}; + SerdSink* const sink = serd_sink_new(NULL, &rt, test_sink, NULL); + SerdEnv* const env = serd_env_new(NULL, serd_empty_string()); + SerdReader* reader = serd_reader_new(world, SERD_TURTLE, 0U, env, sink); size_t n_reads = 0U; SerdInputStream in = serd_open_input_stream( @@ -305,12 +381,12 @@ test_read_nquads_chunks(const char* const path) fseek(f, 0, SEEK_SET); - SerdWorld* const world = serd_world_new(); + SerdWorld* const world = serd_world_new(NULL); ReaderTest rt = {0, 0, 0, 0}; - SerdSink* const sink = serd_sink_new(&rt, test_sink, NULL); + SerdSink* const sink = serd_sink_new(NULL, &rt, test_sink, NULL); assert(sink); - SerdEnv* const env = serd_env_new(serd_empty_string()); + SerdEnv* const env = serd_env_new(NULL, serd_empty_string()); assert(env); SerdReader* const reader = serd_reader_new(world, SERD_TURTLE, 0U, env, sink); @@ -391,12 +467,12 @@ test_read_turtle_chunks(const char* const path) fwrite(&null, sizeof(null), 1, f); fseek(f, 0, SEEK_SET); - SerdWorld* world = serd_world_new(); - ReaderTest rt = {0, 0, 0, 0}; - SerdSink* sink = serd_sink_new(&rt, test_sink, NULL); + SerdWorld* const world = serd_world_new(NULL); + ReaderTest rt = {0, 0, 0, 0}; + SerdSink* const sink = serd_sink_new(NULL, &rt, test_sink, NULL); assert(sink); - SerdEnv* const env = serd_env_new(serd_empty_string()); + SerdEnv* const env = serd_env_new(NULL, serd_empty_string()); assert(env); SerdReader* const reader = serd_reader_new(world, SERD_TURTLE, 0U, env, sink); @@ -479,13 +555,13 @@ test_read_turtle_chunks(const char* const path) static void test_read_empty(const char* const path) { - SerdWorld* const world = serd_world_new(); + SerdWorld* const world = serd_world_new(NULL); ReaderTest rt = {0, 0, 0, 0}; - SerdSink* const sink = serd_sink_new(&rt, test_sink, NULL); + SerdSink* const sink = serd_sink_new(NULL, &rt, test_sink, NULL); assert(sink); - SerdEnv* const env = serd_env_new(serd_empty_string()); + SerdEnv* const env = serd_env_new(NULL, serd_empty_string()); assert(env); SerdReader* const reader = @@ -536,10 +612,10 @@ check_cursor(void* handle, const SerdEvent* event) static void test_error_cursor(void) { - SerdWorld* world = serd_world_new(); + SerdWorld* const world = serd_world_new(NULL); bool called = false; - SerdSink* sink = serd_sink_new(&called, check_cursor, NULL); - SerdEnv* const env = serd_env_new(serd_empty_string()); + SerdSink* const sink = serd_sink_new(NULL, &called, check_cursor, NULL); + SerdEnv* const env = serd_env_new(NULL, serd_empty_string()); SerdReader* const reader = serd_reader_new(world, SERD_TURTLE, 0U, env, sink); assert(sink); assert(reader); @@ -548,7 +624,7 @@ test_error_cursor(void) " " " ."; - SerdNode* const string_name = serd_new_string(serd_string("string")); + SerdNode* const string_name = serd_new_string(NULL, serd_string("string")); const char* position = string; SerdInputStream in = serd_open_input_string(&position); @@ -559,7 +635,7 @@ test_error_cursor(void) assert(called); assert(!serd_close_input(&in)); - serd_node_free(string_name); + serd_node_free(NULL, string_name); serd_reader_free(reader); serd_env_free(env); serd_sink_free(sink); @@ -575,6 +651,8 @@ main(void) char* const ttl_path = zix_path_join(NULL, dir, "serd_test_reader.ttl"); char* const nq_path = zix_path_join(NULL, dir, "serd_test_reader.nq"); + test_new_failed_alloc(); + test_start_failed_alloc(ttl_path); test_read_nquads_chunks(nq_path); test_read_turtle_chunks(ttl_path); test_prepare_error(ttl_path); -- cgit v1.2.1