Repository navigation
Releases: hegeldev/hegel
Release list
libhegel v0.49.0
This patch adds HEGEL_MAX_SIZE_DEFAULT, which a frontend passes as the max_size of hegel_string_generator_text or hegel_generate_bytes when the user gave no maximum, or of hegel_new_collection for a collection that builds text or bytes, such as text whose characters come from an arbitrary generator. libhegel then applies its default of 100, or min_size + 100 when min_size is above 100, so every frontend's text and binary generators share one default instead of each hard-coding its own. UINT64_MAX still means no upper bound. The sentinel is UINT64_MAX - 1, so that value is reserved: a frontend passing a user's explicit maximum should pass UINT64_MAX for anything at or above HEGEL_MAX_SIZE_DEFAULT, which no allocation could reach anyway.
It also adds HEGEL_FILTER_ATTEMPTS, the number of times a filtered generator draws a value before it rejects the test case (3), so that every frontend's filter uses the engine's number.
It also adds hegel_settings_set_from_string, which sets one setting from its hegel.toml key and a value given as text, in the vocabulary hegel.toml uses for that key, with these spellings for values that are not strings there: integers as decimal digits, optionally after a + (no _ separators or 0x prefix), booleans as the HEGEL_* environment variables take them, and lists such as phases and suppress_health_check as comma-separated names. A frontend's command-line interface can pass each flag through it, so every setting is settable from the command line without the frontend knowing each setting's vocabulary. unbounded_choices and the database key (database_key) are settable this way too; only the test location, which has four parts, still needs hegel_settings_set_test_location.
It also moves the splicing of explicit grammar terminals into libhegel. A frontend drawing a grammar string whose explicit terminals take values from the user's own generators now starts a draw with hegel_grammar_draw_new, calls hegel_grammar_draw_next to learn which terminal needs a value next, draws that value and hands it over with hegel_grammar_draw_provide, and reads the finished string with hegel_grammar_draw_result once hegel_grammar_draw_next returns HEGEL_E_NOT_FOUND:
hegel_grammar_draw_t *draw;
hegel_grammar_draw_new(ctx, grammar, 0, &draw);
size_t terminal;
hegel_result_t rc;
while ((rc = hegel_grammar_draw_next(ctx, tc, draw, &terminal)) == HEGEL_OK) {
/* draw a value for explicit_names[terminal] */
hegel_grammar_draw_provide(ctx, draw, value);
}
if (rc == HEGEL_E_NOT_FOUND)
hegel_grammar_draw_result(ctx, draw, &string);
hegel_grammar_draw_free(ctx, draw);libhegel replaces each placeholder marker with its value, keeps the whole string, values included, under the size cap by drawing it again with less room for the grammar's own text when the values overflow it, and rejects the test case after HEGEL_FILTER_ATTEMPTS attempts that do not fit, so a frontend no longer reimplements any of this. The draw's max_size is read as hegel_generate_grammar reads its own: 0 means the grammar's cap, and a cap below the grammar's smallest string or above its cap is read as that. A draw belongs to the choice stream of the test-case handle it is first advanced with: hegel_grammar_draw_next accepts that handle and its block handles from hegel_test_case_block, returns HEGEL_E_INVALID_ARG for a handle on another stream (a clone, or a later test case's handle), and a draw handle used from two threads at once returns HEGEL_E_CONCURRENT_USE. hegel_generate_grammar and hegel_grammar_placeholder still work as before.
The header's list of constructors and their matching frees now includes hegel_settings_new_for_profile, hegel_new_recursion and the new grammar draw functions, and the documentation of hegel_stop_span no longer claims that libhegel retries a discarded span itself: the caller draws again.
It also makes the unbounded_choices setting reachable the way the other settings are: profiles in hegel.toml accept an unbounded_choices key (a boolean), and the HEGEL_UNBOUNDED_CHOICES environment variable (true, 1 or yes, or false, 0 or no) sets it over the resolved profile. Previously it could only be set through hegel_settings_set_unbounded_choices or carried by a registered profile.
It also moves the policy of a frontend's repeat loop (run the body as many times as the engine wants, so that a failure shrinks to the fewest repetitions) into libhegel, as four new functions over a hegel_repeat_t handle. A frontend starts the loop with hegel_new_repeat, asks hegel_repeat_more before each repetition whether to run another, tells the engine with hegel_repeat_failed when a repetition failed before it lets the failure propagate (a repetition that only fails an assumption is skipped, and needs no call), and releases the handle with hegel_repeat_free:
hegel_repeat_t *repeat;
hegel_new_repeat(ctx, tc, &repeat);
bool more;
while (hegel_repeat_more(ctx, tc, repeat, &more) == HEGEL_OK && more) {
/* note "// Repetition #N", run the body on a block of tc */
if (/* the body failed */) {
hegel_repeat_failed(ctx, tc, repeat);
/* rethrow */
}
}
hegel_repeat_free(ctx, repeat);The choices the engine makes are the ones the Rust frontend's own loop used to make, so a reproduce blob printed by an earlier release still replays once a frontend switches to these functions.
It also renames the type of the recursion handle in the header from HegelRecursion to hegel_recursion_t, the name the documentation and every other handle type already used. A C consumer that spelt the type out should replace HegelRecursion with hegel_recursion_t; the functions are unchanged.
It also publishes HEGEL_RECURSION_ATTEMPTS, the number of attempts in a row that hegel_recursion_leaf and hegel_recursion_finish may discard before the engine rejects the test case (9), which the recursion documentation had left unspecified. The documentation of HEGEL_HC_LARGE_INITIAL_TEST_CASE now says that the health check aborts the run, as it does, rather than warns; and the documentation of hegel_verbosity_t now describes what libhegel itself prints at each level rather than what a frontend might.
It also adds the environment variables the remaining per-run settings were missing, so that every setting but the per-test database_key and test_location can be changed for one run without editing the test: HEGEL_VERBOSITY (quiet, normal, verbose or debug), HEGEL_BACKEND (default or urandom), HEGEL_REPORT_MULTIPLE_FAILURES (true, 1 or yes, or false, 0 or no), HEGEL_PHASES (comma-separated phase names, or none for no phases) and HEGEL_SUPPRESS_HEALTH_CHECK (comma-separated health check names, all, or none for no checks). As with the existing variables, each applies over the resolved profile and under the setters, an empty value is ignored, and a malformed value makes hegel_settings_new and hegel_settings_new_for_profile fail with a message naming the variable.
Hegel for OCaml v0.26.7
This patch adds Stateful.Pool.to_list and Stateful.Concurrent_pool.to_list, which return a pool's values, each passed to the pool's clone.
Hegel for OCaml v0.26.6
This patch fixes an OxCaml mode error in the run that module%hegel_concurrent_state_machine generates when it is passed a concurrency capability @ local.
Hegel for OCaml v0.26.5
This patch moves Hegel for OCaml into the hegeldev/hegel monorepo, next to the engine it drives, where it is built and tested against the in-tree libhegel. The opam packages are used exactly as before, and the bundled engine stays at libhegel 0.48.0.
The library no longer downloads libhegel. Where it used to fall back to a checksum-verified download from the libhegel GitHub release, it now looks for $HEGEL_LIBHEGEL_PATH, then the engine bundled into the installed package, then the in-tree build of a hegeldev/hegel checkout (target/release/libhegel_c.<ext>, or target/debug/, under $CARGO_TARGET_DIR or the nearest directory above the working directory that has one), and fails with a message saying so when none is found. opam install hegel is unaffected, since every release bundles its engine; a git pin of the package now needs HEGEL_LIBHEGEL_PATH pointing at a libhegel library, and the HEGEL_LIBHEGEL_NO_DOWNLOAD variable no longer does anything. To pin the development version, pin the monorepo's frontends/ocaml subpath:
opam pin add --subpath frontends/ocaml hegel "git+https://github.com/hegeldev/hegel.git"libhegel v0.48.0
This release makes the string generators follow the host's Unicode version. A binding sets it once with the new hegel_set_unicode_version, passing a version number such as "15.1.0" (Python's unicodedata.unidata_version, say): the General Categories a text alphabet is built from, and the \w, \d and \s, word boundaries and case-insensitive matching of regex and grammar patterns, then follow the Unicode tables of that version rather than the engine's newest. A string drawn for a host whose Unicode is older than the engine's is classified as that host classifies it, where it could previously contain a character the host did not know yet or put in another category. The engine has tables for Unicode 14.0.0 to 17.0.0, the versions of CPython 3.11 to 3.15; the empty string selects its newest tables, which a version newer than them uses too, and a version it has no tables for is an invalid argument. The version is read when a generator or grammar is built, so a binding that never sets it gets the engine's newest tables, as before.
This release also accepts \z in regex patterns, the end-of-string anchor Python 3.14 added to re as a spelling of \Z, and rejects as an invalid argument a float draw whose bounds leave only an infinity while infinities are disallowed (a min_value of inf or a max_value of -inf, possibly after stepping an exclusive bound), which used to fail as an internal error.
It also fixes a shrinking regression introduced in 0.46.0. A run that reports a single failure shrinks only the smallest failure it found, but shrinking that failure can run into a different failure with a smaller example than any seen before, and the run then reported that example without shrinking it. Such a failure is now shrunk before it is reported, so the reported failure is minimal again.
libhegel v0.47.2
This patch updates the bug-report link in internal error messages and in the HEGEL_E_INTERNAL documentation to point at https://github.com/hegeldev/hegel/issues, where Hegel development now lives.