Add locale-neutral misc data: currency, country, language, timezone, mimetype, httpstatus, useragent, coordinate, emoji, car

This commit is contained in:
lilleman
2026-06-09 01:58:49 +02:00
parent cde56b7924
commit eaf99d4542
12 changed files with 211 additions and 4 deletions
+13 -4
View File
@@ -164,10 +164,19 @@ Swedish personnummer): `address`, `color`, `company`, `date`, `email`, `ip`,
`person`, `phone`, `price`, `sentence`, `ssn`, `time`, `url`, `username`,
`version`, `word`.
`data/misc` carries locale-neutral categories: `uuid` (a proper random v4),
`mac`, and `creditcard` (per-network numbers ending in a valid `{luhn()}` digit).
A time-ordered v7 UUID can't be expressed as data, so it's the `{uuid()}` builtin
instead (see **Functions**).
`data/misc` carries locale-neutral categories — universal data that isn't tied to
a language or region:
- ids & networking: `uuid` (a proper random v4), `mac`, `creditcard` (per-network
numbers ending in a valid `{luhn()}` digit)
- reference codes: `currency` (ISO 4217), `country` (ISO 3166), `language` (ISO
639), `timezone` (IANA)
- web & systems: `mimetype`, `httpstatus`, `useragent`
- misc: `coordinate` (a lat/long point), `emoji`, `car`
Many carry dotted sub-fields — `currency.symbol`, `country.alpha2`,
`mimetype.ext`, `httpstatus.code`, `car.maker`. A time-ordered v7 UUID can't be
expressed as data, so it's the `{uuid()}` builtin instead (see **Functions**).
## Data format
+10
View File
@@ -0,0 +1,10 @@
[
{ "format": "{maker} {model}", "maker": ["BMW"], "model": ["3 Series", "5 Series", "X3", "X5"] },
{ "format": "{maker} {model}", "maker": ["Ford"], "model": ["Fiesta", "Focus", "Mustang", "Explorer"] },
{ "format": "{maker} {model}", "maker": ["Honda"], "model": ["Civic", "Accord", "CR-V", "Jazz"] },
{ "format": "{maker} {model}", "maker": ["Mercedes-Benz"], "model": ["A-Class", "C-Class", "E-Class", "GLC"] },
{ "format": "{maker} {model}", "maker": ["Tesla"], "model": ["Model 3", "Model S", "Model X", "Model Y"] },
{ "format": "{maker} {model}", "maker": ["Toyota"], "model": ["Corolla", "Camry", "RAV4", "Yaris"] },
{ "format": "{maker} {model}", "maker": ["Volkswagen"], "model": ["Golf", "Passat", "Polo", "Tiguan"] },
{ "format": "{maker} {model}", "maker": ["Volvo"], "model": ["XC40", "XC60", "XC90", "V60"] }
]
+7
View File
@@ -0,0 +1,7 @@
[
{
"format": "{lat}, {lon}",
"lat": { "format": "{float(-90,90,6)}" },
"lon": { "format": "{float(-180,180,6)}" }
}
]
+22
View File
@@ -0,0 +1,22 @@
[
{ "format": "{name}", "name": ["Australia"], "alpha2": ["AU"], "alpha3": ["AUS"] },
{ "format": "{name}", "name": ["Brazil"], "alpha2": ["BR"], "alpha3": ["BRA"] },
{ "format": "{name}", "name": ["Canada"], "alpha2": ["CA"], "alpha3": ["CAN"] },
{ "format": "{name}", "name": ["China"], "alpha2": ["CN"], "alpha3": ["CHN"] },
{ "format": "{name}", "name": ["Denmark"], "alpha2": ["DK"], "alpha3": ["DNK"] },
{ "format": "{name}", "name": ["Finland"], "alpha2": ["FI"], "alpha3": ["FIN"] },
{ "format": "{name}", "name": ["France"], "alpha2": ["FR"], "alpha3": ["FRA"] },
{ "format": "{name}", "name": ["Germany"], "alpha2": ["DE"], "alpha3": ["DEU"] },
{ "format": "{name}", "name": ["India"], "alpha2": ["IN"], "alpha3": ["IND"] },
{ "format": "{name}", "name": ["Italy"], "alpha2": ["IT"], "alpha3": ["ITA"] },
{ "format": "{name}", "name": ["Japan"], "alpha2": ["JP"], "alpha3": ["JPN"] },
{ "format": "{name}", "name": ["Mexico"], "alpha2": ["MX"], "alpha3": ["MEX"] },
{ "format": "{name}", "name": ["Netherlands"], "alpha2": ["NL"], "alpha3": ["NLD"] },
{ "format": "{name}", "name": ["Norway"], "alpha2": ["NO"], "alpha3": ["NOR"] },
{ "format": "{name}", "name": ["Poland"], "alpha2": ["PL"], "alpha3": ["POL"] },
{ "format": "{name}", "name": ["Spain"], "alpha2": ["ES"], "alpha3": ["ESP"] },
{ "format": "{name}", "name": ["Sweden"], "alpha2": ["SE"], "alpha3": ["SWE"] },
{ "format": "{name}", "name": ["Switzerland"], "alpha2": ["CH"], "alpha3": ["CHE"] },
{ "format": "{name}", "name": ["United Kingdom"], "alpha2": ["GB"], "alpha3": ["GBR"] },
{ "format": "{name}", "name": ["United States"], "alpha2": ["US"], "alpha3": ["USA"] }
]
+18
View File
@@ -0,0 +1,18 @@
[
{ "format": "{code}", "code": ["AUD"], "name": ["Australian Dollar"], "symbol": ["$"] },
{ "format": "{code}", "code": ["BRL"], "name": ["Brazilian Real"], "symbol": ["R$"] },
{ "format": "{code}", "code": ["CAD"], "name": ["Canadian Dollar"], "symbol": ["$"] },
{ "format": "{code}", "code": ["CHF"], "name": ["Swiss Franc"], "symbol": ["CHF"] },
{ "format": "{code}", "code": ["CNY"], "name": ["Chinese Yuan"], "symbol": ["¥"] },
{ "format": "{code}", "code": ["DKK"], "name": ["Danish Krone"], "symbol": ["kr"] },
{ "format": "{code}", "code": ["EUR"], "name": ["Euro"], "symbol": ["€"] },
{ "format": "{code}", "code": ["GBP"], "name": ["Pound Sterling"], "symbol": ["£"] },
{ "format": "{code}", "code": ["INR"], "name": ["Indian Rupee"], "symbol": ["₹"] },
{ "format": "{code}", "code": ["JPY"], "name": ["Japanese Yen"], "symbol": ["¥"] },
{ "format": "{code}", "code": ["MXN"], "name": ["Mexican Peso"], "symbol": ["$"] },
{ "format": "{code}", "code": ["NOK"], "name": ["Norwegian Krone"], "symbol": ["kr"] },
{ "format": "{code}", "code": ["PLN"], "name": ["Polish Zloty"], "symbol": ["zł"] },
{ "format": "{code}", "code": ["SEK"], "name": ["Swedish Krona"], "symbol": ["kr"] },
{ "format": "{code}", "code": ["USD"], "name": ["US Dollar"], "symbol": ["$"] },
{ "format": "{code}", "code": ["ZAR"], "name": ["South African Rand"], "symbol": ["R"] }
]
+6
View File
@@ -0,0 +1,6 @@
[
"😀", "😂", "😍", "🤔", "😎", "😭", "😡", "👍", "👎", "🙏",
"👏", "🙌", "💪", "🔥", "✨", "🎉", "❤️", "💔", "💯", "👀",
"🚀", "⭐", "🌈", "☀️", "🌙", "⚡", "❄️", "🍕", "🍔", "🍺",
"☕", "🎂", "🐶", "🐱", "🦊", "🐢", "🦄", "🌸", "🌍", "💡"
]
+18
View File
@@ -0,0 +1,18 @@
[
{ "format": "{code} {reason}", "code": ["200"], "reason": ["OK"] },
{ "format": "{code} {reason}", "code": ["201"], "reason": ["Created"] },
{ "format": "{code} {reason}", "code": ["204"], "reason": ["No Content"] },
{ "format": "{code} {reason}", "code": ["301"], "reason": ["Moved Permanently"] },
{ "format": "{code} {reason}", "code": ["302"], "reason": ["Found"] },
{ "format": "{code} {reason}", "code": ["304"], "reason": ["Not Modified"] },
{ "format": "{code} {reason}", "code": ["400"], "reason": ["Bad Request"] },
{ "format": "{code} {reason}", "code": ["401"], "reason": ["Unauthorized"] },
{ "format": "{code} {reason}", "code": ["403"], "reason": ["Forbidden"] },
{ "format": "{code} {reason}", "code": ["404"], "reason": ["Not Found"] },
{ "format": "{code} {reason}", "code": ["409"], "reason": ["Conflict"] },
{ "format": "{code} {reason}", "code": ["422"], "reason": ["Unprocessable Entity"] },
{ "format": "{code} {reason}", "code": ["429"], "reason": ["Too Many Requests"] },
{ "format": "{code} {reason}", "code": ["500"], "reason": ["Internal Server Error"] },
{ "format": "{code} {reason}", "code": ["502"], "reason": ["Bad Gateway"] },
{ "format": "{code} {reason}", "code": ["503"], "reason": ["Service Unavailable"] }
]
+18
View File
@@ -0,0 +1,18 @@
[
{ "format": "{name}", "name": ["Arabic"], "code": ["ar"] },
{ "format": "{name}", "name": ["Chinese"], "code": ["zh"] },
{ "format": "{name}", "name": ["Danish"], "code": ["da"] },
{ "format": "{name}", "name": ["Dutch"], "code": ["nl"] },
{ "format": "{name}", "name": ["English"], "code": ["en"] },
{ "format": "{name}", "name": ["Finnish"], "code": ["fi"] },
{ "format": "{name}", "name": ["French"], "code": ["fr"] },
{ "format": "{name}", "name": ["German"], "code": ["de"] },
{ "format": "{name}", "name": ["Italian"], "code": ["it"] },
{ "format": "{name}", "name": ["Japanese"], "code": ["ja"] },
{ "format": "{name}", "name": ["Norwegian"], "code": ["no"] },
{ "format": "{name}", "name": ["Polish"], "code": ["pl"] },
{ "format": "{name}", "name": ["Portuguese"], "code": ["pt"] },
{ "format": "{name}", "name": ["Russian"], "code": ["ru"] },
{ "format": "{name}", "name": ["Spanish"], "code": ["es"] },
{ "format": "{name}", "name": ["Swedish"], "code": ["sv"] }
]
+17
View File
@@ -0,0 +1,17 @@
[
{ "format": "{type}", "type": ["application/gzip"], "ext": [".gz"] },
{ "format": "{type}", "type": ["application/json"], "ext": [".json"] },
{ "format": "{type}", "type": ["application/pdf"], "ext": [".pdf"] },
{ "format": "{type}", "type": ["application/xml"], "ext": [".xml"] },
{ "format": "{type}", "type": ["application/zip"], "ext": [".zip"] },
{ "format": "{type}", "type": ["audio/mpeg"], "ext": [".mp3"] },
{ "format": "{type}", "type": ["image/gif"], "ext": [".gif"] },
{ "format": "{type}", "type": ["image/jpeg"], "ext": [".jpg"] },
{ "format": "{type}", "type": ["image/png"], "ext": [".png"] },
{ "format": "{type}", "type": ["image/svg+xml"], "ext": [".svg"] },
{ "format": "{type}", "type": ["image/webp"], "ext": [".webp"] },
{ "format": "{type}", "type": ["text/csv"], "ext": [".csv"] },
{ "format": "{type}", "type": ["text/html"], "ext": [".html"] },
{ "format": "{type}", "type": ["text/plain"], "ext": [".txt"] },
{ "format": "{type}", "type": ["video/mp4"], "ext": [".mp4"] }
]
+29
View File
@@ -0,0 +1,29 @@
[
"UTC",
"Africa/Cairo",
"Africa/Johannesburg",
"America/Chicago",
"America/Denver",
"America/Los_Angeles",
"America/Mexico_City",
"America/New_York",
"America/Sao_Paulo",
"America/Toronto",
"Asia/Dubai",
"Asia/Hong_Kong",
"Asia/Kolkata",
"Asia/Shanghai",
"Asia/Singapore",
"Asia/Tokyo",
"Australia/Sydney",
"Europe/Amsterdam",
"Europe/Berlin",
"Europe/London",
"Europe/Madrid",
"Europe/Moscow",
"Europe/Oslo",
"Europe/Paris",
"Europe/Stockholm",
"Europe/Warsaw",
"Pacific/Auckland"
]
+10
View File
@@ -0,0 +1,10 @@
[
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:123.0) Gecko/20100101 Firefox/123.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15",
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0"
]
+43
View File
@@ -2,6 +2,7 @@ package fakes
import (
"regexp"
"strconv"
"strings"
"testing"
"time"
@@ -84,6 +85,48 @@ func TestShippedMiscCategories(t *testing.T) {
}
}
// TestShippedMiscReferenceData covers the locale-neutral reference categories:
// codes follow their standard shape, dotted sub-paths resolve, emoji is a real
// glyph, and a coordinate parses to a point within geographic bounds.
func TestShippedMiscReferenceData(t *testing.T) {
f := newFakes(t, "data/misc", WithSeed(1))
re := map[string]*regexp.Regexp{
"currency": regexp.MustCompile(`^[A-Z]{3}$`),
"currency.name": regexp.MustCompile(`\p{L}`),
"currency.symbol": regexp.MustCompile(`^\S+$`),
"country": regexp.MustCompile(`\p{L}`),
"country.alpha2": regexp.MustCompile(`^[A-Z]{2}$`),
"country.alpha3": regexp.MustCompile(`^[A-Z]{3}$`),
"language": regexp.MustCompile(`\p{L}`),
"language.code": regexp.MustCompile(`^[a-z]{2}$`),
"timezone": regexp.MustCompile(`^([A-Za-z_]+(/[A-Za-z_]+)+|UTC)$`),
"mimetype": regexp.MustCompile(`^[a-z]+/[a-z0-9.+-]+$`),
"mimetype.ext": regexp.MustCompile(`^\.[a-z0-9]+$`),
"httpstatus": regexp.MustCompile(`^[1-5]\d{2} \S.*$`),
"httpstatus.code": regexp.MustCompile(`^[1-5]\d{2}$`),
"useragent": regexp.MustCompile(`^Mozilla/5\.0 .+`),
"car": regexp.MustCompile(`^\S.* \S`),
"car.maker": regexp.MustCompile(`^\S`),
}
for i := 0; i < 100; i++ {
for p, rx := range re {
if v := fake(t, f, p); !rx.MatchString(v) {
t.Fatalf("misc %s = %q, want %s", p, v, rx)
}
}
if e := fake(t, f, "emoji"); e == "" || []rune(e)[0] < 128 {
t.Fatalf("emoji %q is not a non-ASCII glyph", e)
}
c := fake(t, f, "coordinate")
parts := strings.SplitN(c, ", ", 2)
lat, err1 := strconv.ParseFloat(parts[0], 64)
lon, err2 := strconv.ParseFloat(parts[len(parts)-1], 64)
if len(parts) != 2 || err1 != nil || err2 != nil || lat < -90 || lat > 90 || lon < -180 || lon > 180 {
t.Fatalf("coordinate %q is not a 'lat, lon' point within bounds", c)
}
}
}
// TestSwedishPersonnummer checks the two rules the shape regex can't: the date
// is a real calendar date (so month-length variants never emit e.g. Apr 31 or
// Feb 30) and the trailing digit is a valid Luhn checksum over the other nine.