101 lines
4.2 KiB
C++
101 lines
4.2 KiB
C++
// Standalone C++17 test: no Qt required.
|
|
#include "dbc_tree_builder.h"
|
|
#include <limits>
|
|
#include <stdexcept>
|
|
#include <type_traits>
|
|
|
|
static void Check(bool condition) {
|
|
if (!condition) throw std::runtime_error("Tree navigation test failed");
|
|
}
|
|
|
|
static void CheckNavigation(const TreeNode &node) {
|
|
for (std::size_t row = 0; row < node.GetChildCount(); ++row) {
|
|
const TreeNode *child = node.GetChild(row);
|
|
Check(child->GetParent() == &node && child->GetRow() == row);
|
|
Check(child->GetParent()->GetChild(child->GetRow()) == child);
|
|
CheckNavigation(*child);
|
|
}
|
|
Check(!node.GetChild(node.GetChildCount()));
|
|
Check(!node.GetChild(std::numeric_limits<std::size_t>::max()));
|
|
}
|
|
|
|
static void CheckRejectedInsertion(TreeNode &parent, std::unique_ptr<TreeNode> &owner) {
|
|
const TreeNode *original = owner.get();
|
|
bool rejected = false;
|
|
try {
|
|
parent.AddChild(std::move(owner));
|
|
} catch (const std::invalid_argument &) {
|
|
rejected = true;
|
|
}
|
|
Check(rejected && owner.get() == original);
|
|
CheckNavigation(*owner);
|
|
}
|
|
|
|
int main() {
|
|
static_assert(!std::is_copy_constructible<TreeNode>::value, "Nodes have exclusive ownership");
|
|
static_assert(!std::is_copy_assignable<TreeNode>::value, "Nodes have exclusive ownership");
|
|
static_assert(!std::is_move_constructible<TreeNode>::value, "Node addresses must be stable");
|
|
static_assert(!std::is_move_assignable<TreeNode>::value, "Node addresses must be stable");
|
|
CheckNavigation(*DbcTreeBuilder().Build(DbcDatabase()));
|
|
|
|
DbcDatabase database;
|
|
FrameInfo frame;
|
|
frame.canId = 123U;
|
|
frame.name = "Frame";
|
|
SignalInfo signal;
|
|
signal.name = "Value";
|
|
frame.signals.push_back(signal);
|
|
signal.name = "Other";
|
|
frame.signals.push_back(signal);
|
|
database.frames.push_back(frame);
|
|
frame.isExtended = true;
|
|
database.frames.push_back(frame);
|
|
std::unique_ptr<TreeNode> root = DbcTreeBuilder().Build(database);
|
|
Check(root->GetParent() == nullptr && root->GetRow() == 0);
|
|
Check(!root->GetFrameKey() && !root->GetSignalKey());
|
|
root->AddChild(nullptr);
|
|
Check(root->GetChildCount() == 2 && !root->GetChild(2));
|
|
Check(!root->GetChild(std::numeric_limits<std::size_t>::max()));
|
|
CheckNavigation(*root);
|
|
|
|
const TreeNode *firstFrame = root->GetChild(0);
|
|
const TreeNode *firstSignal = firstFrame->GetChild(0);
|
|
const FrameKey standard(123U, false);
|
|
const FrameKey extended(123U, true);
|
|
Check(firstFrame->GetFrameKey() == standard && !firstFrame->GetSignalKey());
|
|
Check(firstSignal->GetFrameKey() == standard);
|
|
Check(firstSignal->GetSignalKey() == SignalKey(standard, "Value"));
|
|
Check(firstFrame->GetChild(1)->GetSignalKey() == SignalKey(standard, "Other"));
|
|
Check(root->GetChild(1)->GetFrameKey() == extended);
|
|
Check(root->GetChild(1)->GetChild(0)->GetSignalKey() == SignalKey(extended, "Value"));
|
|
|
|
TreeNode detached(signal);
|
|
Check(!detached.GetFrameKey() && !detached.GetSignalKey());
|
|
Check(!detached.GetParent() && detached.GetRow() == 0);
|
|
TreeNode detachedFrame(frame);
|
|
Check(detachedFrame.GetFrameKey() == extended && !detachedFrame.GetSignalKey());
|
|
|
|
// Reordering/reloading source metadata does not change the original tree's keys.
|
|
database.frames.clear();
|
|
database.frames.push_back(frame);
|
|
std::unique_ptr<TreeNode> replacement = DbcTreeBuilder().Build(database);
|
|
Check(replacement->GetChild(0)->GetFrameKey() == root->GetChild(1)->GetFrameKey());
|
|
Check(firstSignal->GetSignalKey() == SignalKey(standard, "Value"));
|
|
|
|
// Grow both child vectors, retaining all existing addresses and rows.
|
|
for (std::size_t index = 0; index < 64; ++index) {
|
|
root->AddChild(std::make_unique<TreeNode>(frame));
|
|
root->GetChild(0)->AddChild(std::make_unique<TreeNode>(signal));
|
|
}
|
|
Check(root->GetChild(0) == firstFrame && firstFrame->GetChild(0) == firstSignal);
|
|
CheckNavigation(*root);
|
|
CheckRejectedInsertion(*root, root);
|
|
CheckRejectedInsertion(*root->GetChild(0)->GetChild(0), root);
|
|
|
|
const TreeNode *original = root.get();
|
|
std::unique_ptr<TreeNode> transferred = std::move(root);
|
|
Check(!root && transferred.get() == original);
|
|
CheckNavigation(*transferred);
|
|
Check(firstSignal->GetSignalKey() == SignalKey(standard, "Value"));
|
|
}
|