data tree FEATURE support for NETCONF messages
diff --git a/tests/utests/data/test_parser_xml.c b/tests/utests/data/test_parser_xml.c
index b2e2805..35b0e09 100644
--- a/tests/utests/data/test_parser_xml.c
+++ b/tests/utests/data/test_parser_xml.c
@@ -321,7 +321,7 @@
             "  </config>\n"
             "</edit-config>\n";
     assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
-    assert_int_equal(LY_SUCCESS, lyd_parse_rpc(UTEST_LYCTX, in, LYD_XML, &tree, &op));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_YANG_RPC, &tree, &op));
     ly_in_free(in, 0);
 
     assert_non_null(op);
@@ -387,7 +387,7 @@
             "  </act>\n"
             "</c>\n";
     assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
-    assert_int_equal(LY_SUCCESS, lyd_parse_rpc(UTEST_LYCTX, in, LYD_XML, &tree, &op));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_YANG_RPC, &tree, &op));
     ly_in_free(in, 0);
 
     assert_non_null(op);
@@ -421,7 +421,7 @@
             "  </n1>\n"
             "</c>\n";
     assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
-    assert_int_equal(LY_SUCCESS, lyd_parse_notif(UTEST_LYCTX, in, LYD_XML, &tree, &ntf));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_YANG_NOTIF, &tree, &ntf));
     ly_in_free(in, 0);
 
     assert_non_null(ntf);
@@ -435,7 +435,7 @@
     /* top-level notif without envelope */
     data = "<n2 xmlns=\"urn:tests:a\"/>\n";
     assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
-    assert_int_equal(LY_SUCCESS, lyd_parse_notif(UTEST_LYCTX, in, LYD_XML, &tree, &ntf));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_YANG_NOTIF, &tree, &ntf));
     ly_in_free(in, 0);
 
     assert_non_null(ntf);
@@ -465,7 +465,7 @@
             "  </act>\n"
             "</c>\n";
     assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
-    assert_int_equal(LY_SUCCESS, lyd_parse_reply(UTEST_LYCTX, in, LYD_XML, &tree, &op));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_YANG_REPLY, &tree, &op));
     ly_in_free(in, 0);
 
     assert_non_null(op);
@@ -486,6 +486,260 @@
     /* TODO */
 }
 
