test(app): add end-to-end scenarios against the real main window
Bundled registry/sample loading, edge selection populating the grouped property panel, undoable title edit, solver + animation clock, and a headless render smoke check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
18289b33e1
commit
4f6fe37b4d
@ -13,3 +13,9 @@ diag_add_test(tst_solver diagcore)
|
|||||||
diag_add_test(tst_json diagcore)
|
diag_add_test(tst_json diagcore)
|
||||||
diag_add_test(tst_undo diagscene)
|
diag_add_test(tst_undo diagscene)
|
||||||
diag_add_test(tst_scene diagscene)
|
diag_add_test(tst_scene diagscene)
|
||||||
|
|
||||||
|
qt_add_resources(TEST_RESOURCES ${CMAKE_SOURCE_DIR}/resources/resources.qrc)
|
||||||
|
add_executable(tst_app tst_app.cpp ${TEST_RESOURCES})
|
||||||
|
target_link_libraries(tst_app PRIVATE diagapp Qt6::Test)
|
||||||
|
add_test(NAME tst_app COMMAND tst_app)
|
||||||
|
set_tests_properties(tst_app PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
|
||||||
|
|||||||
138
tests/tst_app.cpp
Normal file
138
tests/tst_app.cpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// 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 <QComboBox>
|
||||||
|
#include <QDoubleSpinBox>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QTest>
|
||||||
|
#include <QUndoStack>
|
||||||
|
|
||||||
|
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<PropertyPanel*>();
|
||||||
|
QVERIFY(panel);
|
||||||
|
const auto groups = panel->findChildren<QGroupBox*>();
|
||||||
|
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<QComboBox*>().size() >= 3);
|
||||||
|
QVERIFY(panel->findChildren<QDoubleSpinBox*>().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<PropertyPanel*>();
|
||||||
|
auto* titleEdit = panel->findChild<QLineEdit*>();
|
||||||
|
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"
|
||||||
Loading…
x
Reference in New Issue
Block a user