Add test that std::vector<icinga::String> uses move overloads

This commit is contained in:
Julian Brost 2025-03-06 11:46:48 +01:00
parent 8236d74669
commit 39ec24d638
2 changed files with 26 additions and 0 deletions

View File

@ -113,6 +113,7 @@ add_boost_test(base
base_string/replace
base_string/index
base_string/find
base_string/vector_move
base_timer/construct
base_timer/interval
base_timer/invoke

View File

@ -1,6 +1,7 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "base/string.hpp"
#include <vector>
#include <BoostTestTargetConfig.h>
using namespace icinga;
@ -101,4 +102,28 @@ BOOST_AUTO_TEST_CASE(find)
BOOST_CHECK(s.FindFirstOf("xl") == 2);
}
// Check that if a std::vector<icinga::String> is grown beyond its capacity (i.e. it has to reallocate the memory),
// it uses the move constructor of icinga::String (i.e. the underlying string storage stays the same).
BOOST_AUTO_TEST_CASE(vector_move)
{
std::vector<String> vec {
// std::string (which is internally used by icinga::String) has an optimization that small strings can be
// allocated inside it instead of in a separate heap allocation. In that case, the small string would still be
// copied even by the move constructor. Using sizeof() ensures that the string is long enough so that it must
// be allocated separately and can be used to test for the desired move to happen.
std::string(sizeof(String) + 1, 'A'),
};
void *oldAddr = vec[0].GetData().data();
// Sanity check that the data buffer is actually allocated outside the icinga::String instance.
BOOST_CHECK(!(&vec[0] <= oldAddr && oldAddr < &vec[1]));
// Force the vector to grow.
vec.reserve(vec.capacity() + 1);
// If the string was moved, the location of its underlying data buffer should not have changed.
void *newAddr = vec[0].GetData().data();
BOOST_CHECK_EQUAL(oldAddr, newAddr);
}
BOOST_AUTO_TEST_SUITE_END()