diff --git a/README.md b/README.md index 8fdb287..90cf8d6 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,12 @@ The library ships a ready-to-use set under [`locales/`](locales) (`en_US`, `sv_SE`). Pass `New` the path to one of them, a copy, or your own directory — anywhere on disk. +Each ships these categories, formatted per locale (e.g. `date` is `MM/DD/YYYY` +in `en_US`, `YYYY-MM-DD` in `sv_SE`; `ssn` is a US SSN vs a Swedish +personnummer): `address`, `color`, `company`, `date`, `email`, `ip`, `person`, +`phone`, `price`, `sentence`, `ssn`, `time`, `url`, `username`, `uuid`, +`version`, `word`. + The directory's name is the locale and must be a full tag (`sv_SE`, never `sv`). Any casing or separator is accepted and canonicalised (`sv-se`, `SV_SE` → `sv_SE`); a non-full name returns an error. diff --git a/data_test.go b/data_test.go new file mode 100644 index 0000000..cdd38c0 --- /dev/null +++ b/data_test.go @@ -0,0 +1,65 @@ +package fakes + +import ( + "regexp" + "testing" +) + +// TestShippedDataCategories asserts every shipped locale emits only well-formed +// values for each data category. en and sv patterns differ where the format is +// locale-specific (date, time, ssn, company, price, ...); the rest are shared. +func TestShippedDataCategories(t *testing.T) { + letters := regexp.MustCompile(`^[\pL'-]+$`) + semver := regexp.MustCompile(`^v?\d+\.\d+\.\d+(-(alpha|beta|rc)\.\d+)?$`) + ip := regexp.MustCompile(`^((\d{1,3}\.){3}\d{1,3}|([0-9a-f]{4}:){7}[0-9a-f]{4})$`) + uuid := regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`) + color := regexp.MustCompile(`^(#[0-9a-f]{6}|[\pL ]+)$`) + url := regexp.MustCompile(`^https?://([a-z0-9-]+\.)+[a-z]{2,}(/[a-z0-9./-]*)?$`) + email := regexp.MustCompile(`^[a-z0-9._-]+@([a-z0-9-]+\.)+[a-z]{2,}$`) + uname := regexp.MustCompile(`^[a-z][a-z0-9._]*$`) + + cases := []struct { + path string + en, sv *regexp.Regexp + }{ + {"word", letters, letters}, + {"sentence", + regexp.MustCompile(`^[A-Z].* .*[.!?]$`), + regexp.MustCompile(`^[A-ZÅÄÖ].* .*[.!?]$`)}, + {"date", + regexp.MustCompile(`^(0[1-9]|1[0-2])/(0[1-9]|[12]\d|3[01])/\d{4}$`), + regexp.MustCompile(`^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$`)}, + {"time", + regexp.MustCompile(`^([1-9]|1[0-2]):[0-5]\d (AM|PM)$`), + regexp.MustCompile(`^([01]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$`)}, + {"ssn", + regexp.MustCompile(`^[1-9]\d{2}-\d{2}-\d{4}$`), + regexp.MustCompile(`^\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])-\d{4}$`)}, + {"version", semver, semver}, + {"email", email, email}, + {"ip", ip, ip}, + {"company", + regexp.MustCompile(`^.+ (Inc\.|LLC|Corp\.|Co\.|Group|Ltd\.)$`), + regexp.MustCompile(`^.+ (AB|HB|KB)$`)}, + {"color", color, color}, + {"url", url, url}, + {"uuid", uuid, uuid}, + {"username", uname, uname}, + {"price", + regexp.MustCompile(`^\$\d{1,3}(,\d{3})?\.\d{2}$`), + regexp.MustCompile(`^\d{1,3}( \d{3})?(,\d{2})? kr$`)}, + } + + en := newFakes(t, "locales/en_US", WithSeed(1)) + sv := newFakes(t, "locales/sv_SE", WithSeed(1)) + for _, c := range cases { + for i := 0; i < 200; i++ { + if v := fake(t, en, c.path); !c.en.MatchString(v) { + t.Fatalf("en_US %s = %q, want %s", c.path, v, c.en) + } + if v := fake(t, sv, c.path); !c.sv.MatchString(v) { + t.Fatalf("sv_SE %s = %q, want %s", c.path, v, c.sv) + } + } + } +} diff --git a/locales/en_US/color.json b/locales/en_US/color.json new file mode 100644 index 0000000..250251d --- /dev/null +++ b/locales/en_US/color.json @@ -0,0 +1,8 @@ +[ + { + "format": "##{x}{x}{x}{x}{x}{x}", + "x": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"], + "weight": 2 + }, + ["Black", "Blue", "Brown", "Gray", "Green", "Orange", "Pink", "Purple", "Red", "Sky Blue", "White", "Yellow"] +] diff --git a/locales/en_US/company.json b/locales/en_US/company.json new file mode 100644 index 0000000..2071f9d --- /dev/null +++ b/locales/en_US/company.json @@ -0,0 +1,14 @@ +[ + { + "format": "{base} {suffix}", + "base": [ + { + "format": "{a}{b}", + "a": ["Acme", "Apex", "Blue", "Bright", "Iron", "North", "Pioneer", "Silver", "Summit", "Vertex"], + "b": ["core", "field", "line", "logic", "point", "soft", "tech", "ware", "wave", "works"] + }, + ["Atlas Industries", "Hudson Partners", "Liberty Holdings", "Riverside", "Smith & Sons"] + ], + "suffix": ["Co.", "Corp.", "Group", "Inc.", "LLC", "Ltd."] + } +] diff --git a/locales/en_US/date.json b/locales/en_US/date.json new file mode 100644 index 0000000..afee0f8 --- /dev/null +++ b/locales/en_US/date.json @@ -0,0 +1,15 @@ +[ + { + "format": "{month}/{day}/{year}", + "month": ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"], + "day": ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28"], + "year": [ + { "format": "#1970" }, + { "format": "#1980" }, + { "format": "#1990", "weight": 2 }, + { "format": "2#0#00", "weight": 3 }, + { "format": "2#0#10", "weight": 3 }, + { "format": "2#020", "weight": 2 } + ] + } +] diff --git a/locales/en_US/email.json b/locales/en_US/email.json new file mode 100644 index 0000000..81d4b14 --- /dev/null +++ b/locales/en_US/email.json @@ -0,0 +1,15 @@ +[ + { + "format": "{local}@{domain}", + "local": [ + { + "format": "{first}{sep}{last}{n}", + "first": ["james", "mary", "john", "patricia", "robert", "linda", "michael", "emma", "david", "olivia"], + "last": ["smith", "johnson", "williams", "brown", "jones", "garcia", "miller", "davis", "wilson", "taylor"], + "sep": [".", "_", "."], + "n": ["", "", "1", "7", "42"] + } + ], + "domain": ["example.com", "example.org", "example.net", "mail.example.com"] + } +] diff --git a/locales/en_US/ip.json b/locales/en_US/ip.json new file mode 100644 index 0000000..67191c7 --- /dev/null +++ b/locales/en_US/ip.json @@ -0,0 +1,11 @@ +[ + { + "format": "{o}.{o}.{o}.{o}", + "weight": 8, + "o": [{ "format": "0", "weight": 3 }, { "format": "10", "weight": 4 }, { "format": "#100", "weight": 2 }] + }, + { + "format": "{g}:{g}:{g}:{g}:{g}:{g}:{g}:{g}", + "g": [{ "format": "{x}{x}{x}{x}", "x": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"] }] + } +] diff --git a/locales/en_US/price.json b/locales/en_US/price.json new file mode 100644 index 0000000..cd0a5d8 --- /dev/null +++ b/locales/en_US/price.json @@ -0,0 +1,7 @@ +[ + { + "format": "${amt}.{cents}", + "amt": [{ "format": "10", "weight": 3 }, { "format": "100", "weight": 2 }, { "format": "1#,000" }], + "cents": [{ "format": "00" }] + } +] diff --git a/locales/en_US/sentence.json b/locales/en_US/sentence.json new file mode 100644 index 0000000..e0666bc --- /dev/null +++ b/locales/en_US/sentence.json @@ -0,0 +1,10 @@ +[ + { + "format": "{lead} {adj} {noun} {verb} {prep} {adj} {noun}.", + "lead": ["A", "Each", "Every", "One", "The"], + "adj": ["ancient", "bright", "fierce", "golden", "lazy", "modern", "quick", "silent"], + "noun": ["engine", "forest", "fox", "garden", "harbor", "mountain", "river", "signal"], + "verb": ["builds", "carries", "crosses", "follows", "guards", "reveals", "shapes"], + "prep": ["across", "beneath", "beyond", "over", "through"] + } +] diff --git a/locales/en_US/ssn.json b/locales/en_US/ssn.json new file mode 100644 index 0000000..d7ff95d --- /dev/null +++ b/locales/en_US/ssn.json @@ -0,0 +1,3 @@ +[ + { "format": "100-00-0000" } +] diff --git a/locales/en_US/time.json b/locales/en_US/time.json new file mode 100644 index 0000000..0a04213 --- /dev/null +++ b/locales/en_US/time.json @@ -0,0 +1,8 @@ +[ + { + "format": "{hour}:{minute} {ampm}", + "hour": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"], + "minute": [{ "format": "{t}0", "t": ["0", "1", "2", "3", "4", "5"] }], + "ampm": ["AM", "PM"] + } +] diff --git a/locales/en_US/url.json b/locales/en_US/url.json new file mode 100644 index 0000000..6c66094 --- /dev/null +++ b/locales/en_US/url.json @@ -0,0 +1,7 @@ +[ + { + "format": "https://{host}{path}", + "host": ["example.com", "www.example.com", "example.org", "blog.example.net", "shop.example.com", "example.io"], + "path": ["", { "format": "/{seg}", "seg": ["about", "account", "blog", "contact", "help", "items", "login", "news", "products", "search"] }] + } +] diff --git a/locales/en_US/username.json b/locales/en_US/username.json new file mode 100644 index 0000000..9fb302f --- /dev/null +++ b/locales/en_US/username.json @@ -0,0 +1,9 @@ +[ + { + "format": "{first}{sep}{last}{n}", + "first": ["alex", "chris", "jamie", "jordan", "morgan", "sam", "taylor", "casey", "riley", "drew"], + "last": ["adams", "brooks", "carter", "evans", "fisher", "grant", "hayes", "lane", "morris", "reed"], + "sep": ["", "", ".", "_"], + "n": ["", "", "", "1", "7", "23", "99"] + } +] diff --git a/locales/en_US/uuid.json b/locales/en_US/uuid.json new file mode 100644 index 0000000..5c78bd6 --- /dev/null +++ b/locales/en_US/uuid.json @@ -0,0 +1,6 @@ +[ + { + "format": "{x}{x}{x}{x}{x}{x}{x}{x}-{x}{x}{x}{x}-{x}{x}{x}{x}-{x}{x}{x}{x}-{x}{x}{x}{x}{x}{x}{x}{x}{x}{x}{x}{x}", + "x": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"] + } +] diff --git a/locales/en_US/version.json b/locales/en_US/version.json new file mode 100644 index 0000000..65bc1cc --- /dev/null +++ b/locales/en_US/version.json @@ -0,0 +1,8 @@ +[ + { + "format": "{pre}{n}.{n}.{n}{suffix}", + "n": [{ "format": "0", "weight": 3 }, { "format": "10" }], + "pre": ["", { "format": "v", "weight": 0.4 }], + "suffix": ["", { "format": "-{tag}.{m}", "tag": ["alpha", "beta", "rc"], "m": ["1", "2", "3"], "weight": 0.3 }] + } +] diff --git a/locales/en_US/word.json b/locales/en_US/word.json new file mode 100644 index 0000000..4f82e7b --- /dev/null +++ b/locales/en_US/word.json @@ -0,0 +1 @@ +["able", "after", "again", "beach", "bridge", "candle", "clever", "dream", "early", "forest", "garden", "gentle", "harbor", "island", "journey", "kettle", "ladder", "meadow", "narrow", "ocean", "pencil", "quiet", "river", "silver", "timber", "under", "velvet", "window", "yellow", "zephyr"] diff --git a/locales/sv_SE/color.json b/locales/sv_SE/color.json new file mode 100644 index 0000000..f8446fd --- /dev/null +++ b/locales/sv_SE/color.json @@ -0,0 +1,8 @@ +[ + { + "format": "##{x}{x}{x}{x}{x}{x}", + "x": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"], + "weight": 2 + }, + ["Blå", "Brun", "Grå", "Grön", "Gul", "Himmelsblå", "Lila", "Orange", "Rosa", "Röd", "Svart", "Vit"] +] diff --git a/locales/sv_SE/company.json b/locales/sv_SE/company.json new file mode 100644 index 0000000..8798a80 --- /dev/null +++ b/locales/sv_SE/company.json @@ -0,0 +1,14 @@ +[ + { + "format": "{base} {suffix}", + "base": [ + { + "format": "{a}{b}", + "a": ["Berg", "Blå", "Järn", "Nord", "Ny", "Sjö", "Skog", "Sol", "Sten", "Stor"], + "b": ["bygg", "data", "gruppen", "handel", "konsult", "logistik", "produkter", "system", "teknik", "verkstad"] + }, + ["Aktiebolaget Vega", "Ekonomihuset", "Lindberg", "Nordström", "Svensson & Co"] + ], + "suffix": ["AB", "AB", "AB", "HB", "KB"] + } +] diff --git a/locales/sv_SE/date.json b/locales/sv_SE/date.json new file mode 100644 index 0000000..f19ce7b --- /dev/null +++ b/locales/sv_SE/date.json @@ -0,0 +1,15 @@ +[ + { + "format": "{year}-{month}-{day}", + "month": ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"], + "day": ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28"], + "year": [ + { "format": "#1970" }, + { "format": "#1980" }, + { "format": "#1990", "weight": 2 }, + { "format": "2#0#00", "weight": 3 }, + { "format": "2#0#10", "weight": 3 }, + { "format": "2#020", "weight": 2 } + ] + } +] diff --git a/locales/sv_SE/email.json b/locales/sv_SE/email.json new file mode 100644 index 0000000..6334fdf --- /dev/null +++ b/locales/sv_SE/email.json @@ -0,0 +1,15 @@ +[ + { + "format": "{local}@{domain}", + "local": [ + { + "format": "{first}{sep}{last}{n}", + "first": ["erik", "anna", "lars", "karin", "johan", "sara", "anders", "emma", "per", "sofia"], + "last": ["andersson", "johansson", "karlsson", "nilsson", "eriksson", "larsson", "olsson", "persson", "svensson", "gustafsson"], + "sep": [".", "_", "."], + "n": ["", "", "1", "7", "42"] + } + ], + "domain": ["example.com", "example.org", "example.net", "mail.example.com"] + } +] diff --git a/locales/sv_SE/ip.json b/locales/sv_SE/ip.json new file mode 100644 index 0000000..67191c7 --- /dev/null +++ b/locales/sv_SE/ip.json @@ -0,0 +1,11 @@ +[ + { + "format": "{o}.{o}.{o}.{o}", + "weight": 8, + "o": [{ "format": "0", "weight": 3 }, { "format": "10", "weight": 4 }, { "format": "#100", "weight": 2 }] + }, + { + "format": "{g}:{g}:{g}:{g}:{g}:{g}:{g}:{g}", + "g": [{ "format": "{x}{x}{x}{x}", "x": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"] }] + } +] diff --git a/locales/sv_SE/price.json b/locales/sv_SE/price.json new file mode 100644 index 0000000..8c31782 --- /dev/null +++ b/locales/sv_SE/price.json @@ -0,0 +1,7 @@ +[ + { + "format": "{amt}{ore} kr", + "amt": [{ "format": "10", "weight": 3 }, { "format": "100", "weight": 2 }, { "format": "1 000" }], + "ore": ["", { "format": ",{c}", "c": [{ "format": "00" }], "weight": 0.4 }] + } +] diff --git a/locales/sv_SE/sentence.json b/locales/sv_SE/sentence.json new file mode 100644 index 0000000..797d48b --- /dev/null +++ b/locales/sv_SE/sentence.json @@ -0,0 +1,10 @@ +[ + { + "format": "{lead} {adj} {noun} {verb} {prep} {adj} {noun}.", + "lead": ["Alla", "Den", "En", "Ett", "Varje"], + "adj": ["gamla", "gyllene", "ljusa", "mörka", "snabba", "stora", "tysta", "vilda"], + "noun": ["berget", "floden", "hamnen", "motorn", "räven", "signalen", "skogen", "trädgården"], + "verb": ["bygger", "bär", "följer", "formar", "korsar", "når", "vaktar"], + "prep": ["bortom", "genom", "längs", "under", "över"] + } +] diff --git a/locales/sv_SE/ssn.json b/locales/sv_SE/ssn.json new file mode 100644 index 0000000..7329e21 --- /dev/null +++ b/locales/sv_SE/ssn.json @@ -0,0 +1,8 @@ +[ + { + "format": "{yy}{month}{day}-0000", + "yy": [{ "format": "00" }], + "month": ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"], + "day": ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28"] + } +] diff --git a/locales/sv_SE/time.json b/locales/sv_SE/time.json new file mode 100644 index 0000000..856e733 --- /dev/null +++ b/locales/sv_SE/time.json @@ -0,0 +1,8 @@ +[ + { + "format": "{hour}:{minute}{sec}", + "hour": [{ "format": "#00", "weight": 4 }, { "format": "#10", "weight": 4 }, { "format": "2{t}", "t": ["0", "1", "2", "3"], "weight": 2 }], + "minute": [{ "format": "{t}0", "t": ["0", "1", "2", "3", "4", "5"] }], + "sec": ["", { "format": ":{s}", "s": [{ "format": "{t}0", "t": ["0", "1", "2", "3", "4", "5"] }], "weight": 0.4 }] + } +] diff --git a/locales/sv_SE/url.json b/locales/sv_SE/url.json new file mode 100644 index 0000000..9fef1ee --- /dev/null +++ b/locales/sv_SE/url.json @@ -0,0 +1,7 @@ +[ + { + "format": "https://{host}{path}", + "host": ["example.com", "www.example.com", "example.org", "blogg.example.net", "butik.example.com", "example.se"], + "path": ["", { "format": "/{seg}", "seg": ["om", "produkter", "blogg", "kontakt", "hjalp", "artiklar", "logga-in", "nyheter", "start", "sok"] }] + } +] diff --git a/locales/sv_SE/username.json b/locales/sv_SE/username.json new file mode 100644 index 0000000..5cda617 --- /dev/null +++ b/locales/sv_SE/username.json @@ -0,0 +1,9 @@ +[ + { + "format": "{first}{sep}{last}{n}", + "first": ["erik", "anna", "lars", "karin", "johan", "sara", "anders", "emma", "per", "sofia"], + "last": ["berg", "lind", "holm", "strom", "dahl", "ek", "sjo", "ahl", "falk", "ros"], + "sep": ["", "", ".", "_"], + "n": ["", "", "", "1", "7", "23", "99"] + } +] diff --git a/locales/sv_SE/uuid.json b/locales/sv_SE/uuid.json new file mode 100644 index 0000000..5c78bd6 --- /dev/null +++ b/locales/sv_SE/uuid.json @@ -0,0 +1,6 @@ +[ + { + "format": "{x}{x}{x}{x}{x}{x}{x}{x}-{x}{x}{x}{x}-{x}{x}{x}{x}-{x}{x}{x}{x}-{x}{x}{x}{x}{x}{x}{x}{x}{x}{x}{x}{x}", + "x": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"] + } +] diff --git a/locales/sv_SE/version.json b/locales/sv_SE/version.json new file mode 100644 index 0000000..65bc1cc --- /dev/null +++ b/locales/sv_SE/version.json @@ -0,0 +1,8 @@ +[ + { + "format": "{pre}{n}.{n}.{n}{suffix}", + "n": [{ "format": "0", "weight": 3 }, { "format": "10" }], + "pre": ["", { "format": "v", "weight": 0.4 }], + "suffix": ["", { "format": "-{tag}.{m}", "tag": ["alpha", "beta", "rc"], "m": ["1", "2", "3"], "weight": 0.3 }] + } +] diff --git a/locales/sv_SE/word.json b/locales/sv_SE/word.json new file mode 100644 index 0000000..0f579b1 --- /dev/null +++ b/locales/sv_SE/word.json @@ -0,0 +1 @@ +["dröm", "fjäll", "glädje", "hav", "höst", "insjö", "källa", "ljus", "morgon", "norr", "ödmjuk", "penna", "regn", "skog", "sommar", "stjärna", "träd", "under", "vinter", "väg", "åker", "äng", "öken", "blomma", "fågel", "gata", "höjd", "klocka", "ljud", "måne"]