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 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 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, }, }