Merge changes If469110d,Ia7919e8f

* changes:
  Fix includes for GCC 8.2
  Update sysrepo
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1807991..c03cb47 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -92,6 +92,7 @@
     src/utils.cpp
     src/parser_context.cpp
     src/interpreter.cpp
+    src/ast_handlers.cpp
     )
 target_link_libraries(parser schemas)
 
@@ -172,7 +173,8 @@
     cli_test(sysrepo)
     target_link_libraries(test_sysrepo sysreposubscription sysrepoaccess yangschema parser)
     target_include_directories(test_sysrepo PRIVATE ${PROJECT_SOURCE_DIR}/tests/mock)
-
+    cli_test(utils)
+    cli_test(path_completion)
 endif()
 
 if(WITH_DOCS)
diff --git a/src/ast_handlers.cpp b/src/ast_handlers.cpp
new file mode 100644
index 0000000..ca5fe25
--- /dev/null
+++ b/src/ast_handlers.cpp
@@ -0,0 +1,15 @@
+#include "ast_handlers.hpp"
+std::set<std::string> generateMissingKeyCompletionSet(std::set<std::string> keysNeeded, std::set<std::string> currentSet)
+{
+    std::set<std::string> missingKeys;
+    std::set_difference(keysNeeded.begin(), keysNeeded.end(),
+            currentSet.begin(), currentSet.end(),
+            std::inserter(missingKeys, missingKeys.end()));
+
+    std::set<std::string> res;
+
+    std::transform(missingKeys.begin(), missingKeys.end(),
+                   std::inserter(res, res.end()),
+                   [] (auto it) { return it + "="; });
+    return res;
+}
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index 717f077..5a55f36 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -11,6 +11,9 @@
 #include "parser_context.hpp"
 #include "schema.hpp"
 #include "utils.hpp"
+namespace x3 = boost::spirit::x3;
+
+struct parser_context_tag;
 
 struct keyValue_class {
     template <typename T, typename Iterator, typename Context>
@@ -469,7 +472,7 @@
     }
 };
 
