1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
/*
* Xournal++
*
* This file is part of the Xournal UnitTests
*
* @author Xournal++ Team
* https://github.com/xournalpp/xournalpp
*
* @license GNU GPLv2 or later
*/
#include <string>
#include <config-test.h>
#include <gtest/gtest.h>
#include <gtk/gtk.h>
#include "control/actions/ActionProperties.h"
#include "gui/menus/menubar/Menubar.h"
#include "util/EnumIndexedArray.h"
#include "util/StringUtils.h"
#include "util/raii/GObjectSPtr.h"
#include "util/raii/GVariantSPtr.h"
#include "util/safe_casts.h" // for to_underlying Todo(cpp20) replace with <utility>
#include "filesystem.h"
/**
* Test if the GActions referred to in MENU_XML_FILE have a counterpart in enums/Action.h, and checks if the (optional)
* action target value has the same type as set in control/actions/ActionProperties.h
*/
constexpr auto MENU_XML_FILE = "mainmenubar.xml";
constexpr auto MENU_ID = "menubar";
namespace {
template <Action a, class U = void>
struct helper {
static void setup(EnumIndexedArray<const GVariantType*, Action>& expectedTypes) { expectedTypes[a] = nullptr; };
};
template <Action a>
struct helper<a, std::void_t<typename ActionProperties<a>::parameter_type>> {
static void setup(EnumIndexedArray<const GVariantType*, Action>& expectedTypes) {
expectedTypes[a] = gVariantType<typename ActionProperties<a>::parameter_type>();
}
};
template <size_t... As>
static auto setupImpl(std::index_sequence<As...>) {
EnumIndexedArray<const GVariantType*, Action> expectedTypes;
((helper<static_cast<Action>(As)>::setup(expectedTypes)), ...);
return expectedTypes;
}
static const auto expectedTypes = setupImpl(std::make_index_sequence<xoj::to_underlying(Action::ENUMERATOR_COUNT)>());
void exploreMenu(GMenuModel* m) {
int n = g_menu_model_get_n_items(m);
for (int i = 0; i < n; i++) {
xoj::util::GVariantSPtr val(g_menu_model_get_item_attribute_value(m, i, "action", nullptr), xoj::util::adopt);
if (val) {
std::string value = g_variant_get_string(val.get(), nullptr);
auto pos = value.find('.');
EXPECT_TRUE(pos != std::string::npos);
EXPECT_TRUE(pos != 0);
std::string prefix = value.substr(0, pos);
std::string action = value.substr(pos + 1);
Action a = Action_fromString(action);
xoj::util::GVariantSPtr target(g_menu_model_get_item_attribute_value(m, i, "target", nullptr),
xoj::util::adopt);
if (target) {
EXPECT_TRUE(g_variant_type_equal(g_variant_get_type(target.get()), expectedTypes[a]));
} else {
EXPECT_TRUE(expectedTypes[a] == nullptr);
}
}
{
xoj::util::GObjectSPtr<GMenuLinkIter> it(g_menu_model_iterate_item_links(m, i), xoj::util::adopt);
while (g_menu_link_iter_next(it.get())) {
xoj::util::GObjectSPtr<GMenuModel> subm(g_menu_link_iter_get_value(it.get()), xoj::util::adopt);
exploreMenu(subm.get());
}
}
}
}
}; // namespace
TEST(ActionDatabaseTest, testActionTargetMatch) {
xoj::util::GObjectSPtr<GtkBuilder> builder(gtk_builder_new(), xoj::util::adopt);
GError* error = nullptr;
auto filepath = fs::path(GET_UI_FOLDER) / MENU_XML_FILE;
if (!gtk_builder_add_from_file(builder.get(), char_cast(filepath.u8string().c_str()), &error)) {
std::string msg = "Error loading menubar XML file ";
msg.append(char_cast(filepath.u8string()));
if (error != nullptr) {
msg += "\n";
msg += error->message;
g_error_free(error);
}
FAIL() << msg;
return;
}
GMenuModel* menu = G_MENU_MODEL(gtk_builder_get_object(builder.get(), MENU_ID));
ASSERT_TRUE(menu);
exploreMenu(menu);
}
|