Skip to content

Commit

Permalink
Add Json generator (#147)
Browse files Browse the repository at this point in the history
Add Json generator
  • Loading branch information
jaswdr authored Aug 18, 2023
1 parent 1eae534 commit e53a3c3
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 0 deletions.
5 changes: 5 additions & 0 deletions faker.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,3 +595,8 @@ func NewWithSeed(src rand.Source) (f Faker) {
func (f Faker) Blood() Blood {
return Blood{&f}
}

// Json returns a fake Json instance for Faker
func (f Faker) Json() Json {
return Json{&f}
}
79 changes: 79 additions & 0 deletions json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package faker

import (
"encoding/json"
"strconv"
)

// Json is a faker struct for json files
type Json struct {
Faker *Faker
}

var (
attributesTypes = []string{"string", "number", "object", "array", "boolean", "null"}
attributesTypesWithoutArrayAndObject = []string{"string", "number", "boolean", "null"}
)

func (j *Json) randomAttributeValueFromListAsString(validAttributesTypes []string) string {
attributeType := j.Faker.RandomStringElement(validAttributesTypes)
switch attributeType {
case "string":
return "\"" + j.Faker.Lorem().Word() + "\""
case "number":
number := strconv.Itoa(j.Faker.RandomNumber(j.Faker.RandomDigit()))
return number
case "object":
// Avoid having multiple nested objects by not using object and array as valid attribute types
return j.randomJsonObjectAsString(attributesTypesWithoutArrayAndObject)
case "array":
objects := ""
for i := 0; i < j.Faker.IntBetween(1, 10); i++ {
if objects != "" {
objects += ", "
}
// Avoid having multiple nested objects by not using object and array as valid attribute types
objects += j.randomJsonObjectAsString(attributesTypesWithoutArrayAndObject)
}
return "[" + objects + "]"
case "boolean":
return j.Faker.RandomStringElement([]string{"true", "false"})
case "null":
return "null"
}

panic("Invalid attribute type: " + attributeType)
}

func (j *Json) randomJsonObjectAsString(validAttributesTypes []string) string {
numberAttributes := j.Faker.IntBetween(1, 10)
attributes := make([]string, numberAttributes)
for i := 0; i < numberAttributes; i++ {
attributeName := j.Faker.Lorem().Word()
attributeValue := j.randomAttributeValueFromListAsString(validAttributesTypes)
attributes[i] = "\"" + attributeName + "\": " + attributeValue
}

result := "{"
for i := 0; i < len(attributes); i++ {
if i > 0 {
result += ", "
}
result += attributes[i]
}
result += "}"
return result
}

// String generates a random json string
func (j *Json) String() string {
return j.randomJsonObjectAsString(attributesTypes)
}

// Object generates a random json object
func (j *Json) Object() map[string]interface{} {
result := j.String()
var data map[string]interface{}
json.Unmarshal([]byte(result), &data)
return data
}
79 changes: 79 additions & 0 deletions json_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package faker

import (
"encoding/json"
"testing"
)

func TestJsonString(t *testing.T) {
faker := New()
j := faker.Json()

for i := 0; i < 10; i++ {
result := j.String()

// Attempt to unmarshal the result into a map[string]interface{}
var data map[string]interface{}
err := json.Unmarshal([]byte(result), &data)
Expect(t, err, nil)

// Ensure that the result is a valid JSON object
Expect(t, len(data) > 0, true)

// Ensure that all attribute values are valid JSON types
for _, value := range data {
switch value.(type) {
case string, float64, bool, nil:
// Valid JSON types
case []interface{}:
// Valid JSON array type
case map[string]interface{}:
// Valid JSON object type
default:
t.FailNow()
}
}
}
}

func TestJsonObject(t *testing.T) {
faker := New()
j := faker.Json()

for i := 0; i < 10; i++ {
data := j.Object()

// Ensure that the result is not nil
NotExpect(t, data, nil)

// Ensure that the result is a valid JSON object
Expect(t, len(data) > 0, true)

// Ensure that all attribute values are valid JSON types
for _, value := range data {
switch value.(type) {
case string, float64, bool, nil:
// Valid JSON types
case []interface{}:
// Valid JSON array type
case map[string]interface{}:
// Valid JSON object type
default:
t.FailNow()
}
}
}
}

func TestRandomAttributeValueFromListAsStringPanicWhenUnsupportedTypeIsPassed(t *testing.T) {
faker := New()
j := faker.Json()

defer func() {
if r := recover(); r == nil {
NotExpect(t, r, nil)
}
}()

j.randomAttributeValueFromListAsString([]string{"unsupported"})
}

0 comments on commit e53a3c3

Please sign in to comment.