Skip to content

Commit

Permalink
rMlib: More unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
timower committed Oct 15, 2023
1 parent 3159336 commit e10fad5
Show file tree
Hide file tree
Showing 22 changed files with 537 additions and 80 deletions.
378 changes: 298 additions & 80 deletions test/unit/TestRMLib.cpp

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions test/unit/assets/button-pressed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/button-released.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/column-text.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/container-text.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/counter-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/counter-5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/counter-init.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/counter-reset.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/expanded-flex-text.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/expanded-text.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/nav-init.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/nav-second.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/nav-third.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/row-text.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/stateless.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/text-basic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/text-sized.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/text-sized2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/text-sized3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/unit/assets/text-sized4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
179 changes: 179 additions & 0 deletions test/unit/rMLibTestHelper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#pragma once

#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_templated.hpp>

#include <UI/AppContext.h>
#include <UI/Text.h>

#include <filesystem>

#include <SDL_events.h>

const std::filesystem::path assets_path = ASSETS_PATH;

using Finder = std::function<bool(const rmlib::RenderObject*)>;

template<typename RO = rmlib::RenderObject>
using FindResult = std::vector<RO*>;

struct TestContext : rmlib::AppContext {
struct GoldenImageMatcher : Catch::Matchers::MatcherGenericBase {
static inline const bool update_golden_files = [] {
auto* update = std::getenv("UPDATE_GOLDEN");
return update != nullptr && std::string_view(update) == "1";
}();

GoldenImageMatcher(std::filesystem::path path, TestContext& ctx)
: path(path), ctx(ctx) {}

template<typename RO>
bool match(const FindResult<RO>& other) const {
if (other.size() != 1) {
return false;
}

if (update_golden_files) {
ctx.writeImage(path, *other.front());
return true;
}

const auto canvas =
ctx.framebuffer.canvas.subCanvas(other.front()->getRect());
const auto goldenCanvas = rmlib::ImageCanvas::load(path.c_str());
if (!goldenCanvas.has_value()) {
return false;
}

return canvas == goldenCanvas->canvas;
}

std::string describe() const override { return "Matches image"; }

std::filesystem::path path;
TestContext& ctx;
};

static constexpr auto default_pump = std::chrono::milliseconds(1);

static TestContext make() {
auto appCtx = AppContext::makeContext();
REQUIRE(appCtx.has_value());
return TestContext(std::move(*appCtx));
}

TestContext(AppContext appCtx) : AppContext(std::move(appCtx)) {
framebuffer.clear();
}

template<typename Widget>
void pumpWidget(const Widget& widget) {
setRootRenderObject(widget.createRenderObject());
pump();
}

void pump(std::chrono::milliseconds duration = default_pump) {
bool running = true;
auto handle = addTimer(duration, [&running] { running = false; });
while (running) {
step();
}
}

FindResult<> getAllNodes(rmlib::RenderObject* obj = nullptr) {
if (obj == nullptr) {
obj = &getRootRenderObject();
}

std::vector<rmlib::RenderObject*> result;
result.emplace_back(obj);

for (auto* child : obj->getChildren()) {
auto childNodes = getAllNodes(child);
result.insert(result.end(), childNodes.begin(), childNodes.end());
}
return result;
}

// TODO: find stuff
template<typename Widget>
FindResult<typename Widget::RenderObjectType> findByType() {
auto res =
find([typeID = rmlib::typeID::type_id<Widget>()](const auto& ro) {
return ro->getWidgetTypeID() == typeID;
});

std::vector<typename Widget::RenderObjectType*> casted;
casted.reserve(res.size());
std::transform(
res.begin(), res.end(), std::back_inserter(casted), [](auto* ro) {
return static_cast<typename Widget::RenderObjectType*>(ro);
});

return casted;
}

FindResult<rmlib::TextRenderObject> findByText(std::string_view text) {
auto res = findByType<rmlib::Text>();
res.erase(std::remove_if(
res.begin(),
res.end(),
[text](auto* ro) { return ro->getWidget().getText() != text; }),
res.end());
return res;
}

std::vector<rmlib::RenderObject*> find(Finder finder) {
auto nodes = getAllNodes();
nodes.erase(std::remove_if(nodes.begin(), nodes.end(), std::not_fn(finder)),
nodes.end());

return nodes;
}

void writeImage(std::filesystem::path path, const rmlib::RenderObject& ro) {
const auto canvas = framebuffer.canvas.subCanvas(ro.getRect());
REQUIRE(rmlib::writeImage(path.c_str(), canvas).has_value());
}

GoldenImageMatcher matchesGolden(std::string_view name) {
return GoldenImageMatcher(assets_path / name, *this);
}

void sendEv(SDL_Event& ev) {
SDL_PushEvent(&ev);
step();
}

template<typename RO>
void press(const FindResult<RO>& ros) {
REQUIRE(ros.size() == 1);
auto pos = ros.front()->getRect().center();

SDL_Event ev;
ev.type = SDL_MOUSEBUTTONDOWN;
ev.motion.x = pos.x / EMULATE_SCALE;
ev.motion.y = pos.y / EMULATE_SCALE;
ev.button.button = SDL_BUTTON_LEFT;
sendEv(ev);
}

template<typename RO>
void release(const FindResult<RO>& ros) {
REQUIRE(ros.size() == 1);
auto pos = ros.front()->getRect().center();

SDL_Event ev;
ev.type = SDL_MOUSEBUTTONUP;
ev.motion.x = pos.x / EMULATE_SCALE;
ev.motion.y = pos.y / EMULATE_SCALE;
ev.button.button = SDL_BUTTON_LEFT;
sendEv(ev);
}

template<typename RO>
void tap(const FindResult<RO>& ros) {
press(ros);
release(ros);
}
};

0 comments on commit e10fad5

Please sign in to comment.