-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcli.cpp
More file actions
142 lines (117 loc) · 4.39 KB
/
cli.cpp
File metadata and controls
142 lines (117 loc) · 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Eggs.Test
//
// Copyright Agustin K-ballo Berge, Fusion Fenix 2026
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "cli.hpp"
#include <eggs/test/detail/print.hpp>
#include <cstdio>
#include <format>
#include <span>
#include <string>
#include <string_view>
namespace eggs::test {
namespace {
// ── Option table ─────────────────────────────────────────────────────────────
//
// flag — the flag text
// value - the flag value
// also — extra form shown alongside in --help:
// short alias (-x) → listed before the flag: "-v, --verbose"
// desc — --help right-column text; empty = hidden from --help (alias or internal flag)
struct opt_spec
{
std::string_view flag;
std::string_view value;
std::string_view also;
std::span<std::string_view const> desc;
};
#define EGGS_TEST_MAKE_STRING_VIEW_SPAN(...) \
[]() -> std::span<std::string_view const> { \
static constexpr std::string_view arr[] = {__VA_ARGS__}; \
return arr; \
}()
constexpr opt_spec k_opts[] = {
// {flag, value, also, desc}
{"--list",
{},
{},
EGGS_TEST_MAKE_STRING_VIEW_SPAN(
"list selected test case names and exit;", "respects --run filters"
)},
{"--run=",
"<test_case>",
{},
EGGS_TEST_MAKE_STRING_VIEW_SPAN(
"run only the specified test cases (repeatable).",
"all test cases will run if omitted"
)},
};
#undef EGGS_TEST_MAKE_SPAN
// ── Help printing ────────────────────────────────────────────────────────────
// description starts at this column (0-based)
static constexpr std::size_t k_desc_col = 29u;
void print_help()
{
detail::print(
stdout, "Usage: <test-executable> [options]\n"
"\n"
"Options:\n"
);
for (opt_spec const& opt : k_opts) {
if (opt.desc.empty()) continue;
// Build left-column display string from flag + value + also.
auto disp = std::string(opt.flag) += opt.value;
if (!opt.also.empty()) {
// "-h, --help"
disp = std::format("{}, {}", opt.also, disp);
}
bool first = true;
for (auto const& line : opt.desc) {
if (first) {
// Print left column + description.
if (2 + disp.size() <= k_desc_col) {
// Fits on one line. Pad left column to (k_desc_col - 2)
detail::println(
stdout, " {:<{}} {}", disp, k_desc_col - 2, line
);
} else {
// Too long. Print option name, wrap to next line, pad description
detail::println(stdout, " {}", disp);
detail::println(stdout, "{:>{}} {}", "", k_desc_col, line);
}
first = false;
} else {
// Subsequent lines are always padded to match the description column
detail::println(stdout, "{:>{}} {}", "", k_desc_col, line);
}
}
}
}
} // namespace
// ── Public interface ─────────────────────────────────────────────────────────
parse_result parse_args(int argc, char const* const argv[])
{
parse_result pr;
pr.action = parse_action::run;
for (int i = 1; i < argc; ++i) {
std::string_view const arg = argv[i];
if (arg == "--help" || arg == "-h") {
print_help();
pr.action = parse_action::exit_success;
return pr;
} else if (arg == "--list") {
pr.opts.list = true;
} else if (arg.starts_with("--run=")) {
auto const name = arg.substr(6);
pr.opts.run.push_back(name);
} else {
detail::println(stderr, "error: unknown argument '{}'", arg);
pr.action = parse_action::exit_failure;
return pr;
}
}
return pr;
}
} // namespace eggs::test