faker.gno

7.84 Kb ยท 342 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	"math/rand"
  8	"std"
  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 std.Address.
175func (f *Faker) StdAddress() std.Address {
176	var rawAddr std.RawAddress
177
178	for i := 0; i < std.RawAddressSize; i++ {
179		rawAddr[i] = byte(f.rng.IntN(256))
180	}
181
182	addr := std.EncodeBech32("g", rawAddr)
183
184	return std.Address(addr)
185}
186
187// Username returns a random gno username following the rules:
188// - Start with minimum 3 letters (lowercase)
189// - End with minimum 3 numbers
190// - Less than 20 chars total
191// - Only letters, numbers, and underscore allowed
192func (f *Faker) Username() string {
193	var (
194		username = ""
195		sources  = []*[]string{
196			&FirstNames,
197			&LastNames,
198			&LoremWords,
199		}
200	)
201
202	for {
203		var (
204			source = sources[f.rng.IntN(len(sources))]
205			word   = strings.ToLower(f.pickRandomLettersOnly(source))
206			next   = username + word
207		)
208
209		if len(next) > 16 && len(username) > 3 {
210			break
211		} else if len(next) <= 16 {
212			username = next
213		}
214	}
215
216	for i := 0; i < 3; i++ {
217		username += strconv.Itoa(f.rng.IntN(10))
218	}
219
220	return username
221}
222
223func (f *Faker) pickRandom(source *[]string) string {
224	return (*source)[f.rng.IntN(len(*source))]
225}
226
227func (f *Faker) pickRandomLettersOnly(source *[]string) string {
228	isLettersOnly := func(s string) bool {
229		for _, r := range s {
230			if !unicode.IsLetter(r) {
231				return false
232			}
233		}
234		return true
235	}
236
237	// Limit attempts to 100 to avoid infinite loops.
238	for i := 0; i < 100; i++ {
239		word := f.pickRandom(source)
240		if isLettersOnly(word) {
241			return word
242		}
243	}
244
245	panic("could not find a letters-only word after 100 attempts")
246}
247
248func itoa2Digits(n int) string {
249	str := strconv.Itoa(n)
250	if n < 10 {
251		return "0" + str
252	}
253	return str
254}
255
256// defaultFaker is the default Faker instance used by package-level functions.
257var defaultFaker = NewGenerator()
258
259// FirstName returns a random first name using the default faker.
260func FirstName() string {
261	return defaultFaker.FirstName()
262}
263
264// LastName returns a random last name using the default faker.
265func LastName() string {
266	return defaultFaker.LastName()
267}
268
269// FullName returns a random full name using the default faker.
270func FullName() string {
271	return defaultFaker.FullName()
272}
273
274// Age returns a random age using the default faker.
275func Age(min int) int {
276	return defaultFaker.Age(min)
277}
278
279// City returns a random city name using the default faker.
280func City() string {
281	return defaultFaker.City()
282}
283
284// Country returns a random country name using the default faker.
285func Country() string {
286	return defaultFaker.Country()
287}
288
289// Address returns a random address using the default faker.
290func Address() string {
291	return defaultFaker.Address()
292}
293
294// Lorem returns random lorem ipsum text using the default faker.
295func Lorem(wordCount int) string {
296	return defaultFaker.Lorem(wordCount)
297}
298
299// LoremSentence returns a random lorem ipsum sentence using the default faker.
300func LoremSentence() string {
301	return defaultFaker.LoremSentence()
302}
303
304// LoremParagraph returns a random lorem ipsum paragraph using the default faker.
305func LoremParagraph() string {
306	return defaultFaker.LoremParagraph()
307}
308
309// Date returns a random date using the default faker.
310func Date() string {
311	return defaultFaker.Date()
312}
313
314// Time returns a random time using the default faker.
315func Time() string {
316	return defaultFaker.Time()
317}
318
319// DateTime returns a random date and time using the default faker.
320func DateTime() string {
321	return defaultFaker.DateTime()
322}
323
324// Email returns a random email address using the default faker.
325func Email() string {
326	return defaultFaker.Email()
327}
328
329// Phone returns a random phone number using the default faker.
330func Phone() string {
331	return defaultFaker.Phone()
332}
333
334// StdAddress returns a random std.Address using the default faker.
335func StdAddress() std.Address {
336	return defaultFaker.StdAddress()
337}
338
339// Username returns a random gno username using the default faker.
340func Username() string {
341	return defaultFaker.Username()
342}