Skip to content

Commit 55164ad

Browse files
Merge pull request GoogleCloudPlatform#3356 from acpana/acpana/krmgen-2
refactor:tests: add overrides
2 parents 2f35b56 + 72649f1 commit 55164ad

File tree

2 files changed

+93
-70
lines changed

2 files changed

+93
-70
lines changed

pkg/test/fuzz/fuzz_test.go

+63-38
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ package fuzz
1616

1717
import (
1818
"encoding/json"
19+
"math/rand"
20+
"reflect"
21+
"strconv"
1922
"testing"
2023
)
2124

@@ -38,14 +41,17 @@ type TestKRMType struct {
3841
ComplexMapFieldPtr *map[string]NestedKRMType
3942
NestedStruct NestedKRMType
4043
NestedStructPtr *NestedKRMType
41-
EnumField MyEnumType
42-
EnumFieldPtr *MyEnumType
43-
StringEnumField MyStringEnumType
44-
StringEnumFieldPtr *MyStringEnumType
45-
StructSlice []NestedKRMType
46-
StructSlicePtr *[]NestedKRMType
47-
IntSlice []int
48-
IntSlicePtr *[]int
44+
// EnumField MyEnumType
45+
// EnumFieldPtr *MyEnumType
46+
// StringEnumField MyStringEnumType
47+
// StringEnumFieldPtr *MyStringEnumType
48+
StructSlice []NestedKRMType
49+
StructSlicePtr *[]NestedKRMType
50+
IntSlice []int
51+
IntSlicePtr *[]int
52+
53+
PtrStringFieldThatNeedsInt *string
54+
StringFieldThatNeedsInt string
4955
}
5056

5157
// Nested structs
@@ -66,35 +72,36 @@ type DeepNestedKRMType struct {
6672
FieldCPtr *[]byte
6773
}
6874

69-
// Integer enum type
70-
type MyEnumType int
75+
// // Integer enum type
76+
// type MyEnumType int
7177

72-
const (
73-
EnumValueA MyEnumType = iota
74-
EnumValueB
75-
EnumValueC
76-
)
78+
// const (
79+
// EnumValueA MyEnumType = iota
80+
// EnumValueB
81+
// EnumValueC
82+
// )
7783

78-
// String enum type
79-
type MyStringEnumType string
84+
// // String enum type
85+
// type MyStringEnumType string
8086

81-
const (
82-
StringEnumOptionA MyStringEnumType = "OptionA"
83-
StringEnumOptionB MyStringEnumType = "OptionB"
84-
StringEnumOptionC MyStringEnumType = "OptionC"
85-
)
87+
// const (
88+
// StringEnumOptionA MyStringEnumType = "OptionA"
89+
// StringEnumOptionB MyStringEnumType = "OptionB"
90+
// StringEnumOptionC MyStringEnumType = "OptionC"
91+
// )
8692

