feat(registry): commands, watches, samples, the timeline and conditions
The app side of Crafter.Debug, minus the session:
- Command(name, description, handler): the handler takes nothing or
one argument struct and returns void, a value, Result<T> or
Async<T>. Arguments are decoded before it runs, so a mistyped call
is answered with every mistake and never reaches it; a throwing
handler becomes an Exception error instead of unwinding into the
frame loop. This replaces 3DForts' three-file pattern per verb.
- Watch(path, variable | getter [, setter]) with bounds, help and
read-only, and Sample(path, value) from any thread with a
frame-stamped history. Paths resolve into values ("bodies[1].pos.y")
and set the same way, writing a member writes the whole value back.
Unknown paths and commands get a suggestion.
- Group: registrations under a prefix that end with their owner. Not
movable, so neither is its owner: its watches refer to the owner's
members, and a move would leave them pointing at the old object.
- Log, LogWarn, LogError, Check and Emit on one frame-stamped
timeline, with source locations captured without macros. A check
failing every frame is counted every time but stored sparsely, and
the session's listener hears every failure.
- Condition: what `wait` and `pause --when` evaluate each frame. A
condition that cannot be decided reports why instead of being false,
which would make a wait hang.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
89a12bcd61
commit
3500b73ecf
12 changed files with 1829 additions and 7 deletions
27
project.cpp
27
project.cpp
|
|
@ -27,12 +27,21 @@ namespace {
|
|||
return fs::path(std::source_location::current().file_name()).parent_path();
|
||||
}
|
||||
|
||||
constexpr std::array<std::string_view, 4> tests = {
|
||||
// Tests of the core, linked against it alone.
|
||||
constexpr std::array<std::string_view, 4> coreTests = {
|
||||
"ShouldRoundTripJson",
|
||||
"ShouldRoundTripAggregates",
|
||||
"ShouldReportDecodeErrorsWithPaths",
|
||||
"ShouldDescribeDefaultsAndRequired",
|
||||
};
|
||||
|
||||
// Tests of the app library.
|
||||
constexpr std::array<std::string_view, 4> libraryTests = {
|
||||
"ShouldInvokeCommands",
|
||||
"ShouldResolveWatchPaths",
|
||||
"ShouldRecordTimeline",
|
||||
"ShouldEvaluateConditions",
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
|
||||
|
|
@ -85,15 +94,25 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
|
|||
|
||||
cfg.dependencies = { &core, &client };
|
||||
{
|
||||
std::array<fs::path, 1> interfaces = { "interfaces/Crafter.Debug" };
|
||||
std::array<fs::path, 0> implementations = {};
|
||||
std::array<fs::path, 4> interfaces = {
|
||||
"interfaces/Crafter.Debug-Registry",
|
||||
"interfaces/Crafter.Debug-Timeline",
|
||||
"interfaces/Crafter.Debug-Condition",
|
||||
"interfaces/Crafter.Debug",
|
||||
};
|
||||
std::array<fs::path, 3> implementations = {
|
||||
"implementations/Crafter.Debug-Registry",
|
||||
"implementations/Crafter.Debug-Timeline",
|
||||
"implementations/Crafter.Debug-Condition",
|
||||
};
|
||||
cfg.GetInterfacesAndImplementations(interfaces, implementations);
|
||||
}
|
||||
|
||||
// Tests only when this is the project being built: a consumer's load of
|
||||
// this file has no use for them.
|
||||
if (IsTopLevelProject()) {
|
||||
for (const std::string_view test : tests) cfg.AddTest(test).Dependencies({ &core });
|
||||
for (const std::string_view test : coreTests) cfg.AddTest(test).Dependencies({ &core });
|
||||
for (const std::string_view test : libraryTests) cfg.AddTest(test).Dependencies({ &cfg });
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue