#include "AcceptanceFixtures.h" #include "DialogDesk.h" #include "UI/ExportAsSheet.h" #include "UI/NewCanvasSheet.h" #include "Rendering/NavigatorGeometry.h" #include #include #include #include #include #include // The acceptance run, part seven: 1.4.6 to 1.4.9. class AcceptanceLatestTests : public QObject { Q_OBJECT private slots: void initTestCase() { QStandardPaths::setTestModeEnabled(true); } void searchRotateAndFullscreen(); void lastFilterAndCameraRaw(); void navigatorAndMiddleZoom(); void newCanvasExportAndTabs(); }; namespace { QUuid photo(App &app) { if (!scene(1200, 800).save(app.path("photo.png"))) throw std::runtime_error("the photo could not be written"); app.session().createDocument(1200, 800); app.importFile(app.path("photo.png")); return app.session().activeLayerID().value(); } // A shown widget of that name, once its panel shows. template Widget &shownChild(QWidget &root, const QString &name) { Widget *shown = nullptr; static_cast(QTest::qWaitFor([&] { for (Widget *each : root.findChildren(name)) if (each->isVisible()) shown = each; return shown != nullptr; }, 5000)); if (!shown) throw std::runtime_error("no shown " + name.toStdString()); return *shown; } QSize documentSize(App &app) { return app.session().document().value().size().toSize(); } } void AcceptanceLatestTests::searchRotateAndFullscreen() { App app; photo(app); const int steps = app.session().history.undoCount(); // Ctrl+F finds Rotate Canvas 90° Clockwise by words. QTest::keyClick(&app.window, Qt::Key_F, Qt::ControlModifier); QLineEdit &search = shownChild(app.window, QStringLiteral("commandSearch")); QTest::keyClicks(&search, QStringLiteral("rotate canvas clockwise")); QTest::keyClick(&search, Qt::Key_Return); QTRY_COMPARE(documentSize(app), QSize(800, 1200)); QCOMPARE(app.session().history.undoName(), QString("Rotate Canvas 90° Clockwise")); QCOMPARE(app.session().history.undoCount(), steps + 1); // Clockwise: the new top left was the old bottom left. const QImage old = scene(1200, 800); QCOMPARE(app.shown(100, 50), old.pixelColor(50, 799 - 100)); QCOMPARE(app.shown(700, 1100), old.pixelColor(1100, 799 - 700)); app.shot(QStringLiteral("19-search")); // F: the canvas alone, bars away; Escape brings them back. app.canvas().setFocus(); QTest::keyClick(&app.canvas(), Qt::Key_F); QTRY_VERIFY(app.window.isFullScreen()); QVERIFY(app.window.menuBar()->isHidden() && app.window.findChild()->isHidden()); QTest::keyClick(&app.canvas(), Qt::Key_Escape); QTRY_VERIFY(!app.window.isFullScreen()); QVERIFY(!app.window.menuBar()->isHidden() && !app.window.findChild()->isHidden()); } void AcceptanceLatestTests::lastFilterAndCameraRaw() { App app; photo(app); // Gaussian Blur at radius 3; Last Filter repeats it. app.action("gaussianBlur").trigger(); QLineEdit &radius = shownChild(app.window, QStringLiteral("radiusField")); radius.setFocus(); radius.selectAll(); QTest::keyClicks(&radius, QStringLiteral("3")); QTest::keyClick(&radius, Qt::Key_Return); QTRY_VERIFY(!app.session().filterEdit() && !app.session().isProjectBusy()); QCOMPARE(app.action("lastFilter").text(), QString("Last Filter: Gaussian Blur")); const int steps = app.session().history.undoCount(); app.action("lastFilter").trigger(); QTRY_COMPARE(app.session().history.undoCount(), steps + 1); QCOMPARE(app.session().history.undoName(), QString("Gaussian Blur")); QVERIFY(!app.session().filterEdit()); const QImage repeated = app.session().activeLayer().value().asset.value().image(); // The sheet again, as it opens, blurs the same. app.action("undo").trigger(); app.action("gaussianBlur").trigger(); QCOMPARE(shownChild(app.window, QStringLiteral("radiusField")).text(), QString("3")); shownChild(app.window, QStringLiteral("filterOK")).click(); QTRY_VERIFY(!app.session().filterEdit() && !app.session().isProjectBusy()); QVERIFY(app.session().activeLayer().value().asset.value().image() == repeated); // Camera Raw's Temperature +100 on mid gray, as Photoshop's. app.session().createDocument(64, 64); QImage gray(64, 64, QImage::Format_RGB32); gray.fill(QColor(128, 128, 128)); QVERIFY(gray.save(app.path("gray.png"))); app.importFile(app.path("gray.png")); app.action("cameraRawFilter").trigger(); QLineEdit &temperature = shownChild(app.window, QStringLiteral("temperatureField")); temperature.setFocus(); temperature.selectAll(); QTest::keyClicks(&temperature, QStringLiteral("100")); // Return takes the number and goes on to OK. QTest::keyClick(&temperature, Qt::Key_Return); QTRY_VERIFY(!app.session().filterEdit() && !app.session().isProjectBusy()); QCOMPARE(app.session().history.undoName(), QString("Camera Raw Filter")); app.shot(QStringLiteral("20-camera-raw")); QCOMPARE(app.session().history.undoName(), QString("Camera Raw Filter")); const QColor warm = app.shown(32, 32); QVERIFY2(std::abs(warm.red() - 235) <= 4 && std::abs(warm.green() - 189) <= 4 && std::abs(warm.blue() - 117) <= 4, qPrintable(warm.name())); } void AcceptanceLatestTests::navigatorAndMiddleZoom() { App app; photo(app); // From 300% the Navigator shows; a click moves the view. app.action("navigator").trigger(); app.session().zoom(4, app.session().viewport.center()); QWidget &minimap = shownChild(app.window, QStringLiteral("navigatorMinimap")); QTest::mouseClick(&minimap, Qt::LeftButton, Qt::NoModifier, QPoint(4, 4)); // The view's middle on the document point under the click. const QPointF target = NavigatorGeometry{QSizeF(1200, 800), QSizeF(minimap.size())}.documentPoint(QPointF(4, 4)); const QPointF middle = app.session().viewport.visibleDocumentRect(QSizeF(1200, 800)).center(); QVERIFY2(std::abs(middle.x() - target.x()) < 1 && std::abs(middle.y() - target.y()) < 1, qPrintable(QStringLiteral("%1,%2 %3,%4").arg(middle.x()).arg(middle.y()).arg(target.x()).arg(target.y()))); QVERIFY(target.x() < 300 && target.y() < 200); app.shot(QStringLiteral("21-navigator")); app.action("navigator").trigger(); // Ctrl with the middle button: a hundred points up doubles. app.session().zoom(1, app.session().viewport.center()); const QPoint start = app.at(QPointF(600, 400)); QTest::mousePress(&app.canvas(), Qt::MiddleButton, Qt::ControlModifier, start); const QPointF up = start - QPointF(0, 100); QMouseEvent event(QEvent::MouseMove, up, up, app.canvas().mapToGlobal(up.toPoint()), Qt::NoButton, Qt::MiddleButton, Qt::ControlModifier); QApplication::sendEvent(&app.canvas(), &event); QTest::mouseRelease(&app.canvas(), Qt::MiddleButton, Qt::ControlModifier, up.toPoint()); QCOMPARE(app.session().viewport.zoom(), 2.0); } void AcceptanceLatestTests::newCanvasExportAndTabs() { App app; // The blank start tab has no cross; Close leaves it. QToolButton *cross = app.window.findChild(QStringLiteral("closeTab")); QVERIFY(cross && cross->isHidden()); const QUuid start = app.workspace.current().id; app.action("closeProject").trigger(); QTest::qWait(100); QVERIFY(app.workspace.tabs().size() == 1 && app.workspace.selectedID() == start && app.workspace.tabs()[0]->id == start); // New Canvas: two by one inches, 300 DPI, white. NewCanvasSheet &sheet = shownChild(app.window, QString()); QAbstractButton &unit = shownChild(sheet, QStringLiteral("canvasUnit")); while (!unit.text().contains(QStringLiteral("Inches"))) unit.click(); QAbstractButton &dpi = shownChild(sheet, QStringLiteral("canvasResolution")); while (!dpi.text().startsWith(QStringLiteral("300"))) dpi.click(); QAbstractButton &ground = shownChild(sheet, QStringLiteral("canvasBackground")); while (!ground.text().startsWith(QStringLiteral("White"))) ground.click(); QLineEdit &width = shownChild(sheet, QStringLiteral("widthInput")); QLineEdit &height = shownChild(sheet, QStringLiteral("heightInput")); width.selectAll(); QTest::keyClicks(&width, QStringLiteral("2")); height.selectAll(); QTest::keyClicks(&height, QStringLiteral("1")); shownChild(sheet, QStringLiteral("createCanvas")).click(); QTRY_COMPARE(documentSize(app), QSize(600, 300)); QCOMPARE(app.session().document().value().resolution, 300.0); QCOMPARE(app.shown(300, 150), QColor(Qt::white)); QTRY_VERIFY(!cross->isHidden()); // File › Export As, PDF chosen: two inches by one. DialogDesk desk; desk.replies = {app.path("page.pdf")}; app.action("exportAs").trigger(); shownChild(app.window, QStringLiteral("exportFormatPDF")).click(); QPushButton &exporting = shownChild(app.window, QStringLiteral("exportExport")); QTRY_VERIFY(shownChild(app.window, QStringLiteral("exportPage")).isVisible() && exporting.isEnabled()); app.shot(QStringLiteral("22-export-as")); exporting.click(); QTRY_VERIFY_WITH_TIMEOUT(QFileInfo::exists(app.path("page.pdf")) && !app.session().isProjectBusy(), 30000); QFile pdf(app.path("page.pdf")); QVERIFY(pdf.open(QIODevice::ReadOnly)); const QByteArray bytes = pdf.readAll(); QVERIFY(bytes.startsWith("%PDF-1.4") && bytes.contains("/MediaBox [0 0 144.0000 72.0000]")); } QTEST_MAIN(AcceptanceLatestTests) #include "AcceptanceLatestTests.moc"