#include "ApplicationSetup.hpp"
#include <QtNodes/DataFlowGraphModel>
#include <QtNodes/NodeDelegateModel>
#include <QtNodes/NodeDelegateModelRegistry>
#include <QtNodes/Definitions>
#include <catch2/catch.hpp>
using QtNodes::ConnectionId;
using QtNodes::DataFlowGraphModel;
using QtNodes::InvalidNodeId;
using QtNodes::NodeDelegateModel;
using QtNodes::NodeDelegateModelRegistry;
using QtNodes::NodeId;
using QtNodes::NodeRole;
using QtNodes::PortType;
class TestNodeDelegate : public NodeDelegateModel
{
public:
QString name() const override { return "TestNode"; }
QString caption() const override { return "Test Node"; }
unsigned int nPorts(QtNodes::PortType portType) const override
{
return (portType == PortType::In) ? 2 : 1;
}
QtNodes::NodeDataType dataType(QtNodes::PortType, QtNodes::PortIndex) const override { return {}; }
void setInData(std::shared_ptr<QtNodes::NodeData>, QtNodes::PortIndex const) override {}
std::shared_ptr<QtNodes::NodeData> outData(QtNodes::PortIndex const) override { return nullptr; }
QWidget* embeddedWidget() override { return nullptr; }
};
TEST_CASE("DataFlowGraphModel basic functionality", "[dataflow]")
{
auto app = applicationSetup();
auto registry = std::make_shared<NodeDelegateModelRegistry>();
registry->registerModel<TestNodeDelegate>("TestNode");
DataFlowGraphModel model(registry);
SECTION("Node creation with delegate")
{
CHECK(model.allNodeIds().empty());
NodeId nodeId = model.addNode("TestNode");
CHECK(nodeId != InvalidNodeId);
CHECK(model.nodeExists(nodeId));
CHECK(model.allNodeIds().size() == 1);
CHECK(model.nodeData(nodeId, NodeRole::Type).toString() == "TestNode");
CHECK(model.nodeData(nodeId, NodeRole::Caption).toString() == "Test Node");
CHECK(model.nodeData(nodeId, NodeRole::InPortCount).toUInt() == 2);
CHECK(model.nodeData(nodeId, NodeRole::OutPortCount).toUInt() == 1);
}
SECTION("Invalid node type")
{
NodeId nodeId = model.addNode("NonExistentType");
CHECK(nodeId == InvalidNodeId);
CHECK_FALSE(model.nodeExists(nodeId));
}
SECTION("Registry access")
{
auto retrievedRegistry = model.dataModelRegistry();
CHECK(retrievedRegistry == registry);
CHECK(retrievedRegistry != nullptr);
}
}
TEST_CASE("DataFlowGraphModel connections", "[dataflow]")
{
auto app = applicationSetup();
auto registry = std::make_shared<NodeDelegateModelRegistry>();
registry->registerModel<TestNodeDelegate>("TestNode");
DataFlowGraphModel model(registry);
NodeId node1 = model.addNode("TestNode");
NodeId node2 = model.addNode("TestNode");
SECTION("Valid connection between delegate nodes")
{
ConnectionId connId{node1, 0, node2, 0};
CHECK(model.connectionPossible(connId));
model.addConnection(connId);
CHECK(model.connectionExists(connId));
auto connections = model.connections(node1, PortType::Out, 0);
CHECK(connections.size() == 1);
CHECK(connections.count(connId) == 1);
}
SECTION("Connection validation with port bounds")
{
ConnectionId validConn{node1, 0, node2, 0};
CHECK(model.connectionPossible(validConn));
ConnectionId validConn2{node1, 0, node2, 1};
CHECK(model.connectionPossible(validConn2));
ConnectionId invalidOut{node1, 1, node2, 0};
CHECK_FALSE(model.connectionPossible(invalidOut));
ConnectionId invalidIn{node1, 0, node2, 2};
CHECK_FALSE(model.connectionPossible(invalidIn));
}
SECTION("Loop connection between three nodes")
{
NodeId node3 = model.addNode("TestNode");
ConnectionId connId12{node1, 0, node2, 0};
CHECK(model.connectionPossible(connId12));
model.addConnection(connId12);
CHECK(model.connectionExists(connId12));
ConnectionId connId23{node2, 0, node3, 0};
CHECK(model.connectionPossible(connId23));
model.addConnection(connId23);
CHECK(model.connectionExists(connId23));
ConnectionId connId31{node3, 0, node1, 0};
CHECK_FALSE(model.connectionPossible(connId31));
model.addConnection(connId31);
CHECK(model.connectionExists(connId31));
}
}
TEST_CASE("DataFlowGraphModel serialization support", "[dataflow]")
{
auto app = applicationSetup();
auto registry = std::make_shared<NodeDelegateModelRegistry>();
registry->registerModel<TestNodeDelegate>("TestNode");
DataFlowGraphModel model(registry);
NodeId node1 = model.addNode("TestNode");
NodeId node2 = model.addNode("TestNode");
model.setNodeData(node1, NodeRole::Position, QPointF(0, 0));
model.setNodeData(node2, NodeRole::Position, QPointF(100, 100));
ConnectionId connId{node1, 0, node2, 0};
model.addConnection(connId);
SECTION("Save and load operations exist")
{
QJsonObject nodeJson = model.saveNode(node1);
QJsonObject fullJson = model.save();
CHECK_FALSE(nodeJson.isEmpty());
CHECK_FALSE(fullJson.isEmpty());
CHECK(fullJson.contains("nodes"));
CHECK(fullJson.contains("connections"));
}
}