+static void
+test_netconf_rpc(void **state)
+{
+    const char *data;
+    struct ly_in *in;
+    struct lyd_node *tree, *op;
+    const struct lyd_node *node;
+    const char *dsc = "The <edit-config> operation loads all or part of a specified\n"
+            "configuration to the specified target configuration.";
+    const char *ref = "RFC 6241, Section 7.2";
+    const char *feats[] = {"writable-running", NULL};
+
+    assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf", "2011-06-01", feats)));
+
+    data = "<rpc message-id=\"25\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+            "<edit-config>\n"
+            "  <target>\n"
+            "    <running/>\n"
+            "  </target>\n"
+            "  <config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+            "    <l1 xmlns=\"urn:tests:a\" nc:operation=\"replace\">\n"
+            "      <a>val_a</a>\n"
+            "      <b>val_b</b>\n"
+            "      <c>val_c</c>\n"
+            "    </l1>\n"
+            "    <cp xmlns=\"urn:tests:a\">\n"
+            "      <z nc:operation=\"delete\"/>\n"
+            "    </cp>\n"
+            "  </config>\n"
+            "</edit-config>\n"
+            "</rpc>\n";
+    assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_NETCONF_RPC, &tree, &op));
+    ly_in_free(in, 0);
+
+    assert_non_null(op);
+
+    node = tree;
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 1, 0, LY_PREF_XML, "rpc", 0, 0, 0, 0, "");
+
+    assert_non_null(tree);
+
+    node = op;
+    CHECK_LYSC_ACTION((struct lysc_node_action *)node->schema, dsc, 0, LYS_STATUS_CURR,
+            1, 0, 0, 1, "edit-config", LYS_RPC,
+            0, 0, 0, 0, 0, ref, 0);
+    node = lyd_child(node)->next;
+    dsc = "Inline Config content.";
+    CHECK_LYSC_NODE(node->schema, dsc, 0, LYS_STATUS_CURR | LYS_IS_INPUT, 1, "config", 0, LYS_ANYXML, 1, 0, NULL, 0);
+
+    node = ((struct lyd_node_any *)node)->value.tree;
+    CHECK_LYSC_NODE(node->schema, NULL, 0, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_PRESENCE | LYS_SET_PRESENCE, 1, "cp",
+            1, LYS_CONTAINER, 0, 0, NULL, 0);
+
+    node = lyd_child(node);
+    /* z has no value */
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0, LY_PREF_XML, "z", 0, 0, NULL,  0,  "");
+    node = node->parent->next;
+    /* l1 key c has invalid value so it is at the end */
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)node, 0x1, 0x1, LY_PREF_XML, "l1", 0, 0, NULL,  0,  "");
+
+    CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS,
+            "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"25\"/>\n");
+    CHECK_LYD_STRING(op, LYD_PRINT_WITHSIBLINGS,
+            "<edit-config xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+            "  <target>\n"
+            "    <running/>\n"
+            "  </target>\n"
+            "  <config>\n"
+            "    <cp xmlns=\"urn:tests:a\">\n"
+            "      <z xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"delete\"/>\n"
+            "    </cp>\n"
+            "    <l1 xmlns=\"urn:tests:a\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" nc:operation=\"replace\">\n"
+            "      <a>val_a</a>\n"
+            "      <b>val_b</b>\n"
+            "      <c>val_c</c>\n"
+            "    </l1>\n"
+            "  </config>\n"
+            "</edit-config>\n");
+
+    lyd_free_all(tree);
+    lyd_free_all(op);
+
+    /* wrong namespace, element name, whatever... */
+    /* TODO */
+}
+
+static void
+test_netconf_action(void **state)
+{
+    const char *data;
+    struct ly_in *in;
+    struct lyd_node *tree, *op;
+
+    data = "<rpc message-id=\"25\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+            "<action xmlns=\"urn:ietf:params:xml:ns:yang:1\">"
+            "<c xmlns=\"urn:tests:a\">\n"
+            "  <act>\n"
+            "    <al>value</al>\n"
+            "  </act>\n"
+            "</c>\n"
+            "</action>\n"
+            "</rpc>\n";
+    assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_NETCONF_RPC, &tree, &op));
+    ly_in_free(in, 0);
+
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 1, LY_PREF_XML, "rpc", 0, 0, 0, 0, "");
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 0, LY_PREF_XML, "action", 0, 0, 0, 0, "");
+
+    assert_non_null(op);
+    CHECK_LYSC_ACTION((struct lysc_node_action *)op->schema, NULL, 0, LYS_STATUS_CURR,
+            1, 0, 0, 1, "act", LYS_ACTION,
+            1, 0, 0, 1, 0, NULL, 0);
+
+    CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS,
+            "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"25\">\n"
+            "  <action xmlns=\"urn:ietf:params:xml:ns:yang:1\"/>\n"
+            "</rpc>\n");
+    CHECK_LYD_STRING(op, LYD_PRINT_WITHSIBLINGS,
+            "<act xmlns=\"urn:tests:a\">\n"
+            "  <al>value</al>\n"
+            "</act>\n");
+
+    lyd_free_all(tree);
+    lyd_free_all(op);
+
+    /* wrong namespace, element name, whatever... */
+    /* TODO */
+}
+
+static void
+test_netconf_reply_or_notification(void **state)
+{
+    const char *data;
+    struct ly_in *in;
+    struct lyd_node *action, *tree, *op, *op2;
+
+    /* parse the action */
+    data = "<c xmlns=\"urn:tests:a\">\n"
+            "  <act>\n"
+            "    <al>value</al>\n"
+            "  </act>\n"
+            "</c>\n";
+    assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, NULL, in, LYD_XML, LYD_TYPE_YANG_RPC, &action, &op));
+    ly_in_free(in, 0);
+
+    /* parse notification first */
+    data = "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">\n"
+            "<eventTime>2010-12-06T08:00:01Z</eventTime>\n"
+            "<c xmlns=\"urn:tests:a\">\n"
+            "  <n1>\n"
+            "    <nl>value</nl>\n"
+            "  </n1>\n"
+            "</c>\n"
+            "</notification>\n";
+    assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_XML, LYD_TYPE_NETCONF_REPLY_OR_NOTIF, &tree, &op2));
+    ly_in_free(in, 0);
+
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 1, LY_PREF_XML, "notification", 0, 0, 0, 0, "");
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 0, LY_PREF_XML, "eventTime", 0, 0, 0, 0,
+            "2010-12-06T08:00:01Z");
+
+    assert_non_null(op2);
+    CHECK_LYSC_NOTIF((struct lysc_node_notif *)op2->schema, 1, NULL, 0, 0x4, 1, 0, "n1", 1, 0, NULL, 0);
+
+    CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS,
+            "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">\n"
+            "  <eventTime>2010-12-06T08:00:01Z</eventTime>\n"
+            "</notification>\n");
+    CHECK_LYD_STRING(op2, LYD_PRINT_WITHSIBLINGS,
+            "<n1 xmlns=\"urn:tests:a\">\n"
+            "  <nl>value</nl>\n"
+            "</n1>\n");
+
+    lyd_free_all(tree);
+    lyd_free_all(op2);
+
+    /* parse a data reply */
+    data = "<rpc-reply message-id=\"55\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+            "  <al xmlns=\"urn:tests:a\">25</al>\n"
+            "</rpc-reply>\n";
+    assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_XML, LYD_TYPE_NETCONF_REPLY_OR_NOTIF, &tree, &op2));
+    ly_in_free(in, 0);
+
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 0, LY_PREF_XML, "rpc-reply", 0, 0, 0, 0, "");
+
+    assert_non_null(op2);
+    CHECK_LYSC_ACTION((struct lysc_node_action *)op2->schema, NULL, 0, LYS_STATUS_CURR,
+            1, 0, 0, 1, "act", LYS_ACTION,
+            1, 0, 0, 1, 0, NULL, 0);
+
+    CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS,
+            "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"55\"/>\n");
+    CHECK_LYD_STRING(op2, LYD_PRINT_WITHSIBLINGS,
+            "<act xmlns=\"urn:tests:a\">\n"
+            "  <al>25</al>\n"
+            "  <al>value</al>\n"
+            "</act>\n");
+
+    lyd_free_all(tree);
+    /* it was connected to the action, do not free */
+
+    /* parse an ok reply */
+    data = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"55\">\n"
+            "  <ok/>\n"
+            "</rpc-reply>\n";
+    assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_XML, LYD_TYPE_NETCONF_REPLY_OR_NOTIF, &tree, &op2));
+    ly_in_free(in, 0);
+
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 1, LY_PREF_XML, "rpc-reply", 0, 0, 0, 0, "");
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 0, LY_PREF_XML, "ok", 0, 0, 0, 0, "");
+
+    assert_null(op2);
+
+    CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+
+    lyd_free_all(tree);
+
+    /* parse an error reply */
+    data = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"55\">\n"
+            "  <rpc-error>\n"
+            "    <error-type>rpc</error-type>\n"
+            "    <error-tag>missing-attribute</error-tag>\n"
+            "    <error-severity>error</error-severity>\n"
+            "    <error-info>\n"
+            "      <bad-attribute>message-id</bad-attribute>\n"
+            "      <bad-element>rpc</bad-element>\n"
+            "    </error-info>\n"
+            "  </rpc-error>\n"
+            "</rpc-reply>\n";
+    assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
+    assert_int_equal(LY_SUCCESS, lyd_parse_op(UTEST_LYCTX, op, in, LYD_XML, LYD_TYPE_NETCONF_REPLY_OR_NOTIF, &tree, &op2));
+    ly_in_free(in, 0);
+
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 1, LY_PREF_XML, "rpc-reply", 0, 0, 0, 0, "");
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 1, LY_PREF_XML, "rpc-error", 0, 0, 0, 0, "");
+
+    assert_null(op2);
+
+    CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
+
+    lyd_free_all(tree);
+
+    lyd_free_all(action);
+
+    /* wrong namespace, element name, whatever... */
+    /* TODO */
+}
+
 int
 main(void)
 {
@@ -499,6 +753,9 @@
         UTEST(test_action, setup),
         UTEST(test_notification, setup),
         UTEST(test_reply, setup),
+        UTEST(test_netconf_rpc, setup),
+        UTEST(test_netconf_action, setup),
+        UTEST(test_netconf_reply_or_notification, setup),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);