Browse Source

Test coverage

Sam Jaffe 2 years ago
parent
commit
40a90787a8
3 changed files with 76 additions and 9 deletions
  1. 4 0
      include/string_utils/cast.h
  2. 0 3
      include/string_utils/forwards.h
  3. 72 6
      test/cast_test.cxx

+ 4 - 0
include/string_utils/cast.h

@@ -109,12 +109,14 @@ bool cast(Out & out, std::vector<std::string_view> const & strs) noexcept {
       if (!success) { return false; }
       out.insert(std::move(tmp));
     }
+    return true;
   } else if constexpr (detail::is_container_v<Out>) {
     for (auto elem : strs) {
       auto [tmp, success] = cast<typename Out::value_type>(elem);
       if (!success) { return false; }
       out.insert(out.end(), std::move(tmp));
     }
+    return true;
   } else if constexpr (detail::is_tuple_v<Out>) {
     constexpr size_t N = std::tuple_size_v<Out>;
     return strs.size() == N &&
@@ -127,6 +129,7 @@ bool cast(Out & out, std::vector<std::string_view> const & strs) noexcept {
 
 template <typename T> std::pair<T, bool> cast(std::string_view str) noexcept {
   std::pair<detail::decay_t<T>, bool> rval;
+  using ::string_utils::cast;
   rval.second = cast(rval.first, str);
   return rval;
 }
@@ -135,6 +138,7 @@ template <typename T, typename S>
 std::pair<T, bool> cast(std::vector<S> const & strs) noexcept {
   std::vector<std::string_view> tmp{strs.begin(), strs.end()};
   std::pair<detail::decay_t<T>, bool> rval;
+  using ::string_utils::cast;
   rval.second = cast(rval.first, tmp);
   return rval;
 }

+ 0 - 3
include/string_utils/forwards.h

@@ -15,9 +15,6 @@ namespace string_utils {
 class Tokenizer;
 class EscapedTokenizer;
 
-// A helper object for providing partial specializations for casting
-template <typename, typename = void> struct cast_helper;
-
 // The main parser
 template <typename T> std::pair<T, bool> cast(std::string_view str) noexcept;
 template <typename T, typename S>

+ 72 - 6
test/cast_test.cxx

@@ -10,6 +10,7 @@
 
 #include "xcode_gtest_helper.h"
 
+using testing::ElementsAre;
 using testing::FieldsAre;
 using testing::Pair;
 using namespace string_utils;
@@ -95,33 +96,98 @@ TEST(CastKeyValTest, FailsOnTooFewTokens) {
 }
 
 TEST(CastKeyValTest, ParsesTokens) {
-  auto [value, success] = cast<pair_t>(std::vector{"key","value"});
+  auto [value, success] = cast<pair_t>(std::vector{"key", "value"});
   EXPECT_TRUE(success);
   EXPECT_THAT(value, Pair("key", "value"));
 }
 
 TEST(CastKeyValTest, FailsOnTooManyTokens) {
-  auto [value, success] = cast<pair_t>(std::vector{"key","value","mapping"});
+  auto [value, success] = cast<pair_t>(std::vector{"key", "value", "mapping"});
   EXPECT_FALSE(success);
 }
 
 TEST(CastTupleTest, FailsOnTooFewTokens) {
-  auto [value, success] = cast<tuple_t>(std::vector{"0","A"});
+  auto [value, success] = cast<tuple_t>(std::vector{"0", "A"});
   EXPECT_FALSE(success);
 }
 
 TEST(CastTupleTest, FailsOnTooManyTokens) {
-  auto [value, success] = cast<tuple_t>(std::vector{"0","1","A","B"});
+  auto [value, success] = cast<tuple_t>(std::vector{"0", "1", "A", "B"});
   EXPECT_FALSE(success);
 }
 
 TEST(CastTupleTest, ParsesIfAllGood) {
-  auto [value, success] = cast<tuple_t>(std::vector{"0","1","A"});
+  auto [value, success] = cast<tuple_t>(std::vector{"0", "1", "A"});
   EXPECT_TRUE(success);
   EXPECT_THAT(value, FieldsAre(0, 1, "A"));
 }
 
 TEST(CastTupleTest, FailsOnAnyParseError) {
-  auto [value, success] = cast<tuple_t>(std::vector{"0","Q","A"});
+  auto [value, success] = cast<tuple_t>(std::vector{"0", "Q", "A"});
+  EXPECT_FALSE(success);
+}
+
+struct Bindable {
+  int a;
+  std::string b;
+};
+
+bool cast(Bindable & out, std::vector<std::string_view> const & strs) {
+  return strs.size() == 2 && cast(out.a, strs[0]) && cast(out.b, strs[1]);
+}
+
+struct Positive {
+  int value;
+};
+
+bool cast(Positive & out, std::string_view str) {
+  return cast(out.value, str) && out.value > 0;
+}
+
+TEST(CastTest, UsesADL) {
+  auto [value, success] = cast<Bindable>(std::vector{"0", "Q"});
+  EXPECT_TRUE(success);
+}
+
+TEST(CastTest, CanImposeConstraint) {
+  auto [value, success] = cast<Positive>("0");
+  EXPECT_FALSE(success);
+}
+
+TEST(CastContainerTest, CanCastVector) {
+  auto [value, success] =
+      cast<std::vector<std::string>>(std::vector{"0", "Q", "A"});
+  EXPECT_TRUE(success);
+  EXPECT_THAT(value, ElementsAre("0", "Q", "A"));
+}
+
+TEST(CastContainerTest, FailsIfBadValueCast) {
+  auto [value, success] = cast<std::vector<int>>(std::vector{"0", "Q", "A"});
+  EXPECT_FALSE(success);
+}
+
+TEST(CastContainerTest, CanCastSet) {
+  auto [value, success] =
+      cast<std::set<std::string>>(std::vector{"0", "0", "A"});
+  EXPECT_TRUE(success);
+  EXPECT_THAT(value, ElementsAre("0", "A"));
+}
+
+TEST(CastContainerTest, CanCastMap) {
+  auto [value, success] = cast<std::map<std::string, std::string>>(
+      std::vector{"0=1", "0=2", "A=B"});
+  EXPECT_TRUE(success);
+  EXPECT_THAT(value, ElementsAre(Pair("0", "1"), Pair("A", "B")));
+}
+
+TEST(CastContainerTest, FailsIfBadCastOnKey) {
+  auto [value, success] =
+      cast<std::map<int, std::string>>(std::vector{"0=1", "0=2", "A=B"});
+  EXPECT_FALSE(success);
+}
+
+TEST(CastContainerTest, FailsIfBadCastOnValue) {
+  auto [value, success] =
+      cast<std::map<std::string, int>>(std::vector{"0=1", "0=2", "A=B"});
   EXPECT_FALSE(success);
 }