Data-driven node types (SVG + port config) loaded from JSON, relation-based connection validation, and a property system supporting string, int, float, enum, catalogue item(s), color and value-list types grouped by category. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
135 lines
5.5 KiB
C++
135 lines
5.5 KiB
C++
#include "TestFixtures.h"
|
|
#include "core/NetworkModel.h"
|
|
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QSignalSpy>
|
|
#include <QTest>
|
|
|
|
using namespace diag;
|
|
|
|
class TestProperties : public QObject {
|
|
Q_OBJECT
|
|
private slots:
|
|
void init()
|
|
{
|
|
fixtures::fillRegistry(m_reg);
|
|
delete m_model;
|
|
m_model = new NetworkModel(&m_reg, this);
|
|
}
|
|
|
|
void nodeProperty_fallsBackToDefault()
|
|
{
|
|
const QUuid src = m_model->addNode(QStringLiteral("source"), {0, 0});
|
|
QCOMPARE(m_model->nodeProperty(src, "supply").toDouble(), 10.0);
|
|
QCOMPARE(m_model->nodeProperty(src, "title").toString(), QString());
|
|
m_model->setNodeProperty(src, "supply", 42.5);
|
|
QCOMPARE(m_model->nodeProperty(src, "supply").toDouble(), 42.5);
|
|
}
|
|
|
|
void edgeProperty_commonAndRelationSpecs()
|
|
{
|
|
const QUuid src = m_model->addNode(QStringLiteral("source"), {0, 0});
|
|
const QUuid pump = m_model->addNode(QStringLiteral("pump"), {200, 0});
|
|
const QUuid e = m_model->addEdge(src, "out", pump, "in");
|
|
|
|
const auto specs = m_reg.edgeProperties(QStringLiteral("water"));
|
|
QStringList ids;
|
|
for (const auto& s : specs)
|
|
ids << s.id;
|
|
// Common presentation specs plus water physics specs.
|
|
for (const char* expected : {"title", "lineStyle", "lineWidth", "color",
|
|
"headDecoration", "tailDecoration", "length", "diameter",
|
|
"flowType", "series"})
|
|
QVERIFY2(ids.contains(QLatin1String(expected)), expected);
|
|
|
|
QCOMPARE(m_model->edgeProperty(e, "lineStyle").toString(), QStringLiteral("Solid"));
|
|
QCOMPARE(m_model->edgeProperty(e, "diameter").toDouble(), 100.0);
|
|
QCOMPARE(m_model->edgeProperty(e, "flowType").toString(), QStringLiteral("Laminar"));
|
|
}
|
|
|
|
void propertyGroups_present()
|
|
{
|
|
const auto specs = m_reg.edgeProperties(QStringLiteral("water"));
|
|
QStringList groups;
|
|
for (const auto& s : specs)
|
|
if (!groups.contains(s.group))
|
|
groups << s.group;
|
|
QVERIFY(groups.contains(QStringLiteral("General")));
|
|
QVERIFY(groups.contains(QStringLiteral("Presentation")));
|
|
QVERIFY(groups.contains(QStringLiteral("Physics")));
|
|
}
|
|
|
|
void allPropertyTypes_storeAndRead()
|
|
{
|
|
const QUuid src = m_model->addNode(QStringLiteral("source"), {0, 0});
|
|
const QUuid pump = m_model->addNode(QStringLiteral("pump"), {200, 0});
|
|
const QUuid e = m_model->addEdge(src, "out", pump, "in");
|
|
|
|
m_model->setNodeProperty(src, "title", QStringLiteral("Main intake")); // String
|
|
m_model->setNodeProperty(src, "tags", QStringList{"district-1", "hp"}); // ValueList
|
|
m_model->setNodeProperty(src, "labelColor", QStringLiteral("#ff8800")); // Color
|
|
m_model->setEdgeProperty(e, "length", 125.5); // Float
|
|
m_model->setEdgeProperty(e, "flowType", QStringLiteral("Turbulent")); // Enum
|
|
m_model->setEdgeProperty(e, "series", QStringLiteral("dn50")); // CatalogueItem
|
|
|
|
QCOMPARE(m_model->nodeProperty(src, "title").toString(), QStringLiteral("Main intake"));
|
|
QCOMPARE(m_model->nodeProperty(src, "tags").toStringList(),
|
|
(QStringList{"district-1", "hp"}));
|
|
QCOMPARE(m_model->nodeProperty(src, "labelColor").toString(), QStringLiteral("#ff8800"));
|
|
QCOMPARE(m_model->edgeProperty(e, "length").toDouble(), 125.5);
|
|
QCOMPARE(m_model->edgeProperty(e, "flowType").toString(), QStringLiteral("Turbulent"));
|
|
QCOMPARE(m_model->edgeProperty(e, "series").toString(), QStringLiteral("dn50"));
|
|
}
|
|
|
|
void catalogue_lookup()
|
|
{
|
|
const Catalogue* c = m_reg.catalogue(QStringLiteral("pipe_series"));
|
|
QVERIFY(c);
|
|
QCOMPARE(c->items.size(), 2);
|
|
const CatalogueItem* dn50 = c->item(QStringLiteral("dn50"));
|
|
QVERIFY(dn50);
|
|
QCOMPARE(dn50->attributes.value(QStringLiteral("diameter")).toInt(), 50);
|
|
QVERIFY(!c->item(QStringLiteral("missing")));
|
|
}
|
|
|
|
void propertySpec_parsesFromJson()
|
|
{
|
|
const auto doc = QJsonDocument::fromJson(R"({
|
|
"id": "materials", "name": "Materials", "group": "Physics",
|
|
"type": "catalogueItems", "catalogue": "pipe_series",
|
|
"default": ["dn50"], "readOnly": false
|
|
})");
|
|
const PropertySpec s = propertySpecFromJson(doc.object());
|
|
QCOMPARE(s.type, PropertyType::CatalogueItems);
|
|
QCOMPARE(s.catalogueId, QStringLiteral("pipe_series"));
|
|
QCOMPARE(s.defaultValue.toStringList(), QStringList{"dn50"});
|
|
|
|
const auto doc2 = QJsonDocument::fromJson(R"({
|
|
"id": "mode", "type": "enum", "values": ["A", "B"], "default": "B",
|
|
"min": 1, "max": 5
|
|
})");
|
|
const PropertySpec s2 = propertySpecFromJson(doc2.object());
|
|
QCOMPARE(s2.enumValues, (QStringList{"A", "B"}));
|
|
QCOMPARE(s2.defaultValue.toString(), QStringLiteral("B"));
|
|
QCOMPARE(s2.min, 1.0);
|
|
QCOMPARE(s2.max, 5.0);
|
|
}
|
|
|
|
void propertyChange_emitsSignal()
|
|
{
|
|
const QUuid src = m_model->addNode(QStringLiteral("source"), {0, 0});
|
|
QSignalSpy spy(m_model, &NetworkModel::nodeChanged);
|
|
m_model->setNodeProperty(src, "title", QStringLiteral("A"));
|
|
m_model->setNodeProperty(src, "title", QStringLiteral("A")); // no-op
|
|
QCOMPARE(spy.count(), 1);
|
|
}
|
|
|
|
private:
|
|
TypeRegistry m_reg;
|
|
NetworkModel* m_model = nullptr;
|
|
};
|
|
|
|
QTEST_GUILESS_MAIN(TestProperties)
|
|
#include "tst_properties.moc"
|