Fix create/delete/set command crash

These commands crashed when they were given an empty path. Right now,
PathParser is allowed to parse empty paths (an empty string or just a
slash). The parsers that check the last node of a path don't expect the
path to be empty. Right now, I chose this easy fix, but PathParser
probably shouldn't be allowed to parse empty paths in the future (and
empty path should be dealt with in a different way).

Issue: https://tree.taiga.io/project/jktjkt-netconf-cli/issue/171
Change-Id: If0a1b97319307f88e83a07914186b6cf8c61b1d2
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index 735700a..4c5bdaa 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -168,6 +168,12 @@
     {
         auto& parserContext = x3::get<parser_context_tag>(context);
         const auto& schema = parserContext.m_schema;
+        if (ast.m_nodes.empty()) {
+            parserContext.m_errorMsg = "This container is not a presence container.";
+            _pass(context) = false;
+            return;
+        }
+
         try {
             boost::optional<std::string> module;
             if (ast.m_nodes.back().m_prefix)
@@ -191,6 +197,12 @@
     void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
     {
         auto& parserContext = x3::get<parser_context_tag>(context);
+        if (ast.m_nodes.empty()) {
+            parserContext.m_errorMsg = "This is not a list instance.";
+            _pass(context) = false;
+            return;
+        }
+
         if (ast.m_nodes.back().m_suffix.type() != typeid(listElement_)) {
             parserContext.m_errorMsg = "This is not a list instance.";
             _pass(context) = false;
@@ -235,6 +247,12 @@
     void on_success(Iterator const&, Iterator const&, T&, Context const& context)
     {
         auto& parserContext = x3::get<parser_context_tag>(context);
+        if (parserContext.currentSchemaPath().m_nodes.empty()) {
+            parserContext.m_errorMsg = "This is not a path to leaf.";
+            _pass(context) = false;
+            return;
+        }
+
         try {
             auto lastNode = parserContext.currentSchemaPath().m_nodes.back();
             auto leaf = boost::get<leaf_>(lastNode.m_suffix);
diff --git a/tests/leaf_editing.cpp b/tests/leaf_editing.cpp
index 75433e0..d955ab0 100644
--- a/tests/leaf_editing.cpp
+++ b/tests/leaf_editing.cpp
@@ -601,6 +601,11 @@
             input = "set mod:dummy";
         }
 
+        SECTION("empty path")
+        {
+            input = "set ";
+        }
+
         REQUIRE_THROWS_AS(parser.parseCommand(input, errorStream), InvalidCommandException);
         REQUIRE(errorStream.str().find(expectedError) != std::string::npos);
     }
diff --git a/tests/presence_containers.cpp b/tests/presence_containers.cpp
index 7c6397d..f248597 100644
--- a/tests/presence_containers.cpp
+++ b/tests/presence_containers.cpp
@@ -107,6 +107,11 @@
             input = "list[quote='lol']";
         }
 
+        SECTION("no path")
+        {
+            input = " ";
+        }
+
         REQUIRE_THROWS_AS(parser.parseCommand("create " + input, errorStream), InvalidCommandException);
         REQUIRE_THROWS_AS(parser.parseCommand("delete " + input, errorStream), InvalidCommandException);
     }