remove proxy api (moved to logos-module-client)

This commit is contained in:
Logos Workspace
2026-03-25 13:39:23 -04:00
parent 21f8fb43d3
commit c1c374bbcc
12 changed files with 1 additions and 964 deletions
-9
View File
@@ -51,12 +51,6 @@ set(SDK_SOURCES
implementations/mock/mock_transport.h
implementations/mock/mock_registry.h
implementations/mock/logos_mock.h
logos_json_utils.cpp
logos_json_utils.h
logos_core_client.cpp
logos_core_client.h
logos_sdk_c.cpp
logos_sdk_c.h
)
# Create the SDK library as STATIC instead of SHARED
@@ -104,9 +98,6 @@ install(FILES
logos_transport_factory.h
logos_registry.h
logos_registry_factory.h
logos_json_utils.h
logos_core_client.h
logos_sdk_c.h
DESTINATION include
)
-85
View File
@@ -1,85 +0,0 @@
#include "logos_core_client.h"
#include "logos_api.h"
#include "logos_api_client.h"
#include "logos_object.h"
#include "logos_json_utils.h"
#include <QDebug>
LogosCoreClient::LogosCoreClient(QObject* parent)
: QObject(parent)
, m_api(new LogosAPI("core", this))
{
}
LogosCoreClient::~LogosCoreClient()
{
}
LogosAPIClient* LogosCoreClient::clientFor(const QString& pluginName)
{
return m_api->getClient(pluginName);
}
void LogosCoreClient::callMethodAsync(const QString& pluginName,
const QString& methodName,
const QString& paramsJson,
AsyncCallback callback)
{
if (!callback) return;
bool ok = false;
QString errorMessage;
QVariantList args = LogosJsonUtils::parseMethodParams(paramsJson, &ok, &errorMessage);
if (!ok) {
callback(false, errorMessage);
return;
}
LogosAPIClient* client = m_api->getClient(pluginName);
if (!client) {
callback(false, QString("Failed to get client for plugin: %1").arg(pluginName));
return;
}
client->invokeRemoteMethodAsync(
pluginName, methodName, args,
[callback, pluginName, methodName](QVariant result) {
if (result.isValid()) {
QString resultStr;
if (result.canConvert<QString>()) {
resultStr = result.toString();
} else {
resultStr = QString("Result of type: %1").arg(result.typeName());
}
callback(true, QString("Method call successful. Result: %1").arg(resultStr));
} else {
callback(false, QStringLiteral("Method call returned invalid result"));
}
});
}
void LogosCoreClient::subscribeEvent(const QString& pluginName,
const QString& eventName,
AsyncCallback callback)
{
if (!callback) return;
LogosAPIClient* client = m_api->getClient(pluginName);
if (!client) {
qWarning() << "LogosCoreClient: Failed to get client for event subscription:" << pluginName;
return;
}
LogosObject* obj = client->requestObject(pluginName);
if (!obj) {
qWarning() << "LogosCoreClient: Failed to get object for event subscription:" << pluginName;
return;
}
client->onEvent(obj, eventName,
[callback](const QString& evName, const QVariantList& evData) {
QString json = LogosJsonUtils::formatEventJson(evName, evData);
callback(true, json);
});
}
-62
View File
@@ -1,62 +0,0 @@
#ifndef LOGOS_CORE_CLIENT_H
#define LOGOS_CORE_CLIENT_H
#include <QObject>
#include <QString>
#include <QVariant>
#include <QVariantList>
#include <QHash>
#include <functional>
class LogosAPI;
class LogosAPIClient;
class LogosObject;
/**
* @brief LogosCoreClient provides a high-level async interface for calling
* plugin methods and subscribing to events from the "core" (host) perspective.
*
* Unlike creating ephemeral LogosAPI instances per call, this class maintains
* a single persistent LogosAPI("core") and reuses cached client connections.
*
* It uses LogosAPIClient::invokeRemoteMethodAsync for connection-aware calls,
* eliminating manual QTimer-based connection delays.
*/
class LogosCoreClient : public QObject
{
Q_OBJECT
public:
using AsyncCallback = std::function<void(bool success, const QString& message)>;
explicit LogosCoreClient(QObject* parent = nullptr);
~LogosCoreClient();
/**
* Call a plugin method asynchronously, with parameters provided as a JSON
* string in the [{name,value,type},...] format used by FFI consumers.
* The callback receives (success, resultMessage).
*/
void callMethodAsync(const QString& pluginName,
const QString& methodName,
const QString& paramsJson,
AsyncCallback callback);
/**
* Subscribe to an event from a plugin. The callback fires each time
* the event is emitted, with a JSON-formatted message.
*/
void subscribeEvent(const QString& pluginName,
const QString& eventName,
AsyncCallback callback);
/**
* Get (or lazily create) a LogosAPIClient for the named plugin.
*/
LogosAPIClient* clientFor(const QString& pluginName);
private:
LogosAPI* m_api;
};
#endif // LOGOS_CORE_CLIENT_H
-115
View File
@@ -1,115 +0,0 @@
#include "logos_json_utils.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QDebug>
namespace LogosJsonUtils {
QVariant jsonParamToVariant(const QJsonObject& param)
{
QString name = param.value("name").toString();
QString value = param.value("value").toString();
QString type = param.value("type").toString();
qDebug() << "LogosJsonUtils: Converting param:" << name << "value:" << value << "type:" << type;
if (type == "string" || type == "QString") {
return QVariant(value);
} else if (type == "int" || type == "integer") {
bool ok;
int intValue = value.toInt(&ok);
return ok ? QVariant(intValue) : QVariant();
} else if (type == "bool" || type == "boolean") {
if (value.toLower() == "true" || value == "1") {
return QVariant(true);
} else if (value.toLower() == "false" || value == "0") {
return QVariant(false);
}
return QVariant();
} else if (type == "double" || type == "float") {
bool ok;
double doubleValue = value.toDouble(&ok);
return ok ? QVariant(doubleValue) : QVariant();
} else {
qWarning() << "LogosJsonUtils: Unknown parameter type:" << type << "- treating as string";
return QVariant(value);
}
}
QVariantList parseMethodParams(const QString& json, bool* ok, QString* errorMessage)
{
QVariantList args;
QJsonParseError parseError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(json.toUtf8(), &parseError);
if (parseError.error != QJsonParseError::NoError) {
if (ok) *ok = false;
if (errorMessage) *errorMessage = QString("JSON parse error: %1").arg(parseError.errorString());
return args;
}
QJsonArray paramsArray = jsonDoc.array();
for (const QJsonValue& paramValue : paramsArray) {
if (paramValue.isObject()) {
QJsonObject paramObj = paramValue.toObject();
QVariant variant = jsonParamToVariant(paramObj);
if (variant.isValid()) {
args.append(variant);
} else {
if (ok) *ok = false;
if (errorMessage) *errorMessage = QString("Invalid parameter: %1").arg(paramObj.value("name").toString());
return QVariantList();
}
}
}
if (ok) *ok = true;
return args;
}
QString variantToJsonString(const QVariant& value)
{
if (!value.isValid())
return QStringLiteral("null");
switch (value.userType()) {
case QMetaType::Bool:
return value.toBool() ? QStringLiteral("true") : QStringLiteral("false");
case QMetaType::Int:
case QMetaType::LongLong:
return QString::number(value.toLongLong());
case QMetaType::Double:
case QMetaType::Float:
return QString::number(value.toDouble());
case QMetaType::QString:
return value.toString();
case QMetaType::QVariantMap: {
QJsonDocument doc(QJsonObject::fromVariantMap(value.toMap()));
return QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
}
case QMetaType::QVariantList: {
QJsonDocument doc(QJsonArray::fromVariantList(value.toList()));
return QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
}
default:
break;
}
return value.toString();
}
QString formatEventJson(const QString& eventName, const QVariantList& data)
{
QString result = QString("{\"event\":\"%1\",\"data\":[").arg(eventName);
for (int i = 0; i < data.size(); ++i) {
if (i > 0) result += ",";
result += QString("\"%1\"").arg(data[i].toString());
}
result += "]}";
return result;
}
} // namespace LogosJsonUtils
-44
View File
@@ -1,44 +0,0 @@
#ifndef LOGOS_JSON_UTILS_H
#define LOGOS_JSON_UTILS_H
#include <QVariant>
#include <QVariantList>
#include <QString>
#include <QJsonObject>
namespace LogosJsonUtils {
/**
* Convert a single JSON parameter object {name, value, type} to a QVariant.
* Supports types: string, QString, int, integer, bool, boolean, double, float.
* Unknown types are treated as strings.
* Returns invalid QVariant for unparseable values (e.g. "abc" as int).
*/
QVariant jsonParamToVariant(const QJsonObject& param);
/**
* Parse a JSON string containing an array of {name, value, type} objects
* into a QVariantList. This is the format used by FFI consumers (e.g. logos-js-sdk).
*
* On success, sets ok=true and returns the converted arguments.
* On failure (JSON parse error or invalid parameter), sets ok=false and
* fills errorMessage with a description.
*/
QVariantList parseMethodParams(const QString& json, bool* ok = nullptr, QString* errorMessage = nullptr);
/**
* Convert a QVariant result into a JSON-formatted string suitable for
* returning through the C callback API.
*/
QString variantToJsonString(const QVariant& value);
/**
* Format event data (event name + QVariantList payload) as a JSON string
* matching the format expected by FFI consumers:
* {"event":"<name>","data":["<val1>","<val2>",...]}
*/
QString formatEventJson(const QString& eventName, const QVariantList& data);
}
#endif // LOGOS_JSON_UTILS_H
-62
View File
@@ -1,62 +0,0 @@
#include "logos_sdk_c.h"
#include "logos_core_client.h"
#include <QString>
#include <QByteArray>
static LogosCoreClient* s_coreClient = nullptr;
static LogosCoreClient* ensureClient()
{
if (!s_coreClient)
s_coreClient = new LogosCoreClient();
return s_coreClient;
}
void logos_sdk_call_method_async(
const char* plugin_name,
const char* method_name,
const char* params_json,
LogosSdkCallback callback,
void* user_data)
{
if (!callback) return;
if (!plugin_name || !method_name) {
callback(0, "Plugin name or method name is null", user_data);
return;
}
QString pluginStr = QString::fromUtf8(plugin_name);
QString methodStr = QString::fromUtf8(method_name);
QString paramsStr = params_json ? QString::fromUtf8(params_json) : QStringLiteral("[]");
ensureClient()->callMethodAsync(pluginStr, methodStr, paramsStr,
[callback, user_data](bool success, const QString& message) {
QByteArray msgBytes = message.toUtf8();
callback(success ? 1 : 0, msgBytes.constData(), user_data);
});
}
void logos_sdk_register_event(
const char* plugin_name,
const char* event_name,
LogosSdkCallback callback,
void* user_data)
{
if (!plugin_name || !event_name || !callback) return;
QString pluginStr = QString::fromUtf8(plugin_name);
QString eventStr = QString::fromUtf8(event_name);
ensureClient()->subscribeEvent(pluginStr, eventStr,
[callback, user_data](bool success, const QString& message) {
QByteArray msgBytes = message.toUtf8();
callback(success ? 1 : 0, msgBytes.constData(), user_data);
});
}
void logos_sdk_shutdown()
{
delete s_coreClient;
s_coreClient = nullptr;
}
-57
View File
@@ -1,57 +0,0 @@
#ifndef LOGOS_SDK_C_H
#define LOGOS_SDK_C_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* C callback type matching the AsyncCallback in logos_core.h:
* void(int result, const char* message, void* user_data)
*/
typedef void (*LogosSdkCallback)(int result, const char* message, void* user_data);
/**
* Call a plugin method asynchronously.
*
* @param plugin_name Target plugin name
* @param method_name Method to call
* @param params_json JSON array of [{name,value,type},...] parameters (may be NULL for "[]")
* @param callback Receives (1=success/0=failure, message, user_data) on completion
* @param user_data Opaque pointer passed through to callback
*/
void logos_sdk_call_method_async(
const char* plugin_name,
const char* method_name,
const char* params_json,
LogosSdkCallback callback,
void* user_data
);
/**
* Register an event listener for a specific event from a plugin.
*
* @param plugin_name Plugin that emits the event
* @param event_name Event name to listen for
* @param callback Receives (1, json_event_data, user_data) each time event fires
* @param user_data Opaque pointer passed through to callback
*/
void logos_sdk_register_event(
const char* plugin_name,
const char* event_name,
LogosSdkCallback callback,
void* user_data
);
/**
* Shut down the SDK's internal core client, releasing connections.
* Safe to call multiple times. After this, async calls will lazily re-create
* the client on next use.
*/
void logos_sdk_shutdown(void);
#ifdef __cplusplus
}
#endif
#endif // LOGOS_SDK_C_H
+1 -4
View File
@@ -36,10 +36,7 @@ pkgs.stdenv.mkDerivation {
qt_provider_object.h qt_provider_object.cpp \
logos_transport.h logos_transport_factory.h logos_transport_factory.cpp \
logos_registry.h logos_registry_factory.h logos_registry_factory.cpp \
plugin_registry.h \
logos_json_utils.h logos_json_utils.cpp \
logos_core_client.h logos_core_client.cpp \
logos_sdk_c.h logos_sdk_c.cpp; do
plugin_registry.h; do
if [ -f cpp/$file ]; then
cp cpp/$file $out/include/cpp/
fi
-3
View File
@@ -38,9 +38,6 @@ add_executable(sdk_tests
test_local_transport_integration.cpp
test_event_system.cpp
test_provider_dispatch.cpp
test_logos_json_utils.cpp
test_logos_core_client.cpp
test_logos_sdk_c.cpp
fixtures/sample_provider.cpp
${GENERATED_DISPATCH}
)
-127
View File
@@ -1,127 +0,0 @@
#include <gtest/gtest.h>
#include <QCoreApplication>
#include "logos_mock.h"
#include "logos_core_client.h"
class LogosCoreClientTest : public ::testing::Test {
protected:
void SetUp() override { m_mock = new LogosMockSetup(); }
void TearDown() override { delete m_mock; }
LogosMockSetup* m_mock = nullptr;
void processEvents() {
for (int i = 0; i < 10; ++i)
QCoreApplication::processEvents();
}
};
TEST_F(LogosCoreClientTest, CallMethodAsync_SuccessfulCall)
{
m_mock->when("test_module", "greet").thenReturn(QVariant("hello world"));
LogosCoreClient client;
bool called = false;
bool success = false;
QString message;
client.callMethodAsync("test_module", "greet", "[]",
[&](bool s, const QString& m) { called = true; success = s; message = m; });
processEvents();
EXPECT_TRUE(called);
EXPECT_TRUE(success);
EXPECT_TRUE(message.contains("hello world"));
}
TEST_F(LogosCoreClientTest, CallMethodAsync_WithJsonParams)
{
m_mock->when("math", "add").thenReturn(QVariant(30));
LogosCoreClient client;
bool called = false;
bool success = false;
QString params = R"([{"name":"a","value":"10","type":"int"},{"name":"b","value":"20","type":"int"}])";
client.callMethodAsync("math", "add", params,
[&](bool s, const QString&) { called = true; success = s; });
processEvents();
EXPECT_TRUE(called);
EXPECT_TRUE(success);
EXPECT_TRUE(m_mock->wasCalled("math", "add"));
}
TEST_F(LogosCoreClientTest, CallMethodAsync_InvalidJsonReportsError)
{
LogosCoreClient client;
bool called = false;
bool success = true;
QString message;
client.callMethodAsync("mod", "fn", "not valid json",
[&](bool s, const QString& m) { called = true; success = s; message = m; });
EXPECT_TRUE(called);
EXPECT_FALSE(success);
EXPECT_TRUE(message.contains("JSON parse error"));
}
TEST_F(LogosCoreClientTest, CallMethodAsync_InvalidParamReportsError)
{
LogosCoreClient client;
bool called = false;
bool success = true;
QString message;
QString params = R"([{"name":"a","value":"abc","type":"int"}])";
client.callMethodAsync("mod", "fn", params,
[&](bool s, const QString& m) { called = true; success = s; message = m; });
EXPECT_TRUE(called);
EXPECT_FALSE(success);
EXPECT_TRUE(message.contains("Invalid parameter"));
}
TEST_F(LogosCoreClientTest, CallMethodAsync_NullCallbackIsNoOp)
{
LogosCoreClient client;
client.callMethodAsync("mod", "fn", "[]", nullptr);
}
TEST_F(LogosCoreClientTest, CallMethodAsync_InvalidResultReportsError)
{
// No expectation set -> mock returns invalid QVariant
m_mock->when("mod", "other").thenReturn(QVariant(1));
LogosCoreClient client;
bool called = false;
bool success = true;
QString message;
client.callMethodAsync("mod", "missing_fn", "[]",
[&](bool s, const QString& m) { called = true; success = s; message = m; });
processEvents();
EXPECT_TRUE(called);
EXPECT_FALSE(success);
EXPECT_TRUE(message.contains("invalid result"));
}
TEST_F(LogosCoreClientTest, ClientFor_ReturnsSameClientForSamePlugin)
{
LogosCoreClient client;
auto* c1 = client.clientFor("mod");
auto* c2 = client.clientFor("mod");
EXPECT_EQ(c1, c2);
}
TEST_F(LogosCoreClientTest, ClientFor_ReturnsDifferentForDifferentPlugins)
{
LogosCoreClient client;
auto* c1 = client.clientFor("mod_a");
auto* c2 = client.clientFor("mod_b");
EXPECT_NE(c1, c2);
}
-236
View File
@@ -1,236 +0,0 @@
#include <gtest/gtest.h>
#include "logos_json_utils.h"
#include <QJsonObject>
// =============================================================================
// jsonParamToVariant tests
// =============================================================================
TEST(LogosJsonUtilsTest, ConvertsStringType)
{
QJsonObject p;
p["name"] = "arg0"; p["value"] = "hello"; p["type"] = "string";
QVariant v = LogosJsonUtils::jsonParamToVariant(p);
EXPECT_TRUE(v.isValid());
EXPECT_EQ(v.toString(), "hello");
}
TEST(LogosJsonUtilsTest, ConvertsQStringType)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "qt"; p["type"] = "QString";
EXPECT_EQ(LogosJsonUtils::jsonParamToVariant(p).toString(), "qt");
}
TEST(LogosJsonUtilsTest, ConvertsIntType)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "42"; p["type"] = "int";
QVariant v = LogosJsonUtils::jsonParamToVariant(p);
EXPECT_TRUE(v.isValid());
EXPECT_EQ(v.toInt(), 42);
}
TEST(LogosJsonUtilsTest, ConvertsIntegerType)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "99"; p["type"] = "integer";
EXPECT_EQ(LogosJsonUtils::jsonParamToVariant(p).toInt(), 99);
}
TEST(LogosJsonUtilsTest, ConvertsBoolTrue)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "true"; p["type"] = "bool";
EXPECT_TRUE(LogosJsonUtils::jsonParamToVariant(p).toBool());
p["value"] = "1";
EXPECT_TRUE(LogosJsonUtils::jsonParamToVariant(p).toBool());
}
TEST(LogosJsonUtilsTest, ConvertsBoolFalse)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "false"; p["type"] = "bool";
EXPECT_FALSE(LogosJsonUtils::jsonParamToVariant(p).toBool());
p["value"] = "0";
EXPECT_FALSE(LogosJsonUtils::jsonParamToVariant(p).toBool());
}
TEST(LogosJsonUtilsTest, ConvertsBooleanType)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "true"; p["type"] = "boolean";
EXPECT_TRUE(LogosJsonUtils::jsonParamToVariant(p).toBool());
}
TEST(LogosJsonUtilsTest, ConvertsDoubleType)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "3.14"; p["type"] = "double";
EXPECT_NEAR(LogosJsonUtils::jsonParamToVariant(p).toDouble(), 3.14, 0.001);
}
TEST(LogosJsonUtilsTest, ConvertsFloatType)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "2.718"; p["type"] = "float";
EXPECT_NEAR(LogosJsonUtils::jsonParamToVariant(p).toDouble(), 2.718, 0.001);
}
TEST(LogosJsonUtilsTest, InvalidIntReturnsInvalid)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "abc"; p["type"] = "int";
EXPECT_FALSE(LogosJsonUtils::jsonParamToVariant(p).isValid());
}
TEST(LogosJsonUtilsTest, InvalidBoolReturnsInvalid)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "maybe"; p["type"] = "bool";
EXPECT_FALSE(LogosJsonUtils::jsonParamToVariant(p).isValid());
}
TEST(LogosJsonUtilsTest, InvalidDoubleReturnsInvalid)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "xyz"; p["type"] = "double";
EXPECT_FALSE(LogosJsonUtils::jsonParamToVariant(p).isValid());
}
TEST(LogosJsonUtilsTest, UnknownTypeTreatedAsString)
{
QJsonObject p;
p["name"] = "a"; p["value"] = "data"; p["type"] = "custom_thing";
QVariant v = LogosJsonUtils::jsonParamToVariant(p);
EXPECT_TRUE(v.isValid());
EXPECT_EQ(v.toString(), "data");
}
// =============================================================================
// parseMethodParams tests
// =============================================================================
TEST(LogosJsonUtilsTest, ParseMixedParams)
{
QString json = R"([
{"name":"arg0","value":"hello","type":"string"},
{"name":"arg1","value":"42","type":"int"},
{"name":"arg2","value":"true","type":"bool"},
{"name":"arg3","value":"3.14","type":"double"}
])";
bool ok = false;
QString err;
QVariantList args = LogosJsonUtils::parseMethodParams(json, &ok, &err);
EXPECT_TRUE(ok);
EXPECT_TRUE(err.isEmpty());
ASSERT_EQ(args.size(), 4);
EXPECT_EQ(args[0].toString(), "hello");
EXPECT_EQ(args[1].toInt(), 42);
EXPECT_TRUE(args[2].toBool());
EXPECT_NEAR(args[3].toDouble(), 3.14, 0.001);
}
TEST(LogosJsonUtilsTest, ParseEmptyArray)
{
bool ok = false;
QVariantList args = LogosJsonUtils::parseMethodParams("[]", &ok);
EXPECT_TRUE(ok);
EXPECT_EQ(args.size(), 0);
}
TEST(LogosJsonUtilsTest, ParseInvalidJson)
{
bool ok = true;
QString err;
QVariantList args = LogosJsonUtils::parseMethodParams("not json", &ok, &err);
EXPECT_FALSE(ok);
EXPECT_TRUE(err.contains("JSON parse error"));
EXPECT_EQ(args.size(), 0);
}
TEST(LogosJsonUtilsTest, ParseInvalidParamValue)
{
QString json = R"([{"name":"a","value":"abc","type":"int"}])";
bool ok = true;
QString err;
QVariantList args = LogosJsonUtils::parseMethodParams(json, &ok, &err);
EXPECT_FALSE(ok);
EXPECT_TRUE(err.contains("Invalid parameter"));
}
TEST(LogosJsonUtilsTest, ParseSingleString)
{
QString json = R"([{"name":"arg0","value":"test","type":"string"}])";
bool ok = false;
QVariantList args = LogosJsonUtils::parseMethodParams(json, &ok);
EXPECT_TRUE(ok);
ASSERT_EQ(args.size(), 1);
EXPECT_EQ(args[0].toString(), "test");
}
TEST(LogosJsonUtilsTest, ParseNullOkPointer)
{
QVariantList args = LogosJsonUtils::parseMethodParams("[]");
EXPECT_EQ(args.size(), 0);
}
// =============================================================================
// variantToJsonString tests
// =============================================================================
TEST(LogosJsonUtilsTest, VariantToJson_Invalid)
{
EXPECT_EQ(LogosJsonUtils::variantToJsonString(QVariant()), "null");
}
TEST(LogosJsonUtilsTest, VariantToJson_String)
{
EXPECT_EQ(LogosJsonUtils::variantToJsonString(QVariant("hello")), "hello");
}
TEST(LogosJsonUtilsTest, VariantToJson_Int)
{
EXPECT_EQ(LogosJsonUtils::variantToJsonString(QVariant(42)), "42");
}
TEST(LogosJsonUtilsTest, VariantToJson_Bool)
{
EXPECT_EQ(LogosJsonUtils::variantToJsonString(QVariant(true)), "true");
EXPECT_EQ(LogosJsonUtils::variantToJsonString(QVariant(false)), "false");
}
TEST(LogosJsonUtilsTest, VariantToJson_Double)
{
QString result = LogosJsonUtils::variantToJsonString(QVariant(3.14));
EXPECT_TRUE(result.startsWith("3.14"));
}
TEST(LogosJsonUtilsTest, VariantToJson_Map)
{
QVariantMap map;
map["key"] = "value";
QString result = LogosJsonUtils::variantToJsonString(QVariant(map));
EXPECT_TRUE(result.contains("key"));
EXPECT_TRUE(result.contains("value"));
}
// =============================================================================
// formatEventJson tests
// =============================================================================
TEST(LogosJsonUtilsTest, FormatEventJson_Basic)
{
QVariantList data;
data << QVariant("hello") << QVariant(42);
QString result = LogosJsonUtils::formatEventJson("myEvent", data);
EXPECT_EQ(result, R"({"event":"myEvent","data":["hello","42"]})");
}
TEST(LogosJsonUtilsTest, FormatEventJson_Empty)
{
QString result = LogosJsonUtils::formatEventJson("evt", {});
EXPECT_EQ(result, R"({"event":"evt","data":[]})");
}
-160
View File
@@ -1,160 +0,0 @@
#include <gtest/gtest.h>
#include <QCoreApplication>
#include "logos_mock.h"
#include "logos_sdk_c.h"
#include <cstring>
static bool s_called = false;
static int s_result = -1;
static std::string s_message;
static void* s_user_data = nullptr;
static void resetState()
{
s_called = false;
s_result = -1;
s_message.clear();
s_user_data = nullptr;
}
static void testCCallback(int result, const char* message, void* user_data)
{
s_called = true;
s_result = result;
s_message = message ? message : "";
s_user_data = user_data;
}
class LogosSdkCTest : public ::testing::Test {
protected:
void SetUp() override
{
m_mock = new LogosMockSetup();
resetState();
}
void TearDown() override
{
logos_sdk_shutdown();
delete m_mock;
}
LogosMockSetup* m_mock = nullptr;
void processEvents() {
for (int i = 0; i < 10; ++i)
QCoreApplication::processEvents();
}
};
TEST_F(LogosSdkCTest, CallMethodAsync_Success)
{
m_mock->when("mod", "fn").thenReturn(QVariant("ok"));
logos_sdk_call_method_async("mod", "fn", "[]", testCCallback, nullptr);
processEvents();
EXPECT_TRUE(s_called);
EXPECT_EQ(s_result, 1);
EXPECT_TRUE(s_message.find("ok") != std::string::npos);
}
TEST_F(LogosSdkCTest, CallMethodAsync_WithParams)
{
m_mock->when("mod", "fn").thenReturn(QVariant(42));
const char* params = R"([{"name":"a","value":"hello","type":"string"}])";
logos_sdk_call_method_async("mod", "fn", params, testCCallback, nullptr);
processEvents();
EXPECT_TRUE(s_called);
EXPECT_EQ(s_result, 1);
}
TEST_F(LogosSdkCTest, CallMethodAsync_NullPluginName)
{
logos_sdk_call_method_async(nullptr, "fn", "[]", testCCallback, nullptr);
EXPECT_TRUE(s_called);
EXPECT_EQ(s_result, 0);
EXPECT_TRUE(s_message.find("null") != std::string::npos);
}
TEST_F(LogosSdkCTest, CallMethodAsync_NullMethodName)
{
logos_sdk_call_method_async("mod", nullptr, "[]", testCCallback, nullptr);
EXPECT_TRUE(s_called);
EXPECT_EQ(s_result, 0);
}
TEST_F(LogosSdkCTest, CallMethodAsync_NullCallback)
{
logos_sdk_call_method_async("mod", "fn", "[]", nullptr, nullptr);
EXPECT_FALSE(s_called);
}
TEST_F(LogosSdkCTest, CallMethodAsync_InvalidJson)
{
logos_sdk_call_method_async("mod", "fn", "bad json", testCCallback, nullptr);
EXPECT_TRUE(s_called);
EXPECT_EQ(s_result, 0);
EXPECT_TRUE(s_message.find("JSON parse error") != std::string::npos);
}
TEST_F(LogosSdkCTest, CallMethodAsync_NullParamsDefaultsToEmptyArray)
{
m_mock->when("mod", "fn").thenReturn(QVariant("ok"));
logos_sdk_call_method_async("mod", "fn", nullptr, testCCallback, nullptr);
processEvents();
EXPECT_TRUE(s_called);
EXPECT_EQ(s_result, 1);
}
TEST_F(LogosSdkCTest, CallMethodAsync_PassesUserData)
{
m_mock->when("mod", "fn").thenReturn(QVariant("ok"));
int data = 999;
logos_sdk_call_method_async("mod", "fn", "[]", testCCallback, &data);
processEvents();
EXPECT_TRUE(s_called);
EXPECT_EQ(s_user_data, &data);
}
TEST_F(LogosSdkCTest, RegisterEvent_NullParams)
{
logos_sdk_register_event(nullptr, "evt", testCCallback, nullptr);
EXPECT_FALSE(s_called);
logos_sdk_register_event("mod", nullptr, testCCallback, nullptr);
EXPECT_FALSE(s_called);
logos_sdk_register_event("mod", "evt", nullptr, nullptr);
EXPECT_FALSE(s_called);
}
TEST_F(LogosSdkCTest, Shutdown_SafeToCallMultipleTimes)
{
logos_sdk_shutdown();
logos_sdk_shutdown();
}
TEST_F(LogosSdkCTest, Shutdown_ThenCallRecreatesClient)
{
m_mock->when("mod", "fn").thenReturn(QVariant("first"));
logos_sdk_call_method_async("mod", "fn", "[]", testCCallback, nullptr);
processEvents();
EXPECT_EQ(s_result, 1);
logos_sdk_shutdown();
resetState();
m_mock->when("mod", "fn").thenReturn(QVariant("second"));
logos_sdk_call_method_async("mod", "fn", "[]", testCCallback, nullptr);
processEvents();
EXPECT_EQ(s_result, 1);
EXPECT_TRUE(s_message.find("second") != std::string::npos);
}