Browse Source

Add tests for `StringUtilities::ExpandString`

Michael Ragazzon 1 month ago
parent
commit
e797d4c698
2 changed files with 86 additions and 0 deletions
  1. 32 0
      Tests/Source/Common/TypesToString.h
  2. 54 0
      Tests/Source/UnitTests/StringUtilities.cpp

+ 32 - 0
Tests/Source/Common/TypesToString.h

@@ -36,6 +36,7 @@
 #include <RmlUi/Core/Vertex.h>
 #include <RmlUi/Core/Vertex.h>
 #include <doctest.h>
 #include <doctest.h>
 #include <ostream>
 #include <ostream>
+#include <sstream>
 
 
 /*
 /*
  *   Provides string conversion of types for doctest.
  *   Provides string conversion of types for doctest.
@@ -102,6 +103,37 @@ inline std::ostream& operator<<(std::ostream& os, const Variant& value)
 	return os;
 	return os;
 }
 }
 
 
+struct StringListWrapper {
+	StringList string_list;
+	bool operator==(const StringListWrapper& other) const { return string_list == other.string_list; }
+};
+
 } // namespace Rml
 } // namespace Rml
 
 
+namespace doctest {
+//  Some types are aliases to underlying std-types, so they need to be converted with a StringMaker.
+
+// For some reason, this doesn't seem to actually work. Instead, we use the StringListWrapper wrapper object in the Rml namespace.
+template <>
+struct StringMaker<Rml::StringList> {
+	static ::doctest::String convert(const Rml::StringList& value)
+	{
+		std::ostringstream os;
+		for (const auto& string : value)
+		{
+			os << string;
+			if (&string != &value.back())
+				os << ", ";
+		}
+		return ::doctest::String(os.str().c_str());
+	}
+};
+
+template <>
+struct StringMaker<Rml::StringListWrapper> {
+	static ::doctest::String convert(const Rml::StringListWrapper& value) { return StringMaker<Rml::StringList>::convert(value.string_list); }
+};
+
+} // namespace doctest
+
 #endif
 #endif

+ 54 - 0
Tests/Source/UnitTests/StringUtilities.cpp

@@ -26,6 +26,7 @@
  *
  *
  */
  */
 
 
+#include "../Common/TypesToString.h"
 #include <RmlUi/Core/StringUtilities.h>
 #include <RmlUi/Core/StringUtilities.h>
 #include <RmlUi/Core/Types.h>
 #include <RmlUi/Core/Types.h>
 #include <doctest.h>
 #include <doctest.h>
@@ -61,6 +62,59 @@ TEST_CASE("StringUtilities::TrimTrailingDotZeros")
 	WARN(RunTrimTrailingDotZeros("11") == "11");
 	WARN(RunTrimTrailingDotZeros("11") == "11");
 }
 }
 
 
+TEST_CASE("StringUtilities::ExpandString")
+{
+	auto ExpandStringShort = [](const String string, char delimiter, bool ignore_repeated_delimiters = false) {
+		StringList result;
+		StringUtilities::ExpandString(result, string, delimiter, ignore_repeated_delimiters);
+		return StringListWrapper{result};
+	};
+	auto ExpandStringLong = [](const String string, char delimiter, char quote, char unquote, bool ignore_repeated_delimiters) {
+		StringList result;
+		StringUtilities::ExpandString(result, string, delimiter, quote, unquote, ignore_repeated_delimiters);
+		return StringListWrapper{result};
+	};
+	auto ExpandString = [&](const String string, char delimiter, bool ignore_repeated_delimiters = false) {
+		const StringListWrapper short_result = ExpandStringShort(string, delimiter, ignore_repeated_delimiters);
+		const StringListWrapper long_result = ExpandStringLong(string, delimiter, '(', ')', ignore_repeated_delimiters);
+		CAPTURE(string);
+		CAPTURE(String{delimiter});
+		CHECK(short_result == long_result);
+		return short_result;
+	};
+
+	CHECK(ExpandString("a,b,c", ',') == StringListWrapper{{"a", "b", "c"}});
+	CHECK(ExpandString("a,b,c", ' ') == StringListWrapper{{"a,b,c"}});
+	CHECK(ExpandString("a b c", ' ') == StringListWrapper{{"a", "b", "c"}});
+
+	CHECK(ExpandString("a,b,,c", ',') == StringListWrapper{{"a", "b", "", "c"}});
+	CHECK(ExpandString(" a ,  b  , c ", ',') == StringListWrapper{{"a", "b", "c"}});
+
+	CHECK(ExpandString("a", ',') == StringListWrapper{{"a"}});
+	CHECK(ExpandStringShort("", ',') == StringListWrapper{{""}});
+	CHECK(ExpandStringShort("", ' ') == StringListWrapper{{""}});
+	CHECK(ExpandStringShort(" ", ' ') == StringListWrapper{{""}});
+	CHECK(ExpandString(",a,b", ',') == StringListWrapper{{"", "a", "b"}});
+	CHECK(ExpandString("a,,b", ',') == StringListWrapper{{"a", "", "b"}});
+	CHECK(ExpandString("a;b;c", ';') == StringListWrapper{{"a", "b", "c"}});
+
+	CHECK(ExpandStringLong("(a,b),c", ',', '(', ')', false) == StringListWrapper{{"(a,b)", "c"}});
+	CHECK(ExpandStringLong("((a,b),c),d", ',', '(', ')', false) == StringListWrapper{{"((a,b),c)", "d"}});
+	CHECK(ExpandStringLong("a,,b", ',', '(', ')', false) == StringListWrapper{{"a", "", "b"}});
+	CHECK(ExpandStringLong("a,,b", ',', '(', ')', true) == StringListWrapper{{"a", "b"}});
+	CHECK(ExpandStringLong("a  b", ' ', '(', ')', false) == StringListWrapper{{"a", "", "b"}});
+	CHECK(ExpandStringLong("a  b", ' ', '(', ')', true) == StringListWrapper{{"a", "b"}});
+
+	// Questionable behavior, consider changing implementation to match the suggestion.
+	CHECK(ExpandString("a,b,", ',') == StringListWrapper{{"a", "b"}});                       // { "a", "b", ""}
+	CHECK(ExpandString("  ,  ", ',') == StringListWrapper{{""}});                            // {"", ""}}
+	CHECK(ExpandString(" a  b  c ", ' ') == StringListWrapper{{"", "a", "", "b", "", "c"}}); // {"a", "b", "c"}}
+	CHECK(ExpandStringShort("'a,b',c", ',') == StringListWrapper{{"a,b", "c"}});             // {"'a,b'", "c"}
+	CHECK(ExpandStringShort(R"("a,b",c)", ',') == StringListWrapper{{R"(a,b)", "c"}});       // {R"("a,b")", "c"}
+	CHECK(ExpandStringShort("\"a\\\",b\",c", ',') == StringListWrapper{{R"(a\",b)", "c"}});  // {R"("a\",b")", "c"} (MSVC fails using raw string here)
+	CHECK(ExpandStringLong("\"a,b,c\",d", ',', '"', '"', false) == StringListWrapper{{"\"a,b,c\",d"}}); // {"\"a,b,c\"", "d"}}
+}
+
 TEST_CASE("StringUtilities::StartsWith")
 TEST_CASE("StringUtilities::StartsWith")
 {
 {
 	using namespace Rml::StringUtilities;
 	using namespace Rml::StringUtilities;