keyfile-utils: Add API to parse tristate strings
authorColin Walters <walters@verbum.org>
Wed, 10 Jul 2024 21:21:57 +0000 (17:21 -0400)
committerColin Walters <walters@verbum.org>
Wed, 10 Jul 2024 21:52:28 +0000 (17:52 -0400)
Prep for using this in multiple places. Add unit tests.

src/libotutil/ot-keyfile-utils.c
src/libotutil/ot-keyfile-utils.h
tests/test-keyfile-utils.c

index d6cd102ca054699196c42b7f0ad655d65f8c0048..12f4ac0b6d0a9e1642e2cf6b57f6e184caac3a1f 100644 (file)
@@ -60,6 +60,51 @@ ot_keyfile_get_boolean_with_default (GKeyFile *keyfile, const char *section, con
   return TRUE;
 }
 
+// Keep this in sync with
+// https://gitlab.gnome.org/GNOME/glib/-/blob/4a73fbda8be6f80f14b05983eb575c1eb1329c2c/glib/gkeyfile.c?page=5#L4585
+// Except for some reason at some point we added "yes" or "no" as possible values too...
+gboolean
+_ostree_parse_boolean (const char *s, gboolean *out_val, GError **error)
+{
+  g_assert (s);
+  g_assert (out_val);
+
+  if (g_str_equal (s, "yes") || g_str_equal (s, "true") || g_str_equal (s, "1"))
+    {
+      *out_val = TRUE;
+      return TRUE;
+    }
+  else if (g_str_equal (s, "no") || g_str_equal (s, "false") || g_str_equal (s, "0"))
+    {
+      *out_val = FALSE;
+      return TRUE;
+    }
+  return glnx_throw (error, "Invalid boolean: %s", s);
+}
+
+gboolean
+_ostree_parse_tristate (const char *s, OtTristate *out_tri, GError **error)
+{
+  if (strcmp (s, "maybe") == 0)
+    {
+      *out_tri = OT_TRISTATE_MAYBE;
+      return TRUE;
+    }
+
+  gboolean bool_value = FALSE;
+  // Discard the error here, just check if it's valid
+  if (_ostree_parse_boolean (s, &bool_value, NULL))
+    {
+      if (bool_value)
+        *out_tri = OT_TRISTATE_YES;
+      else
+        *out_tri = OT_TRISTATE_NO;
+      return TRUE;
+    }
+  // If it's invalid, be clear a tristate was expected.
+  return glnx_throw (error, "Invalid tri-state value: %s", s);
+}
+
 gboolean
 ot_keyfile_get_tristate_with_default (GKeyFile *keyfile, const char *section, const char *value,
                                       OtTristate default_value, OtTristate *out_tri, GError **error)
@@ -85,23 +130,7 @@ ot_keyfile_get_tristate_with_default (GKeyFile *keyfile, const char *section, co
     }
 
   ret_value = g_strstrip (ret_value);
-
-  if (strcmp (ret_value, "yes") == 0 || strcmp (ret_value, "true") == 0
-      || strcmp (ret_value, "1") == 0)
-    *out_tri = OT_TRISTATE_YES;
-  else if (strcmp (ret_value, "no") == 0 || strcmp (ret_value, "false") == 0
-           || strcmp (ret_value, "0") == 0)
-    *out_tri = OT_TRISTATE_NO;
-  else if (strcmp (ret_value, "maybe") == 0)
-    *out_tri = OT_TRISTATE_MAYBE;
-  else
-    {
-      g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
-                   "Invalid tri-state value: %s", ret_value);
-      return FALSE;
-    }
-
-  return TRUE;
+  return _ostree_parse_tristate (ret_value, out_tri, error);
 }
 
 gboolean
index eb97c8d7c615b261c8766347094af2002d8cbfa9..1ed6747328118acfb024cc8c33a01b4444bf937a 100644 (file)
@@ -32,6 +32,9 @@ typedef enum
 
 G_BEGIN_DECLS
 
+gboolean _ostree_parse_boolean (const char *s, gboolean *out_val, GError **error);
+gboolean _ostree_parse_tristate (const char *s, OtTristate *out_tri, GError **error);
+
 gboolean ot_keyfile_get_boolean_with_default (GKeyFile *keyfile, const char *section,
                                               const char *value, gboolean default_value,
                                               gboolean *out_bool, GError **error);
index 198e71d2563b15e0d7fe4dc04e4097ba5c2160c0..748e029af0a2a858d5a97c900284255fde26eb45 100644 (file)
@@ -173,6 +173,42 @@ fill_keyfile (GKeyFile *file)
   g_key_file_set_value (file, "section", "value_bar", "bar");
 }
 
+static void
+test_parse_tristate (void)
+{
+  g_autoptr (GError) error = NULL;
+
+  OtTristate t = OT_TRISTATE_NO;
+  // Verify maybe
+  (void)_ostree_parse_tristate ("maybe", &t, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (t, ==, OT_TRISTATE_MAYBE);
+
+  // Alternate yes and no
+  (void)_ostree_parse_tristate ("yes", &t, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (t, ==, OT_TRISTATE_YES);
+  (void)_ostree_parse_tristate ("no", &t, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (t, ==, OT_TRISTATE_NO);
+  (void)_ostree_parse_tristate ("1", &t, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (t, ==, OT_TRISTATE_YES);
+  (void)_ostree_parse_tristate ("0", &t, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (t, ==, OT_TRISTATE_NO);
+  (void)_ostree_parse_tristate ("true", &t, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (t, ==, OT_TRISTATE_YES);
+  (void)_ostree_parse_tristate ("false", &t, &error);
+  g_assert_no_error (error);
+  g_assert_cmpint (t, ==, OT_TRISTATE_NO);
+
+  // And an error case
+  (void)_ostree_parse_tristate ("foobar", &t, &error);
+  g_assert (error != NULL);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -186,6 +222,7 @@ main (int argc, char **argv)
   g_test_add_func ("/keyfile-utils/get-value-with-default-group-optional",
                    test_get_value_with_default_group_optional);
   g_test_add_func ("/keyfile-utils/copy-group", test_copy_group);
+  g_test_add_func ("/keyfile-utils/parse-tristate", test_parse_tristate);
 
   ret = g_test_run ();