blob: de4084e602944ae3d1a2f246d6d42c7d1e567623 [file] [log] [blame]
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
"reflect"
"testing"
)
// TODO: add missing unit tests (istio/istio#17246).
// errToString returns the string representation of err and the empty string if
// err is nil.
func errToString(err error) string {
if err == nil {
return ""
}
return err.Error()
}
// to ptr conversion utility functions
func toInt8Ptr(i int8) *int8 { return &i }
func TestIsValueNil(t *testing.T) {
if !IsValueNil(nil) {
t.Error("got IsValueNil(nil) false, want true")
}
if !IsValueNil((*int)(nil)) {
t.Error("got IsValueNil(ptr) false, want true")
}
if !IsValueNil(map[int]int(nil)) {
t.Error("got IsValueNil(map) false, want true")
}
if !IsValueNil([]int(nil)) {
t.Error("got IsValueNil(slice) false, want true")
}
if !IsValueNil(interface{}(nil)) {
t.Error("got IsValueNil(interface) false, want true")
}
if IsValueNil(toInt8Ptr(42)) {
t.Error("got IsValueNil(ptr) true, want false")
}
if IsValueNil(map[int]int{42: 42}) {
t.Error("got IsValueNil(map) true, want false")
}
if IsValueNil([]int{1, 2, 3}) {
t.Error("got IsValueNil(slice) true, want false")
}
if IsValueNil(interface{}(42)) {
t.Error("got IsValueNil(interface) true, want false")
}
}
func TestIsValueNilOrDefault(t *testing.T) {
if !IsValueNilOrDefault(nil) {
t.Error("got IsValueNilOrDefault(nil) false, want true")
}
if !IsValueNilOrDefault((*int)(nil)) {
t.Error("got IsValueNilOrDefault(ptr) false, want true")
}
if !IsValueNilOrDefault(map[int]int(nil)) {
t.Error("got IsValueNilOrDefault(map) false, want true")
}
if !IsValueNilOrDefault([]int(nil)) {
t.Error("got IsValueNilOrDefault(slice) false, want true")
}
if !IsValueNilOrDefault(interface{}(nil)) {
t.Error("got IsValueNilOrDefault(interface) false, want true")
}
if !IsValueNilOrDefault(int(0)) {
t.Error("got IsValueNilOrDefault(int(0)) false, want true")
}
if !IsValueNilOrDefault("") {
t.Error("got IsValueNilOrDefault(\"\") false, want true")
}
if !IsValueNilOrDefault(false) {
t.Error("got IsValueNilOrDefault(false) false, want true")
}
i := 32
ip := &i
if IsValueNilOrDefault(&ip) {
t.Error("got IsValueNilOrDefault(ptr to ptr) false, want true")
}
}
func TestIsValueFuncs(t *testing.T) {
testInt := int(42)
testStruct := struct{}{}
testSlice := []bool{}
testMap := map[bool]bool{}
var testNilSlice []bool
var testNilMap map[bool]bool
allValues := []interface{}{nil, testInt, &testInt, testStruct, &testStruct, testNilSlice, testSlice, &testSlice, testNilMap, testMap, &testMap}
tests := []struct {
desc string
function func(v reflect.Value) bool
okValues []interface{}
}{
{
desc: "IsValuePtr",
function: IsValuePtr,
okValues: []interface{}{&testInt, &testStruct, &testSlice, &testMap},
},
{
desc: "IsValueStruct",
function: IsValueStruct,
okValues: []interface{}{testStruct},
},
{
desc: "IsValueInterface",
function: IsValueInterface,
okValues: []interface{}{},
},
{
desc: "IsValueStructPtr",
function: IsValueStructPtr,
okValues: []interface{}{&testStruct},
},
{
desc: "IsValueMap",
function: IsValueMap,
okValues: []interface{}{testNilMap, testMap},
},
{
desc: "IsValueSlice",
function: IsValueSlice,
okValues: []interface{}{testNilSlice, testSlice},
},
{
desc: "IsValueScalar",
function: IsValueScalar,
okValues: []interface{}{testInt, &testInt},
},
}
for _, tt := range tests {
for vidx, v := range allValues {
if got, want := tt.function(reflect.ValueOf(v)), isInListOfInterface(tt.okValues, v); got != want {
t.Errorf("%s with %s (#%d): got: %t, want: %t", tt.desc, reflect.TypeOf(v), vidx, got, want)
}
}
}
}
func TestValuesAreSameType(t *testing.T) {
type EnumType int64
tests := []struct {
inDesc string
inV1 interface{}
inV2 interface{}
want bool
}{
{
inDesc: "success both are int32 types",
inV1: int32(42),
inV2: int32(43),
want: true,
},
{
inDesc: "fail unmatching int types",
inV1: int16(42),
inV2: int32(43),
want: false,
},
{
inDesc: "fail unmatching int and string type",
inV1: int32(42),
inV2: "42",
want: false,
},
{
inDesc: "fail EnumType and int64 types",
inV1: EnumType(42),
inV2: int64(43),
want: false,
},
}
for _, tt := range tests {
t.Run(tt.inDesc, func(t *testing.T) {
got := ValuesAreSameType(reflect.ValueOf(tt.inV1), reflect.ValueOf(tt.inV2))
if got != tt.want {
t.Errorf("got %v, want %v for comparing %T against %T", got, tt.want, tt.inV1, tt.inV2)
}
})
}
}
func TestIsTypeFuncs(t *testing.T) {
testInt := int(42)
testStruct := struct{}{}
testSlice := []bool{}
testSliceOfInterface := []interface{}{}
testMap := map[bool]bool{}
var testNilSlice []bool
var testNilMap map[bool]bool
allTypes := []interface{}{
nil, testInt, &testInt, testStruct, &testStruct, testNilSlice,
testSlice, &testSlice, testSliceOfInterface, testNilMap, testMap, &testMap,
}
tests := []struct {
desc string
function func(v reflect.Type) bool
okTypes []interface{}
}{
{
desc: "IsTypeStructPtr",
function: IsTypeStructPtr,
okTypes: []interface{}{&testStruct},
},
{
desc: "IsTypeSlicePtr",
function: IsTypeSlicePtr,
okTypes: []interface{}{&testSlice},
},
{
desc: "IsTypeMap",
function: IsTypeMap,
okTypes: []interface{}{testNilMap, testMap},
},
{
desc: "IsTypeInterface",
function: IsTypeInterface,
okTypes: []interface{}{},
},
{
desc: "IsTypeSliceOfInterface",
function: IsTypeSliceOfInterface,
okTypes: []interface{}{testSliceOfInterface},
},
}
for _, tt := range tests {
for vidx, v := range allTypes {
if got, want := tt.function(reflect.TypeOf(v)), isInListOfInterface(tt.okTypes, v); got != want {
t.Errorf("%s with %s (#%d): got: %t, want: %t", tt.desc, reflect.TypeOf(v), vidx, got, want)
}
}
}
}
type interfaceContainer struct {
I anInterface
}
type anInterface interface {
IsU()
}
type implementsInterface struct {
A string
}
func (*implementsInterface) IsU() {}
func TestIsValueInterface(t *testing.T) {
intf := &interfaceContainer{
I: &implementsInterface{
A: "a",
},
}
iField := reflect.ValueOf(intf).Elem().FieldByName("I")
if !IsValueInterface(iField) {
t.Errorf("IsValueInterface(): got false, want true")
}
}
func TestIsTypeInterface(t *testing.T) {
intf := &interfaceContainer{
I: &implementsInterface{
A: "a",
},
}
testIfField := reflect.ValueOf(intf).Elem().Field(0)
if !IsTypeInterface(testIfField.Type()) {
t.Errorf("IsTypeInterface(): got false, want true")
}
}
func isInListOfInterface(lv []interface{}, v interface{}) bool {
for _, vv := range lv {
if reflect.DeepEqual(vv, v) {
return true
}
}
return false
}
func TestDeleteFromSlicePtr(t *testing.T) {
parentSlice := []int{42, 43, 44, 45}
var parentSliceI interface{} = parentSlice
if err := DeleteFromSlicePtr(&parentSliceI, 1); err != nil {
t.Fatalf("got error: %s, want error: nil", err)
}
wantSlice := []int{42, 44, 45}
if got, want := parentSliceI, wantSlice; !reflect.DeepEqual(got, want) {
t.Errorf("got:\n%v\nwant:\n%v\n", got, want)
}
badParent := struct{}{}
wantErr := `deleteFromSlicePtr parent type is *struct {}, must be *[]interface{}`
if got, want := errToString(DeleteFromSlicePtr(&badParent, 1)), wantErr; got != want {
t.Fatalf("got error: %s, want error: %s", got, want)
}
}
func TestUpdateSlicePtr(t *testing.T) {
parentSlice := []int{42, 43, 44, 45}
var parentSliceI interface{} = parentSlice
if err := UpdateSlicePtr(&parentSliceI, 1, 42); err != nil {
t.Fatalf("got error: %s, want error: nil", err)
}
wantSlice := []int{42, 42, 44, 45}
if got, want := parentSliceI, wantSlice; !reflect.DeepEqual(got, want) {
t.Errorf("got:\n%v\nwant:\n%v\n", got, want)
}
badParent := struct{}{}
wantErr := `updateSlicePtr parent type is *struct {}, must be *[]interface{}`
if got, want := errToString(UpdateSlicePtr(&badParent, 1, 42)), wantErr; got != want {
t.Fatalf("got error: %s, want error: %s", got, want)
}
}
func TestInsertIntoMap(t *testing.T) {
parentMap := map[int]string{42: "forty two", 43: "forty three"}
key := 44
value := "forty four"
if err := InsertIntoMap(parentMap, key, value); err != nil {
t.Fatalf("got error: %s, want error: nil", err)
}
wantMap := map[int]string{42: "forty two", 43: "forty three", 44: "forty four"}
if got, want := parentMap, wantMap; !reflect.DeepEqual(got, want) {
t.Errorf("got:\n%v\nwant:\n%v\n", got, want)
}
badParent := struct{}{}
wantErr := `insertIntoMap parent type is *struct {}, must be map`
if got, want := errToString(InsertIntoMap(&badParent, key, value)), wantErr; got != want {
t.Fatalf("got error: %s, want error: %s", got, want)
}
}
var (
allIntTypes = []interface{}{int(-42), int8(-43), int16(-44), int32(-45), int64(-46)}
allUintTypes = []interface{}{uint(42), uint8(43), uint16(44), uint32(45), uint64(46)}
allIntegerTypes = append(allIntTypes, allUintTypes...)
nonIntTypes = []interface{}{nil, "", []int{}, map[string]bool{}}
allTypes = append(allIntegerTypes, nonIntTypes...)
)
func TestIsInteger(t *testing.T) {
tests := []struct {
desc string
function func(v reflect.Kind) bool
want []interface{}
}{
{
desc: "ints",
function: IsIntKind,
want: allIntTypes,
},
{
desc: "uints",
function: IsUintKind,
want: allUintTypes,
},
}
for _, tt := range tests {
var got []interface{}
for _, v := range allTypes {
if tt.function(reflect.ValueOf(v).Kind()) {
got = append(got, v)
}
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("%s: got %v, want %v", tt.desc, got, tt.want)
}
}
}
func TestToIntValue(t *testing.T) {
var got []int
for _, v := range allTypes {
if i, ok := ToIntValue(v); ok {
got = append(got, i)
}
}
want := []int{-42, -43, -44, -45, -46, 42, 43, 44, 45, 46}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
}