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 }