From cf1697a002d7af2496b4db29af46b101681717c6 Mon Sep 17 00:00:00 2001 From: Artem Grinev Date: Tue, 24 Sep 2024 16:29:52 +0000 Subject: [PATCH] test(daemon): cover domain layer with unit tests Covers (most of) the domain layer with unit tests, also fixes some bugs found along the way. --- CMakeLists.txt | 2 + CMakePresets.json | 4 +- conanfile.py | 12 +++- daemon/CMakeLists.txt | 7 +- daemon/core/domain/entities/Section.h | 1 + .../domain/services/PermissionMatcher.cpp | 7 ++ .../domain/value_objects/PackageVersion.h | 4 ++ .../domain/entities/PackageLogEntry.h | 2 + .../domain/entities/PackageUpdateLogEntry.h | 2 + daemon/tests/CMakeLists.txt | 53 ++++++++++++++ daemon/tests/data/dummy-1-1-any.pkg.tar.zst | Bin 0 -> 19459 bytes .../tests/data/dummy-1-1-any.pkg.tar.zst.sig | Bin 0 -> 140 bytes .../unit/core/domain/entities/PackageTest.cpp | 27 +++++++ .../unit/core/domain/entities/SectionTest.cpp | 49 +++++++++++++ .../unit/core/domain/entities/UserTest.cpp | 59 ++++++++++++++++ .../core/domain/enums/PoolLocationTest.cpp | 52 ++++++++++++++ .../domain/services/PermissionMatcherTest.cpp | 62 ++++++++++++++++ .../core/domain/value_objects/NameTest.cpp | 41 +++++++++++ .../value_objects/PackageArchitectureTest.cpp | 44 ++++++++++++ .../value_objects/PackagePoolEntryTest.cpp | 59 ++++++++++++++++ .../value_objects/PackageVersionTest.cpp | 66 ++++++++++++++++++ .../domain/value_objects/PermissionTest.cpp | 60 ++++++++++++++++ .../domain/entities/CommitLogEntryTest.cpp | 58 +++++++++++++++ .../domain/entities/DeployLogEntryTest.cpp | 47 +++++++++++++ .../domain/entities/EventLogEntryTest.cpp | 43 ++++++++++++ .../domain/entities/PackageLogEntryTest.cpp | 29 ++++++++ .../entities/PackageUpdateLogEntryTest.cpp | 54 ++++++++++++++ .../domain/entities/SyncLogEntryTest.cpp | 63 +++++++++++++++++ .../unit/event_log/domain/entities/helpers.h | 46 ++++++++++++ 29 files changed, 950 insertions(+), 3 deletions(-) create mode 100644 daemon/tests/CMakeLists.txt create mode 100644 daemon/tests/data/dummy-1-1-any.pkg.tar.zst create mode 100644 daemon/tests/data/dummy-1-1-any.pkg.tar.zst.sig create mode 100644 daemon/tests/src/unit/core/domain/entities/PackageTest.cpp create mode 100644 daemon/tests/src/unit/core/domain/entities/SectionTest.cpp create mode 100644 daemon/tests/src/unit/core/domain/entities/UserTest.cpp create mode 100644 daemon/tests/src/unit/core/domain/enums/PoolLocationTest.cpp create mode 100644 daemon/tests/src/unit/core/domain/services/PermissionMatcherTest.cpp create mode 100644 daemon/tests/src/unit/core/domain/value_objects/NameTest.cpp create mode 100644 daemon/tests/src/unit/core/domain/value_objects/PackageArchitectureTest.cpp create mode 100644 daemon/tests/src/unit/core/domain/value_objects/PackagePoolEntryTest.cpp create mode 100644 daemon/tests/src/unit/core/domain/value_objects/PackageVersionTest.cpp create mode 100644 daemon/tests/src/unit/core/domain/value_objects/PermissionTest.cpp create mode 100644 daemon/tests/src/unit/event_log/domain/entities/CommitLogEntryTest.cpp create mode 100644 daemon/tests/src/unit/event_log/domain/entities/DeployLogEntryTest.cpp create mode 100644 daemon/tests/src/unit/event_log/domain/entities/EventLogEntryTest.cpp create mode 100644 daemon/tests/src/unit/event_log/domain/entities/PackageLogEntryTest.cpp create mode 100644 daemon/tests/src/unit/event_log/domain/entities/PackageUpdateLogEntryTest.cpp create mode 100644 daemon/tests/src/unit/event_log/domain/entities/SyncLogEntryTest.cpp create mode 100644 daemon/tests/src/unit/event_log/domain/entities/helpers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4954bfb..378ecc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ ################################################################################ cmake_minimum_required(VERSION 3.23) project(bxt C CXX) +enable_testing() list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}) @@ -15,6 +16,7 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi") set(FETCHCONTENT_QUIET FALSE) option(BXT_EXPERIMENTAL_COPY_MOVE "Enable experimental copy/move operations" OFF) +option(BXT_BUILD_TESTS "Build unit tests" OFF) ################################################################################ # Dependencies: Fetch and configure external libraries not available in Conan diff --git a/CMakePresets.json b/CMakePresets.json index 9b10888..80ac583 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -20,7 +20,9 @@ "inherits": "base", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "BXT_BUILD_TESTS": "ON", + "CONAN_INSTALL_ARGS": "--build=missing;-o testing=True" } }, { diff --git a/conanfile.py b/conanfile.py index faa0b06..216cab6 100644 --- a/conanfile.py +++ b/conanfile.py @@ -5,7 +5,13 @@ class BxtConanFile(ConanFile): settings = "os", "arch", "compiler", "build_type" generators = "CMakeDeps" - + options = { + "testing": [True, False], + } + default_options = { + "testing": False, + } + def requirements(self): # to link to them you need to change cmake/deps.cmake self.requires("openssl/3.3.1") @@ -27,6 +33,10 @@ def requirements(self): self.requires("cereal/1.3.2") self.requires("libcoro/0.12.1") self.requires("scope-lite/0.2.0") + + if self.options.testing: + print("Testing enabled") + self.requires("catch2/3.7.0") def configure(self): self.options["boost/*"].shared = True diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 83c794e..2444c73 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -9,7 +9,12 @@ project(bxtd LANGUAGES CXX) ################################################################################ add_subdirectory(swagger) +if(BXT_BUILD_TESTS) + add_subdirectory(tests) +endif() + file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS "*.cpp") +list(FILTER SOURCES EXCLUDE REGEX "tests/.*") ################################################################################ # Executable Configuration @@ -41,4 +46,4 @@ target_link_libraries(${PROJECT_NAME} PRIVATE reflectcpp ) -add_dependencies(${PROJECT_NAME} deploy_swagger) +add_dependencies(${PROJECT_NAME} deploy_swagger daemon_tests) diff --git a/daemon/core/domain/entities/Section.h b/daemon/core/domain/entities/Section.h index 904dd7f..4380a31 100644 --- a/daemon/core/domain/entities/Section.h +++ b/daemon/core/domain/entities/Section.h @@ -52,6 +52,7 @@ class Section { std::string string() const { return fmt::format("{}/{}/{}", branch(), repository(), architecture()); } + auto operator<=>(Section const& other) const = default; private: Name m_branch; diff --git a/daemon/core/domain/services/PermissionMatcher.cpp b/daemon/core/domain/services/PermissionMatcher.cpp index e04ab19..73b2267 100644 --- a/daemon/core/domain/services/PermissionMatcher.cpp +++ b/daemon/core/domain/services/PermissionMatcher.cpp @@ -6,6 +6,8 @@ */ #include "PermissionMatcher.h" +#include + namespace bxt::Core::Domain::PermissionMatcher { bool match(Permission const& lh, Permission const& rh) { @@ -23,6 +25,11 @@ bool match(Permission const& lh, Permission const& rh) { } } + if (ltags.size() != rtags.size() && !std::ranges::contains(ltags, "*") + && !std::ranges::contains(rtags, "*")) { + return false; + } + return true; } diff --git a/daemon/core/domain/value_objects/PackageVersion.h b/daemon/core/domain/value_objects/PackageVersion.h index 2e00416..2f8a273 100644 --- a/daemon/core/domain/value_objects/PackageVersion.h +++ b/daemon/core/domain/value_objects/PackageVersion.h @@ -44,6 +44,10 @@ struct PackageVersion { return compare(*this, rh); }; + auto operator==(PackageVersion const& rh) const { + return compare(*this, rh) == 0; + } + static ParseResult from_string(std::string_view str); std::string string() const; diff --git a/daemon/event_log/domain/entities/PackageLogEntry.h b/daemon/event_log/domain/entities/PackageLogEntry.h index 975df2f..6840b8a 100644 --- a/daemon/event_log/domain/entities/PackageLogEntry.h +++ b/daemon/event_log/domain/entities/PackageLogEntry.h @@ -46,6 +46,8 @@ class PackageLogEntry { return m_version; } + bool operator==(PackageLogEntry const& other) const = default; + private: LogEntryType m_type; Core::Domain::Section m_section; diff --git a/daemon/event_log/domain/entities/PackageUpdateLogEntry.h b/daemon/event_log/domain/entities/PackageUpdateLogEntry.h index 1c3e80a..a6e3aae 100644 --- a/daemon/event_log/domain/entities/PackageUpdateLogEntry.h +++ b/daemon/event_log/domain/entities/PackageUpdateLogEntry.h @@ -26,6 +26,8 @@ class PackageUpdateLogEntry { return previous_package_log_entry; } + bool operator==(PackageUpdateLogEntry const& other) const = default; + private: PackageLogEntry package_log_entry; PackageLogEntry previous_package_log_entry; diff --git a/daemon/tests/CMakeLists.txt b/daemon/tests/CMakeLists.txt new file mode 100644 index 0000000..0d53dc5 --- /dev/null +++ b/daemon/tests/CMakeLists.txt @@ -0,0 +1,53 @@ +################################################################################ +# Test Configuration +################################################################################ +enable_testing() +include(CTest) + +find_package(Catch2 REQUIRED) + +################################################################################ +# Test Sources +################################################################################ + +file(GLOB_RECURSE TEST_SOURCES "src/unit/*/**.cpp") +file(GLOB_RECURSE BXT_SOURCES "../*/**.cpp") + +################################################################################ +# Test Executable +################################################################################ + +add_executable(daemon_tests + ${TEST_SOURCES} ${BXT_SOURCES} +) + +target_link_libraries(daemon_tests PRIVATE + Catch2::Catch2WithMain + deps + reflectcpp + Dexode::EventBus +) + +target_include_directories(daemon_tests PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ${lmdbxx_SOURCE_DIR}/include +) + +set_target_properties(daemon_tests PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/tests +) + + +################################################################################ +# Test Data +################################################################################ + +get_target_property(TESTS_RUNTIME_OUTPUT_DIRECTORY daemon_tests RUNTIME_OUTPUT_DIRECTORY) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data DESTINATION ${TESTS_RUNTIME_OUTPUT_DIRECTORY}) + +################################################################################ +# CTest Integration +################################################################################ +include(Catch) + +catch_discover_tests(daemon_tests WORKING_DIRECTORY ${TESTS_RUNTIME_OUTPUT_DIRECTORY}) diff --git a/daemon/tests/data/dummy-1-1-any.pkg.tar.zst b/daemon/tests/data/dummy-1-1-any.pkg.tar.zst new file mode 100644 index 0000000000000000000000000000000000000000..eb546212060e8c448ffc0bbb3f66d049a57ddcc6 GIT binary patch literal 19459 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%0A%CK7<9 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 asORl-F=rt~(c@>{VJI+-KSt(!4X}01(urgM literal 0 HcmV?d00001 diff --git a/daemon/tests/data/dummy-1-1-any.pkg.tar.zst.sig b/daemon/tests/data/dummy-1-1-any.pkg.tar.zst.sig new file mode 100644 index 0000000000000000000000000000000000000000..060ef82131ea85a84af0816c9a9051613a2eeaa7 GIT binary patch literal 140 zcmeC^Vqp;DVlWa@WNFT0KQLqBn_!2dZ8wj-YjBx$ob3`TQ`)CnJ4Iv?(~C0mQp+52 z6Z5hXi}LmIi_#gmI0azJOqv)Ot}`zGk`;e>@nr8;@teOCUl%zlpE^nTv|+zh^~%MC q4EYTIgM%_AWNU5+3kuk|uy)b$j~C?UJc^DK?mFc2j#rPhl?MPEhCJ*5 literal 0 HcmV?d00001 diff --git a/daemon/tests/src/unit/core/domain/entities/PackageTest.cpp b/daemon/tests/src/unit/core/domain/entities/PackageTest.cpp new file mode 100644 index 0000000..29e47a4 --- /dev/null +++ b/daemon/tests/src/unit/core/domain/entities/PackageTest.cpp @@ -0,0 +1,27 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "core/domain/entities/Package.h" + +#include + +using namespace bxt::Core::Domain; + +TEST_CASE("Package", "[core][domain][entities]") { + SECTION("Parse file name") { + REQUIRE(Package::parse_file_name("package-1.0.0-1-x86_64.pkg.tar.zst").value() + == "package"); + REQUIRE(Package::parse_file_name("package-1.0.0-1-any.pkg.tar.zst").value() == "package"); + REQUIRE(Package::parse_file_name("lib32-package-1.0.0-1-x86_64.pkg.tar.zst").value() + == "lib32-package"); + + // Invalid cases + REQUIRE(Package::parse_file_name("package.pkg.tar.zst") == std::nullopt); + REQUIRE(Package::parse_file_name("1.0.0-1-x86_64.pkg.tar.zst") == std::nullopt); + REQUIRE(Package::parse_file_name("package-") == std::nullopt); + REQUIRE(Package::parse_file_name("package-1.0.0-1.pkg.tar.zst") == std::nullopt); + } +} diff --git a/daemon/tests/src/unit/core/domain/entities/SectionTest.cpp b/daemon/tests/src/unit/core/domain/entities/SectionTest.cpp new file mode 100644 index 0000000..f233d96 --- /dev/null +++ b/daemon/tests/src/unit/core/domain/entities/SectionTest.cpp @@ -0,0 +1,49 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "core/domain/entities/Section.h" + +#include + +using namespace bxt::Core::Domain; + +TEST_CASE("Section entity", "[core][domain][entities]") { + SECTION("Construction and getters") { + Section section(Name("stable"), Name("core"), Name("x86_64")); + + REQUIRE(section.branch() == Name("stable")); + REQUIRE(section.repository() == Name("core")); + REQUIRE(section.architecture() == Name("x86_64")); + } + + SECTION("Setters") { + Section section(Name("stable"), Name("core"), Name("x86_64")); + + section.set_branch(Name("testing")); + REQUIRE(section.branch() == Name("testing")); + + section.set_repository(Name("extra")); + REQUIRE(section.repository() == Name("extra")); + + section.set_architecture(Name("aarch64")); + REQUIRE(section.architecture() == Name("aarch64")); + } + + SECTION("ID generation") { + Section section(Name("stable"), Name("core"), Name("x86_64")); + REQUIRE(section.id() == "stable/core/x86_64"); + } + + SECTION("String representation") { + Section section(Name("stable"), Name("core"), Name("x86_64")); + REQUIRE(section.string() == "stable/core/x86_64"); + } + + SECTION("to_string function") { + Section section(Name("stable"), Name("core"), Name("x86_64")); + REQUIRE(bxt::to_string(section) == "stable/core/x86_64"); + } +} diff --git a/daemon/tests/src/unit/core/domain/entities/UserTest.cpp b/daemon/tests/src/unit/core/domain/entities/UserTest.cpp new file mode 100644 index 0000000..8b3ea64 --- /dev/null +++ b/daemon/tests/src/unit/core/domain/entities/UserTest.cpp @@ -0,0 +1,59 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "core/domain/entities/User.h" + +#include + +using namespace bxt::Core::Domain; + +TEST_CASE("User entity", "[core][domain][entities]") { + SECTION("Construction and getters") { + User user(Name("testuser"), "password123"); + + REQUIRE(user.name() == Name("testuser")); + REQUIRE(user.password() == "password123"); + REQUIRE(user.permissions().empty()); + } + + SECTION("Setters") { + User user(Name("testuser"), "password123"); + + user.set_name("newuser"); + REQUIRE(user.name() == Name("newuser")); + + user.set_password("newpassword"); + REQUIRE(user.password() == "newpassword"); + + std::set new_permissions = {Permission("read"), Permission("write")}; + user.set_permissions(new_permissions); + REQUIRE(user.permissions() == new_permissions); + } + + SECTION("ID") { + User user(Name("testuser"), "password123"); + REQUIRE(user.id() == Name("testuser")); + } + + SECTION("Permission checking") { + User user(Name("testuser"), "password123"); + std::set permissions = {Permission("sections.*.*.*"), + Permission("packages.get.stable.core.x86_64")}; + user.set_permissions(permissions); + + REQUIRE(user.has_permission("sections.stable.core.x86_64")); + REQUIRE(user.has_permission("packages.get.stable.core.x86_64")); + REQUIRE_FALSE(user.has_permission("packages.snap.stable.core.x86_64")); + REQUIRE_FALSE(user.has_permission("users.add")); + } + + SECTION("Default constructor") { + User default_user; + REQUIRE(default_user.name() == Name("Unnamed")); + REQUIRE(default_user.password().empty()); + REQUIRE(default_user.permissions().empty()); + } +} diff --git a/daemon/tests/src/unit/core/domain/enums/PoolLocationTest.cpp b/daemon/tests/src/unit/core/domain/enums/PoolLocationTest.cpp new file mode 100644 index 0000000..51f7620 --- /dev/null +++ b/daemon/tests/src/unit/core/domain/enums/PoolLocationTest.cpp @@ -0,0 +1,52 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "core/domain/enums/PoolLocation.h" + +#include +#include + +using namespace bxt::Core::Domain; + +TEST_CASE("PoolLocation enum", "[core][domain][enums]") { + SECTION("to_string conversion") { + REQUIRE(bxt::to_string(PoolLocation::Sync) == "sync"); + REQUIRE(bxt::to_string(PoolLocation::Overlay) == "overlay"); + REQUIRE(bxt::to_string(PoolLocation::Automated) == "automated"); + REQUIRE_THROWS(bxt::to_string(PoolLocation::Unknown)); + } + + SECTION("select_preferred_pool_location") { + SECTION("Empty map") { + std::map empty_map; + auto result = select_preferred_pool_location(empty_map); + REQUIRE_FALSE(result.has_value()); + } + + SECTION("Single element map") { + std::map single_map = {{PoolLocation::Sync, 1}}; + auto result = select_preferred_pool_location(single_map); + REQUIRE(result.has_value()); + REQUIRE(*result == PoolLocation::Sync); + } + + SECTION("Multiple elements map") { + std::map multi_map = { + {PoolLocation::Sync, 1}, {PoolLocation::Overlay, 2}, {PoolLocation::Automated, 3}}; + auto result = select_preferred_pool_location(multi_map); + REQUIRE(result.has_value()); + REQUIRE(*result == PoolLocation::Overlay); + } + + SECTION("Map with Unknown location") { + std::map map_with_unknown = { + {PoolLocation::Unknown, 0}, {PoolLocation::Automated, 1}, {PoolLocation::Sync, 2}}; + auto result = select_preferred_pool_location(map_with_unknown); + REQUIRE(result.has_value()); + REQUIRE(*result == PoolLocation::Automated); + } + } +} diff --git a/daemon/tests/src/unit/core/domain/services/PermissionMatcherTest.cpp b/daemon/tests/src/unit/core/domain/services/PermissionMatcherTest.cpp new file mode 100644 index 0000000..81e1d2d --- /dev/null +++ b/daemon/tests/src/unit/core/domain/services/PermissionMatcherTest.cpp @@ -0,0 +1,62 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "core/domain/services/PermissionMatcher.h" + +#include "core/domain/value_objects/Permission.h" + +#include +using namespace bxt::Core::Domain; + +TEST_CASE("PermissionMatcher", "[core][domain][services]") { + SECTION("Exact match") { + Permission p1("a.b.c"); + Permission p2("a.b.c"); + REQUIRE(PermissionMatcher::match(p1, p2)); + } + + SECTION("Wildcard match") { + Permission p1("a.*.c"); + Permission p2("a.b.c"); + REQUIRE(PermissionMatcher::match(p1, p2)); + } + + SECTION("Partial match with wildcard") { + Permission p1("a.*"); + Permission p2("a.b.c"); + REQUIRE(PermissionMatcher::match(p1, p2)); + } + + SECTION("No match") { + Permission p1("a.b.c"); + Permission p2("x.y.z"); + REQUIRE_FALSE(PermissionMatcher::match(p1, p2)); + } + + SECTION("Different length, no match") { + Permission p1("a.b"); + Permission p2("a.b.c"); + REQUIRE_FALSE(PermissionMatcher::match(p1, p2)); + } + + SECTION("Different length with wildcard, match") { + Permission p1("a.b.*"); + Permission p2("a.b.c.d"); + REQUIRE(PermissionMatcher::match(p1, p2)); + } + + SECTION("Empty permissions") { + Permission p1(""); + Permission p2(""); + REQUIRE(PermissionMatcher::match(p1, p2)); + } + + SECTION("Single wildcard") { + Permission p1("*"); + Permission p2("a.b.c"); + REQUIRE(PermissionMatcher::match(p1, p2)); + } +} diff --git a/daemon/tests/src/unit/core/domain/value_objects/NameTest.cpp b/daemon/tests/src/unit/core/domain/value_objects/NameTest.cpp new file mode 100644 index 0000000..3892b14 --- /dev/null +++ b/daemon/tests/src/unit/core/domain/value_objects/NameTest.cpp @@ -0,0 +1,41 @@ + +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "core/domain/value_objects/Name.h" + +#include +#include + +using namespace bxt::Core::Domain; + +TEST_CASE("Name", "[core][domain][value_objects]") { + SECTION("Construction and string conversion") { + Name name("TestName"); + REQUIRE(static_cast(name) == "TestName"); + } + + SECTION("Empty name throws exception") { + REQUIRE_THROWS(Name("")); + } + + SECTION("Comparison") { + Name name1("Name1"); + Name name2("Name1"); + Name name3("Name2"); + + REQUIRE(name1 == name2); + REQUIRE(name1 != name3); + REQUIRE(name1 < name3); + REQUIRE(name3 > name1); + } + + SECTION("Formatting") { + Name name("FormatTest"); + std::string formatted = fmt::format("{}", name); + REQUIRE(formatted == "FormatTest"); + } +} diff --git a/daemon/tests/src/unit/core/domain/value_objects/PackageArchitectureTest.cpp b/daemon/tests/src/unit/core/domain/value_objects/PackageArchitectureTest.cpp new file mode 100644 index 0000000..eb5c4c5 --- /dev/null +++ b/daemon/tests/src/unit/core/domain/value_objects/PackageArchitectureTest.cpp @@ -0,0 +1,44 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "core/domain/value_objects/PackageArchitecture.h" + +#include +#include + +using namespace bxt::Core::Domain; + +TEST_CASE("PackageArchitecture value object", "[core][domain][value_objects]") { + SECTION("Default constructor") { + PackageArchitecture arch; + REQUIRE(std::string(arch) == "any"); + } + + SECTION("Constructor with non-empty string") { + PackageArchitecture arch("x86_64"); + REQUIRE(std::string(arch) == "x86_64"); + } + + SECTION("Constructor with empty string") { + PackageArchitecture arch(""); + REQUIRE(std::string(arch) == "any"); + } + + SECTION("Implicit conversion to string") { + PackageArchitecture arch("arm64"); + std::string arch_str = arch; + REQUIRE(arch_str == "arm64"); + } + + SECTION("Comparison") { + PackageArchitecture arch1("x86_64"); + PackageArchitecture arch2("x86_64"); + PackageArchitecture arch3("arm64"); + + REQUIRE(std::string(arch1) == std::string(arch2)); + REQUIRE(std::string(arch1) != std::string(arch3)); + } +} diff --git a/daemon/tests/src/unit/core/domain/value_objects/PackagePoolEntryTest.cpp b/daemon/tests/src/unit/core/domain/value_objects/PackagePoolEntryTest.cpp new file mode 100644 index 0000000..727a8be --- /dev/null +++ b/daemon/tests/src/unit/core/domain/value_objects/PackagePoolEntryTest.cpp @@ -0,0 +1,59 @@ + +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "core/domain/value_objects/PackagePoolEntry.h" + +#include +#include + +using namespace bxt::Core::Domain; + +TEST_CASE("PackagePoolEntry", "[core][domain][value_objects]") { + SECTION("Parse valid file path") { + auto cwd = std::filesystem::absolute("."); + std::filesystem::path file_path = "data/dummy-1-1-any.pkg.tar.zst"; + auto result = PackagePoolEntry::parse_file_path(file_path, std::nullopt); + REQUIRE(result.has_value()); + auto entry = result.value(); + REQUIRE(entry.file_path() == file_path); + REQUIRE(entry.version().string() == "1-1"); + } + + SECTION("Parse file path with signature") { + std::filesystem::path file_path = "data/dummy-1-1-any.pkg.tar.zst"; + std::filesystem::path sig_path = "data/dummy-1-1-any.pkg.tar.zst.sig"; + auto result = PackagePoolEntry::parse_file_path(file_path, sig_path); + REQUIRE(result.has_value()); + auto entry = result.value(); + REQUIRE(entry.file_path() == file_path); + REQUIRE(entry.signature_path() == sig_path); + } + + SECTION("Parse invalid file path") { + std::filesystem::path file_path = "invalid-package-name"; + auto result = PackagePoolEntry::parse_file_path(file_path, std::nullopt); + REQUIRE_FALSE(result.has_value()); + REQUIRE(result.error().error_code + == PackagePoolEntry::ParsingError::ErrorCode::InvalidFilename); + } + + + SECTION("Accessors") { + std::filesystem::path file_path = "data/dummy-1-1-x86_64.pkg.tar.zst"; + std::filesystem::path sig_path = "data/dummy-1-1-x86_64.pkg.tar.zst.sig"; + bxt::Utilities::AlpmDb::Desc desc; + PackageVersion version = PackageVersion::from_string("1.0.0-1").value(); + + PackagePoolEntry entry(file_path, sig_path, desc, version); + + REQUIRE(entry.file_path() == file_path); + REQUIRE(entry.signature_path() == sig_path); + REQUIRE(entry.version().string() == version.string()); + REQUIRE(entry.desc().desc == desc.desc); + REQUIRE(entry.desc().files == desc.files); + } +} diff --git a/daemon/tests/src/unit/core/domain/value_objects/PackageVersionTest.cpp b/daemon/tests/src/unit/core/domain/value_objects/PackageVersionTest.cpp new file mode 100644 index 0000000..45b60bf --- /dev/null +++ b/daemon/tests/src/unit/core/domain/value_objects/PackageVersionTest.cpp @@ -0,0 +1,66 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "core/domain/value_objects/PackageVersion.h" + +#include + +using namespace bxt::Core::Domain; + +TEST_CASE("PackageVersion", "[core][domain][value_objects]") { + SECTION("Parse valid version string") { + auto result = PackageVersion::from_string("1:2.3.4-5"); + REQUIRE(result.has_value()); + auto version = result.value(); + REQUIRE(version.epoch == Name("1")); + REQUIRE(version.version == Name("2.3.4")); + REQUIRE(version.release.has_value()); + REQUIRE(version.release.value() == Name("5")); + } + + SECTION("Parse version string without epoch") { + auto result = PackageVersion::from_string("2.3.4-5"); + REQUIRE(result.has_value()); + auto version = result.value(); + REQUIRE(version.epoch == Name("0")); + REQUIRE(version.version == Name("2.3.4")); + REQUIRE(version.release.has_value()); + REQUIRE(version.release.value() == Name("5")); + } + + SECTION("Parse version string without release") { + auto result = PackageVersion::from_string("1:2.3.4"); + REQUIRE(result.has_value()); + auto version = result.value(); + REQUIRE(version.epoch == Name("1")); + REQUIRE(version.version == Name("2.3.4")); + REQUIRE_FALSE(version.release.has_value()); + } + + SECTION("Compare versions") { + auto v1 = PackageVersion::from_string("1:2.3.4-5").value(); + auto v2 = PackageVersion::from_string("1:2.3.4-6").value(); + auto v3 = PackageVersion::from_string("2:1.0.0-1").value(); + + REQUIRE(v1 < v2); + REQUIRE(v2 < v3); + REQUIRE(v1 < v3); + } + + SECTION("Version to string") { + auto version = PackageVersion::from_string("1:2.3.4-5").value(); + REQUIRE(version.string() == "1:2.3.4-5"); + + auto version_no_epoch = PackageVersion::from_string("2.3.4-5").value(); + REQUIRE(version_no_epoch.string() == "2.3.4-5"); + + auto version_no_release = PackageVersion::from_string("1:2.3.4").value(); + REQUIRE(version_no_release.string() == "1:2.3.4"); + + auto version_simple = PackageVersion::from_string("2.3.4").value(); + REQUIRE(version_simple.string() == "2.3.4"); + } +} diff --git a/daemon/tests/src/unit/core/domain/value_objects/PermissionTest.cpp b/daemon/tests/src/unit/core/domain/value_objects/PermissionTest.cpp new file mode 100644 index 0000000..128441e --- /dev/null +++ b/daemon/tests/src/unit/core/domain/value_objects/PermissionTest.cpp @@ -0,0 +1,60 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "core/domain/value_objects/Permission.h" + +#include + +using namespace bxt::Core::Domain; + +TEST_CASE("Permission", "[core][domain][value_objects]") { + SECTION("Create permission from string") { + Permission permission("sections.stable.core.x86_64"); + REQUIRE(permission.tags().size() == 4); + REQUIRE(permission.tags()[0] == "sections"); + REQUIRE(permission.tags()[1] == "stable"); + REQUIRE(permission.tags()[2] == "core"); + REQUIRE(permission.tags()[3] == "x86_64"); + } + + SECTION("Convert permission to string") { + Permission permission("packages.get.unstable.extra.arm"); + std::string permission_str = permission; + REQUIRE(permission_str == "packages.get.unstable.extra.arm"); + } + + SECTION("Compare permissions") { + Permission p1("users.add"); + Permission p2("users.remove"); + Permission p3("users.add"); + + REQUIRE(p1 < p2); + REQUIRE(p1 == p3); + REQUIRE(p2 > p1); + } + + SECTION("Create permission with single tag") { + Permission permission("logs"); + REQUIRE(permission.tags().size() == 1); + REQUIRE(permission.tags()[0] == "logs"); + } + + SECTION("Create permission with multiple tags") { + Permission permission("packages.commit.testing.community.aarch64"); + REQUIRE(permission.tags().size() == 5); + REQUIRE(permission.tags()[0] == "packages"); + REQUIRE(permission.tags()[1] == "commit"); + REQUIRE(permission.tags()[2] == "testing"); + REQUIRE(permission.tags()[3] == "community"); + REQUIRE(permission.tags()[4] == "aarch64"); + } + + SECTION("Create permission with empty string") { + Permission permission(""); + REQUIRE(permission.tags().size() == 1); + REQUIRE(permission.tags()[0].empty()); + } +} diff --git a/daemon/tests/src/unit/event_log/domain/entities/CommitLogEntryTest.cpp b/daemon/tests/src/unit/event_log/domain/entities/CommitLogEntryTest.cpp new file mode 100644 index 0000000..5910479 --- /dev/null +++ b/daemon/tests/src/unit/event_log/domain/entities/CommitLogEntryTest.cpp @@ -0,0 +1,58 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "event_log/domain/entities/CommitLogEntry.h" + +#include "helpers.h" + +#include + +using namespace bxt::EventLog::Domain; +using namespace bxt::Core::Domain; + +// Helper functions to create PackageLogEntry objects + +TEST_CASE("CommitLogEntry entity", "[event_log][domain][entities]") { + SECTION("Construction and getters") { + Section section {Name {"stable"}, Name {"core"}, Name {"x86_64"}}; + std::vector added = {bxt::tests::create_pkg_entry1(), + bxt::tests::create_pkg_entry2()}; + std::vector deleted = {bxt::tests::create_pkg_entry3()}; + std::vector moved = {PackageUpdateLogEntry( + bxt::tests::create_pkg_entry4(), bxt::tests::create_pkg_entry4())}; + std::vector copied = {PackageUpdateLogEntry( + bxt::tests::create_pkg_entry5(), bxt::tests::create_pkg_entry5())}; + + CommitLogEntry entry(std::chrono::system_clock::now(), "John Doe", added, deleted, moved, + copied); + + REQUIRE(entry.commiter_name() == "John Doe"); + REQUIRE(entry.added() == added); + REQUIRE(entry.deleted() == deleted); + REQUIRE(entry.moved() == moved); + REQUIRE(entry.copied() == copied); + REQUIRE(entry.type() == EventLogEntryType::Commit); + } + + SECTION("Time comparison") { + auto time1 = std::chrono::system_clock::now(); + auto time2 = time1 + std::chrono::hours(1); + + CommitLogEntry entry1(time1, "Alice", {}, {}, {}, {}); + CommitLogEntry entry2(time2, "Bob", {}, {}, {}, {}); + + REQUIRE(entry1.time() < entry2.time()); + } + + SECTION("Empty collections") { + CommitLogEntry entry(std::chrono::system_clock::now(), "Empty", {}, {}, {}, {}); + + REQUIRE(entry.added().empty()); + REQUIRE(entry.deleted().empty()); + REQUIRE(entry.moved().empty()); + REQUIRE(entry.copied().empty()); + } +} diff --git a/daemon/tests/src/unit/event_log/domain/entities/DeployLogEntryTest.cpp b/daemon/tests/src/unit/event_log/domain/entities/DeployLogEntryTest.cpp new file mode 100644 index 0000000..ea59e3c --- /dev/null +++ b/daemon/tests/src/unit/event_log/domain/entities/DeployLogEntryTest.cpp @@ -0,0 +1,47 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "event_log/domain/entities/DeployLogEntry.h" + +#include "helpers.h" + +#include + +using namespace bxt::EventLog::Domain; +using namespace bxt::Core::Domain; + +TEST_CASE("DeployLogEntry entity", "[event_log][domain][entities]") { + SECTION("Construction and getters") { + Section section {Name {"stable"}, Name {"core"}, Name {"x86_64"}}; + std::vector added = {bxt::tests::create_pkg_entry1(), + bxt::tests::create_pkg_entry2()}; + + DeployLogEntry entry(std::chrono::system_clock::now(), + "https://example.com/actions/run/12345", added); + + REQUIRE(entry.runner_url() == "https://example.com/actions/run/12345"); + REQUIRE(entry.added() == added); + + REQUIRE(entry.type() == EventLogEntryType::Deploy); + } + + SECTION("Time comparison") { + auto time1 = std::chrono::system_clock::now(); + auto time2 = time1 + std::chrono::hours(1); + + DeployLogEntry entry1(time1, "https://example.com/actions/run/12345", {}); + DeployLogEntry entry2(time2, "https://example.com/actions/run/54321", {}); + + REQUIRE(entry1.time() < entry2.time()); + } + + SECTION("Empty collections") { + DeployLogEntry entry(std::chrono::system_clock::now(), + "https://example.com/actions/run/00000", {}); + + REQUIRE(entry.added().empty()); + } +} diff --git a/daemon/tests/src/unit/event_log/domain/entities/EventLogEntryTest.cpp b/daemon/tests/src/unit/event_log/domain/entities/EventLogEntryTest.cpp new file mode 100644 index 0000000..b7ab3ca --- /dev/null +++ b/daemon/tests/src/unit/event_log/domain/entities/EventLogEntryTest.cpp @@ -0,0 +1,43 @@ + +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "event_log/domain/entities/EventLogEntry.h" + +#include +#include + +using namespace bxt::EventLog::Domain; + +TEST_CASE("EventLogEntryBase", "[event_log][domain][entities]") { + SECTION("Construction and basic properties") { + auto now = std::chrono::system_clock::now(); + EventLogEntryBase entry {EventLogEntryType::Commit, now}; + + REQUIRE(entry.id() == std::to_string(now.time_since_epoch().count())); + REQUIRE(entry.time() == now); + REQUIRE(entry.type() == EventLogEntryType::Commit); + } + + SECTION("Different types") { + auto now = std::chrono::system_clock::now(); + EventLogEntryBase commit_entry {EventLogEntryType::Commit, now}; + EventLogEntryBase deploy_entry {EventLogEntryType::Deploy, now}; + + REQUIRE(commit_entry.type() == EventLogEntryType::Commit); + REQUIRE(deploy_entry.type() == EventLogEntryType::Deploy); + } + + SECTION("Unique IDs for different time points") { + auto time1 = std::chrono::system_clock::now(); + auto time2 = time1 + std::chrono::seconds(1); + + EventLogEntryBase entry1 {EventLogEntryType::Commit, time1}; + EventLogEntryBase entry2 {EventLogEntryType::Deploy, time2}; + + REQUIRE(entry1.id() != entry2.id()); + } +} diff --git a/daemon/tests/src/unit/event_log/domain/entities/PackageLogEntryTest.cpp b/daemon/tests/src/unit/event_log/domain/entities/PackageLogEntryTest.cpp new file mode 100644 index 0000000..faea994 --- /dev/null +++ b/daemon/tests/src/unit/event_log/domain/entities/PackageLogEntryTest.cpp @@ -0,0 +1,29 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "event_log/domain/entities/PackageLogEntry.h" + +#include "core/domain/entities/Section.h" +#include "core/domain/enums/PoolLocation.h" +#include "core/domain/value_objects/PackageVersion.h" + +#include + +using namespace bxt::Core::Domain; +using namespace bxt::EventLog::Domain; + +TEST_CASE("PackageLogEntry", "[event_log][domain][entities]") { + SECTION("Construction and basic properties") { + Section section {Name {"stable"}, Name {"core"}, Name {"x86_64"}}; + PackageLogEntry entry {LogEntryType::Add, section, "test-package", PoolLocation::Sync, + PackageVersion::from_string("1.0.0-1").value()}; + + REQUIRE(entry.name() == "test-package"); + REQUIRE(entry.version()->string() == "1.0.0-1"); + REQUIRE(entry.section().string() == "stable/core/x86_64"); + REQUIRE(entry.location() == PoolLocation::Sync); + } +} diff --git a/daemon/tests/src/unit/event_log/domain/entities/PackageUpdateLogEntryTest.cpp b/daemon/tests/src/unit/event_log/domain/entities/PackageUpdateLogEntryTest.cpp new file mode 100644 index 0000000..877cad7 --- /dev/null +++ b/daemon/tests/src/unit/event_log/domain/entities/PackageUpdateLogEntryTest.cpp @@ -0,0 +1,54 @@ + +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "event_log/domain/entities/PackageUpdateLogEntry.h" + +#include "core/domain/entities/Section.h" +#include "core/domain/enums/PoolLocation.h" +#include "core/domain/value_objects/PackageVersion.h" + +#include + +using namespace bxt::Core::Domain; +using namespace bxt::EventLog::Domain; + +TEST_CASE("PackageUpdateLogEntry", "[event_log][domain][entities]") { + SECTION("Construction and basic properties") { + Section section {Name {"stable"}, Name {"core"}, Name {"x86_64"}}; + PackageLogEntry old_entry {LogEntryType::Add, section, "test-package", PoolLocation::Sync, + PackageVersion::from_string("1.0.0-1").value()}; + PackageLogEntry new_entry {LogEntryType::Update, section, "test-package", + PoolLocation::Sync, + PackageVersion::from_string("1.1.0-1").value()}; + + PackageUpdateLogEntry update_entry {new_entry, old_entry}; + + REQUIRE(update_entry.package().name() == "test-package"); + REQUIRE(update_entry.package().version()->string() == "1.1.0-1"); + REQUIRE(update_entry.package().section().string() == "stable/core/x86_64"); + REQUIRE(update_entry.package().location() == PoolLocation::Sync); + + REQUIRE(update_entry.previous_package().name() == "test-package"); + REQUIRE(update_entry.previous_package().version()->string() == "1.0.0-1"); + REQUIRE(update_entry.previous_package().section().string() == "stable/core/x86_64"); + REQUIRE(update_entry.previous_package().location() == PoolLocation::Sync); + } + + SECTION("Equality comparison") { + Section section {Name {"stable"}, Name {"core"}, Name {"x86_64"}}; + PackageLogEntry old_entry {LogEntryType::Add, section, "test-package", PoolLocation::Sync, + PackageVersion::from_string("1.0.0-1").value()}; + PackageLogEntry new_entry {LogEntryType::Update, section, "test-package", + PoolLocation::Sync, + PackageVersion::from_string("1.1.0-1").value()}; + + PackageUpdateLogEntry update_entry1 {new_entry, old_entry}; + PackageUpdateLogEntry update_entry2 {new_entry, old_entry}; + + REQUIRE(update_entry1 == update_entry2); + } +} diff --git a/daemon/tests/src/unit/event_log/domain/entities/SyncLogEntryTest.cpp b/daemon/tests/src/unit/event_log/domain/entities/SyncLogEntryTest.cpp new file mode 100644 index 0000000..be605b3 --- /dev/null +++ b/daemon/tests/src/unit/event_log/domain/entities/SyncLogEntryTest.cpp @@ -0,0 +1,63 @@ + +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ +#include "event_log/domain/entities/SyncLogEntry.h" + +#include + +using namespace bxt::EventLog::Domain; +using namespace bxt::Core::Domain; + +// Helper functions to create PackageLogEntry objects +PackageLogEntry create_pkg_entry1() { + Section section {Name {"stable"}, Name {"core"}, Name {"x86_64"}}; + return PackageLogEntry {LogEntryType::Add, section, "pkg1", PoolLocation::Sync, + PackageVersion::from_string("1.0").value()}; +} + +PackageLogEntry create_pkg_entry2() { + Section section {Name {"stable"}, Name {"core"}, Name {"x86_64"}}; + return PackageLogEntry {LogEntryType::Add, section, "pkg2", PoolLocation::Sync, + PackageVersion::from_string("2.0").value()}; +} + +PackageLogEntry create_pkg_entry3() { + Section section {Name {"stable"}, Name {"core"}, Name {"x86_64"}}; + return PackageLogEntry {LogEntryType::Remove, section, "pkg3", PoolLocation::Sync, + PackageVersion::from_string("3.0").value()}; +} + +TEST_CASE("SyncLogEntry entity", "[event_log][domain][entities]") { + SECTION("Construction and getters") { + std::vector added = {create_pkg_entry1(), create_pkg_entry2()}; + std::vector deleted = {create_pkg_entry3()}; + + SyncLogEntry entry(std::chrono::system_clock::now(), "John Doe", added, deleted); + + REQUIRE(entry.sync_trigger_username() == "John Doe"); + REQUIRE(entry.added() == added); + REQUIRE(entry.deleted() == deleted); + REQUIRE(entry.type() == EventLogEntryType::Sync); + } + + SECTION("Time comparison") { + auto time1 = std::chrono::system_clock::now(); + auto time2 = time1 + std::chrono::hours(1); + + SyncLogEntry entry1(time1, "Alice", {}, {}); + SyncLogEntry entry2(time2, "Bob", {}, {}); + + REQUIRE(entry1.time() < entry2.time()); + } + + SECTION("Empty collections") { + SyncLogEntry entry(std::chrono::system_clock::now(), "Empty", {}, {}); + + REQUIRE(entry.added().empty()); + REQUIRE(entry.deleted().empty()); + } +} diff --git a/daemon/tests/src/unit/event_log/domain/entities/helpers.h b/daemon/tests/src/unit/event_log/domain/entities/helpers.h new file mode 100644 index 0000000..c0f0e7b --- /dev/null +++ b/daemon/tests/src/unit/event_log/domain/entities/helpers.h @@ -0,0 +1,46 @@ +/* === This file is part of bxt === + * + * SPDX-FileCopyrightText: 2024 Artem Grinev + * SPDX-License-Identifier: AGPL-3.0-or-later + * + */ + +#pragma once +#include "core/domain/entities/Section.h" +#include "core/domain/value_objects/Name.h" +#include "event_log/domain/entities/PackageLogEntry.h" + +namespace bxt::tests { +using namespace bxt::Core::Domain; +using namespace bxt::EventLog::Domain; +inline PackageLogEntry create_pkg_entry1() { + Section section {Name {"stable"}, Name {"core"}, Name {"x86_64"}}; + return PackageLogEntry {LogEntryType::Add, section, "pkg1", PoolLocation::Sync, + PackageVersion::from_string("1.0").value()}; +} + +inline PackageLogEntry create_pkg_entry2() { + Section section {Name {"stable"}, Name {"core"}, Name {"x86_64"}}; + return PackageLogEntry {LogEntryType::Add, section, "pkg2", PoolLocation::Sync, + PackageVersion::from_string("2.0").value()}; +} + +inline PackageLogEntry create_pkg_entry3() { + Section section {Name {"stable"}, Name {"core"}, Name {"x86_64"}}; + return PackageLogEntry {LogEntryType::Remove, section, "pkg3", PoolLocation::Sync, + PackageVersion::from_string("3.0").value()}; +} + +inline PackageLogEntry create_pkg_entry4() { + Section section {Name {"testing"}, Name {"extra"}, Name {"x86_64"}}; + return PackageLogEntry {LogEntryType::Add, section, "pkg4", PoolLocation::Sync, + PackageVersion::from_string("4.0").value()}; +} + +inline PackageLogEntry create_pkg_entry5() { + Section section {Name {"unstable"}, Name {"community"}, Name {"x86_64"}}; + return PackageLogEntry {LogEntryType::Add, section, "pkg5", PoolLocation::Sync, + PackageVersion::from_string("5.0").value()}; +} + +} // namespace bxt::tests