14.31 round 1: the acceptance scenarios check what each row claims; WebP in the window
This commit is contained in:
3 files changed
+52
-23
No files matched your search
+6
-6
@@ -25,7 +25,7 @@ The screenshots come from Qt's offscreen platform, so floating panels appear wit
|
||||
| Layer effects | A 12 px red stroke rings a shape outside its edge, and a drop shadow's sheet shows. The shape keeps its fill. | [07](acceptance/07-effects.png) | `LayerEffectsTests`, `LayerEffectsKernelTests`, `EffectsPanelTests`, `EffectsCanvasTests`, `InnerGlowTests` | pass |
|
||||
| Filters | Dither leaves only black and white dots. Remove Background masks the photo around its subject: the centre stays opaque and a corner turns clear. | [08](acceptance/08-filters-dither.png), [09](acceptance/09-remove-background.png) | `DitherTests`, `FilterTests`, `FinishingFilterTests`, `SubjectRemovalTests`, `RemoveBackgroundTests` | pass |
|
||||
| Crop, trim, canvas size, image size; PNG and JPEG export | Crops to 1000 × 600. Canvas Size widens it to 1400. Trim finds the photo's own 1200 again. Image Size halves it. Exports a PNG through the save panel and a JPEG through its sheet and panel, then reads both back at 600 × 300. | [10](acceptance/10-canvas-size.png), [11](acceptance/11-export-jpeg.png) | `CropTests`, `ImageTrimTests`, `ProjectResizeTests`, `ProjectExportTests`, `JPEGExportTests` | pass |
|
||||
| Imports | Takes JPEG, PNG, TIFF, HEIC, SVG, a layered Photoshop file (it arrives as a folder) and a camera RAW file, which asks how to develop it. That makes eight layers with no import error. | [12](acceptance/12-raw-develop.png), [13](acceptance/13-imports.png) | `ImageImportTests`, `PSDImportTests`, `RawImporterTests`, `RawDevelopTests`, `SVGImportTests` | pass |
|
||||
| Imports | Takes JPEG, PNG, TIFF, WebP (red and clear halves kept), HEIC, SVG, a layered Photoshop file (it arrives as a folder) and a camera RAW file, which asks how to develop it. That makes eight layers with no import error. | [12](acceptance/12-raw-develop.png), [13](acceptance/13-imports.png) | `ImageImportTests`, `PSDImportTests`, `RawImporterTests`, `RawDevelopTests`, `SVGImportTests` | pass |
|
||||
| Open Recent; Keyboard Shortcuts window | Saves a project, and Open Recent lists it. The shortcuts window opens over the editor. | [15](acceptance/15-shortcuts.png) | `OpenRecentTests`, `RecentProjectsCoreTests`, `KeyboardShortcutsTests`, `KeyboardShortcutsSheetTests` | pass |
|
||||
| Scrub a number by its label | Dragging the Opacity title 40 points left lowers the layer's opacity. | [14](acceptance/14-scrub.png) | `NumericScrubTests`, `ScrubbableLabelsTests`, `ScrubbableSheetsTests` | pass |
|
||||
| Keep working while a project saves | Another layer is added while a save runs. The file holds the state the save began with. | — | `ProjectSaveWhileEditingTests` | pass |
|
||||
@@ -60,13 +60,13 @@ The screenshots come from Qt's offscreen platform, so floating panels appear wit
|
||||
|
||||
| Feature | What the run checks | Screenshot | Suites that hold the details | Result |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Search Commands and Rotate Canvas 90° | Ctrl+F, "rotate canvas clockwise" and Return turn a 1200 × 800 photo to 800 × 1200, one undo step. | [19](acceptance/19-search.png) | `CommandPaletteTests`, `CommandPaletteWindowTests`, `CanvasRotationTests` | pass |
|
||||
| Search Commands and Rotate Canvas 90° | Ctrl+F, "rotate canvas clockwise" and Return turn a 1200 × 800 photo to 800 × 1200, one undo step; the new top left holds the old bottom left's pixels. | [19](acceptance/19-search.png) | `CommandPaletteTests`, `CommandPaletteWindowTests`, `CanvasRotationTests` | pass |
|
||||
| Toggle Fullscreen | F puts the menus and toolbar away over the whole screen; Escape brings them back. | — | `CanvasOnlyWindowTests`, `CanvasOnlySessionTests` | pass |
|
||||
| Last Filter | After a Gaussian Blur, Filter › Last Filter is titled for it and blurs again as one more step, without its panel. | — | `LastFilterTests` | pass |
|
||||
| Last Filter | After a Gaussian Blur of radius 3 typed in its sheet, Filter › Last Filter is titled for it and blurs again as one more step, without its panel, to the same pixels the sheet makes at radius 3. | — | `LastFilterTests` | pass |
|
||||
| Camera Raw as Photoshop's | Temperature +100 typed into the docked panel turns mid gray to Photoshop's own warm (235, 189, 117), within four levels. | [20](acceptance/20-camera-raw.png) | `CameraRawTests`, `CameraRawTablesTests`, `CameraRawFoldTests` | pass |
|
||||
| Navigator and Ctrl with the middle button | At 400% the minimap shows in the corner; a click at its edge moves the view there. Ctrl with the middle button dragged up 100 points doubles the zoom. | [21](acceptance/21-navigator.png) | `NavigatorTests`, `CanvasNavigationTests` | pass |
|
||||
| New Canvas in units, DPI and background | The blank start tab has no close button and Close Project leaves it. Inches, 300 DPI and White make a 2 × 1 inch canvas of 600 × 300 white pixels at 300 DPI. | — | `NewCanvasUnitTests`, `NewCanvasSheetTests`, `ProjectTabStripTests` | pass |
|
||||
| Export As PDF | Export As in PDF writes a one-page PDF 1.4 whose page is 144 × 72 points, two inches by one. | [22](acceptance/22-export-as.png) | `ExportPDFTests`, `ExportAsSheetTests`, `ProjectExportTests` | pass |
|
||||
| Navigator and Ctrl with the middle button | At 400% the minimap shows in the corner; a click at its edge centres the view on the document point under it, both ways. Ctrl with the middle button dragged up 100 points doubles the zoom. | [21](acceptance/21-navigator.png) | `NavigatorTests`, `CanvasNavigationTests` | pass |
|
||||
| New Canvas in units, DPI and background | The blank start tab has no close button and Close Project leaves that very tab. Inches, 300 DPI and White make a 2 × 1 inch canvas of 600 × 300 white pixels at 300 DPI. | — | `NewCanvasUnitTests`, `NewCanvasSheetTests`, `ProjectTabStripTests` | pass |
|
||||
| Export As PDF | File › Export As, PDF chosen in the sheet, writes a one-page PDF 1.4 whose page is 144 × 72 points, two inches by one. | [22](acceptance/22-export-as.png) | `ExportPDFTests`, `ExportAsSheetTests`, `ProjectExportTests` | pass |
|
||||
|
||||
## Known differences from Compositor
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "DialogDesk.h"
|
||||
#include "UI/ExportAsSheet.h"
|
||||
#include "UI/NewCanvasSheet.h"
|
||||
#include "Rendering/NavigatorGeometry.h"
|
||||
#include <QAbstractButton>
|
||||
#include <QLineEdit>
|
||||
#include <QMenuBar>
|
||||
@@ -55,6 +56,7 @@ 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<QLineEdit>(app.window, QStringLiteral("commandSearch"));
|
||||
@@ -62,6 +64,11 @@ void AcceptanceLatestTests::searchRotateAndFullscreen()
|
||||
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();
|
||||
@@ -76,10 +83,14 @@ void AcceptanceLatestTests::searchRotateAndFullscreen()
|
||||
void AcceptanceLatestTests::lastFilterAndCameraRaw()
|
||||
{
|
||||
App app;
|
||||
const QUuid layer = photo(app);
|
||||
// Gaussian Blur once, then Last Filter repeats it.
|
||||
photo(app);
|
||||
// Gaussian Blur at radius 3; Last Filter repeats it.
|
||||
app.action("gaussianBlur").trigger();
|
||||
shownChild<QPushButton>(app.window, QStringLiteral("filterOK")).click();
|
||||
QLineEdit &radius = shownChild<QLineEdit>(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();
|
||||
@@ -87,6 +98,14 @@ void AcceptanceLatestTests::lastFilterAndCameraRaw()
|
||||
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<QLineEdit>(app.window, QStringLiteral("radiusField")).text(), QString("3"));
|
||||
shownChild<QPushButton>(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);
|
||||
@@ -106,7 +125,6 @@ void AcceptanceLatestTests::lastFilterAndCameraRaw()
|
||||
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()));
|
||||
static_cast<void>(layer);
|
||||
}
|
||||
|
||||
void AcceptanceLatestTests::navigatorAndMiddleZoom()
|
||||
@@ -117,10 +135,13 @@ void AcceptanceLatestTests::navigatorAndMiddleZoom()
|
||||
app.action("navigator").trigger();
|
||||
app.session().zoom(4, app.session().viewport.center());
|
||||
QWidget &minimap = shownChild<QWidget>(app.window, QStringLiteral("navigatorMinimap"));
|
||||
const QRectF before = app.session().viewport.visibleDocumentRect(QSizeF(1200, 800));
|
||||
QTest::mouseClick(&minimap, Qt::LeftButton, Qt::NoModifier, QPoint(4, 4));
|
||||
const QRectF after = app.session().viewport.visibleDocumentRect(QSizeF(1200, 800));
|
||||
QVERIFY2(after.center().x() < before.center().x() - 100, qPrintable(QString::number(after.center().x())));
|
||||
// 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.
|
||||
@@ -140,9 +161,10 @@ void AcceptanceLatestTests::newCanvasExportAndTabs()
|
||||
// The blank start tab has no cross; Close leaves it.
|
||||
QToolButton *cross = app.window.findChild<QToolButton *>(QStringLiteral("closeTab"));
|
||||
QVERIFY(cross && cross->isHidden());
|
||||
const QUuid start = app.workspace.current().id;
|
||||
app.action("closeProject").trigger();
|
||||
QTest::qWait(100);
|
||||
QCOMPARE(int(app.workspace.tabs().size()), 1);
|
||||
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<NewCanvasSheet>(app.window, QString());
|
||||
QAbstractButton &unit = shownChild<QAbstractButton>(sheet, QStringLiteral("canvasUnit"));
|
||||
@@ -165,16 +187,16 @@ void AcceptanceLatestTests::newCanvasExportAndTabs()
|
||||
QCOMPARE(app.session().document().value().resolution, 300.0);
|
||||
QCOMPARE(app.shown(300, 150), QColor(Qt::white));
|
||||
QTRY_VERIFY(!cross->isHidden());
|
||||
// Export As a one-page PDF, two inches by one.
|
||||
// File › Export As, PDF chosen: two inches by one.
|
||||
DialogDesk desk;
|
||||
desk.replies = {app.path("page.pdf")};
|
||||
bool done = false;
|
||||
app.workspace.current().controller.exportAs(ExportFormat::pdf, [&done] { done = true; });
|
||||
app.action("exportAs").trigger();
|
||||
shownChild<QAbstractButton>(app.window, QStringLiteral("exportFormatPDF")).click();
|
||||
QPushButton &exporting = shownChild<QPushButton>(app.window, QStringLiteral("exportExport"));
|
||||
QTRY_VERIFY(exporting.isEnabled());
|
||||
QTRY_VERIFY(shownChild<QWidget>(app.window, QStringLiteral("exportPage")).isVisible() && exporting.isEnabled());
|
||||
app.shot(QStringLiteral("22-export-as"));
|
||||
exporting.click();
|
||||
QTRY_VERIFY_WITH_TIMEOUT(done, 30000);
|
||||
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();
|
||||
|
||||
@@ -106,6 +106,11 @@ void AcceptanceProjectTests::imports()
|
||||
QVERIFY(scene(200, 150).save(app.path("Scene.jpg")));
|
||||
QVERIFY(scene(200, 150).save(app.path("Scene.png")));
|
||||
QVERIFY(scene(200, 150).save(app.path("Scene.tif")));
|
||||
// WebP, lossless: red on the left, clear on the right.
|
||||
QImage half(40, 20, QImage::Format_ARGB32);
|
||||
half.fill(Qt::transparent);
|
||||
QPainter(&half).fillRect(QRect(0, 0, 20, 20), QColor(200, 20, 20));
|
||||
QVERIFY(half.save(app.path("Half.webp"), "webp", 100));
|
||||
QVERIFY(QFile::copy(QFINDTESTDATA("fixtures/red.heic"), app.path("Red.heic")));
|
||||
QFile svg(app.path("Mark.svg"));
|
||||
QVERIFY(svg.open(QIODevice::WriteOnly));
|
||||
@@ -118,7 +123,7 @@ void AcceptanceProjectTests::imports()
|
||||
psd.close();
|
||||
DNGFixture::write(app.path("Gray.dng"), {});
|
||||
QList<QUrl> urls;
|
||||
for (const char *name : {"Scene.jpg", "Scene.png", "Scene.tif", "Red.heic", "Mark.svg", "Trip.psd", "Gray.dng"})
|
||||
for (const char *name : {"Scene.jpg", "Scene.png", "Scene.tif", "Half.webp", "Red.heic", "Mark.svg", "Trip.psd", "Gray.dng"})
|
||||
urls << QUrl::fromLocalFile(app.path(QString::fromLatin1(name)));
|
||||
bool done = false;
|
||||
app.session().importImages(urls, std::nullopt, [&done] { done = true; });
|
||||
@@ -132,10 +137,12 @@ void AcceptanceProjectTests::imports()
|
||||
for (const ImageLayer &layer : app.session().document().value().layers)
|
||||
names << layer.name;
|
||||
// A layered Photoshop file arrives as a folder of layers.
|
||||
QCOMPARE(names, (QStringList{"Scene", "Scene", "Scene", "Red", "Mark", "Trip", "Sky", "Gray"}));
|
||||
QCOMPARE(names, (QStringList{"Scene", "Scene", "Scene", "Half", "Red", "Mark", "Trip", "Sky", "Gray"}));
|
||||
const std::vector<ImageLayer> &layers = app.session().document().value().layers;
|
||||
QVERIFY(layers[5].isGroup);
|
||||
QCOMPARE(layers[6].parentID, std::optional<QUuid>(layers[5].id));
|
||||
QVERIFY(layers[6].isGroup);
|
||||
QCOMPARE(layers[7].parentID, std::optional<QUuid>(layers[6].id));
|
||||
const QImage webp = layers[3].asset.value().image();
|
||||
QVERIFY(webp.size() == QSize(40, 20) && webp.pixelColor(5, 10) == QColor(200, 20, 20) && webp.pixelColor(35, 10).alpha() == 0);
|
||||
app.shot(QStringLiteral("13-imports"));
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user