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 * 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); 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 243 ATF_TP_ADD_TCS(tp) 244 { 245 246 ATF_TP_ADD_TC(tp, fmtmsg_test); 247 248 return (atf_no_error()); 249 } 250