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  }