diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/meson.build | 1 | ||||
-rw-r--r-- | test/test_reader.c | 233 | ||||
-rw-r--r-- | test/test_reader_writer.c | 176 |
3 files changed, 234 insertions, 176 deletions
diff --git a/test/meson.build b/test/meson.build index 1245e29d..676fbcf3 100644 --- a/test/meson.build +++ b/test/meson.build @@ -13,6 +13,7 @@ unit_tests = [ 'nodes', 'overflow', 'read_chunk', + 'reader', 'reader_writer', 'sink', 'statement', diff --git a/test/test_reader.c b/test/test_reader.c new file mode 100644 index 00000000..a641a26a --- /dev/null +++ b/test/test_reader.c @@ -0,0 +1,233 @@ +/* + Copyright 2011-2021 David Robillard <d@drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#undef NDEBUG + +#include "serd/serd.h" + +#include <assert.h> +#include <stdio.h> +#include <string.h> + +static SerdStatus +count_statements(void* handle, const SerdEvent* event) +{ + if (event->type == SERD_STATEMENT) { + ++*(size_t*)handle; + } + + return SERD_SUCCESS; +} + +static void +test_read_string(void) +{ + SerdWorld* world = serd_world_new(); + size_t n_statements = 0; + + SerdSink* sink = serd_sink_new(&n_statements, count_statements, NULL); + assert(sink); + + SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096); + assert(reader); + + // Test reading a string that ends exactly at the end of input (no newline) + assert( + !serd_reader_start_string(reader, + "<http://example.org/s> <http://example.org/p> " + "<http://example.org/o> .", + NULL)); + + assert(!serd_reader_read_document(reader)); + assert(n_statements == 1); + assert(!serd_reader_finish(reader)); + + serd_reader_free(reader); + serd_sink_free(sink); + serd_world_free(world); +} + +/// Reads a null byte after a statement, then succeeds again (like a socket) +static size_t +eof_test_read(void* buf, size_t size, size_t nmemb, void* stream) +{ + assert(size == 1); + assert(nmemb == 1); + (void)size; + + static const char* const string = "_:s1 <http://example.org/p> _:o1 .\n" + "_:s2 <http://example.org/p> _:o2 .\n"; + + size_t* const count = (size_t*)stream; + + // Normal reading for the first statement + if (*count < 35) { + *(char*)buf = string[*count]; + ++*count; + return nmemb; + } + + // EOF for the first read at the start of the second statement + if (*count == 35) { + assert(string[*count] == '_'); + ++*count; + return 0; + } + + if (*count >= strlen(string)) { + return 0; + } + + // Normal reading after the EOF, adjusting for the skipped index 35 + *(char*)buf = string[*count - 1]; + ++*count; + return nmemb; +} + +static int +eof_test_error(void* stream) +{ + (void)stream; + return 0; +} + +/// A read of a big page hits EOF then fails to read chunks immediately +static void +test_read_eof_by_page(void) +{ + FILE* const temp = tmpfile(); + assert(temp); + + fprintf(temp, "_:s <http://example.org/p> _:o .\n"); + fflush(temp); + fseek(temp, 0L, SEEK_SET); + + SerdWorld* world = serd_world_new(); + size_t ignored = 0u; + SerdSink* sink = serd_sink_new(&ignored, count_statements, NULL); + SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096); + + serd_reader_start_stream( + reader, (SerdReadFunc)fread, (SerdStreamErrorFunc)ferror, temp, NULL, 4096); + + assert(serd_reader_read_chunk(reader) == SERD_SUCCESS); + assert(serd_reader_read_chunk(reader) == SERD_FAILURE); + assert(serd_reader_read_chunk(reader) == SERD_FAILURE); + + serd_reader_free(reader); + serd_sink_free(sink); + serd_world_free(world); + fclose(temp); +} + +// A byte-wise reader hits EOF once then continues (like a socket) +static void +test_read_eof_by_byte(void) +{ + SerdWorld* world = serd_world_new(); + size_t ignored = 0u; + SerdSink* sink = serd_sink_new(&ignored, count_statements, NULL); + SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096); + + size_t n_reads = 0u; + serd_reader_start_stream(reader, + (SerdReadFunc)eof_test_read, + (SerdStreamErrorFunc)eof_test_error, + &n_reads, + NULL, + 1); + + assert(serd_reader_read_chunk(reader) == SERD_SUCCESS); + assert(serd_reader_read_chunk(reader) == SERD_FAILURE); + assert(serd_reader_read_chunk(reader) == SERD_SUCCESS); + assert(serd_reader_read_chunk(reader) == SERD_FAILURE); + + serd_reader_free(reader); + serd_sink_free(sink); + serd_world_free(world); +} + +static void +test_read_chunks(void) +{ + SerdWorld* world = serd_world_new(); + size_t n_statements = 0; + FILE* const f = tmpfile(); + static const char null = 0; + + SerdSink* const sink = serd_sink_new(&n_statements, count_statements, NULL); + assert(sink); + + SerdReader* const reader = serd_reader_new(world, SERD_TURTLE, sink, 4096); + assert(reader); + + SerdStatus st = serd_reader_start_stream( + reader, (SerdReadFunc)fread, (SerdStreamErrorFunc)ferror, f, NULL, 1); + assert(st == SERD_SUCCESS); + + // Write two statement separated by null characters + fprintf(f, "@prefix eg: <http://example.org/> .\n"); + fprintf(f, "eg:s eg:p eg:o1 .\n"); + fwrite(&null, sizeof(null), 1, f); + fprintf(f, "eg:s eg:p eg:o2 .\n"); + fwrite(&null, sizeof(null), 1, f); + fseek(f, 0, SEEK_SET); + + // Read prefix + st = serd_reader_read_chunk(reader); + assert(st == SERD_SUCCESS); + assert(n_statements == 0); + + // Read first statement + st = serd_reader_read_chunk(reader); + assert(st == SERD_SUCCESS); + assert(n_statements == 1); + + // Read terminator + st = serd_reader_read_chunk(reader); + assert(st == SERD_FAILURE); + assert(n_statements == 1); + + // Read second statement (after null terminator) + st = serd_reader_read_chunk(reader); + assert(st == SERD_SUCCESS); + assert(n_statements == 2); + + // Read terminator + st = serd_reader_read_chunk(reader); + assert(st == SERD_FAILURE); + assert(n_statements == 2); + + // EOF + st = serd_reader_read_chunk(reader); + assert(st == SERD_FAILURE); + assert(n_statements == 2); + + serd_reader_free(reader); + serd_sink_free(sink); + fclose(f); + serd_world_free(world); +} + +int +main(void) +{ + test_read_string(); + test_read_eof_by_page(); + test_read_eof_by_byte(); + test_read_chunks(); + return 0; +} diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c index 82d67bee..fa45786c 100644 --- a/test/test_reader_writer.c +++ b/test/test_reader_writer.c @@ -34,140 +34,6 @@ count_statements(void* handle, const SerdEvent* event) return SERD_SUCCESS; } -/// Reads a null byte after a statement, then succeeds again (like a socket) -static size_t -eof_test_read(void* buf, size_t size, size_t nmemb, void* stream) -{ - assert(size == 1); - assert(nmemb == 1); - (void)size; - - static const char* const string = "_:s1 <http://example.org/p> _:o1 .\n" - "_:s2 <http://example.org/p> _:o2 .\n"; - - size_t* const count = (size_t*)stream; - - // Normal reading for the first statement - if (*count < 35) { - *(char*)buf = string[*count]; - ++*count; - return nmemb; - } - - // EOF for the first read at the start of the second statement - if (*count == 35) { - assert(string[*count] == '_'); - ++*count; - return 0; - } - - if (*count >= strlen(string)) { - return 0; - } - - // Normal reading after the EOF, adjusting for the skipped index 35 - *(char*)buf = string[*count - 1]; - ++*count; - return nmemb; -} - -static int -eof_test_error(void* stream) -{ - (void)stream; - return 0; -} - -static void -test_read_chunks(void) -{ - SerdWorld* world = serd_world_new(); - size_t n_statements = 0; - FILE* const f = tmpfile(); - static const char null = 0; - - SerdSink* const sink = serd_sink_new(&n_statements, count_statements, NULL); - assert(sink); - - SerdReader* const reader = serd_reader_new(world, SERD_TURTLE, sink, 4096); - assert(reader); - - SerdStatus st = serd_reader_start_stream( - reader, (SerdReadFunc)fread, (SerdStreamErrorFunc)ferror, f, NULL, 1); - assert(st == SERD_SUCCESS); - - // Write two statement separated by null characters - fprintf(f, "@prefix eg: <http://example.org/> .\n"); - fprintf(f, "eg:s eg:p eg:o1 .\n"); - fwrite(&null, sizeof(null), 1, f); - fprintf(f, "eg:s eg:p eg:o2 .\n"); - fwrite(&null, sizeof(null), 1, f); - fseek(f, 0, SEEK_SET); - - // Read prefix - st = serd_reader_read_chunk(reader); - assert(st == SERD_SUCCESS); - assert(n_statements == 0); - - // Read first statement - st = serd_reader_read_chunk(reader); - assert(st == SERD_SUCCESS); - assert(n_statements == 1); - - // Read terminator - st = serd_reader_read_chunk(reader); - assert(st == SERD_FAILURE); - assert(n_statements == 1); - - // Read second statement (after null terminator) - st = serd_reader_read_chunk(reader); - assert(st == SERD_SUCCESS); - assert(n_statements == 2); - - // Read terminator - st = serd_reader_read_chunk(reader); - assert(st == SERD_FAILURE); - assert(n_statements == 2); - - // EOF - st = serd_reader_read_chunk(reader); - assert(st == SERD_FAILURE); - assert(n_statements == 2); - - serd_reader_free(reader); - serd_sink_free(sink); - fclose(f); - serd_world_free(world); -} - -static void -test_read_string(void) -{ - SerdWorld* world = serd_world_new(); - size_t n_statements = 0; - - SerdSink* sink = serd_sink_new(&n_statements, count_statements, NULL); - assert(sink); - - SerdReader* reader = serd_reader_new(world, SERD_TURTLE, sink, 4096); - assert(reader); - - // Test reading a string that ends exactly at the end of input (no newline) - assert( - !serd_reader_start_string(reader, - "<http://example.org/s> <http://example.org/p> " - "<http://example.org/o> .", - NULL)); - - assert(!serd_reader_read_document(reader)); - assert(n_statements == 1); - assert(!serd_reader_finish(reader)); - - serd_reader_free(reader); - serd_sink_free(sink); - serd_world_free(world); -} - static void test_writer(const char* const path) { @@ -303,45 +169,6 @@ test_reader(const char* path) assert(n_statements == 6); serd_reader_finish(reader); - // A read of a big page hits EOF then fails to read chunks immediately - { - FILE* temp = tmpfile(); - assert(temp); - fprintf(temp, "_:s <http://example.org/p> _:o .\n"); - fflush(temp); - fseek(temp, 0L, SEEK_SET); - - serd_reader_start_stream(reader, - (SerdReadFunc)fread, - (SerdStreamErrorFunc)ferror, - temp, - NULL, - 4096); - - assert(serd_reader_read_chunk(reader) == SERD_SUCCESS); - assert(serd_reader_read_chunk(reader) == SERD_FAILURE); - assert(serd_reader_read_chunk(reader) == SERD_FAILURE); - - serd_reader_finish(reader); - fclose(temp); - } - - // A byte-wise reader that hits EOF once then continues (like a socket) - { - size_t n_reads = 0; - serd_reader_start_stream(reader, - (SerdReadFunc)eof_test_read, - (SerdStreamErrorFunc)eof_test_error, - &n_reads, - NULL, - 1); - - assert(serd_reader_read_chunk(reader) == SERD_SUCCESS); - assert(serd_reader_read_chunk(reader) == SERD_FAILURE); - assert(serd_reader_read_chunk(reader) == SERD_SUCCESS); - assert(serd_reader_read_chunk(reader) == SERD_FAILURE); - } - serd_reader_free(reader); serd_sink_free(sink); serd_world_free(world); @@ -350,9 +177,6 @@ test_reader(const char* path) int main(void) { - test_read_chunks(); - test_read_string(); - const char* const path = "serd_test.ttl"; test_writer(path); test_reader(path); |