├── LICENSE ├── README.md └── randjson.go /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Josh Baker 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `randjson` 2 | [![GoDoc](https://img.shields.io/badge/api-reference-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/tidwall/randjson) 3 | 4 | Make random JSON in Go 5 | 6 | ## Usage 7 | 8 | Get the package 9 | 10 | ``` 11 | go get github.com/tidwall/randjson 12 | ``` 13 | 14 | Make some random JSON using the default options and a maximum of 12 nested child 15 | elements. 16 | 17 | ```go 18 | js := randjson.Make(12, nil) 19 | println(string(js)) 20 | ``` 21 | 22 | Outputs: 23 | 24 | ```json 25 | { 26 | "interlocal": true, 27 | "subterjacent": null, 28 | "unpalpitating": false, 29 | "semitruth": null, 30 | "democratical": "becher", 31 | "extrapoetical": null, 32 | "sympathetically": null, 33 | "townless": [true], 34 | "glisten": null, 35 | "unverifiedness": null, 36 | "polariscopy": { 37 | "ayacahuite": { 38 | "vertebrocostal": true, 39 | "Langhian": [false, 89.32, null], 40 | "bubo": "albe", 41 | "avoidless": "unconsolatory", 42 | "revitalize": true, 43 | "brassiness": true 44 | }, 45 | "booksellerish": true, 46 | "unduplicable": 44.49, 47 | "overtopple": { 48 | "sclerometer": "reune", 49 | "unbelt": false, 50 | "personalia": { 51 | "epeirogenic": "epeirogenic" 52 | }, 53 | "scutellated": "unfroward" 54 | }, 55 | "muffishness": false, 56 | "preignition": [true, "ramus", null, false], 57 | "evangeliarium": null, 58 | "ardri": 24.53, 59 | "playfulness": null 60 | }, 61 | "playfulness": { 62 | "mumper": [], 63 | "contriturate": "avoidless" 64 | } 65 | } 66 | ``` 67 | 68 | ## Options 69 | 70 | ```go 71 | type Options struct { 72 | // Pretty formats and indents the random json. Default true 73 | Pretty bool 74 | // Words are the number of unique words to use. Default 1,000 75 | Words int 76 | // Rand is the random number generator to use. Default global rng 77 | Rand *rand.Rand 78 | } 79 | ``` 80 | 81 | -------------------------------------------------------------------------------- /randjson.go: -------------------------------------------------------------------------------- 1 | package randjson 2 | 3 | import ( 4 | "math/rand" 5 | "strconv" 6 | 7 | "github.com/tidwall/pretty" 8 | "github.com/tidwall/words" 9 | ) 10 | 11 | // Options for Make() 12 | type Options struct { 13 | // Pretty formats and indents the random json. Default true 14 | Pretty bool 15 | // Spread is the number of unique words to use. Default 1,000 16 | Words int 17 | // Rand is the random number generator to use. Default global rng 18 | Rand *rand.Rand 19 | } 20 | 21 | // DefaultOptions for Make() 22 | var DefaultOptions = &Options{ 23 | Pretty: true, 24 | Words: 1000, 25 | Rand: nil, 26 | } 27 | 28 | // Append a random json document to dst. The depth param is the maximum nested 29 | // depth of json document 30 | func Append(dst []byte, depth int, opts *Options) []byte { 31 | if opts == nil { 32 | opts = DefaultOptions 33 | } 34 | var p float64 35 | if opts.Words > len(words.Words) { 36 | p = 1.0 37 | } else if opts.Words < 1 { 38 | p = 1 / float64(len(words.Words)) 39 | } else { 40 | p = float64(opts.Words) / float64(len(words.Words)) 41 | } 42 | s := int(float64(len(words.Words)) * p) 43 | t := (len(words.Words) / s) 44 | mark := len(dst) 45 | dst = appendRandObject(dst, opts.Rand, s, t, depth) 46 | if opts.Pretty { 47 | dst = append(dst[:mark], pretty.Pretty(dst[mark:])...) 48 | } 49 | return dst 50 | } 51 | 52 | // Make returns a random json document. The depth param is the maximum nested 53 | // depth of json document 54 | func Make(depth int, opts *Options) []byte { 55 | return Append(nil, depth, opts) 56 | } 57 | 58 | func randInt(rng *rand.Rand) int { 59 | if rng == nil { 60 | return rand.Int() 61 | } 62 | return rng.Int() 63 | } 64 | func appendRandString(dst []byte, rng *rand.Rand, s, t int) []byte { 65 | dst = append(dst, '"') 66 | dst = append(dst, words.Words[(randInt(rng)%s)*t]...) 67 | return append(dst, '"') 68 | } 69 | func appendRandAny(dst []byte, rng *rand.Rand, nested bool, s, t, d int) []byte { 70 | switch randInt(rng) % 7 { 71 | case 0: 72 | dst = appendRandString(dst, rng, s, t) 73 | case 1: 74 | if !nested { 75 | dst = appendRandAny(dst, rng, nested, s, t, d) 76 | } else { 77 | dst = append(dst, '[') 78 | if d > 1 { 79 | n := randInt(rng) % (d - 1) 80 | for i := 0; i < n; i++ { 81 | if i > 0 { 82 | dst = append(dst, ',') 83 | } 84 | dst = appendRandAny(dst, rng, false, s, t, d-1) 85 | } 86 | } 87 | dst = append(dst, ']') 88 | } 89 | case 2: 90 | if !nested { 91 | dst = appendRandAny(dst, rng, nested, s, t, d) 92 | } else { 93 | if d > 1 { 94 | d = randInt(rng) % (d - 1) 95 | } 96 | dst = appendRandObject(dst, rng, s, t, d) 97 | } 98 | case 3: 99 | dst = strconv.AppendFloat(dst, 100 | float64(randInt(rng)%10000)/100, 'f', 2, 64) 101 | case 4: 102 | dst = append(dst, "true"...) 103 | case 5: 104 | dst = append(dst, "false"...) 105 | case 6: 106 | dst = append(dst, "null"...) 107 | } 108 | return dst 109 | } 110 | func appendRandObject(dst []byte, rng *rand.Rand, s, t, d int) []byte { 111 | dst = append(dst, '{') 112 | for i := 0; i < d; i++ { 113 | if i > 0 { 114 | dst = append(dst, ',') 115 | } 116 | dst = appendRandString(dst, rng, s, t) 117 | dst = append(dst, ':') 118 | dst = appendRandAny(dst, rng, true, s, t, d-1) 119 | } 120 | return append(dst, '}') 121 | } 122 | --------------------------------------------------------------------------------