Expand gtest coverage across recently changed modules

Adds ~60 new unit tests covering the modules touched in recent bug-fix
passes and UI refactors:

- RenderTicket: result/finish-count semantics, empty watcher defaults,
  ticket-reuse rejection
- Preferences tabs: behavior options migrated into General/Audio tabs,
  translation context helper, audio-tab initialization
- NodeView: context management, 'Show in Parameter Editor' action wiring
- PreviewAutoCacher: construction, pause toggles, single-frame render
  cancellation, force-cache range
- SeekableWidget/TimeBasedWidget: scroll, marker editing, context reset
- OCIOLutNode: empty/missing/unsupported LUT paths, string direction
  values, file-switching regression coverage
- ProxyManager: working filename, disabled state, empty proxy fields
- Frame/VideoParams/AudioParams/Timecode/ExportFormat/ExportCodec:
  additional edge-case and enumeration coverage

Also fixes the PreferencesAudioTab test crash by initializing
AudioManager in the offscreen test environment.

All tests pass: ctest --output-on-failure
This commit is contained in:
2026-07-13 10:19:30 +08:00
parent b47887e127
commit b7ff687220
14 changed files with 1047 additions and 48 deletions
+144
View File
@@ -0,0 +1,144 @@
#include <gtest/gtest.h>
#include <QCoreApplication>
#include <QtTest/QSignalSpy>
#include "render/renderticket.h"
using namespace olive;
TEST(RenderTicketWatcher, DoesNotEmitFinishedForRunningTicketSynchronously)
{
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
ticket->Start();
RenderTicketWatcher watcher;
QSignalSpy spy(&watcher, &RenderTicketWatcher::Finished);
watcher.SetTicket(ticket);
// The ticket is still running, so the watcher must not emit Finished
// synchronously when SetTicket is called.
EXPECT_EQ(spy.count(), 0);
ticket->Finish();
// Once the ticket finishes, the watcher should emit Finished.
spy.wait(100);
EXPECT_EQ(spy.count(), 1);
}
TEST(RenderTicketWatcher, EmitsFinishedForAlreadyFinishedTicketAsynchronously)
{
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
ticket->Start();
ticket->Finish();
RenderTicketWatcher watcher;
QSignalSpy spy(&watcher, &RenderTicketWatcher::Finished);
watcher.SetTicket(ticket);
// The ticket has already finished. The watcher must not delete itself or
// emit Finished synchronously inside SetTicket, because the caller may still
// need the returned pointer. Instead it should defer the signal.
EXPECT_EQ(spy.count(), 0);
EXPECT_FALSE(watcher.GetTicket() == nullptr);
// Process the queued Finished emission.
QCoreApplication::processEvents();
EXPECT_EQ(spy.count(), 1);
}
TEST(RenderTicketWatcher, CancelMarksTicketAsCancelled)
{
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
ticket->Start();
RenderTicketWatcher watcher;
watcher.SetTicket(ticket);
EXPECT_TRUE(watcher.IsRunning());
EXPECT_FALSE(ticket->IsCancelled());
watcher.Cancel();
EXPECT_TRUE(ticket->IsCancelled());
}
TEST(RenderTicket, HasResultIsFalseWhileRunning)
{
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
ticket->Start();
EXPECT_TRUE(ticket->IsRunning());
EXPECT_FALSE(ticket->HasResult());
}
TEST(RenderTicket, FinishWithValueProvidesResult)
{
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
ticket->Start();
ticket->Finish(QVariant(42));
EXPECT_FALSE(ticket->IsRunning());
EXPECT_TRUE(ticket->HasResult());
EXPECT_EQ(ticket->Get().toInt(), 42);
}
TEST(RenderTicket, FinishCountIncrementsOnEachFinish)
{
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
EXPECT_EQ(ticket->GetFinishCount(), 0);
ticket->Start();
ticket->Finish();
EXPECT_EQ(ticket->GetFinishCount(), 1);
ticket->Start();
ticket->Finish();
EXPECT_EQ(ticket->GetFinishCount(), 2);
}
TEST(RenderTicket, FinishWithoutStartIsIgnored)
{
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
ticket->Finish();
EXPECT_EQ(ticket->GetFinishCount(), 0);
}
TEST(RenderTicketWatcher, DelegatesGetAndHasResultToTicket)
{
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
ticket->Start();
ticket->Finish(QVariant(QStringLiteral("result")));
RenderTicketWatcher watcher;
watcher.SetTicket(ticket);
EXPECT_FALSE(watcher.IsRunning());
EXPECT_TRUE(watcher.HasResult());
EXPECT_EQ(watcher.Get().toString(), QStringLiteral("result"));
}
TEST(RenderTicketWatcher, EmptyWatcherReturnsDefaults)
{
RenderTicketWatcher watcher;
EXPECT_FALSE(watcher.IsRunning());
EXPECT_FALSE(watcher.HasResult());
EXPECT_TRUE(watcher.Get().isNull());
EXPECT_EQ(watcher.GetTicket(), nullptr);
}
TEST(RenderTicketWatcher, SettingTicketTwiceIsRejected)
{
RenderTicketPtr first = std::make_shared<RenderTicket>();
RenderTicketPtr second = std::make_shared<RenderTicket>();
RenderTicketWatcher watcher;
watcher.SetTicket(first);
watcher.SetTicket(second);
EXPECT_EQ(watcher.GetTicket(), first);
}