From 420a6bae76968413ab75b8b17002a07c18bd762a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com> Date: Tue, 3 Nov 2020 10:49:33 +0100 Subject: [PATCH] Add tests for EscapeString utilities Actually fixed a few issues and make functions escapeString() and unescapeString() reciprocal. This later change leads to a grammar change, now literal do not store quotes: before `"foo"` was stored as the string "\"foo\"", now it is just stored as "foo". --- src/language/PEGGrammar.hpp | 6 ++++-- src/language/utils/ASTPrinter.cpp | 5 +++-- src/utils/EscapedString.hpp | 9 +++++++-- tests/CMakeLists.txt | 1 + tests/test_EscapedString.cpp | 27 +++++++++++++++++++++++++++ 5 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 tests/test_EscapedString.cpp diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp index fb3b1d74a..553a2797c 100644 --- a/src/language/PEGGrammar.hpp +++ b/src/language/PEGGrammar.hpp @@ -55,11 +55,13 @@ struct character : if_must_else< one< '\\' >, escaped_c, ascii::any> {}; struct open_parent : seq< one< '(' >, ignored > {}; struct close_parent : seq< one< ')' >, ignored > {}; -struct literal : if_must< one< '"' >, until< one< '"' >, character > > {}; +struct literal : star< minus<character, one < '"' > > >{}; + +struct quoted_literal : if_must< one< '"' >, seq< literal, one< '"' > > >{}; struct import_kw : TAO_PEGTL_KEYWORD("import") {}; -struct LITERAL : seq< literal, ignored >{}; +struct LITERAL : seq< quoted_literal, ignored >{}; struct REAL : seq< real, ignored >{}; diff --git a/src/language/utils/ASTPrinter.cpp b/src/language/utils/ASTPrinter.cpp index 9bf18bdcf..8cc88b530 100644 --- a/src/language/utils/ASTPrinter.cpp +++ b/src/language/utils/ASTPrinter.cpp @@ -14,9 +14,10 @@ ASTPrinter::_print(std::ostream& os, const ASTNode& node) const } os << rang::fg::reset; - if (node.is_type<language::name>() or node.is_type<language::literal>() or node.is_type<language::integer>() or - node.is_type<language::real>()) { + if (node.is_type<language::name>() or node.is_type<language::integer>() or node.is_type<language::real>()) { os << ':' << rang::fgB::green << node.string() << rang::fg::reset; + } else if (node.is_type<language::literal>()) { + os << ":\"" << rang::fgB::green << node.string() << rang::fg::reset << '"'; } if (m_info & static_cast<InfoBaseType>(Info::data_type)) { diff --git a/src/utils/EscapedString.hpp b/src/utils/EscapedString.hpp index ed525abd0..cf0f0c676 100644 --- a/src/utils/EscapedString.hpp +++ b/src/utils/EscapedString.hpp @@ -1,6 +1,7 @@ #ifndef ESCAPED_STRING_HPP #define ESCAPED_STRING_HPP +#include <utils/Exceptions.hpp> #include <utils/PugsMacros.hpp> #include <sstream> @@ -11,7 +12,7 @@ PUGS_INLINE std::string unescapeString(std::string_view input_string) { std::stringstream ss; - for (size_t i = 1; i < input_string.size() - 1; ++i) { + for (size_t i = 0; i < input_string.size(); ++i) { char c = input_string[i]; if (c == '\\') { ++i; @@ -81,11 +82,15 @@ escapeString(std::string_view input_string) ss << R"(\\)"; break; } + case '\'': { + ss << R"(\')"; + break; + } case '\"': { ss << R"(\")"; break; } - case '?': { + case '\?': { ss << R"(\?)"; break; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 027b1293f..b58ed3cf8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -60,6 +60,7 @@ add_executable (unit_tests test_Demangle.cpp test_DoWhileProcessor.cpp test_EmbeddedData.cpp + test_EscapedString.cpp test_ExecutionPolicy.cpp test_FakeProcessor.cpp test_ForProcessor.cpp diff --git a/tests/test_EscapedString.cpp b/tests/test_EscapedString.cpp new file mode 100644 index 000000000..925ebadbd --- /dev/null +++ b/tests/test_EscapedString.cpp @@ -0,0 +1,27 @@ +#ifndef TEST_ESCAPED_STRING_HPP +#define TEST_ESCAPED_STRING_HPP + +#include <catch2/catch.hpp> + +#include <utils/EscapedString.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("EscapedString", "[utils]") +{ + SECTION("escape string") + { + const std::string s = "foo\'\\\"\?\a\b\f\n\r\t\vbar"; + + REQUIRE(escapeString(s) == R"(foo\'\\\"\?\a\b\f\n\r\t\vbar)"); + } + + SECTION("unescape string") + { + const std::string s = R"(foo\'\\\"\?\a\b\f\n\r\t\vbar)"; + + REQUIRE(unescapeString(s) == std::string{"foo\'\\\"\?\a\b\f\n\r\t\vbar"}); + } +} + +#endif // TEST_ESCAPED_STRING_HPP -- GitLab