What to do is in WIP.md (Where things live, the contributed packages) and in test/package-tests/README.md. This file says why.
A contributed section's NOTEs and WARNINGs are claims about someone else's code: that a member raises 53, that a match is cut short, that a dialog ignores a property. Each was true of one version when an agent checked it, and nothing kept that evidence: the probe pages were deleted after use. So the claims are written down as cases that persist, run again whenever the package's version moves, and say which claims no longer hold. The owner wants the same cases to be usable by the package's author, which decides most of what follows.
A case asserts the behaviour the package should have, not the behaviour it has. To the author a
red case is a defect to fix and a green one is done, with a message that reads as a bug report.
The documentation needs the opposite question answered too (does the page still describe the
package?), and expect.json answers it: it records, per case and architecture, the exact failure
report or that the case never returns, on the documented version. The runner's three verdicts
come from comparing the two: documented, fixed (the callout goes, by the rule that the
documentation is not a record of past defects), changed.
The failure report is compared exactly, after the line number and the assertion prefix are stripped, so a defect that changes shape (a different wrong value) is changed, not documented.
twinBASIC's own form is a [TestFixture] module of [TestCase] Subs checked with the Assert
package, and tbrun --tests runs those in the compiler's test mode. But in BETA 1010 the IDE has
no way for a person to run a test case, and outside test mode a failed Assert stops the run at
the error panel, uncatchable by On Error (WIP.Harness.md, Running a project's test cases). An
author who opens the project would see the first failure only. So the cases check through
Expect.twin:
- Under
RunAll(the project'sSub Main, which an author runs with F5),Expectcollects:Expect.Donerecords the case's report, andRunAllcalls every case underOn Error Resume Nextand printsPASS,FAILorSKIPfor each. - Under
tbrun --tests,Expect.Doneends a failed case withAssert.Strict.Failand the whole report as its message. AnAssertfailure is the one thing a case's ownOn Error Resume Nextcannot hide; anErr.RaisefromDonewould be swallowed by it and the case would pass. Checked on BETA 1010: the message comes back whole in the response'sbody.error. - Every check of a case runs, and
Donereports all failed ones, so one run of a case shows every defect it covers.
The [TestFixture] and [TestCase] attributes stay, so the cases are in twinBASIC's own form
for whatever runner the IDE gains. RunAll.twin is generated rather than written, because a
hand-kept list of calls drifts from the cases; the gate refuses a stale one.
Some defects are a loop that never ends (TBMANLIB_Xml on some malformed text). In test mode such a case holds the compiler: tbrun gives up on it after
its timeout, and every case after it would time out too. So the runner, on a case that does not
return, records it and runs the cases after it again in a new IDE; once expect.json says
hangs, the case is run alone with a short timeout, and RunAll skips it, because an author's
IDE would hang.
Embedding the package in the published file would mean either the build fetching from TWINSERV
(the deploy then depends on that server) or committing every documented version's .twinpack
(about 35 MB, some of it WinDevLib, and four packages declare no licence that allows passing them
on). The owner chose neither.
The published project keeps the template's reference to the package and has no Packages/
folder, which makes it a linked reference. Checked on BETA 1010 (private APPDATA, private
desktop):
- With the package's
.twinpackin%APPDATA%\twinBASIC\packages, the project compiles. The IDE finds the file by the package's project id, whatever its name, and takes the version from the file: a 1.7.0.0 file under a reference that says 1.8.0.0 compiles against 1.7.0.0. - Without it, every name of the package is TB5079, and Enabled Libraries shows
[LINKED-PACKAGE] ... ERROR unable to load this reference; its FIX link is not implemented. - A file put in the folder while the IDE runs is used after Restart Compiler.
- Nothing downloads a missing package by itself. The IDE's only download path is the Available
Packages tab (
importPackageinmain.js); a project load calls only/packages/checkVersions, and only for a reference with apublisherfield.path32/path64set to a file path or a TWINSERV URL, or a.twinpackbeside the project, are not used.
So the reader puts the documented version's file in the packages folder (or adds the package from
Available Packages with Embedded cleared) and restarts the compiler; an author points the folder at
their own build. The runner embeds the package from %TEMP%\tb-twinserv instead, as
check_examples does, so it never touches a packages folder.
A compile case that expects an error is, by design, a compile error of the project it is in, and
the compiler's test mode runs nothing in a project with errors: tbrun --tests reports every
[TestCase] not run. The first package with such claims (Generics: TB5074 on New of a package
generic, TB5124 on its unusable tuples) lost all its run-time cases to one line. So those cases
go in the package folder's compile/, a second project that package_tests.mjs stages with the
package embedded and judges with the rest. The published project stays Sources/ alone, which
compiles, so the author's Sub Main still runs every run-time case; the compile cases are the
documentation's own re-check on each new build and version.
A callout names its cases in an HTML comment on the line above it. The marker lives with the
callout, so moving or rewording the callout keeps its tie, and it is invisible on the page. The
cases name nothing back: a case file referring to a page and a heading would break on every edit
of the page. The gate checks both directions (an unmarked callout, an unnamed case) from the
sources alone, so it runs in test.bat and CI, where the cases themselves cannot run.
The sections were written before any project existed, so the gate starts with every section in
PENDING and fails on a section that has a project and is still listed, or has none and is not:
the list can only shrink, one package at a time.
none -- <reason> exists for a callout no program can check (a fact about the IDE, a licence); it
keeps the decision explicit and visible in review, where a missing marker would be ambiguous.