maint: update copyright
[gnulib.git] / tests / test-sh-quote.c
1 /* Test of sh-quote module.
2    Copyright (C) 2012-2014 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Bruno Haible <bruno@clisp.org>, 2012.  */
18
19 #include <config.h>
20
21 /* Specification.  */
22 #include "sh-quote.h"
23
24 #include <limits.h>
25 #include <string.h>
26
27 #include "macros.h"
28
29 static void
30 check_one (const char *input, const char *expected)
31 {
32   char buf[1000];
33   size_t output_len;
34   char *output;
35   char *bufend;
36
37   output_len = shell_quote_length (input);
38
39   output = shell_quote (input);
40   ASSERT (strlen (output) == output_len);
41
42   ASSERT (output_len <= sizeof (buf) - 2);
43   memset (buf, '\0', output_len + 1);
44   buf[output_len + 1] = '%';
45   bufend = shell_quote_copy (buf, input);
46   ASSERT (bufend == buf + output_len);
47   ASSERT (memcmp (buf, output, output_len + 1) == 0);
48   ASSERT (buf[output_len + 1] == '%');
49
50   ASSERT (strcmp (output, expected) == 0);
51
52   free (output);
53 }
54
55 int
56 main (void)
57 {
58   /* Check the shell_quote_length, shell_quote_copy, shell_quote functions.  */
59   {
60     int c;
61
62     /* Empty argument.  */
63     check_one ("", "''");
64
65     /* Identifier or number.  */
66     check_one ("foo", "foo");
67     check_one ("phr0ck", "phr0ck");
68
69     /* Whitespace would be interpreted as argument separator by the shell.  */
70     check_one ("foo\tbar", "'foo\tbar'");
71     check_one ("foo\nbar", "'foo\nbar'");
72     check_one ("foo\rbar", "'foo\rbar'");
73     check_one ("foo bar", "'foo bar'");
74
75     /* '!' at the beginning of argv[0] would introduce a negated command.  */
76     check_one ("!foo", "'!foo'");
77
78     /* '"' would be interpreted as the start of a string.  */
79     check_one ("\"foo\"bar", "'\"foo\"bar'");
80
81     /* '#' at the beginning of an argument would be interpreted as the start
82        of a comment.  */
83     check_one ("#foo", "'#foo'");
84
85     /* '$' at the beginning of an argument would be interpreted as a variable
86        reference.  */
87     check_one ("$foo", "'$foo'");
88
89     /* '&' at the beginning of an argument would be interpreted as a background
90        task indicator.  */
91     check_one ("&", "'&'");
92
93     /* "'" would be interpreted as the start of a string.  */
94     check_one ("'foo'bar", "''\\''foo'\\''bar'"); /* or "\"'foo'bar\"" */
95
96     /* '(' at the beginning of argv[0] would introduce a subshell command.  */
97     check_one ("(", "'('");
98
99     /* ')' at the beginning of an argument would be interpreted as the end of
100        the command.  */
101     check_one (")", "')'");
102
103     /* '*' would be interpreted as a wildcard character.  */
104     check_one ("*", "'*'");
105     check_one ("*foo", "'*foo'");
106
107     /* ';' at the beginning of an argument would be interpreted as an empty
108        statement in argv[0] and as the end of the command otherwise.  */
109     check_one (";", "';'");
110     check_one ("foo;", "'foo;'");
111
112     /* '<' would be interpreted as a redirection of stdin.  */
113     check_one ("<", "'<'");
114
115     /* '=' inside argv[0] would be interpreted as an environment variable
116        assignment.  */
117     check_one ("foo=bar", "'foo=bar'");
118
119     /* '>' would be interpreted as a redirection of stdout.  */
120     check_one (">", "'>'");
121
122     /* '?' would be interpreted as a wildcard character.  */
123     check_one ("?", "'?'");
124     check_one ("foo?bar", "'foo?bar'");
125
126     /* '^' would be interpreted in old /bin/sh, e.g. SunOS 4.1.4.  */
127     check_one ("^", "'^'");
128
129     /* "[...]" would be interpreted as a wildcard pattern.  */
130     check_one ("[", "'['");
131     check_one ("]", "]"); /* or "']'" */
132
133     /* '\' would be interpreted as an escape character.  */
134     check_one ("\\foo", "'\\foo'");
135
136     /* '`' would be interpreted as the start of a command substitution.  */
137     check_one ("`foo", "'`foo'");
138
139     /* '{' at the beginning of argv[0] would introduce a complex command.  */
140     check_one ("{", "'{'");
141
142     /* '|' at the beginning of an argument would be interpreted as a pipe
143        between commands.  */
144     check_one ("|", "'|'");
145
146     /* '}' at the beginning of an argument would be interpreted as the end of
147        the command.  */
148     check_one ("}", "'}'");
149
150     /* '~' at the beginning of an argument would be interpreted as a reference
151        to a user's home directory.  */
152     check_one ("~", "'~'");
153     check_one ("~foo", "'~foo'");
154
155     /* A string that contains both ' and ".  */
156     check_one ("foo'bar\"baz", "'foo'\\''bar\"baz'"); /* or "\"foo'bar\\\"baz\"" */
157
158     /* All other characters don't need quoting.  */
159     for (c = 1; c <= UCHAR_MAX; c++)
160       if (strchr ("\t\n\r !\"#$&'()*;<=>?^[\\]`{|}~", c) == NULL)
161         {
162           char s[5];
163           s[0] = 'a';
164           s[1] = (char) c;
165           s[2] = 'z';
166           s[3] = (char) c;
167           s[4] = '\0';
168
169           check_one (s, s);
170         }
171   }
172
173   /* Check the shell_quote_argv function.  */
174   {
175     char *argv[1];
176     char *result;
177     argv[0] = NULL;
178     result = shell_quote_argv (argv);
179     ASSERT (strcmp (result, "") == 0);
180     free (result);
181   }
182   {
183     char *argv[2];
184     char *result;
185     argv[0] = (char *) "foo bar/baz";
186     argv[1] = NULL;
187     result = shell_quote_argv (argv);
188     ASSERT (strcmp (result, "'foo bar/baz'") == 0); /* or "\"foo bar/baz\"" */
189     free (result);
190   }
191   {
192     char *argv[3];
193     char *result;
194     argv[0] = (char *) "foo bar/baz";
195     argv[1] = (char *) "$";
196     argv[2] = NULL;
197     result = shell_quote_argv (argv);
198     ASSERT (strcmp (result, "'foo bar/baz' '$'") == 0); /* or "\"foo bar/baz\" \"\\$\"" */
199     free (result);
200   }
201
202   return 0;
203 }