Skip to content
This repository has been archived by the owner on Dec 8, 2022. It is now read-only.

Commit

Permalink
feat: float_boundaries(#156)
Browse files Browse the repository at this point in the history
* added ability to set boundaries for float32 and float64 types
* rename old methods which supports only integers to more explicit
* update tests
* delete test which checks float to unsupported struct to boundaries

Co-authored-by: Iman Tumorang <iman.tumorang@gmail.com>
  • Loading branch information
Xaspy and bxcodec committed Mar 10, 2022
1 parent 7db514b commit f6a1e82
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 33 deletions.
5 changes: 5 additions & 0 deletions example_with_tags_lenbounds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ func Example_withTagsLengthAndBoundary() {
UInt32 uint32 `faker:"boundary_start=0, boundary_end=40"`
UInt64 uint64 `faker:"boundary_start=14, boundary_end=50"`

Float32 float32 `faker:"boundary_start=12.65, boundary_end=184.05"`
Float64 float64 `faker:"boundary_start=1.256, boundary_end=3.4"`

ASString []string `faker:"len=50"`
SString string `faker:"len=25"`
MSString map[string]string `faker:"len=30"`
Expand All @@ -45,6 +48,8 @@ func Example_withTagsLengthAndBoundary() {
UInt16:1797
UInt32:8
UInt64:34
Float32:60.999058
Float64:2.590148738554016
ASString:[
geHYIpEoQhQdijFooVEAOyvtTwJOofbQPJdbHvEEdjueZaKIgI
WVJBBtmrrVccyIydAiLSkMwWbFzFMEotEXsyUXqcmBTVORlkJK
Expand Down
76 changes: 63 additions & 13 deletions faker.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ var (
testRandZero = false
//Sets the default number of string when it is created randomly.
randomStringLen = 25
//Sets the boundary for random value generation. Boundaries can not exceed integer(4 byte...)
nBoundary = numberBoundary{start: 0, end: 100}
//Sets the boundary for random integer value generation. Boundaries can not exceed integer(4 byte...)
iBoundary = intBoundary{start: 0, end: 100}
//Sets the boundary for random float value generation. Boundaries should comply with float values constraints (IEEE 754)
fBoundary = floatBoundary{start: 0, end: 100}
//Sets the random max size for slices and maps.
randomMaxSize = 100
//Sets the random min size for slices and maps.
Expand All @@ -43,11 +45,16 @@ var (
maxGenerateStringRetries = 1000000
)

type numberBoundary struct {
type intBoundary struct {
start int
end int
}

type floatBoundary struct {
start float64
end float64
}

type langRuneBoundary struct {
start rune
end rune
Expand Down Expand Up @@ -366,7 +373,7 @@ func SetRandomNumberBoundaries(start, end int) error {
if start > end {
return errors.New(ErrStartValueBiggerThanEnd)
}
nBoundary = numberBoundary{start: start, end: end}
iBoundary = intBoundary{start: start, end: end}
return nil
}

Expand Down Expand Up @@ -596,9 +603,9 @@ func getValue(a interface{}) (reflect.Value, error) {
case reflect.Int64:
return reflect.ValueOf(int64(randomInteger())), nil
case reflect.Float32:
return reflect.ValueOf(rand.Float32()), nil
return reflect.ValueOf(float32(randomFloat())), nil
case reflect.Float64:
return reflect.ValueOf(rand.Float64()), nil
return reflect.ValueOf(randomFloat()), nil
case reflect.Bool:
val := rand.Intn(2) > 0
return reflect.ValueOf(val), nil
Expand Down Expand Up @@ -799,7 +806,7 @@ func userDefinedMap(v reflect.Value, tag string) error {
func getValueWithTag(t reflect.Type, tag string) (interface{}, error) {
switch t.Kind() {
case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int8, reflect.Int16, reflect.Uint, reflect.Uint8,
reflect.Uint16, reflect.Uint32, reflect.Uint64:
reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
res, err := extractNumberFromTag(tag, t)
if err != nil {
return nil, err
Expand Down Expand Up @@ -1095,15 +1102,35 @@ func extractNumberFromTag(tag string, t reflect.Type) (interface{}, error) {
if len(valuesStr) != 2 {
return nil, fmt.Errorf(ErrWrongFormattedTag, tag)
}
startBoundary, err := extractNumberFromText(valuesStr[0])

// TODO(Xaspy): When Golang provides generics, we will be able to make this method simpler and more beautiful.
if t.Kind() == reflect.Float64 || t.Kind() == reflect.Float32 {
startBoundary, err := extractFloatFromText(valuesStr[0])
if err != nil {
return nil, err
}
endBoundary, err := extractFloatFromText(valuesStr[1])
if err != nil {
return nil, err
}
boundary := floatBoundary{start: startBoundary, end: endBoundary}
switch t.Kind() {
case reflect.Float32:
return float32(randomFloatWithBoundary(boundary)), nil
case reflect.Float64:
return randomFloatWithBoundary(boundary), nil
}
}

startBoundary, err := extractIntFromText(valuesStr[0])
if err != nil {
return nil, err
}
endBoundary, err := extractNumberFromText(valuesStr[1])
endBoundary, err := extractIntFromText(valuesStr[1])
if err != nil {
return nil, err
}
boundary := numberBoundary{start: startBoundary, end: endBoundary}
boundary := intBoundary{start: startBoundary, end: endBoundary}
switch t.Kind() {
case reflect.Uint:
return uint(randomIntegerWithBoundary(boundary)), nil
Expand All @@ -1130,7 +1157,7 @@ func extractNumberFromTag(tag string, t reflect.Type) (interface{}, error) {
}
}

func extractNumberFromText(text string) (int, error) {
func extractIntFromText(text string) (int, error) {
text = strings.TrimSpace(text)
texts := strings.SplitN(text, Equals, -1)
if len(texts) != 2 {
Expand All @@ -1139,6 +1166,15 @@ func extractNumberFromText(text string) (int, error) {
return strconv.Atoi(texts[1])
}

func extractFloatFromText(text string) (float64, error) {
text = strings.TrimSpace(text)
texts := strings.SplitN(text, Equals, -1)
if len(texts) != 2 {
return 0, fmt.Errorf(ErrWrongFormattedTag, text)
}
return strconv.ParseFloat(texts[1], 64)
}

func fetchOneOfArgsFromTag(tag string) ([]string, error) {
items := strings.Split(tag, colon)
argsList := items[1:]
Expand Down Expand Up @@ -1189,17 +1225,31 @@ func randomString(n int, lang *langRuneBoundary) (string, error) {
}

// randomIntegerWithBoundary returns a random integer between input start and end boundary. [start, end)
func randomIntegerWithBoundary(boundary numberBoundary) int {
func randomIntegerWithBoundary(boundary intBoundary) int {
span := boundary.end - boundary.start
if span <= 0 {
return boundary.start
}
return rand.Intn(span) + boundary.start
}

// randomFloatWithBoundary returns a random float between input start and end boundary. [start, end)
func randomFloatWithBoundary(boundary floatBoundary) float64 {
span := boundary.end - boundary.start
if span <= 0 {
return boundary.start
}
return boundary.start + rand.Float64()*span
}

// randomInteger returns a random integer between start and end boundary. [start, end)
func randomInteger() int {
return randomIntegerWithBoundary(nBoundary)
return randomIntegerWithBoundary(iBoundary)
}

// randomFloat returns a random float between start and end boundary. [start, end)
func randomFloat() float64 {
return randomFloatWithBoundary(fBoundary)
}

// randomSliceAndMapSize returns a random integer between [0,randomSliceAndMapSize). If the testRandZero is set, returns 0
Expand Down
51 changes: 31 additions & 20 deletions faker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ type SomeStructWithLen struct {
UInt32 uint32 `faker:"boundary_start=5, boundary_end=10"`
UInt64 uint64 `faker:"boundary_start=5, boundary_end=10"`

Float32 float32 `faker:"boundary_start=5, boundary_end=10"`
Float64 float64 `faker:"boundary_start=5, boundary_end=10"`

ASString []string `faker:"len=2"`
SString string `faker:"len=2"`
MSString map[string]string `faker:"len=2"`
Expand Down Expand Up @@ -485,7 +488,7 @@ func TestSetRandomNumberBoundaries(t *testing.T) {
if err := SetRandomNumberBoundaries(10, 0); err == nil {
t.Error("Start must be smaller than end value")
}
boundary := numberBoundary{start: 10, end: 90}
boundary := intBoundary{start: 10, end: 90}
if err := SetRandomNumberBoundaries(boundary.start, boundary.end); err != nil {
t.Error("SetRandomNumberBoundaries method is corrupted.")
}
Expand Down Expand Up @@ -551,34 +554,40 @@ func TestBoundaryAndLen(t *testing.T) {
if err := FakeData(&someStruct); err != nil {
t.Error(err)
}
if err := validateRange(int(someStruct.Int8)); err != nil {
if err := validateIntRange(int(someStruct.Int8)); err != nil {
t.Error(err)
}
if err := validateIntRange(int(someStruct.Int16)); err != nil {
t.Error(err)
}
if err := validateRange(int(someStruct.Int16)); err != nil {
if err := validateIntRange(int(someStruct.Int32)); err != nil {
t.Error(err)
}
if err := validateRange(int(someStruct.Int32)); err != nil {
if err := validateIntRange(someStruct.Inta); err != nil {
t.Error(err)
}
if err := validateRange(someStruct.Inta); err != nil {
if err := validateIntRange(int(someStruct.Int64)); err != nil {
t.Error(err)
}
if err := validateRange(int(someStruct.Int64)); err != nil {
if err := validateIntRange(int(someStruct.UInt8)); err != nil {
t.Error(err)
}
if err := validateRange(int(someStruct.UInt8)); err != nil {
if err := validateIntRange(int(someStruct.UInt16)); err != nil {
t.Error(err)
}
if err := validateRange(int(someStruct.UInt16)); err != nil {
if err := validateIntRange(int(someStruct.UInt32)); err != nil {
t.Error(err)
}
if err := validateRange(int(someStruct.UInt32)); err != nil {
if err := validateIntRange(int(someStruct.UInta)); err != nil {
t.Error(err)
}
if err := validateRange(int(someStruct.UInta)); err != nil {
if err := validateIntRange(int(someStruct.UInt64)); err != nil {
t.Error(err)
}
if err := validateRange(int(someStruct.UInt64)); err != nil {
if err := validateFloatRange(float64(someStruct.Float32)); err != nil {
t.Error(err)
}
if err := validateFloatRange(someStruct.Float64); err != nil {
t.Error(err)
}
if err := validateLen(someStruct.SString); err != nil {
Expand All @@ -598,10 +607,10 @@ func TestBoundaryAndLen(t *testing.T) {
}
}
for k, v := range someStruct.MIint {
if err := validateRange(k); err != nil {
if err := validateIntRange(k); err != nil {
t.Error(err)
}
if err := validateRange(v); err != nil {
if err := validateIntRange(v); err != nil {
t.Error(err)
}
}
Expand Down Expand Up @@ -823,12 +832,6 @@ func isStringLangCorrect(value string, lang langRuneBoundary) error {
}

func TestExtractNumberFromTagFail(t *testing.T) {
notSupportedTypeStruct := &struct {
Test float32 `faker:"boundary_start=5, boundary_end=10"`
}{}
if err := FakeData(&notSupportedTypeStruct); err == nil {
t.Error(err)
}
notSupportedStruct := &struct {
Test int `faker:"boundary_start=5"`
}{}
Expand Down Expand Up @@ -877,14 +880,22 @@ func validateLen(value string) error {
return nil
}

func validateRange(value int) error {
func validateIntRange(value int) error {
if value < someStructBoundaryStart || value > someStructBoundaryEnd {
return fmt.Errorf("%d must be between %d and %d", value, someStructBoundaryStart,
someStructBoundaryEnd)
}
return nil
}

func validateFloatRange(value float64) error {
if value < someStructBoundaryStart || value > someStructBoundaryEnd {
return fmt.Errorf("%f must be between %d and %d", value, someStructBoundaryStart,
someStructBoundaryEnd)
}
return nil
}

func TestSetDataWithTagIfFirstArgumentNotPtr(t *testing.T) {
temp := struct{}{}
if setDataWithTag(reflect.ValueOf(temp), "").Error() != "Not a pointer value" {
Expand Down

0 comments on commit f6a1e82

Please sign in to comment.