Files
Mahdi ramezaan zaadeandAlexander Medvednikov 89cbb11d9c tests: expand library and tool coverage and fix exposed HTTP and ASN.1 defects (#29945)
* driver: share monolithic TCC flags with -dump-c-flags

* cgen: preserve core runtime ABI across OS targets without repeated headers

* cgen: use native ARM Linux directory open flags

* cgen: preserve application C bindings and standalone generator contexts

* tests: use a valid local name in the Linux rwmutex fixture

* cgen: restore POSIX file-lock SDK declarations

* tests: add coverage for untested public functions across 26 stdlib modules

714 test functions in 76 files, all new. No source file is modified and no
existing test is changed: `vlib/strconv/atoi_test.v` gains three appended
`test_byte_to_lower_*` functions and is otherwise untouched.

These modules had public functions no test mentioned. Each new test was
measured against the running library rather than derived from the docs, and
each fix in this suite was confirmed by reverting it and watching a test go
red.

Where a module turned out to be all network, display or platform I/O and had
no deterministic surface, or already had a suite covering it, it was skipped
rather than given a test that would be flaky somewhere else. Both are noted
in the file-level comments.

Highlights, by value rather than by size:

- math/easing: all 33 easing functions, asserted by closed form where one
  exists and by the in/out duality and midpoint symmetry otherwise.
- term: the whole of `colors.v`, which had no test at all.
- regex: character classes, quantifiers, groups, the error table and the
  flags, table-driven.
- picohttpparser: hand-built HTTP/1.1 inputs including malformed and
  boundary cases.
- crypto: real RFC 1321, FIPS 180-1/180-2 and RFC 8032 vectors.
- compress/deflate: hand-built RFC 1951 bitstreams and round-trips.
- time: round-trips and boundary dates rather than golden values.

Pre-existing failures on this host are unrelated to these files and fail the
same way on a pristine tree: the bundled tcc's three-digit `%e`/`%g`
exponents, and the Windows-specific `udp_test`, `process_*_test`,
`walk_dir_test` and `zoneinfo_test`. The tcc one is reported separately.

* tests: cover the cbor value API, base32 and leb128 32-bit halves, x/ttf and veb assets

A second coverage pass, same rules as the first: no source file touched,
no existing test modified, every expected value measured rather than
recalled, and each break-control proved by reverting it and watching a
test go red.

cbor: the whole Value accessor family, the decoder's typed reads and the
packer's float widths had no test mentions.

base32: the entire Encoding API and the byte-array entry points. The
suite only drove the default alphabet. RFC 4648 section 10 vectors are
used for both the standard and hex alphabets.

leb128: the 32-bit half was completely untested; only the 64-bit pair
was driven.

x/ttf: the table readers, glyph cache, metrics and kern walk were
untested, and ttf_test.v only asserted one golden bitmap. Added table
parsing and the full rendering pipeline.

veb: filter_html had no test anywhere, and the assets manager's
lookup, exists and minify paths were untested.

* tests: cover the blake2 convenience API, szip entries, os stdin and error paths, strings builder methods and time json helpers

A third coverage pass, same rules: no source file touched, no existing
test modified, expected values measured before being asserted, and each
break-control proved red before restoring.

crypto/blake2s and crypto/blake2b each had 16 of 20 public functions
with no test mention, the largest single gap found. The convenience
constructors, the named digests and the `str` helper are now covered.
The digest values are checked against published vectors rather than
recorded from this tree: BLAKE2s-256("abc") is the RFC 7693 Appendix A
check value, and both files state in a header comment that the wider
vector set was confirmed against CPython 3.13's hashlib, an independent
RFC 7693 implementation.

compress/szip: the entry API had 9 of 19 public functions untested. Its
crc32 assertions compare the archive's stored checksum against
hash.crc32, an independent CRC-32 implementation already in the tree.

os and strings and time: the stdin readers, the error and directory-mode
parameters, the strings.Builder byte methods, and the json conversion
and `clean`/`clean12` formatting.

Behaviours pinned as-is with a `// NOTE:` rather than changed, since
this branch is tests-only:

- Digest.checksum() is not idempotent: a second call re-hashes the
  zero-padded remainder of the previous block.
- szip.open_entry() on an unknown name succeeds silently and leaves the
  reader positioned nowhere.
- szip.write_entry()'s leading-byte guard is dead code, because int(u8)
  is never -1.
- Time.from_json_string() does not round-trip through to_json(), which
  wraps its output in quotes.

* tests: cover veb cors and response helpers, static hosts, and the x json5, jsonc, dataframe, markdown and sessions middleware surfaces

A fourth coverage pass, same rules: no source file touched, no existing
test modified, expected values measured before being asserted, and each
break-control proved red before restoring.

veb: the context response helpers, the CORS option handling, and the
static_hosts map had the largest untested counts in the root module.

x: json5's Doc and path syntax, jsonc's option-taking parsers, the
dataframe construction and Series API, the markdown processor and AST
walker, and x/sessions/veb_middleware, which had no test file at all.

Behaviour pinned as-is with a `// NOTE:` rather than changed, since this
branch is tests-only. Two of these are substantial enough that they are
being reported separately rather than left in a comment:

- CorsOptions.validate_request rejects every request when
  allowed_headers is non-empty, because the loop that checks request
  headers includes Origin, which no allow-list is expected to name.
  Reported as #30074.
- An empty allowed_methods matches nothing, so a minimal CorsOptions
  405s every request including GET.

The rest: EncodeOpts.trailing_commas only takes effect when indent is
also set; markdown's parse puts block text in `literal` with no children
rather than building the inline tree; PlainTextRenderer.render of an
empty source returns a newline; dataframe's `new` trims the index keys
it looks up by but not the `columns` it stores.

* tests: cover the asn1 streaming parser, the wrapper types and the field-option
variants, and the x/crypto ascon, chacha20 and poly1305 surfaces

A fifth coverage pass, same rules: no source file touched, no existing
test modified, expected values measured before being asserted, and each
break-control proved red before restoring.

asn1: the streaming Parser API had the largest untested surface in the
module. peek_tag, read_tag, read_length, read_bytes, read_tlv, reset,
finish and is_empty are now covered, table-driven over hand-built TLV
byte sequences and length tables. The wrapper types and the three
*_with_field_options entry points follow.

x/crypto: ascon's accessors and free paths, the chacha20 and
chacha20poly1305 constant helpers, and poly1305's clone.

Two findings are reported as issues rather than left in comments, because
they are defects rather than gaps:

- Poly1305.clone shares its buffer with its parent, so a forked pair
  computes different tags. Reported as #30151; pinned here with a test
  asserting the measured difference so a fix shows as a changed value.
- The bindings that need OpenSSL cannot run on a host without it. mldsa
  and slhdsa unconditionally include openssl/obj_mac.h, so every build
  fails at C compilation before any assertion runs. Nothing was written
  for them, because tests that could never be executed would be
  unverified assertions. Recorded here so the next person does not
  repeat the discovery.

Everything else is pinned with a NOTE: Enumerated.payload_with_rule
scales by 8, Sequence.into_sequence_of errors on exactly the sequences
it is meant to convert, decode_with_field_options cannot take empty
options, and ascon's new_xof128 panics where new_cxof128 returns an
error.

* tests: cover the pure geometry in gg and m4, os/font variants, the build task
graph, the static file handler, picoev surface, and the veb request_id, sse,
assets and picohttpparser response helpers

A sixth coverage pass, same rules: no source file touched, no existing
test modified, expected values measured before being asserted, and each
break-control proved red before restoring.

The graphics-adjacent modules are mostly untestable without a window, a
GPU or an audio device, and the survey is explicit about which parts are
and are not reachable. What is reachable is: gg's colour structs and
hex/float conversion, m4's transform helpers, the static file handler
called directly rather than through a server, and the sokol clear-pass
and memory builders that do not touch a context.

Behaviour pinned as-is with a NOTE rather than changed, since this branch
is tests-only. The clearest of these are genuine defects and are worth
filing separately:

- os/font.get_path_variant tests fpath, the directory half, where the
  file name was meant, so the bold variant reads a condition that can
  never hold. Measured consequence: LiberationSans-Regular.ttf with
  .bold yields Regular-bold, while .italic yields Italic.
- The static handler guards path traversal with a string prefix rather
  than a path boundary, so a sibling directory named <folder>_secret is
  also served.
- veb.build drops config.repeatable while veb.artifact forwards it, so
  the two agree only by accident.
- veb.csrf.CsrfContext.clear_csrf_token does not compile: it reads a
  free `config` identifier, which the checker accepts and cgen rejects.
  It is recorded in a NOTE rather than tested, because no test can call
  it.
- vlib/gx is now untestable rather than untested: every symbol carries
  @[deprecated_after: '2026-01-24'], and the checker turns a passed
  deprecation date into a hard error, so no test can import it again.
- vlib/db cannot be built in a checkout without thirdparty/sqlite or
  libpq, and x/crypto/mldsa and x/crypto/slhdsa still need OpenSSL. All
  three are reported with that scope rather than papered over.

* tests: cover cmd/tools pure helpers, the orm where-clause and tenant filters,
the transaction nil handles, veb route parsing, and 20 more vlib/v modules

A seventh coverage pass, same rules: no source file touched, no existing
test modified, expected values measured before being asserted, and each
break-control proved red before restoring.

cmd/tools: the tools that are thin or untested were surveyed rather than
assumed. Several turned out to have nothing unit-testable — builders and
bench are main()-only; vsqlite, fast and the measure speed tools cannot
compile in this tree, either because three files in the same directory
redeclare the same symbols or because db.sqlite needs a thirdparty
directory that is absent. What is pure is covered: vgit's commit-line
parsing, measure/file_lists' expansion, vvet's line filtering, vwhere's
file collection, vast's absolute_path, fuzz's string generation, and
vdoc's slug/URL/markdown helpers.

orm: the module is 5,641 lines with 44 test files and 220 test
functions, so gaps were narrow and specific. All 12 OperationKind
keywords are now asserted, including the ones the existing suite skipped;
the tenant-filter state and its default-fallback path; and the
zero-value Tx/Savepoint branches, which no test constructed before.

veb: parse_attrs, parse_query_from_url, parse_form_from_request and
has_route_attributes had no coverage at all, and controller_host is now
called directly rather than only through the registration path.

vlib/v: twenty more modules, chosen from a survey of which public
functions were unmentioned — ansi, cmdexec, debug, embed_file, errors,
pref, skills, token, util and its submodules, vmod.

One point worth recording: a first break-control attempt failed
silently. Breaking trim_attr_arg's inner trim_space left the suite
green, because the field name is normalised twice and the second pass
masks the first. The break was replaced with a discriminating one and
the double normalisation is recorded in a comment rather than a test,
since it cannot be observed this way.

* tests: exercise the V3 JavaScript backend end to end under node

`vlib/v/gen/js` had 22 source files and no test at all, and the fixture
corpus in `vlib/v/gen/js/tests/` was not run by anything. This adds the
first test: it compiles a program with `-b js`, runs the generated file
under node, and asserts on its output.

The compile and run steps are kept separate on purpose, so a failure
says whether the backend or node is at fault.

The tests also pin the backend's scope. It is a compatibility generator
rather than a full JS lowering: it supports `JS.eval` and a literal
`println`, and for anything else it reports
"the V3 JavaScript compatibility generator currently supports only
JS.eval and literal println" at compile time instead of generating code
that would misbehave. Asserting that message is more useful than a test
that pretends the surface is wider than it is, so the unsupported-feature
case is pinned as a diagnostic rather than as a working program.

A first version of this file had a test asserting that program arguments
are forwarded to the generated file. It failed, because `os.args` is
outside the backend's scope. The measurement is what caught it, not a
recall of what the backend should do.

* tests: cover the remaining math, stat, bit, hash, toml and rand config and
utf8 validation surfaces

An eighth and final pass. The survey walked every directory under
vlib/ and matched public names against the test text of each module,
then the candidates were filtered by hand for the two classes that the
survey over-reports: generic type names captured as Foo[T], and type
names whose behaviour is already exercised through @[params] sugar and
helper constructors.

Two of these modules had no test file at all before this:
rand/config and toml/util.

The rest narrows genuine gaps in math (log_n, ilog_b, cot, logf, minmax,
cubic_bezier_coords, the float bit helpers, the _mean wrappers and the
checked big-number variants), net/conv's htonf32/htonf64, hash/wymum,
os's MkdirParams and DiskUsage, and encoding/utf8's validate_str, validate
and the global-punct predicates.

Expected values are mostly invariants rather than literals, so that a
green test means correct behaviour rather than merely current behaviour:
f64_from_bits(f64_bits(x)) == x, wymum(a, b) == hi64(a * b) ^ lo64(a * b),
population_variance_mean(d, m) == population_variance(d), htonf32 is an
involution. Where a literal was unavoidable it came from a probe first.

Behaviour pinned as-is with a NOTE rather than changed. The clearest is
that is_rune_punct and is_rune_global_punct have byte-identical bodies
despite doc comments implying different Unicode tables.

* tests: isolate coverage fixtures and avoid scheduler timing assumptions

* cgen: match Darwin statvfs counter widths and storage

* cgen: preserve metadata handle WinAPI calling convention

* tests(cgen): expect the declared i32 metadata handle result

* tests: follow current APIs and confine coverage fixture cleanup

* tests(cgen): cover standalone and SDK-owned BSD runtime declarations

* driver: match invoked macOS TCC framework flags with flag dumps

* cgen: defer the shipped FastC signal header in standalone builds

* tests: observe pool timestamps and release waiters without expiry races

* tests: add coverage for untested public functions across 26 stdlib modules

714 test functions in 76 files, all new. No source file is modified and no
existing test is changed: `vlib/strconv/atoi_test.v` gains three appended
`test_byte_to_lower_*` functions and is otherwise untouched.

These modules had public functions no test mentioned. Each new test was
measured against the running library rather than derived from the docs, and
each fix in this suite was confirmed by reverting it and watching a test go
red.

Where a module turned out to be all network, display or platform I/O and had
no deterministic surface, or already had a suite covering it, it was skipped
rather than given a test that would be flaky somewhere else. Both are noted
in the file-level comments.

Highlights, by value rather than by size:

- math/easing: all 33 easing functions, asserted by closed form where one
  exists and by the in/out duality and midpoint symmetry otherwise.
- term: the whole of `colors.v`, which had no test at all.
- regex: character classes, quantifiers, groups, the error table and the
  flags, table-driven.
- picohttpparser: hand-built HTTP/1.1 inputs including malformed and
  boundary cases.
- crypto: real RFC 1321, FIPS 180-1/180-2 and RFC 8032 vectors.
- compress/deflate: hand-built RFC 1951 bitstreams and round-trips.
- time: round-trips and boundary dates rather than golden values.

Pre-existing failures on this host are unrelated to these files and fail the
same way on a pristine tree: the bundled tcc's three-digit `%e`/`%g`
exponents, and the Windows-specific `udp_test`, `process_*_test`,
`walk_dir_test` and `zoneinfo_test`. The tcc one is reported separately.

* tests: cover the cbor value API, base32 and leb128 32-bit halves, x/ttf and veb assets

A second coverage pass, same rules as the first: no source file touched,
no existing test modified, every expected value measured rather than
recalled, and each break-control proved by reverting it and watching a
test go red.

cbor: the whole Value accessor family, the decoder's typed reads and the
packer's float widths had no test mentions.

base32: the entire Encoding API and the byte-array entry points. The
suite only drove the default alphabet. RFC 4648 section 10 vectors are
used for both the standard and hex alphabets.

leb128: the 32-bit half was completely untested; only the 64-bit pair
was driven.

x/ttf: the table readers, glyph cache, metrics and kern walk were
untested, and ttf_test.v only asserted one golden bitmap. Added table
parsing and the full rendering pipeline.

veb: filter_html had no test anywhere, and the assets manager's
lookup, exists and minify paths were untested.

* tests: cover the blake2 convenience API, szip entries, os stdin and error paths, strings builder methods and time json helpers

A third coverage pass, same rules: no source file touched, no existing
test modified, expected values measured before being asserted, and each
break-control proved red before restoring.

crypto/blake2s and crypto/blake2b each had 16 of 20 public functions
with no test mention, the largest single gap found. The convenience
constructors, the named digests and the `str` helper are now covered.
The digest values are checked against published vectors rather than
recorded from this tree: BLAKE2s-256("abc") is the RFC 7693 Appendix A
check value, and both files state in a header comment that the wider
vector set was confirmed against CPython 3.13's hashlib, an independent
RFC 7693 implementation.

compress/szip: the entry API had 9 of 19 public functions untested. Its
crc32 assertions compare the archive's stored checksum against
hash.crc32, an independent CRC-32 implementation already in the tree.

os and strings and time: the stdin readers, the error and directory-mode
parameters, the strings.Builder byte methods, and the json conversion
and `clean`/`clean12` formatting.

Behaviours pinned as-is with a `// NOTE:` rather than changed, since
this branch is tests-only:

- Digest.checksum() is not idempotent: a second call re-hashes the
  zero-padded remainder of the previous block.
- szip.open_entry() on an unknown name succeeds silently and leaves the
  reader positioned nowhere.
- szip.write_entry()'s leading-byte guard is dead code, because int(u8)
  is never -1.
- Time.from_json_string() does not round-trip through to_json(), which
  wraps its output in quotes.

* tests: cover veb cors and response helpers, static hosts, and the x json5, jsonc, dataframe, markdown and sessions middleware surfaces

A fourth coverage pass, same rules: no source file touched, no existing
test modified, expected values measured before being asserted, and each
break-control proved red before restoring.

veb: the context response helpers, the CORS option handling, and the
static_hosts map had the largest untested counts in the root module.

x: json5's Doc and path syntax, jsonc's option-taking parsers, the
dataframe construction and Series API, the markdown processor and AST
walker, and x/sessions/veb_middleware, which had no test file at all.

Behaviour pinned as-is with a `// NOTE:` rather than changed, since this
branch is tests-only. Two of these are substantial enough that they are
being reported separately rather than left in a comment:

- CorsOptions.validate_request rejects every request when
  allowed_headers is non-empty, because the loop that checks request
  headers includes Origin, which no allow-list is expected to name.
  Reported as #30074.
- An empty allowed_methods matches nothing, so a minimal CorsOptions
  405s every request including GET.

The rest: EncodeOpts.trailing_commas only takes effect when indent is
also set; markdown's parse puts block text in `literal` with no children
rather than building the inline tree; PlainTextRenderer.render of an
empty source returns a newline; dataframe's `new` trims the index keys
it looks up by but not the `columns` it stores.

* tests: cover the asn1 streaming parser, the wrapper types and the field-option
variants, and the x/crypto ascon, chacha20 and poly1305 surfaces

A fifth coverage pass, same rules: no source file touched, no existing
test modified, expected values measured before being asserted, and each
break-control proved red before restoring.

asn1: the streaming Parser API had the largest untested surface in the
module. peek_tag, read_tag, read_length, read_bytes, read_tlv, reset,
finish and is_empty are now covered, table-driven over hand-built TLV
byte sequences and length tables. The wrapper types and the three
*_with_field_options entry points follow.

x/crypto: ascon's accessors and free paths, the chacha20 and
chacha20poly1305 constant helpers, and poly1305's clone.

Two findings are reported as issues rather than left in comments, because
they are defects rather than gaps:

- Poly1305.clone shares its buffer with its parent, so a forked pair
  computes different tags. Reported as #30151; pinned here with a test
  asserting the measured difference so a fix shows as a changed value.
- The bindings that need OpenSSL cannot run on a host without it. mldsa
  and slhdsa unconditionally include openssl/obj_mac.h, so every build
  fails at C compilation before any assertion runs. Nothing was written
  for them, because tests that could never be executed would be
  unverified assertions. Recorded here so the next person does not
  repeat the discovery.

Everything else is pinned with a NOTE: Enumerated.payload_with_rule
scales by 8, Sequence.into_sequence_of errors on exactly the sequences
it is meant to convert, decode_with_field_options cannot take empty
options, and ascon's new_xof128 panics where new_cxof128 returns an
error.

* tests: cover the pure geometry in gg and m4, os/font variants, the build task
graph, the static file handler, picoev surface, and the veb request_id, sse,
assets and picohttpparser response helpers

A sixth coverage pass, same rules: no source file touched, no existing
test modified, expected values measured before being asserted, and each
break-control proved red before restoring.

The graphics-adjacent modules are mostly untestable without a window, a
GPU or an audio device, and the survey is explicit about which parts are
and are not reachable. What is reachable is: gg's colour structs and
hex/float conversion, m4's transform helpers, the static file handler
called directly rather than through a server, and the sokol clear-pass
and memory builders that do not touch a context.

Behaviour pinned as-is with a NOTE rather than changed, since this branch
is tests-only. The clearest of these are genuine defects and are worth
filing separately:

- os/font.get_path_variant tests fpath, the directory half, where the
  file name was meant, so the bold variant reads a condition that can
  never hold. Measured consequence: LiberationSans-Regular.ttf with
  .bold yields Regular-bold, while .italic yields Italic.
- The static handler guards path traversal with a string prefix rather
  than a path boundary, so a sibling directory named <folder>_secret is
  also served.
- veb.build drops config.repeatable while veb.artifact forwards it, so
  the two agree only by accident.
- veb.csrf.CsrfContext.clear_csrf_token does not compile: it reads a
  free `config` identifier, which the checker accepts and cgen rejects.
  It is recorded in a NOTE rather than tested, because no test can call
  it.
- vlib/gx is now untestable rather than untested: every symbol carries
  @[deprecated_after: '2026-01-24'], and the checker turns a passed
  deprecation date into a hard error, so no test can import it again.
- vlib/db cannot be built in a checkout without thirdparty/sqlite or
  libpq, and x/crypto/mldsa and x/crypto/slhdsa still need OpenSSL. All
  three are reported with that scope rather than papered over.

* tests: cover cmd/tools pure helpers, the orm where-clause and tenant filters,
the transaction nil handles, veb route parsing, and 20 more vlib/v modules

A seventh coverage pass, same rules: no source file touched, no existing
test modified, expected values measured before being asserted, and each
break-control proved red before restoring.

cmd/tools: the tools that are thin or untested were surveyed rather than
assumed. Several turned out to have nothing unit-testable — builders and
bench are main()-only; vsqlite, fast and the measure speed tools cannot
compile in this tree, either because three files in the same directory
redeclare the same symbols or because db.sqlite needs a thirdparty
directory that is absent. What is pure is covered: vgit's commit-line
parsing, measure/file_lists' expansion, vvet's line filtering, vwhere's
file collection, vast's absolute_path, fuzz's string generation, and
vdoc's slug/URL/markdown helpers.

orm: the module is 5,641 lines with 44 test files and 220 test
functions, so gaps were narrow and specific. All 12 OperationKind
keywords are now asserted, including the ones the existing suite skipped;
the tenant-filter state and its default-fallback path; and the
zero-value Tx/Savepoint branches, which no test constructed before.

veb: parse_attrs, parse_query_from_url, parse_form_from_request and
has_route_attributes had no coverage at all, and controller_host is now
called directly rather than only through the registration path.

vlib/v: twenty more modules, chosen from a survey of which public
functions were unmentioned — ansi, cmdexec, debug, embed_file, errors,
pref, skills, token, util and its submodules, vmod.

One point worth recording: a first break-control attempt failed
silently. Breaking trim_attr_arg's inner trim_space left the suite
green, because the field name is normalised twice and the second pass
masks the first. The break was replaced with a discriminating one and
the double normalisation is recorded in a comment rather than a test,
since it cannot be observed this way.

* tests: exercise the V3 JavaScript backend end to end under node

`vlib/v/gen/js` had 22 source files and no test at all, and the fixture
corpus in `vlib/v/gen/js/tests/` was not run by anything. This adds the
first test: it compiles a program with `-b js`, runs the generated file
under node, and asserts on its output.

The compile and run steps are kept separate on purpose, so a failure
says whether the backend or node is at fault.

The tests also pin the backend's scope. It is a compatibility generator
rather than a full JS lowering: it supports `JS.eval` and a literal
`println`, and for anything else it reports
"the V3 JavaScript compatibility generator currently supports only
JS.eval and literal println" at compile time instead of generating code
that would misbehave. Asserting that message is more useful than a test
that pretends the surface is wider than it is, so the unsupported-feature
case is pinned as a diagnostic rather than as a working program.

A first version of this file had a test asserting that program arguments
are forwarded to the generated file. It failed, because `os.args` is
outside the backend's scope. The measurement is what caught it, not a
recall of what the backend should do.

* tests: cover the remaining math, stat, bit, hash, toml and rand config and
utf8 validation surfaces

An eighth and final pass. The survey walked every directory under
vlib/ and matched public names against the test text of each module,
then the candidates were filtered by hand for the two classes that the
survey over-reports: generic type names captured as Foo[T], and type
names whose behaviour is already exercised through @[params] sugar and
helper constructors.

Two of these modules had no test file at all before this:
rand/config and toml/util.

The rest narrows genuine gaps in math (log_n, ilog_b, cot, logf, minmax,
cubic_bezier_coords, the float bit helpers, the _mean wrappers and the
checked big-number variants), net/conv's htonf32/htonf64, hash/wymum,
os's MkdirParams and DiskUsage, and encoding/utf8's validate_str, validate
and the global-punct predicates.

Expected values are mostly invariants rather than literals, so that a
green test means correct behaviour rather than merely current behaviour:
f64_from_bits(f64_bits(x)) == x, wymum(a, b) == hi64(a * b) ^ lo64(a * b),
population_variance_mean(d, m) == population_variance(d), htonf32 is an
involution. Where a literal was unavoidable it came from a probe first.

Behaviour pinned as-is with a NOTE rather than changed. The clearest is
that is_rune_punct and is_rune_global_punct have byte-identical bodies
despite doc comments implying different Unicode tables.

* fix(driver): normalize framework flags for native TCC helpers

* http.file: reject sibling traversal and execute all coverage assertions

* tests: reject empty compile-time integer bounds after parse_int validation

* cgen: defer compiler worker helper header ownership precisely

* asn1: return success after replacing a default value with force

* tests: ensure rejected default replacement leaves the original value intact

* http.file: validate resolved directory index targets against the served root

---------

Co-authored-by: Alexander Medvednikov <alexander@medvednikov.com>
2026-10-14 16:15:26 +03:00
..
2026-09-17 10:47:56 +03:00
2026-05-09 17:30:51 +03:00
2026-09-17 10:47:56 +03:00
2026-05-08 14:50:39 -04:00

Context

This module defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.

Incoming requests to a server should create a Context, and outgoing calls to servers should accept a Context. The chain of function calls between them must propagate the Context, optionally replacing it with a derived Context created using with_cancel, with_deadline, with_timeout, or with_value. When a Context is canceled, all Contexts derived from it are also canceled.

The with_cancel, with_deadline, and with_timeout functions take a Context (the parent) and return a derived Context (the child). Calling the cancel function cancels the child and its children, removes the parent's reference to the child, and stops any associated timers.

Programs that use Contexts should follow these rules to keep interfaces consistent across different modules.

Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it. The Context should be the first parameter, typically named ctx, just to make it more consistent.

String Representation

Context.str() returns the normal representation for contexts provided by this module. For a user-defined Context implementation, it falls back to the concrete implementation type name. For example, a value containing MyContext is represented as MyContext.

Cancellation with Causes

When a context is canceled, you can optionally attach a cause — an error describing why the cancellation happened. Use with_cancel_cause instead of with_cancel to attach a cause:

import context

fn main() {
	mut bg := context.background()
	mut ctx, cancel := context.with_cancel_cause(mut bg)
	defer { cancel(none) }

	// Cancel with a specific error cause
	cancel(error('request timed out'))
}

Retrieve the cause from any context using cause(ctx):

import context

fn main() {
	mut bg := context.background()
	mut ctx, cancel := context.with_cancel_cause(mut bg)
	cancel(none)
	c := context.cause(ctx)
	if c !is none {
		println('canceled: ${c}')
	}
}

The cause is propagated through the context tree. If a parent context is canceled with a cause, all derived contexts inherit the same cause. If multiple ancestors are canceled, the first cause encountered is returned.

Convenience variants

  • with_timeout_cause(ctx, dur, err) — timeout with a custom cause
  • with_deadline_cause(ctx, deadline, err) — deadline with a custom cause

Examples

In this section you can see some usage examples for this module

Context With Cancellation

import time
import context

// This example demonstrates the use of a cancelable context to prevent a
// routine leak. By the end of the example function, the routine started
// by gen will return without leaking.
fn main() {
	// gen generates integers in a separate routine and
	// sends them to the returned channel.
	// The callers of gen need to cancel the context once
	// they are done consuming generated integers not to leak
	// the internal routine started by gen.
	gen := fn (mut ctx context.Context) chan int {
		dst := chan int{}
		spawn fn (mut ctx context.Context, dst chan int) {
			mut v := 0
			ch := ctx.done()
			for {
				select {
					_ := <-ch {
						// returning not to leak the routine
						eprintln('> go thread returns because ctx was canceled/done')
						return
					}
					dst <- v {
						v++
					}
				}
			}
		}(mut ctx, dst)
		return dst
	}

	mut background := context.background()
	mut ctx, cancel := context.with_cancel(mut background)
	defer {
		cancel()
		time.sleep(2 * time.millisecond) // give a small time window, in which the go thread routine has a chance to return
	}

	mut mut_ctx := ctx
	mut ctx2 := &mut_ctx
	ch := gen(mut ctx2)
	for i in 0 .. 5 {
		v := <-ch
		println('> received value: ${v}')
		assert i == v
	}
	println('> main is finished here')
}

Context With Deadline

import time
import context

const short_duration = 2 * time.millisecond // a reasonable duration to block in an example

// This example passes a context with an arbitrary deadline to tell a blocking
// function that it should abandon its work as soon as it gets to it.
fn main() {
	dur := time.now().add(short_duration)
	mut background := context.background()
	mut ctx, cancel := context.with_deadline(mut background, dur)

	defer {
		// Even though ctx will be expired, it is good practice to call its
		// cancellation function in any case. Failure to do so may keep the
		// context and its parent alive longer than necessary.
		cancel()
		time.sleep(short_duration) // give a small time window, in which the go thread routine has a chance to return
		eprintln('> defer block finishes')
	}

	ctx_ch := ctx.done()
	select {
		_ := <-ctx_ch {
			println('>> read from ctx_ch succeeded')
		}
		1 * time.second {
			panic('This should not happen')
		}
	}
	eprintln('> main finishes')
}

Context With Timeout

import time
import context

const short_duration = 2 * time.millisecond // a reasonable duration to block in an example

// This example passes a context with a timeout to tell a blocking function that
// it should abandon its work after the timeout elapses.
fn main() {
	// Pass a context with a timeout to tell a blocking function that it
	// should abandon its work after the timeout elapses.
	mut background := context.background()
	mut ctx, cancel := context.with_timeout(mut background, short_duration)
	defer {
		cancel()
		eprintln('> defer finishes')
	}

	ctx_ch := ctx.done()
	select {
		_ := <-ctx_ch {
			eprintln('> reading from ctx_ch succeeded')
		}
		1 * time.second {
			panic('This should not happen')
		}
	}
	eprintln('> main finishes')
}

Context With Value

import context

const not_found_value = &Value{
	val: 'key not found'
}

struct Value {
	val string
}

// This example demonstrates how a value can be passed to the context
// and also how to retrieve it if it exists.
fn main() {
	f := fn (ctx context.Context, key context.Key) &Value {
		if value := ctx.value(key) {
			match value {
				Value {
					return value
				}
				else {}
			}
		}
		return not_found_value
	}

	key := 'language'
	value := &Value{
		val: 'VAL'
	}
	ctx := context.with_value(context.background(), key, value)

	assert value == dump(f(ctx, key))
	assert not_found_value == dump(f(ctx, 'color'))
}

Context With Cancellation Cause

import context

struct AppError {
	msg string
}

fn (e AppError) msg() string {
	return e.msg
}

fn (e AppError) code() int {
	return 0
}

fn main() {
	mut bg := context.background()
	mut ctx, cancel := context.with_cancel_cause(mut bg)
	defer { cancel(none) }

	// Simulate an error condition and cancel with a cause
	cancel(AppError{
		msg: 'operation failed'
	})

	// Retrieve the cause
	c := context.cause(ctx)
	if c !is none {
		eprintln('context canceled: ${c}')
	}
}