oak-cli and oak-render-worker use the C ABI exclusively (0 olive:: symbols). Google Test suites updated for the migrated APIs, new engine facade test coverage, CLI transcode verification.
594 lines
16 KiB
C++
594 lines
16 KiB
C++
#include <gtest/gtest.h>
|
|
|
|
#include <memory>
|
|
|
|
#include <QAction>
|
|
#include <QCheckBox>
|
|
#include <QComboBox>
|
|
#include <QDateTime>
|
|
#include <QListWidget>
|
|
#include <QMenuBar>
|
|
#include <QPlainTextEdit>
|
|
#include <QPointer>
|
|
#include <QPushButton>
|
|
#include <QStackedWidget>
|
|
#include <QStandardPaths>
|
|
#include <QTemporaryDir>
|
|
#include <QTreeWidget>
|
|
|
|
#include "common/filefunctions.h"
|
|
#include "config/config.h"
|
|
#include "core.h"
|
|
#include "dialog/about/about.h"
|
|
#include "dialog/actionsearch/actionsearch.h"
|
|
#include "dialog/autorecovery/autorecoverydialog.h"
|
|
#include "dialog/color/colordialog.h"
|
|
#include "widget/manageddisplay/colorprocessorhandle.h"
|
|
#include "dialog/configbase/configdialogbase.h"
|
|
#include "dialog/diskcache/diskcachedialog.h"
|
|
#include "dialog/preferences/keysequenceeditor.h"
|
|
#include "dialog/preferences/tabs/preferencesappearancetab.h"
|
|
#include "dialog/preferences/tabs/preferencesdisktab.h"
|
|
#include "dialog/preferences/tabs/preferencesluttab.h"
|
|
#include "dialog/progress/progress.h"
|
|
#include "dialog/rendercancel/rendercancel.h"
|
|
#include "dialog/task/task.h"
|
|
#include "dialog/text/text.h"
|
|
#include "node/color/colormanager/colormanager.h"
|
|
#include "node/project.h"
|
|
#include "render/diskmanager.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
void ensure_app_singletons()
|
|
{
|
|
if (!olive::Core::instance()) {
|
|
new olive::Core(); // intentionally leaked
|
|
}
|
|
if (!olive::DiskManager::instance()) {
|
|
olive::DiskManager::create_instance();
|
|
}
|
|
}
|
|
|
|
// Redirects QStandardPaths (config/autorecovery locations) to a disposable
|
|
// test location for the lifetime of the guard
|
|
class StandardPathsTestModeGuard {
|
|
public:
|
|
StandardPathsTestModeGuard()
|
|
{
|
|
QStandardPaths::setTestModeEnabled(true);
|
|
}
|
|
|
|
~StandardPathsTestModeGuard()
|
|
{
|
|
QStandardPaths::setTestModeEnabled(false);
|
|
}
|
|
};
|
|
|
|
class DummyTab : public olive::ConfigDialogBaseTab {
|
|
public:
|
|
bool validate_result = true;
|
|
int accept_count = 0;
|
|
|
|
virtual bool validate() override
|
|
{
|
|
return validate_result;
|
|
}
|
|
|
|
virtual void accept(void *) override
|
|
{
|
|
++accept_count;
|
|
}
|
|
};
|
|
|
|
class TestConfigDialog : public olive::ConfigDialogBase {
|
|
public:
|
|
using olive::ConfigDialogBase::add_tab;
|
|
using olive::ConfigDialogBase::ConfigDialogBase;
|
|
|
|
bool accept_event_called = false;
|
|
|
|
protected:
|
|
virtual void AcceptEvent() override
|
|
{
|
|
accept_event_called = true;
|
|
}
|
|
};
|
|
|
|
class DummyTask : public olive::Task {
|
|
public:
|
|
DummyTask()
|
|
{
|
|
set_title(QStringLiteral("DummyTask"));
|
|
}
|
|
|
|
protected:
|
|
virtual bool run() override
|
|
{
|
|
return true;
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
//
|
|
// about
|
|
//
|
|
TEST(DialogAbout, WelcomeDialogHasDontShowAgainCheckbox)
|
|
{
|
|
olive::AboutDialog welcome(true);
|
|
EXPECT_NE(welcome.findChild<QCheckBox *>(), nullptr);
|
|
|
|
olive::AboutDialog about(false);
|
|
EXPECT_EQ(about.findChild<QCheckBox *>(), nullptr);
|
|
}
|
|
|
|
TEST(DialogAbout, AcceptWithCheckboxWritesConfig)
|
|
{
|
|
const QVariant old_value =
|
|
olive::Config::current()[QStringLiteral("ShowWelcomeDialog")];
|
|
|
|
{
|
|
olive::AboutDialog welcome(true);
|
|
QCheckBox *box = welcome.findChild<QCheckBox *>();
|
|
ASSERT_NE(box, nullptr);
|
|
box->setChecked(true);
|
|
welcome.accept();
|
|
}
|
|
|
|
EXPECT_FALSE(
|
|
olive::Config::current()[QStringLiteral("ShowWelcomeDialog")].toBool());
|
|
|
|
olive::Config::current()[QStringLiteral("ShowWelcomeDialog")] = old_value;
|
|
}
|
|
|
|
//
|
|
// actionsearch
|
|
//
|
|
TEST(DialogActionSearch, SearchFiltersActionsCaseInsensitively)
|
|
{
|
|
QWidget parent;
|
|
olive::ActionSearch dialog(&parent);
|
|
|
|
QMenuBar bar;
|
|
QMenu *file_menu = bar.addMenu(QStringLiteral("&File"));
|
|
file_menu->addAction(QStringLiteral("New Project"));
|
|
file_menu->addAction(QStringLiteral("&Open..."));
|
|
file_menu->addSeparator();
|
|
QMenu *recent_menu = file_menu->addMenu(QStringLiteral("Recent"));
|
|
recent_menu->addAction(QStringLiteral("Project A"));
|
|
bar.addMenu(QStringLiteral("&Edit"))->addAction(QStringLiteral("Undo"));
|
|
|
|
dialog.set_menu_bar(&bar);
|
|
|
|
auto *entry = dialog.findChild<olive::ActionSearchEntry *>();
|
|
auto *list = dialog.findChild<olive::ActionSearchList *>();
|
|
ASSERT_NE(entry, nullptr);
|
|
ASSERT_NE(list, nullptr);
|
|
|
|
entry->setText(QStringLiteral("OPEN"));
|
|
ASSERT_EQ(list->count(), 1);
|
|
// Item text is "action\n(menu hierarchy)" with accelerator '&' stripped
|
|
EXPECT_TRUE(list->item(0)->text().contains(QStringLiteral("Open...")));
|
|
EXPECT_TRUE(list->item(0)->text().contains(QStringLiteral("(File)")));
|
|
// First match is auto-selected for keyboard use
|
|
EXPECT_TRUE(list->item(0)->isSelected());
|
|
|
|
entry->setText(QStringLiteral("zzzz-no-match"));
|
|
EXPECT_EQ(list->count(), 0);
|
|
|
|
// Nested menus are searched recursively
|
|
entry->setText(QStringLiteral("project a"));
|
|
ASSERT_EQ(list->count(), 1);
|
|
EXPECT_TRUE(list->item(0)->text().contains(QStringLiteral("Recent")));
|
|
}
|
|
|
|
TEST(DialogActionSearch, PerformActionTriggersSelectedAction)
|
|
{
|
|
QWidget parent;
|
|
olive::ActionSearch dialog(&parent);
|
|
|
|
QMenuBar bar;
|
|
QMenu *file_menu = bar.addMenu(QStringLiteral("&File"));
|
|
QAction *open_action = file_menu->addAction(QStringLiteral("Open..."));
|
|
|
|
dialog.set_menu_bar(&bar);
|
|
|
|
bool triggered = false;
|
|
QObject::connect(open_action, &QAction::triggered,
|
|
[&triggered]() { triggered = true; });
|
|
|
|
auto *entry = dialog.findChild<olive::ActionSearchEntry *>();
|
|
entry->setText(QStringLiteral("open"));
|
|
|
|
QMetaObject::invokeMethod(&dialog, "perform_action");
|
|
|
|
EXPECT_TRUE(triggered);
|
|
EXPECT_EQ(dialog.result(), QDialog::Accepted);
|
|
}
|
|
|
|
TEST(DialogActionSearch, SelectionMovesUpAndDown)
|
|
{
|
|
QWidget parent;
|
|
olive::ActionSearch dialog(&parent);
|
|
|
|
QMenuBar bar;
|
|
QMenu *file_menu = bar.addMenu(QStringLiteral("&File"));
|
|
file_menu->addAction(QStringLiteral("Alpha"));
|
|
file_menu->addAction(QStringLiteral("Beta"));
|
|
|
|
dialog.set_menu_bar(&bar);
|
|
|
|
auto *entry = dialog.findChild<olive::ActionSearchEntry *>();
|
|
auto *list = dialog.findChild<olive::ActionSearchList *>();
|
|
entry->setText(QStringLiteral("a"));
|
|
ASSERT_GE(list->count(), 2);
|
|
ASSERT_TRUE(list->item(0)->isSelected());
|
|
|
|
QMetaObject::invokeMethod(&dialog, "move_selection_down");
|
|
EXPECT_TRUE(list->item(1)->isSelected());
|
|
|
|
QMetaObject::invokeMethod(&dialog, "move_selection_up");
|
|
EXPECT_TRUE(list->item(0)->isSelected());
|
|
|
|
// Already at the top: moving up again is a no-op
|
|
QMetaObject::invokeMethod(&dialog, "move_selection_up");
|
|
EXPECT_TRUE(list->item(0)->isSelected());
|
|
}
|
|
|
|
//
|
|
// autorecovery
|
|
//
|
|
TEST(DialogAutoRecovery, PopulatesTreeFromRecoveryFolders)
|
|
{
|
|
StandardPathsTestModeGuard test_mode;
|
|
ensure_app_singletons();
|
|
|
|
const QString root = olive::FileFunctions::get_auto_recovery_root();
|
|
const QString folder = QStringLiteral("uuid-abc");
|
|
QDir recovery_dir(QDir(root).filePath(folder));
|
|
ASSERT_TRUE(recovery_dir.mkpath(QStringLiteral(".")));
|
|
|
|
QFile realname(recovery_dir.filePath(QStringLiteral("realname.txt")));
|
|
ASSERT_TRUE(realname.open(QFile::WriteOnly));
|
|
realname.write("My Project");
|
|
realname.close();
|
|
|
|
QFile newest(recovery_dir.filePath(QStringLiteral("1700000000.ove")));
|
|
ASSERT_TRUE(newest.open(QFile::WriteOnly));
|
|
newest.write("x");
|
|
newest.close();
|
|
|
|
QFile oldest(recovery_dir.filePath(QStringLiteral("1699999000.ove")));
|
|
ASSERT_TRUE(oldest.open(QFile::WriteOnly));
|
|
oldest.write("x");
|
|
oldest.close();
|
|
|
|
// Non-project files must be ignored
|
|
QFile notes(recovery_dir.filePath(QStringLiteral("notes.txt")));
|
|
ASSERT_TRUE(notes.open(QFile::WriteOnly));
|
|
notes.write("x");
|
|
notes.close();
|
|
|
|
{
|
|
olive::AutoRecoveryDialog dialog(QStringLiteral("message"), { folder },
|
|
true, nullptr);
|
|
|
|
auto *tree = dialog.findChild<QTreeWidget *>();
|
|
ASSERT_NE(tree, nullptr);
|
|
ASSERT_EQ(tree->topLevelItemCount(), 1);
|
|
|
|
QTreeWidgetItem *top = tree->topLevelItem(0);
|
|
// Pretty name comes from realname.txt
|
|
EXPECT_EQ(top->text(0), QStringLiteral("My Project"));
|
|
ASSERT_EQ(top->childCount(), 2);
|
|
|
|
// Entries are newest-first; autocheck_latest checks only the newest
|
|
EXPECT_EQ(top->child(0)->checkState(0), Qt::Checked);
|
|
EXPECT_EQ(top->child(1)->checkState(0), Qt::Unchecked);
|
|
|
|
// Timestamped filenames are shown as a formatted date/time
|
|
EXPECT_EQ(top->child(0)->text(0),
|
|
QDateTime::fromSecsSinceEpoch(1700000000).toString());
|
|
EXPECT_TRUE(top->child(0)
|
|
->data(0, Qt::UserRole)
|
|
.toString()
|
|
.endsWith(QStringLiteral("1700000000.ove")));
|
|
}
|
|
|
|
{
|
|
// Without autocheck_latest nothing is pre-checked
|
|
olive::AutoRecoveryDialog dialog(QStringLiteral("message"), { folder },
|
|
false, nullptr);
|
|
|
|
auto *tree = dialog.findChild<QTreeWidget *>();
|
|
QTreeWidgetItem *top = tree->topLevelItem(0);
|
|
EXPECT_EQ(top->child(0)->checkState(0), Qt::Unchecked);
|
|
EXPECT_EQ(top->child(1)->checkState(0), Qt::Unchecked);
|
|
|
|
// Accepting with nothing checked must not attempt to open anything
|
|
dialog.accept();
|
|
EXPECT_EQ(dialog.result(), QDialog::Accepted);
|
|
}
|
|
|
|
QDir(root).removeRecursively();
|
|
}
|
|
|
|
TEST(DialogAutoRecovery, MissingRealnameFallsBackToFolderName)
|
|
{
|
|
StandardPathsTestModeGuard test_mode;
|
|
ensure_app_singletons();
|
|
|
|
const QString root = olive::FileFunctions::get_auto_recovery_root();
|
|
const QString folder = QStringLiteral("uuid-no-realname");
|
|
QDir recovery_dir(QDir(root).filePath(folder));
|
|
ASSERT_TRUE(recovery_dir.mkpath(QStringLiteral(".")));
|
|
|
|
QFile recovery(recovery_dir.filePath(QStringLiteral("1700000000.ove")));
|
|
ASSERT_TRUE(recovery.open(QFile::WriteOnly));
|
|
recovery.write("x");
|
|
recovery.close();
|
|
|
|
olive::AutoRecoveryDialog dialog(QStringLiteral("message"), { folder },
|
|
false, nullptr);
|
|
|
|
auto *tree = dialog.findChild<QTreeWidget *>();
|
|
ASSERT_NE(tree, nullptr);
|
|
ASSERT_EQ(tree->topLevelItemCount(), 1);
|
|
EXPECT_EQ(tree->topLevelItem(0)->text(0), folder);
|
|
|
|
QDir(root).removeRecursively();
|
|
}
|
|
|
|
//
|
|
// configbase
|
|
//
|
|
TEST(DialogConfigBase, AddTabPopulatesListAndStack)
|
|
{
|
|
TestConfigDialog dialog;
|
|
|
|
auto *tab_a = new DummyTab();
|
|
auto *tab_b = new DummyTab();
|
|
dialog.add_tab(tab_a, QStringLiteral("First"));
|
|
dialog.add_tab(tab_b, QStringLiteral("Second"));
|
|
|
|
auto *list = dialog.findChild<QListWidget *>();
|
|
auto *stack = dialog.findChild<QStackedWidget *>();
|
|
ASSERT_NE(list, nullptr);
|
|
ASSERT_NE(stack, nullptr);
|
|
|
|
EXPECT_EQ(list->count(), 2);
|
|
EXPECT_EQ(stack->count(), 2);
|
|
|
|
dialog.set_current_tab(1);
|
|
EXPECT_EQ(list->currentRow(), 1);
|
|
EXPECT_EQ(stack->currentIndex(), 1);
|
|
}
|
|
|
|
TEST(DialogConfigBase, AcceptCallsTabsAndAcceptEvent)
|
|
{
|
|
ensure_app_singletons();
|
|
|
|
TestConfigDialog dialog;
|
|
auto *tab_a = new DummyTab();
|
|
auto *tab_b = new DummyTab();
|
|
dialog.add_tab(tab_a, QStringLiteral("First"));
|
|
dialog.add_tab(tab_b, QStringLiteral("Second"));
|
|
|
|
// accept() is a private slot, invoke it through the meta-object
|
|
QMetaObject::invokeMethod(&dialog, "accept");
|
|
|
|
EXPECT_EQ(tab_a->accept_count, 1);
|
|
EXPECT_EQ(tab_b->accept_count, 1);
|
|
EXPECT_TRUE(dialog.accept_event_called);
|
|
EXPECT_EQ(dialog.result(), QDialog::Accepted);
|
|
}
|
|
|
|
TEST(DialogConfigBase, FailedValidateBlocksAccept)
|
|
{
|
|
ensure_app_singletons();
|
|
|
|
TestConfigDialog dialog;
|
|
auto *tab_a = new DummyTab();
|
|
auto *tab_b = new DummyTab();
|
|
tab_a->validate_result = false;
|
|
dialog.add_tab(tab_a, QStringLiteral("First"));
|
|
dialog.add_tab(tab_b, QStringLiteral("Second"));
|
|
|
|
// accept() is a private slot, invoke it through the meta-object
|
|
QMetaObject::invokeMethod(&dialog, "accept");
|
|
|
|
EXPECT_EQ(tab_a->accept_count, 0);
|
|
EXPECT_EQ(tab_b->accept_count, 0);
|
|
EXPECT_FALSE(dialog.accept_event_called);
|
|
EXPECT_NE(dialog.result(), QDialog::Accepted);
|
|
}
|
|
|
|
//
|
|
// diskcache
|
|
//
|
|
TEST(DialogDiskCache, AcceptAppliesLimitAndClearOnClose)
|
|
{
|
|
QTemporaryDir temp_dir;
|
|
ASSERT_TRUE(temp_dir.isValid());
|
|
|
|
olive::DiskCacheFolder folder(temp_dir.path());
|
|
|
|
olive::DiskCacheDialog dialog(&folder);
|
|
|
|
auto *limit_slider = dialog.findChild<olive::FloatSlider *>();
|
|
auto *clear_box = dialog.findChild<QCheckBox *>();
|
|
ASSERT_NE(limit_slider, nullptr);
|
|
ASSERT_NE(clear_box, nullptr);
|
|
|
|
// Fields reflect the folder's current settings (20 GB default)
|
|
EXPECT_DOUBLE_EQ(limit_slider->get_value(), 20.0);
|
|
EXPECT_FALSE(clear_box->isChecked());
|
|
|
|
limit_slider->set_value(5.0);
|
|
clear_box->setChecked(true);
|
|
|
|
dialog.accept();
|
|
|
|
EXPECT_EQ(folder.get_limit(),
|
|
5 * static_cast<qint64>(olive::k_bytes_in_gigabyte));
|
|
EXPECT_TRUE(folder.get_clear_on_close());
|
|
}
|
|
|
|
//
|
|
// text
|
|
//
|
|
TEST(DialogText, TextIsReadBackFromEditor)
|
|
{
|
|
olive::TextDialog dialog(QStringLiteral("Hello"));
|
|
EXPECT_EQ(dialog.text(), QStringLiteral("Hello"));
|
|
|
|
auto *edit = dialog.findChild<QPlainTextEdit *>();
|
|
ASSERT_NE(edit, nullptr);
|
|
edit->setPlainText(QStringLiteral("World"));
|
|
EXPECT_EQ(dialog.text(), QStringLiteral("World"));
|
|
}
|
|
|
|
//
|
|
// progress
|
|
//
|
|
TEST(DialogProgress, CancelButtonEmitsCancelledAndDisables)
|
|
{
|
|
olive::ProgressDialog dialog(QStringLiteral("Working..."),
|
|
QStringLiteral("Title"));
|
|
EXPECT_EQ(dialog.windowTitle(), QStringLiteral("Title"));
|
|
|
|
QPushButton *cancel_btn = nullptr;
|
|
foreach (QPushButton *btn, dialog.findChildren<QPushButton *>()) {
|
|
if (btn->text() == QStringLiteral("Cancel")) {
|
|
cancel_btn = btn;
|
|
break;
|
|
}
|
|
}
|
|
ASSERT_NE(cancel_btn, nullptr);
|
|
|
|
bool cancelled = false;
|
|
QObject::connect(&dialog, &olive::ProgressDialog::cancelled,
|
|
[&cancelled]() { cancelled = true; });
|
|
|
|
cancel_btn->click();
|
|
|
|
EXPECT_TRUE(cancelled);
|
|
EXPECT_FALSE(cancel_btn->isEnabled());
|
|
}
|
|
|
|
//
|
|
// rendercancel
|
|
//
|
|
TEST(DialogRenderCancel, IdleWorkersDoNotBlock)
|
|
{
|
|
olive::RenderCancelDialog dialog;
|
|
|
|
dialog.set_worker_count(2);
|
|
dialog.worker_started();
|
|
dialog.worker_done();
|
|
|
|
// No busy workers: must return immediately without exec()ing
|
|
dialog.run_if_workers_are_busy();
|
|
|
|
EXPECT_FALSE(dialog.isVisible());
|
|
}
|
|
|
|
//
|
|
// task
|
|
//
|
|
TEST(DialogTask, WrapsAndOwnsTask)
|
|
{
|
|
auto *task = new DummyTask();
|
|
QPointer<olive::Task> task_guard(task);
|
|
|
|
auto *dialog = new olive::TaskDialog(
|
|
reinterpret_cast<OakEngineTask*>(task), QStringLiteral("Title"));
|
|
|
|
EXPECT_EQ(dialog->get_task(), reinterpret_cast<OakEngineTask*>(task));
|
|
|
|
// The dialog takes ownership of the task
|
|
delete dialog;
|
|
EXPECT_TRUE(task_guard.isNull());
|
|
}
|
|
|
|
//
|
|
// color
|
|
//
|
|
TEST(DialogColor, SelectedColorRoundTrips)
|
|
{
|
|
olive::ColorManager::set_up_default_config();
|
|
olive::Project project;
|
|
|
|
olive::ColorDialog dialog(oak_color_manager(project.color_manager()),
|
|
olive::Color(1.0f, 0.0f, 0.0f, 1.0f));
|
|
|
|
olive::ManagedColor selected = dialog.get_selected_color();
|
|
EXPECT_GT(selected.red(), selected.green());
|
|
EXPECT_GT(selected.red(), selected.blue());
|
|
|
|
dialog.set_color(olive::Color(0.0f, 0.0f, 1.0f, 1.0f));
|
|
|
|
olive::ManagedColor blue = dialog.get_selected_color();
|
|
EXPECT_GT(blue.blue(), blue.red());
|
|
EXPECT_GT(blue.blue(), blue.green());
|
|
}
|
|
|
|
//
|
|
// preferences (remaining tabs)
|
|
//
|
|
TEST(PreferencesAppearanceTab, ContainsStyleAndColorChoices)
|
|
{
|
|
olive::PreferencesAppearanceTab tab;
|
|
|
|
EXPECT_FALSE(tab.findChildren<QComboBox *>().isEmpty());
|
|
EXPECT_FALSE(tab.findChildren<olive::ColorCodingComboBox *>().isEmpty());
|
|
}
|
|
|
|
TEST(PreferencesDiskTab, ValidatesUnchangedCacheLocation)
|
|
{
|
|
ensure_app_singletons();
|
|
|
|
olive::PreferencesDiskTab tab;
|
|
|
|
// Unchanged location must validate without prompting
|
|
EXPECT_TRUE(tab.validate());
|
|
}
|
|
|
|
TEST(PreferencesLutTab, ConstructsWithDirectoryList)
|
|
{
|
|
olive::PreferencesLutTab tab;
|
|
|
|
EXPECT_NE(tab.findChild<QListWidget *>(), nullptr);
|
|
}
|
|
|
|
TEST(DialogKeySequenceEditor, TransfersShortcutsToAndFromAction)
|
|
{
|
|
QAction action(QStringLiteral("Test Action"));
|
|
action.setShortcut(QKeySequence(QStringLiteral("Ctrl+T")));
|
|
action.setProperty("id", QStringLiteral("test.action"));
|
|
action.setProperty("keydefault", QKeySequence(QStringLiteral("Ctrl+T")));
|
|
|
|
olive::KeySequenceEditor editor(nullptr, &action);
|
|
|
|
// Editor initializes from the action's current shortcut
|
|
EXPECT_EQ(editor.keySequence(), QKeySequence(QStringLiteral("Ctrl+T")));
|
|
EXPECT_EQ(editor.action_name(), QStringLiteral("test.action"));
|
|
|
|
// Shortcut matching the default does not need to be saved
|
|
EXPECT_TRUE(editor.export_shortcut().isEmpty());
|
|
|
|
editor.setKeySequence(QKeySequence(QStringLiteral("Ctrl+U")));
|
|
EXPECT_EQ(editor.export_shortcut(),
|
|
QStringLiteral("test.action\tCtrl+U"));
|
|
|
|
// The action is only updated when set_action_shortcut() is called
|
|
EXPECT_EQ(action.shortcut(), QKeySequence(QStringLiteral("Ctrl+T")));
|
|
editor.set_action_shortcut();
|
|
EXPECT_EQ(action.shortcut(), QKeySequence(QStringLiteral("Ctrl+U")));
|
|
|
|
editor.reset_to_default();
|
|
EXPECT_EQ(editor.keySequence(), QKeySequence(QStringLiteral("Ctrl+T")));
|
|
}
|