1 /*-
2 * Copyright (c) 2012 Jilles Tjoelker
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/param.h>
28 #include <sys/wait.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <fmtmsg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #include <atf-c.h>
38
39 static char *run_test(long classification, const char *label, int severity,
40 const char *text, const char *action, const char *tag);
41
42 struct testcase {
43 long classification;
44 const char *label;
45 int severity;
46 const char *text;
47 const char *action;
48 const char *tag;
49 const char *msgverb;
50 const char *result;
51 } testcases[] = {
52 {
53 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
54 "illegal option -- z", "refer to manual", "BSD:ls:001",
55 NULL,
56 "BSD:ls: ERROR: illegal option -- z\n"
57 "TO FIX: refer to manual BSD:ls:001\n"
58 },
59 {
60 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
61 "illegal option -- z", "refer to manual", "BSD:ls:001",
62 "text:severity:action:tag",
63 "illegal option -- z: ERROR\n"
64 "TO FIX: refer to manual BSD:ls:001\n"
65 },
66 {
67 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
68 "illegal option -- z", "refer to manual", "BSD:ls:001",
69 "text",
70 "illegal option -- z\n"
71 },
72 {
73 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
74 "illegal option -- z", "refer to manual", "BSD:ls:001",
75 "severity:text",
76 "ERROR: illegal option -- z\n"
77 },
78 {
79 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
80 "illegal option -- z", "refer to manual", "BSD:ls:001",
81 "ignore me",
82 "BSD:ls: ERROR: illegal option -- z\n"
83 "TO FIX: refer to manual BSD:ls:001\n"
84 },
85 {
86 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
87 "illegal option -- z", "refer to manual", "BSD:ls:001",
88 "tag:severity:text:nothing:action",
89 "BSD:ls: ERROR: illegal option -- z\n"
90 "TO FIX: refer to manual BSD:ls:001\n"
91 },
92 {
93 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
94 "illegal option -- z", "refer to manual", "BSD:ls:001",
95 "",
96 "BSD:ls: ERROR: illegal option -- z\n"
97 "TO FIX: refer to manual BSD:ls:001\n"
98 },
99 {
100 MM_UTIL | MM_PRINT, MM_NULLLBL, MM_ERROR,
101 "illegal option -- z", "refer to manual", "BSD:ls:001",
102 NULL,
103 "ERROR: illegal option -- z\n"
104 "TO FIX: refer to manual BSD:ls:001\n"
105 },
106 {
107 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
108 "illegal option -- z", MM_NULLACT, MM_NULLTAG,
109 NULL,
110 "BSD:ls: ERROR: illegal option -- z\n"
111 },
112 {
113 MM_UTIL | MM_NULLMC, "BSD:ls", MM_ERROR,
114 "illegal option -- z", "refer to manual", "BSD:ls:001",
115 NULL,
116 ""
117 },
118 {
119 MM_APPL | MM_PRINT, "ABCDEFGHIJ:abcdefghijklmn", MM_INFO,
120 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
121 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
122 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
123 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
124 "refer to manual", "ABCDEFGHIJ:abcdefghijklmn:001",
125 NULL,
126 "ABCDEFGHIJ:abcdefghijklmn: INFO: "
127 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
128 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
129 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
130 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
131 "TO FIX: refer to manual ABCDEFGHIJ:abcdefghijklmn:001\n"
132 },
133 {
134 MM_OPSYS | MM_PRINT, "TEST:test", MM_HALT,
135 "failed", "nothing can help me", "NOTHING",
136 NULL,
137 "TEST:test: HALT: failed\n"
138 "TO FIX: nothing can help me NOTHING\n"
139 },
140 {
141 MM_OPSYS | MM_PRINT, "TEST:test", MM_WARNING,
142 "failed", "nothing can help me", "NOTHING",
143 NULL,
144 "TEST:test: WARNING: failed\n"
145 "TO FIX: nothing can help me NOTHING\n"
146 },
147 {
148 MM_OPSYS | MM_PRINT, "TEST:test", MM_NOSEV,
149 "failed", "nothing can help me", "NOTHING",
150 NULL,
151 "TEST:test: failed\n"
152 "TO FIX: nothing can help me NOTHING\n"
153 }
154 };
155
156 static char *
run_test(long classification,const char * label,int severity,const char * text,const char * action,const char * tag)157 run_test(long classification, const char *label, int severity,
158 const char *text, const char *action, const char *tag)
159 {
160 int pip[2];
161 pid_t pid, wpid;
162 char *result, *p;
163 size_t resultsize;
164 ssize_t n;
165 int status;
166
167 if (pipe(pip) == -1)
168 err(2, "pipe");
169 pid = fork();
170 if (pid == -1)
171 err(2, "fork");
172 if (pid == 0) {
173 close(pip[0]);
174 if (pip[1] != STDERR_FILENO &&
175 dup2(pip[1], STDERR_FILENO) == -1)
176 _exit(2);
177 if (fmtmsg(classification, label, severity, text, action, tag)
178 != MM_OK)
179 _exit(1);
180 else
181 _exit(0);
182 }
183 close(pip[1]);
184 resultsize = 1024;
185 result = malloc(resultsize);
186 p = result;
187 while ((n = read(pip[0], p, result + resultsize - p - 1)) != 0) {
188 if (n == -1) {
189 if (errno == EINTR)
190 continue;
191 else
192 err(2, "read");
193 }
194 p += n;
195 if (result + resultsize == p - 1) {
196 resultsize *= 2;
197 result = realloc(result, resultsize);
198 if (result == NULL)
199 err(2, "realloc");
200 }
201 }
202 if (memchr(result, '\0', p - result) != NULL) {
203 free(result);
204 return (NULL);
205 }
206 *p = '\0';
207 close(pip[0]);
208 while ((wpid = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
209 ;
210 if (wpid == -1)
211 err(2, "waitpid");
212 if (status != 0) {
213 free(result);
214 return (NULL);
215 }
216 return (result);
217 }
218
219 ATF_TC_WITHOUT_HEAD(fmtmsg_test);
ATF_TC_BODY(fmtmsg_test,tc)220 ATF_TC_BODY(fmtmsg_test, tc)
221 {
222 char *result;
223 struct testcase *t;
224 int i;
225
226 for (i = 0; i < nitems(testcases); i++) {
227 t = &testcases[i];
228 if (t->msgverb != NULL)
229 setenv("MSGVERB", t->msgverb, 1);
230 else
231 unsetenv("MSGVERB");
232 result = run_test(t->classification, t->label, t->severity,
233 t->text, t->action, t->tag);
234 ATF_CHECK_MSG(result != NULL, "testcase %d failed", i + 1);
235 if (result != NULL)
236 ATF_CHECK_MSG(strcmp(result, t->result) == 0,
237 "results for testcase %d didn't match; "
238 "`%s` != `%s`", i + 1, result, t->result);
239 free(result);
240 }
241 }
242
ATF_TP_ADD_TCS(tp)243 ATF_TP_ADD_TCS(tp)
244 {
245
246 ATF_TP_ADD_TC(tp, fmtmsg_test);
247
248 return (atf_no_error());
249 }
250