diff options
108 files changed, 1036 insertions, 757 deletions
@@ -1,9 +1,11 @@ -# Copyright 2017-2023 David Robillard <d@drobilla.net> +# Copyright 2017-2025 David Robillard <d@drobilla.net> # SPDX-License-Identifier: 0BSD OR ISC -.meson-subproject-wrap-hash.txt -__pycache__ -build/ -subprojects/packagecache/ -subprojects/sphinxygen-1.0.4/ -subprojects/sphinxygen/ +/.meson-subproject-wrap-hash.txt +/build/ +/subprojects/packagecache/ +/subprojects/sphinxygen-1.0.10/ +/subprojects/sphinxygen/ + +*.pyc +__pycache__/ diff --git a/.reuse/dep5 b/.reuse/dep5 index 78dc2af5..f21e0ee1 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -14,17 +14,17 @@ Comment: Standard test suites from the W3C License: BSD-3-Clause Files: test/extra/* -Copyright: 2011-2023 David Robillard <d@drobilla.net> +Copyright: 2011-2025 David Robillard <d@drobilla.net> Comment: Extra test suites for serd License: BSD-3-Clause OR ISC Files: AUTHORS NEWS serd.ttl -Copyright: 2011-2023 David Robillard <d@drobilla.net> +Copyright: 2011-2025 David Robillard <d@drobilla.net> Comment: Contributed to the Commons as a representation of simple facts License: 0BSD OR ISC Files: doc/.stylelintrc.json -Copyright: 2022 David Robillard <d@drobilla.net> +Copyright: 2022-2024 David Robillard <d@drobilla.net> Comment: Contributed to the Commons as a tool configuration License: 0BSD OR ISC diff --git a/.suppress.cppcheck b/.suppress.cppcheck index 292f6884..c6e4fdc0 100644 --- a/.suppress.cppcheck +++ b/.suppress.cppcheck @@ -1,4 +1,8 @@ +assertWithSideEffect assignmentInAssert normalCheckLevelMaxBranches +nullPointerArithmeticOutOfMemory +nullPointerOutOfMemory redundantInitialization unreadVariable +unusedStructMember @@ -1,4 +1,4 @@ -Copyright 2011-2023 David Robillard <d@drobilla.net> +Copyright 2011-2025 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 diff --git a/LICENSES/0BSD.txt b/LICENSES/0BSD.txt index c338c71a..f33ca7b4 100644 --- a/LICENSES/0BSD.txt +++ b/LICENSES/0BSD.txt @@ -1,4 +1,4 @@ -Copyright 2011-2023 David Robillard <d@drobilla.net> +Copyright 2011-2025 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. diff --git a/LICENSES/ISC.txt b/LICENSES/ISC.txt index 012065c8..d16d277c 120000..100644 --- a/LICENSES/ISC.txt +++ b/LICENSES/ISC.txt @@ -1 +1,13 @@ -../COPYING
\ No newline at end of file +Copyright 2011-2025 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. + +THE 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. @@ -1,4 +1,16 @@ -serd (0.32.3) unstable; urgency=medium +serd (0.32.5) unstable; urgency=medium + + * Drop graphs when writing Turtle output + * Fix handling of some invalid EOF cases in lax mode + * Fix invalid characters in error messages + * Fix reading numbers with no space before the final dot + * Fix reading prefix names that start with "true." or "false." + * Refuse to write incoherent statements + * Remove project and version number from man page OS field + + -- David Robillard <d@drobilla.net> Sun, 16 Mar 2025 22:02:00 +0000 + +serd (0.32.4) stable; urgency=medium * Clean up enum declarations * Fix library current_version on MacOS @@ -13,7 +25,7 @@ serd (0.32.3) unstable; urgency=medium * Treat out of range unicode characters as errors * Write blank lines between graphs and statements in TriG - -- David Robillard <d@drobilla.net> Sat, 03 Aug 2024 15:50:39 +0000 + -- David Robillard <d@drobilla.net> Sun, 19 Jan 2025 00:17:58 +0000 serd (0.32.2) stable; urgency=medium @@ -165,7 +177,7 @@ serd (0.28.0) stable; urgency=medium * Add support for reading from a user provided callback * Fix hangs when reading corrupt UTF-8 * Fix parsing of hex escapes in file URIs (thanks Johannes Mueller) - * Fix strict parsing of abolute URI schemes + * Fix strict parsing of absolute URI schemes * Gracefully handle applications that write corrupt UTF-8 -- David Robillard <d@drobilla.net> Fri, 21 Jul 2017 06:28:47 +0000 diff --git a/doc/conf.py.in b/doc/conf.py.in index 5037d217..77a7752b 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -1,10 +1,10 @@ -# Copyright 2020-2022 David Robillard <d@drobilla.net> +# Copyright 2020-2025 David Robillard <d@drobilla.net> # SPDX-License-Identifier: ISC # Project information project = "@SERD_TITLE@" -copyright = "2022-2023, David Robillard" +copyright = "2022-2025, David Robillard" author = "David Robillard" release = "@SERD_VERSION@" version = "@SERD_VERSION@" diff --git a/doc/man/meson.build b/doc/man/meson.build index 0ce65d01..f714b6be 100644 --- a/doc/man/meson.build +++ b/doc/man/meson.build @@ -49,6 +49,7 @@ if not get_option('tools').disabled() mandoc, '-Kutf-8', '-Ostyle=mandoc.css,man=%N.html', + '-Ios=Serd @0@'.format(meson.project_version()), '-Thtml', '-Wwarning,stop', '@INPUT@', diff --git a/doc/man/serdi.1 b/doc/man/serdi.1 index ef710527..d928ad39 100644 --- a/doc/man/serdi.1 +++ b/doc/man/serdi.1 @@ -1,8 +1,8 @@ -.\" Copyright 2011-2024 David Robillard <d@drobilla.net> +.\" Copyright 2011-2025 David Robillard <d@drobilla.net> .\" SPDX-License-Identifier: ISC -.Dd April 30, 2023 +.Dd January 30, 2025 .Dt SERDI 1 -.Os Serd 0.32.2 +.Os .Sh NAME .Nm serdi .Nd read and write RDF syntax diff --git a/include/serd/serd.h b/include/serd/serd.h index 19b4a49c..416da630 100644 --- a/include/serd/serd.h +++ b/include/serd/serd.h @@ -812,7 +812,7 @@ serd_reader_read_string(SerdReader* SERD_NONNULL reader, /** Skip over bytes in the input until a specific byte is encountered. - Typically used for recording from errors in a line-based syntax by skipping + Typically used for recovering from errors in a line-based syntax by skipping ahead to the next newline. @return #SERD_SUCCESS if the given byte was reached, or #SERD_FAILURE if the diff --git a/meson.build b/meson.build index f674bfa4..255c1870 100644 --- a/meson.build +++ b/meson.build @@ -12,7 +12,7 @@ project( ], license: 'ISC', meson_version: '>= 0.56.0', - version: '0.32.3', + version: '0.32.5', ) serd_src_root = meson.current_source_dir() @@ -39,7 +39,6 @@ if cc.get_id() in ['clang', 'emscripten'] '-Wno-cast-function-type-strict', '-Wno-cast-qual', '-Wno-declaration-after-statement', - '-Wno-double-promotion', '-Wno-format-nonliteral', '-Wno-padded', '-Wno-switch-default', @@ -223,6 +222,7 @@ libserd = library( darwin_versions: [major_version + '.0.0', meson.project_version()], dependencies: m_dep, gnu_symbol_visibility: 'hidden', + implicit_include_directories: false, include_directories: include_dirs, install: true, soversion: soversion, @@ -236,7 +236,7 @@ serd_dep = declare_dependency( link_with: libserd, ) -# Generage pkg-config file for external dependants +# Generate pkg-config file for external dependants pkg.generate( libserd, description: 'Lightweight C library for working with RDF data', @@ -269,6 +269,7 @@ if not get_option('tools').disabled() files('src/serdi.c'), c_args: c_suppressions + platform_c_args, dependencies: serd_dep, + implicit_include_directories: false, install: true, link_args: tool_link_args, ) diff --git a/scripts/check_formatting.py b/scripts/check_formatting.py index e3342603..27daebe5 100755 --- a/scripts/check_formatting.py +++ b/scripts/check_formatting.py @@ -20,7 +20,7 @@ def run_formatter(command, good_path): """Run the formatter and compare the output.""" with subprocess.Popen( - command, stderr=DEVNULL, stdout=PIPE, encoding="utf-8" + command, encoding="utf-8", stderr=DEVNULL, stdout=PIPE ) as proc: out = list(proc.stdout) diff --git a/scripts/serd_bench.py b/scripts/serd_bench.py index e342976b..8e176322 100755 --- a/scripts/serd_bench.py +++ b/scripts/serd_bench.py @@ -3,7 +3,7 @@ # Copyright 2018-2023 David Robillard <d@drobilla.net> # SPDX-License-Identifier: ISC -""""Benchmark RDF reading and writing commands.""" +"""Benchmark RDF reading and writing commands.""" # pylint: disable=consider-using-f-string # pylint: disable=consider-using-with @@ -192,10 +192,13 @@ def run(progs, n_min, n_max, step): with open(filename(n) + ".out", "w") as out: sys.stderr.write(cmd + "\n") proc = subprocess.Popen( - cmd.split(), stdout=out, stderr=subprocess.PIPE + cmd.split(), + encoding="utf-8", + stdout=out, + stderr=subprocess.PIPE, ) - time, memory = parse_time(proc.communicate()[1].decode()) + time, memory = parse_time(proc.communicate()[1]) rows["time"] += ["%.07f" % time] rows["throughput"] += ["%d" % (n / time)] rows["memory"] += [str(memory)] diff --git a/src/base64.c b/src/base64.c index b12db9ff..07fdcbfd 100644 --- a/src/base64.c +++ b/src/base64.c @@ -51,7 +51,7 @@ encode_chunk(uint8_t out[4], const uint8_t in[3], const size_t n_in) size_t serd_base64_get_length(const size_t size, const bool wrap_lines) { - return (size + 2) / 3 * 4 + (wrap_lines * ((size - 1) / 57)); + return ((size + 2) / 3 * 4) + (wrap_lines * ((size - 1) / 57)); } bool @@ -102,7 +102,7 @@ serd_base64_decode(const uint8_t* const str, assert(str); assert(size); - void* buf = malloc((len * 3) / 4 + 2); + void* buf = malloc(((len * 3) / 4) + 2); *size = 0; for (size_t i = 0, j = 0; i < len; j += 3) { @@ -1,9 +1,8 @@ -// Copyright 2011-2023 David Robillard <d@drobilla.net> +// Copyright 2011-2025 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #include "reader.h" #include "serd_internal.h" -#include "stack.h" #include "string_utils.h" #include "try.h" #include "uri_utils.h" @@ -46,7 +45,7 @@ read_HEX(SerdReader* const reader) return (uint8_t)eat_byte_safe(reader, c); } - r_err(reader, SERD_ERR_BAD_SYNTAX, "invalid hexadecimal digit '%c'\n", c); + r_err_char(reader, "hexadecimal", c); return 0; } @@ -354,11 +353,11 @@ read_STRING_LITERAL_LONG(SerdReader* const reader, push_byte(reader, ref, c); st = read_character(reader, ref, flags, (uint8_t)q2); } - } else if (c == EOF) { - st = r_err(reader, SERD_ERR_BAD_SYNTAX, "end of file in long string\n"); - } else { + } else if (c > 0) { st = read_character(reader, ref, flags, (uint8_t)eat_byte_safe(reader, c)); + } else { + return r_err(reader, SERD_ERR_BAD_SYNTAX, "end of file in long string\n"); } } @@ -457,7 +456,7 @@ read_PN_CHARS_BASE(SerdReader* const reader, const Ref dest) return push_byte(reader, dest, eat_byte_safe(reader, c)); } - if (c == EOF || !(c & 0x80)) { + if (c < 0x80) { return SERD_FAILURE; } @@ -465,11 +464,7 @@ read_PN_CHARS_BASE(SerdReader* const reader, const Ref dest) read_utf8_code(reader, dest, &code, (uint8_t)c); if (!is_PN_CHARS_BASE(code)) { - r_err( - reader, SERD_ERR_BAD_SYNTAX, "invalid character U+%04X in name\n", code); - if (reader->strict) { - return SERD_ERR_BAD_SYNTAX; - } + st = r_err_char(reader, "name", (int)code); } return st; @@ -493,7 +488,7 @@ read_PN_CHARS(SerdReader* const reader, const Ref dest) return push_byte(reader, dest, eat_byte_safe(reader, c)); } - if (c == EOF || !(c & 0x80)) { + if (c < 0x80) { return SERD_FAILURE; } @@ -501,8 +496,7 @@ read_PN_CHARS(SerdReader* const reader, const Ref dest) TRY(st, read_utf8_code(reader, dest, &code, (uint8_t)c)); if (!is_PN_CHARS(code)) { - return r_err( - reader, SERD_ERR_BAD_SYNTAX, "invalid character U+%04X in name\n", code); + st = r_err_char(reader, "name", (int)code); } return st; @@ -531,7 +525,7 @@ read_PN_LOCAL_ESC(SerdReader* const reader, const Ref dest) return ((c == '!') || in_range(c, '#', '/') || (c == ';') || (c == '=') || (c == '?') || (c == '@') || (c == '_') || (c == '~')) ? push_byte(reader, dest, eat_byte_safe(reader, c)) - : r_err(reader, SERD_ERR_BAD_SYNTAX, "invalid escape\n"); + : r_err(reader, SERD_ERR_BAD_SYNTAX, "bad escape\n"); } static SerdStatus @@ -589,9 +583,7 @@ read_PN_LOCAL(SerdReader* const reader, const Ref dest, bool* const ate_dot) SerdNode* const n = deref(reader, dest); if (trailing_unescaped_dot) { // Ate trailing dot, pop it from stack/node and inform caller - --n->n_bytes; - serd_stack_pop(&reader->stack, 1); - *ate_dot = true; + *ate_dot = pop_last_node_char(reader, n); } return (st > SERD_FAILURE) ? st : SERD_SUCCESS; @@ -599,31 +591,37 @@ read_PN_LOCAL(SerdReader* const reader, const Ref dest, bool* const ate_dot) // Read the remainder of a PN_PREFIX after some initial characters static SerdStatus -read_PN_PREFIX_tail(SerdReader* const reader, const Ref dest) +read_PN_PREFIX_tail(SerdReader* const reader, + const Ref dest, + bool* const ate_dot) { - int c = 0; - while ((c = peek_byte(reader)) > 0) { // Middle: (PN_CHARS | '.')* + SerdStatus st = SERD_SUCCESS; + bool trailing_unescaped_dot = false; + + while (!st) { // Middle: (PN_CHARS | '.')* + const int c = peek_byte(reader); if (c == '.') { push_byte(reader, dest, eat_byte_safe(reader, c)); - } else if (read_PN_CHARS(reader, dest)) { - break; + trailing_unescaped_dot = true; + } else if (!(st = read_PN_CHARS(reader, dest))) { + trailing_unescaped_dot = false; } } - const SerdNode* const n = deref(reader, dest); - if (n->buf[n->n_bytes - 1] == '.' && read_PN_CHARS(reader, dest)) { - return r_err(reader, SERD_ERR_BAD_SYNTAX, "prefix ends with '.'\n"); + if (trailing_unescaped_dot) { + SerdNode* const n = deref(reader, dest); + *ate_dot = pop_last_node_char(reader, n); } - return SERD_SUCCESS; + return st; } static SerdStatus -read_PN_PREFIX(SerdReader* const reader, const Ref dest) +read_PN_PREFIX(SerdReader* const reader, const Ref dest, bool* const ate_dot) { const SerdStatus st = read_PN_CHARS_BASE(reader, dest); - return st ? st : read_PN_PREFIX_tail(reader, dest); + return st ? st : read_PN_PREFIX_tail(reader, dest, ate_dot); } static SerdStatus @@ -631,7 +629,7 @@ read_LANGTAG(SerdReader* const reader, Ref* const dest) { int c = peek_byte(reader); if (!is_alpha(c)) { - return r_err(reader, SERD_ERR_BAD_SYNTAX, "unexpected '%c'\n", c); + return r_err_char(reader, "language", c); } *dest = push_node(reader, SERD_LITERAL, "", 0); @@ -657,7 +655,7 @@ read_IRIREF_scheme(SerdReader* const reader, const Ref dest) { int c = peek_byte(reader); if (!is_alpha(c)) { - return r_err(reader, SERD_ERR_BAD_SYNTAX, "bad IRI scheme start '%c'\n", c); + return r_err_char(reader, "IRI scheme start", c); } while ((c = peek_byte(reader)) > 0) { @@ -666,11 +664,7 @@ read_IRIREF_scheme(SerdReader* const reader, const Ref dest) } if (!is_uri_scheme_char(c)) { - return r_err(reader, - SERD_ERR_BAD_SYNTAX, - "bad IRI scheme char U+%04X (%c)\n", - (unsigned)c, - (char)c); + return r_err_char(reader, "IRI scheme", c); } push_byte(reader, dest, eat_byte_safe(reader, c)); @@ -704,8 +698,7 @@ read_IRIREF(SerdReader* const reader, Ref* const dest) case '"': case '<': *dest = pop_node(reader, *dest); - return r_err( - reader, SERD_ERR_BAD_SYNTAX, "invalid IRI character '%c'\n", c); + return r_err_char(reader, "IRI", c); case '>': return SERD_SUCCESS; @@ -713,7 +706,7 @@ read_IRIREF(SerdReader* const reader, Ref* const dest) case '\\': if (read_UCHAR(reader, *dest, &code)) { *dest = pop_node(reader, *dest); - return r_err(reader, SERD_ERR_BAD_SYNTAX, "invalid IRI escape\n"); + return r_err_char(reader, "IRI escape", c); } if (code == ' ' || code == '<' || code == '>') { @@ -731,11 +724,12 @@ read_IRIREF(SerdReader* const reader, Ref* const dest) case '|': case '}': *dest = pop_node(reader, *dest); - return r_err( - reader, SERD_ERR_BAD_SYNTAX, "invalid IRI character '%c'\n", c); + return r_err_char(reader, "IRI", c); default: - if (c <= 0x20) { + if (c <= 0) { + st = r_err(reader, SERD_ERR_BAD_SYNTAX, "unexpected end of file\n"); + } else if (c <= 0x20) { st = r_err(reader, SERD_ERR_BAD_SYNTAX, "invalid IRI character (escape %%%02X)\n", @@ -743,8 +737,6 @@ read_IRIREF(SerdReader* const reader, Ref* const dest) if (!reader->strict) { st = SERD_FAILURE; push_byte(reader, *dest, c); - } else { - break; } } else if (!(c & 0x80)) { push_byte(reader, *dest, c); @@ -762,15 +754,10 @@ read_IRIREF(SerdReader* const reader, Ref* const dest) } static SerdStatus -read_PrefixedName(SerdReader* const reader, - const Ref dest, - const bool read_prefix, - bool* const ate_dot) +read_PrefixedName(SerdReader* const reader, const Ref dest, bool* const ate_dot) { SerdStatus st = SERD_SUCCESS; - if (read_prefix) { - TRY_FAILING(st, read_PN_PREFIX(reader, dest)); - } + TRY_FAILING(st, read_PN_PREFIX(reader, dest, ate_dot)); if (peek_byte(reader) != ':') { return SERD_FAILURE; @@ -825,18 +812,16 @@ read_number(SerdReader* const reader, // all other cases ::= ( '-' | '+' ) [0-9]+ ( . )? ( [0-9]+ )? ... TRY(st, read_0_9(reader, *dest, true)); if ((c = peek_byte(reader)) == '.') { - has_decimal = true; - // Annoyingly, dot can be end of statement, so tentatively eat skip_byte(reader, c); c = peek_byte(reader); if (!is_digit(c) && c != 'e' && c != 'E') { - *ate_dot = true; // Force caller to deal with stupid grammar - return SERD_SUCCESS; // Next byte is not a number character + *ate_dot = true; // Force caller to deal with silly grammar + } else { + has_decimal = true; + push_byte(reader, *dest, '.'); + read_0_9(reader, *dest, false); } - - push_byte(reader, *dest, '.'); - read_0_9(reader, *dest, false); } } c = peek_byte(reader); @@ -868,7 +853,7 @@ read_iri(SerdReader* const reader, Ref* const dest, bool* const ate_dot) } *dest = push_node(reader, SERD_CURIE, "", 0); - return read_PrefixedName(reader, *dest, true, ate_dot); + return read_PrefixedName(reader, *dest, ate_dot); } static SerdStatus @@ -920,29 +905,30 @@ read_verb(SerdReader* const reader, Ref* const dest) return read_IRIREF(reader, dest); } - /* Either a qname, or "a". Read the prefix first, and if it is in fact - "a", produce that instead. - */ - *dest = push_node(reader, SERD_CURIE, "", 0); + Ref p = push_node(reader, SERD_CURIE, "", 0); - 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); - *dest = push_node(reader, SERD_URI, NS_RDF "type", 47); - return SERD_SUCCESS; + // Try to read as a prefixed name + bool ate_dot = false; + SerdStatus st = read_PrefixedName(reader, p, &ate_dot); + + if (st == SERD_FAILURE) { + // Check if this is actually the "a" shorthand + const SerdNode* const node = deref(reader, p); + if (node->n_bytes == 1 && node->buf[0] == 'a') { + pop_node(reader, p); + p = push_node(reader, SERD_URI, NS_RDF "type", 47); + st = SERD_SUCCESS; + } else { + st = SERD_ERR_BAD_SYNTAX; + } } - if (st > SERD_FAILURE || - (st = read_PrefixedName(reader, *dest, false, &ate_dot)) || ate_dot) { - *dest = pop_node(reader, *dest); - st = st > SERD_FAILURE ? st : SERD_ERR_BAD_SYNTAX; + if (st) { + pop_node(reader, p); return r_err(reader, st, "bad verb\n"); } + *dest = p; return SERD_SUCCESS; } @@ -981,9 +967,7 @@ read_BLANK_NODE_LABEL(SerdReader* const reader, SerdNode* n = deref(reader, ref); if (n->buf[n->n_bytes - 1] == '.' && read_PN_CHARS(reader, ref)) { // Ate trailing dot, pop it from stack/node and inform caller - --n->n_bytes; - serd_stack_pop(&reader->stack, 1); - *ate_dot = true; + *ate_dot = pop_last_node_char(reader, n); } if (fancy_syntax(reader)) { @@ -1078,6 +1062,40 @@ read_anon(SerdReader* const reader, : SERD_ERR_BAD_SYNTAX; } +// Read a "named" object: a boolean literal or a prefixed name +static SerdStatus +read_named_object(SerdReader* const reader, + Ref* const dest, + Ref* const datatype, + bool* const ate_dot) +{ + static const char* const XSD_BOOLEAN = NS_XSD "boolean"; + static const size_t XSD_BOOLEAN_LEN = 40; + + // Try to read as a prefixed name + const Ref o = push_node(reader, SERD_CURIE, "", 0); + SerdStatus st = read_PrefixedName(reader, o, ate_dot); + + if (st == SERD_FAILURE) { + // Check if this is actually a boolean literal + SerdNode* const node = deref(reader, o); + if ((node->n_bytes == 4 && !memcmp(node->buf, "true", 4)) || + (node->n_bytes == 5 && !memcmp(node->buf, "false", 5))) { + node->type = SERD_LITERAL; + *datatype = push_node(reader, SERD_URI, XSD_BOOLEAN, XSD_BOOLEAN_LEN); + st = SERD_SUCCESS; + } + } + + if (st) { + pop_node(reader, o); + return r_err(reader, SERD_ERR_BAD_SYNTAX, "expected prefixed name\n"); + } + + *dest = o; + return SERD_SUCCESS; +} + /* If emit is true: recurses, calling statement_sink for every statement encountered, and leaves stack in original calling state (i.e. pops everything it pushes). */ @@ -1087,9 +1105,6 @@ read_object(SerdReader* const reader, const bool emit, bool* const ate_dot) { - static const char* const XSD_BOOLEAN = NS_XSD "boolean"; - static const size_t XSD_BOOLEAN_LEN = 40; - #ifndef NDEBUG const size_t orig_stack_size = reader->stack.size; #endif @@ -1097,7 +1112,6 @@ read_object(SerdReader* const reader, SerdStatus st = SERD_FAILURE; bool simple = (ctx->subject != 0); - SerdNode* node = NULL; Ref o = 0; Ref datatype = 0; Ref lang = 0; @@ -1147,27 +1161,8 @@ read_object(SerdReader* const reader, st = read_literal(reader, &o, &datatype, &lang, &flags, ate_dot); break; default: - /* Either a boolean literal, or a qname. Read the prefix first, and if - it is in fact a "true" or "false" literal, produce that instead. - */ - o = push_node(reader, SERD_CURIE, "", 0); - while (!read_PN_CHARS_BASE(reader, o)) { - } - node = deref(reader, o); - if ((node->n_bytes == 4 && !memcmp(node->buf, "true", 4)) || - (node->n_bytes == 5 && !memcmp(node->buf, "false", 5))) { - node->type = SERD_LITERAL; - datatype = push_node(reader, SERD_URI, XSD_BOOLEAN, XSD_BOOLEAN_LEN); - st = SERD_SUCCESS; - } else if (read_PN_PREFIX_tail(reader, o) > SERD_FAILURE) { - st = SERD_ERR_BAD_SYNTAX; - } else { - if ((st = read_PrefixedName(reader, o, false, ate_dot))) { - st = st > SERD_FAILURE ? st : SERD_ERR_BAD_SYNTAX; - pop_node(reader, o); - return r_err(reader, st, "expected prefixed name\n"); - } - } + // Either a boolean literal or a prefixed name + st = read_named_object(reader, &o, &datatype, ate_dot); } if (!st && simple && o) { @@ -1444,12 +1439,12 @@ read_prefixID(SerdReader* const reader, const bool sparql, const bool token) } read_ws_star(reader); - Ref name = push_node(reader, SERD_LITERAL, "", 0); - TRY_FAILING(st, read_PN_PREFIX(reader, name)); - - if (eat_byte_check(reader, ':') != ':') { + Ref name = push_node(reader, SERD_LITERAL, "", 0); + bool ate_dot = false; + TRY_FAILING(st, read_PN_PREFIX(reader, name, &ate_dot)); + if (ate_dot || eat_byte_check(reader, ':') != ':') { pop_node(reader, name); - return SERD_ERR_BAD_SYNTAX; + return r_err(reader, SERD_ERR_BAD_SYNTAX, "expected a prefix name\n"); } read_ws_star(reader); @@ -1,8 +1,6 @@ // Copyright 2011-2023 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC -#include "node.h" - #include "base64.h" #include "string_utils.h" @@ -17,6 +15,12 @@ #include <stdlib.h> #include <string.h> +struct SerdNodeImpl { + size_t n_bytes; /**< Size in bytes (not including null) */ + SerdNodeFlags flags; /**< Node flags (e.g. string properties) */ + SerdType type; /**< Node type */ +}; + static size_t serd_uri_string_length(const SerdURI* const uri) { @@ -288,7 +292,7 @@ serd_node_new_decimal(const double d, const unsigned frac_digits) char* t = s - 1; uint64_t dec = (uint64_t)int_part; do { - *t-- = (char)('0' + dec % 10); + *t-- = (char)('0' + (dec % 10)); } while ((dec /= 10) > 0); *s++ = '.'; diff --git a/src/node.h b/src/node.h deleted file mode 100644 index ce53a1be..00000000 --- a/src/node.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2011-2023 David Robillard <d@drobilla.net> -// SPDX-License-Identifier: ISC - -#ifndef SERD_SRC_NODE_H -#define SERD_SRC_NODE_H - -#include <serd/serd.h> - -#include <stddef.h> - -struct SerdNodeImpl { - size_t n_bytes; /**< Size in bytes (not including null) */ - SerdNodeFlags flags; /**< Node flags (e.g. string properties) */ - SerdType type; /**< Node type */ -}; - -static inline char* SERD_NONNULL -serd_node_buffer(SerdNode* const SERD_NONNULL node) -{ - return (char*)(node + 1); -} - -static inline const char* SERD_NONNULL -serd_node_buffer_c(const SerdNode* const SERD_NONNULL node) -{ - return (const char*)(node + 1); -} - -SerdNode* SERD_ALLOCATED -serd_node_malloc(size_t n_bytes, SerdNodeFlags flags, SerdType type); - -void -serd_node_set(SerdNode* SERD_NULLABLE* SERD_NONNULL dst, - const SerdNode* SERD_NULLABLE src); - -#endif // SERD_SRC_NODE_H diff --git a/src/reader.c b/src/reader.c index b2563c49..d5ac379b 100644 --- a/src/reader.c +++ b/src/reader.c @@ -30,6 +30,17 @@ r_err(SerdReader* const reader, const SerdStatus st, const char* const fmt, ...) return st; } +SerdStatus +r_err_char(SerdReader* const reader, const char* const kind, const int c) +{ + const SerdStatus st = SERD_ERR_BAD_SYNTAX; + + return (c < 0x20 || c == 0x7F) ? r_err(reader, st, "bad %s character\n", kind) + : (c == '\'' || c >= 0x80) + ? r_err(reader, st, "bad %s character U+%04X\n", kind, (uint32_t)c) + : r_err(reader, st, "bad %s character '%c'\n", kind, c); +} + void set_blank_id(SerdReader* const reader, const Ref ref, const size_t buf_size) { @@ -119,6 +130,14 @@ deref(SerdReader* const reader, const Ref ref) return NULL; } +bool +pop_last_node_char(SerdReader* const reader, SerdNode* const node) +{ + --node->n_bytes; + serd_stack_pop(&reader->stack, 1); + return true; +} + Ref pop_node(SerdReader* const reader, const Ref ref) { diff --git a/src/reader.h b/src/reader.h index d7b06a98..9ff26e3e 100644 --- a/src/reader.h +++ b/src/reader.h @@ -69,6 +69,9 @@ SERD_LOG_FUNC(3, 4) SerdStatus r_err(SerdReader* reader, SerdStatus st, const char* fmt, ...); +SerdStatus +r_err_char(SerdReader* reader, const char* kind, int c); + Ref push_node_padded(SerdReader* reader, size_t maxlen, @@ -91,6 +94,9 @@ set_blank_id(SerdReader* reader, Ref ref, size_t buf_size); SerdNode* deref(SerdReader* reader, Ref ref); +bool +pop_last_node_char(SerdReader* reader, SerdNode* node); + Ref pop_node(SerdReader* reader, Ref ref); @@ -127,7 +133,7 @@ skip_byte(SerdReader* const reader, const int byte) return serd_byte_source_advance(&reader->source); } -static inline int SERD_NODISCARD +SERD_NODISCARD static inline int eat_byte_safe(SerdReader* const reader, const int byte) { (void)byte; @@ -138,12 +144,12 @@ eat_byte_safe(SerdReader* const reader, const int byte) return byte; } -static inline int SERD_NODISCARD +SERD_NODISCARD static inline int eat_byte_check(SerdReader* const reader, const int byte) { const int c = peek_byte(reader); if (c != byte) { - r_err(reader, SERD_ERR_BAD_SYNTAX, "expected '%c', not '%c'\n", byte, c); + r_err(reader, SERD_ERR_BAD_SYNTAX, "expected '%c'\n", byte); return 0; } return eat_byte_safe(reader, byte); diff --git a/src/serd_config.h b/src/serd_config.h index 150ffb81..d4165a20 100644 --- a/src/serd_config.h +++ b/src/serd_config.h @@ -36,7 +36,7 @@ #define SERD_SRC_SERD_CONFIG_H // Define version unconditionally so a warning will catch a mismatch -#define SERD_VERSION "0.32.3" +#define SERD_VERSION "0.32.5" #if !defined(SERD_NO_DEFAULT_CONFIG) diff --git a/src/stack.h b/src/stack.h index f82de9d2..63c6ba01 100644 --- a/src/stack.h +++ b/src/stack.h @@ -20,9 +20,6 @@ typedef struct { size_t size; ///< Conceptual size of stack in buf } SerdStack; -/** An offset to start the stack at. Note 0 is reserved for NULL. */ -#define SERD_STACK_BOTTOM sizeof(void*) - static inline SerdStack serd_stack_new(const size_t size) { @@ -79,7 +76,7 @@ serd_stack_push_aligned(SerdStack* const stack, serd_stack_push(stack, 1); // Push padding if necessary - const size_t pad = align - stack->size % align; + const size_t pad = align - (stack->size % align); serd_stack_push(stack, pad); // Set top of stack to pad count so we can properly pop later diff --git a/src/string_utils.h b/src/string_utils.h index 6a098991..f4b27bcc 100644 --- a/src/string_utils.h +++ b/src/string_utils.h @@ -51,13 +51,13 @@ is_xdigit(const int c) static inline bool is_space(const char c) { - return c == ' ' || (c >= '\t' && c <= '\r'); + return c == ' ' || in_range(c, '\t', '\r'); } static inline bool is_print(const int c) { - return c >= 0x20 && c <= 0x7E; + return in_range(c, 0x20, 0x7E); } static inline bool @@ -88,7 +88,7 @@ hex_digit_value(const uint8_t c) static inline char serd_to_upper(const char c) { - return (char)((c >= 'a' && c <= 'z') ? c - 32 : c); + return (char)(in_range(c, 'a', 'z') ? (c - 32) : c); } SERD_PURE_FUNC static inline int @@ -4,6 +4,8 @@ #ifndef SERD_SRC_TRY_H #define SERD_SRC_TRY_H +#include <serd/serd.h> + #define TRY(st, exp) \ do { \ if (((st) = (exp))) { \ diff --git a/src/writer.c b/src/writer.c index f0a9ad16..7e4a1060 100644 --- a/src/writer.c +++ b/src/writer.c @@ -1,4 +1,4 @@ -// Copyright 2011-2023 David Robillard <d@drobilla.net> +// Copyright 2011-2025 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #include "attributes.h" @@ -37,20 +37,12 @@ typedef enum { typedef struct { ContextType type; + bool comma_indented; SerdNode graph; SerdNode subject; SerdNode predicate; - bool predicates; - bool comma_indented; } WriteContext; -static const WriteContext WRITE_CONTEXT_NULL = {CTX_NAMED, - {0, 0, 0, 0, SERD_NOTHING}, - {0, 0, 0, 0, SERD_NOTHING}, - {0, 0, 0, 0, SERD_NOTHING}, - 0U, - 0U}; - typedef enum { SEP_NONE, ///< Sentinel after "nothing" SEP_NEWLINE, ///< Sentinel after a line end @@ -205,7 +197,7 @@ push_context(SerdWriter* const writer, *(WriteContext*)top = writer->context; // Update the current context - const WriteContext current = {type, graph, subject, predicate, 0U, 0U}; + const WriteContext current = {type, false, graph, subject, predicate}; writer->context = current; } @@ -238,7 +230,7 @@ sink(const void* const buf, const size_t len, SerdWriter* const writer) return written; } -SERD_NODISCARD static inline SerdStatus +SERD_NODISCARD static SerdStatus esink(const void* const buf, const size_t len, SerdWriter* const writer) { return sink(buf, len, writer) == len ? SERD_SUCCESS : SERD_ERR_BAD_WRITE; @@ -550,10 +542,13 @@ write_sep(SerdWriter* const writer, const Sep sep) : 0); } - // If this is the first comma, bump the increment for the following object + // Adjust indentation for object comma if necessary if (sep == SEP_END_O && !writer->context.comma_indented) { ++writer->indent; writer->context.comma_indented = true; + } else if (sep == SEP_END_P && writer->context.comma_indented) { + --writer->indent; + writer->context.comma_indented = false; } // Write newline or space before separator if necessary @@ -579,7 +574,6 @@ write_sep(SerdWriter* const writer, const Sep sep) // Reset context and write a blank line after ends of subjects if (sep == SEP_END_S) { writer->indent = writer->context.graph.type ? 1 : 0; - writer->context.predicates = false; writer->context.comma_indented = false; TRY(st, esink("\n", 1, writer)); } @@ -612,7 +606,6 @@ reset_context(SerdWriter* const writer, const unsigned flags) writer->context.type = CTX_NAMED; writer->context.subject.type = SERD_NOTHING; writer->context.predicate.type = SERD_NOTHING; - writer->context.predicates = false; writer->context.comma_indented = false; return SERD_SUCCESS; } @@ -864,7 +857,6 @@ write_pred(SerdWriter* const writer, TRY(st, write_sep(writer, SEP_P_O)); copy_node(&writer->context.predicate, pred); - writer->context.predicates = true; writer->context.comma_indented = false; return st; } @@ -926,10 +918,6 @@ serd_writer_write_statement(SerdWriter* const writer, SerdStatus st = SERD_SUCCESS; - if (!is_resource(subject) || !is_resource(predicate) || !object->buf) { - return SERD_ERR_BAD_ARG; - } - if ((flags & SERD_LIST_O_BEGIN) && !strcmp((const char*)object->buf, NS_RDF "nil")) { /* Tolerate LIST_O_BEGIN for "()" objects, even though it doesn't make @@ -938,6 +926,17 @@ serd_writer_write_statement(SerdWriter* const writer, flags &= (SerdStatementFlags)~SERD_LIST_O_BEGIN; } + // Refuse to write incoherent statements + if (!is_resource(subject) || !is_resource(predicate) || + object->type == SERD_NOTHING || !object->buf || + (datatype && datatype->buf && lang && lang->buf) || + ((flags & SERD_ANON_S_BEGIN) && (flags & SERD_LIST_S_BEGIN)) || + ((flags & SERD_EMPTY_S) && (flags & SERD_LIST_S_BEGIN)) || + ((flags & SERD_ANON_O_BEGIN) && (flags & SERD_LIST_O_BEGIN)) || + ((flags & SERD_EMPTY_O) && (flags & SERD_LIST_O_BEGIN))) { + return SERD_ERR_BAD_ARG; + } + // Simple case: write a line of NTriples or NQuads if (writer->syntax == SERD_NTRIPLES || writer->syntax == SERD_NQUADS) { TRY(st, write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags)); @@ -953,23 +952,21 @@ serd_writer_write_statement(SerdWriter* const writer, return SERD_SUCCESS; } - SERD_DISABLE_NULL_WARNINGS - // Separate graphs if necessary - if ((graph && !serd_node_equals(graph, &writer->context.graph)) || - (!graph && writer->context.graph.type)) { + const SerdNode* const out_graph = writer->syntax == SERD_TRIG ? graph : NULL; + if ((out_graph && !serd_node_equals(out_graph, &writer->context.graph)) || + (!out_graph && writer->context.graph.type)) { TRY(st, terminate_context(writer)); reset_context(writer, RESET_GRAPH | RESET_INDENT); TRY(st, write_newline(writer)); - if (graph) { - TRY(st, write_node(writer, graph, datatype, lang, FIELD_GRAPH, flags)); + if (out_graph) { + TRY(st, + write_node(writer, out_graph, datatype, lang, FIELD_GRAPH, flags)); TRY(st, write_sep(writer, SEP_GRAPH_BEGIN)); - copy_node(&writer->context.graph, graph); + copy_node(&writer->context.graph, out_graph); } } - SERD_RESTORE_WARNINGS - if ((flags & SERD_LIST_CONT)) { // Continue a list if (!strcmp((const char*)predicate->buf, NS_RDF "first") && @@ -1003,11 +1000,6 @@ serd_writer_write_statement(SerdWriter* const writer, } else { // Elide S (write P and O) - if (writer->context.comma_indented) { - --writer->indent; - writer->context.comma_indented = false; - } - const bool first = !writer->context.predicate.type; TRY(st, write_sep(writer, first ? SEP_S_P : SEP_END_P)); TRY(st, write_pred(writer, flags, predicate)); @@ -1052,7 +1044,7 @@ serd_writer_write_statement(SerdWriter* const writer, const bool is_list = (flags & SERD_LIST_S_BEGIN); push_context(writer, is_list ? CTX_LIST : CTX_BLANK, - serd_node_copy(graph), + serd_node_copy(out_graph), serd_node_copy(subject), is_list ? SERD_NODE_NULL : serd_node_copy(predicate)); } @@ -1061,7 +1053,7 @@ serd_writer_write_statement(SerdWriter* const writer, // Push context for anonymous or list object if necessary push_context(writer, (flags & SERD_LIST_O_BEGIN) ? CTX_LIST : CTX_BLANK, - serd_node_copy(graph), + serd_node_copy(out_graph), serd_node_copy(object), SERD_NODE_NULL); } @@ -1089,14 +1081,11 @@ serd_writer_end_anon(SerdWriter* const writer, const SerdNode* const node) TRY(st, write_sep(writer, SEP_ANON_END)); pop_context(writer); - SERD_DISABLE_NULL_WARNINGS - if (node && serd_node_equals(node, &writer->context.subject)) { // Now-finished anonymous node is the new subject with no other context writer->context.predicate.type = SERD_NOTHING; } - SERD_RESTORE_WARNINGS return st; } @@ -1123,8 +1112,7 @@ serd_writer_new(const SerdSyntax syntax, assert(env); assert(ssink); - const WriteContext context = WRITE_CONTEXT_NULL; - SerdWriter* writer = (SerdWriter*)calloc(1, sizeof(SerdWriter)); + SerdWriter* writer = (SerdWriter*)calloc(1, sizeof(SerdWriter)); writer->syntax = syntax; writer->style = style; @@ -1133,7 +1121,6 @@ serd_writer_new(const SerdSyntax syntax, writer->root_uri = SERD_URI_NULL; writer->base_uri = base_uri ? *base_uri : SERD_URI_NULL; writer->anon_stack = serd_stack_new(SERD_PAGE_SIZE); - writer->context = context; writer->byte_sink = serd_byte_sink_new( ssink, stream, (style & SERD_STYLE_BULK) ? SERD_PAGE_SIZE : 1); @@ -1244,9 +1231,7 @@ serd_writer_free(SerdWriter* const writer) return; } - SERD_DISABLE_NULL_WARNINGS serd_writer_finish(writer); - SERD_RESTORE_WARNINGS free_context(&writer->context); free_anon_stack(writer); serd_stack_free(&writer->anon_stack); diff --git a/subprojects/sphinxygen.wrap b/subprojects/sphinxygen.wrap index 9707d1a6..898ee526 100644 --- a/subprojects/sphinxygen.wrap +++ b/subprojects/sphinxygen.wrap @@ -1,14 +1,14 @@ -# Copyright 2022-2023 David Robillard <d@drobilla.net> +# Copyright 2022-2025 David Robillard <d@drobilla.net> # SPDX-License-Identifier: 0BSD OR ISC [wrap-file] -directory = sphinxygen-1.0.4 -source_url = https://download.drobilla.net/sphinxygen-1.0.4.tar.gz -source_filename = sphinxygen-1.0.4.tar.gz -source_hash = 12fa9f18ed9fca608f272520072257ba61fd9eff25613f86d83d4fce14fc01f5 +directory = sphinxygen-1.0.10 +source_url = https://download.drobilla.net/sphinxygen-1.0.10.tar.gz +source_filename = sphinxygen-1.0.10.tar.gz +source_hash = 4b5eeb1ff47d43ee1ddae9327c2b49bab1e49363538c569bc544705284f3695d # [wrap-git] # url = https://gitlab.com/drobilla/sphinxygen.git # push-url = ssh://git@gitlab.com:drobilla/sphinxygen.git -# revision = v1.0.4 +# revision = v1.0.10 # depth = 1 diff --git a/test/.clang-tidy b/test/.clang-tidy index 99a3264a..80737308 100644 --- a/test/.clang-tidy +++ b/test/.clang-tidy @@ -7,7 +7,6 @@ Checks: > -bugprone-assert-side-effect, -bugprone-easily-swappable-parameters, -cert-err33-c, - -clang-analyzer-nullability.NullableDereferenced, -clang-analyzer-optin.core.EnumCastOutOfRange, -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, -concurrency-mt-unsafe, diff --git a/test/extra/bad/bad-lang-start-delete.nt b/test/extra/bad/bad-lang-start-delete.nt new file mode 100644 index 00000000..122625e0 --- /dev/null +++ b/test/extra/bad/bad-lang-start-delete.nt @@ -0,0 +1 @@ +<http://example.org/s> <http://example.org/p> "hello"@bad . diff --git a/test/extra/bad/bad-lang-start-space.nt b/test/extra/bad/bad-lang-start-space.nt new file mode 100644 index 00000000..ff5c12ab --- /dev/null +++ b/test/extra/bad/bad-lang-start-space.nt @@ -0,0 +1 @@ +<http://example.org/s> <http://example.org/p> "hello"@ bad . diff --git a/test/extra/bad/bad-lang-start-tab.nt b/test/extra/bad/bad-lang-start-tab.nt new file mode 100644 index 00000000..ad005c6d --- /dev/null +++ b/test/extra/bad/bad-lang-start-tab.nt @@ -0,0 +1 @@ +<http://example.org/s> <http://example.org/p> "hello"@ bad . diff --git a/test/extra/bad/bad-lang-start-wide.nt b/test/extra/bad/bad-lang-start-wide.nt new file mode 100644 index 00000000..04ca4899 --- /dev/null +++ b/test/extra/bad/bad-lang-start-wide.nt @@ -0,0 +1 @@ +<http://example.org/s> <http://example.org/p> "hello"@βad . diff --git a/test/extra/bad/bad-lang.ttl b/test/extra/bad/bad-lang.ttl index 01e04328..b51df89c 100644 --- a/test/extra/bad/bad-lang.ttl +++ b/test/extra/bad/bad-lang.ttl @@ -1 +1 @@ -<> <http://example.org/pred> "hello"@\bad .
\ No newline at end of file +<> <http://example.org/pred> "hello"@b\ad . diff --git a/test/extra/bad/bad-uri-scheme-start-apostrophe.nt b/test/extra/bad/bad-uri-scheme-start-apostrophe.nt new file mode 100644 index 00000000..265b46d1 --- /dev/null +++ b/test/extra/bad/bad-uri-scheme-start-apostrophe.nt @@ -0,0 +1 @@ +<http://example.org/s> <http://example.org/p> <'http://example.org/o> . diff --git a/test/extra/bad/bad-uri-scheme-start-delete.nt b/test/extra/bad/bad-uri-scheme-start-delete.nt new file mode 100644 index 00000000..70b4962a --- /dev/null +++ b/test/extra/bad/bad-uri-scheme-start-delete.nt @@ -0,0 +1 @@ +<http://example.org/s> <http://example.org/p> <http://example.org/o> . diff --git a/test/extra/bad/bad-uri-scheme-start-space.nt b/test/extra/bad/bad-uri-scheme-start-space.nt new file mode 100644 index 00000000..d396d6dd --- /dev/null +++ b/test/extra/bad/bad-uri-scheme-start-space.nt @@ -0,0 +1 @@ +<http://example.org/s> <http://example.org/p> < http://example.org/o> . diff --git a/test/extra/bad/bad-uri-scheme-start-tab.nt b/test/extra/bad/bad-uri-scheme-start-tab.nt new file mode 100644 index 00000000..458a5743 --- /dev/null +++ b/test/extra/bad/bad-uri-scheme-start-tab.nt @@ -0,0 +1 @@ +<http://example.org/s> <http://example.org/p> < http://example.org/o> . diff --git a/test/extra/bad/bad-uri-scheme-start-wide.nt b/test/extra/bad/bad-uri-scheme-start-wide.nt new file mode 100644 index 00000000..7ddfff60 --- /dev/null +++ b/test/extra/bad/bad-uri-scheme-start-wide.nt @@ -0,0 +1 @@ +<http://example.org/s> <http://example.org/p> <σhttp://example.org/o> . diff --git a/test/extra/bad/bad-uri-scheme-start.nt b/test/extra/bad/bad-uri-scheme-start.nt deleted file mode 100644 index cd3fd70f..00000000 --- a/test/extra/bad/bad-uri-scheme-start.nt +++ /dev/null @@ -1 +0,0 @@ -<2http://example.org/s> <http://example.org/p> <http://example.org/o> . diff --git a/test/extra/bad/manifest.ttl b/test/extra/bad/manifest.ttl index 64dbf05f..a4bb4b4f 100644 --- a/test/extra/bad/manifest.ttl +++ b/test/extra/bad/manifest.ttl @@ -28,24 +28,6 @@ <#bad-dot-after-subject> <#bad-dot-in-collection> <#bad-empty-blank-predicate> - <#bad-nt-eof-after-blank> - <#bad-nt-eof-after-lang> - <#bad-nt-eof-after-lang-hyphen> - <#bad-nt-eof-after-lang-subtag> - <#bad-nt-eof-after-object> - <#bad-nt-eof-after-predicate> - <#bad-nt-eof-after-string> - <#bad-nt-eof-after-string-escape> - <#bad-nt-eof-after-subject> - <#bad-nt-eof-after-underscore> - <#bad-nt-eof-before-blank> - <#bad-nt-eof-before-iri> - <#bad-nt-eof-before-lang> - <#bad-nt-eof-before-string> - <#bad-nt-eof-before-string-escape> - <#bad-nt-eof-in-iri-path> - <#bad-nt-eof-in-iri-scheme> - <#bad-nt-eof-in-string> <#bad-nt-syntax-blank-u00F7.nt> <#bad-nt-syntax-blank-u037E.nt> <#bad-nt-syntax-blank-u200B.nt> @@ -65,24 +47,6 @@ <#bad-nt-syntax-uri-grave> <#bad-nt-syntax-uri-less-than> <#bad-nt-syntax-uri-opening-brace> - <#bad-eof-after-quotes> - <#bad-eof-at-string-start> - <#bad-eof-in-blank> - <#bad-eof-in-escape> - <#bad-eof-in-lang-suffix> - <#bad-eof-in-lang> - <#bad-eof-in-list> - <#bad-eof-in-long-string> - <#bad-eof-in-object-list> - <#bad-eof-in-object-list2> - <#bad-eof-in-predicate-list> - <#bad-eof-in-string> - <#bad-eof-in-text-character> - <#bad-eof-in-triple-quote> - <#bad-eof-in-uri> - <#bad-eof-in-uri-character> - <#bad-eof-in-uri-scheme> - <#bad-eof-in-utf8-character> <#bad-equivalence> <#bad-escape> <#bad-ext-namedblank-op> @@ -99,6 +63,10 @@ <#bad-is-of-keywords> <#bad-keywords> <#bad-lang> + <#bad-lang-start-delete> + <#bad-lang-start-space> + <#bad-lang-start-tab> + <#bad-lang-start-wide> <#bad-list> <#bad-list-close-object> <#bad-list2> @@ -128,7 +96,10 @@ <#bad-true-subject> <#bad-uri-escape> <#bad-uri-scheme> - <#bad-uri-scheme-start> + <#bad-uri-scheme-start-delete> + <#bad-uri-scheme-start-space> + <#bad-uri-scheme-start-tab> + <#bad-uri-scheme-start-wide> <#bad-uri-truncated> <#bad-verb> ) . @@ -243,96 +214,6 @@ mf:action <bad-empty-blank-predicate.ttl> ; mf:name "bad-empty-blank-predicate" . -<#bad-nt-eof-after-blank> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-after-blank.nt> ; - mf:name "bad-nt-eof-after-blank" . - -<#bad-nt-eof-after-lang> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-after-lang.nt> ; - mf:name "bad-nt-eof-after-lang" . - -<#bad-nt-eof-after-lang-hyphen> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-after-lang-hyphen.nt> ; - mf:name "bad-nt-eof-after-lang-hyphen" . - -<#bad-nt-eof-after-lang-subtag> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-after-lang-subtag.nt> ; - mf:name "bad-nt-eof-after-lang-subtag" . - -<#bad-nt-eof-after-object> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-after-object.nt> ; - mf:name "bad-nt-eof-after-object" . - -<#bad-nt-eof-after-predicate> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-after-predicate.nt> ; - mf:name "bad-nt-eof-after-predicate" . - -<#bad-nt-eof-after-string> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-after-string.nt> ; - mf:name "bad-nt-eof-after-string" . - -<#bad-nt-eof-after-string-escape> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-after-string-escape.nt> ; - mf:name "bad-nt-eof-after-string-escape" . - -<#bad-nt-eof-after-subject> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-after-subject.nt> ; - mf:name "bad-nt-eof-after-subject" . - -<#bad-nt-eof-after-underscore> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-after-underscore.nt> ; - mf:name "bad-nt-eof-after-underscore" . - -<#bad-nt-eof-before-blank> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-before-blank.nt> ; - mf:name "bad-nt-eof-before-blank" . - -<#bad-nt-eof-before-iri> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-before-iri.nt> ; - mf:name "bad-nt-eof-before-iri" . - -<#bad-nt-eof-before-lang> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-before-lang.nt> ; - mf:name "bad-nt-eof-before-lang" . - -<#bad-nt-eof-before-string> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-before-string.nt> ; - mf:name "bad-nt-eof-before-string" . - -<#bad-nt-eof-before-string-escape> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-before-string-escape.nt> ; - mf:name "bad-nt-eof-before-string-escape" . - -<#bad-nt-eof-in-iri-path> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-in-iri-path.nt> ; - mf:name "bad-nt-eof-in-iri-path" . - -<#bad-nt-eof-in-iri-scheme> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-in-iri-scheme.nt> ; - mf:name "bad-nt-eof-in-iri-scheme" . - -<#bad-nt-eof-in-string> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-nt-eof-in-string.nt> ; - mf:name "bad-nt-eof-in-string" . - <#bad-nt-syntax-blank-u00F7> a rdft:TestNTriplesNegativeSyntax ; mf:action <bad-nt-syntax-blank-u00F7.nt> ; @@ -428,96 +309,6 @@ mf:action <bad-nt-syntax-uri-opening-brace.nt> ; mf:name "bad-nt-syntax-uri-opening-brace" . -<#bad-eof-after-quotes> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-after-quotes.ttl> ; - mf:name "bad-eof-after-quotes" . - -<#bad-eof-at-string-start> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-at-string-start.ttl> ; - mf:name "bad-eof-at-string-start" . - -<#bad-eof-in-blank> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-blank.ttl> ; - mf:name "bad-eof-in-blank" . - -<#bad-eof-in-escape> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-escape.ttl> ; - mf:name "bad-eof-in-escape" . - -<#bad-eof-in-lang> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-lang.ttl> ; - mf:name "bad-eof-in-lang" . - -<#bad-eof-in-lang-suffix> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-lang-suffix.ttl> ; - mf:name "bad-eof-in-lang-suffix" . - -<#bad-eof-in-list> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-list.ttl> ; - mf:name "bad-eof-in-list" . - -<#bad-eof-in-long-string> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-long-string.ttl> ; - mf:name "bad-eof-in-long-string" . - -<#bad-eof-in-object-list> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-object-list.ttl> ; - mf:name "bad-eof-in-object-list" . - -<#bad-eof-in-object-list2> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-object-list2.ttl> ; - mf:name "bad-eof-in-object-list2" . - -<#bad-eof-in-predicate-list> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-predicate-list.ttl> ; - mf:name "bad-eof-in-predicate-list" . - -<#bad-eof-in-string> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-string.ttl> ; - mf:name "bad-eof-in-string" . - -<#bad-eof-in-text-character> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-text-character.ttl> ; - mf:name "bad-eof-in-text-character" . - -<#bad-eof-in-triple-quote> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-triple-quote.ttl> ; - mf:name "bad-eof-in-triple-quote" . - -<#bad-eof-in-uri> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-uri.ttl> ; - mf:name "bad-eof-in-uri" . - -<#bad-eof-in-uri-character> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-uri-character.ttl> ; - mf:name "bad-eof-in-uri-character" . - -<#bad-eof-in-uri-scheme> - a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-eof-in-uri-scheme.nt> ; - mf:name "bad-eof-in-uri-scheme" . - -<#bad-eof-in-utf8-character> - a rdft:TestTurtleNegativeSyntax ; - mf:action <bad-eof-in-utf8-character.ttl> ; - mf:name "bad-eof-in-utf8-character" . - <#bad-equivalence> a rdft:TestTurtleNegativeSyntax ; mf:action <bad-equivalence.ttl> ; @@ -598,6 +389,26 @@ mf:action <bad-lang.ttl> ; mf:name "bad-lang" . +<#bad-lang-start-delete> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-lang-start-delete.nt> ; + mf:name "bad-lang-start-delete" . + +<#bad-lang-start-space> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-lang-start-space.nt> ; + mf:name "bad-lang-start-space" . + +<#bad-lang-start-tab> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-lang-start-tab.nt> ; + mf:name "bad-lang-start-tab" . + +<#bad-lang-start-wide> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-lang-start-wide.nt> ; + mf:name "bad-lang-start-wide" . + <#bad-list> a rdft:TestTurtleNegativeSyntax ; mf:action <bad-list.ttl> ; @@ -743,10 +554,30 @@ mf:action <bad-uri-scheme.nt> ; mf:name "bad-uri-scheme" . -<#bad-uri-scheme-start> +<#bad-uri-scheme-start-apostrophe> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-uri-scheme-start-apostrophe.nt> ; + mf:name "bad-uri-scheme-start-apostrophe" . + +<#bad-uri-scheme-start-delete> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-uri-scheme-start-delete.nt> ; + mf:name "bad-uri-scheme-start-delete" . + +<#bad-uri-scheme-start-space> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-uri-scheme-start-space.nt> ; + mf:name "bad-uri-scheme-start-space" . + +<#bad-uri-scheme-start-tab> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-uri-scheme-start-tab.nt> ; + mf:name "bad-uri-scheme-start-tab" . + +<#bad-uri-scheme-start-wide> a rdft:TestNTriplesNegativeSyntax ; - mf:action <bad-uri-scheme-start.nt> ; - mf:name "bad-uri-scheme-start" . + mf:action <bad-uri-scheme-start-wide.nt> ; + mf:name "bad-uri-scheme-start-wide" . <#bad-uri-truncated> a rdft:TestNTriplesNegativeSyntax ; diff --git a/test/extra/eof/README.md b/test/extra/eof/README.md new file mode 100644 index 00000000..1e461f79 --- /dev/null +++ b/test/extra/eof/README.md @@ -0,0 +1,5 @@ +EOF Test Suite +============== + +This simple suite tests that inputs truncated in various places are handled +correctly. diff --git a/test/extra/bad/bad-nt-eof-after-blank.nt b/test/extra/eof/bad-nt-eof-after-blank.nt index bc66ca37..bc66ca37 100644 --- a/test/extra/bad/bad-nt-eof-after-blank.nt +++ b/test/extra/eof/bad-nt-eof-after-blank.nt diff --git a/test/extra/bad/bad-nt-eof-after-lang-hyphen.nt b/test/extra/eof/bad-nt-eof-after-lang-hyphen.nt index 9e885d80..9e885d80 100644 --- a/test/extra/bad/bad-nt-eof-after-lang-hyphen.nt +++ b/test/extra/eof/bad-nt-eof-after-lang-hyphen.nt diff --git a/test/extra/bad/bad-nt-eof-after-lang-subtag.nt b/test/extra/eof/bad-nt-eof-after-lang-subtag.nt index f8158aec..f8158aec 100644 --- a/test/extra/bad/bad-nt-eof-after-lang-subtag.nt +++ b/test/extra/eof/bad-nt-eof-after-lang-subtag.nt diff --git a/test/extra/bad/bad-nt-eof-after-lang.nt b/test/extra/eof/bad-nt-eof-after-lang.nt index 7ab04b06..7ab04b06 100644 --- a/test/extra/bad/bad-nt-eof-after-lang.nt +++ b/test/extra/eof/bad-nt-eof-after-lang.nt diff --git a/test/extra/bad/bad-nt-eof-after-object.nt b/test/extra/eof/bad-nt-eof-after-object.nt index e796f2b0..e796f2b0 100644 --- a/test/extra/bad/bad-nt-eof-after-object.nt +++ b/test/extra/eof/bad-nt-eof-after-object.nt diff --git a/test/extra/bad/bad-nt-eof-after-predicate.nt b/test/extra/eof/bad-nt-eof-after-predicate.nt index ea47bfbe..ea47bfbe 100644 --- a/test/extra/bad/bad-nt-eof-after-predicate.nt +++ b/test/extra/eof/bad-nt-eof-after-predicate.nt diff --git a/test/extra/bad/bad-nt-eof-after-string-escape.nt b/test/extra/eof/bad-nt-eof-after-string-escape.nt index 869907e8..869907e8 100644 --- a/test/extra/bad/bad-nt-eof-after-string-escape.nt +++ b/test/extra/eof/bad-nt-eof-after-string-escape.nt diff --git a/test/extra/bad/bad-nt-eof-after-string.nt b/test/extra/eof/bad-nt-eof-after-string.nt index 32dda36d..32dda36d 100644 --- a/test/extra/bad/bad-nt-eof-after-string.nt +++ b/test/extra/eof/bad-nt-eof-after-string.nt diff --git a/test/extra/bad/bad-nt-eof-after-subject.nt b/test/extra/eof/bad-nt-eof-after-subject.nt index 21fa07f4..21fa07f4 100644 --- a/test/extra/bad/bad-nt-eof-after-subject.nt +++ b/test/extra/eof/bad-nt-eof-after-subject.nt diff --git a/test/extra/bad/bad-nt-eof-after-underscore.nt b/test/extra/eof/bad-nt-eof-after-underscore.nt index 4b05f2ac..4b05f2ac 100644 --- a/test/extra/bad/bad-nt-eof-after-underscore.nt +++ b/test/extra/eof/bad-nt-eof-after-underscore.nt diff --git a/test/extra/bad/bad-nt-eof-before-blank.nt b/test/extra/eof/bad-nt-eof-before-blank.nt index 99f70844..99f70844 100644 --- a/test/extra/bad/bad-nt-eof-before-blank.nt +++ b/test/extra/eof/bad-nt-eof-before-blank.nt diff --git a/test/extra/bad/bad-nt-eof-before-iri.nt b/test/extra/eof/bad-nt-eof-before-iri.nt index c5fa7845..c5fa7845 100644 --- a/test/extra/bad/bad-nt-eof-before-iri.nt +++ b/test/extra/eof/bad-nt-eof-before-iri.nt diff --git a/test/extra/bad/bad-nt-eof-before-lang.nt b/test/extra/eof/bad-nt-eof-before-lang.nt index f1a9d0df..f1a9d0df 100644 --- a/test/extra/bad/bad-nt-eof-before-lang.nt +++ b/test/extra/eof/bad-nt-eof-before-lang.nt diff --git a/test/extra/bad/bad-nt-eof-before-string-escape.nt b/test/extra/eof/bad-nt-eof-before-string-escape.nt index 30443488..30443488 100644 --- a/test/extra/bad/bad-nt-eof-before-string-escape.nt +++ b/test/extra/eof/bad-nt-eof-before-string-escape.nt diff --git a/test/extra/bad/bad-nt-eof-before-string.nt b/test/extra/eof/bad-nt-eof-before-string.nt index 6a2a7543..6a2a7543 100644 --- a/test/extra/bad/bad-nt-eof-before-string.nt +++ b/test/extra/eof/bad-nt-eof-before-string.nt diff --git a/test/extra/bad/bad-nt-eof-in-iri-path.nt b/test/extra/eof/bad-nt-eof-in-iri-path.nt index e8555e2b..e8555e2b 100644 --- a/test/extra/bad/bad-nt-eof-in-iri-path.nt +++ b/test/extra/eof/bad-nt-eof-in-iri-path.nt diff --git a/test/extra/bad/bad-nt-eof-in-iri-scheme.nt b/test/extra/eof/bad-nt-eof-in-iri-scheme.nt index 2c071547..2c071547 100644 --- a/test/extra/bad/bad-nt-eof-in-iri-scheme.nt +++ b/test/extra/eof/bad-nt-eof-in-iri-scheme.nt diff --git a/test/extra/bad/bad-nt-eof-in-string.nt b/test/extra/eof/bad-nt-eof-in-string.nt index 98944654..98944654 100644 --- a/test/extra/bad/bad-nt-eof-in-string.nt +++ b/test/extra/eof/bad-nt-eof-in-string.nt diff --git a/test/extra/bad/bad-eof-after-quotes.ttl b/test/extra/eof/bad-ttl-eof-after-quotes.ttl index 40e429cb..40e429cb 100644 --- a/test/extra/bad/bad-eof-after-quotes.ttl +++ b/test/extra/eof/bad-ttl-eof-after-quotes.ttl diff --git a/test/extra/bad/bad-eof-at-string-start.ttl b/test/extra/eof/bad-ttl-eof-at-string-start.ttl index 93d20bcc..93d20bcc 100644 --- a/test/extra/bad/bad-eof-at-string-start.ttl +++ b/test/extra/eof/bad-ttl-eof-at-string-start.ttl diff --git a/test/extra/bad/bad-eof-in-blank.ttl b/test/extra/eof/bad-ttl-eof-in-blank.ttl index 8cf4ee84..8cf4ee84 100644 --- a/test/extra/bad/bad-eof-in-blank.ttl +++ b/test/extra/eof/bad-ttl-eof-in-blank.ttl diff --git a/test/extra/bad/bad-eof-in-escape.ttl b/test/extra/eof/bad-ttl-eof-in-escape.ttl index 24b4eec6..24b4eec6 100644 --- a/test/extra/bad/bad-eof-in-escape.ttl +++ b/test/extra/eof/bad-ttl-eof-in-escape.ttl diff --git a/test/extra/bad/bad-eof-in-lang-suffix.ttl b/test/extra/eof/bad-ttl-eof-in-lang-suffix.ttl index f46a7763..f46a7763 100644 --- a/test/extra/bad/bad-eof-in-lang-suffix.ttl +++ b/test/extra/eof/bad-ttl-eof-in-lang-suffix.ttl diff --git a/test/extra/bad/bad-eof-in-lang.ttl b/test/extra/eof/bad-ttl-eof-in-lang.ttl index bfdffd02..bfdffd02 100644 --- a/test/extra/bad/bad-eof-in-lang.ttl +++ b/test/extra/eof/bad-ttl-eof-in-lang.ttl diff --git a/test/extra/bad/bad-eof-in-list.ttl b/test/extra/eof/bad-ttl-eof-in-list.ttl index 13eeb88d..13eeb88d 100644 --- a/test/extra/bad/bad-eof-in-list.ttl +++ b/test/extra/eof/bad-ttl-eof-in-list.ttl diff --git a/test/extra/bad/bad-eof-in-long-string.ttl b/test/extra/eof/bad-ttl-eof-in-long-string.ttl index 2ef179a8..2ef179a8 100644 --- a/test/extra/bad/bad-eof-in-long-string.ttl +++ b/test/extra/eof/bad-ttl-eof-in-long-string.ttl diff --git a/test/extra/bad/bad-eof-in-object-list.ttl b/test/extra/eof/bad-ttl-eof-in-object-list.ttl index 9bbcd17a..9bbcd17a 100644 --- a/test/extra/bad/bad-eof-in-object-list.ttl +++ b/test/extra/eof/bad-ttl-eof-in-object-list.ttl diff --git a/test/extra/bad/bad-eof-in-object-list2.ttl b/test/extra/eof/bad-ttl-eof-in-object-list2.ttl index 9186fb9f..9186fb9f 100644 --- a/test/extra/bad/bad-eof-in-object-list2.ttl +++ b/test/extra/eof/bad-ttl-eof-in-object-list2.ttl diff --git a/test/extra/bad/bad-eof-in-predicate-list.ttl b/test/extra/eof/bad-ttl-eof-in-predicate-list.ttl index eab5b05b..eab5b05b 100644 --- a/test/extra/bad/bad-eof-in-predicate-list.ttl +++ b/test/extra/eof/bad-ttl-eof-in-predicate-list.ttl diff --git a/test/extra/bad/bad-eof-in-string.ttl b/test/extra/eof/bad-ttl-eof-in-string.ttl index bb6e817f..bb6e817f 100644 --- a/test/extra/bad/bad-eof-in-string.ttl +++ b/test/extra/eof/bad-ttl-eof-in-string.ttl diff --git a/test/extra/bad/bad-eof-in-text-character.ttl b/test/extra/eof/bad-ttl-eof-in-text-character.ttl index a614803a..a614803a 100644 --- a/test/extra/bad/bad-eof-in-text-character.ttl +++ b/test/extra/eof/bad-ttl-eof-in-text-character.ttl diff --git a/test/extra/bad/bad-eof-in-triple-quote.ttl b/test/extra/eof/bad-ttl-eof-in-triple-quote.ttl index fb935441..fb935441 100644 --- a/test/extra/bad/bad-eof-in-triple-quote.ttl +++ b/test/extra/eof/bad-ttl-eof-in-triple-quote.ttl diff --git a/test/extra/bad/bad-eof-in-uri-character.ttl b/test/extra/eof/bad-ttl-eof-in-uri-character.ttl index eda70770..eda70770 100644 --- a/test/extra/bad/bad-eof-in-uri-character.ttl +++ b/test/extra/eof/bad-ttl-eof-in-uri-character.ttl diff --git a/test/extra/bad/bad-eof-in-uri-scheme.nt b/test/extra/eof/bad-ttl-eof-in-uri-scheme.ttl index de892dcf..de892dcf 100644 --- a/test/extra/bad/bad-eof-in-uri-scheme.nt +++ b/test/extra/eof/bad-ttl-eof-in-uri-scheme.ttl diff --git a/test/extra/bad/bad-eof-in-uri.ttl b/test/extra/eof/bad-ttl-eof-in-uri.ttl index 07b6e6ab..07b6e6ab 100644 --- a/test/extra/bad/bad-eof-in-uri.ttl +++ b/test/extra/eof/bad-ttl-eof-in-uri.ttl diff --git a/test/extra/bad/bad-eof-in-utf8-character.ttl b/test/extra/eof/bad-ttl-eof-in-utf8-character.ttl index 16784e88..16784e88 100644 --- a/test/extra/bad/bad-eof-in-utf8-character.ttl +++ b/test/extra/eof/bad-ttl-eof-in-utf8-character.ttl diff --git a/test/extra/eof/manifest.ttl b/test/extra/eof/manifest.ttl new file mode 100644 index 00000000..465333f7 --- /dev/null +++ b/test/extra/eof/manifest.ttl @@ -0,0 +1,225 @@ +@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix rdft: <http://www.w3.org/ns/rdftest#> . + +<> + a mf:Manifest ; + rdfs:comment "Serd EOF (truncated input) test suite" ; + mf:entries ( + <#bad-nt-eof-after-blank> + <#bad-nt-eof-after-lang> + <#bad-nt-eof-after-lang-hyphen> + <#bad-nt-eof-after-lang-subtag> + <#bad-nt-eof-after-object> + <#bad-nt-eof-after-predicate> + <#bad-nt-eof-after-string> + <#bad-nt-eof-after-string-escape> + <#bad-nt-eof-after-subject> + <#bad-nt-eof-after-underscore> + <#bad-nt-eof-before-blank> + <#bad-nt-eof-before-iri> + <#bad-nt-eof-before-lang> + <#bad-nt-eof-before-string> + <#bad-nt-eof-before-string-escape> + <#bad-nt-eof-in-iri-path> + <#bad-nt-eof-in-iri-scheme> + <#bad-nt-eof-in-string> + <#bad-ttl-eof-after-quotes> + <#bad-ttl-eof-at-string-start> + <#bad-ttl-eof-in-blank> + <#bad-ttl-eof-in-escape> + <#bad-ttl-eof-in-lang> + <#bad-ttl-eof-in-lang-suffix> + <#bad-ttl-eof-in-list> + <#bad-ttl-eof-in-long-string> + <#bad-ttl-eof-in-object-list> + <#bad-ttl-eof-in-object-list2> + <#bad-ttl-eof-in-predicate-list> + <#bad-ttl-eof-in-string> + <#bad-ttl-eof-in-text-character> + <#bad-ttl-eof-in-triple-quote> + <#bad-ttl-eof-in-uri> + <#bad-ttl-eof-in-uri-character> + <#bad-ttl-eof-in-uri-scheme> + <#bad-ttl-eof-in-utf8-character> + ) . + +<#bad-nt-eof-after-blank> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-after-blank.nt> ; + mf:name "bad-nt-eof-after-blank" . + +<#bad-nt-eof-after-lang> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-after-lang.nt> ; + mf:name "bad-nt-eof-after-lang" . + +<#bad-nt-eof-after-lang-hyphen> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-after-lang-hyphen.nt> ; + mf:name "bad-nt-eof-after-lang-hyphen" . + +<#bad-nt-eof-after-lang-subtag> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-after-lang-subtag.nt> ; + mf:name "bad-nt-eof-after-lang-subtag" . + +<#bad-nt-eof-after-object> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-after-object.nt> ; + mf:name "bad-nt-eof-after-object" . + +<#bad-nt-eof-after-predicate> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-after-predicate.nt> ; + mf:name "bad-nt-eof-after-predicate" . + +<#bad-nt-eof-after-string> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-after-string.nt> ; + mf:name "bad-nt-eof-after-string" . + +<#bad-nt-eof-after-string-escape> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-after-string-escape.nt> ; + mf:name "bad-nt-eof-after-string-escape" . + +<#bad-nt-eof-after-subject> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-after-subject.nt> ; + mf:name "bad-nt-eof-after-subject" . + +<#bad-nt-eof-after-underscore> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-after-underscore.nt> ; + mf:name "bad-nt-eof-after-underscore" . + +<#bad-nt-eof-before-blank> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-before-blank.nt> ; + mf:name "bad-nt-eof-before-blank" . + +<#bad-nt-eof-before-iri> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-before-iri.nt> ; + mf:name "bad-nt-eof-before-iri" . + +<#bad-nt-eof-before-lang> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-before-lang.nt> ; + mf:name "bad-nt-eof-before-lang" . + +<#bad-nt-eof-before-string> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-before-string.nt> ; + mf:name "bad-nt-eof-before-string" . + +<#bad-nt-eof-before-string-escape> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-before-string-escape.nt> ; + mf:name "bad-nt-eof-before-string-escape" . + +<#bad-nt-eof-in-iri-path> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-in-iri-path.nt> ; + mf:name "bad-nt-eof-in-iri-path" . + +<#bad-nt-eof-in-iri-scheme> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-in-iri-scheme.nt> ; + mf:name "bad-nt-eof-in-iri-scheme" . + +<#bad-nt-eof-in-string> + a rdft:TestNTriplesNegativeSyntax ; + mf:action <bad-nt-eof-in-string.nt> ; + mf:name "bad-nt-eof-in-string" . + +<#bad-ttl-eof-after-quotes> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-after-quotes.ttl> ; + mf:name "bad-ttl-eof-after-quotes" . + +<#bad-ttl-eof-at-string-start> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-at-string-start.ttl> ; + mf:name "bad-ttl-eof-at-string-start" . + +<#bad-ttl-eof-in-blank> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-blank.ttl> ; + mf:name "bad-ttl-eof-in-blank" . + +<#bad-ttl-eof-in-escape> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-escape.ttl> ; + mf:name "bad-ttl-eof-in-escape" . + +<#bad-ttl-eof-in-lang> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-lang.ttl> ; + mf:name "bad-ttl-eof-in-lang" . + +<#bad-ttl-eof-in-lang-suffix> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-lang-suffix.ttl> ; + mf:name "bad-ttl-eof-in-lang-suffix" . + +<#bad-ttl-eof-in-list> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-list.ttl> ; + mf:name "bad-ttl-eof-in-list" . + +<#bad-ttl-eof-in-long-string> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-long-string.ttl> ; + mf:name "bad-ttl-eof-in-long-string" . + +<#bad-ttl-eof-in-object-list> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-object-list.ttl> ; + mf:name "bad-ttl-eof-in-object-list" . + +<#bad-ttl-eof-in-object-list2> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-object-list2.ttl> ; + mf:name "bad-ttl-eof-in-object-list2" . + +<#bad-ttl-eof-in-predicate-list> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-predicate-list.ttl> ; + mf:name "bad-ttl-eof-in-predicate-list" . + +<#bad-ttl-eof-in-string> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-string.ttl> ; + mf:name "bad-ttl-eof-in-string" . + +<#bad-ttl-eof-in-text-character> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-text-character.ttl> ; + mf:name "bad-ttl-eof-in-text-character" . + +<#bad-ttl-eof-in-triple-quote> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-triple-quote.ttl> ; + mf:name "bad-ttl-eof-in-triple-quote" . + +<#bad-ttl-eof-in-uri> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-uri.ttl> ; + mf:name "bad-ttl-eof-in-uri" . + +<#bad-ttl-eof-in-uri-character> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-uri-character.ttl> ; + mf:name "bad-ttl-eof-in-uri-character" . + +<#bad-ttl-eof-in-uri-scheme> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-uri-scheme.ttl> ; + mf:name "bad-ttl-eof-in-uri-scheme" . + +<#bad-ttl-eof-in-utf8-character> + a rdft:TestTurtleNegativeSyntax ; + mf:action <bad-ttl-eof-in-utf8-character.ttl> ; + mf:name "bad-ttl-eof-in-utf8-character" . diff --git a/test/extra/good/manifest.ttl b/test/extra/good/manifest.ttl index 350d7d9c..659f8fd1 100644 --- a/test/extra/good/manifest.ttl +++ b/test/extra/good/manifest.ttl @@ -16,16 +16,21 @@ <#test-blank-node-statement> <#test-blankdot> <#test-bom> + <#test-boolish-prefix> <#test-changing-base> <#test-comment-whitespace> <#test-cr> <#test-digit-start-pname> + <#test-decimal-ends-with-dot> <#test-double> + <#test-double-ends-with-dot> <#test-empty-path-base> <#test-eof-at-page-end> <#test-ext-namedblank-iri> <#test-ext-namedblank-prefix> + <#test-false-ends-with-dot> <#test-id> + <#test-integer-ends-with-dot> <#test-list-in-blank> <#test-list-subject> <#test-local-name-ends-with-dot> @@ -56,6 +61,7 @@ <#test-several-eaten-dots> <#test-string-escapes> <#test-trig-syntax-all-rules> + <#test-true-ends-with-dot> <#test-ttl-syntax-all-rules> <#test-uri> ) . @@ -120,6 +126,18 @@ mf:name "test-bom" ; mf:result <test-bom.nt> . +<#test-bom-only> + a rdft:TestTurtleEval ; + mf:action <test-bom-only.ttl> ; + mf:name "test-bom-only" ; + mf:result <test-bom-only.nt> . + +<#test-boolish-prefix> + a rdft:TestTurtleEval ; + mf:action <test-boolish-prefix.ttl> ; + mf:name "test-boolish-prefix" ; + mf:result <test-boolish-prefix.nt> . + <#test-changing-base> a rdft:TestTurtleEval ; mf:action <test-changing-base.ttl> ; @@ -144,12 +162,24 @@ mf:name "test-digit-start-pname" ; mf:result <test-digit-start-pname.nt> . +<#test-decimal-ends-with-dot> + a rdft:TestTurtleEval ; + mf:action <test-decimal-ends-with-dot.ttl> ; + mf:name "test-decimal-ends-with-dot" ; + mf:result <test-decimal-ends-with-dot.nt> . + <#test-double> a rdft:TestTurtleEval ; mf:action <test-double.ttl> ; mf:name "test-double" ; mf:result <test-double.nt> . +<#test-double-ends-with-dot> + a rdft:TestTurtleEval ; + mf:action <test-double-ends-with-dot.ttl> ; + mf:name "test-double-ends-with-dot" ; + mf:result <test-double-ends-with-dot.nt> . + <#test-empty-path-base> a rdft:TestTurtleEval ; mf:action <test-empty-path-base.ttl> ; @@ -174,12 +204,24 @@ mf:name "test-ext-namedblank-prefix" ; mf:result <test-ext-namedblank-prefix.nt> . +<#test-false-ends-with-dot> + a rdft:TestTurtleEval ; + mf:action <test-false-ends-with-dot.ttl> ; + mf:name "test-false-ends-with-dot" ; + mf:result <test-false-ends-with-dot.nt> . + <#test-id> a rdft:TestTurtleEval ; mf:action <test-id.ttl> ; mf:name "test-id" ; mf:result <test-id.nt> . +<#test-integer-ends-with-dot> + a rdft:TestTurtleEval ; + mf:action <test-integer-ends-with-dot.ttl> ; + mf:name "test-integer-ends-with-dot" ; + mf:result <test-integer-ends-with-dot.nt> . + <#test-list-in-blank> a rdft:TestTurtleEval ; mf:action <test-list-in-blank.ttl> ; @@ -344,6 +386,12 @@ mf:action <test-trig-syntax-all-rules.trig> ; mf:name "test-trig-syntax-all-rules" . +<#test-true-ends-with-dot> + a rdft:TestTurtleEval ; + mf:action <test-true-ends-with-dot.ttl> ; + mf:name "test-true-ends-with-dot" ; + mf:result <test-true-ends-with-dot.nt> . + <#test-ttl-syntax-all-rules> a rdft:TestTurtlePositiveSyntax ; mf:action <test-ttl-syntax-all-rules.ttl> ; diff --git a/test/extra/good/test-bom-only.nt b/test/extra/good/test-bom-only.nt new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/extra/good/test-bom-only.nt diff --git a/test/extra/good/test-bom-only.ttl b/test/extra/good/test-bom-only.ttl new file mode 100644 index 00000000..5f282702 --- /dev/null +++ b/test/extra/good/test-bom-only.ttl @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/test/extra/good/test-boolish-prefix.nt b/test/extra/good/test-boolish-prefix.nt new file mode 100644 index 00000000..d49eeab2 --- /dev/null +++ b/test/extra/good/test-boolish-prefix.nt @@ -0,0 +1,2 @@ +<http://example.org/s> <http://example.org/p> <http://example.org/falseish#o> . +<http://example.org/s> <http://example.org/p> <http://example.org/trueish#o> . diff --git a/test/extra/good/test-boolish-prefix.ttl b/test/extra/good/test-boolish-prefix.ttl new file mode 100644 index 00000000..81ffdf11 --- /dev/null +++ b/test/extra/good/test-boolish-prefix.ttl @@ -0,0 +1,5 @@ +@prefix false.ish: <http://example.org/falseish#> . +@prefix true.ish: <http://example.org/trueish#> . + +<http://example.org/s> <http://example.org/p> false.ish:o . +<http://example.org/s> <http://example.org/p> true.ish:o . diff --git a/test/extra/good/test-decimal-ends-with-dot.nt b/test/extra/good/test-decimal-ends-with-dot.nt new file mode 100644 index 00000000..be0802bc --- /dev/null +++ b/test/extra/good/test-decimal-ends-with-dot.nt @@ -0,0 +1 @@ +<http://example.org/eg#s> <http://example.org/eg#p> "12.3"^^<http://www.w3.org/2001/XMLSchema#decimal> . diff --git a/test/extra/good/test-decimal-ends-with-dot.ttl b/test/extra/good/test-decimal-ends-with-dot.ttl new file mode 100644 index 00000000..a63970d3 --- /dev/null +++ b/test/extra/good/test-decimal-ends-with-dot.ttl @@ -0,0 +1,4 @@ +@prefix eg: <http://example.org/eg#> . + +eg:s + eg:p 12.3. diff --git a/test/extra/good/test-double-ends-with-dot.nt b/test/extra/good/test-double-ends-with-dot.nt new file mode 100644 index 00000000..20e4395e --- /dev/null +++ b/test/extra/good/test-double-ends-with-dot.nt @@ -0,0 +1 @@ +<http://example.org/eg#s> <http://example.org/eg#p> "12.3e4"^^<http://www.w3.org/2001/XMLSchema#double> . diff --git a/test/extra/good/test-double-ends-with-dot.ttl b/test/extra/good/test-double-ends-with-dot.ttl new file mode 100644 index 00000000..4bd17a0b --- /dev/null +++ b/test/extra/good/test-double-ends-with-dot.ttl @@ -0,0 +1,4 @@ +@prefix eg: <http://example.org/eg#> . + +eg:s + eg:p 12.3e4. diff --git a/test/extra/good/test-false-ends-with-dot.nt b/test/extra/good/test-false-ends-with-dot.nt new file mode 100644 index 00000000..3b811813 --- /dev/null +++ b/test/extra/good/test-false-ends-with-dot.nt @@ -0,0 +1 @@ +<http://example.org/eg#s> <http://example.org/eg#p> "false"^^<http://www.w3.org/2001/XMLSchema#boolean> . diff --git a/test/extra/good/test-false-ends-with-dot.ttl b/test/extra/good/test-false-ends-with-dot.ttl new file mode 100644 index 00000000..14e2aa90 --- /dev/null +++ b/test/extra/good/test-false-ends-with-dot.ttl @@ -0,0 +1,4 @@ +@prefix eg: <http://example.org/eg#> . + +eg:s + eg:p false. diff --git a/test/extra/good/test-integer-ends-with-dot.nt b/test/extra/good/test-integer-ends-with-dot.nt new file mode 100644 index 00000000..7d6ff362 --- /dev/null +++ b/test/extra/good/test-integer-ends-with-dot.nt @@ -0,0 +1 @@ +<http://example.org/eg#s> <http://example.org/eg#p> "12"^^<http://www.w3.org/2001/XMLSchema#integer> . diff --git a/test/extra/good/test-integer-ends-with-dot.ttl b/test/extra/good/test-integer-ends-with-dot.ttl new file mode 100644 index 00000000..350ea41d --- /dev/null +++ b/test/extra/good/test-integer-ends-with-dot.ttl @@ -0,0 +1,4 @@ +@prefix eg: <http://example.org/eg#> . + +eg:s + eg:p 12. diff --git a/test/extra/good/test-nq-syntax-all-rules.nq b/test/extra/good/test-nq-syntax-all-rules.nq index a8b80b9a..f9bffe20 100644 --- a/test/extra/good/test-nq-syntax-all-rules.nq +++ b/test/extra/good/test-nq-syntax-all-rules.nq @@ -2,6 +2,6 @@ _:e.u.s <http://example.org/p> _:o. _:e.u.s <http://example.org/p> "o"@en-gb _:g. _:s <http://example.org/p> "ob\t\b\n\r\f\\\"\'\u0025\U00015678ject" <http://example.org/g> . -_:s <http://example.org/p> "߿ࠀက쿿퀀�𐀀" <http://example.org/g> . +_:Σ <http://example.org/p> "߿ࠀက쿿퀀�𐀀" <http://example.org/g> . _:s <http://example.org/p> "o"^^<http://example.org/T> <http://example.org/g> . _:s <http://example.org/p> "o"@en _:g . diff --git a/test/extra/good/test-nt-syntax-all-rules.nt b/test/extra/good/test-nt-syntax-all-rules.nt index ed84f410..c626a702 100644 --- a/test/extra/good/test-nt-syntax-all-rules.nt +++ b/test/extra/good/test-nt-syntax-all-rules.nt @@ -4,4 +4,4 @@ _:s <http://example.org/p> "߿ࠀက쿿퀀�𐀀 _:s <http://example.org/p> "o"^^<http://example.org/T> . _:s <http://example.org/p> "o"@en . _:e.u.s <http://example.org/p> "o"@en-gb . -_:e.u.s <http://example.org/p> _:o. +_:e.u.s <http://example.org/p> _:Ω. diff --git a/test/extra/good/test-trig-syntax-all-rules.trig b/test/extra/good/test-trig-syntax-all-rules.trig index 97557b86..c824ffae 100644 --- a/test/extra/good/test-trig-syntax-all-rules.trig +++ b/test/extra/good/test-trig-syntax-all-rules.trig @@ -7,13 +7,13 @@ ""string""\t\b\n\r\f\'\u0025\U00015678""" . eg:s eg:p "߿ࠀက쿿퀀�𐀀" . eg:sub%25ject eg:pr\~d "o"^^eg:T . -eg:sub%25ject eg:pr\~d "o"@en . +eg:s\@bject eg:pr\~d "o"@en . _:e.u.s eg:p "o"@en-gb . _:e.u.s eg:p _:o. _:e.u.s eg:p‿r⁀d 2. _:e.u.s eg:prèd 3 . _:e.u.s eg:pͯ 4.5. -eg:s eg:p 0 , .1 , 2.3 , 4E5, 6e07 . +eg:Σ eg:p 0 , .1 , 2.3 , 4E5, 6e07 . eg:s eg:p .7e8 , .9E0 , 1.e2 , 3.E4 . eg:s eg:p .2E3 , .4e5 , 6.7E8 , 9. [ ] eg:p 0.e1, 2.E3. diff --git a/test/extra/good/test-true-ends-with-dot.nt b/test/extra/good/test-true-ends-with-dot.nt new file mode 100644 index 00000000..9938065b --- /dev/null +++ b/test/extra/good/test-true-ends-with-dot.nt @@ -0,0 +1 @@ +<http://example.org/eg#s> <http://example.org/eg#p> "true"^^<http://www.w3.org/2001/XMLSchema#boolean> . diff --git a/test/extra/good/test-true-ends-with-dot.ttl b/test/extra/good/test-true-ends-with-dot.ttl new file mode 100644 index 00000000..ebd3b6e1 --- /dev/null +++ b/test/extra/good/test-true-ends-with-dot.ttl @@ -0,0 +1,4 @@ +@prefix eg: <http://example.org/eg#> . + +eg:s + eg:p true. diff --git a/test/extra/good/test-ttl-syntax-all-rules.ttl b/test/extra/good/test-ttl-syntax-all-rules.ttl index ead2e8a8..dd4fa315 100644 --- a/test/extra/good/test-ttl-syntax-all-rules.ttl +++ b/test/extra/good/test-ttl-syntax-all-rules.ttl @@ -6,13 +6,13 @@ ""string""\t\b\n\r\f\'\u0025\U00015678""" . eg:s eg:p "߿ࠀက쿿퀀�𐀀" . eg:sub%25ject eg:pr\~d "o"^^eg:T . -eg:sub%25ject eg:pr\~d "o"@en . +eg:s\@bject eg:pr\~d "o"@en . _:e.u.s eg:p "o"@en-gb . _:e.u.s eg:p _:o. _:e.u.s eg:p‿r⁀d 2. _:e.u.s eg:prèd 3 . _:e.u.s eg:pͯ 4.5. -eg:s eg:p 0 , .1 , 2.3 , 4E5, 6e07 . +eg:Σ eg:p 0 , .1 , 2.3 , 4E5, 6e07 . eg:s eg:p .7e8 , .9E0 , 1.e2 , 3.E4 . eg:s eg:p .2E3 , .4e5 , 6.7E8 , 9. [ ] eg:p 0.e1, 2.E3. @@ -20,7 +20,7 @@ eg:s eg:p .2E3 , .4e5 , 6.7E8 , 9. eg:s eg:p [] . [ eg:p1 eg:o1 ; - eg:p2 _:o2 ; + eg:p2 _:β2 ; eg:p3 "o3" ; ] a eg:S . diff --git a/test/headers/meson.build b/test/headers/meson.build index 6cb14f6e..b9125d2b 100644 --- a/test/headers/meson.build +++ b/test/headers/meson.build @@ -38,6 +38,7 @@ test( files('test_headers.c'), c_args: header_c_suppressions, dependencies: serd_dep, + implicit_include_directories: false, ), suite: 'unit', ) diff --git a/test/lint/meson.build b/test/lint/meson.build new file mode 100644 index 00000000..cca43342 --- /dev/null +++ b/test/lint/meson.build @@ -0,0 +1,133 @@ +# Copyright 2020-2023 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +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 + +all_sources = sources + unit_test_sources + files('../../src/serdi.c') + +# 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 = 'black_' + script_path.substring(3).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 +if is_variable('serdi') + foreach ttl_file_path : ttl_metadata_file_paths + test( + ttl_file_path.substring(3).underscorify(), + check_formatting_py, + args: [files(ttl_file_path), serdi, '-o', 'turtle'], + suite: 'data', + ) + endforeach +endif + +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 diff --git a/test/meson.build b/test/meson.build index 4d770304..223e279d 100644 --- a/test/meson.build +++ b/test/meson.build @@ -37,6 +37,7 @@ foreach name : unit_test_names source, c_args: c_suppressions, dependencies: serd_dep, + implicit_include_directories: false, ), suite: 'unit', ) @@ -212,6 +213,17 @@ test_suites = { '--', '-b', ], + 'eof': [ + files('extra/eof/manifest.ttl'), + ns_serdtest + 'eof/', + ], + 'eof_lax': [ + '--ignore', + files('extra/eof/manifest.ttl'), + ns_serdtest + 'eof/', + '--', + '-l' + ], 'fast': [ files('extra/good/manifest.ttl'), ns_serdtest + 'good/', @@ -298,133 +310,6 @@ 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 + subdir('lint') endif diff --git a/test/run_suite.py b/test/run_suite.py index 2e93502f..84c74dd1 100755 --- a/test/run_suite.py +++ b/test/run_suite.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright 2022-2023 David Robillard <d@drobilla.net> +# Copyright 2022-2025 David Robillard <d@drobilla.net> # SPDX-License-Identifier: ISC """Run a "simple" one-pass RDF-based test suite for serd.""" @@ -43,7 +43,7 @@ def run_eval_test(base_uri, command, in_path, good_path, out_path): syntax = util.syntax_from_path(out_path) command = command + ["-o", syntax, in_path, base_uri] - with subprocess.Popen(command, stdout=PIPE, encoding="utf-8") as proc: + with subprocess.Popen(command, encoding="utf-8", stdout=PIPE) as proc: out = list(proc.stdout) with open(good_path, "r", encoding="utf-8") as good: @@ -58,19 +58,25 @@ def run_positive_test(base_uri, command, in_path): return True -def run_negative_test(base_uri, command, in_path): +def run_negative_test(base_uri, command, in_path, ignore): """Run a negative syntax test and return whether the error was detected.""" if not os.path.exists(in_path): raise RuntimeError("Input file missing: " + in_path) command = command + [in_path, base_uri] - proc = subprocess.run(command, check=False, stderr=PIPE, stdout=DEVNULL) + proc = subprocess.run( + command, check=False, encoding="utf-8", stderr=PIPE, stdout=DEVNULL + ) - if proc.returncode == 0: + if not ignore and proc.returncode == 0: util.error("Unexpected successful return: " + in_path) return False + if proc.returncode < 0: + util.error("Command seems to have crashed: " + in_path) + return False + if len(proc.stderr) == 0: util.error("Command failed with no error output: " + in_path) return False @@ -86,7 +92,7 @@ def run_entry(args, entry, command, out_dir, suite_dir): negative = "Negative" in entry[NS_RDF + "type"][0] if negative and not args.lax: - return run_negative_test(base, command, in_path) + return run_negative_test(base, command, in_path, args.ignore) if NS_MF + "result" not in entry: return run_positive_test(base, command, in_path) @@ -151,6 +157,7 @@ def main(): ) parser.add_argument("--asserter", help="asserter URI for test report") + parser.add_argument("--ignore", action="store_true", help="ignore status") parser.add_argument("--lax", action="store_true", help="tolerate errors") parser.add_argument("--report", help="path to write result report to") parser.add_argument("--reverse", action="store_true", help="reverse test") diff --git a/test/serd_test_util/__init__.py b/test/serd_test_util/__init__.py index ad417762..c38100b5 100644 --- a/test/serd_test_util/__init__.py +++ b/test/serd_test_util/__init__.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright 2022-2023 David Robillard <d@drobilla.net> +# Copyright 2022-2025 David Robillard <d@drobilla.net> # SPDX-License-Identifier: ISC """Utilities for data-driven tests.""" @@ -157,12 +157,14 @@ def load_rdf(filename, base_uri, command_prefix): cmd = command_prefix + [filename, base_uri] proc = subprocess.run( - cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True + cmd, + encoding="utf-8", + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=True, ) for line in proc.stdout.splitlines(): - matches = re.match( - r"<([^ ]*)> <([^ ]*)> <([^ ]*)> \.", line.decode("utf-8") - ) + matches = re.match(r"<([^ ]*)> <([^ ]*)> <([^ ]*)> \.", line) if matches: s, p, o = (matches.group(1), matches.group(2), matches.group(3)) if s not in model: diff --git a/test/test_node.c b/test/test_node.c index eb432c40..c2fccf08 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -71,8 +71,8 @@ test_double_to_node(void) -16.00001, 5.000000005, 0.0000000001, - NAN, - INFINITY}; + (double)NAN, + (double)INFINITY}; const char* dbl_test_strs[] = {"0.0", "9.0", @@ -123,6 +123,7 @@ test_blob_to_node(void) { for (size_t size = 1; size < 256; ++size) { uint8_t* const data = (uint8_t*)malloc(size); + assert(data); for (size_t i = 0; i < size; ++i) { data[i] = (uint8_t)((size + i) % 256); } diff --git a/test/test_quiet.py b/test/test_quiet.py index 676284bb..ff53e26e 100755 --- a/test/test_quiet.py +++ b/test/test_quiet.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright 2022 David Robillard <d@drobilla.net> +# Copyright 2022-2025 David Robillard <d@drobilla.net> # SPDX-License-Identifier: ISC """Test quiet command-line option.""" @@ -13,7 +13,11 @@ import serd_test_util as util 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 + command, + encoding="utf-8", + check=False, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, ) assert proc.returncode != 0 diff --git a/test/test_reader.c b/test/test_reader.c index e1ca0934..6c38e447 100644 --- a/test/test_reader.c +++ b/test/test_reader.c @@ -217,6 +217,7 @@ test_read_nquads_chunks(const char* const path) static const char null = 0; FILE* const f = fopen(path, "w+b"); + assert(f); // Write two statements, a null separator, then another statement @@ -303,6 +304,7 @@ test_read_turtle_chunks(const char* const path) static const char null = 0; FILE* const f = fopen(path, "w+b"); + assert(f); // Write two statements separated by null characters fprintf(f, "@base <http://example.org/base/> .\n"); @@ -406,6 +408,7 @@ main(void) const size_t nq_name_len = strlen(nq_name); const size_t path_len = tmp_len + 1 + ttl_name_len; char* const path = (char*)calloc(path_len + 1, 1); + assert(path); memcpy(path, tmp, tmp_len + 1); path[tmp_len] = '/'; diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c index bebda449..ceaae30f 100644 --- a/test/test_reader_writer.c +++ b/test/test_reader_writer.c @@ -1,4 +1,4 @@ -// Copyright 2011-2024 David Robillard <d@drobilla.net> +// Copyright 2011-2025 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #undef NDEBUG @@ -103,42 +103,58 @@ quiet_error_sink(void* const handle, const SerdError* const e) } static void -test_write_errors(void) +check_write_error_offset(const SerdSyntax syntax, + const size_t offset, + const SerdStatus expected_status) { - ErrorContext ctx = {0U, 0U}; + ErrorContext ctx = {0U, offset}; const SerdStyle style = (SerdStyle)(SERD_STYLE_STRICT | SERD_STYLE_CURIED); + SerdEnv* const env = serd_env_new(NULL); + assert(env); + + SerdWriter* const writer = + serd_writer_new(syntax, style, env, NULL, faulty_sink, &ctx); + assert(writer); + + 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); + assert(reader); + + serd_writer_set_error_sink(writer, quiet_error_sink, NULL); + serd_reader_set_error_sink(reader, quiet_error_sink, NULL); + + const SerdStatus rst = serd_reader_read_string(reader, USTR(doc_string)); + const SerdStatus wst = serd_writer_finish(writer); + + serd_reader_free(reader); + serd_writer_free(writer); + serd_env_free(env); - const size_t max_offsets[] = {0, 462, 1911, 2003, 462}; + const SerdStatus st = rst ? rst : wst; + assert(st == expected_status); +} + +static void +test_write_errors(void) +{ + // Syntax-keyed array of output document sizes + static const size_t max_offsets[] = {0, 451, 1911, 2003, 465}; - // Test errors at different offsets to hit different code paths for (unsigned s = 1; s <= (unsigned)SERD_TRIG; ++s) { const SerdSyntax syntax = (SerdSyntax)s; + + // Check successfully writing with enough space + check_write_error_offset(syntax, max_offsets[s], SERD_SUCCESS); + + // Check write error at every offset in the output 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); + check_write_error_offset(syntax, o, SERD_ERR_BAD_WRITE); } } } @@ -146,10 +162,12 @@ test_write_errors(void) static void test_writer(const char* const path) { - FILE* fd = fopen(path, "wb"); - SerdEnv* env = serd_env_new(NULL); + FILE* const fd = fopen(path, "wb"); assert(fd); + SerdEnv* const env = serd_env_new(NULL); + assert(env); + SerdWriter* writer = serd_writer_new(SERD_TURTLE, (SerdStyle)0, env, NULL, serd_file_sink, fd); assert(writer); @@ -166,15 +184,19 @@ test_writer(const char* const path) 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); + const SerdNode s = serd_node_from_string(SERD_URI, USTR("")); + const SerdNode p = + serd_node_from_string(SERD_URI, USTR("http://example.org/pred")); + const SerdNode o = serd_node_from_string(SERD_LITERAL, buf); + const SerdNode t = serd_node_from_string(SERD_URI, USTR("urn:Type")); + const SerdNode l = serd_node_from_string(SERD_LITERAL, USTR("en")); - // Write 3 invalid statements (should write nothing) + // Attempt to write invalid statements (should write nothing) const SerdNode* junk[][5] = {{&s, &p, &SERD_NODE_NULL, NULL, NULL}, {&s, &SERD_NODE_NULL, &o, NULL, NULL}, {&SERD_NODE_NULL, &p, &o, NULL, NULL}, {&s, &o, &o, NULL, NULL}, + {&s, &o, &o, &t, &l}, {&o, &p, &o, NULL, NULL}, {&s, &p, &SERD_NODE_NULL, NULL, NULL}}; for (size_t i = 0; i < sizeof(junk) / (sizeof(SerdNode*) * 5); ++i) { @@ -188,13 +210,12 @@ test_writer(const char* const path) junk[i][4])); } - const SerdNode t = serd_node_from_string(SERD_URI, USTR("urn:Type")); - const SerdNode l = serd_node_from_string(SERD_LITERAL, USTR("en")); + // Write some valid statements const SerdNode* good[][5] = {{&s, &p, &o, NULL, NULL}, + {&s, &p, &lit, NULL, NULL}, {&s, &p, &o, &SERD_NODE_NULL, &SERD_NODE_NULL}, {&s, &p, &o, &t, NULL}, {&s, &p, &o, NULL, &l}, - {&s, &p, &o, &t, &l}, {&s, &p, &o, &t, &SERD_NODE_NULL}, {&s, &p, &o, &SERD_NODE_NULL, &l}, {&s, &p, &o, NULL, &SERD_NODE_NULL}, @@ -220,46 +241,7 @@ test_writer(const char* const path) assert(!serd_writer_write_statement( writer, 0, NULL, &s, &p, &bad_uri, NULL, NULL)); - // Write 1 valid statement - o = serd_node_from_string(SERD_LITERAL, USTR("hello")); - assert(!serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL)); - serd_writer_free(writer); - - // Test chunk sink - SerdChunk chunk = {NULL, 0}; - writer = serd_writer_new( - SERD_TURTLE, (SerdStyle)0, env, NULL, serd_chunk_sink, &chunk); - - o = serd_node_from_string(SERD_URI, USTR("http://example.org/base")); - assert(!serd_writer_set_base_uri(writer, &o)); - - serd_writer_free(writer); - uint8_t* out = serd_chunk_sink_finish(&chunk); - - assert(!strcmp((const char*)out, "@base <http://example.org/base> .\n")); - serd_free(out); - - // Test writing empty node - SerdNode nothing = serd_node_from_string(SERD_NOTHING, USTR("")); - - chunk.buf = NULL; - chunk.len = 0; - writer = serd_writer_new( - SERD_TURTLE, (SerdStyle)0, env, NULL, serd_chunk_sink, &chunk); - - assert(!serd_writer_write_statement( - writer, 0, NULL, &s, &p, ¬hing, NULL, NULL)); - - assert( - !strncmp((const char*)chunk.buf, "<>\n\t<http://example.org/pred> ", 30)); - - serd_writer_free(writer); - out = serd_chunk_sink_finish(&chunk); - - assert(!strcmp((const char*)out, "<>\n\t<http://example.org/pred> .\n")); - serd_free(out); - serd_env_free(env); assert(!fclose(fd)); } @@ -267,7 +249,9 @@ test_writer(const char* const path) static void test_reader(const char* const path) { - ReaderTest* rt = (ReaderTest*)calloc(1, sizeof(ReaderTest)); + ReaderTest* const rt = (ReaderTest*)calloc(1, sizeof(ReaderTest)); + assert(rt); + SerdReader* reader = serd_reader_new( SERD_TURTLE, rt, free, NULL, NULL, test_statement_sink, NULL); @@ -295,7 +279,7 @@ test_reader(const char* const path) const SerdStatus st = serd_reader_read_file(reader, USTR(path)); assert(!st); - assert(rt->n_statement == 13); + assert(rt->n_statement == 12); assert(rt->graph && rt->graph->buf && !strcmp((const char*)rt->graph->buf, "http://example.org/")); @@ -320,6 +304,7 @@ main(void) const size_t ttl_name_len = strlen(ttl_name); const size_t path_len = tmp_len + 1 + ttl_name_len; char* const path = (char*)calloc(path_len + 1, 1); + assert(path); memcpy(path, tmp, tmp_len + 1); path[tmp_len] = '/'; diff --git a/test/test_uri.c b/test/test_uri.c index 5177359c..96fde600 100644 --- a/test/test_uri.c +++ b/test/test_uri.c @@ -52,6 +52,7 @@ check_file_uri(const char* const hostname, uint8_t* out_path = serd_file_uri_parse((const uint8_t*)node.buf, &out_hostname); + assert(out_path); assert(!strcmp((const char*)node.buf, expected_uri)); assert((hostname && out_hostname) || (!hostname && !out_hostname)); assert(!hostname || !strcmp(hostname, (const char*)out_hostname)); @@ -68,40 +69,27 @@ check_file_uri(const char* const hostname, #endif static void -test_uri_to_path(void) +check_uri_to_path(const char* const uri, const char* const expected_path) { - assert(!strcmp( - (const char*)serd_uri_to_path((const uint8_t*)"file:///home/user/foo.ttl"), - "/home/user/foo.ttl")); - - assert(!strcmp((const char*)serd_uri_to_path( - (const uint8_t*)"file://localhost/home/user/foo.ttl"), - "/home/user/foo.ttl")); - - assert(!serd_uri_to_path((const uint8_t*)"file:illegal/file/uri")); - - assert(!strcmp( - (const char*)serd_uri_to_path((const uint8_t*)"file:///c:/awful/system"), - "c:/awful/system")); - - assert(!strcmp( - (const char*)serd_uri_to_path((const uint8_t*)"file:///c:awful/system"), - "/c:awful/system")); - - assert(!strcmp((const char*)serd_uri_to_path((const uint8_t*)"file:///0/1"), - "/0/1")); - - assert( - !strcmp((const char*)serd_uri_to_path((const uint8_t*)"C:\\Windows\\Sucks"), - "C:\\Windows\\Sucks")); - - assert( - !strcmp((const char*)serd_uri_to_path((const uint8_t*)"C|/Windows/Sucks"), - "C|/Windows/Sucks")); + const uint8_t* const path = serd_uri_to_path((const uint8_t*)uri); + assert(path); + assert(!strcmp((const char*)path, expected_path)); +} +static void +test_uri_to_path(void) +{ + assert(!serd_uri_to_path((const uint8_t*)"file:invalid/file/uri")); assert(!serd_uri_to_path((const uint8_t*)"http://example.org/path")); - assert(!strcmp((const char*)serd_uri_to_path((const uint8_t*)"rel"), "rel")); + check_uri_to_path("file:///home/user/foo.ttl", "/home/user/foo.ttl"); + check_uri_to_path("file://localhost/home/user/foo.ttl", "/home/user/foo.ttl"); + check_uri_to_path("file:///c:/awful/system", "c:/awful/system"); + check_uri_to_path("file:///c:awful/system", "/c:awful/system"); + check_uri_to_path("file:///0/1", "/0/1"); + check_uri_to_path("C:\\Windows\\Sucks", "C:\\Windows\\Sucks"); + check_uri_to_path("C|/Windows/Sucks", "C|/Windows/Sucks"); + check_uri_to_path("rel", "rel"); } #if defined(__GNUC__) @@ -171,16 +159,19 @@ test_uri_parsing(void) // Test tolerance of NULL hostname parameter uint8_t* const hosted = serd_file_uri_parse(USTR("file://host/path"), NULL); + assert(hosted); assert(!strcmp((const char*)hosted, "/path")); serd_free(hosted); // Test tolerance of parsing junk URI escapes uint8_t* const junk1 = serd_file_uri_parse(USTR("file:///foo/%0Xbar"), NULL); + assert(junk1); assert(!strcmp((const char*)junk1, "/foo/bar")); serd_free(junk1); uint8_t* const junk2 = serd_file_uri_parse(USTR("file:///foo/%X0bar"), NULL); + assert(junk2); assert(!strcmp((const char*)junk2, "/foo/bar")); serd_free(junk2); } @@ -206,7 +197,7 @@ test_uri_from_string(void) serd_node_free(&base); } -static inline bool +static bool chunk_equals(const SerdChunk* const a, const SerdChunk* const b) { return (!a->len && !b->len && !a->buf && !b->buf) || diff --git a/test/test_write_error.py b/test/test_write_error.py index b62f981a..93b0249a 100755 --- a/test/test_write_error.py +++ b/test/test_write_error.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright 2022-2023 David Robillard <d@drobilla.net> +# Copyright 2022-2025 David Robillard <d@drobilla.net> # SPDX-License-Identifier: ISC """Test errors writing to a file.""" @@ -18,11 +18,15 @@ command = shlex.split(args.wrapper) + [args.serdi, args.input] if os.path.exists("/dev/full"): with open("/dev/full", "w", encoding="utf-8") as out: proc = subprocess.run( - command, check=False, stdout=out, stderr=subprocess.PIPE + command, + encoding="utf-8", + check=False, + stdout=out, + stderr=subprocess.PIPE, ) assert proc.returncode != 0 - assert "error" in proc.stderr.decode("utf-8") + assert "error" in proc.stderr else: sys.stderr.write("warning: /dev/full not present, skipping test") diff --git a/test/test_writer.c b/test/test_writer.c index 28c8e117..51f5d9ed 100644 --- a/test/test_writer.c +++ b/test/test_writer.c @@ -1,4 +1,4 @@ -// Copyright 2011-2023 David Robillard <d@drobilla.net> +// Copyright 2011-2025 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC #undef NDEBUG @@ -21,7 +21,6 @@ test_write_long_literal(void) SerdChunk chunk = {NULL, 0}; SerdWriter* writer = serd_writer_new( SERD_TURTLE, (SerdStyle)0, env, NULL, serd_chunk_sink, &chunk); - assert(writer); SerdNode s = serd_node_from_string(SERD_URI, USTR(NS_EG "s")); @@ -30,18 +29,19 @@ test_write_long_literal(void) serd_node_from_string(SERD_LITERAL, USTR("hello \"\"\"world\"\"\"!")); assert(!serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL)); - - serd_writer_free(writer); - serd_env_free(env); - - uint8_t* out = serd_chunk_sink_finish(&chunk); + assert(!serd_writer_finish(writer)); static const char* const expected = "<http://example.org/s>\n" "\t<http://example.org/p> \"\"\"hello \"\"\\\"world\"\"\\\"!\"\"\" .\n"; + uint8_t* const out = serd_chunk_sink_finish(&chunk); + assert(out); assert(!strcmp((char*)out, expected)); serd_free(out); + + serd_writer_free(writer); + serd_env_free(env); } static void @@ -51,7 +51,6 @@ test_write_nested_anon(void) SerdChunk chunk = {NULL, 0}; SerdWriter* writer = serd_writer_new( SERD_TURTLE, (SerdStyle)0, env, NULL, serd_chunk_sink, &chunk); - assert(writer); SerdNode s0 = serd_node_from_string(SERD_URI, USTR(NS_EG "s0")); @@ -96,11 +95,7 @@ test_write_nested_anon(void) writer, SERD_ANON_CONT, NULL, &b0, &p4, &o4, NULL, NULL)); assert(!serd_writer_end_anon(writer, &b0)); - - serd_writer_free(writer); - serd_env_free(env); - - uint8_t* const out = serd_chunk_sink_finish(&chunk); + assert(!serd_writer_finish(writer)); static const char* const expected = "<http://example.org/s0>\n" @@ -112,8 +107,13 @@ test_write_nested_anon(void) "\t\t<http://example.org/p4> <http://example.org/o4>\n" "\t] .\n"; + uint8_t* const out = serd_chunk_sink_finish(&chunk); + assert(out); assert(!strcmp((char*)out, expected)); serd_free(out); + + serd_writer_free(writer); + serd_env_free(env); } static size_t @@ -132,6 +132,7 @@ test_writer_cleanup(void) SerdEnv* env = serd_env_new(NULL); SerdWriter* writer = serd_writer_new(SERD_TURTLE, (SerdStyle)0U, env, NULL, null_sink, NULL); + assert(writer); SerdNode s = serd_node_from_string(SERD_URI, USTR(NS_EG "s")); SerdNode p = serd_node_from_string(SERD_URI, USTR(NS_EG "p")); @@ -185,6 +186,7 @@ test_write_bad_anon_stack(void) SerdEnv* env = serd_env_new(NULL); SerdWriter* writer = serd_writer_new(SERD_TURTLE, (SerdStyle)0U, env, NULL, null_sink, NULL); + assert(writer); SerdNode s = serd_node_from_string(SERD_URI, USTR(NS_EG "s")); SerdNode p = serd_node_from_string(SERD_URI, USTR(NS_EG "p")); @@ -212,14 +214,9 @@ test_write_bad_anon_stack(void) static void test_strict_write(void) { - const char* const path = "serd_strict_write_test.ttl"; - FILE* const fd = fopen(path, "wb"); - assert(fd); - SerdEnv* const env = serd_env_new(NULL); SerdWriter* const writer = serd_writer_new( - SERD_TURTLE, (SerdStyle)SERD_STYLE_STRICT, env, NULL, null_sink, fd); - + SERD_TURTLE, (SerdStyle)SERD_STYLE_STRICT, env, NULL, null_sink, NULL); assert(writer); const uint8_t bad_str[] = {0xFF, 0x90, 'h', 'i', 0}; @@ -238,9 +235,6 @@ test_strict_write(void) serd_writer_free(writer); serd_env_free(env); - - assert(!fclose(fd)); - assert(!remove(path)); } // Produce a write error without setting errno @@ -256,19 +250,129 @@ error_sink(const void* const buf, const size_t len, void* const stream) static void test_write_error(void) { - SerdEnv* const env = serd_env_new(NULL); - SerdWriter* writer = NULL; - SerdStatus st = SERD_SUCCESS; + SerdEnv* const env = serd_env_new(NULL); - SerdNode u = serd_node_from_string(SERD_URI, USTR("http://example.com/u")); - - writer = + SerdWriter* const writer = serd_writer_new(SERD_TURTLE, (SerdStyle)0, env, NULL, error_sink, NULL); assert(writer); - st = serd_writer_write_statement(writer, 0U, NULL, &u, &u, &u, NULL, NULL); + + SerdNode u = serd_node_from_string(SERD_URI, USTR("http://example.com/u")); + + const SerdStatus st = + serd_writer_write_statement(writer, 0U, NULL, &u, &u, &u, NULL, NULL); assert(st == SERD_ERR_BAD_WRITE); + + serd_writer_free(writer); + serd_env_free(env); +} + +static void +test_chunk_sink(void) +{ + SerdEnv* const env = serd_env_new(NULL); + assert(env); + + SerdChunk chunk = {NULL, 0}; + SerdWriter* const writer = serd_writer_new( + SERD_TURTLE, (SerdStyle)0, env, NULL, serd_chunk_sink, &chunk); + assert(writer); + + const SerdNode base = + serd_node_from_string(SERD_URI, USTR("http://example.org/base")); + assert(!serd_writer_set_base_uri(writer, &base)); + assert(!serd_writer_finish(writer)); + + uint8_t* const out = serd_chunk_sink_finish(&chunk); + assert(out); + assert(!strcmp((const char*)out, "@base <http://example.org/base> .\n")); + serd_free(out); + + serd_writer_free(writer); + serd_env_free(env); +} + +static void +test_write_nothing_node(void) +{ + SerdEnv* const env = serd_env_new(NULL); + assert(env); + + SerdChunk chunk = {NULL, 0}; + SerdWriter* const writer = serd_writer_new( + SERD_TURTLE, (SerdStyle)0, env, NULL, serd_chunk_sink, &chunk); + assert(writer); + + 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_NOTHING, USTR("")); + assert(serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL) == + SERD_ERR_BAD_ARG); + + assert(!chunk.buf); serd_writer_free(writer); + serd_env_free(env); +} + +static void +test_write_bad_statement(void) +{ + SerdEnv* const env = serd_env_new(NULL); + assert(env); + + SerdChunk chunk = {NULL, 0}; + SerdWriter* const writer = serd_writer_new( + SERD_TURTLE, (SerdStyle)0, env, NULL, serd_chunk_sink, &chunk); + assert(writer); + + SerdNode s = serd_node_from_string(SERD_URI, USTR("http://example.org/s")); + SerdNode p = serd_node_from_string(SERD_URI, USTR("http://example.org/p")); + SerdNode o = serd_node_from_string(SERD_URI, USTR("http://example.org/o")); + SerdNode l = serd_node_from_string(SERD_LITERAL, USTR("lang")); + assert(serd_writer_write_statement( + writer, + (SerdStatementFlags)(SERD_ANON_S_BEGIN | SERD_LIST_S_BEGIN), + NULL, + &s, + &p, + &o, + NULL, + NULL) == SERD_ERR_BAD_ARG); + + assert(serd_writer_write_statement( + writer, + (SerdStatementFlags)(SERD_EMPTY_S | SERD_LIST_S_BEGIN), + NULL, + &s, + &p, + &o, + NULL, + NULL) == SERD_ERR_BAD_ARG); + + assert(serd_writer_write_statement( + writer, + (SerdStatementFlags)(SERD_ANON_O_BEGIN | SERD_LIST_O_BEGIN), + NULL, + &s, + &p, + &o, + NULL, + NULL) == SERD_ERR_BAD_ARG); + + assert(serd_writer_write_statement( + writer, + (SerdStatementFlags)(SERD_EMPTY_O | SERD_LIST_O_BEGIN), + NULL, + &s, + &p, + &o, + NULL, + NULL) == SERD_ERR_BAD_ARG); + + assert(serd_writer_write_statement(writer, 0U, NULL, &s, &p, &o, &o, &l) == + SERD_ERR_BAD_ARG); + + serd_writer_free(writer); serd_env_free(env); } @@ -281,6 +385,9 @@ main(void) test_write_bad_anon_stack(); test_strict_write(); test_write_error(); + test_chunk_sink(); + test_write_nothing_node(); + test_write_bad_statement(); return 0; } |