|
libose
|
describes how libose is tested, and the one rule the tests follow
describes the test suite
Test code may never use anything from the library under test.
A round trip – write a bundle with libose, read it back with libose – proves only that libose agrees with itself. It would pass just as happily on a layout nobody intended, and it cannot detect a change that is applied consistently to both halves.
So every expected value in the suite is built by ose_test_ctosc.h, a small OSC constructor made entirely of C preprocessor macros (STOC1–STOC4, S0N–S16N) that turn string literals into byte lists at compile time. It includes nothing from libose. A test asserts that libose produced the same bytes an independent construction did.
Two fixtures are checked in as byte arrays rather than constructed at run time:
ose_test/ose_test_vm_literal.h – a whole VM, used by UNIT_TEST_WITH_VMose_test/ose_test_bundle_literal.h – a plain context bundle, used by UNIT_TEST_WITH_CONTEXT_BUNDLEA literal satisfies the rule differently from ctosc, and more strongly: it is a fixed array of bytes, so it uses nothing at all. What it tests is whether libose can still read a VM that libose wrote earlier – which is exactly the question a fixture stops asking once it goes stale.
And one did. The hand-written predecessor of the VM literal fell behind a change to the context message layout – the typetag string went from ,iiiibb to ,bbbiiiiib, a 256-byte per-context cache was added, and the per-context overhead went from about 52 bytes to 332 – and nothing failed, because a byte array always compiles and nothing included the file. Its working bundle sat 128 bytes into the buffer while the cache was addressed 292 bytes below that, so cache reads landed before the array entirely, and no test using it could touch any code that did a lookup.
The fixtures are therefore generated, by ose_test/tools/emit_vm_literal.c and emit_bundle_literal.c, and both the generator and the suite validate the bytes against ose_context.h using tools/validate_context.h. That checks the typetag string, the cache blob's length, the offset from the message start to the bundle, and that the message is exactly OSE_CONTEXT_BUNDLE_OFFSET larger than the total it declares – against the declaration, not against the writer. A layout change fails the suite with the field named, and the fix is to regenerate.
The suite in test/ links libose and nothing else. No stdlib is bound and no lookup hook is installed, so /!/add resolves to nothing there, by design. What is testable is bundle and VM mechanics: the stack operations, the register prefixes, the run loop, the dump, errno.
Anything needing a bound name belongs to osekit's suite, where the hooks exist. /!/exec1, /!/exec2 and /!/exec3 are a case in point: each ends by dropping its own instruction from the control bundle, so calling one directly from a test trips a precondition assert on an empty control bundle. In a debug build that aborts; in a release build it sets errno and carries on, so the function appears to work. That difference is the source of at least one confidently wrong conclusion about exec3 crashing, which it does not.
OSE_CONF_VALIDATE_VM_STEP (ose.h) compiles in a check that validates all five registers after every instruction. It is off by default and costs accordingly, and it changes nothing when it passes – an observer, so that a violation is not masked by whatever the checker does about it.
It exists because "the state is always a valid OSC bundle" is the claim the whole design rests on, and a claim nothing tests is a hope. It has already found a real malformed message, produced by a wrong literal length passed to ose_pushMessage().
A note for anyone editing the build: this suite has twice reported success while running a stale binary, both times because the pattern rule's prerequisites were incomplete. First the test's own source was missing, so editing a test rebuilt nothing; then libose's headers were missing, so a change confined to a header rebuilt nothing. Both are fixed, and both were found only because a result looked impossible. If a change appears to have no effect, check that it was compiled before concluding anything about it.
Testing is done by writing a program that consists of a number of test functions, each of which may consist of any number of tests.
...