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

     1  // Copyright 2020 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 message
    16  
    17  import (
    18  	"bytes"
    19  	"errors"
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  
    24  	"github.com/datastax/go-cassandra-native-protocol/primitive"
    25  )
    26  
    27  func TestSupported_DeepCopy(t *testing.T) {
    28  	msg := &Supported{
    29  		Options: map[string][]string{
    30  			"opt1": {"val1"},
    31  			"opt2": {"val2"},
    32  		},
    33  	}
    34  
    35  	cloned := msg.DeepCopy()
    36  	assert.Equal(t, msg, cloned)
    37  
    38  	cloned.Options["opt1"] = []string{"val5"}
    39  	cloned.Options["opt3"] = []string{"val6"}
    40  
    41  	assert.NotEqual(t, msg, cloned)
    42  
    43  	assert.Equal(t, "val1", msg.Options["opt1"][0])
    44  	assert.Equal(t, "val2", msg.Options["opt2"][0])
    45  
    46  	assert.Equal(t, "val5", cloned.Options["opt1"][0])
    47  	assert.Equal(t, "val2", cloned.Options["opt2"][0])
    48  	assert.Equal(t, "val6", cloned.Options["opt3"][0])
    49  }
    50  
    51  func TestSupportedCodec_Encode(test *testing.T) {
    52  	codec := &supportedCodec{}
    53  	for _, version := range primitive.SupportedProtocolVersions() {
    54  		test.Run(version.String(), func(test *testing.T) {
    55  			tests := []struct {
    56  				name     string
    57  				input    Message
    58  				expected [][]byte // required because there can be multiple valid encodings
    59  				err      error
    60  			}{
    61  				{
    62  					"supported with nil options",
    63  					&Supported{},
    64  					[][]byte{{0, 0}},
    65  					nil,
    66  				},
    67  				{
    68  					"supported with empty options",
    69  					&Supported{Options: map[string][]string{}},
    70  					[][]byte{{0, 0}},
    71  					nil,
    72  				},
    73  				{
    74  					"supported with 1 option",
    75  					&Supported{Options: map[string][]string{"option1": {"value1a", "value1b"}}},
    76  					[][]byte{{
    77  						0, 1, // map length
    78  						// key "option1"
    79  						0, 7, o, p, t, i, o, n, _1,
    80  						// list length
    81  						0, 2,
    82  						// value1a
    83  						0, 7, v, a, l, u, e, _1, a,
    84  						// value1b
    85  						0, 7, v, a, l, u, e, _1, b,
    86  					}},
    87  					nil,
    88  				},
    89  				{
    90  					"supported with 2 options",
    91  					&Supported{Options: map[string][]string{"option1": {"value1a", "value1b"}, "option2": {"value2a", "value2b"}}},
    92  					// we have two possible encodings because maps do not have deterministic iteration order
    93  					[][]byte{
    94  						{
    95  							0, 2, // map length
    96  							// key "option1"
    97  							0, 7, o, p, t, i, o, n, _1,
    98  							// list length
    99  							0, 2,
   100  							// value1a
   101  							0, 7, v, a, l, u, e, _1, a,
   102  							// value1b
   103  							0, 7, v, a, l, u, e, _1, b,
   104  							// key "option2"
   105  							0, 7, o, p, t, i, o, n, _2,
   106  							// list length
   107  							0, 2,
   108  							// value1a
   109  							0, 7, v, a, l, u, e, _2, a,
   110  							// value1b
   111  							0, 7, v, a, l, u, e, _2, b,
   112  						},
   113  						{
   114  							0, 2, // map length
   115  							// key "option2"
   116  							0, 7, o, p, t, i, o, n, _2,
   117  							// list length
   118  							0, 2,
   119  							// value1a
   120  							0, 7, v, a, l, u, e, _2, a,
   121  							// value1b
   122  							0, 7, v, a, l, u, e, _2, b,
   123  							// key "option1"
   124  							0, 7, o, p, t, i, o, n, _1,
   125  							// list length
   126  							0, 2,
   127  							// value1a
   128  							0, 7, v, a, l, u, e, _1, a,
   129  							// value1b
   130  							0, 7, v, a, l, u, e, _1, b,
   131  						},
   132  					},
   133  					nil,
   134  				},
   135  				{
   136  					"not a supported",
   137  					&Options{},
   138  					nil,
   139  					errors.New("expected *message.Supported, got *message.Options"),
   140  				},
   141  			}
   142  			for _, tt := range tests {
   143  				test.Run(tt.name, func(t *testing.T) {
   144  					dest := &bytes.Buffer{}
   145  					err := codec.Encode(tt.input, dest, version)
   146  					if err == nil {
   147  						assert.Contains(t, tt.expected, dest.Bytes())
   148  						assert.Nil(t, tt.err)
   149  					} else {
   150  						assert.Equal(t, tt.err, err)
   151  					}
   152  				})
   153  			}
   154  		})
   155  	}
   156  }
   157  
   158  func TestSupportedCodec_EncodedLength(test *testing.T) {
   159  	codec := &supportedCodec{}
   160  	for _, version := range primitive.SupportedProtocolVersions() {
   161  		test.Run(version.String(), func(test *testing.T) {
   162  			tests := []encodedLengthTestCase{
   163  				{
   164  					"supported with nil options",
   165  					&Supported{},
   166  					primitive.LengthOfShort, // map length
   167  					nil,
   168  				},
   169  				{
   170  					"supported with empty options",
   171  					&Supported{Options: map[string][]string{}},
   172  					primitive.LengthOfShort, // map length
   173  					nil,
   174  				},
   175  				{
   176  					"supported with 1 option",
   177  					&Supported{Options: map[string][]string{"option1": {"value1a", "value1b"}}},
   178  					primitive.LengthOfShort + // map length
   179  						primitive.LengthOfString("option1") + // map key
   180  						primitive.LengthOfShort + // list length
   181  						primitive.LengthOfString("value1a") + // map value
   182  						primitive.LengthOfString("value1b"), // map value
   183  					nil,
   184  				},
   185  				{
   186  					"supported with 2 options",
   187  					&Supported{Options: map[string][]string{"option1": {"value1a", "value1b"}, "option2": {"value2a", "value2b"}}},
   188  					primitive.LengthOfShort + // map length
   189  						primitive.LengthOfString("option1") + // map key
   190  						primitive.LengthOfShort + // list length
   191  						primitive.LengthOfString("value1a") + // map value
   192  						primitive.LengthOfString("value1b") + // map value
   193  						primitive.LengthOfString("option2") + // map key
   194  						primitive.LengthOfShort + // list length
   195  						primitive.LengthOfString("value2a") + // map value
   196  						primitive.LengthOfString("value2b"), // map value
   197  					nil,
   198  				},
   199  				{
   200  					"not a supported",
   201  					&Options{},
   202  					-1,
   203  					errors.New("expected *message.Supported, got *message.Options"),
   204  				},
   205  			}
   206  			for _, tt := range tests {
   207  				test.Run(tt.name, func(t *testing.T) {
   208  					actual, err := codec.EncodedLength(tt.input, version)
   209  					assert.Equal(t, tt.expected, actual)
   210  					assert.Equal(t, tt.err, err)
   211  				})
   212  			}
   213  		})
   214  	}
   215  }
   216  
   217  func TestSupportedCodec_Decode(test *testing.T) {
   218  	codec := &supportedCodec{}
   219  	for _, version := range primitive.SupportedProtocolVersions() {
   220  		test.Run(version.String(), func(test *testing.T) {
   221  			tests := []decodeTestCase{
   222  				{
   223  					"supported with empty options",
   224  					[]byte{0, 0},
   225  					&Supported{Options: map[string][]string{}},
   226  					nil,
   227  				},
   228  				{
   229  					"supported with 1 option",
   230  					[]byte{
   231  						0, 1, // map length
   232  						// key "option1"
   233  						0, 7, o, p, t, i, o, n, _1,
   234  						// list length
   235  						0, 2,
   236  						// value1a
   237  						0, 7, v, a, l, u, e, _1, a,
   238  						// value1b
   239  						0, 7, v, a, l, u, e, _1, b,
   240  					},
   241  					&Supported{Options: map[string][]string{"option1": {"value1a", "value1b"}}},
   242  					nil,
   243  				},
   244  				{
   245  					"supported with 2 options",
   246  					// we have two possible encodings because maps do not have deterministic iteration order
   247  					[]byte{
   248  						0, 2, // map length
   249  						// key "option1"
   250  						0, 7, o, p, t, i, o, n, _1,
   251  						// list length
   252  						0, 2,
   253  						// value1a
   254  						0, 7, v, a, l, u, e, _1, a,
   255  						// value1b
   256  						0, 7, v, a, l, u, e, _1, b,
   257  						// key "option2"
   258  						0, 7, o, p, t, i, o, n, _2,
   259  						// list length
   260  						0, 2,
   261  						// value1a
   262  						0, 7, v, a, l, u, e, _2, a,
   263  						// value1b
   264  						0, 7, v, a, l, u, e, _2, b,
   265  					},
   266  					&Supported{Options: map[string][]string{"option1": {"value1a", "value1b"}, "option2": {"value2a", "value2b"}}},
   267  					nil,
   268  				},
   269  			}
   270  			for _, tt := range tests {
   271  				test.Run(tt.name, func(t *testing.T) {
   272  					source := bytes.NewBuffer(tt.input)
   273  					actual, err := codec.Decode(source, version)
   274  					assert.Equal(t, tt.expected, actual)
   275  					assert.Equal(t, tt.err, err)
   276  				})
   277  			}
   278  		})
   279  	}
   280  }