Files
OmaPhoto/tests/ProjectResizeTests.cpp

240 lines
9.9 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "DialogDesk.h"
#include "IO/ProjectController.h"
#include "UI/CanvasSizeSheet.h"
#include "UI/ColorPaletteControls.h"
#include "UI/ColorPickerSheet+Dialog.h"
#include "UI/ColorPickerSheet.h"
#include "UI/GridSettingsSheet.h"
#include <QComboBox>
#include "UI/ImageSizeSheet.h"
#include <QDialog>
#include <QPushButton>
#include <QtTest>
// The controller's Canvas Size and Image Size: sheet, resize, step.
class ProjectResizeTests : public QObject {
Q_OBJECT
private slots:
void theCanvasSizeSheetResizesTheCanvasAsOneStep();
void aCancelledOrRefusedSheetChangesNothing();
void theImageSizeSheetScalesThePixelsAsOneStep();
void aResizeThatFailsIsExplained();
void theSheetsColourOpensTheAppsPickerOverIt();
void gridSettingsPreviewsThenKeepsOrPutsBack();
};
namespace {
struct Desk {
EditorSession session;
ProjectController controller{session};
QWidget window;
bool done = false;
Desk()
{
session.createDocument(100, 50);
session.insert(ImportedImage(QImage(10, 10, QImage::Format_RGBA8888_Premultiplied), QImage(), "Image"), QPointF(45, 25));
window.resize(600, 400);
window.show();
controller.window = &window;
}
QDialog &dialog()
{
auto *shown = window.findChild<QDialog *>();
if (!shown)
throw std::runtime_error("no sheet shown");
return *shown;
}
// Typed, then Return: the field commits, then the default button.
void type(const char *name, const QString &text)
{
auto *field = dialog().findChild<PickerField *>(QString::fromLatin1(name));
if (!field)
throw std::runtime_error(std::string("no field named ") + name);
field->setFocus();
field->selectAll();
QTest::keyClicks(field, text);
QTest::keyClick(field, Qt::Key_Return);
}
std::function<void()> finished()
{
done = false;
return [this] { done = true; };
}
};
}
void ProjectResizeTests::theCanvasSizeSheetResizesTheCanvasAsOneStep()
{
Desk desk;
const int steps = desk.session.history.undoCount();
desk.controller.canvasSize(desk.finished());
// The sheet holds the window; the project is busy meanwhile.
QVERIFY(desk.session.isProjectBusy());
QCOMPARE(desk.dialog().windowTitle(), QString("Canvas Size"));
QVERIFY(desk.dialog().isVisible() && desk.dialog().windowModality() == Qt::WindowModal);
QCOMPARE(desk.dialog().minimumSize(), desk.dialog().maximumSize());
QVERIFY(desk.dialog().findChild<CanvasSizeSheet *>());
desk.type("canvasWidth", "200");
QTRY_VERIFY(desk.done);
QCOMPARE(desk.session.document().value().width, 200);
QCOMPARE(desk.session.document().value().height, 50);
// Centred: the layer moves half the growth to the right.
QCOMPARE(desk.session.activeLayer().value().origin(), QPointF(90, 20));
QCOMPARE(desk.session.history.undoCount(), steps + 1);
QCOMPARE(desk.session.history.undoName(), QString("Canvas Size"));
QVERIFY(!desk.session.isProjectBusy());
QTRY_VERIFY(!desk.window.findChild<QDialog *>());
}
void ProjectResizeTests::aCancelledOrRefusedSheetChangesNothing()
{
Desk desk;
const CanvasDocument before = desk.session.document().value();
// Escape and Cancel close the sheet; the project frees.
desk.controller.canvasSize(desk.finished());
QTest::keyClick(&desk.dialog(), Qt::Key_Escape);
QTRY_VERIFY(desk.done);
QVERIFY(!desk.session.isProjectBusy());
desk.controller.imageSize(desk.finished());
desk.dialog().findChild<QPushButton *>(QStringLiteral("imageCancel"))->click();
QTRY_VERIFY(desk.done);
QVERIFY(desk.session.document().value() == before);
QVERIFY(!desk.session.isProjectBusy());
QTRY_VERIFY(!desk.window.findChild<QDialog *>());
// Busy, or without a window, no sheet opens.
desk.session.setIsProjectBusy(true);
desk.controller.canvasSize(desk.finished());
QTRY_VERIFY(desk.done);
QVERIFY(!desk.window.findChild<QDialog *>());
desk.session.setIsProjectBusy(false);
desk.controller.window = nullptr;
desk.controller.imageSize(desk.finished());
QTRY_VERIFY(desk.done);
desk.controller.canvasSize(desk.finished());
QTRY_VERIFY(desk.done);
QVERIFY(!desk.session.isProjectBusy());
QVERIFY(desk.session.document().value() == before);
}
void ProjectResizeTests::theImageSizeSheetScalesThePixelsAsOneStep()
{
Desk desk;
desk.controller.imageSize(desk.finished());
QCOMPARE(desk.dialog().windowTitle(), QString("Image Size"));
QVERIFY(desk.dialog().findChild<ImageSizeSheet *>());
desk.type("imageWidth", "50");
QTRY_VERIFY(desk.done);
QCOMPARE(desk.session.document().value().width, 50);
QCOMPARE(desk.session.document().value().height, 25);
QCOMPARE(desk.session.activeLayer().value().transform.size, QSizeF(5, 5));
QCOMPARE(desk.session.history.undoName(), QString("Image Size"));
QVERIFY(!desk.session.isProjectBusy());
}
void ProjectResizeTests::aResizeThatFailsIsExplained()
{
Desk desk;
// Stretched past what twice the size may hold.
LayerTransform wide = desk.session.activeLayer().value().transform;
wide.size = QSizeF(20'000, 10);
desk.session.beginTransform();
desk.session.previewTransform(wide);
desk.session.commitTransform();
const CanvasDocument before = desk.session.document().value();
DialogDesk alerts;
alerts.replies = {"OK"};
alerts.note = [&] { return QStringLiteral("busy %1").arg(desk.session.isProjectBusy()); };
desk.controller.imageSize(desk.finished());
desk.type("imageWidth", "200");
QTRY_VERIFY(desk.done);
QCOMPARE(alerts.seen, (QStringList{QStringLiteral("alert|2|Couldn’t resize the image|%1|OK|busy 1")
.arg(QString::fromUtf8(ProjectError(ProjectError::Kind::tooLarge).what()))}));
QVERIFY(desk.session.document().value() == before);
QVERIFY(!desk.session.isProjectBusy());
// The canvas's own failure, alike, under its own title.
alerts.replies = {"OK"};
wide.origin = QPointF(999'000, 0);
wide.size = QSizeF(10, 10);
desk.session.beginTransform();
desk.session.previewTransform(wide);
desk.session.commitTransform();
desk.controller.canvasSize(desk.finished());
desk.type("canvasWidth", "5000");
QTRY_VERIFY(desk.done);
QCOMPARE(alerts.seen.size(), 2);
QVERIFY(alerts.seen.last().startsWith("alert|2|Couldn’t change canvas size|"));
}
void ProjectResizeTests::theSheetsColourOpensTheAppsPickerOverIt()
{
Desk desk;
new ColorPaletteControls(desk.session, &desk.window);
desk.controller.canvasSize(desk.finished());
auto &extension = *desk.dialog().findChild<QComboBox *>(QStringLiteral("canvasExtension"));
extension.setCurrentIndex(5);
emit extension.activated(5);
desk.dialog().findChild<DialogColorSwatch *>()->click();
// The panel sits over the sheet and takes the keys.
QWidget *panel = nullptr;
QTRY_VERIFY((panel = desk.dialog().findChild<QDialog *>(ColorPickerPanelController::identifier())) && panel->isVisible());
QTRY_COMPARE(QApplication::activeWindow(), panel);
desk.session.setColorPickerHSB(PickerHSB(PaletteColor{0, 0, 1}));
// Escape there cancels the picker; the sheet stays.
QTest::keyClick(panel, Qt::Key_Escape);
QTRY_VERIFY(!desk.session.colorPicker() && !panel->isVisible());
QVERIFY(desk.dialog().isVisible() && !desk.done);
desk.dialog().findChild<DialogColorSwatch *>()->click();
QTRY_VERIFY(panel->isVisible());
desk.session.setColorPickerHSB(PickerHSB(PaletteColor{0, 0, 1}));
panel->findChild<QPushButton *>(QStringLiteral("pickerOK"))->click();
QVERIFY(!desk.session.colorPicker());
desk.type("canvasWidth", "200");
QTRY_VERIFY(desk.done);
// The added canvas takes the colour picked.
const ImageLayer bottom = desk.session.document().value().layers.front();
QCOMPARE(bottom.asset.value().image().pixelColor(0, 25), QColor(0, 0, 255));
QVERIFY(!desk.session.isProjectBusy());
}
void ProjectResizeTests::gridSettingsPreviewsThenKeepsOrPutsBack()
{
Desk desk;
QVERIFY(!desk.session.showsGrid() && !desk.session.isProjectBusy());
const int steps = desk.session.history.undoCount();
desk.controller.gridSettings(desk.finished());
// The grid shows while the sheet is open; nothing busy.
QVERIFY(desk.session.showsGrid() && !desk.session.isProjectBusy());
QVERIFY(desk.dialog().windowTitle() == "Grid" && desk.dialog().windowModality() == Qt::WindowModal);
auto &preset = *desk.dialog().findChild<QComboBox *>(QStringLiteral("gridPreset"));
preset.setCurrentIndex(7);
emit preset.activated(7);
QCOMPARE(desk.session.gridAppearance().preset, GridAppearance::Preset::cyan);
// Another sheet waits for this one.
bool refused = false;
desk.controller.gridSettings([&refused] { refused = true; });
QTRY_VERIFY(refused);
QCOMPARE(desk.window.findChildren<GridSettingsSheet *>().size(), 1);
// Cancel puts back the look and the hidden grid.
QTest::keyClick(&desk.dialog(), Qt::Key_Escape);
QTRY_VERIFY(desk.done);
QVERIFY(desk.session.gridAppearance() == GridAppearance() && !desk.session.showsGrid() && desk.session.history.undoCount() == steps);
QTRY_VERIFY(!desk.window.findChild<QDialog *>());
// OK keeps what was set, shown grid or not.
desk.session.setShowsGrid(true);
desk.controller.gridSettings(desk.finished());
auto &again = *desk.dialog().findChild<QComboBox *>(QStringLiteral("gridPreset"));
again.setCurrentIndex(7);
emit again.activated(7);
desk.type("gridSpacing", "100");
QTRY_VERIFY(desk.done);
QVERIFY(desk.session.layoutGrid() == LayoutGrid(100, 8) && desk.session.showsGrid());
QCOMPARE(desk.session.gridAppearance().preset, GridAppearance::Preset::cyan);
// Without a window, nothing opens.
desk.controller.window = nullptr;
desk.controller.gridSettings(desk.finished());
QTRY_VERIFY(desk.done);
}
QTEST_MAIN(ProjectResizeTests)
#include "ProjectResizeTests.moc"