131 lines
6.1 KiB
C++
131 lines
6.1 KiB
C++
#include "zeroerr/assert.h"
|
|
#include "zeroerr/unittest.h"
|
|
|
|
#include "climbing/ClimbingAnchorAuthoring.h"
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
namespace {
|
|
|
|
eve::climbing::ClimbingAnchorBakeRequest request() {
|
|
eve::climbing::ClimbingAnchorBakeRequest value;
|
|
value.graphId = "playground.route";
|
|
value.sourceGeometryContentId = "sha256:playground-geometry";
|
|
value.settings.handSpacing = 0.4f;
|
|
value.settings.hangingFeetDrop = 1.4f;
|
|
eve::climbing::ClimbingLedgeBakeSource ledge;
|
|
ledge.id = "wall";
|
|
ledge.points = {{0.f, 2.f, 0.f}, {1.f, 2.f, 0.f}, {1.f, 2.f, 1.f}};
|
|
ledge.localNormals = {{0.f, 0.f, -1.f}, {-1.f, 0.f, 0.f}, {-1.f, 0.f, 0.f}};
|
|
ledge.tags = {"stone"};
|
|
value.ledges.push_back(std::move(ledge));
|
|
value.ladders.push_back({"ladder", {3.f, 0.3f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, -1.f}, 0.3f, 0.5f, 4, {"metal"}});
|
|
return value;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("climbing.anchorAuthoring.bakeIsCanonicalAndExecutable") {
|
|
auto first = eve::climbing::bakeClimbingAnchorGraph(request());
|
|
auto second = eve::climbing::bakeClimbingAnchorGraph(request());
|
|
REQUIRE(first.ok());
|
|
REQUIRE(second.ok());
|
|
CHECK_EQ(first.value().ledgeNodeCount, std::uint32_t(3));
|
|
CHECK_EQ(first.value().ladderNodeCount, std::uint32_t(4));
|
|
CHECK_EQ(first.value().graph.buildSettingsHash, second.value().graph.buildSettingsHash);
|
|
|
|
auto firstEncoded = eve::climbing::encodeClimbingAnchorGraphDefinition(first.value().graph);
|
|
auto secondEncoded = eve::climbing::encodeClimbingAnchorGraphDefinition(second.value().graph);
|
|
REQUIRE(firstEncoded.ok());
|
|
REQUIRE(secondEncoded.ok());
|
|
CHECK(firstEncoded.value() == secondEncoded.value());
|
|
|
|
bool hasCorner = false;
|
|
bool hasMount = false;
|
|
bool hasClimb = false;
|
|
bool hasDismount = false;
|
|
for (const auto& node : first.value().graph.nodes)
|
|
hasCorner = hasCorner || node.kind == eve::climbing::ClimbingAnchorKind::CornerOuter ||
|
|
node.kind == eve::climbing::ClimbingAnchorKind::CornerInner;
|
|
for (const auto& edge : first.value().graph.edges) {
|
|
hasMount = hasMount || edge.kind == eve::climbing::ClimbingAnchorEdgeKind::Mount;
|
|
hasClimb = hasClimb || edge.kind == eve::climbing::ClimbingAnchorEdgeKind::Climb;
|
|
hasDismount = hasDismount || edge.kind == eve::climbing::ClimbingAnchorEdgeKind::Dismount;
|
|
}
|
|
CHECK(hasCorner);
|
|
CHECK(hasMount);
|
|
CHECK(hasClimb);
|
|
CHECK(hasDismount);
|
|
}
|
|
|
|
TEST_CASE("climbing.anchorAuthoring.hashIgnoresSourceAndTagOrdering") {
|
|
auto canonical = request();
|
|
eve::climbing::ClimbingLedgeBakeSource secondLedge;
|
|
secondLedge.id = "balcony";
|
|
secondLedge.points = {{4.f, 1.f, 0.f}, {5.f, 1.f, 0.f}};
|
|
secondLedge.localNormal = {0.f, 0.f, -1.f};
|
|
secondLedge.tags = {"outdoor", "stone"};
|
|
canonical.ledges.push_back(secondLedge);
|
|
canonical.ladders.front().tags = {"metal", "outdoor"};
|
|
|
|
auto permuted = canonical;
|
|
std::reverse(permuted.ledges.begin(), permuted.ledges.end());
|
|
std::reverse(permuted.ledges.front().tags.begin(), permuted.ledges.front().tags.end());
|
|
std::reverse(permuted.ledges.back().tags.begin(), permuted.ledges.back().tags.end());
|
|
std::reverse(permuted.ladders.front().tags.begin(), permuted.ladders.front().tags.end());
|
|
|
|
auto first = eve::climbing::bakeClimbingAnchorGraph(canonical);
|
|
auto second = eve::climbing::bakeClimbingAnchorGraph(permuted);
|
|
REQUIRE(first.ok());
|
|
REQUIRE(second.ok());
|
|
CHECK_EQ(first.value().graph.buildSettingsHash, second.value().graph.buildSettingsHash);
|
|
auto firstEncoded = eve::climbing::encodeClimbingAnchorGraphDefinition(first.value().graph);
|
|
auto secondEncoded = eve::climbing::encodeClimbingAnchorGraphDefinition(second.value().graph);
|
|
REQUIRE(firstEncoded.ok());
|
|
REQUIRE(secondEncoded.ok());
|
|
CHECK(firstEncoded.value() == secondEncoded.value());
|
|
}
|
|
|
|
TEST_CASE("climbing.anchorAuthoring.requestCodecRoundTripsAndRejectsFuture") {
|
|
auto encoded = eve::climbing::encodeClimbingAnchorBakeRequest(request());
|
|
REQUIRE(encoded.ok());
|
|
auto decoded = eve::climbing::decodeClimbingAnchorBakeRequest(encoded.value());
|
|
REQUIRE(decoded.ok());
|
|
auto reencoded = eve::climbing::encodeClimbingAnchorBakeRequest(decoded.value());
|
|
REQUIRE(reencoded.ok());
|
|
CHECK(reencoded.value() == encoded.value());
|
|
|
|
eve::Value future = encoded.value();
|
|
future.set("schemaVersion", eve::Value(eve::climbing::ClimbingAnchorBakeRequest::SchemaVersion + 1));
|
|
auto rejected = eve::climbing::decodeClimbingAnchorBakeRequest(future);
|
|
CHECK(!rejected.ok());
|
|
CHECK_EQ(static_cast<int>(rejected.error()->code()), static_cast<int>(eve::DiagnosticCode::UnknownVersion));
|
|
}
|
|
|
|
TEST_CASE("climbing.anchorAuthoring.overlayOwnsCanonicalPrimitives") {
|
|
auto baked = eve::climbing::bakeClimbingAnchorGraph(request());
|
|
REQUIRE(baked.ok());
|
|
auto overlay = eve::climbing::inspectClimbingAnchorGraphAuthoring(baked.value().graph);
|
|
REQUIRE(overlay.ok());
|
|
CHECK_EQ(overlay.value().graphId, std::string("playground.route"));
|
|
CHECK_EQ(overlay.value().nodes.size(), baked.value().graph.nodes.size());
|
|
CHECK_EQ(overlay.value().edges.size(), baked.value().graph.edges.size());
|
|
CHECK_EQ(overlay.value().nodes.front().id, baked.value().graph.nodes.front().id);
|
|
|
|
auto invalid = baked.value().graph;
|
|
invalid.nodes.front().localNormal = {};
|
|
auto rejected = eve::climbing::inspectClimbingAnchorGraphAuthoring(invalid);
|
|
CHECK(!rejected.ok());
|
|
CHECK_EQ(static_cast<int>(rejected.error()->code()), static_cast<int>(eve::DiagnosticCode::InvalidArgument));
|
|
}
|
|
|
|
TEST_CASE("climbing.anchorAuthoring.rejectsInvalidSourceWithoutPartialGraph") {
|
|
auto candidate = request();
|
|
candidate.ladders.front().rungSpacing = 0.f;
|
|
auto rejected = eve::climbing::bakeClimbingAnchorGraph(candidate);
|
|
CHECK(!rejected.ok());
|
|
CHECK_EQ(static_cast<int>(rejected.error()->code()), static_cast<int>(eve::DiagnosticCode::InvalidArgument));
|
|
}
|