Repository navigation
Releases
Releases · mcpp-community/mtest
mtest 0.9.0
- A selection excludes, and selects where declared (SPEC-017 P4.3). In
MTEST_SELECT, a line
!<id>leaves out that case and the cases it declares, and a line?<id>selects a case where
it is declared and is notmissingwhere it is not; a selection of exclusions alone runs every
case but those. Theprogramevent states"selection": ["except", "optional"], so a runner
uses them only with a program that understands them. A runner divides a long case among
processes by the cases it declares, which a list does not name (P3.4) and its history does: each
process but one selects (?) the measured cases it was given, so a case since removed fails
nothing, and the last selects the case without them (!), so a case no run measured runs once.
Measured on mcpp's CI: two suites of 1373 s and 1375 s ran their cases one after another, and
the longest case of either takes 564 s. - CI builds and tests with mcpp 2026.11.14.1. 2026.11.10.1 took an emsdk from a package store
restored without the loader its compiler names as present (provides no std module source);
2026.11.13.1 and later restore that loader's link.
mtest 0.8.5
- An output cut at its limit says so (#22).
e2e::runkeeps at most 1 MiB
of a program's standard error (256 MiB of its standard output), and an outcome cut there looked
complete: a case that searched it could not tell an absent line from a dropped one. The outcome
now carriesout_truncated,err_truncatedandheld_openasmcpplibs.osreports them; a
command states its own limits (out_limit,err_limit, the former values by default); and a
failedsucceededorexitednames the output that was cut and its size. Nothing changes for an
output within its limit. - CI caches the package store with its ABI directory. The store alone, restored, held the emsdk
compiler without the loader its interpreter names, and the Web row of 0.8.4's release failed with
"provides no std module source"; a store cached before this is not restored.
mtest 0.8.4
- A test program links where no program can be started (the Web). A capability that asks for a
command (probe::command) ran it throughmcpplibs.os's process functions, which every test
program could reach; a target whose system provides none of them --wasm32-emscripten, by
openkal's rule that an absent capability is absent at link -- then linked no test program at all
(undefined symbol: kal_process_wait, ...), since 0.8.0. The target answers at compile time now:
asked for a command there, the capability is absent ("this system starts no programs"), and
nothing of starting one is in the program. Nothing changes where programs are started.
mtest 0.8.3
- Each call measured by itself, as a loop (
bench::laps).bench::eachtakes the call as a
function; a body that keeps its state in the function it runs in writes the same measurement as
a loop:bench::laps run{"draw"}; while (run.next()) { ... }. The time from onenextto the
following one is a call's,runis the call'slap(pause,resume,items,part,time,
value,say,last), and whennextreturns false the metrics have been reported aseach
reports them;result()is where the calls lay.eachis that loop around its function: one
way of measuring, in two forms. - Run alone, a program shows what it measured. A measurement's line in the program's output --
draw: 2.100 ms (p95 5.300 ms, p99 7.700 ms, max 8.400 ms; mean 2.900 ms; 139 calls; 0 over 8.333 ms), then a line for each part and quantity -- where no runner keeps the run's record.
Under a runner nothing is added to the case's output: the record has the metrics. - What the lap keeps is not the call's. The allocations
part,timeandvaluemake to keep
what a call says are left out of the call's count: a frame that allocates nothing reports none
while it states its parts (lib/tests/allocations.cpp, a program that replacesoperator new). - A program run alone selects as the runner does. Its arguments name cases by identifier, by
the name they lie under (suite/group, which was run and then reported as no case), or by a
pattern with*(the cases it matches, asmcpp test --casetakes one); a selection no
case answers fails the run. The interface said "by prefix" and the program took whole
identifiers: the statement and the behaviour are now one (lib/tests/alone.cpp). - Additive:
eachmeasures and reports as it did.
mtest 0.8.2
- 0.8.1 as released: its tag was made and its release was not (a test of
bench::eachheld that
the call it had slowed was the slowest of all, which a loaded machine does not grant). The tests
now hold each stated call to what that call said, whichever calls the machine slowed. The library
is 0.8.1's.
mtest 0.8.0
- Where a case runs is stated by the case (
only{},except{}). A case or a suite names the
platforms and architectures ofmcpplibs.osit runs on (only{platform::windows},
only{platform::linux, architecture::x86_64}) or not (except{platform::macos}); a suite's and
its case's narrow together. Elsewhere it is skipped with one reason,only on windows (this host: linux x86_64). The Bash adapter (--only,--except), the Python adapter (only=,
excepted=) and the C ABI (mtest_case_only,mtest_case_except) state the same; the engine
skips a listed case outside its places without starting it. - Code for one platform is selected when it is compiled. mtest re-exports mcpplibs.os's
platform,architecture,can_run_on,hostandon<P>:on<platform::windows>([&](auto) { ... })is a body that a build for another platform discards, and an ok image decides when it is
loaded. - What a machine can do is declared in code and answered by the program (
capability). The
tests of[capabilities]-- a system, an architecture, programs on PATH, a file a glob matches, a
command, environment values, other capabilities that must or must not hold -- and a function for
what they cannot state, answered once per process. A capability is an attribute
("links"_test[gcc], with the tagrequires:gcc); a case whose machine lacks it is skipped,
missing capability: gcc (no g++ on PATH), under any runner (mtest,mcpp test, the program
alone). The engine takes the program's answers: a word the program answers needs no
[capabilities]entry, and the run records it. - The listing says why a case is skipped, and where it runs (P3.3): a
caseevent may carry
reason(withexpect: skip),only,exceptandcapabilities; the schema states them. The
conformance suite checks them of every level-3 implementation (placed). mtest ci coveragechecks each case on its places: a case that statesonlymust pass on
each of its places that a collected run covered, and some run must have been on one -- what
[ci.coverage] hostsstates of a program, stated by the case.- Additive: a program, a listing and a configuration that state none of these mean what they did.
mtest 0.7.2
- Each call measured by itself (
bench::each,mcpplibs.mtest.bench).bench::measuretimes
batches and states what one call costs on the whole;eachtimes every call, for work whose
calls differ and whose slow ones are the point -- a frame, a request, a step of a simulation. It
reports where the calls lie as metrics a bound can name: the median asname, andname.p95,
name.p99,name.max,name.mean(at_most{"draw.p95", 0.016}). The body may take a
bench::lap:pause()andresume()leave out what is not the call's (preparing the next
input),items(n)states what the call worked through and addsname.per_item. The samples are
not stated with these metrics: the verdict on samples that spread is for a measurement meant to
be one number.bench::distributeandbench::percentileare the same arithmetic on samples a
test has already. Additive; no event and no clause changed.
mtest 0.7.1
mcpplibs.mtest.e2e,.benchand.ctsare public modules of the library. Each re-exports
mcpplibs.mtest, so the lib root cannot re-export them, and a program that imported one was told
that it was not public and would fail against the packed library (mcpp SPEC-008). Each is now a
feature, on by default (e2e,bench,cts), which is how mcpp counts a module beside the root
as public; a program's imports and its manifest are unchanged.
mtest 0.7.0
- What a machine can do is declared once, and a requirement no machine answers is an error
([capabilities]). Each word states its tests -- a system, an architecture, a program on PATH, a
command that succeeds, a file a glob matches, an environment value, other words that must or must
not hold -- and a case that requires a word (requires:<word>, from# requires:lines through
tags_from) that this machine lacks is skipped with the reasonmissing capability: <word> (<the test that failed>). A word no entry declares stops the run, naming the program.mtest capabilitiesprints the answers; each run records its host (MTEST_HOST, else the system) and
its answers. Before, a project probed in a script of its own and kept a list of known words beside
it. - Whether every program ran somewhere is a command (
mtest ci coverage). Over the runs of all
the jobs of a CI run, collected into one store, each program isran,unaffected,excusedor
owedby the tables[ci.coverage]names, oruncovered, which fails; an entry that outlived its
reason fails too, and a program that must pass on given hosts is checked on each. The capability
words no job's machine provided are listed. - A selection is divided among CI's hosts before any builds (
mtest ci plan): for each host, the
cases its recorded capabilities admit, their measured time on that host, and the number of shards
that fit[ci.plan] shard;--format githubwrites a job matrix toGITHUB_OUTPUT. A host with
no history counts every case. - An interrupted run resumes (
mtest run --resume RUN): the cases RUN judged are carried into
the new run and are not run again. - A program under test is judged with matchers that carry the session
(mcpplibs.mtest.e2e):succeeded,exited,contains,matches; an outcome carries the
command as a POSIX shell line (shell_line), and a failed matcher reports it with the tails of
both outputs. - An interactive program is driven by expecting and sending (
e2e::session:start,expect,
saw,send,send_line,finish,transcript). Both streams travel in one pipe; no terminal
is involved, so the same session runs on every system. A serial console of an emulator is driven
this way (measured: QEMU's serial console delivers the same bytes over a pipe as over a pseudo
terminal).
mtest 0.6.3
- A conformance suite is run against a subject, which may lack what a specification leaves
optional (mcpplibs.mtest.cts:against,subject,needs).cts::against({.name, .has, .required}, declare)runs the casesdeclaredeclares as the parts of a case named after the
implementation, taggedsubject:<name>, so one program runs a suite against several. A case that
statescts::needs{"capability"}and whose subject lacks it is not run:skip, with the reason
unsupported: <capability>-- from what the subject states it can do, never a pass. A capability
the run requires and the subject lacks fails once, as the caserequires <capability>. Before, a
suite wrote this in each body (if (!has(x)) skip(...)), where a missing capability and a
machine's reason read alike, and a required one could only be skipped. The protocol is unchanged:
the statuses and events are the ones it has.