github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/extractors_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  	"reflect"
    19  	"testing"
    20  
    21  	"github.com/stretchr/testify/assert"
    22  )
    23  
    24  func Test_sliceExtractor_get(t *testing.T) {
    25  	tests := []struct {
    26  		name    string
    27  		source  interface{}
    28  		index   int
    29  		want    interface{}
    30  		wantErr string
    31  	}{
    32  		{"[]interface empty", []interface{}{}, 0, nil, "slice index out of range: 0"},
    33  		{"[]interface single", []interface{}{123}, 0, 123, ""},
    34  		{"[]interface single", []interface{}{123}, 0, 123, ""},
    35  		{"[]interface multi", []interface{}{123, true, "abc"}, 2, "abc", ""},
    36  		{"[3]interface multi", [3]interface{}{123, true, "abc"}, 2, "abc", ""},
    37  		{"[]interface pointers", []interface{}{intPtr(123), boolPtr(true), stringPtr("abc")}, 2, stringPtr("abc"), ""},
    38  		{"[]interface nil elem", []interface{}{123, nil}, 1, nil, ""},
    39  		{"[]interface complex", []interface{}{[]interface{}{"abc"}}, 0, []interface{}{"abc"}, ""},
    40  		{"[]int", []int{1, 2, 3}, 0, 1, ""},
    41  		{"[3]int", [3]int{1, 2, 3}, 0, 1, ""},
    42  		{"[]*int", []*int{intPtr(123)}, 0, intPtr(123), ""},
    43  		{"[3]*int", [3]*int{intPtr(123)}, 0, intPtr(123), ""},
    44  		{"out of range", []interface{}{123}, 1, nil, "slice index out of range: 1"},
    45  	}
    46  	for _, tt := range tests {
    47  		t.Run(tt.name, func(t *testing.T) {
    48  			e, _ := newSliceExtractor(reflect.ValueOf(tt.source))
    49  			got, gotErr := e.getElem(tt.index, "")
    50  			assert.Equal(t, tt.want, got)
    51  			assertErrorMessage(t, tt.wantErr, gotErr)
    52  		})
    53  	}
    54  }
    55  
    56  func Test_mapExtractor_get(t *testing.T) {
    57  	tests := []struct {
    58  		name    string
    59  		source  interface{}
    60  		key     interface{}
    61  		want    interface{}
    62  		wantErr string
    63  	}{
    64  		{"[string]interface empty", map[string]interface{}{}, "abc", nil, ""},
    65  		{"[string]interface single", map[string]interface{}{"abc": 123}, "abc", 123, ""},
    66  		{"[string]interface multi", map[string]interface{}{"abc": 123, "def": true, "ghi": "abc"}, "abc", 123, ""},
    67  		{"[string]interface pointers", map[string]interface{}{"abc": intPtr(123), "def": boolPtr(true), "ghi": stringPtr("abc")}, "abc", intPtr(123), ""},
    68  		{"[string]interface nil elem", map[string]interface{}{"abc": 123, "def": nil}, "def", nil, ""},
    69  		{"[string]interface complex", map[string]interface{}{"abc": map[int]int{123: 456}}, "abc", map[int]int{123: 456}, ""},
    70  		{"[string]int", map[string]int{"abc": 1, "def": 2, "ghi": 3}, "ghi", 3, ""},
    71  		{"[string]*int", map[string]*int{"abc": intPtr(123)}, "abc", intPtr(123), ""},
    72  		{"[int]interface empty", map[int]interface{}{}, 123, nil, ""},
    73  		{"[int]interface single", map[int]interface{}{123: 456}, 123, 456, ""},
    74  		{"[int]interface multi", map[int]interface{}{123: 123, 456: true, 789: "abc"}, 789, "abc", ""},
    75  		{"[int]interface pointers", map[int]interface{}{123: intPtr(123), 456: boolPtr(true), 789: stringPtr("abc")}, 789, stringPtr("abc"), ""},
    76  		{"[int]interface nil elem", map[int]interface{}{123: 123, 456: nil}, 456, nil, ""},
    77  		{"[int]interface complex", map[int]interface{}{123: map[int]int{123: 456}}, 123, map[int]int{123: 456}, ""},
    78  		{"[int]int", map[int]int{123: 1, 456: 2, 789: 3}, 789, 3, ""},
    79  		{"[int]*int", map[int]*int{123: intPtr(123)}, 123, intPtr(123), ""},
    80  		{"wrong key type", map[string]int{"abc": 1}, 123, nil, "wrong map key, expected string, got: int"},
    81  	}
    82  	for _, tt := range tests {
    83  		t.Run(tt.name, func(t *testing.T) {
    84  			e, _ := newMapExtractor(reflect.ValueOf(tt.source))
    85  			got, gotErr := e.getElem(-1, tt.key)
    86  			assert.Equal(t, tt.want, got)
    87  			assertErrorMessage(t, tt.wantErr, gotErr)
    88  		})
    89  	}
    90  }
    91  
    92  func Test_structExtractor_get(t *testing.T) {
    93  	type testStruct struct {
    94  		Int        int
    95  		String     *string `cassandra:"foo"`
    96  		unexported bool
    97  	}
    98  	tests := []struct {
    99  		name    string
   100  		source  testStruct
   101  		key     interface{}
   102  		want    interface{}
   103  		wantErr string
   104  	}{
   105  		{"by index empty", testStruct{Int: 0}, 0, 0, ""},
   106  		{"by index simple", testStruct{String: stringPtr("abc")}, 1, stringPtr("abc"), ""},
   107  		{"by index nil elem", testStruct{}, 1, stringNilPtr(), ""},
   108  		{"by index unexported", testStruct{}, 2, nil, "no accessible field with index 2 found in struct datacodec.testStruct"},
   109  		{"by index out of range", testStruct{}, -1, nil, "no accessible field with index -1 found in struct datacodec.testStruct"},
   110  		{"by name empty", testStruct{Int: 0}, "int", 0, ""},
   111  		{"by name simple", testStruct{String: stringPtr("abc")}, "foo", stringPtr("abc"), ""},
   112  		{"by name nil elem", testStruct{}, "foo", stringNilPtr(), ""},
   113  		{"by name unexported", testStruct{unexported: true}, "unexported", nil, "no accessible field with name 'unexported' found in struct datacodec.testStruct"},
   114  		{"by name non existent", testStruct{}, "nonexistent", nil, "no accessible field with name 'nonexistent' found in struct datacodec.testStruct"},
   115  		{"wrong key type", testStruct{}, true, nil, "no accessible field with name 'true' found in struct datacodec.testStruct"},
   116  	}
   117  	for _, tt := range tests {
   118  		t.Run(tt.name, func(t *testing.T) {
   119  			e, _ := newStructExtractor(reflect.ValueOf(tt.source))
   120  			got, gotErr := e.getElem(-1, tt.key)
   121  			assert.Equal(t, tt.want, got)
   122  			assertErrorMessage(t, tt.wantErr, gotErr)
   123  		})
   124  	}
   125  }
   126  
   127  func Test_structExtractor_getKey(t *testing.T) {
   128  	tests := []struct {
   129  		name   string
   130  		source testStruct
   131  		index  int
   132  		want   interface{}
   133  	}{
   134  		{"simple", testStruct{}, 0, "value"},
   135  		{"tag", testStruct{}, 3, "pointer_slice"},
   136  	}
   137  	for _, tt := range tests {
   138  		t.Run(tt.name, func(t *testing.T) {
   139  			e, _ := newStructExtractor(reflect.ValueOf(tt.source))
   140  			got := e.getKey(tt.index)
   141  			assert.Equal(t, tt.want, got)
   142  		})
   143  	}
   144  }
   145  
   146  func Test_mapExtractor_getKey(t *testing.T) {
   147  	tests := []struct {
   148  		name   string
   149  		source map[string]string
   150  		index  int
   151  		want   interface{}
   152  	}{
   153  		{"simple", map[string]string{"abc": "def"}, 0, "abc"},
   154  	}
   155  	for _, tt := range tests {
   156  		t.Run(tt.name, func(t *testing.T) {
   157  			e, _ := newMapExtractor(reflect.ValueOf(tt.source))
   158  			got := e.getKey(tt.index)
   159  			assert.Equal(t, tt.want, got)
   160  		})
   161  	}
   162  }
   163  
   164  func Test_newSliceExtractor(t *testing.T) {
   165  	tests := []struct {
   166  		name    string
   167  		source  reflect.Value
   168  		want    *sliceExtractor
   169  		wantErr string
   170  	}{
   171  		{"wrong type", reflect.ValueOf(123), nil, "expected slice or array, got: int"},
   172  		{"nil slice", reflect.ValueOf([]byte(nil)), nil, "slice is nil"},
   173  		{"slice", reflect.ValueOf([]byte{1, 2, 3}), &sliceExtractor{reflect.ValueOf([]byte{1, 2, 3})}, ""},
   174  		{"array", reflect.ValueOf([3]byte{1, 2, 3}), &sliceExtractor{reflect.ValueOf([3]byte{1, 2, 3})}, ""},
   175  	}
   176  	for _, tt := range tests {
   177  		t.Run(tt.name, func(t *testing.T) {
   178  			got, err := newSliceExtractor(tt.source)
   179  			if got == nil {
   180  				assert.Nil(t, tt.want)
   181  			} else {
   182  				assert.Equal(t, tt.want.source.Interface(), got.(*sliceExtractor).source.Interface())
   183  			}
   184  			assertErrorMessage(t, tt.wantErr, err)
   185  		})
   186  	}
   187  }
   188  
   189  func Test_newMapExtractor(t *testing.T) {
   190  	validSource := reflect.ValueOf(map[string]int{"abc": 123})
   191  	tests := []struct {
   192  		name    string
   193  		source  reflect.Value
   194  		want    *mapExtractor
   195  		wantErr string
   196  	}{
   197  		{"wrong type", reflect.ValueOf(123), nil, "expected map, got: int"},
   198  		{"nil map", reflect.ValueOf(map[string]int(nil)), nil, "map is nil"},
   199  		{"ok", validSource, &mapExtractor{validSource, validSource.MapKeys()}, ""},
   200  	}
   201  	for _, tt := range tests {
   202  		t.Run(tt.name, func(t *testing.T) {
   203  			got, err := newMapExtractor(tt.source)
   204  			if got == nil {
   205  				assert.Nil(t, tt.want)
   206  			} else {
   207  				assert.Equal(t, tt.want.source.Interface(), got.(*mapExtractor).source.Interface())
   208  				assert.Len(t, tt.want.keys, 1)
   209  				assert.Equal(t, tt.want.keys[0].Interface(), got.(*mapExtractor).keys[0].Interface())
   210  			}
   211  			assertErrorMessage(t, tt.wantErr, err)
   212  		})
   213  	}
   214  }
   215  
   216  func Test_newStructExtractor(t *testing.T) {
   217  	type testStruct struct {
   218  		Int int
   219  	}
   220  	tests := []struct {
   221  		name    string
   222  		source  reflect.Value
   223  		want    *structExtractor
   224  		wantErr string
   225  	}{
   226  		{"wrong type", reflect.ValueOf(123), nil, "expected struct, got: int"},
   227  		{"ok", reflect.ValueOf(testStruct{}), &structExtractor{reflect.ValueOf(testStruct{})}, ""},
   228  	}
   229  	for _, tt := range tests {
   230  		t.Run(tt.name, func(t *testing.T) {
   231  			got, err := newStructExtractor(tt.source)
   232  			if got == nil {
   233  				assert.Nil(t, tt.want)
   234  			} else {
   235  				assert.Equal(t, tt.want.source.Interface(), got.(*structExtractor).source.Interface())
   236  			}
   237  			assertErrorMessage(t, tt.wantErr, err)
   238  		})
   239  	}
   240  }