Add some tests for the suggestions

This commit is contained in:
regnat 2022-03-03 13:12:27 +01:00
parent c0792b1546
commit 2405bbbb5e
3 changed files with 48 additions and 10 deletions

View file

@ -5,15 +5,8 @@
namespace nix { namespace nix {
/** int levenshteinDistance(std::string_view first, std::string_view second)
* Return `some(distance)` where distance is an integer representing some
* notion of distance between both arguments.
*
* If the distance is too big, return none
*/
int distanceBetween(std::string_view first, std::string_view second)
{ {
// Levenshtein distance.
// Implementation borrowed from // Implementation borrowed from
// https://en.wikipedia.org/wiki/Levenshtein_distance#Iterative_with_two_matrix_rows // https://en.wikipedia.org/wiki/Levenshtein_distance#Iterative_with_two_matrix_rows
@ -49,7 +42,7 @@ Suggestions Suggestions::bestMatches (
std::set<Suggestion> res; std::set<Suggestion> res;
for (const auto & possibleMatch : allMatches) { for (const auto & possibleMatch : allMatches) {
res.insert(Suggestion { res.insert(Suggestion {
.distance = distanceBetween(query, possibleMatch), .distance = levenshteinDistance(query, possibleMatch),
.suggestion = possibleMatch, .suggestion = possibleMatch,
}); });
} }
@ -63,7 +56,7 @@ Suggestions Suggestions::trim(int limit, int maxDistance) const
int count = 0; int count = 0;
for (auto & elt : suggestions) { for (auto & elt : suggestions) {
if (count >= limit || elt.distance >= maxDistance) if (count >= limit || elt.distance > maxDistance)
break; break;
count++; count++;
res.insert(elt); res.insert(elt);

View file

@ -6,6 +6,8 @@
namespace nix { namespace nix {
int levenshteinDistance(std::string_view first, std::string_view second);
/** /**
* A potential suggestion for the cli interface. * A potential suggestion for the cli interface.
*/ */

View file

@ -0,0 +1,43 @@
#include "suggestions.hh"
#include <gtest/gtest.h>
namespace nix {
struct LevenshteinDistanceParam {
std::string s1, s2;
int distance;
};
class LevenshteinDistanceTest :
public testing::TestWithParam<LevenshteinDistanceParam> {
};
TEST_P(LevenshteinDistanceTest, CorrectlyComputed) {
auto params = GetParam();
ASSERT_EQ(levenshteinDistance(params.s1, params.s2), params.distance);
ASSERT_EQ(levenshteinDistance(params.s2, params.s1), params.distance);
}
INSTANTIATE_TEST_SUITE_P(LevenshteinDistance, LevenshteinDistanceTest,
testing::Values(
LevenshteinDistanceParam{"foo", "foo", 0},
LevenshteinDistanceParam{"foo", "", 3},
LevenshteinDistanceParam{"", "", 0},
LevenshteinDistanceParam{"foo", "fo", 1},
LevenshteinDistanceParam{"foo", "oo", 1},
LevenshteinDistanceParam{"foo", "fao", 1},
LevenshteinDistanceParam{"foo", "abc", 3}
)
);
TEST(Suggestions, Trim) {
auto suggestions = Suggestions::bestMatches({"foooo", "bar", "fo", "gao"}, "foo");
auto onlyOne = suggestions.trim(1);
ASSERT_EQ(onlyOne.suggestions.size(), 1);
ASSERT_TRUE(onlyOne.suggestions.begin()->suggestion == "fo");
auto closest = suggestions.trim(999, 2);
ASSERT_EQ(closest.suggestions.size(), 3);
}
}