From 41141360516e93101ae60bd737a3fb8f250f8f7d Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 11 Jul 2021 11:14:28 -0400 Subject: Split out simple reader unit tests --- test/test_reader.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 test/test_reader.c (limited to 'test/test_reader.c') 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 + + 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 +#include +#include + +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, + " " + " .", + 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 _:o1 .\n" + "_:s2 _: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 _: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: .\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; +} -- cgit v1.2.1