summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2012-05-09 03:38:34 +0200
committerBruno Haible <bruno@clisp.org>2012-05-09 03:38:34 +0200
commit9b3cba021116a2c273ba15564dbcd6fe5dc6ad2a (patch)
tree6670525a0099cb79eecfaac53fa442f703992461 /tests
parent83142d08d8fa02a5e133f4b5c0f989584c0427bb (diff)
downloadgnulib-9b3cba021116a2c273ba15564dbcd6fe5dc6ad2a.tar.gz
Tests for module 'system-quote'.
* modules/system-quote-tests: New file. * tests/test-system-quote.sh: New file. * tests/test-system-quote-main.c: New file. * tests/test-system-quote-child.c: New file.
Diffstat (limited to 'tests')
-rw-r--r--tests/test-system-quote-child.c59
-rw-r--r--tests/test-system-quote-main.c344
-rwxr-xr-xtests/test-system-quote.sh3
3 files changed, 406 insertions, 0 deletions
diff --git a/tests/test-system-quote-child.c b/tests/test-system-quote-child.c
new file mode 100644
index 0000000000..9b63de0887
--- /dev/null
+++ b/tests/test-system-quote-child.c
@@ -0,0 +1,59 @@
+/* Child program invoked by test-system-quote-main.
+ Copyright (C) 2012 Free Software Foundation, Inc.
+
+ 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, 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#define EXPECTED_DATA_FILE "t-sq-data.tmp"
+
+int
+main (int argc, char *argv[])
+{
+ const char *arg;
+ char expected_data[1000];
+ size_t expected_data_len;
+
+ if (argc < 2)
+ /* Expected one data argument, received none. */
+ return 2;
+ if (argc > 2)
+ /* Expected one data argument, received more than one. */
+ return 3;
+ arg = argv[1];
+
+ /* Read the contents of EXPECTED_DATA_FILE. */
+ {
+ FILE *fp = fopen (EXPECTED_DATA_FILE, "rb");
+ if (fp == NULL)
+ return 4;
+ expected_data_len = fread (expected_data, 1, sizeof (expected_data), fp);
+ if (fclose (fp))
+ return 5;
+ }
+
+ if (!(strlen (arg) == expected_data_len
+ && memcmp (arg, expected_data, expected_data_len) == 0))
+ {
+ /* arg is not as expected. */
+ fprintf (stderr, "expected: %.*s\nreceived: %s\n",
+ (int)expected_data_len, expected_data, arg);
+ return 1;
+ }
+ else
+ return 0;
+}
diff --git a/tests/test-system-quote-main.c b/tests/test-system-quote-main.c
new file mode 100644
index 0000000000..10fe82308c
--- /dev/null
+++ b/tests/test-system-quote-main.c
@@ -0,0 +1,344 @@
+/* Test of system-quote module.
+ Copyright (C) 2012 Free Software Foundation, Inc.
+
+ 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, 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 <http://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2012. */
+
+#include <config.h>
+
+/* Specification. */
+#include "system-quote.h"
+
+#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
+# define WINDOWS_NATIVE
+#endif
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef WINDOWS_NATIVE
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+
+#include "progname.h"
+#include "macros.h"
+
+#define EXPECTED_DATA_FILE "t-sq-data.tmp"
+
+static int failed;
+
+static void
+check_one (enum system_command_interpreter interpreter, const char *prog,
+ const char *input)
+{
+ char buf[1000];
+ size_t output_len;
+ char *output;
+ char *bufend;
+
+ output_len = system_quote_length (interpreter, input);
+
+ output = system_quote (interpreter, input);
+ ASSERT (strlen (output) == output_len);
+
+ ASSERT (output_len <= sizeof (buf) - 2);
+ memset (buf, '\0', output_len + 1);
+ buf[output_len + 1] = '%';
+ bufend = system_quote_copy (buf, interpreter, input);
+ ASSERT (bufend == buf + output_len);
+ ASSERT (memcmp (buf, output, output_len + 1) == 0);
+ ASSERT (buf[output_len + 1] == '%');
+
+ /* Store INPUT in EXPECTED_DATA_FILE, for verification by the child
+ process. */
+ {
+ FILE *fp = fopen (EXPECTED_DATA_FILE, "wb");
+ if (fp == NULL)
+ exit (3);
+ if (fwrite (input, 1, strlen (input), fp) != strlen (input))
+ exit (4);
+ if (fclose (fp))
+ exit (5);
+ }
+
+ /* Invoke the child process through system() and popen(). */
+ {
+ char command[1000];
+
+ sprintf (command, "%s %s", prog, output);
+
+ switch (interpreter)
+ {
+ case SCI_SYSTEM:
+#ifdef WINDOWS_NATIVE
+ case SCI_WINDOWS_CMD:
+#endif
+ {
+ int exitcode = system (command);
+ if (exitcode != 0)
+ {
+ fprintf (stderr, "for input = |%s|: system() command failed with status %d: %s\n",
+ input, exitcode, command);
+ failed = 1;
+ }
+ }
+ {
+ FILE *fp = popen (command, "r");
+ int exitcode = pclose (fp);
+ if (exitcode != 0)
+ {
+ fprintf (stderr, "for input = |%s|: popen() command failed with status %d: %s\n",
+ input, exitcode, command);
+ failed = 1;
+ }
+ }
+ break;
+#ifdef WINDOWS_NATIVE
+ case SCI_WINDOWS_CREATEPROCESS:
+ {
+ PROCESS_INFORMATION pinfo;
+ STARTUPINFO sinfo;
+ sinfo.cb = sizeof (STARTUPINFO);
+ sinfo.lpReserved = NULL;
+ sinfo.lpDesktop = NULL;
+ sinfo.lpTitle = NULL;
+ sinfo.cbReserved2 = 0;
+ sinfo.lpReserved2 = NULL;
+ sinfo.dwFlags = STARTF_USESTDHANDLES;
+ sinfo.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
+ sinfo.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
+ sinfo.hStdError = GetStdHandle (STD_ERROR_HANDLE);
+
+ if (CreateProcess (NULL, command, NULL, NULL, TRUE, 0, NULL, NULL,
+ &sinfo, &pinfo))
+ {
+ DWORD exitcode;
+ CloseHandle (pinfo.hThread);
+ if (WaitForSingleObject (pinfo.hProcess, INFINITE) == WAIT_OBJECT_0)
+ {
+ if (GetExitCodeProcess (pinfo.hProcess, &exitcode))
+ {
+ if (exitcode != 0)
+ {
+ fprintf (stderr, "for input = |%s|: CreateProcess() command failed with status %d: %s\n",
+ input, exitcode, command);
+ failed = 1;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "for input = |%s|: GetExitCodeProcess failed, GetLastError() = %u\n",
+ input, GetLastError ());
+ failed = 1;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "for input = |%s|: WaitForSingleObject failed\n",
+ input);
+ failed = 1;
+ }
+ CloseHandle (pinfo.hProcess);
+ }
+ else
+ {
+ fprintf (stderr, "for input = |%s|: CreateProcess failed, GetLastError() = %u\n",
+ input, GetLastError ());
+ failed = 1;
+ }
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+
+ free (output);
+}
+
+static void
+check_all (enum system_command_interpreter interpreter,
+ bool windows_cmd_limitations,
+ const char *prog)
+{
+ /* Check the system_quote_length, system_quote_copy, system_quote
+ functions. */
+ {
+ int c;
+
+ /* Empty argument. */
+ check_one (interpreter, prog, "");
+
+ /* Identifier or number. */
+ check_one (interpreter, prog, "foo");
+ check_one (interpreter, prog, "phr0ck");
+
+ /* Whitespace would be interpreted as argument separator by the shell. */
+ check_one (interpreter, prog, "foo\tbar");
+ if (!windows_cmd_limitations)
+ {
+ check_one (interpreter, prog, "foo\nbar");
+ check_one (interpreter, prog, "foo\rbar");
+ }
+ check_one (interpreter, prog, "foo bar");
+
+ /* '!' at the beginning of argv[0] would introduce a negated command. */
+ check_one (interpreter, prog, "!foo");
+
+ /* '"' would be interpreted as the start of a string. */
+ check_one (interpreter, prog, "\"foo\"bar");
+
+ /* '#' at the beginning of an argument would be interpreted as the start
+ of a comment. */
+ check_one (interpreter, prog, "#foo");
+
+ /* '$' at the beginning of an argument would be interpreted as a variable
+ reference. */
+ check_one (interpreter, prog, "$foo");
+
+ /* '&' at the beginning of an argument would be interpreted as a background
+ task indicator. */
+ check_one (interpreter, prog, "&");
+
+ /* "'" would be interpreted as the start of a string. */
+ check_one (interpreter, prog, "'foo'bar");
+
+ /* '(' at the beginning of argv[0] would introduce a subshell command. */
+ check_one (interpreter, prog, "(");
+
+ /* ')' at the beginning of an argument would be interpreted as the end of
+ the command. */
+ check_one (interpreter, prog, ")");
+
+ /* '*' would be interpreted as a wildcard character. */
+ check_one (interpreter, prog, "*");
+ check_one (interpreter, prog, "*foo");
+
+ /* ';' at the beginning of an argument would be interpreted as an empty
+ statement in argv[0] and as the end of the command otherwise. */
+ check_one (interpreter, prog, ";");
+ check_one (interpreter, prog, "foo;");
+
+ /* '<' would be interpreted as a redirection of stdin. */
+ check_one (interpreter, prog, "<");
+
+ /* '=' inside argv[0] would be interpreted as an environment variable
+ assignment. */
+ check_one (interpreter, prog, "foo=bar");
+
+ /* '>' would be interpreted as a redirection of stdout. */
+ check_one (interpreter, prog, ">");
+
+ /* '?' would be interpreted as a wildcard character. */
+ check_one (interpreter, prog, "?");
+ check_one (interpreter, prog, "foo?bar");
+
+ /* '^' would be interpreted in old /bin/sh, e.g. SunOS 4.1.4. */
+ check_one (interpreter, prog, "^");
+
+ /* "[...]" would be interpreted as a wildcard pattern. */
+ check_one (interpreter, prog, "[");
+ check_one (interpreter, prog, "]");
+
+ /* '\' would be interpreted as an escape character. */
+ check_one (interpreter, prog, "\\foo");
+
+ /* '`' would be interpreted as the start of a command substitution. */
+ check_one (interpreter, prog, "`foo");
+
+ /* '{' at the beginning of argv[0] would introduce a complex command. */
+ check_one (interpreter, prog, "{");
+
+ /* '|' at the beginning of an argument would be interpreted as a pipe
+ between commands. */
+ check_one (interpreter, prog, "|");
+
+ /* '}' at the beginning of an argument would be interpreted as the end of
+ the command. */
+ check_one (interpreter, prog, "}");
+
+ /* '~' at the beginning of an argument would be interpreted as a reference
+ to a user's home directory. */
+ check_one (interpreter, prog, "~");
+ check_one (interpreter, prog, "~foo");
+
+ /* A string that contains both ' and ". */
+ check_one (interpreter, prog, "foo'bar\"baz");
+
+ /* '%' is used for environment variable references in Windows cmd.exe. */
+ check_one (interpreter, prog, "%");
+ check_one (interpreter, prog, "%%");
+ check_one (interpreter, prog, "%foo%");
+ check_one (interpreter, prog, "%PATH%");
+
+ /* All other characters don't need quoting. */
+ for (c = 1; c <= UCHAR_MAX; c++)
+ if (strchr ("\t\n\r !\"#$&'()*;<=>?^[\\]`{|}~", c) == NULL)
+ {
+ char s[5];
+ s[0] = 'a';
+ s[1] = (char) c;
+ s[2] = 'z';
+ s[3] = (char) c;
+ s[4] = '\0';
+
+ check_one (interpreter, prog, s);
+ }
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ char *prog;
+
+ set_program_name (argv[0]);
+
+ if (argc != 2)
+ {
+ fprintf (stderr, "%s: need 1 argument\n", argv[0]);
+ return 2;
+ }
+ prog = argv[1];
+
+#ifdef WINDOWS_NATIVE
+ /* Make PROG suitable for native Windows system calls and cmd.exe:
+ Replace '/' with '\\'. */
+ {
+ char *p;
+ for (p = prog; *p != '\0'; p++)
+ if (*p == '/')
+ *p = '\\';
+ }
+#endif
+
+#ifdef WINDOWS_NATIVE
+ check_all (SCI_SYSTEM, true, prog); /* equivalent to SCI_WINDOWS_CMD */
+ check_all (SCI_WINDOWS_CREATEPROCESS, false, prog);
+ check_all (SCI_WINDOWS_CMD, true, prog);
+#else
+ check_all (SCI_SYSTEM, false, prog); /* equivalent to SCI_POSIX_SH */
+#endif
+
+ /* Clean up. */
+ unlink (EXPECTED_DATA_FILE);
+
+ return failed;
+}
diff --git a/tests/test-system-quote.sh b/tests/test-system-quote.sh
new file mode 100755
index 0000000000..d5202865a2
--- /dev/null
+++ b/tests/test-system-quote.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+./test-system-quote-main${EXEEXT} ./test-system-quote-child${EXEEXT}