mirror of
https://github.com/logos-co/logos-test-modules.git
synced 2026-08-30 19:51:16 +00:00
feat: full_api test chain (providers, proxies, UI) + fullapi-tests check (#24)
* feat: full_api test chain — providers, proxies, and a UI plugin
Adds a hermetic test chain that exercises the entire supported type surface
(every method param/return + event param type) end to end, replacing the
network-dependent cross-version checks:
- test_fullapi_cpp universal C++ provider (reference impl of full_api)
- test_fullapi_rust Rust cdylib provider, same contract (cross-language parity)
- test_fullapi_proxy universal C++ consumer/proxy via interface dependency
(forwards every method, re-emits every event)
- test_fullapi_proxy_rust Rust mirror of the proxy
- test_fullapi_ui universal ui_qml plugin consuming full_api via an
interface dependency; drives every method type + all
events, surfaced to QML for a headless UI doctest
All five build; the core chain (both providers + both proxies, incl. cross-
language method calls and event round-trips) is proven at runtime under
logoscore, and the UI plugin is proven in Basecamp (method calls + typed event
delivery). Requires the cpp-sdk/rust-sdk codegen fixes (bstr/composite type
handling) re-pinned through module-builder.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(fullapi-ui): verify echoAny too; document the typed-scalar-array gap
The UI backend now also verifies echoAny (any round-trips) in the ALL_OK token,
and documents that typed-scalar arrays ([int]/[uint]/[float64]/[bool], and [any]
carrying numbers) still round-trip empty over the ui-host QtRO transport — a
Qt-path marshaling gap partially addressed by logos-protocol's container int-
preservation fix but not fully resolved. They are exercised but kept out of the
token so the basecamp UI doctest stays green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(fullapi): add fullapi-tests check proving every array type round-trips
Adds a proxy probeArrays() method that round-trips one array of EVERY array type
([int]/[uint]/[float64]/[bool]/[tstr]/[any]) through the bound provider over the
lp path, plus a 'fullapi' group in run_tests.sh and a checks.fullapi-tests
derivation. This is CLI-observable (logoscore can't pass a list arg directly)
and proves both the C++ and Rust providers decode every array type identically.
Result: 5/5 green — probeArrays returns intList=3 uintList=2 doubleList=2
boolList=2 stringList=2 anyList=3 against both providers, plus scalar forwarding
and an event round-trip through the proxy. This isolates the earlier UI
[int]-empties symptom to the Qt-path host-side qvariantToNlohmann conversion
(fixed in logos-protocol), NOT the provider decode.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(fullapi): package + exercise the Rust proxy in fullapi-tests
Copilot review: the fullapi-tests modulesDir aggregated only the C++
provider/proxy installs, so test_fullapi_proxy_rust wasn't built/packaged by the
check. Add it to modulesDir and load + exercise it in the fullapi group (echoInt
forwarding + intEvent round-trip). 7/7 green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore: re-lock module-builder (brings the full_api SDK fixes)
Bumps logos-module-builder to 206c364 (#150), which re-pins cpp-sdk/qt-sdk/
rust-sdk/protocol to the merged full_api fixes. The five full_api modules now
build with no SDK overrides; checks.fullapi-tests is 7/7 green against master.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
ab4be29aae
commit
a8675f2e57
@@ -0,0 +1,21 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(TestFullapiCppPlugin LANGUAGES CXX)
|
||||
|
||||
if(DEFINED ENV{LOGOS_MODULE_BUILDER_ROOT})
|
||||
include($ENV{LOGOS_MODULE_BUILDER_ROOT}/cmake/LogosModule.cmake)
|
||||
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/LogosModule.cmake")
|
||||
include(cmake/LogosModule.cmake)
|
||||
else()
|
||||
message(FATAL_ERROR "LogosModule.cmake not found")
|
||||
endif()
|
||||
|
||||
# Universal module: `interface: "universal"` in metadata.json makes the builder
|
||||
# run the code generator over the impl header in preConfigure, emitting the Qt
|
||||
# plugin glue + dispatch + typed-event sources into generated_code/, which
|
||||
# LogosModule.cmake globs automatically.
|
||||
logos_module(
|
||||
NAME test_fullapi_cpp
|
||||
SOURCES
|
||||
src/test_fullapi_cpp_impl.h
|
||||
src/test_fullapi_cpp_impl.cpp
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "test_fullapi_cpp",
|
||||
"version": "1.0.0",
|
||||
"type": "core",
|
||||
"category": "testing",
|
||||
"description": "Universal C++ provider exercising every supported method parameter type, return type, and event parameter type. Reference implementation of the full_api contract; mirrored 1:1 by the Rust provider test_fullapi_rust so the same interface can be bound to either.",
|
||||
"main": "test_fullapi_cpp_plugin",
|
||||
"interface": "universal",
|
||||
"dependencies": [],
|
||||
|
||||
"nix": {
|
||||
"packages": {
|
||||
"build": [],
|
||||
"runtime": ["nlohmann_json"]
|
||||
},
|
||||
"external_libraries": [],
|
||||
"cmake": {
|
||||
"find_packages": [],
|
||||
"extra_sources": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "test_fullapi_cpp_impl.h"
|
||||
|
||||
// Every echo returns its input unchanged so a consumer can assert round-trip
|
||||
// fidelity per type, and so the C++ and Rust providers answer identically (the
|
||||
// cross-language parity check). `whoAmI()` is the one intentional difference.
|
||||
|
||||
// ── Identity ─────────────────────────────────────────────────────────────────
|
||||
|
||||
std::string TestFullapiCppImpl::whoAmI() { return "test_fullapi_cpp"; }
|
||||
|
||||
// ── Scalar echoes ─────────────────────────────────────────────────────────────
|
||||
|
||||
std::string TestFullapiCppImpl::echoString(const std::string& v) { return v; }
|
||||
std::vector<uint8_t> TestFullapiCppImpl::echoBytes(const std::vector<uint8_t>& v) { return v; }
|
||||
int64_t TestFullapiCppImpl::echoInt(int64_t v) { return v; }
|
||||
uint64_t TestFullapiCppImpl::echoUint(uint64_t v) { return v; }
|
||||
double TestFullapiCppImpl::echoDouble(double v) { return v; }
|
||||
bool TestFullapiCppImpl::echoBool(bool v) { return v; }
|
||||
nlohmann::json TestFullapiCppImpl::echoAny(const nlohmann::json& v) { return v; }
|
||||
|
||||
// ── Container echoes ──────────────────────────────────────────────────────────
|
||||
|
||||
std::vector<std::string> TestFullapiCppImpl::echoStringList(const std::vector<std::string>& v) { return v; }
|
||||
std::vector<int64_t> TestFullapiCppImpl::echoIntList(const std::vector<int64_t>& v) { return v; }
|
||||
std::vector<uint64_t> TestFullapiCppImpl::echoUintList(const std::vector<uint64_t>& v) { return v; }
|
||||
std::vector<double> TestFullapiCppImpl::echoDoubleList(const std::vector<double>& v) { return v; }
|
||||
std::vector<bool> TestFullapiCppImpl::echoBoolList(const std::vector<bool>& v) { return v; }
|
||||
LogosList TestFullapiCppImpl::echoList(const LogosList& v) { return v; }
|
||||
LogosMap TestFullapiCppImpl::echoMap(const LogosMap& v) { return v; }
|
||||
|
||||
// ── Return-only types ─────────────────────────────────────────────────────────
|
||||
|
||||
void TestFullapiCppImpl::doVoid() {}
|
||||
|
||||
StdLogosResult TestFullapiCppImpl::makeResult(bool ok) {
|
||||
if (!ok) {
|
||||
return {false, {}, "deliberate error for testing"};
|
||||
}
|
||||
nlohmann::json data;
|
||||
data["provider"] = "test_fullapi_cpp";
|
||||
data["ok"] = true;
|
||||
return {true, data, ""};
|
||||
}
|
||||
|
||||
// ── Event trigger drivers ─────────────────────────────────────────────────────
|
||||
// Each fires its typed event and returns true. The typed event method bodies
|
||||
// live in the generated test_fullapi_cpp_events.cpp.
|
||||
|
||||
bool TestFullapiCppImpl::fireStringEvent(const std::string& v) { stringEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireBytesEvent(const std::vector<uint8_t>& v) { bytesEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireIntEvent(int64_t v) { intEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireUintEvent(uint64_t v) { uintEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireDoubleEvent(double v) { doubleEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireBoolEvent(bool v) { boolEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireAnyEvent(const nlohmann::json& v) { anyEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireStringListEvent(const std::vector<std::string>& v) { stringListEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireIntListEvent(const std::vector<int64_t>& v) { intListEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireUintListEvent(const std::vector<uint64_t>& v) { uintListEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireDoubleListEvent(const std::vector<double>& v) { doubleListEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireBoolListEvent(const std::vector<bool>& v) { boolListEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireListEvent(const LogosList& v) { listEvent(v); return true; }
|
||||
bool TestFullapiCppImpl::fireMapEvent(const LogosMap& v) { mapEvent(v); return true; }
|
||||
@@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// test_fullapi_cpp — universal C++ provider covering the ENTIRE supported type
|
||||
// surface.
|
||||
//
|
||||
// It exercises, for the code generator + wire, every type that works end-to-end
|
||||
// across C++ std, the cdylib/Rust ABI, and the Qt/UI boundary:
|
||||
//
|
||||
// method params/returns : tstr, bstr, int, uint, float64, bool, any,
|
||||
// [tstr], [int], [uint], [float64], [bool],
|
||||
// [any] (LogosList), {tstr:any} (LogosMap),
|
||||
// result + void (returns only)
|
||||
// event params : the same set minus result/void
|
||||
//
|
||||
// The Rust provider `test_fullapi_rust` implements the SAME method + event names
|
||||
// and shapes, so a consumer can bind the `full_api` interface to either one.
|
||||
//
|
||||
// Authoring rules (universal / Qt-free):
|
||||
// * no Qt headers — the impl is parsed as text by the generator, which maps
|
||||
// std / LogosMap / LogosList / StdLogosResult to the wire and emits the Qt
|
||||
// glue in generated_code/.
|
||||
// * `any` -> a bare `nlohmann::json` (NOT LogosMap/LogosList, which the parser
|
||||
// recognises by name as map/list; anything else falls back to `any`).
|
||||
// * event params that are non-scalar (string, vector, LogosMap/List) MUST be
|
||||
// `const T&`; scalars are by value.
|
||||
// * NO trailing `// comments` on declaration lines: the header parser only
|
||||
// accepts a line that ends with `;`, so a trailing comment silently drops
|
||||
// the method/event. Type annotations therefore live above each group.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <logos_json.h> // LogosMap, LogosList, nlohmann::json
|
||||
#include <logos_module_context.h> // LogosModuleContext base + `logos_events`
|
||||
#include <logos_result.h> // StdLogosResult
|
||||
|
||||
class TestFullapiCppImpl : public LogosModuleContext {
|
||||
public:
|
||||
TestFullapiCppImpl() = default;
|
||||
~TestFullapiCppImpl() = default;
|
||||
|
||||
// Identity — lets a consumer prove which provider a bound interface resolved
|
||||
// to ("test_fullapi_cpp" vs "test_fullapi_rust").
|
||||
std::string whoAmI();
|
||||
|
||||
// ── Scalar echoes: param type == return type ─────────────────────────────
|
||||
// tstr / bstr / int / uint / float64 / bool / any
|
||||
std::string echoString(const std::string& v);
|
||||
std::vector<uint8_t> echoBytes(const std::vector<uint8_t>& v);
|
||||
int64_t echoInt(int64_t v);
|
||||
uint64_t echoUint(uint64_t v);
|
||||
double echoDouble(double v);
|
||||
bool echoBool(bool v);
|
||||
nlohmann::json echoAny(const nlohmann::json& v);
|
||||
|
||||
// ── Container echoes ─────────────────────────────────────────────────────
|
||||
// [tstr] / [int] / [uint] / [float64] / [bool] / [any] / {tstr:any}
|
||||
std::vector<std::string> echoStringList(const std::vector<std::string>& v);
|
||||
std::vector<int64_t> echoIntList(const std::vector<int64_t>& v);
|
||||
std::vector<uint64_t> echoUintList(const std::vector<uint64_t>& v);
|
||||
std::vector<double> echoDoubleList(const std::vector<double>& v);
|
||||
std::vector<bool> echoBoolList(const std::vector<bool>& v);
|
||||
LogosList echoList(const LogosList& v);
|
||||
LogosMap echoMap(const LogosMap& v);
|
||||
|
||||
// ── Return-only types ────────────────────────────────────────────────────
|
||||
// void return (no value); result return (success or error)
|
||||
void doVoid();
|
||||
StdLogosResult makeResult(bool ok);
|
||||
|
||||
// ── Event trigger drivers ────────────────────────────────────────────────
|
||||
// Each fires the correspondingly-typed event declared in `logos_events:`.
|
||||
// Bool-returning (not void) so `logoscore call` can invoke and read them —
|
||||
// void returns make the CLI exit non-zero. A consumer subscribes to the
|
||||
// event and reads back the captured payload.
|
||||
bool fireStringEvent(const std::string& v);
|
||||
bool fireBytesEvent(const std::vector<uint8_t>& v);
|
||||
bool fireIntEvent(int64_t v);
|
||||
bool fireUintEvent(uint64_t v);
|
||||
bool fireDoubleEvent(double v);
|
||||
bool fireBoolEvent(bool v);
|
||||
bool fireAnyEvent(const nlohmann::json& v);
|
||||
bool fireStringListEvent(const std::vector<std::string>& v);
|
||||
bool fireIntListEvent(const std::vector<int64_t>& v);
|
||||
bool fireUintListEvent(const std::vector<uint64_t>& v);
|
||||
bool fireDoubleListEvent(const std::vector<double>& v);
|
||||
bool fireBoolListEvent(const std::vector<bool>& v);
|
||||
bool fireListEvent(const LogosList& v);
|
||||
bool fireMapEvent(const LogosMap& v);
|
||||
|
||||
// ── Typed events (one per event-legal type) ──────────────────────────────
|
||||
// Codegen emits bodies in test_fullapi_cpp_events.cpp and exposes typed
|
||||
// on<Event>(callback) accessors on the consumer-side wrapper. Order mirrors
|
||||
// the trigger drivers above:
|
||||
// tstr / bstr / int / uint / float64 / bool / any /
|
||||
// [tstr] / [int] / [uint] / [float64] / [bool] / [any] / {tstr:any}
|
||||
logos_events:
|
||||
void stringEvent(const std::string& v);
|
||||
void bytesEvent(const std::vector<uint8_t>& v);
|
||||
void intEvent(int64_t v);
|
||||
void uintEvent(uint64_t v);
|
||||
void doubleEvent(double v);
|
||||
void boolEvent(bool v);
|
||||
void anyEvent(const nlohmann::json& v);
|
||||
void stringListEvent(const std::vector<std::string>& v);
|
||||
void intListEvent(const std::vector<int64_t>& v);
|
||||
void uintListEvent(const std::vector<uint64_t>& v);
|
||||
void doubleListEvent(const std::vector<double>& v);
|
||||
void boolListEvent(const std::vector<bool>& v);
|
||||
void listEvent(const LogosList& v);
|
||||
void mapEvent(const LogosMap& v);
|
||||
};
|
||||
Reference in New Issue
Block a user