Dario Lipicar c727e25c30 fix(doctests): track two upstream changes the specs still assert against (#80)
CI has been red on every run since the dependencies moved underneath it.  The
repo itself has not changed -- master's HEAD IS the commit that last went green,
on 2026-07-22 -- but logos-tutorial has no flake.lock: the specs scaffold
projects that resolve `github:logos-co/...` fresh at run time, so the same
commit passes or fails depending on the day.  Both failures below are the specs
asserting behaviour that upstream deliberately changed.

1. INTEGER WIDTH: `int` -> `qlonglong` in the generated Qt surface.

   `lm methods` now reports `qlonglong add(qlonglong a, qlonglong b)` where the
   spec expected `int add(int a, int b)`.  This is the LIDL type contract: one
   type per language, integers 64-bit throughout, no widening or narrowing.

   The tutorial's explanation was not merely stale -- it documented the OLD
   BUG as intended behaviour, telling the reader that their `int64_t` "shows up
   as `add(int,int)`".  That silent 64->32 narrowing is exactly what the type
   contract removed.  The bullet now says the width is preserved and why that
   matters, which is the part a tutorial is for.

   Only tutorial-wrapping-c-library asserts generator OUTPUT, so only it moves.
   The `int` in tutorial-cpp-ui-app is C++ the reader writes themselves (`.rep`
   SLOTs and their own `override` declarations), where the reader picks the
   type -- that spec passes, and is deliberately left alone.

2. BASECAMP NAVIGATION: the Settings section was renamed and its tab removed.

   `click("Modules")` failed with "No clickable element found with text
   'Modules'".  On basecamp master the section label is now "Module Inspector"
   (SettingsView.qml:53), and the "Core Modules" tab is gone -- it was split
   into its own view, which ModuleInspectorView.qml:18 says in as many words
   ("Formerly the 'Core Modules' tab of ModulesView").  So the tab-click step is
   deleted rather than renamed, and the objectName the Interface screen is
   opened through is `moduleInspectorView`, not `coreModulesView`.

   Verified against origin/master of logos-basecamp, which is what CI builds:
   `openInterface(name)` still exists (ModuleInspectorView.qml:46), and the
   surrounding anchors "Settings", "Sections", "Dashboard" are all still there.

NOT ADDRESSED HERE, because it is not a tutorial bug: the third failure,
`persistenceDir` not containing `calc-data`, is a real regression in
logos-logoscore-cli.  daemon_state.cpp:264 applies `--persistence-path` only
`if (cfg.dirs.data.empty())`, and dirs.data has a default -- so an explicitly
passed CLI flag loses to a default, silently.  The spec is right and should
stay red until that is fixed.
2026-08-10 19:45:46 -03:00
2026-05-30 10:23:00 -04:00
2026-06-28 00:39:59 -03:00
2026-05-30 10:23:00 -04:00
2026-06-28 00:39:59 -03:00
2026-06-28 00:39:59 -03:00

logos-tutorial

Tutorial series and reference documentation for building Logos modules.

Start Here

New to Logos? Start with the developer guide -- it walks through creating, building, packaging, and running your first module:

Next Tutorials

Step-by-step tutorials that build on each other. Each creates a working module you can run.

  • Part 1: Wrapping a C Library -- build calc_module, a core module that wraps a C library (libcalc). Covers external library configuration, CMake integration, building, inspecting with lm, testing with logoscore, and packaging with nix-bundle-lgx.

  • Part 2: Building a QML UI App -- build calc_ui, a QML-only ui_qml module that calls calc_module through the logos.callModule() bridge. No compilation needed. Scaffold: nix flake init -t ...#ui-qml

  • Part 3: Building a C++ UI Module (Process-Isolated) — build calc_ui_cpp, a ui_qml module with a C++ backend that runs in a separate ui-host process. Define the remote interface in a .rep file; the C++ backend inherits from the generated SimpleSource; QML accesses it via a typed replica using logos.module() and QtRemoteObjects.watch(). Scaffold: nix flake init -t ...#ui-qml-backend

  • Composing Modules: Composing Modules with the Module Context — build calc_aggregator, a core module that depends on calc_module and showcases everything LogosModuleContext offers: the modulePath / instanceId / instancePersistencePath properties, per-instance persistence wired up in onContextReady(), typed sync and async dependency callers (modules().calc_module), and typed event subscribers. No UI — driven entirely from logoscore. Needs only Part 1.

  • logos-dev-boost: (⚠️ EXPERIMENTAL — NOT READY) Scaffolding Modules with logos-dev-boost — use the logos-dev-boost CLI to auto-generate modules from C library directories. Wraps libcalc (source-only) and sqlcipher (pre-built .so), including integration tests that create encrypted databases. Covers --type module, --type full-app, and --lib-dir.

Executable Tutorials

Tutorials have YAML specs in tests/ that can be both executed (to verify they work) and used to generate the .md files. They run through the shared doctest CLI, invoked directly via its flake (nix run github:logos-co/logos-doctest -- …). See docs/spec.md for the full format reference.

# Run a tutorial end-to-end (temp dir, deleted afterwards)
nix run github:logos-co/logos-doctest -- run tests/tutorial-wrapping-c-library.test.yaml --verbose

# Keep the build results in a directory of your choice (created if missing,
# never deleted). For a chained tutorial each part lands in its own subdir.
nix run github:logos-co/logos-doctest -- run tests/tutorial-cpp-ui-app.test.yaml \
  --output-dir ./outputs --continue-on-fail

# Write a two-column HTML report: rendered tutorial on the left, the commands
# actually run and their output on the right. Open the file in a browser.
nix run github:logos-co/logos-doctest -- run tests/tutorial-cpp-ui-app.test.yaml \
  --report ./tutorial-report.html --continue-on-fail

# Generate the .md tutorial from the YAML spec
nix run github:logos-co/logos-doctest -- generate tests/tutorial-wrapping-c-library.test.yaml

# Pin all GitHub URLs to a specific release tag
nix run github:logos-co/logos-doctest -- run tests/tutorial-wrapping-c-library.test.yaml --release 0.2.0
nix run github:logos-co/logos-doctest -- generate tests/tutorial-wrapping-c-library.test.yaml --release 0.2.0

Tip: developing against a local logos-doctest checkout? Swap github:logos-co/logos-doctest for path:../logos-doctest (or wherever your checkout lives) to run your local changes.

Where the results go

  • --output-dir DIR — run into DIR and keep it (created if missing, never auto-deleted). This is the flag to use when you want to inspect or reuse the built modules. A tutorial with requires: (e.g. Part 3, which pulls in Parts 1 and 2) treats DIR as the chain root and writes each project into its own subdirectory:

    ./outputs/
    ├── logos-calc-module/    # Part 1 (built first via requires:)
    ├── logos-calc-ui/        # Part 2
    └── logos-calc-ui-cpp/    # Part 3
    

    A standalone spec (no requires:) is written directly into DIR.

  • --workdir DIR — run into an existing directory. Unlike --output-dir, it does not create the directory, it is deleted on exit unless you add --keep-workdir, and it runs the spec standalone (prerequisite requires: chains are skipped). Prefer --output-dir for chained tutorials.

  • Without either flag, a temp directory is created and deleted after the run (add --keep-workdir to preserve the temp dir).

Reviewing what ran (--report)

--report PATH writes a self-contained HTML report with two columns per step:

  • left — the rendered tutorial markdown (identical to the published .md),
  • right — the command(s) actually executed at that step and their output, with a pass/fail badge.

It covers every step type (file writes, shell commands, check_file, and headless ui_test runs). Pair it with --continue-on-fail so the report captures the whole run instead of stopping at the first failure. CI publishes this report for every run — see .github/workflows/ci.yml.

Watching it live in a terminal (--tui)

--tui runs the same two-column view live in your terminal instead of writing a file: the left pane shows the rendered tutorial for the current step, the right pane shows the command being run and its output, updating as the run proceeds.

# Auto-advancing: steps run one after another
nix run github:logos-co/logos-doctest -- run tests/tutorial-cpp-ui-app.test.yaml --tui

# Iterative: press the down/right arrow (or space) to execute each next step
nix run github:logos-co/logos-doctest -- run tests/tutorial-cpp-ui-app.test.yaml --tui --iterative

Press q to quit at any time. --tui needs an interactive terminal and the rich package — both are bundled in the doctest flake, so no extra install is needed when using nix.

The --release flag (or the release field in the YAML) pins all {release} placeholders in GitHub URLs to a git tag, so github:logos-co/repo{release}#output becomes github:logos-co/repo/0.2.0#output. Set it to "" or omit it for latest.

Example Modules

Working module source code used by the tutorials:

Directory Module Type Tutorial
logos-calc-module/ calc_module core (wraps libcalc) Part 1
logos-calc-ui/ calc_ui ui_qml (QML-only) Part 2
logos-calc-ui-cpp/ calc_ui_cpp ui_qml (C++ backend + QML view) Part 3
logos-calc-aggregator-module/ calc_aggregator core (depends on calc_module) Composing Modules

Regenerating the outputs

The outputs/ directory (the rendered .md tutorials linked above, plus the built module source trees) is generated from the YAML specs. To regenerate it, run:

./run.sh

This:

  1. Runs the full tutorial chain (Part 1 → 2 → 3) into ./outputs/, executing every step so the result is verified, not just rendered. Each part lands in its own subdirectory (outputs/logos-calc-module/, outputs/logos-calc-ui/, outputs/logos-calc-ui-cpp/). It then runs the Composing Modules tutorial into outputs/logos-calc-aggregator-module/, reusing the calc_module the chain just built (--workdir, so its requires: chain is not rebuilt).
  2. Generates the .md tutorial for every tests/*.test.yaml spec into outputs/ (tutorial-wrapping-c-library.md, tutorial-qml-ui-app.md, tutorial-cpp-ui-app.md, tutorial-composing-modules.md).
  3. Cleans each output project so only the source remains — it removes the per-project .git/ directories (each tutorial git inits its project), the nix out-link symlinks (lm, logos, pm, result*), build output (modules/), compiled libraries (*.dylib, *.so), and the aggregator tutorial's calc-data/ persistence scratch dir.

Pinning to a release tag

By default run.sh resolves every {release} placeholder to the latest commit on each repo. Pass --release TAG to pin them all to a git tag, so the executed commands and the generated Markdown both reference that tag:

./run.sh --release 0.2.0

Any further arguments are forwarded verbatim to the underlying doctest run/generate calls, so you can override a single repo's ref with --release-for:

./run.sh --release 0.2.0 --release-for logos-basecamp=main

The TAG must exist on each referenced repo, or the nix build/nix flake init steps will fail to resolve it. Pinning expands each {release} placeholder so github:logos-co/repo{release}#output becomes github:logos-co/repo/TAG#output; omitting --release leaves them at latest.

To run against a local logos-doctest checkout instead of the published flake, export DOCTEST:

DOCTEST="nix run path:../logos-doctest --" ./run.sh --release 0.2.0

Note: the run requires Nix with flakes and pulls/builds real dependencies (Qt, the Logos SDK), so the first run is slow. On Linux, add --continue-on-fail to the run command in run.sh if a known-failing prerequisite step would otherwise stop the chain early.

S
Description
WIP
Readme
19 MiB
Languages
C++ 53.2%
QML 23%
Shell 8.8%
CMake 5.2%
Nix 4.7%
Other 5.1%