package urn

import (
	"fmt"
	"strconv"
	"strings"
)

func ierror(index int) string {
	return "Test case num. " + strconv.Itoa(index+1)
}

func herror(index int, test testCase) string {
	return ierror(index) + ", input \"" + string(test.in) + "\""
}

func rxpad(str string, lim int) string {
	str = str + strings.Repeat(" ", lim)
	return str[:lim]
}

type testCase struct {
	in     []byte // the input
	ok     bool   // whether it is valid or not
	obj    *URN   // a pointer to the resulting urn.URN instance
	str    string // string representation
	norm   string // norm string representation
	estr   string // error string
	isSCIM bool   // whether it is a SCIM URN or not
}

var urnlexTestCases = []testCase{
	// Italian act
	{
		[]byte("urn:lex:it:stato:legge:2003-09-21;456"),
		true,
		&URN{
			prefix: "urn",
			ID:     "lex",
			SS:     "it:stato:legge:2003-09-21;456",
		},
		"urn:lex:it:stato:legge:2003-09-21;456",
		"urn:lex:it:stato:legge:2003-09-21;456",
		"",
		false,
	},
	// French act
	{
		[]byte("urn:lex:fr:etat:lois:2004-12-06;321"),
		true,
		&URN{
			prefix: "urn",
			ID:     "lex",
			SS:     "fr:etat:lois:2004-12-06;321",
		},
		"urn:lex:fr:etat:lois:2004-12-06;321",
		"urn:lex:fr:etat:lois:2004-12-06;321",
		"",
		false,
	},
	// Spanish act
	{
		[]byte("urn:lex:es:estado:ley:2002-07-12;123"),
		true,
		&URN{
			prefix: "urn",
			ID:     "lex",
			SS:     "es:estado:ley:2002-07-12;123",
		},
		"urn:lex:es:estado:ley:2002-07-12;123",
		"urn:lex:es:estado:ley:2002-07-12;123",
		"",
		false,
	},
	// Glarus Swiss Canton decree
	{
		[]byte("urn:lex:ch;glarus:regiere:erlass:2007-10-15;963"),
		true,
		&URN{
			prefix: "urn",
			ID:     "lex",
			SS:     "ch;glarus:regiere:erlass:2007-10-15;963",
		},
		"urn:lex:ch;glarus:regiere:erlass:2007-10-15;963",
		"urn:lex:ch;glarus:regiere:erlass:2007-10-15;963",
		"",
		false,
	},
	// EU Council Directive
	{
		[]byte("urn:lex:eu:council:directive:2010-03-09;2010-19-UE"),
		true,
		&URN{
			prefix: "urn",
			ID:     "lex",
			SS:     "eu:council:directive:2010-03-09;2010-19-UE",
		},
		"urn:lex:eu:council:directive:2010-03-09;2010-19-UE",
		"urn:lex:eu:council:directive:2010-03-09;2010-19-UE",
		"",
		false,
	},
	{
		[]byte("urn:lex:eu:council:directive:2010-03-09;2010-19-UE"),
		true,
		&URN{
			prefix: "urn",
			ID:     "lex",
			SS:     "eu:council:directive:2010-03-09;2010-19-UE",
		},
		"urn:lex:eu:council:directive:2010-03-09;2010-19-UE",
		"urn:lex:eu:council:directive:2010-03-09;2010-19-UE",
		"",
		false,
	},
	// US FSC decision
	{
		[]byte("urn:lex:us:federal.supreme.court:decision:1963-03-18;372.us.335"),
		true,
		&URN{
			prefix: "urn",
			ID:     "lex",
			SS:     "us:federal.supreme.court:decision:1963-03-18;372.us.335",
		},
		"urn:lex:us:federal.supreme.court:decision:1963-03-18;372.us.335",
		"urn:lex:us:federal.supreme.court:decision:1963-03-18;372.us.335",
		"",
		false,
	},
}

