// End-to-end scenarios against the real MainWindow with bundled resources // (registry config, SVGs, sample document), offscreen. #include "app/MainWindow.h" #include "app/PropertyPanel.h" #include "core/FlowSolver.h" #include "core/NetworkModel.h" #include "scene/DiagramScene.h" #include "scene/EdgeItem.h" #include "scene/NodeItem.h" #include #include #include #include #include #include using namespace diag; class TestApp : public QObject { Q_OBJECT private slots: void initTestCase() { Q_INIT_RESOURCE(resources); } void registryLoads_fromBundledConfig() { MainWindow window; const TypeRegistry* reg = window.model()->registry(); QVERIFY(reg->nodeTypes().size() >= 9); QVERIFY(reg->relation(QStringLiteral("water"))); QVERIFY(reg->relation(QStringLiteral("power"))); QVERIFY(reg->catalogue(QStringLiteral("pipe_series"))); QCOMPARE(reg->nodeGroups(), (QStringList{QStringLiteral("Water supply"), QStringLiteral("Power")})); } void sampleLoads_andRoutes() { MainWindow window; window.show(); window.loadSample(); QVERIFY(window.model()->nodeIds().size() >= 8); QVERIFY(window.model()->edgeIds().size() >= 7); // Every edge item has an orthogonal polyline attached to its ports. for (QUuid id : window.model()->edgeIds()) { EdgeItem* item = window.scene()->edgeItem(id); QVERIFY(item); QVERIFY(item->polyline().size() >= 2); } } void selectingEdge_populatesGroupedPropertyPanel() { MainWindow window; window.show(); window.loadSample(); const QUuid edgeId = window.model()->edgeIds().first(); window.scene()->clearSelection(); window.scene()->edgeItem(edgeId)->setSelected(true); auto* panel = window.findChild(); QVERIFY(panel); const auto groups = panel->findChildren(); QStringList titles; for (auto* g : groups) titles << g->title(); QVERIFY(titles.contains(QStringLiteral("General"))); QVERIFY(titles.contains(QStringLiteral("Presentation"))); QVERIFY(titles.contains(QStringLiteral("Physics"))); // Style enums and physics editors exist. QVERIFY(panel->findChildren().size() >= 3); QVERIFY(panel->findChildren().size() >= 2); } void editingTitle_isUndoable() { MainWindow window; window.show(); window.loadSample(); const QUuid nodeId = window.model()->nodeIds().first(); window.scene()->clearSelection(); window.scene()->nodeItem(nodeId)->setSelected(true); auto* panel = window.findChild(); auto* titleEdit = panel->findChild(); QVERIFY(titleEdit); titleEdit->setText(QStringLiteral("Renamed")); emit titleEdit->editingFinished(); QCOMPARE(window.model()->nodeProperty(nodeId, "title").toString(), QStringLiteral("Renamed")); window.scene()->undoStack()->undo(); QCOMPARE(window.model()->nodeProperty(nodeId, "title").toString(), QStringLiteral("Intake")); } void simulation_assignsFlowsAndAnimates() { MainWindow window; window.show(); window.loadSample(); window.scene()->setFlowAnimationEnabled(true); // Solve both networks like the Simulation menu action does. for (const Relation& rel : window.model()->registry()->relations()) FlowSolver::apply(*window.model(), FlowSolver::solve(*window.model(), rel.id)); // Water main from the intake carries the full balanced demand. double maxWater = 0; for (QUuid id : window.model()->edgeIds()) if (window.model()->edge(id)->relation == QLatin1String("water")) maxWater = qMax(maxWater, qAbs(window.model()->edge(id)->flowRate)); QVERIFY(maxWater > 1.0); QVERIFY(window.scene()->maxAbsFlow() >= maxWater); const double phase0 = window.scene()->animationPhase(); QTRY_VERIFY_WITH_TIMEOUT(window.scene()->animationPhase() > phase0, 1000); window.scene()->setFlowAnimationEnabled(false); } void screenshot_rendersWithoutCrash() { MainWindow window; window.resize(1000, 700); window.show(); window.loadSample(); const QPixmap shot = window.grab(); QVERIFY(!shot.isNull()); QVERIFY(shot.width() > 0); } }; QTEST_MAIN(TestApp) #include "tst_app.moc"