Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ControllerCreatorTest.cpp 11.20 KiB
/*******************************************************************************
 * Copyright (c) 2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
 * Copyright (c) 2023 Ansys, Inc.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *******************************************************************************/

#include <ApiClassWriterInterfacesV1_2.h>
#include <MantleAPI/Test/test_utils.h>
#include <gtest/gtest.h>
#include <openScenarioLib/generated/v1_2/impl/ApiClassImplV1_2.h>
#include <openScenarioLib/generated/v1_2/impl/OpenScenarioWriterFactoryImplV1_2.h>

#include "MantleAPI/Common/i_identifiable.h"
#include "TestUtils.h"
#include "TestUtils/TestLogger.h"
#include "Utils/ControllerCreator.h"

using testing::_;
using testing::Gt;
using testing::HasSubstr;
using testing::Ne;
using testing::Return;
using testing::ReturnRef;
using testing::SizeIs;

class ControllerCreator : public ::testing::Test
{
public:
  inline static constexpr mantle_api::UniqueId TEST_CONTROLLER_ID{1234};
  inline static const std::string TEST_CONTROLLER_NAME{"TEST_CONTROLLER"};

  ControllerCreator()
      : LOGGER{std::make_unique<testing::OpenScenarioEngine::v1_2::TestLogger>()},
        mockEnvironment{},
        mockEntityRepository{dynamic_cast<mantle_api::MockEntityRepository&>(mockEnvironment.GetEntityRepository())},
        mockControllerRepository{mockEnvironment.GetControllerRepository()},
        mockController{}
  {
    ON_CALL(mockController, GetName()).WillByDefault(ReturnRef(TEST_CONTROLLER_NAME));
    ON_CALL(mockController, GetUniqueId()).WillByDefault(testing::Invoke([] {
      // id will be incremented at every call, starting with 1000
      static mantle_api::UniqueId id{1000};
      return id++;
    }));
  }

  void SET_VEHICLE_MOCK_NAME_AND_ID(const std::string& name, mantle_api::UniqueId id)
  {
    auto& mockVehicle = dynamic_cast<mantle_api::MockVehicle&>(mockEnvironment.GetEntityRepository().Get(name).value().get());

    mockVehicle.SetName(name);
    ON_CALL(mockVehicle, GetUniqueId()).WillByDefault(Return(id));
  }

  void SETUP_ENTITY(std::string entity_name, mantle_api::UniqueId entity_id, bool entity_is_controllable, bool with_user_defined_controller)
  {
    using namespace NET_ASAM_OPENSCENARIO::v1_2;
    auto scenario_object = std::make_shared<ScenarioObjectImpl>();
    scenario_object->SetName(std::move(entity_name));

    if (with_user_defined_controller)
    {
      // create a controller
      auto controller = std::make_shared<ControllerImpl>();
      controller->SetName("USER_DEFINED_CONTROLLER");

      // adding a property to controller
      std::shared_ptr<IPropertiesWriter> properties{std::make_shared<PropertiesImpl>()};
      std::shared_ptr<IPropertyWriter> property{std::make_shared<PropertyImpl>()};
      property->SetName("TEST_PROPERTY_NAME");
      property->SetValue("TEST_PROPERTY_VALUE");
      controller->SetProperties({properties});

      // create object_controllers and add controller to the first (and only) object_controller
      std::vector<std::shared_ptr<IObjectControllerWriter>> object_controller{std::make_shared<ObjectControllerImpl>()};
      auto object_controller_impl = std::dynamic_pointer_cast<ObjectControllerImpl>(object_controller.front());
      object_controller_impl->SetController(std::move(controller));

      // wiring objects to scenario
      scenario_object->SetObjectController(object_controller);
    }

    auto entity_object = std::make_shared<EntityObjectImpl>();
    if (entity_is_controllable)
    {
      auto vehicle = std::make_shared<VehicleImpl>();
      entity_object->SetVehicle(vehicle);
      SET_VEHICLE_MOCK_NAME_AND_ID(entity_name, entity_id);
    }
    else
    {
      auto misc_object = std::make_shared<MiscObjectImpl>();
      entity_object->SetMiscObject(misc_object);
    }
    scenario_object->SetEntityObject(entity_object);
    scenario_objects.push_back(std::move(scenario_object));
  }

  std::unique_ptr<testing::OpenScenarioEngine::v1_2::TestLogger> LOGGER;

