tests: Add image checking for graphical tests

Add image checking from saved image references as a way to check that
the generated pixmaps are consistent from run to run.

Fixes: #732

Signed-off-by: Christophe de Dinechin <christophe@dinechin.org>
This commit is contained in:
Christophe de Dinechin 2024-01-17 00:16:51 +01:00
parent ae4a9517a2
commit 6cffed9615
42 changed files with 101 additions and 36 deletions

1
images/bad/README.md Normal file
View file

@ -0,0 +1 @@
This directory contains the output of failed graphic tests

BIN
images/barplot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
images/circles-complex.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

BIN
images/circles-fill.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
images/circles.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
images/cleanup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 945 B

BIN
images/clip-circles.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
images/cllcd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 B

BIN
images/ellipses-fill.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
images/ellipses.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
images/line-width-gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
images/line-width.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 B

BIN
images/lines.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
images/plot-eq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
images/plot-pgm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
images/plot-sine.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
images/polar-eq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
images/polar-pgm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
images/polar-zoomx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
images/polar-zoomxy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
images/polar-zoomy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
images/pplot-deg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

BIN
images/pplot-eq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
images/pplot-pgm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
images/rectangle-fill.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
images/rectangles.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
images/scatterplot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
images/text-compat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
images/text-font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
images/text-frac.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
images/text-gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
images/text-invert.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
images/text-normal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
images/text-pixrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
images/text-pixxy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
images/text-xy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -43,6 +43,7 @@
#include "sim-rpl.h"
#include "ui_sim-window.h"
#include "recorder.h"
#include "tests.h"
RECORDER(sim_keys, 16, "Recorder keys from the simulator");
@ -528,3 +529,24 @@ bool MainWindow::eventFilter(QObject * obj, QEvent * ev)
return false;
}
bool tests::image_match(cstring file, bool force)
// ----------------------------------------------------------------------------
// Check if the screen matches a given file
// ----------------------------------------------------------------------------
{
QPixmap &screen = MainWindow::theScreen();
QPixmap data;
QString name = force ? "images/bad/" : "images/";
name += file;
name += ".png";
QFileInfo reference(name);
if (force || !reference.exists() || !data.load(name, "PNG"))
{
screen.save(name, "PNG");
return true;
}
return data.toImage() == screen.toImage();
}

View file

@ -84,7 +84,9 @@ public:
~MainWindow();
void pushKey(int key);
QPixmap &screen() { return ui.screen->mainPixmap; }
static MainWindow * theMainWindow() { return mainWindow; }
static QPixmap & theScreen() { return mainWindow->screen(); }
protected:
virtual void keyPressEvent(QKeyEvent *ev);

View file

