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_undo 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