  mantle_api::MockEnvironment mockEnvironment;
  mantle_api::MockEntityRepository& mockEntityRepository;
  mantle_api::MockControllerRepository& mockControllerRepository;
  mantle_api::MockController mockController;

  std::vector<std::shared_ptr<NET_ASAM_OPENSCENARIO::v1_2::IScenarioObject>> scenario_objects{};
  std::vector<std::unique_ptr<mantle_api::IEntity>> entities_{};
};

TEST_F(ControllerCreator, GivenNoScenarioObjects_WhenCreateIsCalled_ThenDoesNothing)
{
  EXPECT_CALL(mockControllerRepository, Create(_)).Times(0);
  OpenScenarioEngine::v1_2::ControllerCreator controller_creator(mockEnvironment);

  controller_creator.CreateControllers(scenario_objects);
}

TEST_F(ControllerCreator, GivenScenarioObjectWithoutController_WhenCreateIsCalled_ThenCreatesDefaultController)
{
  SETUP_ENTITY("test_entity", 1234, true, false);

  EXPECT_CALL(mockControllerRepository, Create(_)).WillOnce(ReturnRef(mockController));
  OpenScenarioEngine::v1_2::ControllerCreator controller_creator(mockEnvironment);

  controller_creator.CreateControllers(scenario_objects);
}

TEST_F(ControllerCreator, GivenUncontrollableScenarioObject_WhenCreateIsCalled_ThenDoesNothingAndLogsMessage)
{
  SETUP_ENTITY("test_entity", 1234, false, false);

  EXPECT_CALL(mockControllerRepository, Create(_)).Times(0);
  OpenScenarioEngine::v1_2::ControllerCreator controller_creator(mockEnvironment);

  controller_creator.CreateControllers(scenario_objects);

  EXPECT_THAT(LOGGER->LastLogLevel(), mantle_api::LogLevel::kInfo);
  EXPECT_THAT(LOGGER->LastLogMessage(), HasSubstr("No controller created"));
  EXPECT_THAT(LOGGER->LastLogMessage(), HasSubstr("test_entity"));
}

TEST_F(ControllerCreator, GivenUncontrollableAndControllableScenarioObject_WhenCreateIsCalled_ThenControllerOnlyForControllableObjectIsCreated)
{
  SETUP_ENTITY("uncontrollable_entity", 1234, false, false);
  SETUP_ENTITY("entity_2", 5678, true, false);

  EXPECT_CALL(mockControllerRepository, Create(_)).Times(1).WillOnce(ReturnRef(mockController));
  OpenScenarioEngine::v1_2::ControllerCreator controller_creator(mockEnvironment);

  controller_creator.CreateControllers(scenario_objects);
}

TEST_F(ControllerCreator, GivenScenarioObjectWithController_WhenCreateIsCalled_ThenCreatesDefaultAndUserDefinedController)
{
  SETUP_ENTITY("test_entity", 1234, true, true);

  EXPECT_CALL(mockControllerRepository, Create(_))
      .WillOnce(ReturnRef(mockController))
      .WillOnce(ReturnRef(mockController));

  OpenScenarioEngine::v1_2::ControllerCreator controller_creator(mockEnvironment);

  controller_creator.CreateControllers(scenario_objects);
}

TEST_F(ControllerCreator, GivenScenarioObjectWithController_WhenCreateIsCalled_ThenControllerServiceContainsEntitiyControllers)
{
  constexpr mantle_api::UniqueId ENTITY_ID = 1234;
  SETUP_ENTITY("test_entity", ENTITY_ID, true, true);

  ON_CALL(mockControllerRepository, Create(_)).WillByDefault(ReturnRef(mockController));

  OpenScenarioEngine::v1_2::ControllerCreator controller_creator(mockEnvironment);
  controller_creator.CreateControllers(scenario_objects);

  auto controller_service = controller_creator.GetControllerService();
  auto controllers = controller_service->GetControllers(ENTITY_ID);

  auto internal_controller_id = controllers->internal.first;
  EXPECT_THAT(internal_controller_id, Gt(0));

  ASSERT_THAT(controllers->user_defined, SizeIs(1));
  auto user_defined_controller_id = controllers->user_defined.begin()->first;
  EXPECT_THAT(user_defined_controller_id, Gt(0));

  ASSERT_THAT(internal_controller_id, Ne(user_defined_controller_id));
}

