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  }