var scimOnlyTestCases = []testCase{
	// ok
	{
		[]byte("urn:ietf:params:scim:schemas:core:2.0:User"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ietf:params:scim",
			SS:     "schemas:core:2.0:User",
		},
		"urn:ietf:params:scim:schemas:core:2.0:User",
		"urn:ietf:params:scim:schemas:core:2.0:User",
		"",
		true,
	},
	{
		[]byte("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ietf:params:scim",
			SS:     "schemas:extension:enterprise:2.0:User",
		},
		"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
		"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
		"",
		true,
	},
	{
		[]byte("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:userName"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ietf:params:scim",
			SS:     "schemas:extension:enterprise:2.0:User:userName",
		},
		"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:userName",
		"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:userName",
		"",
		true,
	},
	{
		[]byte("urn:ietf:params:scim:api:messages:2.0:ListResponse"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ietf:params:scim",
			SS:     "api:messages:2.0:ListResponse",
		},
		"urn:ietf:params:scim:api:messages:2.0:ListResponse",
		"urn:ietf:params:scim:api:messages:2.0:ListResponse",
		"",
		true,
	},
	{
		[]byte("urn:ietf:params:scim:schemas:core"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ietf:params:scim",
			SS:     "schemas:core",
		},
		"urn:ietf:params:scim:schemas:core",
		"urn:ietf:params:scim:schemas:core",
		"",
		true,
	},
	{
		[]byte("urn:ietf:params:scim:param:core"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ietf:params:scim",
			SS:     "param:core",
		},
		"urn:ietf:params:scim:param:core",
		"urn:ietf:params:scim:param:core",
		"",
		true,
	},
	{
		[]byte("urn:ietf:params:scim:api:messages:%FF"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ietf:params:scim",
			SS:     "api:messages:%FF",
		},
		"urn:ietf:params:scim:api:messages:%FF",
		"urn:ietf:params:scim:api:messages:%ff",
		"",
		true,
	},

	// no
	{
		[]byte("arn:ietf:params:scim:schemas:core"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 0),
		false,
	},
	{
		[]byte("usn:ietf:params:scim:schemas:core"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 1),
		false,
	},
	{
		[]byte("urm:ietf:params:scim:schemas:core"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 2),
		false,
	},
	{
		[]byte("urno:ietf:params:scim:schemas:core"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 3),
		false,
	},
	{
		[]byte("urno"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 3),
		false,
	},
	{
		[]byte("urn:WRONG:schemas:core"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMNamespace, 4),
		false,
	},
	{
		[]byte("urn:ietf:params:scim:WRONG:core"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMType, 21),
		false,
	},
	{
		[]byte("urn:ietf:params:scim:schemas:$"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMName, 29),
		false,
	},
	{
		[]byte("urn:ietf:params:scim:schemas:core-"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMName, 33),
		false,
	},
	{
		[]byte("urn:ietf:params:scim:schemas:core:"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMOtherIncomplete, 33),
		false,
	},
	{
		[]byte("urn:ietf:params:scim:schemas:core:2.&"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMOther, 36),
		false,
	},
	{
		[]byte("urn:ietf:params:scim:api:messages:%"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMOtherIncomplete, 34),
		false,
	},
	{
		[]byte("urn:ietf:params:scim:api:messages:%F"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMOtherIncomplete, 35),
		false,
	},
	// TODO: verify
	// {
	// 	[]byte("urn:ietf:params:scim:api:core:"),
	// 	true,
	// 	nil,
	// 	"",
	// 	"",
	// 	fmt.Sprintf(errSCIMOtherIncomplete, 29),
	// 	false,
	// },
	{
		[]byte("urn:"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMNamespace, 4),
		false,
	},
	{
		[]byte("urn::"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMNamespace, 4),
		false,
	},
	{
		[]byte("urn:a:"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMNamespace, 4),
		false,
	},
	{
		[]byte("urn:a"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSCIMNamespace, 4),
		false,
	},
	{
		[]byte(`u`),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 1),
		false,
	},
	{
		[]byte(`ur`),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 2),
		false,
	},
	{
		[]byte(`urn`),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 3),
		false,
	},
}

