mirror of
https://github.com/luanti-org/luanti.git
synced 2025-07-22 17:18:39 +00:00
Fix bugs in ModifySafeMap (#14276)
This commit is contained in:
parent
e9233bc169
commit
8cbd629010
3 changed files with 206 additions and 10 deletions
|
@ -9,6 +9,7 @@ set (UNITTEST_SRCS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/test_compression.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_connection.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_craft.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_datastructures.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_filesys.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_inventory.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_irrptr.cpp
|
||||
|
|
181
src/unittest/test_datastructures.cpp
Normal file
181
src/unittest/test_datastructures.cpp
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2024 sfan5
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#include "util/container.h"
|
||||
|
||||
class TestDataStructures : public TestBase
|
||||
{
|
||||
public:
|
||||
TestDataStructures() { TestManager::registerTestModule(this); }
|
||||
const char *getName() { return "TestDataStructures"; }
|
||||
|
||||
void runTests(IGameDef *gamedef);
|
||||
|
||||
void testMap1();
|
||||
void testMap2();
|
||||
void testMap3();
|
||||
void testMap4();
|
||||
void testMap5();
|
||||
};
|
||||
|
||||
static TestDataStructures g_test_instance;
|
||||
|
||||
void TestDataStructures::runTests(IGameDef *gamedef)
|
||||
{
|
||||
rawstream << "-------- ModifySafeMap" << std::endl;
|
||||
TEST(testMap1);
|
||||
TEST(testMap2);
|
||||
TEST(testMap3);
|
||||
TEST(testMap4);
|
||||
TEST(testMap5);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct TrackerState {
|
||||
bool copied = false;
|
||||
bool deleted = false;
|
||||
};
|
||||
|
||||
class Tracker {
|
||||
TrackerState *res = nullptr;
|
||||
|
||||
inline void trackDeletion() { res && (res->deleted = true); }
|
||||
|
||||
public:
|
||||
Tracker() {}
|
||||
Tracker(TrackerState &res) : res(&res) {}
|
||||
|
||||
operator bool() const { return !!res; }
|
||||
|
||||
Tracker(const Tracker &other) { *this = other; }
|
||||
Tracker &operator=(const Tracker &other) {
|
||||
trackDeletion();
|
||||
res = other.res;
|
||||
res && (res->copied = true);
|
||||
return *this;
|
||||
}
|
||||
Tracker(Tracker &&other) { *this = std::move(other); }
|
||||
Tracker &operator=(Tracker &&other) {
|
||||
trackDeletion();
|
||||
res = other.res;
|
||||
other.res = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Tracker() { trackDeletion(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void TestDataStructures::testMap1()
|
||||
{
|
||||
ModifySafeMap<int, Tracker> map;
|
||||
TrackerState t0, t1;
|
||||
|
||||
// no-copy put
|
||||
map.put(1, Tracker(t0));
|
||||
UASSERT(!t0.copied);
|
||||
UASSERT(!t0.deleted);
|
||||
|
||||
// overwrite during iter
|
||||
bool once = false;
|
||||
for (auto &it : map.iter()) {
|
||||
(void)it;
|
||||
map.put(1, Tracker(t1));
|
||||
UASSERT(t0.deleted);
|
||||
UASSERT(!t1.copied);
|
||||
UASSERT(!t1.deleted);
|
||||
if (once |= 1)
|
||||
break;
|
||||
}
|
||||
UASSERT(once);
|
||||
}
|
||||
|
||||
void TestDataStructures::testMap2()
|
||||
{
|
||||
ModifySafeMap<int, Tracker> map;
|
||||
TrackerState t0, t1;
|
||||
|
||||
// overwrite
|
||||
map.put(1, Tracker(t0));
|
||||
map.put(1, Tracker(t1));
|
||||
UASSERT(t0.deleted);
|
||||
UASSERT(!t1.copied);
|
||||
UASSERT(!t1.deleted);
|
||||
}
|
||||
|
||||
void TestDataStructures::testMap3()
|
||||
{
|
||||
ModifySafeMap<int, Tracker> map;
|
||||
TrackerState t0, t1;
|
||||
|
||||
// take
|
||||
map.put(1, Tracker(t0));
|
||||
{
|
||||
auto v = map.take(1);
|
||||
UASSERT(!t0.copied);
|
||||
UASSERT(!t0.deleted);
|
||||
}
|
||||
UASSERT(t0.deleted);
|
||||
|
||||
// remove during iter
|
||||
map.put(1, Tracker(t1));
|
||||
for (auto &it : map.iter()) {
|
||||
(void)it;
|
||||
map.remove(1);
|
||||
UASSERT(t1.deleted);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TestDataStructures::testMap4()
|
||||
{
|
||||
ModifySafeMap<int, u32> map;
|
||||
|
||||
// overwrite + take during iter
|
||||
map.put(1, 100);
|
||||
for (auto &it : map.iter()) {
|
||||
(void)it;
|
||||
map.put(1, 200);
|
||||
u32 taken = map.take(1);
|
||||
UASSERTEQ(u32, taken, 200);
|
||||
break;
|
||||
}
|
||||
|
||||
UASSERT(map.get(1) == u32());
|
||||
UASSERTEQ(size_t, map.size(), 0);
|
||||
}
|
||||
|
||||
void TestDataStructures::testMap5()
|
||||
{
|
||||
ModifySafeMap<int, u32> map;
|
||||
|
||||
// overwrite 2x during iter
|
||||
map.put(9001, 9001);
|
||||
for (auto &it : map.iter()) {
|
||||
(void)it;
|
||||
map.put(1, 100);
|
||||
map.put(1, 200);
|
||||
UASSERTEQ(u32, map.get(1), 200);
|
||||
break;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue