mirror of
https://github.com/logos-co/logos-test-modules.git
synced 2026-08-30 19:51:16 +00:00
add test-basic-module-cpp (#17)
* add test-basic-module-cpp * change to new liblogos api
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(TestBasicModuleCppPlugin 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 `logos-cpp-generator --from-header` in preConfigure. The
|
||||
# generator produces `generated_code/test_basic_module_cpp_qt_glue.h` +
|
||||
# `generated_code/test_basic_module_cpp_dispatch.cpp` which LogosModule.cmake
|
||||
# picks up automatically — no loader / dispatch source needs to live here.
|
||||
logos_module(
|
||||
NAME test_basic_module_cpp
|
||||
SOURCES
|
||||
src/test_basic_module_cpp_impl.h
|
||||
src/test_basic_module_cpp_impl.cpp
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "test_basic_module_cpp",
|
||||
"version": "1.0.0",
|
||||
"type": "core",
|
||||
"category": "testing",
|
||||
"description": "Pure-C++ mirror of test_basic_module: every method uses std/LogosMap/LogosList/StdLogosResult (no Qt in the impl), so the generated qt_glue layer is exercised end-to-end.",
|
||||
"main": "test_basic_module_cpp_plugin",
|
||||
"interface": "universal",
|
||||
"dependencies": [],
|
||||
|
||||
"nix": {
|
||||
"packages": {
|
||||
"build": [],
|
||||
"runtime": ["nlohmann_json"]
|
||||
},
|
||||
"external_libraries": [],
|
||||
"cmake": {
|
||||
"find_packages": [],
|
||||
"extra_sources": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
#include "test_basic_module_cpp_impl.h"
|
||||
|
||||
#include <cstddef> // std::size_t (used in splitString below)
|
||||
#include <utility> // std::move (used in splitString below)
|
||||
|
||||
// Keep return shapes closely aligned with test-basic-module's Qt versions
|
||||
// so the docker smoke / integration tests can exercise the same matrix
|
||||
// against both modules. Some values intentionally differ where they
|
||||
// identify the concrete module implementation — notably `returnString()`
|
||||
// reports `"test_basic_module_cpp"` so the test can distinguish which of
|
||||
// the two modules answered the call.
|
||||
|
||||
// ── void ─────────────────────────────────────────────────────────────────
|
||||
|
||||
void TestBasicModuleCppImpl::doNothing() {}
|
||||
void TestBasicModuleCppImpl::doNothingWithArgs(const std::string&, int64_t) {}
|
||||
|
||||
// ── bool ─────────────────────────────────────────────────────────────────
|
||||
|
||||
bool TestBasicModuleCppImpl::returnTrue() { return true; }
|
||||
bool TestBasicModuleCppImpl::returnFalse() { return false; }
|
||||
bool TestBasicModuleCppImpl::isPositive(int64_t value) { return value > 0; }
|
||||
|
||||
// ── int64_t ──────────────────────────────────────────────────────────────
|
||||
|
||||
int64_t TestBasicModuleCppImpl::returnInt() { return 42; }
|
||||
int64_t TestBasicModuleCppImpl::addInts(int64_t a, int64_t b) { return a + b; }
|
||||
int64_t TestBasicModuleCppImpl::stringLength(const std::string& s) {
|
||||
return static_cast<int64_t>(s.size());
|
||||
}
|
||||
|
||||
// ── uint64_t ─────────────────────────────────────────────────────────────
|
||||
|
||||
uint64_t TestBasicModuleCppImpl::returnUint() { return 99u; }
|
||||
uint64_t TestBasicModuleCppImpl::echoUint(uint64_t n) { return n; }
|
||||
|
||||
// ── double ───────────────────────────────────────────────────────────────
|
||||
|
||||
double TestBasicModuleCppImpl::returnDouble() { return 3.5; }
|
||||
double TestBasicModuleCppImpl::addDoubles(double a, double b) { return a + b; }
|
||||
|
||||
// ── std::string ──────────────────────────────────────────────────────────
|
||||
|
||||
std::string TestBasicModuleCppImpl::returnString() { return "test_basic_module_cpp"; }
|
||||
std::string TestBasicModuleCppImpl::echo(const std::string& input) { return input; }
|
||||
std::string TestBasicModuleCppImpl::concat(const std::string& a, const std::string& b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// ── StdLogosResult ───────────────────────────────────────────────────────
|
||||
// Mirrors test_basic_module's `successResult` / `errorResult` / `…WithMap`
|
||||
// / `…WithList` / `validateInput` — payloads tuned so the pytest assertion
|
||||
// matrix can compare row-for-row with the Qt-module expectations.
|
||||
|
||||
StdLogosResult TestBasicModuleCppImpl::successResult() {
|
||||
return {true, "operation succeeded", ""};
|
||||
}
|
||||
|
||||
StdLogosResult TestBasicModuleCppImpl::errorResult() {
|
||||
return {false, {}, "deliberate error for testing"};
|
||||
}
|
||||
|
||||
StdLogosResult TestBasicModuleCppImpl::resultWithMap() {
|
||||
nlohmann::json m;
|
||||
m["name"] = "test";
|
||||
m["count"] = 42;
|
||||
m["active"] = true;
|
||||
return {true, m, ""};
|
||||
}
|
||||
|
||||
StdLogosResult TestBasicModuleCppImpl::resultWithList() {
|
||||
nlohmann::json list = nlohmann::json::array();
|
||||
list.push_back({{"id", 1}, {"label", "first"}});
|
||||
list.push_back({{"id", 2}, {"label", "second"}});
|
||||
return {true, list, ""};
|
||||
}
|
||||
|
||||
StdLogosResult TestBasicModuleCppImpl::validateInput(const std::string& input) {
|
||||
if (input.empty()) {
|
||||
return {false, {}, "input cannot be empty"};
|
||||
}
|
||||
nlohmann::json data;
|
||||
data["input"] = input;
|
||||
data["length"] = static_cast<int64_t>(input.size());
|
||||
return {true, data, ""};
|
||||
}
|
||||
|
||||
// ── LogosMap ─────────────────────────────────────────────────────────────
|
||||
|
||||
LogosMap TestBasicModuleCppImpl::returnMap() {
|
||||
LogosMap m;
|
||||
m["key"] = "value";
|
||||
m["number"] = 7;
|
||||
return m;
|
||||
}
|
||||
|
||||
LogosMap TestBasicModuleCppImpl::makeMap(const std::string& key,
|
||||
const std::string& value) {
|
||||
LogosMap m;
|
||||
m[key] = value;
|
||||
return m;
|
||||
}
|
||||
|
||||
// ── LogosList ────────────────────────────────────────────────────────────
|
||||
|
||||
LogosList TestBasicModuleCppImpl::returnList() {
|
||||
LogosList list = nlohmann::json::array();
|
||||
list.push_back(1);
|
||||
list.push_back(2);
|
||||
list.push_back(3);
|
||||
return list;
|
||||
}
|
||||
|
||||
LogosList TestBasicModuleCppImpl::makeList(const std::string& a,
|
||||
const std::string& b) {
|
||||
LogosList list = nlohmann::json::array();
|
||||
list.push_back(a);
|
||||
list.push_back(b);
|
||||
return list;
|
||||
}
|
||||
|
||||
// ── std::vector<std::string> ─────────────────────────────────────────────
|
||||
|
||||
std::vector<std::string> TestBasicModuleCppImpl::returnStringList() {
|
||||
return {"one", "two", "three"};
|
||||
}
|
||||
|
||||
std::vector<std::string> TestBasicModuleCppImpl::splitString(const std::string& input) {
|
||||
// Split on ','. Simple, matches the Qt module's semantics.
|
||||
std::vector<std::string> out;
|
||||
std::string cur;
|
||||
for (char c : input) {
|
||||
if (c == ',') { out.push_back(std::move(cur)); cur.clear(); }
|
||||
else { cur.push_back(c); }
|
||||
}
|
||||
out.push_back(std::move(cur));
|
||||
return out;
|
||||
}
|
||||
|
||||
// ── std::vector<uint8_t> ─────────────────────────────────────────────────
|
||||
|
||||
std::vector<uint8_t> TestBasicModuleCppImpl::returnBytes() {
|
||||
return {0x01, 0x02, 0x03, 0x04, 0x05};
|
||||
}
|
||||
|
||||
int64_t TestBasicModuleCppImpl::byteArraySize(const std::vector<uint8_t>& data) {
|
||||
return static_cast<int64_t>(data.size());
|
||||
}
|
||||
|
||||
// ── Parameter types ──────────────────────────────────────────────────────
|
||||
|
||||
int64_t TestBasicModuleCppImpl::echoInt(int64_t n) { return n; }
|
||||
bool TestBasicModuleCppImpl::echoBool(bool b) { return b; }
|
||||
|
||||
std::string TestBasicModuleCppImpl::joinStrings(const std::vector<std::string>& list) {
|
||||
std::string out;
|
||||
for (std::size_t i = 0; i < list.size(); ++i) {
|
||||
if (i > 0) out += ",";
|
||||
out += list[i];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// ── 0–5 args ─────────────────────────────────────────────────────────────
|
||||
// The format-string trick (QString("...arg() / arg()")) the Qt module uses
|
||||
// doesn't translate directly; plain string concatenation produces the same
|
||||
// output, which keeps the pytest expected-value strings identical.
|
||||
|
||||
static std::string toDec(int64_t n) { return std::to_string(n); }
|
||||
static std::string toBoolStr(bool b) { return b ? "true" : "false"; }
|
||||
|
||||
std::string TestBasicModuleCppImpl::noArgs() {
|
||||
return "noArgs()";
|
||||
}
|
||||
std::string TestBasicModuleCppImpl::oneArg(const std::string& a) {
|
||||
return "oneArg(" + a + ")";
|
||||
}
|
||||
std::string TestBasicModuleCppImpl::twoArgs(const std::string& a, int64_t b) {
|
||||
return "twoArgs(" + a + ", " + toDec(b) + ")";
|
||||
}
|
||||
std::string TestBasicModuleCppImpl::threeArgs(const std::string& a, int64_t b, bool c) {
|
||||
return "threeArgs(" + a + ", " + toDec(b) + ", " + toBoolStr(c) + ")";
|
||||
}
|
||||
std::string TestBasicModuleCppImpl::fourArgs(const std::string& a, int64_t b,
|
||||
bool c, const std::string& d) {
|
||||
return "fourArgs(" + a + ", " + toDec(b) + ", " + toBoolStr(c) + ", " + d + ")";
|
||||
}
|
||||
std::string TestBasicModuleCppImpl::fiveArgs(const std::string& a, int64_t b,
|
||||
bool c, const std::string& d, int64_t e) {
|
||||
return "fiveArgs(" + a + ", " + toDec(b) + ", " + toBoolStr(c) + ", " + d + ", " + toDec(e) + ")";
|
||||
}
|
||||
|
||||
// ── Events ───────────────────────────────────────────────────────────────
|
||||
|
||||
void TestBasicModuleCppImpl::emitTestEvent(const std::string& data) {
|
||||
if (emitEvent) emitEvent("testEvent", data);
|
||||
}
|
||||
|
||||
void TestBasicModuleCppImpl::emitMultiArgEvent(const std::string& name, int64_t count) {
|
||||
// The generator-wired emitEvent takes (name, data). Pack the multi-arg
|
||||
// payload as a JSON string so the wire shape is lossless (Python test
|
||||
// just asserts both fragments appear in the stringified event).
|
||||
if (emitEvent) {
|
||||
nlohmann::json payload;
|
||||
payload["name"] = name;
|
||||
payload["count"] = count;
|
||||
emitEvent("multiArgEvent", payload.dump());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
#pragma once
|
||||
|
||||
// Pure-C++ mirror of `test_basic_module`. Exercises every parameter/return
|
||||
// type the code generator needs to translate between C++ std types and Qt
|
||||
// on the wire:
|
||||
//
|
||||
// void, bool, int64_t, uint64_t, double, std::string,
|
||||
// std::vector<std::string>, std::vector<uint8_t>,
|
||||
// LogosMap / LogosList (nlohmann::json aliases), StdLogosResult
|
||||
//
|
||||
// Absolutely no Qt headers here — `logos-cpp-generator --from-header`
|
||||
// parses this file as text to derive method signatures, then emits a
|
||||
// `test_basic_module_cpp_qt_glue.h` + `_dispatch.cpp` that does all the
|
||||
// QVariant ↔ std conversion. See spec.md in logos-cpp-sdk/cpp-generator/docs/
|
||||
// for the full conversion table.
|
||||
//
|
||||
// Event emission: the generator detects the `std::function emitEvent`
|
||||
// member by name and wires it to LogosProviderBase::emitEvent in the
|
||||
// generated glue layer, so the impl can fire events without touching Qt.
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <logos_json.h> // LogosMap, LogosList (nlohmann::json aliases)
|
||||
#include <logos_result.h> // StdLogosResult
|
||||
|
||||
class TestBasicModuleCppImpl {
|
||||
public:
|
||||
TestBasicModuleCppImpl() = default;
|
||||
~TestBasicModuleCppImpl() = default;
|
||||
|
||||
// Generated glue wires this in its ctor — call it to emit events. The
|
||||
// two-string signature (name, json-serialised data) is the one the
|
||||
// parser recognises; the generator emits a shim that dispatches to
|
||||
// LogosProviderBase::emitEvent with a QVariantList payload.
|
||||
std::function<void(const std::string& eventName, const std::string& data)> emitEvent;
|
||||
|
||||
// ── Return type: void ────────────────────────────────────────────────
|
||||
void doNothing();
|
||||
void doNothingWithArgs(const std::string& a, int64_t b);
|
||||
|
||||
// ── Return type: bool ────────────────────────────────────────────────
|
||||
bool returnTrue();
|
||||
bool returnFalse();
|
||||
bool isPositive(int64_t value);
|
||||
|
||||
// ── Return type: int64_t ─────────────────────────────────────────────
|
||||
int64_t returnInt();
|
||||
int64_t addInts(int64_t a, int64_t b);
|
||||
int64_t stringLength(const std::string& s);
|
||||
|
||||
// ── Return type: uint64_t ────────────────────────────────────────────
|
||||
uint64_t returnUint();
|
||||
uint64_t echoUint(uint64_t n);
|
||||
|
||||
// ── Return type: double ──────────────────────────────────────────────
|
||||
double returnDouble();
|
||||
double addDoubles(double a, double b);
|
||||
|
||||
// ── Return type: std::string ─────────────────────────────────────────
|
||||
std::string returnString();
|
||||
std::string echo(const std::string& input);
|
||||
std::string concat(const std::string& a, const std::string& b);
|
||||
|
||||
// ── Return type: StdLogosResult ──────────────────────────────────────
|
||||
// Generator emits a StdLogosResult → Qt LogosResult conversion in glue,
|
||||
// so over the wire this comes out the same shape as test_basic_module's
|
||||
// `LogosResult` methods: { success, value, error }.
|
||||
StdLogosResult successResult();
|
||||
StdLogosResult errorResult();
|
||||
StdLogosResult resultWithMap();
|
||||
StdLogosResult resultWithList();
|
||||
StdLogosResult validateInput(const std::string& input);
|
||||
|
||||
// ── Return type: LogosMap (json object) ─────────────────────────────
|
||||
// `jsonReturn=true` → glue calls nlohmannToQVariant to unpack into
|
||||
// QVariantMap, which then serialises as a regular JSON object over RPC.
|
||||
LogosMap returnMap();
|
||||
LogosMap makeMap(const std::string& key, const std::string& value);
|
||||
|
||||
// ── Return type: LogosList (json array) ─────────────────────────────
|
||||
LogosList returnList();
|
||||
LogosList makeList(const std::string& a, const std::string& b);
|
||||
|
||||
// ── Return type: std::vector<std::string> ───────────────────────────
|
||||
std::vector<std::string> returnStringList();
|
||||
std::vector<std::string> splitString(const std::string& input);
|
||||
|
||||
// ── Return type: std::vector<uint8_t> (bytes) ───────────────────────
|
||||
std::vector<uint8_t> returnBytes();
|
||||
int64_t byteArraySize(const std::vector<uint8_t>& data);
|
||||
|
||||
// ── Parameter types ─────────────────────────────────────────────────
|
||||
int64_t echoInt(int64_t n);
|
||||
bool echoBool(bool b);
|
||||
std::string joinStrings(const std::vector<std::string>& list);
|
||||
|
||||
// ── Argument counts 0–5 (same matrix as the Qt module) ──────────────
|
||||
std::string noArgs();
|
||||
std::string oneArg(const std::string& a);
|
||||
std::string twoArgs(const std::string& a, int64_t b);
|
||||
std::string threeArgs(const std::string& a, int64_t b, bool c);
|
||||
std::string fourArgs(const std::string& a, int64_t b, bool c, const std::string& d);
|
||||
std::string fiveArgs(const std::string& a, int64_t b, bool c, const std::string& d, int64_t e);
|
||||
|
||||
// ── Events ──────────────────────────────────────────────────────────
|
||||
void emitTestEvent(const std::string& data);
|
||||
void emitMultiArgEvent(const std::string& name, int64_t count);
|
||||
};
|
||||
Reference in New Issue
Block a user