/* Self tests for GDB's argument splitting and merging. Copyright (C) 2023-2025 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "defs.h" #include "gdbsupport/selftest.h" #include "gdbsupport/buildargv.h" #include "gdbsupport/common-inferior.h" #include "gdbsupport/remote-args.h" #include "gdbsupport/gdb_argv_vec.h" namespace selftests { namespace remote_args_tests { /* The data needed to perform a single remote argument test. */ struct arg_test_desc { /* The original inferior argument string. */ std::string input; /* The individual arguments once they have been split. */ std::vector split; /* The new inferior argument string, created by joining SPLIT. */ std::string joined; }; /* The list of tests. */ arg_test_desc desc[] = { { "abc", { "abc" }, "abc" }, { "a b c", { "a", "b", "c" }, "a b c" }, { "\"a b\" 'c d'", { "a b", "c d" }, "a\\ b c\\ d" }, { "\\' \\\"", { "'", "\"" }, "\\' \\\"" }, { "'\\'", { "\\" }, "\\\\" }, { "\"\\\\\" \"\\\\\\\"\"", { "\\", "\\\"" }, "\\\\ \\\\\\\"" }, { "\\ \" \" ' '", { " ", " ", " "}, "\\ \\ \\ " }, { "\"'\"", { "'" }, "\\'" }, { "'\"' '\\\"'", { "\"", "\\\"" } , "\\\" \\\\\\\""}, { "\"first arg\" \"\" \"third-arg\" \"'\" \"\\\"\" \"\\\\\\\"\" \" \" \"\"", { "first arg", "", "third-arg", "'", "\"", "\\\""," ", "" }, "first\\ arg '' third-arg \\' \\\" \\\\\\\" \\ ''"}, { "\"\\a\" \"\\&\" \"\\#\" \"\\<\" \"\\^\"", { "\\a", "\\&", "\\#" , "\\<" , "\\^"}, "\\\\a \\\\\\& \\\\\\# \\\\\\< \\\\\\^" }, { "1 '\n' 3", { "1", "\n", "3" }, "1 '\n' 3" }, }; /* Run the remote argument passing self tests. */ static void self_test () { int failure_count = 0; for (const auto &d : desc) { if (run_verbose ()) { if (&d != &desc[0]) debug_printf ("------------------------------\n"); debug_printf ("Input (%s)\n", d.input.c_str ()); } /* Split argument string into individual arguments. */ std::vector split_args = gdb::remote_args::split (d.input); if (run_verbose ()) { debug_printf ("Split:\n"); size_t len = std::max (split_args.size (), d.split.size ()); for (size_t i = 0; i < len; ++i) { const char *got = "N/A"; const char *expected = got; if (i < split_args.size ()) got = split_args[i].c_str (); if (i < d.split.size ()) expected = d.split[i].c_str (); debug_printf (" got (%s), expected (%s)\n", got, expected); } } if (split_args != d.split) { ++failure_count; if (run_verbose ()) debug_printf ("FAIL\n"); continue; } /* Now join the arguments. */ gdb::argv_vec split_args_c_str; for (const std::string &s : split_args) split_args_c_str.push_back (xstrdup (s.c_str ())); std::string joined_args = gdb::remote_args::join (split_args_c_str.get ()); if (run_verbose ()) debug_printf ("Joined (%s), expected (%s)\n", joined_args.c_str (), d.joined.c_str ()); if (joined_args != d.joined) { ++failure_count; if (run_verbose ()) debug_printf ("FAIL\n"); continue; } /* The contents of JOINED_ARGS will not be identical to D.INPUT. There are multiple ways that an argument can be escaped, and our join function just picks one. However, if we split JOINED_ARGS again then each individual argument should be the same as those in SPLIT_ARGS. So test that next. */ std::vector split_args_v2 = gdb::remote_args::split (joined_args); if (split_args_v2 != split_args) { ++failure_count; if (run_verbose ()) { debug_printf ("Re-split:\n"); for (const auto &a : split_args_v2) debug_printf (" got (%s)\n", a.c_str ()); debug_printf ("FAIL\n"); } continue; } if (run_verbose ()) debug_printf ("PASS\n"); } SELF_CHECK (failure_count == 0); } } /* namespace remote_args_tests */ } /* namespace selftests */ void _initialize_remote_arg_selftests (); void _initialize_remote_arg_selftests () { selftests::register_test ("remote-args", selftests::remote_args_tests::self_test); }