Files
FrameAssistant/tests/tst_surfaces.cpp
T
matzmanandClaude Opus 5.5 4a5b09053e Initial FrameAssistant baseline from the vrdashboard template
Template stripped to the overlay platform (examples, demo UI and Frame
test package removed), renamed to FrameAssistant, and working rules for
the project recorded in CLAUDE.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 00:06:58 +02:00

117 lines
4.5 KiB
C++

// An app with two surfaces, run in snapshot mode: checks surface set-up
// (overlay keys, names, sizes, shared engine, backends), the lifecycle hooks
// and that every surface renders its own scene. No SteamVR involved.
// Exit codes: 0 pass, 1 fail, 77 skipped (no GPU context).
#include <QDir>
#include <QImage>
#include <QTemporaryDir>
#include <cstdio>
#include <string>
#include <vector>
#include "app/DashboardApplication.h"
namespace {
bool check(bool condition, const char* what) {
if (!condition) fprintf(stderr, "FAIL: %s\n", what);
return condition;
}
class TwoSurfaceApp : public DashboardApplication {
public:
TwoSurfaceApp(int& argc, char** argv) : DashboardApplication(argc, argv) {
setQmlModule(QStringLiteral("SurfacesTest"));
setDisplayName(QStringLiteral("Test App"));
setAppKey(QStringLiteral("config.key"));
addSurface({.id = QStringLiteral("red"),
.qmlRootType = QStringLiteral("Red"),
.textureSize = QSize(64, 32)});
addSurface({.id = QStringLiteral("blue"),
.qmlRootType = QStringLiteral("Blue"),
.displayName = QStringLiteral("Blue tab"),
.textureSize = QSize(32, 32)});
}
QString expectedKey; // --app-key overrides setAppKey()
int loadingCalls = 0;
int startedCalls = 0;
bool ok = true;
protected:
void loading() override {
++loadingCalls;
Surface* red = surface(QStringLiteral("red"));
Surface* blue = surface(QStringLiteral("blue"));
ok &= check(surfaces().size() == 2 && red && blue, "two surfaces by id");
ok &= check(surface() == red, "primary is the first");
ok &= check(surface(QStringLiteral("none")) == nullptr, "unknown id");
ok &= check(engine() != nullptr, "shared engine");
ok &= check(mode() == DashboardMode::Snapshot, "mode");
ok &= check(red && blue && red->backend() && blue->backend() &&
red->backend() != blue->backend(),
"a backend per surface");
ok &= check(appKey() == expectedKey, "app key (setAppKey / --app-key)");
ok &= check(red && red->overlayKey() == expectedKey + QLatin1String(".red"),
"overlay key = <app key>.<id>");
ok &= check(red && red->displayName() == QLatin1String("Test App"),
"tab name defaults to the app name");
ok &= check(blue && blue->displayName() == QLatin1String("Blue tab"),
"tab name from config");
ok &= check(blue && blue->textureSize() == QSize(32, 32),
"texture size from config");
ok &= check(vrRuntime() == nullptr, "no VR outside overlay mode");
}
void started() override {
++startedCalls;
const QList<Surface*> all = surfaces();
ok &= check(all.size() == 2 && all[0]->window() && all[1]->window() &&
all[0]->window() != all[1]->window(),
"a window per surface");
}
};
} // namespace
int main(int argc, char* argv[]) {
QTemporaryDir dir;
const std::string snapshot =
QDir(dir.path()).filePath(QStringLiteral("shot.png")).toStdString();
// VRDASH_TEST_CLI_KEY=1: also pass --app-key (must win over setAppKey()).
const bool cliKey = qEnvironmentVariableIntValue("VRDASH_TEST_CLI_KEY");
std::vector<std::string> args = {argv[0], "--snapshot", snapshot};
if (cliKey) {
args.emplace_back("--app-key");
args.emplace_back("cli.key");
}
for (int i = 1; i < argc; ++i) args.emplace_back(argv[i]);
std::vector<char*> cargs;
for (std::string& arg : args) cargs.push_back(arg.data());
int cargc = int(cargs.size());
TwoSurfaceApp app(cargc, cargs.data());
app.expectedKey =
cliKey ? QStringLiteral("cli.key") : QStringLiteral("config.key");
const int result = app.exec();
if (app.loadingCalls == 0) {
fprintf(stderr, "SKIP: no render backend (no GPU context?)\n");
return 77;
}
bool ok = app.ok;
ok &= check(result == 0, "exec() succeeded");
ok &= check(app.loadingCalls == 1 && app.startedCalls == 1,
"each hook called once");
const QImage red(QDir(dir.path()).filePath(QStringLiteral("shot-red.png")));
const QImage blue(QDir(dir.path()).filePath(QStringLiteral("shot-blue.png")));
ok &= check(red.size() == QSize(64, 32) &&
red.pixelColor(10, 10) == QColor(255, 0, 0),
"red surface rendered");
ok &= check(blue.size() == QSize(32, 32) &&
blue.pixelColor(10, 10) == QColor(0, 0, 255),
"blue surface rendered");
fprintf(stderr, ok ? "PASS\n" : "FAILED\n");
return ok ? 0 : 1;
}