var urn2141OnlyTestCases = []testCase{
	// ok
	{
		[]byte("urn:simple:simple"),
		true,
		&URN{
			prefix: "urn",
			ID:     "simple",
			SS:     "simple",
		},
		"urn:simple:simple",
		"urn:simple:simple",
		"",
		false,
	},
	{
		[]byte("urn:ciao:%5D"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     "%5D",
		},
		"urn:ciao:%5D",
		"urn:ciao:%5d",
		"",
		false,
	},

	// ok - RFC examples
	{
		[]byte("URN:foo:a123,456"),
		true,
		&URN{
			prefix: "URN",
			ID:     "foo",
			SS:     "a123,456",
		},
		"URN:foo:a123,456",
		"urn:foo:a123,456",
		"",
		false,
	},
	{
		[]byte("urn:foo:a123,456"),
		true,
		&URN{
			prefix: "urn",
			ID:     "foo",
			SS:     "a123,456",
		},
		"urn:foo:a123,456",
		"urn:foo:a123,456",
		"",
		false,
	},
	{
		[]byte("urn:FOO:a123,456"),
		true,
		&URN{
			prefix: "urn",
			ID:     "FOO",
			SS:     "a123,456",
		},
		"urn:FOO:a123,456",
		"urn:foo:a123,456",
		"",
		false,
	},
	{
		[]byte("urn:foo:A123,456"),
		true,
		&URN{
			prefix: "urn",
			ID:     "foo",
			SS:     "A123,456",
		},
		"urn:foo:A123,456",
		"urn:foo:A123,456",
		"",
		false,
	},
	{
		[]byte("urn:foo:a123%2C456"),
		true,
		&URN{
			prefix: "urn",
			ID:     "foo",
			SS:     "a123%2C456",
		},
		"urn:foo:a123%2C456",
		"urn:foo:a123%2c456",
		"",
		false,
	},
	{
		[]byte("URN:FOO:a123%2c456"),
		true,
		&URN{
			prefix: "URN",
			ID:     "FOO",
			SS:     "a123%2c456",
		},
		"URN:FOO:a123%2c456",
		"urn:foo:a123%2c456",
		"",
		false,
	},
	{
		[]byte("URN:FOO:ABC%FFabc123%2c456"),
		true,
		&URN{
			prefix: "URN",
			ID:     "FOO",
			SS:     "ABC%FFabc123%2c456",
		},
		"URN:FOO:ABC%FFabc123%2c456",
		"urn:foo:ABC%ffabc123%2c456",
		"",
		false,
	},
	{
		[]byte("URN:FOO:ABC%FFabc123%2C456%9A"),
		true,
		&URN{
			prefix: "URN",
			ID:     "FOO",
			SS:     "ABC%FFabc123%2C456%9A",
		},
		"URN:FOO:ABC%FFabc123%2C456%9A",
		"urn:foo:ABC%ffabc123%2c456%9a",
		"",
		false,
	},

	// ok - SCIM v2
	{
		[]byte("urn:ietf:params:scim:schemas:core:2.0:User"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ietf",
			SS:     "params:scim:schemas:core:2.0:User",
		},
		"urn:ietf:params:scim:schemas:core:2.0:User",
		"urn:ietf:params:scim:schemas:core:2.0:User",
		"",
		true,
	},
	{
		[]byte("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ietf",
			SS:     "params:scim:schemas:extension:enterprise:2.0:User",
		},
		"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
		"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
		"",
		true,
	},
	{
		[]byte("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:userName"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ietf",
			SS:     "params:scim:schemas:extension:enterprise:2.0:User:userName",
		},
		"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:userName",
		"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:userName",
		"",
		true,
	},
	{
		[]byte("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:meta.lastModified"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ietf",
			SS:     "params:scim:schemas:extension:enterprise:2.0:User:meta.lastModified",
		},
		"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:meta.lastModified",
		"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:meta.lastModified",
		"",
		true,
	},

	// ok - minimum urn
	{
		[]byte("urn:a:b"),
		true,
		&URN{
			prefix: "urn",
			ID:     "a",
			SS:     "b",
		},
		"urn:a:b",
		"urn:a:b",
		"",
		false,
	},
	{
		[]byte("urn:a::"),
		true,
		&URN{
			prefix: "urn",
			ID:     "a",
			SS:     ":",
		},
		"urn:a::",
		"urn:a::",
		"",
		false,
	},
	{
		[]byte("urn:a:-"),
		true,
		&URN{
			prefix: "urn",
			ID:     "a",
			SS:     "-",
		},
		"urn:a:-",
		"urn:a:-",
		"",
		false,
	},

	// ok - URN prefix is case-insensitive
	{
		[]byte("URN:simple:simple"),
		true,
		&URN{
			prefix: "URN",
			ID:     "simple",
			SS:     "simple",
		},
		"URN:simple:simple",
		"urn:simple:simple",
		"",
		false,
	},
	{
		[]byte("Urn:simple:simple"),
		true,
		&URN{
			prefix: "Urn",
			ID:     "simple",
			SS:     "simple",
		},
		"Urn:simple:simple",
		"urn:simple:simple",
		"",
		false,
	},

	// ok - ID can contain the "urn" string but it can not be exactly equal to it
	{
		[]byte("urn:urna:simple"),
		true,
		&URN{
			prefix: "urn",
			ID:     "urna",
			SS:     "simple",
		},
		"urn:urna:simple",
		"urn:urna:simple",
		"",
		false,
	},
	{
		[]byte("urn:burnout:nss"),
		true,
		&URN{
			prefix: "urn",
			ID:     "burnout",
			SS:     "nss",
		},
		"urn:burnout:nss",
		"urn:burnout:nss",
		"",
		false,
	},
	{
		[]byte("urn:burn:nss"),
		true,
		&URN{
			prefix: "urn",
			ID:     "burn",
			SS:     "nss",
		},
		"urn:burn:nss",
		"urn:burn:nss",
		"",
		false,
	},
	{
		[]byte("urn:urnurnurn:x"),
		true,
		&URN{
			prefix: "urn",
			ID:     "urnurnurn",
			SS:     "x",
		},
		"urn:urnurnurn:x",
		"urn:urnurnurn:x",
		"",
		false,
	},

	// ok - ID can contains maximum 32 characters
	{
		[]byte("urn:abcdefghilmnopqrstuvzabcdefghilm:x"),
		true,
		&URN{
			prefix: "urn",
			ID:     "abcdefghilmnopqrstuvzabcdefghilm",
			SS:     "x",
		},
		"urn:abcdefghilmnopqrstuvzabcdefghilm:x",
		"urn:abcdefghilmnopqrstuvzabcdefghilm:x",
		"",
		false,
	},

	// ok - ID can be alpha numeric
	{
		[]byte("URN:123:x"),
		true,
		&URN{
			prefix: "URN",
			ID:     "123",
			SS:     "x",
		},
		"URN:123:x",
		"urn:123:x",
		"",
		false,
	},
	{
		[]byte("URN:1ab:x"),
		true,
		&URN{
			prefix: "URN",
			ID:     "1ab",
			SS:     "x",
		},
		"URN:1ab:x",
		"urn:1ab:x",
		"",
		false,
	},
	{
		[]byte("URN:a1b:x"),
		true,
		&URN{
			prefix: "URN",
			ID:     "a1b",
			SS:     "x",
		},
		"URN:a1b:x",
		"urn:a1b:x",
		"",
		false,
	},
	{
		[]byte("URN:a12:x"),
		true,
		&URN{
			prefix: "URN",
			ID:     "a12",
			SS:     "x",
		},
		"URN:a12:x",
		"urn:a12:x",
		"",
		false,
	},
	{
		[]byte("URN:cd2:x"),
		true,
		&URN{
			prefix: "URN",
			ID:     "cd2",
			SS:     "x",
		},
		"URN:cd2:x",
		"urn:cd2:x",
		"",
		false,
	},

	// ok - ID can contain an hyphen (not in its first position, see below)
	{
		[]byte("URN:abcd-:x"),
		true,
		&URN{
			prefix: "URN",
			ID:     "abcd-",
			SS:     "x",
		},
		"URN:abcd-:x",
		"urn:abcd-:x",
		"",
		false,
	},
	{
		[]byte("URN:abcd-abcd:x"),
		true,
		&URN{
			prefix: "URN",
			ID:     "abcd-abcd",
			SS:     "x",
		},
		"URN:abcd-abcd:x",
		"urn:abcd-abcd:x",
		"",
		false,
	},
	{
		[]byte("URN:a123-456z:x"),
		true,
		&URN{
			prefix: "URN",
			ID:     "a123-456z",
			SS:     "x",
		},
		"URN:a123-456z:x",
		"urn:a123-456z:x",
		"",
		false,
	},

	// ok - SS can contain the "urn" string, also be exactly equal to it
	{
		[]byte("urn:urnx:urn"),
		true,
		&URN{
			prefix: "urn",
			ID:     "urnx",
			SS:     "urn",
		},
		"urn:urnx:urn",
		"urn:urnx:urn",
		"",
		false,
	},
	{
		[]byte("urn:urnurnurn:urn"),
		true,
		&URN{
			prefix: "urn",
			ID:     "urnurnurn",
			SS:     "urn",
		},
		"urn:urnurnurn:urn",
		"urn:urnurnurn:urn",
		"",
		false,
	},
	{
		[]byte("urn:hey:urnurnurn"),
		true,
		&URN{
			prefix: "urn",
			ID:     "hey",
			SS:     "urnurnurn",
		},
		"urn:hey:urnurnurn",
		"urn:hey:urnurnurn",
		"",
		false,
	},

	// ok - SS can contains and discerns multiple colons, also at the end
	{
		[]byte("urn:ciao:a:b:c"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     "a:b:c",
		},
		"urn:ciao:a:b:c",
		"urn:ciao:a:b:c",
		"",
		false,
	},
	{
		[]byte("urn:aaa:x:y:"),
		true,
		&URN{
			prefix: "urn",
			ID:     "aaa",
			SS:     "x:y:",
		},
		"urn:aaa:x:y:",
		"urn:aaa:x:y:",
		"",
		false,
	},
	{
		[]byte("urn:aaa:x:y:"),
		true,
		&URN{
			prefix: "urn",
			ID:     "aaa",
			SS:     "x:y:",
		},
		"urn:aaa:x:y:",
		"urn:aaa:x:y:",
		"",
		false,
	},

	// ok - SS can contain (and also start with) some non-alphabetical (ie., OTHER) characters
	{
		[]byte("urn:ciao:-"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     "-",
		},
		"urn:ciao:-",
		"urn:ciao:-",
		"",
		false,
	},
	{
		[]byte("urn:ciao:("),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     "(",
		},
		"urn:ciao:(",
		"urn:ciao:(",
		"",
		false,
	},
	{
		[]byte("urn:ciao:)"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     ")",
		},
		"urn:ciao:)",
		"urn:ciao:)",
		"",
		false,
	},
	{
		[]byte("urn:ciao:+"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     "+",
		},
		"urn:ciao:+",
		"urn:ciao:+",
		"",
		false,
	},
	{
		[]byte("urn:ciao::"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     ":",
		},
		"urn:ciao::",
		"urn:ciao::",
		"",
		false,
	},
	{
		[]byte("urn:colon:::::nss"),
		true,
		&URN{
			prefix: "urn",
			ID:     "colon",
			SS:     "::::nss",
		},
		"urn:colon:::::nss",
		"urn:colon:::::nss",
		"",
		false,
	},
	{
		[]byte("urn:ciao:!"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     "!",
		},
		"urn:ciao:!",
		"urn:ciao:!",
		"",
		false,
	},
	{
		[]byte("urn:ciao:!!*"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     "!!*",
		},
		"urn:ciao:!!*",
		"urn:ciao:!!*",
		"",
		false,
	},
	{
		[]byte("urn:ciao:-!:-,:x"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     "-!:-,:x",
		},
		"urn:ciao:-!:-,:x",
		"urn:ciao:-!:-,:x",
		"",
		false,
	},
	{
		[]byte("urn:ciao:=@"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     "=@",
		},
		"urn:ciao:=@",
		"urn:ciao:=@",
		"",
		false,
	},
	{
		[]byte("urn:ciao:@!=%2C(xyz)+a,b.*@g=$_'"),
		true,
		&URN{
			prefix: "urn",
			ID:     "ciao",
			SS:     "@!=%2C(xyz)+a,b.*@g=$_'",
		},
		"urn:ciao:@!=%2C(xyz)+a,b.*@g=$_'",
		"urn:ciao:@!=%2c(xyz)+a,b.*@g=$_'",
		"",
		false,
	},

	// ok - SS can contain (and also start with) hexadecimal representation of octets
	{
		[]byte("URN:hexes:%25"),
		true,
		&URN{
			prefix: "URN",
			ID:     "hexes",
			SS:     "%25",
		},
		"URN:hexes:%25",
		"urn:hexes:%25",
		"",
		false,
	}, // Literal use of the "%" character in a namespace must be encoded using "%25"
	{
		[]byte("URN:x:abc%1Dz%2F%3az"),
		true,
		&URN{
			prefix: "URN",
			ID:     "x",
			SS:     "abc%1Dz%2F%3az",
		},
		"URN:x:abc%1Dz%2F%3az",
		"urn:x:abc%1dz%2f%3az",
		"",
		false,
	}, // Literal use of the "%" character in a namespace must be encoded using "%25"

	// no - ID can not start with an hyphen
	{
		[]byte("URN:-xxx:x"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 4]`,
		false,
	},
	{
		[]byte("URN:---xxx:x"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 4]`,
		false,
	},

	// no - ID can not start with a colon
	{
		[]byte("urn::colon:nss"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 4]`,
		false,
	},
	{
		[]byte("urn::::nss"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 4]`,
		false,
	},

	// no - ID can not contains more than 32 characters
	{
		[]byte("urn:abcdefghilmnopqrstuvzabcdefghilmn:specificstring"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 36]`,
		false,
	},

	// no - ID can not contain special characters
	{
		[]byte("URN:a!?:x"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 5]`,
		false,
	},
	{
		[]byte("URN:@,:x"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 4]`,
		false,
	},
	{
		[]byte("URN:#,:x"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 4]`,
		false,
	},
	{
		[]byte("URN:bc'.@:x"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 6]`,
		false,
	},

	// no - ID can not be equal to "urn"
	{
		[]byte("urn:urn:NSS"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to not contain the "urn" reserved string [col 7]`,
		false,
	},
	{
		[]byte("urn:URN:NSS"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to not contain the "urn" reserved string [col 7]`,
		false,
	},
	{
		[]byte("URN:URN:NSS"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to not contain the "urn" reserved string [col 7]`,
		false,
	},
	{
		[]byte("urn:UrN:NSS"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to not contain the "urn" reserved string [col 7]`,
		false,
	},
	{
		[]byte("urn:Urn:NSS"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to not contain the "urn" reserved string [col 7]`,
		false,
	},

	// no - ID can not contain spaces
	{
		[]byte("urn:white space:NSS"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 9]`,
		false,
	},

	// no - SS can not contain spaces
	{
		[]byte("urn:concat:no spaces"),
		false,
		nil,
		"",
		"",
		`expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col 13]`,
		false,
	},

	// no - SS can not contain reserved characters (can accept them only if %-escaped)
	{
		[]byte("urn:a:%"), // the presence of an "%" character in an URN MUST be followed by two characters from the <hex> character set
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errHex, 7),
		false,
	},
	{
		[]byte("urn:a:%A"), // the presence of an "%" character in an URN MUST be followed by two characters from the <hex> character set
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errHex, 8),
		false,
	},
	{
		[]byte("urn:a:?"),
		false,
		nil,
		"",
		"",
		`expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col 6]`,
		false,
	},
	{
		[]byte("urn:a:#"),
		false,
		nil,
		"",
		"",
		`expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col 6]`,
		false,
	},
	{
		[]byte("urn:a:/"),
		false,
		nil,
		"",
		"",
		`expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col 6]`,
		false,
	},
	{
		[]byte("urn:ietf:params:scim:api:messages:%"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errHex, 35),
		false,
	},
	{
		[]byte("urn:ietf:params:scim:api:messages:%F"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errHex, 36),
		false,
	},
	{
		[]byte("arn:ietf:params:scim:schemas:core"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 0),
		false,
	},
	{
		[]byte("usn:ietf:params:scim:schemas:core"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 1),
		false,
	},
	{
		[]byte("urm:ietf:params:scim:schemas:core"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 2),
		false,
	},
	{
		[]byte("urno:ietf:params:scim:schemas:core"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 3),
		false,
	},
	{
		[]byte("urno"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 3),
		false,
	},
	{
		[]byte("URN:a!?:x"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 5]`,
		false,
	},
	{
		[]byte("urn:Urn:NSS"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to not contain the "urn" reserved string [col 7]`,
		false,
	},
	{
		[]byte("urn:spazio bianco:NSS"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 10]`,
		false,
	},
	{
		[]byte("urn:conca:z ws"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSpecificString, 11),
		false,
	},
	{
		[]byte("urn:ietf:params:scim:schemas:core:2.&"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errSpecificString, 36),
		false,
	},

	// no - Incomplete URNs
	{
		[]byte("urn:"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 4]`,
		false,
	},
	{
		[]byte("urn::"),
		false,
		nil,
		"",
		"",
		`expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its beginning) [col 4]`,
		false,
	},
	{
		[]byte("urn:a:"),
		false,
		nil,
		"",
		"",
		`expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col 6]`,
		false,
	},
	{
		[]byte("urn:a"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errIdentifier, 5),
		false,
	},
	// no - Incomplete prefix
	{
		[]byte(`u`),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 1),
		false,
	},
	{
		[]byte(`ur`),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 2),
		false,
	},
	{
		[]byte(`urn`),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 3),
		false,
	},

	// no, empty
	{
		[]byte(""),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 0),
		false,
	},
}

var rfc8141TestCases = []testCase{
	// ok
	{
		[]byte("urn:lex:it:ministero.giustizia:decreto:1992-07-24;358~art5"), // Italian decree
		true,
		&URN{
			prefix: "urn",
			ID:     "lex",
			SS:     "it:ministero.giustizia:decreto:1992-07-24;358~art5",
		},
		"urn:lex:it:ministero.giustizia:decreto:1992-07-24;358~art5",
		"urn:lex:it:ministero.giustizia:decreto:1992-07-24;358~art5",
		"",
		false,
	}, // ~ allowed in the NSS
	{
		[]byte("urn:nid:nss/"),
		true,
		&URN{
			prefix: "urn",
			ID:     "nid",
			SS:     "nss/",
		},
		"urn:nid:nss/",
		"urn:nid:nss/",
		"",
		false,
	}, // / allowed in the NSS
	{
		[]byte("urn:nid:nss&"),
		true,
		&URN{
			prefix: "urn",
			ID:     "nid",
			SS:     "nss&",
		},
		"urn:nid:nss&",
		"urn:nid:nss&",
		"",
		false,
	}, // & allowed in the NSS
	{
		[]byte("urn:example:1/406/47452/2"),
		true,
		&URN{
			prefix: "urn",
			ID:     "example",
			SS:     "1/406/47452/2",
		},
		"urn:example:1/406/47452/2",
		"urn:example:1/406/47452/2",
		"",
		false,
	}, // & allowed in the NSS
	{
		[]byte("urn:example:foo-bar-baz-qux?+CCResolve:cc=uk"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "foo-bar-baz-qux",
			rComponent: "CCResolve:cc=uk",
		},
		"urn:example:foo-bar-baz-qux?+CCResolve:cc=uk",
		"urn:example:foo-bar-baz-qux",
		"",
		false,
	},
	{
		[]byte("urn:example:foo-bar-baz-qux?+&"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "foo-bar-baz-qux",
			rComponent: "&",
		},
		"urn:example:foo-bar-baz-qux?+&",
		"urn:example:foo-bar-baz-qux",
		"",
		false,
	},
	{
		[]byte("urn:example:foo-bar-baz-qux?+~"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "foo-bar-baz-qux",
			rComponent: "~",
		},
		"urn:example:foo-bar-baz-qux?+~",
		"urn:example:foo-bar-baz-qux",
		"",
		false,
	},
	{
		[]byte("urn:example:foo-bar-baz-qux?+%16CCResolve:cc=uk"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "foo-bar-baz-qux",
			rComponent: "%16CCResolve:cc=uk",
		},
		"urn:example:foo-bar-baz-qux?+%16CCResolve:cc=uk",
		"urn:example:foo-bar-baz-qux",
		"",
		false,
	},
	{
		[]byte("urn:example:foo-bar-baz-qut?+~&%FF()+,-.:=@;$_!/?Alnum123456"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "foo-bar-baz-qut",
			rComponent: "~&%FF()+,-.:=@;$_!/?Alnum123456",
		},
		"urn:example:foo-bar-baz-qut?+~&%FF()+,-.:=@;$_!/?Alnum123456",
		"urn:example:foo-bar-baz-qut",
		"",
		false,
	},
	{
		[]byte("urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "weather",
			qComponent: "op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z",
		},
		"urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z",
		"urn:example:weather",
		"",
		false,
	},
	{
		[]byte("urn:esempio:climate?=alnum~&%FF()+,-.:=@;$_!/?123456"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "esempio",
			SS:         "climate",
			qComponent: "alnum~&%FF()+,-.:=@;$_!/?123456",
		},
		"urn:esempio:climate?=alnum~&%FF()+,-.:=@;$_!/?123456",
		"urn:esempio:climate",
		"",
		false,
	},
	{
		[]byte("urn:esempio:climate?=&&"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "esempio",
			SS:         "climate",
			qComponent: "&&",
		},
		"urn:esempio:climate?=&&",
		"urn:esempio:climate",
		"",
		false,
	},
	{
		[]byte("urn:esempio:climate?=%A1alnum~&%FF()+,-.:=@;$_!/?123456"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "esempio",
			SS:         "climate",
			qComponent: "%A1alnum~&%FF()+,-.:=@;$_!/?123456",
		},
		"urn:esempio:climate?=%A1alnum~&%FF()+,-.:=@;$_!/?123456",
		"urn:esempio:climate",
		"",
		false,
	},
	{
		[]byte("urn:example:foo-bar-baz-qux#somepart"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "foo-bar-baz-qux",
			fComponent: "somepart",
		},
		"urn:example:foo-bar-baz-qux#somepart",
		"urn:example:foo-bar-baz-qux",
		"",
		false,
	},
	{
		[]byte("urn:example:foo-bar-baz-qux#~&"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "foo-bar-baz-qux",
			fComponent: "~&",
		},
		"urn:example:foo-bar-baz-qux#~&",
		"urn:example:foo-bar-baz-qux",
		"",
		false,
	},
	{
		[]byte("urn:example:foo-bar-baz-qux#alnum~&%FF()+,-.:=@;$_!/?123456"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "foo-bar-baz-qux",
			fComponent: "alnum~&%FF()+,-.:=@;$_!/?123456",
		},
		"urn:example:foo-bar-baz-qux#alnum~&%FF()+,-.:=@;$_!/?123456",
		"urn:example:foo-bar-baz-qux",
		"",
		false,
	},
	{
		[]byte("urn:example:foo-bar-baz-qux#%D0alnum~&%FF()+,-.:=@;$_!/?123456"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "foo-bar-baz-qux",
			fComponent: "%D0alnum~&%FF()+,-.:=@;$_!/?123456",
		},
		"urn:example:foo-bar-baz-qux#%D0alnum~&%FF()+,-.:=@;$_!/?123456",
		"urn:example:foo-bar-baz-qux",
		"",
		false,
	},
	{
		[]byte("urn:example:CamelCase1/406/47452/2?+Cc=it&prefix=39?=lat=41.22255&long=16.06596#frag"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "CamelCase1/406/47452/2",
			rComponent: "Cc=it&prefix=39",
			qComponent: "lat=41.22255&long=16.06596",
			fComponent: "frag",
		},
		"urn:example:CamelCase1/406/47452/2?+Cc=it&prefix=39?=lat=41.22255&long=16.06596#frag",
		"urn:example:CamelCase1/406/47452/2",
		"",
		false,
	}, // r_component, q_component, f_component
	{
		[]byte("urn:example:CamelCase1/406/47452/2?=lat=41.22255&long=16.06596#frag"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "CamelCase1/406/47452/2",
			qComponent: "lat=41.22255&long=16.06596",
			fComponent: "frag",
		},
		"urn:example:CamelCase1/406/47452/2?=lat=41.22255&long=16.06596#frag",
		"urn:example:CamelCase1/406/47452/2",
		"",
		false,
	}, // q_component, f_component
	{
		[]byte("urn:example:CamelCase1/406/47452/2?=lat=41.22255&long=16.06596#frag?some/slash/~%D0"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "CamelCase1/406/47452/2",
			qComponent: "lat=41.22255&long=16.06596",
			fComponent: "frag?some/slash/~%D0",
		},
		"urn:example:CamelCase1/406/47452/2?=lat=41.22255&long=16.06596#frag?some/slash/~%D0",
		"urn:example:CamelCase1/406/47452/2",
		"",
		false,
	}, // q_component, f_component
	{
		[]byte("urn:example:CamelCase1/406/47452/2?+Cc=it&prefix=39?=lat=41.22255&long=16.06596"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "example",
			SS:         "CamelCase1/406/47452/2",
			rComponent: "Cc=it&prefix=39",
			qComponent: "lat=41.22255&long=16.06596",
		},
		"urn:example:CamelCase1/406/47452/2?+Cc=it&prefix=39?=lat=41.22255&long=16.06596",
		"urn:example:CamelCase1/406/47452/2",
		"",
		false,
	}, // r_component, q_component
	{
		[]byte("urn:TESTt3st:&/987/QWERTYUIOP/0#"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "TESTt3st",
			SS:         "&/987/QWERTYUIOP/0",
			fComponent: "",
		},
		"urn:TESTt3st:&/987/QWERTYUIOP/0",
		"urn:testt3st:&/987/QWERTYUIOP/0",
		"",
		false,
	}, // empty fragment
	{
		[]byte("urn:example:%D0%B0123,z456"),
		true,
		&URN{
			prefix: "urn",
			ID:     "example",
			SS:     "%D0%B0123,z456",
		},
		"urn:example:%D0%B0123,z456",
		"urn:example:%d0%b0123,z456",
		"",
		false,
	},
	{
		[]byte("urn:example:apple:pear:plum:cherry"),
		true,
		&URN{
			prefix: "urn",
			ID:     "example",
			SS:     "apple:pear:plum:cherry",
		},
		"urn:example:apple:pear:plum:cherry",
		"urn:example:apple:pear:plum:cherry",
		"",
		false,
	},
	{
		[]byte("urn:z------------------------------a:q"),
		true,
		&URN{
			prefix: "urn",
			ID:     "z------------------------------a",
			SS:     "q",
		},
		"urn:z------------------------------a:q",
		"urn:z------------------------------a:q",
		"",
		false,
	},
	{
		[]byte("urn:10:2"),
		true,
		&URN{
			prefix: "urn",
			ID:     "10",
			SS:     "2",
		},
		"urn:10:2",
		"urn:10:2",
		"",
		false,
	},
	{
		[]byte("urn:a1l2n3m4-56789aeiou:2"),
		true,
		&URN{
			prefix: "urn",
			ID:     "a1l2n3m4-56789aeiou",
			SS:     "2",
		},
		"urn:a1l2n3m4-56789aeiou:2",
		"urn:a1l2n3m4-56789aeiou:2",
		"",
		false,
	},
	{
		[]byte("urn:a1l2n3m4-56789aeiou:2%D0%B0"),
		true,
		&URN{
			prefix: "urn",
			ID:     "a1l2n3m4-56789aeiou",
			SS:     "2%D0%B0",
		},
		"urn:a1l2n3m4-56789aeiou:2%D0%B0",
		"urn:a1l2n3m4-56789aeiou:2%d0%b0",
		"",
		false,
	},
	{
		[]byte("urn:amp:&"),
		true,
		&URN{
			prefix: "urn",
			ID:     "amp",
			SS:     "&",
		},
		"urn:amp:&",
		"urn:amp:&",
		"",
		false,
	},
	{
		[]byte("urn:tilde:~~~"),
		true,
		&URN{
			prefix: "urn",
			ID:     "tilde",
			SS:     "~~~",
		},
		"urn:tilde:~~~",
		"urn:tilde:~~~",
		"",
		false,
	},
	{
		[]byte("urn:signs:()+,-.:=@;$_!*alnum123456789"),
		true,
		&URN{
			prefix: "urn",
			ID:     "signs",
			SS:     "()+,-.:=@;$_!*alnum123456789",
		},
		"urn:signs:()+,-.:=@;$_!*alnum123456789",
		"urn:signs:()+,-.:=@;$_!*alnum123456789",
		"",
		false,
	},
	{
		[]byte("URN:signs:()+,-.:=@;$_!*alnum123456789"),
		true,
		&URN{
			prefix: "URN",
			ID:     "signs",
			SS:     "()+,-.:=@;$_!*alnum123456789",
		},
		"URN:signs:()+,-.:=@;$_!*alnum123456789",
		"urn:signs:()+,-.:=@;$_!*alnum123456789",
		"",
		false,
	},
	{
		[]byte("urn:urn-7:informal"),
		true,
		&URN{
			prefix: "urn",
			ID:     "urn-7",
			SS:     "informal",
		},
		"urn:urn-7:informal",
		"urn:urn-7:informal",
		"",
		false,
	}, // NID containing informal URN namespace
	{
		[]byte("urn:ex:ex?+a?"),
		true,
		&URN{
			prefix:     "urn",
			ID:         "ex",
			SS:         "ex",
			rComponent: "a?",
		},
		"urn:ex:ex?+a?",
		"urn:ex:ex",
		"",
		false,
	}, // r_component containing ? not immediately followed by + or =

	// no
	{
		[]byte("urn:urn-0:nss"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141InformalID, 7),
		false,
	}, // NID must not start the a wrong informal URN namespace
	{
		[]byte("urn:urn-s:nss"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141InformalID, 7),
		false,
	}, // NID must not start the "urn-" prefix followed by a string
	{
		[]byte("urn:example:а123,z456"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141SpecificString, 12),
		false,
	}, // CYRILLIC а (U+0430)
	{
		[]byte("URN:-leading:w"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 4),
		false,
	}, // leading - not allowed in the NID
	{
		[]byte("URN:trailing-:w"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 13),
		false,
	}, // trailing - not allowed in the NID
	{
		[]byte("urn:a:nss"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 5),
		false,
	}, // NID at least 2 characters
	{
		[]byte("urn:1:nss"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 5),
		false,
	}, // NID at least 2 characters
	{
		[]byte("urn:yz-:nss"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 7),
		false,
	}, // NID must not start with 2 characters followerd by a dash
	{
		[]byte("urn:9x-:nss"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 7),
		false,
	}, // NID must not start with 2 characters followerd by a dash
	{
		[]byte("urn:X-:nss"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 6),
		false,
	}, // NID must not start with experimental URN namespace of RFC3406
	{
		[]byte("urn:xn--:nss"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 8),
		false,
	}, // NID must not start with "xn" followed by 2 dashes
	{
		[]byte("urn:ss--:nss"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 8),
		false,
	}, // NID must not start with 2 chars followed by 2 dashes
	{
		[]byte("urn:1E--:nss"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 8),
		false,
	}, // NID must not start with 2 chars followed by 2 dashes
	{
		[]byte("urn:ex:ex?+a?+"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141RComponentStart, 14),
		false,
	}, // r_component containing ?+
	{
		[]byte("urn:ex:ex?+"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141MalformedRComp, 11),
		false,
	}, // empty r_component
	{
		[]byte("urn:ex:ex?=a?="),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141QComponentStart, 14),
		false,
	}, // q_component containing ?=
	{
		[]byte("urn:example:CamelCase1/406/47452/2?="),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141MalformedQComp, 36),
		false,
	}, // empty q_component
	{
		[]byte("urn:ex:ex?+rcomponent?+rcomponent?=qcomponent"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141RComponentStart, 23),
		false,
	}, // r_component containing ?+ followed by q_component
	{
		[]byte("urn:ex:ex?+rcomponent?+rcomponent?="),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141RComponentStart, 23),
		false,
	}, // r_component containing ?+ followed by empty q_component
	{
		[]byte("urn:ex:ex?+rcomponent?=qcomponent?=q"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141QComponentStart, 35),
		false,
	}, // r_component followed by q_component containing ?+
	{
		[]byte("urn:ex:ex?+?=q"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141MalformedRComp, 12),
		false,
	}, // empty r_component followed by q_component
	{
		[]byte("urn:ex:ex?+/"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141MalformedRComp, 11),
		false,
	}, // r_component starting with /
	{
		[]byte("urn:ex:ex?+?"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141MalformedRComp, 12),
		false,
	}, // r_component starting with /
	{
		[]byte("urn:ex:ex?=/"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141MalformedQComp, 11),
		false,
	}, // q_component starting with /
	{
		[]byte("urn:ex:ex?=?"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141MalformedQComp, 12),
		false,
	}, // q_component starting with /
	{
		[]byte("urn:mm:/"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141SpecificString, 7),
		false,
	}, // / not in first position in the NSS part
	{
		[]byte("urn:mm:?"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141SpecificString, 7),
		false,
	}, // ? not in first position in the NSS part
	{
		[]byte("urn:123456789-1234567890-abcdefghilmn:o"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 36),
		false,
	}, // too long NID
	{
		[]byte("urn:"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 4),
		false,
	},
	{
		[]byte("urn::"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 4),
		false,
	},
	{
		[]byte("urn:aa:"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141SpecificString, 7),
		false,
	},
	{
		[]byte("urn:a"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 5),
		false,
	},
	{
		[]byte("urn:ex:ex?=%"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errHex, 12),
		false,
	}, // q_component containing incomplete percent encoded chars
	{
		[]byte("urn:ex:ex?+%"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errHex, 12),
		false,
	}, // r_component containing incomplete percent encoded chars
	{
		[]byte("urn:ex:ex?=something#%"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errHex, 22),
		false,
	}, // fragment containing incomplete percent encoded chars
	{
		[]byte("urn:example%:test"),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 11),
		false,
	},
	{
		[]byte(`urn:"`),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 4),
		false,
	},
	{
		[]byte(`urn:a1{}`),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(err8141Identifier, 6),
		false,
	},
	{
		[]byte(`u`),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 1),
		false,
	},
	{
		[]byte(`ur`),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 2),
		false,
	},
	{
		[]byte(`urn`),
		false,
		nil,
		"",
		"",
		fmt.Sprintf(errPrefix, 3),
		false,
	},
}
