mirror of
https://github.com/logos-co/logos-protocol.git
synced 2026-08-30 21:41:10 +00:00
133 lines
4.4 KiB
C++
133 lines
4.4 KiB
C++
#include <gtest/gtest.h>
|
|||
|
|
|
||
|
|
#include <QJsonObject>
|
||
|
|
#include <QString>
|
||
|
|
#include <QVariant>
|
||
|
|
#include <QVariantList>
|
||
|
|
#include <QVariantMap>
|
||
|
|
|
||
|
|
#include "logos_async_dispatch.h"
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// The pending-call sentinel is in-band: a "multi" provider returns a QVariantMap
|
||
|
|
// carrying the call id under __logos_pending_call__, because the dispatch slot
|
||
|
|
// returns a single QVariant and there is no out-of-band place to say "deferred"
|
||
|
|
// without an ABI break.
|
||
|
|
//
|
||
|
|
// In-band means user data can imitate it. The four detection sites used to test
|
||
|
|
// `m.contains(pendingCallKey())` and nothing else, so ANY map carrying that key
|
||
|
|
// was taken for a deferred call: the consumer waited in a nested event loop for
|
||
|
|
// a completion that never arrives and the call hung for the full timeout. An
|
||
|
|
// `any` slot is enough to reach it.
|
||
|
|
//
|
||
|
|
// These pin the shape check. They do NOT claim the sentinel is unforgeable — a
|
||
|
|
// forgery of the canonical shape is still indistinguishable, because that is the
|
||
|
|
// real thing. See known.json.
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
QVariant canonical(const QString& id)
|
||
|
|
{
|
||
|
|
QVariantMap m;
|
||
|
|
m[logos::pendingCallKey()] = id;
|
||
|
|
return QVariant(m);
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
TEST(PendingSentinel, CanonicalShapeIsRecognisedAndYieldsTheCallId)
|
||
|
|
{
|
||
|
|
QString id;
|
||
|
|
ASSERT_TRUE(logos::isPendingCallSentinel(canonical("lc-7"), &id));
|
||
|
|
EXPECT_EQ(id, QStringLiteral("lc-7"));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(PendingSentinel, CallIdOutParamIsOptional)
|
||
|
|
{
|
||
|
|
EXPECT_TRUE(logos::isPendingCallSentinel(canonical("lc-0")));
|
||
|
|
}
|
||
|
|
|
||
|
|
// The case the conformance matrix measured: user data that merely CONTAINS the
|
||
|
|
// key. Previously hijacked the call; must now pass through as an ordinary map.
|
||
|
|
TEST(PendingSentinel, ExtraKeysMeanItIsOrdinaryUserData)
|
||
|
|
{
|
||
|
|
QVariantMap m;
|
||
|
|
m[logos::pendingCallKey()] = QStringLiteral("lc-1");
|
||
|
|
m[QStringLiteral("x")] = 2;
|
||
|
|
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(QVariant(m)));
|
||
|
|
}
|
||
|
|
|
||
|
|
// echoAny({"__logos_pending_call__": 1, "x": 2}) — the exact matrix payload.
|
||
|
|
TEST(PendingSentinel, MatrixPayloadIsNotASentinel)
|
||
|
|
{
|
||
|
|
QVariantMap m;
|
||
|
|
m[logos::pendingCallKey()] = 1;
|
||
|
|
m[QStringLiteral("x")] = 2;
|
||
|
|
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(QVariant(m)));
|
||
|
|
}
|
||
|
|
|
||
|
|
// A call id is a string. A one-key map whose value is a number is user data.
|
||
|
|
TEST(PendingSentinel, NonStringValueIsNotASentinel)
|
||
|
|
{
|
||
|
|
QVariantMap m;
|
||
|
|
m[logos::pendingCallKey()] = 1;
|
||
|
|
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(QVariant(m)));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(PendingSentinel, EmptyCallIdIsNotASentinel)
|
||
|
|
{
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(canonical(QString())));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(PendingSentinel, WrongKeyIsNotASentinel)
|
||
|
|
{
|
||
|
|
QVariantMap m;
|
||
|
|
m[QStringLiteral("pending")] = QStringLiteral("lc-1");
|
||
|
|
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(QVariant(m)));
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(PendingSentinel, NonMapValuesAreNotSentinels)
|
||
|
|
{
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(QVariant()));
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(QVariant(QStringLiteral("lc-1"))));
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(QVariant(42)));
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(QVariant(QVariantList{1, 2})));
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(QVariant(QVariantMap{})));
|
||
|
|
}
|
||
|
|
|
||
|
|
// The QJsonObject arm mirrors isUnauthorizedSentinel's: some json_convert paths
|
||
|
|
// historically produced QJsonObject rather than QVariantMap.
|
||
|
|
TEST(PendingSentinel, QJsonObjectArmBehavesTheSame)
|
||
|
|
{
|
||
|
|
QJsonObject good;
|
||
|
|
good[logos::pendingCallKey()] = QStringLiteral("lc-2");
|
||
|
|
QString id;
|
||
|
|
ASSERT_TRUE(logos::isPendingCallSentinel(QVariant(good), &id));
|
||
|
|
EXPECT_EQ(id, QStringLiteral("lc-2"));
|
||
|
|
|
||
|
|
QJsonObject extra;
|
||
|
|
extra[logos::pendingCallKey()] = QStringLiteral("lc-2");
|
||
|
|
extra[QStringLiteral("x")] = 2;
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(QVariant(extra)));
|
||
|
|
|
||
|
|
QJsonObject numeric;
|
||
|
|
numeric[logos::pendingCallKey()] = 1;
|
||
|
|
EXPECT_FALSE(logos::isPendingCallSentinel(QVariant(numeric)));
|
||
|
|
}
|
||
|
|
|
||
|
|
// What the guard does NOT do, pinned so nobody reads the green cells above as
|
||
|
|
// "the sentinel is safe". A canonical-shape forgery is the real thing.
|
||
|
|
TEST(PendingSentinel, CanonicalShapeForgeryIsStillIndistinguishable)
|
||
|
|
{
|
||
|
|
QVariantMap forged;
|
||
|
|
forged[logos::pendingCallKey()] = QStringLiteral("lc-0");
|
||
|
|
|
||
|
|
EXPECT_TRUE(logos::isPendingCallSentinel(QVariant(forged)))
|
||
|
|
<< "if this ever fails the in-band design changed — update known.json";
|
||
|
|
}
|