github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/primitive/values_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 primitive
    16  
    17  import (
    18  	"bytes"
    19  	"errors"
    20  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  )
    25  
    26  func TestReadValue(t *testing.T) {
    27  	// versions < 4
    28  	for _, version := range SupportedProtocolVersionsLesserThan(ProtocolVersion4) {
    29  		t.Run(version.String(), func(t *testing.T) {
    30  			tests := []struct {
    31  				name     string
    32  				source   []byte
    33  				expected *Value
    34  				err      error
    35  			}{
    36  				{
    37  					"value length null",
    38  					[]byte{
    39  						0xff, 0xff, 0xff, 0xff, // length -1
    40  					},
    41  					NewNullValue(),
    42  					nil,
    43  				},
    44  				{
    45  					"value length unset",
    46  					[]byte{
    47  						0xff, 0xff, 0xff, 0xfe, // length -2
    48  					},
    49  					nil,
    50  					fmt.Errorf("cannot use unset value with %v", version),
    51  				},
    52  				{
    53  					"value empty",
    54  					[]byte{
    55  						0, 0, 0, 0, // length
    56  					},
    57  					NewValue([]byte{}),
    58  					nil,
    59  				},
    60  				{
    61  					"value non empty",
    62  					[]byte{
    63  						0, 0, 0, 5, // length
    64  						1, 2, 3, 4, 5, // contents
    65  					},
    66  					NewValue([]byte{1, 2, 3, 4, 5}),
    67  					nil,
    68  				},
    69  				{
    70  					"cannot read value length",
    71  					[]byte{
    72  						0, 0, 0,
    73  					},
    74  					nil,
    75  					fmt.Errorf("cannot read [value] length: %w",
    76  						fmt.Errorf("cannot read [int]: %w",
    77  							errors.New("unexpected EOF")),
    78  					),
    79  				},
    80  				{
    81  					"invalid value length",
    82  					[]byte{
    83  						0xff, 0xff, 0xff, 0xfd, // -3
    84  					},
    85  					nil,
    86  					errors.New("invalid [value] length: -3"),
    87  				},
    88  				{
    89  					"cannot read value contents",
    90  					[]byte{
    91  						0, 0, 0, 2, // length
    92  						1, // contents
    93  					},
    94  					nil,
    95  					fmt.Errorf("cannot read [value] content: %w",
    96  						errors.New("unexpected EOF")),
    97  				},
    98  			}
    99  			for _, tt := range tests {
   100  				t.Run(tt.name, func(t *testing.T) {
   101  					buf := bytes.NewReader(tt.source)
   102  					actual, err := ReadValue(buf, version)
   103  					assert.Equal(t, tt.expected, actual)
   104  					assert.Equal(t, tt.err, err)
   105  				})
   106  			}
   107  		})
   108  	}
   109  	// versions >= 4
   110  	for _, version := range SupportedProtocolVersionsGreaterThanOrEqualTo(ProtocolVersion4) {
   111  		t.Run(version.String(), func(t *testing.T) {
   112  			var tests = []struct {
   113  				name     string
   114  				source   []byte
   115  				expected *Value
   116  				err      error
   117  			}{
   118  				{
   119  					"value length null",
   120  					[]byte{
   121  						0xff, 0xff, 0xff, 0xff, // length -1
   122  					},
   123  					NewNullValue(),
   124  					nil,
   125  				},
   126  				{
   127  					"value length unset",
   128  					[]byte{
   129  						0xff, 0xff, 0xff, 0xfe, // length -2
   130  					},
   131  					NewUnsetValue(),
   132  					nil,
   133  				},
   134  				{
   135  					"value empty",
   136  					[]byte{
   137  						0, 0, 0, 0, // length
   138  					},
   139  					NewValue([]byte{}),
   140  					nil,
   141  				},
   142  				{
   143  					"value non empty",
   144  					[]byte{
   145  						0, 0, 0, 5, // length
   146  						1, 2, 3, 4, 5, // contents
   147  					},
   148  					NewValue([]byte{1, 2, 3, 4, 5}),
   149  					nil,
   150  				},
   151  				{
   152  					"cannot read value length",
   153  					[]byte{
   154  						0, 0, 0,
   155  					},
   156  					nil,
   157  					fmt.Errorf("cannot read [value] length: %w",
   158  						fmt.Errorf("cannot read [int]: %w",
   159  							errors.New("unexpected EOF")),
   160  					),
   161  				},
   162  				{
   163  					"invalid value length",
   164  					[]byte{
   165  						0xff, 0xff, 0xff, 0xfd, // -3
   166  					},
   167  					nil,
   168  					errors.New("invalid [value] length: -3"),
   169  				},
   170  				{
   171  					"cannot read value contents",
   172  					[]byte{
   173  						0, 0, 0, 2, // length
   174  						1, // contents
   175  					},
   176  					nil,
   177  					fmt.Errorf("cannot read [value] content: %w",
   178  						errors.New("unexpected EOF")),
   179  				},
   180  			}
   181  			for _, tt := range tests {
   182  				t.Run(tt.name, func(t *testing.T) {
   183  					buf := bytes.NewReader(tt.source)
   184  					actual, err := ReadValue(buf, version)
   185  					assert.Equal(t, tt.expected, actual)
   186  					assert.Equal(t, tt.err, err)
   187  				})
   188  			}
   189  		})
   190  	}
   191  }
   192  
   193  func TestWriteValue(t *testing.T) {
   194  	// versions < 4
   195  	for _, version := range SupportedProtocolVersionsLesserThan(ProtocolVersion4) {
   196  		t.Run(version.String(), func(t *testing.T) {
   197  			tests := []struct {
   198  				name     string
   199  				input    *Value
   200  				expected []byte
   201  				err      error
   202  			}{
   203  				{
   204  					"nil value",
   205  					nil,
   206  					nil,
   207  					errors.New("cannot write a nil [value]"),
   208  				},
   209  				{
   210  					"empty value (type regular, nil contents)",
   211  					&Value{},
   212  					[]byte{0xff, 0xff, 0xff, 0xff}, // length -1
   213  					nil,
   214  				},
   215  				{
   216  					"non empty value (type regular, non nil contents)",
   217  					&Value{
   218  						Type:     ValueTypeRegular,
   219  						Contents: []byte{1, 2, 3, 4},
   220  					},
   221  					[]byte{0, 0, 0, 4, 1, 2, 3, 4},
   222  					nil,
   223  				},
   224  				{
   225  					"empty value with type null",
   226  					&Value{Type: ValueTypeNull},
   227  					[]byte{0xff, 0xff, 0xff, 0xff}, // length -1
   228  					nil,
   229  				},
   230  				{
   231  					"empty value with type null but non nil contents",
   232  					&Value{
   233  						Type:     ValueTypeNull,
   234  						Contents: []byte{1, 2, 3, 4},
   235  					},
   236  					[]byte{0xff, 0xff, 0xff, 0xff}, // length -1
   237  					nil,
   238  				},
   239  				{
   240  					"empty value with type unset",
   241  					&Value{Type: ValueTypeUnset},
   242  					nil,
   243  					fmt.Errorf("cannot use unset value with %v", version),
   244  				},
   245  				{
   246  					"empty value with type unset but non nil contents",
   247  					&Value{
   248  						Type:     ValueTypeUnset,
   249  						Contents: []byte{1, 2, 3, 4},
   250  					},
   251  					nil,
   252  					fmt.Errorf("cannot use unset value with %v", version),
   253  				},
   254  				{
   255  					"unknown type",
   256  					&Value{Type: 1},
   257  					nil,
   258  					errors.New("unknown [value] type: 1"),
   259  				},
   260  			}
   261  			for _, tt := range tests {
   262  				t.Run(tt.name, func(t *testing.T) {
   263  					buf := &bytes.Buffer{}
   264  					err := WriteValue(tt.input, buf, version)
   265  					assert.Equal(t, tt.expected, buf.Bytes())
   266  					assert.Equal(t, tt.err, err)
   267  				})
   268  			}
   269  		})
   270  	}
   271  	// versions >= 4
   272  	for _, version := range SupportedProtocolVersionsGreaterThanOrEqualTo(ProtocolVersion4) {
   273  		t.Run(version.String(), func(t *testing.T) {
   274  			var tests = []struct {
   275  				name     string
   276  				input    *Value
   277  				expected []byte
   278  				err      error
   279  			}{
   280  				{
   281  					"nil value",
   282  					nil,
   283  					nil,
   284  					errors.New("cannot write a nil [value]"),
   285  				},
   286  				{
   287  					"empty value (type regular, nil contents)",
   288  					&Value{},
   289  					[]byte{0xff, 0xff, 0xff, 0xff}, // length -1
   290  					nil,
   291  				},
   292  				{
   293  					"non empty value (type regular, non nil contents)",
   294  					&Value{
   295  						Type:     ValueTypeRegular,
   296  						Contents: []byte{1, 2, 3, 4},
   297  					},
   298  					[]byte{0, 0, 0, 4, 1, 2, 3, 4},
   299  					nil,
   300  				},
   301  				{
   302  					"empty value with type null",
   303  					&Value{Type: ValueTypeNull},
   304  					[]byte{0xff, 0xff, 0xff, 0xff}, // length -1
   305  					nil,
   306  				},
   307  				{
   308  					"empty value with type null but non nil contents",
   309  					&Value{
   310  						Type:     ValueTypeNull,
   311  						Contents: []byte{1, 2, 3, 4},
   312  					},
   313  					[]byte{0xff, 0xff, 0xff, 0xff}, // length -1
   314  					nil,
   315  				},
   316  				{
   317  					"empty value with type unset",
   318  					&Value{Type: ValueTypeUnset},
   319  					[]byte{0xff, 0xff, 0xff, 0xfe}, // length -2
   320  					nil,
   321  				},
   322  				{
   323  					"empty value with type unset but non nil contents",
   324  					&Value{
   325  						Type:     ValueTypeUnset,
   326  						Contents: []byte{1, 2, 3, 4},
   327  					},
   328  					[]byte{0xff, 0xff, 0xff, 0xfe}, // length -2
   329  					nil,
   330  				},
   331  				{
   332  					"unknown type",
   333  					&Value{Type: 1},
   334  					nil,
   335  					errors.New("unknown [value] type: 1"),
   336  				},
   337  			}
   338  			for _, tt := range tests {
   339  				t.Run(tt.name, func(t *testing.T) {
   340  					buf := &bytes.Buffer{}
   341  					err := WriteValue(tt.input, buf, version)
   342  					assert.Equal(t, tt.expected, buf.Bytes())
   343  					assert.Equal(t, tt.err, err)
   344  				})
   345  			}
   346  		})
   347  	}
   348  }
   349  
   350  func TestLengthOfValue(t *testing.T) {
   351  	tests := []struct {
   352  		name     string
   353  		input    *Value
   354  		expected int
   355  		err      error
   356  	}{
   357  		{
   358  			"nil value",
   359  			nil,
   360  			-1,
   361  			errors.New("cannot compute length of a nil [value]"),
   362  		},
   363  		{
   364  			"empty value (type regular, nil contents)",
   365  			&Value{},
   366  			LengthOfInt, // length -1
   367  			nil,
   368  		},
   369  		{
   370  			"non empty value (type regular, non nil contents)",
   371  			NewValue([]byte{1, 2, 3, 4}),
   372  			LengthOfInt + len([]byte{1, 2, 3, 4}),
   373  			nil,
   374  		},
   375  		{
   376  			"empty value with type null",
   377  			NewNullValue(),
   378  			LengthOfInt,
   379  			nil,
   380  		},
   381  		{
   382  			"empty value with type null but non nil contents",
   383  			&Value{
   384  				Type:     ValueTypeNull,
   385  				Contents: []byte{1, 2, 3, 4},
   386  			},
   387  			LengthOfInt,
   388  			nil,
   389  		},
   390  		{
   391  			"empty value with type unset",
   392  			NewUnsetValue(),
   393  			LengthOfInt,
   394  			nil,
   395  		},
   396  		{
   397  			"empty value with type unset but non nil contents",
   398  			&Value{
   399  				Type:     ValueTypeUnset,
   400  				Contents: []byte{1, 2, 3, 4},
   401  			},
   402  			LengthOfInt,
   403  			nil,
   404  		},
   405  		{
   406  			"unknown type",
   407  			&Value{Type: 1},
   408  			-1,
   409  			errors.New("unknown [value] type: 1"),
   410  		},
   411  	}
   412  	for _, tt := range tests {
   413  		t.Run(tt.name, func(t *testing.T) {
   414  			actual, err := LengthOfValue(tt.input)
   415  			assert.Equal(t, tt.expected, actual)
   416  			assert.Equal(t, tt.err, err)
   417  		})
   418  	}
   419  }
   420  
   421  func TestReadPositionalValues(t *testing.T) {
   422  	for _, version := range SupportedProtocolVersions() {
   423  		t.Run(version.String(), func(t *testing.T) {
   424  			tests := []struct {
   425  				name     string
   426  				source   []byte
   427  				expected []*Value
   428  				err      error
   429  			}{
   430  				{
   431  					"empty positional values",
   432  					[]byte{0, 0},
   433  					[]*Value{},
   434  					nil,
   435  				},
   436  				{
   437  					"1 element, value empty",
   438  					[]byte{
   439  						0, 1, // length of list
   440  						0, 0, 0, 0, // length of element
   441  					},
   442  					[]*Value{{
   443  						Type:     ValueTypeRegular,
   444  						Contents: []byte{},
   445  					}},
   446  					nil,
   447  				},
   448  				{
   449  					"1 element, value non empty",
   450  					[]byte{
   451  						0, 1, // length of list
   452  						0, 0, 0, 5, // length of element
   453  						1, 2, 3, 4, 5, // contents of element
   454  					},
   455  					[]*Value{{
   456  						Type:     ValueTypeRegular,
   457  						Contents: []byte{1, 2, 3, 4, 5},
   458  					}},
   459  					nil,
   460  				},
   461  				{
   462  					"3 elements",
   463  					[]byte{
   464  						0, 3, // length of list
   465  						0xff, 0xff, 0xff, 0xff, // length of element 1
   466  						0, 0, 0, 0, // length of element 2
   467  						0, 0, 0, 5, // length of element 3
   468  						1, 2, 3, 4, 5, // contents of element 3
   469  					},
   470  					[]*Value{
   471  						{
   472  							Type:     ValueTypeNull,
   473  							Contents: nil,
   474  						},
   475  						{
   476  							Type:     ValueTypeRegular,
   477  							Contents: []byte{},
   478  						},
   479  						{
   480  							Type:     ValueTypeRegular,
   481  							Contents: []byte{1, 2, 3, 4, 5},
   482  						},
   483  					},
   484  					nil,
   485  				},
   486  				{
   487  					"cannot read positional values length",
   488  					[]byte{0},
   489  					nil,
   490  					fmt.Errorf("cannot read positional [value]s length: %w",
   491  						fmt.Errorf("cannot read [short]: %w",
   492  							errors.New("unexpected EOF"))),
   493  				},
   494  				{
   495  					"cannot read positional values element",
   496  					[]byte{0, 1, 0, 0, 0, 1},
   497  					nil,
   498  					fmt.Errorf("cannot read positional [value]s element 0 content: %w",
   499  						fmt.Errorf("cannot read [value] content: %w",
   500  							errors.New("EOF"))),
   501  				},
   502  			}
   503  			for _, tt := range tests {
   504  				t.Run(tt.name, func(t *testing.T) {
   505  					buf := bytes.NewBuffer(tt.source)
   506  					actual, err := ReadPositionalValues(buf, version)
   507  					assert.Equal(t, tt.expected, actual)
   508  					assert.Equal(t, tt.err, err)
   509  				})
   510  			}
   511  		})
   512  	}
   513  }
   514  
   515  func TestWritePositionalValues(t *testing.T) {
   516  	// versions < 4
   517  	for _, version := range SupportedProtocolVersionsLesserThan(ProtocolVersion4) {
   518  		t.Run(version.String(), func(t *testing.T) {
   519  			tests := []struct {
   520  				name     string
   521  				input    []*Value
   522  				expected []byte
   523  				err      error
   524  			}{
   525  				{
   526  					"nil positional values",
   527  					nil,
   528  					[]byte{0, 0},
   529  					nil,
   530  				},
   531  				{
   532  					"nil positional values",
   533  					[]*Value{},
   534  					[]byte{0, 0},
   535  					nil,
   536  				},
   537  				{
   538  					"1 element, value empty",
   539  					[]*Value{{
   540  						Type:     ValueTypeRegular,
   541  						Contents: []byte{},
   542  					}},
   543  					[]byte{
   544  						0, 1, // length of list
   545  						0, 0, 0, 0, // length of element
   546  					},
   547  					nil,
   548  				},
   549  				{
   550  					"1 element, value null",
   551  					[]*Value{{
   552  						Type:     ValueTypeRegular,
   553  						Contents: nil,
   554  					}},
   555  					[]byte{
   556  						0, 1, // length of list
   557  						0xff, 0xff, 0xff, 0xff, // length of element
   558  					},
   559  					nil,
   560  				},
   561  				{
   562  					"1 element, value null",
   563  					[]*Value{{
   564  						Type:     ValueTypeNull,
   565  						Contents: nil,
   566  					}},
   567  					[]byte{
   568  						0, 1, // length of list
   569  						0xff, 0xff, 0xff, 0xff, // length of element
   570  					},
   571  					nil,
   572  				},
   573  				{
   574  					"1 element, value non empty",
   575  					[]*Value{{
   576  						Type:     ValueTypeRegular,
   577  						Contents: []byte{1, 2, 3, 4, 5},
   578  					}},
   579  					[]byte{
   580  						0, 1, // length of list
   581  						0, 0, 0, 5, // length of element
   582  						1, 2, 3, 4, 5, // contents of element
   583  					},
   584  					nil,
   585  				},
   586  				{
   587  					"3 elements",
   588  					[]*Value{
   589  						{
   590  							Type:     ValueTypeNull,
   591  							Contents: nil,
   592  						},
   593  						{
   594  							Type:     ValueTypeRegular,
   595  							Contents: []byte{},
   596  						},
   597  						{
   598  							Type:     ValueTypeRegular,
   599  							Contents: []byte{1, 2, 3, 4, 5},
   600  						},
   601  					},
   602  					[]byte{
   603  						0, 3, // length of list
   604  						0xff, 0xff, 0xff, 0xff, // length of element 1
   605  						0, 0, 0, 0, // length of element 2
   606  						0, 0, 0, 5, // length of element 3
   607  						1, 2, 3, 4, 5, // contents of element 3
   608  					},
   609  					nil,
   610  				},
   611  			}
   612  			for _, tt := range tests {
   613  				t.Run(tt.name, func(t *testing.T) {
   614  					buf := &bytes.Buffer{}
   615  					err := WritePositionalValues(tt.input, buf, version)
   616  					assert.Equal(t, tt.expected, buf.Bytes())
   617  					assert.Equal(t, tt.err, err)
   618  				})
   619  			}
   620  		})
   621  	}
   622  	// versions >= 4
   623  	for _, version := range SupportedProtocolVersionsGreaterThanOrEqualTo(ProtocolVersion4) {
   624  		t.Run(version.String(), func(t *testing.T) {
   625  			var tests = []struct {
   626  				name     string
   627  				input    []*Value
   628  				expected []byte
   629  				err      error
   630  			}{
   631  				{
   632  					"nil positional values",
   633  					nil,
   634  					[]byte{0, 0},
   635  					nil,
   636  				},
   637  				{
   638  					"nil positional values",
   639  					[]*Value{},
   640  					[]byte{0, 0},
   641  					nil,
   642  				},
   643  				{
   644  					"1 element, value empty",
   645  					[]*Value{{
   646  						Type:     ValueTypeRegular,
   647  						Contents: []byte{},
   648  					}},
   649  					[]byte{
   650  						0, 1, // length of list
   651  						0, 0, 0, 0, // length of element
   652  					},
   653  					nil,
   654  				},
   655  				{
   656  					"1 element, value null",
   657  					[]*Value{{
   658  						Type:     ValueTypeRegular,
   659  						Contents: nil,
   660  					}},
   661  					[]byte{
   662  						0, 1, // length of list
   663  						0xff, 0xff, 0xff, 0xff, // length of element
   664  					},
   665  					nil,
   666  				},
   667  				{
   668  					"1 element, value null",
   669  					[]*Value{{
   670  						Type:     ValueTypeNull,
   671  						Contents: nil,
   672  					}},
   673  					[]byte{
   674  						0, 1, // length of list
   675  						0xff, 0xff, 0xff, 0xff, // length of element
   676  					},
   677  					nil,
   678  				},
   679  				{
   680  					"1 element, value non empty",
   681  					[]*Value{{
   682  						Type:     ValueTypeRegular,
   683  						Contents: []byte{1, 2, 3, 4, 5},
   684  					}},
   685  					[]byte{
   686  						0, 1, // length of list
   687  						0, 0, 0, 5, // length of element
   688  						1, 2, 3, 4, 5, // contents of element
   689  					},
   690  					nil,
   691  				},
   692  				{
   693  					"4 elements",
   694  					[]*Value{
   695  						{
   696  							Type:     ValueTypeNull,
   697  							Contents: nil,
   698  						},
   699  						{
   700  							Type:     ValueTypeUnset,
   701  							Contents: nil,
   702  						},
   703  						{
   704  							Type:     ValueTypeRegular,
   705  							Contents: []byte{},
   706  						},
   707  						{
   708  							Type:     ValueTypeRegular,
   709  							Contents: []byte{1, 2, 3, 4, 5},
   710  						},
   711  					},
   712  					[]byte{
   713  						0, 4, // length of list
   714  						0xff, 0xff, 0xff, 0xff, // length of element 1
   715  						0xff, 0xff, 0xff, 0xfe, // length of element 2
   716  						0, 0, 0, 0, // length of element 3
   717  						0, 0, 0, 5, // length of element 4
   718  						1, 2, 3, 4, 5, // contents of element 4
   719  					},
   720  					nil,
   721  				},
   722  			}
   723  			for _, tt := range tests {
   724  				t.Run(tt.name, func(t *testing.T) {
   725  					buf := &bytes.Buffer{}
   726  					err := WritePositionalValues(tt.input, buf, version)
   727  					assert.Equal(t, tt.expected, buf.Bytes())
   728  					assert.Equal(t, tt.err, err)
   729  				})
   730  			}
   731  		})
   732  	}
   733  }
   734  
   735  func TestLengthOfPositionalValues(t *testing.T) {
   736  	tests := []struct {
   737  		name     string
   738  		input    []*Value
   739  		expected int
   740  		err      error
   741  	}{
   742  		{
   743  			"nil positional values",
   744  			nil,
   745  			LengthOfShort,
   746  			nil,
   747  		},
   748  		{
   749  			"nil positional values",
   750  			[]*Value{},
   751  			LengthOfShort,
   752  			nil,
   753  		},
   754  		{
   755  			"1 element, value empty",
   756  			[]*Value{{
   757  				Type:     ValueTypeRegular,
   758  				Contents: []byte{},
   759  			}},
   760  			LengthOfShort + LengthOfInt,
   761  			nil,
   762  		},
   763  		{
   764  			"1 element, value null",
   765  			[]*Value{{
   766  				Type:     ValueTypeRegular,
   767  				Contents: nil,
   768  			}},
   769  			LengthOfShort + LengthOfInt,
   770  			nil,
   771  		},
   772  		{
   773  			"1 element, value null",
   774  			[]*Value{{
   775  				Type:     ValueTypeNull,
   776  				Contents: nil,
   777  			}},
   778  			LengthOfShort + LengthOfInt,
   779  			nil,
   780  		},
   781  		{
   782  			"1 element, value non empty",
   783  			[]*Value{{
   784  				Type:     ValueTypeRegular,
   785  				Contents: []byte{1, 2, 3, 4, 5},
   786  			}},
   787  			LengthOfShort + LengthOfInt + len([]byte{1, 2, 3, 4, 5}),
   788  			nil,
   789  		},
   790  		{
   791  			"4 elements",
   792  			[]*Value{
   793  				{
   794  					Type:     ValueTypeNull,
   795  					Contents: nil,
   796  				},
   797  				{
   798  					Type:     ValueTypeUnset,
   799  					Contents: nil,
   800  				},
   801  				{
   802  					Type:     ValueTypeRegular,
   803  					Contents: []byte{},
   804  				},
   805  				{
   806  					Type:     ValueTypeRegular,
   807  					Contents: []byte{1, 2, 3, 4, 5},
   808  				},
   809  			},
   810  			LengthOfShort + // length of list
   811  				LengthOfInt + // length of element 1
   812  				LengthOfInt + // length of element 2
   813  				LengthOfInt + // length of element 3
   814  				LengthOfInt + // length of element 4
   815  				len([]byte{1, 2, 3, 4, 5}), // contents of element 4
   816  			nil,
   817  		},
   818  	}
   819  	for _, tt := range tests {
   820  		t.Run(tt.name, func(t *testing.T) {
   821  			actual, err := LengthOfPositionalValues(tt.input)
   822  			assert.Equal(t, tt.expected, actual)
   823  			assert.Equal(t, tt.err, err)
   824  		})
   825  	}
   826  }
   827  
   828  func TestReadNamedValues(t *testing.T) {
   829  	for _, version := range SupportedProtocolVersions() {
   830  		t.Run(version.String(), func(t *testing.T) {
   831  			tests := []struct {
   832  				name     string
   833  				source   []byte
   834  				expected map[string]*Value
   835  				err      error
   836  			}{
   837  				{
   838  					"empty named values",
   839  					[]byte{0, 0},
   840  					map[string]*Value{},
   841  					nil,
   842  				},
   843  				{
   844  					"1 element, value empty",
   845  					[]byte{
   846  						0, 1, // length of list
   847  						0, 0, // length of element key
   848  						0, 0, 0, 0, // length of element
   849  					},
   850  					map[string]*Value{
   851  						"": {
   852  							Type:     ValueTypeRegular,
   853  							Contents: []byte{},
   854  						}},
   855  					nil,
   856  				},
   857  				{
   858  					"1 element, value non empty",
   859  					[]byte{
   860  						0, 1, // length of list
   861  						0, 5, // length of element key
   862  						h, e, l, l, o, // contents of element key
   863  						0, 0, 0, 5, // length of element value
   864  						1, 2, 3, 4, 5, // contents of element value
   865  					},
   866  					map[string]*Value{
   867  						"hello": {
   868  							Type:     ValueTypeRegular,
   869  							Contents: []byte{1, 2, 3, 4, 5},
   870  						}},
   871  					nil,
   872  				},
   873  				{
   874  					"3 elements",
   875  					[]byte{
   876  						0, 3, // length of list
   877  						0, 5, // length of element 1 key
   878  						h, e, l, l, o, // contents of element 1 key
   879  						0xff, 0xff, 0xff, 0xff, // length of element 1 value
   880  						0, 5, // length of element 2 key
   881  						w, o, r, l, d, // contents of element 2 key
   882  						0, 0, 0, 0, // length of element 2 value
   883  						0, 6, // length of element 3 key
   884  						h, o, l, 0xc3, 0xa0, 0x21, // contents of element 3 key: holà!
   885  						0, 0, 0, 5, // length of element 3 value
   886  						1, 2, 3, 4, 5, // contents of element 3 value
   887  					},
   888  					map[string]*Value{
   889  						"hello": {
   890  							Type:     ValueTypeNull,
   891  							Contents: nil,
   892  						},
   893  						"world": {
   894  							Type:     ValueTypeRegular,
   895  							Contents: []byte{},
   896  						},
   897  						"holà!": {
   898  							Type:     ValueTypeRegular,
   899  							Contents: []byte{1, 2, 3, 4, 5},
   900  						},
   901  					},
   902  					nil,
   903  				},
   904  				{
   905  					"cannot read named values length",
   906  					[]byte{0},
   907  					nil,
   908  					fmt.Errorf("cannot read named [value]s length: %w",
   909  						fmt.Errorf("cannot read [short]: %w",
   910  							errors.New("unexpected EOF"))),
   911  				},
   912  				{
   913  					"cannot read named values element key",
   914  					[]byte{0, 1, 0, 1},
   915  					nil,
   916  					fmt.Errorf("cannot read named [value]s entry 0 name: %w",
   917  						fmt.Errorf("cannot read [string] content: %w",
   918  							errors.New("EOF"))),
   919  				},
   920  				{
   921  					"cannot read named values element value",
   922  					[]byte{0, 1, 0, 1, h, 0, 1},
   923  					nil,
   924  					fmt.Errorf("cannot read named [value]s entry 0 content: %w",
   925  						fmt.Errorf("cannot read [value] length: %w",
   926  							fmt.Errorf("cannot read [int]: %w",
   927  								errors.New("unexpected EOF")))),
   928  				},
   929  			}
   930  			for _, tt := range tests {
   931  				t.Run(tt.name, func(t *testing.T) {
   932  					buf := bytes.NewBuffer(tt.source)
   933  					actual, err := ReadNamedValues(buf, version)
   934  					assert.EqualValues(t, tt.expected, actual)
   935  					assert.Equal(t, tt.err, err)
   936  				})
   937  			}
   938  		})
   939  	}
   940  }
   941  
   942  func TestWriteNamedValues(t *testing.T) {
   943  	for _, version := range SupportedProtocolVersions() {
   944  		t.Run(version.String(), func(t *testing.T) {
   945  			tests := []struct {
   946  				name     string
   947  				input    map[string]*Value
   948  				expected []byte
   949  				err      error
   950  			}{
   951  				{
   952  					"nil named values",
   953  					nil,
   954  					[]byte{0, 0},
   955  					nil,
   956  				},
   957  				{
   958  					"nil named values",
   959  					map[string]*Value{},
   960  					[]byte{0, 0},
   961  					nil,
   962  				},
   963  				{
   964  					"1 element, value empty",
   965  					map[string]*Value{
   966  						"": {
   967  							Type:     ValueTypeRegular,
   968  							Contents: []byte{},
   969  						}},
   970  					[]byte{
   971  						0, 1, // length of list
   972  						0, 0, // length of element key
   973  						0, 0, 0, 0, // length of element
   974  					},
   975  					nil,
   976  				},
   977  				{
   978  					"1 element, value non empty",
   979  					map[string]*Value{
   980  						"hello": {
   981  							Type:     ValueTypeRegular,
   982  							Contents: []byte{1, 2, 3, 4, 5},
   983  						}},
   984  					[]byte{
   985  						0, 1, // length of list
   986  						0, 5, // length of element key
   987  						h, e, l, l, o, // contents of element key
   988  						0, 0, 0, 5, // length of element value
   989  						1, 2, 3, 4, 5, // contents of element value
   990  					},
   991  					nil,
   992  				},
   993  				// cannot reliably test maps with more than one key because iteration order is not deterministic
   994  			}
   995  			for _, tt := range tests {
   996  				t.Run(tt.name, func(t *testing.T) {
   997  					buf := &bytes.Buffer{}
   998  					err := WriteNamedValues(tt.input, buf, version)
   999  					assert.Equal(t, tt.expected, buf.Bytes())
  1000  					assert.Equal(t, tt.err, err)
  1001  				})
  1002  			}
  1003  		})
  1004  	}
  1005  }
  1006  
  1007  func TestLengthOfNamedValues(t *testing.T) {
  1008  	tests := []struct {
  1009  		name     string
  1010  		input    map[string]*Value
  1011  		expected int
  1012  		err      error
  1013  	}{
  1014  		{
  1015  			"nil named values",
  1016  			nil,
  1017  			LengthOfShort,
  1018  			nil,
  1019  		},
  1020  		{
  1021  			"nil named values",
  1022  			map[string]*Value{},
  1023  			LengthOfShort,
  1024  			nil,
  1025  		},
  1026  		{
  1027  			"1 element, value empty",
  1028  			map[string]*Value{
  1029  				"": {
  1030  					Type:     ValueTypeRegular,
  1031  					Contents: []byte{},
  1032  				}},
  1033  			LengthOfShort + // length of list
  1034  				LengthOfShort + // length of element key
  1035  				LengthOfInt, // length of element
  1036  			nil,
  1037  		},
  1038  		{
  1039  			"1 element, value non empty",
  1040  			map[string]*Value{
  1041  				"hello": {
  1042  					Type:     ValueTypeRegular,
  1043  					Contents: []byte{1, 2, 3, 4, 5},
  1044  				}},
  1045  			LengthOfShort + // length of list
  1046  				LengthOfShort + // length of element key
  1047  				len("hello") + // contents of element key
  1048  				LengthOfInt + // length of element value
  1049  				5, // contents of element value
  1050  			nil,
  1051  		},
  1052  		{
  1053  			"3 elements",
  1054  			map[string]*Value{
  1055  				"hello": {
  1056  					Type:     ValueTypeNull,
  1057  					Contents: nil,
  1058  				},
  1059  				"world": {
  1060  					Type:     ValueTypeRegular,
  1061  					Contents: []byte{},
  1062  				},
  1063  				"holà!": {
  1064  					Type:     ValueTypeRegular,
  1065  					Contents: []byte{1, 2, 3, 4, 5},
  1066  				},
  1067  			},
  1068  			LengthOfShort + // length of list
  1069  				LengthOfShort + // length of element 1 key
  1070  				len("hello") + // contents of element 1 key
  1071  				LengthOfInt + // length of element 1 value
  1072  				LengthOfShort + // length of element 2 key
  1073  				len("world") + // contents of element 2 key
  1074  				LengthOfInt + // length of element 2 value
  1075  				LengthOfShort + // length of element 3 key
  1076  				len("holà!") + // contents of element 3 key: holà!
  1077  				LengthOfInt + // length of element 3 value
  1078  				5, // contents of element 3 value
  1079  			nil,
  1080  		},
  1081  	}
  1082  	for _, tt := range tests {
  1083  		t.Run(tt.name, func(t *testing.T) {
  1084  			actual, err := LengthOfNamedValues(tt.input)
  1085  			assert.Equal(t, tt.expected, actual)
  1086  			assert.Equal(t, tt.err, err)
  1087  		})
  1088  	}
  1089  }