Automated with clang-tidy readability-identifier-naming (config added to .clang-tidy) plus scripted passes, per the updated rules now documented in CONTRIBUTING.md: - types (class/struct/enum/alias/template params): PascalCase - functions, variables, members: snake_case (incl. rational -> Rational) - private/protected members: trailing underscore; static member variables likewise (instance_, available_themes_) - constants and enum values: snake_case (kLinear -> k_linear, F32P -> f32p); ALL_CAPS reserved for macros - macros: OAK_ prefix (OLIVE_ADD_TEST/OLIVE_ASSERT/OLIVE_CONFIG -> OAK_ADD_TEST/OAK_ASSERT/OAK_CONFIG, GL_PREAMBLE -> OAK_GL_PREAMBLE, include guards -> OAK_*) - file names: all lowercase (Current/Plugin/OliveHost/OliveClip/ OlivePluginInstance -> current/plugin/olivehost/oliveclip/ oliveplugininstance) - getters share the member name sans underscore, setters set_foo() - Qt and third-party (OpenFX) virtual overrides and framework callbacks keep their original names (exempt in .clang-tidy) Manual follow-ups required where automation could not reach: - string-based QMetaObject/SIGNAL/SLOT references updated to renamed methods (AddTask, CreatedFile, DeleteSpecificFile, moveSelectionUp, ...) - macro bodies referencing renamed methods (OLIVE_CONFIG, NODE_DEFAULT_DESTRUCTOR, MANAGEDDISPLAYWIDGET_*) - self-shadowing locals renamed where signals/methods became same-named (size_changed, worker_count, selected_items, import param, filters) - third_party OFX member/namespace usages restored (OFX::Host::*, _created, _clipPrefsDirty, createInstance, clearPersistentMessage) - STL protocol aliases restored (const_iterator) with .clang-tidy ignore rules; qHash overloads restored Full build and test suite pass: ctest 4/4, ~1960 gtest cases green.
189 lines
4.2 KiB
C++
189 lines
4.2 KiB
C++
#include <gtest/gtest.h>
|
|
|
|
#include <QColor>
|
|
|
|
#include "undo/undostack.h"
|
|
#include "undo/undocommand.h"
|
|
|
|
namespace
|
|
{
|
|
class TestCommand final : public olive::UndoCommand {
|
|
public:
|
|
explicit TestCommand(int *value)
|
|
: value_(value)
|
|
{
|
|
}
|
|
|
|
olive::Project *get_relevant_project() const override
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
protected:
|
|
void redo() override
|
|
{
|
|
if (value_) {
|
|
(*value_)++;
|
|
}
|
|
}
|
|
|
|
void undo() override
|
|
{
|
|
if (value_) {
|
|
(*value_)--;
|
|
}
|
|
}
|
|
|
|
private:
|
|
int *value_ = nullptr;
|
|
};
|
|
}
|
|
|
|
TEST(UndoStack, PushUndoRedo)
|
|
{
|
|
int counter = 0;
|
|
olive::UndoStack stack;
|
|
stack.push(new TestCommand(&counter), QStringLiteral("Test"));
|
|
EXPECT_EQ(counter, 1);
|
|
stack.undo();
|
|
EXPECT_EQ(counter, 0);
|
|
stack.redo();
|
|
EXPECT_EQ(counter, 1);
|
|
}
|
|
|
|
TEST(UndoStack, EmptyStateAndModelData)
|
|
{
|
|
olive::UndoStack stack;
|
|
EXPECT_FALSE(stack.can_undo());
|
|
EXPECT_FALSE(stack.can_redo());
|
|
EXPECT_EQ(stack.columnCount(), 2);
|
|
EXPECT_EQ(stack.rowCount(), 1);
|
|
EXPECT_TRUE(stack.hasChildren(QModelIndex()));
|
|
|
|
QModelIndex name_index = stack.index(0, 1);
|
|
EXPECT_EQ(stack.data(name_index, Qt::DisplayRole).toString(),
|
|
QStringLiteral("New/Open Project"));
|
|
EXPECT_EQ(stack.headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(),
|
|
QStringLiteral("Number"));
|
|
EXPECT_EQ(stack.headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(),
|
|
QStringLiteral("Action"));
|
|
}
|
|
|
|
TEST(UndoStack, UndoRedoListsAndColors)
|
|
{
|
|
int counter = 0;
|
|
olive::UndoStack stack;
|
|
stack.push(new TestCommand(&counter), QStringLiteral("First"));
|
|
stack.push(new TestCommand(&counter), QStringLiteral("Second"));
|
|
EXPECT_EQ(counter, 2);
|
|
EXPECT_EQ(stack.rowCount(), 3);
|
|
|
|
stack.undo();
|
|
EXPECT_EQ(counter, 1);
|
|
EXPECT_TRUE(stack.can_redo());
|
|
|
|
QModelIndex undone_name = stack.index(2, 1);
|
|
EXPECT_EQ(stack.data(undone_name, Qt::DisplayRole).toString(),
|
|
QStringLiteral("Second"));
|
|
QColor undone_color =
|
|
stack.data(undone_name, Qt::ForegroundRole).value<QColor>();
|
|
EXPECT_EQ(undone_color, QColor(Qt::gray));
|
|
|
|
stack.redo();
|
|
EXPECT_EQ(counter, 2);
|
|
EXPECT_FALSE(stack.can_redo());
|
|
}
|
|
|
|
TEST(UndoStack, JumpRestoresState)
|
|
{
|
|
int counter = 0;
|
|
olive::UndoStack stack;
|
|
stack.push(new TestCommand(&counter), QStringLiteral("A"));
|
|
stack.push(new TestCommand(&counter), QStringLiteral("B"));
|
|
stack.push(new TestCommand(&counter), QStringLiteral("C"));
|
|
EXPECT_EQ(counter, 3);
|
|
EXPECT_EQ(stack.rowCount(), 4);
|
|
|
|
stack.jump(1);
|
|
EXPECT_EQ(counter, 0);
|
|
EXPECT_TRUE(stack.can_redo());
|
|
|
|
stack.jump(4);
|
|
EXPECT_EQ(counter, 3);
|
|
EXPECT_FALSE(stack.can_redo());
|
|
}
|
|
|
|
TEST(UndoStack, EmptyMultiUndoCommandIsIgnored)
|
|
{
|
|
olive::UndoStack stack;
|
|
auto *empty_multi = new olive::MultiUndoCommand();
|
|
stack.push(empty_multi, QStringLiteral("Empty"));
|
|
EXPECT_EQ(stack.rowCount(), 1);
|
|
EXPECT_FALSE(stack.can_undo());
|
|
}
|
|
|
|
TEST(UndoStack, MultipleUndosAndRedos)
|
|
{
|
|
int counter = 0;
|
|
olive::UndoStack stack;
|
|
stack.push(new TestCommand(&counter), QStringLiteral("One"));
|
|
stack.push(new TestCommand(&counter), QStringLiteral("Two"));
|
|
stack.push(new TestCommand(&counter), QStringLiteral("Three"));
|
|
EXPECT_EQ(counter, 3);
|
|
|
|
stack.undo();
|
|
stack.undo();
|
|
EXPECT_EQ(counter, 1);
|
|
EXPECT_TRUE(stack.can_undo());
|
|
EXPECT_TRUE(stack.can_redo());
|
|
|
|
stack.redo();
|
|
EXPECT_EQ(counter, 2);
|
|
}
|
|
|
|
TEST(UndoStack, PushAfterUndoClearsRedoBranch)
|
|
{
|
|
int counter = 0;
|
|
olive::UndoStack stack;
|
|
stack.push(new TestCommand(&counter), QStringLiteral("First"));
|
|
stack.push(new TestCommand(&counter), QStringLiteral("Second"));
|
|
EXPECT_EQ(counter, 2);
|
|
|
|
stack.undo();
|
|
EXPECT_EQ(counter, 1);
|
|
|
|
stack.push(new TestCommand(&counter), QStringLiteral("Third"));
|
|
EXPECT_EQ(counter, 2);
|
|
EXPECT_FALSE(stack.can_redo());
|
|
}
|
|
|
|
TEST(UndoStack, ResetClearsHistory)
|
|
{
|
|
int counter = 0;
|
|
olive::UndoStack stack;
|
|
stack.push(new TestCommand(&counter), QStringLiteral("Action"));
|
|
EXPECT_EQ(counter, 1);
|
|
|
|
stack.clear();
|
|
EXPECT_FALSE(stack.can_undo());
|
|
EXPECT_FALSE(stack.can_redo());
|
|
EXPECT_EQ(stack.rowCount(), 1);
|
|
}
|
|
|
|
TEST(UndoStack, MultiUndoCommandWithChildren)
|
|
{
|
|
int counter = 0;
|
|
olive::UndoStack stack;
|
|
|
|
auto *multi = new olive::MultiUndoCommand();
|
|
multi->add_child(new TestCommand(&counter));
|
|
multi->add_child(new TestCommand(&counter));
|
|
stack.push(multi, QStringLiteral("Multi"));
|
|
|
|
EXPECT_EQ(counter, 2);
|
|
stack.undo();
|
|
EXPECT_EQ(counter, 0);
|
|
stack.redo();
|
|
EXPECT_EQ(counter, 2);
|
|
}
|