tests: Add tests for handling of fstab and mtab files

While GLib doesn’t parse these files, it does provide API to access the
fields from them, and does implement some logic based on options fields
in them. It would be nice to be able to test that, and get coverage of
the methods for `GUnixMountPoint` and `GUnixMountEntry`.
This commit is contained in:
Philip Withnall 2024-07-20 16:59:19 +02:00
parent 5040cf1943
commit 04ee011171
No known key found for this signature in database
GPG Key ID: DCDF5885B1F3ED73

View File

@ -18,6 +18,8 @@
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib.h>
#ifndef G_OS_UNIX
@ -26,6 +28,12 @@
#include <errno.h>
#include <locale.h>
#ifdef HAVE_XLOCALE_H
/* Needed on macOS and FreeBSD for uselocale() */
#include <xlocale.h>
#endif
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <gio/gunixmounts.h>
@ -50,6 +58,279 @@ test_is_system_device_path (void)
g_assert_false (g_unix_is_system_device_path ("/"));
}
static void
assert_cmp_icon (GIcon *icon,
gboolean expected_icon)
{
if (expected_icon)
{
char *icon_str = NULL;
/* While it would be nice to compare the icon value, that would make these
* tests depend on the icon themes installed. So just compare nullness. */
g_assert_nonnull (icon);
icon_str = g_icon_to_string (icon);
g_test_message ("Icon: %s", icon_str);
g_free (icon_str);
}
else
{
g_assert_null (icon);
}
}
static void
test_get_mount_points (void)
{
GUnixMountPoint **points = NULL;
uint64_t time_read = 0;
size_t n_points = 0;
int fd = -1;
char *tmp_file = NULL;
gboolean res;
#ifdef HAVE_USELOCALE
locale_t original_locale;
locale_t new_locale;
locale_t result;
#endif
const char *fake_fstab = "# Some comment\n"
"/dev/mapper/fedora-root / ext4 defaults,x-systemd.device-timeout=0 1 1\n"
"UUID=1234-ABCD /boot ext4 defaults 1 2\n"
"UUID=ABCD-1234 /boot/efi vfat umask=0077,shortname=winnt,ro 0 2\n"
"/dev/mapper/fedora-home /home ext4 defaults,x-systemd.device-timeout=0 1 2\n"
"/dev/mapper/fedora-swap none swap defaults,x-systemd.device-timeout=0 0 0\n"
"/dev/mapper/unused none ext4 defaults\n";
const struct
{
const char *device_path;
const char *fs_type;
const char *options;
gboolean is_readonly;
gboolean is_user_mountable;
gboolean is_loopback;
gboolean guessed_icon;
gboolean guessed_symbolic_icon;
const char *guessed_name;
gboolean guessed_can_eject;
}
expected_points[] =
{
{
.device_path = "/dev/mapper/fedora-root",
.fs_type = "ext4",
.options = "defaults,x-systemd.device-timeout=0",
.is_readonly = FALSE,
.is_user_mountable = FALSE,
.is_loopback = FALSE,
.guessed_icon = TRUE,
.guessed_symbolic_icon = TRUE,
.guessed_name = "Filesystem root",
.guessed_can_eject = FALSE,
},
{
.device_path = "UUID=1234-ABCD",
.fs_type = "ext4",
.options = "defaults",
.is_readonly = FALSE,
.is_user_mountable = FALSE,
.is_loopback = FALSE,
.guessed_icon = TRUE,
.guessed_symbolic_icon = TRUE,
.guessed_name = "boot",
.guessed_can_eject = FALSE,
},
{
.device_path = "UUID=ABCD-1234",
.fs_type = "vfat",
.options = "umask=0077,shortname=winnt,ro",
.is_readonly = TRUE,
.is_user_mountable = FALSE,
.is_loopback = FALSE,
.guessed_icon = TRUE,
.guessed_symbolic_icon = TRUE,
.guessed_name = "efi",
.guessed_can_eject = FALSE,
},
{
.device_path = "/dev/mapper/fedora-home",
.fs_type = "ext4",
.options = "defaults,x-systemd.device-timeout=0",
.is_readonly = FALSE,
.is_user_mountable = FALSE,
.is_loopback = FALSE,
.guessed_icon = TRUE,
.guessed_symbolic_icon = TRUE,
.guessed_name = "home",
.guessed_can_eject = FALSE,
},
/* the swap partition is ignored */
/* as is the ignored unused partition */
};
g_test_summary ("Basic test of g_unix_mount_points_get_from_file()");
fd = g_file_open_tmp ("unix-mounts-XXXXXX", &tmp_file, NULL);
g_assert (fd != -1);
close (fd);
res = g_file_set_contents (tmp_file, fake_fstab, -1, NULL);
g_assert (res);
points = g_unix_mount_points_get_from_file (tmp_file, &time_read, &n_points);
if (points == NULL)
{
/* Some platforms may not support parsing a specific mount point file */
g_assert_cmpuint (time_read, ==, 0);
g_assert_cmpuint (n_points, ==, 0);
g_test_skip ("Parsing mount points from a file not supported on this platform");
return;
}
g_assert_nonnull (points);
/* Check the properties of the mount points. This needs to be done in a known
* locale, because the guessed mount point name is translatable. */
g_assert_cmpuint (n_points, ==, G_N_ELEMENTS (expected_points));
#ifdef HAVE_USELOCALE
original_locale = uselocale ((locale_t) 0);
g_assert_true (original_locale != (locale_t) 0);
new_locale = newlocale (LC_ALL_MASK, "C", (locale_t) 0);
g_assert_true (new_locale != (locale_t) 0);
result = uselocale (new_locale);
g_assert_true (result == original_locale);
#endif /* HAVE_USELOCALE */
for (size_t i = 0; i < n_points; i++)
{
GIcon *icon = NULL;
char *name = NULL;
g_assert_cmpstr (g_unix_mount_point_get_device_path (points[i]), ==, expected_points[i].device_path);
g_assert_cmpstr (g_unix_mount_point_get_fs_type (points[i]), ==, expected_points[i].fs_type);
g_assert_cmpstr (g_unix_mount_point_get_options (points[i]), ==, expected_points[i].options);
g_assert_true (g_unix_mount_point_is_readonly (points[i]) == expected_points[i].is_readonly);
g_assert_true (g_unix_mount_point_is_user_mountable (points[i]) == expected_points[i].is_user_mountable);
g_assert_true (g_unix_mount_point_is_loopback (points[i]) == expected_points[i].is_loopback);
icon = g_unix_mount_point_guess_icon (points[i]);
assert_cmp_icon (icon, expected_points[i].guessed_icon);
g_clear_object (&icon);
icon = g_unix_mount_point_guess_symbolic_icon (points[i]);
assert_cmp_icon (icon, expected_points[i].guessed_symbolic_icon);
g_clear_object (&icon);
name = g_unix_mount_point_guess_name (points[i]);
#ifdef HAVE_USELOCALE
g_assert_cmpstr (name, ==, expected_points[i].guessed_name);
#else
g_assert_nonnull (name);
#endif
g_free (name);
g_assert_true (g_unix_mount_point_guess_can_eject (points[i]) == expected_points[i].guessed_can_eject);
}
for (size_t i = 0; i < n_points; i++)
g_unix_mount_point_free (points[i]);
g_free (points);
g_free (tmp_file);
#ifdef HAVE_USELOCALE
result = uselocale (original_locale);
g_assert_true (result == new_locale);
freelocale (new_locale);
#endif
}
static void
test_get_mount_entries (void)
{
GUnixMountEntry **entries = NULL;
uint64_t time_read = 0;
size_t n_entries = 0;
int fd = -1;
char *tmp_file = NULL;
gboolean res;
const char *fake_mtab = "# Some comment\n"
"67 1 253:1 / / rw,relatime shared:1 - ext4 /dev/mapper/fedora-root rw,seclabel\n"
"35 67 0:6 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,seclabel,size=4096k,nr_inodes=1995515,mode=755,inode64\n"
"1537 1080 253:1 /usr/share/fonts /run/host/fonts ro,nosuid,nodev,relatime master:1 - ext4 /dev/mapper/fedora-root rw,seclabel\n";
const struct
{
const char *device_path;
const char *fs_type;
const char *mount_path;
const char *options;
const char *root_path;
}
expected_entries[] =
{
{
.device_path = "/dev/mapper/fedora-root",
.fs_type = "ext4",
.mount_path = "/",
.options = "rw,relatime,seclabel",
.root_path = "/",
},
{
.device_path = "devtmpfs",
.fs_type = "devtmpfs",
.mount_path = "/dev",
.options = "rw,nosuid,seclabel,size=4096k,nr_inodes=1995515,mode=755,inode64",
.root_path = "/",
},
{
.device_path = "/dev/mapper/fedora-root",
.fs_type = "ext4",
.mount_path = "/run/host/fonts",
.options = "ro,nosuid,nodev,relatime,seclabel",
.root_path = "/usr/share/fonts",
},
};
g_test_summary ("Basic test of g_unix_mounts_get_from_file()");
fd = g_file_open_tmp ("unix-mounts-XXXXXX", &tmp_file, NULL);
g_assert (fd != -1);
close (fd);
res = g_file_set_contents (tmp_file, fake_mtab, -1, NULL);
g_assert (res);
entries = g_unix_mounts_get_from_file (tmp_file, &time_read, &n_entries);
if (entries == NULL)
{
/* Some platforms may not support parsing a specific mount entry file */
g_assert_cmpuint (time_read, ==, 0);
g_assert_cmpuint (n_entries, ==, 0);
g_test_skip ("Parsing mount entries from a file not supported on this platform");
return;
}
g_assert_nonnull (entries);
/* Check the properties of the mount entries. */
g_assert_cmpuint (n_entries, ==, G_N_ELEMENTS (expected_entries));
for (size_t i = 0; i < n_entries; i++)
{
g_assert_cmpstr (g_unix_mount_get_device_path (entries[i]), ==, expected_entries[i].device_path);
g_assert_cmpstr (g_unix_mount_get_fs_type (entries[i]), ==, expected_entries[i].fs_type);
g_assert_cmpstr (g_unix_mount_get_mount_path (entries[i]), ==, expected_entries[i].mount_path);
g_assert_cmpstr (g_unix_mount_get_options (entries[i]), ==, expected_entries[i].options);
g_assert_cmpstr (g_unix_mount_get_root_path (entries[i]), ==, expected_entries[i].root_path);
}
for (size_t i = 0; i < n_entries; i++)
g_unix_mount_free (entries[i]);
g_free (entries);
g_free (tmp_file);
}
int
main (int argc,
char *argv[])
@ -60,6 +341,8 @@ main (int argc,
g_test_add_func ("/unix-mounts/is-system-fs-type", test_is_system_fs_type);
g_test_add_func ("/unix-mounts/is-system-device-path", test_is_system_device_path);
g_test_add_func ("/unix-mounts/get-mount-points", test_get_mount_points);
g_test_add_func ("/unix-mounts/get-mount-entries", test_get_mount_entries);
return g_test_run ();
}