Skip to content

Commit 8ff5f62

Browse files
feat: add inc function (for basic release types) (#15)
1 parent 587cd17 commit 8ff5f62

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

include/version_weaver.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,27 @@ enum parse_error {
6262
std::expected<version, parse_error> clean(std::string_view input);
6363

6464
std::expected<version, parse_error> parse(std::string_view version);
65+
66+
enum release_type {
67+
MAJOR,
68+
MINOR,
69+
PATCH,
70+
// TODO: also support
71+
// - PRE_MAJOR
72+
// - PRE_MINOR
73+
// - PRE_PATCH
74+
// - PRE_RELEASE
75+
// - RELEASE
76+
};
77+
78+
enum inc_error {
79+
INVALID_MAJOR,
80+
INVALID_MINOR,
81+
INVALID_PATCH,
82+
INVALID_RELEASE_TYPE,
83+
};
84+
85+
std::expected<version, inc_error> inc(version version, release_type release_type);
6586
} // namespace version_weaver
6687

6788
// https://semver.org/#spec-item-11

src/version_weaver.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,51 @@ std::optional<std::string> coerce(const std::string& version) {
3333

3434
std::string minimum(std::string_view range) { return ""; }
3535

36+
std::expected<version, inc_error> inc(version input, release_type release_type) {
37+
switch (release_type) {
38+
case MAJOR: {
39+
int major_int;
40+
try {
41+
major_int = std::stoi(std::string(input.major));
42+
} catch (...) {
43+
return std::unexpected(inc_error::INVALID_MAJOR);
44+
}
45+
auto incremented_major_int = major_int + 1;
46+
std::string_view incremented_major(std::to_string(incremented_major_int));
47+
return version_weaver::version{incremented_major, "0", "0"};
48+
}
49+
case MINOR: {
50+
int minor_int;
51+
try {
52+
minor_int = std::stoi(std::string(input.minor));
53+
} catch (...) {
54+
return std::unexpected(inc_error::INVALID_MINOR);
55+
}
56+
auto incremented_minor_int = minor_int + 1;
57+
std::string_view incremented_minor(std::to_string(incremented_minor_int));
58+
return version_weaver::version{input.major, incremented_minor, "0"};
59+
}
60+
case PATCH: {
61+
auto dash_post = input.patch.find("-");
62+
if (dash_post != std::string::npos) {
63+
auto incremented_patch = input.patch.substr(0, dash_post);
64+
return version_weaver::version{input.major, input.minor, incremented_patch};
65+
}
66+
int patch_int;
67+
try {
68+
patch_int = std::stoi(std::string(input.patch));
69+
} catch (...) {
70+
return std::unexpected(inc_error::INVALID_PATCH);
71+
}
72+
auto incremented_patch_int = patch_int + 1;
73+
std::string_view incremented_patch(std::to_string(incremented_patch_int));
74+
return version_weaver::version{input.major, input.minor, incremented_patch};
75+
}
76+
default:
77+
return std::unexpected(inc_error::INVALID_RELEASE_TYPE);
78+
}
79+
}
80+
3681
constexpr inline void trim_whitespace(std::string_view* input) noexcept {
3782
while (!input->empty() && std::isspace(input->front())) {
3883
input->remove_prefix(1);

tests/basictests.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,45 @@ TEST(basictests, coerce) {
184184
}
185185
}
186186
}
187+
188+
using IncTestData = std::tuple<
189+
version_weaver::version,
190+
version_weaver::release_type,
191+
std::expected<version_weaver::version, version_weaver::inc_error>
192+
>;
193+
194+
std::vector<IncTestData> inc_values = {
195+
{version_weaver::version{"1", "2", "3"}, version_weaver::release_type::MAJOR, version_weaver::version{"2", "0", "0"}},
196+
{version_weaver::version{"1", "2", "3"}, version_weaver::release_type::MINOR, version_weaver::version{"1", "3", "0"}},
197+
{version_weaver::version{"1", "2", "3"}, version_weaver::release_type::PATCH, version_weaver::version{"1", "2", "4"}},
198+
{version_weaver::version{"1", "2", "3tag"}, version_weaver::release_type::MAJOR, version_weaver::version{"2", "0", "0"}},
199+
{version_weaver::version{"1", "2", "3-tag"}, version_weaver::release_type::MAJOR, version_weaver::version{"2", "0", "0"}},
200+
{version_weaver::version{"1", "2", "3"}, static_cast<version_weaver::release_type>(-1), std::unexpected(version_weaver::inc_error::INVALID_RELEASE_TYPE)},
201+
{version_weaver::version{"1", "2", "0-0"}, version_weaver::release_type::PATCH, version_weaver::version{"1", "2", "0"}},
202+
{version_weaver::version{"fake"}, version_weaver::release_type::MAJOR, std::unexpected(version_weaver::inc_error::INVALID_MAJOR)},
203+
{version_weaver::version{"1", "2", "3-4"}, version_weaver::release_type::MAJOR, version_weaver::version{"2", "0", "0"}},
204+
{version_weaver::version{"1", "2", "3-4"}, version_weaver::release_type::MINOR, version_weaver::version{"1", "3", "0"}},
205+
{version_weaver::version{"1", "2", "3-4"}, version_weaver::release_type::PATCH, version_weaver::version{"1", "2", "3"}},
206+
{version_weaver::version{"1", "2", "3-alpha.0.beta"}, version_weaver::release_type::MAJOR, version_weaver::version{"2", "0", "0"}},
207+
{version_weaver::version{"1", "2", "3-alpha.0.beta"}, version_weaver::release_type::MINOR, version_weaver::version{"1", "3", "0"}},
208+
{version_weaver::version{"1", "2", "3-alpha.0.beta"}, version_weaver::release_type::PATCH, version_weaver::version{"1", "2", "3"}},
209+
};
210+
211+
TEST(basictests, inc) {
212+
for (const auto& [input, release_type, expected] : inc_values) {
213+
auto incremented = version_weaver::inc(input, release_type);
214+
215+
ASSERT_EQ(incremented.has_value(), expected.has_value());
216+
if (incremented.has_value()) {
217+
ASSERT_EQ(incremented->major, expected->major);
218+
ASSERT_EQ(incremented->minor, expected->minor);
219+
ASSERT_EQ(incremented->patch, expected->patch);
220+
ASSERT_EQ(incremented->pre_release, expected->pre_release);
221+
ASSERT_EQ(incremented->build, expected->build);
222+
} else {
223+
ASSERT_EQ(incremented.error(), expected.error());
224+
}
225+
}
226+
227+
SUCCEED();
228+
}

0 commit comments

Comments
 (0)