package urn import ( "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 } 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", "", }, // Italian decree // fixme(leodido) // verify whether it is correct or not that ~ is not accepted // does it requires RFC 8141 (issue #17) ? // { // []byte("urn:lex:it:ministero.giustizia:decreto:1992-07-24;358~art5"), // true, // &URN{ // prefix: "urn", // ID: "lex", // SS: "it:ministero.giustizia:decreto:1992-07-24;358~art5", // }, // "it:ministero.giustizia:decreto:1992-07-24;358~art5", // "it:ministero.giustizia:decreto:1992-07-24;358~art5", // "", // }, // 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", "", }, // 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", "", }, // 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", "", }, // 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", "", }, { []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", "", }, // 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", "", }, } var genericTestCases = []testCase{ // ok { []byte("urn:simple:simple"), true, &URN{ prefix: "urn", ID: "simple", SS: "simple", }, "urn:simple:simple", "urn:simple:simple", "", }, { []byte("urn:ciao:%5D"), true, &URN{ prefix: "urn", ID: "ciao", SS: "%5D", }, "urn:ciao:%5D", "urn:ciao:%5d", "", }, // 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", "", }, { []byte("urn:foo:a123,456"), true, &URN{ prefix: "urn", ID: "foo", SS: "a123,456", }, "urn:foo:a123,456", "urn:foo:a123,456", "", }, { []byte("urn:FOO:a123,456"), true, &URN{ prefix: "urn", ID: "FOO", SS: "a123,456", }, "urn:FOO:a123,456", "urn:foo:a123,456", "", }, { []byte("urn:foo:A123,456"), true, &URN{ prefix: "urn", ID: "foo", SS: "A123,456", }, "urn:foo:A123,456", "urn:foo:A123,456", "", }, { []byte("urn:foo:a123%2C456"), true, &URN{ prefix: "urn", ID: "foo", SS: "a123%2C456", }, "urn:foo:a123%2C456", "urn:foo:a123%2c456", "", }, { []byte("URN:FOO:a123%2c456"), true, &URN{ prefix: "URN", ID: "FOO", SS: "a123%2c456", }, "URN:FOO:a123%2c456", "urn:foo:a123%2c456", "", }, { []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", "", }, { []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", "", }, // 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", "", }, { []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", "", }, { []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", "", }, { []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", "", }, // ok - minimum urn { []byte("urn:a:b"), true, &URN{ prefix: "urn", ID: "a", SS: "b", }, "urn:a:b", "urn:a:b", "", }, { []byte("urn:a::"), true, &URN{ prefix: "urn", ID: "a", SS: ":", }, "urn:a::", "urn:a::", "", }, { []byte("urn:a:-"), true, &URN{ prefix: "urn", ID: "a", SS: "-", }, "urn:a:-", "urn:a:-", "", }, // ok - URN prefix is case-insensitive { []byte("URN:simple:simple"), true, &URN{ prefix: "URN", ID: "simple", SS: "simple", }, "URN:simple:simple", "urn:simple:simple", "", }, { []byte("Urn:simple:simple"), true, &URN{ prefix: "Urn", ID: "simple", SS: "simple", }, "Urn:simple:simple", "urn:simple:simple", "", }, // 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", "", }, { []byte("urn:burnout:nss"), true, &URN{ prefix: "urn", ID: "burnout", SS: "nss", }, "urn:burnout:nss", "urn:burnout:nss", "", }, { []byte("urn:burn:nss"), true, &URN{ prefix: "urn", ID: "burn", SS: "nss", }, "urn:burn:nss", "urn:burn:nss", "", }, { []byte("urn:urnurnurn:x"), true, &URN{ prefix: "urn", ID: "urnurnurn", SS: "x", }, "urn:urnurnurn:x", "urn:urnurnurn:x", "", }, // 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", "", }, // ok - ID can be alpha numeric { []byte("URN:123:x"), true, &URN{ prefix: "URN", ID: "123", SS: "x", }, "URN:123:x", "urn:123:x", "", }, { []byte("URN:1ab:x"), true, &URN{ prefix: "URN", ID: "1ab", SS: "x", }, "URN:1ab:x", "urn:1ab:x", "", }, { []byte("URN:a1b:x"), true, &URN{ prefix: "URN", ID: "a1b", SS: "x", }, "URN:a1b:x", "urn:a1b:x", "", }, { []byte("URN:a12:x"), true, &URN{ prefix: "URN", ID: "a12", SS: "x", }, "URN:a12:x", "urn:a12:x", "", }, { []byte("URN:cd2:x"), true, &URN{ prefix: "URN", ID: "cd2", SS: "x", }, "URN:cd2:x", "urn:cd2:x", "", }, // 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", "", }, { []byte("URN:abcd-abcd:x"), true, &URN{ prefix: "URN", ID: "abcd-abcd", SS: "x", }, "URN:abcd-abcd:x", "urn:abcd-abcd:x", "", }, { []byte("URN:a123-456z:x"), true, &URN{ prefix: "URN", ID: "a123-456z", SS: "x", }, "URN:a123-456z:x", "urn:a123-456z:x", "", }, // 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", "", }, { []byte("urn:urnurnurn:urn"), true, &URN{ prefix: "urn", ID: "urnurnurn", SS: "urn", }, "urn:urnurnurn:urn", "urn:urnurnurn:urn", "", }, { []byte("urn:hey:urnurnurn"), true, &URN{ prefix: "urn", ID: "hey", SS: "urnurnurn", }, "urn:hey:urnurnurn", "urn:hey:urnurnurn", "", }, // 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", "", }, { []byte("urn:aaa:x:y:"), true, &URN{ prefix: "urn", ID: "aaa", SS: "x:y:", }, "urn:aaa:x:y:", "urn:aaa:x:y:", "", }, { []byte("urn:aaa:x:y:"), true, &URN{ prefix: "urn", ID: "aaa", SS: "x:y:", }, "urn:aaa:x:y:", "urn:aaa:x:y:", "", }, // 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:-", "", }, { []byte("urn:ciao::"), true, &URN{ prefix: "urn", ID: "ciao", SS: ":", }, "urn:ciao::", "urn:ciao::", "", }, { []byte("urn:colon:::::nss"), true, &URN{ prefix: "urn", ID: "colon", SS: "::::nss", }, "urn:colon:::::nss", "urn:colon:::::nss", "", }, { []byte("urn:ciao:!"), true, &URN{ prefix: "urn", ID: "ciao", SS: "!", }, "urn:ciao:!", "urn:ciao:!", "", }, { []byte("urn:ciao:!!*"), true, &URN{ prefix: "urn", ID: "ciao", SS: "!!*", }, "urn:ciao:!!*", "urn:ciao:!!*", "", }, { []byte("urn:ciao:-!:-,:x"), true, &URN{ prefix: "urn", ID: "ciao", SS: "-!:-,:x", }, "urn:ciao:-!:-,:x", "urn:ciao:-!:-,:x", "", }, { []byte("urn:ciao:=@"), true, &URN{ prefix: "urn", ID: "ciao", SS: "=@", }, "urn:ciao:=@", "urn:ciao:=@", "", }, { []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=$_'", "", }, // 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", "", }, // 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", "", }, // 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 start) [col 4]`, }, { []byte("URN:---xxx:x"), false, nil, "", "", `expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its start) [col 4]`, }, // 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 start) [col 4]`, }, { []byte("urn::::nss"), false, nil, "", "", `expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its start) [col 4]`, }, // 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 start) [col 36]`, }, // 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 start) [col 5]`, }, { []byte("URN:@,:x"), false, nil, "", "", `expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its start) [col 4]`, }, { []byte("URN:#,:x"), false, nil, "", "", `expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its start) [col 4]`, }, { []byte("URN:bc'.@:x"), false, nil, "", "", `expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its start) [col 6]`, }, // 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]`, }, { []byte("urn:URN:NSS"), false, nil, "", "", `expecting the identifier to not contain the "urn" reserved string [col 7]`, }, { []byte("URN:URN:NSS"), false, nil, "", "", `expecting the identifier to not contain the "urn" reserved string [col 7]`, }, { []byte("urn:UrN:NSS"), false, nil, "", "", `expecting the identifier to not contain the "urn" reserved string [col 7]`, }, { []byte("urn:Urn:NSS"), false, nil, "", "", `expecting the identifier to not contain the "urn" reserved string [col 7]`, }, // 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 start) [col 9]`, }, // 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]`, }, // 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, "", "", `expecting the specific string hex chars to be well-formed (%alnum{2}) [col 7]`, }, { []byte("urn:a:?"), false, nil, "", "", `expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col 6]`, }, { []byte("urn:a:#"), false, nil, "", "", `expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col 6]`, }, { []byte("urn:a:/"), false, nil, "", "", `expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col 6]`, }, // no - Incomplete URNs { []byte("urn:"), false, nil, "", "", `expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its start) [col 4]`, }, { []byte("urn::"), false, nil, "", "", `expecting the identifier to be string (1..31 alnum chars, also containing dashes but not at its start) [col 4]`, }, { []byte("urn:a:"), false, nil, "", "", `expecting the specific string to be a string containing alnum, hex, or others ([()+,-.:=@;$_!*']) chars [col 6]`, }, // { // "urn:a", // false, // nil, // "", // "", // "", // }, } var equivalenceTests = []struct { eq bool lx []byte rx []byte }{ { true, []byte("urn:foo:a123%2C456"), []byte("URN:FOO:a123%2c456"), }, { true, []byte("urn:foo:AbC123%2C456"), []byte("URN:FOO:AbC123%2c456"), }, { true, []byte("urn:foo:AbC123%2C456%1f"), []byte("URN:FOO:AbC123%2c456%1f"), }, { true, []byte("URN:foo:a123,456"), []byte("urn:foo:a123,456"), }, { true, []byte("URN:foo:a123,456"), []byte("urn:FOO:a123,456"), }, { true, []byte("urn:foo:a123,456"), []byte("urn:FOO:a123,456"), }, { true, []byte("urn:ciao:%2E"), []byte("urn:ciao:%2e"), }, { false, []byte("urn:foo:A123,456"), []byte("URN:foo:a123,456"), }, { false, []byte("urn:foo:A123,456"), []byte("urn:foo:a123,456"), }, { false, []byte("urn:foo:A123,456"), []byte("urn:FOO:a123,456"), }, }