Move Sketch2D's session recorder into the framework: SessionRecorder in GraphicsInput, SessionRecordingControl (REC badge, save and discard dialogs) in Widgets, and DebugTools in WidgetsApp. Every WidgetApplication attaches a trailing Debug menu with Debug UI, Record session and Stop recording and save unless it opts out. Sessions save environment, raw input and per-frame profiles; apps add their own state through a snapshot hook, which Sketch2D uses for its document.
125 lines
4.6 KiB
C++
125 lines
4.6 KiB
C++
#include "AppDriver.hpp"
|
|
#include "LibraryViewerApplication.hpp"
|
|
|
|
#include "UnitTest++/UnitTest++.h"
|
|
|
|
using namespace tp;
|
|
using namespace tp::ui;
|
|
|
|
namespace {
|
|
constexpr halnf kPaintBudgetMs = 4;
|
|
constexpr int kMeasuredFrames = 30;
|
|
constexpr ualni kPaintedWidgetsBudget = 150;
|
|
|
|
halnf averagePaintMs(LibraryViewerApplication& application, AppDriver& driver) {
|
|
halnf total = 0;
|
|
for (int frame = 0; frame < kMeasuredFrames; frame++) {
|
|
application.ui().resetStats();
|
|
application.gui().requestPaint();
|
|
driver.frame();
|
|
total += (halnf) application.ui().stats().paintNs / 1.0e6f;
|
|
}
|
|
return total / kMeasuredFrames;
|
|
}
|
|
}
|
|
|
|
SUITE(LibraryViewerIntegration) {
|
|
TEST(ThousandsOfTracksPaintWithinBudget) {
|
|
LibraryViewerApplication application("library/Library.json");
|
|
AppDriver driver(application);
|
|
CHECK(application.library().mTraks.size() > 2000);
|
|
|
|
const halnf atTop = averagePaintMs(application, driver);
|
|
CHECK(atTop < kPaintBudgetMs);
|
|
CHECK(application.ui().stats().paintedWidgets < kPaintedWidgetsBudget);
|
|
|
|
for (int notch = 0; notch < 200; notch++)
|
|
driver.scroll({ 300, 300 }, -3);
|
|
driver.advance(500);
|
|
const halnf scrolled = averagePaintMs(application, driver);
|
|
CHECK(scrolled < kPaintBudgetMs);
|
|
printf("library paint: %.3f ms at top, %.3f ms scrolled\n", atTop, scrolled);
|
|
}
|
|
|
|
TEST(ClickingTrackSelectsIt) {
|
|
LibraryViewerApplication application("library/Library.json");
|
|
AppDriver driver(application);
|
|
driver.click(*application.gui().visibleTracks()[0]);
|
|
CHECK(application.gui().selectedTrack() != nullptr);
|
|
}
|
|
}
|
|
|
|
SUITE(LibraryViewerChrome) {
|
|
TEST(DefaultMenuBarCarriesLibraryMenus) {
|
|
LibraryViewerApplication application("library/Library.json");
|
|
AppDriver driver(application);
|
|
CHECK(application.isMenuBarVisible());
|
|
CHECK_EQUAL(4u, application.menuBar().titles().size());
|
|
CHECK_EQUAL("Debug", application.menuBar().titles().back()->text());
|
|
CHECK(application.menuBar().windowRect().pos.y < application.gui().windowRect().pos.y + 1);
|
|
const RectF player = application.gui().player.windowRect();
|
|
CHECK(player.pos.y + player.size.y > application.gui().windowRect().size.y - 4);
|
|
}
|
|
|
|
TEST(SearchingNarrowsTheRealLibrary) {
|
|
LibraryViewerApplication application("library/Library.json");
|
|
AppDriver driver(application);
|
|
const size_t all = application.gui().visibleTracks().size();
|
|
driver.click(application.gui().search);
|
|
driver.type("jack");
|
|
CHECK(application.gui().visibleTracks().size() < all);
|
|
CHECK(!application.gui().visibleTracks().empty());
|
|
}
|
|
}
|
|
|
|
SUITE(LibraryViewerInputCoalescing) {
|
|
TEST(MotionBurstWithinOneFrameIsDeliveredOnce) {
|
|
LibraryViewerApplication application("library/Library.json");
|
|
AppDriver driver(application);
|
|
const CoalescingStatistics before = application.window().inputStatistics();
|
|
|
|
WindowInputObserver& input = application.window().injectInput();
|
|
for (int step = 0; step < 50; step++)
|
|
input.onPointerMoved({ 100.0f + (halnf) step, 200.0f });
|
|
driver.frame();
|
|
|
|
const CoalescingStatistics after = application.window().inputStatistics();
|
|
CHECK_EQUAL(50u, after.received - before.received);
|
|
CHECK_EQUAL(1u, after.delivered - before.delivered);
|
|
}
|
|
|
|
TEST(ClickInsideBurstStillLandsOnItsPosition) {
|
|
LibraryViewerApplication application("library/Library.json");
|
|
AppDriver driver(application);
|
|
const RectF target = application.gui().visibleTracks()[1]->windowRect();
|
|
|
|
WindowInputObserver& input = application.window().injectInput();
|
|
input.onPointerMoved({ 5, 5 });
|
|
input.onPointerMoved(target.center());
|
|
input.onPointerButton(InputID::MOUSE1, true);
|
|
input.onPointerButton(InputID::MOUSE1, false);
|
|
input.onPointerMoved({ 5, 5 });
|
|
driver.frame();
|
|
|
|
CHECK(application.gui().selectedTrack() == &application.gui().visibleTracks()[1]->track());
|
|
}
|
|
}
|
|
|
|
SUITE(LibraryViewerResize) {
|
|
TEST(MaximizeAppliesOneConfigurePerFrameAndRelayouts) {
|
|
LibraryViewerApplication application("library/Library.json");
|
|
AppDriver driver(application);
|
|
const Vec2F before = application.window().getSize();
|
|
const CoalescingStatistics start = application.window().inputStatistics();
|
|
|
|
application.window().toggleMaximize();
|
|
for (int frame = 0; frame < 30 && application.window().getSize() == before; frame++)
|
|
driver.frame();
|
|
|
|
const CoalescingStatistics end = application.window().inputStatistics();
|
|
CHECK(application.window().getSize().x > before.x || application.window().getSize().y > before.y);
|
|
CHECK(end.configuresApplied - start.configuresApplied >= 1);
|
|
CHECK(end.configuresApplied - start.configuresApplied <= end.configuresReceived - start.configuresReceived);
|
|
CHECK_CLOSE(application.window().getSize().x, application.gui().windowRect().size.x, 1.0f);
|
|
}
|
|
}
|