mirror of
https://github.com/logos-co/logos-test-modules.git
synced 2026-08-27 10:11:12 +00:00
test: retire test_ipc_module, now fully duplicated
It was the last `interface: "legacy"` provider in the repo, and it no longer
covers anything of its own. Its 21-method surface is mirrored 1:1 by
test_ipc_new_api_module, and the Qt-typed consumer style it exercised now has a
dedicated home in test_fullapi_qtproxy (`consumer_api_style: "qt"`).
Removing it is what makes an absent `interface` mean "not a provider" rather
than "a provider whose glue silently went missing" — see the throw added to
logos-module-builder alongside this.
Groups `ipc` and `async` go with it, and so does the `unit` group, whose binary
came from the deleted derivation and would otherwise have gone permanently SKIP.
The `multi` group is repointed at the successor rather than deleted: it tests
sequential -c chaining, not the module, and the successor answers the same three
calls.
The async group is NOT simply gone. Its assertions were ported to the
ipc-new-api group in bc942e2 first, and they assert more there — on the lp
surface `<name>Async` IS the generated wrapper, so they cover async into a
module with no Qt in its own TUs. That ordering was the point: the coverage
moved before the module was removed, never the other way round.
Verified with the full suite: 172 passed, 0 failed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bc942e2a37
commit
af567c1cbc
@@ -8,8 +8,7 @@ and a standalone thread-safety test suite:
|
||||
|--------|---------|
|
||||
| **test_basic_module** | Standalone module (no external libs, no IPC). Covers every supported parameter type, return type, argument count (0–5), LogosResult patterns, and events. |
|
||||
| **test_extlib_module** | Wraps an external C library (`libstrutil`). Validates the external-library build pipeline. |
|
||||
| **test_ipc_module** | Calls the two modules above via `LogosAPI`. Validates inter-module communication, generated type-safe wrappers, and event subscriptions. |
|
||||
| **test_ipc_new_api_module** | Same as test_ipc_module but uses the new provider API (`LogosProviderBase` + `LOGOS_METHOD`). No `QObject` inheritance in the implementation class. |
|
||||
| **test_ipc_new_api_module** | Calls the two modules above. Validates inter-module communication, generated type-safe wrappers (sync and async), cross-module chaining, and events — all from an `interface: "universal"` module with no Qt in its own translation units. |
|
||||
| **test_dummy_module** | Minimal `LogosProviderBase` module (`noop()` only). Used as a binary template for the thread-safety tests — patched at the binary level to generate unique module copies. |
|
||||
|
||||
## SDK coverage matrix
|
||||
@@ -18,7 +17,7 @@ and a standalone thread-safety test suite:
|
||||
|
||||
| Type | Tested in |
|
||||
|------|-----------|
|
||||
| `QString` | test_basic_module, test_extlib_module, test_ipc_module |
|
||||
| `QString` | test_basic_module, test_extlib_module, test_ipc_new_api_module |
|
||||
| `qlonglong` | test_basic_module |
|
||||
| `bool` | test_basic_module |
|
||||
| `QStringList` | test_basic_module |
|
||||
@@ -31,8 +30,8 @@ and a standalone thread-safety test suite:
|
||||
| `void` | test_basic_module |
|
||||
| `bool` | test_basic_module |
|
||||
| `qlonglong` | test_basic_module, test_extlib_module |
|
||||
| `QString` | test_basic_module, test_extlib_module, test_ipc_module |
|
||||
| `LogosResult` | test_basic_module, test_ipc_module |
|
||||
| `QString` | test_basic_module, test_extlib_module, test_ipc_new_api_module |
|
||||
| `LogosResult` | test_basic_module, test_ipc_new_api_module |
|
||||
| `QVariant` | test_basic_module |
|
||||
| `QVariantList` | test_basic_module |
|
||||
| `QStringList` | test_basic_module |
|
||||
@@ -104,16 +103,16 @@ they are ASCII-only case mappings performed by the external C library, and bytes
|
||||
|
||||
| Pattern | Tested in |
|
||||
|---------|-----------|
|
||||
| `LogosAPI::getClient` + `invokeRemoteMethod` | test_ipc_module |
|
||||
| Generated `LogosModules` wrappers | test_ipc_module |
|
||||
| Event subscription (`onEvent`) | test_ipc_module |
|
||||
| Event emission — typed `logos_events:` | test_basic_module |
|
||||
| Event emission — dynamic `eventResponse` | test_ipc_module |
|
||||
| Cross-module chaining | test_ipc_module |
|
||||
| Generated `modules().<dep>` wrappers (sync) | test_ipc_new_api_module |
|
||||
| Generated `<name>Async` wrappers over `lp_invoke_async` | test_ipc_new_api_module |
|
||||
| Event subscription | test_ipc_new_api_module |
|
||||
| Event emission — typed `logos_events:` | test_basic_module, test_ipc_new_api_module |
|
||||
| Cross-module chaining | test_ipc_new_api_module |
|
||||
| Qt-typed consumer (`consumer_api_style: "qt"`) | test_fullapi_qtproxy |
|
||||
|
||||
## Running tests
|
||||
|
||||
The integration test suite exercises the core modules (`test_basic_module`, `test_extlib_module`, `test_ipc_module`, `test_ipc_new_api_module`) via `logoscore`:
|
||||
The integration test suite exercises the core modules (`test_basic_module`, `test_extlib_module`, `test_ipc_new_api_module`) via `logoscore`:
|
||||
|
||||
```bash
|
||||
# From logos-test-modules
|
||||
@@ -212,7 +211,7 @@ nix build
|
||||
# Individual modules
|
||||
nix build .#test_basic_module
|
||||
nix build .#test_extlib_module
|
||||
nix build .#test_ipc_module
|
||||
nix build .#test_ipc_new_api_module
|
||||
nix build .#test_ipc_new_api_module
|
||||
nix build .#test_dummy_module
|
||||
```
|
||||
|
||||
@@ -229,14 +229,6 @@
|
||||
configFile = ./test-extlib-module/metadata.json;
|
||||
};
|
||||
|
||||
ipc = mkModule {
|
||||
src = ./test-ipc-module;
|
||||
configFile = ./test-ipc-module/metadata.json;
|
||||
flakeInputs = {
|
||||
test_basic_module = basic;
|
||||
test_extlib_module = extlib;
|
||||
};
|
||||
};
|
||||
|
||||
# interface: "universal" — the impl header IS the contract; the builder
|
||||
# derives the LIDL and emits the glue. No preConfigure hook.
|
||||
@@ -353,7 +345,6 @@
|
||||
test_context_module_cpp = contextCpp.packages.${system};
|
||||
test_interface_module_cpp = interfaceCpp.packages.${system};
|
||||
test_extlib_module = extlib.packages.${system};
|
||||
test_ipc_module = ipc.packages.${system};
|
||||
test_ipc_new_api_module = ipc-new-api.packages.${system};
|
||||
test_dummy_module = dummy.packages.${system};
|
||||
test_qml_only = qmlOnly.packages.${system};
|
||||
@@ -387,7 +378,6 @@
|
||||
test_context_module_cpp = contextCpp.packages.${system}.default;
|
||||
test_interface_module_cpp = interfaceCpp.packages.${system}.default;
|
||||
test_extlib_module = extlib.packages.${system}.default;
|
||||
test_ipc_module = ipc.packages.${system}.default;
|
||||
test_ipc_new_api_module = ipc-new-api.packages.${system}.default;
|
||||
test_dummy_module = dummy.packages.${system}.default;
|
||||
test_qml_only = qmlOnly.packages.${system}.default;
|
||||
@@ -403,7 +393,6 @@
|
||||
basicCpp.packages.${system}.default
|
||||
contextCpp.packages.${system}.default
|
||||
extlib.packages.${system}.default
|
||||
ipc.packages.${system}.default
|
||||
ipc-new-api.packages.${system}.default
|
||||
dummy.packages.${system}.default
|
||||
];
|
||||
@@ -420,7 +409,6 @@
|
||||
basicCppInstall = basicCpp.packages.${system}.install;
|
||||
contextCppInstall = contextCpp.packages.${system}.install;
|
||||
extlibInstall = extlib.packages.${system}.install;
|
||||
ipcInstall = ipc.packages.${system}.install;
|
||||
ipcNewApiInstall = ipc-new-api.packages.${system}.install;
|
||||
fullapiCppInstall = fullapiCpp.packages.${system}.install;
|
||||
fullapiRustInstall = fullapiRust.packages.${system}.install;
|
||||
@@ -470,7 +458,7 @@
|
||||
modulesDir = pkgs.runCommand "test-modules-dir" {} ''
|
||||
mkdir -p $out
|
||||
|
||||
for installed in ${basicInstall} ${basicCppInstall} ${contextCppInstall} ${extlibInstall} ${ipcInstall} ${ipcNewApiInstall} ${fullapiCppInstall} ${fullapiRustInstall} ${fullapiProxyInstall} ${fullapiProxyRustInstall}; do
|
||||
for installed in ${basicInstall} ${basicCppInstall} ${contextCppInstall} ${extlibInstall} ${ipcNewApiInstall} ${fullapiCppInstall} ${fullapiRustInstall} ${fullapiProxyInstall} ${fullapiProxyRustInstall}; do
|
||||
if [ -d "$installed/modules" ]; then
|
||||
cp -rn "$installed/modules/." "$out/"
|
||||
|
||||
@@ -636,56 +624,6 @@
|
||||
# ws run logos-standalone-app --local ... -l test_qml_backend
|
||||
|
||||
# Async-only tests (validates invokeRemoteMethodAsync + generated wrappers)
|
||||
async-tests = pkgs.runCommand "logos-test-modules-async-tests" {
|
||||
nativeBuildInputs = [
|
||||
logoscorePkg
|
||||
pkgs.jq
|
||||
] ++ pkgs.lib.optionals pkgs.stdenv.isLinux [ pkgs.qt6.qtbase ];
|
||||
} ''
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
export QT_FORCE_STDERR_LOGGING=1
|
||||
export TEST_GROUPS=async
|
||||
export TEST_TIMEOUT=30
|
||||
${pkgs.lib.optionalString pkgs.stdenv.isLinux ''
|
||||
export QT_PLUGIN_PATH="${pkgs.qt6.qtbase}/${pkgs.qt6.qtbase.qtPluginPrefix}"
|
||||
''}
|
||||
mkdir -p $out
|
||||
|
||||
echo "Running async-only tests..."
|
||||
bash ${./tests/run_tests.sh} \
|
||||
${logoscorePkg}/bin/logoscore \
|
||||
${modulesDir} \
|
||||
2>&1 | tee $out/test-results.txt
|
||||
|
||||
echo "Async tests completed."
|
||||
'';
|
||||
|
||||
# IPC-only tests (faster iteration on inter-module communication)
|
||||
ipc-tests = pkgs.runCommand "logos-test-modules-ipc-tests" {
|
||||
nativeBuildInputs = [
|
||||
logoscorePkg
|
||||
pkgs.jq
|
||||
] ++ pkgs.lib.optionals pkgs.stdenv.isLinux [ pkgs.qt6.qtbase ];
|
||||
} ''
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
export QT_FORCE_STDERR_LOGGING=1
|
||||
export TEST_GROUPS=ipc
|
||||
export TEST_TIMEOUT=30
|
||||
${pkgs.lib.optionalString pkgs.stdenv.isLinux ''
|
||||
export QT_PLUGIN_PATH="${pkgs.qt6.qtbase}/${pkgs.qt6.qtbase.qtPluginPrefix}"
|
||||
''}
|
||||
mkdir -p $out
|
||||
|
||||
echo "Running IPC-only tests..."
|
||||
bash ${./tests/run_tests.sh} \
|
||||
${logoscorePkg}/bin/logoscore \
|
||||
${modulesDir} \
|
||||
2>&1 | tee $out/test-results.txt
|
||||
|
||||
echo "IPC tests completed."
|
||||
'';
|
||||
|
||||
# IPC new-API tests (LogosProviderBase path)
|
||||
ipc-new-api-tests = pkgs.runCommand "logos-test-modules-ipc-new-api-tests" {
|
||||
nativeBuildInputs = [
|
||||
logoscorePkg
|
||||
@@ -711,116 +649,6 @@
|
||||
'';
|
||||
|
||||
# Unit tests using the mock transport — no real IPC / logoscore required
|
||||
unit-tests =
|
||||
let
|
||||
# test_ipc_module is still a LEGACY Qt module, so its test consumes
|
||||
# the qt-typed header variant. (Its universal sibling next door
|
||||
# uses headers-lp; do not unify these two without also switching
|
||||
# this derivation's generator call to --api-style lp.)
|
||||
basicInclude = basic.packages.${system}.include;
|
||||
extlibInclude = extlib.packages.${system}.include;
|
||||
|
||||
# Build the test executable via CMake
|
||||
testBin = pkgs.stdenv.mkDerivation {
|
||||
pname = "test-ipc-module-unit-tests";
|
||||
version = "1.0.0";
|
||||
|
||||
src = ./test-ipc-module;
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.cmake
|
||||
pkgs.ninja
|
||||
pkgs.qt6.wrapQtAppsNoGuiHook
|
||||
logosSdkPkg # provides logos-cpp-generator + SDK headers
|
||||
logosQtHostPkg
|
||||
logosQtSdkPkg # seam headers for the generated qt wrapper
|
||||
logosProtocolPkg
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
pkgs.qt6.qtbase
|
||||
pkgs.qt6.qtremoteobjects
|
||||
];
|
||||
|
||||
env = {
|
||||
LOGOS_CPP_SDK_ROOT = "${logosSdkPkg}";
|
||||
LOGOS_QT_HOST_ROOT = "${logosQtHostPkg}";
|
||||
LOGOS_QT_SDK_ROOT = "${logosQtSdkPkg}";
|
||||
LOGOS_PROTOCOL_ROOT = "${logosProtocolPkg}";
|
||||
LOGOS_LIBLOGOS_ROOT = "${logosLiblogosPkg}";
|
||||
};
|
||||
|
||||
dontUseCmakeConfigure = true;
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
# Generate logos_sdk.cpp (general mode)
|
||||
mkdir -p generated_code
|
||||
cat > metadata.json <<'METADATA_EOF'
|
||||
{
|
||||
"name": "test_ipc_module",
|
||||
"version": "1.0.0",
|
||||
"type": "core",
|
||||
"category": "testing",
|
||||
"description": "Test module exercising inter-module communication via LogosAPI",
|
||||
"dependencies": ["test_basic_module", "test_extlib_module"]
|
||||
}
|
||||
METADATA_EOF
|
||||
logos-cpp-generator --metadata metadata.json --general-only --output-dir ./generated_code
|
||||
|
||||
# Copy dependency-generated API headers alongside the umbrella headers
|
||||
cp ${basicInclude}/include/*.h ./generated_code/ 2>/dev/null || true
|
||||
cp ${basicInclude}/include/*.cpp ./generated_code/ 2>/dev/null || true
|
||||
cp ${extlibInclude}/include/*.h ./generated_code/ 2>/dev/null || true
|
||||
cp ${extlibInclude}/include/*.cpp ./generated_code/ 2>/dev/null || true
|
||||
|
||||
# MOC needs metadata.json next to the plugin header for Q_PLUGIN_METADATA
|
||||
cp metadata.json src/metadata.json
|
||||
|
||||
# CMake configure + build (out-of-source, pointing at tests/ subdir)
|
||||
mkdir -p build && cd build
|
||||
cmake ../tests -GNinja \
|
||||
-DLOGOS_CPP_SDK_ROOT=${logosSdkPkg} \
|
||||
-DLOGOS_QT_HOST_ROOT=${logosQtHostPkg} \
|
||||
-DLOGOS_QT_SDK_ROOT=${logosQtSdkPkg} \
|
||||
-DLOGOS_PROTOCOL_ROOT=${logosProtocolPkg} \
|
||||
-DLOGOS_LIBLOGOS_ROOT=${logosLiblogosPkg}
|
||||
ninja test_ipc_module_tests
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/bin
|
||||
cp test_ipc_module_tests $out/bin/
|
||||
runHook postInstall
|
||||
'';
|
||||
};
|
||||
in
|
||||
pkgs.runCommand "logos-test-modules-unit-tests" {
|
||||
nativeBuildInputs = [ testBin ]
|
||||
++ pkgs.lib.optionals pkgs.stdenv.isLinux [ pkgs.qt6.qtbase ];
|
||||
} ''
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
export QT_FORCE_STDERR_LOGGING=1
|
||||
export TEST_GROUPS=unit
|
||||
${pkgs.lib.optionalString pkgs.stdenv.isLinux ''
|
||||
export QT_PLUGIN_PATH="${pkgs.qt6.qtbase}/${pkgs.qt6.qtbase.qtPluginPrefix}"
|
||||
''}
|
||||
mkdir -p $out
|
||||
|
||||
export UNIT_TEST_BIN="${testBin}/bin/test_ipc_module_tests"
|
||||
bash ${./tests/run_tests.sh} \
|
||||
${logoscorePkg}/bin/logoscore \
|
||||
${modulesDir} \
|
||||
2>&1 | tee $out/unit-test-results.txt
|
||||
|
||||
echo "Unit tests completed."
|
||||
'';
|
||||
|
||||
# Unit tests for the new provider API (mock transport, no logoscore)
|
||||
unit-tests-new-api =
|
||||
let
|
||||
# The impl is now `interface: "universal"`, i.e. Qt-free and
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(TestIpcModulePlugin 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()
|
||||
|
||||
logos_module(
|
||||
NAME test_ipc_module
|
||||
SOURCES
|
||||
src/test_ipc_module_interface.h
|
||||
src/test_ipc_module_plugin.h
|
||||
src/test_ipc_module_plugin.cpp
|
||||
)
|
||||
Generated
-7757
File diff suppressed because it is too large
Load Diff
@@ -1,24 +0,0 @@
|
||||
{
|
||||
description = "Test IPC Module — exercises inter-module communication via LogosAPI";
|
||||
|
||||
inputs = {
|
||||
logos-module-builder.url = "github:logos-co/logos-module-builder";
|
||||
|
||||
test_basic_module = {
|
||||
url = "github:logos-co/logos-test-modules?dir=test-basic-module";
|
||||
inputs.logos-module-builder.follows = "logos-module-builder";
|
||||
};
|
||||
|
||||
test_extlib_module = {
|
||||
url = "github:logos-co/logos-test-modules?dir=test-extlib-module";
|
||||
inputs.logos-module-builder.follows = "logos-module-builder";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = inputs@{ logos-module-builder, ... }:
|
||||
logos-module-builder.lib.mkLogosModule {
|
||||
src = ./.;
|
||||
configFile = ./metadata.json;
|
||||
flakeInputs = inputs; # test_basic_module and test_extlib_module resolved from dependencies[]
|
||||
};
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "test_ipc_module",
|
||||
"version": "1.0.0",
|
||||
"type": "core",
|
||||
"category": "testing",
|
||||
"description": "Test module exercising inter-module communication via LogosAPI",
|
||||
"main": "test_ipc_module_plugin",
|
||||
"dependencies": ["test_basic_module", "test_extlib_module"],
|
||||
|
||||
"nix": {
|
||||
"packages": {
|
||||
"build": [],
|
||||
"runtime": []
|
||||
},
|
||||
"external_libraries": [],
|
||||
"cmake": {
|
||||
"find_packages": [],
|
||||
"extra_sources": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
#ifndef TEST_IPC_MODULE_INTERFACE_H
|
||||
#define TEST_IPC_MODULE_INTERFACE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include "interface.h"
|
||||
#include "logos_types.h"
|
||||
|
||||
class TestIpcModuleInterface : public PluginInterface
|
||||
{
|
||||
public:
|
||||
virtual ~TestIpcModuleInterface() = default;
|
||||
|
||||
// ── Calls to test_basic_module ───────────────────────────────────────────
|
||||
|
||||
// Call echo(QString) -> QString via raw invokeRemoteMethod
|
||||
Q_INVOKABLE virtual QString callBasicEcho(const QString& input) = 0;
|
||||
|
||||
// Call addInts(int, int) -> int via raw invokeRemoteMethod
|
||||
Q_INVOKABLE virtual int callBasicAddInts(int a, int b) = 0;
|
||||
|
||||
// Call returnTrue() -> bool via raw invokeRemoteMethod
|
||||
Q_INVOKABLE virtual bool callBasicReturnTrue() = 0;
|
||||
|
||||
// Call noArgs() -> QString (0 args)
|
||||
Q_INVOKABLE virtual QString callBasicNoArgs() = 0;
|
||||
|
||||
// Call fiveArgs() -> QString (5 args)
|
||||
Q_INVOKABLE virtual QString callBasicFiveArgs(const QString& a, int b, bool c, const QString& d, int e) = 0;
|
||||
|
||||
// Call successResult() -> LogosResult
|
||||
Q_INVOKABLE virtual LogosResult callBasicSuccessResult() = 0;
|
||||
|
||||
// Call errorResult() -> LogosResult
|
||||
Q_INVOKABLE virtual LogosResult callBasicErrorResult() = 0;
|
||||
|
||||
// Call resultWithMap() and extract a value
|
||||
Q_INVOKABLE virtual QString callBasicResultMapField(const QString& key) = 0;
|
||||
|
||||
// ── Calls to test_extlib_module ──────────────────────────────────────────
|
||||
|
||||
// Call reverseString(QString) -> QString
|
||||
Q_INVOKABLE virtual QString callExtlibReverse(const QString& input) = 0;
|
||||
|
||||
// Call uppercaseString(QString) -> QString
|
||||
Q_INVOKABLE virtual QString callExtlibUppercase(const QString& input) = 0;
|
||||
|
||||
// Call countChars(QString) -> int
|
||||
Q_INVOKABLE virtual int callExtlibCountChars(const QString& input) = 0;
|
||||
|
||||
// ── Cross-module chaining ────────────────────────────────────────────────
|
||||
|
||||
// Chain: echo from basic -> reverse from extlib
|
||||
Q_INVOKABLE virtual QString chainEchoThenReverse(const QString& input) = 0;
|
||||
|
||||
// Chain: uppercase from extlib -> concat from basic
|
||||
Q_INVOKABLE virtual QString chainUppercaseThenConcat(const QString& a, const QString& b) = 0;
|
||||
|
||||
// ── Generated wrappers (LogosModules) ────────────────────────────────────
|
||||
|
||||
// Call via generated type-safe wrapper: test_basic_module.echo
|
||||
Q_INVOKABLE virtual QString wrapperBasicEcho(const QString& input) = 0;
|
||||
|
||||
// Call via generated type-safe wrapper: test_extlib_module.reverseString
|
||||
Q_INVOKABLE virtual QString wrapperExtlibReverse(const QString& input) = 0;
|
||||
|
||||
// ── Events ───────────────────────────────────────────────────────────────
|
||||
|
||||
// Trigger an event on test_basic_module and report
|
||||
Q_INVOKABLE virtual void triggerBasicEvent(const QString& data) = 0;
|
||||
|
||||
// ── Async calls ───────────────────────────────────────────────────────────
|
||||
|
||||
// Async echo via raw invokeRemoteMethodAsync, blocks with QEventLoop until callback
|
||||
Q_INVOKABLE virtual QString asyncCallBasicEcho(const QString& input) = 0;
|
||||
|
||||
// Async addInts via raw invokeRemoteMethodAsync (exercises multi-arg async overload)
|
||||
Q_INVOKABLE virtual int asyncCallBasicAddInts(int a, int b) = 0;
|
||||
|
||||
// Async reverseString via raw invokeRemoteMethodAsync (cross-module to extlib)
|
||||
Q_INVOKABLE virtual QString asyncCallExtlibReverse(const QString& input) = 0;
|
||||
|
||||
// Async echo via generated type-safe echoAsync() wrapper
|
||||
Q_INVOKABLE virtual QString asyncWrapperBasicEcho(const QString& input) = 0;
|
||||
};
|
||||
|
||||
#define TestIpcModuleInterface_iid "org.logos.TestIpcModuleInterface"
|
||||
Q_DECLARE_INTERFACE(TestIpcModuleInterface, TestIpcModuleInterface_iid)
|
||||
|
||||
#endif // TEST_IPC_MODULE_INTERFACE_H
|
||||
@@ -1,247 +0,0 @@
|
||||
#include "test_ipc_module_plugin.h"
|
||||
#include "logos_api.h"
|
||||
#include "logos_api_client.h"
|
||||
#include <QDebug>
|
||||
#include <QEventLoop>
|
||||
#include <QVariantMap>
|
||||
|
||||
TestIpcModulePlugin::TestIpcModulePlugin(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
qDebug() << "TestIpcModulePlugin: created";
|
||||
}
|
||||
|
||||
TestIpcModulePlugin::~TestIpcModulePlugin()
|
||||
{
|
||||
qDebug() << "TestIpcModulePlugin: destroyed";
|
||||
delete logos;
|
||||
}
|
||||
|
||||
void TestIpcModulePlugin::initLogos(LogosAPI* logosAPIInstance)
|
||||
{
|
||||
delete logos;
|
||||
logos = nullptr;
|
||||
logosAPI = logosAPIInstance;
|
||||
if (logosAPI) {
|
||||
logos = new LogosModules(logosAPI);
|
||||
basicClient = logosAPI->getClient("test_basic_module");
|
||||
extlibClient = logosAPI->getClient("test_extlib_module");
|
||||
}
|
||||
qDebug() << "TestIpcModulePlugin: LogosAPI initialized";
|
||||
}
|
||||
|
||||
// ── Raw invokeRemoteMethod calls to test_basic_module ────────────────────────
|
||||
|
||||
QString TestIpcModulePlugin::callBasicEcho(const QString& input)
|
||||
{
|
||||
QVariant result = basicClient->invokeRemoteMethod(
|
||||
"test_basic_module", "echo", QVariant(input));
|
||||
qDebug() << "TestIpcModulePlugin::callBasicEcho" << input << "->" << result;
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
int TestIpcModulePlugin::callBasicAddInts(int a, int b)
|
||||
{
|
||||
QVariant result = basicClient->invokeRemoteMethod(
|
||||
"test_basic_module", "addInts", QVariant(a), QVariant(b));
|
||||
qDebug() << "TestIpcModulePlugin::callBasicAddInts" << a << b << "->" << result;
|
||||
return result.toInt();
|
||||
}
|
||||
|
||||
bool TestIpcModulePlugin::callBasicReturnTrue()
|
||||
{
|
||||
QVariant result = basicClient->invokeRemoteMethod(
|
||||
"test_basic_module", "returnTrue");
|
||||
qDebug() << "TestIpcModulePlugin::callBasicReturnTrue ->" << result;
|
||||
return result.toBool();
|
||||
}
|
||||
|
||||
QString TestIpcModulePlugin::callBasicNoArgs()
|
||||
{
|
||||
QVariant result = basicClient->invokeRemoteMethod(
|
||||
"test_basic_module", "noArgs");
|
||||
qDebug() << "TestIpcModulePlugin::callBasicNoArgs ->" << result;
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
QString TestIpcModulePlugin::callBasicFiveArgs(const QString& a, int b, bool c, const QString& d, int e)
|
||||
{
|
||||
QVariant result = basicClient->invokeRemoteMethod(
|
||||
"test_basic_module", "fiveArgs",
|
||||
QVariant(a), QVariant(b), QVariant(c), QVariant(d), QVariant(e));
|
||||
qDebug() << "TestIpcModulePlugin::callBasicFiveArgs ->" << result;
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
LogosResult TestIpcModulePlugin::callBasicSuccessResult()
|
||||
{
|
||||
QVariant result = basicClient->invokeRemoteMethod(
|
||||
"test_basic_module", "successResult");
|
||||
if (result.canConvert<LogosResult>()) {
|
||||
return result.value<LogosResult>();
|
||||
}
|
||||
return {true, result, QVariant()};
|
||||
}
|
||||
|
||||
LogosResult TestIpcModulePlugin::callBasicErrorResult()
|
||||
{
|
||||
QVariant result = basicClient->invokeRemoteMethod(
|
||||
"test_basic_module", "errorResult");
|
||||
if (result.canConvert<LogosResult>()) {
|
||||
return result.value<LogosResult>();
|
||||
}
|
||||
return {false, QVariant(), result};
|
||||
}
|
||||
|
||||
QString TestIpcModulePlugin::callBasicResultMapField(const QString& key)
|
||||
{
|
||||
QVariant result = basicClient->invokeRemoteMethod(
|
||||
"test_basic_module", "resultWithMap");
|
||||
if (result.canConvert<LogosResult>()) {
|
||||
LogosResult lr = result.value<LogosResult>();
|
||||
if (lr.success) {
|
||||
QVariantMap map = lr.getValue<QVariantMap>();
|
||||
return map.value(key).toString();
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
// ── Raw invokeRemoteMethod calls to test_extlib_module ───────────────────────
|
||||
|
||||
QString TestIpcModulePlugin::callExtlibReverse(const QString& input)
|
||||
{
|
||||
QVariant result = extlibClient->invokeRemoteMethod(
|
||||
"test_extlib_module", "reverseString", QVariant(input));
|
||||
qDebug() << "TestIpcModulePlugin::callExtlibReverse" << input << "->" << result;
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
QString TestIpcModulePlugin::callExtlibUppercase(const QString& input)
|
||||
{
|
||||
QVariant result = extlibClient->invokeRemoteMethod(
|
||||
"test_extlib_module", "uppercaseString", QVariant(input));
|
||||
qDebug() << "TestIpcModulePlugin::callExtlibUppercase" << input << "->" << result;
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
int TestIpcModulePlugin::callExtlibCountChars(const QString& input)
|
||||
{
|
||||
QVariant result = extlibClient->invokeRemoteMethod(
|
||||
"test_extlib_module", "countChars", QVariant(input));
|
||||
qDebug() << "TestIpcModulePlugin::callExtlibCountChars" << input << "->" << result;
|
||||
return result.toInt();
|
||||
}
|
||||
|
||||
// ── Cross-module chaining ────────────────────────────────────────────────────
|
||||
|
||||
QString TestIpcModulePlugin::chainEchoThenReverse(const QString& input)
|
||||
{
|
||||
QVariant echoed = basicClient->invokeRemoteMethod(
|
||||
"test_basic_module", "echo", QVariant(input));
|
||||
QVariant reversed = extlibClient->invokeRemoteMethod(
|
||||
"test_extlib_module", "reverseString", echoed);
|
||||
qDebug() << "TestIpcModulePlugin::chainEchoThenReverse" << input << "->" << reversed;
|
||||
return reversed.toString();
|
||||
}
|
||||
|
||||
QString TestIpcModulePlugin::chainUppercaseThenConcat(const QString& a, const QString& b)
|
||||
{
|
||||
QVariant upperA = extlibClient->invokeRemoteMethod(
|
||||
"test_extlib_module", "uppercaseString", QVariant(a));
|
||||
QVariant upperB = extlibClient->invokeRemoteMethod(
|
||||
"test_extlib_module", "uppercaseString", QVariant(b));
|
||||
QVariant result = basicClient->invokeRemoteMethod(
|
||||
"test_basic_module", "concat", upperA, upperB);
|
||||
qDebug() << "TestIpcModulePlugin::chainUppercaseThenConcat" << a << b << "->" << result;
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
// ── Generated type-safe wrappers (LogosModules) ─────────────────────────────
|
||||
|
||||
QString TestIpcModulePlugin::wrapperBasicEcho(const QString& input)
|
||||
{
|
||||
if (!logos) return QString();
|
||||
QString result = logos->test_basic_module.echo(input);
|
||||
qDebug() << "TestIpcModulePlugin::wrapperBasicEcho" << input << "->" << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
QString TestIpcModulePlugin::wrapperExtlibReverse(const QString& input)
|
||||
{
|
||||
if (!logos) return QString();
|
||||
QString result = logos->test_extlib_module.reverseString(input);
|
||||
qDebug() << "TestIpcModulePlugin::wrapperExtlibReverse" << input << "->" << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── Events ───────────────────────────────────────────────────────────────────
|
||||
|
||||
void TestIpcModulePlugin::triggerBasicEvent(const QString& data)
|
||||
{
|
||||
basicClient->invokeRemoteMethod(
|
||||
"test_basic_module", "emitTestEvent", QVariant(data));
|
||||
emit eventResponse("triggeredBasicEvent", QVariantList() << data);
|
||||
qDebug() << "TestIpcModulePlugin::triggerBasicEvent" << data;
|
||||
}
|
||||
|
||||
// ── Async calls ──────────────────────────────────────────────────────────────
|
||||
// Each method uses a QEventLoop to block until the async callback fires,
|
||||
// making the result observable by logoscore's synchronous -c interface.
|
||||
|
||||
QString TestIpcModulePlugin::asyncCallBasicEcho(const QString& input)
|
||||
{
|
||||
QString result;
|
||||
QEventLoop loop;
|
||||
basicClient->invokeRemoteMethodAsync("test_basic_module", "echo", QVariant(input),
|
||||
[&result, &loop](QVariant v) {
|
||||
result = v.toString();
|
||||
loop.quit();
|
||||
});
|
||||
loop.exec();
|
||||
qDebug() << "TestIpcModulePlugin::asyncCallBasicEcho" << input << "->" << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
int TestIpcModulePlugin::asyncCallBasicAddInts(int a, int b)
|
||||
{
|
||||
int result = 0;
|
||||
QEventLoop loop;
|
||||
basicClient->invokeRemoteMethodAsync("test_basic_module", "addInts",
|
||||
QVariantList{QVariant(a), QVariant(b)},
|
||||
[&result, &loop](QVariant v) {
|
||||
result = v.toInt();
|
||||
loop.quit();
|
||||
});
|
||||
loop.exec();
|
||||
qDebug() << "TestIpcModulePlugin::asyncCallBasicAddInts" << a << b << "->" << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
QString TestIpcModulePlugin::asyncCallExtlibReverse(const QString& input)
|
||||
{
|
||||
QString result;
|
||||
QEventLoop loop;
|
||||
extlibClient->invokeRemoteMethodAsync("test_extlib_module", "reverseString", QVariant(input),
|
||||
[&result, &loop](QVariant v) {
|
||||
result = v.toString();
|
||||
loop.quit();
|
||||
});
|
||||
loop.exec();
|
||||
qDebug() << "TestIpcModulePlugin::asyncCallExtlibReverse" << input << "->" << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
QString TestIpcModulePlugin::asyncWrapperBasicEcho(const QString& input)
|
||||
{
|
||||
if (!logos) return QString();
|
||||
QString result;
|
||||
QEventLoop loop;
|
||||
logos->test_basic_module.echoAsync(input, [&result, &loop](QString v) {
|
||||
result = v;
|
||||
loop.quit();
|
||||
});
|
||||
loop.exec();
|
||||
qDebug() << "TestIpcModulePlugin::asyncWrapperBasicEcho" << input << "->" << result;
|
||||
return result;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
#ifndef TEST_IPC_MODULE_PLUGIN_H
|
||||
#define TEST_IPC_MODULE_PLUGIN_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include "test_ipc_module_interface.h"
|
||||
#include "logos_api.h"
|
||||
#include "logos_sdk.h"
|
||||
|
||||
class TestIpcModulePlugin : public QObject, public TestIpcModuleInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID TestIpcModuleInterface_iid FILE "metadata.json")
|
||||
Q_INTERFACES(TestIpcModuleInterface PluginInterface)
|
||||
|
||||
public:
|
||||
explicit TestIpcModulePlugin(QObject* parent = nullptr);
|
||||
~TestIpcModulePlugin() override;
|
||||
|
||||
QString name() const override { return "test_ipc_module"; }
|
||||
QString version() const override { return "1.0.0"; }
|
||||
|
||||
Q_INVOKABLE void initLogos(LogosAPI* logosAPIInstance);
|
||||
|
||||
// ── Calls to test_basic_module ───────────────────────────────────────────
|
||||
Q_INVOKABLE QString callBasicEcho(const QString& input) override;
|
||||
Q_INVOKABLE int callBasicAddInts(int a, int b) override;
|
||||
Q_INVOKABLE bool callBasicReturnTrue() override;
|
||||
Q_INVOKABLE QString callBasicNoArgs() override;
|
||||
Q_INVOKABLE QString callBasicFiveArgs(const QString& a, int b, bool c, const QString& d, int e) override;
|
||||
Q_INVOKABLE LogosResult callBasicSuccessResult() override;
|
||||
Q_INVOKABLE LogosResult callBasicErrorResult() override;
|
||||
Q_INVOKABLE QString callBasicResultMapField(const QString& key) override;
|
||||
|
||||
// ── Calls to test_extlib_module ──────────────────────────────────────────
|
||||
Q_INVOKABLE QString callExtlibReverse(const QString& input) override;
|
||||
Q_INVOKABLE QString callExtlibUppercase(const QString& input) override;
|
||||
Q_INVOKABLE int callExtlibCountChars(const QString& input) override;
|
||||
|
||||
// ── Cross-module chaining ────────────────────────────────────────────────
|
||||
Q_INVOKABLE QString chainEchoThenReverse(const QString& input) override;
|
||||
Q_INVOKABLE QString chainUppercaseThenConcat(const QString& a, const QString& b) override;
|
||||
|
||||
// ── Generated wrappers (LogosModules) ────────────────────────────────────
|
||||
Q_INVOKABLE QString wrapperBasicEcho(const QString& input) override;
|
||||
Q_INVOKABLE QString wrapperExtlibReverse(const QString& input) override;
|
||||
|
||||
// ── Events ───────────────────────────────────────────────────────────────
|
||||
Q_INVOKABLE void triggerBasicEvent(const QString& data) override;
|
||||
|
||||
// ── Async calls ───────────────────────────────────────────────────────────
|
||||
Q_INVOKABLE QString asyncCallBasicEcho(const QString& input) override;
|
||||
Q_INVOKABLE int asyncCallBasicAddInts(int a, int b) override;
|
||||
Q_INVOKABLE QString asyncCallExtlibReverse(const QString& input) override;
|
||||
Q_INVOKABLE QString asyncWrapperBasicEcho(const QString& input) override;
|
||||
|
||||
signals:
|
||||
void eventResponse(const QString& eventName, const QVariantList& args);
|
||||
|
||||
private:
|
||||
LogosModules* logos = nullptr;
|
||||
LogosAPIClient* basicClient = nullptr;
|
||||
LogosAPIClient* extlibClient = nullptr;
|
||||
};
|
||||
|
||||
#endif // TEST_IPC_MODULE_PLUGIN_H
|
||||
@@ -1,246 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(TestIpcModuleTests LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
# ── Locate dependencies ──────────────────────────────────────────────────────
|
||||
|
||||
# logos-liblogos (for PluginInterface / interface.h)
|
||||
if(NOT DEFINED LOGOS_LIBLOGOS_ROOT)
|
||||
if(DEFINED ENV{LOGOS_LIBLOGOS_ROOT})
|
||||
set(LOGOS_LIBLOGOS_ROOT "$ENV{LOGOS_LIBLOGOS_ROOT}")
|
||||
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../logos-liblogos/interface.h")
|
||||
get_filename_component(LOGOS_LIBLOGOS_ROOT
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../logos-liblogos" ABSOLUTE)
|
||||
else()
|
||||
message(FATAL_ERROR "logos-liblogos not found. Set LOGOS_LIBLOGOS_ROOT.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# logos-cpp-sdk (Qt-free base SDK headers; logos_api.h lives in logos-qt-host)
|
||||
if(NOT DEFINED LOGOS_CPP_SDK_ROOT)
|
||||
if(DEFINED ENV{LOGOS_CPP_SDK_ROOT})
|
||||
set(LOGOS_CPP_SDK_ROOT "$ENV{LOGOS_CPP_SDK_ROOT}")
|
||||
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../logos-cpp-sdk/cpp/logos_module_context.h")
|
||||
get_filename_component(LOGOS_CPP_SDK_ROOT
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../logos-cpp-sdk" ABSOLUTE)
|
||||
else()
|
||||
message(FATAL_ERROR "logos-cpp-sdk not found. Set LOGOS_CPP_SDK_ROOT.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# logos-qt-host (Qt HOST RUNTIME: LogosAPI, LogosAPIProvider, the provider base
|
||||
# classes and the legacy QMetaObject adapter). It is built from logos-plugin-qt
|
||||
# and exported as the logos-qt-host::logos_qt_host target; logos-qt-sdk no
|
||||
# longer carries it, so the source-checkout fallback names the REPO
|
||||
# (logos-plugin-qt) while the installed prefix is the logos-qt-host package.
|
||||
if(NOT DEFINED LOGOS_QT_HOST_ROOT)
|
||||
if(DEFINED ENV{LOGOS_QT_HOST_ROOT})
|
||||
set(LOGOS_QT_HOST_ROOT "$ENV{LOGOS_QT_HOST_ROOT}")
|
||||
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../logos-plugin-qt/cpp/logos_api.h")
|
||||
get_filename_component(LOGOS_QT_HOST_ROOT
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../logos-plugin-qt" ABSOLUTE)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"logos-qt-host not found. Set LOGOS_QT_HOST_ROOT to an installed "
|
||||
"logos-qt-host prefix or to a logos-plugin-qt source checkout.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# logos-qt-sdk — SEAM HEADERS ONLY (logos_qt_lp_bridge.h, logos_qt_wire.h).
|
||||
#
|
||||
# NOT the host runtime; that is logos-qt-host above, and nothing here links a
|
||||
# logos-qt-sdk library (the package ships headers, no archive). What needs it
|
||||
# is the GENERATED Qt-typed dependency wrapper this binary compiles:
|
||||
# test_basic_module_api.cpp is copied out of the dependency's `headers-qt`
|
||||
# output, and since the builder started emitting that wrapper as a veneer over
|
||||
# the lp path it opens with `#include "logos_qt_lp_bridge.h"`. Without this
|
||||
# include dir the failure is a `file not found` deep inside generated code.
|
||||
#
|
||||
# The lp-typed sibling (test-ipc-module-new-api) consumes `headers-lp`, whose
|
||||
# wrapper has no such include — which is why only this CMakeLists carries it.
|
||||
if(NOT DEFINED LOGOS_QT_SDK_ROOT)
|
||||
if(DEFINED ENV{LOGOS_QT_SDK_ROOT})
|
||||
set(LOGOS_QT_SDK_ROOT "$ENV{LOGOS_QT_SDK_ROOT}")
|
||||
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../logos-qt-sdk/cpp/logos_qt_lp_bridge.h")
|
||||
get_filename_component(LOGOS_QT_SDK_ROOT
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../logos-qt-sdk" ABSOLUTE)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"logos-qt-sdk not found. Set LOGOS_QT_SDK_ROOT to an installed "
|
||||
"logos-qt-sdk prefix or a source checkout — the generated Qt-typed "
|
||||
"dependency wrapper includes logos_qt_lp_bridge.h.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# logos-protocol (transports, consumer core, mock implementations)
|
||||
if(NOT DEFINED LOGOS_PROTOCOL_ROOT)
|
||||
if(DEFINED ENV{LOGOS_PROTOCOL_ROOT})
|
||||
set(LOGOS_PROTOCOL_ROOT "$ENV{LOGOS_PROTOCOL_ROOT}")
|
||||
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../logos-protocol/cpp/logos_protocol.h")
|
||||
get_filename_component(LOGOS_PROTOCOL_ROOT
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../logos-protocol" ABSOLUTE)
|
||||
else()
|
||||
message(FATAL_ERROR "logos-protocol not found. Set LOGOS_PROTOCOL_ROOT.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Detect source vs installed layouts.
|
||||
if(EXISTS "${LOGOS_CPP_SDK_ROOT}/cpp/logos_module_context.h")
|
||||
set(LOGOS_CPP_SDK_IS_SOURCE TRUE)
|
||||
set(LOGOS_CPP_SDK_INCLUDE "${LOGOS_CPP_SDK_ROOT}/cpp")
|
||||
else()
|
||||
set(LOGOS_CPP_SDK_IS_SOURCE FALSE)
|
||||
set(LOGOS_CPP_SDK_INCLUDE "${LOGOS_CPP_SDK_ROOT}/include/cpp")
|
||||
endif()
|
||||
if(EXISTS "${LOGOS_QT_HOST_ROOT}/cpp/logos_api.h")
|
||||
set(LOGOS_QT_HOST_IS_SOURCE TRUE)
|
||||
set(LOGOS_QT_HOST_INCLUDE "${LOGOS_QT_HOST_ROOT}/cpp")
|
||||
set(LOGOS_QT_HOST_CORE_INCLUDE "${LOGOS_QT_HOST_ROOT}/core")
|
||||
else()
|
||||
set(LOGOS_QT_HOST_IS_SOURCE FALSE)
|
||||
set(LOGOS_QT_HOST_INCLUDE "${LOGOS_QT_HOST_ROOT}/include/cpp")
|
||||
set(LOGOS_QT_HOST_CORE_INCLUDE "${LOGOS_QT_HOST_ROOT}/include/core")
|
||||
endif()
|
||||
if(EXISTS "${LOGOS_QT_SDK_ROOT}/cpp/logos_qt_lp_bridge.h")
|
||||
set(LOGOS_QT_SDK_INCLUDE "${LOGOS_QT_SDK_ROOT}/cpp")
|
||||
else()
|
||||
set(LOGOS_QT_SDK_INCLUDE "${LOGOS_QT_SDK_ROOT}/include/cpp")
|
||||
endif()
|
||||
if(EXISTS "${LOGOS_PROTOCOL_ROOT}/cpp/logos_protocol.h")
|
||||
set(LOGOS_PROTOCOL_INCLUDE "${LOGOS_PROTOCOL_ROOT}/cpp")
|
||||
set(LOGOS_PROTOCOL_IMPL_INCLUDE "${LOGOS_PROTOCOL_ROOT}/cpp/implementations")
|
||||
else()
|
||||
set(LOGOS_PROTOCOL_INCLUDE "${LOGOS_PROTOCOL_ROOT}/include")
|
||||
set(LOGOS_PROTOCOL_IMPL_INCLUDE "${LOGOS_PROTOCOL_ROOT}/include/implementations")
|
||||
endif()
|
||||
# Mock transport headers live in logos-protocol since the extraction.
|
||||
set(LOGOS_CPP_SDK_MOCK_INCLUDE "${LOGOS_PROTOCOL_IMPL_INCLUDE}/mock")
|
||||
|
||||
if(EXISTS "${LOGOS_LIBLOGOS_ROOT}/interface.h")
|
||||
set(LOGOS_LIBLOGOS_INCLUDE "${LOGOS_LIBLOGOS_ROOT}")
|
||||
elseif(EXISTS "${LOGOS_LIBLOGOS_ROOT}/include/core/interface.h")
|
||||
set(LOGOS_LIBLOGOS_INCLUDE "${LOGOS_LIBLOGOS_ROOT}/include/core")
|
||||
else()
|
||||
set(LOGOS_LIBLOGOS_INCLUDE "${LOGOS_LIBLOGOS_ROOT}/include")
|
||||
endif()
|
||||
|
||||
message(STATUS "logos-liblogos include : ${LOGOS_LIBLOGOS_INCLUDE}")
|
||||
message(STATUS "logos-cpp-sdk include : ${LOGOS_CPP_SDK_INCLUDE}")
|
||||
message(STATUS "logos-cpp-sdk is source: ${LOGOS_CPP_SDK_IS_SOURCE}")
|
||||
|
||||
# ── Qt ───────────────────────────────────────────────────────────────────────
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core RemoteObjects)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core RemoteObjects)
|
||||
|
||||
# ── Source lists ─────────────────────────────────────────────────────────────
|
||||
|
||||
set(TEST_SOURCES
|
||||
main.cpp
|
||||
test_call_basic.cpp
|
||||
test_call_extlib.cpp
|
||||
test_chaining.cpp
|
||||
../src/test_ipc_module_plugin.cpp
|
||||
)
|
||||
|
||||
if(LOGOS_QT_HOST_IS_SOURCE)
|
||||
# Source layout: compile the Qt host runtime into the test binary.
|
||||
# The transport/consumer core (types, api_client, token_manager, mock
|
||||
# transports, ...) lives in the logos-protocol LIBRARY and is linked
|
||||
# below instead of compiled in.
|
||||
list(APPEND TEST_SOURCES
|
||||
${LOGOS_QT_HOST_INCLUDE}/logos_api.cpp
|
||||
${LOGOS_QT_HOST_INCLUDE}/logos_api_provider.cpp
|
||||
${LOGOS_QT_HOST_INCLUDE}/logos_provider_object.cpp
|
||||
${LOGOS_QT_HOST_INCLUDE}/qt_provider_object.cpp
|
||||
# qt_provider_object.cpp decodes every incoming argument through
|
||||
# logos::qtArgDecode, so the legacy adapter belongs to the source
|
||||
# layout too. Listed unconditionally: a checkout that lacks it must
|
||||
# fail at configure time, not silently drop the translation unit and
|
||||
# then fail on an undefined symbol at link.
|
||||
${LOGOS_QT_HOST_INCLUDE}/logos_qt_arg_decode.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
# logos_sdk.cpp is the generated wrapper; look in generated_code/ relative to the module.
|
||||
# SKIP_AUTOMOC is required to avoid a ninja dependency cycle — this file has no Q_OBJECT macros.
|
||||
set(GENERATED_CODE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../generated_code")
|
||||
if(EXISTS "${GENERATED_CODE_DIR}/logos_sdk.cpp")
|
||||
list(APPEND TEST_SOURCES "${GENERATED_CODE_DIR}/logos_sdk.cpp")
|
||||
set_source_files_properties("${GENERATED_CODE_DIR}/logos_sdk.cpp"
|
||||
PROPERTIES SKIP_AUTOMOC ON)
|
||||
elseif(EXISTS "${GENERATED_CODE_DIR}/include/logos_sdk.cpp")
|
||||
list(APPEND TEST_SOURCES "${GENERATED_CODE_DIR}/include/logos_sdk.cpp")
|
||||
set_source_files_properties("${GENERATED_CODE_DIR}/include/logos_sdk.cpp"
|
||||
PROPERTIES SKIP_AUTOMOC ON)
|
||||
endif()
|
||||
|
||||
# ── Test executable ──────────────────────────────────────────────────────────
|
||||
|
||||
add_executable(test_ipc_module_tests ${TEST_SOURCES})
|
||||
|
||||
target_include_directories(test_ipc_module_tests PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../src
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${LOGOS_LIBLOGOS_INCLUDE}
|
||||
${LOGOS_CPP_SDK_INCLUDE}
|
||||
${LOGOS_QT_HOST_INCLUDE}
|
||||
${LOGOS_QT_HOST_CORE_INCLUDE}
|
||||
${LOGOS_QT_SDK_INCLUDE}
|
||||
${LOGOS_PROTOCOL_INCLUDE}
|
||||
${LOGOS_PROTOCOL_IMPL_INCLUDE}/qt_local
|
||||
${LOGOS_PROTOCOL_IMPL_INCLUDE}/qt_remote
|
||||
${LOGOS_CPP_SDK_MOCK_INCLUDE}
|
||||
${GENERATED_CODE_DIR}
|
||||
${GENERATED_CODE_DIR}/include
|
||||
)
|
||||
|
||||
target_link_libraries(test_ipc_module_tests PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Core
|
||||
Qt${QT_VERSION_MAJOR}::RemoteObjects
|
||||
)
|
||||
|
||||
# Link the Qt host runtime via its exported CMake target so the consumer
|
||||
# inherits the full transitive link interface (logos-protocol, and through it
|
||||
# OpenSSL::SSL, OpenSSL::Crypto, Boost::system, nlohmann_json). A bare
|
||||
# archive on the link line would leave Boost.Asio TLS symbols undefined.
|
||||
#
|
||||
# find_package(logos-qt-host) is REQUIRED and the target reference below is
|
||||
# unconditional on purpose: no `if(TARGET ...)` guard, so a renamed or missing
|
||||
# prefix is a hard configure error rather than a silently unlinked runtime.
|
||||
if(NOT LOGOS_QT_HOST_IS_SOURCE)
|
||||
find_package(logos-protocol REQUIRED CONFIG
|
||||
PATHS ${LOGOS_PROTOCOL_ROOT}/lib/cmake/logos-protocol
|
||||
NO_DEFAULT_PATH)
|
||||
find_package(logos-qt-host REQUIRED CONFIG
|
||||
PATHS ${LOGOS_QT_HOST_ROOT}/lib/cmake/logos-qt-host
|
||||
NO_DEFAULT_PATH)
|
||||
target_link_libraries(test_ipc_module_tests PRIVATE logos-qt-host::logos_qt_host)
|
||||
else()
|
||||
# Source-layout host runtime compiled in above; link the protocol library.
|
||||
if(NOT TARGET logos_protocol)
|
||||
add_subdirectory("${LOGOS_PROTOCOL_ROOT}/cpp"
|
||||
"${CMAKE_BINARY_DIR}/logos-protocol-build")
|
||||
endif()
|
||||
target_link_libraries(test_ipc_module_tests PRIVATE logos_protocol)
|
||||
endif()
|
||||
|
||||
# Qt-free base SDK headers (nlohmann include path for logos_json.h etc.)
|
||||
if(EXISTS "${LOGOS_CPP_SDK_ROOT}/lib/cmake/logos-cpp-sdk")
|
||||
find_package(logos-cpp-sdk REQUIRED CONFIG
|
||||
PATHS ${LOGOS_CPP_SDK_ROOT}/lib/cmake/logos-cpp-sdk
|
||||
NO_DEFAULT_PATH)
|
||||
target_link_libraries(test_ipc_module_tests PRIVATE logos-cpp-sdk::logos_headers)
|
||||
else()
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
target_link_libraries(test_ipc_module_tests PRIVATE nlohmann_json::nlohmann_json)
|
||||
endif()
|
||||
|
||||
# ── CTest integration ────────────────────────────────────────────────────────
|
||||
|
||||
enable_testing()
|
||||
add_test(NAME logos_module_unit_tests COMMAND test_ipc_module_tests)
|
||||
@@ -1,181 +0,0 @@
|
||||
#ifndef LOGOS_TEST_H
|
||||
#define LOGOS_TEST_H
|
||||
|
||||
/**
|
||||
* @file logos_test.h
|
||||
* @brief Lightweight unit-test framework for Logos module tests.
|
||||
*
|
||||
* No external dependencies. Tests self-register at static-initialisation
|
||||
* time via the LOGOS_TEST macro, so just #include this header and define
|
||||
* your tests — the test runner in main.cpp discovers them automatically.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* #include "logos_test.h"
|
||||
* #include "logos_mock.h"
|
||||
*
|
||||
* LOGOS_TEST(my_feature_works) {
|
||||
* LogosMockSetup mock;
|
||||
* mock.when("mod", "method").thenReturn(QVariant(7));
|
||||
* // ...
|
||||
* LOGOS_ASSERT_EQ(someValue, 7);
|
||||
* }
|
||||
*/
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QList>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
// Allow QString and QVariant to be streamed into std::ostream (for assertion messages)
|
||||
inline std::ostream& operator<<(std::ostream& os, const QString& s) { return os << s.toStdString(); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const QVariant& v) { return os << v.toString().toStdString(); }
|
||||
|
||||
// ── Test failure exception ───────────────────────────────────────────────────
|
||||
|
||||
class LogosTestFailure : public std::runtime_error {
|
||||
public:
|
||||
explicit LogosTestFailure(const std::string& msg) : std::runtime_error(msg) {}
|
||||
};
|
||||
|
||||
// ── Assertion macros ─────────────────────────────────────────────────────────
|
||||
|
||||
#define LOGOS_ASSERT(expr) \
|
||||
do { \
|
||||
if (!(expr)) { \
|
||||
std::ostringstream _oss; \
|
||||
_oss << "ASSERT failed: " #expr \
|
||||
<< " (" << __FILE__ << ":" << __LINE__ << ")"; \
|
||||
throw LogosTestFailure(_oss.str()); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define LOGOS_ASSERT_TRUE(expr) LOGOS_ASSERT(expr)
|
||||
#define LOGOS_ASSERT_FALSE(expr) LOGOS_ASSERT(!(expr))
|
||||
|
||||
#define LOGOS_ASSERT_EQ(actual, expected) \
|
||||
do { \
|
||||
auto _a = (actual); \
|
||||
auto _e = (expected); \
|
||||
if (!(_a == _e)) { \
|
||||
std::ostringstream _oss; \
|
||||
_oss << "ASSERT_EQ failed: expected [" \
|
||||
<< _e << "] but got [" << _a << "]" \
|
||||
<< " (" << __FILE__ << ":" << __LINE__ << ")"; \
|
||||
throw LogosTestFailure(_oss.str()); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define LOGOS_ASSERT_NE(actual, expected) \
|
||||
do { \
|
||||
auto _a = (actual); \
|
||||
auto _e = (expected); \
|
||||
if (_a == _e) { \
|
||||
std::ostringstream _oss; \
|
||||
_oss << "ASSERT_NE failed: both equal [" << _a << "]" \
|
||||
<< " (" << __FILE__ << ":" << __LINE__ << ")"; \
|
||||
throw LogosTestFailure(_oss.str()); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
// ── Test runner ──────────────────────────────────────────────────────────────
|
||||
|
||||
class LogosTestRunner {
|
||||
public:
|
||||
struct TestEntry {
|
||||
QString name;
|
||||
std::function<void()> fn;
|
||||
};
|
||||
|
||||
static LogosTestRunner& instance() {
|
||||
static LogosTestRunner runner;
|
||||
return runner;
|
||||
}
|
||||
|
||||
bool registerTest(const char* name, std::function<void()> fn) {
|
||||
m_tests.append({QString::fromUtf8(name), fn});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Run all registered tests.
|
||||
* @return 0 if all pass, 1 if any fail.
|
||||
*/
|
||||
int runAll() {
|
||||
int passed = 0;
|
||||
int failed = 0;
|
||||
|
||||
std::cout << "\n=== Logos Module Unit Tests ===\n\n";
|
||||
|
||||
for (const TestEntry& t : m_tests) {
|
||||
std::cout << " [ RUN ] " << t.name.toStdString() << "\n";
|
||||
try {
|
||||
t.fn();
|
||||
std::cout << " [ PASS ] " << t.name.toStdString() << "\n";
|
||||
++passed;
|
||||
} catch (const LogosTestFailure& ex) {
|
||||
std::cout << " [ FAIL ] " << t.name.toStdString()
|
||||
<< "\n " << ex.what() << "\n";
|
||||
++failed;
|
||||
} catch (const std::exception& ex) {
|
||||
std::cout << " [ FAIL ] " << t.name.toStdString()
|
||||
<< "\n Unexpected exception: " << ex.what() << "\n";
|
||||
++failed;
|
||||
} catch (...) {
|
||||
std::cout << " [ FAIL ] " << t.name.toStdString()
|
||||
<< "\n Unknown exception\n";
|
||||
++failed;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\n=== Results: " << passed << " passed, "
|
||||
<< failed << " failed";
|
||||
if (m_tests.isEmpty()) {
|
||||
std::cout << " (no tests registered!)";
|
||||
}
|
||||
std::cout << " ===\n\n";
|
||||
|
||||
return failed > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
QList<TestEntry> m_tests;
|
||||
};
|
||||
|
||||
// ── LOGOS_TEST macro ─────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @brief Define a test function and auto-register it with LogosTestRunner.
|
||||
*
|
||||
* The body of the function follows the macro, like a regular function:
|
||||
*
|
||||
* LOGOS_TEST(my_test) {
|
||||
* LOGOS_ASSERT_EQ(1 + 1, 2);
|
||||
* }
|
||||
*/
|
||||
#define LOGOS_TEST(name) \
|
||||
static void _logos_test_fn_##name(); \
|
||||
static bool _logos_test_reg_##name = \
|
||||
LogosTestRunner::instance().registerTest(#name, _logos_test_fn_##name); \
|
||||
static void _logos_test_fn_##name()
|
||||
|
||||
// ── Test main ────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @brief Generate a standard main() that sets up QCoreApplication and runs all
|
||||
* registered tests. Place this in exactly one .cpp file (typically main.cpp).
|
||||
*
|
||||
* #include "logos_test.h"
|
||||
* LOGOS_TEST_MAIN()
|
||||
*/
|
||||
#define LOGOS_TEST_MAIN() \
|
||||
int main(int argc, char* argv[]) { \
|
||||
QCoreApplication app(argc, argv); \
|
||||
return LogosTestRunner::instance().runAll(); \
|
||||
}
|
||||
|
||||
#endif // LOGOS_TEST_H
|
||||
@@ -1,3 +0,0 @@
|
||||
#include "logos_test.h"
|
||||
|
||||
LOGOS_TEST_MAIN()
|
||||
@@ -1,190 +0,0 @@
|
||||
#include "logos_test.h"
|
||||
#include "logos_mock.h"
|
||||
#include "test_ipc_module_plugin.h"
|
||||
#include "logos_api.h"
|
||||
|
||||
// ── callBasicAddInts ─────────────────────────────────────────────────────────
|
||||
|
||||
LOGOS_TEST(callBasicAddInts_returns_mocked_sum) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "addInts").thenReturn(QVariant(30));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
int result = plugin.callBasicAddInts(10, 20);
|
||||
|
||||
LOGOS_ASSERT_EQ(result, 30);
|
||||
}
|
||||
|
||||
LOGOS_TEST(callBasicAddInts_records_correct_args) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "addInts").thenReturn(QVariant(12));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.callBasicAddInts(5, 7);
|
||||
|
||||
LOGOS_ASSERT(mock.wasCalled("test_basic_module", "addInts"));
|
||||
LOGOS_ASSERT(mock.wasCalledWith("test_basic_module", "addInts",
|
||||
{QVariant(5), QVariant(7)}));
|
||||
}
|
||||
|
||||
LOGOS_TEST(callBasicAddInts_callCount_is_one) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "addInts").thenReturn(QVariant(0));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.callBasicAddInts(1, 2);
|
||||
|
||||
LOGOS_ASSERT_EQ(mock.callCount("test_basic_module", "addInts"), 1);
|
||||
}
|
||||
|
||||
LOGOS_TEST(callBasicAddInts_called_multiple_times) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "addInts").thenReturn(QVariant(0));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.callBasicAddInts(1, 2);
|
||||
plugin.callBasicAddInts(3, 4);
|
||||
plugin.callBasicAddInts(5, 6);
|
||||
|
||||
LOGOS_ASSERT_EQ(mock.callCount("test_basic_module", "addInts"), 3);
|
||||
}
|
||||
|
||||
LOGOS_TEST(callBasicAddInts_last_args_are_recorded) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "addInts").thenReturn(QVariant(0));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.callBasicAddInts(10, 20);
|
||||
plugin.callBasicAddInts(99, 1);
|
||||
|
||||
QVariantList last = mock.lastArgs("test_basic_module", "addInts");
|
||||
LOGOS_ASSERT_EQ(last.size(), 2);
|
||||
LOGOS_ASSERT_EQ(last.at(0).toInt(), 99);
|
||||
LOGOS_ASSERT_EQ(last.at(1).toInt(), 1);
|
||||
}
|
||||
|
||||
// ── callBasicEcho ────────────────────────────────────────────────────────────
|
||||
|
||||
LOGOS_TEST(callBasicEcho_returns_mocked_string) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "echo").thenReturn(QVariant(QString("hello back")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
QString result = plugin.callBasicEcho("hello");
|
||||
|
||||
LOGOS_ASSERT_EQ(result, QString("hello back"));
|
||||
}
|
||||
|
||||
LOGOS_TEST(callBasicEcho_records_input_arg) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "echo").thenReturn(QVariant(QString("")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.callBasicEcho("test-input");
|
||||
|
||||
LOGOS_ASSERT(mock.wasCalledWith("test_basic_module", "echo",
|
||||
{QVariant(QString("test-input"))}));
|
||||
}
|
||||
|
||||
// ── callBasicReturnTrue ──────────────────────────────────────────────────────
|
||||
|
||||
LOGOS_TEST(callBasicReturnTrue_returns_mocked_true) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "returnTrue").thenReturn(QVariant(true));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
bool result = plugin.callBasicReturnTrue();
|
||||
|
||||
LOGOS_ASSERT_TRUE(result);
|
||||
}
|
||||
|
||||
LOGOS_TEST(callBasicReturnTrue_can_be_mocked_false) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "returnTrue").thenReturn(QVariant(false));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
bool result = plugin.callBasicReturnTrue();
|
||||
|
||||
LOGOS_ASSERT_FALSE(result);
|
||||
}
|
||||
|
||||
// ── callBasicNoArgs ──────────────────────────────────────────────────────────
|
||||
|
||||
LOGOS_TEST(callBasicNoArgs_is_called_with_no_args) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "noArgs").thenReturn(QVariant(QString("ok")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.callBasicNoArgs();
|
||||
|
||||
LOGOS_ASSERT(mock.wasCalled("test_basic_module", "noArgs"));
|
||||
LOGOS_ASSERT(mock.wasCalledWith("test_basic_module", "noArgs", {}));
|
||||
}
|
||||
|
||||
// ── callBasicFiveArgs ────────────────────────────────────────────────────────
|
||||
|
||||
LOGOS_TEST(callBasicFiveArgs_records_all_five_args) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "fiveArgs").thenReturn(QVariant(QString("result")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.callBasicFiveArgs("alpha", 2, true, "delta", 5);
|
||||
|
||||
QVariantList expected = {
|
||||
QVariant(QString("alpha")),
|
||||
QVariant(2),
|
||||
QVariant(true),
|
||||
QVariant(QString("delta")),
|
||||
QVariant(5)
|
||||
};
|
||||
LOGOS_ASSERT(mock.wasCalledWith("test_basic_module", "fiveArgs", expected));
|
||||
}
|
||||
|
||||
// ── wrapperBasicEcho (generated wrapper) ────────────────────────────────────
|
||||
|
||||
LOGOS_TEST(wrapperBasicEcho_calls_basic_echo) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "echo").thenReturn(QVariant(QString("wrapped")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
QString result = plugin.wrapperBasicEcho("input");
|
||||
|
||||
LOGOS_ASSERT_EQ(result, QString("wrapped"));
|
||||
LOGOS_ASSERT(mock.wasCalled("test_basic_module", "echo"));
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
#include "logos_test.h"
|
||||
#include "logos_mock.h"
|
||||
#include "test_ipc_module_plugin.h"
|
||||
#include "logos_api.h"
|
||||
|
||||
// ── callExtlibReverse ────────────────────────────────────────────────────────
|
||||
|
||||
LOGOS_TEST(callExtlibReverse_returns_mocked_string) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_extlib_module", "reverseString")
|
||||
.thenReturn(QVariant(QString("dlrow olleh")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
QString result = plugin.callExtlibReverse("hello world");
|
||||
|
||||
LOGOS_ASSERT_EQ(result, QString("dlrow olleh"));
|
||||
}
|
||||
|
||||
LOGOS_TEST(callExtlibReverse_records_correct_input) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_extlib_module", "reverseString").thenReturn(QVariant(QString("")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.callExtlibReverse("abc");
|
||||
|
||||
LOGOS_ASSERT(mock.wasCalledWith("test_extlib_module", "reverseString",
|
||||
{QVariant(QString("abc"))}));
|
||||
}
|
||||
|
||||
LOGOS_TEST(callExtlibReverse_called_once) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_extlib_module", "reverseString").thenReturn(QVariant(QString("")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.callExtlibReverse("test");
|
||||
|
||||
LOGOS_ASSERT_EQ(mock.callCount("test_extlib_module", "reverseString"), 1);
|
||||
}
|
||||
|
||||
// ── callExtlibUppercase ──────────────────────────────────────────────────────
|
||||
|
||||
LOGOS_TEST(callExtlibUppercase_returns_mocked_string) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_extlib_module", "uppercaseString")
|
||||
.thenReturn(QVariant(QString("HELLO")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
QString result = plugin.callExtlibUppercase("hello");
|
||||
|
||||
LOGOS_ASSERT_EQ(result, QString("HELLO"));
|
||||
}
|
||||
|
||||
LOGOS_TEST(callExtlibUppercase_records_correct_input) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_extlib_module", "uppercaseString").thenReturn(QVariant(QString("")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.callExtlibUppercase("lower");
|
||||
|
||||
LOGOS_ASSERT(mock.wasCalledWith("test_extlib_module", "uppercaseString",
|
||||
{QVariant(QString("lower"))}));
|
||||
}
|
||||
|
||||
// ── callExtlibCountChars ─────────────────────────────────────────────────────
|
||||
|
||||
LOGOS_TEST(callExtlibCountChars_returns_mocked_count) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_extlib_module", "countChars").thenReturn(QVariant(5));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
int result = plugin.callExtlibCountChars("hello");
|
||||
|
||||
LOGOS_ASSERT_EQ(result, 5);
|
||||
}
|
||||
|
||||
LOGOS_TEST(callExtlibCountChars_records_correct_input) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_extlib_module", "countChars").thenReturn(QVariant(0));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.callExtlibCountChars("testing");
|
||||
|
||||
LOGOS_ASSERT(mock.wasCalledWith("test_extlib_module", "countChars",
|
||||
{QVariant(QString("testing"))}));
|
||||
}
|
||||
|
||||
// ── wrapperExtlibReverse (generated wrapper) ─────────────────────────────────
|
||||
|
||||
LOGOS_TEST(wrapperExtlibReverse_calls_reverseString) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_extlib_module", "reverseString")
|
||||
.thenReturn(QVariant(QString("reversed")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
QString result = plugin.wrapperExtlibReverse("input");
|
||||
|
||||
LOGOS_ASSERT_EQ(result, QString("reversed"));
|
||||
LOGOS_ASSERT(mock.wasCalled("test_extlib_module", "reverseString"));
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
#include "logos_test.h"
|
||||
#include "logos_mock.h"
|
||||
#include "test_ipc_module_plugin.h"
|
||||
#include "logos_api.h"
|
||||
|
||||
// ── chainEchoThenReverse ─────────────────────────────────────────────────────
|
||||
|
||||
LOGOS_TEST(chainEchoThenReverse_calls_both_modules) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "echo")
|
||||
.thenReturn(QVariant(QString("hello")));
|
||||
mock.when("test_extlib_module", "reverseString")
|
||||
.thenReturn(QVariant(QString("olleh")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
QString result = plugin.chainEchoThenReverse("hello");
|
||||
|
||||
LOGOS_ASSERT_EQ(result, QString("olleh"));
|
||||
LOGOS_ASSERT(mock.wasCalled("test_basic_module", "echo"));
|
||||
LOGOS_ASSERT(mock.wasCalled("test_extlib_module", "reverseString"));
|
||||
}
|
||||
|
||||
LOGOS_TEST(chainEchoThenReverse_passes_echo_output_to_reverse) {
|
||||
LogosMockSetup mock;
|
||||
// echo returns a transformed string; reverse should receive that output
|
||||
mock.when("test_basic_module", "echo")
|
||||
.thenReturn(QVariant(QString("echoed_value")));
|
||||
mock.when("test_extlib_module", "reverseString")
|
||||
.thenReturn(QVariant(QString("final")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.chainEchoThenReverse("input");
|
||||
|
||||
// reverseString should have been called with the output of echo
|
||||
LOGOS_ASSERT(mock.wasCalledWith("test_extlib_module", "reverseString",
|
||||
{QVariant(QString("echoed_value"))}));
|
||||
}
|
||||
|
||||
LOGOS_TEST(chainEchoThenReverse_each_module_called_once) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_basic_module", "echo").thenReturn(QVariant(QString("x")));
|
||||
mock.when("test_extlib_module", "reverseString").thenReturn(QVariant(QString("y")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.chainEchoThenReverse("abc");
|
||||
|
||||
LOGOS_ASSERT_EQ(mock.callCount("test_basic_module", "echo"), 1);
|
||||
LOGOS_ASSERT_EQ(mock.callCount("test_extlib_module", "reverseString"), 1);
|
||||
}
|
||||
|
||||
// ── chainUppercaseThenConcat ─────────────────────────────────────────────────
|
||||
|
||||
LOGOS_TEST(chainUppercaseThenConcat_calls_three_methods) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_extlib_module", "uppercaseString")
|
||||
.thenReturn(QVariant(QString("UPPER")));
|
||||
mock.when("test_basic_module", "concat")
|
||||
.thenReturn(QVariant(QString("UPPER UPPER")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
QString result = plugin.chainUppercaseThenConcat("hello", "world");
|
||||
|
||||
LOGOS_ASSERT_EQ(result, QString("UPPER UPPER"));
|
||||
// uppercaseString called twice (once for each input)
|
||||
LOGOS_ASSERT_EQ(mock.callCount("test_extlib_module", "uppercaseString"), 2);
|
||||
LOGOS_ASSERT(mock.wasCalled("test_basic_module", "concat"));
|
||||
}
|
||||
|
||||
LOGOS_TEST(chainUppercaseThenConcat_passes_uppercased_values_to_concat) {
|
||||
LogosMockSetup mock;
|
||||
// Return different values for the two uppercase calls based on call order
|
||||
mock.when("test_extlib_module", "uppercaseString")
|
||||
.thenReturn(QVariant(QString("MOCKED")));
|
||||
mock.when("test_basic_module", "concat")
|
||||
.thenReturn(QVariant(QString("MOCKED MOCKED")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.chainUppercaseThenConcat("a", "b");
|
||||
|
||||
// concat should have been called with the two uppercase results
|
||||
LOGOS_ASSERT(mock.wasCalledWith("test_basic_module", "concat",
|
||||
{QVariant(QString("MOCKED")),
|
||||
QVariant(QString("MOCKED"))}));
|
||||
}
|
||||
|
||||
LOGOS_TEST(chainUppercaseThenConcat_records_original_inputs_for_uppercase) {
|
||||
LogosMockSetup mock;
|
||||
mock.when("test_extlib_module", "uppercaseString")
|
||||
.thenReturn(QVariant(QString("X")));
|
||||
mock.when("test_basic_module", "concat")
|
||||
.thenReturn(QVariant(QString("X X")));
|
||||
|
||||
TestIpcModulePlugin plugin;
|
||||
LogosAPI api("test_ipc_module");
|
||||
plugin.initLogos(&api);
|
||||
|
||||
plugin.chainUppercaseThenConcat("foo", "bar");
|
||||
|
||||
// First call should be "foo", last call (which we can verify) should be "bar"
|
||||
QVariantList lastUpperArgs = mock.lastArgs("test_extlib_module", "uppercaseString");
|
||||
LOGOS_ASSERT_EQ(lastUpperArgs.size(), 1);
|
||||
LOGOS_ASSERT_EQ(lastUpperArgs.at(0).toString(), QString("bar"));
|
||||
}
|
||||
+15
-149
@@ -9,7 +9,6 @@ set -uo pipefail
|
||||
|
||||
LOGOSCORE="${1:?Usage: run_tests.sh <logoscore> <modules-dir>}"
|
||||
MODULES_DIR="${2:?}"
|
||||
UNIT_TEST_BIN="${UNIT_TEST_BIN:-}" # optional: path to test_ipc_module_tests binary (env var)
|
||||
|
||||
|
||||
# UNIT_NEW_API_TEST_BIN: set via env var; path to test_ipc_new_api_module_tests binary
|
||||
@@ -19,9 +18,9 @@ UNIT_NEW_API_TEST_BIN="${UNIT_NEW_API_TEST_BIN:-}"
|
||||
CALL_TIMEOUT="${TEST_TIMEOUT:-30}"
|
||||
|
||||
# TEST_GROUPS: comma-separated list of groups to run (default: all)
|
||||
# Available groups: basic, basic-cpp, context-cpp, extlib, ipc, ipc-new-api,
|
||||
# async, multi, errors, unit, unit-new-api
|
||||
# Example: TEST_GROUPS=ipc or TEST_GROUPS=ipc,basic or TEST_GROUPS=ipc-new-api
|
||||
# Available groups: basic, basic-cpp, context-cpp, extlib, ipc-new-api,
|
||||
# multi, errors, unit-new-api
|
||||
# Example: TEST_GROUPS=ipc-new-api or TEST_GROUPS=ipc-new-api,basic
|
||||
if [[ -n "${TEST_GROUPS:-}" ]]; then
|
||||
IFS=',' read -ra ENABLED_GROUPS <<< "$TEST_GROUPS"
|
||||
else
|
||||
@@ -118,7 +117,7 @@ echo " daemon ready (pid $DAEMON_PID)"
|
||||
# Load every test module up front. The `load-module` subcommand DOES
|
||||
# auto-resolve and load a module's declared dependencies (the daemon
|
||||
# discovers every module under -m at startup, so the dependency closure is
|
||||
# known), so loading e.g. test_ipc_module also brings up its deps
|
||||
# known), so loading e.g. test_ipc_new_api_module also brings up its deps
|
||||
# (test_basic_module, test_extlib_module). We still load each module
|
||||
# explicitly because any single group can be selected on its own via
|
||||
# TEST_GROUPS, and a standalone group's module (e.g. test_basic_module_cpp)
|
||||
@@ -127,7 +126,7 @@ echo " daemon ready (pid $DAEMON_PID)"
|
||||
# run; order is irrelevant since deps resolve automatically. (The daemon
|
||||
# auto-loads capability_module itself.)
|
||||
for _mod in test_basic_module test_basic_module_cpp test_extlib_module \
|
||||
test_context_module_cpp test_ipc_module test_ipc_new_api_module \
|
||||
test_context_module_cpp test_ipc_new_api_module \
|
||||
test_fullapi_cpp test_fullapi_rust test_fullapi_proxy test_fullapi_proxy_rust; do
|
||||
if "$LOGOSCORE" --config-dir "$LOGOSCORE_CONFIG_DIR" load-module "$_mod" >/dev/null 2>&1; then
|
||||
echo " loaded: $_mod"
|
||||
@@ -298,7 +297,7 @@ test_extlib() {
|
||||
assert_call "$1" "$2" -m "$MODULES_DIR" -l test_extlib_module -c "$3"
|
||||
}
|
||||
test_ipc() {
|
||||
assert_call "$1" "$2" -m "$MODULES_DIR" -l test_ipc_module -c "$3"
|
||||
assert_call "$1" "$2" -m "$MODULES_DIR" -l test_ipc_new_api_module -c "$3"
|
||||
}
|
||||
|
||||
# ── Banner ───────────────────────────────────────────────────────────────────
|
||||
@@ -945,70 +944,6 @@ test_extlib "libVersion()" "Result: 1.0.0" "test_extlib_module.lib
|
||||
|
||||
|
||||
fi # end extlib group
|
||||
|
||||
# ═════════════════════════════════════════════════════════════════════════════
|
||||
# TEST GROUP 3: test_ipc_module (inter-module communication)
|
||||
# ═════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
if should_run_group "ipc"; then
|
||||
|
||||
echo ""
|
||||
echo "-----------------------------------------------------------------"
|
||||
echo " test_ipc_module (requires all 3 modules)"
|
||||
echo "-----------------------------------------------------------------"
|
||||
|
||||
# NOTE: The capability_module must be bundled with logoscore for IPC to work.
|
||||
# logoscore auto-discovers it from its default modules dir (../modules relative
|
||||
# to the binary). When user-specified -m dirs are also provided, both the default
|
||||
# and user dirs are scanned.
|
||||
|
||||
# ── Calls to test_basic_module via invokeRemoteMethod ─────────────────────────
|
||||
echo ""
|
||||
echo " -- IPC: calls to test_basic_module --"
|
||||
test_ipc "callBasicEcho(hello)" "Result: hello" "test_ipc_module.callBasicEcho(hello)"
|
||||
test_ipc "callBasicEcho(world)" "Result: world" "test_ipc_module.callBasicEcho(world)"
|
||||
test_ipc "callBasicAddInts(10, 20)" "Result: 30" "test_ipc_module.callBasicAddInts(10, 20)"
|
||||
test_ipc "callBasicAddInts(0, 0)" "Result: 0" "test_ipc_module.callBasicAddInts(0, 0)"
|
||||
test_ipc "callBasicReturnTrue()" "Result: true" "test_ipc_module.callBasicReturnTrue()"
|
||||
test_ipc "callBasicNoArgs()" "Result: noArgs()" "test_ipc_module.callBasicNoArgs()"
|
||||
test_ipc "callBasicFiveArgs(a, 1, true, b, 2)" "Result: fiveArgs(a, 1, true, b, 2)" "test_ipc_module.callBasicFiveArgs(a, 1, true, b, 2)"
|
||||
test_ipc "callBasicSuccessResult()" "Method call successful" "test_ipc_module.callBasicSuccessResult()"
|
||||
test_ipc "callBasicErrorResult()" "Method call successful" "test_ipc_module.callBasicErrorResult()"
|
||||
test_ipc "callBasicResultMapField(name)" "Result: test" "test_ipc_module.callBasicResultMapField(name)"
|
||||
test_ipc "callBasicResultMapField(count)" "Result: 42" "test_ipc_module.callBasicResultMapField(count)"
|
||||
|
||||
# ── Calls to test_extlib_module ───────────────────────────────────────────────
|
||||
echo ""
|
||||
echo " -- IPC: calls to test_extlib_module --"
|
||||
test_ipc "callExtlibReverse(hello)" "Result: olleh" "test_ipc_module.callExtlibReverse(hello)"
|
||||
test_ipc "callExtlibReverse(abc)" "Result: cba" "test_ipc_module.callExtlibReverse(abc)"
|
||||
test_ipc "callExtlibUppercase(hello)" "Result: HELLO" "test_ipc_module.callExtlibUppercase(hello)"
|
||||
test_ipc "callExtlibCountChars(hello)" "Result: 5" "test_ipc_module.callExtlibCountChars(hello)"
|
||||
|
||||
# ── Cross-module chaining ─────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo " -- IPC: cross-module chaining --"
|
||||
test_ipc "chainEchoThenReverse(hello)" "Result: olleh" "test_ipc_module.chainEchoThenReverse(hello)"
|
||||
test_ipc "chainEchoThenReverse(abcdef)" "Result: fedcba" "test_ipc_module.chainEchoThenReverse(abcdef)"
|
||||
test_ipc "chainUppercaseThenConcat(foo, bar)" "Result: FOOBAR" "test_ipc_module.chainUppercaseThenConcat(foo, bar)"
|
||||
test_ipc "chainUppercaseThenConcat(hello, world)" "Result: HELLOWORLD" "test_ipc_module.chainUppercaseThenConcat(hello, world)"
|
||||
|
||||
# ── Generated type-safe wrappers ──────────────────────────────────────────────
|
||||
echo ""
|
||||
echo " -- IPC: generated wrappers (LogosModules) --"
|
||||
test_ipc "wrapperBasicEcho(hello)" "Result: hello" "test_ipc_module.wrapperBasicEcho(hello)"
|
||||
test_ipc "wrapperBasicEcho(test123)" "Result: test123" "test_ipc_module.wrapperBasicEcho(test123)"
|
||||
test_ipc "wrapperExtlibReverse(hello)" "Result: olleh" "test_ipc_module.wrapperExtlibReverse(hello)"
|
||||
test_ipc "wrapperExtlibReverse(abc)" "Result: cba" "test_ipc_module.wrapperExtlibReverse(abc)"
|
||||
|
||||
# ── Events ────────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo " -- IPC: events --"
|
||||
skip_test "triggerBasicEvent(data)" "void return → invalid QVariant → logoscore exit 1"
|
||||
|
||||
|
||||
fi # end ipc group
|
||||
|
||||
# ═════════════════════════════════════════════════════════════════════════════
|
||||
# TEST GROUP 3b: test_ipc_new_api_module (new LogosProviderBase API)
|
||||
# ═════════════════════════════════════════════════════════════════════════════
|
||||
@@ -1064,9 +999,10 @@ test_ipc_new_api "wrapperExtlibReverse(abc)" "Result: cba"
|
||||
echo ""
|
||||
echo " -- IPC new-API: async over the lp transport --"
|
||||
# The async half of the same generated wrappers used above. On this surface
|
||||
# `<name>Async` bottoms out in lp_invoke_async, so unlike the `async` group
|
||||
# (which exercises the QT consumer through test_ipc_module) these assert async
|
||||
# delivery into a module with NO Qt in its own translation units.
|
||||
# `<name>Async` bottoms out in lp_invoke_async, so these assert async delivery
|
||||
# into a module with NO Qt in its own translation units. The Qt-consumer side of
|
||||
# async lives in test_fullapi_qtproxy, which reads completions from a separate
|
||||
# call rather than blocking for them.
|
||||
test_ipc_new_api "asyncCallBasicEcho(hello)" "Result: hello" "test_ipc_new_api_module.asyncCallBasicEcho(hello)"
|
||||
test_ipc_new_api "asyncCallBasicEcho(world)" "Result: world" "test_ipc_new_api_module.asyncCallBasicEcho(world)"
|
||||
test_ipc_new_api "asyncCallBasicAddInts(3, 4)" "Result: 7" "test_ipc_new_api_module.asyncCallBasicAddInts(3, 4)"
|
||||
@@ -1143,14 +1079,14 @@ fi
|
||||
|
||||
TOTAL=$((TOTAL + 1))
|
||||
# shellcheck disable=SC2086
|
||||
printf " cmd: timeout %s %s %s -m %s -l test_ipc_module -c ... -c ... -c ...\n" \
|
||||
printf " cmd: timeout %s %s %s -m %s -l test_ipc_new_api_module -c ... -c ... -c ...\n" \
|
||||
"$CALL_TIMEOUT" "$LOGOSCORE" "$QUIT_FLAG" "$MODULES_DIR"
|
||||
# shellcheck disable=SC2086
|
||||
output=$(dcall_inline \
|
||||
-m "$MODULES_DIR" -l test_ipc_module \
|
||||
-c "test_ipc_module.callBasicEcho(chain)" \
|
||||
-c "test_ipc_module.callExtlibReverse(hello)" \
|
||||
-c "test_ipc_module.callBasicAddInts(5, 7)" \
|
||||
-m "$MODULES_DIR" -l test_ipc_new_api_module \
|
||||
-c "test_ipc_new_api_module.callBasicEcho(chain)" \
|
||||
-c "test_ipc_new_api_module.callExtlibReverse(hello)" \
|
||||
-c "test_ipc_new_api_module.callBasicAddInts(5, 7)" \
|
||||
2>/dev/null) && rc=0 || rc=$?
|
||||
if [[ $rc -eq 0 ]] && \
|
||||
printf '%s' "$output" | grep -qF "Result: chain" && \
|
||||
@@ -1190,76 +1126,6 @@ assert_call_fails "nonexistent module" \
|
||||
|
||||
|
||||
fi # end errors group
|
||||
|
||||
# ═════════════════════════════════════════════════════════════════════════════
|
||||
# TEST GROUP 6: Async calls (invokeRemoteMethodAsync + generated wrappers)
|
||||
# ═════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
if should_run_group "async"; then
|
||||
|
||||
echo ""
|
||||
echo "-----------------------------------------------------------------"
|
||||
echo " Async calls"
|
||||
echo "-----------------------------------------------------------------"
|
||||
|
||||
echo ""
|
||||
echo " -- Raw invokeRemoteMethodAsync --"
|
||||
test_ipc "asyncCallBasicEcho(hello)" "Result: hello" "test_ipc_module.asyncCallBasicEcho(hello)"
|
||||
test_ipc "asyncCallBasicEcho(world)" "Result: world" "test_ipc_module.asyncCallBasicEcho(world)"
|
||||
test_ipc "asyncCallBasicAddInts(3, 4)" "Result: 7" "test_ipc_module.asyncCallBasicAddInts(3, 4)"
|
||||
test_ipc "asyncCallBasicAddInts(0, 0)" "Result: 0" "test_ipc_module.asyncCallBasicAddInts(0, 0)"
|
||||
|
||||
echo ""
|
||||
echo " -- Async cross-module (ipc -> extlib) --"
|
||||
test_ipc "asyncCallExtlibReverse(hello)" "Result: olleh" "test_ipc_module.asyncCallExtlibReverse(hello)"
|
||||
test_ipc "asyncCallExtlibReverse(abc)" "Result: cba" "test_ipc_module.asyncCallExtlibReverse(abc)"
|
||||
|
||||
echo ""
|
||||
echo " -- Generated async wrapper (echoAsync) --"
|
||||
test_ipc "asyncWrapperBasicEcho(hello)" "Result: hello" "test_ipc_module.asyncWrapperBasicEcho(hello)"
|
||||
test_ipc "asyncWrapperBasicEcho(test123)" "Result: test123" "test_ipc_module.asyncWrapperBasicEcho(test123)"
|
||||
|
||||
|
||||
fi # end async group
|
||||
|
||||
# ═════════════════════════════════════════════════════════════════════════════
|
||||
# TEST GROUP 7: Unit tests (mock transport, no logoscore required)
|
||||
# ═════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
if should_run_group "unit"; then
|
||||
|
||||
echo ""
|
||||
echo "-----------------------------------------------------------------"
|
||||
echo " Unit tests (mock transport)"
|
||||
echo "-----------------------------------------------------------------"
|
||||
echo ""
|
||||
|
||||
if [[ -z "$UNIT_TEST_BIN" ]]; then
|
||||
echo " SKIP unit tests (no unit test binary provided)"
|
||||
echo " Set UNIT_TEST_BIN env var to the path of test_ipc_module_tests binary"
|
||||
SKIP=$((SKIP + 1))
|
||||
elif [[ ! -x "$UNIT_TEST_BIN" ]]; then
|
||||
FAIL=$((FAIL + 1))
|
||||
printf " FAIL unit tests — binary not found or not executable: %s\n" "$UNIT_TEST_BIN"
|
||||
FAILURES="${FAILURES} FAIL unit tests: binary not found: ${UNIT_TEST_BIN}\n"
|
||||
else
|
||||
TOTAL=$((TOTAL + 1))
|
||||
printf " cmd: %s\n" "$UNIT_TEST_BIN"
|
||||
unit_output=$("$UNIT_TEST_BIN" 2>&1) && unit_rc=0 || unit_rc=$?
|
||||
printf "%s\n" "$unit_output"
|
||||
if [[ $unit_rc -eq 0 ]]; then
|
||||
PASS=$((PASS + 1))
|
||||
printf " PASS unit tests\n"
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
printf " FAIL unit tests (exit code %d)\n" "$unit_rc"
|
||||
FAILURES="${FAILURES} FAIL unit tests: exit code ${unit_rc}\n"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
fi # end unit group
|
||||
|
||||
# ═════════════════════════════════════════════════════════════════════════════
|
||||
# TEST GROUP 7: Unit tests — new provider API (mock transport, no logoscore)
|
||||
# ═════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user