// 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 #include #include #include #include #include #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 = ."); 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 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 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 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; }