TEST_F(ControllerCreator, GivenExternalControllerOverrideSet_WhenCreateControllerIsCalled_ThenHostGetsUserDefinedController)
{
  constexpr mantle_api::UniqueId ENTITY_ID = 1234;
  // "DSpace" host "M1:..." and no external controller
  SETUP_ENTITY("M1:test_entity", ENTITY_ID, true, false);

  mantle_api::MockController default_controller{};
  constexpr mantle_api::UniqueId DEFAULT_CONTROLLER_ID{1000};
  std::string DEFAULT_CONTROLLER_NAME{"DEFAULT_CONTROLLER"};
  ON_CALL(default_controller, GetUniqueId()).WillByDefault(Return(DEFAULT_CONTROLLER_ID));
  ON_CALL(default_controller, GetName()).WillByDefault(ReturnRef(DEFAULT_CONTROLLER_NAME));
  EXPECT_CALL(default_controller,
              ChangeState(mantle_api::IController::LateralState::kActivate, mantle_api::IController::LongitudinalState::kActivate))
      .Times(1);
  EXPECT_CALL(default_controller,
              ChangeState(mantle_api::IController::LateralState::kDeactivate, mantle_api::IController::LongitudinalState::kDeactivate))
      .Times(1);

  mantle_api::MockController user_defined_controller{};
  constexpr mantle_api::UniqueId USER_DEFINED_CONTROLLER_ID{1001};
  std::string USER_DEFINED_CONTROLLER_NAME{"USED_DEFINED_CONTROLLER"};
  ON_CALL(user_defined_controller, GetUniqueId()).WillByDefault(Return(USER_DEFINED_CONTROLLER_ID));
  ON_CALL(user_defined_controller, GetName()).WillByDefault(ReturnRef(USER_DEFINED_CONTROLLER_NAME));
  EXPECT_CALL(user_defined_controller,
              ChangeState(mantle_api::IController::LateralState::kActivate, mantle_api::IController::LongitudinalState::kActivate))
      .Times(1);

  EXPECT_CALL(mockControllerRepository, Create(_))
      .WillOnce(ReturnRef(default_controller))
      .WillOnce(ReturnRef(user_defined_controller));

  OpenScenarioEngine::v1_2::ControllerCreator controller_creator(mockEnvironment);
  controller_creator.EnableUserDefinedControllerOverride();
  controller_creator.CreateControllers(scenario_objects);

  auto controller_service = controller_creator.GetControllerService();
  auto controllers = controller_service->GetControllers(ENTITY_ID);

  auto actual_internal_controller_id = controllers->internal.first;
  EXPECT_EQ(actual_internal_controller_id, DEFAULT_CONTROLLER_ID);

  ASSERT_THAT(controllers->user_defined, SizeIs(1));
  auto actual_user_defined_controller_id = controllers->user_defined.begin()->first;
  EXPECT_EQ(actual_user_defined_controller_id, USER_DEFINED_CONTROLLER_ID);
}

TEST_F(ControllerCreator, GivenScenarioObjectWithoutController_WhenCreateControllersIsCalled_ThenDefaultControllerIsCreatedAndActivated)
{
  SETUP_ENTITY("test_entity", 1234, true, false);

  EXPECT_CALL(mockControllerRepository, Create(_)).WillOnce(ReturnRef(mockController));
  EXPECT_CALL(mockController, ChangeState(_, _)).Times(1);
  OpenScenarioEngine::v1_2::ControllerCreator controller_creator(mockEnvironment);

  controller_creator.CreateControllers(scenario_objects);
}

TEST_F(ControllerCreator, GivenScenarioObjectWithController_WhenResetControllerMappingsIsCalled_ThenControllerServiceInternalStateIsReset)
{
  constexpr mantle_api::UniqueId ENTITY_ID = 1234;
  SETUP_ENTITY("test_entity", ENTITY_ID, true, true);

  ON_CALL(mockControllerRepository, Create(_)).WillByDefault(ReturnRef(mockController));

  OpenScenarioEngine::v1_2::ControllerCreator controller_creator(mockEnvironment);
  controller_creator.CreateControllers(scenario_objects);

  auto controller_service = controller_creator.GetControllerService();
  ASSERT_TRUE(controller_service->GetControllers(ENTITY_ID).has_value());

  controller_service->ResetControllerMappings();
  EXPECT_FALSE(controller_service->GetControllers(ENTITY_ID).has_value());
}