From dc4adadef657d86559c48e8fefb5652132b50b72 Mon Sep 17 00:00:00 2001 From: Agustin Alba Chicar Date: Wed, 10 Jul 2024 16:51:19 +0200 Subject: [PATCH 1/2] Adds tests to GenerateDotStream(). Signed-off-by: Agustin Alba Chicar --- test/CMakeLists.txt | 2 + test/generate_dot_test.cc | 142 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 test/generate_dot_test.cc diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0fa41da..7ca54ff 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -43,6 +43,7 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/StackedBranchPointsObjContent.obj DES ament_add_gtest(derive_lane_s_routes_test derive_lane_s_routes_test.cc) ament_add_gtest(distance_router_test distance_router_test.cc) ament_add_gtest(find_lane_sequences_test find_lane_sequences_test.cc) +ament_add_gtest(generate_dot_test generate_dot_test.cc) ament_add_gtest(generate_obj_test generate_obj_test.cc WORKING_DIRECTORY ${TEST_PATH}) ament_add_gtest(generate_string_test generate_string_test.cc) ament_add_gtest(generate_urdf_test generate_urdf_test.cc) @@ -57,6 +58,7 @@ ament_add_gtest(waypoints_test waypoints_test.cc) add_dependencies_to_test(derive_lane_s_routes_test) add_dependencies_to_test(distance_router_test) add_dependencies_to_test(find_lane_sequences_test) +add_dependencies_to_test(generate_dot_test) add_dependencies_to_test(generate_obj_test) add_dependencies_to_test(generate_string_test) add_dependencies_to_test(generate_urdf_test) diff --git a/test/generate_dot_test.cc b/test/generate_dot_test.cc new file mode 100644 index 0000000..029d196 --- /dev/null +++ b/test/generate_dot_test.cc @@ -0,0 +1,142 @@ +// BSD 3-Clause License +// +// Copyright (c) 2024, Woven by Toyota. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace maliput { +namespace test { +namespace { + +static constexpr char kMalidriveResourcesPath[] = DEF_MALIDRIVE_RESOURCES; + +class TShapeRoadGenerateDotTest : public ::testing::Test { + public: + //@{ Tolerances set to match the involved geometries and the parser resolution. + static constexpr double kLinearTolerance{1e-6}; + static constexpr double kAngularTolerance{1e-6}; + static constexpr double kScaleLength{1.0}; + //@} + static constexpr routing::RoutingConstraints kDefaultRoutingConstraints{}; + const std::string kTShapeRoadFilePath{std::string(kMalidriveResourcesPath) + + std::string("/resources/odr/TShapeRoad.xodr")}; + const api::LaneId kStartLaneId{"0_0_1"}; + const api::LaneId kEndLaneId{"0_0_1"}; + + std::unique_ptr road_network_{}; + std::unique_ptr router_{}; + routing::graph::Graph graph_{}; + std::vector routes_{}; + + void SetUp() override { + std::map road_network_configuration; + road_network_configuration.emplace(malidrive::builder::params::kRoadGeometryId, "malidrive_rg"); + road_network_configuration.emplace(malidrive::builder::params::kOpendriveFile, kTShapeRoadFilePath); + road_network_configuration.emplace(malidrive::builder::params::kLinearTolerance, std::to_string(kLinearTolerance)); + road_network_configuration.emplace(malidrive::builder::params::kAngularTolerance, + std::to_string(kAngularTolerance)); + road_network_configuration.emplace(malidrive::builder::params::kScaleLength, std::to_string(kScaleLength)); + road_network_configuration.emplace(malidrive::builder::params::kInertialToBackendFrameTranslation, "{0., 0., 0.}"); + road_network_ = malidrive::loader::Load(road_network_configuration); + + router_ = std::make_unique(*road_network_, kLinearTolerance); + + graph_ = routing::graph::BuildGraph(road_network_->road_geometry()); + + const api::RoadPosition start(road_network_->road_geometry()->ById().GetLane(kStartLaneId), + api::LanePosition(1., 0., 0.)); + const api::RoadPosition end(road_network_->road_geometry()->ById().GetLane(kEndLaneId), + api::LanePosition(10., 0., 0.)); + routes_ = router_->ComputeRoutes(start, end, kDefaultRoutingConstraints); + ASSERT_EQ(1u, routes_.size()); + } +}; + +// Evaluates the graph is correct and the api::Segment containing the routing::Route is marked with the red color. +TEST_F(TShapeRoadGenerateDotTest, DotGraphWithARouteMarksInRedWhereTheRouteGoesThrough) { + const std::string kResult(R"(graph { +1 -- 5 [ label = "9_0" ]; +5 -- 1 [ label = "8_0" ]; +5 -- 2 [ label = "7_0" ]; +1 -- 2 [ label = "5_0" ]; +4 -- 5 [ label = "2_0" ]; +2 -- 5 [ label = "6_0" ]; +1 -- 2 [ label = "4_0" ]; +2 -- 3 [ label = "1_0" ]; +0 -- 1 [ label = "0_0" color = "red" ]; +} +)"); + + std::stringstream ss; + maliput::utility::GenerateDotStream(graph_, routes_.front(), &ss); + + ASSERT_EQ(kResult, ss.str()); +} + +// Evaluates the graph serialization is the expected one. There is no prescriptive order in the serialization, thus +// differences are expected in the order of the edges. +TEST_F(TShapeRoadGenerateDotTest, DotGraphWithoutARouteYieldsTheExpectedGraph) { + const std::string kResult(R"(graph { +1 -- 5 [ label = "9_0" ]; +5 -- 2 [ label = "7_0" ]; +2 -- 5 [ label = "6_0" ]; +1 -- 2 [ label = "5_0" ]; +5 -- 1 [ label = "8_0" ]; +1 -- 2 [ label = "4_0" ]; +4 -- 5 [ label = "2_0" ]; +2 -- 3 [ label = "1_0" ]; +0 -- 1 [ label = "0_0" ]; +} +)"); + + std::stringstream ss; + maliput::utility::GenerateDotStream(graph_, &ss); + + ASSERT_EQ(kResult, ss.str()); +} + +} // namespace +} // namespace test +} // namespace maliput From db8afbd2ce9695f2fe50d579c4132901bcfaf4ea Mon Sep 17 00:00:00 2001 From: Agustin Alba Chicar Date: Tue, 1 Oct 2024 11:42:40 +0200 Subject: [PATCH 2/2] Addresses review comments and makes the test robust to changes in the edge order. Signed-off-by: Agustin Alba Chicar --- test/generate_dot_test.cc | 55 ++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/test/generate_dot_test.cc b/test/generate_dot_test.cc index 029d196..d85f83c 100644 --- a/test/generate_dot_test.cc +++ b/test/generate_dot_test.cc @@ -26,6 +26,7 @@ // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include #include #include #include @@ -52,6 +53,19 @@ namespace { static constexpr char kMalidriveResourcesPath[] = DEF_MALIDRIVE_RESOURCES; +// Splits @p input by new lines and returns a vector of lines. +std::vector SplitByLines(const std::string& input) { + std::vector lines; + std::stringstream ss(input); + std::string line; + + while (std::getline(ss, line)) { + lines.push_back(line); + } + + return lines; +} + class TShapeRoadGenerateDotTest : public ::testing::Test { public: //@{ Tolerances set to match the involved geometries and the parser resolution. @@ -94,9 +108,16 @@ class TShapeRoadGenerateDotTest : public ::testing::Test { } }; +// Using an empty routing::graph::Graph to show that the function throws when the api::Segments from the routing::Route +// cannot be found in the routing::graph::Edges from the routing::graph::Graph. +TEST_F(TShapeRoadGenerateDotTest, ThrowsWhenTheSegmentIsNotInGraph) { + std::stringstream ss; + ASSERT_THROW({ utility::GenerateDotStream(routing::graph::Graph{}, routes_.front(), &ss); }, common::assertion_error); +} + // Evaluates the graph is correct and the api::Segment containing the routing::Route is marked with the red color. -TEST_F(TShapeRoadGenerateDotTest, DotGraphWithARouteMarksInRedWhereTheRouteGoesThrough) { - const std::string kResult(R"(graph { +TEST_F(TShapeRoadGenerateDotTest, DotGraphWithRouteHighlightedInRed) { + const std::string kExpectedResult(R"(graph { 1 -- 5 [ label = "9_0" ]; 5 -- 1 [ label = "8_0" ]; 5 -- 2 [ label = "7_0" ]; @@ -108,17 +129,25 @@ TEST_F(TShapeRoadGenerateDotTest, DotGraphWithARouteMarksInRedWhereTheRouteGoesT 0 -- 1 [ label = "0_0" color = "red" ]; } )"); + const std::vector kExpectedResultInLines = SplitByLines(kExpectedResult); std::stringstream ss; - maliput::utility::GenerateDotStream(graph_, routes_.front(), &ss); - - ASSERT_EQ(kResult, ss.str()); + utility::GenerateDotStream(graph_, routes_.front(), &ss); + + const std::vector result = SplitByLines(ss.str()); + ASSERT_EQ(kExpectedResultInLines.size(), result.size()); + ASSERT_EQ(kExpectedResultInLines.front(), result.front()); + ASSERT_EQ(kExpectedResultInLines.back(), result.back()); + for (size_t i = 1; i < result.size() - 1; ++i) { + ASSERT_NE(kExpectedResultInLines.end(), + std::find(kExpectedResultInLines.begin() + 1, kExpectedResultInLines.end() - 1, result[i])); + } } // Evaluates the graph serialization is the expected one. There is no prescriptive order in the serialization, thus // differences are expected in the order of the edges. TEST_F(TShapeRoadGenerateDotTest, DotGraphWithoutARouteYieldsTheExpectedGraph) { - const std::string kResult(R"(graph { + const std::string kExpectedResult(R"(graph { 1 -- 5 [ label = "9_0" ]; 5 -- 2 [ label = "7_0" ]; 2 -- 5 [ label = "6_0" ]; @@ -130,11 +159,19 @@ TEST_F(TShapeRoadGenerateDotTest, DotGraphWithoutARouteYieldsTheExpectedGraph) { 0 -- 1 [ label = "0_0" ]; } )"); + const std::vector kExpectedResultInLines = SplitByLines(kExpectedResult); std::stringstream ss; - maliput::utility::GenerateDotStream(graph_, &ss); - - ASSERT_EQ(kResult, ss.str()); + utility::GenerateDotStream(graph_, &ss); + + const std::vector result = SplitByLines(ss.str()); + ASSERT_EQ(kExpectedResultInLines.size(), result.size()); + ASSERT_EQ(kExpectedResultInLines.front(), result.front()); + ASSERT_EQ(kExpectedResultInLines.back(), result.back()); + for (size_t i = 1; i < result.size() - 1; ++i) { + ASSERT_NE(kExpectedResultInLines.end(), + std::find(kExpectedResultInLines.begin() + 1, kExpectedResultInLines.end() - 1, result[i])); + } } } // namespace