[set] add test for inverted set operations.

This test checks all possible set configurations against each operation type.
diff --git a/test/api/test-set.c b/test/api/test-set.c
index 54a31c2..f6aba86 100644
--- a/test/api/test-set.c
+++ b/test/api/test-set.c
@@ -678,6 +678,8 @@
                    max_set_elements - 3436 - 38 - 13);
   g_assert_cmpint (hb_set_get_min (s), ==, 38);
   g_assert_cmpint (hb_set_get_max (s), ==, max_set_elements - 14);
+
+  hb_set_destroy (s);
 }
 
 static void
@@ -780,6 +782,8 @@
   g_assert (hb_set_next_range (s, &start, &end));
   g_assert_cmpint (start, ==, max_set_elements - 2);
   g_assert_cmpint (end, ==, max_set_elements - 2);
+
+  hb_set_destroy (s);
 }
 
 static void
@@ -886,6 +890,8 @@
   g_assert (hb_set_previous_range (s, &start, &end));
   g_assert_cmpint (start, ==, 1);
   g_assert_cmpint (end, ==, 1);
+
+  hb_set_destroy (s);
 }
 
 
@@ -941,6 +947,124 @@
   hb_set_invert (b);
   g_assert (hb_set_is_equal (a, b));
   g_assert (hb_set_is_equal (b, a));
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+}
+
+typedef enum {
+  UNION = 0,
+  INTERSECT,
+  SUBTRACT,
+  SYM_DIFF,
+  LAST,
+} set_operation;
+
+static hb_set_t* prepare_set(hb_bool_t has_x,
+                             hb_bool_t inverted,
+                             hb_bool_t has_page)
+{
+  static const hb_codepoint_t x = 13;
+  hb_set_t* s = hb_set_create ();
+  if (inverted) hb_set_invert (s);
+  if (has_page)
+  {
+    // Ensure a page exists for x.
+    inverted ? hb_set_del (s, x) : hb_set_add (s, x);
+  }
+  if (has_x)
+    hb_set_add (s, x);
+  else
+    hb_set_del (s, x);
+
+  return s;
+}
+
+static hb_bool_t
+check_set_operations(hb_bool_t a_has_x,
+                     hb_bool_t a_inverted,
+                     hb_bool_t a_has_page,
+                     hb_bool_t b_has_x,
+                     hb_bool_t b_inverted,
+                     hb_bool_t b_has_page,
+                     set_operation op)
+{
+  hb_codepoint_t x = 13;
+  hb_set_t* a = prepare_set (a_has_x, a_inverted, a_has_page);
+  hb_set_t* b = prepare_set (b_has_x, b_inverted, b_has_page);
+
+  char* op_name;
+  hb_bool_t has_expected;
+  hb_bool_t should_have_x;
+  switch (op) {
+  case UNION:
+  default:
+    op_name = "union";
+    should_have_x = (a_has_x || b_has_x);
+    hb_set_union (a, b);
+    has_expected = (hb_set_has (a, x) == should_have_x);
+    break;
+  case INTERSECT:
+    op_name = "intersect";
+    should_have_x = (a_has_x && b_has_x);
+    hb_set_intersect (a, b);
+    has_expected = (hb_set_has (a, x) == should_have_x);
+    break;
+  case SUBTRACT:
+    op_name = "subtract";
+    should_have_x = (a_has_x && !b_has_x);
+    hb_set_subtract (a, b);
+    has_expected = (hb_set_has (a, x) == should_have_x);
+    break;
+  case SYM_DIFF:
+    op_name = "sym_diff";
+    should_have_x = (a_has_x ^ b_has_x);
+    hb_set_symmetric_difference (a, b);
+    has_expected = (hb_set_has (a, x) == should_have_x);
+    break;
+  }
+
+  printf ("%s%s%s %-9s %s%s%s == %s  [%s]\n",
+          a_inverted ? "i" : " ",
+          a_has_page ? "p" : " ",
+          a_has_x ? "{13}" : "{}  ",
+          op_name,
+          b_inverted ? "i" : " ",
+          b_has_page ? "p" : " ",
+          b_has_x ? "{13}" : "{}  ",
+          should_have_x ? "{13}" : "{}  ",
+          has_expected ? "succeeded" : "failed");
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+
+  return has_expected;
+}
+
+static void
+test_set_inverted_operations (void)
+{
+  hb_bool_t all_succeeded = 1;
+  for (hb_bool_t a_has_x = 0; a_has_x <= 1; a_has_x++) {
+    for (hb_bool_t a_inverted = 0; a_inverted <= 1; a_inverted++) {
+      for (hb_bool_t b_has_x = 0; b_has_x <= 1; b_has_x++) {
+        for (hb_bool_t b_inverted = 0; b_inverted <= 1; b_inverted++) {
+          for (hb_bool_t a_has_page = 0; a_has_page <= !(a_has_x ^ a_inverted); a_has_page++) {
+            for (hb_bool_t b_has_page = 0; b_has_page <= !(b_has_x ^ b_inverted); b_has_page++) {
+              for (set_operation op = UNION; op < LAST; op++) {
+                all_succeeded = check_set_operations (a_has_x, a_inverted, a_has_page,
+                                                      b_has_x, b_inverted, b_has_page,
+                                                      op)
+                                && all_succeeded;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  g_assert (all_succeeded);
 }
 
 int
@@ -964,6 +1088,7 @@
   hb_test_add (test_set_inverted_iteration_next);
   hb_test_add (test_set_inverted_iteration_prev);
   hb_test_add (test_set_inverted_equality);
+  hb_test_add (test_set_inverted_operations);
 
   return hb_test_run();
 }