github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/uuid_test.go (about)

     1  // Copyright 2021 DataStax
     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 datacodec
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  
    21  	"github.com/stretchr/testify/assert"
    22  
    23  	"github.com/datastax/go-cassandra-native-protocol/datatype"
    24  	"github.com/datastax/go-cassandra-native-protocol/primitive"
    25  )
    26  
    27  var (
    28  	uuid      = primitive.UUID{0xC0, 0xD1, 0xD2, 0x1E, 0xBB, 0x01, 0x41, 0x96, 0x86, 0xDB, 0xBC, 0x31, 0x7B, 0xC1, 0x79, 0x6A}
    29  	uuidBytes = []byte{0xC0, 0xD1, 0xD2, 0x1E, 0xBB, 0x01, 0x41, 0x96, 0x86, 0xDB, 0xBC, 0x31, 0x7B, 0xC1, 0x79, 0x6A}
    30  )
    31  
    32  func Test_uuidCodec_DataType(t *testing.T) {
    33  	assert.Equal(t, datatype.Uuid, Uuid.DataType())
    34  	assert.Equal(t, datatype.Timeuuid, Timeuuid.DataType())
    35  }
    36  
    37  func Test_uuidCodec_Encode(t *testing.T) {
    38  	codecs := []Codec{Uuid, Timeuuid}
    39  	for _, codec := range codecs {
    40  		t.Run(codec.DataType().AsCql(), func(t *testing.T) {
    41  			for _, version := range primitive.SupportedProtocolVersions() {
    42  				t.Run(version.String(), func(t *testing.T) {
    43  					tests := []struct {
    44  						name     string
    45  						source   interface{}
    46  						expected []byte
    47  						err      string
    48  					}{
    49  						{"nil", nil, nil, ""},
    50  						{"nil pointer", uuidNilPtr(), nil, ""},
    51  						{"zero", primitive.UUID{}, (&primitive.UUID{}).Bytes(), ""},
    52  						{"non nil", uuid, uuidBytes, ""},
    53  						{"non nil pointer", &uuid, uuidBytes, ""},
    54  						{"conversion failed", 123, nil, fmt.Sprintf("cannot encode int as CQL %v with %v: cannot convert from int to []uint8: conversion not supported", codec.DataType(), version)},
    55  					}
    56  					for _, tt := range tests {
    57  						t.Run(tt.name, func(t *testing.T) {
    58  							actual, err := codec.Encode(tt.source, version)
    59  							assert.Equal(t, tt.expected, actual)
    60  							assertErrorMessage(t, tt.err, err)
    61  						})
    62  					}
    63  				})
    64  			}
    65  		})
    66  	}
    67  }
    68  
    69  func Test_uuidCodec_Decode(t *testing.T) {
    70  	codecs := []Codec{Uuid, Timeuuid}
    71  	for _, codec := range codecs {
    72  		t.Run(codec.DataType().AsCql(), func(t *testing.T) {
    73  			for _, version := range primitive.SupportedProtocolVersions() {
    74  				t.Run(version.String(), func(t *testing.T) {
    75  					tests := []struct {
    76  						name     string
    77  						source   []byte
    78  						dest     interface{}
    79  						expected interface{}
    80  						wasNull  bool
    81  						err      string
    82  					}{
    83  						{"null", nil, new(primitive.UUID), new(primitive.UUID), true, ""},
    84  						{"zero", []byte{}, new(primitive.UUID), new(primitive.UUID), true, ""},
    85  						{"non null", uuidBytes, new(primitive.UUID), &uuid, false, ""},
    86  						{"non null interface", uuidBytes, new(interface{}), interfacePtr(uuid), false, ""},
    87  						{"invalid", []byte{1, 2, 3}, new(primitive.UUID), new(primitive.UUID), false, fmt.Sprintf("cannot decode CQL %v as *primitive.UUID with %v: cannot read []uint8: expected 16 bytes but got: 3", codec.DataType(), version)},
    88  						{"conversion failed", uuidBytes, new(float64), new(float64), false, fmt.Sprintf("cannot decode CQL %v as *float64 with %v: cannot convert from []uint8 to *float64: conversion not supported", codec.DataType(), version)},
    89  					}
    90  					for _, tt := range tests {
    91  						t.Run(tt.name, func(t *testing.T) {
    92  							wasNull, err := codec.Decode(tt.source, tt.dest, version)
    93  							assert.Equal(t, tt.expected, tt.dest)
    94  							assert.Equal(t, tt.wasNull, wasNull)
    95  							assertErrorMessage(t, tt.err, err)
    96  						})
    97  					}
    98  				})
    99  			}
   100  		})
   101  	}
   102  }
   103  
   104  func Test_convertToUuid(t *testing.T) {
   105  	tests := []struct {
   106  		name     string
   107  		source   interface{}
   108  		wantDest []byte
   109  		wantErr  string
   110  	}{
   111  		{"from primitive.UUID", uuid, uuidBytes, ""},
   112  		{"from *primitive.UUID", &uuid, uuidBytes, ""},
   113  		{"from *primitive.UUID nil", uuidNilPtr(), nil, ""},
   114  		{"from []byte", uuidBytes, uuidBytes, ""},
   115  		{"from []byte wrong length", []byte{1, 2, 3}, nil, "cannot convert from []uint8 to []uint8: expected 16 bytes but got: 3"},
   116  		{"from []byte wrong length oversize", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, nil, "cannot convert from []uint8 to []uint8: expected 16 bytes but got: 17"},
   117  		{"from *[]byte", &uuidBytes, uuidBytes, ""},
   118  		{"from *[]byte nil", byteSliceNilPtr(), nil, ""},
   119  		{"from *[]byte wrong length", &[]byte{1, 2, 3}, nil, "cannot convert from *[]uint8 to []uint8: expected 16 bytes but got: 3"},
   120  		{"from *[]byte wrong length oversize", &[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, nil, "cannot convert from *[]uint8 to []uint8: expected 16 bytes but got: 17"},
   121  		{"from [16]byte", [16]byte(uuid), uuidBytes, ""},
   122  		{"from *[16]byte", byteArrayPtr(uuid), uuidBytes, ""},
   123  		{"from *[16]byte nil", byteArrayNilPtr(), nil, ""},
   124  		{"from string", uuid.String(), uuidBytes, ""},
   125  		{"from string wrong", "not a valid uuid", nil, "cannot convert from string to []uint8: invalid UUID: \"not a valid uuid\""},
   126  		{"from *string", stringPtr(uuid.String()), uuidBytes, ""},
   127  		{"from *string nil", byteSliceNilPtr(), nil, ""},
   128  		{"from *string wrong", stringPtr("not a valid uuid"), nil, "cannot convert from *string to []uint8: invalid UUID: \"not a valid uuid\""},
   129  		{"from untyped nil", nil, nil, ""},
   130  		{"from unsupported value type", 123, nil, "cannot convert from int to []uint8: conversion not supported"},
   131  		{"from unsupported pointer type", intPtr(123), nil, "cannot convert from *int to []uint8: conversion not supported"},
   132  	}
   133  	for _, tt := range tests {
   134  		t.Run(tt.name, func(t *testing.T) {
   135  			gotDest, gotErr := convertToUuidBytes(tt.source)
   136  			assert.Equal(t, tt.wantDest, gotDest)
   137  			assertErrorMessage(t, tt.wantErr, gotErr)
   138  		})
   139  	}
   140  }
   141  
   142  func Test_convertFromUuid(t *testing.T) {
   143  	tests := []struct {
   144  		name     string
   145  		val      []byte
   146  		wasNull  bool
   147  		dest     interface{}
   148  		expected interface{}
   149  		err      string
   150  	}{
   151  		{"to *interface{} nil dest", uuidBytes, false, interfaceNilPtr(), interfaceNilPtr(), "cannot convert from []uint8 to *interface {}: destination is nil"},
   152  		{"to *interface{} nil source", nil, true, new(interface{}), new(interface{}), ""},
   153  		{"to *interface{} non nil", uuidBytes, false, new(interface{}), interfacePtr(uuid), ""},
   154  		{"to *primitive.UUID nil dest", uuidBytes, false, uuidNilPtr(), uuidNilPtr(), "cannot convert from []uint8 to *primitive.UUID: destination is nil"},
   155  		{"to *primitive.UUID empty source", []byte{}, true, new(primitive.UUID), new(primitive.UUID), ""},
   156  		{"to *primitive.UUID wrong length", []byte{1, 2, 3}, false, new(primitive.UUID), &primitive.UUID{1, 2, 3}, ""},
   157  		{"to *primitive.UUID wrong length oversize", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, false, new(primitive.UUID), &primitive.UUID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, ""},
   158  		{"to *primitive.UUID non nil", uuidBytes, false, new(primitive.UUID), &uuid, ""},
   159  		{"to *[]byte nil dest", uuidBytes, false, byteSliceNilPtr(), byteSliceNilPtr(), "cannot convert from []uint8 to *[]uint8: destination is nil"},
   160  		{"to *[]byte empty source", []byte{}, true, new([]byte), new([]byte), ""},
   161  		{"to *[]byte non nil", uuidBytes, false, new([]byte), &uuidBytes, ""},
   162  		{"to *[]byte wrong length", []byte{1, 2, 3}, false, new([]byte), &[]byte{1, 2, 3}, ""},
   163  		{"to *[]byte wrong length oversize", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, false, new([]byte), &[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, ""},
   164  		{"to *[16]byte nil dest", uuidBytes, false, byteArrayNilPtr(), byteArrayNilPtr(), "cannot convert from []uint8 to *[16]uint8: destination is nil"},
   165  		{"to *[16]byte empty source", []byte{}, true, new([16]byte), new([16]byte), ""},
   166  		{"to *[16]byte non nil", uuidBytes, false, new([16]byte), byteArrayPtr(uuid), ""},
   167  		{"to *[16]byte wrong length", []byte{1, 2, 3}, false, new([16]byte), &[16]byte{1, 2, 3}, ""},
   168  		{"to *[16]byte wrong length oversize", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, false, new([16]byte), &[16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, ""},
   169  		{"to *string nil dest", uuidBytes, false, stringNilPtr(), stringNilPtr(), "cannot convert from []uint8 to *string: destination is nil"},
   170  		{"to *string empty source", []byte{}, true, new(string), new(string), ""},
   171  		{"to *string non nil", uuidBytes, false, new(string), stringPtr(uuid.String()), ""},
   172  		{"to *string wrong length", []byte{1, 2, 3}, false, new(string), stringPtr("01020300-0000-0000-0000-000000000000"), ""},
   173  		{"to *string wrong length oversize", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, false, new(string), stringPtr("01020304-0506-0708-090a-0b0c0d0e0f10"), ""},
   174  		{"to untyped nil", uuidBytes, false, nil, nil, "cannot convert from []uint8 to <nil>: destination is nil"},
   175  		{"to non pointer", uuidBytes, false, primitive.UUID{}, primitive.UUID{}, "cannot convert from []uint8 to primitive.UUID: destination is not pointer"},
   176  		{"to unsupported pointer type", uuidBytes, false, new(float64), new(float64), "cannot convert from []uint8 to *float64: conversion not supported"},
   177  	}
   178  	for _, tt := range tests {
   179  		t.Run(tt.name, func(t *testing.T) {
   180  			gotErr := convertFromUuidBytes(tt.val, tt.wasNull, tt.dest)
   181  			assert.Equal(t, tt.expected, tt.dest)
   182  			assertErrorMessage(t, tt.err, gotErr)
   183  		})
   184  	}
   185  }
   186  
   187  func Test_readUuid(t *testing.T) {
   188  	tests := []struct {
   189  		name     string
   190  		source   []byte
   191  		expected []byte
   192  		wasNull  bool
   193  		err      string
   194  	}{
   195  		{"null", nil, nil, true, ""},
   196  		{"empty", []byte{}, nil, true, ""},
   197  		{"wrong length", []byte{1}, nil, false, "cannot read []uint8: expected 16 bytes but got: 1"},
   198  		{"non null", uuidBytes, uuidBytes, false, ""},
   199  	}
   200  	for _, tt := range tests {
   201  		t.Run(tt.name, func(t *testing.T) {
   202  			actual, wasNull, err := readUuid(tt.source)
   203  			assert.Equal(t, tt.expected, actual)
   204  			assert.Equal(t, tt.wasNull, wasNull)
   205  			assertErrorMessage(t, tt.err, err)
   206  		})
   207  	}
   208  }