diff --git a/toplabel/bytes.go b/toplabel/bytes.go new file mode 100644 index 0000000..3619c5a --- /dev/null +++ b/toplabel/bytes.go @@ -0,0 +1,44 @@ +package toplabel + +import ( + "sourcecode.social/reiver/go-rfc2396/alpha" + "sourcecode.social/reiver/go-rfc2396/alphanum" +) + +func Bytes(p []byte) (result []byte, rest []byte, ok bool) { + + length := len(p) + + if length < 1 { + return nil, p, false + } + + { + p0 := p[0] + + if !alpha.ByteIs(p0) { + return nil, p, false + } + } + + { + for i,b := range p { + if !alphanum.ByteIs(b) && '-' != b { + + if !alphanum.ByteIs(p[i-1]) { + return p[:i-1], p[i-1:], true + } + + return p[:i], p[i:], true + } + } + + + if !alphanum.ByteIs(p[length-1]) { + return p[:length-1], p[length-1:], true + } + + + return p, nil, true + } +} diff --git a/toplabel/bytes_test.go b/toplabel/bytes_test.go new file mode 100644 index 0000000..fec4250 --- /dev/null +++ b/toplabel/bytes_test.go @@ -0,0 +1,463 @@ +package toplabel_test + +import ( + "testing" + + "bytes" + + "sourcecode.social/reiver/go-rfc2396/toplabel" +) + +func TestBytes(t *testing.T) { + + tests := []struct{ + Value []byte + ExpectedResult []byte + ExpectedRest []byte + ExpectedOK bool + }{ + { + Value: nil, + ExpectedResult: nil, + ExpectedRest: nil, + ExpectedOK: false, + }, + { + Value: []byte(nil), + ExpectedResult: nil, + ExpectedRest: nil, + ExpectedOK: false, + }, + + + + { + Value: []byte{}, + ExpectedResult: nil, + ExpectedRest: nil, + ExpectedOK: false, + }, + { + Value: []byte(""), + ExpectedResult: nil, + ExpectedRest: nil, + ExpectedOK: false, + }, + + + + { + Value: []byte("com"), + ExpectedResult: []byte("com"), + ExpectedRest: nil, + ExpectedOK: true, + }, + { + Value: []byte("com/"), + ExpectedResult: []byte("com"), + ExpectedRest: []byte("/"), + ExpectedOK: true, + }, + { + Value: []byte("com/once/twice/thrice/fource.php"), + ExpectedResult: []byte("com"), + ExpectedRest: []byte("/once/twice/thrice/fource.php"), + ExpectedOK: true, + }, + { + Value: []byte("com."), + ExpectedResult: []byte("com"), + ExpectedRest: []byte("."), + ExpectedOK: true, + }, + { + Value: []byte("com./"), + ExpectedResult: []byte("com"), + ExpectedRest: []byte("./"), + ExpectedOK: true, + }, + + + + { + Value: []byte("co"), + ExpectedResult: []byte("co"), + ExpectedRest: nil, + ExpectedOK: true, + }, + { + Value: []byte("co/"), + ExpectedResult: []byte("co"), + ExpectedRest: []byte("/"), + ExpectedOK: true, + }, + { + Value: []byte("co/once/twice/thrice/fource.php"), + ExpectedResult: []byte("co"), + ExpectedRest: []byte("/once/twice/thrice/fource.php"), + ExpectedOK: true, + }, + { + Value: []byte("co."), + ExpectedResult: []byte("co"), + ExpectedRest: []byte("."), + ExpectedOK: true, + }, + { + Value: []byte("co./"), + ExpectedResult: []byte("co"), + ExpectedRest: []byte("./"), + ExpectedOK: true, + }, + + + + { + Value: []byte("c"), + ExpectedResult: []byte("c"), + ExpectedRest: nil, + ExpectedOK: true, + }, + { + Value: []byte("c/"), + ExpectedResult: []byte("c"), + ExpectedRest: []byte("/"), + ExpectedOK: true, + }, + { + Value: []byte("c/once/twice/thrice/fource.php"), + ExpectedResult: []byte("c"), + ExpectedRest: []byte("/once/twice/thrice/fource.php"), + ExpectedOK: true, + }, + { + Value: []byte("c."), + ExpectedResult: []byte("c"), + ExpectedRest: []byte("."), + ExpectedOK: true, + }, + { + Value: []byte("c./"), + ExpectedResult: []byte("c"), + ExpectedRest: []byte("./"), + ExpectedOK: true, + }, + + + + { + Value: []byte("c-"), + ExpectedResult: []byte("c"), + ExpectedRest: []byte("-"), + ExpectedOK: true, + }, + { + Value: []byte("c-/"), + ExpectedResult: []byte("c"), + ExpectedRest: []byte("-/"), + ExpectedOK: true, + }, + { + Value: []byte("c-/once/twice/thrice/fource.php"), + ExpectedResult: []byte("c"), + ExpectedRest: []byte("-/once/twice/thrice/fource.php"), + ExpectedOK: true, + }, + { + Value: []byte("c-."), + ExpectedResult: []byte("c"), + ExpectedRest: []byte("-."), + ExpectedOK: true, + }, + { + Value: []byte("c-./"), + ExpectedResult: []byte("c"), + ExpectedRest: []byte("-./"), + ExpectedOK: true, + }, + + + + { + Value: []byte("c1"), + ExpectedResult: []byte("c1"), + ExpectedRest: nil, + ExpectedOK: true, + }, + { + Value: []byte("c1/"), + ExpectedResult: []byte("c1"), + ExpectedRest: []byte("/"), + ExpectedOK: true, + }, + { + Value: []byte("c1/once/twice/thrice/fource.php"), + ExpectedResult: []byte("c1"), + ExpectedRest: []byte("/once/twice/thrice/fource.php"), + ExpectedOK: true, + }, + { + Value: []byte("c1."), + ExpectedResult: []byte("c1"), + ExpectedRest: []byte("."), + ExpectedOK: true, + }, + { + Value: []byte("c1./"), + ExpectedResult: []byte("c1"), + ExpectedRest: []byte("./"), + ExpectedOK: true, + }, + + + + { + Value: []byte("c-1"), + ExpectedResult: []byte("c-1"), + ExpectedRest: nil, + ExpectedOK: true, + }, + { + Value: []byte("c-1/"), + ExpectedResult: []byte("c-1"), + ExpectedRest: []byte("/"), + ExpectedOK: true, + }, + { + Value: []byte("c-1/once/twice/thrice/fource.php"), + ExpectedResult: []byte("c-1"), + ExpectedRest: []byte("/once/twice/thrice/fource.php"), + ExpectedOK: true, + }, + { + Value: []byte("c-1."), + ExpectedResult: []byte("c-1"), + ExpectedRest: []byte("."), + ExpectedOK: true, + }, + { + Value: []byte("c-1./"), + ExpectedResult: []byte("c-1"), + ExpectedRest: []byte("./"), + ExpectedOK: true, + }, + + + + { + Value: []byte("c1-"), + ExpectedResult: []byte("c1"), + ExpectedRest: []byte("-"), + ExpectedOK: true, + }, + { + Value: []byte("c1-/"), + ExpectedResult: []byte("c1"), + ExpectedRest: []byte("-/"), + ExpectedOK: true, + }, + { + Value: []byte("c1-/once/twice/thrice/fource.php"), + ExpectedResult: []byte("c1"), + ExpectedRest: []byte("-/once/twice/thrice/fource.php"), + ExpectedOK: true, + }, + { + Value: []byte("c1-."), + ExpectedResult: []byte("c1"), + ExpectedRest: []byte("-."), + ExpectedOK: true, + }, + { + Value: []byte("c1-./"), + ExpectedResult: []byte("c1"), + ExpectedRest: []byte("-./"), + ExpectedOK: true, + }, + } + + for b0:=byte('a'); b0 <= 'z'; b0++ { + + { + test := struct{ + Value []byte + ExpectedResult []byte + ExpectedRest []byte + ExpectedOK bool + }{ + Value: []byte{b0}, + ExpectedResult: []byte{b0}, + ExpectedRest: nil, + ExpectedOK: true, + } + + tests = append(tests, test) + } + + for b1:=byte('0'); b1 <= '9'; b1++ { + + test := struct{ + Value []byte + ExpectedResult []byte + ExpectedRest []byte + ExpectedOK bool + }{ + Value: []byte{b0,b1}, + ExpectedResult: []byte{b0,b1}, + ExpectedRest: nil, + ExpectedOK: true, + } + + tests = append(tests, test) + } + + for b1:=byte('A'); b1 <= 'Z'; b1++ { + + test := struct{ + Value []byte + ExpectedResult []byte + ExpectedRest []byte + ExpectedOK bool + }{ + Value: []byte{b0,b1}, + ExpectedResult: []byte{b0,b1}, + ExpectedRest: nil, + ExpectedOK: true, + } + + tests = append(tests, test) + } + + for b1:=byte('a'); b1 <= 'z'; b1++ { + + test := struct{ + Value []byte + ExpectedResult []byte + ExpectedRest []byte + ExpectedOK bool + }{ + Value: []byte{b0,b1}, + ExpectedResult: []byte{b0,b1}, + ExpectedRest: nil, + ExpectedOK: true, + } + + tests = append(tests, test) + } + } + + for b0:=byte('A'); b0 <= 'Z'; b0++ { + + { + test := struct{ + Value []byte + ExpectedResult []byte + ExpectedRest []byte + ExpectedOK bool + }{ + Value: []byte{b0}, + ExpectedResult: []byte{b0}, + ExpectedRest: nil, + ExpectedOK: true, + } + + tests = append(tests, test) + } + + for b1:=byte('0'); b1 <= '9'; b1++ { + + test := struct{ + Value []byte + ExpectedResult []byte + ExpectedRest []byte + ExpectedOK bool + }{ + Value: []byte{b0,b1}, + ExpectedResult: []byte{b0,b1}, + ExpectedRest: nil, + ExpectedOK: true, + } + + tests = append(tests, test) + } + + for b1:=byte('A'); b1 <= 'Z'; b1++ { + + test := struct{ + Value []byte + ExpectedResult []byte + ExpectedRest []byte + ExpectedOK bool + }{ + Value: []byte{b0,b1}, + ExpectedResult: []byte{b0,b1}, + ExpectedRest: nil, + ExpectedOK: true, + } + + tests = append(tests, test) + } + + for b1:=byte('a'); b1 <= 'z'; b1++ { + + test := struct{ + Value []byte + ExpectedResult []byte + ExpectedRest []byte + ExpectedOK bool + }{ + Value: []byte{b0,b1}, + ExpectedResult: []byte{b0,b1}, + ExpectedRest: nil, + ExpectedOK: true, + } + + tests = append(tests, test) + } + } + + for testNumber, test := range tests { + + actualResult, actualRest, actualOK := toplabel.Bytes(test.Value) + + { + expected := test.ExpectedOK + actual := actualOK + + if expected != actual { + t.Errorf("For test #%d, the actual ok-result is not what was expected.", testNumber) + t.Logf("EXPECTED: %t", expected) + t.Logf("ACTUAL: %t", actual) + t.Logf("VALUE: %q", test.Value) + continue + } + } + + { + expected := test.ExpectedResult + actual := actualResult + + if !bytes.Equal(expected, actual) { + t.Errorf("For test #%d, the actual result is not what was expected.", testNumber) + t.Logf("EXPECTED: %q (%#v)", expected, expected) + t.Logf("ACTUAL: %q (%#v)", actual, actual) + t.Logf("VALUE: %q", test.Value) + t.Logf("ACTUAL-REST: %q (%#v)", actualRest, actualRest) + continue + } + } + + { + expected := test.ExpectedRest + actual := actualRest + + if !bytes.Equal(expected, actual) { + t.Errorf("For test #%d, the actual rest is not what was expected.", testNumber) + t.Logf("EXPECTED: %q (%#v)", expected, expected) + t.Logf("ACTUAL: %q (%#v)", actual, actual) + t.Logf("VALUE: %q", test.Value) + continue + } + } + } +}