diff options
-rw-r--r-- | .clang-format | 30 | ||||
-rw-r--r-- | .gitlab-ci.yml | 4 | ||||
-rw-r--r-- | .reuse/dep5 | 5 | ||||
-rw-r--r-- | .suppress.cppcheck | 4 | ||||
-rw-r--r-- | include/serd/serd.h | 15 | ||||
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | meson_options.txt | 12 | ||||
-rw-r--r-- | src/byte_sink.h | 8 | ||||
-rw-r--r-- | src/byte_source.h | 4 | ||||
-rw-r--r-- | src/n3.c | 28 | ||||
-rw-r--r-- | src/node.h | 4 | ||||
-rw-r--r-- | src/reader.c | 4 | ||||
-rw-r--r-- | src/reader.h | 23 | ||||
-rw-r--r-- | src/serd_internal.h | 4 | ||||
-rw-r--r-- | src/stack.h | 16 | ||||
-rw-r--r-- | src/string_utils.h | 8 | ||||
-rw-r--r-- | src/system.c | 1 | ||||
-rw-r--r-- | src/uri.c | 16 | ||||
-rw-r--r-- | src/uri_utils.h | 12 | ||||
-rw-r--r-- | src/writer.c | 185 | ||||
-rw-r--r-- | test/headers/test_headers.c | 3 | ||||
-rw-r--r-- | test/meson.build | 252 | ||||
-rw-r--r-- | test/serd_test_util/__init__.py | 29 | ||||
-rw-r--r-- | test/test_env.c | 4 | ||||
-rw-r--r-- | test/test_node.c | 6 | ||||
-rwxr-xr-x | test/test_quiet.py | 12 | ||||
-rw-r--r-- | test/test_reader.c | 78 | ||||
-rw-r--r-- | test/test_reader_writer.c | 24 | ||||
-rwxr-xr-x | test/test_stdin.py | 37 | ||||
-rw-r--r-- | test/test_string.c | 3 | ||||
-rw-r--r-- | test/test_uri.c | 107 | ||||
-rwxr-xr-x | test/test_write_error.py | 9 | ||||
-rw-r--r-- | test/test_writer.c | 1 |
33 files changed, 486 insertions, 463 deletions
diff --git a/.clang-format b/.clang-format index 26b10123..1ec52448 100644 --- a/.clang-format +++ b/.clang-format @@ -1,17 +1,29 @@ -# Copyright 2020-2023 David Robillard <d@drobilla.net> +# Copyright 2020-2024 David Robillard <d@drobilla.net> # SPDX-License-Identifier: 0BSD OR ISC --- AlignConsecutiveAssignments: true AlignConsecutiveDeclarations: true -AlignEscapedNewlinesLeft: true +AlignEscapedNewlines: Left +AttributeMacros: + - SERD_ALLOCATED + - SERD_API + - SERD_CONST_API + - SERD_CONST_FUNC + - SERD_FALLTHROUGH + - SERD_MALLOC_FUNC + - SERD_NODISCARD + - SERD_NONNULL + - SERD_NULLABLE + - SERD_PURE_API + - SERD_PURE_FUNC BasedOnStyle: Mozilla BraceWrapping: - AfterNamespace: false AfterClass: true AfterEnum: false AfterExternBlock: false AfterFunction: true + AfterNamespace: false AfterStruct: false SplitEmptyFunction: false SplitEmptyRecord: false @@ -21,20 +33,10 @@ IndentCaseLabels: false IndentPPDirectives: AfterHash KeepEmptyLinesAtTheStartOfBlocks: false SpacesInContainerLiterals: false -AttributeMacros: - - SERD_ALLOCATED - - SERD_API - - SERD_CONST_FINC - - SERD_FALLTHROUGH - - SERD_MALLOC_FUNC - - SERD_NODISCARD - - SERD_NONNULL - - SERD_NULLABLE - - SERD_PURE_FUNC StatementMacros: - SERD_DEPRECATED_BY - - SERD_LOG_FUNC - SERD_DISABLE_NULL_WARNINGS + - SERD_LOG_FUNC - SERD_RESTORE_WARNINGS - _Pragma ... diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ec20e2f7..41904c85 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,7 +41,7 @@ sanitize: stage: build image: lv2plugin/debian-x64-clang script: - - meson setup build -Db_lundef=false -Dbuildtype=plain -Dc_std=c11 -Ddocs=disabled -Dwarning_level=3 -Dwerror=true + - meson setup build -Db_lundef=false -Dbuildtype=plain -Dc_std=c11 -Ddocs=disabled -Dlint=true -Dwarning_level=3 -Dwerror=true - ninja -C build test variables: CC: "clang" @@ -158,4 +158,4 @@ pages: paths: - public only: - - master + - main diff --git a/.reuse/dep5 b/.reuse/dep5 index 3173226a..78dc2af5 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -3,6 +3,11 @@ Upstream-Name: serd Upstream-Contact: David Robillard <d@drobilla.net> Source: https://gitlab.com/drobilla/serd +Files: .suppress.cppcheck +Copyright: 2024 David Robillard <d@drobilla.net> +Comment: Contributed to the Commons as a tool configuration +License: 0BSD OR ISC + Files: test/w3c/* Copyright: 2010 World Wide Web Consortium, (MIT, ERCIM, Keio, Beihang) and others. Comment: Standard test suites from the W3C diff --git a/.suppress.cppcheck b/.suppress.cppcheck new file mode 100644 index 00000000..292f6884 --- /dev/null +++ b/.suppress.cppcheck @@ -0,0 +1,4 @@ +assignmentInAssert +normalCheckLevelMaxBranches +redundantInitialization +unreadVariable diff --git a/include/serd/serd.h b/include/serd/serd.h index 1f84950b..19b4a49c 100644 --- a/include/serd/serd.h +++ b/include/serd/serd.h @@ -127,8 +127,7 @@ typedef enum { } SerdStatus; /// Return a string describing a status code -SERD_CONST_API -const uint8_t* SERD_NONNULL +SERD_CONST_API const uint8_t* SERD_NONNULL serd_strerror(SerdStatus status); /** @@ -268,8 +267,7 @@ serd_file_uri_parse(const uint8_t* SERD_NONNULL uri, uint8_t* SERD_UNSPECIFIED* SERD_NULLABLE hostname); /// Return true iff `utf8` starts with a valid URI scheme -SERD_PURE_API -bool +SERD_PURE_API bool serd_uri_string_has_scheme(const uint8_t* SERD_NULLABLE utf8); /// Parse `utf8`, writing result to `out` @@ -501,8 +499,7 @@ SERD_API SerdNode serd_node_copy(const SerdNode* SERD_NULLABLE node); /// Return true iff `a` is equal to `b` -SERD_PURE_API -bool +SERD_PURE_API bool serd_node_equals(const SerdNode* SERD_NONNULL a, const SerdNode* SERD_NONNULL b); @@ -717,8 +714,7 @@ serd_reader_set_error_sink(SerdReader* SERD_NONNULL reader, void* SERD_UNSPECIFIED error_handle); /// Return the `handle` passed to serd_reader_new() -SERD_PURE_API -void* SERD_UNSPECIFIED +SERD_PURE_API void* SERD_UNSPECIFIED serd_reader_get_handle(const SerdReader* SERD_NONNULL reader); /** @@ -868,8 +864,7 @@ SERD_API void serd_writer_free(SerdWriter* SERD_NULLABLE writer); /// Return the env used by `writer` -SERD_PURE_API -SerdEnv* SERD_NONNULL +SERD_PURE_API SerdEnv* SERD_NONNULL serd_writer_get_env(SerdWriter* SERD_NONNULL writer); /** diff --git a/meson.build b/meson.build index 4b01ff9c..2a05f8a6 100644 --- a/meson.build +++ b/meson.build @@ -16,6 +16,7 @@ project( ) serd_src_root = meson.current_source_dir() +serd_build_root = meson.current_build_dir() major_version = meson.project_version().split('.')[0] version_suffix = '-@0@'.format(major_version) versioned_name = 'serd' + version_suffix diff --git a/meson_options.txt b/meson_options.txt index 09fc2334..30473e89 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,10 +4,10 @@ option('checks', type: 'feature', value: 'enabled', yield: true, description: 'Check for platform-specific features') -option('docs', type: 'feature', value: 'auto', yield: true, +option('docs', type: 'feature', yield: true, description: 'Build documentation') -option('html', type: 'feature', value: 'auto', yield: true, +option('html', type: 'feature', yield: true, description: 'Build paginated HTML documentation') option('lint', type: 'boolean', value: false, yield: true, @@ -16,20 +16,20 @@ option('lint', type: 'boolean', value: false, yield: true, option('man', type: 'feature', value: 'enabled', yield: true, description: 'Install man pages') -option('man_html', type: 'feature', value: 'auto', yield: true, +option('man_html', type: 'feature', yield: true, description: 'Build HTML man pages') -option('singlehtml', type: 'feature', value: 'auto', yield: true, +option('singlehtml', type: 'feature', yield: true, description: 'Build single-page HTML documentation') option('static', type: 'boolean', value: false, yield: true, description: 'Statically link executables') -option('tests', type: 'feature', value: 'auto', yield: true, +option('tests', type: 'feature', yield: true, description: 'Build tests') option('title', type: 'string', value: 'Serd', description: 'Project title') -option('tools', type: 'feature', value: 'auto', yield: true, +option('tools', type: 'feature', yield: true, description: 'Build command line utilities') diff --git a/src/byte_sink.h b/src/byte_sink.h index 65b5eb12..b99b5551 100644 --- a/src/byte_sink.h +++ b/src/byte_sink.h @@ -22,7 +22,7 @@ typedef struct SerdByteSinkImpl { } SerdByteSink; static inline SerdByteSink -serd_byte_sink_new(SerdSink sink, void* stream, size_t block_size) +serd_byte_sink_new(SerdSink sink, void* const stream, const size_t block_size) { SerdByteSink bsink = {sink, stream, NULL, 0, block_size}; @@ -34,7 +34,7 @@ serd_byte_sink_new(SerdSink sink, void* stream, size_t block_size) } static inline SerdStatus -serd_byte_sink_flush(SerdByteSink* bsink) +serd_byte_sink_flush(SerdByteSink* const bsink) { if (bsink->block_size > 1 && bsink->size > 0) { const size_t size = bsink->size; @@ -48,7 +48,7 @@ serd_byte_sink_flush(SerdByteSink* bsink) } static inline void -serd_byte_sink_free(SerdByteSink* bsink) +serd_byte_sink_free(SerdByteSink* const bsink) { serd_byte_sink_flush(bsink); serd_free_aligned(bsink->buf); @@ -56,7 +56,7 @@ serd_byte_sink_free(SerdByteSink* bsink) } static inline size_t -serd_byte_sink_write(const void* buf, size_t len, SerdByteSink* bsink) +serd_byte_sink_write(const void* buf, size_t len, SerdByteSink* const bsink) { if (len == 0) { return 0; diff --git a/src/byte_source.h b/src/byte_source.h index afd9ccb9..961fae72 100644 --- a/src/byte_source.h +++ b/src/byte_source.h @@ -58,14 +58,14 @@ SerdStatus serd_byte_source_page(SerdByteSource* source); static inline SERD_PURE_FUNC uint8_t -serd_byte_source_peek(SerdByteSource* source) +serd_byte_source_peek(SerdByteSource* const source) { assert(source->prepared); return source->read_buf[source->read_head]; } static inline SerdStatus -serd_byte_source_advance(SerdByteSource* source) +serd_byte_source_advance(SerdByteSource* const source) { SerdStatus st = SERD_SUCCESS; @@ -172,7 +172,7 @@ bad_char(SerdReader* const reader, const char* const fmt, const uint8_t c) static SerdStatus read_utf8_bytes(SerdReader* const reader, uint8_t bytes[4], - uint32_t* const size, + uint8_t* const size, const uint8_t c) { *size = utf8_num_bytes(c); @@ -181,9 +181,9 @@ read_utf8_bytes(SerdReader* const reader, } bytes[0] = c; - for (unsigned i = 1; i < *size; ++i) { + for (uint8_t i = 1U; i < *size; ++i) { const int b = peek_byte(reader); - if (b == EOF || ((uint8_t)b & 0x80) == 0) { + if (b == EOF || ((uint8_t)b & 0x80U) == 0U) { return bad_char(reader, "invalid UTF-8 continuation 0x%X\n", (uint8_t)b); } @@ -196,7 +196,7 @@ read_utf8_bytes(SerdReader* const reader, static SerdStatus read_utf8_character(SerdReader* const reader, const Ref dest, const uint8_t c) { - uint32_t size = 0; + uint8_t size = 0U; uint8_t bytes[4] = {0, 0, 0, 0}; SerdStatus st = read_utf8_bytes(reader, bytes, &size, c); if (st) { @@ -214,7 +214,7 @@ read_utf8_code(SerdReader* const reader, uint32_t* const code, const uint8_t c) { - uint32_t size = 0; + uint8_t size = 0U; uint8_t bytes[4] = {0, 0, 0, 0}; SerdStatus st = read_utf8_bytes(reader, bytes, &size, c); if (st) { @@ -740,12 +740,12 @@ read_IRIREF(SerdReader* const reader, Ref* const dest) SERD_ERR_BAD_SYNTAX, "invalid IRI character (escape %%%02X)\n", (unsigned)c); - if (reader->strict) { + if (!reader->strict) { + st = SERD_FAILURE; + push_byte(reader, *dest, c); + } else { break; } - - st = SERD_FAILURE; - push_byte(reader, *dest, c); } else if (!(c & 0x80)) { push_byte(reader, *dest, c); } else if (read_utf8_character(reader, *dest, (uint8_t)c)) { @@ -925,10 +925,10 @@ read_verb(SerdReader* const reader, Ref* const dest) */ *dest = push_node(reader, SERD_CURIE, "", 0); - SerdStatus st = read_PN_PREFIX(reader, *dest); - bool ate_dot = false; - SerdNode* node = deref(reader, *dest); - const int next = peek_byte(reader); + SerdStatus st = read_PN_PREFIX(reader, *dest); + bool ate_dot = false; + const SerdNode* const node = deref(reader, *dest); + const int next = peek_byte(reader); if (!st && node->n_bytes == 1 && node->buf[0] == 'a' && next != ':' && !is_PN_CHARS_BASE((uint32_t)next)) { pop_node(reader, *dest); @@ -1540,7 +1540,7 @@ token_equals(SerdReader* const reader, const char* const tok, const size_t n) { - SerdNode* const node = deref(reader, ref); + const SerdNode* const node = deref(reader, ref); if (!node || node->n_bytes != n) { return false; } @@ -15,13 +15,13 @@ struct SerdNodeImpl { }; static inline char* SERD_NONNULL -serd_node_buffer(SerdNode* SERD_NONNULL node) +serd_node_buffer(SerdNode* const SERD_NONNULL node) { return (char*)(node + 1); } static inline const char* SERD_NONNULL -serd_node_buffer_c(const SerdNode* SERD_NONNULL node) +serd_node_buffer_c(const SerdNode* const SERD_NONNULL node) { return (const char*)(node + 1); } diff --git a/src/reader.c b/src/reader.c index aa24a9ca..5cd978bf 100644 --- a/src/reader.c +++ b/src/reader.c @@ -127,8 +127,8 @@ pop_node(SerdReader* const reader, const Ref ref) SERD_STACK_ASSERT_TOP(reader, ref); --reader->n_allocs; #endif - SerdNode* const node = deref(reader, ref); - uint8_t* const top = reader->stack.buf + reader->stack.size; + SerdNode* const node = deref(reader, ref); + const uint8_t* const top = reader->stack.buf + reader->stack.size; serd_stack_pop_aligned(&reader->stack, (size_t)(top - (uint8_t*)node)); } return 0; diff --git a/src/reader.h b/src/reader.h index 9b558d1f..a867ffc0 100644 --- a/src/reader.h +++ b/src/reader.h @@ -12,8 +12,8 @@ #include <assert.h> #include <stdbool.h> +#include <stddef.h> #include <stdint.h> -#include <stdio.h> #ifdef SERD_STACK_CHECK # define SERD_STACK_ASSERT_TOP(reader, ref) \ @@ -110,15 +110,15 @@ SerdStatus read_turtleTrigDoc(SerdReader* reader); static inline int -peek_byte(SerdReader* reader) +peek_byte(SerdReader* const reader) { SerdByteSource* source = &reader->source; - return source->eof ? EOF : (int)source->read_buf[source->read_head]; + return source->eof ? -1 : (int)source->read_buf[source->read_head]; } static inline SerdStatus -skip_byte(SerdReader* reader, const int byte) +skip_byte(SerdReader* const reader, const int byte) { (void)byte; @@ -128,7 +128,7 @@ skip_byte(SerdReader* reader, const int byte) } static inline int SERD_NODISCARD -eat_byte_safe(SerdReader* reader, const int byte) +eat_byte_safe(SerdReader* const reader, const int byte) { (void)byte; @@ -139,7 +139,7 @@ eat_byte_safe(SerdReader* reader, const int byte) } static inline int SERD_NODISCARD -eat_byte_check(SerdReader* reader, const int byte) +eat_byte_check(SerdReader* const reader, const int byte) { const int c = peek_byte(reader); if (c != byte) { @@ -150,7 +150,7 @@ eat_byte_check(SerdReader* reader, const int byte) } static inline SerdStatus -eat_string(SerdReader* reader, const char* str, unsigned n) +eat_string(SerdReader* const reader, const char* const str, const unsigned n) { for (unsigned i = 0; i < n; ++i) { if (!eat_byte_check(reader, ((const uint8_t*)str)[i])) { @@ -161,9 +161,9 @@ eat_string(SerdReader* reader, const char* str, unsigned n) } static inline SerdStatus -push_byte(SerdReader* reader, Ref ref, const int c) +push_byte(SerdReader* const reader, const Ref ref, const int c) { - assert(c != EOF); + assert(c >= 0); SERD_STACK_ASSERT_TOP(reader, ref); uint8_t* const s = (uint8_t*)serd_stack_push(&reader->stack, 1); @@ -180,7 +180,10 @@ push_byte(SerdReader* reader, Ref ref, const int c) } static inline void -push_bytes(SerdReader* reader, Ref ref, const uint8_t* bytes, unsigned len) +push_bytes(SerdReader* const reader, + const Ref ref, + const uint8_t* const bytes, + const unsigned len) { for (unsigned i = 0; i < len; ++i) { push_byte(reader, ref, bytes[i]); diff --git a/src/serd_internal.h b/src/serd_internal.h index 388c12ec..5508c111 100644 --- a/src/serd_internal.h +++ b/src/serd_internal.h @@ -20,7 +20,9 @@ /* Error reporting */ static inline void -serd_error(SerdErrorSink error_sink, void* handle, const SerdError* e) +serd_error(const SerdErrorSink error_sink, + void* const handle, + const SerdError* const e) { if (error_sink) { error_sink(handle, e); diff --git a/src/stack.h b/src/stack.h index 388dd054..f82de9d2 100644 --- a/src/stack.h +++ b/src/stack.h @@ -24,7 +24,7 @@ typedef struct { #define SERD_STACK_BOTTOM sizeof(void*) static inline SerdStack -serd_stack_new(size_t size) +serd_stack_new(const size_t size) { SerdStack stack; stack.buf = (uint8_t*)calloc(size, 1); @@ -34,13 +34,13 @@ serd_stack_new(size_t size) } static inline bool -serd_stack_is_empty(const SerdStack* stack) +serd_stack_is_empty(const SerdStack* const stack) { return stack->size <= SERD_STACK_BOTTOM; } static inline void -serd_stack_free(SerdStack* stack) +serd_stack_free(SerdStack* const stack) { free(stack->buf); stack->buf = NULL; @@ -49,7 +49,7 @@ serd_stack_free(SerdStack* stack) } static inline void* -serd_stack_push(SerdStack* stack, size_t n_bytes) +serd_stack_push(SerdStack* const stack, const size_t n_bytes) { const size_t new_size = stack->size + n_bytes; if (stack->buf_size < new_size) { @@ -64,14 +64,16 @@ serd_stack_push(SerdStack* stack, size_t n_bytes) } static inline void -serd_stack_pop(SerdStack* stack, size_t n_bytes) +serd_stack_pop(SerdStack* const stack, const size_t n_bytes) { assert(stack->size >= n_bytes); stack->size -= n_bytes; } static inline void* -serd_stack_push_aligned(SerdStack* stack, size_t n_bytes, size_t align) +serd_stack_push_aligned(SerdStack* const stack, + const size_t n_bytes, + const size_t align) { // Push one byte to ensure space for a pad count serd_stack_push(stack, 1); @@ -89,7 +91,7 @@ serd_stack_push_aligned(SerdStack* stack, size_t n_bytes, size_t align) } static inline void -serd_stack_pop_aligned(SerdStack* stack, size_t n_bytes) +serd_stack_pop_aligned(SerdStack* const stack, const size_t n_bytes) { // Pop requested space down to aligned location serd_stack_pop(stack, n_bytes); diff --git a/src/string_utils.h b/src/string_utils.h index 2ce90ac9..7c8348ca 100644 --- a/src/string_utils.h +++ b/src/string_utils.h @@ -107,7 +107,7 @@ serd_strcasecmp(const char* s1, const char* s2) return (c1 == c2) ? 0 : (c1 < c2) ? -1 : +1; } -static inline uint32_t +static inline uint8_t utf8_num_bytes(const uint8_t leading) { return ((leading & 0x80U) == 0x00U) ? 1U // Starts with `0' @@ -119,18 +119,18 @@ utf8_num_bytes(const uint8_t leading) /// Return the code point of a UTF-8 character with known length static inline uint32_t -parse_counted_utf8_char(const uint8_t* utf8, size_t size) +parse_counted_utf8_char(const uint8_t* const utf8, const uint8_t size) { uint32_t c = utf8[0] & ((1U << (8U - size)) - 1U); for (size_t i = 1; i < size; ++i) { - c = (c << 6) | (utf8[i] & 0x3FU); + c = (c << 6U) | (utf8[i] & 0x3FU); } return c; } /// Parse a UTF-8 character, set *size to the length, and return the code point static inline uint32_t -parse_utf8_char(const uint8_t* utf8, size_t* size) +parse_utf8_char(const uint8_t* const utf8, uint8_t* const size) { switch (*size = utf8_num_bytes(utf8[0])) { case 1: diff --git a/src/system.c b/src/system.c index 072d2ed5..84916060 100644 --- a/src/system.c +++ b/src/system.c @@ -15,7 +15,6 @@ #endif #include <errno.h> -#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -15,7 +15,7 @@ #include <string.h> const uint8_t* -serd_uri_to_path(const uint8_t* uri) +serd_uri_to_path(const uint8_t* const uri) { assert(uri); @@ -344,7 +344,7 @@ serd_uri_resolve(const SerdURI* const r, /** Write the path of `uri` starting at index `i` */ static size_t -write_path_tail(SerdSink sink, +write_path_tail(const SerdSink sink, void* const stream, const SerdURI* const uri, const size_t i) @@ -372,7 +372,7 @@ write_path_tail(SerdSink sink, /** Write the path of `uri` relative to the path of `base`. */ static size_t -write_rel_path(SerdSink sink, +write_rel_path(const SerdSink sink, void* const stream, const SerdURI* const uri, const SerdURI* const base) @@ -413,7 +413,7 @@ write_rel_path(SerdSink sink, } static uint8_t -serd_uri_path_starts_without_slash(const SerdURI* uri) +serd_uri_path_starts_without_slash(const SerdURI* const uri) { return ((uri->path_base.len || uri->path.len) && ((!uri->path_base.len || uri->path_base.buf[0] != '/') && @@ -425,7 +425,7 @@ size_t serd_uri_serialise_relative(const SerdURI* const uri, const SerdURI* const base, const SerdURI* const root, - SerdSink sink, + const SerdSink sink, void* const stream) { assert(uri); @@ -441,7 +441,7 @@ serd_uri_serialise_relative(const SerdURI* const uri, SERD_DISABLE_NULL_WARNINGS - if (!relative || (!len && base->query.buf)) { + if (!relative || (!len && base && base->query.buf)) { if (uri->scheme.buf) { len += sink(uri->scheme.buf, uri->scheme.len, stream); len += sink(":", 1, stream); @@ -481,7 +481,9 @@ serd_uri_serialise_relative(const SerdURI* const uri, /// See http://tools.ietf.org/html/rfc3986#section-5.3 size_t -serd_uri_serialise(const SerdURI* const uri, SerdSink sink, void* const stream) +serd_uri_serialise(const SerdURI* const uri, + const SerdSink sink, + void* const stream) { assert(uri); assert(sink); diff --git a/src/uri_utils.h b/src/uri_utils.h index 0d3bd74e..4005b47d 100644 --- a/src/uri_utils.h +++ b/src/uri_utils.h @@ -18,20 +18,20 @@ typedef struct { } SlashIndexes; static inline bool -chunk_equals(const SerdChunk* a, const SerdChunk* b) +chunk_equals(const SerdChunk* const a, const SerdChunk* const b) { return a->len == b->len && !strncmp((const char*)a->buf, (const char*)b->buf, a->len); } static inline size_t -uri_path_len(const SerdURI* uri) +uri_path_len(const SerdURI* const uri) { return uri->path_base.len + uri->path.len; } static inline uint8_t -uri_path_at(const SerdURI* uri, size_t i) +uri_path_at(const SerdURI* const uri, const size_t i) { return (i < uri->path_base.len) ? uri->path_base.buf[i] : uri->path.buf[i - uri->path_base.len]; @@ -46,7 +46,7 @@ uri_path_at(const SerdURI* uri, size_t i) otherwise it may merely share some leading path components). */ static inline SERD_PURE_FUNC SlashIndexes -uri_rooted_index(const SerdURI* uri, const SerdURI* root) +uri_rooted_index(const SerdURI* const uri, const SerdURI* const root) { SlashIndexes indexes = {SIZE_MAX, SIZE_MAX}; @@ -84,14 +84,14 @@ uri_rooted_index(const SerdURI* uri, const SerdURI* root) /** Return true iff `uri` shares path components with `root` */ static inline SERD_PURE_FUNC bool -uri_is_related(const SerdURI* uri, const SerdURI* root) +uri_is_related(const SerdURI* const uri, const SerdURI* const root) { return uri_rooted_index(uri, root).shared != SIZE_MAX; } /** Return true iff `uri` is within the base of `root` */ static inline SERD_PURE_FUNC bool -uri_is_under(const SerdURI* uri, const SerdURI* root) +uri_is_under(const SerdURI* const uri, const SerdURI* const root) { const SlashIndexes indexes = uri_rooted_index(uri, root); return indexes.shared && indexes.shared != SIZE_MAX && diff --git a/src/writer.c b/src/writer.c index e4ef5651..3905cb9c 100644 --- a/src/writer.c +++ b/src/writer.c @@ -143,7 +143,7 @@ write_node(SerdWriter* writer, SerdStatementFlags flags); SERD_NODISCARD static bool -supports_abbrev(const SerdWriter* writer) +supports_abbrev(const SerdWriter* const writer) { return writer->syntax == SERD_TURTLE || writer->syntax == SERD_TRIG; } @@ -162,7 +162,7 @@ free_context(WriteContext* const ctx) SERD_LOG_FUNC(3, 4) static SerdStatus -w_err(SerdWriter* writer, SerdStatus st, const char* fmt, ...) +w_err(SerdWriter* const writer, const SerdStatus st, const char* const fmt, ...) { /* TODO: This results in errors with no file information, which is not helpful when re-serializing a file (particularly for "undefined @@ -179,7 +179,7 @@ w_err(SerdWriter* writer, SerdStatus st, const char* fmt, ...) } static void -copy_node(SerdNode* dst, const SerdNode* src) +copy_node(SerdNode* const dst, const SerdNode* const src) { const size_t new_size = src->n_bytes + 1U; uint8_t* const new_buf = (uint8_t*)realloc((char*)dst->buf, new_size); @@ -210,7 +210,7 @@ push_context(SerdWriter* const writer, } static void -pop_context(SerdWriter* writer) +pop_context(SerdWriter* const writer) { // Replace the current context with the top of the stack free_context(&writer->context); @@ -223,7 +223,7 @@ pop_context(SerdWriter* writer) } SERD_NODISCARD static size_t -sink(const void* buf, size_t len, SerdWriter* writer) +sink(const void* const buf, const size_t len, SerdWriter* const writer) { const size_t written = serd_byte_sink_write(buf, len, &writer->byte_sink); if (written != len) { @@ -239,7 +239,7 @@ sink(const void* buf, size_t len, SerdWriter* writer) } SERD_NODISCARD static inline SerdStatus -esink(const void* buf, size_t len, SerdWriter* writer) +esink(const void* const buf, const size_t len, SerdWriter* const writer) { return sink(buf, len, writer) == len ? SERD_SUCCESS : SERD_ERR_BAD_WRITE; } @@ -247,10 +247,10 @@ esink(const void* buf, size_t len, SerdWriter* writer) // Write a single character, as an escape for single byte characters // (Caller prints any single byte characters that don't need escaping) static size_t -write_character(SerdWriter* writer, - const uint8_t* utf8, - size_t* size, - SerdStatus* st) +write_character(SerdWriter* const writer, + const uint8_t* const utf8, + uint8_t* const size, + SerdStatus* const st) { char escape[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; const uint32_t c = parse_utf8_char(utf8, size); @@ -288,10 +288,10 @@ uri_must_escape(const uint8_t c) } static size_t -write_uri(SerdWriter* writer, - const uint8_t* utf8, - size_t n_bytes, - SerdStatus* st) +write_uri(SerdWriter* const writer, + const uint8_t* const utf8, + const size_t n_bytes, + SerdStatus* const st) { size_t len = 0; for (size_t i = 0; i < n_bytes;) { @@ -315,14 +315,14 @@ write_uri(SerdWriter* writer, } // Write UTF-8 character - size_t size = 0; + uint8_t size = 0U; len += write_character(writer, utf8 + i, &size, st); i += size; if (*st && (writer->style & SERD_STYLE_STRICT)) { break; } - if (size == 0) { + if (!size) { // Corrupt input, write percent-encoded bytes and scan to next start char escape[4] = {0, 0, 0, 0}; for (; i < n_bytes && (utf8[i] & 0x80); ++i) { @@ -336,7 +336,9 @@ write_uri(SerdWriter* writer, } SERD_NODISCARD static SerdStatus -ewrite_uri(SerdWriter* writer, const uint8_t* utf8, size_t n_bytes) +ewrite_uri(SerdWriter* const writer, + const uint8_t* const utf8, + const size_t n_bytes) { SerdStatus st = SERD_SUCCESS; write_uri(writer, utf8, n_bytes, &st); @@ -347,7 +349,7 @@ ewrite_uri(SerdWriter* writer, const uint8_t* utf8, size_t n_bytes) } SERD_NODISCARD static SerdStatus -write_uri_from_node(SerdWriter* writer, const SerdNode* node) +write_uri_from_node(SerdWriter* const writer, const SerdNode* const node) { return ewrite_uri(writer, node->buf, node->n_bytes); } @@ -369,7 +371,9 @@ lname_must_escape(const uint8_t c) } SERD_NODISCARD static SerdStatus -write_lname(SerdWriter* writer, const uint8_t* utf8, size_t n_bytes) +write_lname(SerdWriter* const writer, + const uint8_t* const utf8, + const size_t n_bytes) { SerdStatus st = SERD_SUCCESS; for (size_t i = 0; i < n_bytes; ++i) { @@ -395,10 +399,10 @@ write_lname(SerdWriter* writer, const uint8_t* utf8, size_t n_bytes) } SERD_NODISCARD static SerdStatus -write_text(SerdWriter* writer, - TextContext ctx, - const uint8_t* utf8, - size_t n_bytes) +write_text(SerdWriter* const writer, + const TextContext ctx, + const uint8_t* const utf8, + const size_t n_bytes) { size_t n_consecutive_quotes = 0; SerdStatus st = SERD_SUCCESS; @@ -484,19 +488,19 @@ write_text(SerdWriter* writer, } // Write UTF-8 character - size_t size = 0; + uint8_t size = 0U; write_character(writer, utf8 + i - 1, &size, &st); if (st && (writer->style & SERD_STYLE_STRICT)) { return st; } - if (size == 0) { + if (!size) { // Corrupt input, write replacement character and scan to the next start st = esink(replacement_char, sizeof(replacement_char), writer); - for (; i < n_bytes && (utf8[i] & 0x80); ++i) { + for (; i < n_bytes && (utf8[i] & 0x80U); ++i) { } } else { - i += size - 1; + i += size - 1U; } } @@ -509,7 +513,7 @@ typedef struct { } UriSinkContext; SERD_NODISCARD static size_t -uri_sink(const void* buf, size_t len, void* stream) +uri_sink(const void* const buf, const size_t len, void* const stream) { UriSinkContext* const context = (UriSinkContext*)stream; SerdWriter* const writer = context->writer; @@ -518,7 +522,7 @@ uri_sink(const void* buf, size_t len, void* stream) } SERD_NODISCARD static SerdStatus -write_newline(SerdWriter* writer) +write_newline(SerdWriter* const writer) { SerdStatus st = SERD_SUCCESS; @@ -531,7 +535,7 @@ write_newline(SerdWriter* writer) } SERD_NODISCARD static SerdStatus -write_sep(SerdWriter* writer, const Sep sep) +write_sep(SerdWriter* const writer, const Sep sep) { SerdStatus st = SERD_SUCCESS; const SepRule* const rule = &rules[sep]; @@ -585,7 +589,7 @@ write_sep(SerdWriter* writer, const Sep sep) } static void -free_anon_stack(SerdWriter* writer) +free_anon_stack(SerdWriter* const writer) { while (!serd_stack_is_empty(&writer->anon_stack)) { pop_context(writer); @@ -593,7 +597,7 @@ free_anon_stack(SerdWriter* writer) } static SerdStatus -reset_context(SerdWriter* writer, const unsigned flags) +reset_context(SerdWriter* const writer, const unsigned flags) { free_anon_stack(writer); @@ -639,11 +643,11 @@ get_xsd_name(const SerdEnv* const env, const SerdNode* const datatype) } SERD_NODISCARD static SerdStatus -write_literal(SerdWriter* writer, - const SerdNode* node, - const SerdNode* datatype, - const SerdNode* lang, - SerdStatementFlags flags) +write_literal(SerdWriter* const writer, + const SerdNode* const node, + const SerdNode* const datatype, + const SerdNode* const lang, + const SerdStatementFlags flags) { SerdStatus st = SERD_SUCCESS; @@ -679,7 +683,7 @@ write_literal(SerdWriter* writer, // Return true iff `buf` is a valid prefixed name prefix or suffix static bool -is_name(const uint8_t* buf, const size_t len) +is_name(const uint8_t* const buf, const size_t len) { // TODO: This is more strict than it should be for (size_t i = 0; i < len; ++i) { @@ -692,9 +696,9 @@ is_name(const uint8_t* buf, const size_t len) } SERD_NODISCARD static SerdStatus -write_uri_node(SerdWriter* const writer, - const SerdNode* node, - const Field field) +write_uri_node(SerdWriter* const writer, + const SerdNode* const node, + const Field field) { SerdStatus st = SERD_SUCCESS; SerdNode prefix = SERD_NODE_NULL; @@ -741,8 +745,8 @@ write_uri_node(SerdWriter* const writer, serd_uri_parse(node->buf, &uri); SERD_RESTORE_WARNINGS serd_uri_resolve(&uri, &in_base_uri, &abs_uri); - bool rooted = uri_is_under(&writer->base_uri, &writer->root_uri); - SerdURI* root = rooted ? &writer->root_uri : &writer->base_uri; + const bool rooted = uri_is_under(&writer->base_uri, &writer->root_uri); + const SerdURI* root = rooted ? &writer->root_uri : &writer->base_uri; UriSinkContext ctx = {writer, SERD_SUCCESS}; if (!uri_is_under(&abs_uri, root) || writer->syntax == SERD_NTRIPLES || writer->syntax == SERD_NQUADS) { @@ -789,7 +793,7 @@ write_curie(SerdWriter* const writer, const SerdNode* const node) SERD_NODISCARD static SerdStatus write_blank(SerdWriter* const writer, - const SerdNode* node, + const SerdNode* const node, const Field field, const SerdStatementFlags flags) { @@ -828,12 +832,12 @@ write_blank(SerdWriter* const writer, } SERD_NODISCARD static SerdStatus -write_node(SerdWriter* writer, - const SerdNode* node, - const SerdNode* datatype, - const SerdNode* lang, - Field field, - SerdStatementFlags flags) +write_node(SerdWriter* const writer, + const SerdNode* const node, + const SerdNode* const datatype, + const SerdNode* const lang, + const Field field, + const SerdStatementFlags flags) { return (node->type == SERD_LITERAL) ? write_literal(writer, node, datatype, lang, flags) @@ -844,13 +848,15 @@ write_node(SerdWriter* writer, } static bool -is_resource(const SerdNode* node) +is_resource(const SerdNode* const node) { return node->buf && node->type > SERD_LITERAL; } SERD_NODISCARD static SerdStatus -write_pred(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* pred) +write_pred(SerdWriter* const writer, + const SerdStatementFlags flags, + const SerdNode* const pred) { SerdStatus st = SERD_SUCCESS; @@ -864,12 +870,12 @@ write_pred(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* pred) } SERD_NODISCARD static SerdStatus -write_list_next(SerdWriter* writer, - SerdStatementFlags flags, - const SerdNode* predicate, - const SerdNode* object, - const SerdNode* datatype, - const SerdNode* lang) +write_list_next(SerdWriter* const writer, + const SerdStatementFlags flags, + const SerdNode* const predicate, + const SerdNode* const object, + const SerdNode* const datatype, + const SerdNode* const lang) { SerdStatus st = SERD_SUCCESS; @@ -888,7 +894,7 @@ write_list_next(SerdWriter* writer, } SERD_NODISCARD static SerdStatus -terminate_context(SerdWriter* writer) +terminate_context(SerdWriter* const writer) { SerdStatus st = SERD_SUCCESS; @@ -904,14 +910,14 @@ terminate_context(SerdWriter* writer) } SerdStatus -serd_writer_write_statement(SerdWriter* writer, - SerdStatementFlags flags, - const SerdNode* graph, - const SerdNode* subject, - const SerdNode* predicate, - const SerdNode* object, - const SerdNode* datatype, - const SerdNode* lang) +serd_writer_write_statement(SerdWriter* const writer, + SerdStatementFlags flags, + const SerdNode* const graph, + const SerdNode* const subject, + const SerdNode* const predicate, + const SerdNode* const object, + const SerdNode* const datatype, + const SerdNode* const lang) { assert(writer); assert(subject); @@ -1064,7 +1070,7 @@ serd_writer_write_statement(SerdWriter* writer, } SerdStatus -serd_writer_end_anon(SerdWriter* writer, const SerdNode* node) +serd_writer_end_anon(SerdWriter* const writer, const SerdNode* const node) { assert(writer); @@ -1095,7 +1101,7 @@ serd_writer_end_anon(SerdWriter* writer, const SerdNode* node) } SerdStatus -serd_writer_finish(SerdWriter* writer) +serd_writer_finish(SerdWriter* const writer) { assert(writer); @@ -1107,12 +1113,12 @@ serd_writer_finish(SerdWriter* writer) } SerdWriter* -serd_writer_new(SerdSyntax syntax, - SerdStyle style, - SerdEnv* env, - const SerdURI* base_uri, - SerdSink ssink, - void* stream) +serd_writer_new(const SerdSyntax syntax, + const SerdStyle style, + SerdEnv* const env, + const SerdURI* const base_uri, + SerdSink ssink, + void* const stream) { assert(env); assert(ssink); @@ -1135,9 +1141,9 @@ serd_writer_new(SerdSyntax syntax, } void -serd_writer_set_error_sink(SerdWriter* writer, - SerdErrorSink error_sink, - void* error_handle) +serd_writer_set_error_sink(SerdWriter* const writer, + const SerdErrorSink error_sink, + void* const error_handle) { assert(writer); assert(error_sink); @@ -1146,7 +1152,8 @@ serd_writer_set_error_sink(SerdWriter* writer, } void -serd_writer_chop_blank_prefix(SerdWriter* writer, const uint8_t* prefix) +serd_writer_chop_blank_prefix(SerdWriter* const writer, + const uint8_t* const prefix) { assert(writer); @@ -1163,7 +1170,7 @@ serd_writer_chop_blank_prefix(SerdWriter* writer, const uint8_t* prefix) } SerdStatus -serd_writer_set_base_uri(SerdWriter* writer, const SerdNode* uri) +serd_writer_set_base_uri(SerdWriter* const writer, const SerdNode* const uri) { assert(writer); @@ -1185,7 +1192,7 @@ serd_writer_set_base_uri(SerdWriter* writer, const SerdNode* uri) } SerdStatus -serd_writer_set_root_uri(SerdWriter* writer, const SerdNode* uri) +serd_writer_set_root_uri(SerdWriter* const writer, const SerdNode* const uri) { assert(writer); @@ -1205,9 +1212,9 @@ serd_writer_set_root_uri(SerdWriter* writer, const SerdNode* uri) } SerdStatus -serd_writer_set_prefix(SerdWriter* writer, - const SerdNode* name, - const SerdNode* uri) +serd_writer_set_prefix(SerdWriter* const writer, + const SerdNode* const name, + const SerdNode* const uri) { assert(writer); assert(name); @@ -1231,7 +1238,7 @@ serd_writer_set_prefix(SerdWriter* writer, } void -serd_writer_free(SerdWriter* writer) +serd_writer_free(SerdWriter* const writer) { if (!writer) { return; @@ -1250,14 +1257,14 @@ serd_writer_free(SerdWriter* writer) } SerdEnv* -serd_writer_get_env(SerdWriter* writer) +serd_writer_get_env(SerdWriter* const writer) { assert(writer); return writer->env; } size_t -serd_file_sink(const void* buf, size_t len, void* stream) +serd_file_sink(const void* const buf, const size_t len, void* const stream) { assert(buf); assert(stream); @@ -1265,7 +1272,7 @@ serd_file_sink(const void* buf, size_t len, void* stream) } size_t -serd_chunk_sink(const void* buf, size_t len, void* stream) +serd_chunk_sink(const void* const buf, const size_t len, void* const stream) { assert(buf); assert(stream); @@ -1281,7 +1288,7 @@ serd_chunk_sink(const void* buf, size_t len, void* stream) } uint8_t* -serd_chunk_sink_finish(SerdChunk* stream) +serd_chunk_sink_finish(SerdChunk* const stream) { assert(stream); serd_chunk_sink("", 1, stream); diff --git a/test/headers/test_headers.c b/test/headers/test_headers.c index c855c103..62be0976 100644 --- a/test/headers/test_headers.c +++ b/test/headers/test_headers.c @@ -3,8 +3,7 @@ #include "serd/serd.h" // IWYU pragma: keep -SERD_CONST_FUNC -int +SERD_CONST_FUNC int main(void) { return 0; diff --git a/test/meson.build b/test/meson.build index 33f86dfb..4d770304 100644 --- a/test/meson.build +++ b/test/meson.build @@ -4,109 +4,6 @@ run_suite = find_program('run_suite.py') wrapper = meson.get_external_property('exe_wrapper', '') -######################## -# Scripts and Metadata # -######################## - -plot_script_paths = [ - '../scripts/serd_bench.py', -] - -simple_script_paths = [ - '../scripts/check_formatting.py', - 'serd_test_util/__init__.py', - 'run_suite.py', - 'test_quiet.py', - 'test_stdin.py', - 'test_write_error.py', -] - -ttl_metadata_file_paths = [ - '../serd.ttl', - 'extra/abbreviate/manifest.ttl', - 'extra/bad/manifest.ttl', - 'extra/big/manifest.ttl', - 'extra/full/manifest.ttl', - 'extra/good/manifest.ttl', - 'extra/lax/manifest.ttl', - 'extra/perfect/manifest.ttl', - 'extra/prefix/manifest.ttl', - 'extra/pretty/manifest.ttl', - 'extra/qualify/manifest.ttl', - 'extra/root/manifest.ttl', -] - -plot_scripts = files(plot_script_paths) -simple_scripts = files(simple_script_paths) -python_script_paths = simple_script_paths + plot_script_paths -python_scripts = plot_scripts + simple_scripts - -if get_option('lint') - # Check release metadata - if not meson.is_subproject() - autoship = find_program('autoship', required: false) - if autoship.found() - test('autoship', autoship, args: ['test', serd_src_root], suite: 'data') - endif - endif - - # Check licensing metadata - reuse = find_program('reuse', required: false) - if reuse.found() - test( - 'REUSE', - reuse, - args: ['--root', serd_src_root, 'lint'], - suite: 'data', - ) - endif - - # Check script formatting - black = find_program('black', required: false) - if black.found() - black_opts = ['--check', '-q', '-l', '79'] - foreach script_path : python_script_paths - script = files(script_path) - name = script_path.underscorify() - test(name, black, args: black_opts + [script], suite: 'scripts') - endforeach - endif - - # Check scripts for errors with flake8 - flake8 = find_program('flake8', required: false) - if flake8.found() - test('flake8', flake8, args: python_scripts, suite: 'scripts') - endif - - # Check scripts for errors with pylint - pylint = find_program('pylint', required: false) - if pylint.found() - pymod = import('python') - plot_py = pymod.find_installation( - 'python3', - modules: ['matplotlib'], - required: false, - ) - - pylint_args = ['--disable', 'bad-option-value'] + simple_scripts - if plot_py.found() - pylint_args += plot_scripts - endif - - test('pylint', pylint, args: pylint_args, suite: 'scripts') - endif - - # Check Turtle formatting with serdi - foreach ttl_file_path : ttl_metadata_file_paths - test( - ttl_file_path.underscorify(), - check_formatting_py, - args: [files(ttl_file_path), serdi, '-o', 'turtle'], - suite: 'data', - ) - endforeach -endif - ################### # Header Warnings # ################### @@ -117,7 +14,7 @@ subdir('headers') # Unit Tests # ############## -unit_tests = [ +unit_test_names = [ 'env', 'free_null', 'node', @@ -128,12 +25,16 @@ unit_tests = [ 'writer', ] -foreach unit : unit_tests +unit_test_sources = files('headers/test_headers.c') + +foreach name : unit_test_names + source = files('test_@0@.c'.format(name)) + unit_test_sources += source test( - unit, + name, executable( - 'test_@0@'.format(unit), - files('test_@0@.c'.format(unit)), + 'test_@0@'.format(name), + source, c_args: c_suppressions, dependencies: serd_dep, ), @@ -392,3 +293,138 @@ if is_variable('serdi') ) endforeach endif + +######## +# Lint # +######## + +plot_script_paths = [ + '../scripts/serd_bench.py', +] + +simple_script_paths = [ + '../scripts/check_formatting.py', + 'serd_test_util/__init__.py', + 'run_suite.py', + 'test_quiet.py', + 'test_stdin.py', + 'test_write_error.py', +] + +ttl_metadata_file_paths = [ + '../serd.ttl', + 'extra/abbreviate/manifest.ttl', + 'extra/bad/manifest.ttl', + 'extra/big/manifest.ttl', + 'extra/full/manifest.ttl', + 'extra/good/manifest.ttl', + 'extra/lax/manifest.ttl', + 'extra/perfect/manifest.ttl', + 'extra/prefix/manifest.ttl', + 'extra/pretty/manifest.ttl', + 'extra/qualify/manifest.ttl', + 'extra/root/manifest.ttl', +] + +plot_scripts = files(plot_script_paths) +simple_scripts = files(simple_script_paths) +python_script_paths = simple_script_paths + plot_script_paths +python_scripts = plot_scripts + simple_scripts + +if get_option('lint') + all_sources = sources + unit_test_sources + files('../src/serdi.c') + + if not meson.is_subproject() + # Check release metadata + autoship = find_program('autoship', required: false) + if autoship.found() + test('autoship', autoship, args: ['test', serd_src_root], suite: 'data') + endif + + # Check code with cppcheck + cppcheck = find_program('cppcheck', required: false) + if cppcheck.found() + compdb_path = join_paths(serd_build_root, 'compile_commands.json') + suppress_path = join_paths(serd_src_root, '.suppress.cppcheck') + test( + 'cppcheck', + cppcheck, + args: [ + '--enable=warning,style,performance,portability', + '--error-exitcode=1', + '--project=' + compdb_path, + '--suppressions-list=' + suppress_path, + '-q', + ], + suite: 'code', + ) + endif + endif + + # Check licensing metadata + reuse = find_program('reuse', required: false) + if reuse.found() + test( + 'REUSE', + reuse, + args: ['--root', serd_src_root, 'lint'], + suite: 'data', + ) + endif + + # Check code formatting + clang_format = find_program('clang-format', required: false) + if clang_format.found() + test( + 'format', + clang_format, + args: ['--Werror', '--dry-run'] + c_headers + all_sources, + suite: 'code', + ) + endif + + # Check script formatting + black = find_program('black', required: false) + if black.found() + black_opts = ['--check', '-q', '-l', '79'] + foreach script_path : python_script_paths + script = files(script_path) + name = script_path.underscorify() + test(name, black, args: black_opts + [script], suite: 'scripts') + endforeach + endif + + # Check scripts for errors with flake8 + flake8 = find_program('flake8', required: false) + if flake8.found() + test('flake8', flake8, args: python_scripts, suite: 'scripts') + endif + + # Check scripts for errors with pylint + pylint = find_program('pylint', required: false) + if pylint.found() + pymod = import('python') + plot_py = pymod.find_installation( + 'python3', + modules: ['matplotlib'], + required: false, + ) + + pylint_args = ['--disable', 'bad-option-value'] + simple_scripts + if plot_py.found() + pylint_args += plot_scripts + endif + + test('pylint', pylint, args: pylint_args, suite: 'scripts') + endif + + # Check Turtle formatting with serdi + foreach ttl_file_path : ttl_metadata_file_paths + test( + ttl_file_path.underscorify(), + check_formatting_py, + args: [files(ttl_file_path), serdi, '-o', 'turtle'], + suite: 'data', + ) + endforeach +endif diff --git a/test/serd_test_util/__init__.py b/test/serd_test_util/__init__.py index 8027462b..ad417762 100644 --- a/test/serd_test_util/__init__.py +++ b/test/serd_test_util/__init__.py @@ -8,10 +8,12 @@ # pylint: disable=consider-using-f-string # pylint: disable=invalid-name +import argparse import datetime import difflib import os import re +import shlex import subprocess import sys import urllib.parse @@ -51,6 +53,33 @@ def error(message): sys.stderr.write("\n") +def wrapper_args(description, with_input=False): + """Return the command line arguments for a wrapped test.""" + + parser = argparse.ArgumentParser(description) + parser.add_argument("--serdi", default="./serdi", help="serdi executable") + parser.add_argument("--wrapper", default="", help="executable wrapper") + if with_input: + parser.add_argument("input", help="input file") + + return parser.parse_args(sys.argv[1:]) + + +def command_output(wrapper, command, stdin=None): + """Run a command and check that stdout matches the expected output.""" + + proc = subprocess.run( + shlex.split(wrapper) + command, + capture_output=True, + check=True, + encoding="utf-8", + input=stdin, + ) + + assert wrapper or not proc.stderr + return proc.stdout + + def print_result_summary(results): """Print test result summary to stdout or stderr as appropriate.""" diff --git a/test/test_env.c b/test/test_env.c index d51e0595..903ae3f2 100644 --- a/test/test_env.c +++ b/test/test_env.c @@ -13,7 +13,9 @@ #define USTR(s) ((const uint8_t*)(s)) static SerdStatus -count_prefixes(void* handle, const SerdNode* name, const SerdNode* uri) +count_prefixes(void* const handle, + const SerdNode* const name, + const SerdNode* const uri) { (void)name; (void)uri; diff --git a/test/test_node.c b/test/test_node.c index af14171b..28db00ea 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -24,7 +24,7 @@ #endif static void -test_strtod(double dbl, double max_delta) +check_strtod(const double dbl, const double max_delta) { char buf[1024]; snprintf(buf, sizeof(buf), "%f", dbl); @@ -56,7 +56,7 @@ test_string_to_double(void) const double delta = fabs(num - expt_test_nums[i]); assert(delta <= DBL_EPSILON); - test_strtod(expt_test_nums[i], DBL_EPSILON); + check_strtod(expt_test_nums[i], DBL_EPSILON); } } @@ -285,7 +285,5 @@ main(void) test_node_from_string(); test_node_from_substring(); test_uri_node_from_node(); - - printf("Success\n"); return 0; } diff --git a/test/test_quiet.py b/test/test_quiet.py index 42d05785..676284bb 100755 --- a/test/test_quiet.py +++ b/test/test_quiet.py @@ -3,20 +3,14 @@ # Copyright 2022 David Robillard <d@drobilla.net> # SPDX-License-Identifier: ISC -"""Test serdi quiet option.""" +"""Test quiet command-line option.""" -import argparse -import sys import shlex import subprocess -parser = argparse.ArgumentParser(description=__doc__) +import serd_test_util as util -parser.add_argument("--serdi", default="./serdi", help="path to serdi") -parser.add_argument("--wrapper", default="", help="executable wrapper") -parser.add_argument("input", help="invalid input file") - -args = parser.parse_args(sys.argv[1:]) +args = util.wrapper_args(__doc__, True) command = shlex.split(args.wrapper) + [args.serdi, "-q", args.input] proc = subprocess.run( command, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE diff --git a/test/test_reader.c b/test/test_reader.c index 18794f9e..e185b915 100644 --- a/test/test_reader.c +++ b/test/test_reader.c @@ -26,7 +26,7 @@ typedef struct { } ReaderTest; static SerdStatus -test_base_sink(void* const handle, const SerdNode* const uri) +base_sink(void* const handle, const SerdNode* const uri) { (void)uri; @@ -36,9 +36,9 @@ test_base_sink(void* const handle, const SerdNode* const uri) } static SerdStatus -test_prefix_sink(void* const handle, - const SerdNode* const name, - const SerdNode* const uri) +prefix_sink(void* const handle, + const SerdNode* const name, + const SerdNode* const uri) { (void)name; (void)uri; @@ -49,14 +49,14 @@ test_prefix_sink(void* const handle, } static SerdStatus -test_statement_sink(void* const handle, - SerdStatementFlags flags, - const SerdNode* const graph, - const SerdNode* const subject, - const SerdNode* const predicate, - const SerdNode* const object, - const SerdNode* const object_datatype, - const SerdNode* const object_lang) +statement_sink(void* const handle, + SerdStatementFlags flags, + const SerdNode* const graph, + const SerdNode* const subject, + const SerdNode* const predicate, + const SerdNode* const object, + const SerdNode* const object_datatype, + const SerdNode* const object_lang) { (void)flags; (void)graph; @@ -72,7 +72,7 @@ test_statement_sink(void* const handle, } static SerdStatus -test_end_sink(void* const handle, const SerdNode* const node) +end_sink(void* const handle, const SerdNode* const node) { (void)node; @@ -85,13 +85,8 @@ static void test_read_string(void) { ReaderTest rt = {0, 0, 0, 0}; - SerdReader* const reader = serd_reader_new(SERD_TURTLE, - &rt, - NULL, - test_base_sink, - test_prefix_sink, - test_statement_sink, - test_end_sink); + SerdReader* const reader = serd_reader_new( + SERD_TURTLE, &rt, NULL, base_sink, prefix_sink, statement_sink, end_sink); assert(reader); assert(serd_reader_get_handle(reader) == &rt); @@ -113,7 +108,10 @@ test_read_string(void) /// 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) +eof_test_read(void* const buf, + const size_t size, + const size_t nmemb, + void* const stream) { assert(size == 1); assert(nmemb == 1); @@ -149,7 +147,7 @@ eof_test_read(void* buf, size_t size, size_t nmemb, void* stream) } static int -eof_test_error(void* stream) +eof_test_error(void* const stream) { (void)stream; return 0; @@ -167,13 +165,8 @@ test_read_eof_file(const char* const path) fseek(f, 0L, SEEK_SET); ReaderTest rt = {0, 0, 0, 0}; - SerdReader* const reader = serd_reader_new(SERD_TURTLE, - &rt, - NULL, - test_base_sink, - test_prefix_sink, - test_statement_sink, - test_end_sink); + SerdReader* const reader = serd_reader_new( + SERD_TURTLE, &rt, NULL, base_sink, prefix_sink, statement_sink, end_sink); fseek(f, 0L, SEEK_SET); serd_reader_start_stream(reader, f, (const uint8_t*)"test", true); @@ -198,13 +191,8 @@ static void test_read_eof_by_byte(void) { ReaderTest rt = {0, 0, 0, 0}; - SerdReader* const reader = serd_reader_new(SERD_TURTLE, - &rt, - NULL, - test_base_sink, - test_prefix_sink, - test_statement_sink, - test_end_sink); + SerdReader* const reader = serd_reader_new( + SERD_TURTLE, &rt, NULL, base_sink, prefix_sink, statement_sink, end_sink); size_t n_reads = 0U; serd_reader_start_source_stream(reader, @@ -249,13 +237,8 @@ test_read_nquads_chunks(const char* const path) fseek(f, 0, SEEK_SET); ReaderTest rt = {0, 0, 0, 0}; - SerdReader* const reader = serd_reader_new(SERD_NQUADS, - &rt, - NULL, - test_base_sink, - test_prefix_sink, - test_statement_sink, - test_end_sink); + SerdReader* const reader = serd_reader_new( + SERD_NQUADS, &rt, NULL, base_sink, prefix_sink, statement_sink, end_sink); assert(reader); assert(serd_reader_get_handle(reader) == &rt); @@ -330,13 +313,8 @@ test_read_turtle_chunks(const char* const path) fseek(f, 0, SEEK_SET); ReaderTest rt = {0, 0, 0, 0}; - SerdReader* const reader = serd_reader_new(SERD_TURTLE, - &rt, - NULL, - test_base_sink, - test_prefix_sink, - test_statement_sink, - test_end_sink); + SerdReader* const reader = serd_reader_new( + SERD_TURTLE, &rt, NULL, base_sink, prefix_sink, statement_sink, end_sink); assert(reader); assert(serd_reader_get_handle(reader) == &rt); diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c index c229d1c5..515d5e5b 100644 --- a/test/test_reader_writer.c +++ b/test/test_reader_writer.c @@ -54,14 +54,14 @@ static const char* const doc_string = "( eg:o ) eg:t eg:u .\n"; static SerdStatus -test_statement_sink(void* handle, - SerdStatementFlags flags, - const SerdNode* graph, - const SerdNode* subject, - const SerdNode* predicate, - const SerdNode* object, - const SerdNode* object_datatype, - const SerdNode* object_lang) +test_statement_sink(void* const handle, + const SerdStatementFlags flags, + const SerdNode* const graph, + const SerdNode* const subject, + const SerdNode* const predicate, + const SerdNode* const object, + const SerdNode* const object_datatype, + const SerdNode* const object_lang) { (void)flags; (void)subject; @@ -164,8 +164,9 @@ test_writer(const char* const path) assert(serd_writer_end_anon(writer, NULL)); assert(serd_writer_get_env(writer) == env); - uint8_t buf[] = {0x80, 0, 0, 0, 0}; - SerdNode s = serd_node_from_string(SERD_URI, USTR("")); + const uint8_t buf[] = {0x80, 0, 0, 0, 0}; + + SerdNode s = serd_node_from_string(SERD_URI, USTR("")); SerdNode p = serd_node_from_string(SERD_URI, USTR("http://example.org/pred")); SerdNode o = serd_node_from_string(SERD_LITERAL, buf); @@ -264,7 +265,7 @@ test_writer(const char* const path) } static void -test_reader(const char* path) +test_reader(const char* const path) { ReaderTest* rt = (ReaderTest*)calloc(1, sizeof(ReaderTest)); SerdReader* reader = serd_reader_new( @@ -332,6 +333,5 @@ main(void) assert(!remove(path)); free(path); - printf("Success\n"); return 0; } diff --git a/test/test_stdin.py b/test/test_stdin.py index f976ca52..fb01f4ee 100755 --- a/test/test_stdin.py +++ b/test/test_stdin.py @@ -7,37 +7,14 @@ # pylint: disable=consider-using-f-string -import argparse -import sys -import shlex -import subprocess -import tempfile +import serd_test_util as util -parser = argparse.ArgumentParser(description=__doc__) +args = util.wrapper_args(__doc__) +command = [args.serdi, "-i", "ntriples", "-", "http://example.org"] -parser.add_argument("--serdi", default="./serdi", help="path to serdi") -parser.add_argument("--wrapper", default="", help="executable wrapper") +DOC = "<{0}s> <{0}p> <{0}o> .".format("http://example.org/") -args = parser.parse_args(sys.argv[1:]) -command = shlex.split(args.wrapper) + [args.serdi, "-"] +lines = util.command_output(args.wrapper, command, DOC).splitlines(True) -DOCUMENT = "<{0}s> <{0}p> <{0}o> .".format("http://example.org/") - -with tempfile.TemporaryFile() as out: - proc = subprocess.run( - command, - check=False, - encoding="utf-8", - input=DOCUMENT, - stdout=out, - stderr=subprocess.PIPE, - ) - - assert proc.returncode == 0 - assert args.wrapper or len(proc.stderr) == 0 - - out.seek(0) - lines = out.readlines() - - assert len(lines) == 1 - assert lines[0].decode("utf-8").strip() == DOCUMENT +assert len(lines) == 1 +assert lines[0].strip() == DOC diff --git a/test/test_string.c b/test/test_string.c index 23835ca9..1af3f45a 100644 --- a/test/test_string.c +++ b/test/test_string.c @@ -7,7 +7,6 @@ #include <assert.h> #include <stdint.h> -#include <stdio.h> #include <string.h> static void @@ -57,7 +56,5 @@ main(void) { test_strlen(); test_strerror(); - - printf("Success\n"); return 0; } diff --git a/test/test_uri.c b/test/test_uri.c index fc5eab71..7315a0fc 100644 --- a/test/test_uri.c +++ b/test/test_uri.c @@ -8,7 +8,6 @@ #include <assert.h> #include <stdbool.h> #include <stdint.h> -#include <stdio.h> #include <string.h> #define USTR(s) ((const uint8_t*)(s)) @@ -37,11 +36,11 @@ test_uri_string_has_scheme(void) } static void -test_file_uri(const char* const hostname, - const char* const path, - const bool escape, - const char* const expected_uri, - const char* expected_path) +check_file_uri(const char* const hostname, + const char* const path, + const bool escape, + const char* const expected_uri, + const char* expected_path) { if (!expected_path) { expected_path = path; @@ -112,62 +111,62 @@ test_uri_to_path(void) static void test_uri_parsing(void) { - test_file_uri(NULL, "C:/My 100%", true, "file:///C:/My%20100%%", NULL); - test_file_uri(NULL, "/foo/bar", true, "file:///foo/bar", NULL); - test_file_uri("bhost", "/foo/bar", true, "file://bhost/foo/bar", NULL); - test_file_uri(NULL, "a/relative path", false, "a/relative path", NULL); - test_file_uri( + check_file_uri(NULL, "C:/My 100%", true, "file:///C:/My%20100%%", NULL); + check_file_uri(NULL, "/foo/bar", true, "file:///foo/bar", NULL); + check_file_uri("bhost", "/foo/bar", true, "file://bhost/foo/bar", NULL); + check_file_uri(NULL, "a/relative path", false, "a/relative path", NULL); + check_file_uri( NULL, "a/relative <path>", true, "a/relative%20%3Cpath%3E", NULL); #ifdef _WIN32 - test_file_uri( + check_file_uri( NULL, "C:\\My 100%", true, "file:///C:/My%20100%%", "C:/My 100%"); - test_file_uri(NULL, - "\\drive\\relative", - true, - "file:///drive/relative", - "/drive/relative"); - - test_file_uri(NULL, - "C:\\Program Files\\Serd", - true, - "file:///C:/Program%20Files/Serd", - "C:/Program Files/Serd"); - - test_file_uri("ahost", - "C:\\Pointless Space", - true, - "file://ahost/C:/Pointless%20Space", - "C:/Pointless Space"); + check_file_uri(NULL, + "\\drive\\relative", + true, + "file:///drive/relative", + "/drive/relative"); + + check_file_uri(NULL, + "C:\\Program Files\\Serd", + true, + "file:///C:/Program%20Files/Serd", + "C:/Program Files/Serd"); + + check_file_uri("ahost", + "C:\\Pointless Space", + true, + "file://ahost/C:/Pointless%20Space", + "C:/Pointless Space"); #else /* What happens with Windows paths on other platforms is a bit weird, but more or less unavoidable. It doesn't work to interpret backslashes as path separators on any other platform. */ - test_file_uri("ahost", - "C:\\Pointless Space", - true, - "file://ahost/C:%5CPointless%20Space", - "/C:\\Pointless Space"); - - test_file_uri(NULL, - "\\drive\\relative", - true, - "%5Cdrive%5Crelative", - "\\drive\\relative"); - - test_file_uri(NULL, - "C:\\Program Files\\Serd", - true, - "file:///C:%5CProgram%20Files%5CSerd", - "/C:\\Program Files\\Serd"); - - test_file_uri("ahost", - "C:\\Pointless Space", - true, - "file://ahost/C:%5CPointless%20Space", - "/C:\\Pointless Space"); + check_file_uri("ahost", + "C:\\Pointless Space", + true, + "file://ahost/C:%5CPointless%20Space", + "/C:\\Pointless Space"); + + check_file_uri(NULL, + "\\drive\\relative", + true, + "%5Cdrive%5Crelative", + "\\drive\\relative"); + + check_file_uri(NULL, + "C:\\Program Files\\Serd", + true, + "file:///C:%5CProgram%20Files%5CSerd", + "/C:\\Program Files\\Serd"); + + check_file_uri("ahost", + "C:\\Pointless Space", + true, + "file://ahost/C:%5CPointless%20Space", + "/C:\\Pointless Space"); #endif // Test tolerance of NULL hostname parameter @@ -208,7 +207,7 @@ test_uri_from_string(void) } static inline bool -chunk_equals(const SerdChunk* a, const SerdChunk* b) +chunk_equals(const SerdChunk* const a, const SerdChunk* const b) { return (!a->len && !b->len && !a->buf && !b->buf) || (a->len && b->len && a->buf && b->buf && @@ -382,7 +381,5 @@ main(void) test_uri_parsing(); test_uri_from_string(); test_relative_uri(); - - printf("Success\n"); return 0; } diff --git a/test/test_write_error.py b/test/test_write_error.py index 35fde232..b62f981a 100755 --- a/test/test_write_error.py +++ b/test/test_write_error.py @@ -5,19 +5,14 @@ """Test errors writing to a file.""" -import argparse import sys import shlex import subprocess import os -parser = argparse.ArgumentParser(description=__doc__) +import serd_test_util as util -parser.add_argument("--serdi", default="./serdi", help="path to serdi") -parser.add_argument("--wrapper", default="", help="executable wrapper") -parser.add_argument("input", help="valid input file") - -args = parser.parse_args(sys.argv[1:]) +args = util.wrapper_args(__doc__, True) command = shlex.split(args.wrapper) + [args.serdi, args.input] if os.path.exists("/dev/full"): diff --git a/test/test_writer.c b/test/test_writer.c index 6c765148..9e94e139 100644 --- a/test/test_writer.c +++ b/test/test_writer.c @@ -112,7 +112,6 @@ test_write_nested_anon(void) "\t\t<http://example.org/p4> <http://example.org/o4>\n" "\t] .\n"; - fprintf(stderr, "%s\n", out); assert(!strcmp((char*)out, expected)); serd_free(out); } |