Generate massive amounts of fake (but realistic) data for testing and development.
An OCaml port of @faker-js/faker 10.6.0 with seed-for-seed output parity.
af_ZA to zu_ZA.dune test checks this against fixtures generated by running faker-js itself.unix.opam install fakerFor the development version, pin it from git:
opam pin add faker https://github.com/barteo/faker-ocaml.gitThen add it to your dune file:
(executable
(name main)
(libraries faker))type user = {
user_id : string;
username : string;
email : string;
avatar : string;
password : string;
birthdate : float; (* epoch milliseconds *)
registered_at : float;
}
(* Bind each value with [let] so the RNG is consumed in the same order as faker-js
(OCaml evaluates record fields right to left). *)
let create_random_user f =
let user_id = Faker.String.uuid f in
let username = Faker.Internet.username f in
let email = Faker.Internet.email f in
let avatar = Faker.Image.avatar f in
let password = Faker.Internet.password f in
let birthdate = Faker.Date.birthdate f in
let registered_at = Faker.Date.past f in
{ user_id; username; email; avatar; password; birthdate; registered_at }
let () =
let f = Faker.create () in
let users = Faker.Helpers.multiple ~count:(`N 5) (fun _ -> create_random_user f) f in
Array.iter
(fun u -> Printf.printf "%s <%s>, born %s\n" u.username u.email (Faker.Date_util.to_iso u.birthdate))
usersA few more, with a fixed seed:
let () =
let f = Faker.create ~seed:42 () in
print_endline (Faker.Person.full_name f); (* Nikita Crist *)
print_endline (Faker.Location.street_address ~use_full_address:true f);
print_endline (Faker.Internet.email f);
print_endline (Faker.String.uuid f);
Printf.printf "%d\n" (Faker.Number.int ~min:1 ~max:10 f);
print_endline (Faker.Helpers.from_reg_exp "[A-Z]{3}-[0-9]{4}" f)The API mirrors faker-js, so the faker-js API reference documents every method. It translates like this:
faker-js | OCaml |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NumberOrRange option becomes `N n or `Range (min, max). String unions become polymorphic variants.float epoch milliseconds. Use Faker.Date_util.to_iso and of_iso to convert.bigint is a Faker.Bigint.t, an arbitrary-precision integer (of_int, of_string, to_string, ...).Faker.Faker_error msg, with the same messages as faker-js.All 26 faker-js modules are ported, each as Faker.<Module>: Airline, Animal, Book, Color, Commerce, Company, Database, Datatype, Date, Finance, Food, Git, Hacker, Helpers, Image, Internet, Location, Lorem, Music, Number, Person, Phone, Science, String, System, Vehicle and Word.
Faker.Helpers.fake combines faker methods using a mustache string format:
print_endline
(Faker.Helpers.fake "Hello {{person.prefix}} {{person.lastName}}, how are you today?" f)All 77 faker-js locales are included. Faker.create uses English (en with base as fallback). Every locale has a module in Faker.Locales, named after its code (De, De_AT, Pt_BR, Zh_CN, ...), with the same pieces faker-js exports:
let () =
let f = Faker.Locales.De.faker () in (* fakerDE: a shared instance *)
Faker.seed f 42;
print_endline (Faker.Person.full_name f); (* Melinda Dragu *)
(* Your own instance, with the same fallback chain as fakerDE_AT: de_AT, de, en, base. *)
let g = Faker.create ~locale:(Faker.Locales.De_AT.chain ()) ~seed:42 () in
print_endline (Faker.Location.city g)Like importing a single locale from @faker-js/faker, a program only links the locales it references, so English-only programs stay small. Faker.All_locales (allLocales, allFakers) references every locale and links all of them (about 1.2 MB more).
Locale data is generated from the faker-js npm package with node tools/gen_locale.mjs, so it is never hand-copied (see CONTRIBUTING.md).
If you want consistent results, you can set your own seed:
let () =
let f = Faker.create () in
Faker.seed f 123;
let first_random = Faker.Number.int f in
(* Setting the seed again resets the sequence. *)
Faker.seed f 123;
let second_random = Faker.Number.int f in
Printf.printf "%b\n" (first_random = second_random) (* true *)Faker.Date methods are relative to the current time by default. For reproducible dates, also fix the reference date with Faker.set_default_ref_date f ms, or pass ~ref_date.
opam install dune alcotest
dune build
dune test # parity fixtures + property tests
ONLY=person dune test --force # one module's parity fixtures
ONLY='sweep_*' dune test --force # every method in every locale (or sweep_de, l10n_ja, ...)
dune exec ./bin/demo.exe -- 42 # one value per module
dune exec ./bin/demo.exe -- 42 ja # ... in another localeFixtures come from the real faker-js package (tools/package.json pins 10.6.0):
cd tools && npm install
node gen_locale.mjs # lib/locales/: every locale's data, chain and instance
node gen_unicode.mjs # lib/internal/unicode_*.ml: JS case mapping and NFKD tables
node gen_fixtures.mjs [group] # test/expected/expected_<group>.ml from tools/cases/<group>.mjsSee docs/PORTING.md for the porting conventions and the parity pitfalls, such as FMA contraction on arm64, UTF-16 vs UTF-8, and JS number formatting.
finance.amount ~auto_format:true always formats as en-US. faker-js uses the runtime's default locale (not the faker locale), so this matches node running in en-US.helpers.fake, a date-returning method yields an ISO string. JS would produce its locale-dependent Date.toString().location.nearbyGPSCoordinate uses a port of V8's fdlibm sin/cos, which is bit-exact with node on arm64.Distributor.exponential calls the platform's libm pow, as node's Math.pow does. Its results can differ in the last bit between platforms (e.g. FreeBSD vs Linux/macOS) in faker-js too, so they match faker-js running on the same platform.Please read the Contributing Guide and the Porting Guide before making a pull request.
All the data and algorithms come from faker-js. Thanks to the faker-js team and everyone who contributed to it, and to Marak Squires for the original faker.js.
MIT. It includes the faker-js license, since the locale data is derived from faker-js.