Merge branch '3158-info-critical' into 'main'

gio-tool-info: Fix critical warning when --attributes are specified and add basic unit tests

Closes #3158

See merge request GNOME/glib!3684
This commit is contained in:
Philip Withnall 2023-11-07 14:37:11 +00:00
commit e87f8e9c5a
10 changed files with 221 additions and 72 deletions

View File

@ -177,7 +177,8 @@ show_info (GFile *file, GFileInfo *info)
g_free (flatten);
}
name = g_file_info_get_name (info);
name = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_NAME) ?
g_file_info_get_name (info) : NULL;
if (name)
{
escaped = escape_string (name);

View File

@ -219,35 +219,67 @@ handle_version (int argc, char *argv[], gboolean do_help)
return 0;
}
static void
usage (void)
typedef int (*HandleSubcommand) (int argc, char *argv[], gboolean do_help);
static const struct
{
g_printerr ("%s\n", _("Usage:"));
g_printerr (" gio %s %s\n", _("COMMAND"), _("[ARGS…]"));
g_printerr ("\n");
g_printerr ("%s\n", _("Commands:"));
g_printerr (" help %s\n", _("Print help"));
g_printerr (" version %s\n", _("Print version"));
g_printerr (" cat %s\n", _("Concatenate files to standard output"));
g_printerr (" copy %s\n", _("Copy one or more files"));
g_printerr (" info %s\n", _("Show information about locations"));
g_printerr (" launch %s\n", _("Launch an application from a desktop file"));
g_printerr (" list %s\n", _("List the contents of locations"));
g_printerr (" mime %s\n", _("Get or set the handler for a mimetype"));
g_printerr (" mkdir %s\n", _("Create directories"));
g_printerr (" monitor %s\n", _("Monitor files and directories for changes"));
g_printerr (" mount %s\n", _("Mount or unmount the locations"));
g_printerr (" move %s\n", _("Move one or more files"));
g_printerr (" open %s\n", _("Open files with the default application"));
g_printerr (" rename %s\n", _("Rename a file"));
g_printerr (" remove %s\n", _("Delete one or more files"));
g_printerr (" save %s\n", _("Read from standard input and save"));
g_printerr (" set %s\n", _("Set a file attribute"));
g_printerr (" trash %s\n", _("Move files or directories to the trash"));
g_printerr (" tree %s\n", _("Lists the contents of locations in a tree"));
g_printerr ("\n");
g_printerr (_("Use %s to get detailed help.\n"), "“gio help COMMAND”");
exit (1);
const char *name; /* as used on the command line */
HandleSubcommand handle_func; /* (nullable) for "help" only */
const char *description; /* translatable */
} gio_subcommands[] = {
{ "help", NULL, N_("Print help") },
{ "version", handle_version, N_("Print version") },
{ "cat", handle_cat, N_("Concatenate files to standard output") },
{ "copy", handle_copy, N_("Copy one or more files") },
{ "info", handle_info, N_("Show information about locations") },
{ "launch", handle_launch, N_("Launch an application from a desktop file") },
{ "list", handle_list, N_("List the contents of locations") },
{ "mime", handle_mime, N_("Get or set the handler for a mimetype") },
{ "mkdir", handle_mkdir, N_("Create directories") },
{ "monitor", handle_monitor, N_("Monitor files and directories for changes") },
{ "mount", handle_mount, N_("Mount or unmount the locations") },
{ "move", handle_move, N_("Move one or more files") },
{ "open", handle_open, N_("Open files with the default application") },
{ "rename", handle_rename, N_("Rename a file") },
{ "remove", handle_remove, N_("Delete one or more files") },
{ "save", handle_save, N_("Read from standard input and save") },
{ "set", handle_set, N_("Set a file attribute") },
{ "trash", handle_trash, N_("Move files or directories to the trash") },
{ "tree", handle_tree, N_("Lists the contents of locations in a tree") },
};
static void
usage (gboolean is_error)
{
GString *out = NULL;
size_t name_width = 0;
out = g_string_new ("");
g_string_append_printf (out, "%s\n", _("Usage:"));
g_string_append_printf (out, " gio %s %s\n", _("COMMAND"), _("[ARGS…]"));
g_string_append_c (out, '\n');
g_string_append_printf (out, "%s\n", _("Commands:"));
/* Work out the maximum name length for column alignment. */
for (size_t i = 0; i < G_N_ELEMENTS (gio_subcommands); i++)
name_width = MAX (name_width, strlen (gio_subcommands[i].name));
for (size_t i = 0; i < G_N_ELEMENTS (gio_subcommands); i++)
{
g_string_append_printf (out, " %-*s %s\n",
(int) name_width, gio_subcommands[i].name,
_(gio_subcommands[i].description));
}
g_string_append_c (out, '\n');
g_string_append_printf (out, _("Use %s to get detailed help.\n"), "“gio help COMMAND”");
if (is_error)
g_printerr ("%s", out->str);
else
g_print ("%s", out->str);
g_string_free (out, TRUE);
}
int
@ -277,7 +309,7 @@ main (int argc, char **argv)
if (argc < 2)
{
usage ();
usage (TRUE);
return 1;
}
@ -290,7 +322,7 @@ main (int argc, char **argv)
{
if (argc == 1)
{
usage ();
usage (FALSE);
return 0;
}
else
@ -301,50 +333,24 @@ main (int argc, char **argv)
}
else if (g_str_equal (command, "--help"))
{
usage ();
usage (FALSE);
return 0;
}
else if (g_str_equal (command, "--version"))
command = "version";
if (g_str_equal (command, "version"))
return handle_version (argc, argv, do_help);
else if (g_str_equal (command, "cat"))
return handle_cat (argc, argv, do_help);
else if (g_str_equal (command, "copy"))
return handle_copy (argc, argv, do_help);
else if (g_str_equal (command, "info"))
return handle_info (argc, argv, do_help);
else if (g_str_equal (command, "launch"))
return handle_launch (argc, argv, do_help);
else if (g_str_equal (command, "list"))
return handle_list (argc, argv, do_help);
else if (g_str_equal (command, "mime"))
return handle_mime (argc, argv, do_help);
else if (g_str_equal (command, "mkdir"))
return handle_mkdir (argc, argv, do_help);
else if (g_str_equal (command, "monitor"))
return handle_monitor (argc, argv, do_help);
else if (g_str_equal (command, "mount"))
return handle_mount (argc, argv, do_help);
else if (g_str_equal (command, "move"))
return handle_move (argc, argv, do_help);
else if (g_str_equal (command, "open"))
return handle_open (argc, argv, do_help);
else if (g_str_equal (command, "rename"))
return handle_rename (argc, argv, do_help);
else if (g_str_equal (command, "remove"))
return handle_remove (argc, argv, do_help);
else if (g_str_equal (command, "save"))
return handle_save (argc, argv, do_help);
else if (g_str_equal (command, "set"))
return handle_set (argc, argv, do_help);
else if (g_str_equal (command, "trash"))
return handle_trash (argc, argv, do_help);
else if (g_str_equal (command, "tree"))
return handle_tree (argc, argv, do_help);
else
usage ();
/* Work out which subcommand it is. */
for (size_t i = 0; i < G_N_ELEMENTS (gio_subcommands); i++)
{
if (g_str_equal (command, gio_subcommands[i].name))
{
g_assert (gio_subcommands[i].handle_func != NULL);
return gio_subcommands[i].handle_func (argc, argv, do_help);
}
}
/* Unknown subcommand. */
usage (TRUE);
return 1;
}

