mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 12:18:16 +00:00 
			
		
		
		
	Add go fuzzer in preparation for testing. Also gofmt a few files that needed it.
This commit is contained in:
		
							
								
								
									
										263
									
								
								pkg/util/fuzz.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								pkg/util/fuzz.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,263 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2014 Google Inc. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"math/rand"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Fuzzer knows how to fill any object with random fields.
 | 
				
			||||||
 | 
					type Fuzzer struct {
 | 
				
			||||||
 | 
						customFuzz map[reflect.Type]func(reflect.Value)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewFuzzer returns a new Fuzzer with the given custom fuzzing functions.
 | 
				
			||||||
 | 
					// Each entry in fuzzFuncs must be a function with one parameter, which will
 | 
				
			||||||
 | 
					// be the variable we wish that function to fill with random data. For this
 | 
				
			||||||
 | 
					// to be effective, the variable type should be either a pointer, map, slice,
 | 
				
			||||||
 | 
					// etc. These functions are called sensibly, e.g., if you wanted custom string
 | 
				
			||||||
 | 
					// fuzzing, the function `func(s *string)` would get called and passed the
 | 
				
			||||||
 | 
					// address of strings.
 | 
				
			||||||
 | 
					func NewFuzzer(fuzzFuncs ...interface{}) *Fuzzer {
 | 
				
			||||||
 | 
						f := &Fuzzer{
 | 
				
			||||||
 | 
							map[reflect.Type]func(reflect.Value){},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for i := range fuzzFuncs {
 | 
				
			||||||
 | 
							v := reflect.ValueOf(fuzzFuncs[i])
 | 
				
			||||||
 | 
							if v.Kind() != reflect.Func {
 | 
				
			||||||
 | 
								panic("Need only funcs!")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							t := v.Type()
 | 
				
			||||||
 | 
							if t.NumIn() != 1 || t.NumOut() != 0 {
 | 
				
			||||||
 | 
								panic("Need 1 in and 0 out params!")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							argT := t.In(0)
 | 
				
			||||||
 | 
							// fmt.Printf("Making entry for thing with '%v' type\n", argT)
 | 
				
			||||||
 | 
							f.customFuzz[argT] = func(toFuzz reflect.Value) {
 | 
				
			||||||
 | 
								if toFuzz.Type().AssignableTo(argT) {
 | 
				
			||||||
 | 
									v.Call([]reflect.Value{toFuzz})
 | 
				
			||||||
 | 
								} else if toFuzz.Type().ConvertibleTo(argT) {
 | 
				
			||||||
 | 
									v.Call([]reflect.Value{toFuzz.Convert(argT)})
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									panic(fmt.Errorf("%#v neither ConvertibleTo nor AssignableTo %v",
 | 
				
			||||||
 | 
										toFuzz.Interface(),
 | 
				
			||||||
 | 
										argT))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return f
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Fuzz recursively fills all of obj's fields with something random.
 | 
				
			||||||
 | 
					// Not safe for cyclic or tree-like structs!
 | 
				
			||||||
 | 
					// obj must be a pointer. Only exported (public) fields can be set (thanks, golang :/ )
 | 
				
			||||||
 | 
					// Intended for tests, so will panic on bad input or unimplemented fields.
 | 
				
			||||||
 | 
					func (f *Fuzzer) Fuzz(obj interface{}) {
 | 
				
			||||||
 | 
						v := reflect.ValueOf(obj)
 | 
				
			||||||
 | 
						if v.Kind() != reflect.Ptr {
 | 
				
			||||||
 | 
							panic("needed ptr!")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						v = v.Elem()
 | 
				
			||||||
 | 
						f.doFuzz(v)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (f *Fuzzer) doFuzz(v reflect.Value) {
 | 
				
			||||||
 | 
						if !v.CanSet() {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Check for both pointer and non-pointer custom functions.
 | 
				
			||||||
 | 
						if v.CanAddr() && f.tryCustom(v.Addr()) {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if f.tryCustom(v) {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if fn, ok := fillFuncMap[v.Kind()]; ok {
 | 
				
			||||||
 | 
							fn(v)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch v.Kind() {
 | 
				
			||||||
 | 
						case reflect.Map:
 | 
				
			||||||
 | 
							if rand.Intn(5) > 0 {
 | 
				
			||||||
 | 
								v.Set(reflect.MakeMap(v.Type()))
 | 
				
			||||||
 | 
								if f.tryCustom(v) {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								n := 1 + rand.Intn(10)
 | 
				
			||||||
 | 
								for i := 0; i < n; i++ {
 | 
				
			||||||
 | 
									key := reflect.New(v.Type().Key()).Elem()
 | 
				
			||||||
 | 
									f.doFuzz(key)
 | 
				
			||||||
 | 
									val := reflect.New(v.Type().Elem()).Elem()
 | 
				
			||||||
 | 
									f.doFuzz(val)
 | 
				
			||||||
 | 
									v.SetMapIndex(key, val)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							v.Set(reflect.Zero(v.Type()))
 | 
				
			||||||
 | 
						case reflect.Ptr:
 | 
				
			||||||
 | 
							if rand.Intn(5) > 0 {
 | 
				
			||||||
 | 
								v.Set(reflect.New(v.Type().Elem()))
 | 
				
			||||||
 | 
								f.doFuzz(v.Elem())
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							v.Set(reflect.Zero(v.Type()))
 | 
				
			||||||
 | 
						case reflect.Slice:
 | 
				
			||||||
 | 
							if rand.Intn(5) > 0 {
 | 
				
			||||||
 | 
								n := 1 + rand.Intn(10)
 | 
				
			||||||
 | 
								v.Set(reflect.MakeSlice(v.Type(), n, n))
 | 
				
			||||||
 | 
								if f.tryCustom(v) {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for i := 0; i < n; i++ {
 | 
				
			||||||
 | 
									f.doFuzz(v.Index(i))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							v.Set(reflect.Zero(v.Type()))
 | 
				
			||||||
 | 
						case reflect.Struct:
 | 
				
			||||||
 | 
							for i := 0; i < v.NumField(); i++ {
 | 
				
			||||||
 | 
								f.doFuzz(v.Field(i))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case reflect.Array:
 | 
				
			||||||
 | 
							fallthrough
 | 
				
			||||||
 | 
						case reflect.Chan:
 | 
				
			||||||
 | 
							fallthrough
 | 
				
			||||||
 | 
						case reflect.Func:
 | 
				
			||||||
 | 
							fallthrough
 | 
				
			||||||
 | 
						case reflect.Interface:
 | 
				
			||||||
 | 
							fallthrough
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							panic(fmt.Sprintf("Can't handle %#v", v.Interface()))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// tryCustom searches for custom handlers and Randomizer implementations, and
 | 
				
			||||||
 | 
					// returns true if it finds a match and successfully randomizes v.
 | 
				
			||||||
 | 
					func (f Fuzzer) tryCustom(v reflect.Value) bool {
 | 
				
			||||||
 | 
						// fmt.Printf("Trying thing with '%v' type\n", v.Type())
 | 
				
			||||||
 | 
						switch v.Kind() {
 | 
				
			||||||
 | 
						case reflect.Chan, reflect.Func, reflect.Interface, reflect.Slice:
 | 
				
			||||||
 | 
							if v.IsNil() {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case reflect.Ptr:
 | 
				
			||||||
 | 
							if v.IsNil() {
 | 
				
			||||||
 | 
								if !v.CanSet() {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								v.Set(reflect.New(v.Type().Elem()))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case reflect.Map:
 | 
				
			||||||
 | 
							if v.IsNil() {
 | 
				
			||||||
 | 
								if !v.CanSet() {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								v.Set(reflect.MakeMap(v.Type()))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if f, ok := f.customFuzz[v.Type()]; ok {
 | 
				
			||||||
 | 
							f(v)
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func fuzzInt(v reflect.Value) {
 | 
				
			||||||
 | 
						v.SetInt(int64(RandUint64()))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func fuzzUint(v reflect.Value) {
 | 
				
			||||||
 | 
						v.SetUint(RandUint64())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var fillFuncMap = map[reflect.Kind]func(reflect.Value){
 | 
				
			||||||
 | 
						reflect.Bool: func(v reflect.Value) {
 | 
				
			||||||
 | 
							v.SetBool(RandBool())
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						reflect.Int:     fuzzInt,
 | 
				
			||||||
 | 
						reflect.Int8:    fuzzInt,
 | 
				
			||||||
 | 
						reflect.Int16:   fuzzInt,
 | 
				
			||||||
 | 
						reflect.Int32:   fuzzInt,
 | 
				
			||||||
 | 
						reflect.Int64:   fuzzInt,
 | 
				
			||||||
 | 
						reflect.Uint:    fuzzUint,
 | 
				
			||||||
 | 
						reflect.Uint8:   fuzzUint,
 | 
				
			||||||
 | 
						reflect.Uint16:  fuzzUint,
 | 
				
			||||||
 | 
						reflect.Uint32:  fuzzUint,
 | 
				
			||||||
 | 
						reflect.Uint64:  fuzzUint,
 | 
				
			||||||
 | 
						reflect.Uintptr: fuzzUint,
 | 
				
			||||||
 | 
						reflect.Float32: func(v reflect.Value) {
 | 
				
			||||||
 | 
							v.SetFloat(float64(rand.Float32()))
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						reflect.Float64: func(v reflect.Value) {
 | 
				
			||||||
 | 
							v.SetFloat(rand.Float64())
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						reflect.Complex64: func(v reflect.Value) {
 | 
				
			||||||
 | 
							panic("unimplemented")
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						reflect.Complex128: func(v reflect.Value) {
 | 
				
			||||||
 | 
							panic("unimplemented")
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						reflect.String: func(v reflect.Value) {
 | 
				
			||||||
 | 
							v.SetString(RandString())
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						reflect.UnsafePointer: func(v reflect.Value) {
 | 
				
			||||||
 | 
							panic("unimplemented")
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RandBool returns true or false randomly.
 | 
				
			||||||
 | 
					func RandBool() bool {
 | 
				
			||||||
 | 
						if rand.Int()&1 == 1 {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type charRange struct {
 | 
				
			||||||
 | 
						first, last rune
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// choose returns a random unicode character from the given range.
 | 
				
			||||||
 | 
					func (r *charRange) choose() rune {
 | 
				
			||||||
 | 
						count := int64(r.last - r.first)
 | 
				
			||||||
 | 
						return r.first + rune(rand.Int63n(count))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var unicodeRanges = []charRange{
 | 
				
			||||||
 | 
						{' ', '~'},           // ASCII characters
 | 
				
			||||||
 | 
						{'\u00a0', '\u02af'}, // Multi-byte encoded characters
 | 
				
			||||||
 | 
						{'\u4e00', '\u9fff'}, // Common CJK (even longer encodings)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RandString makes a random string up to 20 characters long. The returned string
 | 
				
			||||||
 | 
					// may include a variety of (valid) UTF-8 encodings. For testing.
 | 
				
			||||||
 | 
					func RandString() string {
 | 
				
			||||||
 | 
						n := rand.Intn(20)
 | 
				
			||||||
 | 
						runes := make([]rune, n)
 | 
				
			||||||
 | 
						for i := range runes {
 | 
				
			||||||
 | 
							runes[i] = unicodeRanges[rand.Intn(len(unicodeRanges))].choose()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return string(runes)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RandUint64 makes random 64 bit numbers.
 | 
				
			||||||
 | 
					// Weirdly, rand doesn't have a function that gives you 64 random bits.
 | 
				
			||||||
 | 
					func RandUint64() uint64 {
 | 
				
			||||||
 | 
						return uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										229
									
								
								pkg/util/fuzz_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								pkg/util/fuzz_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,229 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2014 Google Inc. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestFuzz_basic(t *testing.T) {
 | 
				
			||||||
 | 
						obj := &struct {
 | 
				
			||||||
 | 
							I    int
 | 
				
			||||||
 | 
							I8   int8
 | 
				
			||||||
 | 
							I16  int16
 | 
				
			||||||
 | 
							I32  int32
 | 
				
			||||||
 | 
							I64  int64
 | 
				
			||||||
 | 
							U    uint
 | 
				
			||||||
 | 
							U8   uint8
 | 
				
			||||||
 | 
							U16  uint16
 | 
				
			||||||
 | 
							U32  uint32
 | 
				
			||||||
 | 
							U64  uint64
 | 
				
			||||||
 | 
							Uptr uintptr
 | 
				
			||||||
 | 
							S    string
 | 
				
			||||||
 | 
							B    bool
 | 
				
			||||||
 | 
						}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						failed := map[string]int{}
 | 
				
			||||||
 | 
						for i := 0; i < 10; i++ {
 | 
				
			||||||
 | 
							NewFuzzer().Fuzz(obj)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if n, v := "i", obj.I; v == 0 {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "i8", obj.I8; v == 0 {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "i16", obj.I16; v == 0 {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "i32", obj.I32; v == 0 {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "i64", obj.I64; v == 0 {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "u", obj.U; v == 0 {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "u8", obj.U8; v == 0 {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "u16", obj.U16; v == 0 {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "u32", obj.U32; v == 0 {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "u64", obj.U64; v == 0 {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "uptr", obj.Uptr; v == 0 {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "s", obj.S; v == "" {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "b", obj.B; v == false {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						checkFailed(t, failed)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func checkFailed(t *testing.T, failed map[string]int) {
 | 
				
			||||||
 | 
						for k, v := range failed {
 | 
				
			||||||
 | 
							if v > 8 {
 | 
				
			||||||
 | 
								t.Errorf("%v seems to not be getting set, was zero value %v times", k, v)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestFuzz_structptr(t *testing.T) {
 | 
				
			||||||
 | 
						obj := &struct {
 | 
				
			||||||
 | 
							A *struct {
 | 
				
			||||||
 | 
								S string
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						failed := map[string]int{}
 | 
				
			||||||
 | 
						for i := 0; i < 10; i++ {
 | 
				
			||||||
 | 
							NewFuzzer().Fuzz(obj)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if n, v := "a", obj.A; v == nil {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, v := "as", obj.A; v == nil || v.S == "" {
 | 
				
			||||||
 | 
								failed[n] = failed[n] + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						checkFailed(t, failed)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Try fuzzing up to 20 times. Fail if check() never passes.
 | 
				
			||||||
 | 
					func tryFuzz(t *testing.T, obj interface{}, check func() (stage int, passed bool)) {
 | 
				
			||||||
 | 
						maxStage := 0
 | 
				
			||||||
 | 
						for i := 0; i < 20; i++ {
 | 
				
			||||||
 | 
							NewFuzzer().Fuzz(obj)
 | 
				
			||||||
 | 
							stage, passed := check()
 | 
				
			||||||
 | 
							if stage > maxStage {
 | 
				
			||||||
 | 
								maxStage = stage
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if passed {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Errorf("Only ever got to stage %v", maxStage)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestFuzz_structmap(t *testing.T) {
 | 
				
			||||||
 | 
						obj := &struct {
 | 
				
			||||||
 | 
							A map[struct {
 | 
				
			||||||
 | 
								S string
 | 
				
			||||||
 | 
							}]struct {
 | 
				
			||||||
 | 
								S2 string
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							B map[string]string
 | 
				
			||||||
 | 
						}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tryFuzz(t, obj, func() (int, bool) {
 | 
				
			||||||
 | 
							if obj.A == nil {
 | 
				
			||||||
 | 
								return 1, false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(obj.A) == 0 {
 | 
				
			||||||
 | 
								return 2, false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for k, v := range obj.A {
 | 
				
			||||||
 | 
								if k.S == "" {
 | 
				
			||||||
 | 
									return 3, false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if v.S2 == "" {
 | 
				
			||||||
 | 
									return 4, false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if obj.B == nil {
 | 
				
			||||||
 | 
								return 5, false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(obj.B) == 0 {
 | 
				
			||||||
 | 
								return 6, false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for k, v := range obj.B {
 | 
				
			||||||
 | 
								if k == "" {
 | 
				
			||||||
 | 
									return 7, false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if v == "" {
 | 
				
			||||||
 | 
									return 8, false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 9, true
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestFuzz_structslice(t *testing.T) {
 | 
				
			||||||
 | 
						obj := &struct {
 | 
				
			||||||
 | 
							A []struct {
 | 
				
			||||||
 | 
								S string
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							B []string
 | 
				
			||||||
 | 
						}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tryFuzz(t, obj, func() (int, bool) {
 | 
				
			||||||
 | 
							if obj.A == nil {
 | 
				
			||||||
 | 
								return 1, false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(obj.A) == 0 {
 | 
				
			||||||
 | 
								return 2, false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, v := range obj.A {
 | 
				
			||||||
 | 
								if v.S == "" {
 | 
				
			||||||
 | 
									return 3, false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if obj.B == nil {
 | 
				
			||||||
 | 
								return 4, false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(obj.B) == 0 {
 | 
				
			||||||
 | 
								return 5, false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, v := range obj.B {
 | 
				
			||||||
 | 
								if v == "" {
 | 
				
			||||||
 | 
									return 6, false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 7, true
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestFuzz_custom(t *testing.T) {
 | 
				
			||||||
 | 
						obj := &struct {
 | 
				
			||||||
 | 
							A string
 | 
				
			||||||
 | 
							B *string
 | 
				
			||||||
 | 
						}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						testPhrase := "gotcalled"
 | 
				
			||||||
 | 
						NewFuzzer(func(s *string) { *s = testPhrase }).Fuzz(obj)
 | 
				
			||||||
 | 
						if obj.A != testPhrase {
 | 
				
			||||||
 | 
							t.Errorf("A not set")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if obj.B == nil {
 | 
				
			||||||
 | 
							t.Fatalf("B is nil")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if *obj.B != testPhrase {
 | 
				
			||||||
 | 
							t.Errorf("B not set")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -62,7 +62,7 @@ func (s StringSet) HasAll(items ...string) bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// IsSuperset returns true iff s1 is a superset of s2.
 | 
					// IsSuperset returns true iff s1 is a superset of s2.
 | 
				
			||||||
func (s1 StringSet) IsSuperset(s2 StringSet) bool {
 | 
					func (s1 StringSet) IsSuperset(s2 StringSet) bool {
 | 
				
			||||||
	for item, _ := range s2 {
 | 
						for item := range s2 {
 | 
				
			||||||
		if !s1.Has(item) {
 | 
							if !s1.Has(item) {
 | 
				
			||||||
			return false
 | 
								return false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,13 +43,13 @@ func TestStringSet(t *testing.T) {
 | 
				
			|||||||
		t.Errorf("Unexpected contents: %#v", s)
 | 
							t.Errorf("Unexpected contents: %#v", s)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	s.Insert("a")
 | 
						s.Insert("a")
 | 
				
			||||||
	if s.HasAll("a","b","d") {
 | 
						if s.HasAll("a", "b", "d") {
 | 
				
			||||||
		t.Errorf("Unexpected contents: %#v", s)
 | 
							t.Errorf("Unexpected contents: %#v", s)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !s.HasAll("a","b",) {
 | 
						if !s.HasAll("a", "b") {
 | 
				
			||||||
		t.Errorf("Missing contents: %#v", s)
 | 
							t.Errorf("Missing contents: %#v", s)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	s2.Insert("a","b","d")
 | 
						s2.Insert("a", "b", "d")
 | 
				
			||||||
	if s.IsSuperset(s2) {
 | 
						if s.IsSuperset(s2) {
 | 
				
			||||||
		t.Errorf("Unexpected contents: %#v", s)
 | 
							t.Errorf("Unexpected contents: %#v", s)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -132,3 +132,23 @@ func (intstr IntOrString) MarshalJSON() ([]byte, error) {
 | 
				
			|||||||
		return []byte{}, fmt.Errorf("impossible IntOrString.Kind")
 | 
							return []byte{}, fmt.Errorf("impossible IntOrString.Kind")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// StringDiff diffs a and b and returns a human readable diff.
 | 
				
			||||||
 | 
					func StringDiff(a, b string) string {
 | 
				
			||||||
 | 
						ba := []byte(a)
 | 
				
			||||||
 | 
						bb := []byte(b)
 | 
				
			||||||
 | 
						out := []byte{}
 | 
				
			||||||
 | 
						i := 0
 | 
				
			||||||
 | 
						for ; i < len(ba) && i < len(bb); i++ {
 | 
				
			||||||
 | 
							if ba[i] != bb[i] {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							out = append(out, ba[i])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						out = append(out, []byte("\n\nA: ")...)
 | 
				
			||||||
 | 
						out = append(out, ba[i:]...)
 | 
				
			||||||
 | 
						out = append(out, []byte("\n\nB: ")...)
 | 
				
			||||||
 | 
						out = append(out, bb[i:]...)
 | 
				
			||||||
 | 
						out = append(out, []byte("\n\n")...)
 | 
				
			||||||
 | 
						return string(out)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -153,3 +153,11 @@ func TestIntOrStringMarshalJSON(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestStringDiff(t *testing.T) {
 | 
				
			||||||
 | 
						diff := StringDiff("aaabb", "aaacc")
 | 
				
			||||||
 | 
						expect := "aaa\n\nA: bb\n\nB: cc\n\n"
 | 
				
			||||||
 | 
						if diff != expect {
 | 
				
			||||||
 | 
							t.Errorf("diff returned %v", diff)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user