aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/.clang-tidy9
-rw-r--r--test/extra/bad/bad-bom-1.ttl3
-rw-r--r--test/extra/bad/bad-bom-2.ttl3
-rw-r--r--test/extra/bad/bad-bom-only-1.ttl1
-rw-r--r--test/extra/bad/bad-bom-only-2.ttl1
-rw-r--r--test/extra/bad/bad-lang-start-delete.nt1
-rw-r--r--test/extra/bad/bad-lang-start-space.nt1
-rw-r--r--test/extra/bad/bad-lang-start-tab.nt1
-rw-r--r--test/extra/bad/bad-lang-start-wide.nt1
-rw-r--r--test/extra/bad/bad-lang.ttl2
-rw-r--r--test/extra/bad/bad-predicate-in-blank.ttl1
-rw-r--r--test/extra/bad/bad-prefix-dot.ttl1
-rw-r--r--test/extra/bad/bad-uri-scheme-start-apostrophe.nt1
-rw-r--r--test/extra/bad/bad-uri-scheme-start-delete.nt1
-rw-r--r--test/extra/bad/bad-uri-scheme-start-space.nt1
-rw-r--r--test/extra/bad/bad-uri-scheme-start-tab.nt1
-rw-r--r--test/extra/bad/bad-uri-scheme-start-wide.nt1
-rw-r--r--test/extra/bad/bad-uri-scheme-start.nt1
-rw-r--r--test/extra/bad/manifest.ttl311
-rw-r--r--test/extra/eof/README.md5
-rw-r--r--test/extra/eof/bad-nt-eof-after-blank.nt (renamed from test/extra/bad/bad-nt-eof-after-blank.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-after-lang-hyphen.nt (renamed from test/extra/bad/bad-nt-eof-after-lang-hyphen.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-after-lang-subtag.nt (renamed from test/extra/bad/bad-nt-eof-after-lang-subtag.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-after-lang.nt (renamed from test/extra/bad/bad-nt-eof-after-lang.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-after-object.nt (renamed from test/extra/bad/bad-nt-eof-after-object.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-after-predicate.nt (renamed from test/extra/bad/bad-nt-eof-after-predicate.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-after-string-escape.nt (renamed from test/extra/bad/bad-nt-eof-after-string-escape.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-after-string.nt (renamed from test/extra/bad/bad-nt-eof-after-string.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-after-subject.nt (renamed from test/extra/bad/bad-nt-eof-after-subject.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-after-underscore.nt (renamed from test/extra/bad/bad-nt-eof-after-underscore.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-before-blank.nt (renamed from test/extra/bad/bad-nt-eof-before-blank.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-before-iri.nt (renamed from test/extra/bad/bad-nt-eof-before-iri.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-before-lang.nt (renamed from test/extra/bad/bad-nt-eof-before-lang.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-before-string-escape.nt (renamed from test/extra/bad/bad-nt-eof-before-string-escape.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-before-string.nt (renamed from test/extra/bad/bad-nt-eof-before-string.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-in-iri-path.nt (renamed from test/extra/bad/bad-nt-eof-in-iri-path.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-in-iri-scheme.nt (renamed from test/extra/bad/bad-nt-eof-in-iri-scheme.nt)0
-rw-r--r--test/extra/eof/bad-nt-eof-in-string.nt (renamed from test/extra/bad/bad-nt-eof-in-string.nt)0
-rw-r--r--test/extra/eof/bad-ttl-eof-after-quotes.ttl (renamed from test/extra/bad/bad-eof-after-quotes.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-at-string-start.ttl (renamed from test/extra/bad/bad-eof-at-string-start.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-blank.ttl (renamed from test/extra/bad/bad-eof-in-blank.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-escape.ttl (renamed from test/extra/bad/bad-eof-in-escape.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-lang-suffix.ttl (renamed from test/extra/bad/bad-eof-in-lang-suffix.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-lang.ttl (renamed from test/extra/bad/bad-eof-in-lang.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-list.ttl (renamed from test/extra/bad/bad-eof-in-list.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-long-string.ttl (renamed from test/extra/bad/bad-eof-in-long-string.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-object-list.ttl (renamed from test/extra/bad/bad-eof-in-object-list.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-object-list2.ttl (renamed from test/extra/bad/bad-eof-in-object-list2.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-predicate-list.ttl (renamed from test/extra/bad/bad-eof-in-predicate-list.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-string.ttl (renamed from test/extra/bad/bad-eof-in-string.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-text-character.ttl (renamed from test/extra/bad/bad-eof-in-text-character.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-triple-quote.ttl (renamed from test/extra/bad/bad-eof-in-triple-quote.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-uri-character.ttl (renamed from test/extra/bad/bad-eof-in-uri-character.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-uri-scheme.ttl (renamed from test/extra/bad/bad-eof-in-uri-scheme.nt)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-uri.ttl (renamed from test/extra/bad/bad-eof-in-uri.ttl)0
-rw-r--r--test/extra/eof/bad-ttl-eof-in-utf8-character.ttl (renamed from test/extra/bad/bad-eof-in-utf8-character.ttl)0
-rw-r--r--test/extra/eof/manifest.ttl225
-rw-r--r--test/extra/good/manifest.ttl100
-rw-r--r--test/extra/good/test-bom-only.nt0
-rw-r--r--test/extra/good/test-bom-only.ttl1
-rw-r--r--test/extra/good/test-boolish-prefix.nt2
-rw-r--r--test/extra/good/test-boolish-prefix.ttl5
-rw-r--r--test/extra/good/test-decimal-ends-with-dot.nt1
-rw-r--r--test/extra/good/test-decimal-ends-with-dot.ttl4
-rw-r--r--test/extra/good/test-double-ends-with-dot.nt1
-rw-r--r--test/extra/good/test-double-ends-with-dot.ttl4
-rw-r--r--test/extra/good/test-false-ends-with-dot.nt1
-rw-r--r--test/extra/good/test-false-ends-with-dot.ttl4
-rw-r--r--test/extra/good/test-integer-ends-with-dot.nt1
-rw-r--r--test/extra/good/test-integer-ends-with-dot.ttl4
-rw-r--r--test/extra/good/test-local-name-ends-with-dot.nt1
-rw-r--r--test/extra/good/test-local-name-escapes.nt17
-rw-r--r--test/extra/good/test-local-name-escapes.ttl19
-rw-r--r--test/extra/good/test-local-name-percent.nt2
-rw-r--r--test/extra/good/test-local-name-percent.ttl4
-rw-r--r--test/extra/good/test-nq-syntax-all-rules.nq2
-rw-r--r--test/extra/good/test-nt-syntax-all-rules.nt2
-rw-r--r--test/extra/good/test-trig-syntax-all-rules.trig4
-rw-r--r--test/extra/good/test-true-ends-with-dot.nt1
-rw-r--r--test/extra/good/test-true-ends-with-dot.ttl4
-rw-r--r--test/extra/good/test-ttl-syntax-all-rules.ttl6
-rw-r--r--test/extra/lax/manifest.ttl28
-rw-r--r--test/extra/lax/test-bad-string.trig3
-rw-r--r--test/extra/lax/test-bad-uri.trig8
-rw-r--r--test/extra/lax/test-bad-utf8.trig6
-rw-r--r--test/extra/lax/test-out-of-range-unicode.nt (renamed from test/extra/good/test-out-of-range-unicode.nt)0
-rw-r--r--test/extra/lax/test-out-of-range-unicode.ttl (renamed from test/extra/good/test-out-of-range-unicode.ttl)0
-rw-r--r--test/extra/pretty/datatypes.ttl2
-rw-r--r--test/extra/pretty/manifest.ttl7
-rw-r--r--test/extra/pretty/named-graph.trig16
-rw-r--r--test/extra/pretty/repeated-directives.ttl17
-rw-r--r--test/headers/.clang-tidy5
-rw-r--r--test/headers/meson.build1
-rw-r--r--test/headers/test_headers.c5
-rw-r--r--test/lint/meson.build133
-rw-r--r--test/meson.build151
-rwxr-xr-xtest/run_suite.py19
-rw-r--r--test/serd_test_util/__init__.py41
-rw-r--r--test/test_env.c26
-rw-r--r--test/test_free_null.c2
-rw-r--r--test/test_node.c103
-rwxr-xr-xtest/test_quiet.py20
-rw-r--r--test/test_reader.c429
-rw-r--r--test/test_reader_writer.c515
-rwxr-xr-xtest/test_stdin.py37
-rw-r--r--test/test_string.c35
-rw-r--r--test/test_uri.c195
-rwxr-xr-xtest/test_write_error.py19
-rw-r--r--test/test_writer.c263
109 files changed, 1808 insertions, 1040 deletions
diff --git a/test/.clang-tidy b/test/.clang-tidy
index 75f5312d..80737308 100644
--- a/test/.clang-tidy
+++ b/test/.clang-tidy
@@ -7,9 +7,14 @@ 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,
-hicpp-signed-bitwise,
- -readability-function-cognitive-complexity,
+ -readability-redundant-casting,
+CheckOptions:
+ - key: readability-function-cognitive-complexity.IgnoreMacros
+ value: 'true'
+ - key: readability-function-cognitive-complexity.Threshold
+ value: '6'
InheritParentConfig: true
diff --git a/test/extra/bad/bad-bom-1.ttl b/test/extra/bad/bad-bom-1.ttl
new file mode 100644
index 00000000..7d7681d4
--- /dev/null
+++ b/test/extra/bad/bad-bom-1.ttl
@@ -0,0 +1,3 @@
+ï# This file starts with the first byte of the UTF-8 Byte Order Mark
+
+<http://example.org/thing> a <http://example.org/Thing> .
diff --git a/test/extra/bad/bad-bom-2.ttl b/test/extra/bad/bad-bom-2.ttl
new file mode 100644
index 00000000..9ce3f093
--- /dev/null
+++ b/test/extra/bad/bad-bom-2.ttl
@@ -0,0 +1,3 @@
+ï»# This file starts with the first two bytes of the UTF-8 Byte Order Mark
+
+<http://example.org/thing> a <http://example.org/Thing> .
diff --git a/test/extra/bad/bad-bom-only-1.ttl b/test/extra/bad/bad-bom-only-1.ttl
new file mode 100644
index 00000000..a4a063a1
--- /dev/null
+++ b/test/extra/bad/bad-bom-only-1.ttl
@@ -0,0 +1 @@
+ï \ No newline at end of file
diff --git a/test/extra/bad/bad-bom-only-2.ttl b/test/extra/bad/bad-bom-only-2.ttl
new file mode 100644
index 00000000..022c50f1
--- /dev/null
+++ b/test/extra/bad/bad-bom-only-2.ttl
@@ -0,0 +1 @@
+ï» \ No newline at end of file
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-predicate-in-blank.ttl b/test/extra/bad/bad-predicate-in-blank.ttl
new file mode 100644
index 00000000..e4200f15
--- /dev/null
+++ b/test/extra/bad/bad-predicate-in-blank.ttl
@@ -0,0 +1 @@
+<a> <b> [ ERRORHERE <c> ]
diff --git a/test/extra/bad/bad-prefix-dot.ttl b/test/extra/bad/bad-prefix-dot.ttl
new file mode 100644
index 00000000..7b02211f
--- /dev/null
+++ b/test/extra/bad/bad-prefix-dot.ttl
@@ -0,0 +1 @@
+@prefix dotted.: <http://example.org/> .
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 6b6df540..acadde28 100644
--- a/test/extra/bad/manifest.ttl
+++ b/test/extra/bad/manifest.ttl
@@ -13,7 +13,10 @@
<#bad-blank-node-label>
<#bad-blank-predicate>
<#bad-blank-syntax>
- <#bad-bom>
+ <#bad-bom-1>
+ <#bad-bom-2>
+ <#bad-bom-only-1>
+ <#bad-bom-only-2>
<#bad-char-in-local>
<#bad-char-in-prefix>
<#bad-char-in-uri>
@@ -25,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>
@@ -62,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>
@@ -96,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>
@@ -113,8 +84,10 @@
<#bad-object2>
<#bad-paths>
<#bad-pn-escape>
- <#bad-prefix-missing-colon>
+ <#bad-predicate-in-blank>
<#bad-prefix>
+ <#bad-prefix-dot>
+ <#bad-prefix-missing-colon>
<#bad-quote-in-uri>
<#bad-semicolon-after-subject>
<#bad-string>
@@ -124,7 +97,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>
) .
@@ -164,10 +140,25 @@
mf:action <bad-blank-syntax.ttl> ;
mf:name "bad-blank-syntax" .
-<#bad-bom>
+<#bad-bom-1>
+ a rdft:TestTurtleNegativeSyntax ;
+ mf:action <bad-bom-1.ttl> ;
+ mf:name "bad-bom-1" .
+
+<#bad-bom-2>
a rdft:TestTurtleNegativeSyntax ;
- mf:action <bad-bom.ttl> ;
- mf:name "bad-bom" .
+ mf:action <bad-bom-2.ttl> ;
+ mf:name "bad-bom-2" .
+
+<#bad-bom-only-1>
+ a rdft:TestTurtleNegativeSyntax ;
+ mf:action <bad-bom-only-1.ttl> ;
+ mf:name "bad-bom-only-1" .
+
+<#bad-bom-only-2>
+ a rdft:TestTurtleNegativeSyntax ;
+ mf:action <bad-bom-only-2.ttl> ;
+ mf:name "bad-bom-only-2" .
<#bad-char-in-local>
a rdft:TestTurtleNegativeSyntax ;
@@ -224,96 +215,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> ;
@@ -409,96 +310,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> ;
@@ -579,6 +390,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> ;
@@ -664,11 +495,21 @@
mf:action <bad-pn-escape.ttl> ;
mf:name "bad-pn-escape" .
+<#bad-predicate-in-blank>
+ a rdft:TestTurtleNegativeSyntax ;
+ mf:action <bad-predicate-in-blank.ttl> ;
+ mf:name "bad-predicate-in-blank" .
+
<#bad-prefix>
a rdft:TestTurtleNegativeSyntax ;
mf:action <bad-prefix.ttl> ;
mf:name "bad-prefix" .
+<#bad-prefix-dot>
+ a rdft:TestTurtleNegativeSyntax ;
+ mf:action <bad-prefix-dot.ttl> ;
+ mf:name "bad-prefix-dot" .
+
<#bad-prefix-missing-colon>
a rdft:TestTurtleNegativeSyntax ;
mf:action <bad-prefix-missing-colon.ttl> ;
@@ -719,10 +560,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 befe9451..659f8fd1 100644
--- a/test/extra/good/manifest.ttl
+++ b/test/extra/good/manifest.ttl
@@ -16,24 +16,32 @@
<#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>
+ <#test-local-name-escapes>
+ <#test-local-name-percent>
<#test-long-utf8>
<#test-no-spaces>
<#test-non-curie-uri>
<#test-nq-syntax-all-rules>
<#test-nq-syntax-dot-end>
- <#test-nq-syntax-eof-after-blank-dot>
+ <#test-nt-syntax-all-rules>
<#test-nq-syntax-eol-cr>
<#test-nq-syntax-eol-crlf>
<#test-nq-syntax-eol-lf>
@@ -46,13 +54,15 @@
<#test-nt-syntax-eol-crlf>
<#test-nt-syntax-eol-lf>
<#test-nt-syntax-eol-lfcr>
- <#test-out-of-range-unicode>
<#test-prefix>
<#test-quote-escapes>
<#test-rel>
<#test-semi-dot>
<#test-several-eaten-dots>
<#test-string-escapes>
+ <#test-trig-syntax-all-rules>
+ <#test-true-ends-with-dot>
+ <#test-ttl-syntax-all-rules>
<#test-uri>
) .
@@ -116,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> ;
@@ -140,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> ;
@@ -170,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> ;
@@ -188,6 +234,24 @@
mf:name "test-list-subject" ;
mf:result <test-list-subject.nt> .
+<#test-local-name-ends-with-dot>
+ a rdft:TestTurtleEval ;
+ mf:action <test-local-name-ends-with-dot.ttl> ;
+ mf:name "test-local-name-ends-with-dot" ;
+ mf:result <test-local-name-ends-with-dot.nt> .
+
+<#test-local-name-escapes>
+ a rdft:TestTurtleEval ;
+ mf:action <test-local-name-escapes.ttl> ;
+ mf:name "test-local-name-escapes" ;
+ mf:result <test-local-name-escapes.nt> .
+
+<#test-local-name-percent>
+ a rdft:TestTurtleEval ;
+ mf:action <test-local-name-percent.ttl> ;
+ mf:name "test-local-name-percent" ;
+ mf:result <test-local-name-percent.nt> .
+
<#test-long-utf8>
a rdft:TestTurtleEval ;
mf:action <test-long-utf8.ttl> ;
@@ -206,11 +270,6 @@
mf:name "test-non-curie-uri" ;
mf:result <test-non-curie-uri.nt> .
-<#test-nq-syntax-eof-after-blank-dot>
- a rdft:TestNTriplesPositiveSyntax ;
- mf:action <test-nq-syntax-eof-after-blank-dot.nq> ;
- mf:name "test-nq-syntax-eof-after-blank-dot" .
-
<#test-nq-syntax-all-rules>
a rdft:TestNQuadsPositiveSyntax ;
mf:action <test-nq-syntax-all-rules.nq> ;
@@ -221,6 +280,11 @@
mf:action <test-nq-syntax-dot-end.nq> ;
mf:name "test-nq-syntax-dot-end" .
+<#test-nq-syntax-eof-after-blank-dot>
+ a rdft:TestNTriplesPositiveSyntax ;
+ mf:action <test-nq-syntax-eof-after-blank-dot.nq> ;
+ mf:name "test-nq-syntax-eof-after-blank-dot" .
+
<#test-nq-syntax-eol-cr>
a rdft:TestNTriplesPositiveSyntax ;
mf:action <test-nq-syntax-eol-cr.nq> ;
@@ -281,12 +345,6 @@
mf:action <test-nt-syntax-eol-lfcr.nt> ;
mf:name "test-nt-syntax-eol-lfcr" .
-<#test-out-of-range-unicode>
- a rdft:TestTurtleEval ;
- mf:action <test-out-of-range-unicode.ttl> ;
- mf:name "test-out-of-range-unicode" ;
- mf:result <test-out-of-range-unicode.nt> .
-
<#test-prefix>
a rdft:TestTurtleEval ;
mf:action <test-prefix.ttl> ;
@@ -323,6 +381,22 @@
mf:name "test-string-escapes" ;
mf:result <test-string-escapes.nt> .
+<#test-trig-syntax-all-rules>
+ a rdft:TestTrigPositiveSyntax ;
+ 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> ;
+ mf:name "test-ttl-syntax-all-rules" .
+
<#test-uri>
a rdft:TestTurtleEval ;
mf:action <test-uri.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-local-name-ends-with-dot.nt b/test/extra/good/test-local-name-ends-with-dot.nt
new file mode 100644
index 00000000..3285348a
--- /dev/null
+++ b/test/extra/good/test-local-name-ends-with-dot.nt
@@ -0,0 +1 @@
+<http://example.org/eg#s> <http://example.org/eg#p> <http://example.org/eg#foo.> .
diff --git a/test/extra/good/test-local-name-escapes.nt b/test/extra/good/test-local-name-escapes.nt
new file mode 100644
index 00000000..a6362d7a
--- /dev/null
+++ b/test/extra/good/test-local-name-escapes.nt
@@ -0,0 +1,17 @@
+<http://example.org/s> <http://example.org/p> <http://example.org/o'> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o!> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o#> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o$> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o%> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o&> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o(> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o)> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o*> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o+> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o,> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o/> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o;> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o=> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o?> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o@> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o~> .
diff --git a/test/extra/good/test-local-name-escapes.ttl b/test/extra/good/test-local-name-escapes.ttl
new file mode 100644
index 00000000..8c5fce37
--- /dev/null
+++ b/test/extra/good/test-local-name-escapes.ttl
@@ -0,0 +1,19 @@
+@prefix eg: <http://example.org/> .
+
+eg:s eg:p eg:o\' .
+eg:s eg:p eg:o\! .
+eg:s eg:p eg:o\# .
+eg:s eg:p eg:o\$ .
+eg:s eg:p eg:o\% .
+eg:s eg:p eg:o\& .
+eg:s eg:p eg:o\( .
+eg:s eg:p eg:o\) .
+eg:s eg:p eg:o\* .
+eg:s eg:p eg:o\+ .
+eg:s eg:p eg:o\, .
+eg:s eg:p eg:o\/ .
+eg:s eg:p eg:o\; .
+eg:s eg:p eg:o\= .
+eg:s eg:p eg:o\? .
+eg:s eg:p eg:o\@ .
+eg:s eg:p eg:o\~ .
diff --git a/test/extra/good/test-local-name-percent.nt b/test/extra/good/test-local-name-percent.nt
new file mode 100644
index 00000000..e6330547
--- /dev/null
+++ b/test/extra/good/test-local-name-percent.nt
@@ -0,0 +1,2 @@
+<http://example.org/s> <http://example.org/p> <http://example.org/o%3E> .
+<http://example.org/s> <http://example.org/p> <http://example.org/o%3f> .
diff --git a/test/extra/good/test-local-name-percent.ttl b/test/extra/good/test-local-name-percent.ttl
new file mode 100644
index 00000000..32fb63d5
--- /dev/null
+++ b/test/extra/good/test-local-name-percent.ttl
@@ -0,0 +1,4 @@
+@prefix eg: <http://example.org/> .
+
+eg:s eg:p eg:o%3E .
+eg:s eg:p eg:o%3f .
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/extra/lax/manifest.ttl b/test/extra/lax/manifest.ttl
index b9890e14..f79e1984 100644
--- a/test/extra/lax/manifest.ttl
+++ b/test/extra/lax/manifest.ttl
@@ -8,14 +8,18 @@
mf:entries (
<#test-bad-string-nq>
<#test-bad-string-nt>
+ <#test-bad-string-trig>
<#test-bad-string-ttl>
<#test-bad-uri-nq>
<#test-bad-uri-nt>
<#test-bad-uri-ttl>
+ <#test-bad-uri-trig>
<#test-bad-utf8-nq>
<#test-bad-utf8-nt>
<#test-bad-utf8-ttl>
+ <#test-bad-utf8-trig>
<#test-lone-list>
+ <#test-out-of-range-unicode>
) .
<#test-bad-string-nq>
@@ -36,6 +40,12 @@
mf:name "test-bad-string-ttl" ;
mf:result <test-bad-string-out.nt> .
+<#test-bad-string-trig>
+ a rdft:TestTrigNegativeSyntax ;
+ mf:action <test-bad-string.trig> ;
+ mf:name "test-bad-string-trig" ;
+ mf:result <test-bad-string-out.nt> .
+
<#test-bad-uri-nq>
a rdft:TestNQuadsNegativeSyntax ;
mf:action <test-bad-uri.nq> ;
@@ -54,6 +64,12 @@
mf:name "test-bad-uri-ttl" ;
mf:result <test-bad-uri-out.nt> .
+<#test-bad-uri-trig>
+ a rdft:TestTurtleNegativeSyntax ;
+ mf:action <test-bad-uri.trig> ;
+ mf:name "test-bad-uri-trig" ;
+ mf:result <test-bad-uri-nq-out.nq> .
+
<#test-bad-utf8-nq>
a rdft:TestNQuadsNegativeSyntax ;
mf:action <test-bad-utf8.nq> ;
@@ -72,8 +88,20 @@
mf:name "test-bad-utf8-ttl" ;
mf:result <test-bad-utf8-ttl-out.nt> .
+<#test-bad-utf8-trig>
+ a rdft:TestTurtleNegativeSyntax ;
+ mf:action <test-bad-utf8.trig> ;
+ mf:name "test-bad-utf8-trig" ;
+ mf:result <test-bad-utf8-ttl-out.nt> .
+
<#test-lone-list>
a rdft:TestTurtleNegativeSyntax ;
mf:action <test-lone-list.ttl> ;
mf:name "test-lone-list" ;
mf:result <test-lone-list.nt> .
+
+<#test-out-of-range-unicode>
+ a rdft:TestTurtleNegativeSyntax ;
+ mf:action <test-out-of-range-unicode.ttl> ;
+ mf:name "test-out-of-range-unicode" ;
+ mf:result <test-out-of-range-unicode.nt> .
diff --git a/test/extra/lax/test-bad-string.trig b/test/extra/lax/test-bad-string.trig
new file mode 100644
index 00000000..72eb9621
--- /dev/null
+++ b/test/extra/lax/test-bad-string.trig
@@ -0,0 +1,3 @@
+<http://example.org/s1> <http://example.org/p1> "Truncated line
+<http://example.org/s1> <http://example.org/p1> "Bad escape \? " .
+<http://example.org/s1> <http://example.org/p2> "Good" .
diff --git a/test/extra/lax/test-bad-uri.trig b/test/extra/lax/test-bad-uri.trig
new file mode 100644
index 00000000..ba852fef
--- /dev/null
+++ b/test/extra/lax/test-bad-uri.trig
@@ -0,0 +1,8 @@
+<http://example.org/ÿÿbadg1> {
+ <http://example.org/s> <http://example.org/p> <http://example.org/goodo1>
+}
+
+<http://example.org/s>
+ <http://example.org/p> <http://example.org/ bado1> ;
+ <http://example.org/p> <http://example.org/ÿÿbado2> ;
+ <http://example.org/p> <http://example.org/goodo2> .
diff --git a/test/extra/lax/test-bad-utf8.trig b/test/extra/lax/test-bad-utf8.trig
new file mode 100644
index 00000000..0e177366
--- /dev/null
+++ b/test/extra/lax/test-bad-utf8.trig
@@ -0,0 +1,6 @@
+<http://example.org/s> <http://example.org/p> "Impossible bytes: þ ÿ" .
+<http://example.org/s> <http://example.org/p> "2 continuation bytes: €¿" .
+<http://example.org/s> <http://example.org/p> "Missing continuation: À" .
+<http://example.org/s> <http://example.org/p> """Impossible bytes: þ ÿ""" .
+<http://example.org/s> <http://example.org/p> """2 continuation bytes: €¿""" .
+<http://example.org/s> <http://example.org/p> """Missing continuation: À""" .
diff --git a/test/extra/good/test-out-of-range-unicode.nt b/test/extra/lax/test-out-of-range-unicode.nt
index 5def9e31..5def9e31 100644
--- a/test/extra/good/test-out-of-range-unicode.nt
+++ b/test/extra/lax/test-out-of-range-unicode.nt
diff --git a/test/extra/good/test-out-of-range-unicode.ttl b/test/extra/lax/test-out-of-range-unicode.ttl
index 7e64785a..7e64785a 100644
--- a/test/extra/good/test-out-of-range-unicode.ttl
+++ b/test/extra/lax/test-out-of-range-unicode.ttl
diff --git a/test/extra/pretty/datatypes.ttl b/test/extra/pretty/datatypes.ttl
index 721dfe4d..8f8b13f2 100644
--- a/test/extra/pretty/datatypes.ttl
+++ b/test/extra/pretty/datatypes.ttl
@@ -9,6 +9,8 @@ eg:s
1 ,
2.3 ,
"4."^^xsd:decimal ,
+ "5"^^xsd:decimal ,
+ "6.7E8"^^xsd:float ,
false ,
true ,
"x"^^eg:datatype ,
diff --git a/test/extra/pretty/manifest.ttl b/test/extra/pretty/manifest.ttl
index 6422c9e0..26ed63be 100644
--- a/test/extra/pretty/manifest.ttl
+++ b/test/extra/pretty/manifest.ttl
@@ -35,6 +35,7 @@
<#nested-list-object>
<#nested-list-object-with-empty-lists>
<#relative-uris>
+ <#repeated-directives>
<#short-string-escapes>
<#uri-escapes>
<#nested-list-subject>
@@ -214,6 +215,12 @@
mf:name "relative-uris" ;
mf:result <relative-uris.ttl> .
+<#repeated-directives>
+ a rdft:TestTurtleEval ;
+ mf:action <repeated-directives.ttl> ;
+ mf:name "repeated-directives" ;
+ mf:result <repeated-directives.ttl> .
+
<#short-string-escapes>
a rdft:TestTurtleEval ;
mf:action <short-string-escapes.ttl> ;
diff --git a/test/extra/pretty/named-graph.trig b/test/extra/pretty/named-graph.trig
index 5cd12f3b..29f1d970 100644
--- a/test/extra/pretty/named-graph.trig
+++ b/test/extra/pretty/named-graph.trig
@@ -1,8 +1,18 @@
@prefix eg: <http://example.org/> .
-eg:g {
- eg:s
- eg:p [
+eg:g1 {
+ eg:s1
+ eg:p1 [
a eg:Object
] .
}
+
+eg:g2 {
+ eg:s2
+ eg:p2 [
+ a eg:Object
+ ] .
+}
+
+eg:s3
+ eg:p3 eg:o3 .
diff --git a/test/extra/pretty/repeated-directives.ttl b/test/extra/pretty/repeated-directives.ttl
new file mode 100644
index 00000000..c7875c31
--- /dev/null
+++ b/test/extra/pretty/repeated-directives.ttl
@@ -0,0 +1,17 @@
+@base <http://example.org/base> .
+@base <http://example.org/base> .
+@base <base> .
+@prefix eg: <http://example.org/eg#> .
+@prefix eg: <http://example.org/eg#> .
+@prefix eg: <eg#> .
+
+eg:s
+ eg:p eg:o ,
+ eg:o .
+
+@prefix eg: <eg#> .
+@prefix eg: <http://example.org/eg#> .
+@prefix eg: <http://example.org/eg#> .
+@base <base> .
+@base <http://example.org/base> .
+@base <http://example.org/base> .
diff --git a/test/headers/.clang-tidy b/test/headers/.clang-tidy
index eaf6ac95..06ede334 100644
--- a/test/headers/.clang-tidy
+++ b/test/headers/.clang-tidy
@@ -1,4 +1,4 @@
-# Copyright 2020-2022 David Robillard <d@drobilla.net>
+# Copyright 2020-2024 David Robillard <d@drobilla.net>
# SPDX-License-Identifier: 0BSD OR ISC
Checks: >
@@ -6,6 +6,9 @@ Checks: >
-altera-*,
-llvmlibc-*,
-readability-identifier-length,
+CheckOptions:
+ - key: readability-function-cognitive-complexity.Threshold
+ value: '0'
WarningsAsErrors: '*'
HeaderFilterRegex: '.*'
FormatStyle: file
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/headers/test_headers.c b/test/headers/test_headers.c
index c855c103..2f923c7e 100644
--- a/test/headers/test_headers.c
+++ b/test/headers/test_headers.c
@@ -1,10 +1,9 @@
// Copyright 2022 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
-#include "serd/serd.h" // IWYU pragma: keep
+#include <serd/serd.h> // IWYU pragma: keep
-SERD_CONST_FUNC
-int
+SERD_CONST_FUNC int
main(void)
{
return 0;
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 f6f56c2b..223e279d 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -4,110 +4,6 @@
run_suite = find_program('run_suite.py')
wrapper = meson.get_external_property('exe_wrapper', '')
-########################
-# Scripts and Metadata #
-########################
-
-plot_script_paths = [
- '../scripts/serd_bench.py',
-]
-
-simple_script_paths = [
- '../scripts/check_formatting.py',
- 'serd_test_util/__init__.py',
- 'run_suite.py',
- 'test_quiet.py',
- 'test_stdin.py',
- 'test_write_error.py',
-]
-
-ttl_metadata_file_paths = [
- '../serd.ttl',
- 'extra/abbreviate/manifest.ttl',
- 'extra/bad/manifest.ttl',
- 'extra/big/manifest.ttl',
- 'extra/full/manifest.ttl',
- 'extra/good/manifest.ttl',
- 'extra/lax/manifest.ttl',
- 'extra/perfect/manifest.ttl',
- 'extra/prefix/manifest.ttl',
- 'extra/pretty/manifest.ttl',
- 'extra/qualify/manifest.ttl',
- 'extra/root/manifest.ttl',
-]
-
-plot_scripts = files(plot_script_paths)
-simple_scripts = files(simple_script_paths)
-python_script_paths = simple_script_paths + plot_script_paths
-python_scripts = plot_scripts + simple_scripts
-
-if get_option('lint')
- # Check release metadata
- if not meson.is_subproject()
- autoship = find_program('autoship', required: false)
- if autoship.found()
- test('autoship', autoship, args: ['test', serd_src_root], suite: 'data')
- endif
- endif
-
- # Check licensing metadata
- reuse = find_program('reuse', required: false)
- if reuse.found()
- test(
- 'REUSE',
- reuse,
- args: ['--root', serd_src_root, 'lint'],
- suite: 'data',
- )
- endif
-
- # Check script formatting
- black = find_program('black', required: false)
- if black.found()
- black_opts = ['--check', '-q', '-l', '79']
- foreach script_path : python_script_paths
- script = files(script_path)
- name = script_path.underscorify()
- test(name, black, args: black_opts + [script], suite: 'scripts')
- endforeach
- endif
-
- # Check scripts for errors with flake8
- flake8 = find_program('flake8', required: false)
- if flake8.found()
- test('flake8', flake8, args: python_scripts, suite: 'scripts')
- endif
-
- # Check scripts for errors with pylint
- pylint = find_program('pylint', required: false)
- if pylint.found()
- pymod = import('python')
- plot_py = pymod.find_installation(
- 'python3',
- modules: ['matplotlib'],
- required: false,
- )
-
- pylint_scripts = simple_scripts
- if plot_py.found()
- pylint_scripts += plot_scripts
- endif
-
- pylint_args = ['--disable', 'bad-option-value']
- test('pylint', pylint, args: pylint_args + pylint_scripts, suite: 'scripts')
- endif
-
- # Check Turtle formatting with serdi
- foreach ttl_file_path : ttl_metadata_file_paths
- test(
- ttl_file_path.underscorify(),
- check_formatting_py,
- args: [files(ttl_file_path), serdi, '-o', 'turtle'],
- suite: 'data',
- )
- endforeach
-endif
-
###################
# Header Warnings #
###################
@@ -118,24 +14,30 @@ subdir('headers')
# Unit Tests #
##############
-unit_tests = [
+unit_test_names = [
'env',
'free_null',
'node',
+ 'reader',
'reader_writer',
'string',
'uri',
'writer',
]
-foreach unit : unit_tests
+unit_test_sources = files('headers/test_headers.c')
+
+foreach name : unit_test_names
+ source = files('test_@0@.c'.format(name))
+ unit_test_sources += source
test(
- unit,
+ name,
executable(
- 'test_@0@'.format(unit),
- files('test_@0@.c'.format(unit)),
+ 'test_@0@'.format(name),
+ source,
c_args: c_suppressions,
dependencies: serd_dep,
+ implicit_include_directories: false,
),
suite: 'unit',
)
@@ -154,14 +56,20 @@ simple_command_tests = {
'serdi': {
'bad': [
['-c'],
+ ['-cx'],
['-fi'],
['-i', 'turtle'],
- ['-i', 'unknown'],
+ ['-i', 'turt'],
['-i'],
- ['-o', 'unknown'],
+ ['-ix'],
+ ['-o', '~unknown'],
+ ['-o', 'ntripleses'],
['-o'],
+ ['-ox'],
['-p'],
+ ['-px'],
['-r'],
+ ['-rx'],
['-z'],
],
'good': [
@@ -178,6 +86,7 @@ if is_variable('serdi')
script_args = common_script_args + ['--serdi', serdi]
serd_ttl = files('../serd.ttl')[0]
bad_input_file = files('extra/bad/bad-base.ttl')
+ text_input_file = files('extra/bad/README.md')
test('serd_ttl', serdi, args: [serd_ttl], suite: 'data')
@@ -214,6 +123,7 @@ if is_variable('serdi')
'string': ['-s', '<foo> a <Bar> .'],
'no_such_file': ['no_such_file'],
'remote': ['ftp://example.org/unsupported.ttl'],
+ 'text': [text_input_file],
}
foreach name, args : bad_input_tests
@@ -303,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/',
@@ -384,3 +305,11 @@ if is_variable('serdi')
)
endforeach
endif
+
+########
+# Lint #
+########
+
+if get_option('lint')
+ 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 8027462b..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."""
@@ -8,10 +8,12 @@
# pylint: disable=consider-using-f-string
# pylint: disable=invalid-name
+import argparse
import datetime
import difflib
import os
import re
+import shlex
import subprocess
import sys
import urllib.parse
@@ -51,6 +53,33 @@ def error(message):
sys.stderr.write("\n")
+def wrapper_args(description, with_input=False):
+ """Return the command line arguments for a wrapped test."""
+
+ parser = argparse.ArgumentParser(description)
+ parser.add_argument("--serdi", default="./serdi", help="serdi executable")
+ parser.add_argument("--wrapper", default="", help="executable wrapper")
+ if with_input:
+ parser.add_argument("input", help="input file")
+
+ return parser.parse_args(sys.argv[1:])
+
+
+def command_output(wrapper, command, stdin=None):
+ """Run a command and check that stdout matches the expected output."""
+
+ proc = subprocess.run(
+ shlex.split(wrapper) + command,
+ capture_output=True,
+ check=True,
+ encoding="utf-8",
+ input=stdin,
+ )
+
+ assert wrapper or not proc.stderr
+ return proc.stdout
+
+
def print_result_summary(results):
"""Print test result summary to stdout or stderr as appropriate."""
@@ -128,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_env.c b/test/test_env.c
index 1de075f3..bd55e47e 100644
--- a/test/test_env.c
+++ b/test/test_env.c
@@ -3,16 +3,19 @@
#undef NDEBUG
-#include "serd/serd.h"
+#include <serd/serd.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
+#define NS_EG "http://example.org/"
#define USTR(s) ((const uint8_t*)(s))
static SerdStatus
-count_prefixes(void* handle, const SerdNode* name, const SerdNode* uri)
+count_prefixes(void* const handle,
+ const SerdNode* const name,
+ const SerdNode* const uri)
{
(void)name;
(void)uri;
@@ -24,12 +27,11 @@ count_prefixes(void* handle, const SerdNode* name, const SerdNode* uri)
static void
test_env(void)
{
- SerdNode u = serd_node_from_string(SERD_URI, USTR("http://example.org/foo"));
- SerdNode b = serd_node_from_string(SERD_CURIE, USTR("invalid"));
- SerdNode c = serd_node_from_string(SERD_CURIE, USTR("eg.2:b"));
+ SerdNode u = serd_node_from_string(SERD_URI, USTR(NS_EG "foo"));
+ SerdNode b = serd_node_from_string(SERD_CURIE, USTR("invalid"));
+ SerdNode c = serd_node_from_string(SERD_CURIE, USTR("eg.2:b"));
SerdEnv* env = serd_env_new(NULL);
- serd_env_set_prefix_from_strings(
- env, USTR("eg.2"), USTR("http://example.org/"));
+ serd_env_set_prefix_from_strings(env, USTR("eg.2"), USTR(NS_EG ""));
assert(!serd_env_set_base_uri(env, NULL));
assert(serd_env_set_base_uri(env, &SERD_NODE_NULL));
@@ -39,7 +41,8 @@ test_env(void)
SerdChunk suffix;
assert(!serd_env_qualify(NULL, &u, &u, &suffix));
assert(serd_env_expand(NULL, &c, &prefix, &suffix));
- assert(serd_env_expand(env, &b, &prefix, &suffix));
+ assert(serd_env_expand(env, &b, &prefix, &suffix) == SERD_ERR_BAD_ARG);
+ assert(serd_env_expand(env, &u, &prefix, &suffix) == SERD_ERR_BAD_ARG);
SerdNode nxnode = serd_env_expand_node(NULL, &c);
assert(serd_node_equals(&nxnode, &SERD_NODE_NULL));
@@ -48,7 +51,7 @@ test_env(void)
assert(serd_node_equals(&xnode, &SERD_NODE_NULL));
SerdNode xu = serd_env_expand_node(env, &u);
- assert(!strcmp((const char*)xu.buf, "http://example.org/foo"));
+ assert(!strcmp((const char*)xu.buf, NS_EG "foo"));
serd_node_free(&xu);
SerdNode badpre = serd_node_from_string(SERD_CURIE, USTR("hm:what"));
@@ -56,7 +59,7 @@ test_env(void)
assert(serd_node_equals(&xbadpre, &SERD_NODE_NULL));
SerdNode xc = serd_env_expand_node(env, &c);
- assert(!strcmp((const char*)xc.buf, "http://example.org/b"));
+ assert(!strcmp((const char*)xc.buf, NS_EG "b"));
serd_node_free(&xc);
assert(serd_env_set_prefix(env, &SERD_NODE_NULL, &SERD_NODE_NULL));
@@ -71,8 +74,7 @@ test_env(void)
assert(serd_node_equals(&xblank, &SERD_NODE_NULL));
int n_prefixes = 0;
- serd_env_set_prefix_from_strings(
- env, USTR("eg.2"), USTR("http://example.org/"));
+ serd_env_set_prefix_from_strings(env, USTR("eg.2"), USTR(NS_EG));
serd_env_foreach(env, count_prefixes, &n_prefixes);
assert(n_prefixes == 1);
diff --git a/test/test_free_null.c b/test/test_free_null.c
index 96153c8d..2bc0b10c 100644
--- a/test/test_free_null.c
+++ b/test/test_free_null.c
@@ -3,7 +3,7 @@
#undef NDEBUG
-#include "serd/serd.h"
+#include <serd/serd.h>
#include <stddef.h>
diff --git a/test/test_node.c b/test/test_node.c
index f08363cb..c2fccf08 100644
--- a/test/test_node.c
+++ b/test/test_node.c
@@ -3,7 +3,7 @@
#undef NDEBUG
-#include "serd/serd.h"
+#include <serd/serd.h>
#include <assert.h>
#include <float.h>
@@ -24,7 +24,7 @@
#endif
static void
-test_strtod(double dbl, double max_delta)
+check_strtod(const double dbl, const double max_delta)
{
char buf[1024];
snprintf(buf, sizeof(buf), "%f", dbl);
@@ -42,15 +42,21 @@ test_string_to_double(void)
const double expt_test_nums[] = {
2.0E18, -5e19, +8e20, 2e+22, -5e-5, 8e0, 9e-0, 2e+0};
- const char* expt_test_strs[] = {
- "02e18", "-5e019", "+8e20", "2E+22", "-5E-5", "8E0", "9e-0", " 2e+0"};
+ const char* expt_test_strs[] = {"02e18",
+ "-5e019",
+ " +8e20",
+ "\f2E+22",
+ "\n-5E-5",
+ "\r8E0",
+ "\t9e-0",
+ "\v2e+0"};
for (size_t i = 0; i < sizeof(expt_test_nums) / sizeof(double); ++i) {
const double num = serd_strtod(expt_test_strs[i], NULL);
const double delta = fabs(num - expt_test_nums[i]);
assert(delta <= DBL_EPSILON);
- test_strtod(expt_test_nums[i], DBL_EPSILON);
+ check_strtod(expt_test_nums[i], DBL_EPSILON);
}
}
@@ -65,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",
@@ -117,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);
}
@@ -144,6 +151,58 @@ test_blob_to_node(void)
}
static void
+test_base64_decode(void)
+{
+ static const char* const decoded = "test";
+ static const size_t decoded_len = 4U;
+
+ // Test decoding clean base64
+ {
+ static const char* const encoded = "dGVzdA==";
+ static const size_t encoded_len = 8U;
+
+ size_t size = 0U;
+ void* const data =
+ serd_base64_decode((const uint8_t*)encoded, encoded_len, &size);
+
+ assert(data);
+ assert(size == decoded_len);
+ assert(!strncmp((const char*)data, decoded, decoded_len));
+ serd_free(data);
+ }
+
+ // Test decoding equivalent dirty base64 with ignored junk characters
+ {
+ static const char* const encoded = "d-G#V!z*d(A$%==";
+ static const size_t encoded_len = 13U;
+
+ size_t size = 0U;
+ void* const data =
+ serd_base64_decode((const uint8_t*)encoded, encoded_len, &size);
+
+ assert(data);
+ assert(size == decoded_len);
+ assert(!strncmp((const char*)data, decoded, decoded_len));
+ serd_free(data);
+ }
+
+ // Test decoding effectively nothing
+ {
+ static const char* const encoded = "@#$%";
+ static const size_t encoded_len = 4U;
+
+ size_t size = 0U;
+ void* const data =
+ serd_base64_decode((const uint8_t*)encoded, encoded_len, &size);
+
+ assert(data);
+ assert(!size);
+ // Contents of data are undefined
+ serd_free(data);
+ }
+}
+
+static void
test_node_equals(void)
{
const uint8_t replacement_char_str[] = {0xEF, 0xBF, 0xBD, 0};
@@ -176,6 +235,8 @@ test_node_from_string(void)
static void
test_node_from_substring(void)
{
+ static const uint8_t utf8_str[] = {'l', 0xC3, 0xB6, 'n', 'g', 0};
+
SerdNode empty = serd_node_from_substring(SERD_LITERAL, NULL, 32);
assert(!empty.buf && !empty.n_bytes && !empty.n_chars && !empty.flags &&
!empty.type);
@@ -187,6 +248,30 @@ test_node_from_substring(void)
a_b = serd_node_from_substring(SERD_LITERAL, USTR("a\"bc"), 10);
assert(a_b.n_bytes == 4 && a_b.n_chars == 4 && a_b.flags == SERD_HAS_QUOTE &&
!strncmp((const char*)a_b.buf, "a\"bc", 4));
+
+ SerdNode utf8 = serd_node_from_substring(SERD_LITERAL, utf8_str, 5);
+ assert(utf8.n_bytes == 5 && utf8.n_chars == 4 && !utf8.flags &&
+ !strncmp((const char*)utf8.buf, (const char*)utf8_str, 6));
+}
+
+static void
+test_uri_node_from_node(void)
+{
+ const SerdNode string = serd_node_from_string(SERD_LITERAL, USTR("s"));
+ SerdNode string_node = serd_node_new_uri_from_node(&string, NULL, NULL);
+ assert(!string_node.n_bytes);
+ serd_node_free(&string_node);
+
+ const SerdNode nouri = {NULL, 0U, 0U, 0U, SERD_URI};
+ SerdNode nouri_node = serd_node_new_uri_from_node(&nouri, NULL, NULL);
+ assert(!nouri_node.n_bytes);
+ serd_node_free(&nouri_node);
+
+ const SerdNode uri =
+ serd_node_from_string(SERD_URI, USTR("http://example.org/p"));
+ SerdNode uri_node = serd_node_new_uri_from_node(&uri, NULL, NULL);
+ assert(uri_node.n_bytes == 20U);
+ serd_node_free(&uri_node);
}
int
@@ -196,10 +281,10 @@ main(void)
test_double_to_node();
test_integer_to_node();
test_blob_to_node();
+ test_base64_decode();
test_node_equals();
test_node_from_string();
test_node_from_substring();
-
- printf("Success\n");
+ test_uri_node_from_node();
return 0;
}
diff --git a/test/test_quiet.py b/test/test_quiet.py
index 42d05785..ff53e26e 100755
--- a/test/test_quiet.py
+++ b/test/test_quiet.py
@@ -1,25 +1,23 @@
#!/usr/bin/env python3
-# Copyright 2022 David Robillard <d@drobilla.net>
+# Copyright 2022-2025 David Robillard <d@drobilla.net>
# SPDX-License-Identifier: ISC
-"""Test serdi quiet option."""
+"""Test quiet command-line option."""
-import argparse
-import sys
import shlex
import subprocess
-parser = argparse.ArgumentParser(description=__doc__)
+import serd_test_util as util
-parser.add_argument("--serdi", default="./serdi", help="path to serdi")
-parser.add_argument("--wrapper", default="", help="executable wrapper")
-parser.add_argument("input", help="invalid input file")
-
-args = parser.parse_args(sys.argv[1:])
+args = util.wrapper_args(__doc__, True)
command = shlex.split(args.wrapper) + [args.serdi, "-q", args.input]
proc = subprocess.run(
- command, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ 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
new file mode 100644
index 00000000..6c38e447
--- /dev/null
+++ b/test/test_reader.c
@@ -0,0 +1,429 @@
+// Copyright 2011-2024 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#undef NDEBUG
+
+#include <serd/serd.h>
+
+#ifdef _WIN32
+# include <windows.h>
+#endif
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define USTR(s) ((const uint8_t*)(s))
+
+typedef struct {
+ int n_base;
+ int n_prefix;
+ int n_statement;
+ int n_end;
+} ReaderTest;
+
+static SerdStatus
+base_sink(void* const handle, const SerdNode* const uri)
+{
+ (void)uri;
+
+ ReaderTest* const rt = (ReaderTest*)handle;
+ ++rt->n_base;
+ return SERD_SUCCESS;
+}
+
+static SerdStatus
+prefix_sink(void* const handle,
+ const SerdNode* const name,
+ const SerdNode* const uri)
+{
+ (void)name;
+ (void)uri;
+
+ ReaderTest* const rt = (ReaderTest*)handle;
+ ++rt->n_prefix;
+ return SERD_SUCCESS;
+}
+
+static SerdStatus
+statement_sink(void* const handle,
+ SerdStatementFlags flags,
+ const SerdNode* const graph,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object,
+ const SerdNode* const object_datatype,
+ const SerdNode* const object_lang)
+{
+ (void)flags;
+ (void)graph;
+ (void)subject;
+ (void)predicate;
+ (void)object;
+ (void)object_datatype;
+ (void)object_lang;
+
+ ReaderTest* const rt = (ReaderTest*)handle;
+ ++rt->n_statement;
+ return SERD_SUCCESS;
+}
+
+static SerdStatus
+end_sink(void* const handle, const SerdNode* const node)
+{
+ (void)node;
+
+ ReaderTest* const rt = (ReaderTest*)handle;
+ ++rt->n_end;
+ return SERD_SUCCESS;
+}
+
+static void
+test_read_string(void)
+{
+ ReaderTest rt = {0, 0, 0, 0};
+ SerdReader* const reader = serd_reader_new(
+ SERD_TURTLE, &rt, NULL, base_sink, prefix_sink, statement_sink, end_sink);
+
+ assert(reader);
+ assert(serd_reader_get_handle(reader) == &rt);
+
+ // Test reading a string that ends exactly at the end of input (no newline)
+ const SerdStatus st = serd_reader_read_string(
+ reader,
+ USTR("<http://example.org/s> <http://example.org/p> "
+ "<http://example.org/o> ."));
+
+ assert(!st);
+ assert(rt.n_base == 0);
+ assert(rt.n_prefix == 0);
+ assert(rt.n_statement == 1);
+ assert(rt.n_end == 0);
+
+ serd_reader_free(reader);
+}
+
+/// Reads a null byte after a statement, then succeeds again (like a socket)
+static size_t
+eof_test_read(void* const buf,
+ const size_t size,
+ const size_t nmemb,
+ void* const stream)
+{
+ assert(size == 1);
+ assert(nmemb == 1);
+ (void)size;
+
+ static const char* const string = "_:s1 <http://example.org/p> _:o1 .\n"
+ "_:s2 <http://example.org/p> _:o2 .\n";
+
+ size_t* const count = (size_t*)stream;
+
+ // Normal reading for the first statement
+ if (*count < 35) {
+ *(char*)buf = string[*count];
+ ++*count;
+ return nmemb;
+ }
+
+ // EOF for the first read at the start of the second statement
+ if (*count == 35) {
+ assert(string[*count] == '_');
+ ++*count;
+ return 0;
+ }
+
+ if (*count >= strlen(string)) {
+ return 0;
+ }
+
+ // Normal reading after the EOF, adjusting for the skipped index 35
+ *(char*)buf = string[*count - 1];
+ ++*count;
+ return nmemb;
+}
+
+static int
+eof_test_error(void* const stream)
+{
+ (void)stream;
+ return 0;
+}
+
+/// A read of a file stream hits EOF then fails to read chunks immediately
+static void
+test_read_eof_file(const char* const path)
+{
+ FILE* const f = fopen(path, "w+b");
+ assert(f);
+
+ fprintf(f, "_:s <http://example.org/p> _:o .\n");
+ fflush(f);
+ fseek(f, 0L, SEEK_SET);
+
+ ReaderTest rt = {0, 0, 0, 0};
+ SerdReader* const reader = serd_reader_new(
+ SERD_TURTLE, &rt, NULL, base_sink, prefix_sink, statement_sink, end_sink);
+
+ fseek(f, 0L, SEEK_SET);
+ serd_reader_start_stream(reader, f, (const uint8_t*)"test", true);
+ assert(serd_reader_read_chunk(reader) == SERD_SUCCESS);
+ assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
+ assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
+ serd_reader_end_stream(reader);
+
+ fseek(f, 0L, SEEK_SET);
+ serd_reader_start_stream(reader, f, (const uint8_t*)"test", false);
+ assert(serd_reader_read_chunk(reader) == SERD_SUCCESS);
+ assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
+ assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
+ serd_reader_end_stream(reader);
+
+ serd_reader_free(reader);
+ assert(!fclose(f));
+}
+
+// A byte-wise reader hits EOF once then continues (like a socket)
+static void
+test_read_eof_by_byte(void)
+{
+ ReaderTest rt = {0, 0, 0, 0};
+ SerdReader* const reader = serd_reader_new(
+ SERD_TURTLE, &rt, NULL, base_sink, prefix_sink, statement_sink, end_sink);
+
+ size_t n_reads = 0U;
+ serd_reader_start_source_stream(reader,
+ eof_test_read,
+ eof_test_error,
+ &n_reads,
+ (const uint8_t*)"test",
+ 1U);
+
+ assert(serd_reader_read_chunk(reader) == SERD_SUCCESS);
+ assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
+ assert(serd_reader_read_chunk(reader) == SERD_SUCCESS);
+ assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
+
+ serd_reader_end_stream(reader);
+ serd_reader_free(reader);
+}
+
+static void
+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
+
+ fprintf(f,
+ "<http://example.org/s> <http://example.org/p1> "
+ "<http://example.org/o1> .\n");
+
+ fprintf(f,
+ "<http://example.org/s> <http://example.org/p2> "
+ "<http://example.org/o2> .\n");
+
+ fwrite(&null, sizeof(null), 1, f);
+
+ fprintf(f,
+ "<http://example.org/s> <http://example.org/p3> "
+ "<http://example.org/o3> .");
+
+ fseek(f, 0, SEEK_SET);
+
+ ReaderTest rt = {0, 0, 0, 0};
+ SerdReader* const reader = serd_reader_new(
+ SERD_NQUADS, &rt, NULL, base_sink, prefix_sink, statement_sink, end_sink);
+
+ assert(reader);
+ assert(serd_reader_get_handle(reader) == &rt);
+ assert(f);
+
+ SerdStatus st = serd_reader_start_source_stream(
+ reader, (SerdSource)fread, (SerdStreamErrorFunc)ferror, f, NULL, 32U);
+
+ assert(st == SERD_SUCCESS);
+
+ // Read first statement
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_SUCCESS);
+ assert(rt.n_base == 0);
+ assert(rt.n_prefix == 0);
+ assert(rt.n_statement == 1);
+ assert(rt.n_end == 0);
+
+ // Read second statement
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_SUCCESS);
+ assert(rt.n_base == 0);
+ assert(rt.n_prefix == 0);
+ assert(rt.n_statement == 2);
+ assert(rt.n_end == 0);
+
+ // Read terminator
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_FAILURE);
+ assert(rt.n_base == 0);
+ assert(rt.n_prefix == 0);
+ assert(rt.n_statement == 2);
+ assert(rt.n_end == 0);
+
+ // Read last statement
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_SUCCESS);
+ assert(rt.n_base == 0);
+ assert(rt.n_prefix == 0);
+ assert(rt.n_statement == 3);
+ assert(rt.n_end == 0);
+
+ // EOF
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_FAILURE);
+ assert(rt.n_base == 0);
+ assert(rt.n_prefix == 0);
+ assert(rt.n_statement == 3);
+ assert(rt.n_end == 0);
+
+ assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
+ serd_reader_end_stream(reader);
+ serd_reader_free(reader);
+
+ assert(!fclose(f));
+ assert(!remove(path));
+}
+
+static void
+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");
+ fprintf(f, "@prefix eg: <http://example.org/> .\n");
+ fprintf(f, "eg:s eg:p1 eg:o1 ;\n");
+ fprintf(f, " eg:p2 eg:o2 .\n");
+ fwrite(&null, sizeof(null), 1, f);
+ fprintf(f, "eg:s eg:p [ eg:sp eg:so ] .");
+ fseek(f, 0, SEEK_SET);
+
+ ReaderTest rt = {0, 0, 0, 0};
+ SerdReader* const reader = serd_reader_new(
+ SERD_TURTLE, &rt, NULL, base_sink, prefix_sink, statement_sink, end_sink);
+
+ assert(reader);
+ assert(serd_reader_get_handle(reader) == &rt);
+ assert(f);
+
+ SerdStatus st = serd_reader_start_source_stream(
+ reader, (SerdSource)fread, (SerdStreamErrorFunc)ferror, f, NULL, 32U);
+ assert(st == SERD_SUCCESS);
+
+ // Read base
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_SUCCESS);
+ assert(rt.n_base == 1);
+ assert(rt.n_prefix == 0);
+ assert(rt.n_statement == 0);
+ assert(rt.n_end == 0);
+
+ // Read prefix
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_SUCCESS);
+ assert(rt.n_base == 1);
+ assert(rt.n_prefix == 1);
+ assert(rt.n_statement == 0);
+ assert(rt.n_end == 0);
+
+ // Read first two statements
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_SUCCESS);
+ assert(rt.n_base == 1);
+ assert(rt.n_prefix == 1);
+ assert(rt.n_statement == 2);
+ assert(rt.n_end == 0);
+
+ // Read terminator
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_FAILURE);
+ assert(rt.n_base == 1);
+ assert(rt.n_prefix == 1);
+ assert(rt.n_statement == 2);
+ assert(rt.n_end == 0);
+
+ // Read statements after null terminator
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_SUCCESS);
+ assert(rt.n_base == 1);
+ assert(rt.n_prefix == 1);
+ assert(rt.n_statement == 4);
+ assert(rt.n_end == 1);
+
+ // Read terminator
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_FAILURE);
+ assert(rt.n_base == 1);
+ assert(rt.n_prefix == 1);
+ assert(rt.n_statement == 4);
+ assert(rt.n_end == 1);
+
+ // EOF
+ st = serd_reader_read_chunk(reader);
+ assert(st == SERD_FAILURE);
+ assert(rt.n_base == 1);
+ assert(rt.n_prefix == 1);
+ assert(rt.n_statement == 4);
+ assert(rt.n_end == 1);
+
+ assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
+ serd_reader_end_stream(reader);
+ serd_reader_free(reader);
+ assert(!fclose(f));
+ assert(!remove(path));
+}
+
+int
+main(void)
+{
+#ifdef _WIN32
+ char tmp[MAX_PATH] = {0};
+ const size_t tmp_len = (size_t)GetTempPath(sizeof(tmp), tmp);
+#else
+ const char* const env_tmp = getenv("TMPDIR");
+ const char* const tmp = env_tmp ? env_tmp : "/tmp";
+ const size_t tmp_len = strlen(tmp);
+#endif
+
+ const char* const ttl_name = "serd_test_reader.ttl";
+ const char* const nq_name = "serd_test_reader.nq";
+ const size_t ttl_name_len = strlen(ttl_name);
+ 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] = '/';
+
+ memcpy(path + tmp_len + 1, nq_name, nq_name_len + 1);
+ test_read_nquads_chunks(path);
+
+ memcpy(path + tmp_len + 1, ttl_name, ttl_name_len + 1);
+ test_read_turtle_chunks(path);
+
+ test_read_string();
+ test_read_eof_file(path);
+ test_read_eof_by_byte();
+ assert(!remove(path));
+
+ free(path);
+ return 0;
+}
diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c
index cd7ca408..78123110 100644
--- a/test/test_reader_writer.c
+++ b/test/test_reader_writer.c
@@ -1,9 +1,9 @@
-// Copyright 2011-2023 David Robillard <d@drobilla.net>
+// Copyright 2011-2025 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
#undef NDEBUG
-#include "serd/serd.h"
+#include <serd/serd.h>
#ifdef _WIN32
# include <windows.h>
@@ -11,7 +11,6 @@
#include <assert.h>
#include <errno.h>
-#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -25,10 +24,7 @@ typedef struct {
} ErrorContext;
typedef struct {
- int n_base;
- int n_prefix;
int n_statement;
- int n_end;
const SerdNode* graph;
} ReaderTest;
@@ -41,6 +37,8 @@ static const char* const doc_string =
" \"lang\"@en ;\n"
" eg:p <http://example.com/o> .\n"
"}\n"
+ "@prefix other: <http://example.org/other> .\n"
+ "@base <http://drobilla.net/> .\n"
"eg:s\n"
" <http://example.org/p> [\n"
" eg:p 3.0 ,\n"
@@ -56,35 +54,14 @@ static const char* const doc_string =
"( eg:o ) eg:t eg:u .\n";
static SerdStatus
-test_base_sink(void* handle, const SerdNode* uri)
-{
- (void)uri;
-
- ReaderTest* rt = (ReaderTest*)handle;
- ++rt->n_base;
- return SERD_SUCCESS;
-}
-
-static SerdStatus
-test_prefix_sink(void* handle, const SerdNode* name, const SerdNode* uri)
-{
- (void)name;
- (void)uri;
-
- ReaderTest* rt = (ReaderTest*)handle;
- ++rt->n_prefix;
- return SERD_SUCCESS;
-}
-
-static SerdStatus
-test_statement_sink(void* handle,
- SerdStatementFlags flags,
- const SerdNode* graph,
- const SerdNode* subject,
- const SerdNode* predicate,
- const SerdNode* object,
- const SerdNode* object_datatype,
- const SerdNode* object_lang)
+test_statement_sink(void* const handle,
+ const SerdStatementFlags flags,
+ const SerdNode* const graph,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object,
+ const SerdNode* const object_datatype,
+ const SerdNode* const object_lang)
{
(void)flags;
(void)subject;
@@ -99,274 +76,6 @@ test_statement_sink(void* handle,
return SERD_SUCCESS;
}
-static SerdStatus
-test_end_sink(void* handle, const SerdNode* node)
-{
- (void)node;
-
- ReaderTest* rt = (ReaderTest*)handle;
- ++rt->n_end;
- return SERD_SUCCESS;
-}
-
-/// Reads a null byte after a statement, then succeeds again (like a socket)
-static size_t
-eof_test_read(void* buf, size_t size, size_t nmemb, void* stream)
-{
- assert(size == 1);
- assert(nmemb == 1);
- (void)size;
-
- static const char* const string = "_:s1 <http://example.org/p> _:o1 .\n"
- "_:s2 <http://example.org/p> _:o2 .\n";
-
- size_t* const count = (size_t*)stream;
-
- // Normal reading for the first statement
- if (*count < 35) {
- *(char*)buf = string[*count];
- ++*count;
- return nmemb;
- }
-
- // EOF for the first read at the start of the second statement
- if (*count == 35) {
- assert(string[*count] == '_');
- ++*count;
- return 0;
- }
-
- if (*count >= strlen(string)) {
- return 0;
- }
-
- // Normal reading after the EOF, adjusting for the skipped index 35
- *(char*)buf = string[*count - 1];
- ++*count;
- return nmemb;
-}
-
-static int
-eof_test_error(void* stream)
-{
- (void)stream;
- return 0;
-}
-
-static void
-test_read_nquads_chunks(const char* const path)
-{
- static const char null = 0;
-
- FILE* const f = fopen(path, "w+b");
-
- // Write two statements, a null separator, then another statement
-
- fprintf(f,
- "<http://example.org/s> <http://example.org/p1> "
- "<http://example.org/o1> .\n");
-
- fprintf(f,
- "<http://example.org/s> <http://example.org/p2> "
- "<http://example.org/o2> .\n");
-
- fwrite(&null, sizeof(null), 1, f);
-
- fprintf(f,
- "<http://example.org/s> <http://example.org/p3> "
- "<http://example.org/o3> .\n");
-
- fseek(f, 0, SEEK_SET);
-
- ReaderTest* const rt = (ReaderTest*)calloc(1, sizeof(ReaderTest));
- SerdReader* const reader = serd_reader_new(SERD_NQUADS,
- rt,
- free,
- test_base_sink,
- test_prefix_sink,
- test_statement_sink,
- test_end_sink);
-
- assert(reader);
- assert(serd_reader_get_handle(reader) == rt);
- assert(f);
-
- SerdStatus st = serd_reader_start_stream(reader, f, NULL, false);
- assert(st == SERD_SUCCESS);
-
- // Read first statement
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_SUCCESS);
- assert(rt->n_base == 0);
- assert(rt->n_prefix == 0);
- assert(rt->n_statement == 1);
- assert(rt->n_end == 0);
-
- // Read second statement
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_SUCCESS);
- assert(rt->n_base == 0);
- assert(rt->n_prefix == 0);
- assert(rt->n_statement == 2);
- assert(rt->n_end == 0);
-
- // Read terminator
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_FAILURE);
- assert(rt->n_base == 0);
- assert(rt->n_prefix == 0);
- assert(rt->n_statement == 2);
- assert(rt->n_end == 0);
-
- // Read last statement
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_SUCCESS);
- assert(rt->n_base == 0);
- assert(rt->n_prefix == 0);
- assert(rt->n_statement == 3);
- assert(rt->n_end == 0);
-
- // EOF
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_FAILURE);
- assert(rt->n_base == 0);
- assert(rt->n_prefix == 0);
- assert(rt->n_statement == 3);
- assert(rt->n_end == 0);
-
- assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
-
- serd_reader_free(reader);
- fclose(f);
- remove(path);
-}
-
-static void
-test_read_turtle_chunks(const char* const path)
-{
- static const char null = 0;
-
- FILE* const f = fopen(path, "w+b");
-
- // Write two statements separated by null characters
- fprintf(f, "@base <http://example.org/base/> .\n");
- fprintf(f, "@prefix eg: <http://example.org/> .\n");
- fprintf(f, "eg:s eg:p1 eg:o1 ;\n");
- fprintf(f, " eg:p2 eg:o2 .\n");
- fwrite(&null, sizeof(null), 1, f);
- fprintf(f, "eg:s eg:p [ eg:sp eg:so ] .\n");
- fwrite(&null, sizeof(null), 1, f);
- fseek(f, 0, SEEK_SET);
-
- ReaderTest* const rt = (ReaderTest*)calloc(1, sizeof(ReaderTest));
- SerdReader* const reader = serd_reader_new(SERD_TURTLE,
- rt,
- free,
- test_base_sink,
- test_prefix_sink,
- test_statement_sink,
- test_end_sink);
-
- assert(reader);
- assert(serd_reader_get_handle(reader) == rt);
- assert(f);
-
- SerdStatus st = serd_reader_start_stream(reader, f, NULL, false);
- assert(st == SERD_SUCCESS);
-
- // Read base
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_SUCCESS);
- assert(rt->n_base == 1);
- assert(rt->n_prefix == 0);
- assert(rt->n_statement == 0);
- assert(rt->n_end == 0);
-
- // Read prefix
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_SUCCESS);
- assert(rt->n_base == 1);
- assert(rt->n_prefix == 1);
- assert(rt->n_statement == 0);
- assert(rt->n_end == 0);
-
- // Read first two statements
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_SUCCESS);
- assert(rt->n_base == 1);
- assert(rt->n_prefix == 1);
- assert(rt->n_statement == 2);
- assert(rt->n_end == 0);
-
- // Read terminator
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_FAILURE);
- assert(rt->n_base == 1);
- assert(rt->n_prefix == 1);
- assert(rt->n_statement == 2);
- assert(rt->n_end == 0);
-
- // Read statements after null terminator
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_SUCCESS);
- assert(rt->n_base == 1);
- assert(rt->n_prefix == 1);
- assert(rt->n_statement == 4);
- assert(rt->n_end == 1);
-
- // Read terminator
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_FAILURE);
- assert(rt->n_base == 1);
- assert(rt->n_prefix == 1);
- assert(rt->n_statement == 4);
- assert(rt->n_end == 1);
-
- // EOF
- st = serd_reader_read_chunk(reader);
- assert(st == SERD_FAILURE);
- assert(rt->n_base == 1);
- assert(rt->n_prefix == 1);
- assert(rt->n_statement == 4);
- assert(rt->n_end == 1);
-
- assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
-
- serd_reader_free(reader);
- fclose(f);
- remove(path);
-}
-
-static void
-test_read_string(void)
-{
- ReaderTest* rt = (ReaderTest*)calloc(1, sizeof(ReaderTest));
- SerdReader* reader = serd_reader_new(SERD_TURTLE,
- rt,
- free,
- test_base_sink,
- test_prefix_sink,
- test_statement_sink,
- test_end_sink);
-
- assert(reader);
- assert(serd_reader_get_handle(reader) == rt);
-
- // Test reading a string that ends exactly at the end of input (no newline)
- const SerdStatus st = serd_reader_read_string(
- reader,
- USTR("<http://example.org/s> <http://example.org/p> "
- "<http://example.org/o> ."));
-
- assert(!st);
- assert(rt->n_base == 0);
- assert(rt->n_prefix == 0);
- assert(rt->n_statement == 1);
- assert(rt->n_end == 0);
-
- serd_reader_free(reader);
-}
-
static size_t
faulty_sink(const void* const buf, const size_t len, void* const stream)
{
@@ -394,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 SerdStatus st = rst ? rst : wst;
+ assert(st == expected_status);
+}
- const size_t max_offsets[] = {0, 386, 1911, 2003, 386};
+static void
+test_write_errors(void)
+{
+ // Syntax-keyed array of output document sizes
+ static const size_t max_offsets[] = {0, 452, 1911, 2003, 466};
- // 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);
}
}
}
@@ -437,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);
@@ -455,16 +182,21 @@ test_writer(const char* const path)
assert(serd_writer_end_anon(writer, NULL));
assert(serd_writer_get_env(writer) == env);
- uint8_t buf[] = {0x80, 0, 0, 0, 0};
- SerdNode s = serd_node_from_string(SERD_URI, USTR(""));
- SerdNode p = serd_node_from_string(SERD_URI, USTR("http://example.org/pred"));
- SerdNode o = serd_node_from_string(SERD_LITERAL, buf);
+ const uint8_t buf[] = {0x80, 0, 0, 0, 0};
- // Write 3 invalid statements (should write nothing)
+ 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"));
+
+ // 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) {
@@ -478,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},
@@ -510,61 +241,19 @@ 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, &nothing, 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);
- fclose(fd);
+ assert(!fclose(fd));
}
static void
-test_reader(const char* path)
+test_reader(const char* const path)
{
- ReaderTest* rt = (ReaderTest*)calloc(1, sizeof(ReaderTest));
- SerdReader* reader = serd_reader_new(SERD_TURTLE,
- rt,
- free,
- test_base_sink,
- test_prefix_sink,
- test_statement_sink,
- test_end_sink);
+ 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);
assert(reader);
assert(serd_reader_get_handle(reader) == rt);
@@ -590,44 +279,12 @@ test_reader(const char* path)
const SerdStatus st = serd_reader_read_file(reader, USTR(path));
assert(!st);
- assert(rt->n_base == 0);
- assert(rt->n_prefix == 0);
- assert(rt->n_statement == 13);
- assert(rt->n_end == 0);
+ assert(rt->n_statement == 12);
assert(rt->graph && rt->graph->buf &&
!strcmp((const char*)rt->graph->buf, "http://example.org/"));
assert(serd_reader_read_string(reader, USTR("This isn't Turtle at all.")));
- // A read of a big page hits EOF then fails to read chunks immediately
- {
- FILE* const in = fopen(path, "rb");
- serd_reader_start_stream(reader, in, (const uint8_t*)"test", true);
-
- assert(serd_reader_read_chunk(reader) == SERD_SUCCESS);
- assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
- assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
-
- serd_reader_end_stream(reader);
- fclose(in);
- }
-
- // A byte-wise reader that hits EOF once then continues (like a socket)
- {
- size_t n_reads = 0;
- serd_reader_start_source_stream(reader,
- (SerdSource)eof_test_read,
- (SerdStreamErrorFunc)eof_test_error,
- &n_reads,
- NULL,
- 1);
-
- assert(serd_reader_read_chunk(reader) == SERD_SUCCESS);
- assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
- assert(serd_reader_read_chunk(reader) == SERD_SUCCESS);
- assert(serd_reader_read_chunk(reader) == SERD_FAILURE);
- }
-
serd_reader_free(reader);
}
@@ -644,22 +301,15 @@ main(void)
#endif
const char* const ttl_name = "serd_test_reader_writer.ttl";
- const char* const nq_name = "serd_test_reader_writer.nq";
const size_t ttl_name_len = strlen(ttl_name);
- 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] = '/';
-
- memcpy(path + tmp_len + 1, nq_name, nq_name_len + 1);
- test_read_nquads_chunks(path);
-
memcpy(path + tmp_len + 1, ttl_name, ttl_name_len + 1);
- test_read_turtle_chunks(path);
- test_read_string();
test_write_errors();
test_writer(path);
@@ -668,6 +318,5 @@ main(void)
assert(!remove(path));
free(path);
- printf("Success\n");
return 0;
}
diff --git a/test/test_stdin.py b/test/test_stdin.py
index f976ca52..fb01f4ee 100755
--- a/test/test_stdin.py
+++ b/test/test_stdin.py
@@ -7,37 +7,14 @@
# pylint: disable=consider-using-f-string
-import argparse
-import sys
-import shlex
-import subprocess
-import tempfile
+import serd_test_util as util
-parser = argparse.ArgumentParser(description=__doc__)
+args = util.wrapper_args(__doc__)
+command = [args.serdi, "-i", "ntriples", "-", "http://example.org"]
-parser.add_argument("--serdi", default="./serdi", help="path to serdi")
-parser.add_argument("--wrapper", default="", help="executable wrapper")
+DOC = "<{0}s> <{0}p> <{0}o> .".format("http://example.org/")
-args = parser.parse_args(sys.argv[1:])
-command = shlex.split(args.wrapper) + [args.serdi, "-"]
+lines = util.command_output(args.wrapper, command, DOC).splitlines(True)
-DOCUMENT = "<{0}s> <{0}p> <{0}o> .".format("http://example.org/")
-
-with tempfile.TemporaryFile() as out:
- proc = subprocess.run(
- command,
- check=False,
- encoding="utf-8",
- input=DOCUMENT,
- stdout=out,
- stderr=subprocess.PIPE,
- )
-
- assert proc.returncode == 0
- assert args.wrapper or len(proc.stderr) == 0
-
- out.seek(0)
- lines = out.readlines()
-
- assert len(lines) == 1
- assert lines[0].decode("utf-8").strip() == DOCUMENT
+assert len(lines) == 1
+assert lines[0].strip() == DOC
diff --git a/test/test_string.c b/test/test_string.c
index 6767e5ae..86b5d19e 100644
--- a/test/test_string.c
+++ b/test/test_string.c
@@ -3,27 +3,38 @@
#undef NDEBUG
-#include "serd/serd.h"
+#include <serd/serd.h>
#include <assert.h>
#include <stdint.h>
-#include <stdio.h>
#include <string.h>
static void
+check_strlen(const char* const str,
+ const size_t expected_n_bytes,
+ const size_t expected_n_chars,
+ const SerdNodeFlags expected_flags)
+{
+ size_t n_bytes = 0U;
+ SerdNodeFlags flags = 0U;
+ const size_t n_chars = serd_strlen((const uint8_t*)str, &n_bytes, &flags);
+
+ assert(n_bytes == expected_n_bytes);
+ assert(n_chars == expected_n_chars);
+ assert(flags == expected_flags);
+}
+
+static void
test_strlen(void)
{
- const uint8_t str[] = {'"', '5', 0xE2, 0x82, 0xAC, '"', '\n', 0};
+ static const uint8_t utf8[] = {'"', '5', 0xE2, 0x82, 0xAC, '"', '\n', 0};
- size_t n_bytes = 0;
- SerdNodeFlags flags = 0;
- size_t len = serd_strlen(str, &n_bytes, &flags);
- assert(len == 5 && n_bytes == 7 &&
- flags == (SERD_HAS_QUOTE | SERD_HAS_NEWLINE));
- len = serd_strlen(str, NULL, &flags);
- assert(len == 5);
+ check_strlen("\"quotes\"", 8U, 8U, SERD_HAS_QUOTE);
+ check_strlen("newline\n", 8U, 8U, SERD_HAS_NEWLINE);
+ check_strlen("\rreturn", 7U, 7U, SERD_HAS_NEWLINE);
+ check_strlen((const char*)utf8, 7U, 5U, SERD_HAS_QUOTE | SERD_HAS_NEWLINE);
- assert(serd_strlen(str, &n_bytes, NULL) == 5);
+ assert(serd_strlen((const uint8_t*)"nulls", NULL, NULL) == 5U);
}
static void
@@ -45,7 +56,5 @@ main(void)
{
test_strlen();
test_strerror();
-
- printf("Success\n");
return 0;
}
diff --git a/test/test_uri.c b/test/test_uri.c
index cc81b40e..96fde600 100644
--- a/test/test_uri.c
+++ b/test/test_uri.c
@@ -3,12 +3,11 @@
#undef NDEBUG
-#include "serd/serd.h"
+#include <serd/serd.h>
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
-#include <stdio.h>
#include <string.h>
#define USTR(s) ((const uint8_t*)(s))
@@ -16,6 +15,8 @@
static void
test_uri_string_has_scheme(void)
{
+ assert(!serd_uri_string_has_scheme(NULL));
+
assert(!serd_uri_string_has_scheme(USTR("relative")));
assert(!serd_uri_string_has_scheme(USTR("http")));
assert(!serd_uri_string_has_scheme(USTR("5nostartdigit")));
@@ -35,11 +36,11 @@ test_uri_string_has_scheme(void)
}
static void
-test_file_uri(const char* const hostname,
- const char* const path,
- const bool escape,
- const char* const expected_uri,
- const char* expected_path)
+check_file_uri(const char* const hostname,
+ const char* const path,
+ const bool escape,
+ const char* const expected_uri,
+ const char* expected_path)
{
if (!expected_path) {
expected_path = path;
@@ -51,6 +52,7 @@ test_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));
@@ -67,38 +69,27 @@ test_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"));
+
+ 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__)
@@ -108,69 +99,81 @@ test_uri_to_path(void)
static void
test_uri_parsing(void)
{
- test_file_uri(NULL, "C:/My 100%", true, "file:///C:/My%20100%%", NULL);
- test_file_uri(NULL, "/foo/bar", true, "file:///foo/bar", NULL);
- test_file_uri("bhost", "/foo/bar", true, "file://bhost/foo/bar", NULL);
- test_file_uri(NULL, "a/relative path", false, "a/relative path", NULL);
- test_file_uri(
+ check_file_uri(NULL, "C:/My 100%", true, "file:///C:/My%20100%%", NULL);
+ check_file_uri(NULL, "/foo/bar", true, "file:///foo/bar", NULL);
+ check_file_uri("bhost", "/foo/bar", true, "file://bhost/foo/bar", NULL);
+ check_file_uri(NULL, "a/relative path", false, "a/relative path", NULL);
+ check_file_uri(
NULL, "a/relative <path>", true, "a/relative%20%3Cpath%3E", NULL);
#ifdef _WIN32
- test_file_uri(
+ check_file_uri(
NULL, "C:\\My 100%", true, "file:///C:/My%20100%%", "C:/My 100%");
- test_file_uri(NULL,
- "\\drive\\relative",
- true,
- "file:///drive/relative",
- "/drive/relative");
-
- test_file_uri(NULL,
- "C:\\Program Files\\Serd",
- true,
- "file:///C:/Program%20Files/Serd",
- "C:/Program Files/Serd");
-
- test_file_uri("ahost",
- "C:\\Pointless Space",
- true,
- "file://ahost/C:/Pointless%20Space",
- "C:/Pointless Space");
+ check_file_uri(NULL,
+ "\\drive\\relative",
+ true,
+ "file:///drive/relative",
+ "/drive/relative");
+
+ check_file_uri(NULL,
+ "C:\\Program Files\\Serd",
+ true,
+ "file:///C:/Program%20Files/Serd",
+ "C:/Program Files/Serd");
+
+ check_file_uri("ahost",
+ "C:\\Pointless Space",
+ true,
+ "file://ahost/C:/Pointless%20Space",
+ "C:/Pointless Space");
#else
/* What happens with Windows paths on other platforms is a bit weird, but
more or less unavoidable. It doesn't work to interpret backslashes as
path separators on any other platform. */
- test_file_uri("ahost",
- "C:\\Pointless Space",
- true,
- "file://ahost/C:%5CPointless%20Space",
- "/C:\\Pointless Space");
-
- test_file_uri(NULL,
- "\\drive\\relative",
- true,
- "%5Cdrive%5Crelative",
- "\\drive\\relative");
-
- test_file_uri(NULL,
- "C:\\Program Files\\Serd",
- true,
- "file:///C:%5CProgram%20Files%5CSerd",
- "/C:\\Program Files\\Serd");
-
- test_file_uri("ahost",
- "C:\\Pointless Space",
- true,
- "file://ahost/C:%5CPointless%20Space",
- "/C:\\Pointless Space");
+ check_file_uri("ahost",
+ "C:\\Pointless Space",
+ true,
+ "file://ahost/C:%5CPointless%20Space",
+ "/C:\\Pointless Space");
+
+ check_file_uri(NULL,
+ "\\drive\\relative",
+ true,
+ "%5Cdrive%5Crelative",
+ "\\drive\\relative");
+
+ check_file_uri(NULL,
+ "C:\\Program Files\\Serd",
+ true,
+ "file:///C:%5CProgram%20Files%5CSerd",
+ "/C:\\Program Files\\Serd");
+
+ check_file_uri("ahost",
+ "C:\\Pointless Space",
+ true,
+ "file://ahost/C:%5CPointless%20Space",
+ "/C:\\Pointless Space");
#endif
+ // Test tolerance of NULL hostname parameter
+ 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* out_path = serd_file_uri_parse(USTR("file:///foo/%0Xbar"), NULL);
- assert(!strcmp((const char*)out_path, "/foo/bar"));
- serd_free(out_path);
+ 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);
}
static void
@@ -194,8 +197,8 @@ test_uri_from_string(void)
serd_node_free(&base);
}
-static inline bool
-chunk_equals(const SerdChunk* a, const SerdChunk* b)
+static bool
+chunk_equals(const SerdChunk* const a, const SerdChunk* const b)
{
return (!a->len && !b->len && !a->buf && !b->buf) ||
(a->len && b->len && a->buf && b->buf &&
@@ -343,6 +346,22 @@ test_relative_uri(void)
"http://example.org/a/b/c",
"http://example.org/a/b",
"http://example.org/a");
+
+ // Tolerance of NULL URI output parameter
+ {
+ SerdURI uri = SERD_URI_NULL;
+ assert(!serd_uri_parse(USTR("http://example.org/path"), &uri));
+
+ SerdURI base = SERD_URI_NULL;
+ assert(!serd_uri_parse(USTR("http://example.org/"), &base));
+
+ SerdNode result_node = serd_node_new_relative_uri(&uri, &base, NULL, NULL);
+
+ assert(result_node.n_bytes == 4U);
+ assert(!strcmp((const char*)result_node.buf, "path"));
+
+ serd_node_free(&result_node);
+ }
}
int
@@ -353,7 +372,5 @@ main(void)
test_uri_parsing();
test_uri_from_string();
test_relative_uri();
-
- printf("Success\n");
return 0;
}
diff --git a/test/test_write_error.py b/test/test_write_error.py
index 35fde232..93b0249a 100755
--- a/test/test_write_error.py
+++ b/test/test_write_error.py
@@ -1,33 +1,32 @@
#!/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."""
-import argparse
import sys
import shlex
import subprocess
import os
-parser = argparse.ArgumentParser(description=__doc__)
+import serd_test_util as util
-parser.add_argument("--serdi", default="./serdi", help="path to serdi")
-parser.add_argument("--wrapper", default="", help="executable wrapper")
-parser.add_argument("input", help="valid input file")
-
-args = parser.parse_args(sys.argv[1:])
+args = util.wrapper_args(__doc__, True)
command = shlex.split(args.wrapper) + [args.serdi, args.input]
if os.path.exists("/dev/full"):
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 b02aba7e..51f5d9ed 100644
--- a/test/test_writer.c
+++ b/test/test_writer.c
@@ -1,15 +1,17 @@
-// Copyright 2011-2023 David Robillard <d@drobilla.net>
+// Copyright 2011-2025 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
#undef NDEBUG
-#include "serd/serd.h"
+#include <serd/serd.h>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
+#define NS_EG "http://example.org/"
+
#define USTR(s) ((const uint8_t*)(s))
static void
@@ -19,27 +21,27 @@ 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("http://example.org/s"));
- SerdNode p = serd_node_from_string(SERD_URI, USTR("http://example.org/p"));
+ SerdNode s = serd_node_from_string(SERD_URI, USTR(NS_EG "s"));
+ SerdNode p = serd_node_from_string(SERD_URI, USTR(NS_EG "p"));
SerdNode o =
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
@@ -49,19 +51,18 @@ 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("http://example.org/s0"));
- SerdNode p0 = serd_node_from_string(SERD_URI, USTR("http://example.org/p0"));
+ SerdNode s0 = serd_node_from_string(SERD_URI, USTR(NS_EG "s0"));
+ SerdNode p0 = serd_node_from_string(SERD_URI, USTR(NS_EG "p0"));
SerdNode b0 = serd_node_from_string(SERD_BLANK, USTR("b0"));
- SerdNode p1 = serd_node_from_string(SERD_URI, USTR("http://example.org/p1"));
+ SerdNode p1 = serd_node_from_string(SERD_URI, USTR(NS_EG "p1"));
SerdNode b1 = serd_node_from_string(SERD_BLANK, USTR("b1"));
- SerdNode p2 = serd_node_from_string(SERD_URI, USTR("http://example.org/p2"));
- SerdNode o2 = serd_node_from_string(SERD_URI, USTR("http://example.org/o2"));
- SerdNode p3 = serd_node_from_string(SERD_URI, USTR("http://example.org/p3"));
- SerdNode p4 = serd_node_from_string(SERD_URI, USTR("http://example.org/p4"));
- SerdNode o4 = serd_node_from_string(SERD_URI, USTR("http://example.org/o4"));
+ SerdNode p2 = serd_node_from_string(SERD_URI, USTR(NS_EG "p2"));
+ SerdNode o2 = serd_node_from_string(SERD_URI, USTR(NS_EG "o2"));
+ SerdNode p3 = serd_node_from_string(SERD_URI, USTR(NS_EG "p3"));
+ SerdNode p4 = serd_node_from_string(SERD_URI, USTR(NS_EG "p4"));
+ SerdNode o4 = serd_node_from_string(SERD_URI, USTR(NS_EG "o4"));
SerdNode nil = serd_node_from_string(
SERD_URI, USTR("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"));
@@ -94,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"
@@ -110,9 +107,13 @@ test_write_nested_anon(void)
"\t\t<http://example.org/p4> <http://example.org/o4>\n"
"\t] .\n";
- fprintf(stderr, "%s\n", out);
+ 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
@@ -131,10 +132,13 @@ 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("http://example.org/s"));
- SerdNode p = serd_node_from_string(SERD_URI, USTR("http://example.org/p"));
- SerdNode o = serd_node_from_string(SERD_BLANK, USTR("http://example.org/o"));
+ SerdNode s = serd_node_from_string(SERD_URI, USTR(NS_EG "s"));
+ SerdNode p = serd_node_from_string(SERD_URI, USTR(NS_EG "p"));
+
+ char o_buf[12] = {'b', '0', '\0'};
+ SerdNode o = serd_node_from_string(SERD_BLANK, USTR(o_buf));
st = serd_writer_write_statement(
writer, SERD_ANON_O_BEGIN, NULL, &s, &p, &o, NULL, NULL);
@@ -142,23 +146,33 @@ test_writer_cleanup(void)
assert(!st);
// Write the start of several nested anonymous objects
- for (unsigned i = 0U; !st && i < 8U; ++i) {
- char buf[12] = {0};
- snprintf(buf, sizeof(buf), "b%u", i);
+ for (unsigned i = 1U; !st && i < 9U; ++i) {
+ char next_o_buf[12] = {'\0'};
+ snprintf(next_o_buf, sizeof(next_o_buf), "b%u", i);
+
+ SerdNode next_o = serd_node_from_string(SERD_BLANK, USTR(next_o_buf));
- SerdNode next_o = serd_node_from_string(SERD_BLANK, USTR(buf));
+ st = serd_writer_write_statement(writer,
+ SERD_ANON_O_BEGIN | SERD_ANON_CONT,
+ NULL,
+ &o,
+ &p,
+ &next_o,
+ NULL,
+ NULL);
- st = serd_writer_write_statement(
- writer, SERD_ANON_O_BEGIN, NULL, &o, &p, &next_o, NULL, NULL);
+ assert(!st);
- o = next_o;
+ memcpy(o_buf, next_o_buf, sizeof(o_buf));
}
// Finish writing without terminating nodes
- assert(!(st = serd_writer_finish(writer)));
+ st = serd_writer_finish(writer);
+ assert(!st);
// Set the base to an empty URI
- assert(!(st = serd_writer_set_base_uri(writer, NULL)));
+ st = serd_writer_set_base_uri(writer, NULL);
+ assert(!st);
// Free (which could leak if the writer doesn't clean up the stack properly)
serd_writer_free(writer);
@@ -166,22 +180,49 @@ test_writer_cleanup(void)
}
static void
-test_strict_write(void)
+test_write_bad_anon_stack(void)
{
- const char* const path = "serd_strict_write_test.ttl";
- FILE* const fd = fopen(path, "wb");
- assert(fd);
+ SerdStatus st = SERD_SUCCESS;
+ 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"));
+ SerdNode b0 = serd_node_from_string(SERD_BLANK, USTR("b0"));
+ SerdNode b1 = serd_node_from_string(SERD_BLANK, USTR("b1"));
+ SerdNode b2 = serd_node_from_string(SERD_BLANK, USTR("b2"));
+
+ st = serd_writer_write_statement(
+ writer, SERD_ANON_O_BEGIN, NULL, &s, &p, &b0, NULL, NULL);
+ assert(!st);
+
+ // (missing call to end the anonymous node here)
+
+ st = serd_writer_write_statement(
+ writer, SERD_ANON_O_BEGIN, NULL, &b1, &p, &b2, NULL, NULL);
+ assert(st == SERD_ERR_BAD_ARG);
+
+ st = serd_writer_finish(writer);
+ assert(!st);
+ serd_writer_free(writer);
+ serd_env_free(env);
+}
+
+static void
+test_strict_write(void)
+{
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};
- 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 s = serd_node_from_string(SERD_URI, USTR(NS_EG "s"));
+ SerdNode p = serd_node_from_string(SERD_URI, USTR(NS_EG "p"));
SerdNode bad_lit = serd_node_from_string(SERD_LITERAL, bad_str);
SerdNode bad_uri = serd_node_from_string(SERD_URI, bad_str);
@@ -194,8 +235,6 @@ test_strict_write(void)
serd_writer_free(writer);
serd_env_free(env);
- fclose(fd);
- remove(path);
}
// Produce a write error without setting errno
@@ -211,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);
}
@@ -233,8 +382,14 @@ main(void)
test_write_long_literal();
test_write_nested_anon();
test_writer_cleanup();
+ test_write_bad_anon_stack();
test_strict_write();
test_write_error();
+ test_chunk_sink();
+ test_write_nothing_node();
+ test_write_bad_statement();
return 0;
}
+
+#undef NS_EG