github.com/creachadair/ffs@v0.17.3/storage/hexkey/hexkey_test.go (about) 1 // Copyright 2024 Michael J. Fromberger. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package hexkey_test 16 17 import ( 18 "strings" 19 "testing" 20 21 "github.com/creachadair/ffs/storage/hexkey" 22 ) 23 24 func TestConfig(t *testing.T) { 25 tests := []struct { 26 name string 27 config hexkey.Config 28 input, want string 29 }{ 30 {"PlainEmpty", hexkey.Config{}, "", ""}, 31 {"PlainKey", hexkey.Config{}, "\x01\x02\x03", "010203"}, 32 {"Prefix", hexkey.Config{Prefix: "foo"}, "0123", "foo/30313233"}, 33 {"Shard1", hexkey.Config{Shard: 1}, "\xab\xcd", "a/abcd"}, 34 {"Shard2", hexkey.Config{Shard: 2}, "\xab\xcd\xef", "ab/abcdef"}, 35 {"Shard3", hexkey.Config{Shard: 3}, "\x01\x02\x03\x04", "010/01020304"}, 36 {"EmptyShard", hexkey.Config{Shard: 3}, "", "---/-"}, 37 {"ShortShard", hexkey.Config{Shard: 3}, "\x01", "01-/01"}, 38 {"PrefixShard", hexkey.Config{Prefix: "foo", Shard: 4}, "ABCDE", "foo/4142/4142434445"}, 39 {"LongShard", hexkey.Config{Shard: 8}, "ABC", "414243--/414243"}, 40 } 41 for _, tc := range tests { 42 t.Run(tc.name, func(t *testing.T) { 43 enc := tc.config.Encode(tc.input) 44 if enc != tc.want { 45 t.Errorf("Encode %q: got %q, want %q", tc.input, enc, tc.want) 46 } 47 48 dec, err := tc.config.Decode(enc) 49 if err != nil { 50 t.Errorf("Decode %q: unexpected error: %v", enc, err) 51 } else if dec != tc.input { 52 t.Errorf("Decode %q: got %q, want %q", enc, dec, tc.input) 53 } 54 }) 55 } 56 } 57 58 func TestStart(t *testing.T) { 59 tests := []struct { 60 name string 61 config hexkey.Config 62 input, want string 63 }{ 64 {"AllEmpty", hexkey.Config{}, "", ""}, 65 {"NoShard", hexkey.Config{}, "\x01\x23", "0123"}, 66 {"Shard2", hexkey.Config{Shard: 2}, "\x01\x23\x45", "01/012345"}, 67 {"Shard3", hexkey.Config{Shard: 3}, "\x01\x23\x45", "012/012345"}, 68 {"Shard10", hexkey.Config{Shard: 10}, "\x01\x23\x45", "012345"}, 69 {"Prefix0", hexkey.Config{Prefix: "ok"}, "\xab\xcd", "ok/abcd"}, 70 {"Prefix2", hexkey.Config{Prefix: "ok", Shard: 2}, "\xab\xcd\xef", "ok/ab/abcdef"}, 71 {"Prefix5", hexkey.Config{Prefix: "ok", Shard: 5}, "\xab\xcd\xef", "ok/abcde/abcdef"}, 72 {"Prefix10", hexkey.Config{Prefix: "ok", Shard: 10}, "\xab\xcd\xef", "ok/abcdef"}, 73 } 74 for _, tc := range tests { 75 t.Run(tc.name, func(t *testing.T) { 76 got := tc.config.Start(tc.input) 77 if got != tc.want { 78 t.Errorf("Start %q: got %q, want %q", tc.input, got, tc.want) 79 } 80 }) 81 } 82 } 83 84 func TestDecodeErrors(t *testing.T) { 85 estr := hexkey.ErrNotMyKey.Error() 86 tests := []struct { 87 name string 88 config hexkey.Config 89 input string 90 errtext string 91 }{ 92 {"NonHex", hexkey.Config{}, "garbage", "invalid byte"}, 93 {"NoPrefix", hexkey.Config{Prefix: "foo"}, "010203", estr}, 94 {"BadShard", hexkey.Config{Shard: 3}, "0a/0b0c0d", estr}, 95 {"EmptyTail", hexkey.Config{Shard: 3}, "0a0/", estr}, 96 {"BadHex", hexkey.Config{Shard: 3}, "0a0/0a0", "odd length hex"}, 97 {"PrefixBadHex", hexkey.Config{Prefix: "foo", Shard: 3}, "foo/abc/abcdefgh", "invalid byte"}, 98 {"PrefixShort", hexkey.Config{Prefix: "bar", Shard: 3}, "foo/012", estr}, 99 } 100 for _, tc := range tests { 101 t.Run(tc.name, func(t *testing.T) { 102 dec, err := tc.config.Decode(tc.input) 103 if err == nil { 104 t.Errorf("Decode %q: got %q, want error", tc.input, dec) 105 } else if got := err.Error(); !strings.Contains(got, tc.errtext) { 106 t.Errorf("Decode %q: got %v, want %q", tc.input, err, tc.errtext) 107 } 108 }) 109 } 110 }