+test_begin_subtest "notmuch_message_remove_all_properties"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+EXPECT0(notmuch_message_remove_all_properties (message, NULL));
+print_properties (message, "", FALSE);
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "testing string map binary search (via message properties)"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+{
+ char *keys[] = {"a", "b", "c", "d", "e", NULL};
+ for (int i=0; keys[i]; i++)
+ EXPECT0(notmuch_message_add_property (message, keys[i], keys[i]));
+
+ for (int i=0; keys[i]; i++) {
+ EXPECT0(notmuch_message_get_property (message, keys[i], &val));
+ printf("%s = %s\n", keys[i], val);
+ }
+
+ for (int i=0; keys[i]; i++) {
+ EXPECT0(notmuch_message_remove_property (message, keys[i], keys[i]));
+ EXPECT0(notmuch_message_get_property (message, keys[i], &val));
+ printf("%s = %s\n", keys[i], val == NULL ? "NULL" : val);
+ }
+}
+EOF
+cat <<EOF > EXPECTED
+== stdout ==
+a = a
+b = b
+c = c
+d = d
+e = e
+a = NULL
+b = NULL
+c = NULL
+d = NULL
+e = NULL
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "notmuch_message_get_properties: empty list"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+{
+ notmuch_message_properties_t *list;
+ list = notmuch_message_get_properties (message, "nonexistent", TRUE);
+ printf("valid = %d\n", notmuch_message_properties_valid (list));
+ notmuch_message_properties_destroy (list);
+}
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+valid = 0
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "notmuch_message_properties: one value"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+print_properties (message, "testkey1", TRUE);
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+testvalue1
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "notmuch_message_properties: multiple values"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+EXPECT0(notmuch_message_add_property (message, "testkey1", "bob"));
+EXPECT0(notmuch_message_add_property (message, "testkey1", "testvalue2"));
+EXPECT0(notmuch_message_add_property (message, "testkey1", "alice"));
+print_properties (message, "testkey1", TRUE);
+EOF
+cat <<'EOF' >EXPECTED
+== stdout ==
+alice
+bob
+testvalue1
+testvalue2
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "notmuch_message_properties: prefix"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+EXPECT0(notmuch_message_add_property (message, "testkey3", "bob3"));
+EXPECT0(notmuch_message_add_property (message, "testkey3", "testvalue3"));
+EXPECT0(notmuch_message_add_property (message, "testkey3", "alice3"));
+print_properties (message, "testkey", FALSE);
+EOF
+# expected: 4 values for testkey1, 3 values for testkey3
+# they are not guaranteed to be sorted, so sort them, leaving the first
+# line '== stdout ==' and the end ('== stderr ==' and whatever error
+# may have been printed) alone
+mv OUTPUT unsorted_OUTPUT
+awk ' NR == 1 { print; next } \
+ NR < 6 { print | "sort"; next } \
+ NR == 6 { close("sort") } \
+ NR < 9 { print | "sort"; next } \
+ NR == 9 { close("sort") } \
+ { print }' unsorted_OUTPUT > OUTPUT
+rm unsorted_OUTPUT
+cat <<'EOF' >EXPECTED
+== stdout ==
+alice
+bob
+testvalue1
+testvalue2
+alice3
+bob3
+testvalue3
+== stderr ==
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
+test_begin_subtest "notmuch_message_properties: modify during iteration"
+cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
+{
+ const char *keys[1000] = {NULL};
+ const char *vals[1000] = {NULL};
+ notmuch_message_properties_t *properties;
+ int i;
+
+ for (properties = notmuch_message_get_properties (message, "", FALSE), i=0;
+ notmuch_message_properties_valid (properties);
+ notmuch_message_properties_move_to_next (properties), i++)
+ {
+ const char *key, *value;