github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/identifier/identifier_test.go (about) 1 package identifier 2 3 import ( 4 "bytes" 5 "math" 6 "strings" 7 "testing" 8 9 "github.com/mutagen-io/mutagen/pkg/encoding" 10 ) 11 12 const ( 13 // expectedIdentifierLength is the expected length for identifiers. 14 expectedIdentifierLength = requiredPrefixLength + 1 + targetBase62Length 15 ) 16 17 // TestLengthRelationships tests the mathematical relationship between 18 // collisionResistantLength and targetBase62Length. 19 func TestLengthRelationships(t *testing.T) { 20 if targetBase62Length != int(math.Ceil(collisionResistantLength*8*math.Log(2)/math.Log(62))) { 21 t.Error("target base62 length incorrect for collision resistant length") 22 } 23 } 24 25 // TestIdentifierCreation tests identifier creation. 26 func TestIdentifierCreation(t *testing.T) { 27 // Set up test cases. 28 testCases := []string{ 29 PrefixSynchronization, 30 PrefixForwarding, 31 PrefixProject, 32 PrefixPrompter, 33 } 34 35 // Process test cases. 36 for _, prefix := range testCases { 37 // Create an identifier with the specified prefix. 38 identifier, err := New(prefix) 39 if err != nil { 40 t.Fatal("unable to create identifier:", err) 41 } 42 43 // Ensure that the prefix is present. 44 if !strings.HasPrefix(identifier, prefix) { 45 t.Error("identifier does not have correct prefix") 46 } 47 48 // Ensure that the length is what's expected. 49 if len(identifier) != expectedIdentifierLength { 50 t.Error("identifier has unexpected length") 51 } 52 } 53 } 54 55 // TestInvalidPrefixLength tests that identifier creation fails with an invalid 56 // prefix length. 57 func TestPrefixLengthEnforcement(t *testing.T) { 58 if _, err := New("xyz"); err == nil { 59 t.Error("invalid prefix length accepted") 60 } 61 } 62 63 // TestInvalidPrefixCharacter tests that identifier creation fails when a prefix 64 // contains invalid characters. 65 func TestInvalidPrefixCharacter(t *testing.T) { 66 if _, err := New("XYZ"); err == nil { 67 t.Error("invalid prefix characters accepted") 68 } 69 } 70 71 // TestIsValid tests that IsValid behaves correctly for an assortment of values. 72 func TestIsValid(t *testing.T) { 73 // Set up test cases. 74 testCases := []struct { 75 value string 76 expectValid bool 77 }{ 78 {"", false}, 79 {"abc", false}, 80 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", false}, 81 {"75A0FDC4-5C08-4AA4-99B5-154350DEA3DB", false}, 82 {"75a0fdc4-5c08-4aa4-99b5-154350dea3dba", false}, 83 {"proj_jndACgB0qejgkorhU21q4oA56QvEfqV1p2yBH9N40h+", false}, 84 {"proj_jndACgB0qejgkorhU21q4oA56QvEfqV1p2yBH9N40hK1", false}, 85 {"pro9_jndACgB0qejgkorhU21q4oA56QvEfqV1p2yBH9N40hK", false}, 86 {"PROJ_jndACgB0qejgkorhU21q4oA56QvEfqV1p2yBH9N40hK", false}, 87 {"75a0fdc4-5c08-4aa4-99b5-154350dea3db", true}, 88 {"proj_jndACgB0qejgkorhU21q4oA56QvEfqV1p2yBH9N40hK", true}, 89 } 90 91 // Process test cases. 92 for _, testCase := range testCases { 93 if valid := IsValid(testCase.value); valid && !testCase.expectValid { 94 t.Error("identifier unexpectedly classified as valid:", testCase.value) 95 } else if !valid && testCase.expectValid { 96 t.Error("identifier unexpectedly classified as invalid:", testCase.value) 97 } 98 } 99 } 100 101 // TestLeftPadRemoval tests that the original bytes of an identifier can be 102 // extracted after padding in Base62 encoding. 103 func TestLeftPadRemoval(t *testing.T) { 104 // Set up test cases. We use 16 byte values, which means that the target 105 // length for Base62-encoded values should be 22. 106 testCases := [][]byte{ 107 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 108 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 109 {0x01, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 110 {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 111 {0xf2, 0xa7, 0x30, 0x90, 0x01, 0x7b, 0x00, 0x01, 0xff, 0xfe, 0x0f, 0x1f, 0xa1, 0x0a, 0x0f, 0xf0}, 112 {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 113 } 114 115 // Process test cases. 116 for _, value := range testCases { 117 // Encode the value. 118 encoded := encoding.EncodeBase62(value) 119 120 // Create a string builder. 121 builder := &strings.Builder{} 122 123 // If the encoded value has a length less than the target length, then 124 // left-pad it with 0s. 125 for i := 22 - len(encoded); i > 0; i-- { 126 builder.WriteByte(encoding.Base62Alphabet[0]) 127 } 128 129 // Write the encoded value. 130 builder.WriteString(encoded) 131 132 // Decode the resulting string. 133 decoded, err := encoding.DecodeBase62(builder.String()) 134 if err != nil { 135 t.Error("unable to decode value:", err) 136 } else if !bytes.Equal(decoded[len(decoded)-16:], value) { 137 t.Error("decoded and extracted bytes do not match original") 138 } 139 } 140 }