// Copyright (C) 2026 Viorel Munteanu // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 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 General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #pragma once #include #include #include #include "config_file.h" // The effective AppConfig for the current -t/--test run -- set once by // run_self_tests() (self_test.cpp) from whatever main() resolved (respecting // -c/--config-file, same as any other command), before Catch2 ever runs a // TEST_CASE. Test code that creates a real container (test_rootless_run.cpp's // own run_in_fixture()) reads this instead of hardcoding a fresh, default // AppConfig{}, so e.g. `-c -t -- "[integration][net]"` // actually exercises what happens with pid/cgroup isolation disabled. Plain // default-constructed AppConfig{} otherwise (matching every test's prior, // unconditional behavior) -- a bare `-t` with no `-c` and no real config file // changes nothing. extern AppConfig g_test_app_config; // Path to a real, runnable OCI Image Layout tar (something with an actual // /bin/sh, unlike tests/gen_fixture.py's minimal single-file fixture used // by the plain mount/unmount smoke test) for [integration][net] tests that // need to actually run a command inside a container. Searches // images/busybox.tar relative to the current working directory -- this // project's own established manual-testing convention (see images/ at the // repo root, gitignored). nullopt if not found; callers should SKIP() // rather than fail, since fetching one is optional -- see // tests/setup-tests.py. std::optional find_busybox_fixture(); // RAII scratch XDG_CONFIG_HOME/XDG_STATE_HOME: for its lifetime, both env // vars point at a fresh throwaway directory under /tmp, so // config_file_path()/xdg_state_dir() (config_file.cpp/pid_file.cpp) // resolve entirely under it instead of the real developer's own $HOME -- // integration tests that actually mount/run something must never touch // real config/state. Restores whatever the two env vars were before (unset // if they were unset) and removes the scratch directory on destruction. class ScratchXdgDirs { public: ScratchXdgDirs(); ~ScratchXdgDirs(); ScratchXdgDirs(const ScratchXdgDirs&) = delete; ScratchXdgDirs& operator=(const ScratchXdgDirs&) = delete; const std::filesystem::path& path() const { return path_; } private: std::filesystem::path path_; std::optional previous_config_home_; std::optional previous_state_home_; }; // RAII stdout capture: for its lifetime, this process's own fd 1 (and // anything a forked/exec'd child -- e.g. the real bwrap-sandboxed command, // via dispatch_command()'s ordinary fork/exec chain -- inherits from it) is // redirected to a throwaway temp file instead of the real terminal/pipe. // contents() flushes C stdio first (so any of *this* process's own // buffered writes land in the file before being read back) and returns // everything captured so far; the destructor restores the original fd 1 // and removes the temp file. Kept narrowly scoped around just the call // under test, so Catch2's own console reporter output is never captured // by mistake. class CapturedStdout { public: CapturedStdout(); ~CapturedStdout(); CapturedStdout(const CapturedStdout&) = delete; CapturedStdout& operator=(const CapturedStdout&) = delete; std::string contents(); private: int saved_fd_ = -1; std::filesystem::path temp_path_; };