From f70bf73e0dfa574e8f2d48e4e2883e5d40564fc1 Mon Sep 17 00:00:00 2001 From: hohmannr Date: Mon, 24 Jul 2023 11:53:56 +0200 Subject: [PATCH 1/6] feat: adds the ability to change the default tag name (#27) (#28) * feat: adds a changeable tag name (#27) Signed-off-by: hohmannr * chore: refactors ErrTagNameInvalid to ErrFieldTagIdentifierInvalid --------- Signed-off-by: hohmannr --- example_with_custom_tags_test.go | 145 +++++++++++++++++++++++++++++++ faker.go | 5 +- faker_test.go | 125 ++++++++++++++++---------- pkg/errors/generic.go | 23 ++--- pkg/options/options.go | 14 +++ 5 files changed, 253 insertions(+), 59 deletions(-) create mode 100644 example_with_custom_tags_test.go diff --git a/example_with_custom_tags_test.go b/example_with_custom_tags_test.go new file mode 100644 index 0000000..0ead2db --- /dev/null +++ b/example_with_custom_tags_test.go @@ -0,0 +1,145 @@ +package faker_test + +import ( + "fmt" + + "github.com/go-faker/faker/v4" + "github.com/go-faker/faker/v4/pkg/options" +) + +// SomeStructWithTags ... +type SomeStructWithACustomTagName struct { + Latitude float32 `custom:"lat"` + Longitude float32 `custom:"long"` + RealAddress faker.RealAddress `custom:"real_address"` + CreditCardNumber string `custom:"cc_number"` + CreditCardType string `custom:"cc_type"` + Email string `custom:"email"` + DomainName string `custom:"domain_name"` + IPV4 string `custom:"ipv4"` + IPV6 string `custom:"ipv6"` + Password string `custom:"password"` + Jwt string `custom:"jwt"` + PhoneNumber string `custom:"phone_number"` + MacAddress string `custom:"mac_address"` + URL string `custom:"url"` + UserName string `custom:"username"` + TollFreeNumber string `custom:"toll_free_number"` + E164PhoneNumber string `custom:"e_164_phone_number"` + TitleMale string `custom:"title_male"` + TitleFemale string `custom:"title_female"` + FirstName string `custom:"first_name"` + FirstNameMale string `custom:"first_name_male"` + FirstNameFemale string `custom:"first_name_female"` + LastName string `custom:"last_name"` + Name string `custom:"name"` + UnixTime int64 `custom:"unix_time"` + Date string `custom:"date"` + Time string `custom:"time"` + MonthName string `custom:"month_name"` + Year string `custom:"year"` + DayOfWeek string `custom:"day_of_week"` + DayOfMonth string `custom:"day_of_month"` + Timestamp string `custom:"timestamp"` + Century string `custom:"century"` + TimeZone string `custom:"timezone"` + TimePeriod string `custom:"time_period"` + Word string `custom:"word"` + Sentence string `custom:"sentence"` + Paragraph string `custom:"paragraph"` + Currency string `custom:"currency"` + Amount float64 `custom:"amount"` + AmountWithCurrency string `custom:"amount_with_currency"` + UUIDHypenated string `custom:"uuid_hyphenated"` + UUID string `custom:"uuid_digit"` + Skip string `custom:"-"` + PaymentMethod string `custom:"oneof: cc, paypal, check, money order"` // oneof will randomly pick one of the comma-separated values supplied in the tag + AccountID int `custom:"oneof: 15, 27, 61"` // use commas to separate the values for now. Future support for other separator characters may be added + Price32 float32 `custom:"oneof: 4.95, 9.99, 31997.97"` + Price64 float64 `custom:"oneof: 47463.9463525, 993747.95662529, 11131997.978767990"` + NumS64 int64 `custom:"oneof: 1, 2"` + NumS32 int32 `custom:"oneof: -3, 4"` + NumS16 int16 `custom:"oneof: -5, 6"` + NumS8 int8 `custom:"oneof: 7, -8"` + NumU64 uint64 `custom:"oneof: 9, 10"` + NumU32 uint32 `custom:"oneof: 11, 12"` + NumU16 uint16 `custom:"oneof: 13, 14"` + NumU8 uint8 `custom:"oneof: 15, 16"` + NumU uint `custom:"oneof: 17, 18"` + PtrNumU *uint `custom:"oneof: 19, 20"` +} + +func Example_withTagsAndCustomTagName() { + + a := SomeStructWithTags{} + // just set the custom tag name option + err := faker.FakeData(&a, options.WithTagName("custom")) + if err != nil { + fmt.Println(err) + } + fmt.Printf("%+v", a) + /* + Result: + { + Latitude: 81.12195 + Longitude: -84.38158 + RealAddress: {Address:107 Guaymas Place City:Davis State:CA PostalCode:95616 Coordinates:{Latitude:38.567048 Longitude:-121.746046}} + CreditCardType: American Express + CreditCardNumber: 373641309057568 + Email: mJBJtbv@OSAaT.ru + DomainName: FWZcaRE.ru, + IPV4: 99.23.42.63 + IPV6: 975c:fb2c:2133:fbdd:beda:282e:1e0a:ec7d + Password: dfJdyHGuVkHBgnHLQQgpINApynzexnRpgIKBpiIjpTPOmNyMFb + Jwt: HDMNSOKhEIYkPIuHcVjfCtHlKkaqLGrUEqjKVkgR.HDMNSOKhEIYkPIuHcVjfCtHlKkaqLGrUEqjKVkgR.HDMNSOKhEIYkPIuHcVjfCtHlKkaqLGrUEqjKVkgR + PhoneNumber: 792-153-4861 + MacAddress: cd:65:e1:d4:76:c6 + URL: https://www.oEuqqAY.org/QgqfOhd + UserName: lVxELHS + TollFreeNumber: (777) 831-964572 + E164PhoneNumber: +724891571063 + TitleMale: Mr. + TitleFemale: Queen + FirstName: Whitney + FirstNameMale: Kenny + FirstNameFemale: Jana + LastName: Rohan + Name: Miss Casandra Kiehn + UnixTime: 1197930901 + Date: 1982-02-27 + Time: 03:10:25 + MonthName: February + Year: 1996 + DayOfWeek: Sunday + DayOfMonth: 20 + Timestamp: 1973-06-21 14:50:46 + Century: IV + TimeZone: Canada/Eastern + TimePeriod: AM + Word: nesciunt + Sentence: Consequatur perferendis aut sit voluptatem accusantium. + Paragraph: Aut consequatur sit perferendis accusantium voluptatem. Accusantium perferendis consequatur voluptatem sit aut. Aut sit accusantium consequatur voluptatem perferendis. Perferendis voluptatem aut accusantium consequatur sit. + Currency: IRR, + Amount: 88.990000, + AmountWithCurrency: XBB 49257.100000, + UUIDHypenated: 8f8e4463-9560-4a38-9b0c-ef24481e4e27, + UUID: 90ea6479fd0e4940af741f0a87596b73, + PaymentMethod: paypal, + AccountID: 61, + Price32: 4.95, + Price64: 993747.95662529 + NumS64: 1 + NumS32: -3 + NumS16: 5 + NumS8: -8 + NumU64: 9 + NumU32: 11 + NumU16: 13 + NumU8: 15 + NumU: 17 + PtrNumU: 19 + Skip: + } + */ + +} \ No newline at end of file diff --git a/faker.go b/faker.go index fc694d3..fe5c1d3 100644 --- a/faker.go +++ b/faker.go @@ -31,7 +31,6 @@ const ( letterIdxMask = 1< Date: Wed, 20 Sep 2023 17:33:43 +0800 Subject: [PATCH 2/6] fix: unexpected logic issue with the ignore interface option (#36) * chore: fix the ignore interface * chore: apply go format * chore: fix linter issue * chore: fix the gh action --- .github/workflows/go.yml | 4 +- .golangci.yaml | 10 ++- faker.go | 167 +++++++++++++++++++++-------------- faker_test.go | 46 +++++++++- go.mod | 2 +- go.sum | 1 - misc/makefile/tools.Makefile | 2 +- pkg/options/options.go | 2 +- random_source_test.go | 2 +- 9 files changed, 156 insertions(+), 80 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 0f80446..4d77c25 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -15,7 +15,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.17 + go-version: 1.18 - name: Linter run: make lint-prepare && make lint @@ -31,7 +31,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.17 + go-version: 1.18 - name: Test run: go test -v ./... -gcflags=all=-l -coverprofile=coverage.txt -covermode=atomic -race diff --git a/.golangci.yaml b/.golangci.yaml index 496d8f3..2ffa708 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -11,7 +11,7 @@ linters-settings: golint: min-confidence: 0.8 gocyclo: - min-complexity: 60 + min-complexity: 70 maligned: suggest-new: true dupl: @@ -27,7 +27,7 @@ linters: # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint disable-all: true enable: - - deadcode + # - deadcode - errcheck - goconst - gocyclo @@ -37,12 +37,12 @@ linters: - ineffassign - misspell - staticcheck - - structcheck + # - structcheck - typecheck - unconvert - unparam - unused - - varcheck + # - varcheck issues: exclude-rules: @@ -52,6 +52,8 @@ issues: - path: datetime.go linters: - misspell + - path: . + text: "parameter 'v' seems to be unused" run: timeout: 5m go: "1.17" diff --git a/faker.go b/faker.go index fe5c1d3..d7a2a18 100644 --- a/faker.go +++ b/faker.go @@ -311,55 +311,60 @@ func FakeData(a interface{}, opt ...options.OptionFunc) error { if err != nil { return err } - if finalValue.Kind() == reflect.Invalid { - return nil + + if rval.Elem().CanSet() && rval.Elem(). + CanConvert(reflectType.Elem()) { + rval.Elem().Set(finalValue.Elem(). + Convert(reflectType.Elem())) } - rval.Elem().Set(finalValue.Elem().Convert(reflectType.Elem())) return nil } // AddProvider extend faker with tag to generate fake data with specified custom algorithm // Example: -// type Gondoruwo struct { -// Name string -// Locatadata int -// } // -// type Sample struct { -// ID int64 `faker:"customIdFaker"` -// Gondoruwo Gondoruwo `faker:"gondoruwo"` -// Danger string `faker:"danger"` -// } +// type Gondoruwo struct { +// Name string +// Locatadata int +// } // -// func CustomGenerator() { -// // explicit -// faker.AddProvider("customIdFaker", func(v reflect.Value) (interface{}, error) { -// return int64(43), nil -// }) -// // functional -// faker.AddProvider("danger", func() faker.TaggedFunction { -// return func(v reflect.Value) (interface{}, error) { -// return "danger-ranger", nil -// } -// }()) -// faker.AddProvider("gondoruwo", func(v reflect.Value) (interface{}, error) { -// obj := Gondoruwo{ -// Name: "Power", -// Locatadata: 324, -// } -// return obj, nil -// }) -// } +// type Sample struct { +// ID int64 `faker:"customIdFaker"` +// Gondoruwo Gondoruwo `faker:"gondoruwo"` +// Danger string `faker:"danger"` +// } // -// func main() { -// CustomGenerator() -// var sample Sample -// faker.FakeData(&sample) -// fmt.Printf("%+v", sample) -// } +// func CustomGenerator() { +// // explicit +// faker.AddProvider("customIdFaker", func(v reflect.Value) (interface{}, error) { +// return int64(43), nil +// }) +// // functional +// faker.AddProvider("danger", func() faker.TaggedFunction { +// return func(v reflect.Value) (interface{}, error) { +// return "danger-ranger", nil +// } +// }()) +// faker.AddProvider("gondoruwo", func(v reflect.Value) (interface{}, error) { +// obj := Gondoruwo{ +// Name: "Power", +// Locatadata: 324, +// } +// return obj, nil +// }) +// } +// +// func main() { +// CustomGenerator() +// var sample Sample +// faker.FakeData(&sample) +// fmt.Printf("%+v", sample) +// } // // Will print -// {ID:43 Gondoruwo:{Name:Power Locatadata:324} Danger:danger-ranger} +// +// {ID:43 Gondoruwo:{Name:Power Locatadata:324} Danger:danger-ranger} +// // Notes: when using a custom provider make sure to return the same type as the field func AddProvider(tag string, provider interfaces.TaggedFunction) error { if _, ok := mapperTag.Load(tag); ok { @@ -380,8 +385,8 @@ func RemoveProvider(tag string) error { return nil } -func getFakedValue(a interface{}, opts *options.Options) (reflect.Value, error) { - t := reflect.TypeOf(a) +func getFakedValue(item interface{}, opts *options.Options) (reflect.Value, error) { + t := reflect.TypeOf(item) if t == nil { if opts.IgnoreInterface { return reflect.ValueOf(nil), nil @@ -396,24 +401,28 @@ func getFakedValue(a interface{}, opts *options.Options) (reflect.Value, error) opts.MaxDepthOption.ForgetType(t) }() k := t.Kind() - switch k { case reflect.Ptr: v := reflect.New(t.Elem()) var val reflect.Value var err error - if a != reflect.Zero(reflect.TypeOf(a)).Interface() { - val, err = getFakedValue(reflect.ValueOf(a).Elem().Interface(), opts) + if item != reflect.Zero(reflect.TypeOf(item)).Interface() { + val, err = getFakedValue(reflect.ValueOf(item).Elem().Interface(), opts) + } else { val, err = getFakedValue(v.Elem().Interface(), opts) } if err != nil { return reflect.Value{}, err } - if val.Kind() == reflect.Invalid { - return val, nil + + if reflect.ValueOf(val).IsZero() { + return v, nil + } + + if v.Elem().CanSet() && v.Elem().CanConvert(t.Elem()) { + v.Elem().Set(val.Convert(t.Elem())) } - v.Elem().Set(val.Convert(t.Elem())) return v, nil case reflect.Struct: switch t.String() { @@ -421,7 +430,7 @@ func getFakedValue(a interface{}, opts *options.Options) (reflect.Value, error) ft := time.Now().Add(time.Duration(rand.Int63())) return reflect.ValueOf(ft), nil default: - originalDataVal := reflect.ValueOf(a) + originalDataVal := reflect.ValueOf(item) v := reflect.New(t).Elem() retry := 0 // error if cannot generate unique value after maxRetry tries for i := 0; i < v.NumField(); i++ { @@ -445,7 +454,7 @@ func getFakedValue(a interface{}, opts *options.Options) (reflect.Value, error) tags := decodeTags(t, i, opts.TagName) switch { case tags.keepOriginal: - zero, err := isZero(reflect.ValueOf(a).Field(i)) + zero, err := isZero(reflect.ValueOf(item).Field(i)) if err != nil { return reflect.Value{}, err } @@ -456,20 +465,24 @@ func getFakedValue(a interface{}, opts *options.Options) (reflect.Value, error) } continue } - v.Field(i).Set(reflect.ValueOf(a).Field(i)) + v.Field(i).Set(reflect.ValueOf(item).Field(i)) case tags.fieldType == "": val, err := getFakedValue(v.Field(i).Interface(), opts) if err != nil { return reflect.Value{}, err } - if val.Kind() != reflect.Invalid { - val = val.Convert(v.Field(i).Type()) - v.Field(i).Set(val) + + if v.Field(i).CanSet() { + if !reflect.ValueOf(val).IsZero() && val.CanConvert(v.Field(i).Type()) { + val = val.Convert(v.Field(i).Type()) + v.Field(i).Set(val) + } + } case tags.fieldType == SKIP: - item := originalDataVal.Field(i).Interface() - if v.CanSet() && item != nil { - v.Field(i).Set(reflect.ValueOf(item)) + data := originalDataVal.Field(i).Interface() + if v.CanSet() && data != nil { + v.Field(i).Set(reflect.ValueOf(data)) } default: err := setDataWithTag(v.Field(i).Addr(), tags.fieldType, *opts) @@ -479,9 +492,8 @@ func getFakedValue(a interface{}, opts *options.Options) (reflect.Value, error) } if tags.unique { - if retry >= maxRetry { - return reflect.Value{}, fmt.Errorf(fakerErrors.ErrUniqueFailure, reflect.TypeOf(a).Field(i).Name) + return reflect.Value{}, fmt.Errorf(fakerErrors.ErrUniqueFailure, reflect.TypeOf(item).Field(i).Name) } value := v.Field(i).Interface() @@ -504,18 +516,26 @@ func getFakedValue(a interface{}, opts *options.Options) (reflect.Value, error) res, err := randomString(opts.RandomStringLength, *opts) return reflect.ValueOf(res), err case reflect.Slice: + length := randomSliceAndMapSize(*opts) if opts.SetSliceMapNilIfLenZero && length == 0 { return reflect.Zero(t), nil } v := reflect.MakeSlice(t, length, length) - for i := 0; i < v.Len(); i++ { + for i := 0; i < length; i++ { val, err := getFakedValue(v.Index(i).Interface(), opts) if err != nil { return reflect.Value{}, err } - val = val.Convert(v.Index(i).Type()) - v.Index(i).Set(val) + // if the value generated is NIL/Zero + // it will kept it as nil + if reflect.ValueOf(val).IsZero() { + continue + } + if val.CanConvert(v.Index(i).Type()) { + val = val.Convert(v.Index(i).Type()) + v.Index(i).Set(val) + } } return v, nil case reflect.Array: @@ -525,7 +545,12 @@ func getFakedValue(a interface{}, opts *options.Options) (reflect.Value, error) if err != nil { return reflect.Value{}, err } - val = val.Convert(v.Index(i).Type()) + if reflect.ValueOf(val).IsZero() { + continue + } + if val.CanConvert(v.Index(i).Type()) { + val = val.Convert(v.Index(i).Type()) + } v.Index(i).Set(val) } return v, nil @@ -580,6 +605,13 @@ func getFakedValue(a interface{}, opts *options.Options) (reflect.Value, error) if err != nil { return reflect.Value{}, err } + + keyIsZero := reflect.ValueOf(key).IsZero() + valIsZero := reflect.ValueOf(val).IsZero() + + if keyIsZero || valIsZero { + continue + } key = key.Convert(t.Key()) val = val.Convert(v.Type().Elem()) v.SetMapIndex(key, val) @@ -909,11 +941,13 @@ func userDefinedNumber(v reflect.Value, tag string) error { return fmt.Errorf(fakerErrors.ErrTagNotSupported, tag) } - v.Set(reflect.ValueOf(res).Convert(v.Type())) + if v.CanSet() && v.CanConvert(v.Type()) { + v.Set(reflect.ValueOf(res).Convert(v.Type())) + } return nil } -//extractSliceLengthFromTag checks if the sliceLength tag 'slice_len' is set, if so, returns its value, else return a random length +// extractSliceLengthFromTag checks if the sliceLength tag 'slice_len' is set, if so, returns its value, else return a random length func extractSliceLengthFromTag(tag string, opt options.Options) (int, error) { if strings.Contains(tag, SliceLength) { lenParts := strings.SplitN(findSliceLenReg.FindString(tag), Equals, -1) @@ -1289,9 +1323,10 @@ func randomStringNumber(n int) string { // RandomInt Get three parameters , only first mandatory and the rest are optional // (minimum_int, maximum_int, count) -// If only set one parameter : An integer greater than minimum_int will be returned -// If only set two parameters : All integers between minimum_int and maximum_int will be returned, in a random order. -// If three parameters: `count` integers between minimum_int and maximum_int will be returned. +// +// If only set one parameter : An integer greater than minimum_int will be returned +// If only set two parameters : All integers between minimum_int and maximum_int will be returned, in a random order. +// If three parameters: `count` integers between minimum_int and maximum_int will be returned. func RandomInt(parameters ...int) (p []int, err error) { switch len(parameters) { case 1: diff --git a/faker_test.go b/faker_test.go index 23d5474..3e950a4 100644 --- a/faker_test.go +++ b/faker_test.go @@ -2477,7 +2477,7 @@ func TestFakeData_RecursiveType(t *testing.T) { } } -func TestFakeDate_ConcurrentSafe(t *testing.T) { +func TestFakeDate_ConcurrentSafe(_ *testing.T) { var wg sync.WaitGroup wg.Add(1000) fmt.Println("Running for loop…") @@ -2492,7 +2492,7 @@ func TestFakeDate_ConcurrentSafe(t *testing.T) { wg.Wait() } -type StructWithInterface struct { +type StructWithInterfaceContainsMethod struct { I Interface } @@ -2501,9 +2501,49 @@ type Interface interface { } func TestNonEmptyInterface(t *testing.T) { - var s StructWithInterface + var s StructWithInterfaceContainsMethod + + if err := FakeData(&s, options.WithIgnoreInterface(true)); err != nil { + t.Errorf("%+v", err) + t.FailNow() + } +} + +type InterfaceStruct struct { + A string + B map[string]any + C map[string]interface{} + D Interface + E interface{} + F map[interface{}]any + G map[any]any + H map[any]interface{} + I []interface{} + J [2]interface{} + K [][]interface{} + L [][2]interface{} + M [3][2]interface{} + N map[any][]any + O []int +} + +func TestWithInterfaceStruct(t *testing.T) { + var s InterfaceStruct if err := FakeData(&s, options.WithIgnoreInterface(true)); err != nil { t.Errorf("%+v", err) t.FailNow() } } + +func TestWithInterfaceStructWithIgnoreFalse(t *testing.T) { + var s InterfaceStruct + err := FakeData(&s, options.WithIgnoreInterface(false)) + if err == nil { + t.Errorf("expect error: but got %v", err) + t.FailNow() + } + if err.Error() != "interface{} not allowed" { + t.Errorf("expect error: \"interface{} not allowed\" but got %v", err.Error()) + t.FailNow() + } +} diff --git a/go.mod b/go.mod index 21d0390..9405849 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ module github.com/go-faker/faker/v4 -go 1.17 +go 1.18 require golang.org/x/text v0.3.7 diff --git a/go.sum b/go.sum index 2274b80..1f78e03 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,2 @@ golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/misc/makefile/tools.Makefile b/misc/makefile/tools.Makefile index 2565418..eac564b 100644 --- a/misc/makefile/tools.Makefile +++ b/misc/makefile/tools.Makefile @@ -42,7 +42,7 @@ bin/tparse: bin GOLANGCI := $(shell command -v golangci-lint || echo "bin/golangci-lint") golangci-lint: bin/golangci-lint ## Installs golangci-lint (linter) -bin/golangci-lint: VERSION := 1.48.0 +bin/golangci-lint: VERSION := 1.49.0 bin/golangci-lint: GITHUB := golangci/golangci-lint bin/golangci-lint: ARCHIVE := golangci-lint-$(VERSION)-$(OSTYPE)-amd64.tar.gz bin/golangci-lint: bin diff --git a/pkg/options/options.go b/pkg/options/options.go index 45bd491..c029177 100644 --- a/pkg/options/options.go +++ b/pkg/options/options.go @@ -18,7 +18,7 @@ var ( randomStringLen int32 = 25 lang unsafe.Pointer randomMaxSize int32 = 100 - randomMinSize int32 = 0 + randomMinSize int32 iBoundary unsafe.Pointer ) diff --git a/random_source_test.go b/random_source_test.go index ed03026..6a94451 100644 --- a/random_source_test.go +++ b/random_source_test.go @@ -8,7 +8,7 @@ import ( "time" ) -func TestSetRandomSource(t *testing.T) { +func TestSetRandomSource(_ *testing.T) { SetRandomSource(NewSafeSource(mathrand.NewSource(time.Now().UnixNano()))) _ = rand.Int31n(100) From ab6c09fa52c346d0098e1a001218602392096c88 Mon Sep 17 00:00:00 2001 From: "fengyun.rui" Date: Wed, 20 Sep 2023 17:38:01 +0800 Subject: [PATCH 3/6] fix: tolower domain by default (#32) Signed-off-by: rfyiamcool --- internet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internet.go b/internet.go index fee85fc..4258023 100644 --- a/internet.go +++ b/internet.go @@ -109,7 +109,7 @@ func (internet Internet) domainName() (string, error) { if err != nil { return "", err } - return (domainPart + "." + randomElementFromSliceString(tld)), nil + return (strings.ToLower(domainPart) + "." + randomElementFromSliceString(tld)), nil } // DomainName generates random domain name From 41dffa2da858f82fe1a2052c254fa4a977a93c8f Mon Sep 17 00:00:00 2001 From: "fengyun.rui" Date: Wed, 20 Sep 2023 17:38:29 +0800 Subject: [PATCH 4/6] feat: add url format (#33) Signed-off-by: rfyiamcool --- internet.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/internet.go b/internet.go index 4258023..5503df5 100644 --- a/internet.go +++ b/internet.go @@ -9,7 +9,7 @@ import ( "github.com/go-faker/faker/v4/pkg/options" ) -var tld = []string{"com", "biz", "info", "net", "org", "ru"} +var tld = []string{"com", "biz", "info", "net", "org", "ru", "edu", "top"} var urlFormats = []string{ "http://www.%s/", "https://www.%s/", @@ -23,6 +23,16 @@ var urlFormats = []string{ "https://%s/%s.html", "http://%s/%s.php", "https://%s/%s.php", + "http://%s/%s.jpg", + "https://%s/%s.jpg", + "http://%s/%s.webp", + "https://%s/%s.webp", + "http://%s/%s.js", + "https://%s/%s.js", + "http://%s/%s.css", + "https://%s/%s.css", + "http://%s/%s.svg", + "https://%s/%s.svg", } // GetNetworker returns a new Networker interface of Internet From 5423ebf673b088fcc56d747fc5280d93351a3550 Mon Sep 17 00:00:00 2001 From: "fengyun.rui" Date: Thu, 21 Sep 2023 11:26:09 +0800 Subject: [PATCH 5/6] perf: improve paragragh performance (#35) * perf: improve paragragh performance Signed-off-by: rfyiamcool * perf: improve paragragh performance Signed-off-by: rfyiamcool --------- Signed-off-by: rfyiamcool --- lorem.go | 31 ++++++++++++++++--------------- lorem_test.go | 6 ++++++ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/lorem.go b/lorem.go index 891c251..27c1144 100644 --- a/lorem.go +++ b/lorem.go @@ -1,8 +1,8 @@ package faker import ( - "fmt" "reflect" + "strings" "golang.org/x/text/cases" "golang.org/x/text/language" @@ -84,47 +84,48 @@ func Word(opts ...options.OptionFunc) string { }, opts...).(string) } -func (l Lorem) sentence() string { - sentence := "" +func (l Lorem) sentence(sentence *strings.Builder) *strings.Builder { r, _ := RandomInt(0, len(wordList)-1, 6) size := len(r) for key, val := range r { if key == 0 { - sentence += cases.Title(language.Und, cases.NoLower).String(wordList[val]) + sentence.WriteString(cases.Title(language.Und, cases.NoLower).String(wordList[val])) } else { - sentence += wordList[val] + sentence.WriteString(wordList[val]) } if key != size-1 { - sentence += " " + sentence.WriteString(" ") } } - return fmt.Sprintf("%s.", sentence) + + sentence.WriteString(".") + return sentence } // Sentence returns a sentence using the wordList const -func (l Lorem) Sentence(v reflect.Value) (interface{}, error) { - sentence := l.sentence() - return sentence, nil +func (l Lorem) Sentence(_ reflect.Value) (interface{}, error) { + sentence := l.sentence(&strings.Builder{}) + return sentence.String(), nil } // Sentence get a sentence randomly in string func Sentence(opts ...options.OptionFunc) string { i := Lorem{} return singleFakeData(SENTENCE, func() interface{} { - return i.sentence() + return i.sentence(&strings.Builder{}).String() }, opts...).(string) } func (l Lorem) paragraph() string { - paragraph := "" + paragraph := &strings.Builder{} size := rand.Intn(10) + 1 for i := 0; i < size; i++ { - paragraph += l.sentence() + l.sentence(paragraph) if i != size-1 { - paragraph += " " + paragraph.WriteString(" ") } } - return paragraph + return paragraph.String() } // Paragraph returns a series of sentences as a paragraph using the wordList const diff --git a/lorem_test.go b/lorem_test.go index b02c337..2360e8e 100644 --- a/lorem_test.go +++ b/lorem_test.go @@ -109,3 +109,9 @@ func TestUniqueParagraph(t *testing.T) { t.Error("Expected paragraph") } } + +func BenchmarkParagraph(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Paragraph() + } +} From 29e74ae47866cdf59fce158148b7566c84a1f5c8 Mon Sep 17 00:00:00 2001 From: "fengyun.rui" Date: Thu, 21 Sep 2023 11:26:40 +0800 Subject: [PATCH 6/6] fix: add random_string unit-test (#34) Signed-off-by: rfyiamcool --- faker_test.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/faker_test.go b/faker_test.go index 3e950a4..97011bb 100644 --- a/faker_test.go +++ b/faker_test.go @@ -2547,3 +2547,33 @@ func TestWithInterfaceStructWithIgnoreFalse(t *testing.T) { t.FailNow() } } + +func BenchmarkRandomString(b *testing.B) { + opt := options.DefaultOption() + for i := 0; i < b.N; i++ { + _, err := randomString(10, *opt) + if err != nil { + b.Error("Expected NoError, but Got Err:", err) + } + } +} + +func TestRandomString(t *testing.T) { + var ( + count = 1000 + set = map[string]struct{}{} + opt = options.DefaultOption() + ) + + for i := 0; i < count; i++ { + str, err := randomString(20, *opt) + if err != nil { + t.Error("Expected NoError, but Got Err:", err) + } + set[str] = struct{}{} + } + + if len(set) != count { + t.Error("random string in set is duplicate") + } +}