@ -2848,59 +2848,63 @@ void tests::plotting()
test(CLEAR, "RAD", ENTER).noerr();
step("Function plot: Sine wave");
test(CLEAR, "'sin(x)' FunctionPlot", ENTER).noerr();
test(CLEAR, "'sin(x)' FunctionPlot", ENTER).noerr()
.wait(200).image("plot-sine");
step("Function plot: Equation");
test(CLEAR,
SHIFT, ENTER, X, ENTER, ENTER, J, 3, MUL, M, 21, MUL, COS, 2, MUL, ADD,
SHIFT, SHIFT, O, F1).noerr();
SHIFT, SHIFT, O, F1).noerr()
.wait(200).image("plot-eq");
step("Function plot: Program");
test(CLEAR, SHIFT, RUNSTOP,
I, SHIFT, F1, L, M, 41, MUL, J, MUL, ENTER, ENTER,
SHIFT, SHIFT, O, F1).noerr();
SHIFT, SHIFT, O, F1).wait(200).image("plot-pgm").noerr();
step("Polar plot: Program");
test(CLEAR, SHIFT, RUNSTOP,
61, MUL, L, SHIFT, C, 2, ADD, ENTER,
SHIFT, SHIFT, O, F2).noerr().wait(500);
SHIFT, SHIFT, O, F2).noerr().wait(200).image("polar-pgm");
step("Polar plot: Equation");
test(CLEAR, F, J, 611, MUL, SHIFT, ENTER, X, SHIFT, ENTER, SHIFT, ENTER,
DOWN, MUL, K, 271, MUL, SHIFT, ENTER, X, LONGPRESS, SHIFT, DOWN,
ADD, KEY2, DOT, KEY5, ENTER,
SHIFT, SHIFT, O,
ENTER, F2).noerr().wait(500);
ENTER, F2).noerr().wait(200).image("polar-eq");
step("Polar plot: Zoom in X and Y");
test(EXIT, "0.5 XSCALE 0.5 YSCALE", ENTER).noerr()
.test(ENTER, F2).noerr().wait(500);
.test(ENTER, F2).noerr().wait(200).image("polar-zoomxy");
step("Polar plot: Zoom out Y");
test(EXIT, "2 YSCALE", ENTER).noerr()
.test(ENTER, F2).noerr().wait(500);
.test(ENTER, F2).noerr().wait(200).image("polar-zoomy");
step("Polar plot: Zoom out X");
test(EXIT, "2 XSCALE", ENTER).noerr()
.test(ENTER, F2).noerr().wait(500);
.test(ENTER, F2).noerr().wait(200).image("polar-zoomx");
step("Parametric plot: Program");
test(CLEAR, SHIFT, RUNSTOP,
"'9.5*sin(31.27*X)' eval '5.5*cos(42.42*X)' eval RealToComplex",
ENTER, ENTER, F3)
.noerr().wait(500);
.noerr().wait(200).image("pplot-pgm");
step("Parametric plot: Degrees");
test("DEG 2 LINEWIDTH", ENTER, F3).noerr().wait(500);
test("DEG 2 LINEWIDTH", ENTER, F3).noerr().wait(200).image("pplot-deg");
step("Parametric plot: Equation");
test(CLEAR,
"3 LINEWIDTH 0.25 GRAY FOREGROUND "
"'exp((0.175.27)*x+(1.58))' ParametricPlot", ENTER).noerr().wait(500);
"'exp((0.175.27)*x+(1.58))' ParametricPlot", ENTER)
.noerr().wait(200).image("pplot-eq");
step("Bar plot");
test(CLEAR,
"[[ 1 -1 ][2 -2][3 -3][4 -4][5 -6][7 -8][9 -10]]", ENTER,
33, MUL, K, 2, MUL,
SHIFT, SHIFT, O, F5).noerr().wait(500);
SHIFT, SHIFT, O, F5).noerr().wait(200).image("barplot");
step("Scatter plot");
test(CLEAR,
"[[ -5 -5][ -3 0][ -5 5][ 0 3][ 5 5][ 3 0][ 5 -5][ 0 -3][-5 -5]]",
ENTER,
"4 LineWidth ScatterPlot", ENTER).noerr().wait(500);
"4 LineWidth ScatterPlot", ENTER)
.noerr().wait(200).image("scatterplot");
step("Reset drawing parameters");
test(CLEAR, "1 LineWidth 0 GRAY Foreground", ENTER).noerr();
@ -2916,53 +2920,53 @@ void tests::graphic_commands()
step("Clear LCD");
test(CLEAR, "ClearLCD", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("cllcd").test(ENTER);
step("Displaying text, compatibility mode");
test(CLEAR,
"\"Hello World\" 1 DISP "
"\"Compatibility mode\" 2 DISP", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("text-compat").test(ENTER);
step("Displaying text, fractional row");
test(CLEAR,
"\"Gutentag\" 1.5 DrawText "
"\"Fractional row\" 3.8 DrawText", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("text-frac").test(ENTER);
step("Displaying text, pixel row");
test(CLEAR,
"\"Bonjour tout le monde\" #5d DISP "
"\"Pixel row mode\" #125d DISP", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("text-pixrow").test(ENTER);
step("Displaying text, x-y coordinates");
test(CLEAR, "\"Hello\" {0 0 } DISP ", ENTER)
.noerr().wait(200).test(ENTER);
test(CLEAR, "\"Hello\" { 0 0 } DISP ", ENTER)
.noerr().wait(200).image("text-xy").test(ENTER);
step("Displaying text, x-y pixel coordinates");
test(CLEAR, "\"Hello\" { #20d #20d } DISP ", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("text-pixxy").test(ENTER);
step("Displaying text, font ID");
test(CLEAR, "\"Hello\" { 0 0 0 } DISP \"World\" { 0 1 2 } DISP ", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("text-font").test(ENTER);
step("Displaying text, erase and invert");
test(CLEAR, "\"Inverted\" { 0 0 0 true true } DISP", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("text-invert").test(ENTER);
step("Displaying text, background and foreground");
test(CLEAR,
"0.25 Gray Foreground 0.75 Gray Background "
"\"Grayed\" { 0 0 } Disp", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("text-gray").test(ENTER);
step("Displaying text, restore background and foreground");
test(CLEAR,
"0 Gray Foreground 1 Gray Background "
"\"Grayed\" { 0 0 } Disp", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("text-normal").test(ENTER);
step("Displaying text, type check");
test(CLEAR, "\"Bad\" \"Hello\" DISP", ENTER)
@ -2970,7 +2974,7 @@ void tests::graphic_commands()
step("Lines");
test(CLEAR, "3 50 for i i * exp i 2 + * exp 5 * Line next", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("lines").test(ENTER);
step("Line width");
test(CLEAR,
@ -2980,7 +2984,7 @@ void tests::graphic_commands()
"i LineWidth Line "
"next "
"1 LineWidth", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("line-width").test(ENTER);
step("Line width, grayed");
test(CLEAR,
@ -2991,7 +2995,7 @@ void tests::graphic_commands()
"i LineWidth Line "
"next "
"1 LineWidth 0 Gray Foreground", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("line-width-gray").test(ENTER);
step("Circles");
test(CLEAR,
@ -2999,14 +3003,14 @@ void tests::graphic_commands()
"{ 0 0 } i Circle "
"{ 0 1 } i 0.25 * Circle "
"next ", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("circles").test(ENTER);
step("Circles, complex coordinates");
test(CLEAR,
"2 150 for i "
" i 0.12 * * exp 0.75 0.05 i * + * 0.4 0.003 i * + Circle "
"next ", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("circles-complex").test(ENTER);
step("Circles, fill and patterns");
test(CLEAR,
@ -3015,7 +3019,7 @@ void tests::graphic_commands()
"i 0.0053 * gray Foreground "
" i 0.12 * * exp 0.75 0.05 i * + * 0.1 0.008 i * + Circle "
"next ", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("circles-fill").test(ENTER);
step("Ellipses");
test(CLEAR,
@ -3025,7 +3029,7 @@ void tests::graphic_commands()
"i 0.17 * * exp 0.05 i * 0.75 + * "
" Ellipse "
"next ", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("ellipses").test(ENTER);
step("Ellipses, fill and patterns");
test(CLEAR,
@ -3036,7 +3040,7 @@ void tests::graphic_commands()
"1.27 * exp 5.45 0.01 i * - * neg "
" Ellipse "
"next ", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("ellipses-fill").test(ENTER);
step("Rectangles");
test(CLEAR,
@ -3046,7 +3050,7 @@ void tests::graphic_commands()
"i 0.17 * * exp 0.05 i * 0.75 + * "
" Rect "
"next ", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("rectangles").test(ENTER);
step("Rectangles, fill and patterns");
test(CLEAR,
@ -3057,7 +3061,7 @@ void tests::graphic_commands()
"1.27 * exp 5.45 0.01 i * - * neg "
" Rect "
"next ", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("rectangle-fill").test(ENTER);
step("Rounded rectangles");
test(CLEAR,
@ -3067,7 +3071,7 @@ void tests::graphic_commands()
"i 0.17 * * exp 0.05 i * 0.75 + * "
"0.8 RRect "
"next ", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("rounded-rectangle").test(ENTER);
step("Rounded rectangles, fill and patterns");
test(CLEAR,
@ -3078,7 +3082,23 @@ void tests::graphic_commands()
"1.27 * exp 5.45 0.01 i * - * neg "
"0.8 RRect "
"next ", ENTER)
.noerr().wait(200).test(ENTER);
.noerr().wait(200).image("rounded-rectangle-fill").test(ENTER);
step("Clipping");
test(CLEAR,
"0 LineWidth CLLCD { 120 135 353 175 } Clip "
"2 150 for i "
"i 0.0053 * gray Foreground "
" i 0.12 * * exp 0.75 0.05 i * + * 0.1 0.008 i * + Circle "
"next "
"{} Clip", ENTER)
.wait(200).noerr().image("clip-circles").test(ENTER);
step("Cleanup");
test(CLEAR,
"1 LineWidth 0 Gray Foreground 1 Gray Background "
"{ -1 -1 } { 3 2 } rect",
ENTER).noerr().wait(200).image("cleanup");
}
@ -3940,6 +3960,23 @@ tests &tests::match(cstring restr)
}
tests &tests::image(cstring file)
// ----------------------------------------------------------------------------
// Check that the output in the screen matches what is in the file
// ----------------------------------------------------------------------------
{
ready();
cindex++;
if (!image_match(file))
{
explain("Expected screen to match [", file, "]");
image_match(file, true);
return fail();
}
return *this;
}
tests &tests::type(object::id ty)
// ----------------------------------------------------------------------------
// Check that the top of stack matches the type

View file

@ -265,6 +265,7 @@ public:
tests &expect(long long output);
tests &expect(unsigned long long output);
tests &match(cstring regexp);
tests &image(cstring name);
tests &type(object::id ty);
tests &shift(bool s);
tests &xshift(bool x);
@ -316,6 +317,8 @@ public:
return check(test);
}
bool image_match(cstring file, bool force = false);
protected:
cstring file;
uint line;