Files
kdenlive/tests/keyframetest.cpp
Jean-Baptiste Mardelle 5b83daefcc Get rid of ugly public/private hack in tests
Get rid of the `#define private public` hack in tests, hopefully will make FreeBsd happy
2024-06-14 17:31:03 +00:00

267 lines
9.1 KiB
C++

/*
SPDX-FileCopyrightText: 2018-2022 Jean-Baptiste Mardelle <jb@kdenlive.org>
SPDX-FileCopyrightText: 2017-2019 Nicolas Carion <french.ebook.lover@gmail.com>
SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "test_utils.hpp"
// test specific includes
#include "doc/docundostack.hpp"
#include "doc/kdenlivedoc.h"
#include <memory>
using namespace fakeit;
bool test_model_equality(const std::shared_ptr<KeyframeModel> &m1, const std::shared_ptr<KeyframeModel> &m2)
{
// we cheat a bit by simply comparing the underlying map
qDebug() << "Equality test" << m1->keyframesCount() << m2->keyframesCount();
QList<QVariant> model1 = m1->testSerializeKeyframes();
QList<QVariant> model2 = m2->testSerializeKeyframes();
return model1 == model2;
}
bool check_anim_identity(const std::shared_ptr<KeyframeModel> &m)
{
auto m2 = KdenliveTests::cloneModel(m);
return test_model_equality(m, m2);
}
TEST_CASE("Keyframe model", "[KeyframeModel]")
{
// Create timeline
auto binModel = pCore->projectItemModel();
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
// Here we do some trickery to enable testing.
// We mock the project class so that the undoStack function returns our undoStack
KdenliveDoc document(undoStack);
pCore->projectManager()->testSetDocument(&document);
QDateTime documentDate = QDateTime::currentDateTime();
KdenliveTests::updateTimeline(false, QString(), QString(), documentDate, 0);
auto timeline = document.getTimeline(document.uuid());
pCore->projectManager()->testSetActiveTimeline(timeline);
const QString binId = KdenliveTests::createProducer(pCore->getProjectProfile(), "red", binModel, 100, false);
std::shared_ptr<ProjectClip> clip = binModel->getClipByBinID(binId);
auto effectstack = clip->getEffectStack();
effectstack->appendEffect(QStringLiteral("audiobalance"));
REQUIRE(effectstack->checkConsistency());
REQUIRE(effectstack->rowCount() == 1);
auto effect = std::dynamic_pointer_cast<EffectItemModel>(effectstack->getEffectStackRow(0));
effect->prepareKeyframes();
qDebug() << effect->getAssetId() << effect->getAllParameters();
REQUIRE(effect->rowCount() == 1);
QModelIndex index = effect->index(0, 0);
auto model = std::make_shared<KeyframeModel>(effect, index, undoStack);
SECTION("Add/remove + undo")
{
auto state0 = [&]() {
REQUIRE(model->rowCount() == 1);
REQUIRE(check_anim_identity(model));
};
state0();
REQUIRE(KdenliveTests::addKeyframe(model, GenTime(1.1), KeyframeType::Linear, 42));
auto state1 = [&]() {
REQUIRE(model->rowCount() == 2);
REQUIRE(check_anim_identity(model));
REQUIRE(model->hasKeyframe(GenTime(1.1)));
bool ok;
auto k = model->getKeyframe(GenTime(1.1), &ok);
REQUIRE(ok);
auto k0 = model->getKeyframe(GenTime(0), &ok);
REQUIRE(ok);
auto k1 = model->getClosestKeyframe(GenTime(0.655555), &ok);
REQUIRE(ok);
REQUIRE(k1 == k);
auto k2 = model->getNextKeyframe(GenTime(0.5), &ok);
REQUIRE(ok);
REQUIRE(k2 == k);
auto k3 = model->getPrevKeyframe(GenTime(0.5), &ok);
REQUIRE(ok);
REQUIRE(k3 == k0);
auto k4 = model->getPrevKeyframe(GenTime(10), &ok);
REQUIRE(ok);
REQUIRE(k4 == k);
model->getNextKeyframe(GenTime(10), &ok);
REQUIRE_FALSE(ok);
};
state1();
undoStack->undo();
state0();
undoStack->redo();
state1();
REQUIRE(KdenliveTests::addKeyframe(model, GenTime(12.6), KeyframeType::Discrete, 33));
auto state2 = [&]() {
REQUIRE(model->rowCount() == 3);
REQUIRE(check_anim_identity(model));
REQUIRE(model->hasKeyframe(GenTime(1.1)));
REQUIRE(model->hasKeyframe(GenTime(12.6)));
bool ok;
auto k = model->getKeyframe(GenTime(1.1), &ok);
REQUIRE(ok);
auto k0 = model->getKeyframe(GenTime(0), &ok);
REQUIRE(ok);
auto kk = model->getKeyframe(GenTime(12.6), &ok);
REQUIRE(ok);
auto k1 = model->getClosestKeyframe(GenTime(0.655555), &ok);
REQUIRE(ok);
REQUIRE(k1 == k);
auto k2 = model->getNextKeyframe(GenTime(0.5), &ok);
REQUIRE(ok);
REQUIRE(k2 == k);
auto k3 = model->getPrevKeyframe(GenTime(0.5), &ok);
REQUIRE(ok);
REQUIRE(k3 == k0);
auto k4 = model->getPrevKeyframe(GenTime(10), &ok);
REQUIRE(ok);
REQUIRE(k4 == k);
auto k5 = model->getNextKeyframe(GenTime(10), &ok);
REQUIRE(ok);
REQUIRE(k5 == kk);
};
state2();
undoStack->undo();
state1();
undoStack->undo();
state0();
undoStack->redo();
state1();
undoStack->redo();
state2();
REQUIRE(KdenliveTests::removeKeyframe(model, GenTime(1.1)));
auto state3 = [&]() {
REQUIRE(model->rowCount() == 2);
REQUIRE(check_anim_identity(model));
REQUIRE(model->hasKeyframe(GenTime(12.6)));
bool ok;
model->getKeyframe(GenTime(1.1), &ok);
REQUIRE_FALSE(ok);
auto k0 = model->getKeyframe(GenTime(0), &ok);
REQUIRE(ok);
auto kk = model->getKeyframe(GenTime(12.6), &ok);
REQUIRE(ok);
auto k1 = model->getClosestKeyframe(GenTime(0.655555), &ok);
REQUIRE(ok);
REQUIRE(k1 == k0);
auto k2 = model->getNextKeyframe(GenTime(0.5), &ok);
REQUIRE(ok);
REQUIRE(k2 == kk);
auto k3 = model->getPrevKeyframe(GenTime(0.5), &ok);
REQUIRE(ok);
REQUIRE(k3 == k0);
auto k4 = model->getPrevKeyframe(GenTime(10), &ok);
REQUIRE(ok);
REQUIRE(k4 == k0);
auto k5 = model->getNextKeyframe(GenTime(10), &ok);
REQUIRE(ok);
REQUIRE(k5 == kk);
};
state3();
undoStack->undo();
state2();
undoStack->undo();
state1();
undoStack->undo();
state0();
undoStack->redo();
state1();
undoStack->redo();
state2();
undoStack->redo();
state3();
REQUIRE(KdenliveTests::removeAllKeyframes(model));
state0();
REQUIRE(KdenliveTests::removeAllKeyframes(model));
state0();
undoStack->undo();
state0();
undoStack->undo();
state3();
undoStack->redo();
state0();
}
SECTION("Move keyframes + undo")
{
auto state0 = [&]() {
REQUIRE(model->rowCount() == 1);
REQUIRE(check_anim_identity(model));
};
state0();
REQUIRE(KdenliveTests::addKeyframe(model, GenTime(1.1), KeyframeType::Linear, 42));
auto state1 = [&](double pos) {
REQUIRE(model->rowCount() == 2);
REQUIRE(check_anim_identity(model));
REQUIRE(model->hasKeyframe(GenTime(pos)));
bool ok;
auto k = model->getKeyframe(GenTime(pos), &ok);
REQUIRE(ok);
auto k0 = model->getKeyframe(GenTime(0), &ok);
REQUIRE(ok);
auto k1 = model->getClosestKeyframe(GenTime(pos + 10), &ok);
REQUIRE(ok);
REQUIRE(k1 == k);
auto k2 = model->getNextKeyframe(GenTime(pos - 0.3), &ok);
REQUIRE(ok);
REQUIRE(k2 == k);
auto k3 = model->getPrevKeyframe(GenTime(pos - 0.3), &ok);
REQUIRE(ok);
REQUIRE(k3 == k0);
auto k4 = model->getPrevKeyframe(GenTime(pos + 0.3), &ok);
REQUIRE(ok);
REQUIRE(k4 == k);
model->getNextKeyframe(GenTime(pos + 0.3), &ok);
REQUIRE_FALSE(ok);
};
state1(1.1);
REQUIRE(model->moveKeyframe(GenTime(1.1), GenTime(2.6), -1, true));
state1(2.6);
undoStack->undo();
state1(1.1);
undoStack->redo();
state1(2.6);
REQUIRE(model->moveKeyframe(GenTime(2.6), GenTime(6.1), -1, true));
state1(6.1);
undoStack->undo();
state1(2.6);
undoStack->undo();
state1(1.1);
undoStack->redo();
state1(2.6);
undoStack->redo();
state1(6.1);
REQUIRE(KdenliveTests::addKeyframe(model, GenTime(12.6), KeyframeType::Discrete, 33));
// Moving a keyframe past another one another will move it 1 frame before or after.
REQUIRE(model->moveKeyframe(GenTime(6.1), GenTime(14), -1, true));
bool ok;
// There should be no keyframe after 12.6
model->getNextKeyframe(GenTime(12.6), &ok);
REQUIRE_FALSE(ok);
undoStack->undo();
undoStack->undo();
state1(6.1);
}
clip.reset();
timeline.reset();
pCore->projectManager()->closeCurrentDocument(false, false);
}