yamlet-1.0.0.0: tests/Yamlet/Test/Decode/SyntaxErrors.hs
module Yamlet.Test.Decode.SyntaxErrors
( syntaxErrorTests
) where
import Control.Monad
import Data.Text qualified as T
import Test.Tasty
import Test.Tasty.HUnit
import Yamlet
import Yamlet.Syntax qualified as S
import Yamlet.Test.Helpers
syntaxErrorTests :: TestTree
syntaxErrorTests =
testGroup
"syntax errors"
[ testCase "syntax" test_syntaxErrors
, testCase "directives and tags" test_directiveErrors
]
test_syntaxErrors :: Assertion
test_syntaxErrors = do
let check :: String -> (Int, Int, String) -> T.Text -> Assertion
check preface expected input =
assertEqual
preface
(Just expected)
(errorOf (decodeAllText @Value input))
check
"bad indentation"
(3, 2, "unexpected indentation")
"a:\n b: 1\n c: 2\n"
check
"indicator at the indentation of a key"
(3, 3, "unexpected '@', a plain scalar cannot start with it, quote the value")
"dependencies:\n typescript: ^5.0.0\n @types/node: ^20.0.0\n"
check
"indicator on an indented first line"
(1, 3, "unexpected '@', a plain scalar cannot start with it, quote the value")
" @b: c\n"
check
"bracket at the indentation of a list item"
(3, 3, "unexpected ']'")
"a:\n - b\n ]\n"
-- The BOM at the start of the input is not content of the first line.
forM_
[
( "colon in an alias"
,
( 1
, 3
, "the name of the alias includes the ':', write a space before ':' if the alias is a key"
)
, "*x: 1"
)
,
( "properties on their own line"
,
( 1
, 1
, "an anchor or a tag cannot be on a line of its own here, write it after the key or the '-'"
)
, "&a &b"
)
, ("tab before a key", (1, 1, "tabs cannot be used for indentation"), "\tx: y")
,
( "mapping on the start marker line"
, (1, 6, "unexpected ':', a mapping cannot start on the line of '---'")
, "--- a: b"
)
, ("key among list items", (2, 1, "unexpected key among list items"), "- a\nb: 1")
, ("list item without a space", (2, 2, "expected a space after '-'"), "- a\n-b")
]
$ \(preface, expected, input) -> do
check
preface
expected
input
check
(preface ++ " after a BOM")
expected
("\xFEFF" <> input)
check
"line after a comment below a plain scalar"
(3, 3, "a comment ends a plain scalar, so this line cannot continue it")
"a: x\n# c\n y\n"
forM_
[ ("literal scalar", 4, "a: |\n x\n# c\n y\n")
, ("single-quoted scalar", 3, "a: 'x'\n# c\n y\n")
, ("flow sequence", 3, "a: [x]\n# c\n y\n")
, ("alias", 3, "a: *x\n# c\n y\n")
]
$ \(node, line, input) ->
check
("line after a comment below a " ++ node)
(line, 3, "unexpected indentation")
input
forM_
[ ("double-quoted scalar", 2, "a: \"x #y\"\n b\n")
, ("single-quoted scalar", 2, "a: 'see #3'\n b\n")
, ("quoted scalar in a flow sequence", 2, "a: [x, \"y #z\"]\n b\n")
, ("multi-line quoted scalar", 3, "a: \"x\n y #z\"\n b\n")
]
$ \(node, line, input) ->
check
("line below a '#' in a " ++ node)
(line, 3, "unexpected indentation")
input
check
"line after a comment with a quote"
(2, 3, "a comment ends a plain scalar, so this line cannot continue it")
"a: x # it's\n b\n"
forM_
[ ("list item", "- # c\nfoo\n")
, ("list item with an anchor", "- &x # c\nfoo\n")
, ("list item with a tag", "- !t # c\nfoo\n")
]
$ \(node, input) ->
check
("line after a comment on an empty " ++ node)
(2, 1, "unexpected value among list items")
input
check
"line after a comment below the header of a block scalar"
( 3
, 3
, "unexpected indentation, the line has less indentation than the block scalar above it"
)
"a: |\n# c\n y\n"
check
"mapping in a plain scalar"
(1, 11, "unexpected ':', quote the value if it contains \": \"")
"key: value: other\n"
check
"content after a quoted value"
(1, 14, "unexpected 't' after the end of a quoted scalar")
"key: \"value\" trailing\n"
check
"content after a flow value"
(1, 12, "unexpected 'i' after the end of a flow collection")
"x: { y: z }in: valid\n"
check
"letter beyond ASCII"
(1, 4, "unexpected 'é' after the end of a flow collection")
"[a]é\n"
check
"character that cannot be shown"
(1, 4, "unexpected U+200B after the end of a flow collection")
"[a]\x200B\n"
check
"comment line in a plain scalar"
(3, 3, "a comment ends a plain scalar, so this line cannot continue it")
"key: word1\n# xxx\n word2\n"
check
"comment at the end of a line of a plain scalar"
(2, 1, "a comment ends a plain scalar, so this line cannot continue it")
"word1 # comment\nword2\n"
check
"directive after a comment"
( 3
, 1
, "unexpected '%', a directive needs '...' on a line above it to end the document"
)
"---\nscalar1 # comment\n%YAML 1.2\n---\nscalar2\n"
check
"directive after a mapping"
( 2
, 1
, "unexpected '%', a directive needs '...' on a line above it to end the document"
)
"a: 1\n%YAML 1.2\n---\nb: 2\n"
check
"percent sign at the start of a line in a flow sequence"
(2, 1, "unexpected '%', a plain scalar cannot start with it, quote the value")
"[a,\n%x]\n"
check
"anchor on its own line in a sequence"
( 2
, 1
, "an anchor or a tag cannot be on a line of its own here, write it after the key or the '-'"
)
"- item1\n&node\n- item2\n"
check
"tag on its own line after a key"
( 2
, 1
, "an anchor or a tag cannot be on a line of its own here, write it after the key or the '-'"
)
"key: &x\n!!map\n a: b\n"
check
"flow key on two lines"
(2, 2, "unexpected ':', a key must be on a single line")
"[23\n]: 42\n"
check
"quoted key on two lines"
(2, 3, "a key must be on a single line")
"a: 1\n\"c\n d\": 1\n"
check
"mapping on the line of the document marker"
(1, 9, "unexpected ':', a mapping cannot start on the line of '---'")
"--- key1: value1\n key2: value2\n"
check
"key indented under a value"
( 2
, 4
, "unexpected ':', this line continues the scalar from the line above, check the indentation and the line above"
)
"a: 1\n b: 2\n"
check
"missing closing quote"
(1, 7, "unterminated double-quoted scalar")
"name: \"abc\nnext: value\n"
check
"badly indented quoted line"
(2, 1, "invalid indentation of a line in a single-quoted scalar")
"name: 'abc\nnext'\n"
check
"missing closing quote before a quoted value"
(1, 7, "unterminated double-quoted scalar")
"name: \"web\nimage: \"nginx:1.25\"\n"
check
"missing closing quote before a single-quoted value"
(1, 7, "unterminated single-quoted scalar")
"name: 'web\nimage: 'nginx:1.25'\n"
check
"badly indented quoted line before the closing quote"
(2, 1, "invalid indentation of a line in a double-quoted scalar")
"key: \"first line\nsecond line\nthird line\"\n"
check
"badly indented quoted line before an escaped quote"
(2, 1, "invalid indentation of a line in a double-quoted scalar")
"key: \"first\nsay \\\"hi\\\" now\"\n"
check
"badly indented quoted line before a doubled quote"
(2, 1, "invalid indentation of a line in a single-quoted scalar")
"key: 'first\nit''s here'\n"
check
"missing colon"
(2, 4, "expected ':' after the key")
"a: 1\nb 2\nc: 3\n"
check
"missing colon in a list item"
(2, 8, "expected ':' after the key")
"- key: value\n other\n"
check
"missing colon before a comment"
(2, 10, "expected ':' after the key")
"name: x\nport 8080 # default\n"
check
"missing colon after a key before a comment"
(2, 5, "expected ':' after the key")
"name: x\nport # default\n"
check
"missing colon after a quoted key with a colon"
(2, 7, "expected ':' after the key")
"a: 1\n\"b: 2\"\n"
check
"missing colon after a key with an escaped quote"
(2, 10, "expected ':' after the key")
"a: 1\n\"b\\\"c: d\"\n"
check
"unterminated quoted key with a colon"
(2, 1, "unterminated double-quoted scalar")
"a: 1\n\"b: 2\n"
check
"unterminated single-quoted key"
(3, 3, "unterminated single-quoted scalar")
"env:\n NAME: x\n 'it''s\n"
check
"missing space after a colon"
(2, 3, "expected a space after ':'")
"a: 1\nb:2\n"
check
"line that has its colon"
(2, 5, "expected an alias name after '*'")
"a: 1\nb: *\n"
check
"anchor without a name"
(1, 5, "expected an anchor name after '&'")
"a: & 1\n"
check
"alias with an anchor"
(2, 7, "unexpected '*', an alias cannot have an anchor or a tag")
"a: &x 1\nb: &y *x\n"
check
"alias with a tag in a flow sequence"
(1, 11, "unexpected '*', an alias cannot have an anchor or a tag")
"[&x a, !t *x]\n"
check
"colon after an alias"
( 2
, 3
, "the name of the alias includes the ':', write a space before ':' if the alias is a key"
)
"a: &x 1\n*x: 2\n"
forM_ [("flow mapping", "{*a: b}\n"), ("flow sequence", "[*a: b]\n")] $ \(node, input) ->
check
("colon after an alias in a " ++ node)
( 1
, 4
, "the name of the alias includes the ':', write a space before ':' if the alias is a key"
)
input
check
"alias without a name in a flow sequence"
(1, 2, "expected an alias name after '*'")
"[*, a]\n"
check
"tab indentation"
(2, 1, "tabs cannot be used for indentation")
"a:\n\tb: 1\n"
check
"tab after spaces before a key"
(2, 3, "tabs cannot be used for indentation")
"a:\n \tb: c\n"
check
"tab before a scalar continuation"
(2, 1, "tabs cannot be used for indentation")
"a: 1\n\t@\n"
-- A space in place of the tab fails too, but the indentation of the line
-- above does not.
check
"tab before a second key"
(3, 1, "tabs cannot be used for indentation")
"a:\n b: 1\n\tc: 2\n"
check
"tab before a second item"
(3, 1, "tabs cannot be used for indentation")
"a:\n - 1\n\t- 2\n"
check
"tab below a comment"
(5, 1, "tabs cannot be used for indentation")
"a:\n b: 1\n # c\n\n\tc: 2\n"
check
"tab on a blank line of a block scalar"
(3, 1, "tabs cannot be used for indentation")
"a: |\n x\n\t\n y\n"
check
"tab before a comment below a block scalar"
(3, 1, "tabs cannot be used for indentation")
"a: |\n x\n\t# c\nb: 1\n"
check
"tab on a blank line of a plain scalar"
(2, 1, "tabs cannot be used for indentation")
"a: b\n\t\n c\n"
check
"tab on a blank line above a line indented too much"
(3, 3, "unexpected indentation")
"a: 1\n\t\n b: 2\n"
check
"tab after a list item indicator"
(3, 3, "tabs cannot be used for indentation")
"x:\n- a\n- \tb: c\n"
check
"tab right after a list item indicator"
(1, 2, "tabs cannot be used for indentation")
"-\tname: x\n"
check
"tab after an explicit key indicator"
(2, 3, "tabs cannot be used for indentation")
"x: 1\n? \ta: b\n"
check
"tab after a value indicator"
(2, 2, "tabs cannot be used for indentation")
"? a\n:\tb: c\n"
-- With a space in place of the tab, the parser fails at the same place.
check
"tab before a list after a key"
(1, 6, "unexpected '-', a list cannot start on the line of its key")
"key:\t- a\n"
-- With spaces in place of the tab, the parser fails at the same place.
check
"tab before an indicator"
(1, 2, "unexpected '@', a plain scalar cannot start with it, quote the value")
"\t@\n"
check
"tab before a bracket"
(1, 2, "unexpected ']'")
"\t]\n"
check
"tab after an end marker"
(3, 2, "unexpected '@', a plain scalar cannot start with it, quote the value")
"a\n...\n\t@\n"
check
"content after spaces after an end marker"
(2, 7, "unexpected content after the document end marker (...)")
"--- a\n... x\n"
check
"unterminated string"
(1, 6, "unterminated double-quoted scalar")
"key: \"abc\n"
check
"flow sequence before a key"
(1, 6, "unterminated flow sequence")
"key: [a, b\nc: d\n"
check
"flow sequence at the end"
(1, 6, "unterminated flow sequence")
"key: [a, b\n"
check
"flow sequence before a comment"
(1, 6, "unterminated flow sequence")
"key: [a, b # c\nd: e\n"
check
"flow sequence before a key with a flow sequence"
(1, 6, "unterminated flow sequence")
"key: [a, b\nc: [d]\n"
check
"flow sequence on a line indented too little"
(2, 1, "the line is indented too little to continue the flow sequence")
"a: [b,\nc]\n"
check
"flow mapping on lines indented too little"
(2, 1, "the line is indented too little to continue the flow mapping")
"a: {x: 1,\ny: 2,\n z: 3}\n"
check
"closing bracket indented too little"
(4, 1, "']' is indented too little to end the flow sequence")
"key: [\n a,\n b\n]\n"
check
"closing brace after a comment line"
(3, 1, "'}' is indented too little to end the flow mapping")
"key: {\n # c\n}\n"
check
"tab in a flow sequence"
(2, 1, "tabs cannot be used for indentation")
"a: [\n\tb\n]\n"
check
"tab in a double-quoted scalar"
(2, 1, "tabs cannot be used for indentation")
"a: \"x\n\ty\"\n"
check
"tab after a blank line in a single-quoted scalar"
(3, 1, "tabs cannot be used for indentation")
"a: 'x\n\n\ty'\n"
check
"tab on a blank line of a double-quoted scalar"
(2, 1, "tabs cannot be used for indentation")
"a: \"x\n\t\n y\"\n"
check
"block scalar in a flow sequence"
(1, 2, "unexpected '|', a block scalar cannot be inside a flow collection")
"[|\n x\n]\n"
check
"block scalar indicator after a quoted scalar"
(1, 8, "unexpected '|' after the end of a quoted scalar")
"a: 'x' |\n"
check
"block scalar indicator after a flow collection"
(1, 8, "unexpected '|' after the end of a flow collection")
"a: [x] |\n"
check
"block scalar indicator at the start of a line"
(2, 1, "unexpected '|'")
"a: b\n| x\n"
check
"dash in a flow sequence"
( 1
, 2
, "unexpected '-', a list item cannot be inside a flow collection, quote '-' if it is a string"
)
"[-]\n"
check
"empty flow entry"
(1, 4, "unexpected ',', a flow collection cannot have an empty entry")
"[1,,2]\n"
check
"content after a flow sequence"
(1, 14, "expected ',' or ']'")
"key: [a, \"b\" c]\n"
check
"flow mapping at the end"
(1, 1, "unterminated flow mapping")
"{\"a\": 1,\n \"b\": 2\n"
check
"flow mapping before a marker"
(1, 1, "unterminated flow mapping")
"{a: 1\n---\nb\n"
check
"start marker in a double-quoted scalar"
(2, 1, "unexpected '---' in a double-quoted scalar, indent the line")
"a: \"x\n---\n y\"\n"
check
"end marker in a single-quoted scalar"
(2, 1, "unexpected '...' in a single-quoted scalar, indent the line")
"a: 'x\n...\n y'\n"
check
"start marker in a flow sequence"
(2, 1, "unexpected '---' in a flow sequence, indent the line")
"a: [x,\n---\n y]\n"
check
"end marker in a flow mapping"
(2, 1, "unexpected '...' in a flow mapping, indent the line")
"a: {x: 1,\n...\n y: 2}\n"
check
"flow sequence before a document with its own"
(1, 7, "unterminated flow sequence")
"args: [a, b\n---\nargs: [c]\n"
check
"flow mapping before a document with its own"
(1, 7, "unterminated flow mapping")
"args: {a: b\n---\nx: {c: d}\n"
forM_
[ ("flow sequence", "flow sequence", "a: [x, y\nb: a]b\n")
, ("flow mapping", "flow mapping", "a: {x: 1\nb: a}b\n")
, ("flow sequence before a document", "flow sequence", "a: [x,\n---\nb: a]b\n")
]
$ \(name, node, input) ->
check
(name ++ " with a bracket in a plain scalar below")
(1, 4, "unterminated " ++ node)
input
check
"double-quoted scalar before a document with its own"
(1, 7, "unterminated double-quoted scalar")
"name: \"web\n---\nname: \"db\"\n"
check
"single-quoted scalar before a document with its own"
(1, 7, "unterminated single-quoted scalar")
"name: 'web\n---\nname: 'it''s'\n"
check
"single-quoted scalar before a document with a quote in a plain scalar"
(1, 4, "unterminated single-quoted scalar")
"a: 'oops\n---\nb: it's here\n"
check
"escaped quote after a marker"
(2, 1, "unexpected '---' in a double-quoted scalar, indent the line")
"a: \"x\n---\n y \\\"z\"\n"
check
"start marker after a missing quote"
(1, 4, "unterminated double-quoted scalar")
"a: \"x\n---\nb: c\n"
check
"missing colon in a flow mapping"
(1, 6, "expected ':', ',' or '}'")
"{\"a\" 1}"
check
"missing comma after a value"
(1, 12, "expected ',' or '}'")
"{\"a\": 1 \"b\": 2}"
check
"quote in a single-quoted scalar"
(1, 10, "unexpected 's' after a single-quoted scalar, write '' for a quote inside it")
"msg: 'it's here'\n"
check
"quote in a tag"
(1, 6, "unexpected '!'")
"&b !'!str ' x '\n"
check
"quote in a double-quoted scalar"
( 1
, 12
, "unexpected 'h' after a double-quoted scalar, write \\\" for a quote inside it"
)
"msg: \"say \"hi\"\"\n"
check
"quote in a quoted scalar in a flow sequence"
( 1
, 5
, "unexpected 'b' after a double-quoted scalar, write \\\" for a quote inside it"
)
"[\"a\"b]\n"
check
"comment after a quote"
(1, 7, "unexpected '#', a comment needs a space before it")
"a: \"x\"#c\n"
check
"comment after a flow sequence"
(1, 7, "unexpected '#', a comment needs a space before it")
"a: [1]#c\n"
check
"reserved indicator"
(1, 7, "unexpected '@', a plain scalar cannot start with it, quote the value")
"user: @admin\n"
check
"reserved indicator in a flow sequence"
(1, 5, "unexpected '`', a plain scalar cannot start with it, quote the value")
"[a, `b`]\n"
check
"key among indented list items after a comment"
(5, 3, "unexpected key among list items")
"a:\n - x\n\n # c\n b: 1\n"
check
"explicit key among list items"
(2, 1, "unexpected key among list items")
"- a\n? b\n"
check
"value among indented list items"
(3, 3, "unexpected value among list items")
"a:\n - x\n y\n"
check
"list item among keys"
(3, 3, "unexpected list item among mapping entries")
"a:\n b: 1\n - x\n"
check
"list item among top keys"
(2, 1, "unexpected list item among mapping entries")
"a: 1\n- b\n"
check
"brace after a list item"
(2, 1, "unexpected '}'")
"- a\n}\n"
check
"text after a block scalar header"
(1, 6, "the content of a block scalar starts on the next line")
"s: | text\n"
check
"zero indentation indicator"
(1, 5, "the indentation indicator of a block scalar must be from 1 to 9")
"s: |0\n x\n"
check
"long key"
(1, 1103, "a key can be at most 1024 characters long, write a longer key after '? '")
("\"" <> T.replicate 1100 "k" <> "\": 1\n")
check
"long flow mapping as a key"
(1, 1106, "a key can be at most 1024 characters long, write a longer key after '? '")
("{a: " <> T.replicate 1100 "k" <> "}: 1\n")
check
"spaces after a key count toward its length"
(1, 1026, "a key can be at most 1024 characters long, write a longer key after '? '")
("a" <> T.replicate 1024 " " <> ": 1\n")
check
"spaces after a key in a flow sequence"
(1, 1029, "a key can be at most 1024 characters long, write a longer key after '? '")
("['a'" <> T.replicate 1024 " " <> ": 1]\n")
check
"long key in a flow sequence"
(1, 1030, "a key can be at most 1024 characters long, write a longer key after '? '")
("[a, " <> T.replicate 1025 "k" <> ": v]\n")
check
"list on the line of its anchor"
(1, 9, "unexpected '-', a list cannot start on the line of its anchor or tag")
"&anchor - sequence entry\n"
check
"list on the line of its key"
(1, 4, "unexpected '-', a list cannot start on the line of its key")
"a: - b\n"
check
"list on the line of a start marker"
(1, 5, "unexpected '-', a list cannot start on the line of '---'")
"--- - a\n"
check
"line of a block scalar"
( 3
, 3
, "unexpected indentation, the line has less indentation than the block scalar above it"
)
"s: >- # folded\n line1\n line2\n"
check
"invalid escape"
(1, 8, "invalid escape sequence, write \\\\ for a backslash or use single quotes")
"key: \"a\\qb\"\n"
check
"Windows path"
(1, 10, "invalid escape sequence, write \\\\ for a backslash or use single quotes")
"path: \"C:\\Users\\me\"\n"
check
"undefined alias"
(2, 4, "undefined alias *x")
"a: 1\nb: *x\n"
check
"invalid character"
(1, 4, "invalid character U+0001")
"a: \x01\n"
check
"backslash at the end of the input"
(1, 4, "unterminated double-quoted scalar")
"a: \"b\\"
check
"backslash at the end of a key"
(1, 2, "unterminated double-quoted scalar")
"[\"a\\"
check
"noncharacter U+FFFE"
(1, 4, "invalid character U+FFFE")
"a: \xFFFE\n"
check
"noncharacter U+FFFF"
(1, 5, "invalid character U+FFFF")
"a: b\xFFFF\n"
check
"delete in a plain scalar"
(1, 5, "invalid character U+007F")
"a: x\DELy\n"
check
"delete at the start of a line"
(1, 1, "invalid character U+007F")
"\DEL\n"
check
"C1 control character in a comment"
(1, 9, "invalid character U+0080")
"a: b # c\x80\n"
check
"C1 control character in a tag"
(1, 6, "invalid character U+0080")
"a: !x\x80 1\n"
check
"noncharacter in a block scalar"
(2, 4, "invalid character U+FFFF")
"a: |\n x\xFFFF\n"
check
"C1 control character after a quoted one"
(2, 4, "invalid character U+0080")
"- \"\x80\"\n- b\x80\n"
check
"byte order mark before a C1 control character"
(1, 5, "unexpected byte order mark")
"a: x\xFEFF\x80\n"
test_directiveErrors :: Assertion
test_directiveErrors = do
let check :: String -> (Int, Int, String) -> T.Text -> Assertion
check preface expected input =
assertEqual
preface
(Just expected)
(errorOf (decodeAllText @Value input))
check
"undefined tag handle"
(1, 1, "undefined tag handle !e!")
"!e!foo bar\n"
check
"unsupported version"
(1, 1, "unsupported YAML version 2.0")
"%YAML 2.0\n--- a\n"
check
"version without a minor number"
(1, 7, "expected a version such as 1.2 after %YAML")
"%YAML 1\n--- a\n"
check
"content after the version"
(1, 11, "unexpected content after the %YAML version")
"%YAML 1.2 x\n--- a\n"
check
"tag directive without a prefix"
(1, 9, "expected a prefix after the tag handle, e.g. tag:example.com,2000:")
"%TAG !e!\n--- a\n"
check
"invalid tag handle"
(1, 6, "invalid tag handle")
"%TAG e tag:x,2000:\n--- a\n"
check
"tag handle without its closing !"
(1, 6, "invalid tag handle")
"%TAG !e tag:x,2000:\n--- a\n"
check
"tag handle with an invalid character"
(1, 6, "invalid tag handle")
"%TAG !e_x! tag:x,2000:\n--- a\n"
check
"tag handle before the prefix without a space"
(1, 9, "expected a space after the tag handle")
"%TAG !e!tag:x,2000:\n--- a\n"
check
"version beyond the limit"
(1, 1, "unsupported YAML version")
"%YAML 1000001.2\n--- a\n"
check
"minor version beyond the limit"
(1, 1, "unsupported YAML version")
"%YAML 1.1000001\n--- a\n"
check
"version beyond Int"
(1, 1, "unsupported YAML version")
"%YAML 18446744073709551617.2\n--- a\n"
check
"minor version beyond Int"
(1, 1, "unsupported YAML version")
("%YAML 1." <> T.replicate 100000 "9" <> "\n--- a\n")
assertEqual
"minor version at the limit"
(Right [Just (S.YamlVersion 1 1000000)])
(map (.version) <$> S.parseDocumentsText "%YAML 1.1000000\n--- a\n")
assertEqual
"version with leading zeros"
(Right [Just (S.YamlVersion 1 2)])
(map (.version) <$> S.parseDocumentsText "%YAML 001.0002\n--- a\n")
check
"verbatim tag without a name"
(1, 1, "invalid verbatim tag")
"!<!> a\n"
check
"verbatim tag without a scheme"
(1, 1, "invalid verbatim tag")
"!<$:?> a\n"
check
"empty verbatim tag"
(1, 1, "invalid verbatim tag")
"!<> a\n"
let badEscape = "invalid escape in the tag, write '%' and two hexadecimal digits"
check
"escape without digits in a tag"
(1, 6, badEscape)
"x: !a%zz b\n"
check
"escape with one digit in a tag"
(1, 6, badEscape)
"x: !a%4 b\n"
check
"escape without digits in a tag prefix"
(1, 8, badEscape)
"%TAG ! %\xE9\n--- a\n"
check
"secondary handle without a suffix"
(1, 6, "expected the rest of the tag after !!")
"a: !! z\n"
check
"invalid UTF-8 in a tag"
(1, 1, "the escapes of the tag are not valid UTF-8")
"!!str%FF a\n"
assertEqual
"character from the escapes of the prefix and the suffix"
(Right ["tag:\xE9"])
$ map (\d -> case d.root.props.tag of S.Tag t -> t; _ -> "")
<$> S.parseDocumentsText "%TAG !e! tag:%C3\n--- !e!%A9 a\n"
assertEqual
"valid verbatim tags"
(Right ["!bar", "tag:yaml.org,2002:str"])
(map valueTag <$> decodeText @[Value] "[!<!bar> a, !<tag:yaml.org,2002:str> b]")
assertEqual
"escapes of verbatim tags"
(Right ["!foo!", "tag:example.com,2000:\xE9"])
$ map valueTag
<$> decodeText @[Value] "[!<!foo%21> a, !<tag:example.com,2000:%C3%A9> b]"
check
"invalid UTF-8 in a verbatim tag"
(1, 1, "the escapes of the tag are not valid UTF-8")
"!<!a%FF> b\n"