tests CHANGE add test for test_parse_instance_predicate()
diff --git a/src/common.c b/src/common.c
index f300958..76f3b84 100644
--- a/src/common.c
+++ b/src/common.c
@@ -452,9 +452,9 @@
         }
 
         /* positive-integer-value */
-        *id = &in[offset++];
+        *value = &in[offset++];
         for (; isdigit(in[offset]); offset++);
-        *id_len = &in[offset] - *id;
+        *value_len = &in[offset] - *value;
 
     } else if (in[offset] == '.') {
         /* leaf-list-predicate: "[" *WSP "." *WSP "=" *WSP quoted-string *WSP "]" */
@@ -462,7 +462,10 @@
         *id_len = 1;
         offset++;
         expr = 1;
-
+    } else if (in[offset] == '-') {
+        /* typically negative value */
+        *errmsg = "Invalid instance predicate format (negative position or invalid node-identifier).";
+        goto error;
     } else {
         /* key-predicate: "[" *WSP node-identifier *WSP "=" *WSP quoted-string *WSP "]" */
         in = &in[offset];
@@ -472,7 +475,7 @@
         }
         offset = in - *pred;
         in = *pred;
-        expr = 1;
+        expr = 2;
     }
 
     if (expr) {
@@ -480,7 +483,11 @@
         for (; isspace(in[offset]); offset++);
 
         if (in[offset] != '=') {
-            *errmsg = "Unexpected character instead of \'=\'.";
+            if (expr == 1) {
+                *errmsg = "Unexpected character instead of \'=\' in leaf-list-predicate.";
+            } else { /* 2 */
+                *errmsg = "Unexpected character instead of \'=\' in key-predicate.";
+            }
             goto error;
         }
         offset++;
@@ -494,17 +501,31 @@
         }
         *value = &in[offset];
         for (;offset < limit && in[offset] != quot; offset++);
-        *value_len = &in[offset] - *value;
+        if (in[offset] == quot) {
+            *value_len = &in[offset] - *value;
+            offset++;
+        } else {
+            *errmsg = "Value is not terminated quoted-string.";
+            goto error;
+        }
     }
 
     /* *WSP "]" */
     for(; isspace(in[offset]); offset++);
     if (in[offset] != ']') {
-        *errmsg = "Predicate is not terminated by \']\' character.";
+        if (expr == 0) {
+            *errmsg = "Predicate (pos) is not terminated by \']\' character.";
+        } else if (expr == 1) {
+            *errmsg = "Predicate (leaf-list-predicate) is not terminated by \']\' character.";
+        } else { /* 2 */
+            *errmsg = "Predicate (key-predicate) is not terminated by \']\' character.";
+        }
         goto error;
     }
+    offset++;
 
-    if (offset < limit) {
+    if (offset <= limit) {
+        *pred = &in[offset];
         return LY_SUCCESS;
     }
 
diff --git a/tests/src/test_common.c b/tests/src/test_common.c
index 771e050..2a1bbe9 100644
--- a/tests/src/test_common.c
+++ b/tests/src/test_common.c
@@ -245,7 +245,7 @@
 static void
 test_parse_nodeid(void **state)
 {
-    (void) state; /* unused */
+    *state = test_parse_nodeid;
     const char *str;
     const char *prefix, *name;
     size_t prefix_len, name_len;
@@ -271,6 +271,106 @@
     assert_int_equal(3, name_len);
     assert_int_equal(0, strncmp("_b2", name, name_len));
     assert_string_equal(" xxx", str);
+
+    *state = NULL;
+}
+
+static void
+test_parse_instance_predicate(void **state)
+{
+    *state = test_parse_instance_predicate;
+    const char *str, *errmsg;
+    const char *prefix, *id, *value;
+    size_t prefix_len, id_len, value_len;
+
+    str = "[ex:name='fred']";
+    assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(str, "");
+    assert_string_equal(prefix, "ex:name='fred']");
+    assert_int_equal(prefix_len, 2);
+    assert_string_equal(id, "name='fred']");
+    assert_int_equal(id_len, 4);
+    assert_string_equal(value, "fred']");
+    assert_int_equal(value_len, 4);
+
+    str = "[ex:ip = \"[192.0.2.1]\"][ex:port='80']";
+    assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(str, "[ex:port='80']");
+    assert_string_equal(prefix, "ex:ip = \"[192.0.2.1]\"][ex:port='80']");
+    assert_int_equal(prefix_len, 2);
+    assert_string_equal(id, "ip = \"[192.0.2.1]\"][ex:port='80']");
+    assert_int_equal(id_len, 2);
+    assert_string_equal(value, "[192.0.2.1]\"][ex:port='80']");
+    assert_int_equal(value_len, 11);
+
+    str = "[. = 'blowfish-cbc']";
+    assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(str, "");
+    assert_null(prefix);
+    assert_int_equal(prefix_len, 0);
+    assert_string_equal(id, ". = 'blowfish-cbc']");
+    assert_int_equal(id_len, 1);
+    assert_string_equal(value, "blowfish-cbc']");
+    assert_int_equal(value_len, 12);
+
+    str = "[ 3 ]";
+    assert_int_equal(LY_SUCCESS, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(str, "");
+    assert_null(prefix);
+    assert_int_equal(prefix_len, 0);
+    assert_null(id);
+    assert_int_equal(id_len, 0);
+    assert_string_equal(value, "3 ]");
+    assert_int_equal(value_len, 1);
+
+    /* invalid predicates */
+    /* position must be positive integer */
+    str = "[0]";
+    assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "The position predicate cannot be zero.");
+    str = "[-1]";
+    assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "Invalid instance predicate format (negative position or invalid node-identifier).");
+
+    /* invalid node-identifier */
+    str = "[$node='value']";
+    assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "Invalid node-identifier.");
+    str = "[.node='value']";
+    assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "Unexpected character instead of '=' in leaf-list-predicate.");
+    str = "[13node='value']";
+    assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "Predicate (pos) is not terminated by \']\' character.");
+
+    str = "[node]";
+    assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "Unexpected character instead of '=' in key-predicate.");
+
+    str = "[node=  value]";
+    assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "String value is not quoted.");
+
+    str = "[node='value\"]";
+    assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "Value is not terminated quoted-string.");
+
+    str = "[node='value  ]";
+    assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "Value is not terminated quoted-string.");
+
+    str = "[node=\"value\"[3]";
+    assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "Predicate (key-predicate) is not terminated by \']\' character.");
+    str = "[.=\"value\"[3]";
+    assert_int_equal(LY_EVALID, ly_parse_instance_predicate(&str, strlen(str), &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "Predicate (leaf-list-predicate) is not terminated by \']\' character.");
+
+    str = "[node='value']";
+    assert_int_equal(LY_EINVAL, ly_parse_instance_predicate(&str, strlen(str) - 1, &prefix, &prefix_len, &id, &id_len, &value, &value_len, &errmsg));
+    assert_string_equal(errmsg, "Predicate is incomplete.");
+
+    *state = NULL;
 }
 
 int main(void)
@@ -283,6 +383,7 @@
         cmocka_unit_test_setup_teardown(test_parse_int, logger_setup, logger_teardown),
         cmocka_unit_test_setup_teardown(test_parse_uint, logger_setup, logger_teardown),
         cmocka_unit_test_setup_teardown(test_parse_nodeid, logger_setup, logger_teardown),
+        cmocka_unit_test_setup_teardown(test_parse_instance_predicate, logger_setup, logger_teardown),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);