faker.gno
7.86 Kb ยท 344 lines
1// Package faker provides fake data generation utilities for testing and
2// development purposes. It includes methods for generating names, addresses,
3// dates, emails, and other common data types using a pseudorandom generator.
4package faker
5
6import (
7 "crypto/bech32"
8 "math/rand"
9 "strconv"
10 "strings"
11 "unicode"
12
13 "gno.land/p/demo/entropy"
14 "gno.land/p/nt/ufmt"
15)
16
17// Faker provides fake data generation using a pseudorandom number generator.
18type Faker struct {
19 rng *rand.Rand
20}
21
22// NewGenerator creates a new Faker instance with a random seed.
23func NewGenerator() *Faker {
24 return NewGeneratorWithSeed(entropy.New().Value64())
25}
26
27// NewGeneratorWithSeed creates a new Faker instance with a specified seed.
28func NewGeneratorWithSeed(seed uint64) *Faker {
29 return &Faker{
30 rng: rand.New(rand.NewPCG(seed, 0xdeadbeef)),
31 }
32}
33
34// FirstName returns a random first name.
35func (f *Faker) FirstName() string {
36 return f.pickRandom(&FirstNames)
37}
38
39// LastName returns a random last name.
40func (f *Faker) LastName() string {
41 return f.pickRandom(&LastNames)
42}
43
44// FullName returns a random full name (first name + last name).
45func (f *Faker) FullName() string {
46 return f.FirstName() + " " + f.LastName()
47}
48
49// Age returns a random age between min and min+80.
50func (f *Faker) Age(min int) int {
51 return f.rng.IntN(80) + min
52}
53
54// City returns a random city name.
55func (f *Faker) City() string {
56 return f.pickRandom(&Cities)
57}
58
59// Country returns a random country name.
60func (f *Faker) Country() string {
61 return f.pickRandom(&Countries)
62}
63
64// Address returns a random address in the format "123 Street Name, City, Country".
65func (f *Faker) Address() string {
66 var (
67 streetNum = strconv.Itoa(f.rng.IntN(9999) + 1)
68 streetName = f.pickRandom(&StreetNames)
69 city = f.City()
70 country = f.Country()
71 )
72
73 return ufmt.Sprintf("%s %s, %s, %s", streetNum, streetName, city, country)
74}
75
76// Lorem returns random lorem ipsum text with the specified number of words.
77func (f *Faker) Lorem(wordCount int) string {
78 if wordCount <= 0 {
79 return ""
80 }
81
82 result := ""
83
84 for i := 0; i < wordCount; i++ {
85 if i > 0 {
86 result += " "
87 }
88 result += f.pickRandom(&LoremWords)
89 }
90
91 return result
92}
93
94// LoremSentence returns a random lorem ipsum sentence with 5-15 words.
95func (f *Faker) LoremSentence() string {
96 var (
97 wordCount = f.rng.IntN(10) + 5
98 sentence = f.Lorem(wordCount)
99 )
100
101 if len(sentence) > 0 {
102 sentence = string(sentence[0]-32) + sentence[1:] + "."
103 }
104
105 return sentence
106}
107
108// LoremParagraph returns a random lorem ipsum paragraph with 3-8 sentences.
109func (f *Faker) LoremParagraph() string {
110 var (
111 sentenceCount = f.rng.IntN(5) + 3
112 paragraph = ""
113 )
114
115 for i := 0; i < sentenceCount; i++ {
116 if i > 0 {
117 paragraph += " "
118 }
119 paragraph += f.LoremSentence()
120 }
121
122 return paragraph
123}
124
125// Date returns a random date in YYYY-MM-DD format between 1974 and 2025.
126func (f *Faker) Date() string {
127 var (
128 year = strconv.Itoa(f.rng.IntN(52) + 1974)
129 month = itoa2Digits(f.rng.IntN(12) + 1)
130 day = itoa2Digits(f.rng.IntN(28) + 1) // Don't bother handling month lengths
131 )
132
133 return ufmt.Sprintf("%s-%s-%s", year, month, day)
134}
135
136// Time returns a random time in HH:MM:SS format (24-hour).
137func (f *Faker) Time() string {
138 var (
139 hour = itoa2Digits(f.rng.IntN(24))
140 minute = itoa2Digits(f.rng.IntN(60))
141 second = itoa2Digits(f.rng.IntN(60))
142 )
143
144 return ufmt.Sprintf("%s:%s:%s", hour, minute, second)
145}
146
147// DateTime returns a random date and time in "YYYY-MM-DD HH:MM:SS" format.
148func (f *Faker) DateTime() string {
149 return f.Date() + " " + f.Time()
150}
151
152// Email returns a random email address in firstname.lastname@domain format.
153func (f *Faker) Email() string {
154 var (
155 firstName = strings.ToLower(f.FirstName())
156 lastName = strings.ToLower(f.LastName())
157 domain = f.pickRandom(&EmailDomains)
158 )
159
160 return ufmt.Sprintf("%s.%s@%s", firstName, lastName, domain)
161}
162
163// Phone returns a random phone number in (XXX) XXX-XXXX format.
164func (f *Faker) Phone() string {
165 var (
166 area = f.rng.IntN(900) + 100
167 exchange = f.rng.IntN(900) + 100
168 number = f.rng.IntN(10000)
169 )
170
171 return ufmt.Sprintf("(%d) %d-%d", area, exchange, number)
172}
173
174// StdAddress returns a random chain.Address.
175func (f *Faker) StdAddress() address {
176 rawAddr := make([]byte, 32)
177 for i := 0; i < 32; i++ {
178 rawAddr[i] = byte(f.rng.IntN(32))
179 }
180
181 addr, err := bech32.Encode("g", rawAddr)
182 if err != nil {
183 panic(err)
184 }
185
186 return address(addr)
187}
188
189// Username returns a random gno username following the rules:
190// - Start with minimum 3 letters (lowercase)
191// - End with minimum 3 numbers
192// - Less than 20 chars total
193// - Only letters, numbers, and underscore allowed
194func (f *Faker) Username() string {
195 var (
196 username = ""
197 sources = []*[]string{
198 &FirstNames,
199 &LastNames,
200 &LoremWords,
201 }
202 )
203
204 for {
205 var (
206 source = sources[f.rng.IntN(len(sources))]
207 word = strings.ToLower(f.pickRandomLettersOnly(source))
208 next = username + word
209 )
210
211 if len(next) > 16 && len(username) > 3 {
212 break
213 } else if len(next) <= 16 {
214 username = next
215 }
216 }
217
218 for i := 0; i < 3; i++ {
219 username += strconv.Itoa(f.rng.IntN(10))
220 }
221
222 return username
223}
224
225func (f *Faker) pickRandom(source *[]string) string {
226 return (*source)[f.rng.IntN(len(*source))]
227}
228
229func (f *Faker) pickRandomLettersOnly(source *[]string) string {
230 isLettersOnly := func(s string) bool {
231 for _, r := range s {
232 if !unicode.IsLetter(r) {
233 return false
234 }
235 }
236 return true
237 }
238
239 // Limit attempts to 100 to avoid infinite loops.
240 for i := 0; i < 100; i++ {
241 word := f.pickRandom(source)
242 if isLettersOnly(word) {
243 return word
244 }
245 }
246
247 panic("could not find a letters-only word after 100 attempts")
248}
249
250func itoa2Digits(n int) string {
251 str := strconv.Itoa(n)
252 if n < 10 {
253 return "0" + str
254 }
255 return str
256}
257
258// defaultFaker is the default Faker instance used by package-level functions.
259var defaultFaker = NewGenerator()
260
261// FirstName returns a random first name using the default faker.
262func FirstName() string {
263 return defaultFaker.FirstName()
264}
265
266// LastName returns a random last name using the default faker.
267func LastName() string {
268 return defaultFaker.LastName()
269}
270
271// FullName returns a random full name using the default faker.
272func FullName() string {
273 return defaultFaker.FullName()
274}
275
276// Age returns a random age using the default faker.
277func Age(min int) int {
278 return defaultFaker.Age(min)
279}
280
281// City returns a random city name using the default faker.
282func City() string {
283 return defaultFaker.City()
284}
285
286// Country returns a random country name using the default faker.
287func Country() string {
288 return defaultFaker.Country()
289}
290
291// Address returns a random address using the default faker.
292func Address() string {
293 return defaultFaker.Address()
294}
295
296// Lorem returns random lorem ipsum text using the default faker.
297func Lorem(wordCount int) string {
298 return defaultFaker.Lorem(wordCount)
299}
300
301// LoremSentence returns a random lorem ipsum sentence using the default faker.
302func LoremSentence() string {
303 return defaultFaker.LoremSentence()
304}
305
306// LoremParagraph returns a random lorem ipsum paragraph using the default faker.
307func LoremParagraph() string {
308 return defaultFaker.LoremParagraph()
309}
310
311// Date returns a random date using the default faker.
312func Date() string {
313 return defaultFaker.Date()
314}
315
316// Time returns a random time using the default faker.
317func Time() string {
318 return defaultFaker.Time()
319}
320
321// DateTime returns a random date and time using the default faker.
322func DateTime() string {
323 return defaultFaker.DateTime()
324}
325
326// Email returns a random email address using the default faker.
327func Email() string {
328 return defaultFaker.Email()
329}
330
331// Phone returns a random phone number using the default faker.
332func Phone() string {
333 return defaultFaker.Phone()
334}
335
336// StdAddress returns a random chain.Address using the default faker.
337func StdAddress() address {
338 return defaultFaker.StdAddress()
339}
340
341// Username returns a random gno username using the default faker.
342func Username() string {
343 return defaultFaker.Username()
344}