/** * @file test_aliases.cpp * @brief Alternate module names: resolution, recording, and enumeration * * @copyright Copyright (c) 2026 SILO GROUP LLC * @author Chris Punches * * Part of the Dark Horse Linux Package Manager (DPM) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "harness.hpp" #include #include namespace fs = std::filesystem; int main(void) { const std::string scratch = std::string(TEST_SCRATCH_ROOT) + "/aliases"; /* ---- a recorded alias reaches the module it names ---- */ { dpm_open_overrides overrides = {TEST_FIXTURE_CONF, TEST_FIXTURE_MODULES, nullptr, -1, TEST_FIXTURE_METADATA}; dpm_ctx* ctx = dpm_open(&overrides); CHECK(ctx != nullptr); if (!ctx) { std::fprintf(stderr, "cannot continue without a context\n"); return 1; } dpm_module* by_alias = dpm_require(ctx, "goodie"); CHECK(by_alias != nullptr); dpm_module_info seen; if (by_alias) { CHECK(dpm_get_module_info(ctx, by_alias, &seen) == 0); CHECK(std::strcmp(seen.name, "good") == 0); } /* the alias and the real name reach the same load */ CHECK(dpm_require(ctx, "good") == by_alias); CHECK(dpm_require(ctx, "gd") == by_alias); /* a name that is neither a module nor an alias stays unresolved */ CHECK(dpm_require(ctx, "nosuchname") == nullptr); dpm_close(ctx); } /* ---- enumeration reports every alias, or one module's ---- */ { dpm_open_overrides overrides = {TEST_FIXTURE_CONF, TEST_FIXTURE_MODULES, nullptr, -1, TEST_FIXTURE_METADATA}; dpm_ctx* ctx = dpm_open(&overrides); CHECK(ctx != nullptr); if (!ctx) { return 1; } dpm_alias_cursor* cur = dpm_list_module_aliases(ctx, nullptr); CHECK(cur != nullptr); if (cur) { int count = 0; dpm_alias_info info; while (dpm_alias_cursor_next(cur, &info) == 0) { count++; CHECK(info.alias != nullptr && *info.alias); CHECK(std::strcmp(info.module, "good") == 0); } CHECK(count == 2); CHECK(dpm_alias_cursor_next(cur, &info) != 0); dpm_alias_cursor_free(cur); } cur = dpm_list_module_aliases(ctx, "good"); CHECK(cur != nullptr); if (cur) { int count = 0; dpm_alias_info info; while (dpm_alias_cursor_next(cur, &info) == 0) { count++; } CHECK(count == 2); dpm_alias_cursor_free(cur); } cur = dpm_list_module_aliases(ctx, "nosuchmodule"); CHECK(cur != nullptr); if (cur) { dpm_alias_info info; CHECK(dpm_alias_cursor_next(cur, &info) != 0); dpm_alias_cursor_free(cur); } CHECK(dpm_list_module_aliases(nullptr, nullptr) == nullptr); CHECK(dpm_alias_cursor_next(nullptr, nullptr) != 0); dpm_alias_cursor_free(nullptr); dpm_close(ctx); } /* ---- recording and removing names against a writable directory ---- */ { fs::remove_all(scratch); dpm_open_overrides overrides = {TEST_FIXTURE_CONF, TEST_FIXTURE_MODULES, nullptr, -1, scratch.c_str()}; dpm_ctx* ctx = dpm_open(&overrides); CHECK(ctx != nullptr); if (!ctx) { return 1; } /* installing records what the module declared */ CHECK(dpm_install_module(ctx, "good") == 0); CHECK(fs::exists(scratch + "/modules.aliases")); dpm_alias_cursor* cur = dpm_list_module_aliases(ctx, "good"); CHECK(cur != nullptr); if (cur) { int count = 0; dpm_alias_info info; while (dpm_alias_cursor_next(cur, &info) == 0) { count++; } CHECK(count == 2); dpm_alias_cursor_free(cur); } /* a name already recorded is refused rather than repointed */ CHECK(dpm_add_module_alias(ctx, "good", "goodie") != 0); CHECK(error_contains(ctx, "already resolves")); /* an installed module's own name is not available */ CHECK(dpm_add_module_alias(ctx, "good", "good") != 0); CHECK(error_contains(ctx, "installed module")); /* bad arguments are refused */ CHECK(dpm_add_module_alias(nullptr, "good", "x") != 0); CHECK(dpm_add_module_alias(ctx, nullptr, "x") != 0); CHECK(dpm_add_module_alias(ctx, "good", nullptr) != 0); CHECK(dpm_add_module_alias(ctx, "good", "") != 0); /* a free name is recorded and resolves in a later context */ CHECK(dpm_add_module_alias(ctx, "good", "gg") == 0); dpm_ctx* reader = dpm_open(&overrides); CHECK(reader != nullptr); if (reader) { CHECK(dpm_require(reader, "gg") != nullptr); dpm_close(reader); } /* removal takes the name back out */ CHECK(dpm_remove_module_alias(ctx, "gg") == 0); CHECK(dpm_remove_module_alias(ctx, "gg") != 0); CHECK(error_contains(ctx, "not recorded")); CHECK(dpm_remove_module_alias(ctx, nullptr) != 0); CHECK(dpm_remove_module_alias(nullptr, "gg") != 0); /* uninstalling a module takes its aliases with it */ CHECK(dpm_uninstall_module(ctx, "good") == 0); dpm_ctx* after = dpm_open(&overrides); CHECK(after != nullptr); if (after) { dpm_alias_cursor* empty = dpm_list_module_aliases(after, nullptr); CHECK(empty != nullptr); if (empty) { dpm_alias_info info; CHECK(dpm_alias_cursor_next(empty, &info) != 0); dpm_alias_cursor_free(empty); } dpm_close(after); } dpm_close(ctx); } return harness_report("aliases"); }