/** * @file test_context.cpp * @brief Context lifecycle, override validation, and configuration reading * * @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" int main(void) { /* ---- an explicit override that cannot work refuses at open ---- */ { dpm_open_overrides bad_conf = {"/does/not/exist/conf", nullptr, nullptr, -1, nullptr}; CHECK(dpm_open(&bad_conf) == nullptr); dpm_open_overrides bad_level = {nullptr, nullptr, nullptr, 99, nullptr}; CHECK(dpm_open(&bad_level) == nullptr); dpm_open_overrides low_level = {nullptr, nullptr, nullptr, -2, nullptr}; CHECK(dpm_open(&low_level) == nullptr); } /* ---- a NULL overrides pointer opens against system defaults ---- */ { dpm_ctx* system_ctx = dpm_open(nullptr); CHECK(system_ctx != nullptr); if (system_ctx) { const char* path = dpm_get_resolved_module_path(system_ctx); CHECK(path != nullptr && *path); dpm_close(system_ctx); } } /* ---- NULL is a no-op everywhere a context is expected ---- */ { dpm_close(nullptr); dpm_log(nullptr, DPM_LOG_INFO, "dropped"); CHECK(dpm_get_resolved_module_path(nullptr) == nullptr); CHECK(dpm_get_last_error(nullptr) == nullptr); CHECK(dpm_config_get(nullptr, "core", "modules", "path") == nullptr); } 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; } /* ---- the version the library reports is the one it was built as ---- */ CHECK(std::strcmp(dpm_core_version(), DPM_CORE_VERSION_EXPECTED) == 0); /* ---- configuration resolves per namespace, per section ---- */ { const char* v = dpm_config_get(ctx, "testmod", "main", "key"); CHECK(v != nullptr && std::strcmp(v, "value") == 0); v = dpm_config_get(ctx, "testmod", "section2", "other"); CHECK(v != nullptr && std::strcmp(v, "42") == 0); CHECK(dpm_config_get(ctx, "testmod", "main", "absent") == nullptr); CHECK(dpm_config_get(ctx, "testmod", "nosection", "key") == nullptr); CHECK(dpm_config_get(ctx, "nomodule", "main", "key") == nullptr); CHECK(dpm_config_get(ctx, nullptr, "main", "key") == nullptr); } /* ---- an override beats the value configuration supplied ---- */ { const char* configured = dpm_config_get(ctx, "core", "modules", "path"); CHECK(configured != nullptr); const char* path = dpm_get_resolved_module_path(ctx); CHECK(path != nullptr); CHECK(path != nullptr && std::strncmp(path, TEST_FIXTURE_MODULES, std::strlen(TEST_FIXTURE_MODULES)) == 0); } /* ---- a resolved directory carries a trailing separator ---- */ { const char* path = dpm_get_resolved_module_path(ctx); CHECK(path != nullptr && *path && path[std::strlen(path) - 1] == '/'); } /* ---- the error slot starts empty and holds what was last written --- */ { CHECK(dpm_get_last_error(ctx) == nullptr); dpm_set_last_error(ctx, "first reason"); CHECK(error_contains(ctx, "first reason")); dpm_set_last_error(ctx, "second reason"); CHECK(error_contains(ctx, "second reason")); CHECK(!error_contains(ctx, "first reason")); dpm_set_last_error(ctx, nullptr); CHECK(error_contains(ctx, "second reason")); dpm_set_last_error(nullptr, "ignored"); } dpm_close(ctx); return harness_report("context"); }