GCC Code Coverage Report


Directory: ./
File: src/iguana/tests/iguana_test.cc
Date: 2025-12-23 16:10:08
Coverage Exec Excl Total
Lines: 82.8% 130 0 157
Functions: 70.0% 7 0 10
Branches: 42.8% 139 0 325

Line Branch Exec Source
1 #include <getopt.h>
2
3 #include "TestAlgorithm.h"
4 #include "TestBanklist.h"
5 #include "TestConfig.h"
6 #include "TestLogger.h"
7 #include "TestMultithreading.h"
8 #include "TestValidator.h"
9 #include <iguana/services/Tools.h>
10
11 37 int main(int argc, char** argv)
12 {
13 // user parameters
14 37 std::string command = "";
15
1/4
✓ Branch 3 → 4 taken 37 times.
✗ Branch 3 → 472 not taken.
✗ Branch 472 → 473 not taken.
✗ Branch 472 → 475 not taken.
37 std::string data_file = "";
16 37 int num_events = 10;
17
1/4
✓ Branch 4 → 5 taken 37 times.
✗ Branch 4 → 466 not taken.
✗ Branch 466 → 467 not taken.
✗ Branch 466 → 469 not taken.
37 std::string algo_name = "";
18 int test_num = 0;
19 37 int num_threads = 0;
20
1/4
✓ Branch 5 → 6 taken 37 times.
✗ Branch 5 → 460 not taken.
✗ Branch 460 → 461 not taken.
✗ Branch 460 → 463 not taken.
37 std::string concurrency_model = "";
21 bool vary_run = false;
22
2/6
✓ Branch 6 → 7 taken 37 times.
✗ Branch 6 → 454 not taken.
✓ Branch 7 → 8 taken 37 times.
✗ Branch 7 → 444 not taken.
✗ Branch 454 → 455 not taken.
✗ Branch 454 → 457 not taken.
37 std::string output_dir = "";
23 bool verbose = false;
24 std::vector<std::string> bank_names;
25 std::vector<std::string> prerequisite_algos;
26
27 // get the command
28
1/2
✓ Branch 7 → 8 taken 37 times.
✗ Branch 7 → 444 not taken.
37 auto exe = std::string(argv[0]);
29 1 auto UsageCommands = [&](int exit_code) {
30
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
2 fmt::print("\nUSAGE: {} [COMMAND] [OPTIONS]...\n", exe);
31 1 fmt::print("\n COMMANDS:\n\n");
32 1 fmt::print(" {:<20} {}\n", "algorithm", "call `Run` on an algorithm");
33 1 fmt::print(" {:<20} {}\n", "multithreading", "call `Run` on an algorithm, multithreaded");
34 1 fmt::print(" {:<20} {}\n", "validator", "run an algorithm's validator");
35 1 fmt::print(" {:<20} {}\n", "unit", "call `Test` on an algorithm, for unit tests");
36 1 fmt::print(" {:<20} {}\n", "config", "test config file parsing");
37 1 fmt::print(" {:<20} {}\n", "logger", "test Logger");
38 1 fmt::print(" {:<20} {}\n", "banklist", "test hipo::banklist");
39 1 fmt::print("\n OPTIONS:\n\n");
40 1 fmt::print(" Each command has its own set of OPTIONS; either provide no OPTIONS\n");
41 1 fmt::print(" or use the --help option for more usage information about a specific command\n");
42 1 fmt::print("\n");
43 1 return exit_code;
44 37 };
45
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 36 times.
37 if(argc <= 1)
46
1/2
✓ Branch 9 → 291 taken 1 time.
✗ Branch 9 → 438 not taken.
1 return UsageCommands(2);
47
1/2
✓ Branch 10 → 11 taken 36 times.
✗ Branch 10 → 438 not taken.
36 command = std::string(argv[1]);
48
2/4
✓ Branch 17 → 18 taken 36 times.
✗ Branch 17 → 19 not taken.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 36 times.
36 if(command == "--help" || command == "-h")
49 return UsageCommands(0);
50 // omit the command, for getopt
51 36 argv++;
52 36 argc--;
53
54 // usage options
55 // clang-format off
56
1/2
✓ Branch 2 → 3 taken 5 times.
✗ Branch 2 → 132 not taken.
5 auto UsageOptions = [&](int exit_code)
57 {
58 std::unordered_map<std::string, std::function<void()>> print_option = {
59 {"f", [&]()
60 {
61 3 fmt::print(" {:<20} {}\n", "-f FILE", "input data file");
62 }},
63
1/2
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 132 not taken.
8 {"n", [&]()
64 {
65 3 fmt::print(" {:<20} {}\n", "-n NUM_EVENTS", "number of events from the data file");
66 3 fmt::print(" {:<20} set to 0 to process ALL events\n", "");
67 3 fmt::print(" {:<20} default: {}\n", "", num_events);
68 3 }},
69
70 {"a-algo", [&]()
71 {
72 2 fmt::print(" {:<20} {}\n", "-a ALGORITHM", "the name of the algorithm");
73 }},
74 {"a-vdor", [&]()
75 {
76 1 fmt::print(" {:<20} {}\n", "-a VALIDATOR", "the name of the validator");
77 }},
78 3 {"b", [&]()
79 {
80 3 fmt::print(" {:<20} {}\n", "-b BANKS", "add a single bank to process");
81 3 fmt::print(" {:<20} you may add as many banks as you need (-b BANK1 -b BANK2 ...)\n", "");
82 3 fmt::print(" {:<20} default: if you do not add any banks, ALL of them will be used\n", "");
83 3 }},
84 2 {"p", [&]()
85 {
86 2 fmt::print(" {:<20} {}\n", "-p PREREQUISITE_ALGOS", "add a prerequisite algorithm");
87 2 fmt::print(" {:<20} these are the algorithms needed upstream of ALGORITHM\n", "");
88 2 fmt::print(" {:<20} this option is repeatable\n", "");
89 2 fmt::print(" {:<20} default: no prerequisites\n", "");
90 2 }},
91 {"t", [&]()
92 {
93 1 fmt::print(" {:<20} {}\n", "-t TESTNUM", "test number");
94 }},
95
1/2
✓ Branch 9 → 10 taken 5 times.
✗ Branch 9 → 132 not taken.
5 {"j", [&]()
96 {
97 fmt::print(" {:<20} {}\n", "-j NUM_THREADS", "number of threads to run");
98 fmt::print(" {:<20} - if = 0: run with `std::thread::hardware_concurrency()` threads\n", "");
99 fmt::print(" {:<20} - if > 0: run with NUM_THREADS threads\n", "");
100 fmt::print(" {:<20} default: {}\n", "", num_threads);
101 }},
102 {"m", [&]()
103 {
104 fmt::print(" {:<20} {}\n", "-m CONCURRENCY_MODEL", "concurrency model");
105 fmt::print(" {:<20} 'memoize' is currently the only option\n", "");
106 }},
107 {"V", [&]()
108 {
109 fmt::print(" {:<20} {}\n", "-V", "randomly vary the run number");
110 fmt::print(" {:<20} this is for testing run-dependent configuration thread safety\n", "");
111 }},
112
1/2
✓ Branch 12 → 13 taken 5 times.
✗ Branch 12 → 132 not taken.
5 {"o", [&]()
113 {
114
3/6
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 1 time.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 11 taken 1 time.
4 fmt::print(" {:<20} {}\n", "-o OUTPUT_DIR", fmt::format("if specified, {} output will write to this directory;", command));
115 1 fmt::print(" {:<20} if not specified, output will not be written\n", "");
116 1 }},
117 {"v", [&]()
118 {
119 4 fmt::print(" {:<20} {}\n", "-v", "increase verbosity");
120
2/4
✓ Branch 18 → 19 taken 60 times.
✓ Branch 18 → 20 taken 5 times.
✗ Branch 129 → 130 not taken.
✗ Branch 129 → 131 not taken.
65 }}};
121 std::map<std::string, std::vector<std::string>> available_options = {
122
1/2
✓ Branch 20 → 21 taken 5 times.
✗ Branch 20 → 195 not taken.
5 {"algorithm", {"f", "n", "a-algo", "b", "p"}},
123
1/2
✓ Branch 23 → 24 taken 5 times.
✗ Branch 23 → 187 not taken.
5 {"unit", {"f", "n", "a-algo", "b", "p"}},
124
1/2
✓ Branch 26 → 27 taken 5 times.
✗ Branch 26 → 179 not taken.
5 {"multithreading", {"f", "n", "a-algo", "b", "p", "j", "m", "V"}},
125
1/2
✓ Branch 29 → 30 taken 5 times.
✗ Branch 29 → 171 not taken.
5 {"validator", {"f", "n", "a-vdor", "b", "o"}},
126
1/2
✓ Branch 32 → 33 taken 5 times.
✗ Branch 32 → 163 not taken.
5 {"config", {"t"}},
127
1/2
✓ Branch 35 → 36 taken 5 times.
✗ Branch 35 → 155 not taken.
5 {"logger", {}},
128
1/2
✓ Branch 37 → 38 taken 5 times.
✗ Branch 37 → 147 not taken.
5 {"banklist", {"f"}}
129
16/46
✓ Branch 21 → 22 taken 5 times.
✗ Branch 21 → 189 not taken.
✓ Branch 24 → 25 taken 5 times.
✗ Branch 24 → 181 not taken.
✓ Branch 27 → 28 taken 5 times.
✗ Branch 27 → 173 not taken.
✓ Branch 30 → 31 taken 5 times.
✗ Branch 30 → 165 not taken.
✓ Branch 33 → 34 taken 5 times.
✗ Branch 33 → 157 not taken.
✓ Branch 38 → 39 taken 5 times.
✗ Branch 38 → 141 not taken.
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 42 taken 5 times.
✓ Branch 43 → 44 taken 35 times.
✓ Branch 43 → 45 taken 5 times.
✓ Branch 46 → 47 taken 5 times.
✗ Branch 46 → 49 not taken.
✓ Branch 52 → 53 taken 5 times.
✗ Branch 52 → 55 not taken.
✓ Branch 58 → 59 taken 5 times.
✗ Branch 58 → 61 not taken.
✓ Branch 64 → 65 taken 5 times.
✗ Branch 64 → 67 not taken.
✓ Branch 70 → 71 taken 5 times.
✗ Branch 70 → 73 not taken.
✓ Branch 76 → 77 taken 5 times.
✗ Branch 76 → 79 not taken.
✓ Branch 82 → 83 taken 5 times.
✗ Branch 82 → 85 not taken.
✗ Branch 136 → 137 not taken.
✗ Branch 136 → 138 not taken.
✗ Branch 141 → 142 not taken.
✗ Branch 141 → 144 not taken.
✗ Branch 149 → 150 not taken.
✗ Branch 149 → 152 not taken.
✗ Branch 157 → 158 not taken.
✗ Branch 157 → 160 not taken.
✗ Branch 165 → 166 not taken.
✗ Branch 165 → 168 not taken.
✗ Branch 173 → 174 not taken.
✗ Branch 173 → 176 not taken.
✗ Branch 181 → 182 not taken.
✗ Branch 181 → 184 not taken.
✗ Branch 189 → 190 not taken.
✗ Branch 189 → 192 not taken.
105 };
130
2/2
✓ Branch 96 → 88 taken 35 times.
✓ Branch 96 → 97 taken 5 times.
40 for(auto& it : available_options)
131
1/2
✓ Branch 88 → 89 taken 35 times.
✗ Branch 88 → 211 not taken.
70 it.second.push_back("v");
132
2/2
✓ Branch 97 → 98 taken 4 times.
✓ Branch 97 → 122 taken 1 time.
5 if(auto it{available_options.find(command)}; it != available_options.end()) {
133
2/4
✗ Branch 98 → 99 not taken.
✓ Branch 98 → 100 taken 4 times.
✓ Branch 103 → 104 taken 4 times.
✗ Branch 103 → 211 not taken.
8 fmt::print("\nUSAGE: {} {} [OPTIONS]...\n", exe, command);
134 4 fmt::print("\n OPTIONS:\n\n");
135
2/2
✓ Branch 120 → 105 taken 20 times.
✓ Branch 120 → 121 taken 4 times.
24 for(auto available_opt : it->second) {
136 print_option.at(available_opt)();
137
1/2
✓ Branch 114 → 115 taken 20 times.
✗ Branch 114 → 117 not taken.
20 fmt::print("\n");
138 }
139 4 return exit_code;
140 }
141 else {
142
1/2
✗ Branch 122 → 123 not taken.
✓ Branch 122 → 124 taken 1 time.
1 fmt::print(stderr, "ERROR: unknown command '{}'\n", command);
143 1 return 1;
144 }
145
7/18
✓ Branch 22 → 23 taken 5 times.
✗ Branch 22 → 187 not taken.
✓ Branch 25 → 26 taken 5 times.
✗ Branch 25 → 179 not taken.
✓ Branch 28 → 29 taken 5 times.
✗ Branch 28 → 171 not taken.
✓ Branch 31 → 32 taken 5 times.
✗ Branch 31 → 163 not taken.
✓ Branch 34 → 35 taken 5 times.
✗ Branch 34 → 155 not taken.
✓ Branch 36 → 37 taken 5 times.
✗ Branch 36 → 147 not taken.
✓ Branch 39 → 40 taken 5 times.
✗ Branch 39 → 139 not taken.
✗ Branch 133 → 134 not taken.
✗ Branch 133 → 135 not taken.
✗ Branch 196 → 197 not taken.
✗ Branch 196 → 198 not taken.
35 };
146 // clang-format on
147
148
4/8
✓ Branch 20 → 21 taken 30 times.
✓ Branch 20 → 22 taken 6 times.
✓ Branch 21 → 23 taken 30 times.
✗ Branch 21 → 438 not taken.
✓ Branch 22 → 23 taken 6 times.
✗ Branch 22 → 438 not taken.
✗ Branch 438 → 439 not taken.
✗ Branch 438 → 441 not taken.
36 auto first_option = argc >= 2 ? std::string(argv[1]) : "";
149
2/4
✓ Branch 23 → 24 taken 36 times.
✗ Branch 23 → 26 not taken.
✓ Branch 24 → 25 taken 36 times.
✗ Branch 24 → 26 not taken.
36 if(first_option == "--help" || first_option == "-h")
150 return UsageOptions(0);
151
4/4
✓ Branch 25 → 27 taken 6 times.
✓ Branch 25 → 28 taken 30 times.
✓ Branch 27 → 28 taken 1 time.
✓ Branch 27 → 29 taken 5 times.
36 if(argc <= 2 && command != "logger")
152
1/2
✓ Branch 29 → 285 taken 5 times.
✗ Branch 29 → 432 not taken.
5 return UsageOptions(2);
153
154 // parse option arguments
155 int opt;
156
2/2
✓ Branch 113 → 30 taken 136 times.
✓ Branch 113 → 114 taken 31 times.
167 while((opt = getopt(argc, argv, "hf:n:a:b:p:t:j:m:Vo:v|")) != -1) {
157
8/13
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 27 times.
✓ Branch 30 → 40 taken 26 times.
✓ Branch 30 → 48 taken 26 times.
✓ Branch 30 → 56 taken 35 times.
✓ Branch 30 → 64 taken 6 times.
✓ Branch 30 → 73 taken 3 times.
✗ Branch 30 → 81 not taken.
✗ Branch 30 → 91 not taken.
✓ Branch 30 → 100 taken 10 times.
✓ Branch 30 → 108 taken 3 times.
✗ Branch 30 → 109 not taken.
✗ Branch 30 → 111 not taken.
136 switch(opt) {
158 case 'h':
159 return UsageOptions(0);
160 case 'f':
161
1/2
✓ Branch 32 → 33 taken 27 times.
✗ Branch 32 → 432 not taken.
27 data_file = std::string(optarg);
162 27 break;
163 case 'n':
164
2/4
✓ Branch 40 → 41 taken 26 times.
✗ Branch 40 → 432 not taken.
✓ Branch 42 → 43 taken 26 times.
✗ Branch 42 → 45 not taken.
52 num_events = std::stoi(optarg);
165 26 break;
166 case 'a':
167
1/2
✓ Branch 48 → 49 taken 26 times.
✗ Branch 48 → 432 not taken.
26 algo_name = std::string(optarg);
168 26 break;
169 case 'b':
170
1/2
✓ Branch 56 → 57 taken 35 times.
✗ Branch 56 → 432 not taken.
35 bank_names.push_back(std::string(optarg));
171 35 break;
172 case 'p':
173
1/2
✓ Branch 64 → 65 taken 6 times.
✗ Branch 64 → 432 not taken.
6 prerequisite_algos.push_back(std::string(optarg));
174 6 break;
175 case 't':
176
1/2
✓ Branch 73 → 74 taken 3 times.
✗ Branch 73 → 432 not taken.
3 test_num = std::stoi(optarg);
177 3 break;
178 case 'j':
179 num_threads = std::stoi(optarg);
180 if(num_threads == 0)
181 num_threads = std::thread::hardware_concurrency();
182 break;
183 case 'm':
184 concurrency_model = std::string(optarg);
185 break;
186 case 'V':
187 vary_run = true;
188 break;
189 case 'o':
190
1/2
✓ Branch 100 → 101 taken 10 times.
✗ Branch 100 → 432 not taken.
10 output_dir = std::string(optarg);
191 10 break;
192 3 case 'v':
193 verbose = true;
194 3 break;
195 default:
196 return UsageOptions(2);
197 }
198 }
199
200 // list of ALL banks needed by the algorithms and validators; we need all of them here,
201 // so that the caller does not have to specifiy the banks
202 std::vector<std::string> const all_bank_names = {
203 "RUN::config",
204 "REC::Particle",
205 "REC::Calorimeter",
206 "REC::Track",
207 "REC::Scintillator",
208
3/6
✓ Branch 114 → 115 taken 31 times.
✗ Branch 114 → 432 not taken.
✓ Branch 115 → 116 taken 16 times.
✓ Branch 115 → 117 taken 15 times.
✗ Branch 432 → 433 not taken.
✗ Branch 432 → 435 not taken.
62 "REC::Traj"};
209
2/2
✓ Branch 115 → 116 taken 16 times.
✓ Branch 115 → 117 taken 15 times.
31 if(bank_names.empty())
210
1/2
✓ Branch 116 → 117 taken 16 times.
✗ Branch 116 → 430 not taken.
16 bank_names = all_bank_names;
211
212
1/2
✗ Branch 118 → 119 not taken.
✓ Branch 118 → 120 taken 31 times.
31 fmt::print("TEST IGUANA:\n");
213
1/2
✗ Branch 121 → 122 not taken.
✓ Branch 121 → 123 taken 31 times.
31 fmt::print(" {:>20} = {}\n", "command", command);
214
1/2
✓ Branch 124 → 125 taken 31 times.
✗ Branch 124 → 430 not taken.
31 fmt::print(" {:>20} = {}\n", "data_file", data_file);
215
1/2
✗ Branch 125 → 126 not taken.
✓ Branch 125 → 127 taken 31 times.
31 fmt::print(" {:>20} = {}\n", "num_events", num_events);
216
1/2
✓ Branch 128 → 129 taken 31 times.
✗ Branch 128 → 430 not taken.
31 fmt::print(" {:>20} = {}\n", "algo_name", algo_name);
217
1/2
✓ Branch 129 → 130 taken 31 times.
✗ Branch 129 → 430 not taken.
31 fmt::print(" {:>20} = {}\n", "banks", fmt::join(bank_names, ", "));
218
1/2
✓ Branch 130 → 131 taken 31 times.
✗ Branch 130 → 430 not taken.
31 fmt::print(" {:>20} = {}\n", "prerequisite_algos", fmt::join(prerequisite_algos, ", "));
219
1/2
✓ Branch 131 → 132 taken 31 times.
✗ Branch 131 → 430 not taken.
31 fmt::print(" {:>20} = {}\n", "test_num", test_num);
220
1/2
✗ Branch 132 → 133 not taken.
✓ Branch 132 → 134 taken 31 times.
31 fmt::print(" {:>20} = {}\n", "num_threads", num_threads);
221
1/2
✓ Branch 135 → 136 taken 31 times.
✗ Branch 135 → 430 not taken.
31 fmt::print(" {:>20} = {}\n", "concurrency_model", concurrency_model);
222
1/2
✗ Branch 136 → 137 not taken.
✓ Branch 136 → 138 taken 31 times.
31 fmt::print(" {:>20} = {}\n", "vary_run", vary_run);
223
1/2
✓ Branch 139 → 140 taken 31 times.
✗ Branch 139 → 430 not taken.
31 fmt::print(" {:>20} = {}\n", "output_dir", output_dir);
224 31 fmt::print("\n");
225
226 // expand `~` in paths
227
1/2
✓ Branch 140 → 141 taken 31 times.
✗ Branch 140 → 430 not taken.
31 data_file = iguana::tools::ExpandTilde(data_file);
228
1/2
✓ Branch 147 → 148 taken 31 times.
✗ Branch 147 → 430 not taken.
31 output_dir = iguana::tools::ExpandTilde(output_dir);
229
230 // run test
231
3/4
✓ Branch 154 → 155 taken 15 times.
✓ Branch 154 → 157 taken 16 times.
✓ Branch 155 → 156 taken 15 times.
✗ Branch 155 → 157 not taken.
31 if(command == "algorithm" || command == "unit")
232
6/16
✗ Branch 157 → 158 not taken.
✓ Branch 157 → 159 taken 16 times.
✓ Branch 161 → 162 taken 16 times.
✗ Branch 161 → 370 not taken.
✓ Branch 162 → 163 taken 16 times.
✗ Branch 162 → 368 not taken.
✓ Branch 171 → 172 taken 16 times.
✗ Branch 171 → 354 not taken.
✗ Branch 177 → 178 not taken.
✓ Branch 177 → 180 taken 16 times.
✗ Branch 184 → 185 not taken.
✓ Branch 184 → 187 taken 16 times.
✗ Branch 360 → 361 not taken.
✗ Branch 360 → 363 not taken.
✗ Branch 370 → 371 not taken.
✗ Branch 370 → 373 not taken.
96 return TestAlgorithm(command, algo_name, prerequisite_algos, bank_names, data_file, num_events, verbose);
233
1/2
✗ Branch 156 → 190 not taken.
✓ Branch 156 → 232 taken 15 times.
15 if(command == "multithreading")
234 return TestMultithreading(command, algo_name, prerequisite_algos, bank_names, data_file, num_events, num_threads, concurrency_model, vary_run, verbose);
235
2/2
✓ Branch 232 → 233 taken 10 times.
✓ Branch 232 → 264 taken 5 times.
15 else if(command == "validator")
236
6/16
✗ Branch 233 → 234 not taken.
✓ Branch 233 → 235 taken 10 times.
✗ Branch 237 → 238 not taken.
✓ Branch 237 → 239 taken 10 times.
✓ Branch 241 → 242 taken 10 times.
✗ Branch 241 → 412 not taken.
✓ Branch 246 → 247 taken 10 times.
✗ Branch 246 → 404 not taken.
✗ Branch 253 → 254 not taken.
✓ Branch 253 → 256 taken 10 times.
✗ Branch 258 → 259 not taken.
✓ Branch 258 → 261 taken 10 times.
✗ Branch 412 → 413 not taken.
✗ Branch 412 → 415 not taken.
✗ Branch 418 → 419 not taken.
✗ Branch 418 → 421 not taken.
70 return TestValidator(algo_name, bank_names, data_file, num_events, output_dir, verbose);
237
2/2
✓ Branch 264 → 265 taken 3 times.
✓ Branch 264 → 266 taken 2 times.
5 else if(command == "config")
238
1/2
✓ Branch 265 → 284 taken 3 times.
✗ Branch 265 → 430 not taken.
3 return TestConfig(test_num, verbose);
239
2/2
✓ Branch 266 → 267 taken 1 time.
✓ Branch 266 → 268 taken 1 time.
2 else if(command == "logger")
240
1/2
✓ Branch 267 → 284 taken 1 time.
✗ Branch 267 → 430 not taken.
1 return TestLogger();
241
1/2
✓ Branch 268 → 269 taken 1 time.
✗ Branch 268 → 280 not taken.
1 else if(command == "banklist")
242
2/4
✗ Branch 269 → 270 not taken.
✓ Branch 269 → 271 taken 1 time.
✓ Branch 273 → 274 taken 1 time.
✗ Branch 273 → 424 not taken.
3 return TestBanklist(data_file, verbose);
243 else {
244 fmt::print(stderr, "ERROR: unknown command '{}'\n", command);
245 return 1;
246 }
247 return 0;
248 37 }
249