-struct initializeContext_class {
+struct initializePath_class {
     template <typename T, typename Iterator, typename Context>
     void on_success(Iterator const&, Iterator const&, T&, Context const& context)
     {
@@ -477,6 +480,7 @@
         parserContext.m_curPath = parserContext.m_curPathOrig;
         parserContext.m_tmpListKeys.clear();
         parserContext.m_tmpListName.clear();
+        parserContext.m_suggestions.clear();
         if (!parserContext.m_curPath.m_nodes.empty() && parserContext.m_curPath.m_nodes.at(0).m_prefix)
             parserContext.m_topLevelModulePresent = true;
         else
@@ -485,3 +489,48 @@
 };
 
 struct trailingSlash_class;
+
+struct createPathSuggestions_class {
+    template <typename T, typename Iterator, typename Context>
+    void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
+    {
+        auto& parserContext = x3::get<parser_context_tag>(context);
+        const auto& schema = parserContext.m_schema;
+
+        parserContext.m_completionIterator = begin;
+        parserContext.m_suggestions = schema.childNodes(parserContext.m_curPath, Recursion::NonRecursive);
+    }
+};
+
+std::set<std::string> generateMissingKeyCompletionSet(std::set<std::string> keysNeeded, std::set<std::string> currentSet);
+
+struct createKeySuggestions_class {
+    template <typename T, typename Iterator, typename Context>
+    void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
+    {
+        auto& parserContext = x3::get<parser_context_tag>(context);
+        const auto& schema = parserContext.m_schema;
+
+        parserContext.m_completionIterator = begin;
+
+        const auto& keysNeeded = schema.listKeys(parserContext.m_curPath, {parserContext.m_curModule, parserContext.m_tmpListName});
+        parserContext.m_suggestions = generateMissingKeyCompletionSet(keysNeeded, parserContext.m_tmpListKeys);
+    }
+};
+
+struct suggestKeysEnd_class {
+    template <typename T, typename Iterator, typename Context>
+    void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
+    {
+        auto& parserContext = x3::get<parser_context_tag>(context);
+        const auto& schema = parserContext.m_schema;
+
+        parserContext.m_completionIterator = begin;
+        const auto& keysNeeded = schema.listKeys(parserContext.m_curPath, {parserContext.m_curModule, parserContext.m_tmpListName});
+        if (generateMissingKeyCompletionSet(keysNeeded, parserContext.m_tmpListKeys).empty()) {
+            parserContext.m_suggestions = {"]/"};
+        } else {
+            parserContext.m_suggestions = {"]"};
+        }
+    }
+};
diff --git a/src/grammars.hpp b/src/grammars.hpp
index d0101fb..2bf7be4 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -53,7 +53,10 @@
 x3::rule<commit_class, commit_> const commit = "commit";
 x3::rule<command_class, command_> const command = "command";
 
-x3::rule<initializeContext_class, x3::unused_type> const initializeContext = "initializeContext";
+x3::rule<initializePath_class, x3::unused_type> const initializePath = "initializePath";
+x3::rule<createPathSuggestions_class, x3::unused_type> const createPathSuggestions = "createPathSuggestions";
+x3::rule<createKeySuggestions_class, x3::unused_type> const createKeySuggestions = "createKeySuggestions";
+x3::rule<suggestKeysEnd_class, x3::unused_type> const suggestKeysEnd = "suggestKeysEnd";
 
 #if __clang__
 #pragma GCC diagnostic push
@@ -72,8 +75,17 @@
 auto const number =
         +x3::digit;
 
+auto const createKeySuggestions_def =
+        x3::eps;
+
+auto const suggestKeysEnd_def =
+        x3::eps;
+
 auto const keyValue_def =
-        lexeme['[' > key_identifier > '=' > (quotedValue | number) > ']'];
+        key_identifier > '=' > (quotedValue | number);
+
+auto const keyValueWrapper =
+        lexeme['[' > createKeySuggestions > keyValue > suggestKeysEnd > ']'];
 
 auto const module_identifier_def =
         lexeme[
@@ -90,7 +102,7 @@
 
 // even though we don't allow no keys to be supplied, the star allows me to check which keys are missing
 auto const listSuffix_def =
-        *keyValue;
+        *keyValueWrapper;
 
 auto const listElement_def =
         listPrefix > listSuffix;
@@ -110,12 +122,15 @@
 auto const leaf_def =
         node_identifier;
 
+auto const createPathSuggestions_def =
+        x3::eps;
+
 // leaf cannot be in the middle of a path, however, I need the grammar's attribute to be a vector of variants
 auto const schemaNode_def =
-        -(module) >> x3::expect[container | list | nodeup | leaf];
+        createPathSuggestions >> -(module) >> (container | list | nodeup | leaf);
 
 auto const dataNode_def =
-        -(module) >> (container | listElement | nodeup | leaf);
+        createPathSuggestions >> -(module) >> (container | listElement | nodeup | leaf);
 
 auto const absoluteStart_def =
         x3::omit['/'] >> x3::attr(Scope::Absolute);
@@ -123,29 +138,32 @@
 auto const trailingSlash_def =
         x3::omit['/'] >> x3::attr(TrailingSlash::Present);
 
+auto const space_separator =
+        x3::omit[x3::no_skip[space]];
+
 // I have to insert an empty vector to the first alternative, otherwise they won't have the same attribute
 auto const dataPath_def =
-        absoluteStart >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi |
-        -(absoluteStart) >> dataNode % '/' >> -trailingSlash;
+        initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi |
+        initializePath >> -(absoluteStart >> createPathSuggestions) >> dataNode % '/' >> (trailingSlash >> createPathSuggestions | (&space_separator | x3::eoi));
 
 auto const dataNodeList_def =
-        -(module) >> list;
+        -(module) >> createPathSuggestions >> list;
 
 // This intermediate rule is mandatory, because we need the first alternative
 // to be collapsed to a vector. If we didn't use the intermediate rule,
 // Spirit wouldn't know we want it to collapse.
 // https://github.com/boostorg/spirit/issues/408
 auto const dataNodesListEnd_def =
-        dataNode % '/' >> '/' >> dataNodeList |
-        initializeContext >> x3::attr(decltype(dataPath_::m_nodes)()) >> dataNodeList;
+        initializePath >> dataNode % '/' >> '/' >> dataNodeList >> -(&char_('/') >> createPathSuggestions) |
+        initializePath >> x3::attr(decltype(dataPath_::m_nodes)()) >> dataNodeList;
 
 auto const dataPathListEnd_def =
-        absoluteStart >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi |
-        -(absoluteStart) >> dataNodesListEnd >> -trailingSlash;
+        initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi |
+        initializePath >> -(absoluteStart >> createPathSuggestions) >> dataNodesListEnd >> (trailingSlash >> createPathSuggestions | (&space_separator | x3::eoi));
 
 auto const schemaPath_def =
-        absoluteStart >> x3::attr(decltype(schemaPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi |
-        -(absoluteStart) >> schemaNode % '/' >> -trailingSlash;
+        initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(schemaPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi |
+        initializePath >> -(absoluteStart >> createPathSuggestions) >> schemaNode % '/' >> (trailingSlash >> createPathSuggestions | (&space_separator | x3::eoi));
 
 auto const leafPath_def =
         dataPath;
@@ -182,9 +200,6 @@
         leaf_data_uint |
         leaf_data_string];
 
-auto const space_separator =
-        x3::omit[x3::no_skip[space]];
-
 struct ls_options_table : x3::symbols<LsOption> {
     ls_options_table()
     {
@@ -193,12 +208,12 @@
     }
 } const ls_options;
 
-// A "nothing" parser, which is used to reset the context (when trying to parse different types of paths)
-auto const initializeContext_def =
+// A "nothing" parser, which is used to indicate we tried to parse a path
+auto const initializePath_def =
         x3::eps;
 
 auto const ls_def =
-        lit("ls") >> *(space_separator >> ls_options) >> -(space_separator >> (dataPathListEnd | initializeContext >> dataPath));
+        lit("ls") >> *(space_separator >> ls_options) >> -(space_separator >> (dataPathListEnd | dataPath | schemaPath));
 
 auto const cd_def =
         lit("cd") >> space_separator > dataPath;
@@ -210,7 +225,7 @@
         lit("delete") >> space_separator > dataPath;
 
 auto const get_def =
-        lit("get") >> -(space_separator >> (dataPathListEnd | initializeContext >> dataPath));
+        lit("get") >> -(space_separator >> (dataPathListEnd | dataPath));
 
 auto const set_def =
         lit("set") >> space_separator > leafPath > leaf_data;
@@ -222,7 +237,7 @@
         lit("discard") >> x3::attr(discard_());
 
 auto const command_def =
-        x3::expect[cd | create | delete_rule | set | commit | get | ls | discard] >> x3::eoi;
+        x3::expect[cd | create | delete_rule | set | commit | get | ls | discard];
 
 #if __clang__
 #pragma GCC diagnostic pop
@@ -257,7 +272,7 @@
 BOOST_SPIRIT_DEFINE(leaf_data_int)
 BOOST_SPIRIT_DEFINE(leaf_data_uint)
 BOOST_SPIRIT_DEFINE(leaf_data_string)
-BOOST_SPIRIT_DEFINE(initializeContext)
+BOOST_SPIRIT_DEFINE(initializePath)
 BOOST_SPIRIT_DEFINE(set)
 BOOST_SPIRIT_DEFINE(commit)
 BOOST_SPIRIT_DEFINE(get)
@@ -267,3 +282,6 @@
 BOOST_SPIRIT_DEFINE(create)
 BOOST_SPIRIT_DEFINE(delete_rule)
 BOOST_SPIRIT_DEFINE(command)
+BOOST_SPIRIT_DEFINE(createPathSuggestions)
+BOOST_SPIRIT_DEFINE(createKeySuggestions)
+BOOST_SPIRIT_DEFINE(suggestKeysEnd)
diff --git a/src/main.cpp b/src/main.cpp
index eaba76a..3c973dd 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -39,6 +39,12 @@
     Parser parser(datastore.schema());
 
     while (true) {
+        linenoise::SetCompletionCallback([&parser](const char* editBuffer, std::vector<std::string>& completions) {
+            std::stringstream stream;
+            auto completionsSet = parser.completeCommand(editBuffer, stream);
+            std::transform(completionsSet.begin(), completionsSet.end(), std::back_inserter(completions),
+                           [editBuffer](auto it) { return std::string(editBuffer) + it; });
+        });
         linenoise::SetHistoryMaxLen(4);
         linenoise::SetMultiLine(true);
         std::string line;
diff --git a/src/parser.cpp b/src/parser.cpp
index ee0233e..2dbea6b 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -39,6 +39,23 @@
     return parsedCommand;
 }
 
+std::set<std::string> Parser::completeCommand(const std::string& line, std::ostream& errorStream) const
+{
+    std::set<std::string> completions;
+    command_ parsedCommand;
+    ParserContext ctx(*m_schema, dataPathToSchemaPath(m_curDir));
+    auto it = line.begin();
+    boost::spirit::x3::error_handler<std::string::const_iterator> errorHandler(it, line.end(), errorStream);
+
+    auto grammar =
+            x3::with<parser_context_tag>(ctx)[
+            x3::with<x3::error_handler_tag>(std::ref(errorHandler))[command]
+    ];
+    x3::phrase_parse(it, line.end(), grammar, space, parsedCommand);
+
+    return filterAndErasePrefix(ctx.m_suggestions, std::string(ctx.m_completionIterator, line.end()));
+}
+
 void Parser::changeNode(const dataPath_& name)
 {
     if (name.m_scope == Scope::Absolute) {
diff --git a/src/parser.hpp b/src/parser.hpp
index 343a1e5..8c9290f 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -30,6 +30,7 @@
     void changeNode(const dataPath_& name);
     std::string currentNode() const;
     std::set<std::string> availableNodes(const boost::optional<boost::variant<dataPath_, schemaPath_>>& path, const Recursion& option) const;
+    std::set<std::string> completeCommand(const std::string& line, std::ostream& errorStream) const;
 
 private:
     const std::shared_ptr<const Schema> m_schema;
diff --git a/src/parser_context.hpp b/src/parser_context.hpp
index a0b8e30..5d0fe38 100644
--- a/src/parser_context.hpp
+++ b/src/parser_context.hpp
@@ -18,4 +18,7 @@
     bool m_topLevelModulePresent = false;
     std::set<std::string> m_tmpListKeys;
     bool m_errorHandled = false;
+    std::set<std::string> m_suggestions;
+    // Iterator pointing to where suggestions were created
+    std::string::const_iterator m_completionIterator;
 };
diff --git a/src/utils.cpp b/src/utils.cpp
index f9eae06..358bc05 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -5,6 +5,8 @@
  * Written by Václav Kubernát <kubervac@fit.cvut.cz>
  *
 */
+#include <boost/algorithm/string/erase.hpp>
+#include <boost/algorithm/string/predicate.hpp>
 #include "utils.hpp"
 
 std::string joinPaths(const std::string& prefix, const std::string& suffix)
@@ -64,3 +66,18 @@
 {
     return fullNodeName(dataPathToSchemaPath(location), pair);
 }
+
+std::set<std::string> filterAndErasePrefix(const std::set<std::string>& set, const std::string_view prefix)
+{
+    std::set<std::string> filtered;
+    std::copy_if(set.begin(), set.end(),
+            std::inserter(filtered, filtered.end()),
+            [prefix] (auto it) { return boost::starts_with(it, prefix); });
+
+    std::set<std::string> withoutPrefix;
+    std::transform(filtered.begin(), filtered.end(),
+            std::inserter(withoutPrefix, withoutPrefix.end()),
+            [prefix] (auto it) { boost::erase_first(it, prefix); return it; });
+    return withoutPrefix;
+}
+
diff --git a/src/utils.hpp b/src/utils.hpp
index f009ccd..38db0af 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -5,6 +5,9 @@
  * Written by Václav Kubernát <kubervac@fit.cvut.cz>
  *
 */
+/*! \file utils.hpp
+    \brief A header containing utility functions
+*/
 #include <string>
 #include "ast_path.hpp"
 #include "schema.hpp"
@@ -16,3 +19,7 @@
 std::string leafDataTypeToString(yang::LeafDataTypes type);
 std::string fullNodeName(const schemaPath_& location, const ModuleNodePair& pair);
 std::string fullNodeName(const dataPath_& location, const ModuleNodePair& pair);
+/** Returns a subset of the original set with only the strings starting with prefix
+ * and with the actual prefix deleted from the string
+ */
+std::set<std::string> filterAndErasePrefix(const std::set<std::string>& set, const std::string_view prefix);
diff --git a/tests/path_completion.cpp b/tests/path_completion.cpp
new file mode 100644
index 0000000..7a9090b
--- /dev/null
+++ b/tests/path_completion.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
+ * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
+ *
+ * Written by Václav Kubernát <kubervac@fit.cvut.cz>
+ *
+*/
+
+#include "trompeloeil_catch.h"
+#include "ast_commands.hpp"
+#include "parser.hpp"
+#include "static_schema.hpp"
+
+TEST_CASE("path_completion")
+{
+    auto schema = std::make_shared<StaticSchema>();
+    schema->addModule("example");
+    schema->addModule("second");
+    schema->addContainer("", "example:ano");
+    schema->addContainer("", "example:anoda");
+    schema->addList("example:ano", "example:listInCont", {"number"});
+    schema->addContainer("", "second:amelie");
+    schema->addContainer("", "example:bota");
+    schema->addContainer("example:ano", "example:a2");
+    schema->addContainer("example:bota", "example:b2");
+    schema->addContainer("example:ano/example:a2", "example:a3");
+    schema->addContainer("example:bota/example:b2", "example:b3");
+    schema->addList("", "example:list", {"number"});
+    schema->addContainer("example:list", "example:contInList");
+    schema->addList("", "example:twoKeyList", {"number", "name"});
+    Parser parser(schema);
+    std::string input;
+    std::ostringstream errorStream;
+    std::set<std::string> expected;
+
+    SECTION("node name completion")
+    {
+        SECTION("ls ")
+        {
+            input = "ls ";
+            expected = {"example:ano", "example:anoda", "example:bota", "second:amelie", "example:list", "example:twoKeyList"};
+        }
+
+        SECTION("ls e")
+        {
+            input = "ls e";
+            expected = {"xample:ano", "xample:anoda", "xample:bota", "xample:list", "xample:twoKeyList"};
+        }
+
+        SECTION("ls example:ano")
+        {
+            input = "ls example:ano";
+            expected = {"", "da"};
+        }
+
+        SECTION("ls example:ano/example:a")
+        {
+            input = "ls example:ano/example:a";
+            expected = {"2"};
+        }
+
+        SECTION("ls x")
+        {
+            input = "ls x";
+            expected = {};
+        }
+
+        SECTION("ls /")
+        {
+            input = "ls /";
+            expected = {"example:ano", "example:anoda", "example:bota", "second:amelie", "example:list", "example:twoKeyList"};
+        }
+
+        SECTION("ls /e")
+        {
+            input = "ls /e";
+            expected = {"xample:ano", "xample:anoda", "xample:bota", "xample:list", "xample:twoKeyList"};
+        }
+
+        SECTION("ls /s")
+        {
+            input = "ls /s";
+            expected = {"econd:amelie"};
+        }
+
+        SECTION("ls /example:list[number=3]/")
+        {
+            input = "ls /example:list[number=3]/";
+            expected = {"example:contInList"};
+        }
+
+        SECTION("ls /example:list[number=3]/c")
+        {
+            input = "ls /example:list[number=3]/e";
+            expected = {"xample:contInList"};
+        }
+
+        SECTION("ls /example:list[number=3]/a")
+        {
+            input = "ls /example:list[number=3]/a";
+            expected = {};
+        }
+    }
+
+    SECTION("list keys completion")
+    {
+        SECTION("cd example:lis")
+        {
+            input = "cd example:lis";
+            expected = {"t"};
+        }
+
+        SECTION("cd example:list[")
+        {
+            input = "cd example:list[";
+            expected = {"number="};
+        }
+
+        SECTION("cd example:list[numb")
+        {
+            input = "cd example:list[numb";
+            expected = {"er="};
+        }
+
+        SECTION("cd example:list[number")
+        {
+            input = "cd example:list[number";
+            expected = {"="};
+        }
+
+        SECTION("cd example:list[number=12")
+        {
+            input = "cd example:list[number=12";
+            expected = {"]/"};
+        }
+
+        SECTION("cd example:list[number=12]")
+        {
+            input = "cd example:list[number=12]";
+            expected = {"/"};
+        }
+
+        SECTION("cd example:twoKeyList[")
+        {
+            input = "cd example:twoKeyList[";
+            expected = {"name=", "number="};
+        }
+
+        SECTION("cd example:twoKeyList[name=\"AHOJ\"][")
+        {
+            input = "cd example:twoKeyList[name=\"AHOJ\"][";
+            expected = {"number="};
+        }
+
+        SECTION("cd example:twoKeyList[number=42][")
+        {
+            input = "cd example:twoKeyList[number=42][";
+            expected = {"name="};
+        }
+
+        SECTION("cd example:twoKeyList[name=\"AHOJ\"][number=123")
+        {
+            input = "cd example:twoKeyList[name=\"AHOJ\"][number=123";
+            expected = {"]/"};
+        }
+
+        SECTION("cd example:twoKeyList[name=\"AHOJ\"][number=123]")
+        {
+            input = "cd example:twoKeyList[name=\"AHOJ\"][number=123]";
+            expected = {"/"};
+        }
+    }
+
+    REQUIRE(parser.completeCommand(input, errorStream) == expected);
+}
diff --git a/tests/utils.cpp b/tests/utils.cpp
new file mode 100644
index 0000000..62e4c23
--- /dev/null
+++ b/tests/utils.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
+ * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
+ *
+ * Written by Václav Kubernát <kubervac@fit.cvut.cz>
+ *
+*/
+
+#include "trompeloeil_catch.h"
+#include "utils.hpp"
+
+TEST_CASE("utils")
+{
+    SECTION("filterAndErasePrefix")
+    {
+        std::set<std::string> set{"ahoj", "coze", "copak", "aha", "polivka"};
+
+        REQUIRE((filterAndErasePrefix(set, "a") == std::set<std::string>{"hoj", "ha"}));
+        REQUIRE((filterAndErasePrefix(set, "ah") == std::set<std::string>{"oj", "a"}));
+        REQUIRE((filterAndErasePrefix(set, "aho") == std::set<std::string>{"j"}));
+        REQUIRE((filterAndErasePrefix(set, "polivka") == std::set<std::string>{""}));
+        REQUIRE((filterAndErasePrefix(set, "polivka") == std::set<std::string>{""}));
+        REQUIRE((filterAndErasePrefix(set, "polivkax") == std::set<std::string>{}));
+        REQUIRE((filterAndErasePrefix(set, "co") == std::set<std::string>{"pak", "ze"}));
+    }
+
+}