8793
func TestRandomFillerFields(t *testing.T) {
88-
// Define allowable bounds for integer enums and specific values for non-integer enums
89-
intEnumAllowableValues := map[string]int64{
90-
"MyEnumType": 2, // Allows values in the range [0, 2]
91-
}
92-
stringEnumAllowableValues := map[string][]interface{}{
93-
"MyStringEnumType": {"OptionA", "OptionB", "OptionC"},
94+
stream := rand.New(rand.NewSource(int64(9201995))) // for determinism
95+
96+
funcF := func(t *testing.T, fieldName string, field reflect.Value) {
97+
field.SetString(strconv.FormatInt(stream.Int63(), 10))
9498
}
9599

96-
seed := int64(9201995) // for determinism
97-
filler := NewRandomFiller(seed, intEnumAllowableValues, stringEnumAllowableValues)
100+
overrides := map[string]OverrideFiller{
101+
".PtrStringFieldThatNeedsInt": funcF,
102+
".StringFieldThatNeedsInt": funcF,
103+
}
104+
filler := NewRandomFiller(&FillerConfig{Stream: stream, FieldOverrides: overrides})
98105

99106
tests := []struct {
100107
name string
@@ -118,14 +125,14 @@ func TestRandomFillerFields(t *testing.T) {
118125
{"ComplexMapFieldPtr", func(krmObj *TestKRMType) bool {
119126
return krmObj.ComplexMapFieldPtr != nil && len(*krmObj.ComplexMapFieldPtr) > 0
120127
}},
121-
{"EnumField", func(krmObj *TestKRMType) bool { return krmObj.EnumField >= 0 && krmObj.EnumField <= 2 }},
122-
{"EnumFieldPtr", func(krmObj *TestKRMType) bool {
123-
return krmObj.EnumFieldPtr != nil && *krmObj.EnumFieldPtr >= 0 && *krmObj.EnumFieldPtr <= 2
124-
}},
125-
{"StringEnumField", func(krmObj *TestKRMType) bool { return krmObj.StringEnumField != "" }},
126-
{"StringEnumFieldPtr", func(krmObj *TestKRMType) bool {
127-
return krmObj.StringEnumFieldPtr != nil && *krmObj.StringEnumFieldPtr != ""
128-
}},
128+
// {"EnumField", func(krmObj *TestKRMType) bool { return krmObj.EnumField >= 0 && krmObj.EnumField <= 2 }},
129+
// {"EnumFieldPtr", func(krmObj *TestKRMType) bool {
130+
// return krmObj.EnumFieldPtr != nil && *krmObj.EnumFieldPtr >= 0 && *krmObj.EnumFieldPtr <= 2
131+
// }},
132+
// {"StringEnumField", func(krmObj *TestKRMType) bool { return krmObj.StringEnumField != "" }},
133+
// {"StringEnumFieldPtr", func(krmObj *TestKRMType) bool {
134+
// return krmObj.StringEnumFieldPtr != nil && *krmObj.StringEnumFieldPtr != ""
135+
// }},
129136
{"StructSlice", func(krmObj *TestKRMType) bool { return len(krmObj.StructSlice) > 0 }},
130137
{"StructSlicePtr", func(krmObj *TestKRMType) bool { return krmObj.StructSlicePtr != nil && len(*krmObj.StructSlicePtr) > 0 }},
131138
{"IntSlice", func(krmObj *TestKRMType) bool { return len(krmObj.IntSlice) > 0 }},
@@ -154,6 +161,24 @@ func TestRandomFillerFields(t *testing.T) {
154161
{"NestedStruct.DeepNestedField.FieldCPtr", func(krmObj *TestKRMType) bool {
155162
return krmObj.NestedStruct.DeepNestedField != nil && krmObj.NestedStruct.DeepNestedField.FieldCPtr != nil && len(*krmObj.NestedStruct.DeepNestedField.FieldCPtr) > 0
156163
}},
164+
{"PtrStringFieldThatNeedsInt", func(krmObj *TestKRMType) bool {
165+
if krmObj.PtrStringFieldThatNeedsInt == nil {
166+
return false
167+
}
168+
if _, err := strconv.ParseInt(*krmObj.PtrStringFieldThatNeedsInt, 10, 64); err != nil {
169+
t.Error("converting string field to int")
170+
}
171+
return true
172+
}},
173+
{"StringFieldThatNeedsInt", func(krmObj *TestKRMType) bool {
174+
if krmObj.PtrStringFieldThatNeedsInt == nil {
175+
return false
176+
}
177+
if _, err := strconv.ParseInt(*krmObj.PtrStringFieldThatNeedsInt, 10, 64); err != nil {
178+
t.Error("converting string field to int")
179+
}
180+
return true
181+
}},
157182
}
158183

159184
krmObj := &TestKRMType{}

pkg/test/fuzz/krmgen.go

+30-32
Original file line numberDiff line numberDiff line change
@@ -20,51 +20,54 @@ import (
2020
"testing"
2121
)
2222

23+
type OverrideFiller func(t *testing.T, fieldName string, field reflect.Value)
2324
type RandomFiller struct {
2425
randStream *rand.Rand
2526

26-
// for iota based enums, defines the upper bound for a named enum type
27-
intEnumAllowableValues map[string]int64
28-
// for non iota based enums, holds the set of allowable values for a named enum type
29-
stringEnumAllowableValues map[string][]interface{}
27+
fieldOverrides map[string]OverrideFiller
3028
}
3129

32-
func NewRandomFiller(seed int64, enumBoundsMap map[string]int64, enumValuesMap map[string][]interface{}) *RandomFiller {
30+
type FillerConfig struct {
31+
Stream *rand.Rand
32+
FieldOverrides map[string]OverrideFiller
33+
}
34+
35+
func NewRandomFiller(fc *FillerConfig) *RandomFiller {
3336
return &RandomFiller{
34-
randStream: rand.New(rand.NewSource(seed)),
35-
intEnumAllowableValues: enumBoundsMap,
36-
stringEnumAllowableValues: enumValuesMap,
37+
randStream: fc.Stream,
38+
fieldOverrides: fc.FieldOverrides,
3739
}
3840
}
3941

4042
// Fill populates the fields of a struct with random values. Enums are handled separately in the
4143
// two maps passed to the RandomFiller.
4244
func (rf *RandomFiller) Fill(t *testing.T, obj interface{}) {
43-
rf.fillWithRandom(t, reflect.ValueOf(obj).Elem())
45+
rf.fillWithRandom(t, "", reflect.ValueOf(obj).Elem())
46+
rf.fillWithRandom(t, "", reflect.ValueOf(obj).Elem())
4447
}
4548

46-
func (rf *RandomFiller) fillWithRandom(t *testing.T, field reflect.Value) {
49+
func (rf *RandomFiller) fillWithRandom(t *testing.T, fieldName string, field reflect.Value) {
4750
if field.Kind() == reflect.Ptr {
4851
if field.IsNil() {
4952
field.Set(reflect.New(field.Type().Elem()))
5053
}
51-
rf.fillWithRandom(t, field.Elem())
54+
rf.fillWithRandom(t, fieldName, field.Elem())
5255
return
5356
}
5457

58+
if rf.fieldOverrides != nil {
59+
if override, ok := rf.fieldOverrides[fieldName]; ok {
60+
override(t, fieldName, field)
61+
return
62+
}
63+
}
64+
5565
switch field.Kind() {
5666
case reflect.Bool:
5767
field.SetBool(rf.randStream.Intn(2) == 1)
5868

5969
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
60-
// if this field is an iota enum field with a set of allowable values
61-
if upperBound, ok := rf.intEnumAllowableValues[field.Type().Name()]; ok {
62-
// Select a random integer value within the range [0, upperBound] for integer enums
63-
field.SetInt(rf.randStream.Int63n(upperBound + 1))
64-
} else {
65-
// Otherwise, fill with a generic random integer
66-
field.SetInt(rf.randStream.Int63())
67-
}
70+
field.SetInt(rf.randStream.Int63())
6871

6972
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
7073
field.SetUint(rf.randStream.Uint64())
@@ -73,22 +76,14 @@ func (rf *RandomFiller) fillWithRandom(t *testing.T, field reflect.Value) {
7376
field.SetFloat(rf.randStream.Float64())
7477

7578
case reflect.String:
76-
// if this field is a enum field with a set of allowable values
77-
if values, ok := rf.stringEnumAllowableValues[field.Type().Name()]; ok {
78-
// Select a random string from predefined values in enumValuesMap
79-
selectedValue := values[rf.randStream.Intn(len(values))]
80-
field.SetString(selectedValue.(string))
81-
} else {
82-
// Otherwise, fill with a generic random string
83-
field.SetString(randomString(rf.randStream))
84-
}
79+
field.SetString(randomString(rf.randStream))
8580

8681
case reflect.Slice:
8782
count := rf.randStream.Intn(10) + 1
8883
slice := reflect.MakeSlice(field.Type(), count, count)
8984
for j := 0; j < count; j++ {
9085
element := reflect.New(field.Type().Elem()).Elem()
91-
rf.fillWithRandom(t, element)
86+
rf.fillWithRandom(t, "", element) // don't need to pass in a field name for slice elements
9287
slice.Index(j).Set(element)
9388
}
9489
field.Set(slice)
@@ -99,15 +94,18 @@ func (rf *RandomFiller) fillWithRandom(t *testing.T, field reflect.Value) {
9994
for j := 0; j < count; j++ {
10095
key := reflect.New(field.Type().Key()).Elem()
10196
value := reflect.New(field.Type().Elem()).Elem()
102-
rf.fillWithRandom(t, key)
103-
rf.fillWithRandom(t, value)
97+
rf.fillWithRandom(t, "", key) // no need to pass in a field name for keys
98+
rf.fillWithRandom(t, "", value) // no need to pass in a field name for values
10499
mapType.SetMapIndex(key, value)
105100
}
106101
field.Set(mapType)
107102

108103
case reflect.Struct:
109104
for i := 0; i < field.NumField(); i++ {
110-
rf.fillWithRandom(t, field.Field(i))
105+
structFieldName := field.Type().Field(i).Name
106+
nestedStructFieldname := fieldName + "." + structFieldName
107+
108+
rf.fillWithRandom(t, nestedStructFieldname, field.Field(i))
111109
}
112110

113111
default:

0 commit comments

Comments
 (0)