View File

@ -985,7 +985,7 @@ gio_tool_sources = [
'gio-tool-tree.c',
]
executable('gio', gio_tool_sources,
gio_tool = executable('gio', gio_tool_sources,
install : true,
install_tag : 'bin',
c_args : gio_c_args,

View File

@ -116,6 +116,7 @@ class TestCodegen(unittest.TestCase):
env = os.environ.copy()
env["LC_ALL"] = "C.UTF-8"
env["G_DEBUG"] = "fatal-warnings"
print("Environment:", env)
# We want to ensure consistent line endings...

132
gio/tests/gio-tool.py Normal file
View File

@ -0,0 +1,132 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Copyright © 2018, 2019 Endless Mobile, Inc.
# Copyright © 2023 Philip Withnall
#
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA
"""Integration tests for the gio utility."""
import collections
import os
import shutil
import subprocess
import tempfile
import unittest
import taptestrunner
Result = collections.namedtuple("Result", ("info", "out", "err"))
class TestGioTool(unittest.TestCase):
"""Integration test for running the gio tool.
This can be run when installed or uninstalled. When uninstalled, it
requires G_TEST_BUILDDIR and G_TEST_SRCDIR to be set.
The idea with this test harness is to test the gio utility, its
handling of command line arguments, its exit statuses, and its actual
effects on the file system.
"""
# Track the cwd, we want to back out to that to clean up our tempdir
cwd = ""
def setUp(self):
self.timeout_seconds = 6 # seconds per test
self.tmpdir = tempfile.TemporaryDirectory()
self.cwd = os.getcwd()
os.chdir(self.tmpdir.name)
print("tmpdir:", self.tmpdir.name)
ext = ""
if os.name == "nt":
ext = ".exe"
if "G_TEST_BUILDDIR" in os.environ:
self.__gio = os.path.join(
os.environ["G_TEST_BUILDDIR"],
"..",
"gio" + ext,
)
else:
self.__gio = shutil.which("gio" + ext)
print("gio:", self.__gio)
def tearDown(self):
os.chdir(self.cwd)
self.tmpdir.cleanup()
def runGio(self, *args):
argv = [self.__gio]
argv.extend(args)
print("Running:", argv)
env = os.environ.copy()
env["LC_ALL"] = "C.UTF-8"
env["G_DEBUG"] = "fatal-warnings"
print("Environment:", env)
# We want to ensure consistent line endings...
info = subprocess.run(
argv,
timeout=self.timeout_seconds,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env,
universal_newlines=True,
)
info.check_returncode()
out = info.stdout.strip()
err = info.stderr.strip()
result = Result(info, out, err)
print("Output:", result.out)
return result
def test_help(self):
"""Test the --help argument and help subcommand."""
result = self.runGio("--help")
result2 = self.runGio("help")
self.assertEqual(result.out, result2.out)
self.assertEqual(result.err, result2.err)
self.assertIn("Usage:\n gio COMMAND", result.out)
self.assertIn("List the contents of locations", result.out)
def test_no_args(self):
"""Test running with no arguments at all."""
with self.assertRaises(subprocess.CalledProcessError):
self.runGio()
def test_info_non_default_attributes(self):
"""Test running `gio info --attributes` with a non-default list."""
with tempfile.NamedTemporaryFile(dir=self.tmpdir.name) as tmpfile:
result = self.runGio(
"info", "--attributes=standard::content-type", tmpfile.name
)
self.assertIn("standard::content-type: application/x-zerosize", result.out)
if __name__ == "__main__":
unittest.main(testRunner=taptestrunner.TAPTestRunner())

View File

@ -181,6 +181,10 @@ python_tests = {
'suite': ['gdbus-codegen', 'slow'],
'timeout': 90,
},
'gio-tool.py' : {
'depends' : gio_tool,
'can_fail' : host_system == 'windows',
},
}
test_env = environment()
@ -1074,6 +1078,7 @@ endforeach
foreach test_name, extra_args : python_tests
depends = [extra_args.get('depends', [])]
suite = ['gio', 'no-valgrind'] + extra_args.get('suite', [])
timeout = extra_args.get('timeout', test_timeout)
if extra_args.get('can_fail', false)
suite += 'failing'
@ -1090,7 +1095,7 @@ foreach test_name, extra_args : python_tests
depends: depends,
args: ['-B', files(test_name)],
env: test_env,
timeout: extra_args.get('timeout'),
timeout: timeout,
suite: suite,
)

View File

@ -63,6 +63,7 @@ class TestMessagesLowMemory(unittest.TestCase):
env = os.environ.copy()
env["LC_ALL"] = "C.UTF-8"
env["G_DEBUG"] = "fatal-warnings"
print("Environment:", env)
# We want to ensure consistent line endings...

View File

@ -88,6 +88,7 @@ class TestGenmarshal(unittest.TestCase):
env = os.environ.copy()
env["LC_ALL"] = "C.UTF-8"
env["G_DEBUG"] = "fatal-warnings"
print("Environment:", env)
# We want to ensure consistent line endings...

View File

@ -59,6 +59,7 @@ class TestGobjectQuery(unittest.TestCase):
env = os.environ.copy()
env["LC_ALL"] = "C.UTF-8"
env["G_DEBUG"] = "fatal-warnings"
print("Environment:", env)
# We want to ensure consistent line endings...

View File

@ -100,6 +100,7 @@ class TestMkenums(unittest.TestCase):
env = os.environ.copy()
env["LC_ALL"] = "C.UTF-8"
env["G_DEBUG"] = "fatal-warnings"
print("Environment:", env)
# We want to ensure consistent line endings...