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