From 36bcdd09a6c428128f6b02953273b541385be5ab Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Sun, 26 Mar 2023 21:09:20 +0200 Subject: [PATCH 01/41] Regularize method signature --- struct.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/struct.go b/struct.go index 33ec1510..64932eb2 100644 --- a/struct.go +++ b/struct.go @@ -34,7 +34,7 @@ func r(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) err case reflect.Struct: return rStruct(ra, t, v, tag) case reflect.String: - return rString(ra, v, tag) + return rString(ra, t, v, tag) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return rUint(ra, t, v, tag) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: @@ -42,7 +42,7 @@ func r(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) err case reflect.Float32, reflect.Float64: return rFloat(ra, t, v, tag) case reflect.Bool: - return rBool(ra, v, tag) + return rBool(ra, t, v, tag) case reflect.Array, reflect.Slice: return rSlice(ra, t, v, tag, size) case reflect.Map: @@ -286,7 +286,7 @@ func rMap(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) return nil } -func rString(ra *rand.Rand, v reflect.Value, tag string) error { +func rString(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { if tag != "" { v.SetString(generate(ra, tag)) } else { @@ -374,7 +374,7 @@ func rFloat(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { return nil } -func rBool(ra *rand.Rand, v reflect.Value, tag string) error { +func rBool(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { if tag != "" { b, err := strconv.ParseBool(generate(ra, tag)) if err != nil { From 60a134db6ef5cf3fd495d0e6ad73026a24705be1 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 27 Mar 2023 02:25:31 +0200 Subject: [PATCH 02/41] Support for data generation via implementation of the Fakeable interface --- fakeable.go | 79 ++++++ fakeable_test.go | 616 +++++++++++++++++++++++++++++++++++++++++++++++ struct.go | 279 ++++++++++++++------- 3 files changed, 885 insertions(+), 89 deletions(-) create mode 100644 fakeable.go create mode 100644 fakeable_test.go diff --git a/fakeable.go b/fakeable.go new file mode 100644 index 00000000..4983b3e7 --- /dev/null +++ b/fakeable.go @@ -0,0 +1,79 @@ +package gofakeit + +import ( + "errors" + "fmt" + "reflect" +) + +// Fakeable is an interface that can be implemented by a type to provide a custom fake value. +type Fakeable interface { + // Fake returns a fake value for the type. + Fake() interface{} +} + +func isFakeable(t reflect.Type) bool { + fakeableTyp := reflect.TypeOf((*Fakeable)(nil)).Elem() + return t.Implements(fakeableTyp) +} + +func callFake(v reflect.Value, possibleKinds ...reflect.Kind) (interface{}, error) { + f, ok := v.Addr().Interface().(Fakeable) + if !ok { + return nil, errors.New("not a Fakeable type") + } + + fakedValue := f.Fake() + k := reflect.TypeOf(fakedValue).Kind() + if !contains(possibleKinds, k) { + return nil, fmt.Errorf("returned value kind %q is not amongst the valid ones: %v", k, possibleKinds) + } + + switch k { + case reflect.String: + return reflect.ValueOf(fakedValue).String(), nil + case reflect.Bool: + return reflect.ValueOf(fakedValue).Bool(), nil + case reflect.Int: + return int(reflect.ValueOf(fakedValue).Int()), nil + case reflect.Int8: + return int8(reflect.ValueOf(fakedValue).Int()), nil + case reflect.Int16: + return int16(reflect.ValueOf(fakedValue).Int()), nil + case reflect.Int32: + return int32(reflect.ValueOf(fakedValue).Int()), nil + case reflect.Int64: + return int64(reflect.ValueOf(fakedValue).Int()), nil + case reflect.Uint: + return uint(reflect.ValueOf(fakedValue).Uint()), nil + case reflect.Uint8: + return uint8(reflect.ValueOf(fakedValue).Uint()), nil + case reflect.Uint16: + return uint16(reflect.ValueOf(fakedValue).Uint()), nil + case reflect.Uint32: + return uint32(reflect.ValueOf(fakedValue).Uint()), nil + case reflect.Uint64: + return uint64(reflect.ValueOf(fakedValue).Uint()), nil + case reflect.Float32: + return float32(reflect.ValueOf(fakedValue).Float()), nil + case reflect.Float64: + return float64(reflect.ValueOf(fakedValue).Float()), nil + case reflect.Slice: + return reflect.ValueOf(fakedValue).Interface(), nil + case reflect.Map: + return reflect.ValueOf(fakedValue).Interface(), nil + case reflect.Struct: + return reflect.ValueOf(fakedValue).Interface(), nil + default: + return nil, fmt.Errorf("unsupported type %q", k) + } +} + +func contains(possibleKinds []reflect.Kind, kind reflect.Kind) bool { + for _, k := range possibleKinds { + if k == kind { + return true + } + } + return false +} diff --git a/fakeable_test.go b/fakeable_test.go new file mode 100644 index 00000000..879b4cd4 --- /dev/null +++ b/fakeable_test.go @@ -0,0 +1,616 @@ +package gofakeit_test + +import ( + "math/rand" + "testing" + "time" + + "github.com/brianvoe/gofakeit/v6" +) + +var ( + testTimeValue = time.Now() +) + +type CustomString string + +func (c CustomString) Fake() interface{} { + return CustomString("hello test") +} + +type CustomBool bool + +func (c CustomBool) Fake() interface{} { + return CustomBool(true) +} + +type CustomInt int + +func (c CustomInt) Fake() interface{} { + return CustomInt(-42) +} + +type CustomInt8 int8 + +func (c CustomInt8) Fake() interface{} { + return CustomInt8(-42) +} + +type CustomInt16 int16 + +func (c CustomInt16) Fake() interface{} { + return CustomInt16(-42) +} + +type CustomInt32 int32 + +func (c CustomInt32) Fake() interface{} { + return CustomInt32(-42) +} + +type CustomInt64 int64 + +func (c CustomInt64) Fake() interface{} { + return CustomInt64(-42) +} + +type CustomUint uint + +func (c CustomUint) Fake() interface{} { + return CustomUint(42) +} + +type CustomUint8 uint8 + +func (c CustomUint8) Fake() interface{} { + return CustomUint8(42) +} + +type CustomUint16 uint16 + +func (c CustomUint16) Fake() interface{} { + return CustomUint16(42) +} + +type CustomUint32 uint32 + +func (c CustomUint32) Fake() interface{} { + return CustomUint32(42) +} + +type CustomUint64 uint64 + +func (c CustomUint64) Fake() interface{} { + return CustomUint64(42) +} + +type CustomFloat32 float32 + +func (c CustomFloat32) Fake() interface{} { + return CustomFloat32(42.123) +} + +type CustomFloat64 float64 + +func (c CustomFloat64) Fake() interface{} { + return CustomFloat64(42.123) +} + +type CustomTime time.Time + +func (c CustomTime) Fake() interface{} { + return CustomTime(testTimeValue) +} + +func (c CustomTime) String() string { + return time.Time(c).String() +} + +type CustomSlice []string + +func (c CustomSlice) Fake() interface{} { + return CustomSlice([]string{"hello", "test"}) +} + +type CustomMap map[string]string + +func (c CustomMap) Fake() interface{} { + return CustomMap(map[string]string{"hello": "1", "test": "2"}) +} + +type CustomStruct struct { + Str string + Int int +} + +func (c CustomStruct) Fake() interface{} { + return CustomStruct{ + Str: "hello test", + Int: 42, + } +} + +type NestedCustom struct { + Str CustomString + Bool CustomBool + Int CustomInt + Int8 CustomInt8 + Int16 CustomInt16 + Int32 CustomInt32 + Int64 CustomInt64 + Uint CustomUint + Uint8 CustomUint8 + Uint16 CustomUint16 + Uint32 CustomUint32 + Uint64 CustomUint64 + Float32 CustomFloat32 + Float64 CustomFloat64 + Timestamp CustomTime + SliceStr CustomSlice + MapStr CustomMap + Struct CustomStruct + PtrStruct *CustomStruct +} + +type NestedOverrideCustom struct { + Str CustomString `fake:"{name}"` + Bool CustomBool `fake:"false"` + Int CustomInt `fake:"{number:-10,1000}"` + Int8 CustomInt8 `fake:"{number:-10,1000}"` + Int16 CustomInt16 `fake:"{number:-10,1000}"` + Int32 CustomInt32 `fake:"{number:-10,1000}"` + Int64 CustomInt64 `fake:"{number:-10,1000}"` + Uint CustomUint `fake:"{number:100,1000}"` + Uint8 CustomUint8 `fake:"{number:100,1000}"` + Uint16 CustomUint16 `fake:"{number:100,1000}"` + Uint32 CustomUint32 `fake:"{number:100,1000}"` + Uint64 CustomUint64 `fake:"{number:100,1000}"` + Float32 CustomFloat32 `fake:"{number:100,1000}"` + Float64 CustomFloat64 `fake:"{number:100,1000}"` + Timestamp CustomTime `fake:"{raw_test_date}"` + SliceStr CustomSlice `fake:"{word}"` + MapStr CustomMap `fakesize:"2"` +} + +func TestCustomString(t *testing.T) { + var d CustomString + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := "hello test" + if d != CustomString(expected) { + t.Errorf("expected %q, got %q", expected, d) + } +} + +func TestCustomBool(t *testing.T) { + var d CustomBool + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := true + if d != CustomBool(expected) { + t.Errorf("expected %t, got %t", expected, d) + } +} + +func TestCustomInt(t *testing.T) { + var d CustomInt + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := -42 + if d != CustomInt(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomInt8(t *testing.T) { + var d CustomInt8 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := -42 + if d != CustomInt8(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomInt16(t *testing.T) { + var d CustomInt16 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := -42 + if d != CustomInt16(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomInt32(t *testing.T) { + var d CustomInt32 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := -42 + if d != CustomInt32(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomInt64(t *testing.T) { + var d CustomInt64 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := -42 + if d != CustomInt64(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomUint(t *testing.T) { + var d CustomUint + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42 + if d != CustomUint(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomUint8(t *testing.T) { + var d CustomUint8 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42 + if d != CustomUint8(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomUint16(t *testing.T) { + var d CustomUint16 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42 + if d != CustomUint16(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomUint32(t *testing.T) { + var d CustomUint32 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42 + if d != CustomUint32(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomUint64(t *testing.T) { + var d CustomUint64 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42 + if d != CustomUint64(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} +func TestCustomFloat32(t *testing.T) { + var d CustomFloat32 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42.123 + if d != CustomFloat32(expected) { + t.Errorf("expected %f, got %f", expected, d) + } +} + +func TestCustomFloat64(t *testing.T) { + var d CustomFloat64 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42.123 + if d != CustomFloat64(expected) { + t.Errorf("expected %f, got %f", expected, d) + } +} + +func TestCustomTime(t *testing.T) { + var d CustomTime + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := testTimeValue + if d != CustomTime(expected) { + t.Errorf("expected %q, got %q", expected.String(), d.String()) + } +} + +func TestCustomSlice(t *testing.T) { + var d CustomSlice + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := []string{"hello", "test"} + if len(d) != len(expected) { + t.Fatalf("expected %v, got %v", expected, d) + } + for i, v := range expected { + if d[i] != v { + t.Errorf("expected item %d of the slice to be: %v, got %v", i, expected[i], d[i]) + } + } +} + +func TestCustomMap(t *testing.T) { + var d CustomMap + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := map[string]string{"hello": "1", "test": "2"} + if len(d) != len(expected) { + t.Fatalf("expected %v, got %v", expected, d) + } + for k, v := range expected { + if d[k] != v { + t.Errorf("expected item %v of the slice to be: %v, got %v", k, expected[k], d[k]) + } + } +} + +func TestCustomStruct(t *testing.T) { + var d CustomStruct + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + if d.Str != "hello test" { + t.Errorf("expected %q, got %q", "hello test", d.Str) + } + if d.Int != 42 { + t.Errorf("expected %d, got %d", 42, d.Int) + } +} + +func TestNestedCustom(t *testing.T) { + var d NestedCustom + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expectedStr := "hello test" + if d.Str != CustomString(expectedStr) { + t.Errorf("Str: expected %q, got %q", expectedStr, d.Str) + } + + if !d.Bool { + t.Errorf("Bool: expected true, got false") + } + + expectedInt := -42 + if d.Int != CustomInt(expectedInt) { + t.Errorf("Int: expected %d, got %d", expectedInt, d.Int) + } + if d.Int8 != CustomInt8(expectedInt) { + t.Errorf("Int: expected %d, got %d", expectedInt, d.Int8) + } + if d.Int16 != CustomInt16(expectedInt) { + t.Errorf("Int: expected %d, got %d", expectedInt, d.Int16) + } + if d.Int32 != CustomInt32(expectedInt) { + t.Errorf("Int: expected %d, got %d", expectedInt, d.Int32) + } + if d.Int64 != CustomInt64(expectedInt) { + t.Errorf("Int: expected %d, got %d", expectedInt, d.Int64) + } + + expectedUint := uint(42) + if d.Uint != CustomUint(expectedUint) { + t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint) + } + if d.Uint8 != CustomUint8(expectedUint) { + t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint8) + } + if d.Uint16 != CustomUint16(expectedUint) { + t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint16) + } + if d.Uint32 != CustomUint32(expectedUint) { + t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint32) + } + if d.Uint64 != CustomUint64(expectedUint) { + t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint64) + } + + expectedFloat := 42.123 + if d.Float32 != CustomFloat32(expectedFloat) { + t.Errorf("Float: expected %f, got %f", expectedFloat, d.Float32) + } + if d.Float64 != CustomFloat64(expectedFloat) { + t.Errorf("Float: expected %f, got %f", expectedFloat, d.Float64) + } + + expectedSlice := []string{"hello", "test"} + if len(d.SliceStr) != len(expectedSlice) { + t.Fatalf("expected %v, got %v", expectedSlice, d.SliceStr) + } + for i, v := range expectedSlice { + if d.SliceStr[i] != v { + t.Errorf("expected item %d of the slice to be: %v, got %v", i, expectedSlice[i], d.SliceStr[i]) + } + } + + expectedMap := map[string]string{"hello": "1", "test": "2"} + if len(d.MapStr) != len(expectedMap) { + t.Fatalf("expected %v, got %v", expectedMap, d) + } + for k, v := range expectedMap { + if d.MapStr[k] != v { + t.Errorf("expected item %v of the map to be: %v, got %v", k, expectedMap[k], d.MapStr[k]) + } + } + + if d.Struct.Str != "hello test" { + t.Errorf("expected %q, got %q", "hello test", d.Struct.Str) + } + if d.Struct.Int != 42 { + t.Errorf("expected %d, got %d", 42, d.Struct.Int) + } + + if d.PtrStruct == nil { + t.Fatal("expected PtrStruct to not be nil") + } + + if d.PtrStruct.Str != "hello test" { + t.Errorf("expected %q, got %q", "hello test", d.PtrStruct.Str) + } + if d.PtrStruct.Int != 42 { + t.Errorf("expected %d, got %d", 42, d.PtrStruct.Int) + } +} + +func TestNestedOverrideCustom(t *testing.T) { + gofakeit.AddFuncLookup("raw_test_date", gofakeit.Info{ + Display: "Date", + Category: "time", + Description: "Random date", + Example: "2006-01-02T15:04:05Z07:00", + Output: "time.Time", + Params: []gofakeit.Param{ + { + Field: "format", + Display: "Format", + Type: "time.Time", + Description: "Raw date time.Time object", + }, + }, + Generate: func(r *rand.Rand, m *gofakeit.MapParams, info *gofakeit.Info) (interface{}, error) { + return gofakeit.Date(), nil + }, + }) + + defer gofakeit.RemoveFuncLookup("raw_test_date") + + var d NestedOverrideCustom + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + nonOverrideStr := "hello test" + if d.Str == CustomString(nonOverrideStr) { + t.Errorf("Str: expected a random string but got the non-overriden value") + } + + if d.Bool { + t.Errorf("Bool: expected false, got true") + } + + nonOverrideInt := -42 + if d.Int == CustomInt(nonOverrideInt) { + t.Errorf("Int: expected a random integer but got the non-overriden value") + } + if d.Int8 == CustomInt8(nonOverrideInt) { + t.Errorf("Int: expected a random integer but got the non-overriden value") + } + if d.Int16 == CustomInt16(nonOverrideInt) { + t.Errorf("Int: expected a random integer but got the non-overriden value") + } + if d.Int32 == CustomInt32(nonOverrideInt) { + t.Errorf("Int: expected a random integer but got the non-overriden value") + } + if d.Int64 == CustomInt64(nonOverrideInt) { + t.Errorf("Int: expected a random integer but got the non-overriden value") + } + + nonOverrideUint := uint(42) + if d.Uint == CustomUint(nonOverrideUint) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + if d.Uint8 == CustomUint8(nonOverrideUint) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + if d.Uint16 == CustomUint16(nonOverrideUint) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + if d.Uint32 == CustomUint32(nonOverrideUint) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + if d.Uint64 == CustomUint64(nonOverrideUint) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + + nonOverrideFloat := 42.123 + if d.Float32 == CustomFloat32(nonOverrideFloat) { + t.Errorf("Float: expected a random unsigned integer but got the non-overriden value") + } + if d.Float64 == CustomFloat64(nonOverrideFloat) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + + nonOverrideSlice := []string{"hello", "test"} + if len(d.SliceStr) == len(nonOverrideSlice) { + t.Logf("Slice: Got the same length as the non-overriden slice: %v vs %v", nonOverrideSlice, d.SliceStr) + for i, v := range nonOverrideSlice { + if d.SliceStr[i] == v { + t.Errorf("Slice: Got non-overriden item %d in the slice", i) + } + } + } + + nonOverrideMap := map[string]string{"hello": "1", "test": "2"} + if len(d.MapStr) == len(nonOverrideMap) { + t.Logf("Map: Got the same length as the non-overriden map: %v vs %v", nonOverrideMap, d.MapStr) + + for k, v := range nonOverrideMap { + if d.MapStr[k] == v { + t.Errorf("Map: Got non-overriden item %v in the slice", k) + } + } + } +} diff --git a/struct.go b/struct.go index 64932eb2..76a24744 100644 --- a/struct.go +++ b/struct.go @@ -10,7 +10,9 @@ import ( ) // Struct fills in exported fields of a struct with random data -// based on the value of `fake` tag of exported fields. +// based on the value of `fake` tag of exported fields +// or with the result of a call to the Fake() method +// if the field type implements `Fakeable`. // Use `fake:"skip"` to explicitly skip an element. // All built-in types are supported, with templating support // for string types. @@ -88,7 +90,7 @@ func rCustom(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { } // Set the value - v.Set(fieldElem) + v.Set(fieldElem.Convert(v.Type())) // If a function is called to set the struct // stop from going through sub fields @@ -102,66 +104,74 @@ func rStruct(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { // Check if tag exists, if so run custom function if t.Name() != "" && tag != "" { return rCustom(ra, t, v, tag) - } + } else if isFakeable(t) { + value, err := callFake(v, reflect.Struct) + if err != nil { + return err + } - n := t.NumField() - for i := 0; i < n; i++ { - elementT := t.Field(i) - elementV := v.Field(i) - fakeTag, ok := elementT.Tag.Lookup("fake") + v.Set(reflect.ValueOf(value)) + } else { - // Check whether or not to skip this field - if ok && fakeTag == "skip" { - // Do nothing, skip it - continue - } + n := t.NumField() + for i := 0; i < n; i++ { + elementT := t.Field(i) + elementV := v.Field(i) + fakeTag, ok := elementT.Tag.Lookup("fake") - // Check to make sure you can set it or that its an embeded(anonymous) field - if elementV.CanSet() || elementT.Anonymous { - // Check if reflect type is of values we can specifically set - switch elementT.Type.String() { - case "time.Time": - err := rTime(ra, elementT, elementV, fakeTag) - if err != nil { - return err - } + // Check whether or not to skip this field + if ok && fakeTag == "skip" { + // Do nothing, skip it continue } - // Check if fakesize is set - size := -1 // Set to -1 to indicate fakesize was not set - fs, ok := elementT.Tag.Lookup("fakesize") - if ok { - var err error - - // Check if size has params separated by , - if strings.Contains(fs, ",") { - sizeSplit := strings.SplitN(fs, ",", 2) - if len(sizeSplit) == 2 { - var sizeMin int - var sizeMax int + // Check to make sure you can set it or that its an embeded(anonymous) field + if elementV.CanSet() || elementT.Anonymous { + // Check if reflect type is of values we can specifically set + switch elementT.Type.String() { + case "time.Time": + err := rTime(ra, elementT, elementV, fakeTag) + if err != nil { + return err + } + continue + } - sizeMin, err = strconv.Atoi(sizeSplit[0]) - if err != nil { - return err + // Check if fakesize is set + size := -1 // Set to -1 to indicate fakesize was not set + fs, ok := elementT.Tag.Lookup("fakesize") + if ok { + var err error + + // Check if size has params separated by , + if strings.Contains(fs, ",") { + sizeSplit := strings.SplitN(fs, ",", 2) + if len(sizeSplit) == 2 { + var sizeMin int + var sizeMax int + + sizeMin, err = strconv.Atoi(sizeSplit[0]) + if err != nil { + return err + } + sizeMax, err = strconv.Atoi(sizeSplit[1]) + if err != nil { + return err + } + + size = ra.Intn(sizeMax-sizeMin+1) + sizeMin } - sizeMax, err = strconv.Atoi(sizeSplit[1]) + } else { + size, err = strconv.Atoi(fs) if err != nil { return err } - - size = ra.Intn(sizeMax-sizeMin+1) + sizeMin - } - } else { - size, err = strconv.Atoi(fs) - if err != nil { - return err } } - } - err := r(ra, elementT.Type, elementV, fakeTag, size) - if err != nil { - return err + err := r(ra, elementT.Type, elementV, fakeTag, size) + if err != nil { + return err + } } } } @@ -201,6 +211,14 @@ func rSlice(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int if err == nil { return nil } + } else if isFakeable(t) { + value, err := callFake(v, reflect.Slice) + if err != nil { + return err + } + + v.Set(reflect.ValueOf(value)) + return nil } // Grab original size to use if needed for sub arrays @@ -246,6 +264,16 @@ func rMap(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) // Check if tag exists, if so run custom function if t.Name() != "" && tag != "" { return rCustom(ra, t, v, tag) + } else if size > 0 { + //NOOP + } else if isFakeable(t) { + value, err := callFake(v, reflect.Map) + if err != nil { + return err + } + + v.Set(reflect.ValueOf(value)) + return nil } // Set a size @@ -289,6 +317,17 @@ func rMap(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) func rString(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { if tag != "" { v.SetString(generate(ra, tag)) + } else if isFakeable(t) { + value, err := callFake(v, reflect.String) + if err != nil { + return err + } + + valueStr, ok := value.(string) + if !ok { + return errors.New("call to Fake method did not return a string") + } + v.SetString(valueStr) } else { v.SetString(generate(ra, strings.Repeat("?", number(ra, 4, 10)))) } @@ -304,21 +343,40 @@ func rInt(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { } v.SetInt(i) - return nil - } + } else if isFakeable(t) { + value, err := callFake(v, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64) + if err != nil { + return err + } - // If no tag or error converting to int, set with random value - switch t.Kind() { - case reflect.Int: - v.SetInt(int64Func(ra)) - case reflect.Int8: - v.SetInt(int64(int8Func(ra))) - case reflect.Int16: - v.SetInt(int64(int16Func(ra))) - case reflect.Int32: - v.SetInt(int64(int32Func(ra))) - case reflect.Int64: - v.SetInt(int64Func(ra)) + switch i := value.(type) { + case int: + v.SetInt(int64(i)) + case int8: + v.SetInt(int64(i)) + case int16: + v.SetInt(int64(i)) + case int32: + v.SetInt(int64(i)) + case int64: + v.SetInt(int64(i)) + default: + return errors.New("call to Fake method did not return an integer") + } + } else { + // If no tag or error converting to int, set with random value + switch t.Kind() { + case reflect.Int: + v.SetInt(int64Func(ra)) + case reflect.Int8: + v.SetInt(int64(int8Func(ra))) + case reflect.Int16: + v.SetInt(int64(int16Func(ra))) + case reflect.Int32: + v.SetInt(int64(int32Func(ra))) + case reflect.Int64: + v.SetInt(int64Func(ra)) + } } return nil @@ -332,21 +390,40 @@ func rUint(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { } v.SetUint(u) - return nil - } + } else if isFakeable(t) { + value, err := callFake(v, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64) + if err != nil { + return err + } - // If no tag or error converting to uint, set with random value - switch t.Kind() { - case reflect.Uint: - v.SetUint(uint64Func(ra)) - case reflect.Uint8: - v.SetUint(uint64(uint8Func(ra))) - case reflect.Uint16: - v.SetUint(uint64(uint16Func(ra))) - case reflect.Uint32: - v.SetUint(uint64(uint32Func(ra))) - case reflect.Uint64: - v.SetUint(uint64Func(ra)) + switch i := value.(type) { + case uint: + v.SetUint(uint64(i)) + case uint8: + v.SetUint(uint64(i)) + case uint16: + v.SetUint(uint64(i)) + case uint32: + v.SetUint(uint64(i)) + case uint64: + v.SetUint(uint64(i)) + default: + return errors.New("call to Fake method did not return an unsigned integer") + } + } else { + // If no tag or error converting to uint, set with random value + switch t.Kind() { + case reflect.Uint: + v.SetUint(uint64Func(ra)) + case reflect.Uint8: + v.SetUint(uint64(uint8Func(ra))) + case reflect.Uint16: + v.SetUint(uint64(uint16Func(ra))) + case reflect.Uint32: + v.SetUint(uint64(uint32Func(ra))) + case reflect.Uint64: + v.SetUint(uint64Func(ra)) + } } return nil @@ -360,15 +437,28 @@ func rFloat(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { } v.SetFloat(f) - return nil - } + } else if isFakeable(t) { + value, err := callFake(v, reflect.Float32, reflect.Float64) + if err != nil { + return err + } - // If no tag or error converting to float, set with random value - switch t.Kind() { - case reflect.Float64: - v.SetFloat(float64Func(ra)) - case reflect.Float32: - v.SetFloat(float64(float32Func(ra))) + switch i := value.(type) { + case float32: + v.SetFloat(float64(i)) + case float64: + v.SetFloat(float64(i)) + default: + return errors.New("call to Fake method did not return a float") + } + } else { + // If no tag or error converting to float, set with random value + switch t.Kind() { + case reflect.Float64: + v.SetFloat(float64Func(ra)) + case reflect.Float32: + v.SetFloat(float64(float32Func(ra))) + } } return nil @@ -382,11 +472,22 @@ func rBool(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { } v.SetBool(b) - return nil - } + } else if isFakeable(t) { + value, err := callFake(v, reflect.Bool) + if err != nil { + return err + } - // If no tag or error converting to boolean, set with random value - v.SetBool(boolFunc(ra)) + switch i := value.(type) { + case bool: + v.SetBool(bool(i)) + default: + return errors.New("call to Fake method did not return a boolean") + } + } else { + // If no tag or error converting to boolean, set with random value + v.SetBool(boolFunc(ra)) + } return nil } From f95414af37006339fdbb43d2029f2d4590df1614 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 27 Mar 2023 02:38:44 +0200 Subject: [PATCH 03/41] Add test for gofakeit.Slice --- fakeable_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fakeable_test.go b/fakeable_test.go index 879b4cd4..d4b2a38d 100644 --- a/fakeable_test.go +++ b/fakeable_test.go @@ -614,3 +614,19 @@ func TestNestedOverrideCustom(t *testing.T) { } } } + +func TestSliceCustom(t *testing.T) { + var B []CustomString + gofakeit.Slice(&B) + + if len(B) == 0 { + t.Errorf("expected slice to not be empty") + } + + expected := CustomString("hello test") + for _, v := range B { + if v != expected { + t.Errorf("expected all items to be %q, got %q", expected, v) + } + } +} From 48870e9e46c31f6ac558660cd10e291123f13057 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 27 Mar 2023 19:28:03 +0200 Subject: [PATCH 04/41] Failing test --- json_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/json_test.go b/json_test.go index 1d273484..c5b6752d 100644 --- a/json_test.go +++ b/json_test.go @@ -352,6 +352,16 @@ func TestJSONNoCount(t *testing.T) { } } +func TestJSONNoOptions(t *testing.T) { + Seed(11) + + // if JSONOptions is nil -> get a random JSONOptions + _, err := JSON(nil) + if err != nil { + t.Fatal(err.Error()) + } +} + func BenchmarkJSONLookup100(b *testing.B) { faker := New(0) From ddba9e0e5266015dd8c116e6b969821c31d61b00 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 27 Mar 2023 19:41:16 +0200 Subject: [PATCH 05/41] Add random JSON generation when JSONOptions is nil --- json.go | 18 ++++++++++++++---- lookup.go | 4 ++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/json.go b/json.go index b284fed6..e5d7b136 100644 --- a/json.go +++ b/json.go @@ -9,8 +9,8 @@ import ( // JSONOptions defines values needed for json generation type JSONOptions struct { - Type string `json:"type" xml:"type"` // array or object - RowCount int `json:"row_count" xml:"row_count"` + Type string `json:"type" xml:"type" fake:"{randomstring:[array,object]}"` // array or object + RowCount int `json:"row_count" xml:"row_count" fake:"{number:1,10}"` Fields []Field `json:"fields" xml:"fields"` Indent bool `json:"indent" xml:"indent"` } @@ -54,14 +54,24 @@ func (okv jsonOrderedKeyVal) MarshalJSON() ([]byte, error) { return buf.Bytes(), nil } -// JSON generates an object or an array of objects in json format +// JSON generates an object or an array of objects in json format. +// A nil JSONOptions returns a randomly structured JSON. func JSON(jo *JSONOptions) ([]byte, error) { return jsonFunc(globalFaker.Rand, jo) } -// JSON generates an object or an array of objects in json format +// JSON generates an object or an array of objects in json format. +// A nil JSONOptions returns a randomly structured JSON. func (f *Faker) JSON(jo *JSONOptions) ([]byte, error) { return jsonFunc(f.Rand, jo) } // JSON generates an object or an array of objects in json format func jsonFunc(r *rand.Rand, jo *JSONOptions) ([]byte, error) { + if jo == nil { + // We didn't get a JSONOptions, so create a new random one + err := Struct(&jo) + if err != nil { + return nil, err + } + } + // Check to make sure they passed in a type if jo.Type != "array" && jo.Type != "object" { return nil, errors.New("invalid type, must be array or object") diff --git a/lookup.go b/lookup.go index 29732932..7f43049c 100644 --- a/lookup.go +++ b/lookup.go @@ -45,8 +45,8 @@ type Param struct { // Field is used for defining what name and function you to generate for file outuputs type Field struct { Name string `json:"name"` - Function string `json:"function"` - Params MapParams `json:"params"` + Function string `json:"function" fake:"{randomstring:[firstname,autoincrement]}"` + Params MapParams `json:"params" fake:"skip"` } func init() { initLookup() } From 92571833af0ac5c2fb005f8fc2d387b545bf41b6 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 27 Mar 2023 19:44:39 +0200 Subject: [PATCH 06/41] Failing test --- xml_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/xml_test.go b/xml_test.go index a78dec06..6854423c 100644 --- a/xml_test.go +++ b/xml_test.go @@ -239,6 +239,16 @@ func TestXMLLookup(t *testing.T) { } } +func TestXMLNoOptions(t *testing.T) { + Seed(11) + + // if XMLOptions is nil -> get a random XMLOptions + _, err := XML(nil) + if err != nil { + t.Fatal(err.Error()) + } +} + func BenchmarkXMLLookup100(b *testing.B) { faker := New(0) From a19bdf771a58afea08ca1a135195805ab0e8f0a5 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 27 Mar 2023 19:46:22 +0200 Subject: [PATCH 07/41] Fix comment to match usage --- xml.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xml.go b/xml.go index 98482cec..eeb15160 100644 --- a/xml.go +++ b/xml.go @@ -11,7 +11,7 @@ import ( // XMLOptions defines values needed for json generation type XMLOptions struct { - Type string `json:"type" xml:"type"` // single or multiple + Type string `json:"type" xml:"type"` // single or array RootElement string `json:"root_element" xml:"root_element"` RecordElement string `json:"record_element" xml:"record_element"` RowCount int `json:"row_count" xml:"row_count"` From 76a2df173096755cfe2e32b5fc37f33b0116785e Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 27 Mar 2023 19:49:11 +0200 Subject: [PATCH 08/41] Add random XML generation when XMLOptions is nil --- xml.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/xml.go b/xml.go index eeb15160..b2e0c9e8 100644 --- a/xml.go +++ b/xml.go @@ -11,10 +11,10 @@ import ( // XMLOptions defines values needed for json generation type XMLOptions struct { - Type string `json:"type" xml:"type"` // single or array + Type string `json:"type" xml:"type" fake:"{randomstring:[array,single]}"` // single or array RootElement string `json:"root_element" xml:"root_element"` RecordElement string `json:"record_element" xml:"record_element"` - RowCount int `json:"row_count" xml:"row_count"` + RowCount int `json:"row_count" xml:"row_count" fake:"{number:1,10}"` Fields []Field `json:"fields" xml:"fields"` Indent bool `json:"indent" xml:"indent"` } @@ -128,12 +128,22 @@ func xmlMapLoop(e *xml.Encoder, m *xmlMap) error { } // XML generates an object or an array of objects in json format +// A nil XMLOptions returns a randomly structured XML. func XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(globalFaker.Rand, xo) } // XML generates an object or an array of objects in json format +// A nil XMLOptions returns a randomly structured XML. func (f *Faker) XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(f.Rand, xo) } func xmlFunc(r *rand.Rand, xo *XMLOptions) ([]byte, error) { + if xo == nil { + // We didn't get a XMLOptions, so create a new random one + err := Struct(&xo) + if err != nil { + return nil, err + } + } + // Check to make sure they passed in a type if xo.Type != "single" && xo.Type != "array" { return nil, errors.New("invalid type, must be array or object") From 49efc36a2fcfd7c2eb371908a74b756306686449 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 28 Mar 2023 00:08:06 +0200 Subject: [PATCH 09/41] Implement random Fields from existing Lookups --- json.go | 2 +- lookup.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++------ xml.go | 2 +- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/json.go b/json.go index e5d7b136..46c8daac 100644 --- a/json.go +++ b/json.go @@ -11,7 +11,7 @@ import ( type JSONOptions struct { Type string `json:"type" xml:"type" fake:"{randomstring:[array,object]}"` // array or object RowCount int `json:"row_count" xml:"row_count" fake:"{number:1,10}"` - Fields []Field `json:"fields" xml:"fields"` + Fields []Field `json:"fields" xml:"fields" fake:"{internal_exampleFields}"` Indent bool `json:"indent" xml:"indent"` } diff --git a/lookup.go b/lookup.go index 7f43049c..e5c4029f 100644 --- a/lookup.go +++ b/lookup.go @@ -14,6 +14,35 @@ import ( var FuncLookups map[string]Info var lockFuncLookups sync.Mutex +// internalFuncLookups is the internal map array with mapping to all available data +var internalFuncLookups map[string]Info = map[string]Info{ + "internal_exampleFields": { + Description: "Example fields for generating xml and json", + Example: `{"name":"{firstname}","age":"{number:1,100}"}`, + Output: "gofakeit.Field", + Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) { + name, _ := getRandomFuncLookup(r, true) + return Field{ + Name: name, + Function: name, + }, nil + }, + }, +} + +func getRandomFuncLookup(r *rand.Rand, excludeWithParams bool) (string, Info) { + var keys []string + for k, v := range FuncLookups { + if excludeWithParams && len(v.Params) != 0 { + continue + } + keys = append(keys, k) + } + + selected := keys[r.Intn(len(keys))] + return selected, FuncLookups[selected] +} + // MapParams is the values to pass into a lookup generate type MapParams map[string]MapParamsValue @@ -45,8 +74,8 @@ type Param struct { // Field is used for defining what name and function you to generate for file outuputs type Field struct { Name string `json:"name"` - Function string `json:"function" fake:"{randomstring:[firstname,autoincrement]}"` - Params MapParams `json:"params" fake:"skip"` + Function string `json:"function"` + Params MapParams `json:"params"` } func init() { initLookup() } @@ -170,6 +199,10 @@ func (m *MapParamsValue) UnmarshalJSON(data []byte) error { // AddFuncLookup takes a field and adds it to map func AddFuncLookup(functionName string, info Info) { + if _, ok := internalFuncLookups[functionName]; ok { + panic(fmt.Sprintf("Function %s is used internally and cannot be overwritten", functionName)) + } + if FuncLookups == nil { FuncLookups = make(map[string]Info) } @@ -186,16 +219,28 @@ func AddFuncLookup(functionName string, info Info) { // GetFuncLookup will lookup func GetFuncLookup(functionName string) *Info { - info, ok := FuncLookups[functionName] - if !ok { - return nil + var info Info + var ok bool + + info, ok = internalFuncLookups[functionName] + if ok { + return &info + } + + info, ok = FuncLookups[functionName] + if ok { + return &info } - return &info + return nil } // RemoveFuncLookup will remove a function from lookup func RemoveFuncLookup(functionName string) { + if _, ok := internalFuncLookups[functionName]; ok { + panic(fmt.Sprintf("Function %s is used internally and cannot be overwritten", functionName)) + } + _, ok := FuncLookups[functionName] if !ok { return diff --git a/xml.go b/xml.go index b2e0c9e8..b34caa53 100644 --- a/xml.go +++ b/xml.go @@ -15,7 +15,7 @@ type XMLOptions struct { RootElement string `json:"root_element" xml:"root_element"` RecordElement string `json:"record_element" xml:"record_element"` RowCount int `json:"row_count" xml:"row_count" fake:"{number:1,10}"` - Fields []Field `json:"fields" xml:"fields"` + Fields []Field `json:"fields" xml:"fields" fake:"{internal_exampleFields}"` Indent bool `json:"indent" xml:"indent"` } From de5f23c1eeab8c27cf6b30cbcc0dab1be7075d39 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 28 Mar 2023 00:31:31 +0200 Subject: [PATCH 10/41] Failing test --- csv_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/csv_test.go b/csv_test.go index 5e08c7a3..19e10971 100644 --- a/csv_test.go +++ b/csv_test.go @@ -99,6 +99,16 @@ func TestCSVLookup(t *testing.T) { // t.Fatal(fmt.Sprintf("%s", value.([]byte))) } +func TestCSVNoOptions(t *testing.T) { + Seed(11) + + // if CSVOptions is nil -> get a random CSVOptions + _, err := CSV(nil) + if err != nil { + t.Fatal(err.Error()) + } +} + func BenchmarkCSVLookup100(b *testing.B) { faker := New(0) From 6302bb96da571ac395af9e1efb1bf30048da413f Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 28 Mar 2023 00:32:28 +0200 Subject: [PATCH 11/41] Add random CSV generation when CSVOptions is nil --- csv.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/csv.go b/csv.go index 0057d5d7..d8294f41 100644 --- a/csv.go +++ b/csv.go @@ -13,18 +13,28 @@ import ( // CSVOptions defines values needed for csv generation type CSVOptions struct { - Delimiter string `json:"delimiter" xml:"delimiter"` - RowCount int `json:"row_count" xml:"row_count"` - Fields []Field `json:"fields" xml:"fields"` + Delimiter string `json:"delimiter" xml:"delimiter" fake:"{randomstring:[,,tab]}"` + RowCount int `json:"row_count" xml:"row_count" fake:"{number:1,10}"` + Fields []Field `json:"fields" xml:"fields" fake:"{internal_exampleFields}"` } // CSV generates an object or an array of objects in json format +// A nil CSVOptions returns a randomly structured CSV. func CSV(co *CSVOptions) ([]byte, error) { return csvFunc(globalFaker.Rand, co) } // CSV generates an object or an array of objects in json format +// A nil CSVOptions returns a randomly structured CSV. func (f *Faker) CSV(co *CSVOptions) ([]byte, error) { return csvFunc(f.Rand, co) } func csvFunc(r *rand.Rand, co *CSVOptions) ([]byte, error) { + if co == nil { + // We didn't get a CSVOptions, so create a new random one + err := Struct(&co) + if err != nil { + return nil, err + } + } + // Check delimiter if co.Delimiter == "" { co.Delimiter = "," From 5821a3a62bf43d4bcd9a8b892f67daee500cfe95 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 28 Mar 2023 20:45:17 +0200 Subject: [PATCH 12/41] Add missing CSV --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 05c27fa9..4a3b9655 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,7 @@ All functions also exist as methods on the Faker struct ### File ```go +CSV(co *CSVOptions) ([]byte, error) JSON(jo *JSONOptions) ([]byte, error) XML(xo *XMLOptions) ([]byte, error) FileExtension() string From 4dc8e21308b8ad8334d67f5a208b94350857055e Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 28 Mar 2023 20:50:53 +0200 Subject: [PATCH 13/41] Explain nil argument to CSV/JSON/XML --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4a3b9655..32884426 100644 --- a/README.md +++ b/README.md @@ -226,6 +226,8 @@ All functions also exist as methods on the Faker struct ### File +Passing `nil` to `CSV`, `JSON` or `XML` it will auto generate data using a random set of generators. + ```go CSV(co *CSVOptions) ([]byte, error) JSON(jo *JSONOptions) ([]byte, error) From a8cf717704e9f7f3d5f2de53198aa326d8df13b8 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 28 Mar 2023 23:30:47 +0200 Subject: [PATCH 14/41] Refactor to pass *Faker instead of *rand.Rand --- slice.go | 9 ++-- struct.go | 121 +++++++++++++++++++++++++++--------------------------- 2 files changed, 64 insertions(+), 66 deletions(-) diff --git a/slice.go b/slice.go index 5f93fa5b..b225abc4 100644 --- a/slice.go +++ b/slice.go @@ -1,16 +1,15 @@ package gofakeit import ( - "math/rand" "reflect" ) // Slice fills built-in types and exported fields of a struct with random data. -func Slice(v interface{}) { sliceFunc(globalFaker.Rand, v) } +func Slice(v interface{}) { sliceFunc(globalFaker, v) } // Slice fills built-in types and exported fields of a struct with random data. -func (f *Faker) Slice(v interface{}) { sliceFunc(f.Rand, v) } +func (f *Faker) Slice(v interface{}) { sliceFunc(f, v) } -func sliceFunc(ra *rand.Rand, v interface{}) { - r(ra, reflect.TypeOf(v), reflect.ValueOf(v), "", -1) +func sliceFunc(f *Faker, v interface{}) { + r(f, reflect.TypeOf(v), reflect.ValueOf(v), "", -1) } diff --git a/struct.go b/struct.go index 76a24744..6e52c1d5 100644 --- a/struct.go +++ b/struct.go @@ -2,7 +2,6 @@ package gofakeit import ( "errors" - "math/rand" "reflect" "strconv" "strings" @@ -16,45 +15,45 @@ import ( // Use `fake:"skip"` to explicitly skip an element. // All built-in types are supported, with templating support // for string types. -func Struct(v interface{}) error { return structFunc(globalFaker.Rand, v) } +func Struct(v interface{}) error { return structFunc(globalFaker, v) } // Struct fills in exported fields of a struct with random data // based on the value of `fake` tag of exported fields. // Use `fake:"skip"` to explicitly skip an element. // All built-in types are supported, with templating support // for string types. -func (f *Faker) Struct(v interface{}) error { return structFunc(f.Rand, v) } +func (f *Faker) Struct(v interface{}) error { return structFunc(f, v) } -func structFunc(ra *rand.Rand, v interface{}) error { - return r(ra, reflect.TypeOf(v), reflect.ValueOf(v), "", 0) +func structFunc(f *Faker, v interface{}) error { + return r(f, reflect.TypeOf(v), reflect.ValueOf(v), "", 0) } -func r(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) error { +func r(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { switch t.Kind() { case reflect.Ptr: - return rPointer(ra, t, v, tag, size) + return rPointer(f, t, v, tag, size) case reflect.Struct: - return rStruct(ra, t, v, tag) + return rStruct(f, t, v, tag) case reflect.String: - return rString(ra, t, v, tag) + return rString(f, t, v, tag) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return rUint(ra, t, v, tag) + return rUint(f, t, v, tag) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return rInt(ra, t, v, tag) + return rInt(f, t, v, tag) case reflect.Float32, reflect.Float64: - return rFloat(ra, t, v, tag) + return rFloat(f, t, v, tag) case reflect.Bool: - return rBool(ra, t, v, tag) + return rBool(f, t, v, tag) case reflect.Array, reflect.Slice: - return rSlice(ra, t, v, tag, size) + return rSlice(f, t, v, tag, size) case reflect.Map: - return rMap(ra, t, v, tag, size) + return rMap(f, t, v, tag, size) } return nil } -func rCustom(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { +func rCustom(f *Faker, t reflect.Type, v reflect.Value, tag string) error { // If tag is empty return error if tag == "" { return errors.New("tag is empty") @@ -67,7 +66,7 @@ func rCustom(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { mapParams := parseMapParams(info, fParams) // Call function - fValue, err := info.Generate(ra, mapParams, info) + fValue, err := info.Generate(f.Rand, mapParams, info) if err != nil { return err } @@ -100,10 +99,10 @@ func rCustom(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { return errors.New("function not found") } -func rStruct(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { +func rStruct(f *Faker, t reflect.Type, v reflect.Value, tag string) error { // Check if tag exists, if so run custom function if t.Name() != "" && tag != "" { - return rCustom(ra, t, v, tag) + return rCustom(f, t, v, tag) } else if isFakeable(t) { value, err := callFake(v, reflect.Struct) if err != nil { @@ -130,7 +129,7 @@ func rStruct(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { // Check if reflect type is of values we can specifically set switch elementT.Type.String() { case "time.Time": - err := rTime(ra, elementT, elementV, fakeTag) + err := rTime(f, elementT, elementV, fakeTag) if err != nil { return err } @@ -159,7 +158,7 @@ func rStruct(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { return err } - size = ra.Intn(sizeMax-sizeMin+1) + sizeMin + size = f.Rand.Intn(sizeMax-sizeMin+1) + sizeMin } } else { size, err = strconv.Atoi(fs) @@ -168,7 +167,7 @@ func rStruct(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { } } } - err := r(ra, elementT.Type, elementV, fakeTag, size) + err := r(f, elementT.Type, elementV, fakeTag, size) if err != nil { return err } @@ -179,17 +178,17 @@ func rStruct(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { return nil } -func rPointer(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) error { +func rPointer(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { elemT := t.Elem() if v.IsNil() { nv := reflect.New(elemT) - err := r(ra, elemT, nv.Elem(), tag, size) + err := r(f, elemT, nv.Elem(), tag, size) if err != nil { return err } v.Set(nv) } else { - err := r(ra, elemT, v.Elem(), tag, size) + err := r(f, elemT, v.Elem(), tag, size) if err != nil { return err } @@ -198,7 +197,7 @@ func rPointer(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size i return nil } -func rSlice(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) error { +func rSlice(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { // If you cant even set it dont even try if !v.CanSet() { return errors.New("cannot set slice") @@ -207,7 +206,7 @@ func rSlice(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int // Check if tag exists, if so run custom function if t.Name() != "" && tag != "" { // Check to see if custom function works if not continue to normal loop of values - err := rCustom(ra, t, v, tag) + err := rCustom(f, t, v, tag) if err == nil { return nil } @@ -228,7 +227,7 @@ func rSlice(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int // use that instead of the requested size elemLen := v.Len() if elemLen == 0 && size == -1 { - size = number(ra, 1, 10) + size = number(f.Rand, 1, 10) } else if elemLen != 0 && (size == -1 || elemLen < size) { size = elemLen } @@ -239,7 +238,7 @@ func rSlice(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int // Loop through the elements length and set based upon the index for i := 0; i < size; i++ { nv := reflect.New(elemT) - err := r(ra, elemT, nv.Elem(), tag, ogSize) + err := r(f, elemT, nv.Elem(), tag, ogSize) if err != nil { return err } @@ -255,7 +254,7 @@ func rSlice(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int return nil } -func rMap(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) error { +func rMap(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { // If you cant even set it dont even try if !v.CanSet() { return errors.New("cannot set slice") @@ -263,7 +262,7 @@ func rMap(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) // Check if tag exists, if so run custom function if t.Name() != "" && tag != "" { - return rCustom(ra, t, v, tag) + return rCustom(f, t, v, tag) } else if size > 0 { //NOOP } else if isFakeable(t) { @@ -279,7 +278,7 @@ func rMap(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) // Set a size newSize := size if newSize == -1 { - newSize = number(ra, 1, 10) + newSize = number(f.Rand, 1, 10) } // Create new map based upon map key value type @@ -289,14 +288,14 @@ func rMap(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) for i := 0; i < newSize; i++ { // Create new key mapIndex := reflect.New(t.Key()) - err := r(ra, t.Key(), mapIndex.Elem(), "", -1) + err := r(f, t.Key(), mapIndex.Elem(), "", -1) if err != nil { return err } // Create new value mapValue := reflect.New(t.Elem()) - err = r(ra, t.Elem(), mapValue.Elem(), "", -1) + err = r(f, t.Elem(), mapValue.Elem(), "", -1) if err != nil { return err } @@ -314,9 +313,9 @@ func rMap(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string, size int) return nil } -func rString(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { +func rString(f *Faker, t reflect.Type, v reflect.Value, tag string) error { if tag != "" { - v.SetString(generate(ra, tag)) + v.SetString(generate(f.Rand, tag)) } else if isFakeable(t) { value, err := callFake(v, reflect.String) if err != nil { @@ -329,15 +328,15 @@ func rString(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { } v.SetString(valueStr) } else { - v.SetString(generate(ra, strings.Repeat("?", number(ra, 4, 10)))) + v.SetString(generate(f.Rand, strings.Repeat("?", number(f.Rand, 4, 10)))) } return nil } -func rInt(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { +func rInt(f *Faker, t reflect.Type, v reflect.Value, tag string) error { if tag != "" { - i, err := strconv.ParseInt(generate(ra, tag), 10, 64) + i, err := strconv.ParseInt(generate(f.Rand, tag), 10, 64) if err != nil { return err } @@ -367,24 +366,24 @@ func rInt(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { // If no tag or error converting to int, set with random value switch t.Kind() { case reflect.Int: - v.SetInt(int64Func(ra)) + v.SetInt(int64Func(f.Rand)) case reflect.Int8: - v.SetInt(int64(int8Func(ra))) + v.SetInt(int64(int8Func(f.Rand))) case reflect.Int16: - v.SetInt(int64(int16Func(ra))) + v.SetInt(int64(int16Func(f.Rand))) case reflect.Int32: - v.SetInt(int64(int32Func(ra))) + v.SetInt(int64(int32Func(f.Rand))) case reflect.Int64: - v.SetInt(int64Func(ra)) + v.SetInt(int64Func(f.Rand)) } } return nil } -func rUint(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { +func rUint(f *Faker, t reflect.Type, v reflect.Value, tag string) error { if tag != "" { - u, err := strconv.ParseUint(generate(ra, tag), 10, 64) + u, err := strconv.ParseUint(generate(f.Rand, tag), 10, 64) if err != nil { return err } @@ -414,24 +413,24 @@ func rUint(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { // If no tag or error converting to uint, set with random value switch t.Kind() { case reflect.Uint: - v.SetUint(uint64Func(ra)) + v.SetUint(uint64Func(f.Rand)) case reflect.Uint8: - v.SetUint(uint64(uint8Func(ra))) + v.SetUint(uint64(uint8Func(f.Rand))) case reflect.Uint16: - v.SetUint(uint64(uint16Func(ra))) + v.SetUint(uint64(uint16Func(f.Rand))) case reflect.Uint32: - v.SetUint(uint64(uint32Func(ra))) + v.SetUint(uint64(uint32Func(f.Rand))) case reflect.Uint64: - v.SetUint(uint64Func(ra)) + v.SetUint(uint64Func(f.Rand)) } } return nil } -func rFloat(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { +func rFloat(f *Faker, t reflect.Type, v reflect.Value, tag string) error { if tag != "" { - f, err := strconv.ParseFloat(generate(ra, tag), 64) + f, err := strconv.ParseFloat(generate(f.Rand, tag), 64) if err != nil { return err } @@ -455,18 +454,18 @@ func rFloat(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { // If no tag or error converting to float, set with random value switch t.Kind() { case reflect.Float64: - v.SetFloat(float64Func(ra)) + v.SetFloat(float64Func(f.Rand)) case reflect.Float32: - v.SetFloat(float64(float32Func(ra))) + v.SetFloat(float64(float32Func(f.Rand))) } } return nil } -func rBool(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { +func rBool(f *Faker, t reflect.Type, v reflect.Value, tag string) error { if tag != "" { - b, err := strconv.ParseBool(generate(ra, tag)) + b, err := strconv.ParseBool(generate(f.Rand, tag)) if err != nil { return err } @@ -486,17 +485,17 @@ func rBool(ra *rand.Rand, t reflect.Type, v reflect.Value, tag string) error { } } else { // If no tag or error converting to boolean, set with random value - v.SetBool(boolFunc(ra)) + v.SetBool(boolFunc(f.Rand)) } return nil } // rTime will set a time.Time field the best it can from either the default date tag or from the generate tag -func rTime(ra *rand.Rand, t reflect.StructField, v reflect.Value, tag string) error { +func rTime(f *Faker, t reflect.StructField, v reflect.Value, tag string) error { if tag != "" { // Generate time - timeOutput := generate(ra, tag) + timeOutput := generate(f.Rand, tag) // Check to see if timeOutput has monotonic clock reading // if so, remove it. This is because time.Parse() does not @@ -536,6 +535,6 @@ func rTime(ra *rand.Rand, t reflect.StructField, v reflect.Value, tag string) er return nil } - v.Set(reflect.ValueOf(date(ra))) + v.Set(reflect.ValueOf(date(f.Rand))) return nil } From 191d15028a4404f5e8d6a954192caa3c96fc7c95 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 28 Mar 2023 23:34:08 +0200 Subject: [PATCH 15/41] Add passing *Faker in the Fakeable interface --- fakeable.go | 6 ++-- fakeable_test.go | 72 ++++++++++++++++++++++++++++++++++++------------ struct.go | 16 +++++------ 3 files changed, 65 insertions(+), 29 deletions(-) diff --git a/fakeable.go b/fakeable.go index 4983b3e7..49b6daf7 100644 --- a/fakeable.go +++ b/fakeable.go @@ -9,7 +9,7 @@ import ( // Fakeable is an interface that can be implemented by a type to provide a custom fake value. type Fakeable interface { // Fake returns a fake value for the type. - Fake() interface{} + Fake(faker *Faker) interface{} } func isFakeable(t reflect.Type) bool { @@ -17,13 +17,13 @@ func isFakeable(t reflect.Type) bool { return t.Implements(fakeableTyp) } -func callFake(v reflect.Value, possibleKinds ...reflect.Kind) (interface{}, error) { +func callFake(faker *Faker, v reflect.Value, possibleKinds ...reflect.Kind) (interface{}, error) { f, ok := v.Addr().Interface().(Fakeable) if !ok { return nil, errors.New("not a Fakeable type") } - fakedValue := f.Fake() + fakedValue := f.Fake(faker) k := reflect.TypeOf(fakedValue).Kind() if !contains(possibleKinds, k) { return nil, fmt.Errorf("returned value kind %q is not amongst the valid ones: %v", k, possibleKinds) diff --git a/fakeable_test.go b/fakeable_test.go index d4b2a38d..ae8f4e09 100644 --- a/fakeable_test.go +++ b/fakeable_test.go @@ -1,6 +1,7 @@ package gofakeit_test import ( + "fmt" "math/rand" "testing" "time" @@ -14,91 +15,91 @@ var ( type CustomString string -func (c CustomString) Fake() interface{} { +func (c CustomString) Fake(faker *gofakeit.Faker) interface{} { return CustomString("hello test") } type CustomBool bool -func (c CustomBool) Fake() interface{} { +func (c CustomBool) Fake(faker *gofakeit.Faker) interface{} { return CustomBool(true) } type CustomInt int -func (c CustomInt) Fake() interface{} { +func (c CustomInt) Fake(faker *gofakeit.Faker) interface{} { return CustomInt(-42) } type CustomInt8 int8 -func (c CustomInt8) Fake() interface{} { +func (c CustomInt8) Fake(faker *gofakeit.Faker) interface{} { return CustomInt8(-42) } type CustomInt16 int16 -func (c CustomInt16) Fake() interface{} { +func (c CustomInt16) Fake(faker *gofakeit.Faker) interface{} { return CustomInt16(-42) } type CustomInt32 int32 -func (c CustomInt32) Fake() interface{} { +func (c CustomInt32) Fake(faker *gofakeit.Faker) interface{} { return CustomInt32(-42) } type CustomInt64 int64 -func (c CustomInt64) Fake() interface{} { +func (c CustomInt64) Fake(faker *gofakeit.Faker) interface{} { return CustomInt64(-42) } type CustomUint uint -func (c CustomUint) Fake() interface{} { +func (c CustomUint) Fake(faker *gofakeit.Faker) interface{} { return CustomUint(42) } type CustomUint8 uint8 -func (c CustomUint8) Fake() interface{} { +func (c CustomUint8) Fake(faker *gofakeit.Faker) interface{} { return CustomUint8(42) } type CustomUint16 uint16 -func (c CustomUint16) Fake() interface{} { +func (c CustomUint16) Fake(faker *gofakeit.Faker) interface{} { return CustomUint16(42) } type CustomUint32 uint32 -func (c CustomUint32) Fake() interface{} { +func (c CustomUint32) Fake(faker *gofakeit.Faker) interface{} { return CustomUint32(42) } type CustomUint64 uint64 -func (c CustomUint64) Fake() interface{} { +func (c CustomUint64) Fake(faker *gofakeit.Faker) interface{} { return CustomUint64(42) } type CustomFloat32 float32 -func (c CustomFloat32) Fake() interface{} { +func (c CustomFloat32) Fake(faker *gofakeit.Faker) interface{} { return CustomFloat32(42.123) } type CustomFloat64 float64 -func (c CustomFloat64) Fake() interface{} { +func (c CustomFloat64) Fake(faker *gofakeit.Faker) interface{} { return CustomFloat64(42.123) } type CustomTime time.Time -func (c CustomTime) Fake() interface{} { +func (c CustomTime) Fake(faker *gofakeit.Faker) interface{} { return CustomTime(testTimeValue) } @@ -108,13 +109,13 @@ func (c CustomTime) String() string { type CustomSlice []string -func (c CustomSlice) Fake() interface{} { +func (c CustomSlice) Fake(faker *gofakeit.Faker) interface{} { return CustomSlice([]string{"hello", "test"}) } type CustomMap map[string]string -func (c CustomMap) Fake() interface{} { +func (c CustomMap) Fake(faker *gofakeit.Faker) interface{} { return CustomMap(map[string]string{"hello": "1", "test": "2"}) } @@ -123,7 +124,7 @@ type CustomStruct struct { Int int } -func (c CustomStruct) Fake() interface{} { +func (c CustomStruct) Fake(faker *gofakeit.Faker) interface{} { return CustomStruct{ Str: "hello test", Int: 42, @@ -630,3 +631,38 @@ func TestSliceCustom(t *testing.T) { } } } + +type testStruct1 struct { + B string `fake:"{firstname}"` +} + +type strTyp string + +type testStruct2 struct { + B strTyp +} + +func (t strTyp) Fake(faker *gofakeit.Faker) interface{} { + return faker.FirstName() +} + +func ExampleFakeable() { + var t1 testStruct1 + var t2 testStruct1 + var t3 testStruct2 + var t4 testStruct2 + gofakeit.New(314).Struct(&t1) + gofakeit.New(314).Struct(&t2) + gofakeit.New(314).Struct(&t3) + gofakeit.New(314).Struct(&t4) + + fmt.Printf("%#v\n", t1) + fmt.Printf("%#v\n", t2) + fmt.Printf("%#v\n", t3) + fmt.Printf("%#v\n", t4) + // Expected Output: + // gofakeit_test.testStruct1{B:"Margarette"} + // gofakeit_test.testStruct1{B:"Margarette"} + // gofakeit_test.testStruct2{B:"Margarette"} + // gofakeit_test.testStruct2{B:"Margarette"} +} diff --git a/struct.go b/struct.go index 6e52c1d5..56dd6431 100644 --- a/struct.go +++ b/struct.go @@ -104,7 +104,7 @@ func rStruct(f *Faker, t reflect.Type, v reflect.Value, tag string) error { if t.Name() != "" && tag != "" { return rCustom(f, t, v, tag) } else if isFakeable(t) { - value, err := callFake(v, reflect.Struct) + value, err := callFake(f, v, reflect.Struct) if err != nil { return err } @@ -211,7 +211,7 @@ func rSlice(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) err return nil } } else if isFakeable(t) { - value, err := callFake(v, reflect.Slice) + value, err := callFake(f, v, reflect.Slice) if err != nil { return err } @@ -266,7 +266,7 @@ func rMap(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error } else if size > 0 { //NOOP } else if isFakeable(t) { - value, err := callFake(v, reflect.Map) + value, err := callFake(f, v, reflect.Map) if err != nil { return err } @@ -317,7 +317,7 @@ func rString(f *Faker, t reflect.Type, v reflect.Value, tag string) error { if tag != "" { v.SetString(generate(f.Rand, tag)) } else if isFakeable(t) { - value, err := callFake(v, reflect.String) + value, err := callFake(f, v, reflect.String) if err != nil { return err } @@ -343,7 +343,7 @@ func rInt(f *Faker, t reflect.Type, v reflect.Value, tag string) error { v.SetInt(i) } else if isFakeable(t) { - value, err := callFake(v, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64) + value, err := callFake(f, v, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64) if err != nil { return err } @@ -390,7 +390,7 @@ func rUint(f *Faker, t reflect.Type, v reflect.Value, tag string) error { v.SetUint(u) } else if isFakeable(t) { - value, err := callFake(v, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64) + value, err := callFake(f, v, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64) if err != nil { return err } @@ -437,7 +437,7 @@ func rFloat(f *Faker, t reflect.Type, v reflect.Value, tag string) error { v.SetFloat(f) } else if isFakeable(t) { - value, err := callFake(v, reflect.Float32, reflect.Float64) + value, err := callFake(f, v, reflect.Float32, reflect.Float64) if err != nil { return err } @@ -472,7 +472,7 @@ func rBool(f *Faker, t reflect.Type, v reflect.Value, tag string) error { v.SetBool(b) } else if isFakeable(t) { - value, err := callFake(v, reflect.Bool) + value, err := callFake(f, v, reflect.Bool) if err != nil { return err } From 2c4a2774b588aa3af375b87e7c7bcb46b1c9f98a Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Sun, 2 Apr 2023 21:28:52 +0200 Subject: [PATCH 16/41] Refactor tests --- fakeable_external_test.go | 660 ++++++++++++++++++++++++++++++++++++++ fakeable_test.go | 651 +------------------------------------ 2 files changed, 676 insertions(+), 635 deletions(-) create mode 100644 fakeable_external_test.go diff --git a/fakeable_external_test.go b/fakeable_external_test.go new file mode 100644 index 00000000..6417e243 --- /dev/null +++ b/fakeable_external_test.go @@ -0,0 +1,660 @@ +package gofakeit_test + +import ( + "math/rand" + "testing" + "time" + + "github.com/brianvoe/gofakeit/v6" +) + +var ( + testTimeValue = time.Now() +) + +type CustomString string + +func (c CustomString) Fake(faker *gofakeit.Faker) interface{} { + return CustomString("hello test") +} + +type CustomBool bool + +func (c CustomBool) Fake(faker *gofakeit.Faker) interface{} { + return CustomBool(true) +} + +type CustomInt int + +func (c CustomInt) Fake(faker *gofakeit.Faker) interface{} { + return CustomInt(-42) +} + +type CustomInt8 int8 + +func (c CustomInt8) Fake(faker *gofakeit.Faker) interface{} { + return CustomInt8(-42) +} + +type CustomInt16 int16 + +func (c CustomInt16) Fake(faker *gofakeit.Faker) interface{} { + return CustomInt16(-42) +} + +type CustomInt32 int32 + +func (c CustomInt32) Fake(faker *gofakeit.Faker) interface{} { + return CustomInt32(-42) +} + +type CustomInt64 int64 + +func (c CustomInt64) Fake(faker *gofakeit.Faker) interface{} { + return CustomInt64(-42) +} + +type CustomUint uint + +func (c CustomUint) Fake(faker *gofakeit.Faker) interface{} { + return CustomUint(42) +} + +type CustomUint8 uint8 + +func (c CustomUint8) Fake(faker *gofakeit.Faker) interface{} { + return CustomUint8(42) +} + +type CustomUint16 uint16 + +func (c CustomUint16) Fake(faker *gofakeit.Faker) interface{} { + return CustomUint16(42) +} + +type CustomUint32 uint32 + +func (c CustomUint32) Fake(faker *gofakeit.Faker) interface{} { + return CustomUint32(42) +} + +type CustomUint64 uint64 + +func (c CustomUint64) Fake(faker *gofakeit.Faker) interface{} { + return CustomUint64(42) +} + +type CustomFloat32 float32 + +func (c CustomFloat32) Fake(faker *gofakeit.Faker) interface{} { + return CustomFloat32(42.123) +} + +type CustomFloat64 float64 + +func (c CustomFloat64) Fake(faker *gofakeit.Faker) interface{} { + return CustomFloat64(42.123) +} + +type CustomTime time.Time + +func (c *CustomTime) Fake(faker *gofakeit.Faker) interface{} { + return CustomTime(testTimeValue) +} + +func (c CustomTime) String() string { + return time.Time(c).String() +} + +type CustomSlice []string + +func (c CustomSlice) Fake(faker *gofakeit.Faker) interface{} { + return CustomSlice([]string{"hello", "test"}) +} + +type CustomMap map[string]string + +func (c CustomMap) Fake(faker *gofakeit.Faker) interface{} { + return CustomMap(map[string]string{"hello": "1", "test": "2"}) +} + +type CustomStruct struct { + Str string + Int int +} + +func (c CustomStruct) Fake(faker *gofakeit.Faker) interface{} { + return CustomStruct{ + Str: "hello test", + Int: 42, + } +} + +type NestedCustom struct { + Str CustomString + PtrStr *CustomString + Bool CustomBool + Int CustomInt + Int8 CustomInt8 + Int16 CustomInt16 + Int32 CustomInt32 + Int64 CustomInt64 + Uint CustomUint + Uint8 CustomUint8 + Uint16 CustomUint16 + Uint32 CustomUint32 + Uint64 CustomUint64 + Float32 CustomFloat32 + Float64 CustomFloat64 + Timestamp CustomTime + PtrTimestamp *CustomTime + SliceStr CustomSlice + MapStr CustomMap + Struct CustomStruct + PtrStruct *CustomStruct +} + +type NestedOverrideCustom struct { + Str CustomString `fake:"{name}"` + PtrStr *CustomString `fake:"{name}"` + Bool CustomBool `fake:"false"` + Int CustomInt `fake:"{number:-10,1000}"` + Int8 CustomInt8 `fake:"{number:-10,1000}"` + Int16 CustomInt16 `fake:"{number:-10,1000}"` + Int32 CustomInt32 `fake:"{number:-10,1000}"` + Int64 CustomInt64 `fake:"{number:-10,1000}"` + Uint CustomUint `fake:"{number:100,1000}"` + Uint8 CustomUint8 `fake:"{number:100,1000}"` + Uint16 CustomUint16 `fake:"{number:100,1000}"` + Uint32 CustomUint32 `fake:"{number:100,1000}"` + Uint64 CustomUint64 `fake:"{number:100,1000}"` + Float32 CustomFloat32 `fake:"{number:100,1000}"` + Float64 CustomFloat64 `fake:"{number:100,1000}"` + Timestamp CustomTime `fake:"{raw_test_date}"` + PtrTimestamp *CustomTime `fake:"{raw_test_date}"` + SliceStr CustomSlice `fake:"{word}"` + MapStr CustomMap `fakesize:"2"` +} + +func TestCustomString(t *testing.T) { + var d CustomString + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := "hello test" + if d != CustomString(expected) { + t.Errorf("expected %q, got %q", expected, d) + } +} + +func TestCustomBool(t *testing.T) { + var d CustomBool + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := true + if d != CustomBool(expected) { + t.Errorf("expected %t, got %t", expected, d) + } +} + +func TestCustomInt(t *testing.T) { + var d CustomInt + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := -42 + if d != CustomInt(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomInt8(t *testing.T) { + var d CustomInt8 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := -42 + if d != CustomInt8(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomInt16(t *testing.T) { + var d CustomInt16 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := -42 + if d != CustomInt16(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomInt32(t *testing.T) { + var d CustomInt32 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := -42 + if d != CustomInt32(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomInt64(t *testing.T) { + var d CustomInt64 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := -42 + if d != CustomInt64(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomUint(t *testing.T) { + var d CustomUint + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42 + if d != CustomUint(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomUint8(t *testing.T) { + var d CustomUint8 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42 + if d != CustomUint8(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomUint16(t *testing.T) { + var d CustomUint16 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42 + if d != CustomUint16(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomUint32(t *testing.T) { + var d CustomUint32 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42 + if d != CustomUint32(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} + +func TestCustomUint64(t *testing.T) { + var d CustomUint64 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42 + if d != CustomUint64(expected) { + t.Errorf("expected %d, got %d", expected, d) + } +} +func TestCustomFloat32(t *testing.T) { + var d CustomFloat32 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42.123 + if d != CustomFloat32(expected) { + t.Errorf("expected %f, got %f", expected, d) + } +} + +func TestCustomFloat64(t *testing.T) { + var d CustomFloat64 + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := 42.123 + if d != CustomFloat64(expected) { + t.Errorf("expected %f, got %f", expected, d) + } +} + +func TestCustomTime(t *testing.T) { + var d CustomTime + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := testTimeValue + if d != CustomTime(expected) { + t.Errorf("expected %q, got %q", expected.String(), d.String()) + } +} + +func TestCustomTimePtr(t *testing.T) { + var d *CustomTime + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := testTimeValue + if d == nil { + t.Fatal("expected a pointer to a CustomTime, got nil") + } + if *d != CustomTime(expected) { + t.Errorf("expected %q, got %q", expected.String(), d.String()) + } +} + +func TestCustomSlice(t *testing.T) { + var d CustomSlice + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := []string{"hello", "test"} + if len(d) != len(expected) { + t.Fatalf("expected %v, got %v", expected, d) + } + for i, v := range expected { + if d[i] != v { + t.Errorf("expected item %d of the slice to be: %v, got %v", i, expected[i], d[i]) + } + } +} + +func TestCustomMap(t *testing.T) { + var d CustomMap + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expected := map[string]string{"hello": "1", "test": "2"} + if len(d) != len(expected) { + t.Fatalf("expected %v, got %v", expected, d) + } + for k, v := range expected { + if d[k] != v { + t.Errorf("expected item %v of the slice to be: %v, got %v", k, expected[k], d[k]) + } + } +} + +func TestCustomStruct(t *testing.T) { + var d CustomStruct + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + if d.Str != "hello test" { + t.Errorf("expected %q, got %q", "hello test", d.Str) + } + if d.Int != 42 { + t.Errorf("expected %d, got %d", 42, d.Int) + } +} + +func TestNestedCustom(t *testing.T) { + var d NestedCustom + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + expectedStr := "hello test" + if d.Str != CustomString(expectedStr) { + t.Errorf("Str: expected %q, got %q", expectedStr, d.Str) + } + + if *d.PtrStr != CustomString(expectedStr) { + t.Errorf("Str: expected %q, got %q", expectedStr, *d.PtrStr) + } + + if !d.Bool { + t.Errorf("Bool: expected true, got false") + } + + expectedInt := -42 + if d.Int != CustomInt(expectedInt) { + t.Errorf("Int: expected %d, got %d", expectedInt, d.Int) + } + if d.Int8 != CustomInt8(expectedInt) { + t.Errorf("Int: expected %d, got %d", expectedInt, d.Int8) + } + if d.Int16 != CustomInt16(expectedInt) { + t.Errorf("Int: expected %d, got %d", expectedInt, d.Int16) + } + if d.Int32 != CustomInt32(expectedInt) { + t.Errorf("Int: expected %d, got %d", expectedInt, d.Int32) + } + if d.Int64 != CustomInt64(expectedInt) { + t.Errorf("Int: expected %d, got %d", expectedInt, d.Int64) + } + + expectedUint := uint(42) + if d.Uint != CustomUint(expectedUint) { + t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint) + } + if d.Uint8 != CustomUint8(expectedUint) { + t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint8) + } + if d.Uint16 != CustomUint16(expectedUint) { + t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint16) + } + if d.Uint32 != CustomUint32(expectedUint) { + t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint32) + } + if d.Uint64 != CustomUint64(expectedUint) { + t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint64) + } + + expectedFloat := 42.123 + if d.Float32 != CustomFloat32(expectedFloat) { + t.Errorf("Float: expected %f, got %f", expectedFloat, d.Float32) + } + if d.Float64 != CustomFloat64(expectedFloat) { + t.Errorf("Float: expected %f, got %f", expectedFloat, d.Float64) + } + + expectedSlice := []string{"hello", "test"} + if len(d.SliceStr) != len(expectedSlice) { + t.Fatalf("expected %v, got %v", expectedSlice, d.SliceStr) + } + for i, v := range expectedSlice { + if d.SliceStr[i] != v { + t.Errorf("expected item %d of the slice to be: %v, got %v", i, expectedSlice[i], d.SliceStr[i]) + } + } + + expectedMap := map[string]string{"hello": "1", "test": "2"} + if len(d.MapStr) != len(expectedMap) { + t.Fatalf("expected %v, got %v", expectedMap, d) + } + for k, v := range expectedMap { + if d.MapStr[k] != v { + t.Errorf("expected item %v of the map to be: %v, got %v", k, expectedMap[k], d.MapStr[k]) + } + } + + if d.Struct.Str != "hello test" { + t.Errorf("expected %q, got %q", "hello test", d.Struct.Str) + } + if d.Struct.Int != 42 { + t.Errorf("expected %d, got %d", 42, d.Struct.Int) + } + + if d.PtrStruct == nil { + t.Fatal("expected PtrStruct to not be nil") + } + + if d.PtrStruct.Str != "hello test" { + t.Errorf("expected %q, got %q", "hello test", d.PtrStruct.Str) + } + if d.PtrStruct.Int != 42 { + t.Errorf("expected %d, got %d", 42, d.PtrStruct.Int) + } +} + +func TestNestedOverrideCustom(t *testing.T) { + gofakeit.AddFuncLookup("raw_test_date", gofakeit.Info{ + Display: "Date", + Category: "time", + Description: "Random date", + Example: "2006-01-02T15:04:05Z07:00", + Output: "time.Time", + Params: []gofakeit.Param{ + { + Field: "format", + Display: "Format", + Type: "time.Time", + Description: "Raw date time.Time object", + }, + }, + Generate: func(r *rand.Rand, m *gofakeit.MapParams, info *gofakeit.Info) (interface{}, error) { + return gofakeit.Date(), nil + }, + }) + + defer gofakeit.RemoveFuncLookup("raw_test_date") + + var d NestedOverrideCustom + err := gofakeit.Struct(&d) + if err != nil { + t.Fatal(err) + } + + nonOverrideStr := "hello test" + if d.Str == CustomString(nonOverrideStr) { + t.Errorf("Str: expected a random string but got the non-overriden value") + } + + if *d.PtrStr == CustomString(nonOverrideStr) { + t.Errorf("PtrStr: expected a random string but got the non-overriden value") + } + + if d.Bool { + t.Errorf("Bool: expected false, got true") + } + + nonOverrideInt := -42 + if d.Int == CustomInt(nonOverrideInt) { + t.Errorf("Int: expected a random integer but got the non-overriden value") + } + if d.Int8 == CustomInt8(nonOverrideInt) { + t.Errorf("Int: expected a random integer but got the non-overriden value") + } + if d.Int16 == CustomInt16(nonOverrideInt) { + t.Errorf("Int: expected a random integer but got the non-overriden value") + } + if d.Int32 == CustomInt32(nonOverrideInt) { + t.Errorf("Int: expected a random integer but got the non-overriden value") + } + if d.Int64 == CustomInt64(nonOverrideInt) { + t.Errorf("Int: expected a random integer but got the non-overriden value") + } + + nonOverrideUint := uint(42) + if d.Uint == CustomUint(nonOverrideUint) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + if d.Uint8 == CustomUint8(nonOverrideUint) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + if d.Uint16 == CustomUint16(nonOverrideUint) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + if d.Uint32 == CustomUint32(nonOverrideUint) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + if d.Uint64 == CustomUint64(nonOverrideUint) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + + nonOverrideFloat := 42.123 + if d.Float32 == CustomFloat32(nonOverrideFloat) { + t.Errorf("Float: expected a random unsigned integer but got the non-overriden value") + } + if d.Float64 == CustomFloat64(nonOverrideFloat) { + t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") + } + + nonOverrideSlice := []string{"hello", "test"} + if len(d.SliceStr) == len(nonOverrideSlice) { + t.Logf("Slice: Got the same length as the non-overriden slice: %v vs %v", nonOverrideSlice, d.SliceStr) + for i, v := range nonOverrideSlice { + if d.SliceStr[i] == v { + t.Errorf("Slice: Got non-overriden item %d in the slice", i) + } + } + } + + nonOverrideMap := map[string]string{"hello": "1", "test": "2"} + if len(d.MapStr) == len(nonOverrideMap) { + t.Logf("Map: Got the same length as the non-overriden map: %v vs %v", nonOverrideMap, d.MapStr) + + for k, v := range nonOverrideMap { + if d.MapStr[k] == v { + t.Errorf("Map: Got non-overriden item %v in the slice", k) + } + } + } +} + +func TestSliceCustom(t *testing.T) { + var B []CustomString + gofakeit.Slice(&B) + + if len(B) == 0 { + t.Errorf("expected slice to not be empty") + } + + expected := CustomString("hello test") + for _, v := range B { + if v != expected { + t.Errorf("expected all items to be %q, got %q", expected, v) + } + } +} diff --git a/fakeable_test.go b/fakeable_test.go index ae8f4e09..7e9714d5 100644 --- a/fakeable_test.go +++ b/fakeable_test.go @@ -1,668 +1,49 @@ -package gofakeit_test +package gofakeit import ( "fmt" - "math/rand" + "reflect" "testing" - "time" - - "github.com/brianvoe/gofakeit/v6" -) - -var ( - testTimeValue = time.Now() ) -type CustomString string - -func (c CustomString) Fake(faker *gofakeit.Faker) interface{} { - return CustomString("hello test") -} - -type CustomBool bool - -func (c CustomBool) Fake(faker *gofakeit.Faker) interface{} { - return CustomBool(true) -} - -type CustomInt int - -func (c CustomInt) Fake(faker *gofakeit.Faker) interface{} { - return CustomInt(-42) -} - -type CustomInt8 int8 - -func (c CustomInt8) Fake(faker *gofakeit.Faker) interface{} { - return CustomInt8(-42) -} - -type CustomInt16 int16 - -func (c CustomInt16) Fake(faker *gofakeit.Faker) interface{} { - return CustomInt16(-42) -} - -type CustomInt32 int32 - -func (c CustomInt32) Fake(faker *gofakeit.Faker) interface{} { - return CustomInt32(-42) -} - -type CustomInt64 int64 - -func (c CustomInt64) Fake(faker *gofakeit.Faker) interface{} { - return CustomInt64(-42) -} - -type CustomUint uint - -func (c CustomUint) Fake(faker *gofakeit.Faker) interface{} { - return CustomUint(42) -} - -type CustomUint8 uint8 - -func (c CustomUint8) Fake(faker *gofakeit.Faker) interface{} { - return CustomUint8(42) -} - -type CustomUint16 uint16 - -func (c CustomUint16) Fake(faker *gofakeit.Faker) interface{} { - return CustomUint16(42) -} - -type CustomUint32 uint32 - -func (c CustomUint32) Fake(faker *gofakeit.Faker) interface{} { - return CustomUint32(42) -} - -type CustomUint64 uint64 - -func (c CustomUint64) Fake(faker *gofakeit.Faker) interface{} { - return CustomUint64(42) -} - -type CustomFloat32 float32 - -func (c CustomFloat32) Fake(faker *gofakeit.Faker) interface{} { - return CustomFloat32(42.123) -} - -type CustomFloat64 float64 - -func (c CustomFloat64) Fake(faker *gofakeit.Faker) interface{} { - return CustomFloat64(42.123) -} - -type CustomTime time.Time - -func (c CustomTime) Fake(faker *gofakeit.Faker) interface{} { - return CustomTime(testTimeValue) -} - -func (c CustomTime) String() string { - return time.Time(c).String() -} - -type CustomSlice []string - -func (c CustomSlice) Fake(faker *gofakeit.Faker) interface{} { - return CustomSlice([]string{"hello", "test"}) -} - -type CustomMap map[string]string - -func (c CustomMap) Fake(faker *gofakeit.Faker) interface{} { - return CustomMap(map[string]string{"hello": "1", "test": "2"}) -} - -type CustomStruct struct { - Str string - Int int -} - -func (c CustomStruct) Fake(faker *gofakeit.Faker) interface{} { - return CustomStruct{ - Str: "hello test", - Int: 42, - } -} - -type NestedCustom struct { - Str CustomString - Bool CustomBool - Int CustomInt - Int8 CustomInt8 - Int16 CustomInt16 - Int32 CustomInt32 - Int64 CustomInt64 - Uint CustomUint - Uint8 CustomUint8 - Uint16 CustomUint16 - Uint32 CustomUint32 - Uint64 CustomUint64 - Float32 CustomFloat32 - Float64 CustomFloat64 - Timestamp CustomTime - SliceStr CustomSlice - MapStr CustomMap - Struct CustomStruct - PtrStruct *CustomStruct -} - -type NestedOverrideCustom struct { - Str CustomString `fake:"{name}"` - Bool CustomBool `fake:"false"` - Int CustomInt `fake:"{number:-10,1000}"` - Int8 CustomInt8 `fake:"{number:-10,1000}"` - Int16 CustomInt16 `fake:"{number:-10,1000}"` - Int32 CustomInt32 `fake:"{number:-10,1000}"` - Int64 CustomInt64 `fake:"{number:-10,1000}"` - Uint CustomUint `fake:"{number:100,1000}"` - Uint8 CustomUint8 `fake:"{number:100,1000}"` - Uint16 CustomUint16 `fake:"{number:100,1000}"` - Uint32 CustomUint32 `fake:"{number:100,1000}"` - Uint64 CustomUint64 `fake:"{number:100,1000}"` - Float32 CustomFloat32 `fake:"{number:100,1000}"` - Float64 CustomFloat64 `fake:"{number:100,1000}"` - Timestamp CustomTime `fake:"{raw_test_date}"` - SliceStr CustomSlice `fake:"{word}"` - MapStr CustomMap `fakesize:"2"` -} - -func TestCustomString(t *testing.T) { - var d CustomString - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := "hello test" - if d != CustomString(expected) { - t.Errorf("expected %q, got %q", expected, d) - } -} - -func TestCustomBool(t *testing.T) { - var d CustomBool - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := true - if d != CustomBool(expected) { - t.Errorf("expected %t, got %t", expected, d) - } -} - -func TestCustomInt(t *testing.T) { - var d CustomInt - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := -42 - if d != CustomInt(expected) { - t.Errorf("expected %d, got %d", expected, d) - } -} - -func TestCustomInt8(t *testing.T) { - var d CustomInt8 - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := -42 - if d != CustomInt8(expected) { - t.Errorf("expected %d, got %d", expected, d) - } -} - -func TestCustomInt16(t *testing.T) { - var d CustomInt16 - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := -42 - if d != CustomInt16(expected) { - t.Errorf("expected %d, got %d", expected, d) - } -} - -func TestCustomInt32(t *testing.T) { - var d CustomInt32 - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := -42 - if d != CustomInt32(expected) { - t.Errorf("expected %d, got %d", expected, d) - } -} - -func TestCustomInt64(t *testing.T) { - var d CustomInt64 - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := -42 - if d != CustomInt64(expected) { - t.Errorf("expected %d, got %d", expected, d) - } -} - -func TestCustomUint(t *testing.T) { - var d CustomUint - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := 42 - if d != CustomUint(expected) { - t.Errorf("expected %d, got %d", expected, d) - } -} - -func TestCustomUint8(t *testing.T) { - var d CustomUint8 - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := 42 - if d != CustomUint8(expected) { - t.Errorf("expected %d, got %d", expected, d) - } -} - -func TestCustomUint16(t *testing.T) { - var d CustomUint16 - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := 42 - if d != CustomUint16(expected) { - t.Errorf("expected %d, got %d", expected, d) - } -} - -func TestCustomUint32(t *testing.T) { - var d CustomUint32 - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := 42 - if d != CustomUint32(expected) { - t.Errorf("expected %d, got %d", expected, d) - } -} - -func TestCustomUint64(t *testing.T) { - var d CustomUint64 - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := 42 - if d != CustomUint64(expected) { - t.Errorf("expected %d, got %d", expected, d) - } -} -func TestCustomFloat32(t *testing.T) { - var d CustomFloat32 - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := 42.123 - if d != CustomFloat32(expected) { - t.Errorf("expected %f, got %f", expected, d) - } -} - -func TestCustomFloat64(t *testing.T) { - var d CustomFloat64 - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := 42.123 - if d != CustomFloat64(expected) { - t.Errorf("expected %f, got %f", expected, d) - } -} - -func TestCustomTime(t *testing.T) { - var d CustomTime - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := testTimeValue - if d != CustomTime(expected) { - t.Errorf("expected %q, got %q", expected.String(), d.String()) - } -} - -func TestCustomSlice(t *testing.T) { - var d CustomSlice - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := []string{"hello", "test"} - if len(d) != len(expected) { - t.Fatalf("expected %v, got %v", expected, d) - } - for i, v := range expected { - if d[i] != v { - t.Errorf("expected item %d of the slice to be: %v, got %v", i, expected[i], d[i]) - } - } -} - -func TestCustomMap(t *testing.T) { - var d CustomMap - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expected := map[string]string{"hello": "1", "test": "2"} - if len(d) != len(expected) { - t.Fatalf("expected %v, got %v", expected, d) - } - for k, v := range expected { - if d[k] != v { - t.Errorf("expected item %v of the slice to be: %v, got %v", k, expected[k], d[k]) - } - } -} - -func TestCustomStruct(t *testing.T) { - var d CustomStruct - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - if d.Str != "hello test" { - t.Errorf("expected %q, got %q", "hello test", d.Str) - } - if d.Int != 42 { - t.Errorf("expected %d, got %d", 42, d.Int) - } -} - -func TestNestedCustom(t *testing.T) { - var d NestedCustom - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - expectedStr := "hello test" - if d.Str != CustomString(expectedStr) { - t.Errorf("Str: expected %q, got %q", expectedStr, d.Str) - } - - if !d.Bool { - t.Errorf("Bool: expected true, got false") - } - - expectedInt := -42 - if d.Int != CustomInt(expectedInt) { - t.Errorf("Int: expected %d, got %d", expectedInt, d.Int) - } - if d.Int8 != CustomInt8(expectedInt) { - t.Errorf("Int: expected %d, got %d", expectedInt, d.Int8) - } - if d.Int16 != CustomInt16(expectedInt) { - t.Errorf("Int: expected %d, got %d", expectedInt, d.Int16) - } - if d.Int32 != CustomInt32(expectedInt) { - t.Errorf("Int: expected %d, got %d", expectedInt, d.Int32) - } - if d.Int64 != CustomInt64(expectedInt) { - t.Errorf("Int: expected %d, got %d", expectedInt, d.Int64) - } - - expectedUint := uint(42) - if d.Uint != CustomUint(expectedUint) { - t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint) - } - if d.Uint8 != CustomUint8(expectedUint) { - t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint8) - } - if d.Uint16 != CustomUint16(expectedUint) { - t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint16) - } - if d.Uint32 != CustomUint32(expectedUint) { - t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint32) - } - if d.Uint64 != CustomUint64(expectedUint) { - t.Errorf("Uint: expected %d, got %d", expectedUint, d.Uint64) - } - - expectedFloat := 42.123 - if d.Float32 != CustomFloat32(expectedFloat) { - t.Errorf("Float: expected %f, got %f", expectedFloat, d.Float32) - } - if d.Float64 != CustomFloat64(expectedFloat) { - t.Errorf("Float: expected %f, got %f", expectedFloat, d.Float64) - } - - expectedSlice := []string{"hello", "test"} - if len(d.SliceStr) != len(expectedSlice) { - t.Fatalf("expected %v, got %v", expectedSlice, d.SliceStr) - } - for i, v := range expectedSlice { - if d.SliceStr[i] != v { - t.Errorf("expected item %d of the slice to be: %v, got %v", i, expectedSlice[i], d.SliceStr[i]) - } - } - - expectedMap := map[string]string{"hello": "1", "test": "2"} - if len(d.MapStr) != len(expectedMap) { - t.Fatalf("expected %v, got %v", expectedMap, d) - } - for k, v := range expectedMap { - if d.MapStr[k] != v { - t.Errorf("expected item %v of the map to be: %v, got %v", k, expectedMap[k], d.MapStr[k]) - } - } - - if d.Struct.Str != "hello test" { - t.Errorf("expected %q, got %q", "hello test", d.Struct.Str) - } - if d.Struct.Int != 42 { - t.Errorf("expected %d, got %d", 42, d.Struct.Int) - } - - if d.PtrStruct == nil { - t.Fatal("expected PtrStruct to not be nil") - } - - if d.PtrStruct.Str != "hello test" { - t.Errorf("expected %q, got %q", "hello test", d.PtrStruct.Str) - } - if d.PtrStruct.Int != 42 { - t.Errorf("expected %d, got %d", 42, d.PtrStruct.Int) - } -} - -func TestNestedOverrideCustom(t *testing.T) { - gofakeit.AddFuncLookup("raw_test_date", gofakeit.Info{ - Display: "Date", - Category: "time", - Description: "Random date", - Example: "2006-01-02T15:04:05Z07:00", - Output: "time.Time", - Params: []gofakeit.Param{ - { - Field: "format", - Display: "Format", - Type: "time.Time", - Description: "Raw date time.Time object", - }, - }, - Generate: func(r *rand.Rand, m *gofakeit.MapParams, info *gofakeit.Info) (interface{}, error) { - return gofakeit.Date(), nil - }, - }) - - defer gofakeit.RemoveFuncLookup("raw_test_date") - - var d NestedOverrideCustom - err := gofakeit.Struct(&d) - if err != nil { - t.Fatal(err) - } - - nonOverrideStr := "hello test" - if d.Str == CustomString(nonOverrideStr) { - t.Errorf("Str: expected a random string but got the non-overriden value") - } - - if d.Bool { - t.Errorf("Bool: expected false, got true") - } - - nonOverrideInt := -42 - if d.Int == CustomInt(nonOverrideInt) { - t.Errorf("Int: expected a random integer but got the non-overriden value") - } - if d.Int8 == CustomInt8(nonOverrideInt) { - t.Errorf("Int: expected a random integer but got the non-overriden value") - } - if d.Int16 == CustomInt16(nonOverrideInt) { - t.Errorf("Int: expected a random integer but got the non-overriden value") - } - if d.Int32 == CustomInt32(nonOverrideInt) { - t.Errorf("Int: expected a random integer but got the non-overriden value") - } - if d.Int64 == CustomInt64(nonOverrideInt) { - t.Errorf("Int: expected a random integer but got the non-overriden value") - } - - nonOverrideUint := uint(42) - if d.Uint == CustomUint(nonOverrideUint) { - t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") - } - if d.Uint8 == CustomUint8(nonOverrideUint) { - t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") - } - if d.Uint16 == CustomUint16(nonOverrideUint) { - t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") - } - if d.Uint32 == CustomUint32(nonOverrideUint) { - t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") - } - if d.Uint64 == CustomUint64(nonOverrideUint) { - t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") - } - - nonOverrideFloat := 42.123 - if d.Float32 == CustomFloat32(nonOverrideFloat) { - t.Errorf("Float: expected a random unsigned integer but got the non-overriden value") - } - if d.Float64 == CustomFloat64(nonOverrideFloat) { - t.Errorf("Uint: expected a random unsigned integer but got the non-overriden value") - } - - nonOverrideSlice := []string{"hello", "test"} - if len(d.SliceStr) == len(nonOverrideSlice) { - t.Logf("Slice: Got the same length as the non-overriden slice: %v vs %v", nonOverrideSlice, d.SliceStr) - for i, v := range nonOverrideSlice { - if d.SliceStr[i] == v { - t.Errorf("Slice: Got non-overriden item %d in the slice", i) - } - } - } - - nonOverrideMap := map[string]string{"hello": "1", "test": "2"} - if len(d.MapStr) == len(nonOverrideMap) { - t.Logf("Map: Got the same length as the non-overriden map: %v vs %v", nonOverrideMap, d.MapStr) +type strTyp string - for k, v := range nonOverrideMap { - if d.MapStr[k] == v { - t.Errorf("Map: Got non-overriden item %v in the slice", k) - } - } - } +func (t strTyp) Fake(faker *Faker) interface{} { + return faker.FirstName() } -func TestSliceCustom(t *testing.T) { - var B []CustomString - gofakeit.Slice(&B) - - if len(B) == 0 { - t.Errorf("expected slice to not be empty") - } +type strTypPtr string - expected := CustomString("hello test") - for _, v := range B { - if v != expected { - t.Errorf("expected all items to be %q, got %q", expected, v) - } - } +func (t *strTypPtr) Fake(faker *Faker) interface{} { + return strTypPtr("hello test ptr") } type testStruct1 struct { B string `fake:"{firstname}"` } -type strTyp string - type testStruct2 struct { B strTyp } -func (t strTyp) Fake(faker *gofakeit.Faker) interface{} { - return faker.FirstName() -} func ExampleFakeable() { var t1 testStruct1 var t2 testStruct1 var t3 testStruct2 var t4 testStruct2 - gofakeit.New(314).Struct(&t1) - gofakeit.New(314).Struct(&t2) - gofakeit.New(314).Struct(&t3) - gofakeit.New(314).Struct(&t4) + New(314).Struct(&t1) + New(314).Struct(&t2) + New(314).Struct(&t3) + New(314).Struct(&t4) fmt.Printf("%#v\n", t1) fmt.Printf("%#v\n", t2) fmt.Printf("%#v\n", t3) fmt.Printf("%#v\n", t4) // Expected Output: - // gofakeit_test.testStruct1{B:"Margarette"} - // gofakeit_test.testStruct1{B:"Margarette"} - // gofakeit_test.testStruct2{B:"Margarette"} - // gofakeit_test.testStruct2{B:"Margarette"} + // gofakeit.testStruct1{B:"Margarette"} + // gofakeit.testStruct1{B:"Margarette"} + // gofakeit.testStruct2{B:"Margarette"} + // gofakeit.testStruct2{B:"Margarette"} } From 293b26aca748494e67b6616bd688d223fcdfbbcb Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Sun, 2 Apr 2023 21:29:03 +0200 Subject: [PATCH 17/41] Failing test --- fakeable_test.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/fakeable_test.go b/fakeable_test.go index 7e9714d5..a6618051 100644 --- a/fakeable_test.go +++ b/fakeable_test.go @@ -26,6 +26,38 @@ type testStruct2 struct { B strTyp } +func TestIsFakeable(t *testing.T) { + var t1 testStruct2 + var t2 *testStruct2 + var t3 strTyp + var t4 *strTyp + var t5 strTypPtr + var t6 *strTypPtr + + if isFakeable(reflect.ValueOf(t1).Type()) { + t.Errorf("expected testStruct2 not to be fakeable") + } + + if isFakeable(reflect.ValueOf(t2).Type()) { + t.Errorf("expected *testStruct2 not to be fakeable") + } + + if !isFakeable(reflect.ValueOf(t3).Type()) { + t.Errorf("expected strTyp to be fakeable") + } + + if !isFakeable(reflect.ValueOf(t4).Type()) { + t.Errorf("expected *strTyp to be fakeable") + } + + if !isFakeable(reflect.ValueOf(t5).Type()) { + t.Errorf("expected strTypPtr to be fakeable") + } + + if !isFakeable(reflect.ValueOf(t6).Type()) { + t.Errorf("expected *strTypPtr to be fakeable") + } +} func ExampleFakeable() { var t1 testStruct1 From 2178caa85629cce7de9b986142a1c835b105f27c Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Sun, 2 Apr 2023 21:30:43 +0200 Subject: [PATCH 18/41] Add support for faking pointer structs --- fakeable.go | 3 ++- struct.go | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fakeable.go b/fakeable.go index 49b6daf7..4d1323bc 100644 --- a/fakeable.go +++ b/fakeable.go @@ -14,7 +14,8 @@ type Fakeable interface { func isFakeable(t reflect.Type) bool { fakeableTyp := reflect.TypeOf((*Fakeable)(nil)).Elem() - return t.Implements(fakeableTyp) + + return t.Implements(fakeableTyp) || reflect.PtrTo(t).Implements(fakeableTyp) } func callFake(faker *Faker, v reflect.Value, possibleKinds ...reflect.Kind) (interface{}, error) { diff --git a/struct.go b/struct.go index 56dd6431..f97ebecc 100644 --- a/struct.go +++ b/struct.go @@ -181,12 +181,13 @@ func rStruct(f *Faker, t reflect.Type, v reflect.Value, tag string) error { func rPointer(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { elemT := t.Elem() if v.IsNil() { - nv := reflect.New(elemT) - err := r(f, elemT, nv.Elem(), tag, size) + nv := reflect.New(elemT).Elem() + err := r(f, elemT, nv, tag, size) if err != nil { return err } - v.Set(nv) + + v.Set(nv.Addr()) } else { err := r(f, elemT, v.Elem(), tag, size) if err != nil { From 13d4efd6fd52d58b8cbb8d68348f822e7a185bf6 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 4 Apr 2023 01:03:20 +0200 Subject: [PATCH 19/41] Refactor to containsKind --- fakeable.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fakeable.go b/fakeable.go index 4d1323bc..f963556c 100644 --- a/fakeable.go +++ b/fakeable.go @@ -26,7 +26,7 @@ func callFake(faker *Faker, v reflect.Value, possibleKinds ...reflect.Kind) (int fakedValue := f.Fake(faker) k := reflect.TypeOf(fakedValue).Kind() - if !contains(possibleKinds, k) { + if !containsKind(possibleKinds, k) { return nil, fmt.Errorf("returned value kind %q is not amongst the valid ones: %v", k, possibleKinds) } @@ -70,7 +70,7 @@ func callFake(faker *Faker, v reflect.Value, possibleKinds ...reflect.Kind) (int } } -func contains(possibleKinds []reflect.Kind, kind reflect.Kind) bool { +func containsKind(possibleKinds []reflect.Kind, kind reflect.Kind) bool { for _, k := range possibleKinds { if k == kind { return true From 50688c4a9f5787e1fb1a17e189573a7f97fffdbf Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 4 Apr 2023 02:18:15 +0200 Subject: [PATCH 20/41] Add examples --- fakeable_test.go | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/fakeable_test.go b/fakeable_test.go index a6618051..4496c713 100644 --- a/fakeable_test.go +++ b/fakeable_test.go @@ -2,6 +2,7 @@ package gofakeit import ( "fmt" + "math" "reflect" "testing" ) @@ -79,3 +80,85 @@ func ExampleFakeable() { // gofakeit.testStruct2{B:"Margarette"} // gofakeit.testStruct2{B:"Margarette"} } + +type gammaFloat64 float64 + +func (gammaFloat64) Fake(faker *Faker) interface{} { + alpha := 2.0 + + // Generate a random value from the Gamma distribution + var r float64 + for r == 0 { + u := faker.Float64Range(0, 1) + v := faker.Float64Range(0, 1) + w := u * (1 - u) + y := math.Sqrt(-2 * math.Log(w) / w) + x := alpha * (y*v + u - 0.5) + if x > 0 { + r = x + } + } + return gammaFloat64(r) +} + +func ExampleGammaFloat64() { + f1 := New(100) + + // Fakes random values from the Gamma distribution + var A1 gammaFloat64 + var A2 gammaFloat64 + var A3 gammaFloat64 + f1.Struct(&A1) + f1.Struct(&A2) + f1.Struct(&A3) + + fmt.Println(A1) + fmt.Println(A2) + fmt.Println(A3) + // Output: + // 10.300651760129734 + // 5.391434877284098 + // 2.0575989252140676 +} + +type poissonInt64 int64 + +func (poissonInt64) Fake(faker *Faker) interface{} { + lambda := 15.0 + + // Generate a random value from the Poisson distribution + var k int64 + var p float64 = 1.0 + var L float64 = math.Exp(-lambda) + for p > L { + u := faker.Float64Range(0, 1) + p *= u + k++ + } + return poissonInt64(k - 1) +} + +type customerSupportEmployee struct { + Name string `fake:"{firstname} {lastname}"` + CallCountPerHour poissonInt64 +} + +func ExamplecustomerSupportEmployee() { + f1 := New(100) + + // Fakes random values from the Gamma distribution + var A1 customerSupportEmployee + var A2 customerSupportEmployee + var A3 customerSupportEmployee + f1.Struct(&A1) + f1.Struct(&A2) + f1.Struct(&A3) + + fmt.Printf("%#v\n", A1) + fmt.Printf("%#v\n", A2) + fmt.Printf("%#v\n", A3) + // Output: + // gofakeit.customerSupportEmployee{Name:"Pearline Rippin", CallCountPerHour:12} + // gofakeit.customerSupportEmployee{Name:"Sammie Renner", CallCountPerHour:23} + // gofakeit.customerSupportEmployee{Name:"Katlyn Runte", CallCountPerHour:8} +} From 6d99f804136a464664035ba08881175592ff7b36 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 4 Apr 2023 02:18:38 +0200 Subject: [PATCH 21/41] Extend test --- fakeable_external_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fakeable_external_test.go b/fakeable_external_test.go index 6417e243..32c77f2f 100644 --- a/fakeable_external_test.go +++ b/fakeable_external_test.go @@ -536,6 +536,18 @@ func TestNestedCustom(t *testing.T) { if d.PtrStruct.Int != 42 { t.Errorf("expected %d, got %d", 42, d.PtrStruct.Int) } + + expectedTimestamp := testTimeValue + if d.Timestamp != CustomTime(expectedTimestamp) { + t.Errorf("expected %q, got %q", expectedTimestamp.String(), d.Timestamp.String()) + } + + if d.PtrTimestamp == nil { + t.Fatal("expected a pointer to a CustomTime, got nil") + } + if *d.PtrTimestamp != CustomTime(expectedTimestamp) { + t.Errorf("expected %q, got %q", expectedTimestamp.String(), d.PtrTimestamp.String()) + } } func TestNestedOverrideCustom(t *testing.T) { From f2e114c3d509a2bfe7e9bdc7b0f8b6a9f6a47a21 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 4 Apr 2023 02:18:56 +0200 Subject: [PATCH 22/41] Add test --- fakeable_external_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fakeable_external_test.go b/fakeable_external_test.go index 32c77f2f..779f2504 100644 --- a/fakeable_external_test.go +++ b/fakeable_external_test.go @@ -670,3 +670,19 @@ func TestSliceCustom(t *testing.T) { } } } + +func TestSliceNestedCustom(t *testing.T) { + var B []NestedCustom + gofakeit.Slice(&B) + + if len(B) == 0 { + t.Errorf("expected slice to not be empty") + } + + expected := CustomString("hello test") + for _, v := range B { + if v.Str != expected { + t.Fatalf("expected all items to be %q, got %q", expected, v.Str) + } + } +} From 81341e0a7216badd64173a54d8c8bdf8bb02e895 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 4 Apr 2023 02:19:04 +0200 Subject: [PATCH 23/41] Add examples --- fakeable_external_test.go | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/fakeable_external_test.go b/fakeable_external_test.go index 779f2504..b30cb6e9 100644 --- a/fakeable_external_test.go +++ b/fakeable_external_test.go @@ -1,6 +1,7 @@ package gofakeit_test import ( + "fmt" "math/rand" "testing" "time" @@ -686,3 +687,43 @@ func TestSliceNestedCustom(t *testing.T) { } } } + +func ExampleCustomInt() { + f1 := gofakeit.New(10) + f2 := gofakeit.New(100) + + var A1 CustomInt + var A2 CustomInt + // CustomInt always returns -42 independently of the seed + f1.Struct(&A1) + f2.Struct(&A2) + + fmt.Println(A1) + fmt.Println(A2) + // Output: + // -42 + // -42 +} + +type EvenInt int + +func (e EvenInt) Fake(faker *gofakeit.Faker) interface{} { + return EvenInt(faker.Int8() * 2) +} + +func ExampleEvenInt() { + f1 := gofakeit.New(10) + f2 := gofakeit.New(100) + + var E1 EvenInt + var E2 EvenInt + // EventInt always returns an even number + f1.Struct(&E1) + f2.Struct(&E2) + + fmt.Println(E1) + fmt.Println(E2) + // Output: + // 6 + // -92 +} From 53abad652930ba9a6e5926752e987714494602c9 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Tue, 4 Apr 2023 03:08:18 +0200 Subject: [PATCH 24/41] Add fakeable types --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/README.md b/README.md index 05c27fa9..b7410683 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,38 @@ fmt.Println(f.Created.String()) // 1908-12-07 04:14:25.685339029 +0000 UTC // Nested Struct Fields and Embedded Fields ``` +## Fakeable types + +It is possible to extend a struct by implementing the `Fakeable` interface +in order to control the generation. + +For example, this is useful when it is not possible to modify the struct that you want to fake by adding struct tags to a field but you still need to be able to control the generation process. + +```go +// Imagine a CustomTime type that is needed to support a custom JSON Marshaler +type CustomTime time.Time + +func (c *CustomTime) Fake(faker *gofakeit.Faker) interface{} { + return CustomTime(time.Now()) +} + +func (c *CustomTime) MarshalJSON() ([]byte, error) { + //... +} + +// This is the struct that we cannot modify to add struct tags +type NotModifiable struct { + Token string + Creation *CustomTime +} + +var f NotModifiable +gofakeit.Struct(&f) +fmt.Printf("%s", f.Token) // yvqqdH +fmt.Printf("%s", f.Creation) // 2023-04-02 23:00:00 +0000 UTC m=+0.000000001 + +``` + ## Custom Functions In a lot of situations you may need to use your own random function usage for your specific needs. From 9a3f85913ea160420885fef996b4ef8bc678a44e Mon Sep 17 00:00:00 2001 From: Wayne Manselle Date: Mon, 3 Apr 2023 23:02:53 -0700 Subject: [PATCH 25/41] CUSIPs WIP --- finance.go | 128 ++++++++++++++++++++++++++++++++++++++++++++++++ finance_test.go | 93 +++++++++++++++++++++++++++++++++++ lookup.go | 1 + 3 files changed, 222 insertions(+) create mode 100644 finance.go create mode 100644 finance_test.go diff --git a/finance.go b/finance.go new file mode 100644 index 00000000..8d77fbe0 --- /dev/null +++ b/finance.go @@ -0,0 +1,128 @@ +package gofakeit + +import ( + "math/rand" + "strconv" + "unicode" +) + +const cusipRunes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" +const ppnRunes = "*@#" + +func replaceWithCusipRunes(r *rand.Rand, str string, ppn bool) string { + if str == "" { + return str + } + bytestr := []byte(str) + for i := 0; i < len(bytestr); i++ { + if bytestr[i] == questionmark { + bytestr[i] = byte(randCusipRune(r, ppn)) + } + } + + return string(bytestr) +} + +func randCusipRune(r *rand.Rand, ppn bool) rune { + randRunes := cusipRunes + if ppn { + randRunes = randRunes + ppnRunes + } + return rune(cusipRunes[r.Intn(len(randRunes))]) +} + +func cusip(r *rand.Rand, ppn bool) string { + cusip := replaceWithCusipRunes(r, "????????", ppn) + chkDigit := CusipCheckDigit(cusip) + return cusip + chkDigit +} + +func CusipCheckDigit(cusip string) string { + + sum := 0 + for i, c := range cusip { + v := 0 + if unicode.IsDigit(c) { + v = int(c - '0') + } + if unicode.IsLetter(c) { + v = int(c-'A') + 10 + } + if c == '*' { + v = 36 + } + if c == '@' { + v = 37 + } + if c == '#' { + v = 38 + } + + if (7 - i%2) == 0 { + v = v * 2 + } + + sum = sum + int(v/10) + v%10 + } + + return strconv.Itoa((10 - (sum % 10)) % 10) +} + +func Cusip() string { + return cusip(globalFaker.Rand, false) +} + +func PpnCusip() string { + return cusip(globalFaker.Rand, true) +} + +func (f *Faker) Cusip() string { + return cusip(f.Rand, false) +} + +func (f *Faker) PpnCusip() string { + return cusip(f.Rand, true) +} + +/* +func isin(r *rand.Rand) string { + return "xxxxxxxxxxxx" +} + +func symbol(r *rand.Rand) string { + return "xxxx" +} +*/ + +func addFinanceLookup() { + AddFuncLookup("cusip", Info{ + Display: "CUSIP", + Category: "finance", + Description: "Random CUSIP", + Example: "38259P508", + Output: "string", + Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) { + return cusip(r, false), nil + }, + }) + /*AddFuncLookup("isin", Info{ + Display: "ISIN", + Category: "finance", + Description: "Random ISIN", + Example: "", + Output: "string", + Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) { + return isin(r), nil + }, + }) + AddFuncLookup("symbol", Info{ + Display: "symbol", + Category: "finance", + Description: "Random Symbol", + Example: "", + Output: "string", + Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) { + return symbol(r), nil + }, + })*/ +} diff --git a/finance_test.go b/finance_test.go new file mode 100644 index 00000000..1b000eba --- /dev/null +++ b/finance_test.go @@ -0,0 +1,93 @@ +package gofakeit + +import ( + "fmt" + "testing" +) + +func ExampleCusip() { + Seed(11) + fmt.Println(Cusip()) + // Output: CBHG2P1N5 +} + +func ExampleFaker_Cusip() { + f := New(11) + fmt.Println(f.Cusip()) + // Output: CBHG2P1N5 +} + +func TestCusip(t *testing.T) { + Seed(11) + cusip := Cusip() + if cusip == "" { + t.Error("Valid Cusips are not blank") + } + if len(cusip) != 9 { + t.Error("Valid Cusips are 9 characters in length") + } + if CusipCheckDigit(cusip[:8]) != string(cusip[8]) { + t.Error("Cusip has invalid checksum") + } + +} + +func BenchmarkCusip(b *testing.B) { + b.Run("package", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Cusip() + } + }) + + b.Run("Faker math", func(b *testing.B) { + f := New(0) + + for i := 0; i < b.N; i++ { + f.Cusip() + } + }) + + b.Run("Faker crypto", func(b *testing.B) { + f := NewCrypto() + + for i := 0; i < b.N; i++ { + f.Cusip() + } + }) +} + +func ExamplePpnCusip() { + Seed(11) + fmt.Println(PpnCusip()) + // Output: 6EHPQ4AK9 +} + +func ExampleFaker_PpnCusip() { + f := New(11) + fmt.Println(f.PpnCusip()) + // Output: 6EHPQ4AK9 +} + +func BenchmarkPpnCusip(b *testing.B) { + b.Run("package", func(b *testing.B) { + for i := 0; i < b.N; i++ { + PpnCusip() + } + }) + + b.Run("Faker math", func(b *testing.B) { + f := New(0) + + for i := 0; i < b.N; i++ { + f.PpnCusip() + } + }) + + b.Run("Faker crypto", func(b *testing.B) { + f := NewCrypto() + + for i := 0; i < b.N; i++ { + f.PpnCusip() + } + }) +} diff --git a/lookup.go b/lookup.go index 29732932..8cca8983 100644 --- a/lookup.go +++ b/lookup.go @@ -98,6 +98,7 @@ func initLookup() { addDatabaseSQLLookup() addErrorLookup() addHtmlLookup() + addFinanceLookup() } // NewMapParams will create a new MapParams From d57151e20fbb41253b1e83786caa87bde3e208e4 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 27 Mar 2023 19:15:36 +0200 Subject: [PATCH 26/41] Failing tests --- json_test.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/json_test.go b/json_test.go index c5b6752d..e5db4960 100644 --- a/json_test.go +++ b/json_test.go @@ -362,6 +362,38 @@ func TestJSONNoOptions(t *testing.T) { } } +func TestJSONRawMessage(t *testing.T) { + type J struct { + Field json.RawMessage `json:"field"` + } + + Seed(100) + + var objs []J + Slice(&objs) + + _, err := json.Marshal(objs) + if err != nil { + t.Fatal(err) + } +} + +func TestJSONRawMessageWithTag(t *testing.T) { + type J struct { + Field json.RawMessage `json:"field" faker:"json"` + } + + Seed(100) + + var objs []J + Slice(&objs) + + _, err := json.Marshal(objs) + if err != nil { + t.Fatal(err) + } +} + func BenchmarkJSONLookup100(b *testing.B) { faker := New(0) From c2a187e324e6504cac23c7a8c6662307ecfa4144 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Wed, 29 Mar 2023 23:41:47 +0200 Subject: [PATCH 27/41] Ensure stable sorting for reproducibility given a seed --- lookup.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lookup.go b/lookup.go index e5c4029f..9fb358f7 100644 --- a/lookup.go +++ b/lookup.go @@ -5,6 +5,7 @@ import ( "fmt" "math/rand" "reflect" + "sort" "strconv" "strings" "sync" @@ -39,6 +40,8 @@ func getRandomFuncLookup(r *rand.Rand, excludeWithParams bool) (string, Info) { keys = append(keys, k) } + sort.Stable(sort.StringSlice(keys)) + selected := keys[r.Intn(len(keys))] return selected, FuncLookups[selected] } From 6d40366093e4417ef96081e096da9e67dabe6ece Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Wed, 29 Mar 2023 23:49:02 +0200 Subject: [PATCH 28/41] internal_exampleFields only returns string, int or slices thereof --- lookup.go | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/lookup.go b/lookup.go index 9fb358f7..5d4ded97 100644 --- a/lookup.go +++ b/lookup.go @@ -18,11 +18,11 @@ var lockFuncLookups sync.Mutex // internalFuncLookups is the internal map array with mapping to all available data var internalFuncLookups map[string]Info = map[string]Info{ "internal_exampleFields": { - Description: "Example fields for generating xml and json", - Example: `{"name":"{firstname}","age":"{number:1,100}"}`, + Description: "Example fields for generating csv, json and xml", Output: "gofakeit.Field", Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) { - name, _ := getRandomFuncLookup(r, true) + name, _ := getRandomFuncLookup(r, excludeWithParams, + validTypes("string", "int", "[]string", "[]int")) return Field{ Name: name, Function: name, @@ -31,13 +31,36 @@ var internalFuncLookups map[string]Info = map[string]Info{ }, } -func getRandomFuncLookup(r *rand.Rand, excludeWithParams bool) (string, Info) { +// filterFuncLookup returns true when the lookup should be accepted +type filterFuncLookup func(Info) bool + +var ( + excludeWithParams filterFuncLookup = func(info Info) bool { + return len(info.Params) == 0 + } + + validTypes = func(acceptedTypes ...string) filterFuncLookup { + return func(info Info) bool { + for _, t := range acceptedTypes { + if info.Output == t { + return true + } + } + return false + } + } +) + +func getRandomFuncLookup(r *rand.Rand, filters ...filterFuncLookup) (string, Info) { var keys []string for k, v := range FuncLookups { - if excludeWithParams && len(v.Params) != 0 { - continue + isValid := true + for _, filter := range filters { + isValid = isValid && filter(v) + } + if isValid { + keys = append(keys, k) } - keys = append(keys, k) } sort.Stable(sort.StringSlice(keys)) From 6067c680d17f7bd4a49a3f7cb23f227fab3e8cf7 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Thu, 30 Mar 2023 00:30:20 +0200 Subject: [PATCH 29/41] Pass the faker object around. Makes the nil case reproducible Replacing Info.Generate that is public would break the API --- csv.go | 13 +++++++------ json.go | 15 ++++++++------- xml.go | 15 ++++++++------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/csv.go b/csv.go index d8294f41..29e01704 100644 --- a/csv.go +++ b/csv.go @@ -20,16 +20,16 @@ type CSVOptions struct { // CSV generates an object or an array of objects in json format // A nil CSVOptions returns a randomly structured CSV. -func CSV(co *CSVOptions) ([]byte, error) { return csvFunc(globalFaker.Rand, co) } +func CSV(co *CSVOptions) ([]byte, error) { return csvFunc(globalFaker, co) } // CSV generates an object or an array of objects in json format // A nil CSVOptions returns a randomly structured CSV. -func (f *Faker) CSV(co *CSVOptions) ([]byte, error) { return csvFunc(f.Rand, co) } +func (f *Faker) CSV(co *CSVOptions) ([]byte, error) { return csvFunc(f, co) } -func csvFunc(r *rand.Rand, co *CSVOptions) ([]byte, error) { +func csvFunc(f *Faker, co *CSVOptions) ([]byte, error) { if co == nil { // We didn't get a CSVOptions, so create a new random one - err := Struct(&co) + err := f.Struct(&co) if err != nil { return nil, err } @@ -84,7 +84,7 @@ func csvFunc(r *rand.Rand, co *CSVOptions) ([]byte, error) { return nil, errors.New("invalid function, " + field.Function + " does not exist") } - value, err := funcInfo.Generate(r, &field.Params, funcInfo) + value, err := funcInfo.Generate(f.Rand, &field.Params, funcInfo) if err != nil { return nil, err } @@ -175,7 +175,8 @@ func addFileCSVLookup() { } co.Delimiter = delimiter - csvOut, err := csvFunc(r, &co) + f := &Faker{Rand: r} + csvOut, err := csvFunc(f, &co) if err != nil { return nil, err } diff --git a/json.go b/json.go index 46c8daac..e40f7a7a 100644 --- a/json.go +++ b/json.go @@ -56,17 +56,17 @@ func (okv jsonOrderedKeyVal) MarshalJSON() ([]byte, error) { // JSON generates an object or an array of objects in json format. // A nil JSONOptions returns a randomly structured JSON. -func JSON(jo *JSONOptions) ([]byte, error) { return jsonFunc(globalFaker.Rand, jo) } +func JSON(jo *JSONOptions) ([]byte, error) { return jsonFunc(globalFaker, jo) } // JSON generates an object or an array of objects in json format. // A nil JSONOptions returns a randomly structured JSON. -func (f *Faker) JSON(jo *JSONOptions) ([]byte, error) { return jsonFunc(f.Rand, jo) } +func (f *Faker) JSON(jo *JSONOptions) ([]byte, error) { return jsonFunc(f, jo) } // JSON generates an object or an array of objects in json format -func jsonFunc(r *rand.Rand, jo *JSONOptions) ([]byte, error) { +func jsonFunc(f *Faker, jo *JSONOptions) ([]byte, error) { if jo == nil { // We didn't get a JSONOptions, so create a new random one - err := Struct(&jo) + err := f.Struct(&jo) if err != nil { return nil, err } @@ -99,7 +99,7 @@ func jsonFunc(r *rand.Rand, jo *JSONOptions) ([]byte, error) { } // Call function value - value, err := funcInfo.Generate(r, &field.Params, funcInfo) + value, err := funcInfo.Generate(f.Rand, &field.Params, funcInfo) if err != nil { return nil, err } @@ -153,7 +153,7 @@ func jsonFunc(r *rand.Rand, jo *JSONOptions) ([]byte, error) { } // Call function value - value, err := funcInfo.Generate(r, &field.Params, funcInfo) + value, err := funcInfo.Generate(f.Rand, &field.Params, funcInfo) if err != nil { return nil, err } @@ -244,7 +244,8 @@ func addFileJSONLookup() { } jo.Indent = indent - return jsonFunc(r, &jo) + f := &Faker{Rand: r} + return jsonFunc(f, &jo) }, }) } diff --git a/xml.go b/xml.go index b34caa53..27b3ad03 100644 --- a/xml.go +++ b/xml.go @@ -129,16 +129,16 @@ func xmlMapLoop(e *xml.Encoder, m *xmlMap) error { // XML generates an object or an array of objects in json format // A nil XMLOptions returns a randomly structured XML. -func XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(globalFaker.Rand, xo) } +func XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(globalFaker, xo) } // XML generates an object or an array of objects in json format // A nil XMLOptions returns a randomly structured XML. -func (f *Faker) XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(f.Rand, xo) } +func (f *Faker) XML(xo *XMLOptions) ([]byte, error) { return xmlFunc(f, xo) } -func xmlFunc(r *rand.Rand, xo *XMLOptions) ([]byte, error) { +func xmlFunc(f *Faker, xo *XMLOptions) ([]byte, error) { if xo == nil { // We didn't get a XMLOptions, so create a new random one - err := Struct(&xo) + err := f.Struct(&xo) if err != nil { return nil, err } @@ -185,7 +185,7 @@ func xmlFunc(r *rand.Rand, xo *XMLOptions) ([]byte, error) { return nil, errors.New("invalid function, " + field.Function + " does not exist") } - value, err := funcInfo.Generate(r, &field.Params, funcInfo) + value, err := funcInfo.Generate(f.Rand, &field.Params, funcInfo) if err != nil { return nil, err } @@ -238,7 +238,7 @@ func xmlFunc(r *rand.Rand, xo *XMLOptions) ([]byte, error) { return nil, errors.New("invalid function, " + field.Function + " does not exist") } - value, err := funcInfo.Generate(r, &field.Params, funcInfo) + value, err := funcInfo.Generate(f.Rand, &field.Params, funcInfo) if err != nil { return nil, err } @@ -346,7 +346,8 @@ func addFileXMLLookup() { } xo.Indent = indent - return xmlFunc(r, &xo) + f := &Faker{Rand: r} + return xmlFunc(f, &xo) }, }) } From 0bfdbd144f51404b8438b812656919070d01cd29 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Thu, 30 Mar 2023 00:31:29 +0200 Subject: [PATCH 30/41] Handle encoding/json.RawMesssage It is defined in the std library and not easy to fake with other methods --- struct.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/struct.go b/struct.go index f97ebecc..0a02db6d 100644 --- a/struct.go +++ b/struct.go @@ -29,6 +29,22 @@ func structFunc(f *Faker, v interface{}) error { } func r(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { + // Handle special types + + // encoding/json.RawMessage is a special case of []byte + // it cannot be handled as a reflect.Array/reflect.Slice + // because it needs additional structure in the output + if t.PkgPath() == "encoding/json" && t.Name() == "RawMessage" { + b, err := f.JSON(nil) + if err != nil { + return err + } + + v.SetBytes(b) + return nil + } + + // Handle generic types switch t.Kind() { case reflect.Ptr: return rPointer(f, t, v, tag, size) From ad83a476bd6092fd4b4e1755452cc1f5a2721dea Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 3 Apr 2023 21:18:57 +0200 Subject: [PATCH 31/41] Failing test --- json_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/json_test.go b/json_test.go index e5db4960..e0d24167 100644 --- a/json_test.go +++ b/json_test.go @@ -394,6 +394,22 @@ func TestJSONRawMessageWithTag(t *testing.T) { } } +func TestJSONNumber(t *testing.T) { + type J struct { + Field json.Number `json:"field"` + } + + Seed(100) + + var objs []J + Slice(&objs) + + _, err := json.Marshal(objs) + if err != nil { + t.Fatal(err) + } +} + func BenchmarkJSONLookup100(b *testing.B) { faker := New(0) From 42799421e287b84dbadae9b80ad3c74e7f9292ca Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 3 Apr 2023 21:45:25 +0200 Subject: [PATCH 32/41] Add support for json.Number --- struct.go | 58 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/struct.go b/struct.go index 0a02db6d..1ab81757 100644 --- a/struct.go +++ b/struct.go @@ -1,6 +1,7 @@ package gofakeit import ( + "encoding/json" "errors" "reflect" "strconv" @@ -30,18 +31,19 @@ func structFunc(f *Faker, v interface{}) error { func r(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { // Handle special types - - // encoding/json.RawMessage is a special case of []byte - // it cannot be handled as a reflect.Array/reflect.Slice - // because it needs additional structure in the output - if t.PkgPath() == "encoding/json" && t.Name() == "RawMessage" { - b, err := f.JSON(nil) - if err != nil { - return err + if t.PkgPath() == "encoding/json" { + // encoding/json has two special types: + // - RawMessage + // - Number + + switch t.Name() { + case "RawMessage": + return rJsonRawMessage(f, t, v, tag, size) + case "Number": + return rJsonNumber(f, t, v, tag, size) + default: + return errors.New("unknown encoding/json type: " + t.Name()) } - - v.SetBytes(b) - return nil } // Handle generic types @@ -69,6 +71,40 @@ func r(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { return nil } +// encoding/json.RawMessage is a special case of []byte +// it cannot be handled as a reflect.Array/reflect.Slice +// because it needs additional structure in the output +func rJsonRawMessage(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { + b, err := f.JSON(nil) + if err != nil { + return err + } + + v.SetBytes(b) + return nil +} + +// encoding/json.Number is a special case of string +// that represents a JSON number literal. +// It cannot be handled as a string because it needs to +// represent an integer or a floating-point number. +func rJsonNumber(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { + var ret json.Number + + numberType := f.RandomInt([]int{0, 1}) + switch numberType { + case 0: + retInt := f.Int16() + ret = json.Number(strconv.Itoa(int(retInt))) + case 1: + retFloat := f.Float64() + ret = json.Number(strconv.FormatFloat(retFloat, 'f', -1, 64)) + } + + v.Set(reflect.ValueOf(ret)) + return nil +} + func rCustom(f *Faker, t reflect.Type, v reflect.Value, tag string) error { // If tag is empty return error if tag == "" { From 3853aeef21ac9834fd9befd8764ceaeddd296a65 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 3 Apr 2023 21:55:17 +0200 Subject: [PATCH 33/41] Failing test --- json_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/json_test.go b/json_test.go index e0d24167..f287f37c 100644 --- a/json_test.go +++ b/json_test.go @@ -410,6 +410,30 @@ func TestJSONNumber(t *testing.T) { } } +func TestJSONNumberWithTag(t *testing.T) { + type J struct { + Field json.Number `json:"field" fake:"number:3,7"` + } + + Seed(100) + + var objs []J + Slice(&objs) + + got, err := objs[0].Field.Int64() + if err != nil { + t.Fatal(err) + } + if got < 3 || got > 7 { + t.Errorf("Expected a number between 3 and 7, got %d", got) + } + + _, err = json.Marshal(objs) + if err != nil { + t.Fatal(err) + } +} + func BenchmarkJSONLookup100(b *testing.B) { faker := New(0) From 3eccca0f59d96d96b064b488cc8ba7b630d81b69 Mon Sep 17 00:00:00 2001 From: Miguel Eduardo Gil Biraud Date: Mon, 3 Apr 2023 23:05:32 +0200 Subject: [PATCH 34/41] Move to json.go and finish implementation for json.Number --- json.go | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ json_test.go | 46 ++++++++++++++++++++++++++++ struct.go | 36 +--------------------- 3 files changed, 131 insertions(+), 35 deletions(-) diff --git a/json.go b/json.go index e40f7a7a..dff59a94 100644 --- a/json.go +++ b/json.go @@ -4,7 +4,10 @@ import ( "bytes" "encoding/json" "errors" + "fmt" "math/rand" + "reflect" + "strconv" ) // JSONOptions defines values needed for json generation @@ -249,3 +252,84 @@ func addFileJSONLookup() { }, }) } + +// encoding/json.RawMessage is a special case of []byte +// it cannot be handled as a reflect.Array/reflect.Slice +// because it needs additional structure in the output +func rJsonRawMessage(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { + b, err := f.JSON(nil) + if err != nil { + return err + } + + v.SetBytes(b) + return nil +} + +// encoding/json.Number is a special case of string +// that represents a JSON number literal. +// It cannot be handled as a string because it needs to +// represent an integer or a floating-point number. +func rJsonNumber(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { + var ret json.Number + + var numberType string + + if tag == "" { + numberType = f.RandomString([]string{"int", "float"}) + + switch numberType { + case "int": + retInt := f.Int16() + ret = json.Number(strconv.Itoa(int(retInt))) + case "float": + retFloat := f.Float64() + ret = json.Number(strconv.FormatFloat(retFloat, 'f', -1, 64)) + } + } else { + fName, fParams := parseNameAndParamsFromTag(tag) + info := GetFuncLookup(fName) + if info == nil { + return fmt.Errorf("invalid function, %s does not exist", fName) + } + + // Parse map params + mapParams := parseMapParams(info, fParams) + + valueIface, err := info.Generate(f.Rand, mapParams, info) + if err != nil { + return err + } + + switch value := valueIface.(type) { + case int: + ret = json.Number(strconv.FormatInt(int64(value), 10)) + case int8: + ret = json.Number(strconv.FormatInt(int64(value), 10)) + case int16: + ret = json.Number(strconv.FormatInt(int64(value), 10)) + case int32: + ret = json.Number(strconv.FormatInt(int64(value), 10)) + case int64: + ret = json.Number(strconv.FormatInt(int64(value), 10)) + case uint: + ret = json.Number(strconv.FormatUint(uint64(value), 10)) + case uint8: + ret = json.Number(strconv.FormatUint(uint64(value), 10)) + case uint16: + ret = json.Number(strconv.FormatUint(uint64(value), 10)) + case uint32: + ret = json.Number(strconv.FormatUint(uint64(value), 10)) + case uint64: + ret = json.Number(strconv.FormatUint(uint64(value), 10)) + case float32: + ret = json.Number(strconv.FormatFloat(float64(value), 'f', -1, 64)) + case float64: + ret = json.Number(strconv.FormatFloat(float64(value), 'f', -1, 64)) + default: + return fmt.Errorf("invalid type, %s is not a valid type for json.Number", reflect.TypeOf(value)) + } + } + v.Set(reflect.ValueOf(ret)) + return nil +} diff --git a/json_test.go b/json_test.go index f287f37c..c8b6a848 100644 --- a/json_test.go +++ b/json_test.go @@ -434,6 +434,52 @@ func TestJSONNumberWithTag(t *testing.T) { } } +func ExampleJSONNumberWithTag() { + Seed(10) + + type J struct { + FieldNumber json.Number `fake:"number:3,7"` + FieldInt8 json.Number `fake:"int8"` + FieldInt16 json.Number `fake:"int16"` + FieldInt32 json.Number `fake:"int32"` + FieldInt64 json.Number `fake:"int64"` + FieldUint8 json.Number `fake:"uint8"` + FieldUint16 json.Number `fake:"uint16"` + FieldUint32 json.Number `fake:"uint32"` + FieldUint64 json.Number `fake:"uint64"` + FieldFloat32 json.Number `fake:"float32"` + FieldFloat64 json.Number `fake:"float64range:12,72"` + } + + var obj J + Struct(&obj) + + fmt.Printf("obj.FieldNumber = %+v\n", obj.FieldNumber) + fmt.Printf("obj.FieldInt8 = %+v\n", obj.FieldInt8) + fmt.Printf("obj.FieldInt16 = %+v\n", obj.FieldInt16) + fmt.Printf("obj.FieldInt32 = %+v\n", obj.FieldInt32) + fmt.Printf("obj.FieldInt64 = %+v\n", obj.FieldInt64) + fmt.Printf("obj.FieldUint8 = %+v\n", obj.FieldUint8) + fmt.Printf("obj.FieldUint16 = %+v\n", obj.FieldUint16) + fmt.Printf("obj.FieldUint32 = %+v\n", obj.FieldUint32) + fmt.Printf("obj.FieldUint64 = %+v\n", obj.FieldUint64) + fmt.Printf("obj.FieldFloat32 = %+v\n", obj.FieldFloat32) + fmt.Printf("obj.FieldFloat64 = %+v\n", obj.FieldFloat64) + + // Output: + // obj.FieldNumber = 3 + // obj.FieldInt8 = 16 + // obj.FieldInt16 = 10619 + // obj.FieldInt32 = -1654523813 + // obj.FieldInt64 = -4710905755560118665 + // obj.FieldUint8 = 200 + // obj.FieldUint16 = 28555 + // obj.FieldUint32 = 162876094 + // obj.FieldUint64 = 7956601014869229133 + // obj.FieldFloat32 = 9227009415507442000000000000000000000 + // obj.FieldFloat64 = 62.323882731848215 +} + func BenchmarkJSONLookup100(b *testing.B) { faker := New(0) diff --git a/struct.go b/struct.go index 1ab81757..cc00c110 100644 --- a/struct.go +++ b/struct.go @@ -1,7 +1,6 @@ package gofakeit import ( - "encoding/json" "errors" "reflect" "strconv" @@ -31,6 +30,7 @@ func structFunc(f *Faker, v interface{}) error { func r(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { // Handle special types + if t.PkgPath() == "encoding/json" { // encoding/json has two special types: // - RawMessage @@ -71,40 +71,6 @@ func r(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { return nil } -// encoding/json.RawMessage is a special case of []byte -// it cannot be handled as a reflect.Array/reflect.Slice -// because it needs additional structure in the output -func rJsonRawMessage(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { - b, err := f.JSON(nil) - if err != nil { - return err - } - - v.SetBytes(b) - return nil -} - -// encoding/json.Number is a special case of string -// that represents a JSON number literal. -// It cannot be handled as a string because it needs to -// represent an integer or a floating-point number. -func rJsonNumber(f *Faker, t reflect.Type, v reflect.Value, tag string, size int) error { - var ret json.Number - - numberType := f.RandomInt([]int{0, 1}) - switch numberType { - case 0: - retInt := f.Int16() - ret = json.Number(strconv.Itoa(int(retInt))) - case 1: - retFloat := f.Float64() - ret = json.Number(strconv.FormatFloat(retFloat, 'f', -1, 64)) - } - - v.Set(reflect.ValueOf(ret)) - return nil -} - func rCustom(f *Faker, t reflect.Type, v reflect.Value, tag string) error { // If tag is empty return error if tag == "" { From 9199e8edeaa4f28195ba7288fadb071a7951fd26 Mon Sep 17 00:00:00 2001 From: Wayne Manselle Date: Sat, 8 Apr 2023 16:43:57 -0700 Subject: [PATCH 35/41] Cleanup and update benchmarks --- BENCHMARKS.md | 631 +++++++++++++++++++++++++++++++++++------------- finance.go | 151 ++++++++---- finance_test.go | 59 ++++- 3 files changed, 618 insertions(+), 223 deletions(-) diff --git a/BENCHMARKS.md b/BENCHMARKS.md index f4b91107..38f1f3e5 100644 --- a/BENCHMARKS.md +++ b/BENCHMARKS.md @@ -1,176 +1,461 @@ go test -bench=. -benchmem -goos: darwin -goarch: amd64 -pkg: github.com/brianvoe/gofakeit +goos: linux +goarch: amd64 +pkg: github.com/brianvoe/gofakeit/v6 +cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz Table generated with tablesgenerator.com/markdown_tables -| Benchmark | Ops | CPU | MEM | MEM alloc | -|---------------------------------|-----------|-------------|------------|--------------| -| BenchmarkAddress-16 | 797298 | 1649 ns/op | 248 B/op | 7 allocs/op | -| BenchmarkStreet-16 | 1987233 | 601 ns/op | 62 B/op | 3 allocs/op | -| BenchmarkStreetNumber-16 | 4808812 | 252 ns/op | 36 B/op | 2 allocs/op | -| BenchmarkStreetPrefix-16 | 12750800 | 83.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkStreetName-16 | 14026328 | 81.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkStreetSuffix-16 | 13836478 | 81.2 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCity-16 | 4617508 | 245 ns/op | 15 B/op | 1 allocs/op | -| BenchmarkState-16 | 12095868 | 86.3 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkStateAbr-16 | 13337152 | 83.5 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkZip-16 | 6264339 | 201 ns/op | 5 B/op | 1 allocs/op | -| BenchmarkCountry-16 | 12378775 | 85.4 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCountryAbr-16 | 12770610 | 86.2 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkLatitude-16 | 30935530 | 32.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkLongitude-16 | 35305698 | 32.4 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkLatitudeInRange-16 | 35285907 | 34.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkLongitudeInRange-16 | 29716158 | 34.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkPetName-16 | 15559858 | 69.6 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkAnimal-16 | 15493616 | 71.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkAnimalType-16 | 15802927 | 72.9 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkFarmAnimal-16 | 13610484 | 81.9 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCat-16 | 14966256 | 76.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkDog-16 | 12833390 | 88.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkUsername-16 | 5720742 | 220 ns/op | 16 B/op | 2 allocs/op | -| BenchmarkPassword-16 | 2016339 | 593 ns/op | 304 B/op | 6 allocs/op | -| BenchmarkBeerName-16 | 15339746 | 72.4 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkBeerStyle-16 | 12902784 | 86.1 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkBeerHop-16 | 15131584 | 71.5 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkBeerYeast-16 | 14747238 | 73.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkBeerMalt-16 | 14982421 | 78.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkBeerIbu-16 | 20595496 | 53.4 ns/op | 8 B/op | 1 allocs/op | -| BenchmarkBeerAlcohol-16 | 3921880 | 299 ns/op | 40 B/op | 3 allocs/op | -| BenchmarkBeerBlg-16 | 4150712 | 300 ns/op | 48 B/op | 3 allocs/op | -| BenchmarkCar-16 | 1996923 | 597 ns/op | 96 B/op | 1 allocs/op | -| BenchmarkCarType-16 | 17076163 | 65.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCarFuelType-16 | 14844217 | 73.2 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCarTransmissionType-16 | 16047379 | 68.6 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCarMaker-16 | 14501310 | 76.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCarModel-16 | 12503469 | 87.9 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkColor-16 | 14812000 | 75.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkSafeColor-16 | 17647850 | 66.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkHexColor-16 | 3710928 | 326 ns/op | 24 B/op | 3 allocs/op | -| BenchmarkRGBColor-16 | 12641104 | 83.3 ns/op | 32 B/op | 1 allocs/op | -| BenchmarkCompany-16 | 17277220 | 67.9 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCompanySuffix-16 | 17099479 | 60.3 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkBuzzWord-16 | 15963231 | 68.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkBS-16 | 15149085 | 71.2 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkJob-16 | 3203989 | 383 ns/op | 64 B/op | 1 allocs/op | -| BenchmarkJobTitle-16 | 15232904 | 70.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkJobDescriptor-16 | 15603652 | 69.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkJobLevel-16 | 14281743 | 77.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkEmoji-16 | 15016417 | 75.3 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkEmojiDescription-16 | 14764699 | 76.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkEmojiCategory-16 | 13463936 | 78.2 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkEmojiAlias-16 | 12291789 | 87.5 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkEmojiTag-16 | 13451284 | 82.3 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkFileMimeType-16 | 16654501 | 67.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkFileExtension-16 | 13656126 | 73.4 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkFruit-16 | 15039096 | 74.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkVegetable-16 | 14397543 | 76.5 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkBreakfast-16 | 5960095 | 181 ns/op | 35 B/op | 1 allocs/op | -| BenchmarkLunch-16 | 6350367 | 189 ns/op | 37 B/op | 1 allocs/op | -| BenchmarkDinner-16 | 6245412 | 177 ns/op | 37 B/op | 1 allocs/op | -| BenchmarkSnack-16 | 5891965 | 192 ns/op | 36 B/op | 1 allocs/op | -| BenchmarkDessert-16 | 6603031 | 186 ns/op | 34 B/op | 2 allocs/op | -| BenchmarkGamertag-16 | 3237366 | 352 ns/op | 36 B/op | 3 allocs/op | -| BenchmarkGenerate-16 | 457622 | 2652 ns/op | 916 B/op | 23 allocs/op | -| BenchmarkMap-16 | 290334 | 4145 ns/op | 1082 B/op | 16 allocs/op | -| BenchmarkHackerPhrase-16 | 200760 | 5623 ns/op | 2909 B/op | 37 allocs/op | -| BenchmarkHackerAbbreviation-16 | 15939142 | 71.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkHackerAdjective-16 | 14837203 | 70.6 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkHackerNoun-16 | 14633212 | 72.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkHackerVerb-16 | 13376676 | 82.3 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkHackerIngverb-16 | 14869647 | 72.6 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkReplaceWithNumbers-16 | 4214044 | 287 ns/op | 32 B/op | 1 allocs/op | -| BenchmarkHipsterWord-16 | 14753112 | 71.2 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkHipsterSentence-16 | 871815 | 1396 ns/op | 305 B/op | 3 allocs/op | -| BenchmarkHipsterParagraph-16 | 42579 | 28624 ns/op | 10560 B/op | 48 allocs/op | -| BenchmarkImageURL-16 | 10556988 | 121 ns/op | 38 B/op | 3 allocs/op | -| BenchmarkDomainName-16 | 2852584 | 428 ns/op | 53 B/op | 2 allocs/op | -| BenchmarkDomainSuffix-16 | 15614646 | 70.2 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkURL-16 | 1128352 | 1056 ns/op | 189 B/op | 4 allocs/op | -| BenchmarkHTTPMethod-16 | 15604741 | 72.3 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkIPv4Address-16 | 3539780 | 332 ns/op | 48 B/op | 5 allocs/op | -| BenchmarkIPv6Address-16 | 2419968 | 490 ns/op | 96 B/op | 7 allocs/op | -| BenchmarkMacAddress-16 | 2003596 | 619 ns/op | 79 B/op | 6 allocs/op | -| BenchmarkHTTPStatusCode-16 | 22232200 | 50.6 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkHTTPStatusCodeSimple-16 | 21198192 | 48.4 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkLogLevel-16 | 13729278 | 78.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkUserAgent-16 | 1000000 | 1044 ns/op | 300 B/op | 5 allocs/op | -| BenchmarkChromeUserAgent-16 | 1591886 | 783 ns/op | 188 B/op | 5 allocs/op | -| BenchmarkFirefoxUserAgent-16 | 742941 | 1400 ns/op | 362 B/op | 6 allocs/op | -| BenchmarkSafariUserAgent-16 | 930159 | 1306 ns/op | 551 B/op | 7 allocs/op | -| BenchmarkOperaUserAgent-16 | 1454205 | 829 ns/op | 216 B/op | 5 allocs/op | -| BenchmarkLanguage-16 | 15265677 | 71.6 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkLanguageAbbreviation-16 | 16144437 | 68.1 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkProgrammingLanguage-16 | 16125788 | 71.6 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkProgrammingLanguageBest-16 | 1000000000 | 0.229 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkBool-16 | 79448815 | 15.1 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkUUID-16 | 11553009 | 106 ns/op | 48 B/op | 1 allocs/op | -| BenchmarkNumber-16 | 59585859 | 17.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkUint8-16 | 79947612 | 15.1 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkUint16-16 | 79249844 | 15.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkUint32-16 | 81112372 | 14.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkUint64-16 | 50800922 | 20.5 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkInt8-16 | 66494482 | 15.1 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkInt16-16 | 79505629 | 15.1 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkInt32-16 | 79967979 | 15.1 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkInt64-16 | 60566858 | 19.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkFloat32-16 | 84251548 | 14.1 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkFloat32Range-16 | 80528571 | 14.9 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkFloat64-16 | 94149510 | 12.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkFloat64Range-16 | 94346104 | 12.9 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkShuffleInts-16 | 9075564 | 130 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCurrency-16 | 11273227 | 115 ns/op | 32 B/op | 1 allocs/op | -| BenchmarkCurrencyShort-16 | 15565836 | 72.2 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCurrencyLong-16 | 15420937 | 71.3 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkPrice-16 | 80781411 | 15.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCreditCard-16 | 1637452 | 751 ns/op | 88 B/op | 4 allocs/op | -| BenchmarkCreditCardType-16 | 17678868 | 64.4 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkCreditCardNumber-16 | 3361524 | 349 ns/op | 16 B/op | 1 allocs/op | -| BenchmarkCreditCardNumberLuhn-16 | 279769 | 3620 ns/op | 160 B/op | 10 allocs/op | -| BenchmarkCreditCardExp-16 | 7523824 | 150 ns/op | 5 B/op | 1 allocs/op | -| BenchmarkCreditCardCvv-16 | 15185973 | 73.6 ns/op | 3 B/op | 1 allocs/op | -| BenchmarkName-16 | 5436148 | 215 ns/op | 17 B/op | 1 allocs/op | -| BenchmarkFirstName-16 | 14362125 | 72.6 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkLastName-16 | 15530926 | 72.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkNamePrefix-16 | 18074462 | 66.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkNameSuffix-16 | 14657012 | 73.9 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkSSN-16 | 18693813 | 68.9 ns/op | 16 B/op | 1 allocs/op | -| BenchmarkGender-16 | 72023787 | 15.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkPerson-16 | 282908 | 4377 ns/op | 752 B/op | 24 allocs/op | -| BenchmarkContact-16 | 1369327 | 911 ns/op | 146 B/op | 6 allocs/op | -| BenchmarkPhone-16 | 6015615 | 204 ns/op | 16 B/op | 1 allocs/op | -| BenchmarkPhoneFormatted-16 | 3928914 | 296 ns/op | 16 B/op | 1 allocs/op | -| BenchmarkEmail-16 | 1901041 | 653 ns/op | 98 B/op | 4 allocs/op | -| BenchmarkLetter-16 | 65959573 | 17.3 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkDigit-16 | 58815334 | 17.4 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkNumerify-16 | 5526314 | 207 ns/op | 16 B/op | 1 allocs/op | -| BenchmarkLexify-16 | 9712312 | 129 ns/op | 8 B/op | 1 allocs/op | -| BenchmarkShuffleStrings-16 | 8997901 | 119 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkDate-16 | 5949220 | 194 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkDateRange-16 | 7122076 | 166 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkMonth-16 | 56979296 | 19.3 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkDay-16 | 61808844 | 17.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkWeekDay-16 | 62598561 | 19.3 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkYear-16 | 14533374 | 76.6 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkHour-16 | 62130793 | 17.0 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkMinute-16 | 66836017 | 17.1 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkSecond-16 | 69860632 | 17.1 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkNanoSecond-16 | 66957362 | 17.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkTimeZone-16 | 13841594 | 78.7 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkTimeZoneFull-16 | 12788362 | 89.2 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkTimeZoneAbv-16 | 14413452 | 77.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkTimeZoneOffset-16 | 10699014 | 103 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkNoun-16 | 15025992 | 74.6 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkVerb-16 | 13394044 | 82.2 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkAdverb-16 | 13968967 | 78.9 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkPreposition-16 | 14575834 | 81.1 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkAdjective-16 | 13957762 | 82.9 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkWord-16 | 11083752 | 98.2 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkSentence-16 | 647954 | 1642 ns/op | 251 B/op | 2 allocs/op | -| BenchmarkParagraph-16 | 34026 | 35489 ns/op | 9587 B/op | 47 allocs/op | -| BenchmarkLoremIpsumWord-16 | 15156211 | 70.8 ns/op | 0 B/op | 0 allocs/op | -| BenchmarkLoremIpsumSentence-16 | 908371 | 1293 ns/op | 229 B/op | 2 allocs/op | -| BenchmarkLoremIpsumParagraph-16 | 41920 | 27860 ns/op | 9214 B/op | 45 allocs/op | -| BenchmarkQuestion-16 | 1000000 | 1152 ns/op | 315 B/op | 4 allocs/op | -| BenchmarkQuote-16 | 924054 | 1263 ns/op | 268 B/op | 3 allocs/op | -| BenchmarkPhrase-16 | 11034157 | 94.6 ns/op | 0 B/op | 0 allocs/op | \ No newline at end of file +| Benchmark | Ops | CPU | MEM | MEM alloc | +|--------------------------------------------------|------------|------------------|----------------|-------------------| +| BenchmarkAddress/package-8 | 1270872 | 940.1 ns/op | 197 B/op | 5 allocs/op | +| BenchmarkAddress/Faker_math-8 | 1238563 | 1042 ns/op | 197 B/op | 5 allocs/op | +| BenchmarkAddress/Faker_crypto-8 | 139857 | 7862 ns/op | 197 B/op | 5 allocs/op | +| BenchmarkStreet/package-8 | 2955518 | 422.6 ns/op | 26 B/op | 2 allocs/op | +| BenchmarkStreet/Faker_math-8 | 3027224 | 427.3 ns/op | 26 B/op | 2 allocs/op | +| BenchmarkStreet/Faker_crypto-8 | 352165 | 3559 ns/op | 26 B/op | 2 allocs/op | +| BenchmarkStreetNumber/package-8 | 6842211 | 149.2 ns/op | 4 B/op | 1 allocs/op | +| BenchmarkStreetNumber/Faker_math-8 | 6924288 | 158.8 ns/op | 4 B/op | 1 allocs/op | +| BenchmarkStreetNumber/Faker_crypto-8 | 549988 | 1900 ns/op | 4 B/op | 1 allocs/op | +| BenchmarkStreetPrefix/package-8 | 18441643 | 74.12 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStreetPrefix/Faker_math-8 | 17888110 | 67.51 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStreetPrefix/Faker_crypto-8 | 2650390 | 458.9 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStreetName/package-8 | 18799832 | 62.90 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStreetName/Faker_math-8 | 16124620 | 63.57 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStreetName/Faker_crypto-8 | 2873138 | 428.2 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStreetSuffix/package-8 | 17192164 | 72.19 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStreetSuffix/Faker_math-8 | 16545355 | 65.44 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStreetSuffix/Faker_crypto-8 | 2986934 | 450.9 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCity/package-8 | 18553683 | 64.93 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCity/Faker_math-8 | 17648109 | 63.77 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCity/Faker_crypto-8 | 2567427 | 470.8 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkState/package-8 | 18262387 | 66.25 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkState/Faker_math-8 | 16690209 | 73.21 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkState/Faker_crypto-8 | 2599795 | 401.3 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStateAbr/package-8 | 17492332 | 63.87 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStateAbr/Faker_math-8 | 18612169 | 64.82 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkStateAbr/Faker_crypto-8 | 2821579 | 460.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkZip/package-8 | 7573238 | 157.1 ns/op | 5 B/op | 1 allocs/op | +| BenchmarkZip/Faker_math-8 | 6644562 | 163.4 ns/op | 5 B/op | 1 allocs/op | +| BenchmarkZip/Faker_crypto-8 | 484525 | 2470 ns/op | 5 B/op | 1 allocs/op | +| BenchmarkCountry/package-8 | 15623450 | 65.65 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCountry/Faker_math-8 | 17786485 | 76.22 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCountry/Faker_crypto-8 | 3002818 | 400.3 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCountryAbr/package-8 | 17296935 | 66.75 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCountryAbr/Faker_math-8 | 17862819 | 67.41 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCountryAbr/Faker_crypto-8 | 2931120 | 426.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLatitude/package-8 | 46248466 | 26.11 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLatitude/Faker_math-8 | 46120956 | 26.00 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLatitude/Faker_crypto-8 | 3512108 | 366.7 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLongitude/package-8 | 47443129 | 24.03 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLongitude/Faker_math-8 | 46691144 | 24.64 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLongitude/Faker_crypto-8 | 3501789 | 365.8 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLatitudeInRange/package-8 | 44125588 | 26.96 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLatitudeInRange/Faker_math-8 | 40113348 | 27.36 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLatitudeInRange/Faker_crypto-8 | 3227358 | 378.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLongitudeInRange/package-8 | 38948743 | 32.36 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLongitudeInRange/Faker_math-8 | 36491187 | 27.86 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLongitudeInRange/Faker_crypto-8 | 3004773 | 350.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPetName/package-8 | 23445927 | 60.81 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPetName/Faker_math-8 | 23982228 | 53.68 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkPetName/Faker_crypto-8 | 2681886 | 458.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAnimal/package-8 | 23230071 | 55.13 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAnimal/Faker_math-8 | 21923606 | 53.10 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAnimal/Faker_crypto-8 | 2680177 | 411.6 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAnimalType/package-8 | 18826995 | 53.45 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAnimalType/Faker_math-8 | 22170756 | 63.39 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAnimalType/Faker_crypto-8 | 2780270 | 399.6 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFarmAnimal/package-8 | 18548028 | 64.87 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFarmAnimal/Faker_math-8 | 17291526 | 62.47 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFarmAnimal/Faker_crypto-8 | 2543520 | 409.9 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCat/package-8 | 21213028 | 68.91 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCat/Faker_math-8 | 19973062 | 58.74 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCat/Faker_crypto-8 | 2985601 | 405.2 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkDog/package-8 | 16995627 | 68.15 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkDog/Faker_math-8 | 17296502 | 81.35 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkDog/Faker_crypto-8 | 2530860 | 433.1 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBird/package-8 | 14445968 | 81.31 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBird/Faker_math-8 | 14545851 | 82.69 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBird/Faker_crypto-8 | 2892721 | 420.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkAppName/package-8 | 2799828 | 438.6 ns/op | 25 B/op | 1 allocs/op | +| BenchmarkAppName/Faker_math-8 | 2784135 | 431.1 ns/op | 25 B/op | 1 allocs/op | +| BenchmarkAppName/Faker_crypto-8 | 611072 | 1923 ns/op | 25 B/op | 1 allocs/op | +| BenchmarkAppVersion/package-8 | 7552165 | 154.1 ns/op | 7 B/op | 1 allocs/op | +| BenchmarkAppVersion/Faker_math-8 | 8020767 | 156.6 ns/op | 7 B/op | 1 allocs/op | +| BenchmarkAppVersion/Faker_crypto-8 | 875899 | 1209 ns/op | 7 B/op | 1 allocs/op | +| BenchmarkAppAuthor/package-8 | 9596493 | 119.7 ns/op | 8 B/op | 0 allocs/op | +| BenchmarkAppAuthor/Faker_math-8 | 10068729 | 121.0 ns/op | 8 B/op | 0 allocs/op | +| BenchmarkAppAuthor/Faker_crypto-8 | 1212542 | 983.7 ns/op | 8 B/op | 0 allocs/op | +| BenchmarkUsername/package-8 | 6687600 | 174.6 ns/op | 16 B/op | 2 allocs/op | +| BenchmarkUsername/Faker_math-8 | 7233685 | 173.3 ns/op | 16 B/op | 2 allocs/op | +| BenchmarkUsername/Faker_crypto-8 | 616884 | 2166 ns/op | 16 B/op | 2 allocs/op | +| BenchmarkPassword/package-8 | 2966407 | 401.0 ns/op | 336 B/op | 6 allocs/op | +| BenchmarkPassword/Faker_math-8 | 3080845 | 399.8 ns/op | 336 B/op | 6 allocs/op | +| BenchmarkPassword/Faker_crypto-8 | 182074 | 5963 ns/op | 336 B/op | 6 allocs/op | +| BenchmarkBeerName/package-8 | 23768442 | 53.26 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerName/Faker_math-8 | 22010898 | 63.87 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerName/Faker_crypto-8 | 2569424 | 392.6 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerStyle/package-8 | 17567354 | 69.64 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerStyle/Faker_math-8 | 16695721 | 80.73 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerStyle/Faker_crypto-8 | 2710214 | 407.6 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerHop/package-8 | 20877854 | 56.43 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerHop/Faker_math-8 | 22603234 | 65.04 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerHop/Faker_crypto-8 | 2618493 | 419.3 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerYeast/package-8 | 20738073 | 67.89 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerYeast/Faker_math-8 | 21325231 | 67.34 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerYeast/Faker_crypto-8 | 3042529 | 399.8 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerMalt/package-8 | 15756969 | 65.67 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerMalt/Faker_math-8 | 18026910 | 71.42 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerMalt/Faker_crypto-8 | 2949741 | 429.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBeerIbu/package-8 | 32683443 | 35.57 ns/op | 8 B/op | 1 allocs/op | +| BenchmarkBeerIbu/Faker_math-8 | 29983339 | 36.03 ns/op | 8 B/op | 1 allocs/op | +| BenchmarkBeerIbu/Faker_crypto-8 | 3094896 | 386.6 ns/op | 8 B/op | 1 allocs/op | +| BenchmarkBeerAlcohol/package-8 | 4744302 | 243.6 ns/op | 32 B/op | 3 allocs/op | +| BenchmarkBeerAlcohol/Faker_math-8 | 4718923 | 252.0 ns/op | 32 B/op | 3 allocs/op | +| BenchmarkBeerAlcohol/Faker_crypto-8 | 1952740 | 656.0 ns/op | 32 B/op | 3 allocs/op | +| BenchmarkBeerBlg/package-8 | 4086861 | 270.6 ns/op | 40 B/op | 3 allocs/op | +| BenchmarkBeerBlg/Faker_math-8 | 4488897 | 259.5 ns/op | 40 B/op | 3 allocs/op | +| BenchmarkBeerBlg/Faker_crypto-8 | 1865367 | 646.7 ns/op | 40 B/op | 3 allocs/op | +| BenchmarkCar/package-8 | 2800782 | 400.5 ns/op | 96 B/op | 1 allocs/op | +| BenchmarkCar/Faker_math-8 | 2938509 | 396.5 ns/op | 96 B/op | 1 allocs/op | +| BenchmarkCar/Faker_crypto-8 | 461906 | 2590 ns/op | 96 B/op | 1 allocs/op | +| BenchmarkCarType/package-8 | 23655384 | 51.72 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarType/Faker_math-8 | 25902462 | 50.55 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarType/Faker_crypto-8 | 3035287 | 455.8 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarFuelType/package-8 | 18750069 | 63.80 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarFuelType/Faker_math-8 | 18858705 | 63.15 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarFuelType/Faker_crypto-8 | 3028026 | 387.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarTransmissionType/package-8 | 22570701 | 54.01 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarTransmissionType/Faker_math-8 | 21484246 | 64.27 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarTransmissionType/Faker_crypto-8 | 3061364 | 387.6 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarMaker/package-8 | 17628445 | 68.23 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarMaker/Faker_math-8 | 21573310 | 64.19 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarMaker/Faker_crypto-8 | 2688284 | 475.5 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarModel/package-8 | 18500498 | 73.43 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarModel/Faker_math-8 | 16116993 | 66.91 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCarModel/Faker_crypto-8 | 2487638 | 440.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebrityActor/package-8 | 18712833 | 74.12 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebrityActor/Faker_math-8 | 18564168 | 68.96 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebrityActor/Faker_crypto-8 | 2593150 | 415.5 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebrityBusiness/package-8 | 18721152 | 68.98 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebrityBusiness/Faker_math-8 | 16916186 | 70.66 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebrityBusiness/Faker_crypto-8 | 2578786 | 407.7 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebritySport/package-8 | 16716724 | 87.51 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebritySport/Faker_math-8 | 16602294 | 86.41 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCelebritySport/Faker_crypto-8 | 2919696 | 419.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkColor/package-8 | 17871778 | 62.28 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkColor/Faker_math-8 | 21601353 | 62.63 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkColor/Faker_crypto-8 | 3040459 | 463.1 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNiceColors/package-8 | 81438092 | 14.86 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNiceColors/Faker_math-8 | 75775309 | 18.52 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkNiceColors/Faker_crypto-8 | 3450939 | 353.9 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkSafeColor/package-8 | 22775230 | 53.52 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkSafeColor/Faker_math-8 | 24526308 | 59.40 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkSafeColor/Faker_crypto-8 | 3103851 | 413.3 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHexColor/package-8 | 4640522 | 255.2 ns/op | 24 B/op | 3 allocs/op | +| BenchmarkHexColor/Faker_math-8 | 4723542 | 257.2 ns/op | 24 B/op | 3 allocs/op | +| BenchmarkHexColor/Faker_crypto-8 | 283828 | 4447 ns/op | 24 B/op | 3 allocs/op | +| BenchmarkRGBColor/package-8 | 19721971 | 59.64 ns/op | 24 B/op | 1 allocs/op | +| BenchmarkRGBColor/Faker_math-8 | 18808492 | 67.35 ns/op | 24 B/op | 1 allocs/op | +| BenchmarkRGBColor/Faker_crypto-8 | 1000000 | 1066 ns/op | 24 B/op | 1 allocs/op | +| BenchmarkCompany/package-8 | 22072651 | 48.06 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCompany/Faker_math-8 | 22528284 | 53.94 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCompany/Faker_crypto-8 | 2690668 | 402.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCompanySuffix/package-8 | 28169413 | 48.00 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCompanySuffix/Faker_math-8 | 20685153 | 52.20 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCompanySuffix/Faker_crypto-8 | 3018765 | 418.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBuzzWord/package-8 | 24238677 | 54.55 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBuzzWord/Faker_math-8 | 22195419 | 52.30 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBuzzWord/Faker_crypto-8 | 2840428 | 392.1 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBS/package-8 | 23481436 | 56.33 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBS/Faker_math-8 | 23195737 | 65.66 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBS/Faker_crypto-8 | 3027972 | 419.8 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJob/package-8 | 4432520 | 253.5 ns/op | 64 B/op | 1 allocs/op | +| BenchmarkJob/Faker_math-8 | 4513154 | 253.7 ns/op | 64 B/op | 1 allocs/op | +| BenchmarkJob/Faker_crypto-8 | 686028 | 1716 ns/op | 64 B/op | 1 allocs/op | +| BenchmarkJobTitle/package-8 | 20079558 | 54.21 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJobTitle/Faker_math-8 | 21871627 | 54.86 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJobTitle/Faker_crypto-8 | 3017896 | 413.3 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJobDescriptor/package-8 | 21579855 | 53.36 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJobDescriptor/Faker_math-8 | 24638751 | 55.91 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJobDescriptor/Faker_crypto-8 | 2984810 | 415.9 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJobLevel/package-8 | 18311070 | 59.35 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJobLevel/Faker_math-8 | 17051210 | 59.53 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkJobLevel/Faker_crypto-8 | 2991106 | 426.8 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCSVLookup100-8 | 1468 | 780852 ns/op | 437416 B/op | 5933 allocs/op | +| BenchmarkCSVLookup1000-8 | 151 | 7853471 ns/op | 4224820 B/op | 59612 allocs/op | +| BenchmarkCSVLookup10000-8 | 14 | 78165009 ns/op | 41208010 B/op | 597842 allocs/op | +| BenchmarkCSVLookup100000-8 | 2 | 768800840 ns/op | 437275164 B/op | 5980461 allocs/op | +| BenchmarkEmoji/package-8 | 22212386 | 54.40 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmoji/Faker_math-8 | 21471013 | 51.55 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmoji/Faker_crypto-8 | 3036081 | 458.1 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiDescription/package-8 | 18250413 | 57.08 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiDescription/Faker_math-8 | 21924381 | 57.58 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiDescription/Faker_crypto-8 | 2837050 | 387.5 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiCategory/package-8 | 21270252 | 55.87 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiCategory/Faker_math-8 | 21421813 | 59.59 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiCategory/Faker_crypto-8 | 2635878 | 491.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiAlias/package-8 | 18760875 | 68.20 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiAlias/Faker_math-8 | 16918242 | 67.60 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiAlias/Faker_crypto-8 | 2854717 | 488.9 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiTag/package-8 | 19953885 | 65.43 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiTag/Faker_math-8 | 18220396 | 72.91 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkEmojiTag/Faker_crypto-8 | 2802847 | 426.2 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkError/package-8 | 1547610 | 786.6 ns/op | 279 B/op | 8 allocs/op | +| BenchmarkError/Faker_math-8 | 1504578 | 794.1 ns/op | 279 B/op | 8 allocs/op | +| BenchmarkError/Faker_crypto-8 | 800712 | 1476 ns/op | 279 B/op | 8 allocs/op | +| BenchmarkErrorObject/package-8 | 6054552 | 190.3 ns/op | 32 B/op | 3 allocs/op | +| BenchmarkErrorObject/Faker_math-8 | 5968180 | 190.3 ns/op | 32 B/op | 3 allocs/op | +| BenchmarkErrorObject/Faker_crypto-8 | 2088008 | 618.0 ns/op | 32 B/op | 3 allocs/op | +| BenchmarkErrorDatabase/package-8 | 5275713 | 212.8 ns/op | 64 B/op | 3 allocs/op | +| BenchmarkErrorDatabase/Faker_math-8 | 5407803 | 217.3 ns/op | 64 B/op | 3 allocs/op | +| BenchmarkErrorDatabase/Faker_crypto-8 | 2005333 | 628.7 ns/op | 63 B/op | 3 allocs/op | +| BenchmarkErrorGRPC/package-8 | 5700810 | 202.9 ns/op | 64 B/op | 3 allocs/op | +| BenchmarkErrorGRPC/Faker_math-8 | 5907589 | 202.5 ns/op | 64 B/op | 3 allocs/op | +| BenchmarkErrorGRPC/Faker_crypto-8 | 2027650 | 643.3 ns/op | 64 B/op | 3 allocs/op | +| BenchmarkErrorHTTP/package-8 | 3182026 | 321.6 ns/op | 157 B/op | 4 allocs/op | +| BenchmarkErrorHTTP/Faker_math-8 | 3667356 | 314.9 ns/op | 157 B/op | 4 allocs/op | +| BenchmarkErrorHTTP/Faker_crypto-8 | 1590696 | 720.2 ns/op | 157 B/op | 4 allocs/op | +| BenchmarkErrorHTTPClient/package-8 | 5745494 | 204.0 ns/op | 52 B/op | 3 allocs/op | +| BenchmarkErrorHTTPClient/Faker_math-8 | 5549187 | 212.8 ns/op | 52 B/op | 3 allocs/op | +| BenchmarkErrorHTTPClient/Faker_crypto-8 | 2011905 | 596.7 ns/op | 52 B/op | 3 allocs/op | +| BenchmarkErrorHTTPServer/package-8 | 5466012 | 214.7 ns/op | 59 B/op | 3 allocs/op | +| BenchmarkErrorHTTPServer/Faker_math-8 | 5542838 | 207.3 ns/op | 59 B/op | 3 allocs/op | +| BenchmarkErrorHTTPServer/Faker_crypto-8 | 1939080 | 633.9 ns/op | 59 B/op | 3 allocs/op | +| BenchmarkErrorRuntime/package-8 | 4245986 | 263.4 ns/op | 150 B/op | 3 allocs/op | +| BenchmarkErrorRuntime/Faker_math-8 | 4355534 | 263.1 ns/op | 150 B/op | 3 allocs/op | +| BenchmarkErrorRuntime/Faker_crypto-8 | 1782044 | 651.4 ns/op | 150 B/op | 3 allocs/op | +| BenchmarkErrorValidation/package-8 | 1659858 | 715.7 ns/op | 268 B/op | 7 allocs/op | +| BenchmarkErrorValidation/Faker_math-8 | 1690849 | 716.4 ns/op | 268 B/op | 7 allocs/op | +| BenchmarkErrorValidation/Faker_crypto-8 | 883600 | 1348 ns/op | 268 B/op | 7 allocs/op | +| BenchmarkFileMimeType/package-8 | 18005230 | 56.88 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFileMimeType/Faker_math-8 | 21229381 | 54.62 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFileMimeType/Faker_crypto-8 | 2605701 | 462.5 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFileExtension/package-8 | 19272264 | 73.07 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFileExtension/Faker_math-8 | 20149288 | 60.79 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFileExtension/Faker_crypto-8 | 2627210 | 423.1 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkCusip/package-8 | 5402995 | 224.9 ns/op | 24 B/op | 2 allocs/op | +| BenchmarkCusip/Faker_math-8 | 5367218 | 221.1 ns/op | 24 B/op | 2 allocs/op | +| BenchmarkCusip/Faker_crypto-8 | 363460 | 2967 ns/op | 24 B/op | 2 allocs/op | +| BenchmarkPpnCusip/package-8 | 4436744 | 267.2 ns/op | 24 B/op | 2 allocs/op | +| BenchmarkPpnCusip/Faker_math-8 | 4465546 | 260.9 ns/op | 24 B/op | 2 allocs/op | +| BenchmarkPpnCusip/Faker_crypto-8 | 307485 | 3621 ns/op | 24 B/op | 2 allocs/op | +| BenchmarkIsin/package-8 | 1742368 | 701.4 ns/op | 533 B/op | 8 allocs/op | +| BenchmarkIsin/Faker_math-8 | 1653408 | 715.5 ns/op | 533 B/op | 8 allocs/op | +| BenchmarkIsin/Faker_crypto-8 | 330396 | 3583 ns/op | 533 B/op | 8 allocs/op | +| BenchmarkFruit/package-8 | 21421066 | 55.23 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFruit/Faker_math-8 | 22680361 | 55.68 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkFruit/Faker_crypto-8 | 2914611 | 486.7 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkVegetable/package-8 | 21113413 | 56.44 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkVegetable/Faker_math-8 | 21101716 | 60.98 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkVegetable/Faker_crypto-8 | 2811384 | 467.1 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBreakfast/package-8 | 8954784 | 127.7 ns/op | 32 B/op | 1 allocs/op | +| BenchmarkBreakfast/Faker_math-8 | 9430814 | 128.8 ns/op | 32 B/op | 1 allocs/op | +| BenchmarkBreakfast/Faker_crypto-8 | 2132481 | 496.5 ns/op | 32 B/op | 1 allocs/op | +| BenchmarkLunch/package-8 | 8934501 | 125.9 ns/op | 34 B/op | 1 allocs/op | +| BenchmarkLunch/Faker_math-8 | 8668546 | 128.9 ns/op | 34 B/op | 1 allocs/op | +| BenchmarkLunch/Faker_crypto-8 | 2216348 | 518.3 ns/op | 34 B/op | 1 allocs/op | +| BenchmarkDinner/package-8 | 9317936 | 125.2 ns/op | 36 B/op | 1 allocs/op | +| BenchmarkDinner/Faker_math-8 | 9023473 | 126.3 ns/op | 36 B/op | 1 allocs/op | +| BenchmarkDinner/Faker_crypto-8 | 2435984 | 518.9 ns/op | 36 B/op | 1 allocs/op | +| BenchmarkDrink/package-8 | 7698025 | 143.4 ns/op | 7 B/op | 2 allocs/op | +| BenchmarkDrink/Faker_math-8 | 8096294 | 139.8 ns/op | 7 B/op | 2 allocs/op | +| BenchmarkDrink/Faker_crypto-8 | 2247427 | 536.2 ns/op | 7 B/op | 2 allocs/op | +| BenchmarkSnack/package-8 | 8109601 | 149.2 ns/op | 32 B/op | 1 allocs/op | +| BenchmarkSnack/Faker_math-8 | 7993006 | 150.5 ns/op | 32 B/op | 1 allocs/op | +| BenchmarkSnack/Faker_crypto-8 | 2214736 | 535.7 ns/op | 32 B/op | 1 allocs/op | +| BenchmarkDessert/package-8 | 8295364 | 133.9 ns/op | 31 B/op | 2 allocs/op | +| BenchmarkDessert/Faker_math-8 | 8610325 | 134.1 ns/op | 31 B/op | 2 allocs/op | +| BenchmarkDessert/Faker_crypto-8 | 2205777 | 507.4 ns/op | 31 B/op | 2 allocs/op | +| BenchmarkGamertag/package-8 | 2111506 | 544.8 ns/op | 83 B/op | 5 allocs/op | +| BenchmarkGamertag/Faker_math-8 | 2203573 | 551.4 ns/op | 83 B/op | 5 allocs/op | +| BenchmarkGamertag/Faker_crypto-8 | 487366 | 2428 ns/op | 83 B/op | 5 allocs/op | +| BenchmarkDice/package-8 | 43259642 | 26.58 ns/op | 8 B/op | 1 allocs/op | +| BenchmarkDice/Faker_math-8 | 42908084 | 26.84 ns/op | 8 B/op | 1 allocs/op | +| BenchmarkDice/Faker_crypto-8 | 2953483 | 395.5 ns/op | 8 B/op | 1 allocs/op | +| BenchmarkGenerate/package-8 | 383122 | 2767 ns/op | 1139 B/op | 29 allocs/op | +| BenchmarkGenerate/Complex-8 | 135508 | 8555 ns/op | 4440 B/op | 80 allocs/op | +| BenchmarkGenerate/Faker_math-8 | 377151 | 2817 ns/op | 1139 B/op | 29 allocs/op | +| BenchmarkGenerate/Faker_crypto-8 | 152226 | 7234 ns/op | 1139 B/op | 29 allocs/op | +| BenchmarkRegex/package-8 | 628683 | 1922 ns/op | 1632 B/op | 27 allocs/op | +| BenchmarkRegex/Faker_math-8 | 591548 | 1940 ns/op | 1632 B/op | 27 allocs/op | +| BenchmarkRegex/Faker_crypto-8 | 616701 | 1934 ns/op | 1632 B/op | 27 allocs/op | +| BenchmarkRegexEmail/package-8 | 174812 | 6607 ns/op | 4084 B/op | 90 allocs/op | +| BenchmarkRegexEmail/Faker_math-8 | 174512 | 6619 ns/op | 4084 B/op | 90 allocs/op | +| BenchmarkRegexEmail/Faker_crypto-8 | 62312 | 18793 ns/op | 4083 B/op | 90 allocs/op | +| BenchmarkMap/package-8 | 318559 | 3275 ns/op | 1113 B/op | 16 allocs/op | +| BenchmarkMap/Faker_math-8 | 315990 | 3319 ns/op | 1113 B/op | 16 allocs/op | +| BenchmarkMap/Faker_crypto-8 | 46202 | 23997 ns/op | 1115 B/op | 16 allocs/op | +| BenchmarkHackerPhrase/package-8 | 155998 | 7191 ns/op | 3004 B/op | 50 allocs/op | +| BenchmarkHackerPhrase/Faker_math-8 | 154675 | 7305 ns/op | 3008 B/op | 50 allocs/op | +| BenchmarkHackerPhrase/Faker_crypto-8 | 109282 | 10268 ns/op | 3007 B/op | 50 allocs/op | +| BenchmarkHackerAbbreviation/package-8 | 21881574 | 57.57 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerAbbreviation/Faker_math-8 | 18534495 | 59.55 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerAbbreviation/Faker_crypto-8 | 2607735 | 401.6 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerAdjective/package-8 | 24286845 | 55.74 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerAdjective/Faker_math-8 | 22684101 | 55.22 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerAdjective/Faker_crypto-8 | 2953530 | 490.5 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerNoun/package-8 | 22554241 | 55.35 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerNoun/Faker_math-8 | 18360708 | 56.78 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerNoun/Faker_crypto-8 | 2823256 | 464.8 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerVerb/package-8 | 19236123 | 65.49 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerVerb/Faker_math-8 | 18090754 | 68.18 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackerVerb/Faker_crypto-8 | 2880181 | 439.2 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackeringVerb/package-8 | 19090326 | 71.74 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackeringVerb/Faker_math-8 | 19048659 | 63.31 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHackeringVerb/Faker_crypto-8 | 3020748 | 404.5 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkReplaceWithNumbers-8 | 162931 | 7098 ns/op | 32 B/op | 2 allocs/op | +| BenchmarkHipsterWord/package-8 | 24059244 | 54.69 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHipsterWord/Faker_math-8 | 21708511 | 52.98 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHipsterWord/Faker_crypto-8 | 2870858 | 396.1 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHipsterSentence/package-8 | 1278764 | 927.7 ns/op | 288 B/op | 3 allocs/op | +| BenchmarkHipsterSentence/Faker_math-8 | 1287939 | 955.0 ns/op | 288 B/op | 3 allocs/op | +| BenchmarkHipsterSentence/Faker_crypto-8 | 237703 | 4595 ns/op | 288 B/op | 3 allocs/op | +| BenchmarkHipsterParagraph/package-8 | 57895 | 18466 ns/op | 10521 B/op | 48 allocs/op | +| BenchmarkHipsterParagraph/Faker_math-8 | 61772 | 19188 ns/op | 10520 B/op | 48 allocs/op | +| BenchmarkHipsterParagraph/Faker_crypto-8 | 12978 | 91733 ns/op | 10522 B/op | 48 allocs/op | +| BenchmarkInputName/package-8 | 15728428 | 74.49 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkInputName/Faker_math-8 | 13243030 | 89.75 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkInputName/Faker_crypto-8 | 2736225 | 478.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkSvg/package-8 | 172828 | 7906 ns/op | 8871 B/op | 52 allocs/op | +| BenchmarkSvg/Faker_math-8 | 161821 | 6754 ns/op | 8875 B/op | 52 allocs/op | +| BenchmarkSvg/Faker_crypto-8 | 29023 | 40910 ns/op | 8862 B/op | 52 allocs/op | +| BenchmarkImageURL/package-8 | 11692422 | 94.34 ns/op | 38 B/op | 3 allocs/op | +| BenchmarkImageURL/Faker_math-8 | 11451087 | 91.39 ns/op | 38 B/op | 3 allocs/op | +| BenchmarkImageURL/Faker_crypto-8 | 12107578 | 92.30 ns/op | 38 B/op | 3 allocs/op | +| BenchmarkImage/package-8 | 50 | 20495942 ns/op | 2457673 B/op | 307202 allocs/op | +| BenchmarkImage/Faker_math-8 | 51 | 20349126 ns/op | 2457780 B/op | 307202 allocs/op | +| BenchmarkImage/Faker_crypto-8 | 3 | 393591549 ns/op | 2457685 B/op | 307202 allocs/op | +| BenchmarkImageJpeg/package-8 | 31 | 32857846 ns/op | 2982318 B/op | 307214 allocs/op | +| BenchmarkImageJpeg/Faker_math-8 | 34 | 31873165 ns/op | 2982479 B/op | 307214 allocs/op | +| BenchmarkImageJpeg/Faker_crypto-8 | 3 | 387670345 ns/op | 2982357 B/op | 307215 allocs/op | +| BenchmarkImagePng/package-8 | 16 | 65425256 ns/op | 5899024 B/op | 307270 allocs/op | +| BenchmarkImagePng/Faker_math-8 | 18 | 67804235 ns/op | 5899314 B/op | 307270 allocs/op | +| BenchmarkImagePng/Faker_crypto-8 | 3 | 396378778 ns/op | 5899005 B/op | 307270 allocs/op | +| BenchmarkDomainName/package-8 | 2344912 | 505.6 ns/op | 95 B/op | 5 allocs/op | +| BenchmarkDomainName/Faker_math-8 | 2265744 | 512.5 ns/op | 95 B/op | 5 allocs/op | +| BenchmarkDomainName/Faker_crypto-8 | 639775 | 1788 ns/op | 95 B/op | 5 allocs/op | +| BenchmarkDomainSuffix/package-8 | 19431498 | 59.95 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkDomainSuffix/Faker_math-8 | 20097267 | 59.04 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkDomainSuffix/Faker_crypto-8 | 2498906 | 437.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkURL/package-8 | 1000000 | 1155 ns/op | 277 B/op | 10 allocs/op | +| BenchmarkURL/Faker_math-8 | 1000000 | 1165 ns/op | 277 B/op | 10 allocs/op | +| BenchmarkURL/Faker_crypto-8 | 275793 | 4371 ns/op | 276 B/op | 10 allocs/op | +| BenchmarkHTTPMethod/package-8 | 17651594 | 59.20 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHTTPMethod/Faker_math-8 | 20081227 | 61.28 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHTTPMethod/Faker_crypto-8 | 2844322 | 460.1 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkIPv4Address/package-8 | 5215255 | 229.2 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkIPv4Address/Faker_math-8 | 4852905 | 224.9 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkIPv4Address/Faker_crypto-8 | 670951 | 1827 ns/op | 16 B/op | 1 allocs/op | +| BenchmarkIPv6Address/package-8 | 2312482 | 510.0 ns/op | 111 B/op | 8 allocs/op | +| BenchmarkIPv6Address/Faker_math-8 | 2261472 | 521.2 ns/op | 111 B/op | 8 allocs/op | +| BenchmarkIPv6Address/Faker_crypto-8 | 338601 | 3623 ns/op | 111 B/op | 8 allocs/op | +| BenchmarkMacAddress/package-8 | 2809762 | 426.2 ns/op | 24 B/op | 1 allocs/op | +| BenchmarkMacAddress/Faker_math-8 | 2863842 | 425.5 ns/op | 24 B/op | 1 allocs/op | +| BenchmarkMacAddress/Faker_crypto-8 | 376604 | 2688 ns/op | 24 B/op | 1 allocs/op | +| BenchmarkHTTPStatusCode/package-8 | 13488582 | 88.27 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHTTPStatusCode/Faker_math-8 | 14188726 | 73.23 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHTTPStatusCode/Faker_crypto-8 | 2497014 | 463.7 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHTTPStatusCodeSimple/package-8 | 17822486 | 81.54 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHTTPStatusCodeSimple/Faker_math-8 | 16282341 | 70.72 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkHTTPStatusCodeSimple/Faker_crypto-8 | 2360576 | 451.7 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLogLevel/package-8 | 19343472 | 67.40 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLogLevel/Faker_math-8 | 19445798 | 61.84 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLogLevel/Faker_crypto-8 | 2296162 | 468.5 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkUserAgent/package-8 | 1503814 | 813.9 ns/op | 297 B/op | 5 allocs/op | +| BenchmarkUserAgent/Faker_math-8 | 1462177 | 803.6 ns/op | 298 B/op | 5 allocs/op | +| BenchmarkUserAgent/Faker_crypto-8 | 181178 | 6157 ns/op | 298 B/op | 5 allocs/op | +| BenchmarkChromeUserAgent/package-8 | 1911201 | 596.8 ns/op | 184 B/op | 5 allocs/op | +| BenchmarkChromeUserAgent/Faker_math-8 | 1969712 | 598.1 ns/op | 184 B/op | 5 allocs/op | +| BenchmarkChromeUserAgent/Faker_crypto-8 | 264816 | 4433 ns/op | 184 B/op | 5 allocs/op | +| BenchmarkFirefoxUserAgent/package-8 | 1000000 | 1043 ns/op | 362 B/op | 6 allocs/op | +| BenchmarkFirefoxUserAgent/Faker_math-8 | 1000000 | 1054 ns/op | 362 B/op | 6 allocs/op | +| BenchmarkFirefoxUserAgent/Faker_crypto-8 | 166128 | 7646 ns/op | 362 B/op | 6 allocs/op | +| BenchmarkSafariUserAgent/package-8 | 1000000 | 1022 ns/op | 551 B/op | 7 allocs/op | +| BenchmarkSafariUserAgent/Faker_math-8 | 1000000 | 1017 ns/op | 551 B/op | 7 allocs/op | +| BenchmarkSafariUserAgent/Faker_crypto-8 | 146463 | 7525 ns/op | 551 B/op | 7 allocs/op | +| BenchmarkOperaUserAgent/package-8 | 1844185 | 643.8 ns/op | 212 B/op | 5 allocs/op | +| BenchmarkOperaUserAgent/Faker_math-8 | 1805168 | 654.3 ns/op | 212 B/op | 5 allocs/op | +| BenchmarkOperaUserAgent/Faker_crypto-8 | 219927 | 5257 ns/op | 212 B/op | 5 allocs/op | +| BenchmarkJSONLookup100-8 | 894 | 1194698 ns/op | 537673 B/op | 8141 allocs/op | +| BenchmarkJSONLookup1000-8 | 91 | 12099728 ns/op | 5616708 B/op | 81606 allocs/op | +| BenchmarkJSONLookup10000-8 | 8 | 128144166 ns/op | 62638763 B/op | 817708 allocs/op | +| BenchmarkJSONLookup100000-8 | 1 | 1324756016 ns/op | 616116744 B/op | 8179136 allocs/op | +| BenchmarkLanguage/package-8 | 20946056 | 68.53 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLanguage/Faker_math-8 | 16884613 | 61.06 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLanguage/Faker_crypto-8 | 2889944 | 442.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLanguageAbbreviation/package-8 | 20782443 | 53.79 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLanguageAbbreviation/Faker_math-8 | 17936367 | 56.26 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLanguageAbbreviation/Faker_crypto-8 | 2630406 | 423.8 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLanguageBCP/package-8 | 19858063 | 59.00 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLanguageBCP/Faker_math-8 | 20712447 | 60.02 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLanguageBCP/Faker_crypto-8 | 2654044 | 469.2 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkProgrammingLanguage/package-8 | 17849598 | 58.34 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkProgrammingLanguage/Faker_math-8 | 20090289 | 70.59 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkProgrammingLanguage/Faker_crypto-8 | 2628798 | 424.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkProgrammingLanguageBest/package-8 | 1000000000 | 0.4044 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkProgrammingLanguageBest/Faker_math-8 | 1000000000 | 0.2975 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkProgrammingLanguageBest/Faker_crypto-8 | 1000000000 | 0.2543 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLoremIpsumWord-8 | 22434632 | 54.96 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkLoremIpsumSentence-8 | 1000000 | 1038 ns/op | 219 B/op | 2 allocs/op | +| BenchmarkLoremIpsumParagraph-8 | 59320 | 19442 ns/op | 8479 B/op | 40 allocs/op | +| BenchmarkMinecraftOre/package-8 | 14624242 | 90.01 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftOre/Faker_math-8 | 16379578 | 86.91 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftOre/Faker_crypto-8 | 2757652 | 477.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWood/package-8 | 15815132 | 83.23 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWood/Faker_math-8 | 14872902 | 75.36 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWood/Faker_crypto-8 | 2524514 | 514.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftArmorTier/package-8 | 15296107 | 78.58 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftArmorTier/Faker_math-8 | 14341870 | 86.33 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftArmorTier/Faker_crypto-8 | 2344278 | 473.1 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftArmorPart/package-8 | 16863422 | 82.04 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftArmorPart/Faker_math-8 | 14052031 | 76.92 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftArmorPart/Faker_crypto-8 | 2770314 | 474.5 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWeapon/package-8 | 15759004 | 77.42 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWeapon/Faker_math-8 | 15945940 | 81.48 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWeapon/Faker_crypto-8 | 2254436 | 464.5 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftTool/package-8 | 15887787 | 76.39 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftTool/Faker_math-8 | 14269508 | 91.01 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftTool/Faker_crypto-8 | 2718507 | 525.7 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftDye/package-8 | 16131942 | 71.06 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftDye/Faker_math-8 | 16802478 | 73.40 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftDye/Faker_crypto-8 | 2584966 | 476.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftFood/package-8 | 14680048 | 87.15 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftFood/Faker_math-8 | 13558227 | 86.71 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftFood/Faker_crypto-8 | 2329946 | 435.6 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftAnimal/package-8 | 15871832 | 85.92 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftAnimal/Faker_math-8 | 12411510 | 83.88 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftAnimal/Faker_crypto-8 | 2528960 | 441.9 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerJob/package-8 | 13549438 | 80.41 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerJob/Faker_math-8 | 13769702 | 104.5 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerJob/Faker_crypto-8 | 2397300 | 452.2 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerStation/package-8 | 15069139 | 93.65 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerStation/Faker_math-8 | 15468883 | 82.27 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerStation/Faker_crypto-8 | 2469778 | 453.9 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerLevel/package-8 | 13468396 | 102.1 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerLevel/Faker_math-8 | 14354506 | 92.55 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftVillagerLevel/Faker_crypto-8 | 2416441 | 544.5 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobPassive/package-8 | 13299806 | 84.84 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobPassive/Faker_math-8 | 14181126 | 87.18 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobPassive/Faker_crypto-8 | 2539264 | 510.0 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobNeutral/package-8 | 11043175 | 110.7 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobNeutral/Faker_math-8 | 13059249 | 99.36 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobNeutral/Faker_crypto-8 | 2394342 | 544.6 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobHostile/package-8 | 13963809 | 95.66 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobHostile/Faker_math-8 | 15182318 | 96.90 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobHostile/Faker_crypto-8 | 2204600 | 538.3 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobBoss/package-8 | 12737437 | 89.68 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobBoss/Faker_math-8 | 13494093 | 90.65 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftMobBoss/Faker_crypto-8 | 2671172 | 461.3 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftBiome/package-8 | 13233918 | 81.47 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftBiome/Faker_math-8 | 16109408 | 85.68 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftBiome/Faker_crypto-8 | 2205704 | 499.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWeather/package-8 | 13371518 | 79.93 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWeather/Faker_math-8 | 14987182 | 80.69 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkMinecraftWeather/Faker_crypto-8 | 2373735 | 473.6 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBool/package-8 | 75772935 | 15.03 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBool/Faker_math-8 | 76893664 | 19.04 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkBool/Faker_crypto-8 | 3141634 | 376.4 ns/op | 0 B/op | 0 allocs/op | +| BenchmarkUUID/package-8 | 9382911 | 115.3 ns/op | 64 B/op | 2 allocs/op | +| BenchmarkUUID/Faker_math-8 | 9492183 | 114.1 ns/op | 64 B/op | 2 allocs/op | +| BenchmarkUUID/Faker_crypto-8 | 1000000 | 1039 ns/op | 64 B/op | 2 allocs/op | +| BenchmarkShuffleAnySlice/package-8 | 2234314 | 511.5 ns/op | 24 B/op | 1 allocs/op | \ No newline at end of file diff --git a/finance.go b/finance.go index 8d77fbe0..fefb5121 100644 --- a/finance.go +++ b/finance.go @@ -6,35 +6,21 @@ import ( "unicode" ) +// Reference Constants const cusipRunes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" const ppnRunes = "*@#" -func replaceWithCusipRunes(r *rand.Rand, str string, ppn bool) string { - if str == "" { - return str - } - bytestr := []byte(str) - for i := 0; i < len(bytestr); i++ { - if bytestr[i] == questionmark { - bytestr[i] = byte(randCusipRune(r, ppn)) - } - } - - return string(bytestr) +// CUSIP +func Cusip() string { + return cusip(globalFaker.Rand) } -func randCusipRune(r *rand.Rand, ppn bool) rune { - randRunes := cusipRunes - if ppn { - randRunes = randRunes + ppnRunes - } - return rune(cusipRunes[r.Intn(len(randRunes))]) +func (f *Faker) Cusip() string { + return cusip(f.Rand) } -func cusip(r *rand.Rand, ppn bool) string { - cusip := replaceWithCusipRunes(r, "????????", ppn) - chkDigit := CusipCheckDigit(cusip) - return cusip + chkDigit +func cusip(r *rand.Rand) string { + return buildCusip(r, false) } func CusipCheckDigit(cusip string) string { @@ -57,7 +43,6 @@ func CusipCheckDigit(cusip string) string { if c == '#' { v = 38 } - if (7 - i%2) == 0 { v = v * 2 } @@ -68,32 +53,104 @@ func CusipCheckDigit(cusip string) string { return strconv.Itoa((10 - (sum % 10)) % 10) } -func Cusip() string { - return cusip(globalFaker.Rand, false) +// PPN CUSIP (Insurance Industry Specific) +func PpnCusip() string { + return ppnCusip(globalFaker.Rand) } -func PpnCusip() string { - return cusip(globalFaker.Rand, true) +func (f *Faker) PpnCusip() string { + return ppnCusip(f.Rand) } -func (f *Faker) Cusip() string { - return cusip(f.Rand, false) +func ppnCusip(r *rand.Rand) string { + return buildCusip(r, true) } -func (f *Faker) PpnCusip() string { - return cusip(f.Rand, true) +// ISIN +func Isin() string { + return isin(globalFaker.Rand) +} + +func (f *Faker) Isin() string { + return isin(f.Rand) } -/* func isin(r *rand.Rand) string { - return "xxxxxxxxxxxx" + countryCode := CountryAbr() + nsin := cusip(r) + isinChkDig := IsinCheckDigit(countryCode + nsin) + return countryCode + nsin + isinChkDig } -func symbol(r *rand.Rand) string { - return "xxxx" +func IsinCheckDigit(isin string) string { + flattened := []int{} + for _, c := range isin { + if unicode.IsLetter(c) { + convVal := int(c) - 55 + // Each digit is added as a separate value + flattened = append(flattened, convVal/10) + flattened = append(flattened, convVal%10) + } + if unicode.IsDigit(c) { + flattened = append(flattened, int(c-'0')) + } + } + + oddSum := 0 + evenSum := 0 + + // Per digit summation of each side. + for i, d := range flattened { + if i%2 == 0 { + elem := 2 * d + if elem > 9 { + lastDigit := elem % 10 + firstDigit := elem / 10 + elem = firstDigit + lastDigit + } + evenSum += elem + } else { + oddSum += d + } + } + + return strconv.Itoa((10 - (oddSum+evenSum)%10) % 10) +} + +// Helper Functions +func buildCusip(r *rand.Rand, ppn bool) string { + cusip := replaceWithCusipRunes(r, "????????", ppn) + chkDigit := CusipCheckDigit(cusip) + return cusip + chkDigit +} + +func replaceWithCusipRunes(r *rand.Rand, str string, ppn bool) string { + if str == "" { + return str + } + bytestr := []byte(str) + for i := 0; i < len(bytestr); i++ { + if bytestr[i] == questionmark { + bytestr[i] = byte(randCusipRune(r)) + } + } + if ppn { + // PPN Identifiers occur in the 6-8th place + bytestr[5+r.Intn(3)] = byte(randPpnRune(r)) + } + + return string(bytestr) } -*/ +func randCusipRune(r *rand.Rand) rune { + return rune(cusipRunes[r.Intn(len(cusipRunes))]) +} + +func randPpnRune(r *rand.Rand) rune { + return rune(ppnRunes[r.Intn(len(ppnRunes))]) +} + +// Lookup Adds func addFinanceLookup() { AddFuncLookup("cusip", Info{ Display: "CUSIP", @@ -102,27 +159,27 @@ func addFinanceLookup() { Example: "38259P508", Output: "string", Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) { - return cusip(r, false), nil + return cusip(r), nil }, }) - /*AddFuncLookup("isin", Info{ - Display: "ISIN", + AddFuncLookup("ppncusip", Info{ + Display: "PPN CUSIP", Category: "finance", - Description: "Random ISIN", - Example: "", + Description: "Random PPN CUSIP", + Example: "38259P508", Output: "string", Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) { - return isin(r), nil + return ppnCusip(r), nil }, }) - AddFuncLookup("symbol", Info{ - Display: "symbol", + AddFuncLookup("isin", Info{ + Display: "ISIN", Category: "finance", - Description: "Random Symbol", + Description: "Random ISIN", Example: "", Output: "string", Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) { - return symbol(r), nil + return isin(r), nil }, - })*/ + }) } diff --git a/finance_test.go b/finance_test.go index 1b000eba..59630852 100644 --- a/finance_test.go +++ b/finance_test.go @@ -5,6 +5,7 @@ import ( "testing" ) +// CUSIP Tests func ExampleCusip() { Seed(11) fmt.Println(Cusip()) @@ -27,7 +28,7 @@ func TestCusip(t *testing.T) { t.Error("Valid Cusips are 9 characters in length") } if CusipCheckDigit(cusip[:8]) != string(cusip[8]) { - t.Error("Cusip has invalid checksum") + t.Error("Generated Cusip has invalid checksum") } } @@ -56,16 +57,17 @@ func BenchmarkCusip(b *testing.B) { }) } +// PPN CUSIP Tests func ExamplePpnCusip() { Seed(11) fmt.Println(PpnCusip()) - // Output: 6EHPQ4AK9 + // Output: CBHG2P*N7 } func ExampleFaker_PpnCusip() { f := New(11) fmt.Println(f.PpnCusip()) - // Output: 6EHPQ4AK9 + // Output: CBHG2P*N7 } func BenchmarkPpnCusip(b *testing.B) { @@ -91,3 +93,54 @@ func BenchmarkPpnCusip(b *testing.B) { } }) } + +// ISIN Tests +func ExampleIsin() { + Seed(11) + fmt.Println(Isin()) + // Output: CVBHG2P1NG14 +} + +func ExampleFaker_Isin() { + f := New(11) + fmt.Println(f.Isin()) + // Output: AMCBHG2P1N52 +} + +func TestIsin(t *testing.T) { + Seed(11) + isin := Isin() + if isin == "" { + t.Error("Valid ISINs are not blank") + } + if len(isin) != 12 { + t.Error("Valid ISINs are 12 characters in length") + } + if IsinCheckDigit(isin[:11]) != string(isin[11]) { + t.Error("Generated ISIN has invalid check digit") + } +} + +func BenchmarkIsin(b *testing.B) { + b.Run("package", func(b *testing.B) { + for i := 0; i < b.N; i++ { + Isin() + } + }) + + b.Run("Faker math", func(b *testing.B) { + f := New(0) + + for i := 0; i < b.N; i++ { + f.Isin() + } + }) + + b.Run("Faker crypto", func(b *testing.B) { + f := NewCrypto() + + for i := 0; i < b.N; i++ { + f.Isin() + } + }) +} From 9838042b60e0c4718590e1c4fceea97bacebc3e5 Mon Sep 17 00:00:00 2001 From: Wayne Manselle Date: Sat, 8 Apr 2023 16:46:40 -0700 Subject: [PATCH 36/41] Add details to README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 05c27fa9..07bed979 100644 --- a/README.md +++ b/README.md @@ -533,6 +533,14 @@ BitcoinAddress() string BitcoinPrivateKey() string ``` +### Finance + +```go +Cusip() string +PpnCusip() string +Isin() string +``` + ### Company ```go From d5b014645d002e213d548956c0bea5c2e4e0a7cf Mon Sep 17 00:00:00 2001 From: Wayne Manselle Date: Tue, 11 Apr 2023 11:51:46 -0700 Subject: [PATCH 37/41] Wrap up simplification, expand check digit tests --- finance.go | 135 ++++++++++++++---------------------------------- finance_test.go | 82 ++++++++++++++--------------- 2 files changed, 80 insertions(+), 137 deletions(-) diff --git a/finance.go b/finance.go index fefb5121..e38b6ce1 100644 --- a/finance.go +++ b/finance.go @@ -6,9 +6,7 @@ import ( "unicode" ) -// Reference Constants -const cusipRunes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" -const ppnRunes = "*@#" +const cusipStr = upperStr + numericStr // CUSIP func Cusip() string { @@ -20,9 +18,34 @@ func (f *Faker) Cusip() string { } func cusip(r *rand.Rand) string { - return buildCusip(r, false) + cusipBytes := make([]byte, 8) + for i := 0; i < len(cusipBytes); i++ { + cusipBytes[i] = byte(cusipStr[r.Intn(len(cusipStr))]) + } + + baseCusip := string(cusipBytes) + + chkDigit := CusipCheckDigit(baseCusip) + return baseCusip + chkDigit +} + +// ISIN +func Isin() string { + return isin(globalFaker.Rand) +} + +func (f *Faker) Isin() string { + return isin(f.Rand) +} + +func isin(r *rand.Rand) string { + countryCode := CountryAbr() + nsin := cusip(r) + isinChkDig := IsinCheckDigit(countryCode + nsin) + return countryCode + nsin + isinChkDig } +// Functions to generate Checksum Digits func CusipCheckDigit(cusip string) string { sum := 0 @@ -32,18 +55,11 @@ func CusipCheckDigit(cusip string) string { v = int(c - '0') } if unicode.IsLetter(c) { + //0-indexed ordinal position of Letter + 10 v = int(c-'A') + 10 } - if c == '*' { - v = 36 - } - if c == '@' { - v = 37 - } - if c == '#' { - v = 38 - } - if (7 - i%2) == 0 { + if i%2 != 0 { + // Multiply odd digits by two v = v * 2 } @@ -53,60 +69,30 @@ func CusipCheckDigit(cusip string) string { return strconv.Itoa((10 - (sum % 10)) % 10) } -// PPN CUSIP (Insurance Industry Specific) -func PpnCusip() string { - return ppnCusip(globalFaker.Rand) -} - -func (f *Faker) PpnCusip() string { - return ppnCusip(f.Rand) -} - -func ppnCusip(r *rand.Rand) string { - return buildCusip(r, true) -} - -// ISIN -func Isin() string { - return isin(globalFaker.Rand) -} - -func (f *Faker) Isin() string { - return isin(f.Rand) -} - -func isin(r *rand.Rand) string { - countryCode := CountryAbr() - nsin := cusip(r) - isinChkDig := IsinCheckDigit(countryCode + nsin) - return countryCode + nsin + isinChkDig -} - func IsinCheckDigit(isin string) string { - flattened := []int{} + isinDigits := make([]int, 0) for _, c := range isin { if unicode.IsLetter(c) { - convVal := int(c) - 55 + letterVal := int(c) - 55 // Each digit is added as a separate value - flattened = append(flattened, convVal/10) - flattened = append(flattened, convVal%10) + isinDigits = append(isinDigits, letterVal/10) + isinDigits = append(isinDigits, letterVal%10) } if unicode.IsDigit(c) { - flattened = append(flattened, int(c-'0')) + isinDigits = append(isinDigits, int(c-'0')) } } oddSum := 0 evenSum := 0 - // Per digit summation of each side. - for i, d := range flattened { + // Take the per digit sum of the digitized ISIN, doubling even indexed digits + for i, d := range isinDigits { if i%2 == 0 { elem := 2 * d if elem > 9 { - lastDigit := elem % 10 - firstDigit := elem / 10 - elem = firstDigit + lastDigit + // If the element now has two digits, sum those digits + elem = (elem % 10) + (elem / 10) } evenSum += elem } else { @@ -117,39 +103,6 @@ func IsinCheckDigit(isin string) string { return strconv.Itoa((10 - (oddSum+evenSum)%10) % 10) } -// Helper Functions -func buildCusip(r *rand.Rand, ppn bool) string { - cusip := replaceWithCusipRunes(r, "????????", ppn) - chkDigit := CusipCheckDigit(cusip) - return cusip + chkDigit -} - -func replaceWithCusipRunes(r *rand.Rand, str string, ppn bool) string { - if str == "" { - return str - } - bytestr := []byte(str) - for i := 0; i < len(bytestr); i++ { - if bytestr[i] == questionmark { - bytestr[i] = byte(randCusipRune(r)) - } - } - if ppn { - // PPN Identifiers occur in the 6-8th place - bytestr[5+r.Intn(3)] = byte(randPpnRune(r)) - } - - return string(bytestr) -} - -func randCusipRune(r *rand.Rand) rune { - return rune(cusipRunes[r.Intn(len(cusipRunes))]) -} - -func randPpnRune(r *rand.Rand) rune { - return rune(ppnRunes[r.Intn(len(ppnRunes))]) -} - // Lookup Adds func addFinanceLookup() { AddFuncLookup("cusip", Info{ @@ -162,16 +115,6 @@ func addFinanceLookup() { return cusip(r), nil }, }) - AddFuncLookup("ppncusip", Info{ - Display: "PPN CUSIP", - Category: "finance", - Description: "Random PPN CUSIP", - Example: "38259P508", - Output: "string", - Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) { - return ppnCusip(r), nil - }, - }) AddFuncLookup("isin", Info{ Display: "ISIN", Category: "finance", diff --git a/finance_test.go b/finance_test.go index 59630852..25f8cd64 100644 --- a/finance_test.go +++ b/finance_test.go @@ -9,13 +9,13 @@ import ( func ExampleCusip() { Seed(11) fmt.Println(Cusip()) - // Output: CBHG2P1N5 + // Output: MLRQCZBX0 } func ExampleFaker_Cusip() { f := New(11) fmt.Println(f.Cusip()) - // Output: CBHG2P1N5 + // Output: MLRQCZBX0 } func TestCusip(t *testing.T) { @@ -30,7 +30,25 @@ func TestCusip(t *testing.T) { if CusipCheckDigit(cusip[:8]) != string(cusip[8]) { t.Error("Generated Cusip has invalid checksum") } +} + +func TestCusipCheckDigit(t *testing.T) { + type test struct { + base string + want string + } + tests := []test{ + {base: "03783310", want: "0"}, + {base: "17275R10", want: "2"}, + {base: "38259P50", want: "8"}, + } + for _, tc := range tests { + digit := CusipCheckDigit(tc.base) + if digit != tc.want { + t.Errorf("Expected check digit of %s, got %s", tc.want, digit) + } + } } func BenchmarkCusip(b *testing.B) { @@ -57,54 +75,17 @@ func BenchmarkCusip(b *testing.B) { }) } -// PPN CUSIP Tests -func ExamplePpnCusip() { - Seed(11) - fmt.Println(PpnCusip()) - // Output: CBHG2P*N7 -} - -func ExampleFaker_PpnCusip() { - f := New(11) - fmt.Println(f.PpnCusip()) - // Output: CBHG2P*N7 -} - -func BenchmarkPpnCusip(b *testing.B) { - b.Run("package", func(b *testing.B) { - for i := 0; i < b.N; i++ { - PpnCusip() - } - }) - - b.Run("Faker math", func(b *testing.B) { - f := New(0) - - for i := 0; i < b.N; i++ { - f.PpnCusip() - } - }) - - b.Run("Faker crypto", func(b *testing.B) { - f := NewCrypto() - - for i := 0; i < b.N; i++ { - f.PpnCusip() - } - }) -} - // ISIN Tests func ExampleIsin() { Seed(11) fmt.Println(Isin()) - // Output: CVBHG2P1NG14 + // Output: CVLRQCZBXQ97 } func ExampleFaker_Isin() { f := New(11) fmt.Println(f.Isin()) - // Output: AMCBHG2P1N52 + // Output: AMMLRQCZBX03 } func TestIsin(t *testing.T) { @@ -121,6 +102,25 @@ func TestIsin(t *testing.T) { } } +func TestIsinCheckDigit(t *testing.T) { + type test struct { + base string + want string + } + + tests := []test{ + {base: "US037833100", want: "5"}, + {base: "GB000263494", want: "6"}, + {base: "US000402625", want: "0"}, + } + for _, tc := range tests { + digit := IsinCheckDigit(tc.base) + if digit != tc.want { + t.Errorf("Expected check digit of %s, got %s", tc.want, digit) + } + } +} + func BenchmarkIsin(b *testing.B) { b.Run("package", func(b *testing.B) { for i := 0; i < b.N; i++ { From e01921f2b1876cbfac7d3873c11ba86cd549cad0 Mon Sep 17 00:00:00 2001 From: Wayne Manselle Date: Tue, 11 Apr 2023 11:56:50 -0700 Subject: [PATCH 38/41] Remove references to PPNCusip --- BENCHMARKS.md | 3 --- README.md | 1 - 2 files changed, 4 deletions(-) diff --git a/BENCHMARKS.md b/BENCHMARKS.md index 38f1f3e5..2568ecf0 100644 --- a/BENCHMARKS.md +++ b/BENCHMARKS.md @@ -236,9 +236,6 @@ Table generated with tablesgenerator.com/markdown_tables | BenchmarkCusip/package-8 | 5402995 | 224.9 ns/op | 24 B/op | 2 allocs/op | | BenchmarkCusip/Faker_math-8 | 5367218 | 221.1 ns/op | 24 B/op | 2 allocs/op | | BenchmarkCusip/Faker_crypto-8 | 363460 | 2967 ns/op | 24 B/op | 2 allocs/op | -| BenchmarkPpnCusip/package-8 | 4436744 | 267.2 ns/op | 24 B/op | 2 allocs/op | -| BenchmarkPpnCusip/Faker_math-8 | 4465546 | 260.9 ns/op | 24 B/op | 2 allocs/op | -| BenchmarkPpnCusip/Faker_crypto-8 | 307485 | 3621 ns/op | 24 B/op | 2 allocs/op | | BenchmarkIsin/package-8 | 1742368 | 701.4 ns/op | 533 B/op | 8 allocs/op | | BenchmarkIsin/Faker_math-8 | 1653408 | 715.5 ns/op | 533 B/op | 8 allocs/op | | BenchmarkIsin/Faker_crypto-8 | 330396 | 3583 ns/op | 533 B/op | 8 allocs/op | diff --git a/README.md b/README.md index 07bed979..5e2416df 100644 --- a/README.md +++ b/README.md @@ -537,7 +537,6 @@ BitcoinPrivateKey() string ```go Cusip() string -PpnCusip() string Isin() string ``` From 5188fe1257cccf3b2ea43c08f1e4e488677d0073 Mon Sep 17 00:00:00 2001 From: brianvoe Date: Fri, 14 Apr 2023 16:41:33 -0500 Subject: [PATCH 39/41] json - updated test example name --- json_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_test.go b/json_test.go index c8b6a848..aecf8c3b 100644 --- a/json_test.go +++ b/json_test.go @@ -434,7 +434,7 @@ func TestJSONNumberWithTag(t *testing.T) { } } -func ExampleJSONNumberWithTag() { +func ExampleJSON_numberWithTag() { Seed(10) type J struct { From 9a6424b54e81d4207b3d4cfb6461dc8887e6664d Mon Sep 17 00:00:00 2001 From: brianvoe Date: Fri, 14 Apr 2023 16:41:54 -0500 Subject: [PATCH 40/41] finance - make private some functions --- finance.go | 12 ++++++------ finance_test.go | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/finance.go b/finance.go index e38b6ce1..6c4fd4ff 100644 --- a/finance.go +++ b/finance.go @@ -25,7 +25,7 @@ func cusip(r *rand.Rand) string { baseCusip := string(cusipBytes) - chkDigit := CusipCheckDigit(baseCusip) + chkDigit := cusipChecksumDigit(baseCusip) return baseCusip + chkDigit } @@ -41,13 +41,12 @@ func (f *Faker) Isin() string { func isin(r *rand.Rand) string { countryCode := CountryAbr() nsin := cusip(r) - isinChkDig := IsinCheckDigit(countryCode + nsin) + isinChkDig := isinChecksumDigit(countryCode + nsin) return countryCode + nsin + isinChkDig } -// Functions to generate Checksum Digits -func CusipCheckDigit(cusip string) string { - +// cusipChecksumDigit returns the checksum digit for a CUSIP +func cusipChecksumDigit(cusip string) string { sum := 0 for i, c := range cusip { v := 0 @@ -69,7 +68,8 @@ func CusipCheckDigit(cusip string) string { return strconv.Itoa((10 - (sum % 10)) % 10) } -func IsinCheckDigit(isin string) string { +// isinChecksumDigit returns the checksum digit for an ISIN +func isinChecksumDigit(isin string) string { isinDigits := make([]int, 0) for _, c := range isin { if unicode.IsLetter(c) { diff --git a/finance_test.go b/finance_test.go index 25f8cd64..51a270ee 100644 --- a/finance_test.go +++ b/finance_test.go @@ -27,7 +27,7 @@ func TestCusip(t *testing.T) { if len(cusip) != 9 { t.Error("Valid Cusips are 9 characters in length") } - if CusipCheckDigit(cusip[:8]) != string(cusip[8]) { + if cusipChecksumDigit(cusip[:8]) != string(cusip[8]) { t.Error("Generated Cusip has invalid checksum") } } @@ -44,7 +44,7 @@ func TestCusipCheckDigit(t *testing.T) { {base: "38259P50", want: "8"}, } for _, tc := range tests { - digit := CusipCheckDigit(tc.base) + digit := cusipChecksumDigit(tc.base) if digit != tc.want { t.Errorf("Expected check digit of %s, got %s", tc.want, digit) } @@ -97,7 +97,7 @@ func TestIsin(t *testing.T) { if len(isin) != 12 { t.Error("Valid ISINs are 12 characters in length") } - if IsinCheckDigit(isin[:11]) != string(isin[11]) { + if isinChecksumDigit(isin[:11]) != string(isin[11]) { t.Error("Generated ISIN has invalid check digit") } } @@ -114,7 +114,7 @@ func TestIsinCheckDigit(t *testing.T) { {base: "US000402625", want: "0"}, } for _, tc := range tests { - digit := IsinCheckDigit(tc.base) + digit := isinChecksumDigit(tc.base) if digit != tc.want { t.Errorf("Expected check digit of %s, got %s", tc.want, digit) } From 272cff490a850d46538827455317ecbb7e1518da Mon Sep 17 00:00:00 2001 From: brianvoe Date: Fri, 14 Apr 2023 16:42:10 -0500 Subject: [PATCH 41/41] readme - updated fakable usage --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6892a7cf..fe179440 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,14 @@ in order to control the generation. For example, this is useful when it is not possible to modify the struct that you want to fake by adding struct tags to a field but you still need to be able to control the generation process. ```go +// Custom string that you want to generate your own data for +// or just return a static value +type CustomString string + +func (c *CustomString) Fake(faker *gofakeit.Faker) interface{} { + return CustomString("my custom string") +} + // Imagine a CustomTime type that is needed to support a custom JSON Marshaler type CustomTime time.Time @@ -190,14 +198,15 @@ func (c *CustomTime) MarshalJSON() ([]byte, error) { // This is the struct that we cannot modify to add struct tags type NotModifiable struct { Token string + Value CustomString Creation *CustomTime } var f NotModifiable gofakeit.Struct(&f) fmt.Printf("%s", f.Token) // yvqqdH +fmt.Printf("%s", f.Value) // my custom string fmt.Printf("%s", f.Creation) // 2023-04-02 23:00:00 +0000 UTC m=+0.000000001 - ``` ## Custom Functions