GCC Code Coverage Report


Directory: ./
File: modules/util/include/util.hpp
Date: 2026-08-18 01:54:56
Exec Total Coverage
Lines: 32 33 97.0%
Functions: 7 7 100.0%
Branches: 32 68 47.1%

Line Branch Exec Source
1 #pragma once
2
3 #include <algorithm>
4 #include <array>
5 #include <atomic>
6 #include <cctype>
7 #include <filesystem>
8 #include <memory>
9 #include <sstream>
10 #include <string>
11 #include <string_view>
12 #include <system_error>
13
14 #include "nlohmann/json_fwd.hpp"
15
16 #ifdef _MSC_VER
17 # pragma warning(push)
18 # pragma warning(disable : 4459)
19 #endif
20
21 #include <gtest/gtest.h>
22
23 #include <libenvpp/detail/environment.hpp>
24 #include <libenvpp/detail/get.hpp>
25 #include <nlohmann/json.hpp>
26
27 /// @brief JSON namespace used for settings and config parsing.
28 using NlohmannJsonParseError = nlohmann::json::parse_error;
29 /// @brief JSON namespace used for settings and config typing.
30 using NlohmannJsonTypeError = nlohmann::json::type_error;
31 #ifdef _MSC_VER
32 # pragma warning(pop)
33 #endif
34
35 namespace ppc::util {
36
37 /// @brief Utility class for tracking destructor failure across tests.
38 /// @details Provides thread-safe methods to set, unset, and check the failure flag.
39 class DestructorFailureFlag {
40 public:
41 /// @brief Marks that a destructor failure has occurred.
42 static void Set() {
43 failure_flag.store(true);
44 20 }
45
46 /// @brief Clears the destructor failure flag.
47 static void Unset() {
48 failure_flag.store(false);
49 }
50
51 /// @brief Checks if a destructor failure was recorded.
52 /// @return True if failure occurred, false otherwise.
53 static bool Get() {
54 return failure_flag.load();
55 }
56
57 private:
58 inline static std::atomic<bool> failure_flag{false};
59 };
60
61 class PerformanceFailureFlag {
62 public:
63 static void Set() {
64 failure_flag.store(true);
65 }
66
67 static void Unset() {
68 failure_flag.store(false);
69 }
70
71 static bool Get() {
72 return failure_flag.load();
73 }
74
75 private:
76 inline static std::atomic<bool> failure_flag{false};
77 };
78
79 std::string GetAbsoluteTaskPath(const std::string &id_path, const std::string &relative_path);
80 int GetNumThreads();
81 int GetNumProc();
82 double GetTaskMaxTime();
83 double GetPerfMaxTime();
84 double GetTimeMPI();
85 int GetMPIRank();
86 void ConfigureMpiEnvironment();
87 void SynchronizeMpiRanks();
88
89 inline std::shared_ptr<nlohmann::json> InitJSONPtr() {
90 return std::make_shared<nlohmann::json>();
91 }
92
93 bool IsUnderMpirun();
94
95 namespace test {
96
97 168 [[nodiscard]] inline std::string SanitizeToken(std::string_view token_sv) {
98
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 168 times.
168 std::string token{token_sv};
99 8976 auto is_allowed = [](char c) -> bool {
100
4/6
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 8808 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 168 times.
✓ Branch 4 taken 168 times.
✗ Branch 5 not taken.
8976 return std::isalnum(static_cast<unsigned char>(c)) || c == '_' || c == '-' || c == '.';
101 };
102 std::ranges::replace(token, ' ', '_');
103
2/2
✓ Branch 0 taken 8976 times.
✓ Branch 1 taken 168 times.
9144 for (char &ch : token) {
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8976 times.
8976 if (!is_allowed(ch)) {
105 ch = '_';
106 }
107 }
108 168 return token;
109 }
110
111
0/4
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
168 class ScopedPerTestEnv {
112 public:
113 168 explicit ScopedPerTestEnv(const std::string &token)
114
4/10
✗ Branch 0 not taken.
✓ Branch 1 taken 168 times.
✓ Branch 4 taken 168 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 168 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 168 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
504 : set_uid_("PPC_TEST_UID", token), set_tmp_("PPC_TEST_TMPDIR", CreateTmpDir(token)) {}
115
116 private:
117 168 static std::string CreateTmpDir(const std::string &token) {
118 namespace fs = std::filesystem;
119 24 auto make_rank_suffix = []() -> std::string {
120 // Derive rank from common MPI env vars without including MPI headers
121 24 constexpr std::array<std::string_view, 5> kRankVars = {"OMPI_COMM_WORLD_RANK", "PMI_RANK", "PMIX_RANK",
122 "SLURM_PROCID", "MSMPI_RANK"};
123
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 for (auto name : kRankVars) {
124
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
24 if (auto r = env::get<int>(name); r.has_value() && r.value() >= 0) {
125
3/8
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 24 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 24 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
72 return std::string("_rank_") + std::to_string(r.value());
126 }
127 }
128 return std::string{};
129 };
130
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 144 times.
168 const std::string rank_suffix = IsUnderMpirun() ? make_rank_suffix() : std::string{};
131
5/12
✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 168 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 168 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 168 times.
✗ Branch 11 not taken.
✓ Branch 15 taken 168 times.
✗ Branch 16 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
504 const fs::path tmp = fs::temp_directory_path() / (std::string("ppc_test_") + token + rank_suffix);
132 std::error_code ec;
133
1/2
✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
168 fs::create_directories(tmp, ec);
134 (void)ec;
135 168 return tmp.string();
136 168 }
137
138 env::detail::set_scoped_environment_variable set_uid_;
139 env::detail::set_scoped_environment_variable set_tmp_;
140 };
141
142 168 [[nodiscard]] inline std::string MakeCurrentGTestToken(std::string_view fallback_name) {
143 168 const auto *unit = ::testing::UnitTest::GetInstance();
144
1/2
✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
168 const auto *info = (unit != nullptr) ? unit->current_test_info() : nullptr;
145 168 std::ostringstream os;
146
1/2
✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
168 if (info != nullptr) {
147
2/4
✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 168 times.
✗ Branch 5 not taken.
336 os << info->test_suite_name() << "." << info->name();
148 } else {
149 os << fallback_name;
150 }
151
1/2
✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
336 return SanitizeToken(os.str());
152 168 }
153
154 168 inline ScopedPerTestEnv MakePerTestEnvForCurrentGTest(std::string_view fallback_name) {
155
1/2
✓ Branch 2 taken 168 times.
✗ Branch 3 not taken.
336 return ScopedPerTestEnv(MakeCurrentGTestToken(fallback_name));
156 }
157
158 } // namespace test
159
160 } // namespace ppc::util
161