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/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/wait.h> 32 #include <err.h> 33 #include <errno.h> 34 #include <fmtmsg.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <unistd.h> 39 40 #include <atf-c.h> 41 42 static char *run_test(long classification, const char *label, int severity, 43 const char *text, const char *action, const char *tag); 44 45 struct testcase { 46 long classification; 47 const char *label; 48 int severity; 49 const char *text; 50 const char *action; 51 const char *tag; 52 const char *msgverb; 53 const char *result; 54 } testcases[] = { 55 { 56 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, 57 "illegal option -- z", "refer to manual", "BSD:ls:001", 58 NULL, 59 "BSD:ls: ERROR: illegal option -- z\n" 60 "TO FIX: refer to manual BSD:ls:001\n" 61 }, 62 { 63 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, 64 "illegal option -- z", "refer to manual", "BSD:ls:001", 65 "text:severity:action:tag", 66 "illegal option -- z: ERROR\n" 67 "TO FIX: refer to manual BSD:ls:001\n" 68 }, 69 { 70 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, 71 "illegal option -- z", "refer to manual", "BSD:ls:001", 72 "text", 73 "illegal option -- z\n" 74 }, 75 { 76 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, 77 "illegal option -- z", "refer to manual", "BSD:ls:001", 78 "severity:text", 79 "ERROR: illegal option -- z\n" 80 }, 81 { 82 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, 83 "illegal option -- z", "refer to manual", "BSD:ls:001", 84 "ignore me", 85 "BSD:ls: ERROR: illegal option -- z\n" 86 "TO FIX: refer to manual BSD:ls:001\n" 87 }, 88 { 89 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, 90 "illegal option -- z", "refer to manual", "BSD:ls:001", 91 "tag:severity:text:nothing:action", 92 "BSD:ls: ERROR: illegal option -- z\n" 93 "TO FIX: refer to manual BSD:ls:001\n" 94 }, 95 { 96 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, 97 "illegal option -- z", "refer to manual", "BSD:ls:001", 98 "", 99 "BSD:ls: ERROR: illegal option -- z\n" 100 "TO FIX: refer to manual BSD:ls:001\n" 101 }, 102 { 103 MM_UTIL | MM_PRINT, MM_NULLLBL, MM_ERROR, 104 "illegal option -- z", "refer to manual", "BSD:ls:001", 105 NULL, 106 "ERROR: illegal option -- z\n" 107 "TO FIX: refer to manual BSD:ls:001\n" 108 }, 109 { 110 MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, 111 "illegal option -- z", MM_NULLACT, MM_NULLTAG, 112 NULL, 113 "BSD:ls: ERROR: illegal option -- z\n" 114 }, 115 { 116 MM_UTIL | MM_NULLMC, "BSD:ls", MM_ERROR, 117 "illegal option -- z", "refer to manual", "BSD:ls:001", 118 NULL, 119 "" 120 }, 121 { 122 MM_APPL | MM_PRINT, "ABCDEFGHIJ:abcdefghijklmn", MM_INFO, 123 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 124 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 125 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 126 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 127 "refer to manual", "ABCDEFGHIJ:abcdefghijklmn:001", 128 NULL, 129 "ABCDEFGHIJ:abcdefghijklmn: INFO: " 130 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 131 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 132 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 133 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" 134 "TO FIX: refer to manual ABCDEFGHIJ:abcdefghijklmn:001\n" 135 }, 136 { 137 MM_OPSYS | MM_PRINT, "TEST:test", MM_HALT, 138 "failed", "nothing can help me", "NOTHING", 139 NULL, 140 "TEST:test: HALT: failed\n" 141 "TO FIX: nothing can help me NOTHING\n" 142 }, 143 { 144 MM_OPSYS | MM_PRINT, "TEST:test", MM_WARNING, 145 "failed", "nothing can help me", "NOTHING", 146 NULL, 147 "TEST:test: WARNING: failed\n" 148 "TO FIX: nothing can help me NOTHING\n" 149 }, 150 { 151 MM_OPSYS | MM_PRINT, "TEST:test", MM_NOSEV, 152 "failed", "nothing can help me", "NOTHING", 153 NULL, 154 "TEST:test: failed\n" 155 "TO FIX: nothing can help me NOTHING\n" 156 } 157 }; 158 159 static char * 160 run_test(long classification, const char *label, int severity, 161 const char *text, const char *action, const char *tag) 162 { 163 int pip[2]; 164 pid_t pid, wpid; 165 char *result, *p; 166 size_t resultsize; 167 ssize_t n; 168 int status; 169 170 if (pipe(pip) == -1) 171 err(2, "pipe"); 172 pid = fork(); 173 if (pid == -1) 174 err(2, "fork"); 175 if (pid == 0) { 176 close(pip[0]); 177 if (pip[1] != STDERR_FILENO && 178 dup2(pip[1], STDERR_FILENO) == -1) 179 _exit(2); 180 if (fmtmsg(classification, label, severity, text, action, tag) 181 != MM_OK) 182 _exit(1); 183 else 184 _exit(0); 185 } 186 close(pip[1]); 187 resultsize = 1024; 188 result = malloc(resultsize); 189 p = result; 190 while ((n = read(pip[0], p, result + resultsize - p - 1)) != 0) { 191 if (n == -1) { 192 if (errno == EINTR) 193 continue; 194 else 195 err(2, "read"); 196 } 197 p += n; 198 if (result + resultsize == p - 1) { 199 resultsize *= 2; 200 result = realloc(result, resultsize); 201 if (result == NULL) 202 err(2, "realloc"); 203 } 204 } 205 if (memchr(result, '\0', p - result) != NULL) { 206 free(result); 207 return (NULL); 208 } 209 *p = '\0'; 210 close(pip[0]); 211 while ((wpid = waitpid(pid, &status, 0)) == -1 && errno == EINTR) 212 ; 213 if (wpid == -1) 214 err(2, "waitpid"); 215 if (status != 0) { 216 free(result); 217 return (NULL); 218 } 219 return (result); 220 } 221 222 ATF_TC_WITHOUT_HEAD(fmtmsg_test); 223 ATF_TC_BODY(fmtmsg_test, tc) 224 { 225 char *result; 226 struct testcase *t; 227 int i; 228 229 for (i = 0; i < nitems(testcases); i++) { 230 t = &testcases[i]; 231 if (t->msgverb != NULL) 232 setenv("MSGVERB", t->msgverb, 1); 233 else 234 unsetenv("MSGVERB"); 235 result = run_test(t->classification, t->label, t->severity, 236 t->text, t->action, t->tag); 237 ATF_CHECK_MSG(result != NULL, "testcase %d failed", i + 1); 238 if (result != NULL) 239 ATF_CHECK_MSG(strcmp(result, t->result) == 0, 240 "results for testcase %d didn't match; " 241 "`%s` != `%s`", i + 1, result, t->result); 242 free(result); 243 } 244 } 245 246 ATF_TP_ADD_TCS(tp) 247 { 248 249 ATF_TP_ADD_TC(tp, fmtmsg_test); 250 251 return (atf_no_error()); 252 } 253