style: reformat C/C++ sources and headers with clang-format

Run clang-format over all project C/C++ source and header files
(.c, .cpp, .cc, .h, .hpp, .hh, .m, .mm) under app/ and tests/.
Non-source files (svg, qm, qrc, etc.) were not touched.
This commit is contained in:
2026-07-13 15:34:11 +08:00
parent 6a696bc234
commit f03b6b58ff
61 changed files with 2873 additions and 2740 deletions
+2 -1
View File
@@ -11,7 +11,8 @@ extern "C" {
#include <libavutil/channel_layout.h>
}
namespace {
namespace
{
olive::core::AudioParams MakeStereoParams()
{
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -13,8 +13,8 @@ TEST(AudioSynchronizer, PlacesCandidateBySourceStartTime)
candidate.has_source_start_time = true;
const olive::AudioSynchronizer::Placement placement =
olive::AudioSynchronizer::PlaceBySourceTime(
reference, candidate, olive::core::rational(10));
olive::AudioSynchronizer::PlaceBySourceTime(reference, candidate,
olive::core::rational(10));
ASSERT_TRUE(placement.valid);
EXPECT_EQ(placement.timeline_in, olive::core::rational(22));
@@ -33,8 +33,8 @@ TEST(AudioSynchronizer, AccountsForMediaInWhenPlacingBySourceTime)
candidate.has_source_start_time = true;
const olive::AudioSynchronizer::Placement placement =
olive::AudioSynchronizer::PlaceBySourceTime(
reference, candidate, olive::core::rational(20));
olive::AudioSynchronizer::PlaceBySourceTime(reference, candidate,
olive::core::rational(20));
ASSERT_TRUE(placement.valid);
EXPECT_EQ(placement.timeline_in, olive::core::rational(23));
@@ -49,8 +49,8 @@ TEST(AudioSynchronizer, RejectsMissingSourceStartTime)
olive::AudioSynchronizer::SourceClip candidate;
const olive::AudioSynchronizer::Placement placement =
olive::AudioSynchronizer::PlaceBySourceTime(
reference, candidate, olive::core::rational(10));
olive::AudioSynchronizer::PlaceBySourceTime(reference, candidate,
olive::core::rational(10));
EXPECT_FALSE(placement.valid);
}
+12 -15
View File
@@ -9,7 +9,8 @@ extern "C" {
#include <libavutil/channel_layout.h>
}
namespace {
namespace
{
olive::core::AudioParams MakeMonoParams()
{
@@ -46,13 +47,11 @@ TEST(AudioWaveformSync, ExtractsRmsEnvelope)
TEST(AudioWaveformSync, EstimatesCandidateLag)
{
const QVector<float> reference_values = {
0.0f, 0.0f, 0.8f, 0.8f, 0.1f, 0.1f, 0.6f, 0.6f, 0.0f, 0.0f
};
const QVector<float> candidate_values = {
0.0f, 0.0f, 0.0f, 0.0f, 0.8f, 0.8f, 0.1f,
0.1f, 0.6f, 0.6f, 0.0f, 0.0f
};
const QVector<float> reference_values = { 0.0f, 0.0f, 0.8f, 0.8f, 0.1f,
0.1f, 0.6f, 0.6f, 0.0f, 0.0f };
const QVector<float> candidate_values = { 0.0f, 0.0f, 0.0f, 0.0f,
0.8f, 0.8f, 0.1f, 0.1f,
0.6f, 0.6f, 0.0f, 0.0f };
const olive::AudioWaveformSync::OffsetResult result =
olive::AudioWaveformSync::EstimateOffset(
@@ -65,13 +64,11 @@ TEST(AudioWaveformSync, EstimatesCandidateLag)
TEST(AudioWaveformSync, EstimatesCandidateLead)
{
const QVector<float> reference_values = {
0.0f, 0.0f, 0.0f, 0.0f, 0.9f, 0.9f, 0.3f,
0.3f, 0.7f, 0.7f, 0.0f, 0.0f
};
const QVector<float> candidate_values = {
0.9f, 0.9f, 0.3f, 0.3f, 0.7f, 0.7f, 0.0f, 0.0f
};
const QVector<float> reference_values = { 0.0f, 0.0f, 0.0f, 0.0f,
0.9f, 0.9f, 0.3f, 0.3f,
0.7f, 0.7f, 0.0f, 0.0f };
const QVector<float> candidate_values = { 0.9f, 0.9f, 0.3f, 0.3f,
0.7f, 0.7f, 0.0f, 0.0f };
const olive::AudioWaveformSync::OffsetResult result =
olive::AudioWaveformSync::EstimateOffset(
+2 -1
View File
@@ -11,7 +11,8 @@ TEST(CodecDecoder, RetrieveVideoFrameFromDemoMp4)
.filePath(QStringLiteral("tests/demo.mp4"));
ASSERT_TRUE(QFileInfo::exists(path));
olive::DecoderPtr decoder = olive::Decoder::CreateFromID(QStringLiteral("ffmpeg"));
olive::DecoderPtr decoder =
olive::Decoder::CreateFromID(QStringLiteral("ffmpeg"));
ASSERT_TRUE(decoder);
ASSERT_TRUE(decoder->Open(olive::Decoder::CodecStream(path, 0, nullptr)));
+10 -12
View File
@@ -2,7 +2,8 @@
#include "codec/encoder.h"
namespace {
namespace
{
class TestEncoder final : public olive::Encoder {
public:
explicit TestEncoder(const olive::EncodingParams &params)
@@ -57,8 +58,8 @@ TEST(CodecEncoder, ImageSequenceFilenames)
QStringLiteral("frame_[####].png")),
QStringLiteral("frame.png"));
const QString filename = encoder.GetFilenameForFrame(
olive::core::rational(1, 24));
const QString filename =
encoder.GetFilenameForFrame(olive::core::rational(1, 24));
EXPECT_EQ(filename, QStringLiteral("frame_0001.png"));
}
@@ -66,21 +67,18 @@ TEST(CodecEncoder, MatrixGeneration)
{
using Method = olive::EncodingParams::VideoScalingMethod;
QMatrix4x4 stretch =
olive::EncodingParams::GenerateMatrix(Method::kStretch, 1920, 1080,
1280, 720);
QMatrix4x4 stretch = olive::EncodingParams::GenerateMatrix(
Method::kStretch, 1920, 1080, 1280, 720);
EXPECT_TRUE(qFuzzyCompare(stretch(0, 0), 1.0f));
EXPECT_TRUE(qFuzzyCompare(stretch(1, 1), 1.0f));
QMatrix4x4 fit =
olive::EncodingParams::GenerateMatrix(Method::kFit, 1920, 1080,
1024, 1024);
QMatrix4x4 fit = olive::EncodingParams::GenerateMatrix(Method::kFit, 1920,
1080, 1024, 1024);
EXPECT_TRUE(qFuzzyCompare(fit(0, 0), 1.0f));
EXPECT_FALSE(qFuzzyCompare(fit(1, 1), 1.0f));
QMatrix4x4 crop =
olive::EncodingParams::GenerateMatrix(Method::kCrop, 1920, 1080,
1024, 1024);
QMatrix4x4 crop = olive::EncodingParams::GenerateMatrix(Method::kCrop, 1920,
1080, 1024, 1024);
EXPECT_FALSE(qFuzzyCompare(crop(0, 0), 1.0f));
EXPECT_TRUE(qFuzzyCompare(crop(1, 1), 1.0f));
}
+2 -1
View File
@@ -12,7 +12,8 @@ TEST(CodecExportFormat, NamesAndExtensions)
QStringLiteral("mxf"));
EXPECT_EQ(ExportFormat::GetName(ExportFormat::kFormatCount),
QStringLiteral("Unknown"));
EXPECT_TRUE(ExportFormat::GetExtension(ExportFormat::kFormatCount).isEmpty());
EXPECT_TRUE(
ExportFormat::GetExtension(ExportFormat::kFormatCount).isEmpty());
}
TEST(CodecExportFormat, AllFormatsHaveNames)
+10 -10
View File
@@ -44,9 +44,9 @@ TEST(CodecFrame, AllocateMatchesLineSize)
TEST(CodecFrame, DestroyDeallocatesData)
{
olive::FramePtr frame = olive::Frame::Create();
frame->set_video_params(olive::VideoParams(
8, 8, olive::core::PixelFormat::U8,
olive::VideoParams::kRGBAChannelCount));
frame->set_video_params(
olive::VideoParams(8, 8, olive::core::PixelFormat::U8,
olive::VideoParams::kRGBAChannelCount));
frame->allocate();
EXPECT_TRUE(frame->is_allocated());
@@ -55,7 +55,6 @@ TEST(CodecFrame, DestroyDeallocatesData)
EXPECT_EQ(frame->data(), nullptr);
}
TEST(CodecFrame, AllocateInvalidParamsFails)
{
olive::Frame frame;
@@ -157,13 +156,15 @@ TEST(CodecFrame, InterlaceFrames)
TEST(CodecFrame, InterlaceIncompatibleReturnsNull)
{
olive::FramePtr top = olive::Frame::Create();
top->set_video_params(olive::VideoParams(
4, 4, olive::core::PixelFormat::U8, olive::VideoParams::kRGBAChannelCount));
top->set_video_params(
olive::VideoParams(4, 4, olive::core::PixelFormat::U8,
olive::VideoParams::kRGBAChannelCount));
top->allocate();
olive::FramePtr bottom = olive::Frame::Create();
bottom->set_video_params(olive::VideoParams(
8, 8, olive::core::PixelFormat::U8, olive::VideoParams::kRGBAChannelCount));
bottom->set_video_params(
olive::VideoParams(8, 8, olive::core::PixelFormat::U8,
olive::VideoParams::kRGBAChannelCount));
bottom->allocate();
EXPECT_EQ(olive::Frame::Interlace(top, bottom), nullptr);
@@ -177,8 +178,7 @@ TEST(CodecFrame, ConvertU8ToU16)
frame->set_video_params(params);
frame->allocate();
olive::FramePtr converted =
frame->convert(olive::core::PixelFormat::U16);
olive::FramePtr converted = frame->convert(olive::core::PixelFormat::U16);
ASSERT_NE(converted, nullptr);
EXPECT_EQ(converted->format(), olive::core::PixelFormat::U16);
EXPECT_EQ(converted->width(), 4);
+58 -68
View File
@@ -18,7 +18,8 @@
namespace OCIO = OCIO_NAMESPACE;
namespace {
namespace
{
bool IsOakSupportedLutExtension(QString suffix)
{
@@ -31,19 +32,19 @@ bool IsOakSupportedLutExtension(QString suffix)
QString WriteTestCube(QTemporaryDir *dir)
{
const QString path = QDir(dir->path()).filePath(QStringLiteral("invert.cube"));
const QString path =
QDir(dir->path()).filePath(QStringLiteral("invert.cube"));
QFile file(path);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return QString();
}
const QByteArray data =
"TITLE \"Oak test invert\"\n"
"LUT_1D_SIZE 2\n"
"DOMAIN_MIN 0.0 0.0 0.0\n"
"DOMAIN_MAX 1.0 1.0 1.0\n"
"1.0 1.0 1.0\n"
"0.0 0.0 0.0\n";
const QByteArray data = "TITLE \"Oak test invert\"\n"
"LUT_1D_SIZE 2\n"
"DOMAIN_MIN 0.0 0.0 0.0\n"
"DOMAIN_MAX 1.0 1.0 1.0\n"
"1.0 1.0 1.0\n"
"0.0 0.0 0.0\n";
file.write(data);
file.close();
return path;
@@ -87,9 +88,10 @@ protected:
}
}
virtual void ProcessColorTransform(olive::TexturePtr destination,
const olive::Node *node,
const olive::ColorTransformJob *job) override
virtual void
ProcessColorTransform(olive::TexturePtr destination,
const olive::Node *node,
const olive::ColorTransformJob *job) override
{
Q_UNUSED(destination)
Q_UNUSED(node)
@@ -110,11 +112,12 @@ protected:
}
};
QString WriteTestCubeLut(QTemporaryDir *dir, const char *title,
float low, float high)
QString WriteTestCubeLut(QTemporaryDir *dir, const char *title, float low,
float high)
{
const QString path = QDir(dir->path()).filePath(
QStringLiteral("%1.cube").arg(QString::fromUtf8(title)));
const QString path =
QDir(dir->path())
.filePath(QStringLiteral("%1.cube").arg(QString::fromUtf8(title)));
QFile file(path);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return QString();
@@ -147,14 +150,13 @@ QString WriteAsymmetricCube(QTemporaryDir *dir)
return QString();
}
const QByteArray data =
"TITLE \"Oak test asymmetric\"\n"
"LUT_1D_SIZE 3\n"
"DOMAIN_MIN 0.0 0.0 0.0\n"
"DOMAIN_MAX 1.0 1.0 1.0\n"
"0.00 0.00 0.00\n"
"0.75 0.75 0.75\n"
"1.00 1.00 1.00\n";
const QByteArray data = "TITLE \"Oak test asymmetric\"\n"
"LUT_1D_SIZE 3\n"
"DOMAIN_MIN 0.0 0.0 0.0\n"
"DOMAIN_MAX 1.0 1.0 1.0\n"
"0.00 0.00 0.00\n"
"0.75 0.75 0.75\n"
"1.00 1.00 1.00\n";
file.write(data);
file.close();
return path;
@@ -231,7 +233,8 @@ TEST(ColorLut, CubeFileTransformConvertsColor)
olive::ColorProcessor::Create(config->getProcessor(transform));
ASSERT_TRUE(processor);
const olive::Color out = processor->ConvertColor(olive::Color(0.25f, 0.50f, 0.75f, 1.0f));
const olive::Color out =
processor->ConvertColor(olive::Color(0.25f, 0.50f, 0.75f, 1.0f));
EXPECT_NEAR(out.red(), 0.75f, 0.02f);
EXPECT_NEAR(out.green(), 0.50f, 0.02f);
EXPECT_NEAR(out.blue(), 0.25f, 0.02f);
@@ -240,9 +243,8 @@ TEST(ColorLut, CubeFileTransformConvertsColor)
TEST(ColorV04, FactoryCreatesColorNodes)
{
std::unique_ptr<olive::Node> lut(
olive::NodeFactory::CreateFromFactoryIndex(
olive::NodeFactory::kOCIOLut));
std::unique_ptr<olive::Node> lut(olive::NodeFactory::CreateFromFactoryIndex(
olive::NodeFactory::kOCIOLut));
ASSERT_NE(lut, nullptr);
EXPECT_EQ(lut->id(), QStringLiteral("org.olivevideoeditor.Olive.ociolut"));
@@ -260,8 +262,8 @@ TEST(ColorV04, FactoryCreatesColorNodes)
olive::ThreeWayColorNode::kHighlightsColorInput));
const olive::Color neutral =
three_way->GetStandardValue(
olive::ThreeWayColorNode::kMidtonesColorInput)
three_way
->GetStandardValue(olive::ThreeWayColorNode::kMidtonesColorInput)
.value<olive::Color>();
EXPECT_FLOAT_EQ(neutral.red(), 0.5f);
EXPECT_FLOAT_EQ(neutral.green(), 0.5f);
@@ -306,9 +308,8 @@ TEST(ColorLutNode, ForwardDirectionInvertsPixels)
olive::Node::ConnectEdge(
solid, olive::NodeInput(lut, olive::OCIOLutNode::kTextureInput));
const olive::VideoParams params(
16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
const olive::VideoParams params(16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
PixelColorTransformTraverser traverser;
traverser.SetCacheVideoParams(params);
@@ -354,9 +355,8 @@ TEST(ColorLutNode, InverseDirectionReversesForwardTransform)
olive::Node::ConnectEdge(
solid, olive::NodeInput(lut, olive::OCIOLutNode::kTextureInput));
const olive::VideoParams params(
16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
const olive::VideoParams params(16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
PixelColorTransformTraverser traverser;
traverser.SetCacheVideoParams(params);
@@ -402,9 +402,8 @@ TEST(ColorLutNode, SwitchingDirectionUpdatesProcessorAndPixels)
olive::Node::ConnectEdge(
solid, olive::NodeInput(lut, olive::OCIOLutNode::kTextureInput));
const olive::VideoParams params(
16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
const olive::VideoParams params(16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
// First render: forward direction.
PixelColorTransformTraverser forward_traverser;
@@ -471,9 +470,8 @@ TEST(ColorLutNode, EmptyFilePathLeavesProcessorNull)
olive::Node::ConnectEdge(
solid, olive::NodeInput(lut, olive::OCIOLutNode::kTextureInput));
const olive::VideoParams params(
16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
const olive::VideoParams params(16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
PixelColorTransformTraverser traverser;
traverser.SetCacheVideoParams(params);
@@ -503,14 +501,13 @@ TEST(ColorLutNode, MissingFilePathLeavesProcessorNull)
auto *lut = new olive::OCIOLutNode();
lut->setParent(&project);
lut->SetStandardValue(olive::OCIOLutNode::kFileInput,
QStringLiteral("/nonexistent/path/lut.cube"));
QStringLiteral("/nonexistent/path/lut.cube"));
olive::Node::ConnectEdge(
solid, olive::NodeInput(lut, olive::OCIOLutNode::kTextureInput));
const olive::VideoParams params(
16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
const olive::VideoParams params(16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
PixelColorTransformTraverser traverser;
traverser.SetCacheVideoParams(params);
@@ -538,14 +535,13 @@ TEST(ColorLutNode, UnsupportedExtensionLeavesProcessorNull)
auto *lut = new olive::OCIOLutNode();
lut->setParent(&project);
lut->SetStandardValue(olive::OCIOLutNode::kFileInput,
QStringLiteral("/tmp/lut.txt"));
QStringLiteral("/tmp/lut.txt"));
olive::Node::ConnectEdge(
solid, olive::NodeInput(lut, olive::OCIOLutNode::kTextureInput));
const olive::VideoParams params(
16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
const olive::VideoParams params(16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
PixelColorTransformTraverser traverser;
traverser.SetCacheVideoParams(params);
@@ -579,14 +575,13 @@ TEST(ColorLutNode, DirectionStringValuesAreAccepted)
lut->setParent(&project);
lut->SetStandardValue(olive::OCIOLutNode::kFileInput, path);
lut->SetStandardValue(olive::OCIOLutNode::kDirectionInput,
QStringLiteral("forward"));
QStringLiteral("forward"));
olive::Node::ConnectEdge(
solid, olive::NodeInput(lut, olive::OCIOLutNode::kTextureInput));
const olive::VideoParams params(
16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
const olive::VideoParams params(16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
PixelColorTransformTraverser traverser;
traverser.SetCacheVideoParams(params);
@@ -626,14 +621,13 @@ TEST(ColorLutNode, DirectionStringInverseIsAccepted)
lut->setParent(&project);
lut->SetStandardValue(olive::OCIOLutNode::kFileInput, path);
lut->SetStandardValue(olive::OCIOLutNode::kDirectionInput,
QStringLiteral("inverse"));
QStringLiteral("inverse"));
olive::Node::ConnectEdge(
solid, olive::NodeInput(lut, olive::OCIOLutNode::kTextureInput));
const olive::VideoParams params(
16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
const olive::VideoParams params(16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
PixelColorTransformTraverser traverser;
traverser.SetCacheVideoParams(params);
@@ -676,9 +670,8 @@ TEST(ColorLutNode, ReusingSameFileDoesNotCrash)
olive::Node::ConnectEdge(
solid, olive::NodeInput(lut, olive::OCIOLutNode::kTextureInput));
const olive::VideoParams params(
16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
const olive::VideoParams params(16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
// Render twice; the second render should reuse the cached processor.
for (int i = 0; i < 2; ++i) {
@@ -708,10 +701,8 @@ TEST(ColorLutNode, SwitchingBackToOriginalFileRestoresOriginalPixels)
QTemporaryDir dir;
ASSERT_TRUE(dir.isValid());
const QString invert_path = WriteTestCubeLut(
&dir, "invert", 0.0f, 1.0f);
const QString boost_path = WriteTestCubeLut(
&dir, "boost", 0.5f, 1.0f);
const QString invert_path = WriteTestCubeLut(&dir, "invert", 0.0f, 1.0f);
const QString boost_path = WriteTestCubeLut(&dir, "boost", 0.5f, 1.0f);
ASSERT_FALSE(invert_path.isEmpty());
ASSERT_FALSE(boost_path.isEmpty());
@@ -728,9 +719,8 @@ TEST(ColorLutNode, SwitchingBackToOriginalFileRestoresOriginalPixels)
olive::Node::ConnectEdge(
solid, olive::NodeInput(lut, olive::OCIOLutNode::kTextureInput));
const olive::VideoParams params(
16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
const olive::VideoParams params(16, 16, olive::core::PixelFormat::F32,
olive::VideoParams::kRGBAChannelCount);
auto render = [&]() {
PixelColorTransformTraverser traverser;
+41 -41
View File
@@ -4,80 +4,80 @@
TEST(CommonCommandLineParser, OptionWithoutArgument)
{
CommandLineParser parser;
const CommandLineParser::Option *opt = parser.AddOption(
{QStringLiteral("help"), QStringLiteral("h")},
QStringLiteral("Show help"), false);
CommandLineParser parser;
const CommandLineParser::Option *opt =
parser.AddOption({ QStringLiteral("help"), QStringLiteral("h") },
QStringLiteral("Show help"), false);
parser.Process({QStringLiteral("app"), QStringLiteral("-help")});
parser.Process({ QStringLiteral("app"), QStringLiteral("-help") });
EXPECT_TRUE(opt->IsSet());
EXPECT_TRUE(opt->IsSet());
}
TEST(CommonCommandLineParser, ShortOption)
{
CommandLineParser parser;
const CommandLineParser::Option *opt = parser.AddOption(
{QStringLiteral("help"), QStringLiteral("h")},
QStringLiteral("Show help"), false);
CommandLineParser parser;
const CommandLineParser::Option *opt =
parser.AddOption({ QStringLiteral("help"), QStringLiteral("h") },
QStringLiteral("Show help"), false);
parser.Process({QStringLiteral("app"), QStringLiteral("-h")});
parser.Process({ QStringLiteral("app"), QStringLiteral("-h") });
EXPECT_TRUE(opt->IsSet());
EXPECT_TRUE(opt->IsSet());
}
TEST(CommonCommandLineParser, OptionWithArgument)
{
CommandLineParser parser;
const CommandLineParser::Option *opt = parser.AddOption(
{QStringLiteral("project")}, QStringLiteral("Project file"), true,
QStringLiteral("file"));
CommandLineParser parser;
const CommandLineParser::Option *opt = parser.AddOption(
{ QStringLiteral("project") }, QStringLiteral("Project file"), true,
QStringLiteral("file"));
parser.Process({QStringLiteral("app"), QStringLiteral("-project"),
QStringLiteral("test.ove")});
parser.Process({ QStringLiteral("app"), QStringLiteral("-project"),
QStringLiteral("test.ove") });
EXPECT_TRUE(opt->IsSet());
EXPECT_EQ(opt->GetSetting(), QStringLiteral("test.ove"));
EXPECT_TRUE(opt->IsSet());
EXPECT_EQ(opt->GetSetting(), QStringLiteral("test.ove"));
}
TEST(CommonCommandLineParser, PositionalArgument)
{
CommandLineParser parser;
const CommandLineParser::PositionalArgument *arg =
parser.AddPositionalArgument(QStringLiteral("filename"),
QStringLiteral("Project file"), true);
CommandLineParser parser;
const CommandLineParser::PositionalArgument *arg =
parser.AddPositionalArgument(QStringLiteral("filename"),
QStringLiteral("Project file"), true);
parser.Process({QStringLiteral("app"), QStringLiteral("test.ove")});
parser.Process({ QStringLiteral("app"), QStringLiteral("test.ove") });
EXPECT_EQ(arg->GetSetting(), QStringLiteral("test.ove"));
EXPECT_EQ(arg->GetSetting(), QStringLiteral("test.ove"));
}
TEST(CommonCommandLineParser, UnknownOptionWarning)
{
CommandLineParser parser;
parser.AddOption({QStringLiteral("known")}, QStringLiteral("Known"));
CommandLineParser parser;
parser.AddOption({ QStringLiteral("known") }, QStringLiteral("Known"));
// Should not crash; unknown option is logged
parser.Process({QStringLiteral("app"), QStringLiteral("-unknown")});
// Should not crash; unknown option is logged
parser.Process({ QStringLiteral("app"), QStringLiteral("-unknown") });
}
TEST(CommonCommandLineParser, UnknownPositionalWarning)
{
CommandLineParser parser;
CommandLineParser parser;
// Should not crash; unknown positional is logged
parser.Process({QStringLiteral("app"), QStringLiteral("extra")});
// Should not crash; unknown positional is logged
parser.Process({ QStringLiteral("app"), QStringLiteral("extra") });
}
TEST(CommonCommandLineParser, HiddenOptionExcludedFromHelp)
{
CommandLineParser parser;
parser.AddOption({QStringLiteral("visible")}, QStringLiteral("Visible"));
parser.AddOption({QStringLiteral("hidden")}, QStringLiteral("Hidden"),
false, QString(), true);
parser.AddPositionalArgument(QStringLiteral("file"),
QStringLiteral("Input file"));
CommandLineParser parser;
parser.AddOption({ QStringLiteral("visible") }, QStringLiteral("Visible"));
parser.AddOption({ QStringLiteral("hidden") }, QStringLiteral("Hidden"),
false, QString(), true);
parser.AddPositionalArgument(QStringLiteral("file"),
QStringLiteral("Input file"));
// Should not crash; hidden option should be skipped during help output
parser.PrintHelp("/usr/bin/app");
// Should not crash; hidden option should be skipped during help output
parser.PrintHelp("/usr/bin/app");
}
+4 -2
View File
@@ -11,7 +11,8 @@ TEST(CommonCurrent, SetAndGetVideoParams)
params.set_height(1080);
Current::getInstance().setCurrentVideoParams(params);
const olive::VideoParams &stored = Current::getInstance().currentVideoParams();
const olive::VideoParams &stored =
Current::getInstance().currentVideoParams();
EXPECT_EQ(stored.width(), 1920);
EXPECT_EQ(stored.height(), 1080);
}
@@ -22,6 +23,7 @@ TEST(CommonCurrent, SetAndGetAudioParams)
params.set_sample_rate(48000);
Current::getInstance().setCurrentAudioParams(params);
const olive::AudioParams &stored = Current::getInstance().currentAudioParams();
const olive::AudioParams &stored =
Current::getInstance().currentAudioParams();
EXPECT_EQ(stored.sample_rate(), 48000);
}
+7 -7
View File
@@ -4,13 +4,13 @@
TEST(CommonDebug, DebugHandlerFormatsAllLevels)
{
// Install handler and restore after test
QtMessageHandler old = qInstallMessageHandler(olive::DebugHandler);
// Install handler and restore after test
QtMessageHandler old = qInstallMessageHandler(olive::DebugHandler);
qDebug() << "debug message";
qInfo() << "info message";
qWarning() << "warning message";
qCritical() << "critical message";
qDebug() << "debug message";
qInfo() << "info message";
qWarning() << "warning message";
qCritical() << "critical message";
qInstallMessageHandler(old);
qInstallMessageHandler(old);
}
+13 -13
View File
@@ -4,49 +4,49 @@
TEST(CommonDecibel, FromLinearZeroReturnsMinimum)
{
EXPECT_DOUBLE_EQ(olive::Decibel::fromLinear(0.0), olive::Decibel::MINIMUM);
EXPECT_DOUBLE_EQ(olive::Decibel::fromLinear(0.0), olive::Decibel::MINIMUM);
}
TEST(CommonDecibel, FromLinearOneReturnsZero)
{
EXPECT_DOUBLE_EQ(olive::Decibel::fromLinear(1.0), 0.0);
EXPECT_DOUBLE_EQ(olive::Decibel::fromLinear(1.0), 0.0);
}
TEST(CommonDecibel, FromLinearTenReturnsTwenty)
{
EXPECT_DOUBLE_EQ(olive::Decibel::fromLinear(10.0), 20.0);
EXPECT_DOUBLE_EQ(olive::Decibel::fromLinear(10.0), 20.0);
}
TEST(CommonDecibel, ToLinearZeroReturnsOne)
{
EXPECT_DOUBLE_EQ(olive::Decibel::toLinear(0.0), 1.0);
EXPECT_DOUBLE_EQ(olive::Decibel::toLinear(0.0), 1.0);
}
TEST(CommonDecibel, ToLinearMinimumReturnsZero)
{
EXPECT_DOUBLE_EQ(olive::Decibel::toLinear(olive::Decibel::MINIMUM), 0.0);
EXPECT_DOUBLE_EQ(olive::Decibel::toLinear(olive::Decibel::MINIMUM), 0.0);
}
TEST(CommonDecibel, ToLinearTwentyReturnsTen)
{
EXPECT_DOUBLE_EQ(olive::Decibel::toLinear(20.0), 10.0);
EXPECT_DOUBLE_EQ(olive::Decibel::toLinear(20.0), 10.0);
}
TEST(CommonDecibel, FromLogarithmicAtEdges)
{
EXPECT_DOUBLE_EQ(olive::Decibel::fromLogarithmic(0.0),
olive::Decibel::MINIMUM);
EXPECT_DOUBLE_EQ(olive::Decibel::fromLogarithmic(1.0), 0.0);
EXPECT_DOUBLE_EQ(olive::Decibel::fromLogarithmic(0.0),
olive::Decibel::MINIMUM);
EXPECT_DOUBLE_EQ(olive::Decibel::fromLogarithmic(1.0), 0.0);
}
TEST(CommonDecibel, ToLogarithmicAtEdges)
{
EXPECT_DOUBLE_EQ(olive::Decibel::toLogarithmic(0.0), 1.0);
EXPECT_DOUBLE_EQ(olive::Decibel::toLogarithmic(0.0), 1.0);
}
TEST(CommonDecibel, LinearLogarithmicRoundTrip)
{
EXPECT_NEAR(olive::Decibel::LogarithmicToLinear(
olive::Decibel::LinearToLogarithmic(0.5)),
0.5, 1e-6);
EXPECT_NEAR(olive::Decibel::LogarithmicToLinear(
olive::Decibel::LinearToLogarithmic(0.5)),
0.5, 1e-6);
}
+8 -8
View File
@@ -4,20 +4,20 @@
TEST(CommonDigit, SingleDigit)
{
EXPECT_EQ(olive::GetDigitCount(0), 1);
EXPECT_EQ(olive::GetDigitCount(5), 1);
EXPECT_EQ(olive::GetDigitCount(-5), 1);
EXPECT_EQ(olive::GetDigitCount(0), 1);
EXPECT_EQ(olive::GetDigitCount(5), 1);
EXPECT_EQ(olive::GetDigitCount(-5), 1);
}
TEST(CommonDigit, MultipleDigits)
{
EXPECT_EQ(olive::GetDigitCount(10), 2);
EXPECT_EQ(olive::GetDigitCount(999), 3);
EXPECT_EQ(olive::GetDigitCount(1000), 4);
EXPECT_EQ(olive::GetDigitCount(-12345), 5);
EXPECT_EQ(olive::GetDigitCount(10), 2);
EXPECT_EQ(olive::GetDigitCount(999), 3);
EXPECT_EQ(olive::GetDigitCount(1000), 4);
EXPECT_EQ(olive::GetDigitCount(-12345), 5);
}
TEST(CommonDigit, LargeValue)
{
EXPECT_EQ(olive::GetDigitCount(123456789012345LL), 15);
EXPECT_EQ(olive::GetDigitCount(123456789012345LL), 15);
}
+120 -115
View File
@@ -6,144 +6,149 @@ using namespace olive;
TEST(CommonFFmpegUtils, GetNativeSampleFormatMapsCorrectly)
{
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_U8),
SampleFormat::U8);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S16),
SampleFormat::S16);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S32),
SampleFormat::S32);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S64),
SampleFormat::S64);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_FLT),
SampleFormat::F32);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_DBL),
SampleFormat::F64);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_U8P),
SampleFormat::U8P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S16P),
SampleFormat::S16P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S32P),
SampleFormat::S32P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S64P),
SampleFormat::S64P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_FLTP),
SampleFormat::F32P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_DBLP),
SampleFormat::F64P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_NONE),
SampleFormat::INVALID);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_U8),
SampleFormat::U8);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S16),
SampleFormat::S16);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S32),
SampleFormat::S32);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S64),
SampleFormat::S64);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_FLT),
SampleFormat::F32);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_DBL),
SampleFormat::F64);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_U8P),
SampleFormat::U8P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S16P),
SampleFormat::S16P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S32P),
SampleFormat::S32P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S64P),
SampleFormat::S64P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_FLTP),
SampleFormat::F32P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_DBLP),
SampleFormat::F64P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_NONE),
SampleFormat::INVALID);
}
TEST(CommonFFmpegUtils, GetFFmpegSampleFormatMapsCorrectly)
{
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::U8),
AV_SAMPLE_FMT_U8);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S16),
AV_SAMPLE_FMT_S16);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S32),
AV_SAMPLE_FMT_S32);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S64),
AV_SAMPLE_FMT_S64);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F32),
AV_SAMPLE_FMT_FLT);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F64),
AV_SAMPLE_FMT_DBL);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::U8P),
AV_SAMPLE_FMT_U8P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S16P),
AV_SAMPLE_FMT_S16P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S32P),
AV_SAMPLE_FMT_S32P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S64P),
AV_SAMPLE_FMT_S64P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F32P),
AV_SAMPLE_FMT_FLTP);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F64P),
AV_SAMPLE_FMT_DBLP);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::INVALID),
AV_SAMPLE_FMT_NONE);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::U8),
AV_SAMPLE_FMT_U8);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S16),
AV_SAMPLE_FMT_S16);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S32),
AV_SAMPLE_FMT_S32);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S64),
AV_SAMPLE_FMT_S64);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F32),
AV_SAMPLE_FMT_FLT);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F64),
AV_SAMPLE_FMT_DBL);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::U8P),
AV_SAMPLE_FMT_U8P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S16P),
AV_SAMPLE_FMT_S16P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S32P),
AV_SAMPLE_FMT_S32P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S64P),
AV_SAMPLE_FMT_S64P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F32P),
AV_SAMPLE_FMT_FLTP);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F64P),
AV_SAMPLE_FMT_DBLP);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::INVALID),
AV_SAMPLE_FMT_NONE);
}
TEST(CommonFFmpegUtils, GetSwsColorspaceFromAVColorSpace)
{
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_BT709),
SWS_CS_ITU709);
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_FCC),
SWS_CS_FCC);
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_BT470BG),
SWS_CS_ITU624);
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_SMPTE170M),
SWS_CS_SMPTE170M);
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_SMPTE240M),
SWS_CS_SMPTE240M);
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_BT2020_NCL),
SWS_CS_BT2020);
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_UNSPECIFIED),
SWS_CS_DEFAULT);
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_BT709),
SWS_CS_ITU709);
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_FCC),
SWS_CS_FCC);
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_BT470BG),
SWS_CS_ITU624);
EXPECT_EQ(
FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_SMPTE170M),
SWS_CS_SMPTE170M);
EXPECT_EQ(
FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_SMPTE240M),
SWS_CS_SMPTE240M);
EXPECT_EQ(
FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_BT2020_NCL),
SWS_CS_BT2020);
EXPECT_EQ(
FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_UNSPECIFIED),
SWS_CS_DEFAULT);
}
TEST(CommonFFmpegUtils, ConvertJPEGSpaceToRegularSpace)
{
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ420P),
AV_PIX_FMT_YUV420P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ422P),
AV_PIX_FMT_YUV422P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ444P),
AV_PIX_FMT_YUV444P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ440P),
AV_PIX_FMT_YUV440P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ411P),
AV_PIX_FMT_YUV411P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUV420P),
AV_PIX_FMT_YUV420P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ420P),
AV_PIX_FMT_YUV420P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ422P),
AV_PIX_FMT_YUV422P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ444P),
AV_PIX_FMT_YUV444P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ440P),
AV_PIX_FMT_YUV440P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ411P),
AV_PIX_FMT_YUV411P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUV420P),
AV_PIX_FMT_YUV420P);
}
TEST(CommonFFmpegUtils, GetCompatiblePixelFormatNative)
{
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::U8),
PixelFormat::U8);
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::U10),
PixelFormat::U8);
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::U16),
PixelFormat::U16);
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::F16),
PixelFormat::U16);
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::F32),
PixelFormat::U16);
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::INVALID),
PixelFormat::INVALID);
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::U8),
PixelFormat::U8);
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::U10),
PixelFormat::U8);
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::U16),
PixelFormat::U16);
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::F16),
PixelFormat::U16);
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::F32),
PixelFormat::U16);
EXPECT_EQ(FFmpegUtils::GetCompatiblePixelFormat(PixelFormat::INVALID),
PixelFormat::INVALID);
}
TEST(CommonFFmpegUtils, GetFFmpegPixelFormat)
{
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U8,
VideoParams::kRGBChannelCount),
AV_PIX_FMT_RGB24);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U16,
VideoParams::kRGBChannelCount),
AV_PIX_FMT_RGB48);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::F32,
VideoParams::kRGBChannelCount),
AV_PIX_FMT_RGBF32);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U8,
VideoParams::kRGBAChannelCount),
AV_PIX_FMT_RGBA);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U16,
VideoParams::kRGBAChannelCount),
AV_PIX_FMT_RGBA64);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::F32,
VideoParams::kRGBAChannelCount),
AV_PIX_FMT_RGBAF32);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::INVALID, 0),
AV_PIX_FMT_NONE);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U8,
VideoParams::kRGBChannelCount),
AV_PIX_FMT_RGB24);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U16,
VideoParams::kRGBChannelCount),
AV_PIX_FMT_RGB48);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::F32,
VideoParams::kRGBChannelCount),
AV_PIX_FMT_RGBF32);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U8,
VideoParams::kRGBAChannelCount),
AV_PIX_FMT_RGBA);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U16,
VideoParams::kRGBAChannelCount),
AV_PIX_FMT_RGBA64);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::F32,
VideoParams::kRGBAChannelCount),
AV_PIX_FMT_RGBAF32);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::INVALID, 0),
AV_PIX_FMT_NONE);
}
TEST(CommonFFmpegUtils, GetCompatiblePixelFormatAV)
{
AVPixelFormat fmt = FFmpegUtils::GetCompatiblePixelFormat(AV_PIX_FMT_YUV420P);
EXPECT_NE(fmt, AV_PIX_FMT_NONE);
AVPixelFormat fmt =
FFmpegUtils::GetCompatiblePixelFormat(AV_PIX_FMT_YUV420P);
EXPECT_NE(fmt, AV_PIX_FMT_NONE);
fmt = FFmpegUtils::GetCompatiblePixelFormat(AV_PIX_FMT_YUV420P,
PixelFormat::U8);
EXPECT_EQ(fmt, AV_PIX_FMT_RGBA);
fmt = FFmpegUtils::GetCompatiblePixelFormat(AV_PIX_FMT_YUV420P,
PixelFormat::U8);
EXPECT_EQ(fmt, AV_PIX_FMT_RGBA);
}
+12 -7
View File
@@ -16,7 +16,9 @@ TEST(CommonFileFunctions, EnsureFilenameExtension)
EXPECT_EQ(olive::FileFunctions::EnsureFilenameExtension(
QStringLiteral("PROJECT"), QStringLiteral("ove")),
QStringLiteral("PROJECT.ove"));
EXPECT_TRUE(olive::FileFunctions::EnsureFilenameExtension(QString(), QStringLiteral("ove")).isEmpty());
EXPECT_TRUE(olive::FileFunctions::EnsureFilenameExtension(
QString(), QStringLiteral("ove"))
.isEmpty());
EXPECT_EQ(olive::FileFunctions::EnsureFilenameExtension(
QStringLiteral("project"), QString()),
QStringLiteral("project"));
@@ -46,7 +48,8 @@ TEST(CommonFileFunctions, DirectoryIsValid)
QTemporaryDir dir;
ASSERT_TRUE(dir.isValid());
EXPECT_TRUE(olive::FileFunctions::DirectoryIsValid(QDir(dir.path()), false));
EXPECT_TRUE(
olive::FileFunctions::DirectoryIsValid(QDir(dir.path()), false));
QDir nonexistent(dir.filePath(QStringLiteral("subdir/nested")));
EXPECT_TRUE(olive::FileFunctions::DirectoryIsValid(nonexistent, true));
@@ -133,7 +136,8 @@ TEST(CommonFileFunctions, ReadFileAsString)
EXPECT_EQ(olive::FileFunctions::ReadFileAsString(f.fileName()),
QStringLiteral("hello world"));
EXPECT_TRUE(olive::FileFunctions::ReadFileAsString(
QStringLiteral("/nonexistent/path")).isEmpty());
QStringLiteral("/nonexistent/path"))
.isEmpty());
}
TEST(CommonFileFunctions, GetUniqueFileIdentifier)
@@ -148,10 +152,10 @@ TEST(CommonFileFunctions, GetUniqueFileIdentifier)
EXPECT_EQ(id1, id2);
EXPECT_TRUE(olive::FileFunctions::GetUniqueFileIdentifier(
QStringLiteral("/nonexistent")).isEmpty());
QStringLiteral("/nonexistent"))
.isEmpty());
}
TEST(CommonFileFunctions, GetConfigurationLocation)
{
QString loc = olive::FileFunctions::GetConfigurationLocation();
@@ -176,7 +180,8 @@ TEST(CommonFileFunctions, DirectoryIsValidExisting)
{
QTemporaryDir dir;
ASSERT_TRUE(dir.isValid());
EXPECT_TRUE(olive::FileFunctions::DirectoryIsValid(QDir(dir.path()), false));
EXPECT_TRUE(
olive::FileFunctions::DirectoryIsValid(QDir(dir.path()), false));
}
TEST(CommonFileFunctions, CopyDirectoryWithOverwrite)
@@ -212,5 +217,5 @@ TEST(CommonFileFunctions, CopyDirectorySourceMissing)
// Should not crash even if source doesn't exist
olive::FileFunctions::CopyDirectory(QStringLiteral("/nonexistent/path"),
dst.path(), false);
dst.path(), false);
}
+20 -20
View File
@@ -4,39 +4,39 @@
TEST(CommonJobTime, ConstructorAcquiresValue)
{
olive::JobTime a;
olive::JobTime b;
olive::JobTime a;
olive::JobTime b;
EXPECT_NE(a.value(), b.value());
EXPECT_LT(a.value(), b.value());
EXPECT_NE(a.value(), b.value());
EXPECT_LT(a.value(), b.value());
}
TEST(CommonJobTime, AcquireUpdatesValue)
{
olive::JobTime a;
uint64_t first = a.value();
a.Acquire();
uint64_t second = a.value();
olive::JobTime a;
uint64_t first = a.value();
a.Acquire();
uint64_t second = a.value();
EXPECT_GT(second, first);
EXPECT_GT(second, first);
}
TEST(CommonJobTime, ComparisonOperators)
{
olive::JobTime a;
olive::JobTime b;
olive::JobTime a;
olive::JobTime b;
EXPECT_LT(a, b);
EXPECT_GT(b, a);
EXPECT_LE(a, a);
EXPECT_GE(b, b);
EXPECT_EQ(a, a);
EXPECT_NE(a, b);
EXPECT_LT(a, b);
EXPECT_GT(b, a);
EXPECT_LE(a, a);
EXPECT_GE(b, b);
EXPECT_EQ(a, a);
EXPECT_NE(a, b);
}
TEST(CommonJobTime, DebugStream)
{
olive::JobTime a;
QDebug debug(QtDebugMsg);
debug << a;
olive::JobTime a;
QDebug debug(QtDebugMsg);
debug << a;
}
+5 -5
View File
@@ -30,7 +30,8 @@ TEST(CommonQtUtils, FlipControlAndShiftModifiers)
// (Qt::ControlModifier & Qt::ShiftModifier is always zero), so the function
// always swaps Control and Shift. This test documents current behavior.
Qt::KeyboardModifiers both = Qt::ControlModifier | Qt::ShiftModifier;
Qt::KeyboardModifiers flipped = olive::QtUtils::FlipControlAndShiftModifiers(both);
Qt::KeyboardModifiers flipped =
olive::QtUtils::FlipControlAndShiftModifiers(both);
EXPECT_TRUE(flipped & Qt::ControlModifier);
EXPECT_FALSE(flipped & Qt::ShiftModifier);
@@ -112,11 +113,10 @@ TEST(CommonQtUtils, ToQColor)
EXPECT_NEAR(qc.alphaF(), 0.4, 0.001);
}
TEST(CommonQtUtils, GetFormattedDateTime)
{
QDateTime dt = QDateTime::fromString(QStringLiteral("2025-01-15T10:30:00"),
Qt::ISODate);
Qt::ISODate);
QString s = olive::QtUtils::GetFormattedDateTime(dt);
EXPECT_FALSE(s.isEmpty());
}
@@ -132,8 +132,8 @@ TEST(CommonQtUtils, WordWrapString)
EXPECT_GE(wrapped.size(), 1u);
// Should preserve manual newlines
wrapped = olive::QtUtils::WordWrapString(
QStringLiteral("line1\nline2"), fm, 1000);
wrapped = olive::QtUtils::WordWrapString(QStringLiteral("line1\nline2"), fm,
1000);
EXPECT_EQ(wrapped.size(), 2);
}
-1
View File
@@ -59,7 +59,6 @@ TEST(CommonXmlUtils, ReadNextStartElementSkipsUnknown)
EXPECT_EQ(reader.name().toString(), QStringLiteral("known"));
}
TEST(CommonXmlUtils, ReadNextStartElementWithCancel)
{
QByteArray xml = "<root><child/></root>";
+12 -12
View File
@@ -46,18 +46,18 @@ TEST(Config, GraphicsBackendStringConversion)
olive::RenderManager::kVulkan);
EXPECT_EQ(olive::RenderManager::BackendFromString(QStringLiteral("dummy")),
olive::RenderManager::kDummy);
EXPECT_EQ(olive::RenderManager::BackendFromString(
QStringLiteral("multiprocess")),
olive::RenderManager::kMultiProcess);
EXPECT_EQ(olive::RenderManager::BackendToString(
olive::RenderManager::kOpenGL),
QStringLiteral("opengl"));
EXPECT_EQ(olive::RenderManager::BackendToString(
olive::RenderManager::kVulkan),
QStringLiteral("vulkan"));
EXPECT_EQ(olive::RenderManager::BackendToString(
olive::RenderManager::kDummy),
QStringLiteral("dummy"));
EXPECT_EQ(
olive::RenderManager::BackendFromString(QStringLiteral("multiprocess")),
olive::RenderManager::kMultiProcess);
EXPECT_EQ(
olive::RenderManager::BackendToString(olive::RenderManager::kOpenGL),
QStringLiteral("opengl"));
EXPECT_EQ(
olive::RenderManager::BackendToString(olive::RenderManager::kVulkan),
QStringLiteral("vulkan"));
EXPECT_EQ(
olive::RenderManager::BackendToString(olive::RenderManager::kDummy),
QStringLiteral("dummy"));
EXPECT_EQ(olive::RenderManager::BackendToString(
olive::RenderManager::kMultiProcess),
QStringLiteral("multiprocess"));
+64 -64
View File
@@ -6,115 +6,115 @@ using namespace olive::core;
TEST(CoreBezier, DefaultConstruction)
{
Bezier b;
EXPECT_DOUBLE_EQ(b.x(), 0.0);
EXPECT_DOUBLE_EQ(b.y(), 0.0);
EXPECT_DOUBLE_EQ(b.cp1_x(), 0.0);
EXPECT_DOUBLE_EQ(b.cp1_y(), 0.0);
EXPECT_DOUBLE_EQ(b.cp2_x(), 0.0);
EXPECT_DOUBLE_EQ(b.cp2_y(), 0.0);
Bezier b;
EXPECT_DOUBLE_EQ(b.x(), 0.0);
EXPECT_DOUBLE_EQ(b.y(), 0.0);
EXPECT_DOUBLE_EQ(b.cp1_x(), 0.0);
EXPECT_DOUBLE_EQ(b.cp1_y(), 0.0);
EXPECT_DOUBLE_EQ(b.cp2_x(), 0.0);
EXPECT_DOUBLE_EQ(b.cp2_y(), 0.0);
}
TEST(CoreBezier, ValueConstruction)
{
Bezier b(1.0, 2.0);
EXPECT_DOUBLE_EQ(b.x(), 1.0);
EXPECT_DOUBLE_EQ(b.y(), 2.0);
Bezier b(1.0, 2.0);
EXPECT_DOUBLE_EQ(b.x(), 1.0);
EXPECT_DOUBLE_EQ(b.y(), 2.0);
}
TEST(CoreBezier, FullConstruction)
{
Bezier b(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
EXPECT_DOUBLE_EQ(b.x(), 1.0);
EXPECT_DOUBLE_EQ(b.y(), 2.0);
EXPECT_DOUBLE_EQ(b.cp1_x(), 3.0);
EXPECT_DOUBLE_EQ(b.cp1_y(), 4.0);
EXPECT_DOUBLE_EQ(b.cp2_x(), 5.0);
EXPECT_DOUBLE_EQ(b.cp2_y(), 6.0);
Bezier b(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
EXPECT_DOUBLE_EQ(b.x(), 1.0);
EXPECT_DOUBLE_EQ(b.y(), 2.0);
EXPECT_DOUBLE_EQ(b.cp1_x(), 3.0);
EXPECT_DOUBLE_EQ(b.cp1_y(), 4.0);
EXPECT_DOUBLE_EQ(b.cp2_x(), 5.0);
EXPECT_DOUBLE_EQ(b.cp2_y(), 6.0);
}
TEST(CoreBezier, Setters)
{
Bezier b;
b.set_x(10.0);
b.set_y(20.0);
b.set_cp1_x(30.0);
b.set_cp1_y(40.0);
b.set_cp2_x(50.0);
b.set_cp2_y(60.0);
Bezier b;
b.set_x(10.0);
b.set_y(20.0);
b.set_cp1_x(30.0);
b.set_cp1_y(40.0);
b.set_cp2_x(50.0);
b.set_cp2_y(60.0);
EXPECT_DOUBLE_EQ(b.x(), 10.0);
EXPECT_DOUBLE_EQ(b.y(), 20.0);
EXPECT_DOUBLE_EQ(b.cp1_x(), 30.0);
EXPECT_DOUBLE_EQ(b.cp1_y(), 40.0);
EXPECT_DOUBLE_EQ(b.cp2_x(), 50.0);
EXPECT_DOUBLE_EQ(b.cp2_y(), 60.0);
EXPECT_DOUBLE_EQ(b.x(), 10.0);
EXPECT_DOUBLE_EQ(b.y(), 20.0);
EXPECT_DOUBLE_EQ(b.cp1_x(), 30.0);
EXPECT_DOUBLE_EQ(b.cp1_y(), 40.0);
EXPECT_DOUBLE_EQ(b.cp2_x(), 50.0);
EXPECT_DOUBLE_EQ(b.cp2_y(), 60.0);
}
TEST(CoreBezier, QuadraticXtoT)
{
double t = Bezier::QuadraticXtoT(0.5, 0.0, 0.5, 1.0);
EXPECT_NEAR(t, 0.5, 0.00001);
double t = Bezier::QuadraticXtoT(0.5, 0.0, 0.5, 1.0);
EXPECT_NEAR(t, 0.5, 0.00001);
t = Bezier::QuadraticXtoT(0.0, 0.0, 0.5, 1.0);
EXPECT_NEAR(t, 0.0, 0.00001);
t = Bezier::QuadraticXtoT(0.0, 0.0, 0.5, 1.0);
EXPECT_NEAR(t, 0.0, 0.00001);
t = Bezier::QuadraticXtoT(1.0, 0.0, 0.5, 1.0);
EXPECT_NEAR(t, 1.0, 0.00001);
t = Bezier::QuadraticXtoT(1.0, 0.0, 0.5, 1.0);
EXPECT_NEAR(t, 1.0, 0.00001);
}
TEST(CoreBezier, QuadraticTtoY)
{
EXPECT_NEAR(Bezier::QuadraticTtoY(0.0, 0.5, 1.0, 0.0), 0.0, 0.00001);
EXPECT_NEAR(Bezier::QuadraticTtoY(0.0, 0.5, 1.0, 0.5), 0.5, 0.00001);
EXPECT_NEAR(Bezier::QuadraticTtoY(0.0, 0.5, 1.0, 1.0), 1.0, 0.00001);
EXPECT_NEAR(Bezier::QuadraticTtoY(0.0, 0.5, 1.0, 0.0), 0.0, 0.00001);
EXPECT_NEAR(Bezier::QuadraticTtoY(0.0, 0.5, 1.0, 0.5), 0.5, 0.00001);
EXPECT_NEAR(Bezier::QuadraticTtoY(0.0, 0.5, 1.0, 1.0), 1.0, 0.00001);
}
TEST(CoreBezier, QuadraticXtoY)
{
Imath::V2d a(0.0, 0.0);
Imath::V2d b(0.5, 0.5);
Imath::V2d c(1.0, 1.0);
Imath::V2d a(0.0, 0.0);
Imath::V2d b(0.5, 0.5);
Imath::V2d c(1.0, 1.0);
EXPECT_NEAR(Bezier::QuadraticXtoY(0.5, a, b, c), 0.5, 0.00001);
EXPECT_NEAR(Bezier::QuadraticXtoY(0.5, a, b, c), 0.5, 0.00001);
}
TEST(CoreBezier, CubicXtoT)
{
double t = Bezier::CubicXtoT(0.5, 0.0, 0.33, 0.66, 1.0);
EXPECT_NEAR(t, 0.5, 0.01);
double t = Bezier::CubicXtoT(0.5, 0.0, 0.33, 0.66, 1.0);
EXPECT_NEAR(t, 0.5, 0.01);
}
TEST(CoreBezier, CubicTtoY)
{
EXPECT_NEAR(Bezier::CubicTtoY(0.0, 0.33, 0.66, 1.0, 0.0), 0.0, 0.00001);
EXPECT_NEAR(Bezier::CubicTtoY(0.0, 0.33, 0.66, 1.0, 1.0), 1.0, 0.00001);
EXPECT_NEAR(Bezier::CubicTtoY(0.0, 0.33, 0.66, 1.0, 0.0), 0.0, 0.00001);
EXPECT_NEAR(Bezier::CubicTtoY(0.0, 0.33, 0.66, 1.0, 1.0), 1.0, 0.00001);
}
TEST(CoreBezier, CubicXtoY)
{
Imath::V2d a(0.0, 0.0);
Imath::V2d b(0.33, 0.0);
Imath::V2d c(0.66, 1.0);
Imath::V2d d(1.0, 1.0);
Imath::V2d a(0.0, 0.0);
Imath::V2d b(0.33, 0.0);
Imath::V2d c(0.66, 1.0);
Imath::V2d d(1.0, 1.0);
double y = Bezier::CubicXtoY(0.5, a, b, c, d);
EXPECT_GE(y, 0.0);
EXPECT_LE(y, 1.0);
double y = Bezier::CubicXtoY(0.5, a, b, c, d);
EXPECT_GE(y, 0.0);
EXPECT_LE(y, 1.0);
}
TEST(CoreBezier, VectorConverters)
{
Bezier b(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
Imath::V2d v = b.to_vec();
EXPECT_DOUBLE_EQ(v.x, 1.0);
EXPECT_DOUBLE_EQ(v.y, 2.0);
Bezier b(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
Imath::V2d v = b.to_vec();
EXPECT_DOUBLE_EQ(v.x, 1.0);
EXPECT_DOUBLE_EQ(v.y, 2.0);
Imath::V2d cp1 = b.control_point_1_to_vec();
EXPECT_DOUBLE_EQ(cp1.x, 3.0);
EXPECT_DOUBLE_EQ(cp1.y, 4.0);
Imath::V2d cp1 = b.control_point_1_to_vec();
EXPECT_DOUBLE_EQ(cp1.x, 3.0);
EXPECT_DOUBLE_EQ(cp1.y, 4.0);
Imath::V2d cp2 = b.control_point_2_to_vec();
EXPECT_DOUBLE_EQ(cp2.x, 5.0);
EXPECT_DOUBLE_EQ(cp2.y, 6.0);
Imath::V2d cp2 = b.control_point_2_to_vec();
EXPECT_DOUBLE_EQ(cp2.x, 5.0);
EXPECT_DOUBLE_EQ(cp2.y, 6.0);
}
+93 -93
View File
@@ -6,164 +6,164 @@ using namespace olive::core;
TEST(CoreColor, DefaultConstruction)
{
Color c;
EXPECT_FLOAT_EQ(c.red(), 0.0f);
EXPECT_FLOAT_EQ(c.green(), 0.0f);
EXPECT_FLOAT_EQ(c.blue(), 0.0f);
EXPECT_FLOAT_EQ(c.alpha(), 0.0f);
Color c;
EXPECT_FLOAT_EQ(c.red(), 0.0f);
EXPECT_FLOAT_EQ(c.green(), 0.0f);
EXPECT_FLOAT_EQ(c.blue(), 0.0f);
EXPECT_FLOAT_EQ(c.alpha(), 0.0f);
}
TEST(CoreColor, ValueConstruction)
{
Color c(0.1f, 0.2f, 0.3f, 0.4f);
EXPECT_FLOAT_EQ(c.red(), 0.1f);
EXPECT_FLOAT_EQ(c.green(), 0.2f);
EXPECT_FLOAT_EQ(c.blue(), 0.3f);
EXPECT_FLOAT_EQ(c.alpha(), 0.4f);
Color c(0.1f, 0.2f, 0.3f, 0.4f);
EXPECT_FLOAT_EQ(c.red(), 0.1f);
EXPECT_FLOAT_EQ(c.green(), 0.2f);
EXPECT_FLOAT_EQ(c.blue(), 0.3f);
EXPECT_FLOAT_EQ(c.alpha(), 0.4f);
}
TEST(CoreColor, SettersAndDataAccess)
{
Color c;
c.set_red(0.5f);
c.set_green(0.6f);
c.set_blue(0.7f);
c.set_alpha(0.8f);
Color c;
c.set_red(0.5f);
c.set_green(0.6f);
c.set_blue(0.7f);
c.set_alpha(0.8f);
EXPECT_FLOAT_EQ(c.data()[0], 0.5f);
EXPECT_FLOAT_EQ(c.data()[1], 0.6f);
EXPECT_FLOAT_EQ(c.data()[2], 0.7f);
EXPECT_FLOAT_EQ(c.data()[3], 0.8f);
EXPECT_FLOAT_EQ(c.data()[0], 0.5f);
EXPECT_FLOAT_EQ(c.data()[1], 0.6f);
EXPECT_FLOAT_EQ(c.data()[2], 0.7f);
EXPECT_FLOAT_EQ(c.data()[3], 0.8f);
}
TEST(CoreColor, FromHsvRed)
{
Color c = Color::fromHsv(0.0f, 1.0f, 1.0f);
EXPECT_NEAR(c.red(), 1.0f, 0.001f);
EXPECT_NEAR(c.green(), 0.0f, 0.001f);
EXPECT_NEAR(c.blue(), 0.0f, 0.001f);
Color c = Color::fromHsv(0.0f, 1.0f, 1.0f);
EXPECT_NEAR(c.red(), 1.0f, 0.001f);
EXPECT_NEAR(c.green(), 0.0f, 0.001f);
EXPECT_NEAR(c.blue(), 0.0f, 0.001f);
}
TEST(CoreColor, FromHsvGreen)
{
Color c = Color::fromHsv(120.0f, 1.0f, 1.0f);
EXPECT_NEAR(c.red(), 0.0f, 0.001f);
EXPECT_NEAR(c.green(), 1.0f, 0.001f);
EXPECT_NEAR(c.blue(), 0.0f, 0.001f);
Color c = Color::fromHsv(120.0f, 1.0f, 1.0f);
EXPECT_NEAR(c.red(), 0.0f, 0.001f);
EXPECT_NEAR(c.green(), 1.0f, 0.001f);
EXPECT_NEAR(c.blue(), 0.0f, 0.001f);
}
TEST(CoreColor, FromHsvBlue)
{
Color c = Color::fromHsv(240.0f, 1.0f, 1.0f);
EXPECT_NEAR(c.red(), 0.0f, 0.001f);
EXPECT_NEAR(c.green(), 0.0f, 0.001f);
EXPECT_NEAR(c.blue(), 1.0f, 0.001f);
Color c = Color::fromHsv(240.0f, 1.0f, 1.0f);
EXPECT_NEAR(c.red(), 0.0f, 0.001f);
EXPECT_NEAR(c.green(), 0.0f, 0.001f);
EXPECT_NEAR(c.blue(), 1.0f, 0.001f);
}
TEST(CoreColor, HsvRoundTrip)
{
Color original(0.8f, 0.4f, 0.2f);
float h, s, v;
original.toHsv(&h, &s, &v);
Color original(0.8f, 0.4f, 0.2f);
float h, s, v;
original.toHsv(&h, &s, &v);
EXPECT_NEAR(original.hsv_hue(), h, 0.001f);
EXPECT_NEAR(original.hsv_saturation(), s, 0.001f);
EXPECT_NEAR(original.value(), v, 0.001f);
EXPECT_NEAR(original.hsv_hue(), h, 0.001f);
EXPECT_NEAR(original.hsv_saturation(), s, 0.001f);
EXPECT_NEAR(original.value(), v, 0.001f);
}
TEST(CoreColor, HslRoundTrip)
{
Color original(0.2f, 0.5f, 0.8f);
float h, s, l;
original.toHsl(&h, &s, &l);
Color original(0.2f, 0.5f, 0.8f);
float h, s, l;
original.toHsl(&h, &s, &l);
EXPECT_NEAR(original.hsl_hue(), h, 0.001f);
EXPECT_NEAR(original.hsl_saturation(), s, 0.001f);
EXPECT_NEAR(original.lightness(), l, 0.001f);
EXPECT_NEAR(original.hsl_hue(), h, 0.001f);
EXPECT_NEAR(original.hsl_saturation(), s, 0.001f);
EXPECT_NEAR(original.lightness(), l, 0.001f);
}
TEST(CoreColor, ArithmeticOperators)
{
Color a(1.0f, 2.0f, 3.0f, 4.0f);
Color b(0.5f, 0.5f, 0.5f, 0.5f);
Color a(1.0f, 2.0f, 3.0f, 4.0f);
Color b(0.5f, 0.5f, 0.5f, 0.5f);
Color sum = a + b;
EXPECT_FLOAT_EQ(sum.red(), 1.5f);
Color sum = a + b;
EXPECT_FLOAT_EQ(sum.red(), 1.5f);
Color diff = a - b;
EXPECT_FLOAT_EQ(diff.red(), 0.5f);
Color diff = a - b;
EXPECT_FLOAT_EQ(diff.red(), 0.5f);
Color scaled = a * 2.0f;
EXPECT_FLOAT_EQ(scaled.red(), 2.0f);
Color scaled = a * 2.0f;
EXPECT_FLOAT_EQ(scaled.red(), 2.0f);
Color divided = a / 2.0f;
EXPECT_FLOAT_EQ(divided.red(), 0.5f);
Color divided = a / 2.0f;
EXPECT_FLOAT_EQ(divided.red(), 0.5f);
Color added_scalar = a + 1.0f;
EXPECT_FLOAT_EQ(added_scalar.red(), 2.0f);
Color added_scalar = a + 1.0f;
EXPECT_FLOAT_EQ(added_scalar.red(), 2.0f);
}
TEST(CoreColor, CompoundAssignment)
{
Color c(1.0f, 2.0f, 3.0f, 4.0f);
c += Color(0.5f, 0.5f, 0.5f, 0.5f);
EXPECT_FLOAT_EQ(c.red(), 1.5f);
Color c(1.0f, 2.0f, 3.0f, 4.0f);
c += Color(0.5f, 0.5f, 0.5f, 0.5f);
EXPECT_FLOAT_EQ(c.red(), 1.5f);
c *= 2.0f;
EXPECT_FLOAT_EQ(c.red(), 3.0f);
c *= 2.0f;
EXPECT_FLOAT_EQ(c.red(), 3.0f);
}
TEST(CoreColor, GetRoughLuminance)
{
Color white(1.0f, 1.0f, 1.0f);
EXPECT_FLOAT_EQ(white.GetRoughLuminance(), 1.0f);
Color white(1.0f, 1.0f, 1.0f);
EXPECT_FLOAT_EQ(white.GetRoughLuminance(), 1.0f);
Color black(0.0f, 0.0f, 0.0f);
EXPECT_FLOAT_EQ(black.GetRoughLuminance(), 0.0f);
Color black(0.0f, 0.0f, 0.0f);
EXPECT_FLOAT_EQ(black.GetRoughLuminance(), 0.0f);
}
TEST(CoreColor, ToDataAndFromDataU8)
{
Color c(1.0f, 0.5f, 0.0f, 1.0f);
uint8_t data[4];
c.toData(reinterpret_cast<char *>(data), PixelFormat::U8, 4);
Color c(1.0f, 0.5f, 0.0f, 1.0f);
uint8_t data[4];
c.toData(reinterpret_cast<char *>(data), PixelFormat::U8, 4);
EXPECT_EQ(data[0], 255u);
EXPECT_EQ(data[1], 127u);
EXPECT_EQ(data[2], 0u);
EXPECT_EQ(data[3], 255u);
EXPECT_EQ(data[0], 255u);
EXPECT_EQ(data[1], 127u);
EXPECT_EQ(data[2], 0u);
EXPECT_EQ(data[3], 255u);
Color restored = Color::fromData(reinterpret_cast<const char *>(data),
PixelFormat::U8, 4);
EXPECT_NEAR(restored.red(), 1.0f, 0.01f);
EXPECT_NEAR(restored.green(), 0.5f, 0.01f);
Color restored = Color::fromData(reinterpret_cast<const char *>(data),
PixelFormat::U8, 4);
EXPECT_NEAR(restored.red(), 1.0f, 0.01f);
EXPECT_NEAR(restored.green(), 0.5f, 0.01f);
}
TEST(CoreColor, ToDataAndFromDataF32)
{
Color c(0.25f, 0.5f, 0.75f, 1.0f);
float data[4];
c.toData(reinterpret_cast<char *>(data), PixelFormat::F32, 4);
Color c(0.25f, 0.5f, 0.75f, 1.0f);
float data[4];
c.toData(reinterpret_cast<char *>(data), PixelFormat::F32, 4);
EXPECT_FLOAT_EQ(data[0], 0.25f);
EXPECT_FLOAT_EQ(data[1], 0.5f);
EXPECT_FLOAT_EQ(data[2], 0.75f);
EXPECT_FLOAT_EQ(data[3], 1.0f);
EXPECT_FLOAT_EQ(data[0], 0.25f);
EXPECT_FLOAT_EQ(data[1], 0.5f);
EXPECT_FLOAT_EQ(data[2], 0.75f);
EXPECT_FLOAT_EQ(data[3], 1.0f);
Color restored = Color::fromData(reinterpret_cast<const char *>(data),
PixelFormat::F32, 4);
EXPECT_FLOAT_EQ(restored.red(), 0.25f);
Color restored = Color::fromData(reinterpret_cast<const char *>(data),
PixelFormat::F32, 4);
EXPECT_FLOAT_EQ(restored.red(), 0.25f);
}
TEST(CoreColor, ToDataAndFromDataU10)
{
Color c(1.0f, 0.5f, 0.0f, 1.0f);
uint32_t data;
c.toData(reinterpret_cast<char *>(&data), PixelFormat::U10, 4);
Color c(1.0f, 0.5f, 0.0f, 1.0f);
uint32_t data;
c.toData(reinterpret_cast<char *>(&data), PixelFormat::U10, 4);
Color restored = Color::fromData(reinterpret_cast<const char *>(&data),
PixelFormat::U10, 4);
EXPECT_NEAR(restored.red(), 1.0f, 0.001f);
EXPECT_NEAR(restored.green(), 0.5f, 0.001f);
EXPECT_NEAR(restored.blue(), 0.0f, 0.001f);
Color restored = Color::fromData(reinterpret_cast<const char *>(&data),
PixelFormat::U10, 4);
EXPECT_NEAR(restored.red(), 1.0f, 0.001f);
EXPECT_NEAR(restored.green(), 0.5f, 0.001f);
EXPECT_NEAR(restored.blue(), 0.0f, 0.001f);
}
+1 -1
View File
@@ -208,7 +208,7 @@ TEST(CoreSampleBuffer, Set)
{
AudioParams params = MakeParams();
SampleBuffer b(params, 4);
float data[2] = {0.3f, 0.4f};
float data[2] = { 0.3f, 0.4f };
b.set(0, data, 1, 2);
EXPECT_FLOAT_EQ(b.data(0)[1], 0.3f);
EXPECT_FLOAT_EQ(b.data(0)[2], 0.4f);
+31 -30
View File
@@ -8,58 +8,59 @@ using namespace olive::core;
TEST(CoreStringUtils, Split)
{
auto result = StringUtils::split("a,b,c", ',');
ASSERT_EQ(result.size(), 3u);
EXPECT_EQ(result[0], "a");
EXPECT_EQ(result[1], "b");
EXPECT_EQ(result[2], "c");
auto result = StringUtils::split("a,b,c", ',');
ASSERT_EQ(result.size(), 3u);
EXPECT_EQ(result[0], "a");
EXPECT_EQ(result[1], "b");
EXPECT_EQ(result[2], "c");
}
TEST(CoreStringUtils, SplitRegex)
{
auto result = StringUtils::split_regex("one:two;three", std::regex("(:)|(;)| "));
ASSERT_EQ(result.size(), 3u);
EXPECT_EQ(result[0], "one");
EXPECT_EQ(result[1], "two");
EXPECT_EQ(result[2], "three");
auto result =
StringUtils::split_regex("one:two;three", std::regex("(:)|(;)| "));
ASSERT_EQ(result.size(), 3u);
EXPECT_EQ(result[0], "one");
EXPECT_EQ(result[1], "two");
EXPECT_EQ(result[2], "three");
}
TEST(CoreStringUtils, ToInt)
{
bool ok = false;
EXPECT_EQ(StringUtils::to_int("42", &ok), 42);
EXPECT_TRUE(ok);
bool ok = false;
EXPECT_EQ(StringUtils::to_int("42", &ok), 42);
EXPECT_TRUE(ok);
EXPECT_EQ(StringUtils::to_int("-7", 10, &ok), -7);
EXPECT_TRUE(ok);
EXPECT_EQ(StringUtils::to_int("-7", 10, &ok), -7);
EXPECT_TRUE(ok);
EXPECT_EQ(StringUtils::to_int("ff", 16, &ok), 255);
EXPECT_TRUE(ok);
EXPECT_EQ(StringUtils::to_int("ff", 16, &ok), 255);
EXPECT_TRUE(ok);
EXPECT_EQ(StringUtils::to_int("abc", &ok), 0);
EXPECT_FALSE(ok);
EXPECT_EQ(StringUtils::to_int("abc", &ok), 0);
EXPECT_FALSE(ok);
}
TEST(CoreStringUtils, ToStringLeftpad)
{
EXPECT_EQ(StringUtils::to_string_leftpad(5, 3), "005");
EXPECT_EQ(StringUtils::to_string_leftpad(123, 2), "123");
EXPECT_EQ(StringUtils::to_string_leftpad(7, 4, '*'), "***7");
EXPECT_EQ(StringUtils::to_string_leftpad(5, 3), "005");
EXPECT_EQ(StringUtils::to_string_leftpad(123, 2), "123");
EXPECT_EQ(StringUtils::to_string_leftpad(7, 4, '*'), "***7");
}
TEST(CoreStringUtils, Format)
{
EXPECT_EQ(StringUtils::format("Hello %s %d", "world", 42),
"Hello world 42");
EXPECT_EQ(StringUtils::format("Hello %s %d", "world", 42),
"Hello world 42");
}
TEST(CoreStringUtils, Trim)
{
std::string s = " hello world ";
StringUtils::trim(s);
EXPECT_EQ(s, "hello world");
std::string s = " hello world ";
StringUtils::trim(s);
EXPECT_EQ(s, "hello world");
EXPECT_EQ(StringUtils::trimmed("\t\nvalue\t\n"), "value");
EXPECT_EQ(StringUtils::ltrimmed(" left"), "left");
EXPECT_EQ(StringUtils::rtrimmed("right "), "right");
EXPECT_EQ(StringUtils::trimmed("\t\nvalue\t\n"), "value");
EXPECT_EQ(StringUtils::ltrimmed(" left"), "left");
EXPECT_EQ(StringUtils::rtrimmed("right "), "right");
}
+55 -54
View File
@@ -6,110 +6,111 @@ using namespace olive::core;
TEST(CoreTimecode, TimeToTimecodeSeconds)
{
rational time(5, 1);
rational tb(1, 25);
std::string tc = Timecode::time_to_timecode(time, tb, Timecode::kTimecodeSeconds);
EXPECT_EQ(tc, "00:00:05.000");
rational time(5, 1);
rational tb(1, 25);
std::string tc =
Timecode::time_to_timecode(time, tb, Timecode::kTimecodeSeconds);
EXPECT_EQ(tc, "00:00:05.000");
}
TEST(CoreTimecode, TimeToTimecodeNonDropFrame)
{
rational time(2, 1);
rational tb(1, 25);
std::string tc =
Timecode::time_to_timecode(time, tb, Timecode::kTimecodeNonDropFrame);
EXPECT_EQ(tc, "00:00:02:00");
rational time(2, 1);
rational tb(1, 25);
std::string tc =
Timecode::time_to_timecode(time, tb, Timecode::kTimecodeNonDropFrame);
EXPECT_EQ(tc, "00:00:02:00");
}
TEST(CoreTimecode, TimeToTimecodePlusSign)
{
rational time(1, 1);
rational tb(1, 25);
std::string tc = Timecode::time_to_timecode(time, tb,
Timecode::kTimecodeSeconds, true);
EXPECT_EQ(tc.substr(0, 1), "+");
rational time(1, 1);
rational tb(1, 25);
std::string tc =
Timecode::time_to_timecode(time, tb, Timecode::kTimecodeSeconds, true);
EXPECT_EQ(tc.substr(0, 1), "+");
}
TEST(CoreTimecode, TimeToTimecodeInvalidTimebase)
{
rational time(1, 1);
EXPECT_EQ(Timecode::time_to_timecode(time, rational(), Timecode::kFrames),
"INVALID TIMEBASE");
rational time(1, 1);
EXPECT_EQ(Timecode::time_to_timecode(time, rational(), Timecode::kFrames),
"INVALID TIMEBASE");
}
TEST(CoreTimecode, TimecodeToTimeSeconds)
{
rational tb(1, 25);
bool ok = false;
rational t = Timecode::timecode_to_time("00:00:05.500", tb,
Timecode::kTimecodeSeconds, &ok);
EXPECT_TRUE(ok);
EXPECT_EQ(t, rational(11, 2));
rational tb(1, 25);
bool ok = false;
rational t = Timecode::timecode_to_time("00:00:05.500", tb,
Timecode::kTimecodeSeconds, &ok);
EXPECT_TRUE(ok);
EXPECT_EQ(t, rational(11, 2));
}
TEST(CoreTimecode, TimecodeToTimeNonDropFrame)
{
rational tb(1, 25);
bool ok = false;
rational t = Timecode::timecode_to_time("00:00:02:03", tb,
Timecode::kTimecodeNonDropFrame, &ok);
EXPECT_TRUE(ok);
EXPECT_EQ(t, rational(53, 25));
rational tb(1, 25);
bool ok = false;
rational t = Timecode::timecode_to_time(
"00:00:02:03", tb, Timecode::kTimecodeNonDropFrame, &ok);
EXPECT_TRUE(ok);
EXPECT_EQ(t, rational(53, 25));
}
TEST(CoreTimecode, TimecodeToTimeInvalid)
{
rational tb(1, 25);
bool ok = true;
Timecode::timecode_to_time("not a timecode", tb,
Timecode::kTimecodeSeconds, &ok);
EXPECT_FALSE(ok);
rational tb(1, 25);
bool ok = true;
Timecode::timecode_to_time("not a timecode", tb, Timecode::kTimecodeSeconds,
&ok);
EXPECT_FALSE(ok);
}
TEST(CoreTimecode, TimeToString)
{
EXPECT_EQ(Timecode::time_to_string(3661000), "01:01:01");
EXPECT_EQ(Timecode::time_to_string(3661000), "01:01:01");
}
TEST(CoreTimecode, SnapTimeToTimebase)
{
rational tb(1, 25);
rational snapped = Timecode::snap_time_to_timebase(rational(1, 10), tb);
// 0.1s @ 25fps rounds to frame 3 (0.12s)
EXPECT_EQ(snapped, rational(3, 25));
rational tb(1, 25);
rational snapped = Timecode::snap_time_to_timebase(rational(1, 10), tb);
// 0.1s @ 25fps rounds to frame 3 (0.12s)
EXPECT_EQ(snapped, rational(3, 25));
}
TEST(CoreTimecode, TimeToTimestamp)
{
rational tb(1, 25);
EXPECT_EQ(Timecode::time_to_timestamp(rational(2, 1), tb), 50);
EXPECT_EQ(Timecode::time_to_timestamp(0.08, tb, Timecode::kFloor), 2);
EXPECT_EQ(Timecode::time_to_timestamp(0.08, tb, Timecode::kCeil), 2);
rational tb(1, 25);
EXPECT_EQ(Timecode::time_to_timestamp(rational(2, 1), tb), 50);
EXPECT_EQ(Timecode::time_to_timestamp(0.08, tb, Timecode::kFloor), 2);
EXPECT_EQ(Timecode::time_to_timestamp(0.08, tb, Timecode::kCeil), 2);
}
TEST(CoreTimecode, TimestampToTime)
{
rational tb(1, 25);
EXPECT_EQ(Timecode::timestamp_to_time(50, tb), rational(2, 1));
rational tb(1, 25);
EXPECT_EQ(Timecode::timestamp_to_time(50, tb), rational(2, 1));
}
TEST(CoreTimecode, RescaleTimestamp)
{
rational src(1, 25);
rational dst(1, 30);
EXPECT_EQ(Timecode::rescale_timestamp(50, src, dst), 60);
EXPECT_EQ(Timecode::rescale_timestamp(50, src, src), 50);
rational src(1, 25);
rational dst(1, 30);
EXPECT_EQ(Timecode::rescale_timestamp(50, src, dst), 60);
EXPECT_EQ(Timecode::rescale_timestamp(50, src, src), 50);
}
TEST(CoreTimecode, RescaleTimestampCeil)
{
rational src(1, 25);
rational dst(1, 30);
EXPECT_EQ(Timecode::rescale_timestamp_ceil(1, src, dst), 2);
rational src(1, 25);
rational dst(1, 30);
EXPECT_EQ(Timecode::rescale_timestamp_ceil(1, src, dst), 2);
}
TEST(CoreTimecode, TimebaseIsDropFrame)
{
EXPECT_FALSE(Timecode::timebase_is_drop_frame(rational(1, 25)));
EXPECT_TRUE(Timecode::timebase_is_drop_frame(rational(1001, 30000)));
EXPECT_FALSE(Timecode::timebase_is_drop_frame(rational(1, 25)));
EXPECT_TRUE(Timecode::timebase_is_drop_frame(rational(1001, 30000)));
}
+102 -101
View File
@@ -6,179 +6,180 @@ using namespace olive::core;
TEST(CoreTimeRange, ConstructAndAccess)
{
TimeRange r(rational(1), rational(5));
EXPECT_EQ(r.in(), rational(1));
EXPECT_EQ(r.out(), rational(5));
EXPECT_EQ(r.length(), rational(4));
TimeRange r(rational(1), rational(5));
EXPECT_EQ(r.in(), rational(1));
EXPECT_EQ(r.out(), rational(5));
EXPECT_EQ(r.length(), rational(4));
}
TEST(CoreTimeRange, NormalizationSwapsReversedBounds)
{
TimeRange r(rational(5), rational(1));
EXPECT_EQ(r.in(), rational(1));
EXPECT_EQ(r.out(), rational(5));
TimeRange r(rational(5), rational(1));
EXPECT_EQ(r.in(), rational(1));
EXPECT_EQ(r.out(), rational(5));
}
TEST(CoreTimeRange, SettersNormalize)
{
TimeRange r(rational(0), rational(10));
r.set_in(rational(15));
EXPECT_EQ(r.in(), rational(10));
EXPECT_EQ(r.out(), rational(15));
TimeRange r(rational(0), rational(10));
r.set_in(rational(15));
EXPECT_EQ(r.in(), rational(10));
EXPECT_EQ(r.out(), rational(15));
r.set_out(rational(2));
EXPECT_EQ(r.in(), rational(2));
EXPECT_EQ(r.out(), rational(10));
r.set_out(rational(2));
EXPECT_EQ(r.in(), rational(2));
EXPECT_EQ(r.out(), rational(10));
}
TEST(CoreTimeRange, ContainsRational)
{
TimeRange r(rational(0), rational(10));
EXPECT_TRUE(r.Contains(rational(5)));
EXPECT_FALSE(r.Contains(rational(10)));
EXPECT_FALSE(r.Contains(rational(-1)));
TimeRange r(rational(0), rational(10));
EXPECT_TRUE(r.Contains(rational(5)));
EXPECT_FALSE(r.Contains(rational(10)));
EXPECT_FALSE(r.Contains(rational(-1)));
}
TEST(CoreTimeRange, ContainsRange)
{
TimeRange outer(rational(0), rational(10));
TimeRange inner(rational(2), rational(8));
TimeRange partial(rational(5), rational(15));
TimeRange outer(rational(0), rational(10));
TimeRange inner(rational(2), rational(8));
TimeRange partial(rational(5), rational(15));
EXPECT_TRUE(outer.Contains(inner));
EXPECT_FALSE(outer.Contains(partial));
EXPECT_TRUE(outer.Contains(inner));
EXPECT_FALSE(outer.Contains(partial));
}
TEST(CoreTimeRange, OverlapsWith)
{
TimeRange a(rational(0), rational(10));
TimeRange b(rational(5), rational(15));
TimeRange c(rational(10), rational(20));
TimeRange a(rational(0), rational(10));
TimeRange b(rational(5), rational(15));
TimeRange c(rational(10), rational(20));
EXPECT_TRUE(a.OverlapsWith(b));
// By default bounds are inclusive, so [0,10] and [10,20] touch and overlap
EXPECT_TRUE(a.OverlapsWith(c));
EXPECT_FALSE(a.OverlapsWith(c, false, false));
EXPECT_TRUE(a.OverlapsWith(b));
// By default bounds are inclusive, so [0,10] and [10,20] touch and overlap
EXPECT_TRUE(a.OverlapsWith(c));
EXPECT_FALSE(a.OverlapsWith(c, false, false));
}
TEST(CoreTimeRange, CombineAndIntersect)
{
TimeRange a(rational(0), rational(10));
TimeRange b(rational(5), rational(15));
TimeRange a(rational(0), rational(10));
TimeRange b(rational(5), rational(15));
TimeRange combined = a.Combined(b);
EXPECT_EQ(combined.in(), rational(0));
EXPECT_EQ(combined.out(), rational(15));
TimeRange combined = a.Combined(b);
EXPECT_EQ(combined.in(), rational(0));
EXPECT_EQ(combined.out(), rational(15));
TimeRange intersect = a.Intersected(b);
EXPECT_EQ(intersect.in(), rational(5));
EXPECT_EQ(intersect.out(), rational(10));
TimeRange intersect = a.Intersected(b);
EXPECT_EQ(intersect.in(), rational(5));
EXPECT_EQ(intersect.out(), rational(10));
}
TEST(CoreTimeRange, Arithmetic)
{
TimeRange r(rational(0), rational(10));
TimeRange shifted = r + rational(5);
EXPECT_EQ(shifted.in(), rational(5));
EXPECT_EQ(shifted.out(), rational(15));
TimeRange r(rational(0), rational(10));
TimeRange shifted = r + rational(5);
EXPECT_EQ(shifted.in(), rational(5));
EXPECT_EQ(shifted.out(), rational(15));
shifted -= rational(3);
EXPECT_EQ(shifted.in(), rational(2));
EXPECT_EQ(shifted.out(), rational(12));
shifted -= rational(3);
EXPECT_EQ(shifted.in(), rational(2));
EXPECT_EQ(shifted.out(), rational(12));
}
TEST(CoreTimeRange, Split)
{
TimeRange r(rational(0), rational(10));
auto pieces = r.Split(3);
ASSERT_EQ(pieces.size(), 4u);
EXPECT_EQ(pieces.front().in(), rational(0));
TimeRange r(rational(0), rational(10));
auto pieces = r.Split(3);
ASSERT_EQ(pieces.size(), 4u);
EXPECT_EQ(pieces.front().in(), rational(0));
}
TEST(CoreTimeRangeList, InsertMergesOverlapping)
{
TimeRangeList list;
list.insert(TimeRange(rational(0), rational(5)));
list.insert(TimeRange(rational(3), rational(8)));
list.insert(TimeRange(rational(10), rational(12)));
TimeRangeList list;
list.insert(TimeRange(rational(0), rational(5)));
list.insert(TimeRange(rational(3), rational(8)));
list.insert(TimeRange(rational(10), rational(12)));
EXPECT_EQ(list.size(), 2);
EXPECT_EQ(list.first().in(), rational(0));
EXPECT_EQ(list.first().out(), rational(8));
EXPECT_EQ(list.size(), 2);
EXPECT_EQ(list.first().in(), rational(0));
EXPECT_EQ(list.first().out(), rational(8));
}
TEST(CoreTimeRangeList, RemoveSplitsRange)
{
TimeRangeList list;
list.insert(TimeRange(rational(0), rational(10)));
list.remove(TimeRange(rational(3), rational(7)));
TimeRangeList list;
list.insert(TimeRange(rational(0), rational(10)));
list.remove(TimeRange(rational(3), rational(7)));
EXPECT_EQ(list.size(), 2);
EXPECT_EQ(list.first().out(), rational(3));
EXPECT_EQ(list.last().in(), rational(7));
EXPECT_EQ(list.size(), 2);
EXPECT_EQ(list.first().out(), rational(3));
EXPECT_EQ(list.last().in(), rational(7));
}
TEST(CoreTimeRangeList, Shift)
{
TimeRangeList list;
list.insert(TimeRange(rational(0), rational(5)));
list.shift(rational(10));
TimeRangeList list;
list.insert(TimeRange(rational(0), rational(5)));
list.shift(rational(10));
EXPECT_EQ(list.first().in(), rational(10));
EXPECT_EQ(list.first().out(), rational(15));
EXPECT_EQ(list.first().in(), rational(10));
EXPECT_EQ(list.first().out(), rational(15));
}
TEST(CoreTimeRangeList, TrimInAndOut)
{
TimeRangeList list;
list.insert(TimeRange(rational(10), rational(20)));
list.trim_in(rational(5));
EXPECT_EQ(list.first().in(), rational(15));
EXPECT_EQ(list.first().out(), rational(20));
TimeRangeList list;
list.insert(TimeRange(rational(10), rational(20)));
list.trim_in(rational(5));
EXPECT_EQ(list.first().in(), rational(15));
EXPECT_EQ(list.first().out(), rational(20));
list.trim_out(rational(-5));
// set_out(out + diff) = 20 + (-5) = 15
EXPECT_EQ(list.first().out(), rational(15));
list.trim_out(rational(-5));
// set_out(out + diff) = 20 + (-5) = 15
EXPECT_EQ(list.first().out(), rational(15));
}
TEST(CoreTimeRangeList, Intersects)
{
TimeRangeList list;
list.insert(TimeRange(rational(0), rational(10)));
list.insert(TimeRange(rational(20), rational(30)));
TimeRangeList list;
list.insert(TimeRange(rational(0), rational(10)));
list.insert(TimeRange(rational(20), rational(30)));
TimeRangeList result = list.Intersects(TimeRange(rational(5), rational(25)));
EXPECT_EQ(result.size(), 2);
EXPECT_EQ(result.first().in(), rational(5));
EXPECT_EQ(result.first().out(), rational(10));
TimeRangeList result =
list.Intersects(TimeRange(rational(5), rational(25)));
EXPECT_EQ(result.size(), 2);
EXPECT_EQ(result.first().in(), rational(5));
EXPECT_EQ(result.first().out(), rational(10));
}
TEST(CoreTimeRangeListFrameIterator, IteratesFrames)
{
TimeRangeList list;
// 5 seconds at 25fps = 125 frames
list.insert(TimeRange(rational(0), rational(5)));
TimeRangeListFrameIterator it(list, rational(1, 25));
TimeRangeList list;
// 5 seconds at 25fps = 125 frames
list.insert(TimeRange(rational(0), rational(5)));
TimeRangeListFrameIterator it(list, rational(1, 25));
rational out;
int count = 0;
while (it.GetNext(&out)) {
count++;
}
rational out;
int count = 0;
while (it.GetNext(&out)) {
count++;
}
EXPECT_EQ(count, 125);
EXPECT_EQ(it.size(), 125);
EXPECT_EQ(count, 125);
EXPECT_EQ(it.size(), 125);
}
TEST(CoreTimeRangeListFrameIterator, HasNext)
{
TimeRangeList list;
list.insert(TimeRange(rational(0), rational(1)));
TimeRangeListFrameIterator it(list, rational(1, 25));
TimeRangeList list;
list.insert(TimeRange(rational(0), rational(1)));
TimeRangeListFrameIterator it(list, rational(1, 25));
EXPECT_TRUE(it.HasNext());
rational out;
while (it.GetNext(&out)) {
}
EXPECT_FALSE(it.HasNext());
EXPECT_TRUE(it.HasNext());
rational out;
while (it.GetNext(&out)) {
}
EXPECT_FALSE(it.HasNext());
}
+80 -67
View File
@@ -21,7 +21,8 @@ TEST(DynamicRenderBackend, LoadsExperimentalOpenGLBackend)
#else
olive::DynamicRenderer renderer(QStringLiteral("opengl"));
if (!renderer.Load()) {
GTEST_SKIP() << "opengl backend library could not be loaded in this environment";
GTEST_SKIP()
<< "opengl backend library could not be loaded in this environment";
}
EXPECT_EQ(renderer.OpenGLContext(), nullptr);
@@ -48,11 +49,13 @@ TEST(DynamicRenderBackend, OpenGLBackendFollowsAdapterToRenderThread)
#else
olive::DynamicRenderer renderer(QStringLiteral("opengl"));
if (!renderer.Load()) {
GTEST_SKIP() << "opengl backend library could not be loaded in this environment";
GTEST_SKIP()
<< "opengl backend library could not be loaded in this environment";
}
if (!renderer.Init()) {
GTEST_SKIP() << "OpenGL backend could not be initialized on this system";
GTEST_SKIP()
<< "OpenGL backend could not be initialized on this system";
}
QThread render_thread;
@@ -71,9 +74,9 @@ TEST(DynamicRenderBackend, OpenGLBackendFollowsAdapterToRenderThread)
&renderer,
[&]() {
renderer.PostInit();
texture = renderer.CreateTexture(olive::VideoParams(
64, 64, olive::PixelFormat::U8,
olive::VideoParams::kRGBAChannelCount));
texture = renderer.CreateTexture(
olive::VideoParams(64, 64, olive::PixelFormat::U8,
olive::VideoParams::kRGBAChannelCount));
},
Qt::BlockingQueuedConnection);
@@ -94,7 +97,8 @@ TEST(DynamicRenderBackend, LoadsExperimentalVulkanBackendWhenAvailable)
#else
olive::DynamicRenderer renderer(QStringLiteral("vulkan"));
if (!renderer.Load()) {
GTEST_SKIP() << "vulkan backend library could not be loaded in this environment";
GTEST_SKIP()
<< "vulkan backend library could not be loaded in this environment";
}
OakRenderBackendInfo info = {};
@@ -121,13 +125,15 @@ TEST(DynamicRenderBackend, FallsBackWhenExperimentalVulkanUnavailable)
#else
olive::DynamicRenderer renderer(QStringLiteral("vulkan"));
if (!renderer.Load()) {
GTEST_SKIP() << "vulkan backend library could not be loaded in this environment";
GTEST_SKIP()
<< "vulkan backend library could not be loaded in this environment";
}
OakRenderBackendInfo info = {};
ASSERT_TRUE(renderer.GetBackendInfo(&info));
if (info.kind == OAK_RENDER_BACKEND_VULKAN) {
GTEST_SKIP() << "Vulkan backend is available on this system; skip fallback test";
GTEST_SKIP()
<< "Vulkan backend is available on this system; skip fallback test";
}
EXPECT_EQ(renderer.backend_name(), QStringLiteral("opengl"));
EXPECT_EQ(renderer.OpenGLContext(), nullptr);
@@ -145,7 +151,8 @@ TEST(DynamicRenderBackend, VulkanUploadBlitDownload)
#else
olive::DynamicRenderer renderer(QStringLiteral("vulkan"));
if (!renderer.Load()) {
GTEST_SKIP() << "vulkan backend library could not be loaded in this environment";
GTEST_SKIP()
<< "vulkan backend library could not be loaded in this environment";
}
OakRenderBackendInfo info = {};
@@ -168,8 +175,8 @@ TEST(DynamicRenderBackend, VulkanUploadBlitDownload)
QByteArray src_data(kSize * kSize * 4, 0);
for (int i = 0; i < kSize * kSize; ++i) {
src_data[i * 4 + 0] = static_cast<char>(255); // R
src_data[i * 4 + 1] = static_cast<char>(0); // G
src_data[i * 4 + 2] = static_cast<char>(0); // B
src_data[i * 4 + 1] = static_cast<char>(0); // G
src_data[i * 4 + 2] = static_cast<char>(0); // B
src_data[i * 4 + 3] = static_cast<char>(255); // A
}
src->Upload(src_data.data(), kSize);
@@ -178,23 +185,24 @@ TEST(DynamicRenderBackend, VulkanUploadBlitDownload)
ASSERT_NE(dst, nullptr);
ASSERT_FALSE(dst->IsDummy());
const QString vert = QStringLiteral(
"uniform mat4 ove_mvpmat;\n"
"in vec4 a_position;\n"
"in vec2 a_texcoord;\n"
"out vec2 ove_texcoord;\n"
"void main() {\n"
" gl_Position = ove_mvpmat * a_position;\n"
" ove_texcoord = a_texcoord;\n"
"}\n");
const QString frag = QStringLiteral(
"uniform sampler2D ove_maintex;\n"
"in vec2 ove_texcoord;\n"
"out vec4 frag_color;\n"
"void main() {\n"
" frag_color = texture(ove_maintex, ove_texcoord);\n"
"}\n");
QVariant shader = renderer.CreateNativeShader(olive::ShaderCode(frag, vert));
const QString vert =
QStringLiteral("uniform mat4 ove_mvpmat;\n"
"in vec4 a_position;\n"
"in vec2 a_texcoord;\n"
"out vec2 ove_texcoord;\n"
"void main() {\n"
" gl_Position = ove_mvpmat * a_position;\n"
" ove_texcoord = a_texcoord;\n"
"}\n");
const QString frag =
QStringLiteral("uniform sampler2D ove_maintex;\n"
"in vec2 ove_texcoord;\n"
"out vec4 frag_color;\n"
"void main() {\n"
" frag_color = texture(ove_maintex, ove_texcoord);\n"
"}\n");
QVariant shader =
renderer.CreateNativeShader(olive::ShaderCode(frag, vert));
ASSERT_FALSE(shader.isNull());
olive::ShaderJob job;
@@ -226,7 +234,8 @@ TEST(DynamicRenderBackend, VulkanNullDestinationBlitDoesNotCrash)
#else
olive::DynamicRenderer renderer(QStringLiteral("vulkan"));
if (!renderer.Load()) {
GTEST_SKIP() << "vulkan backend library could not be loaded in this environment";
GTEST_SKIP()
<< "vulkan backend library could not be loaded in this environment";
}
OakRenderBackendInfo info = {};
@@ -253,23 +262,24 @@ TEST(DynamicRenderBackend, VulkanNullDestinationBlitDoesNotCrash)
}
src->Upload(src_data.data(), kSize);
const QString vert = QStringLiteral(
"uniform mat4 ove_mvpmat;\n"
"in vec4 a_position;\n"
"in vec2 a_texcoord;\n"
"out vec2 ove_texcoord;\n"
"void main() {\n"
" gl_Position = ove_mvpmat * a_position;\n"
" ove_texcoord = a_texcoord;\n"
"}\n");
const QString frag = QStringLiteral(
"uniform sampler2D ove_maintex;\n"
"in vec2 ove_texcoord;\n"
"out vec4 frag_color;\n"
"void main() {\n"
" frag_color = texture(ove_maintex, ove_texcoord);\n"
"}\n");
QVariant shader = renderer.CreateNativeShader(olive::ShaderCode(frag, vert));
const QString vert =
QStringLiteral("uniform mat4 ove_mvpmat;\n"
"in vec4 a_position;\n"
"in vec2 a_texcoord;\n"
"out vec2 ove_texcoord;\n"
"void main() {\n"
" gl_Position = ove_mvpmat * a_position;\n"
" ove_texcoord = a_texcoord;\n"
"}\n");
const QString frag =
QStringLiteral("uniform sampler2D ove_maintex;\n"
"in vec2 ove_texcoord;\n"
"out vec4 frag_color;\n"
"void main() {\n"
" frag_color = texture(ove_maintex, ove_texcoord);\n"
"}\n");
QVariant shader =
renderer.CreateNativeShader(olive::ShaderCode(frag, vert));
ASSERT_FALSE(shader.isNull());
olive::ShaderJob job;
@@ -294,7 +304,8 @@ TEST(DynamicRenderBackend, VulkanIterativeBlitPingPong)
#else
olive::DynamicRenderer renderer(QStringLiteral("vulkan"));
if (!renderer.Load()) {
GTEST_SKIP() << "vulkan backend library could not be loaded in this environment";
GTEST_SKIP()
<< "vulkan backend library could not be loaded in this environment";
}
OakRenderBackendInfo info = {};
@@ -327,24 +338,25 @@ TEST(DynamicRenderBackend, VulkanIterativeBlitPingPong)
ASSERT_FALSE(dst->IsDummy());
// Shader that samples the iterative input and scales RGB by 0.5 each pass.
const QString vert = QStringLiteral(
"uniform mat4 ove_mvpmat;\n"
"in vec4 a_position;\n"
"in vec2 a_texcoord;\n"
"out vec2 ove_texcoord;\n"
"void main() {\n"
" gl_Position = ove_mvpmat * a_position;\n"
" ove_texcoord = a_texcoord;\n"
"}\n");
const QString frag = QStringLiteral(
"uniform sampler2D ove_maintex;\n"
"in vec2 ove_texcoord;\n"
"out vec4 frag_color;\n"
"void main() {\n"
" vec4 c = texture(ove_maintex, ove_texcoord);\n"
" frag_color = vec4(c.rgb * 0.5, c.a);\n"
"}\n");
QVariant shader = renderer.CreateNativeShader(olive::ShaderCode(frag, vert));
const QString vert =
QStringLiteral("uniform mat4 ove_mvpmat;\n"
"in vec4 a_position;\n"
"in vec2 a_texcoord;\n"
"out vec2 ove_texcoord;\n"
"void main() {\n"
" gl_Position = ove_mvpmat * a_position;\n"
" ove_texcoord = a_texcoord;\n"
"}\n");
const QString frag =
QStringLiteral("uniform sampler2D ove_maintex;\n"
"in vec2 ove_texcoord;\n"
"out vec4 frag_color;\n"
"void main() {\n"
" vec4 c = texture(ove_maintex, ove_texcoord);\n"
" frag_color = vec4(c.rgb * 0.5, c.a);\n"
"}\n");
QVariant shader =
renderer.CreateNativeShader(olive::ShaderCode(frag, vert));
ASSERT_FALSE(shader.isNull());
olive::ShaderJob job;
@@ -378,7 +390,8 @@ TEST(DynamicRenderBackend, VulkanUploadDownloadThreeChannel)
#else
olive::DynamicRenderer renderer(QStringLiteral("vulkan"));
if (!renderer.Load()) {
GTEST_SKIP() << "vulkan backend library could not be loaded in this environment";
GTEST_SKIP()
<< "vulkan backend library could not be loaded in this environment";
}
OakRenderBackendInfo info = {};
+2 -1
View File
@@ -12,7 +12,8 @@ using namespace olive;
TEST(FFmpegDecoderHW, H264_422_10bit_CPUFrame_IsNotBlack)
{
const QString path = QStringLiteral("/home/mikesolar/Videos/dual_system_video.MOV");
const QString path =
QStringLiteral("/home/mikesolar/Videos/dual_system_video.MOV");
if (!QFileInfo::exists(path)) {
GTEST_SKIP() << "Test footage not available: " << path.toStdString();
+4 -4
View File
@@ -10,10 +10,10 @@ int main(int argc, char **argv)
{
Q_INIT_RESOURCE(ocioconf);
if (qEnvironmentVariableIsEmpty("OCIO")) {
qputenv("OCIO", QFile::encodeName(
QDir(QStringLiteral(OAK_TEST_SOURCE_DIR))
.filePath(QStringLiteral(
"app/render/ocioconf/config.ocio"))));
qputenv("OCIO",
QFile::encodeName(QDir(QStringLiteral(OAK_TEST_SOURCE_DIR))
.filePath(QStringLiteral(
"app/render/ocioconf/config.ocio"))));
}
if (qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM")) {
qputenv("QT_QPA_PLATFORM", "offscreen");
+37 -18
View File
@@ -5,24 +5,39 @@
TEST(ModuleSmoke, ToolAddableObjectNames)
{
EXPECT_FALSE(olive::Tool::GetAddableObjectName(olive::Tool::kAddableEmpty).isEmpty());
EXPECT_FALSE(olive::Tool::GetAddableObjectName(olive::Tool::kAddableBars).isEmpty());
EXPECT_FALSE(olive::Tool::GetAddableObjectName(olive::Tool::kAddableShape).isEmpty());
EXPECT_FALSE(olive::Tool::GetAddableObjectName(olive::Tool::kAddableSolid).isEmpty());
EXPECT_FALSE(olive::Tool::GetAddableObjectName(olive::Tool::kAddableTitle).isEmpty());
EXPECT_FALSE(olive::Tool::GetAddableObjectName(olive::Tool::kAddableTone).isEmpty());
EXPECT_FALSE(olive::Tool::GetAddableObjectName(olive::Tool::kAddableSubtitle).isEmpty());
EXPECT_FALSE(
olive::Tool::GetAddableObjectName(olive::Tool::kAddableEmpty).isEmpty());
EXPECT_FALSE(
olive::Tool::GetAddableObjectName(olive::Tool::kAddableBars).isEmpty());
EXPECT_FALSE(
olive::Tool::GetAddableObjectName(olive::Tool::kAddableShape).isEmpty());
EXPECT_FALSE(
olive::Tool::GetAddableObjectName(olive::Tool::kAddableSolid).isEmpty());
EXPECT_FALSE(
olive::Tool::GetAddableObjectName(olive::Tool::kAddableTitle).isEmpty());
EXPECT_FALSE(
olive::Tool::GetAddableObjectName(olive::Tool::kAddableTone).isEmpty());
EXPECT_FALSE(
olive::Tool::GetAddableObjectName(olive::Tool::kAddableSubtitle)
.isEmpty());
}
TEST(ModuleSmoke, ToolAddableObjectIds)
{
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableEmpty), QStringLiteral("empty"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableBars), QStringLiteral("bars"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableShape), QStringLiteral("shape"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableSolid), QStringLiteral("solid"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableTitle), QStringLiteral("title"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableTone), QStringLiteral("tone"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableSubtitle), QStringLiteral("subtitle"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableEmpty),
QStringLiteral("empty"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableBars),
QStringLiteral("bars"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableShape),
QStringLiteral("shape"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableSolid),
QStringLiteral("solid"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableTitle),
QStringLiteral("title"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableTone),
QStringLiteral("tone"));
EXPECT_EQ(olive::Tool::GetAddableObjectID(olive::Tool::kAddableSubtitle),
QStringLiteral("subtitle"));
}
TEST(ModuleSmoke, HumanStringsSampleRate)
@@ -33,12 +48,16 @@ TEST(ModuleSmoke, HumanStringsSampleRate)
TEST(ModuleSmoke, HumanStringsChannelLayout)
{
EXPECT_FALSE(olive::HumanStrings::ChannelLayoutToString(AV_CH_LAYOUT_MONO).isEmpty());
EXPECT_FALSE(olive::HumanStrings::ChannelLayoutToString(AV_CH_LAYOUT_STEREO).isEmpty());
EXPECT_FALSE(
olive::HumanStrings::ChannelLayoutToString(AV_CH_LAYOUT_MONO).isEmpty());
EXPECT_FALSE(olive::HumanStrings::ChannelLayoutToString(AV_CH_LAYOUT_STEREO)
.isEmpty());
}
TEST(ModuleSmoke, HumanStringsFormat)
{
EXPECT_FALSE(olive::HumanStrings::FormatToString(olive::SampleFormat::U8).isEmpty());
EXPECT_FALSE(olive::HumanStrings::FormatToString(olive::SampleFormat::F32).isEmpty());
EXPECT_FALSE(
olive::HumanStrings::FormatToString(olive::SampleFormat::U8).isEmpty());
EXPECT_FALSE(
olive::HumanStrings::FormatToString(olive::SampleFormat::F32).isEmpty());
}
+4 -2
View File
@@ -19,8 +19,10 @@ TEST(NodeGlobals, ConstructedWithParams)
audio_params.set_sample_rate(48000);
audio_params.set_channel_layout(AV_CH_LAYOUT_STEREO);
olive::TimeRange time(olive::core::rational(1, 24), olive::core::rational(2, 24));
olive::NodeGlobals globals(video_params, audio_params, time, olive::LoopMode::kLoopModeLoop);
olive::TimeRange time(olive::core::rational(1, 24),
olive::core::rational(2, 24));
olive::NodeGlobals globals(video_params, audio_params, time,
olive::LoopMode::kLoopModeLoop);
EXPECT_EQ(globals.vparams().width(), 1920);
EXPECT_EQ(globals.vparams().height(), 1080);
+5 -3
View File
@@ -47,8 +47,9 @@ TEST(NodeProject, SettingsRoundTrip)
{
olive::Project project;
project.SetSetting(olive::Project::kCacheLocationSettingKey,
QString::number(olive::Project::kCacheStoreAlongsideProject));
project.SetSetting(
olive::Project::kCacheLocationSettingKey,
QString::number(olive::Project::kCacheStoreAlongsideProject));
EXPECT_EQ(project.GetCacheLocationSetting(),
olive::Project::kCacheStoreAlongsideProject);
@@ -62,7 +63,8 @@ TEST(NodeProject, SettingsRoundTrip)
EXPECT_EQ(project.GetDefaultInputColorSpace(), QStringLiteral("ACEScg"));
project.SetColorReferenceSpace(QStringLiteral("ACES - ACEScg"));
EXPECT_EQ(project.GetColorReferenceSpace(), QStringLiteral("ACES - ACEScg"));
EXPECT_EQ(project.GetColorReferenceSpace(),
QStringLiteral("ACES - ACEScg"));
}
TEST(NodeProject, InitializeCreatesRoot)
+7 -3
View File
@@ -10,7 +10,8 @@
#include "node/value.h"
#include "render/diskmanager.h"
namespace {
namespace
{
class TestNode final : public olive::Node {
public:
TestNode()
@@ -55,7 +56,8 @@ public:
TEST(NodeSerialization, SaveAndLoadInput)
{
const bool created_disk_manager = (olive::DiskManager::instance() == nullptr);
const bool created_disk_manager =
(olive::DiskManager::instance() == nullptr);
if (created_disk_manager) {
olive::DiskManager::CreateInstance();
}
@@ -87,7 +89,9 @@ TEST(NodeSerialization, SaveAndLoadInput)
EXPECT_EQ(loaded.GetLabel(), QStringLiteral("MyNode"));
EXPECT_EQ(loaded.GetOverrideColor(), 2);
EXPECT_DOUBLE_EQ(loaded.GetSplitStandardValue(QStringLiteral("Value"), -1)
.first().toDouble(), 3.5);
.first()
.toDouble(),
3.5);
if (created_disk_manager) {
olive::DiskManager::DestroyInstance();
+26 -19
View File
@@ -11,27 +11,27 @@ TEST(NodeValue, VectorRoundTrip)
QVector2D v2(1.5f, -2.0f);
QString encoded = olive::NodeValue::ValueToString(
olive::NodeValue::kVec2, QVariant::fromValue(v2), false);
QVariant decoded = olive::NodeValue::StringToValue(
olive::NodeValue::kVec2, encoded, false);
QVariant decoded = olive::NodeValue::StringToValue(olive::NodeValue::kVec2,
encoded, false);
QVector2D v2_out = decoded.value<QVector2D>();
EXPECT_FLOAT_EQ(v2_out.x(), v2.x());
EXPECT_FLOAT_EQ(v2_out.y(), v2.y());
QVector3D v3(1.0f, 2.0f, 3.0f);
encoded = olive::NodeValue::ValueToString(
olive::NodeValue::kVec3, QVariant::fromValue(v3), false);
decoded = olive::NodeValue::StringToValue(
olive::NodeValue::kVec3, encoded, false);
encoded = olive::NodeValue::ValueToString(olive::NodeValue::kVec3,
QVariant::fromValue(v3), false);
decoded = olive::NodeValue::StringToValue(olive::NodeValue::kVec3, encoded,
false);
QVector3D v3_out = decoded.value<QVector3D>();
EXPECT_FLOAT_EQ(v3_out.x(), v3.x());
EXPECT_FLOAT_EQ(v3_out.y(), v3.y());
EXPECT_FLOAT_EQ(v3_out.z(), v3.z());
QVector4D v4(1.0f, 2.0f, 3.0f, 4.0f);
encoded = olive::NodeValue::ValueToString(
olive::NodeValue::kVec4, QVariant::fromValue(v4), false);
decoded = olive::NodeValue::StringToValue(
olive::NodeValue::kVec4, encoded, false);
encoded = olive::NodeValue::ValueToString(olive::NodeValue::kVec4,
QVariant::fromValue(v4), false);
decoded = olive::NodeValue::StringToValue(olive::NodeValue::kVec4, encoded,
false);
QVector4D v4_out = decoded.value<QVector4D>();
EXPECT_FLOAT_EQ(v4_out.x(), v4.x());
EXPECT_FLOAT_EQ(v4_out.y(), v4.y());
@@ -42,8 +42,8 @@ TEST(NodeValue, VectorRoundTrip)
TEST(NodeValue, BinaryRoundTrip)
{
QByteArray data("OliveTest");
QString encoded = olive::NodeValue::ValueToString(
olive::NodeValue::kBinary, data, false);
QString encoded =
olive::NodeValue::ValueToString(olive::NodeValue::kBinary, data, false);
QVariant decoded = olive::NodeValue::StringToValue(
olive::NodeValue::kBinary, encoded, false);
EXPECT_EQ(decoded.toByteArray(), data);
@@ -51,9 +51,12 @@ TEST(NodeValue, BinaryRoundTrip)
TEST(NodeValue, TypeClassification)
{
EXPECT_TRUE(olive::NodeValue::type_can_be_interpolated(olive::NodeValue::kFloat));
EXPECT_TRUE(olive::NodeValue::type_can_be_interpolated(olive::NodeValue::kColor));
EXPECT_FALSE(olive::NodeValue::type_can_be_interpolated(olive::NodeValue::kInt));
EXPECT_TRUE(
olive::NodeValue::type_can_be_interpolated(olive::NodeValue::kFloat));
EXPECT_TRUE(
olive::NodeValue::type_can_be_interpolated(olive::NodeValue::kColor));
EXPECT_FALSE(
olive::NodeValue::type_can_be_interpolated(olive::NodeValue::kInt));
EXPECT_TRUE(olive::NodeValue::type_is_numeric(olive::NodeValue::kInt));
EXPECT_TRUE(olive::NodeValue::type_is_numeric(olive::NodeValue::kFloat));
@@ -70,7 +73,8 @@ TEST(NodeValue, TypeClassification)
TEST(NodeValue, DataTypeNameRoundTrip)
{
for (int i = olive::NodeValue::kNone; i < olive::NodeValue::kDataTypeCount; ++i) {
for (int i = olive::NodeValue::kNone; i < olive::NodeValue::kDataTypeCount;
++i) {
auto type = static_cast<olive::NodeValue::Type>(i);
QString name = olive::NodeValue::GetDataTypeName(type);
if (name.isEmpty()) {
@@ -109,8 +113,10 @@ TEST(NodeValueTable, PushAndGet)
TEST(NodeValueTable, TakeRemovesValue)
{
olive::NodeValueTable table;
table.Push(olive::NodeValue(olive::NodeValue::kInt, static_cast<int64_t>(1)));
table.Push(olive::NodeValue(olive::NodeValue::kInt, static_cast<int64_t>(2)));
table.Push(
olive::NodeValue(olive::NodeValue::kInt, static_cast<int64_t>(1)));
table.Push(
olive::NodeValue(olive::NodeValue::kInt, static_cast<int64_t>(2)));
olive::NodeValue taken = table.Take(olive::NodeValue::kInt);
EXPECT_EQ(taken.toInt(), 2);
@@ -120,7 +126,8 @@ TEST(NodeValueTable, TakeRemovesValue)
TEST(NodeValueTable, ClearEmptiesTable)
{
olive::NodeValueTable table;
table.Push(olive::NodeValue(olive::NodeValue::kText, QStringLiteral("hello")));
table.Push(
olive::NodeValue(olive::NodeValue::kText, QStringLiteral("hello")));
table.Clear();
EXPECT_TRUE(table.isEmpty());
EXPECT_EQ(table.Count(), 0);
+4 -3
View File
@@ -14,7 +14,8 @@ TEST(OpenGLRenderer, DownloadFromTextureWithoutCurrentContext)
QOpenGLContext context;
if (!context.create()) {
GTEST_SKIP() << "Skipping OpenGL test because no context can be created";
GTEST_SKIP()
<< "Skipping OpenGL test because no context can be created";
}
ASSERT_EQ(QOpenGLContext::currentContext(), nullptr);
@@ -26,8 +27,8 @@ TEST(OpenGLRenderer, DownloadFromTextureWithoutCurrentContext)
olive::VideoParams::kInterlaceNone, 1);
unsigned char buffer[4 * 4 * 4] = {};
renderer.DownloadFromTexture(QVariant::fromValue<GLuint>(0), params,
buffer, 4 * 4);
renderer.DownloadFromTexture(QVariant::fromValue<GLuint>(0), params, buffer,
4 * 4);
EXPECT_EQ(QOpenGLContext::currentContext(), nullptr);
}
+183 -166
View File
@@ -20,219 +20,236 @@ using namespace olive;
using namespace olive::core;
// Test helper to create AVFrame with specific format
static AVFramePtr CreateTestFrame(int width, int height, AVPixelFormat fmt, uint32_t fill_color = 0xFF804020) {
AVFramePtr frame = CreateAVFramePtr();
frame->width = width;
frame->height = height;
frame->format = fmt;
static AVFramePtr CreateTestFrame(int width, int height, AVPixelFormat fmt,
uint32_t fill_color = 0xFF804020)
{
AVFramePtr frame = CreateAVFramePtr();
frame->width = width;
frame->height = height;
frame->format = fmt;
if (av_frame_get_buffer(frame.get(), 0) < 0) {
return nullptr;
}
if (av_frame_get_buffer(frame.get(), 0) < 0) {
return nullptr;
}
if (av_frame_make_writable(frame.get()) < 0) {
return nullptr;
}
if (av_frame_make_writable(frame.get()) < 0) {
return nullptr;
}
// Fill with test pattern
uint8_t r = (fill_color >> 24) & 0xFF;
uint8_t g = (fill_color >> 16) & 0xFF;
uint8_t b = (fill_color >> 8) & 0xFF;
uint8_t a = fill_color & 0xFF;
// Fill with test pattern
uint8_t r = (fill_color >> 24) & 0xFF;
uint8_t g = (fill_color >> 16) & 0xFF;
uint8_t b = (fill_color >> 8) & 0xFF;
uint8_t a = fill_color & 0xFF;
if (fmt == AV_PIX_FMT_RGBA) {
for (int y = 0; y < height; ++y) {
uint8_t *row = frame->data[0] + y * frame->linesize[0];
for (int x = 0; x < width; ++x) {
row[x * 4 + 0] = r;
row[x * 4 + 1] = g;
row[x * 4 + 2] = b;
row[x * 4 + 3] = a;
}
}
} else if (fmt == AV_PIX_FMT_RGBA64) {
uint16_t r16 = (r << 8) | r;
uint16_t g16 = (g << 8) | g;
uint16_t b16 = (b << 8) | b;
uint16_t a16 = (a << 8) | a;
for (int y = 0; y < height; ++y) {
uint16_t *row = reinterpret_cast<uint16_t*>(frame->data[0] + y * frame->linesize[0]);
for (int x = 0; x < width; ++x) {
row[x * 4 + 0] = r16;
row[x * 4 + 1] = g16;
row[x * 4 + 2] = b16;
row[x * 4 + 3] = a16;
}
}
}
if (fmt == AV_PIX_FMT_RGBA) {
for (int y = 0; y < height; ++y) {
uint8_t *row = frame->data[0] + y * frame->linesize[0];
for (int x = 0; x < width; ++x) {
row[x * 4 + 0] = r;
row[x * 4 + 1] = g;
row[x * 4 + 2] = b;
row[x * 4 + 3] = a;
}
}
} else if (fmt == AV_PIX_FMT_RGBA64) {
uint16_t r16 = (r << 8) | r;
uint16_t g16 = (g << 8) | g;
uint16_t b16 = (b << 8) | b;
uint16_t a16 = (a << 8) | a;
for (int y = 0; y < height; ++y) {
uint16_t *row = reinterpret_cast<uint16_t *>(
frame->data[0] + y * frame->linesize[0]);
for (int x = 0; x < width; ++x) {
row[x * 4 + 0] = r16;
row[x * 4 + 1] = g16;
row[x * 4 + 2] = b16;
row[x * 4 + 3] = a16;
}
}
}
return frame;
return frame;
}
// Test U8 to U16 conversion
TEST(FormatConversion, U8ToU16) {
const int width = 10;
const int height = 10;
const uint32_t test_color = 0xFF804020; // ARGB: A=255, R=128, G=64, B=32
TEST(FormatConversion, U8ToU16)
{
const int width = 10;
const int height = 10;
const uint32_t test_color = 0xFF804020; // ARGB: A=255, R=128, G=64, B=32
// Create U8 frame
AVFramePtr u8_frame = CreateTestFrame(width, height, AV_PIX_FMT_RGBA, test_color);
ASSERT_NE(u8_frame, nullptr);
// Create U8 frame
AVFramePtr u8_frame =
CreateTestFrame(width, height, AV_PIX_FMT_RGBA, test_color);
ASSERT_NE(u8_frame, nullptr);
// Verify U8 values
uint8_t *first_pixel_u8 = u8_frame->data[0];
EXPECT_EQ(first_pixel_u8[0], 0xFF); // R
EXPECT_EQ(first_pixel_u8[1], 0x80); // G
EXPECT_EQ(first_pixel_u8[2], 0x40); // B
EXPECT_EQ(first_pixel_u8[3], 0x20); // A
// Verify U8 values
uint8_t *first_pixel_u8 = u8_frame->data[0];
EXPECT_EQ(first_pixel_u8[0], 0xFF); // R
EXPECT_EQ(first_pixel_u8[1], 0x80); // G
EXPECT_EQ(first_pixel_u8[2], 0x40); // B
EXPECT_EQ(first_pixel_u8[3], 0x20); // A
// Create U16 frame
AVFramePtr u16_frame = CreateTestFrame(width, height, AV_PIX_FMT_RGBA64, test_color);
ASSERT_NE(u16_frame, nullptr);
// Create U16 frame
AVFramePtr u16_frame =
CreateTestFrame(width, height, AV_PIX_FMT_RGBA64, test_color);
ASSERT_NE(u16_frame, nullptr);
// Verify U16 values (should be U8 value repeated: 0xFF -> 0xFFFF, 0x80 -> 0x8080)
uint16_t *first_pixel_u16 = reinterpret_cast<uint16_t*>(u16_frame->data[0]);
EXPECT_EQ(first_pixel_u16[0], 0xFFFF); // R
EXPECT_EQ(first_pixel_u16[1], 0x8080); // G
EXPECT_EQ(first_pixel_u16[2], 0x4040); // B
EXPECT_EQ(first_pixel_u16[3], 0x2020); // A
// Verify U16 values (should be U8 value repeated: 0xFF -> 0xFFFF, 0x80 -> 0x8080)
uint16_t *first_pixel_u16 =
reinterpret_cast<uint16_t *>(u16_frame->data[0]);
EXPECT_EQ(first_pixel_u16[0], 0xFFFF); // R
EXPECT_EQ(first_pixel_u16[1], 0x8080); // G
EXPECT_EQ(first_pixel_u16[2], 0x4040); // B
EXPECT_EQ(first_pixel_u16[3], 0x2020); // A
}
// Test FFmpeg sws_scale for U16 to U8 conversion
TEST(FormatConversion, FFmpegU16ToU8) {
const int width = 10;
const int height = 10;
const uint32_t test_color = 0xFF804020;
TEST(FormatConversion, FFmpegU16ToU8)
{
const int width = 10;
const int height = 10;
const uint32_t test_color = 0xFF804020;
// Create U16 frame
AVFramePtr u16_frame = CreateTestFrame(width, height, AV_PIX_FMT_RGBA64, test_color);
ASSERT_NE(u16_frame, nullptr);
// Create U16 frame
AVFramePtr u16_frame =
CreateTestFrame(width, height, AV_PIX_FMT_RGBA64, test_color);
ASSERT_NE(u16_frame, nullptr);
// Create destination U8 frame
AVFramePtr u8_frame = CreateTestFrame(width, height, AV_PIX_FMT_RGBA, 0);
ASSERT_NE(u8_frame, nullptr);
// Create destination U8 frame
AVFramePtr u8_frame = CreateTestFrame(width, height, AV_PIX_FMT_RGBA, 0);
ASSERT_NE(u8_frame, nullptr);
// Use sws_scale to convert
SwsContext *sws_ctx = sws_getContext(
width, height, AV_PIX_FMT_RGBA64,
width, height, AV_PIX_FMT_RGBA,
SWS_POINT, nullptr, nullptr, nullptr);
ASSERT_NE(sws_ctx, nullptr);
// Use sws_scale to convert
SwsContext *sws_ctx = sws_getContext(width, height, AV_PIX_FMT_RGBA64,
width, height, AV_PIX_FMT_RGBA,
SWS_POINT, nullptr, nullptr, nullptr);
ASSERT_NE(sws_ctx, nullptr);
sws_scale(sws_ctx, u16_frame->data, u16_frame->linesize, 0, height,
u8_frame->data, u8_frame->linesize);
sws_freeContext(sws_ctx);
sws_scale(sws_ctx, u16_frame->data, u16_frame->linesize, 0, height,
u8_frame->data, u8_frame->linesize);
sws_freeContext(sws_ctx);
// Verify conversion (U16 0xFFFF -> U8 0xFF, 0x8080 -> ~0x80, etc.)
// Note: FFmpeg sws_scale has rounding offset, so values may be off by 1
uint8_t *first_pixel = u8_frame->data[0];
EXPECT_NEAR(first_pixel[0], 0xFF, 1); // R (255 vs 255)
EXPECT_NEAR(first_pixel[1], 0x80, 1); // G (128 vs 129)
EXPECT_NEAR(first_pixel[2], 0x40, 1); // B (64 vs 64)
EXPECT_NEAR(first_pixel[3], 0x20, 1); // A (32 vs 32)
// Verify conversion (U16 0xFFFF -> U8 0xFF, 0x8080 -> ~0x80, etc.)
// Note: FFmpeg sws_scale has rounding offset, so values may be off by 1
uint8_t *first_pixel = u8_frame->data[0];
EXPECT_NEAR(first_pixel[0], 0xFF, 1); // R (255 vs 255)
EXPECT_NEAR(first_pixel[1], 0x80, 1); // G (128 vs 129)
EXPECT_NEAR(first_pixel[2], 0x40, 1); // B (64 vs 64)
EXPECT_NEAR(first_pixel[3], 0x20, 1); // A (32 vs 32)
}
// Test VideoParams to AVPixelFormat mapping
TEST(FormatConversion, VideoParamsToAVFormat) {
// U8 RGBA
VideoParams u8_rgba(320, 240, PixelFormat::U8, 4);
AVPixelFormat fmt_u8_rgba = FFmpegUtils::GetFFmpegPixelFormat(u8_rgba.format(), u8_rgba.channel_count());
EXPECT_EQ(fmt_u8_rgba, AV_PIX_FMT_RGBA);
TEST(FormatConversion, VideoParamsToAVFormat)
{
// U8 RGBA
VideoParams u8_rgba(320, 240, PixelFormat::U8, 4);
AVPixelFormat fmt_u8_rgba = FFmpegUtils::GetFFmpegPixelFormat(
u8_rgba.format(), u8_rgba.channel_count());
EXPECT_EQ(fmt_u8_rgba, AV_PIX_FMT_RGBA);
// U16 RGBA
VideoParams u16_rgba(320, 240, PixelFormat::U16, 4);
AVPixelFormat fmt_u16_rgba = FFmpegUtils::GetFFmpegPixelFormat(u16_rgba.format(), u16_rgba.channel_count());
EXPECT_EQ(fmt_u16_rgba, AV_PIX_FMT_RGBA64);
// U16 RGBA
VideoParams u16_rgba(320, 240, PixelFormat::U16, 4);
AVPixelFormat fmt_u16_rgba = FFmpegUtils::GetFFmpegPixelFormat(
u16_rgba.format(), u16_rgba.channel_count());
EXPECT_EQ(fmt_u16_rgba, AV_PIX_FMT_RGBA64);
// U8 RGB
VideoParams u8_rgb(320, 240, PixelFormat::U8, 3);
AVPixelFormat fmt_u8_rgb = FFmpegUtils::GetFFmpegPixelFormat(u8_rgb.format(), u8_rgb.channel_count());
EXPECT_EQ(fmt_u8_rgb, AV_PIX_FMT_RGB24);
// U8 RGB
VideoParams u8_rgb(320, 240, PixelFormat::U8, 3);
AVPixelFormat fmt_u8_rgb = FFmpegUtils::GetFFmpegPixelFormat(
u8_rgb.format(), u8_rgb.channel_count());
EXPECT_EQ(fmt_u8_rgb, AV_PIX_FMT_RGB24);
// U16 RGB
VideoParams u16_rgb(320, 240, PixelFormat::U16, 3);
AVPixelFormat fmt_u16_rgb = FFmpegUtils::GetFFmpegPixelFormat(u16_rgb.format(), u16_rgb.channel_count());
EXPECT_EQ(fmt_u16_rgb, AV_PIX_FMT_RGB48);
// U16 RGB
VideoParams u16_rgb(320, 240, PixelFormat::U16, 3);
AVPixelFormat fmt_u16_rgb = FFmpegUtils::GetFFmpegPixelFormat(
u16_rgb.format(), u16_rgb.channel_count());
EXPECT_EQ(fmt_u16_rgb, AV_PIX_FMT_RGB48);
}
// Test row bytes calculation
TEST(FormatConversion, RowBytes) {
const int width = 320;
TEST(FormatConversion, RowBytes)
{
const int width = 320;
// U8 RGBA: 4 bytes per pixel
EXPECT_EQ(width * 4, 1280);
// U8 RGBA: 4 bytes per pixel
EXPECT_EQ(width * 4, 1280);
// U16 RGBA: 8 bytes per pixel
EXPECT_EQ(width * 8, 2560);
// U16 RGBA: 8 bytes per pixel
EXPECT_EQ(width * 8, 2560);
// U8 RGB: 3 bytes per pixel
EXPECT_EQ(width * 3, 960);
// U8 RGB: 3 bytes per pixel
EXPECT_EQ(width * 3, 960);
// U16 RGB: 6 bytes per pixel
EXPECT_EQ(width * 6, 1920);
// U16 RGB: 6 bytes per pixel
EXPECT_EQ(width * 6, 1920);
}
// Test that linesize may differ from width * bpp due to alignment
TEST(FormatConversion, LinesizeAlignment) {
const int width = 10;
const int height = 10;
TEST(FormatConversion, LinesizeAlignment)
{
const int width = 10;
const int height = 10;
AVFramePtr frame = CreateAVFramePtr();
frame->width = width;
frame->height = height;
frame->format = AV_PIX_FMT_RGBA;
AVFramePtr frame = CreateAVFramePtr();
frame->width = width;
frame->height = height;
frame->format = AV_PIX_FMT_RGBA;
ASSERT_EQ(av_frame_get_buffer(frame.get(), 0), 0);
ASSERT_EQ(av_frame_get_buffer(frame.get(), 0), 0);
// linesize[0] should be at least width * 4
EXPECT_GE(frame->linesize[0], width * 4);
// linesize[0] should be at least width * 4
EXPECT_GE(frame->linesize[0], width * 4);
// linesize may be larger due to alignment (typically 32-byte aligned)
qDebug() << "Width:" << width << "Expected bytes:" << width * 4
<< "Actual linesize:" << frame->linesize[0];
// linesize may be larger due to alignment (typically 32-byte aligned)
qDebug() << "Width:" << width << "Expected bytes:" << width * 4
<< "Actual linesize:" << frame->linesize[0];
}
// Test loading actual image file
TEST(FormatConversion, LoadImageFile) {
// Load the test image
QString img_path = QStringLiteral("%1/../tests/img.png").arg(QDir::currentPath());
TEST(FormatConversion, LoadImageFile)
{
// Load the test image
QString img_path =
QStringLiteral("%1/../tests/img.png").arg(QDir::currentPath());
AVFramePtr frame = CreateAVFramePtr();
// Just create a simple test frame instead of loading an image
frame->width = 1920;
frame->height = 1080;
frame->format = AV_PIX_FMT_RGBA;
if (av_frame_get_buffer(frame.get(), 0) < 0) {
return;
}
// Fill with orange color (sunrise sky)
for (int y = 0; y < frame->height; ++y) {
uint8_t *row = frame->data[0] + y * frame->linesize[0];
uint8_t r = 255;
uint8_t g = 128 + (y * 127) / frame->height; // Gradient from 128 to 255
uint8_t b = 64;
uint8_t a = 255;
for (int x = 0; x < frame->width; ++x) {
row[x * 4 + 0] = r;
row[x * 4 + 1] = g;
row[x * 4 + 2] = b;
row[x * 4 + 3] = a;
}
}
ASSERT_NE(frame->data[0], nullptr) << "Failed to create test frame";
AVFramePtr frame = CreateAVFramePtr();
// Just create a simple test frame instead of loading an image
frame->width = 1920;
frame->height = 1080;
frame->format = AV_PIX_FMT_RGBA;
if (av_frame_get_buffer(frame.get(), 0) < 0) {
return;
}
// Fill with orange color (sunrise sky)
for (int y = 0; y < frame->height; ++y) {
uint8_t *row = frame->data[0] + y * frame->linesize[0];
uint8_t r = 255;
uint8_t g = 128 + (y * 127) / frame->height; // Gradient from 128 to 255
uint8_t b = 64;
uint8_t a = 255;
for (int x = 0; x < frame->width; ++x) {
row[x * 4 + 0] = r;
row[x * 4 + 1] = g;
row[x * 4 + 2] = b;
row[x * 4 + 3] = a;
}
}
ASSERT_NE(frame->data[0], nullptr) << "Failed to create test frame";
EXPECT_EQ(frame->width, 1920);
EXPECT_EQ(frame->height, 1080);
EXPECT_EQ(frame->width, 1920);
EXPECT_EQ(frame->height, 1080);
// Check first pixel (top-left corner of the sunrise image)
// Based on the image, it should have some orange/pink color in the sky area
uint8_t *first_pixel = frame->data[0];
qDebug() << "First pixel RGBA:" << first_pixel[0] << first_pixel[1]
<< first_pixel[2] << first_pixel[3];
// Check first pixel (top-left corner of the sunrise image)
// Based on the image, it should have some orange/pink color in the sky area
uint8_t *first_pixel = frame->data[0];
qDebug() << "First pixel RGBA:" << first_pixel[0] << first_pixel[1]
<< first_pixel[2] << first_pixel[3];
// The image is RGB, so we expect 3 channels
// First pixel should be non-black (sky area)
EXPECT_GT(first_pixel[0] + first_pixel[1] + first_pixel[2], 0);
// The image is RGB, so we expect 3 channels
// First pixel should be non-black (sky area)
EXPECT_GT(first_pixel[0] + first_pixel[1] + first_pixel[2], 0);
}
// Tests are registered with gtest, no main needed
+2 -1
View File
@@ -15,7 +15,8 @@ extern "C" {
#include "render/texture.h"
#include "render/videoparams.h"
namespace {
namespace
{
olive::TexturePtr CreateSolidTexture(const olive::VideoParams &params)
{
+61 -41
View File
@@ -27,22 +27,26 @@ extern "C" {
#include "render/texture.h"
#include "render/videoparams.h"
namespace olive {
namespace plugin {
namespace test {
namespace olive
{
namespace plugin
{
namespace test
{
namespace {
namespace
{
// Helper to create a test texture with solid color
// For U8: fill_value is 0-255
// For U16: fill_value is 0-65535
// For Float: fill_value is 0.0-1.0 mapped to bytes
template<typename T>
template <typename T>
TexturePtr CreateSolidTextureT(const VideoParams &params, T fill_value)
{
AVFramePtr frame = CreateAVFramePtr();
frame->format = FFmpegUtils::GetFFmpegPixelFormat(
params.format(), params.channel_count());
frame->format = FFmpegUtils::GetFFmpegPixelFormat(params.format(),
params.channel_count());
frame->width = params.width();
frame->height = params.height();
if (frame->format == AV_PIX_FMT_NONE) {
@@ -57,7 +61,7 @@ TexturePtr CreateSolidTextureT(const VideoParams &params, T fill_value)
const int linesize = frame->linesize[0];
for (int y = 0; y < frame->height; ++y) {
T *row = reinterpret_cast<T*>(frame->data[0] + y * linesize);
T *row = reinterpret_cast<T *>(frame->data[0] + y * linesize);
for (int x = 0; x < frame->width * params.channel_count(); ++x) {
row[x] = fill_value;
}
@@ -68,17 +72,21 @@ TexturePtr CreateSolidTextureT(const VideoParams &params, T fill_value)
return texture;
}
TexturePtr CreateSolidTexture(const VideoParams &params, uint32_t fill_value = 0x7f)
TexturePtr CreateSolidTexture(const VideoParams &params,
uint32_t fill_value = 0x7f)
{
// Choose type based on pixel format
switch (params.format()) {
case core::PixelFormat::U8:
return CreateSolidTextureT<uint8_t>(params, static_cast<uint8_t>(fill_value));
return CreateSolidTextureT<uint8_t>(params,
static_cast<uint8_t>(fill_value));
case core::PixelFormat::U16:
return CreateSolidTextureT<uint16_t>(params, static_cast<uint16_t>(fill_value));
return CreateSolidTextureT<uint16_t>(params,
static_cast<uint16_t>(fill_value));
case core::PixelFormat::F16:
case core::PixelFormat::F32:
return CreateSolidTextureT<float>(params, static_cast<float>(fill_value) / 255.0f);
return CreateSolidTextureT<float>(
params, static_cast<float>(fill_value) / 255.0f);
default:
return nullptr;
}
@@ -87,12 +95,12 @@ TexturePtr CreateSolidTexture(const VideoParams &params, uint32_t fill_value = 0
// Helper to create a gradient texture
// For U8: gradient is 0-255 per byte
// For Float: gradient is 0.0-1.0 per component
template<typename T>
template <typename T>
TexturePtr CreateGradientTextureT(const VideoParams &params, float scale)
{
AVFramePtr frame = CreateAVFramePtr();
frame->format = FFmpegUtils::GetFFmpegPixelFormat(
params.format(), params.channel_count());
frame->format = FFmpegUtils::GetFFmpegPixelFormat(params.format(),
params.channel_count());
frame->width = params.width();
frame->height = params.height();
if (frame->format == AV_PIX_FMT_NONE) {
@@ -107,7 +115,7 @@ TexturePtr CreateGradientTextureT(const VideoParams &params, float scale)
const int linesize = frame->linesize[0];
for (int y = 0; y < frame->height; ++y) {
T *row = reinterpret_cast<T*>(frame->data[0] + y * linesize);
T *row = reinterpret_cast<T *>(frame->data[0] + y * linesize);
T value = static_cast<T>((y * scale) / frame->height);
for (int x = 0; x < frame->width * params.channel_count(); ++x) {
row[x] = value;
@@ -135,14 +143,13 @@ TexturePtr CreateGradientTexture(const VideoParams &params)
}
// Helper function to find and render a plugin
bool RenderPlugin(const std::string &plugin_id,
const VideoParams &params,
const NodeValueRow &inputs,
bool verbose = false)
bool RenderPlugin(const std::string &plugin_id, const VideoParams &params,
const NodeValueRow &inputs, bool verbose = false)
{
auto *cache = OFX::Host::PluginCache::getPluginCache();
if (!cache) {
if (verbose) std::cerr << "Plugin cache not available" << std::endl;
if (verbose)
std::cerr << "Plugin cache not available" << std::endl;
return false;
}
@@ -155,13 +162,16 @@ bool RenderPlugin(const std::string &plugin_id,
}
if (!found) {
if (verbose) std::cerr << "Plugin not found: " << plugin_id << std::endl;
if (verbose)
std::cerr << "Plugin not found: " << plugin_id << std::endl;
return false;
}
auto *image_effect = dynamic_cast<OFX::Host::ImageEffect::ImageEffectPlugin *>(found);
auto *image_effect =
dynamic_cast<OFX::Host::ImageEffect::ImageEffectPlugin *>(found);
if (!image_effect) {
if (verbose) std::cerr << "Not an image effect plugin" << std::endl;
if (verbose)
std::cerr << "Not an image effect plugin" << std::endl;
return false;
}
@@ -175,13 +185,15 @@ bool RenderPlugin(const std::string &plugin_id,
OFX::Host::ImageEffect::Instance *instance =
image_effect->createInstance(context, nullptr);
if (!instance) {
if (verbose) std::cerr << "Failed to create instance" << std::endl;
if (verbose)
std::cerr << "Failed to create instance" << std::endl;
return false;
}
auto *olive_instance = dynamic_cast<OlivePluginInstance *>(instance);
if (!olive_instance) {
if (verbose) std::cerr << "Not an OlivePluginInstance" << std::endl;
if (verbose)
std::cerr << "Not an OlivePluginInstance" << std::endl;
return false;
}
@@ -202,7 +214,8 @@ bool RenderPlugin(const std::string &plugin_id,
}
// Skip check function
bool ShouldSkipTest() {
bool ShouldSkipTest()
{
const char *itest = std::getenv("OAK_OFX_ITEST");
if (!itest || std::string(itest) != "1") {
return true;
@@ -270,7 +283,8 @@ TEST(PluginMisc, TransformTranslate)
row.insert(QString::fromStdString(kOfxImageEffectSimpleSourceClipName),
NodeValue(NodeValue::kTexture, input));
bool result = RenderPlugin("net.sf.openfx.TransformPlugin", params, row, true);
bool result =
RenderPlugin("net.sf.openfx.TransformPlugin", params, row, true);
EXPECT_TRUE(result) << "Transform plugin should produce output";
}
@@ -292,7 +306,8 @@ TEST(PluginMisc, ColorCorrect)
row.insert(QString::fromStdString(kOfxImageEffectSimpleSourceClipName),
NodeValue(NodeValue::kTexture, input));
bool result = RenderPlugin("net.sf.openfx.ColorCorrectPlugin", params, row, true);
bool result =
RenderPlugin("net.sf.openfx.ColorCorrectPlugin", params, row, true);
EXPECT_TRUE(result) << "ColorCorrect plugin should produce output";
}
@@ -310,7 +325,8 @@ TEST(PluginMisc, Saturation)
row.insert(QString::fromStdString(kOfxImageEffectSimpleSourceClipName),
NodeValue(NodeValue::kTexture, input));
bool result = RenderPlugin("net.sf.openfx.SaturationPlugin", params, row, true);
bool result =
RenderPlugin("net.sf.openfx.SaturationPlugin", params, row, true);
EXPECT_TRUE(result) << "Saturation plugin should produce output";
}
@@ -395,7 +411,8 @@ TEST(PluginMisc, NonExistentPlugin)
row.insert(QString::fromStdString(kOfxImageEffectSimpleSourceClipName),
NodeValue(NodeValue::kTexture, input));
bool result = RenderPlugin("net.sf.openfx.NonExistentPlugin", params, row, true);
bool result =
RenderPlugin("net.sf.openfx.NonExistentPlugin", params, row, true);
EXPECT_FALSE(result) << "Non-existent plugin should fail gracefully";
}
@@ -474,8 +491,7 @@ TEST(PluginMisc, MergeOver)
NodeValueRow row;
row.insert(QString::fromStdString(kOfxImageEffectSimpleSourceClipName),
NodeValue(NodeValue::kTexture, input));
row.insert(QStringLiteral("Bg"),
NodeValue(NodeValue::kTexture, input));
row.insert(QStringLiteral("Bg"), NodeValue(NodeValue::kTexture, input));
bool result = RenderPlugin("net.sf.openfx.MergePlugin", params, row, true);
EXPECT_TRUE(result) << "Merge plugin should produce output";
@@ -521,7 +537,8 @@ TEST(PluginMisc, CornerPin)
row.insert(QString::fromStdString(kOfxImageEffectSimpleSourceClipName),
NodeValue(NodeValue::kTexture, input));
bool result = RenderPlugin("net.sf.openfx.CornerPinPlugin", params, row, true);
bool result =
RenderPlugin("net.sf.openfx.CornerPinPlugin", params, row, true);
EXPECT_TRUE(result) << "CornerPin plugin should produce output";
}
@@ -539,7 +556,8 @@ TEST(PluginMisc, LensDistortion)
row.insert(QString::fromStdString(kOfxImageEffectSimpleSourceClipName),
NodeValue(NodeValue::kTexture, input));
bool result = RenderPlugin("net.sf.openfx.LensDistortion", params, row, true);
bool result =
RenderPlugin("net.sf.openfx.LensDistortion", params, row, true);
EXPECT_TRUE(result) << "LensDistortion plugin should produce output";
}
@@ -611,23 +629,25 @@ TEST(PluginMisc, ListAvailablePlugins)
TEST(PluginMisc, CImgBilateralGuided_MultiInput)
{
if (ShouldSkipTest()) GTEST_SKIP() << "OFX integration test not enabled";
if (ShouldSkipTest())
GTEST_SKIP() << "OFX integration test not enabled";
// CImgBilateralGuided is a multi-input plugin (Source + Guide).
// This test verifies that connecting both inputs does not trigger
// the frame-rate mismatch exception in setupClipPreferencesArgs.
VideoParams params(320, 240, core::PixelFormat::F32, 4);
TexturePtr source = CreateSolidTexture(params, 0x80);
TexturePtr guide = CreateSolidTexture(params, 0x40);
TexturePtr guide = CreateSolidTexture(params, 0x40);
ASSERT_NE(source, nullptr);
ASSERT_NE(guide, nullptr);
NodeValueRow row;
row.insert(QString::fromStdString(kOfxImageEffectSimpleSourceClipName),
NodeValue(NodeValue::kTexture, source));
row.insert(QStringLiteral("Guide"),
NodeValue(NodeValue::kTexture, guide));
bool result = RenderPlugin("net.sf.cimg.CImgBilateralGuided", params, row, true);
EXPECT_TRUE(result) << "CImgBilateralGuided plugin should produce output with both Source and Guide connected";
row.insert(QStringLiteral("Guide"), NodeValue(NodeValue::kTexture, guide));
bool result =
RenderPlugin("net.sf.cimg.CImgBilateralGuided", params, row, true);
EXPECT_TRUE(result)
<< "CImgBilateralGuided plugin should produce output with both Source and Guide connected";
}
} // namespace test
+2 -1
View File
@@ -6,7 +6,8 @@
#include "render/texture.h"
#include "render/videoparams.h"
namespace {
namespace
{
class PluginJobTraverser : public olive::NodeTraverser {
public:
@@ -8,9 +8,8 @@ TEST(PluginRendererReadback, BytesToPixels)
olive::core::rational(1, 1),
olive::VideoParams::kInterlaceNone, 1);
const int bytes_per_pixel =
olive::VideoParams::GetBytesPerPixel(params.format(),
params.channel_count());
const int bytes_per_pixel = olive::VideoParams::GetBytesPerPixel(
params.format(), params.channel_count());
ASSERT_EQ(bytes_per_pixel, 4);
EXPECT_EQ(olive::plugin::detail::BytesToPixels(64, params), 16);
File diff suppressed because it is too large Load Diff
+5 -7
View File
@@ -4,10 +4,10 @@
#include "ofxhClip.h"
#include "pluginSupport/OliveClip.h"
namespace {
namespace
{
olive::VideoParams MakeParams(int width, int height,
olive::core::PixelFormat format,
int channels,
olive::core::PixelFormat format, int channels,
bool premultiplied)
{
olive::VideoParams params;
@@ -64,16 +64,14 @@ TEST(PluginSupportClip, GetImageClampsBoundsAndCachesOutput)
olive::plugin::OliveClipInstance clip(nullptr, desc, params);
OfxRectD optional_bounds = { -10.0, -10.0, 200.0, 200.0 };
OFX::Host::ImageEffect::Image *image =
clip.getImage(0.0, &optional_bounds);
OFX::Host::ImageEffect::Image *image = clip.getImage(0.0, &optional_bounds);
ASSERT_NE(image, nullptr);
auto *olive_image = static_cast<olive::plugin::Image *>(image);
EXPECT_EQ(olive_image->width(), 100);
EXPECT_EQ(olive_image->height(), 80);
OFX::Host::ImageEffect::Image *image_again =
clip.getImage(0.0, nullptr);
OFX::Host::ImageEffect::Image *image_again = clip.getImage(0.0, nullptr);
EXPECT_EQ(image, image_again);
}
+5 -5
View File
@@ -5,10 +5,10 @@
#include "pluginSupport/OliveClip.h"
#include "pluginSupport/image.h"
namespace {
namespace
{
olive::VideoParams MakeParams(int width, int height,
olive::core::PixelFormat format,
int channels,
olive::core::PixelFormat format, int channels,
bool premultiplied)
{
olive::VideoParams params;
@@ -106,14 +106,14 @@ TEST(PluginSupportImage, AllocateSetsOfxProperties)
EXPECT_NE(image.data(), nullptr);
EXPECT_EQ(image.row_bytes(), 8 * 4 * 2);
int bounds_props[4] = {0};
int bounds_props[4] = { 0 };
image.getIntPropertyN(kOfxImagePropBounds, bounds_props, 4);
EXPECT_EQ(bounds_props[0], bounds.x1);
EXPECT_EQ(bounds_props[1], bounds.y1);
EXPECT_EQ(bounds_props[2], bounds.x2);
EXPECT_EQ(bounds_props[3], bounds.y2);
int rod_props[4] = {0};
int rod_props[4] = { 0 };
image.getIntPropertyN(kOfxImagePropRegionOfDefinition, rod_props, 4);
EXPECT_EQ(rod_props[0], rod.x1);
EXPECT_EQ(rod_props[1], rod.y1);
+1 -3
View File
@@ -4,7 +4,5 @@
TEST(PluginSupport, LoadPluginsEmptyPath)
{
EXPECT_NO_THROW({
olive::plugin::loadPlugins(QString());
});
EXPECT_NO_THROW({ olive::plugin::loadPlugins(QString()); });
}
+10 -10
View File
@@ -45,16 +45,16 @@ TEST(PreferencesBehaviorTab, BehaviorPrefTrProvidesTranslations)
{
QStringList keys;
keys << QStringLiteral("Enable hover focus")
<< QStringLiteral("Select also selects all children in the graph")
<< QStringLiteral("Double-clicking a node opens its properties")
<< QStringLiteral("Auto-Seek to Beginning of Sequence")
<< QStringLiteral("Scroll wheel zooms instead of scrolling")
<< QStringLiteral("Enable audio scrubbing");
<< QStringLiteral("Select also selects all children in the graph")
<< QStringLiteral("Double-clicking a node opens its properties")
<< QStringLiteral("Auto-Seek to Beginning of Sequence")
<< QStringLiteral("Scroll wheel zooms instead of scrolling")
<< QStringLiteral("Enable audio scrubbing");
foreach (const QString &key, keys) {
EXPECT_FALSE(
PreferencesBehaviorTab::BehaviorPrefTr(
key.toUtf8().constData()).isEmpty())
PreferencesBehaviorTab::BehaviorPrefTr(key.toUtf8().constData())
.isEmpty())
<< key.toStdString();
}
}
@@ -76,8 +76,8 @@ TEST(PreferencesGeneralTab, ContainsHoverFocusOption)
bool found = false;
foreach (QCheckBox *box, boxes) {
if (box->text() == PreferencesBehaviorTab::BehaviorPrefTr(
"Enable hover focus")) {
if (box->text() ==
PreferencesBehaviorTab::BehaviorPrefTr("Enable hover focus")) {
found = true;
break;
}
@@ -96,7 +96,7 @@ TEST(PreferencesAudioTab, AudioScrubbingCheckboxUsesBehaviorTranslation)
bool found = false;
foreach (QCheckBox *box, boxes) {
if (box->text() == PreferencesBehaviorTab::BehaviorPrefTr(
"Enable audio scrubbing")) {
"Enable audio scrubbing")) {
found = true;
break;
}
+2 -1
View File
@@ -79,7 +79,8 @@ TEST_F(PreviewAutoCacherTest, ClearSingleFrameRendersDoesNotCrashWhenEmpty)
cacher.ClearSingleFrameRenders();
}
TEST_F(PreviewAutoCacherTest, ClearSingleFrameRendersThatArentRunningDoesNotCrashWhenEmpty)
TEST_F(PreviewAutoCacherTest,
ClearSingleFrameRendersThatArentRunningDoesNotCrashWhenEmpty)
{
PreviewAutoCacher cacher;
cacher.ClearSingleFrameRendersThatArentRunning();
+7 -6
View File
@@ -13,7 +13,8 @@
TEST(ProjectSerializer, SaveLoadProjectRoundTrip)
{
const bool created_disk_manager = (olive::DiskManager::instance() == nullptr);
const bool created_disk_manager =
(olive::DiskManager::instance() == nullptr);
if (created_disk_manager) {
olive::DiskManager::CreateInstance();
}
@@ -45,15 +46,15 @@ TEST(ProjectSerializer, SaveLoadProjectRoundTrip)
QBuffer read_buffer(&xml);
read_buffer.open(QIODevice::ReadOnly);
QXmlStreamReader reader(&read_buffer);
olive::ProjectSerializer::Result result =
olive::ProjectSerializer::Load(&loaded_project, &reader,
olive::ProjectSerializer::kProject);
olive::ProjectSerializer::Result result = olive::ProjectSerializer::Load(
&loaded_project, &reader, olive::ProjectSerializer::kProject);
EXPECT_EQ(result.code(), olive::ProjectSerializer::kSuccess);
EXPECT_FALSE(loaded_project.nodes().isEmpty());
ASSERT_TRUE(result.GetLoadData().node_ptrs.contains(
reinterpret_cast<quintptr>(node)));
EXPECT_TRUE(loaded_project.nodes().contains(
result.GetLoadData().node_ptrs.value(reinterpret_cast<quintptr>(node))));
EXPECT_TRUE(
loaded_project.nodes().contains(result.GetLoadData().node_ptrs.value(
reinterpret_cast<quintptr>(node))));
olive::ProjectSerializer::Destroy();
if (created_disk_manager) {
+31 -33
View File
@@ -18,14 +18,14 @@ TEST(ProxyManager, BuildsStableProxyFilename)
params.version = 1;
const QString first = olive::ProxyManager::GetProxyFilename(
QStringLiteral("/tmp/oak-cache"),
QStringLiteral("/media/source.mov"), 0, params);
QStringLiteral("/tmp/oak-cache"), QStringLiteral("/media/source.mov"),
0, params);
const QString second = olive::ProxyManager::GetProxyFilename(
QStringLiteral("/tmp/oak-cache"),
QStringLiteral("/media/source.mov"), 0, params);
QStringLiteral("/tmp/oak-cache"), QStringLiteral("/media/source.mov"),
0, params);
const QString other_stream = olive::ProxyManager::GetProxyFilename(
QStringLiteral("/tmp/oak-cache"),
QStringLiteral("/media/source.mov"), 1, params);
QStringLiteral("/tmp/oak-cache"), QStringLiteral("/media/source.mov"),
1, params);
EXPECT_EQ(first, second);
EXPECT_NE(first, other_stream);
@@ -48,11 +48,11 @@ TEST(ProxyManager, ProxyFilenameIncludesPresetParameters)
mov_540p.extension = QStringLiteral("mov");
const QString first = olive::ProxyManager::GetProxyFilename(
QStringLiteral("/tmp/oak-cache"),
QStringLiteral("/media/source.mov"), 0, mp4_720p);
QStringLiteral("/tmp/oak-cache"), QStringLiteral("/media/source.mov"),
0, mp4_720p);
const QString second = olive::ProxyManager::GetProxyFilename(
QStringLiteral("/tmp/oak-cache"),
QStringLiteral("/media/source.mov"), 0, mov_540p);
QStringLiteral("/tmp/oak-cache"), QStringLiteral("/media/source.mov"),
0, mov_540p);
EXPECT_NE(first, second);
EXPECT_TRUE(first.contains(QStringLiteral(".1280x720.v1.")));
@@ -117,21 +117,21 @@ TEST(ProxyManager, ConvertsProxyStateToAndFromStrings)
olive::ProxyManager::kProxyFailed),
QStringLiteral("failed"));
EXPECT_EQ(olive::ProxyManager::ProxyStateFromString(
QStringLiteral("missing")),
olive::ProxyManager::kProxyMissing);
EXPECT_EQ(olive::ProxyManager::ProxyStateFromString(
QStringLiteral("generating")),
olive::ProxyManager::kProxyGenerating);
EXPECT_EQ(olive::ProxyManager::ProxyStateFromString(
QStringLiteral("ready")),
olive::ProxyManager::kProxyReady);
EXPECT_EQ(olive::ProxyManager::ProxyStateFromString(
QStringLiteral("failed")),
olive::ProxyManager::kProxyFailed);
EXPECT_EQ(olive::ProxyManager::ProxyStateFromString(
QStringLiteral("unknown")),
olive::ProxyManager::kProxyMissing);
EXPECT_EQ(
olive::ProxyManager::ProxyStateFromString(QStringLiteral("missing")),
olive::ProxyManager::kProxyMissing);
EXPECT_EQ(
olive::ProxyManager::ProxyStateFromString(QStringLiteral("generating")),
olive::ProxyManager::kProxyGenerating);
EXPECT_EQ(
olive::ProxyManager::ProxyStateFromString(QStringLiteral("ready")),
olive::ProxyManager::kProxyReady);
EXPECT_EQ(
olive::ProxyManager::ProxyStateFromString(QStringLiteral("failed")),
olive::ProxyManager::kProxyFailed);
EXPECT_EQ(
olive::ProxyManager::ProxyStateFromString(QStringLiteral("unknown")),
olive::ProxyManager::kProxyMissing);
}
TEST(ProxyManager, FootagePersistsProxyMetadata)
@@ -225,10 +225,10 @@ TEST(ProxyManager, EmitsProxyFinishedState)
received_state = state;
});
emit olive::ProxyManager::instance()->ProxyFinished(
QStringLiteral("/media/source.mov"), 0,
QStringLiteral("/cache/proxy/example.mp4"),
olive::ProxyManager::kProxyFailed);
emit olive::ProxyManager::instance()
-> ProxyFinished(QStringLiteral("/media/source.mov"), 0,
QStringLiteral("/cache/proxy/example.mp4"),
olive::ProxyManager::kProxyFailed);
EXPECT_TRUE(received);
EXPECT_EQ(received_source, QStringLiteral("/media/source.mov"));
@@ -241,10 +241,8 @@ TEST(ProxyManager, EmitsProxyFinishedState)
TEST(ProxyManager, WorkingProxyFilenamePrependsExtension)
{
const QString proxy =
QStringLiteral("/cache/proxy/example.mp4");
const QString working =
olive::ProxyManager::GetWorkingProxyFilename(proxy);
const QString proxy = QStringLiteral("/cache/proxy/example.mp4");
const QString working = olive::ProxyManager::GetWorkingProxyFilename(proxy);
EXPECT_EQ(working, QStringLiteral("/cache/proxy/example.mp4.working.mp4"));
}
+20 -20
View File
@@ -7,12 +7,12 @@ TEST(RenderAudioParams, ValidityAndEquality)
olive::core::AudioParams invalid;
EXPECT_FALSE(invalid.is_valid());
olive::core::AudioParams params(
48000, AV_CH_LAYOUT_STEREO, olive::core::SampleFormat::S16);
olive::core::AudioParams params(48000, AV_CH_LAYOUT_STEREO,
olive::core::SampleFormat::S16);
EXPECT_TRUE(params.is_valid());
olive::core::AudioParams other(
48000, AV_CH_LAYOUT_STEREO, olive::core::SampleFormat::S16);
olive::core::AudioParams other(48000, AV_CH_LAYOUT_STEREO,
olive::core::SampleFormat::S16);
EXPECT_TRUE(params == other);
other.set_sample_rate(44100);
@@ -21,8 +21,8 @@ TEST(RenderAudioParams, ValidityAndEquality)
TEST(RenderAudioParams, TimeAndSampleConversions)
{
olive::core::AudioParams params(
48000, AV_CH_LAYOUT_STEREO, olive::core::SampleFormat::S16);
olive::core::AudioParams params(48000, AV_CH_LAYOUT_STEREO,
olive::core::SampleFormat::S16);
EXPECT_EQ(params.channel_count(), 2);
EXPECT_EQ(params.bytes_per_sample_per_channel(), 2);
@@ -43,34 +43,34 @@ TEST(RenderAudioParams, TimeAndSampleConversions)
TEST(RenderAudioParams, ChannelLayoutCount)
{
olive::core::AudioParams mono(
48000, AV_CH_LAYOUT_MONO, olive::core::SampleFormat::F32);
olive::core::AudioParams mono(48000, AV_CH_LAYOUT_MONO,
olive::core::SampleFormat::F32);
EXPECT_EQ(mono.channel_count(), 1);
olive::core::AudioParams surround(
48000, AV_CH_LAYOUT_5POINT1, olive::core::SampleFormat::F32);
olive::core::AudioParams surround(48000, AV_CH_LAYOUT_5POINT1,
olive::core::SampleFormat::F32);
EXPECT_EQ(surround.channel_count(), 6);
}
TEST(RenderAudioParams, SampleFormatSizes)
{
olive::core::AudioParams u8(
48000, AV_CH_LAYOUT_MONO, olive::core::SampleFormat::U8);
olive::core::AudioParams u8(48000, AV_CH_LAYOUT_MONO,
olive::core::SampleFormat::U8);
EXPECT_EQ(u8.bytes_per_sample_per_channel(), 1);
olive::core::AudioParams f32(
48000, AV_CH_LAYOUT_MONO, olive::core::SampleFormat::F32);
olive::core::AudioParams f32(48000, AV_CH_LAYOUT_MONO,
olive::core::SampleFormat::F32);
EXPECT_EQ(f32.bytes_per_sample_per_channel(), 4);
olive::core::AudioParams f64(
48000, AV_CH_LAYOUT_MONO, olive::core::SampleFormat::F64);
olive::core::AudioParams f64(48000, AV_CH_LAYOUT_MONO,
olive::core::SampleFormat::F64);
EXPECT_EQ(f64.bytes_per_sample_per_channel(), 8);
}
TEST(RenderAudioParams, CopyAndAssignment)
{
olive::core::AudioParams params(
96000, AV_CH_LAYOUT_STEREO, olive::core::SampleFormat::F32);
olive::core::AudioParams params(96000, AV_CH_LAYOUT_STEREO,
olive::core::SampleFormat::F32);
olive::core::AudioParams copy(params);
EXPECT_EQ(copy.sample_rate(), 96000);
@@ -85,8 +85,8 @@ TEST(RenderAudioParams, CopyAndAssignment)
TEST(RenderAudioParams, SettersModifyState)
{
olive::core::AudioParams params(
44100, AV_CH_LAYOUT_MONO, olive::core::SampleFormat::S16);
olive::core::AudioParams params(44100, AV_CH_LAYOUT_MONO,
olive::core::SampleFormat::S16);
EXPECT_TRUE(params.is_valid());
params.set_sample_rate(48000);
+22 -17
View File
@@ -40,13 +40,13 @@ TEST(SpscRingBuffer, BasicPushPopAndCapacity)
EXPECT_TRUE(ring->IsEmptyApprox());
uint32_t v = 0;
EXPECT_FALSE(ring->Pop(&v)); // empty
EXPECT_FALSE(ring->Pop(&v)); // empty
// Capacity 4 holds at most 3 entries (one slot reserved to disambiguate full/empty).
EXPECT_TRUE(ring->Push(10));
EXPECT_TRUE(ring->Push(20));
EXPECT_TRUE(ring->Push(30));
EXPECT_FALSE(ring->Push(40)); // full
EXPECT_FALSE(ring->Push(40)); // full
EXPECT_TRUE(ring->Pop(&v));
EXPECT_EQ(v, 10u);
@@ -54,7 +54,7 @@ TEST(SpscRingBuffer, BasicPushPopAndCapacity)
EXPECT_EQ(v, 20u);
EXPECT_TRUE(ring->Pop(&v));
EXPECT_EQ(v, 30u);
EXPECT_FALSE(ring->Pop(&v)); // empty again
EXPECT_FALSE(ring->Pop(&v)); // empty again
}
TEST(SpscRingBuffer, WrapAround)
@@ -75,17 +75,18 @@ TEST(SpscRingBuffer, WrapAround)
TEST(SpscRingBuffer, ConcurrentProducerConsumer)
{
constexpr uint32_t kCapacity = 1024;
constexpr uint32_t kCount = 2'000'000; // values 0..kCount-1 streamed through the ring
constexpr uint32_t kCount =
2'000'000; // values 0..kCount-1 streamed through the ring
std::vector<uint8_t> mem(SpscRingBuffer::BytesNeeded(kCapacity));
SpscRingBuffer *ring = SpscRingBuffer::Create(mem.data(), kCapacity);
std::atomic<bool> order_ok{true};
std::atomic<bool> order_ok{ true };
std::thread producer([&] {
for (uint32_t i = 0; i < kCount; i++) {
while (!ring->Push(i)) {
std::this_thread::yield(); // buffer full, spin until consumer drains
std::this_thread::yield(); // buffer full, spin until consumer drains
}
}
});
@@ -124,7 +125,8 @@ TEST(FrameSlotPool, SingleThreadedHandoff)
constexpr size_t kSlotBytes = 256;
std::vector<uint8_t> mem(FrameSlotPool::BytesNeeded(kSlots, kSlotBytes));
FrameSlotPool filler = FrameSlotPool::Create(mem.data(), kSlots, kSlotBytes);
FrameSlotPool filler =
FrameSlotPool::Create(mem.data(), kSlots, kSlotBytes);
FrameSlotPool drainer = FrameSlotPool::Attach(mem.data());
ASSERT_TRUE(filler.IsValid());
@@ -156,7 +158,8 @@ TEST(FrameSlotPool, SingleThreadedHandoff)
EXPECT_EQ(got_meta->id, 4242);
EXPECT_EQ(got_meta->width, 16);
const auto *got_data = static_cast<const uint8_t *>(drainer.SlotData(got_idx));
const auto *got_data =
static_cast<const uint8_t *>(drainer.SlotData(got_idx));
for (size_t i = 0; i < kSlotBytes; i++) {
ASSERT_EQ(got_data[i], uint8_t(i & 0xFF));
}
@@ -180,7 +183,7 @@ TEST(FrameSlotPool, ExhaustionAndRefill)
held.push_back(a);
}
uint32_t overflow = 0;
EXPECT_FALSE(pool.Acquire(&overflow)); // pool exhausted
EXPECT_FALSE(pool.Acquire(&overflow)); // pool exhausted
// Publishing then consuming + releasing returns the slots to the free pool.
for (uint32_t idx : held) {
@@ -192,7 +195,7 @@ TEST(FrameSlotPool, ExhaustionAndRefill)
ASSERT_TRUE(pool.Release(c));
}
uint32_t again = 0;
EXPECT_TRUE(pool.Acquire(&again)); // free again
EXPECT_TRUE(pool.Acquire(&again)); // free again
}
TEST(FrameSlotPool, ConcurrentFillDrainIntegrity)
@@ -202,10 +205,11 @@ TEST(FrameSlotPool, ConcurrentFillDrainIntegrity)
constexpr int64_t kFrames = 200'000;
std::vector<uint8_t> mem(FrameSlotPool::BytesNeeded(kSlots, kSlotBytes));
FrameSlotPool filler = FrameSlotPool::Create(mem.data(), kSlots, kSlotBytes);
FrameSlotPool filler =
FrameSlotPool::Create(mem.data(), kSlots, kSlotBytes);
FrameSlotPool drainer = FrameSlotPool::Attach(mem.data());
std::atomic<bool> integrity_ok{true};
std::atomic<bool> integrity_ok{ true };
// Filler: for each frame id, acquire a slot, stamp the id into meta and a pattern into the data,
// publish. Spins when no slot is free (this is the natural backpressure path).
@@ -220,7 +224,7 @@ TEST(FrameSlotPool, ConcurrentFillDrainIntegrity)
const uint8_t pat = uint8_t(id & 0xFF);
memset(d, pat, kSlotBytes);
while (!filler.Publish(idx)) {
std::this_thread::yield(); // ready ring transiently full
std::this_thread::yield(); // ready ring transiently full
}
}
});
@@ -292,7 +296,7 @@ TEST(IpcMessage, TypedRoundTrip)
rf.channel_count = 4;
rf.mode = 1;
rf.input_slot = 2;
rf.input_slots = {2, 3};
rf.input_slots = { 2, 3 };
ASSERT_TRUE(WriteMessage(&dev, rf.ToJson()));
FrameReadyMsg fr;
@@ -349,7 +353,8 @@ TEST(IpcMessage, PartialFrameByteByByte)
CancelMsg c;
c.ticket_id = 7;
const QByteArray full =
QByteArray(QJsonDocument(c.ToJson()).toJson(QJsonDocument::Compact)) + '\n';
QByteArray(QJsonDocument(c.ToJson()).toJson(QJsonDocument::Compact)) +
'\n';
// Feed the bytes one at a time; ReadMessage must return false until the terminating '\n'.
QByteArray reader;
@@ -357,9 +362,9 @@ TEST(IpcMessage, PartialFrameByteByByte)
bool ok = false;
for (int i = 0; i < full.size() - 1; i++) {
reader.append(full.at(i));
ASSERT_FALSE(ReadMessage(&reader, &obj, &ok)); // no complete line yet
ASSERT_FALSE(ReadMessage(&reader, &obj, &ok)); // no complete line yet
}
reader.append(full.at(full.size() - 1)); // the trailing newline
reader.append(full.at(full.size() - 1)); // the trailing newline
ASSERT_TRUE(ReadMessage(&reader, &obj, &ok));
ASSERT_TRUE(ok);
+21 -24
View File
@@ -15,29 +15,27 @@ TEST(RenderVideoParams, BytesPerChannelAndPixel)
EXPECT_EQ(olive::VideoParams::GetBytesPerChannel(
olive::core::PixelFormat::INVALID),
0);
EXPECT_EQ(olive::VideoParams::GetBytesPerChannel(
olive::core::PixelFormat::U8),
1);
EXPECT_EQ(olive::VideoParams::GetBytesPerChannel(
olive::core::PixelFormat::U16),
2);
EXPECT_EQ(olive::VideoParams::GetBytesPerChannel(
olive::core::PixelFormat::F16),
2);
EXPECT_EQ(olive::VideoParams::GetBytesPerChannel(
olive::core::PixelFormat::F32),
4);
EXPECT_EQ(olive::VideoParams::GetBytesPerPixel(
olive::core::PixelFormat::U8, 4),
EXPECT_EQ(
olive::VideoParams::GetBytesPerChannel(olive::core::PixelFormat::U8),
1);
EXPECT_EQ(
olive::VideoParams::GetBytesPerChannel(olive::core::PixelFormat::U16),
2);
EXPECT_EQ(
olive::VideoParams::GetBytesPerChannel(olive::core::PixelFormat::F16),
2);
EXPECT_EQ(
olive::VideoParams::GetBytesPerChannel(olive::core::PixelFormat::F32),
4);
EXPECT_EQ(olive::VideoParams::GetBytesPerPixel(olive::core::PixelFormat::U8,
4),
4);
}
TEST(RenderVideoParams, DividerAndFormatNames)
{
EXPECT_EQ(olive::VideoParams::GetNameForDivider(1),
QStringLiteral("Full"));
EXPECT_EQ(olive::VideoParams::GetNameForDivider(3),
QStringLiteral("1/3"));
EXPECT_EQ(olive::VideoParams::GetNameForDivider(1), QStringLiteral("Full"));
EXPECT_EQ(olive::VideoParams::GetNameForDivider(3), QStringLiteral("1/3"));
const QString unknown =
olive::VideoParams::GetFormatName(olive::core::PixelFormat::INVALID);
@@ -47,11 +45,11 @@ TEST(RenderVideoParams, DividerAndFormatNames)
TEST(RenderVideoParams, ScalingAndDividerForTarget)
{
EXPECT_EQ(olive::VideoParams::GetScaledDimension(100, 3), 33);
EXPECT_EQ(olive::VideoParams::GetDividerForTargetResolution(
1920, 1080, 960, 540),
EXPECT_EQ(olive::VideoParams::GetDividerForTargetResolution(1920, 1080, 960,
540),
2);
EXPECT_EQ(olive::VideoParams::GetDividerForTargetResolution(
1920, 1080, 480, 270),
EXPECT_EQ(olive::VideoParams::GetDividerForTargetResolution(1920, 1080, 480,
270),
4);
}
@@ -191,8 +189,7 @@ TEST(RenderVideoParams, SaveLoadRoundTripExtended)
EXPECT_FLOAT_EQ(loaded.x(), 1.5f);
EXPECT_FLOAT_EQ(loaded.y(), -2.25f);
EXPECT_EQ(loaded.stream_index(), 7);
EXPECT_EQ(loaded.video_type(),
olive::VideoParams::kVideoTypeImageSequence);
EXPECT_EQ(loaded.video_type(), olive::VideoParams::kVideoTypeImageSequence);
EXPECT_EQ(loaded.frame_rate(), olive::core::rational(30000, 1001));
EXPECT_EQ(loaded.start_time(), 123);
EXPECT_EQ(loaded.duration(), 456);
+52 -39
View File
@@ -49,7 +49,8 @@
using namespace olive;
using namespace olive::core;
namespace {
namespace
{
#ifdef OAK_ENABLE_DYNAMIC_RENDER_BACKEND
bool IsRenderBackendAvailable(const QString &backend)
@@ -96,8 +97,8 @@ QString WorkerBinaryPath()
// The test binary lives in cmake-build-debug/tests/gtest; the worker is in
// cmake-build-debug/app.
QDir dir(QCoreApplication::applicationDirPath());
dir.cdUp(); // tests/gtest -> tests
dir.cdUp(); // tests -> build dir
dir.cdUp(); // tests/gtest -> tests
dir.cdUp(); // tests -> build dir
dir.cd(QStringLiteral("app"));
#if defined(_WIN32)
return dir.filePath(QStringLiteral("oak-render-worker.exe"));
@@ -140,8 +141,10 @@ void SaveFrameAsPng(const void *data, int width, int height,
for (int x = 0; x < width; ++x) {
for (int c = 0; c < 4; ++c) {
float v = src[(y * width + x) * 4 + c];
if (v < 0.0f) v = 0.0f;
if (v > 1.0f) v = 1.0f;
if (v < 0.0f)
v = 0.0f;
if (v > 1.0f)
v = 1.0f;
dst[(x * 4) + c] = static_cast<uchar>(v * 255.0f);
}
}
@@ -153,7 +156,7 @@ void SaveFrameAsPng(const void *data, int width, int height,
}
}
} // namespace
} // namespace
class RenderWorkerFootageTest : public ::testing::Test {
protected:
@@ -210,8 +213,8 @@ protected:
temp_dir_.filePath(QStringLiteral("worker_graph.ove")));
ProjectSerializer::Result r = ProjectSerializer::Save(
ProjectSerializer::SaveData(ProjectSerializer::kProject, project_.get(),
project_file_),
ProjectSerializer::SaveData(ProjectSerializer::kProject,
project_.get(), project_file_),
false);
ASSERT_EQ(r.code(), ProjectSerializer::kSuccess)
<< "Failed to save project file: " << r.GetDetails().toStdString();
@@ -222,7 +225,8 @@ protected:
{
// ---- decode a frame so we know the dimensions and slot sizes ----
DecoderPtr decoder = Decoder::CreateFromID(QStringLiteral("ffmpeg"));
if (!decoder || !decoder->Open(Decoder::CodecStream(demo_path_, 0, nullptr))) {
if (!decoder ||
!decoder->Open(Decoder::CodecStream(demo_path_, 0, nullptr))) {
return false;
}
Decoder::RetrieveVideoParams retrieve;
@@ -251,10 +255,10 @@ protected:
output_shm_key_ = ipc::SharedMemoryRegion::MakeKey(owner_pid, 0);
input_shm_key_ = ipc::SharedMemoryRegion::MakeKey(owner_pid, 1);
const size_t output_bytes = ipc::FrameSlotPool::BytesNeeded(
kOutputSlots, output_data_bytes_);
const size_t input_bytes = ipc::FrameSlotPool::BytesNeeded(
kInputSlots, input_data_bytes_);
const size_t output_bytes =
ipc::FrameSlotPool::BytesNeeded(kOutputSlots, output_data_bytes_);
const size_t input_bytes =
ipc::FrameSlotPool::BytesNeeded(kInputSlots, input_data_bytes_);
if (!output_region_.Open(output_shm_key_, output_bytes,
ipc::SharedMemoryRegion::kCreate)) {
@@ -278,7 +282,8 @@ protected:
// ---- spawn worker ----
worker_.setProcessChannelMode(QProcess::SeparateChannels);
worker_.start(worker_path_, QStringList{QStringLiteral("--backend"), backend});
worker_.start(worker_path_,
QStringList{ QStringLiteral("--backend"), backend });
if (!worker_.waitForStarted(kTimeoutMs)) {
return false;
}
@@ -333,8 +338,8 @@ protected:
if (!input_pool_->Acquire(&input_slot)) {
return false;
}
std::memcpy(input_pool_->SlotData(input_slot), decoded_frame_->const_data(),
input_data_bytes_);
std::memcpy(input_pool_->SlotData(input_slot),
decoded_frame_->const_data(), input_data_bytes_);
ipc::FrameSlotMeta *meta = input_pool_->Meta(input_slot);
meta->id = 0;
meta->time_num = 0;
@@ -345,9 +350,10 @@ protected:
meta->channel_count = decoded_frame_->channel_count();
meta->linesize = input_stride_;
meta->data_size = int32_t(input_data_bytes_);
std::strncpy(meta->colorspace,
decoded_frame_->video_params().colorspace().toUtf8().constData(),
sizeof(meta->colorspace) - 1);
std::strncpy(
meta->colorspace,
decoded_frame_->video_params().colorspace().toUtf8().constData(),
sizeof(meta->colorspace) - 1);
meta->colorspace[sizeof(meta->colorspace) - 1] = '\0';
input_pool_->Publish(input_slot);
@@ -363,7 +369,8 @@ protected:
req.mode = int(RenderMode::kOnline);
req.input_slot = 0;
if (!ipc::WriteMessage(&worker_, req.ToJson())) {
std::cerr << "RenderFrameAndWait: failed to write request" << std::endl;
std::cerr << "RenderFrameAndWait: failed to write request"
<< std::endl;
return false;
}
@@ -378,8 +385,9 @@ protected:
std::cerr << "RenderFrameAndWait: unexpected message type "
<< ready[QStringLiteral("type")].toString().toStdString()
<< " body="
<< QJsonDocument(ready).toJson(QJsonDocument::Compact)
.toStdString()
<< QJsonDocument(ready)
.toJson(QJsonDocument::Compact)
.toStdString()
<< std::endl;
return false;
}
@@ -407,8 +415,9 @@ protected:
if (worker_.state() == QProcess::NotRunning) {
std::cerr << "WaitForMessage: worker exited with code "
<< worker_.exitCode() << std::endl;
std::cerr << "Worker stdout buffer: "
<< read_buffer_.toStdString() << std::endl;
std::cerr
<< "Worker stdout buffer: " << read_buffer_.toStdString()
<< std::endl;
QByteArray err = worker_.readAllStandardError();
if (!err.isEmpty()) {
std::cerr << "Worker stderr:\n"
@@ -417,8 +426,9 @@ protected:
return false;
}
}
std::cerr << "WaitForMessage: timeout, buffer="
<< read_buffer_.toStdString() << std::endl;
std::cerr
<< "WaitForMessage: timeout, buffer=" << read_buffer_.toStdString()
<< std::endl;
return false;
}
@@ -473,19 +483,21 @@ TEST_F(RenderWorkerFootageTest, VulkanFootageIsNotBlack)
ASSERT_EQ(int(consumed_slot), output_slot);
const void *output_data = output_pool_->SlotData(consumed_slot);
const double brightness = SampleBrightnessF32(
output_data, output_width_, output_height_,
output_width_ * 4 * int(sizeof(float)));
const double brightness =
SampleBrightnessF32(output_data, output_width_, output_height_,
output_width_ * 4 * int(sizeof(float)));
EXPECT_GT(brightness, 0.01)
<< "Worker output frame is black (brightness=" << brightness << ")";
SaveFrameAsPng(output_data, output_width_, output_height_,
temp_dir_.filePath(QStringLiteral("worker_output_vulkan.png")));
SaveFrameAsPng(
output_data, output_width_, output_height_,
temp_dir_.filePath(QStringLiteral("worker_output_vulkan.png")));
QFile::remove(QStringLiteral("/tmp/worker_output_vulkan.png"));
QFile::copy(temp_dir_.filePath(QStringLiteral("worker_output_vulkan.png")),
QStringLiteral("/tmp/worker_output_vulkan.png"));
std::cerr << "Vulkan output copied to /tmp/worker_output_vulkan.png" << std::endl;
std::cerr << "Vulkan output copied to /tmp/worker_output_vulkan.png"
<< std::endl;
output_pool_->Release(consumed_slot);
}
@@ -507,19 +519,20 @@ TEST_F(RenderWorkerFootageTest, OpenGLFootageIsNotBlack)
ASSERT_EQ(int(consumed_slot), output_slot);
const void *output_data = output_pool_->SlotData(consumed_slot);
const double brightness = SampleBrightnessF32(
output_data, output_width_, output_height_,
output_width_ * 4 * int(sizeof(float)));
const double brightness =
SampleBrightnessF32(output_data, output_width_, output_height_,
output_width_ * 4 * int(sizeof(float)));
EXPECT_GT(brightness, 0.01)
<< "Worker output frame is black (brightness=" << brightness << ")";
SaveFrameAsPng(output_data, output_width_, output_height_,
temp_dir_.filePath(QStringLiteral("worker_output_opengl.png")));
SaveFrameAsPng(
output_data, output_width_, output_height_,
temp_dir_.filePath(QStringLiteral("worker_output_opengl.png")));
QFile::remove(QStringLiteral("/tmp/worker_output_opengl.png"));
QFile::copy(temp_dir_.filePath(QStringLiteral("worker_output_opengl.png")),
QStringLiteral("/tmp/worker_output_opengl.png"));
std::cerr << "OpenGL output copied to /tmp/worker_output_opengl.png" << std::endl;
std::cerr << "OpenGL output copied to /tmp/worker_output_opengl.png"
<< std::endl;
output_pool_->Release(consumed_slot);
}
+2 -2
View File
@@ -51,8 +51,8 @@ TEST(Shaders, ResourcesAvailable)
for (const QString &path : shader_paths) {
QFile file(path);
ASSERT_TRUE(file.exists()) << "Missing shader resource: "
<< path.toStdString();
ASSERT_TRUE(file.exists())
<< "Missing shader resource: " << path.toStdString();
ASSERT_TRUE(file.open(QIODevice::ReadOnly))
<< "Failed to open shader resource: " << path.toStdString();
const QByteArray contents = file.readAll();
+4 -4
View File
@@ -5,7 +5,8 @@
#include "task/taskmanager.h"
namespace {
namespace
{
class DummyTask final : public olive::Task {
public:
explicit DummyTask(bool *ran)
@@ -74,9 +75,8 @@ TEST(TaskManager, AddAndRunTask)
DummyTask *task = new DummyTask(&ran);
QEventLoop loop;
QObject::connect(task, &olive::Task::Finished, &loop, [&loop](olive::Task *, bool) {
loop.quit();
});
QObject::connect(task, &olive::Task::Finished, &loop,
[&loop](olive::Task *, bool) { loop.quit(); });
mgr->AddTask(task);
+13 -14
View File
@@ -36,8 +36,8 @@ TEST(TimecodeMetadata, ParsesDropFrameTimecode)
TEST(TimecodeMetadata, ParsesBwfTimeReference)
{
const olive::TimecodeMetadata::SourceTime parsed =
olive::TimecodeMetadata::FromBwfTimeReference(
QStringLiteral("96000"), 48000);
olive::TimecodeMetadata::FromBwfTimeReference(QStringLiteral("96000"),
48000);
ASSERT_TRUE(parsed.valid);
EXPECT_EQ(parsed.source, QStringLiteral("bwf_time_reference"));
@@ -63,20 +63,20 @@ TEST(TimecodeMetadata, RejectsInvalidMetadata)
EXPECT_FALSE(olive::TimecodeMetadata::FromBwfTimeReference(
QStringLiteral("not-a-number"), 48000)
.valid);
EXPECT_FALSE(olive::TimecodeMetadata::FromBwfTimeReference(
QStringLiteral("123"), 0)
.valid);
EXPECT_FALSE(olive::TimecodeMetadata::FromTimecodeString(
QStringLiteral("not-a-timecode"),
olive::core::rational(1, 24))
.valid);
EXPECT_FALSE(
olive::TimecodeMetadata::FromBwfTimeReference(QStringLiteral("123"), 0)
.valid);
EXPECT_FALSE(
olive::TimecodeMetadata::FromTimecodeString(
QStringLiteral("not-a-timecode"), olive::core::rational(1, 24))
.valid);
}
TEST(TimecodeMetadata, FromBwfTimeReferenceZeroSampleRateIsInvalid)
{
EXPECT_FALSE(olive::TimecodeMetadata::FromBwfTimeReference(
QStringLiteral("0"), 0)
.valid);
EXPECT_FALSE(
olive::TimecodeMetadata::FromBwfTimeReference(QStringLiteral("0"), 0)
.valid);
}
TEST(TimecodeMetadata, FootageDescriptionWithoutSourceStartTime)
@@ -113,8 +113,7 @@ TEST(TimecodeMetadata, FootagePersistsSourceStartTime)
writer.writeStartElement(QStringLiteral("custom"));
writer.writeTextElement(QStringLiteral("timestamp"), QStringLiteral("0"));
writer.writeStartElement(QStringLiteral("sourcestarttime"));
writer.writeAttribute(QStringLiteral("source"),
QStringLiteral("timecode"));
writer.writeAttribute(QStringLiteral("source"), QStringLiteral("timecode"));
writer.writeCharacters(QStringLiteral("3600/1"));
writer.writeEndElement();
writer.writeEndElement();
+8 -4
View File
@@ -52,13 +52,17 @@ TEST(TimelineCoordinate, CopyAndAssignment)
TEST(TimelineCoordinate, Equality)
{
olive::TimelineCoordinate a(olive::core::rational(5, 1),
olive::Track::Reference(olive::Track::kVideo, 1));
olive::Track::Reference(olive::Track::kVideo,
1));
olive::TimelineCoordinate b(olive::core::rational(5, 1),
olive::Track::Reference(olive::Track::kVideo, 1));
olive::Track::Reference(olive::Track::kVideo,
1));
olive::TimelineCoordinate c(olive::core::rational(6, 1),
olive::Track::Reference(olive::Track::kVideo, 1));
olive::Track::Reference(olive::Track::kVideo,
1));
olive::TimelineCoordinate d(olive::core::rational(5, 1),
olive::Track::Reference(olive::Track::kAudio, 1));
olive::Track::Reference(olive::Track::kAudio,
1));
EXPECT_EQ(a.GetFrame(), b.GetFrame());
EXPECT_EQ(a.GetTrack(), b.GetTrack());
+11 -18
View File
@@ -51,20 +51,17 @@ TEST(TimelineMarkerList, OrderAndLookup)
1,
olive::core::TimeRange(olive::core::rational(10, 1),
olive::core::rational(10, 1)),
QStringLiteral("A"),
&list);
QStringLiteral("A"), &list);
olive::TimelineMarker marker_b(
2,
olive::core::TimeRange(olive::core::rational(5, 1),
olive::core::rational(5, 1)),
QStringLiteral("B"),
&list);
QStringLiteral("B"), &list);
olive::TimelineMarker marker_c(
3,
olive::core::TimeRange(olive::core::rational(20, 1),
olive::core::rational(20, 1)),
QStringLiteral("C"),
&list);
QStringLiteral("C"), &list);
ASSERT_EQ(list.size(), 3);
auto it = list.cbegin();
@@ -85,7 +82,8 @@ TEST(TimelineMarkerList, GetMarkerAtTimeReturnsNullWhenEmpty)
{
olive::TimelineMarkerList list;
EXPECT_EQ(list.GetMarkerAtTime(olive::core::rational(10, 1)), nullptr);
EXPECT_EQ(list.GetClosestMarkerToTime(olive::core::rational(10, 1)), nullptr);
EXPECT_EQ(list.GetClosestMarkerToTime(olive::core::rational(10, 1)),
nullptr);
}
TEST(TimelineMarkerList, SaveLoadWithUnknownElements)
@@ -95,8 +93,7 @@ TEST(TimelineMarkerList, SaveLoadWithUnknownElements)
4,
olive::core::TimeRange(olive::core::rational(12, 1),
olive::core::rational(15, 1)),
QStringLiteral("Span"),
&list);
QStringLiteral("Span"), &list);
QByteArray xml;
QBuffer buffer(&xml);
@@ -130,8 +127,7 @@ TEST(TimelineMarkerCommands, AddRemoveAndChange)
&list,
olive::core::TimeRange(olive::core::rational(1, 1),
olive::core::rational(2, 1)),
QStringLiteral("One"),
1);
QStringLiteral("One"), 1);
add.redo_now();
ASSERT_EQ(list.size(), 1);
auto *marker = list.front();
@@ -159,14 +155,12 @@ TEST(TimelineMarkerCommands, AddRemoveAndChange)
2,
olive::core::TimeRange(olive::core::rational(5, 1),
olive::core::rational(5, 1)),
QStringLiteral("Two"),
&list);
QStringLiteral("Two"), &list);
EXPECT_EQ(list.front()->time().in(), olive::core::rational(1, 1));
olive::MarkerChangeTimeCommand move(
marker,
olive::core::TimeRange(olive::core::rational(0, 1),
olive::core::rational(0, 1)));
marker, olive::core::TimeRange(olive::core::rational(0, 1),
olive::core::rational(0, 1)));
move.redo_now();
EXPECT_EQ(list.front(), marker);
move.undo_now();
@@ -180,8 +174,7 @@ TEST(TimelineMarkerCommands, AddCommandUndo)
&list,
olive::core::TimeRange(olive::core::rational(5, 1),
olive::core::rational(5, 1)),
QStringLiteral("UndoMe"),
2);
QStringLiteral("UndoMe"), 2);
add.redo_now();
EXPECT_EQ(list.size(), 1);
add.undo_now();
+8 -9
View File
@@ -24,7 +24,8 @@ extern "C" {
using namespace olive;
using namespace olive::core;
namespace {
namespace
{
AudioParams MakeMonoParams(int sample_rate)
{
@@ -55,17 +56,16 @@ void WritePartialWaveform(AudioWaveformCache *cache, int sample_rate)
waveform.OverwriteSamples(buf, sample_rate, rational(1));
// Tell the cache that only the middle second is valid in a 3-second clip.
cache->WriteWaveform(TimeRange(1, 2),
TimeRangeList({ TimeRange(1, 2) }),
cache->WriteWaveform(TimeRange(1, 2), TimeRangeList({ TimeRange(1, 2) }),
&waveform);
}
} // namespace
} // namespace
TEST(TimelineWaveformSync, ExtractEnvelopeUsesOnlyValidatedRanges)
{
constexpr int kSampleRate = 48000;
constexpr size_t kWindowSamples = kSampleRate / 20; // 50 ms windows
constexpr size_t kWindowSamples = kSampleRate / 20; // 50 ms windows
AudioWaveformCache cache;
WritePartialWaveform(&cache, kSampleRate);
@@ -76,8 +76,8 @@ TEST(TimelineWaveformSync, ExtractEnvelopeUsesOnlyValidatedRanges)
clip.sample_rate = kSampleRate;
const QVector<double> envelope =
TimelineWaveformSync::ExtractWaveformCacheEnvelope(
clip, kSampleRate, kWindowSamples);
TimelineWaveformSync::ExtractWaveformCacheEnvelope(clip, kSampleRate,
kWindowSamples);
// 3 seconds at 20 windows per second == 60 windows.
EXPECT_EQ(envelope.size(), 60);
@@ -134,8 +134,7 @@ TEST(TimelineWaveformSync, EmptyCacheIsNotReady)
clip.set_length_and_media_out(rational(3));
clip.set_media_in(rational(0));
Node::ConnectEdge(
&footage, NodeInput(&clip, ClipBlock::kBufferIn));
Node::ConnectEdge(&footage, NodeInput(&clip, ClipBlock::kBufferIn));
WaveformSyncClip out;
EXPECT_FALSE(TimelineWaveformSync::GetWaveformSyncClip(&clip, &out));
+5 -5
View File
@@ -28,7 +28,7 @@ TEST(TimelineWorkArea, SaveLoadRoundTrip)
olive::TimelineWorkArea workarea;
workarea.set_enabled(true);
workarea.set_range(olive::core::TimeRange(olive::core::rational(2, 1),
olive::core::rational(6, 1)));
olive::core::rational(6, 1)));
QByteArray xml;
QBuffer buffer(&xml);
@@ -51,7 +51,7 @@ TEST(TimelineWorkArea, SaveLoadRoundTrip)
EXPECT_TRUE(loaded.enabled());
EXPECT_EQ(loaded.range(),
olive::core::TimeRange(olive::core::rational(2, 1),
olive::core::rational(6, 1)));
olive::core::rational(6, 1)));
}
TEST(TimelineWorkArea, DisabledWorkAreaRoundTrip)
@@ -59,7 +59,7 @@ TEST(TimelineWorkArea, DisabledWorkAreaRoundTrip)
olive::TimelineWorkArea workarea;
workarea.set_enabled(false);
workarea.set_range(olive::core::TimeRange(olive::core::rational(0, 1),
olive::core::rational(10, 1)));
olive::core::rational(10, 1)));
QByteArray xml;
QBuffer buffer(&xml);
@@ -82,14 +82,14 @@ TEST(TimelineWorkArea, DisabledWorkAreaRoundTrip)
EXPECT_FALSE(loaded.enabled());
EXPECT_EQ(loaded.range(),
olive::core::TimeRange(olive::core::rational(0, 1),
olive::core::rational(10, 1)));
olive::core::rational(10, 1)));
}
TEST(TimelineWorkArea, SetRangeUpdatesInOut)
{
olive::TimelineWorkArea workarea;
workarea.set_range(olive::core::TimeRange(olive::core::rational(3, 1),
olive::core::rational(8, 1)));
olive::core::rational(8, 1)));
EXPECT_EQ(workarea.in(), olive::core::rational(3, 1));
EXPECT_EQ(workarea.out(), olive::core::rational(8, 1));
+2 -1
View File
@@ -5,7 +5,8 @@
#include "undo/undostack.h"
#include "undo/undocommand.h"
namespace {
namespace
{
class TestCommand final : public olive::UndoCommand {
public:
explicit TestCommand(int *value)
+306 -300
View File
@@ -25,9 +25,12 @@
using namespace olive;
using namespace olive::core;
namespace olive {
namespace viewer {
namespace test {
namespace olive
{
namespace viewer
{
namespace test
{
// ============================================================================
// Smoke Test: ViewerPlaybackTimer
@@ -35,92 +38,92 @@ namespace test {
TEST(ViewerSmokeTimer, DefaultConstruction)
{
ViewerPlaybackTimer timer;
// Timer should be in a valid but not-started state
// After Start() is called, it should return valid timestamps
ViewerPlaybackTimer timer;
// Timer should be in a valid but not-started state
// After Start() is called, it should return valid timestamps
}
TEST(ViewerSmokeTimer, BasicTiming)
{
ViewerPlaybackTimer timer;
ViewerPlaybackTimer timer;
// Start at timestamp 0, 1x speed, 24fps (timebase = 1/24)
timer.Start(0, 1, 1.0 / 24.0);
// Start at timestamp 0, 1x speed, 24fps (timebase = 1/24)
timer.Start(0, 1, 1.0 / 24.0);
// Immediately get timestamp (should be close to 0)
int64_t ts = timer.GetTimestampNow();
EXPECT_GE(ts, 0);
// Immediately get timestamp (should be close to 0)
int64_t ts = timer.GetTimestampNow();
EXPECT_GE(ts, 0);
// Wait a bit and check timestamp has increased
QThread::msleep(50); // 50ms
int64_t ts2 = timer.GetTimestampNow();
// Wait a bit and check timestamp has increased
QThread::msleep(50); // 50ms
int64_t ts2 = timer.GetTimestampNow();
// At 24fps, 50ms should be approximately 1 frame (or slightly more)
// Allow for some timing variance
EXPECT_GE(ts2, ts);
// At 24fps, 50ms should be approximately 1 frame (or slightly more)
// Allow for some timing variance
EXPECT_GE(ts2, ts);
}
TEST(ViewerSmokeTimer, PlaybackSpeedForward)
{
ViewerPlaybackTimer timer;
ViewerPlaybackTimer timer;
// Start at timestamp 100, 2x speed, 30fps
timer.Start(100, 2, 1.0 / 30.0);
// Start at timestamp 100, 2x speed, 30fps
timer.Start(100, 2, 1.0 / 30.0);
int64_t ts1 = timer.GetTimestampNow();
QThread::msleep(50);
int64_t ts2 = timer.GetTimestampNow();
int64_t ts1 = timer.GetTimestampNow();
QThread::msleep(50);
int64_t ts2 = timer.GetTimestampNow();
// At 2x speed, time should advance twice as fast
EXPECT_GT(ts2, ts1);
// At 2x speed, time should advance twice as fast
EXPECT_GT(ts2, ts1);
}
TEST(ViewerSmokeTimer, PlaybackSpeedReverse)
{
ViewerPlaybackTimer timer;
ViewerPlaybackTimer timer;
// Start at timestamp 1000, -1x speed (reverse), 24fps
timer.Start(1000, -1, 1.0 / 24.0);
// Start at timestamp 1000, -1x speed (reverse), 24fps
timer.Start(1000, -1, 1.0 / 24.0);
int64_t ts1 = timer.GetTimestampNow();
QThread::msleep(50);
int64_t ts2 = timer.GetTimestampNow();
int64_t ts1 = timer.GetTimestampNow();
QThread::msleep(50);
int64_t ts2 = timer.GetTimestampNow();
// In reverse, timestamp should decrease
EXPECT_LT(ts2, ts1);
// In reverse, timestamp should decrease
EXPECT_LT(ts2, ts1);
}
TEST(ViewerSmokeTimer, DifferentTimebases)
{
ViewerPlaybackTimer timer;
ViewerPlaybackTimer timer;
// Test with 24fps
timer.Start(0, 1, 1.0 / 24.0);
QThread::msleep(100);
int64_t ts24 = timer.GetTimestampNow();
// Test with 24fps
timer.Start(0, 1, 1.0 / 24.0);
QThread::msleep(100);
int64_t ts24 = timer.GetTimestampNow();
// Test with 60fps
timer.Start(0, 1, 1.0 / 60.0);
QThread::msleep(100);
int64_t ts60 = timer.GetTimestampNow();
// Test with 60fps
timer.Start(0, 1, 1.0 / 60.0);
QThread::msleep(100);
int64_t ts60 = timer.GetTimestampNow();
// At same real time, 60fps should have more frames than 24fps
EXPECT_GT(ts60, ts24);
// At same real time, 60fps should have more frames than 24fps
EXPECT_GT(ts60, ts24);
}
TEST(ViewerSmokeTimer, ZeroSpeed)
{
ViewerPlaybackTimer timer;
ViewerPlaybackTimer timer;
// Start with 0 speed (paused)
timer.Start(500, 0, 1.0 / 24.0);
// Start with 0 speed (paused)
timer.Start(500, 0, 1.0 / 24.0);
int64_t ts1 = timer.GetTimestampNow();
QThread::msleep(50);
int64_t ts2 = timer.GetTimestampNow();
int64_t ts1 = timer.GetTimestampNow();
QThread::msleep(50);
int64_t ts2 = timer.GetTimestampNow();
// With 0 speed, timestamp should not change
EXPECT_EQ(ts1, ts2);
// With 0 speed, timestamp should not change
EXPECT_EQ(ts1, ts2);
}
// ============================================================================
@@ -129,121 +132,121 @@ TEST(ViewerSmokeTimer, ZeroSpeed)
TEST(ViewerSmokeQueue, DefaultConstruction)
{
ViewerQueue queue;
EXPECT_TRUE(queue.empty());
ViewerQueue queue;
EXPECT_TRUE(queue.empty());
}
TEST(ViewerSmokeQueue, AppendForwardPlayback)
{
ViewerQueue queue;
ViewerQueue queue;
// Append frames for forward playback
ViewerPlaybackFrame frame1{rational(0), QVariant()};
ViewerPlaybackFrame frame2{rational(1, 24), QVariant()};
ViewerPlaybackFrame frame3{rational(2, 24), QVariant()};
// Append frames for forward playback
ViewerPlaybackFrame frame1{ rational(0), QVariant() };
ViewerPlaybackFrame frame2{ rational(1, 24), QVariant() };
ViewerPlaybackFrame frame3{ rational(2, 24), QVariant() };
queue.AppendTimewise(frame1, 1); // speed = 1 (forward)
queue.AppendTimewise(frame2, 1);
queue.AppendTimewise(frame3, 1);
queue.AppendTimewise(frame1, 1); // speed = 1 (forward)
queue.AppendTimewise(frame2, 1);
queue.AppendTimewise(frame3, 1);
EXPECT_EQ(queue.size(), 3);
EXPECT_EQ(queue.size(), 3);
// Verify order (should be chronological for forward playback)
auto it = queue.begin();
EXPECT_EQ(it->timestamp, rational(0));
++it;
EXPECT_EQ(it->timestamp, rational(1, 24));
++it;
EXPECT_EQ(it->timestamp, rational(2, 24));
// Verify order (should be chronological for forward playback)
auto it = queue.begin();
EXPECT_EQ(it->timestamp, rational(0));
++it;
EXPECT_EQ(it->timestamp, rational(1, 24));
++it;
EXPECT_EQ(it->timestamp, rational(2, 24));
}
TEST(ViewerSmokeQueue, AppendReversePlayback)
{
ViewerQueue queue;
ViewerQueue queue;
// Append frames for reverse playback
ViewerPlaybackFrame frame1{rational(2, 24), QVariant()};
ViewerPlaybackFrame frame2{rational(1, 24), QVariant()};
ViewerPlaybackFrame frame3{rational(0), QVariant()};
// Append frames for reverse playback
ViewerPlaybackFrame frame1{ rational(2, 24), QVariant() };
ViewerPlaybackFrame frame2{ rational(1, 24), QVariant() };
ViewerPlaybackFrame frame3{ rational(0), QVariant() };
queue.AppendTimewise(frame1, -1); // speed = -1 (reverse)
queue.AppendTimewise(frame2, -1);
queue.AppendTimewise(frame3, -1);
queue.AppendTimewise(frame1, -1); // speed = -1 (reverse)
queue.AppendTimewise(frame2, -1);
queue.AppendTimewise(frame3, -1);
EXPECT_EQ(queue.size(), 3);
EXPECT_EQ(queue.size(), 3);
// Verify order (should be reverse chronological for reverse playback)
auto it = queue.begin();
EXPECT_EQ(it->timestamp, rational(2, 24));
++it;
EXPECT_EQ(it->timestamp, rational(1, 24));
++it;
EXPECT_EQ(it->timestamp, rational(0));
// Verify order (should be reverse chronological for reverse playback)
auto it = queue.begin();
EXPECT_EQ(it->timestamp, rational(2, 24));
++it;
EXPECT_EQ(it->timestamp, rational(1, 24));
++it;
EXPECT_EQ(it->timestamp, rational(0));
}
TEST(ViewerSmokeQueue, InsertOutOfOrder)
{
ViewerQueue queue;
ViewerQueue queue;
// Insert frames out of order for forward playback
ViewerPlaybackFrame frame1{rational(0), QVariant()};
ViewerPlaybackFrame frame2{rational(2, 24), QVariant()};
ViewerPlaybackFrame frame3{rational(1, 24), QVariant()}; // Middle frame
// Insert frames out of order for forward playback
ViewerPlaybackFrame frame1{ rational(0), QVariant() };
ViewerPlaybackFrame frame2{ rational(2, 24), QVariant() };
ViewerPlaybackFrame frame3{ rational(1, 24), QVariant() }; // Middle frame
queue.AppendTimewise(frame1, 1);
queue.AppendTimewise(frame2, 1);
queue.AppendTimewise(frame3, 1); // Should insert in middle
queue.AppendTimewise(frame1, 1);
queue.AppendTimewise(frame2, 1);
queue.AppendTimewise(frame3, 1); // Should insert in middle
EXPECT_EQ(queue.size(), 3);
EXPECT_EQ(queue.size(), 3);
// Verify correct order
auto it = queue.begin();
EXPECT_EQ(it->timestamp, rational(0));
++it;
EXPECT_EQ(it->timestamp, rational(1, 24));
++it;
EXPECT_EQ(it->timestamp, rational(2, 24));
// Verify correct order
auto it = queue.begin();
EXPECT_EQ(it->timestamp, rational(0));
++it;
EXPECT_EQ(it->timestamp, rational(1, 24));
++it;
EXPECT_EQ(it->timestamp, rational(2, 24));
}
TEST(ViewerSmokeQueue, PurgeBefore)
{
ViewerQueue queue;
ViewerQueue queue;
// Add some frames
for (int i = 0; i < 10; i++) {
ViewerPlaybackFrame frame{rational(i, 24), QVariant()};
queue.AppendTimewise(frame, 1);
}
// Add some frames
for (int i = 0; i < 10; i++) {
ViewerPlaybackFrame frame{ rational(i, 24), QVariant() };
queue.AppendTimewise(frame, 1);
}
EXPECT_EQ(queue.size(), 10);
EXPECT_EQ(queue.size(), 10);
// Purge frames before 5/24
queue.PurgeBefore(rational(5, 24), 1);
// Purge frames before 5/24
queue.PurgeBefore(rational(5, 24), 1);
// Should have 5 frames remaining (5, 6, 7, 8, 9)
EXPECT_EQ(queue.size(), 5);
EXPECT_EQ(queue.front().timestamp, rational(5, 24));
// Should have 5 frames remaining (5, 6, 7, 8, 9)
EXPECT_EQ(queue.size(), 5);
EXPECT_EQ(queue.front().timestamp, rational(5, 24));
}
TEST(ViewerSmokeQueue, PurgeBeforeReverse)
{
ViewerQueue queue;
ViewerQueue queue;
// Add frames for reverse playback (newest first)
for (int i = 9; i >= 0; i--) {
ViewerPlaybackFrame frame{rational(i, 24), QVariant()};
queue.AppendTimewise(frame, -1);
}
// Add frames for reverse playback (newest first)
for (int i = 9; i >= 0; i--) {
ViewerPlaybackFrame frame{ rational(i, 24), QVariant() };
queue.AppendTimewise(frame, -1);
}
EXPECT_EQ(queue.size(), 10);
EXPECT_EQ(queue.size(), 10);
// In reverse playback, front() is the largest timestamp (9/24)
// PurgeBefore with negative speed removes frames where front > time
queue.PurgeBefore(rational(5, 24), -1);
// In reverse playback, front() is the largest timestamp (9/24)
// PurgeBefore with negative speed removes frames where front > time
queue.PurgeBefore(rational(5, 24), -1);
// Should have frames 0-5 remaining (those <= 5/24)
EXPECT_EQ(queue.size(), 6);
EXPECT_EQ(queue.front().timestamp, rational(5, 24));
// Should have frames 0-5 remaining (those <= 5/24)
EXPECT_EQ(queue.size(), 6);
EXPECT_EQ(queue.front().timestamp, rational(5, 24));
}
// ============================================================================
@@ -252,57 +255,57 @@ TEST(ViewerSmokeQueue, PurgeBeforeReverse)
TEST(ViewerSmokeSafeMargin, DefaultConstruction)
{
ViewerSafeMarginInfo info;
EXPECT_FALSE(info.is_enabled());
EXPECT_FALSE(info.custom_ratio());
EXPECT_DOUBLE_EQ(info.ratio(), 0.0);
ViewerSafeMarginInfo info;
EXPECT_FALSE(info.is_enabled());
EXPECT_FALSE(info.custom_ratio());
EXPECT_DOUBLE_EQ(info.ratio(), 0.0);
}
TEST(ViewerSmokeSafeMargin, EnabledConstruction)
{
ViewerSafeMarginInfo info(true);
EXPECT_TRUE(info.is_enabled());
EXPECT_FALSE(info.custom_ratio());
ViewerSafeMarginInfo info(true);
EXPECT_TRUE(info.is_enabled());
EXPECT_FALSE(info.custom_ratio());
}
TEST(ViewerSmokeSafeMargin, CustomRatioConstruction)
{
ViewerSafeMarginInfo info(true, 0.9);
EXPECT_TRUE(info.is_enabled());
EXPECT_TRUE(info.custom_ratio());
EXPECT_DOUBLE_EQ(info.ratio(), 0.9);
ViewerSafeMarginInfo info(true, 0.9);
EXPECT_TRUE(info.is_enabled());
EXPECT_TRUE(info.custom_ratio());
EXPECT_DOUBLE_EQ(info.ratio(), 0.9);
}
TEST(ViewerSmokeSafeMargin, EqualityOperators)
{
ViewerSafeMarginInfo info1(true, 0.9);
ViewerSafeMarginInfo info2(true, 0.9);
ViewerSafeMarginInfo info3(false, 0.9);
ViewerSafeMarginInfo info4(true, 0.8);
ViewerSafeMarginInfo info1(true, 0.9);
ViewerSafeMarginInfo info2(true, 0.9);
ViewerSafeMarginInfo info3(false, 0.9);
ViewerSafeMarginInfo info4(true, 0.8);
EXPECT_TRUE(info1 == info2);
EXPECT_FALSE(info1 != info2);
EXPECT_TRUE(info1 == info2);
EXPECT_FALSE(info1 != info2);
EXPECT_FALSE(info1 == info3); // Different enabled state
EXPECT_FALSE(info1 == info4); // Different ratio
EXPECT_TRUE(info1 != info3);
EXPECT_FALSE(info1 == info3); // Different enabled state
EXPECT_FALSE(info1 == info4); // Different ratio
EXPECT_TRUE(info1 != info3);
}
TEST(ViewerSmokeSafeMargin, ZeroRatio)
{
ViewerSafeMarginInfo info(true, 0.0);
EXPECT_TRUE(info.is_enabled());
EXPECT_FALSE(info.custom_ratio()); // 0 ratio means no custom ratio
ViewerSafeMarginInfo info(true, 0.0);
EXPECT_TRUE(info.is_enabled());
EXPECT_FALSE(info.custom_ratio()); // 0 ratio means no custom ratio
}
TEST(ViewerSmokeSafeMargin, CopyConstruction)
{
ViewerSafeMarginInfo original(true, 0.85);
ViewerSafeMarginInfo copy(original);
ViewerSafeMarginInfo original(true, 0.85);
ViewerSafeMarginInfo copy(original);
EXPECT_EQ(copy.is_enabled(), original.is_enabled());
EXPECT_EQ(copy.custom_ratio(), original.custom_ratio());
EXPECT_DOUBLE_EQ(copy.ratio(), original.ratio());
EXPECT_EQ(copy.is_enabled(), original.is_enabled());
EXPECT_EQ(copy.custom_ratio(), original.custom_ratio());
EXPECT_DOUBLE_EQ(copy.ratio(), original.ratio());
}
// ============================================================================
@@ -311,30 +314,30 @@ TEST(ViewerSmokeSafeMargin, CopyConstruction)
TEST(ViewerSmokeAudioCache, DefaultConstruction)
{
AudioPlaybackCache cache;
// Should construct without crashing
SUCCEED();
AudioPlaybackCache cache;
// Should construct without crashing
SUCCEED();
}
TEST(ViewerSmokeAudioCache, ParameterSetters)
{
AudioPlaybackCache cache;
AudioPlaybackCache cache;
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P);
cache.SetParameters(params);
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P);
cache.SetParameters(params);
// Parameters should be retrievable
AudioParams retrieved = cache.GetParameters();
EXPECT_EQ(retrieved.sample_rate(), params.sample_rate());
// Parameters should be retrievable
AudioParams retrieved = cache.GetParameters();
EXPECT_EQ(retrieved.sample_rate(), params.sample_rate());
}
TEST(ViewerSmokeAudioCache, ValidateWithRange)
{
AudioPlaybackCache cache;
AudioPlaybackCache cache;
// Initially no validated ranges
TimeRangeList validated = cache.GetValidatedRanges();
EXPECT_TRUE(validated.isEmpty());
// Initially no validated ranges
TimeRangeList validated = cache.GetValidatedRanges();
EXPECT_TRUE(validated.isEmpty());
}
// ============================================================================
@@ -346,32 +349,32 @@ TEST(ViewerSmokeAudioCache, ValidateWithRange)
TEST(ViewerSmokeAutoCacher, DISABLED_Construction)
{
// PreviewAutoCacher requires full GUI environment
SUCCEED();
// PreviewAutoCacher requires full GUI environment
SUCCEED();
}
TEST(ViewerSmokeAutoCacher, DISABLED_SetPlayhead)
{
// PreviewAutoCacher requires full GUI environment
SUCCEED();
// PreviewAutoCacher requires full GUI environment
SUCCEED();
}
TEST(ViewerSmokeAutoCacher, DISABLED_PauseControls)
{
// PreviewAutoCacher requires full GUI environment
SUCCEED();
// PreviewAutoCacher requires full GUI environment
SUCCEED();
}
TEST(ViewerSmokeAutoCacher, DISABLED_SetIgnoreCacheRequests)
{
// PreviewAutoCacher requires full GUI environment
SUCCEED();
// PreviewAutoCacher requires full GUI environment
SUCCEED();
}
TEST(ViewerSmokeAutoCacher, DISABLED_SetDisplayColorProcessor)
{
// PreviewAutoCacher requires full GUI environment
SUCCEED();
// PreviewAutoCacher requires full GUI environment
SUCCEED();
}
// ============================================================================
@@ -380,73 +383,73 @@ TEST(ViewerSmokeAutoCacher, DISABLED_SetDisplayColorProcessor)
TEST(ViewerSmokeRational, DefaultConstruction)
{
rational r;
EXPECT_EQ(r.numerator(), 0);
EXPECT_EQ(r.denominator(), 1);
rational r;
EXPECT_EQ(r.numerator(), 0);
EXPECT_EQ(r.denominator(), 1);
}
TEST(ViewerSmokeRational, ValueConstruction)
{
rational r(24, 1);
EXPECT_EQ(r.numerator(), 24);
EXPECT_EQ(r.denominator(), 1);
rational r(24, 1);
EXPECT_EQ(r.numerator(), 24);
EXPECT_EQ(r.denominator(), 1);
rational r2(1, 24);
EXPECT_EQ(r2.numerator(), 1);
EXPECT_EQ(r2.denominator(), 24);
rational r2(1, 24);
EXPECT_EQ(r2.numerator(), 1);
EXPECT_EQ(r2.denominator(), 24);
}
TEST(ViewerSmokeRational, ToDouble)
{
rational r(1, 2);
EXPECT_DOUBLE_EQ(r.toDouble(), 0.5);
rational r(1, 2);
EXPECT_DOUBLE_EQ(r.toDouble(), 0.5);
rational r2(3, 4);
EXPECT_DOUBLE_EQ(r2.toDouble(), 0.75);
rational r2(3, 4);
EXPECT_DOUBLE_EQ(r2.toDouble(), 0.75);
}
TEST(ViewerSmokeRational, Arithmetic)
{
rational r1(1, 2);
rational r2(1, 4);
rational r1(1, 2);
rational r2(1, 4);
rational sum = r1 + r2;
EXPECT_EQ(sum.numerator(), 3);
EXPECT_EQ(sum.denominator(), 4);
rational sum = r1 + r2;
EXPECT_EQ(sum.numerator(), 3);
EXPECT_EQ(sum.denominator(), 4);
rational diff = r1 - r2;
EXPECT_EQ(diff.numerator(), 1);
EXPECT_EQ(diff.denominator(), 4);
rational diff = r1 - r2;
EXPECT_EQ(diff.numerator(), 1);
EXPECT_EQ(diff.denominator(), 4);
}
TEST(ViewerSmokeRational, Comparison)
{
rational r1(1, 2);
rational r2(2, 4);
rational r3(3, 4);
rational r1(1, 2);
rational r2(2, 4);
rational r3(3, 4);
EXPECT_TRUE(r1 == r2); // Equivalent fractions
EXPECT_FALSE(r1 == r3);
EXPECT_TRUE(r1 < r3);
EXPECT_TRUE(r3 > r1);
EXPECT_TRUE(r1 == r2); // Equivalent fractions
EXPECT_FALSE(r1 == r3);
EXPECT_TRUE(r1 < r3);
EXPECT_TRUE(r3 > r1);
}
TEST(ViewerSmokeRational, NullCheck)
{
rational r;
EXPECT_TRUE(r.isNull()); // 0/1 is considered null
rational r;
EXPECT_TRUE(r.isNull()); // 0/1 is considered null
rational r2(1, 2);
EXPECT_FALSE(r2.isNull());
rational r2(1, 2);
EXPECT_FALSE(r2.isNull());
}
TEST(ViewerSmokeRational, Flipped)
{
rational r(24, 1);
rational flipped = r.flipped();
rational r(24, 1);
rational flipped = r.flipped();
EXPECT_EQ(flipped.numerator(), 1);
EXPECT_EQ(flipped.denominator(), 24);
EXPECT_EQ(flipped.numerator(), 1);
EXPECT_EQ(flipped.denominator(), 24);
}
// ============================================================================
@@ -455,58 +458,61 @@ TEST(ViewerSmokeRational, Flipped)
TEST(ViewerSmokeThread, ConcurrentTimerAccess)
{
const int num_threads = 4;
const int num_iterations = 100;
const int num_threads = 4;
const int num_iterations = 100;
ViewerPlaybackTimer timer;
timer.Start(0, 1, 1.0 / 30.0);
ViewerPlaybackTimer timer;
timer.Start(0, 1, 1.0 / 30.0);
std::vector<std::thread> threads;
std::atomic<int> success_count{0};
std::vector<std::thread> threads;
std::atomic<int> success_count{ 0 };
for (int t = 0; t < num_threads; ++t) {
threads.emplace_back([&timer, &success_count, num_iterations]() {
for (int i = 0; i < num_iterations; ++i) {
int64_t ts = timer.GetTimestampNow();
if (ts >= 0) {
success_count++;
}
}
});
}
for (int t = 0; t < num_threads; ++t) {
threads.emplace_back([&timer, &success_count, num_iterations]() {
for (int i = 0; i < num_iterations; ++i) {
int64_t ts = timer.GetTimestampNow();
if (ts >= 0) {
success_count++;
}
}
});
}
for (auto &t : threads) {
t.join();
}
for (auto &t : threads) {
t.join();
}
EXPECT_EQ(success_count.load(), num_threads * num_iterations);
EXPECT_EQ(success_count.load(), num_threads * num_iterations);
}
TEST(ViewerSmokeThread, ConcurrentQueueAccess)
{
const int num_threads = 4;
const int num_frames_per_thread = 25;
const int num_threads = 4;
const int num_frames_per_thread = 25;
ViewerQueue queue;
std::vector<std::thread> threads;
std::atomic<int> append_count{0};
ViewerQueue queue;
std::vector<std::thread> threads;
std::atomic<int> append_count{ 0 };
for (int t = 0; t < num_threads; ++t) {
threads.emplace_back([&queue, &append_count, t, num_frames_per_thread]() {
for (int i = 0; i < num_frames_per_thread; ++i) {
ViewerPlaybackFrame frame{rational(t * num_frames_per_thread + i, 24), QVariant()};
queue.AppendTimewise(frame, 1);
append_count++;
}
});
}
for (int t = 0; t < num_threads; ++t) {
threads.emplace_back(
[&queue, &append_count, t, num_frames_per_thread]() {
for (int i = 0; i < num_frames_per_thread; ++i) {
ViewerPlaybackFrame frame{
rational(t * num_frames_per_thread + i, 24), QVariant()
};
queue.AppendTimewise(frame, 1);
append_count++;
}
});
}
for (auto &t : threads) {
t.join();
}
for (auto &t : threads) {
t.join();
}
EXPECT_EQ(append_count.load(), num_threads * num_frames_per_thread);
EXPECT_EQ(queue.size(), num_threads * num_frames_per_thread);
EXPECT_EQ(append_count.load(), num_threads * num_frames_per_thread);
EXPECT_EQ(queue.size(), num_threads * num_frames_per_thread);
}
// ============================================================================
@@ -515,70 +521,70 @@ TEST(ViewerSmokeThread, ConcurrentQueueAccess)
TEST(ViewerSmokeIntegration, PlaybackSequenceSimulation)
{
// Simulate a basic playback sequence
ViewerPlaybackTimer timer;
ViewerQueue queue;
// Simulate a basic playback sequence
ViewerPlaybackTimer timer;
ViewerQueue queue;
// Start playback at frame 0, 24fps
timer.Start(0, 1, 1.0 / 24.0);
// Start playback at frame 0, 24fps
timer.Start(0, 1, 1.0 / 24.0);
// Queue some frames
for (int i = 0; i < 10; i++) {
ViewerPlaybackFrame frame{rational(i, 24), QVariant(i)};
queue.AppendTimewise(frame, 1);
}
// Queue some frames
for (int i = 0; i < 10; i++) {
ViewerPlaybackFrame frame{ rational(i, 24), QVariant(i) };
queue.AppendTimewise(frame, 1);
}
// Get current timestamp
int64_t current_ts = timer.GetTimestampNow();
// Get current timestamp
int64_t current_ts = timer.GetTimestampNow();
// Find frame closest to current time
rational current_time(current_ts, 1);
bool found = false;
for (const auto &frame : queue) {
if (frame.timestamp >= current_time) {
found = true;
break;
}
}
// Find frame closest to current time
rational current_time(current_ts, 1);
bool found = false;
for (const auto &frame : queue) {
if (frame.timestamp >= current_time) {
found = true;
break;
}
}
// Should have frames available
EXPECT_FALSE(queue.empty());
// Should have frames available
EXPECT_FALSE(queue.empty());
}
TEST(ViewerSmokeIntegration, SafeMarginWithDifferentAspectRatios)
{
// Test safe margins for different aspect ratios
std::vector<double> ratios = {0.9, 0.85, 0.8, 0.7};
// Test safe margins for different aspect ratios
std::vector<double> ratios = { 0.9, 0.85, 0.8, 0.7 };
for (double ratio : ratios) {
ViewerSafeMarginInfo info(true, ratio);
EXPECT_TRUE(info.is_enabled());
EXPECT_TRUE(info.custom_ratio());
EXPECT_DOUBLE_EQ(info.ratio(), ratio);
}
for (double ratio : ratios) {
ViewerSafeMarginInfo info(true, ratio);
EXPECT_TRUE(info.is_enabled());
EXPECT_TRUE(info.custom_ratio());
EXPECT_DOUBLE_EQ(info.ratio(), ratio);
}
}
TEST(ViewerSmokeIntegration, ReversePlaybackScenario)
{
ViewerPlaybackTimer timer;
ViewerQueue queue;
ViewerPlaybackTimer timer;
ViewerQueue queue;
// Start reverse playback from frame 100
timer.Start(100, -1, 1.0 / 24.0);
// Start reverse playback from frame 100
timer.Start(100, -1, 1.0 / 24.0);
// Queue frames in reverse order
for (int i = 100; i >= 90; i--) {
ViewerPlaybackFrame frame{rational(i, 24), QVariant(i)};
queue.AppendTimewise(frame, -1);
}
// Queue frames in reverse order
for (int i = 100; i >= 90; i--) {
ViewerPlaybackFrame frame{ rational(i, 24), QVariant(i) };
queue.AppendTimewise(frame, -1);
}
// Get timestamps - should decrease
int64_t ts1 = timer.GetTimestampNow();
QThread::msleep(50);
int64_t ts2 = timer.GetTimestampNow();
// Get timestamps - should decrease
int64_t ts1 = timer.GetTimestampNow();
QThread::msleep(50);
int64_t ts2 = timer.GetTimestampNow();
EXPECT_LT(ts2, ts1);
EXPECT_EQ(queue.front().timestamp, rational(100, 24));
EXPECT_LT(ts2, ts1);
EXPECT_EQ(queue.front().timestamp, rational(100, 24));
}
} // namespace test