Skip to content

Commit 3966d58

Browse files
authored
feat: added coerce function (#10)
1 parent 6d7a4b2 commit 3966d58

File tree

3 files changed

+105
-3
lines changed

3 files changed

+105
-3
lines changed

include/version_weaver.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ static constexpr size_t MAX_VERSION_LENGTH = 256;
1313
bool validate(std::string_view version);
1414

1515
bool satisfies(std::string_view version, std::string_view range);
16-
std::string coerce(std::string_view version);
16+
std::optional<std::string> coerce(const std::string& version);
1717
std::string minimum(std::string_view range);
1818

1919
// A normal version number MUST take the form X.Y.Z where X, Y, and Z are

src/version_weaver.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,36 @@
11
#include "version_weaver.h"
22
#include <algorithm>
33
#include <cctype>
4+
#include <regex>
5+
46
namespace version_weaver {
57
bool validate(std::string_view version) { return parse(version).has_value(); }
6-
std::string coerce(std::string_view version) { return ""; }
8+
9+
std::optional<std::string> coerce(const std::string& version) {
10+
if (version.empty()) {
11+
return std::nullopt;
12+
}
13+
14+
// Regular expression to match major, minor, and patch components
15+
std::regex semverRegex(R"((\d+)(?:\.(\d+))?(?:\.(\d+))?)");
16+
std::smatch match;
17+
18+
if (std::regex_search(version, match, semverRegex)) {
19+
std::string major =
20+
std::to_string(std::stoll(match[1].str())); // First number
21+
std::string minor = match[2].matched
22+
? std::to_string(std::stoll(match[2].str()))
23+
: "0"; // Second number or "0"
24+
std::string patch = match[3].matched
25+
? std::to_string(std::stoll(match[3].str()))
26+
: "0"; // Third number or "0"
27+
28+
return major + "." + minor + "." + patch;
29+
}
30+
31+
return std::nullopt;
32+
}
33+
734
std::string minimum(std::string_view range) { return ""; }
835

936
constexpr inline void trim_whitespace(std::string_view* input) noexcept {

tests/basictests.cpp

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,79 @@ TEST(basictests, order) {
108108
auto v2 = version_weaver::parse(view2).value();
109109
ASSERT_EQ(v1 <=> v2, order);
110110
}
111-
}
111+
}
112+
113+
using CoerceData = std::pair<std::string, std::optional<std::string>>;
114+
std::vector<CoerceData> coerce_values = {
115+
{"001", "1.0.0"},
116+
{"01.002.03", "1.2.3"},
117+
{"000.000.000", "0.0.0"},
118+
{"11111111111111111", "11111111111111111.0.0"},
119+
{"999999999.999999.999999", "999999999.999999.999999"},
120+
{"0.0.01", "0.0.1"},
121+
{"v001", "1.0.0"},
122+
{"v01.002.03", "1.2.3"},
123+
{"1.2.3", "1.2.3"},
124+
{"v2", "2.0.0"},
125+
{" 1.2.3 ", "1.2.3"},
126+
{"1.2.3.4", "1.2.3"},
127+
{"v1.2.3", "1.2.3"},
128+
{"=1.2.3", "1.2.3"},
129+
{"1.2", "1.2.0"},
130+
{"1", "1.0.0"},
131+
{"1.2.x", "1.2.0"},
132+
{"alpha1.2.3", "1.2.3"},
133+
{"", std::nullopt},
134+
{".1", "1.0.0"},
135+
{".1.", "1.0.0"},
136+
{"..1", "1.0.0"},
137+
{".1.1", "1.1.0"},
138+
{"1.", "1.0.0"},
139+
{"1.0", "1.0.0"},
140+
{"1.0.0", "1.0.0"},
141+
{"0", "0.0.0"},
142+
{"0.0", "0.0.0"},
143+
{"0.0.0", "0.0.0"},
144+
{"0.1", "0.1.0"},
145+
{"0.0.1", "0.0.1"},
146+
{"0.1.1", "0.1.1"},
147+
{"1", "1.0.0"},
148+
{"1.2", "1.2.0"},
149+
{"1.2.3", "1.2.3"},
150+
{"1.2.3.4", "1.2.3"},
151+
{"13", "13.0.0"},
152+
{"35.12", "35.12.0"},
153+
{"35.12.18", "35.12.18"},
154+
{"35.12.18.24", "35.12.18"},
155+
{"v1", "1.0.0"},
156+
{"v1.2", "1.2.0"},
157+
{"v1.2.3", "1.2.3"},
158+
{"v1.2.3.4", "1.2.3"},
159+
{" 1", "1.0.0"},
160+
{"1 ", "1.0.0"},
161+
{"1 0", "1.0.0"},
162+
{"1 1", "1.0.0"},
163+
{"1.1 1", "1.1.0"},
164+
{"1.1-1", "1.1.0"},
165+
{"a1", "1.0.0"},
166+
{"a1a", "1.0.0"},
167+
{"1a", "1.0.0"},
168+
{"version 1", "1.0.0"},
169+
{"version1", "1.0.0"},
170+
{"version1.0", "1.0.0"},
171+
{"version1.1", "1.1.0"},
172+
{"42.6.7.9.3-alpha", "42.6.7"},
173+
{"v2", "2.0.0"},
174+
{"v3.4 replaces v3.3.1", "3.4.0"},
175+
{"4.6.3.9.2-alpha2", "4.6.3"}};
176+
177+
TEST(basictests, coerce) {
178+
for (const auto& [input, expected] : coerce_values) {
179+
auto result = version_weaver::coerce(input);
180+
if (expected.has_value()) {
181+
ASSERT_EQ(result, expected.value());
182+
} else {
183+
ASSERT_FALSE(result.has_value());
184+
}
185+
}
186+
}

0 commit comments

Comments
 (0)