From 2f983591866f7116b5c3e12c8e4b8bdeb0efb1ce Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Tue, 26 Nov 2024 13:12:33 +0100 Subject: [PATCH] New System model (2.2) [ANT-2208] (#2500) --- src/study/system-model/CMakeLists.txt | 4 + src/study/system-model/component.cpp | 126 +++++++++++ .../antares/study/system-model/component.h | 96 +++++++++ .../antares/study/system-model/system.h | 79 +++++++ src/study/system-model/system.cpp | 89 ++++++++ src/tests/src/CMakeLists.txt | 2 + src/tests/src/study/CMakeLists.txt | 1 + .../src/study/system-model/CMakeLists.txt | 19 ++ .../src/study/system-model/test_component.cpp | 198 ++++++++++++++++++ .../src/study/system-model/test_main.cpp | 25 +++ .../src/study/system-model/test_system.cpp | 98 +++++++++ src/tests/src/utils/unit_test_utils.h | 38 ++++ 12 files changed, 775 insertions(+) create mode 100644 src/study/system-model/component.cpp create mode 100644 src/study/system-model/include/antares/study/system-model/component.h create mode 100644 src/study/system-model/include/antares/study/system-model/system.h create mode 100644 src/study/system-model/system.cpp create mode 100644 src/tests/src/study/CMakeLists.txt create mode 100644 src/tests/src/study/system-model/CMakeLists.txt create mode 100644 src/tests/src/study/system-model/test_component.cpp create mode 100644 src/tests/src/study/system-model/test_main.cpp create mode 100644 src/tests/src/study/system-model/test_system.cpp create mode 100644 src/tests/src/utils/unit_test_utils.h diff --git a/src/study/system-model/CMakeLists.txt b/src/study/system-model/CMakeLists.txt index e9a7348534..19cbfa7abb 100644 --- a/src/study/system-model/CMakeLists.txt +++ b/src/study/system-model/CMakeLists.txt @@ -3,6 +3,8 @@ project(SystemModel) set(SRC_model library.cpp model.cpp + component.cpp + system.cpp include/antares/study/system-model/library.h include/antares/study/system-model/model.h include/antares/study/system-model/parameter.h @@ -14,6 +16,8 @@ set(SRC_model include/antares/study/system-model/portField.h include/antares/study/system-model/portFieldDefinition.h include/antares/study/system-model/portType.h + include/antares/study/system-model/component.h + include/antares/study/system-model/system.h ) source_group("SystemModel" FILES ${SRC_model}) diff --git a/src/study/system-model/component.cpp b/src/study/system-model/component.cpp new file mode 100644 index 0000000000..b9b7c6a03b --- /dev/null +++ b/src/study/system-model/component.cpp @@ -0,0 +1,126 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator 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 +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ + +#include + +#include + +namespace Antares::Study::SystemModel +{ + +static void checkComponentDataValidity(const ComponentData& data) +{ + // Check that mandatory attributes are not empty + if (data.id.empty()) + { + throw std::invalid_argument("A component can't have an empty id"); + } + if (data.model == nullptr) + { + throw std::invalid_argument("A component can't have an empty model"); + } + if (data.scenario_group_id.empty()) + { + throw std::invalid_argument("A component can't have an empty scenario_group_id"); + } + // Check that parameters values are coherent with the model + if (data.model->Parameters().size() != data.parameter_values.size()) + { + throw std::invalid_argument( + "The component has " + std::to_string(data.parameter_values.size()) + + " parameter(s), but its model has " + std::to_string(data.model->Parameters().size())); + } + for (const auto param: data.model->Parameters() | std::views::keys) + { + if (!data.parameter_values.contains(param)) + { + throw std::invalid_argument("The component has no value for parameter '" + param + "'"); + } + } +} + +Component::Component(const ComponentData& component_data) +{ + checkComponentDataValidity(component_data); + data_ = std::move(component_data); +} + +/** + * \brief Sets the ID of the component. + * + * \param id The ID to set. + * \return Reference to the ComponentBuilder object. + */ +ComponentBuilder& ComponentBuilder::withId(const std::string_view id) +{ + data_.id = id; + return *this; +} + +/** + * \brief Sets the model of the component. + * + * \param model The model to set. + * \return Reference to the ComponentBuilder object. + */ +ComponentBuilder& ComponentBuilder::withModel(Model* model) +{ + data_.model = model; + return *this; +} + +/** + * \brief Sets the parameter values of the component. The parameters included should be all of the + * model's parameters. + * + * \param parameter_values The map of parameter values to set. + * \return Reference to the ComponentBuilder object. + */ +ComponentBuilder& ComponentBuilder::withParameterValues( + std::map parameter_values) +{ + data_.parameter_values = std::move(parameter_values); + return *this; +} + +/** + * \brief Sets the ID of the scenario group to which the component belongs. + * + * \param scenario_group_id The scenario group ID to set. + * \return Reference to the ComponentBuilder object. + */ +ComponentBuilder& ComponentBuilder::withScenarioGroupId(const std::string& scenario_group_id) +{ + data_.scenario_group_id = scenario_group_id; + return *this; +} + +/** + * \brief Builds and returns the Component object. + * + * \return The constructed Component object. + */ +Component ComponentBuilder::build() const +{ + return Component(data_); +} + +} // namespace Antares::Study::SystemModel diff --git a/src/study/system-model/include/antares/study/system-model/component.h b/src/study/system-model/include/antares/study/system-model/component.h new file mode 100644 index 0000000000..d3be08ba80 --- /dev/null +++ b/src/study/system-model/include/antares/study/system-model/component.h @@ -0,0 +1,96 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator 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 +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +#include "model.h" + +namespace Antares::Study::SystemModel +{ + +/** + * Defines the attributes of the Component class + * Made into a struct to avoid duplication in ComponentBuilder + */ +struct ComponentData +{ + std::string id; + Model* model = nullptr; + std::map parameter_values; + std::string scenario_group_id; +}; + +/** + * Defines an actual component of the simulated system. + */ +class Component +{ +public: + // Only allowing one private constructor (see below) to forbid empty Components + Component() = delete; + + const std::string& Id() const + { + return data_.id; + } + + Model* getModel() const + { + return data_.model; + } + + double getParameterValue(const std::string& parameter_id) const + { + if (!data_.parameter_values.contains(parameter_id)) + { + throw std::invalid_argument("Parameter '" + parameter_id + "' not found in component '" + + data_.id + "'"); + } + return data_.parameter_values.at(parameter_id); + } + + std::string getScenarioGroupId() const + { + return data_.scenario_group_id; + } + +private: + // Only ComponentBuilder is allowed to build Component instances + friend class ComponentBuilder; + explicit Component(const ComponentData& component_data); + ComponentData data_; +}; + +class ComponentBuilder +{ +public: + ComponentBuilder& withId(std::string_view id); + ComponentBuilder& withModel(Model* model); + ComponentBuilder& withParameterValues(std::map parameter_values); + ComponentBuilder& withScenarioGroupId(const std::string& scenario_group_id); + Component build() const; + +private: + ComponentData data_; +}; + +} // namespace Antares::Study::SystemModel diff --git a/src/study/system-model/include/antares/study/system-model/system.h b/src/study/system-model/include/antares/study/system-model/system.h new file mode 100644 index 0000000000..50fa196399 --- /dev/null +++ b/src/study/system-model/include/antares/study/system-model/system.h @@ -0,0 +1,79 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator 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 +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +#include "component.h" + +namespace Antares::Study::SystemModel +{ + +/** + * Defines the attributes of the System class + * Made into a struct to avoid duplication in SystemBuilder + */ +struct SystemData +{ +}; + +/** + * Defines the simulated system. + */ +class System +{ +public: + // Only allowing one private constructor (see below) to forbid empty Systems + System() = delete; + System(System& other) = delete; + + const std::string& Id() const + { + return id_; + } + + const std::unordered_map& Components() const + { + return components_; + } + +private: + // Only SystemBuilder is allowed to build System instances + friend class SystemBuilder; + System(std::string_view id, std::vector components); + std::string id_; + std::unordered_map components_; + std::pair makeComponent(Component& component) const; +}; + +class SystemBuilder +{ +public: + SystemBuilder& withId(std::string_view id); + SystemBuilder& withComponents(std::vector&& components); + System build() const; + +private: + std::string id_; + std::vector components_; +}; + +} // namespace Antares::Study::SystemModel diff --git a/src/study/system-model/system.cpp b/src/study/system-model/system.cpp new file mode 100644 index 0000000000..20a26287e1 --- /dev/null +++ b/src/study/system-model/system.cpp @@ -0,0 +1,89 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator 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 +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ + +#include + +#include + +namespace Antares::Study::SystemModel +{ +System::System(const std::string_view id, std::vector components): + id_(id) +{ + // Check that mandatory attributes are not empty + if (id.empty()) + { + throw std::invalid_argument("A system can't have an empty id"); + } + if (components.empty()) + { + throw std::invalid_argument("A system must contain at least one component"); + } + std::ranges::transform(components, + std::inserter(components_, components_.end()), + [this](/*Non const to prevent copy*/ Component& component) + { return makeComponent(component); }); +} + +std::pair System::makeComponent(Component& component) const +{ + if (components_.contains(component.Id())) + { + throw std::invalid_argument("System has at least two components with the same id ('" + + component.Id() + "'), this is not supported"); + } + return std::make_pair(component.Id(), std::move(component)); +} + +/** + * \brief Sets the ID of the system. + * + * \param id The ID to set. + * \return Reference to the SystemBuilder object. + */ +SystemBuilder& SystemBuilder::withId(std::string_view id) +{ + id_ = id; + return *this; +} + +/** + * \brief Sets the components of the system. + * + * \param components A vector of components to set. + * \return Reference to the SystemBuilder object. + */ +SystemBuilder& SystemBuilder::withComponents(std::vector&& components) +{ + components_ = std::move(components); + return *this; +} + +/** + * \brief Builds and returns the System object. + * + * \return The constructed System object. + */ +System SystemBuilder::build() const +{ + return System(id_, components_); +} +} // namespace Antares::Study::SystemModel diff --git a/src/tests/src/CMakeLists.txt b/src/tests/src/CMakeLists.txt index 14c9929f56..02418c5997 100644 --- a/src/tests/src/CMakeLists.txt +++ b/src/tests/src/CMakeLists.txt @@ -5,3 +5,5 @@ add_subdirectory(utils) add_subdirectory(libs) add_subdirectory(solver) + +add_subdirectory(study) diff --git a/src/tests/src/study/CMakeLists.txt b/src/tests/src/study/CMakeLists.txt new file mode 100644 index 0000000000..78be5cda71 --- /dev/null +++ b/src/tests/src/study/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(system-model) \ No newline at end of file diff --git a/src/tests/src/study/system-model/CMakeLists.txt b/src/tests/src/study/system-model/CMakeLists.txt new file mode 100644 index 0000000000..c24ea1e68d --- /dev/null +++ b/src/tests/src/study/system-model/CMakeLists.txt @@ -0,0 +1,19 @@ +set(EXECUTABLE_NAME test-system-model) +add_executable(${EXECUTABLE_NAME}) + +target_sources(${EXECUTABLE_NAME} + PRIVATE + test_main.cpp + test_component.cpp + test_system.cpp +) + +target_link_libraries(${EXECUTABLE_NAME} + PRIVATE + Boost::unit_test_framework + antares-study-system-model +) + +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) +add_test(NAME test-system-model COMMAND ${EXECUTABLE_NAME}) +set_property(TEST test-system-model PROPERTY LABELS unit) diff --git a/src/tests/src/study/system-model/test_component.cpp b/src/tests/src/study/system-model/test_component.cpp new file mode 100644 index 0000000000..e8c69007a9 --- /dev/null +++ b/src/tests/src/study/system-model/test_component.cpp @@ -0,0 +1,198 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator 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 + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include "antares/study/system-model/component.h" + +#include "../../utils/unit_test_utils.h" + +using namespace Antares::Study::SystemModel; + +struct ComponentBuilderCreationFixture +{ + ComponentBuilder component_builder; +}; + +static Model createModelWithParameters() +{ + ModelBuilder model_builder; + return model_builder.withId("model") + .withParameters( + {Parameter("param1", Parameter::TimeDependent::NO, Parameter::ScenarioDependent::NO), + Parameter("param2", Parameter::TimeDependent::NO, Parameter::ScenarioDependent::NO)}) + .build(); +} + +static Model createModelWithoutParameters() +{ + ModelBuilder model_builder; + return model_builder.withId("model").build(); +} + +BOOST_FIXTURE_TEST_SUITE(_Component_, ComponentBuilderCreationFixture) + +BOOST_AUTO_TEST_CASE(nominal_build_with_parameters) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({{"param1", 5}, {"param2", 3}}) + .withScenarioGroupId("scenario_group") + .build(); + BOOST_CHECK_EQUAL(component.Id(), "component"); + BOOST_CHECK_EQUAL(component.getModel(), &model); + BOOST_CHECK_EQUAL(component.getParameterValue("param1"), 5); + BOOST_CHECK_EQUAL(component.getParameterValue("param2"), 3); + BOOST_CHECK_EXCEPTION(component.getParameterValue("param3"), + std::invalid_argument, + checkMessage("Parameter 'param3' not found in component 'component'")); + BOOST_CHECK_EQUAL(component.getScenarioGroupId(), "scenario_group"); +} + +BOOST_AUTO_TEST_CASE(nominal_build_without_parameters1) +{ + Model model = createModelWithoutParameters(); + auto component = component_builder.withId("component2") + .withModel(&model) + .withParameterValues({}) + .withScenarioGroupId("scenario_group2") + .build(); + BOOST_CHECK_EQUAL(component.Id(), "component2"); + BOOST_CHECK_EQUAL(component.getModel(), &model); + BOOST_CHECK_EXCEPTION(component.getParameterValue("param1"), + std::invalid_argument, + checkMessage("Parameter 'param1' not found in component 'component2'")); + BOOST_CHECK_EQUAL(component.getScenarioGroupId(), "scenario_group2"); +} + +BOOST_AUTO_TEST_CASE(nominal_build_without_parameters2) +{ + Model model = createModelWithoutParameters(); + auto component = component_builder.withId("component3") + .withModel(&model) + .withScenarioGroupId("scenario_group3") + .build(); + BOOST_CHECK_EQUAL(component.Id(), "component3"); + BOOST_CHECK_EQUAL(component.getModel(), &model); + BOOST_CHECK_EQUAL(component.getScenarioGroupId(), "scenario_group3"); +} + +BOOST_AUTO_TEST_CASE(fail_on_no_id) +{ + Model model = createModelWithoutParameters(); + auto component = component_builder.withModel(&model).withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("A component can't have an empty id")); +} + +BOOST_AUTO_TEST_CASE(fail_on_no_model) +{ + auto component = component_builder.withId("component").withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("A component can't have an empty model")); +} + +BOOST_AUTO_TEST_CASE(fail_on_no_scenario_group_id) +{ + Model model = createModelWithoutParameters(); + auto component = component_builder.withId("component").withModel(&model); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("A component can't have an empty scenario_group_id")); +} + +BOOST_AUTO_TEST_CASE(fail_on_no_params1) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has 0 parameter(s), but its model has 2")); +} + +BOOST_AUTO_TEST_CASE(fail_on_no_params2) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({}) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has 0 parameter(s), but its model has 2")); +} + +BOOST_AUTO_TEST_CASE(fail_on_missing_param) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({{"param2", 3}}) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has 1 parameter(s), but its model has 2")); +} + +BOOST_AUTO_TEST_CASE(fail_on_missing_wrong_param) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({{"param_1", 3}, {"param2", 3}}) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has no value for parameter 'param1'")); +} + +BOOST_AUTO_TEST_CASE(fail_on_too_many_params1) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({{"param1", 3}, {"param2", 3}, {"param3", 3}}) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has 3 parameter(s), but its model has 2")); +} + +BOOST_AUTO_TEST_CASE(fail_on_too_many_params2) +{ + Model model = createModelWithoutParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({{"param1", 3}}) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has 1 parameter(s), but its model has 0")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/study/system-model/test_main.cpp b/src/tests/src/study/system-model/test_main.cpp new file mode 100644 index 0000000000..85475f9418 --- /dev/null +++ b/src/tests/src/study/system-model/test_main.cpp @@ -0,0 +1,25 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator 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 + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define BOOST_TEST_MODULE systemModel +#define WIN32_LEAN_AND_MEAN + +#include diff --git a/src/tests/src/study/system-model/test_system.cpp b/src/tests/src/study/system-model/test_system.cpp new file mode 100644 index 0000000000..9500b6118b --- /dev/null +++ b/src/tests/src/study/system-model/test_system.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator 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 + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include "antares/study/system-model/system.h" + +#include "../../utils/unit_test_utils.h" + +using namespace Antares::Study::SystemModel; + +struct SystemBuilderCreationFixture +{ + SystemBuilder system_builder; +}; + +static Component createComponent(std::string id) +{ + ModelBuilder model_builder; + auto model = model_builder.withId("model").build(); + ComponentBuilder component_builder; + auto component = component_builder.withId(id) + .withModel(&model) + .withScenarioGroupId("scenario_group") + .build(); + return component; +} + +BOOST_AUTO_TEST_SUITE(_System_) + +BOOST_FIXTURE_TEST_CASE(nominal_build, SystemBuilderCreationFixture) +{ + auto system = system_builder.withId("system") + .withComponents({createComponent("component1"), createComponent("component2")}) + .build(); + BOOST_CHECK_EQUAL(system.Id(), "system"); + BOOST_CHECK_EQUAL(system.Components().size(), 2); + BOOST_CHECK_EQUAL(system.Components().at("component1").Id(), "component1"); + BOOST_CHECK_EQUAL(system.Components().at("component2").Id(), "component2"); +} + +BOOST_FIXTURE_TEST_CASE(fail_on_no_id, SystemBuilderCreationFixture) +{ + system_builder.withComponents({createComponent("component1"), createComponent("component2")}); + BOOST_CHECK_EXCEPTION(system_builder.build(), + std::invalid_argument, + checkMessage("A system can't have an empty id")); +} + +BOOST_FIXTURE_TEST_CASE(fail_on_no_component1, SystemBuilderCreationFixture) +{ + system_builder.withId("system"); + BOOST_CHECK_EXCEPTION(system_builder.build(), + std::invalid_argument, + checkMessage("A system must contain at least one component")); +} + +BOOST_FIXTURE_TEST_CASE(fail_on_no_component2, SystemBuilderCreationFixture) +{ + system_builder.withId("system").withComponents({}); + BOOST_CHECK_EXCEPTION(system_builder.build(), + std::invalid_argument, + checkMessage("A system must contain at least one component")); +} + +BOOST_FIXTURE_TEST_CASE(fail_on_components_with_same_id, SystemBuilderCreationFixture) +{ + system_builder.withId("system").withComponents({}).withComponents( + {createComponent("component1"), + createComponent("component2"), + createComponent("component2")}); + BOOST_CHECK_EXCEPTION(system_builder.build(), + std::invalid_argument, + checkMessage("System has at least two components with the same id " + "('component2'), this is not supported")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/utils/unit_test_utils.h b/src/tests/src/utils/unit_test_utils.h new file mode 100644 index 0000000000..3fe0389f2e --- /dev/null +++ b/src/tests/src/utils/unit_test_utils.h @@ -0,0 +1,38 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator 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 + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +inline std::function checkMessage(std::string expected_message) +{ + auto predicate = [expected_message](const std::exception& e) + { + BOOST_CHECK_EQUAL(e.what(), expected_message); + return true; + }; + return predicate; +}