Files
rtabmap/corelib/test/test_statistics.cpp
matlabbe ee49beaf4f Adding doc and tests (#1492)
* added doc and tests for util2d.h

* updated cmake-ros ci

* Added util3d.h doc and tests

* util3d_transforms.h: Added doc and tests

* util3d_filtering.h: started doc and test

* util3d_filtering.h: more tests and doc

* Added more doc/tests

* finished util3d_filtering doc and tests

* added test for util2d::depthBleedingFiltering

* Added util3d_registration tests

* Added util3d_features.h doc/tests

* added doc/tests for util3d_correspondences.h

* added doc/gtest for util3d_mapping.h (missing hpp functions)

* finished testing util3d_mapping.hpp

* Added util3d_motion_estimation.h tests (2D->3D done)

* finished util3d_motion_estimation.h tests

* minimal util3d_surface.h

* Added Transform and VisualWord tests

* Added doc for CameraModel and StereoCameraModel

* Added more logs in ros ci

* Passing tests on fical

* improved all devcontainer

* added devcontainer kilted, fixed source setup.bash, removed ldconfig in ros-cmake workflow

* cleanup

* source ros

* Added utilite tests

* Added testing to appveyor, github actions cancellable on re-commit on same branch

* appveyor testing without all targets

* appveyor: specifying ALL_BUILD target

* Fixed Util2dTest.NMSImageBoundsRespected test

* Fixing PCL Indices error on old pcl

* Added VWDictionary tests and doc. Fixed LSH not working (fix from https://github.com/flann-lib/flann/pull/472

* fixing some appveyor CI errors, added test to check dictionary serialization against all type

* Added StereoDense, StereoBM and StereoSGBM doc and tests

* Added Stereo tests

* Added CameraModel and StereoCameraModel tests

* Added doc and test for Statistics

* Added doc/tests for Signature

* Added doc/test for SensorEvent, added doc for SensorCaptureInfo

* Added doc to SensorData

* Added SensorData tests

* Added SensorCapture and SensorCaptureThread doc and tests

* fixed sensordata test

* updated SSC test and doc

* Added doc and tests for BayesFilter class

* Enabled testing on mac, updated windows testing like on linux

* added test_link

* fixed unresolved on windows

* fixed ThreadHandle error on macos ci

* Added GPS and GeodeticCoords tests

* Added tests for compression

* Added Odometry tests (base class only)

* Added DBDriver tests

* Added coverage report

* uniformized test names

* fixing concurancy and coverage ci

* dont built tools, examples and app for coverage build

* fixed report tool rebuilt without qt compilation error

* updated coverage option

* updated coverage config

* added doc CI job

* fixing windows and mac ci errors

* Added DBDriverSqlite3 tests

* Added IMU tests

* Added Graph tests

* fixing flaky macos test

* Added IMUThread and IMUFilter tests

* Added Landmarks tests

* Added LASWriter tests

* fixing seed flaky test

* fixing flaky macos timing tests

* Added LocalGrid tests

* Added LocalGridMaker tests

* fixing ci errors

* Added GlobalMap tests

* Added doc for EnvSensor

* Added Features2D tests

* Added Registration tests

* Added RegistrationVis tests

* Added doc for Rtabmap and Memory classes

* Added Memory and Rtabmap tests

* making some tests less flaky

* lcov 1.14 support

* updated compatible tool arguments

* Added integration tests (RGB-D, Stereo, Lidar2d, Lidar3d)

* More octomap checks

* Refactored how/when python interpretor is created to simplify library usage

* Added python tests

* fixed some flaky tests

* suppressed some third party related warnings

* fixed ceres tests

* more flaky fixes

* Fixing tests without libpointmatcher

* Added RANSAC rejection filter to PCL ICP

* fixing multi platform flakiness

* Added test to detect regression

* Fixing windows pcl link error

* fixed some macos flakiness

* bigger 2D2D registration error on opencv 4.6.0

* flakiness

* fixing flaky tests on windows and mac

* flaky thread test on slow mac VM

* windows slow test

* fixing more ci erros

* fxing temp dir on windows

* Added Optimizer tests and discovered some bugs (fixed)

* fixing flaky tests in mac and windows

* Added Optimizer doc

* Added GTSAM BA, updated Ceres to use g2o ba parameters. Renamed g2o's ba related parameters to Optimizer group and used by both gtsam and ceres.

* fixing build without gtsam

* fixing home dir

* fixing python ci isssues

* Added multicam ba tests

* Added Ceres multicam BA support

* Aligned BundleAdjustment parameters with Optimizer/Strategy to avoid confusion in the code

* Added BA integration test

* Added robust graph optimization integration test

* Added loop3it test

* Added stereo20Hz test

* Added smartfactor gtsam

* Fixed bugged check and warn if python didn't return any descriptors

* Fixing gtsam version build issues

* fixing tilt on windows ci

* loosing ceres integration test for ci

* mac ci flakiness

* updating missing param in gui

* updating test bound for mac

* added appearance-based tests, set min gftt quality to quality level

* testing more stuff

* improving features2d tests

* ci flakiness

* fixing flaky ci

* ci fixes

* flaky fixes

* Added RegistrationIcp tests

* Added icp integration test with real-worl corridor like env

* intermediate nodes

* fixing enum

* Updated test to catch #1714

* Fixed 2d corridor failing on pcl

* flaky pnp test

* flaky brisk test

* Set rtabmap_integration test as long

* updating loop closure test

* flaky ci tests

* TEsting roundtrip g2o/toro save/load

* loosing test bound

* fixed cuda capable checks

* flaky tests

* Debugging test hanging

* more debugging stuff

* updating limit

* windows: disabled cuda on ci to avoid incompatible driver issue. Fixing a bad test mem allocation

* trying fixing cuda hanging issue

* fixing ci flakyness

* flaky tests

* Updated BOW flaky tests by checking min precision/recall instead of recall@100precision. Fixed signature test

* CameraModel::load() test initRectificationMap param

* test dbdriver load dictionary idsOnly

* Memory: test keepLinkedInDb param

* added dummyDictionary tests

* test intermediate nodes count

* Added MarkerDetector tests

* reverted breaking change of UMutex and USemaphore

* Features2d: fixed compiltion warnings with clang about override

* clang warnings

* fixing test build with pcl 1.8

* g2o and gtsam build errors on android

* opencv5 test fixes

* disabled testing for ios and android builds

* normalized endline characters for easier diff

* added LF CRLF rule

* bump 0.23.10. fixing doc version

* Publish rtabmap website doc from ci

* fixing MSCVC build error

* macos icp flaky test

* fixing ceres macos test bound

* ficing more flaky tests

* fixing opencv5 related test errors. Also fixed an actual bug in ENU_WGS84ToGeocentric_WGS84()

* added comment about mrpt change

* removed rosdoc2 (will add it for rtabmap_ros later)

* fixing website style

* updated download links

* locally deployable website with api

* sweep doxygen issues

* improved/revised doxygen main pages

* removed examples empty page

* Updated doxygen style

* more concise doxygen groups

* added api link on main readme

* fixing utilite test error

* fixing CommonFilteringGroundNormalsUp test

* updated precisionRecall test bounds for Freak and brief descriptors

* fixing scale check in ba tests

* disabled tests on windows cuda build (missing dlls amd runner cannot test cuda anyway)

* ceres: missing suitesparse dep in windows ci

* adjusting recall thr for fast/freak

* ficing more flaky tests

* fixing flaky tests

* disabled coverage in ros ci

* Enable integration tests for ros ci jobs

* loosing up some threshold for failing tests

* trigger cache

* fixing test data in ros ci. Updated flaky test for mac

* slaking some test limit

* Fixed rtabmap-detectMoreLoopClosures inverted output value

* loosing up sift recall on mac

* optimizer re-ordered distribution for reproducible results (mac g2o)

* macos dump test crash log

* combining all tests to save time on shared library reload. Also fixed Logs with missing arguments.

* Added ENABLE_FORMAT_ERRORS cmake option

* do test only one time

* fixed all format warnings

* format security android build errors

* less verbose tests

* updated ImuUThread test

* fixed a log

* Fixed libpointmatcher 2d normals eigen issue

* Fixing libpointmatcher conversion issues

* fixing libpointmatcher test on windows ci

* cleanup comments, relax some test thr

* disabled sequoia-intel ci build (too flaky, would need extensive testing directly on that machine)
2026-08-06 13:32:20 -07:00

673 lines
18 KiB
C++

#include <gtest/gtest.h>
#include <rtabmap/core/Statistics.h>
#include <rtabmap/core/Signature.h>
#include <rtabmap/core/Link.h>
#include <rtabmap/core/Transform.h>
#include <cmath>
using namespace rtabmap;
// Constructor Tests
TEST(StatisticsTest, DefaultConstructor)
{
Statistics stats;
EXPECT_FALSE(stats.extended());
EXPECT_EQ(stats.refImageId(), 0);
EXPECT_EQ(stats.refImageMapId(), -1);
EXPECT_EQ(stats.loopClosureId(), 0);
EXPECT_EQ(stats.loopClosureMapId(), -1);
EXPECT_EQ(stats.proximityDetectionId(), 0);
EXPECT_EQ(stats.proximityDetectionMapId(), -1);
EXPECT_DOUBLE_EQ(stats.stamp(), 0.0);
EXPECT_EQ(stats.currentGoalId(), 0);
EXPECT_TRUE(stats.data().empty());
EXPECT_TRUE(stats.getSignaturesData().empty());
EXPECT_TRUE(stats.poses().empty());
EXPECT_TRUE(stats.constraints().empty());
}
// Static Methods Tests
TEST(StatisticsTest, DefaultData)
{
// Create a Statistics object to initialize default data
Statistics stats;
const auto& defaultData = Statistics::defaultData();
// Should contain all predefined statistics
EXPECT_FALSE(defaultData.empty());
// Check some known statistics exist
EXPECT_NE(defaultData.find(Statistics::kTimingTotal()), defaultData.end());
EXPECT_NE(defaultData.find(Statistics::kLoopId()), defaultData.end());
EXPECT_NE(defaultData.find(Statistics::kMemoryWorking_memory_size()), defaultData.end());
// All default values should be 0.0
for(const auto& pair : defaultData)
{
EXPECT_FLOAT_EQ(pair.second, 0.0f) << "Statistic: " << pair.first;
}
}
TEST(StatisticsTest, SerializeData)
{
std::map<std::string, float> data;
data["Timing/Total/ms"] = 500.0f;
data["Loop/Id/"] = 42.0f;
data["Memory/Working_memory_size/"] = 100.0f;
std::string serialized = Statistics::serializeData(data);
// Should contain all keys and values
EXPECT_NE(serialized.find("Timing/Total/ms:500"), std::string::npos);
EXPECT_NE(serialized.find("Loop/Id/:42"), std::string::npos);
EXPECT_NE(serialized.find("Memory/Working_memory_size/:100"), std::string::npos);
// Should use semicolons as separators
EXPECT_NE(serialized.find(";"), std::string::npos);
// Should use dots for decimal separators (not commas)
data["Test/Value/"] = 3.14159f;
serialized = Statistics::serializeData(data);
EXPECT_NE(serialized.find("3.14159"), std::string::npos);
EXPECT_EQ(serialized.find("3,14159"), std::string::npos);
}
TEST(StatisticsTest, SerializeDataEmpty)
{
std::map<std::string, float> emptyData;
std::string serialized = Statistics::serializeData(emptyData);
EXPECT_TRUE(serialized.empty());
}
TEST(StatisticsTest, DeserializeData)
{
std::string serialized = "Timing/Total/ms:500.0;Loop/Id/:42;Memory/Working_memory_size/:100.5";
auto deserialized = Statistics::deserializeData(serialized);
EXPECT_EQ(deserialized.size(), 3u);
EXPECT_FLOAT_EQ(deserialized["Timing/Total/ms"], 500.0f);
EXPECT_FLOAT_EQ(deserialized["Loop/Id/"], 42.0f);
EXPECT_FLOAT_EQ(deserialized["Memory/Working_memory_size/"], 100.5f);
}
TEST(StatisticsTest, DeserializeDataEmpty)
{
auto deserialized = Statistics::deserializeData("");
EXPECT_TRUE(deserialized.empty());
}
TEST(StatisticsTest, DeserializeDataInvalid)
{
// Invalid entries should be skipped
std::string serialized = "Valid/Key/:123.0;InvalidEntry;Another/Valid/:456.0;MissingColon";
auto deserialized = Statistics::deserializeData(serialized);
EXPECT_EQ(deserialized.size(), 2u);
EXPECT_FLOAT_EQ(deserialized["Valid/Key/"], 123.0f);
EXPECT_FLOAT_EQ(deserialized["Another/Valid/"], 456.0f);
}
TEST(StatisticsTest, SerializeDeserializeRoundTrip)
{
std::map<std::string, float> original;
original["Timing/Total/ms"] = 500.0f;
original["Loop/Id/"] = 42.0f;
original["Memory/Working_memory_size/"] = 100.5f;
original["Test/Float/"] = 3.14159f;
original["Test/Negative/"] = -10.5f;
std::string serialized = Statistics::serializeData(original);
auto deserialized = Statistics::deserializeData(serialized);
EXPECT_EQ(deserialized.size(), original.size());
for(const auto& pair : original)
{
EXPECT_NE(deserialized.find(pair.first), deserialized.end());
EXPECT_FLOAT_EQ(deserialized[pair.first], pair.second);
}
}
// addStatistic Tests
TEST(StatisticsTest, AddStatistic)
{
Statistics stats;
stats.addStatistic("Timing/Total/ms", 500.0f);
stats.addStatistic("Loop/Id/", 42.0f);
const auto& data = stats.data();
EXPECT_EQ(data.size(), 2u);
EXPECT_FLOAT_EQ(data.at("Timing/Total/ms"), 500.0f);
EXPECT_FLOAT_EQ(data.at("Loop/Id/"), 42.0f);
}
TEST(StatisticsTest, AddStatisticOverwrite)
{
Statistics stats;
stats.addStatistic("Timing/Total/ms", 500.0f);
stats.addStatistic("Timing/Total/ms", 750.0f); // Overwrite
const auto& data = stats.data();
EXPECT_EQ(data.size(), 1u);
EXPECT_FLOAT_EQ(data.at("Timing/Total/ms"), 750.0f);
}
TEST(StatisticsTest, AddStatisticWithRTABMAP_STATS)
{
Statistics stats;
// Use the generated static methods
stats.addStatistic(Statistics::kTimingTotal(), 500.0f);
stats.addStatistic(Statistics::kLoopId(), 42.0f);
stats.addStatistic(Statistics::kMemoryWorking_memory_size(), 100.0f);
const auto& data = stats.data();
EXPECT_EQ(data.size(), 3u);
EXPECT_FLOAT_EQ(data.at(Statistics::kTimingTotal()), 500.0f);
EXPECT_FLOAT_EQ(data.at(Statistics::kLoopId()), 42.0f);
EXPECT_FLOAT_EQ(data.at(Statistics::kMemoryWorking_memory_size()), 100.0f);
}
// Extended Mode Tests
TEST(StatisticsTest, ExtendedMode)
{
Statistics stats;
EXPECT_FALSE(stats.extended());
stats.setExtended(true);
EXPECT_TRUE(stats.extended());
stats.setExtended(false);
EXPECT_FALSE(stats.extended());
}
// Setter/Getter Tests
TEST(StatisticsTest, RefImageId)
{
Statistics stats;
stats.setRefImageId(123);
EXPECT_EQ(stats.refImageId(), 123);
stats.setRefImageId(456);
EXPECT_EQ(stats.refImageId(), 456);
}
TEST(StatisticsTest, RefImageMapId)
{
Statistics stats;
stats.setRefImageMapId(1);
EXPECT_EQ(stats.refImageMapId(), 1);
stats.setRefImageMapId(-1);
EXPECT_EQ(stats.refImageMapId(), -1);
}
TEST(StatisticsTest, LoopClosureId)
{
Statistics stats;
stats.setLoopClosureId(789);
EXPECT_EQ(stats.loopClosureId(), 789);
stats.setLoopClosureId(0);
EXPECT_EQ(stats.loopClosureId(), 0);
}
TEST(StatisticsTest, LoopClosureMapId)
{
Statistics stats;
stats.setLoopClosureMapId(2);
EXPECT_EQ(stats.loopClosureMapId(), 2);
stats.setLoopClosureMapId(-1);
EXPECT_EQ(stats.loopClosureMapId(), -1);
}
TEST(StatisticsTest, ProximityDetectionId)
{
Statistics stats;
stats.setProximityDetectionId(101);
EXPECT_EQ(stats.proximityDetectionId(), 101);
}
TEST(StatisticsTest, ProximityDetectionMapId)
{
Statistics stats;
stats.setProximityDetectionMapId(3);
EXPECT_EQ(stats.proximityDetectionMapId(), 3);
}
TEST(StatisticsTest, Stamp)
{
Statistics stats;
stats.setStamp(12345.678);
EXPECT_DOUBLE_EQ(stats.stamp(), 12345.678);
stats.setStamp(0.0);
EXPECT_DOUBLE_EQ(stats.stamp(), 0.0);
}
// Signature Data Tests
TEST(StatisticsTest, AddSignatureData)
{
Statistics stats;
Signature sig1(1, 0, 0, 100.0);
Signature sig2(2, 0, 0, 200.0);
stats.addSignatureData(sig1);
stats.addSignatureData(sig2);
const auto& signatures = stats.getSignaturesData();
EXPECT_EQ(signatures.size(), 2u);
EXPECT_NE(signatures.find(1), signatures.end());
EXPECT_NE(signatures.find(2), signatures.end());
EXPECT_EQ(signatures.at(1).id(), 1);
EXPECT_EQ(signatures.at(2).id(), 2);
}
TEST(StatisticsTest, AddSignatureDataOverwrite)
{
Statistics stats;
Signature sig1(1, 0, 0, 100.0);
Signature sig2(1, 0, 0, 200.0); // Same ID
stats.addSignatureData(sig1);
stats.addSignatureData(sig2); // Should overwrite
const auto& signatures = stats.getSignaturesData();
EXPECT_EQ(signatures.size(), 1u);
EXPECT_DOUBLE_EQ(signatures.at(1).getStamp(), 200.0);
}
TEST(StatisticsTest, SetSignaturesData)
{
Statistics stats;
std::map<int, Signature> sigs;
sigs[1] = Signature(1, 0, 0, 100.0);
sigs[2] = Signature(2, 0, 0, 200.0);
sigs[3] = Signature(3, 0, 0, 300.0);
stats.setSignaturesData(sigs);
const auto& signatures = stats.getSignaturesData();
EXPECT_EQ(signatures.size(), 3u);
EXPECT_NE(signatures.find(1), signatures.end());
EXPECT_NE(signatures.find(2), signatures.end());
EXPECT_NE(signatures.find(3), signatures.end());
}
TEST(StatisticsTest, GetLastSignatureData)
{
Statistics stats;
// Empty should return dummy
const auto& empty = stats.getLastSignatureData();
EXPECT_EQ(empty.id(), 0);
Signature sig1(1, 0, 0, 100.0);
Signature sig2(2, 0, 0, 200.0);
Signature sig3(3, 0, 0, 300.0);
stats.addSignatureData(sig1);
stats.addSignatureData(sig2);
stats.addSignatureData(sig3);
// Should return the last one (highest ID)
const auto& last = stats.getLastSignatureData();
EXPECT_EQ(last.id(), 3);
EXPECT_DOUBLE_EQ(last.getStamp(), 300.0);
}
// Poses and Constraints Tests
TEST(StatisticsTest, SetPoses)
{
Statistics stats;
std::map<int, Transform> poses;
poses[1] = Transform(1.0f, 0.0f, 0.0f, 0, 0, 0);
poses[2] = Transform(2.0f, 0.0f, 0.0f, 0, 0, 0);
poses[3] = Transform(3.0f, 0.0f, 0.0f, 0, 0, 0);
stats.setPoses(poses);
const auto& retrievedPoses = stats.poses();
EXPECT_EQ(retrievedPoses.size(), 3u);
EXPECT_NE(retrievedPoses.find(1), retrievedPoses.end());
EXPECT_NE(retrievedPoses.find(2), retrievedPoses.end());
EXPECT_NE(retrievedPoses.find(3), retrievedPoses.end());
EXPECT_FLOAT_EQ(retrievedPoses.at(1).x(), 1.0f);
EXPECT_FLOAT_EQ(retrievedPoses.at(2).x(), 2.0f);
EXPECT_FLOAT_EQ(retrievedPoses.at(3).x(), 3.0f);
}
TEST(StatisticsTest, SetConstraints)
{
Statistics stats;
std::multimap<int, Link> constraints;
constraints.insert(std::make_pair(1, Link(1, 2, Link::kNeighbor, Transform::getIdentity())));
constraints.insert(std::make_pair(1, Link(1, 3, Link::kNeighbor, Transform::getIdentity())));
constraints.insert(std::make_pair(2, Link(2, 3, Link::kGlobalClosure, Transform::getIdentity())));
stats.setConstraints(constraints);
const auto& retrievedConstraints = stats.constraints();
EXPECT_EQ(retrievedConstraints.size(), 3u);
// Count constraints for node 1
auto range = retrievedConstraints.equal_range(1);
int count = std::distance(range.first, range.second);
EXPECT_EQ(count, 2);
}
// Transform Tests
TEST(StatisticsTest, MapCorrection)
{
Statistics stats;
Transform correction(1.0f, 2.0f, 3.0f, 0, 0, 0);
stats.setMapCorrection(correction);
const auto& retrieved = stats.mapCorrection();
EXPECT_FLOAT_EQ(retrieved.x(), 1.0f);
EXPECT_FLOAT_EQ(retrieved.y(), 2.0f);
EXPECT_FLOAT_EQ(retrieved.z(), 3.0f);
}
TEST(StatisticsTest, LoopClosureTransform)
{
Statistics stats;
Transform transform(0.5f, 0.5f, 0.5f, 0, 0, 0);
stats.setLoopClosureTransform(transform);
const auto& retrieved = stats.loopClosureTransform();
EXPECT_FLOAT_EQ(retrieved.x(), 0.5f);
EXPECT_FLOAT_EQ(retrieved.y(), 0.5f);
EXPECT_FLOAT_EQ(retrieved.z(), 0.5f);
}
TEST(StatisticsTest, LocalizationCovariance)
{
Statistics stats;
cv::Mat covariance = cv::Mat::eye(6, 6, CV_64FC1) * 0.1;
stats.setLocalizationCovariance(covariance);
const auto& retrieved = stats.localizationCovariance();
EXPECT_FALSE(retrieved.empty());
EXPECT_EQ(retrieved.rows, 6);
EXPECT_EQ(retrieved.cols, 6);
EXPECT_DOUBLE_EQ(retrieved.at<double>(0, 0), 0.1);
}
// Labels and Weights Tests
TEST(StatisticsTest, Labels)
{
Statistics stats;
std::map<int, std::string> labels;
labels[1] = "room1";
labels[2] = "room2";
labels[3] = "corridor";
stats.setLabels(labels);
const auto& retrieved = stats.labels();
EXPECT_EQ(retrieved.size(), 3u);
EXPECT_EQ(retrieved.at(1), "room1");
EXPECT_EQ(retrieved.at(2), "room2");
EXPECT_EQ(retrieved.at(3), "corridor");
}
TEST(StatisticsTest, Weights)
{
Statistics stats;
std::map<int, int> weights;
weights[1] = 10;
weights[2] = 20;
weights[3] = 30;
stats.setWeights(weights);
const auto& retrieved = stats.weights();
EXPECT_EQ(retrieved.size(), 3u);
EXPECT_EQ(retrieved.at(1), 10);
EXPECT_EQ(retrieved.at(2), 20);
EXPECT_EQ(retrieved.at(3), 30);
}
// Likelihood and Posterior Tests
TEST(StatisticsTest, Likelihood)
{
Statistics stats;
std::map<int, float> likelihood;
likelihood[1] = 0.8f;
likelihood[2] = 0.6f;
likelihood[3] = 0.4f;
stats.setLikelihood(likelihood);
const auto& retrieved = stats.likelihood();
EXPECT_EQ(retrieved.size(), 3u);
EXPECT_FLOAT_EQ(retrieved.at(1), 0.8f);
EXPECT_FLOAT_EQ(retrieved.at(2), 0.6f);
EXPECT_FLOAT_EQ(retrieved.at(3), 0.4f);
}
TEST(StatisticsTest, RawLikelihood)
{
Statistics stats;
std::map<int, float> rawLikelihood;
rawLikelihood[1] = 100.0f;
rawLikelihood[2] = 50.0f;
stats.setRawLikelihood(rawLikelihood);
const auto& retrieved = stats.rawLikelihood();
EXPECT_EQ(retrieved.size(), 2u);
EXPECT_FLOAT_EQ(retrieved.at(1), 100.0f);
EXPECT_FLOAT_EQ(retrieved.at(2), 50.0f);
}
TEST(StatisticsTest, Posterior)
{
Statistics stats;
std::map<int, float> posterior;
posterior[1] = 0.9f;
posterior[2] = 0.1f;
stats.setPosterior(posterior);
const auto& retrieved = stats.posterior();
EXPECT_EQ(retrieved.size(), 2u);
EXPECT_FLOAT_EQ(retrieved.at(1), 0.9f);
EXPECT_FLOAT_EQ(retrieved.at(2), 0.1f);
}
// Path and Goal Tests
TEST(StatisticsTest, LocalPath)
{
Statistics stats;
std::vector<int> path = {1, 2, 3, 4, 5};
stats.setLocalPath(path);
const auto& retrieved = stats.localPath();
EXPECT_EQ(retrieved.size(), 5u);
EXPECT_EQ(retrieved[0], 1);
EXPECT_EQ(retrieved[1], 2);
EXPECT_EQ(retrieved[2], 3);
EXPECT_EQ(retrieved[3], 4);
EXPECT_EQ(retrieved[4], 5);
}
TEST(StatisticsTest, CurrentGoalId)
{
Statistics stats;
stats.setCurrentGoalId(42);
EXPECT_EQ(stats.currentGoalId(), 42);
stats.setCurrentGoalId(0);
EXPECT_EQ(stats.currentGoalId(), 0);
}
// Reduced IDs Tests
TEST(StatisticsTest, ReducedIds)
{
Statistics stats;
std::map<int, int> reducedIds;
reducedIds[100] = 1;
reducedIds[200] = 2;
reducedIds[300] = 3;
stats.setReducedIds(reducedIds);
const auto& retrieved = stats.reducedIds();
EXPECT_EQ(retrieved.size(), 3u);
EXPECT_EQ(retrieved.at(100), 1);
EXPECT_EQ(retrieved.at(200), 2);
EXPECT_EQ(retrieved.at(300), 3);
}
// Working Memory State Tests
TEST(StatisticsTest, WmState)
{
Statistics stats;
std::vector<int> wmState = {10, 20, 30, 40};
stats.setWmState(wmState);
const auto& retrieved = stats.wmState();
EXPECT_EQ(retrieved.size(), 4u);
EXPECT_EQ(retrieved[0], 10);
EXPECT_EQ(retrieved[1], 20);
EXPECT_EQ(retrieved[2], 30);
EXPECT_EQ(retrieved[3], 40);
}
// Odometry Cache Tests
TEST(StatisticsTest, OdomCachePoses)
{
Statistics stats;
std::map<int, Transform> odomPoses;
odomPoses[1] = Transform(1.0f, 0.0f, 0.0f, 0, 0, 0);
odomPoses[2] = Transform(2.0f, 0.0f, 0.0f, 0, 0, 0);
stats.setOdomCachePoses(odomPoses);
const auto& retrieved = stats.odomCachePoses();
EXPECT_EQ(retrieved.size(), 2u);
EXPECT_FLOAT_EQ(retrieved.at(1).x(), 1.0f);
EXPECT_FLOAT_EQ(retrieved.at(2).x(), 2.0f);
}
TEST(StatisticsTest, OdomCacheConstraints)
{
Statistics stats;
std::multimap<int, Link> odomConstraints;
odomConstraints.insert(std::make_pair(1, Link(1, 2, Link::kNeighbor, Transform::getIdentity())));
odomConstraints.insert(std::make_pair(2, Link(2, 3, Link::kNeighbor, Transform::getIdentity())));
stats.setOdomCacheConstraints(odomConstraints);
const auto& retrieved = stats.odomCacheConstraints();
EXPECT_EQ(retrieved.size(), 2u);
}
// Comprehensive Test
TEST(StatisticsTest, ComprehensiveUsage)
{
Statistics stats;
// Set basic fields
stats.setExtended(true);
stats.setRefImageId(100);
stats.setRefImageMapId(1);
stats.setLoopClosureId(50);
stats.setLoopClosureMapId(1);
stats.setStamp(12345.678);
// Add statistics
stats.addStatistic(Statistics::kTimingTotal(), 500.0f);
stats.addStatistic(Statistics::kLoopId(), 50.0f);
stats.addStatistic(Statistics::kMemoryWorking_memory_size(), 100.0f);
// Add signature data
Signature sig(100, 1, 0, 12345.678);
stats.addSignatureData(sig);
// Set poses
std::map<int, Transform> poses;
poses[100] = Transform(1.0f, 2.0f, 3.0f, 0, 0, 0);
stats.setPoses(poses);
// Set constraints
std::multimap<int, Link> constraints;
constraints.insert(std::make_pair(100, Link(100, 50, Link::kGlobalClosure, Transform::getIdentity())));
stats.setConstraints(constraints);
// Set transforms
stats.setMapCorrection(Transform(0.1f, 0.2f, 0.3f, 0, 0, 0));
stats.setLoopClosureTransform(Transform(0.5f, 0.5f, 0.5f, 0, 0, 0));
// Set likelihood and posterior
std::map<int, float> likelihood;
likelihood[50] = 0.9f;
stats.setLikelihood(likelihood);
std::map<int, float> posterior;
posterior[50] = 0.95f;
stats.setPosterior(posterior);
// Verify everything
EXPECT_TRUE(stats.extended());
EXPECT_EQ(stats.refImageId(), 100);
EXPECT_EQ(stats.loopClosureId(), 50);
EXPECT_EQ(stats.data().size(), 3u);
EXPECT_EQ(stats.getSignaturesData().size(), 1u);
EXPECT_EQ(stats.poses().size(), 1u);
EXPECT_EQ(stats.constraints().size(), 1u);
EXPECT_FLOAT_EQ(stats.likelihood().at(50), 0.9f);
EXPECT_FLOAT_EQ(stats.posterior().at(50), 0.95f);
}