INSTINCT Code Coverage Report


Directory: src/
File: internal/ConfigManager.cpp
Date: 2025-11-25 23:34:18
Exec Total Coverage
Lines: 64 125 51.2%
Functions: 5 9 55.6%
Branches: 136 518 26.3%

Line Branch Exec Source
1 // This file is part of INSTINCT, the INS Toolkit for Integrated
2 // Navigation Concepts and Training by the Institute of Navigation of
3 // the University of Stuttgart, Germany.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9 #include "ConfigManager.hpp"
10
11 #include <string>
12 #include <filesystem>
13 #include <fstream>
14 #include <iostream>
15 #include <boost/program_options/parsers.hpp>
16 #include <implot.h>
17 #include <implot_internal.h>
18 #include <fmt/ranges.h>
19
20 #include "internal/FlowManager.hpp"
21 #include "util/Logger.hpp"
22
23 #include <boost/tokenizer.hpp>
24
25 #include "util/Json.hpp"
26 #include "util/Plot/Colormap.hpp"
27 #include "internal/gui/windows/Screenshotter.hpp"
28
29 namespace bpo = boost::program_options;
30
31 /// Program option description
32 bpo::options_description program_options{ "Allowed options" }; // NOLINT
33
34 /// Map which stores all options
35 boost::program_options::variables_map NAV::ConfigManager::vm; // NOLINT
36
37 414 void NAV::ConfigManager::initialize()
38 {
39 LOG_TRACE("called");
40
41
2/2
✓ Branch 2 taken 293 times.
✓ Branch 3 taken 121 times.
414 if (program_options.options().empty())
42 {
43 // clang-format off
44 // See https://www.boost.org/doc/libs/1_72_0/doc/html/program_options.html
45
1/2
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
293 program_options.add_options()
46
2/4
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 293 times.
✗ Branch 6 not taken.
293 ("config", bpo::value<std::vector<std::string>>()->multitoken(), "List of configuration files to read parameters from" )
47
1/2
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
293 ("version,v", "Display the version number" )
48
1/2
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
293 ("help,h", "Display this help message" )
49
3/6
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
293 ("sigterm", bpo::bool_switch()->default_value(false), "Programm waits for -SIGUSR1 / -SIGINT / -SIGTERM" )
50
3/6
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
293 ("duration", bpo::value<size_t>()->default_value(0), "Program execution duration [sec]" )
51
3/6
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
293 ("nogui", bpo::bool_switch()->default_value(false), "Launch without the gui" )
52
3/6
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
293 ("noinit", bpo::bool_switch()->default_value(false), "Do not initialize flows after loading them" )
53
2/4
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
293 ("load,l", bpo::value<std::string>(), "Flow file to load" )
54
3/6
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
293 ("rotate-output", bpo::bool_switch()->default_value(false), "Create new folders for output files" )
55
4/8
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 293 times.
✗ Branch 11 not taken.
879 ("output-path,o", bpo::value<std::string>()->default_value("logs"), "Directory path for logs and output files" )
56
4/8
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 293 times.
✗ Branch 11 not taken.
879 ("input-path,i", bpo::value<std::string>()->default_value("data"), "Directory path for searching input files" )
57
4/8
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 293 times.
✗ Branch 11 not taken.
879 ("flow-path,f", bpo::value<std::string>()->default_value("flow"), "Directory path for searching flow files" )
58
4/8
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 293 times.
✗ Branch 11 not taken.
879 ("implot-config", bpo::value<std::string>()->default_value("implot.json"), "Config file to read implot settings from" )
59
4/8
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 293 times.
✗ Branch 11 not taken.
879 ("global-log-level", bpo::value<std::string>()->default_value("trace"), "Global log level of all sinks (possible values: trace/debug/info/warning/error/critical/off" )
60
4/8
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 293 times.
✗ Branch 11 not taken.
879 ("console-log-level", bpo::value<std::string>()->default_value("info"), "Log level on the console (possible values: trace/debug/info/warning/error/critical/off" )
61
4/8
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 293 times.
✗ Branch 11 not taken.
879 ("file-log-level", bpo::value<std::string>()->default_value("debug"), "Log level to the log file (possible values: trace/debug/info/warning/error/critical/off" )
62
4/8
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 293 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 293 times.
✗ Branch 11 not taken.
1172 ("flush-log-level", bpo::value<std::string>()->default_value("info"), "Log level to flush on (possible values: trace/debug/info/warning/error/critical/off" )
63
2/4
✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
293 ("log-filter", bpo::value<std::string>(), "Filter/Regex for log messages" )
64 ;
65 // clang-format on
66 }
67 414 }
68
69 414 void NAV::ConfigManager::deinitialize()
70 {
71 414 vm.clear();
72 414 }
73
74 const boost::program_options::options_description& NAV::ConfigManager::GetProgramOptions()
75 {
76 return program_options;
77 }
78
79 414 std::vector<std::string> NAV::ConfigManager::FetchConfigs(const int argc, const char* argv[]) // NOLINT
80 {
81
2/4
✓ Branch 2 taken 414 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 414 times.
✗ Branch 6 not taken.
414 bpo::store(bpo::parse_command_line(argc, argv, program_options), vm);
82
83 414 std::vector<std::string> failedConfigFiles;
84
85 // if config file is available, the parameters from file will be added
86
4/6
✓ Branch 1 taken 414 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 414 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 412 times.
828 if (vm.contains("config"))
87 {
88
5/8
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 15 taken 4 times.
✓ Branch 16 taken 2 times.
8 for (const std::string& configFile : vm["config"].as<std::vector<std::string>>())
89 {
90
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 std::filesystem::path filepath{ configFile };
91
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (filepath.is_relative())
92 {
93
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 filepath = NAV::flow::GetProgramRootPath();
94
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 filepath /= configFile;
95 }
96
97
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 std::ifstream ifs{ filepath };
98
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
4 if (ifs.good())
99 {
100
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 bpo::store(bpo::parse_config_file(ifs, program_options), vm);
101 }
102 else
103 {
104
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 failedConfigFiles.push_back(configFile);
105 }
106 4 }
107 }
108
109
1/2
✓ Branch 1 taken 414 times.
✗ Branch 2 not taken.
414 bpo::notify(vm);
110
111 414 return failedConfigFiles;
112 }
113
114 114 void NAV::ConfigManager::CheckOptions(const int argc, [[maybe_unused]] const char* argv[]) // NOLINT
115 {
116
1/2
✓ Branch 3 taken 114 times.
✗ Branch 4 not taken.
114 LOG_DEBUG("{} arguments were provided over the command line", argc);
117
118
2/2
✓ Branch 2 taken 456 times.
✓ Branch 3 taken 114 times.
570 for (const char* logger : { "global-log-level", "console-log-level", "file-log-level", "flush-log-level" })
119 {
120
5/14
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 456 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 456 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 456 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 456 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
1824 if (vm[logger].as<std::string>() != "trace"
121
8/18
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 114 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 114 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 114 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 114 times.
✓ Branch 16 taken 342 times.
✓ Branch 17 taken 456 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
684 && vm[logger].as<std::string>() != "debug"
122
9/18
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 114 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 114 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 114 times.
✓ Branch 15 taken 114 times.
✓ Branch 16 taken 342 times.
✓ Branch 17 taken 114 times.
✓ Branch 18 taken 342 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
684 && vm[logger].as<std::string>() != "info"
123
3/18
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 456 times.
✓ Branch 17 taken 114 times.
✓ Branch 18 taken 342 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
456 && vm[logger].as<std::string>() != "warning"
124
2/18
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 456 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 456 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
456 && vm[logger].as<std::string>() != "error"
125
2/18
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 456 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 456 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
456 && vm[logger].as<std::string>() != "critical"
126
6/24
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 114 times.
✓ Branch 4 taken 342 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 456 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 456 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 456 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
1482 && vm[logger].as<std::string>() != "off")
127 {
128 LOG_CRITICAL("The command line argument '{}' has to be one of 'trace/debug/info/warning/error/critical/off' but the value '{}' was provided", logger, vm[logger].as<std::string>());
129 }
130 }
131
132
2/2
✓ Branch 0 taken 913 times.
✓ Branch 1 taken 114 times.
1027 for (int i = 0; i < argc; i++)
133 {
134
2/4
✓ Branch 1 taken 913 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 913 times.
✗ Branch 6 not taken.
913 LOG_DEBUG("\targument[{}] = '{}'", i, argv[i]);
135 }
136
137
1/2
✓ Branch 4 taken 114 times.
✗ Branch 5 not taken.
114 LOG_DEBUG("{} arguments are set in the allowed variable map", vm.size());
138
139
2/2
✓ Branch 5 taken 1596 times.
✓ Branch 6 taken 114 times.
1710 for (const auto& value : vm)
140 {
141
2/2
✓ Branch 2 taken 114 times.
✓ Branch 3 taken 1482 times.
1596 if ([[maybe_unused]] const auto* v = boost::any_cast<size_t>(&value.second.value()))
142 {
143
2/4
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 114 times.
✗ Branch 6 not taken.
114 LOG_DEBUG("\tvm[{}] = '{}'", value.first, *v);
144 }
145
2/2
✓ Branch 2 taken 456 times.
✓ Branch 3 taken 1026 times.
1482 else if ([[maybe_unused]] const auto* v = boost::any_cast<bool>(&value.second.value())) // NOLINT(bugprone-bool-pointer-implicit-conversion)
146 {
147
2/4
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 456 times.
✗ Branch 6 not taken.
456 LOG_DEBUG("\tvm[{}] = '{}'", value.first, *v);
148 }
149
1/2
✓ Branch 2 taken 1026 times.
✗ Branch 3 not taken.
1026 else if ([[maybe_unused]] const auto* v = boost::any_cast<std::string>(&value.second.value()))
150 {
151
2/4
✓ Branch 1 taken 1026 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1026 times.
✗ Branch 6 not taken.
1026 LOG_DEBUG("\tvm[{}] = '{}'", value.first, *v);
152 }
153 else if ([[maybe_unused]] const auto* v = boost::any_cast<std::vector<std::string>>(&value.second.value()))
154 {
155 LOG_DEBUG("\tvm[{}] = '{}'", value.first, fmt::join(v->begin(), v->end(), ", "));
156 }
157 else
158 {
159 LOG_ERROR("The Log option vm[{}] could not be casted. Please report this to the developers.", value.first);
160 }
161 }
162 114 }
163
164 708 bool NAV::ConfigManager::HasKey(const std::string& key)
165 {
166 708 return vm.contains(key);
167 }
168
169 std::vector<std::string> NAV::ConfigManager::GetKeys()
170 {
171 std::vector<std::string> keys;
172
173 for (auto& param : vm)
174 {
175 keys.push_back(param.first);
176 }
177
178 return keys;
179 }
180
181 void NAV::ConfigManager::SaveGlobalSettings()
182 {
183 // Save also global settings
184 std::ofstream filestream(flow::GetConfigPath() / "globals.json");
185 json j;
186 #ifdef IMGUI_IMPL_OPENGL_LOADER_GL3W
187 j["plotScreenshotImPlotStyleFile"] = gui::windows::plotScreenshotImPlotStyleFile;
188 j["copyScreenshotsToClipboard"] = gui::windows::copyScreenshotsToClipboard;
189 j["printScreenshotSaveLocation"] = gui::windows::printScreenshotSaveLocation;
190 #endif
191 j["colormaps"] = ColormapsGlobal;
192
193 ImPlotContext& gp = *ImPlot::GetCurrentContext();
194 j["selectedImPlotColormap"] = gp.Style.Colormap;
195
196 constexpr int CMAP_USER_START = ImPlotColormap_Greys + 2;
197 for (int i = CMAP_USER_START; i < gp.ColormapData.Count; ++i)
198 {
199 j["ImPlotColormaps"][static_cast<size_t>(i - CMAP_USER_START)]["name"] = gp.ColormapData.GetName(i);
200 j["ImPlotColormaps"][static_cast<size_t>(i - CMAP_USER_START)]["qual"] = gp.ColormapData.IsQual(i);
201 for (int c = 0; c < gp.ColormapData.GetKeyCount(i); ++c)
202 {
203 j["ImPlotColormaps"][static_cast<size_t>(i - CMAP_USER_START)]["colors"][static_cast<size_t>(c)] =
204 ImGui::ColorConvertU32ToFloat4(gp.ColormapData.GetKeyColor(i, c));
205 }
206 }
207
208 filestream << std::setw(4) << j << std::endl; // NOLINT(performance-avoid-endl)
209 }
210
211 void NAV::ConfigManager::LoadGlobalSettings()
212 {
213 auto filepath = flow::GetConfigPath() / "globals.json";
214 std::ifstream filestream(filepath);
215
216 if (!filestream.good())
217 {
218 LOG_ERROR("Load Flow error: Could not open file: {}", filepath);
219 return;
220 }
221 json j;
222 filestream >> j;
223
224 if (j.contains("colormaps"))
225 {
226 j.at("colormaps").get_to(ColormapsGlobal);
227 }
228 #ifdef IMGUI_IMPL_OPENGL_LOADER_GL3W
229 if (j.contains("plotScreenshotImPlotStyleFile"))
230 {
231 j.at("plotScreenshotImPlotStyleFile").get_to(gui::windows::plotScreenshotImPlotStyleFile);
232 }
233 if (j.contains("copyScreenshotsToClipboard"))
234 {
235 j.at("copyScreenshotsToClipboard").get_to(gui::windows::copyScreenshotsToClipboard);
236 }
237 if (j.contains("printScreenshotSaveLocation"))
238 {
239 j.at("printScreenshotSaveLocation").get_to(gui::windows::printScreenshotSaveLocation);
240 }
241 #endif
242 if (j.contains("ImPlotColormaps"))
243 {
244 for (size_t i = 0; i < j["ImPlotColormaps"].size(); ++i)
245 {
246 ImVector<ImVec4> custom;
247 for (const auto& c : j.at("ImPlotColormaps").at(i).at("colors"))
248 {
249 custom.push_back(c.get<ImVec4>());
250 }
251
252 ImPlot::AddColormap(j.at("ImPlotColormaps").at(i).at("name").get<std::string>().c_str(),
253 custom.Data, custom.Size, j.at("ImPlotColormaps").at(i).at("qual").get<bool>());
254 ImPlot::BustItemCache();
255 }
256 }
257 if (j.contains("selectedImPlotColormap"))
258 {
259 ImPlotContext& gp = *ImPlot::GetCurrentContext();
260 gp.Style.Colormap = j.at("selectedImPlotColormap").get<int>();
261 ImPlot::BustItemCache();
262 }
263 }
264