• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mbits-os / quick_dra / 22054814568

16 Feb 2026 08:08AM UTC coverage: 95.449% (+8.4%) from 87.008%
22054814568

Pull #39

github

web-flow
Merge c1ce10f54 into 7d773e4d9
Pull Request #39: testing

50 of 54 new or added lines in 22 files covered. (92.59%)

5 existing lines in 4 files now uncovered.

4195 of 4395 relevant lines covered (95.45%)

1613.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.8
/libs/libconv/src/low_level.cpp
1
// Copyright (c) 2026 midnightBITS
2
// This code is licensed under MIT license (see LICENSE for details)
3

4
#include <fmt/format.h>
5
#include <fmt/ranges.h>
6
#include <iostream>
7
#include <quick_dra/conv/low_level.hpp>
8

9
namespace quick_dra {
10
        using std::literals::operator""s;
11
        using std::literals::operator""sv;
12

13
        void comment(std::string_view msg) {
14
                fmt::print("\033[0;90m - {}\033[m\n", msg);
×
UNCOV
15
        }
×
16

17
        bool get_answer(std::string_view label,
42✔
18
                        std::string_view hint,
19
                        std::function<bool(std::string&&)> const& answer_is_valid) {
1✔
20
                auto const hint_brackets =
99✔
21
                    hint.empty() ? ""s : fmt::format("\033[0;90m [{}]", hint);
66✔
22

84✔
23
                while (true) {
1✔
24
                        std::string answer;
127✔
25
                        fmt::print("\033[0;36m{}{}\033[m> ", label, hint_brackets);
127✔
26
                        if (!std::getline(std::cin, answer)) {
43✔
27
                                return false;
×
28
                        }
29
                        if (answer_is_valid(std::move(answer))) {
43✔
30
                                return true;
127✔
31
                        }
84✔
32
                }
126✔
33
        }
126✔
34

35
        bool get_yes_no(std::string_view label, bool hint, bool& dst) {
4✔
36
                auto const handler = [&, hint](std::string&& input) -> bool {
4✔
37
                        if (input.empty()) {
4✔
38
                                dst = hint;
×
39
                                return true;
×
40
                        }
41
                        if (input == "y"sv || input == "Y"sv) {
4✔
42
                                dst = true;
10✔
43
                                return true;
10✔
44
                        }
6✔
45
                        if (input == "n"sv || input == "N"sv) {
46
                                dst = false;
×
47
                                return true;
×
48
                        }
49
                        return false;
50
                };
4✔
51

6✔
52
                return get_answer(label, hint ? "Y/n"sv : "y/N"sv, handler);
5✔
53
        }
7✔
54

55
        bool get_enum_answer(
6✔
56
            std::string_view label,
57
            std::span<std::pair<char, std::string_view> const> const& items,
58
            std::function<void(char)> const& store_enum,
59
            char selected) {
1✔
60
                std::string hint{};
19✔
61
                hint.reserve([&items]() {
7✔
62
                        size_t hint_size = items.size() * 4 + (items.size() - 1) * 2;
19✔
63
                        for (auto const& [_, description] : items) {
52✔
64
                                hint_size += description.size();
46✔
65
                        }
30✔
66
                        return hint_size;
19✔
67
                }() + static_cast<size_t>(selected ? 2u : 0u));
7✔
68

12✔
69
                for (auto const& [value, description] : items) {
52✔
70
                        if (!hint.empty()) hint.append(", "sv);
16✔
71
                        if (value == selected) hint.push_back('[');
16✔
72
                        hint.push_back(value);
46✔
73
                        if (value == selected) hint.push_back(']');
16✔
74
                        hint.append(" - "sv);
46✔
75
                        hint.append(description);
46✔
76
                }
31✔
77

12✔
78
                return get_answer(label, hint, [&, selected](std::string&& answer) {
13✔
79
                        if (selected && answer.empty()) {
7✔
80
                                store_enum(selected);
×
81
                                return true;
×
82
                        }
83

12✔
84
                        if (answer.size() != 1) {
7✔
85
                                return false;
×
86
                        }
87

12✔
88
                        for (auto const& [value, _] : items) {
16✔
89
                                if (value == answer.front()) {
16✔
90
                                        store_enum(value);
19✔
91
                                        return true;
19✔
92
                                }
12✔
93
                        }
30✔
94

95
                        return false;
96
                });
25✔
97
        }
19✔
98

99
        std::string as_string(insurance_title const& value) {
202✔
100
                return fmt::to_string(fmt::join(value.split(), " "));
671✔
101
        }
403✔
102

103
        std::string as_string(ratio const& value) {
121✔
104
                return fmt::format("{}/{}", value.num, value.den);
481✔
105
        }
241✔
106

107
        std::string as_string(currency const& value) {
214✔
108
                if (value == minimal_salary) {
214✔
109
                        return "minimal for a given month"s;
307✔
110
                }
204✔
111
                return fmt::format("{} zł", value);
186✔
112
        }
427✔
113

114
        std::optional<std::string> as_string(std::optional<currency> const& value) {
4✔
115
                return value
7✔
116
                    .transform([](auto const& value) { return as_string(value); })
8✔
117
                    .value_or("none"s);
11✔
118
        }
7✔
119

120
        template <typename Arg>
121
        bool get_field_answer_impl(
627✔
122
            bool ask_questions,
123
            std::string_view label,
124
            std::optional<Arg>& dst,
125
            std::optional<Arg>&& opt,
126
            std::function<bool(std::string&&, std::optional<Arg>&, bool)> const&
127
                validator) {
1✔
128
                if (opt) {
628✔
129
                        dst = std::move(opt);
1,648✔
130
                }
1,098✔
131

1,254✔
132
                if (!ask_questions) {
628✔
133
                        if (dst) {
595✔
134
                                auto copy = *dst;
1,648✔
135
                                auto const is_valid =
1,099✔
136
                                    validator(as_string(std::move(copy)), dst, false);
1,647✔
137
                                if (!is_valid) {
550✔
138
                                        comment("Cannot save invalid data with -y. Stopping.");
×
139
                                        return false;
×
140
                                }
141
                        }
1,513✔
142
                        if constexpr (std::same_as<Arg, currency>) {
1,188✔
143
                                if (!dst) {
91✔
144
                                        auto const is_valid = validator("none"s, dst, false);
×
145
                                        if (!is_valid) {
146
                                                comment("Cannot save invalid data with -y. Stopping.");
×
147
                                                return false;
×
148
                                        }
149
                                }
150
                        }
180✔
151
                        return true;
775✔
152
                }
1,188✔
153

66✔
154
                auto def_value = as_string(dst);
34✔
155
                return get_answer(label, def_value.value_or(""s),
155✔
156
                                  [&](std::string&& answer) {
78✔
157
                                          if (answer.empty() && def_value) {
34✔
158
                                                  answer = *def_value;
37✔
159
                                          }
24✔
160
                                          return validator(std::move(answer), dst, true);
100✔
161
                                  });
100✔
162
        }
1,288✔
163

164
        bool get_field_answer(bool ask_questions,
348✔
165
                              std::string_view label,
166
                              std::optional<std::string>& dst,
167
                              std::optional<std::string>&& opt,
168
                              std::function<bool(std::string&&,
169
                                                 std::optional<std::string>&,
170
                                                 bool)> const& validator) {
1✔
171
                return get_field_answer_impl(ask_questions, label, dst, std::move(opt),
1,045✔
172
                                             validator);
1,044✔
173
        }
697✔
174

175
        bool get_field_answer(bool ask_questions,
93✔
176
                              std::string_view label,
177
                              std::optional<insurance_title>& dst,
178
                              std::optional<insurance_title>&& opt,
179
                              std::function<bool(std::string&&,
180
                                                 std::optional<insurance_title>&,
181
                                                 bool)> const& validator) {
1✔
182
                return get_field_answer_impl(ask_questions, label, dst, std::move(opt),
280✔
183
                                             validator);
279✔
184
        }
187✔
185

186
        static constexpr auto magic_currency = "minimal"sv;
187
        bool get_field_answer(bool ask_questions,
93✔
188
                              std::string_view label,
189
                              std::optional<currency>& dst,
190
                              std::optional<currency>&& opt,
191
                              std::function<bool(std::string&&,
192
                                                 std::optional<currency>&,
193
                                                 bool)> const& validator) {
1✔
194
                std::function<bool(std::string&&, std::optional<currency>&, bool)> const
186✔
195
                    wrapped = [validator](std::string&& in,
373✔
196
                                          std::optional<currency>& out,
186✔
197
                                          bool ask_questions) {
1✔
198
                            if (in.starts_with(magic_currency)) {
94✔
199
                                    in = magic_currency;
154✔
200
                            }
102✔
201
                            return validator(std::move(in), out, ask_questions);
280✔
202
                    };
280✔
203
                return get_field_answer_impl(ask_questions, label, dst, std::move(opt),
280✔
204
                                             wrapped);
372✔
205
        }
280✔
206

207
        bool get_field_answer(
93✔
208
            bool ask_questions,
209
            std::string_view label,
210
            std::optional<ratio>& dst,
211
            std::optional<ratio>&& opt,
212
            std::function<bool(std::string&&, std::optional<ratio>&, bool)> const&
213
                validator) {
1✔
214
                return get_field_answer_impl(ask_questions, label, dst, std::move(opt),
280✔
215
                                             validator);
279✔
216
        }
187✔
217
}  // namespace quick_dra
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc