Improved test coverage for this branch

This commit is contained in:
matlabbe
2026-10-03 15:40:25 -07:00
parent 3107470788
commit 41497e19bf
4 changed files with 88 additions and 39 deletions
+31
View File
@@ -1,5 +1,6 @@
#include <gtest/gtest.h>
#include <rtabmap/core/Compression.h>
#include <rtabmap/utilite/UException.h>
#include <opencv2/core.hpp>
#include <cstring>
#include <limits>
@@ -380,3 +381,33 @@ TEST(CompressionTest, LegacyFloatDepthIsLossless)
EXPECT_EQ(memcmp(restored.data, depth.data, depth.total() * depth.elemSize()), 0);
}
}
TEST(CompressionTest, MalformedDepthFormatsDecodeToEmpty)
{
// Signature and header only, no payload
std::vector<unsigned char> invDepth = {'D', 'E', 'P', 'T', 'H', 'I', 'N', 'V'};
invDepth.resize(16, 0);
EXPECT_TRUE(uncompressImage(invDepth).empty());
EXPECT_EQ(compressedDepthFormat(invDepth), ".png") << "too short to be inverse depth";
// Inverse depth header followed by an 8 bits image instead of a 16 bits one
const std::vector<unsigned char> png8 = compressImage(cv::Mat(4, 4, CV_8UC1, cv::Scalar(1)), ".png");
invDepth.insert(invDepth.end(), png8.begin(), png8.end());
EXPECT_TRUE(uncompressImage(invDepth).empty());
// RVL signature without its size
const std::vector<unsigned char> rvl = {'D', 'E', 'P', 'T', 'H', 'R', 'V', 'L', 4, 0};
EXPECT_TRUE(uncompressImage(rvl).empty());
EXPECT_EQ(compressedDepthFormat(rvl), ".rvl");
EXPECT_TRUE(uncompressImage(nullptr, 0).empty());
}
TEST(CompressionTest, CompressionThreadRejectsInvalidFormat)
{
// std::string: a string literal would select the (bytes, isImage) constructor
const cv::Mat depth(4, 4, CV_32FC1, cv::Scalar(1.0f));
EXPECT_THROW(CompressionThread(depth, std::string(".jpg:10")), UException);
EXPECT_THROW(CompressionThread(depth, std::string(".bmp")), UException);
EXPECT_NO_THROW(CompressionThread(depth, std::string(".rvl:10:100")));
}
+29 -11
View File
@@ -4690,10 +4690,19 @@ TEST(MemoryTest, CreateSignatureRecompressesStereoPairAfterRectification)
namespace {
enum DepthInput
{
kRawDepth,
kCompressedDepthWithRaw, // e.g., received from ROS and decoded
kCompressedDepthOnly // raw depth not needed (no features extracted here)
};
struct InverseDepthCase
{
const char * targetVersion;
bool precompressed; // depth already compressed as inverse depth, e.g., from ROS
DepthInput input;
const char * depthCompressionFormat;
bool parallelCompression;
const char * expectedFormat;
};
@@ -4706,7 +4715,8 @@ TEST_P(MemoryInverseDepthTest, StoredDepthFormatFollowsDatabaseVersion)
const InverseDepthCase & cs = GetParam();
ParametersMap params = defaultMemoryParams();
params[Parameters::kMemBinDataKept()] = "true";
params[Parameters::kMemDepthCompressionFormat()] = ".rvl:10:100";
params[Parameters::kMemDepthCompressionFormat()] = cs.depthCompressionFormat;
params[Parameters::kMemCompressionParallelized()] = cs.parallelCompression ? "true" : "false";
params[Parameters::kDbTargetVersion()] = cs.targetVersion;
Memory memory(params);
const std::string dbPath = uniqueDbPath();
@@ -4717,15 +4727,18 @@ TEST_P(MemoryInverseDepthTest, StoredDepthFormatFollowsDatabaseVersion)
cv::randu(depth, 0.5f, 8.0f);
const CameraModel model(10.0, 10.0, 8.0, 8.0, CameraModel::opticalRotation());
SensorData data;
if(cs.precompressed)
if(cs.input == kRawDepth)
{
data = SensorData(compressImage2(rgb, ".png"), compressImage2(depth, ".png:10:100"), model);
data.uncompressData(); // raw images are also there, as when received from ROS
ASSERT_FALSE(data.depthRaw().empty());
data = SensorData(rgb, depth, model);
}
else
{
data = SensorData(rgb, depth, model);
data = SensorData(compressImage2(rgb, ".png"), compressImage2(depth, ".png:10:100"), model);
if(cs.input == kCompressedDepthWithRaw)
{
data.uncompressData();
ASSERT_FALSE(data.depthRaw().empty());
}
}
ASSERT_TRUE(memory.update(data, Transform(0, 0, 0, 0, 0, 0), cv::Mat::eye(6, 6, CV_64FC1) * 0.01));
@@ -4748,7 +4761,12 @@ INSTANTIATE_TEST_SUITE_P(
DatabaseVersions,
MemoryInverseDepthTest,
::testing::Values(
InverseDepthCase{"", false, ".rvl:10:100"},
InverseDepthCase{"", true, ".png:10:100"}, // reused as is
InverseDepthCase{"0.23.0", false, ".png"}, // legacy 32FC1 format
InverseDepthCase{"0.23.0", true, ".png"})); // re-compressed
InverseDepthCase{"", kRawDepth, ".rvl:10:100", true, ".rvl:10:100"},
InverseDepthCase{"", kRawDepth, ".rvl:10:100", false, ".rvl:10:100"},
InverseDepthCase{"", kCompressedDepthWithRaw, ".rvl:10:100", true, ".png:10:100"}, // reused as is
InverseDepthCase{"", kCompressedDepthOnly, ".rvl:10:100", true, ".png:10:100"}, // reused as is
InverseDepthCase{"0.23.0", kRawDepth, ".rvl:10:100", true, ".png"}, // legacy 32FC1 format
InverseDepthCase{"0.23.0", kCompressedDepthWithRaw, ".rvl:10:100", true, ".png"}, // re-compressed
InverseDepthCase{"0.23.0", kCompressedDepthOnly, ".rvl:10:100", true, ".png"}, // decompressed, re-compressed
InverseDepthCase{"", kRawDepth, ".rvl", true, ".png"}, // RVL is 16UC1 only: legacy
InverseDepthCase{"", kRawDepth, ".jpg", true, ".png"})); // invalid: default ".rvl"