Skip to content

Commit

Permalink
Merge pull request #5 from gmbeard/fix/4-incorrect-metadata-parsing
Browse files Browse the repository at this point in the history
fix(#4): Fixes incorrect parsing of metadata
  • Loading branch information
gmbeard authored Jul 18, 2023
2 parents f823dd5 + 785ecbd commit 90f03ec
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 11 deletions.
1 change: 1 addition & 0 deletions .versioning/changes/QM7uboGFvs.patch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixes an issue where the metadata value was parsed as the pre-release value if the pre-release value was missing from the input [#4](https://github.com/gmbeard/semverutil/issues/4)
36 changes: 27 additions & 9 deletions include/semverutil/semver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,34 @@ template <typename InputIterator>
auto parse_semver(InputIterator first, InputIterator last)
-> std::optional<SemVer>
{
std::string_view const empty = "";

std::array<std::string_view, 3> parts {};
auto r = split_to(first, last, AnyOf { "-+" }, begin(parts), end(parts));

if (r == begin(parts))
return std::nullopt;

while (r != end(parts))
*r++ = empty;
std::array<std::string_view, 2> split_storage {};
auto pos =
split_to(first, last, '-', begin(split_storage), end(split_storage));

/* We have to accommodate for the fact that both the pre-release value and
* the metadata value are optional. We also can't just split on all `-` and
* `+` tokens because both the pre-release and the metadata values may
* contain these tokens, so we must split on only the first occurance of
* each...
*/
if (std::distance(begin(split_storage), pos) == 1) {
split_to(begin(split_storage[0]),
end(split_storage[0]),
'+',
begin(split_storage),
end(split_storage));
parts[0] = split_storage[0];
parts[2] = split_storage[1];
}
else {
parts[0] = split_storage[0];
split_to(begin(split_storage[1]),
end(split_storage[1]),
'+',
next(begin(parts)),
end(parts));
}

decltype(SemVer::version) version {};

Expand Down
8 changes: 7 additions & 1 deletion include/semverutil/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ template <typename InputIterator,
typename OutputIterator>
auto split_to(InputIterator i_first,
InputIterator i_last,
Delim const& delim,
Delim delim,
OutputIterator o_first,
OutputIterator o_last,
F transform) noexcept -> OutputIterator
Expand All @@ -56,8 +56,13 @@ auto split_to(InputIterator i_first,
std::size_t n = 0;

while (o_first != o_last) {
/* If there is only more space left in the output range then we just
* output the rest of the input, regardless of whether there are any
* more delimiters or not...
*/
if (std::next(o_first) == o_last)
delim_pos = i_last;

if constexpr (Transform<F, InputIterator>) {
*o_first++ = transform(from, delim_pos);
}
Expand All @@ -66,6 +71,7 @@ auto split_to(InputIterator i_first,
}

from = delim_pos != i_last ? ++delim_pos : delim_pos;

delim_pos = std::find(from, i_last, delim);

if (delim_pos == i_last && from == delim_pos)
Expand Down
42 changes: 41 additions & 1 deletion tests/parsing_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ using semver::parse_multiple;
using semver::parse_semver;
using semver::SemVer;

auto operator<<(std::ostream& os, semver::SemVer const& val) -> std::ostream&
{
os << val.version[0] << '.' << val.version[1] << '.' << val.version[2];
if (val.version[3])
os << '_' << val.version[3];

if (val.prerelease.size())
os << '-' << val.prerelease;

if (val.metadata.size())
os << '+' << val.metadata;

return os;
}

auto should_parse_multiple() -> void
{
constexpr char const kInput[] = R"#(1.0.1
Expand All @@ -22,6 +37,9 @@ auto should_parse_multiple() -> void

parse_multiple(std::begin(kInput), std::end(kInput), results);

for (auto const& r : results)
std::cerr << r << '\n';
std::cerr << results.size() << '\n';
EXPECT(results.size() == 6);

std::sort(begin(results), end(results));
Expand Down Expand Up @@ -63,10 +81,32 @@ auto should_parse_revision_when_incomplete_core()
EXPECT(results[1].revision() == 2);
}

auto should_parse_metadata_when_prerelease_omitted()
{
constexpr char const kInput[] = "1.0.0+deadbeef";

auto result = parse_semver(kInput);
EXPECT(result);
EXPECT(result->prerelease.size() == 0);
EXPECT(result->metadata == "deadbeef");
}

auto should_handle_multiple_prerelease_separators_and_metadata()
{
constexpr char const kInput[] = "1.0.0-a-b+c+d";

auto result = parse_semver(kInput);
EXPECT(result);
EXPECT(result->prerelease == "a-b");
EXPECT(result->metadata == "c+d");
}

auto main() -> int
{
return semver::testing::run(
{ TEST(should_parse_multiple),
TEST(should_parse_from_stdin),
TEST(should_parse_revision_when_incomplete_core) });
TEST(should_parse_revision_when_incomplete_core),
TEST(should_handle_multiple_prerelease_separators_and_metadata),
TEST(should_parse_metadata_when_prerelease_omitted) });
}

0 comments on commit 90f03ec

Please sign in to comment.