1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * diagcode library unit test
29  *
30  * usually run from "make test" target.  takes a single argument
31  * which is the directory where the test dictionaries are found.
32  * this test driver scans the dictionaries for comments of the form:
33  *	#TEST:<routine>:<errno>:<input>:<output>
34  * and executes that test.
35  *
36  * exit 0 and an "All tests passed" message means no failures.  otherwise
37  * error messages are spewed as appropriate and exit value is non-zero.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include <alloca.h>
47 #include <errno.h>
48 #include <sys/types.h>
49 #include <dirent.h>
50 #include <stdarg.h>
51 
52 #include <fm/diagcode.h>
53 
54 #define	MAXLINE	10240
55 #define	MAXARG 10
56 #define	MAXKEY 100
57 #define	MAXCODE 100
58 
59 static char *Myname;
60 static char *Dict;
61 static int Line;
62 static int Errcount;
63 static fm_dc_handle_t *Dhp;
64 
65 /*PRINTFLIKE1*/
66 static void
67 err(const char *fmt, ...)
68 {
69 	va_list ap;
70 
71 	va_start(ap, fmt);
72 	(void) fprintf(stderr, "%s: %s:%d ", Myname, Dict, Line);
73 	(void) vfprintf(stderr, fmt, ap);
74 	(void) fprintf(stderr, "\n");
75 	Errcount++;
76 }
77 
78 /* parse an expected errno value from test line (numeric or some symbolic) */
79 static int
80 geterrno(const char *s)
81 {
82 	if (*s == '\0' || isspace(*s))
83 		return (0);
84 	else if (isdigit(*s))
85 		return (atoi(s));
86 	else if (strcmp(s, "EPERM") == 0)
87 		return (EPERM);
88 	else if (strcmp(s, "ENOENT") == 0)
89 		return (ENOENT);
90 	else if (strcmp(s, "ESRCH") == 0)
91 		return (ESRCH);
92 	else if (strcmp(s, "ENOMEM") == 0)
93 		return (ENOMEM);
94 	else if (strcmp(s, "EACCES") == 0)
95 		return (EACCES);
96 	else if (strcmp(s, "EINVAL") == 0)
97 		return (EINVAL);
98 	else if (strcmp(s, "ERANGE") == 0)
99 		return (ERANGE);
100 	else if (strcmp(s, "ENOMSG") == 0)
101 		return (ENOMSG);
102 	else if (strcmp(s, "ENOTSUP") == 0)
103 		return (ENOTSUP);
104 	else {
105 		err("geterrno: don't know errno \"%s\"", s);
106 		Errcount++;
107 		return (0);
108 	}
109 }
110 
111 /* call fm_dc_opendict() as part of a test */
112 static void
113 do_open(const char *dirpath, const char *dictname, char *argv[], int argc)
114 {
115 	int reterrno;
116 	int experrno;
117 
118 	if (argc != 2) {
119 		err("argc != 2");
120 		return;
121 	}
122 	experrno = geterrno(argv[1]);
123 
124 	if ((Dhp = fm_dc_opendict(FM_DC_VERSION, dirpath, dictname)) == NULL)
125 		reterrno = errno;
126 	else
127 		reterrno = 0;
128 
129 	if (reterrno != experrno)
130 		err("opendict errno %d, expected %d", reterrno, experrno);
131 }
132 
133 /* call fm_dc_closedict() as part of a test */
134 static void
135 do_close(const char *dirpath, const char *dictname, char *argv[], int argc)
136 {
137 	if (Dhp) {
138 		fm_dc_closedict(Dhp);
139 		Dhp = NULL;
140 	}
141 }
142 
143 /* call fm_dc_codelen() as part of a test */
144 static void
145 do_codelen(const char *dirpath, const char *dictname, char *argv[], int argc)
146 {
147 	int retcodelen;
148 	int expcodelen;
149 
150 	if (argc != 3) {
151 		err("argc != 3");
152 		return;
153 	}
154 	expcodelen = geterrno(argv[2]);
155 
156 	if (Dhp == NULL) {
157 		err("codelen NULL handle");
158 		return;
159 	}
160 
161 	retcodelen = fm_dc_codelen(Dhp);
162 
163 	if (retcodelen != expcodelen)
164 		err("codelen %d, expected %d", retcodelen, expcodelen);
165 }
166 
167 /* call fm_dc_maxkey() as part of a test */
168 static void
169 do_maxkey(const char *dirpath, const char *dictname, char *argv[], int argc)
170 {
171 	int retmaxkey;
172 	int expmaxkey;
173 
174 	if (argc != 3) {
175 		err("argc != 3");
176 		return;
177 	}
178 	expmaxkey = geterrno(argv[2]);
179 
180 	if (Dhp == NULL) {
181 		err("maxkey NULL handle");
182 		return;
183 	}
184 
185 	retmaxkey = fm_dc_maxkey(Dhp);
186 
187 	if (retmaxkey != expmaxkey)
188 		err("maxkey %d, expected %d", retmaxkey, expmaxkey);
189 }
190 
191 /* call fm_dc_key2code() as part of a test */
192 static void
193 do_key2code(const char *dirpath, const char *dictname, char *argv[], int argc)
194 {
195 	int reterrno;
196 	int experrno;
197 	const char *key[MAXKEY];
198 	char code[MAXCODE];
199 	int nel;
200 	char *beginp;
201 	char *endp;
202 
203 	if (argc < 3) {
204 		err("argc < 3");
205 		return;
206 	}
207 	if (argc > 4) {
208 		err("argc > 4");
209 		return;
210 	}
211 	experrno = geterrno(argv[1]);
212 
213 	/* convert key into array */
214 	nel = 0;
215 	beginp = argv[2];
216 	while (nel < MAXKEY - 1) {
217 		key[nel++] = beginp;
218 		if ((endp = strchr(beginp, ' ')) != NULL) {
219 			*endp++ = '\0';
220 			beginp = endp;
221 		} else
222 			break;
223 	}
224 	key[nel] = NULL;
225 
226 	if (Dhp == NULL) {
227 		err("key2code NULL handle");
228 		return;
229 	}
230 
231 	if (fm_dc_key2code(Dhp, key, code, MAXCODE) < 0)
232 		reterrno = errno;
233 	else
234 		reterrno = 0;
235 
236 	if (reterrno != experrno) {
237 		err("key2code errno %d, expected %d", reterrno, experrno);
238 		return;
239 	}
240 
241 	if (reterrno == 0 && argc > 3 && strcmp(code, argv[3]))
242 		err("code \"%s\", expected \"%s\"", code, argv[3]);
243 }
244 
245 /* call fm_dc_code2key() as part of a test */
246 static void
247 do_code2key(const char *dirpath, const char *dictname, char *argv[], int argc)
248 {
249 	int reterrno;
250 	int experrno;
251 	char keystr[MAXLINE];
252 	char *key[MAXKEY];
253 	int nel;
254 
255 	if (argc < 3) {
256 		err("argc < 3");
257 		return;
258 	}
259 	if (argc > 4) {
260 		err("argc > 4");
261 		return;
262 	}
263 	experrno = geterrno(argv[1]);
264 
265 	if (Dhp == NULL) {
266 		err("code2key NULL handle");
267 		return;
268 	}
269 
270 	if (fm_dc_code2key(Dhp, argv[2], key, fm_dc_maxkey(Dhp)) < 0)
271 		reterrno = errno;
272 	else
273 		reterrno = 0;
274 
275 	if (reterrno != experrno) {
276 		err("errno %d, expected %d", reterrno, experrno);
277 		return;
278 	}
279 
280 	if (reterrno)
281 		return;
282 
283 	if (argc > 3) {
284 		/* convert key into string */
285 		keystr[0] = '\0';
286 		for (nel = 0; key[nel]; nel++) {
287 			if (nel)
288 				(void) strcat(keystr, " ");
289 			(void) strcat(keystr, key[nel]);
290 		}
291 
292 		if (strcmp(keystr, argv[3]))
293 			err("key \"%s\", expected \"%s\"", keystr, argv[3]);
294 	}
295 	for (nel = 0; key[nel]; nel++)
296 		free(key[nel]);
297 }
298 
299 /* call fm_dc_getprop() as part of a test */
300 static void
301 do_getprop(const char *dirpath, const char *dictname, char *argv[], int argc)
302 {
303 	int reterrno;
304 	int experrno;
305 	const char *val;
306 
307 	if (argc != 4) {
308 		err("argc != 4");
309 		return;
310 	}
311 	experrno = geterrno(argv[1]);
312 
313 	if (Dhp == NULL) {
314 		err("getprop NULL handle");
315 		return;
316 	}
317 
318 	if ((val = fm_dc_getprop(Dhp, argv[2])) == NULL)
319 		reterrno = errno;
320 	else
321 		reterrno = 0;
322 
323 	if (reterrno != experrno) {
324 		err("getprop errno %d, expected %d", reterrno, experrno);
325 		return;
326 	}
327 
328 	if (reterrno == 0 && strcmp(val, argv[3]))
329 		err("val \"%s\", expected \"%s\"", val, argv[3]);
330 }
331 
332 /* scan a dictionary, looking for test directives embedded in the comments */
333 static void
334 testdict(const char *dirpath, const char *dictname)
335 {
336 	char linebuf[MAXLINE];
337 	char fname[MAXLINE];
338 	FILE *fp;
339 
340 	(void) snprintf(fname, MAXLINE, "%s/%s.dict", dirpath, dictname);
341 
342 	if ((fp = fopen(fname, "r")) == NULL) {
343 		perror(fname);
344 		Errcount++;
345 		return;
346 	}
347 
348 	Line = 0;
349 	Dict = fname;
350 
351 	while (fgets(linebuf, MAXLINE, fp) != NULL) {
352 		char *argv[MAXARG];
353 		int argc;
354 		char *beginp;
355 		char *endp;
356 
357 		Line++;
358 		if (strncmp(linebuf, "#TEST:", 6))
359 			continue;
360 
361 		if ((endp = strchr(linebuf, '\n')) != NULL)
362 			*endp = '\0';
363 		argc = 0;
364 		beginp = &linebuf[6];
365 		while (argc < MAXARG - 1) {
366 			argv[argc++] = beginp;
367 			if ((endp = strchr(beginp, ':')) != NULL) {
368 				*endp++ = '\0';
369 				beginp = endp;
370 			} else
371 				break;
372 		}
373 		argv[argc] = NULL;
374 
375 		if (strcmp(argv[0], "open") == 0)
376 			do_open(dirpath, dictname, argv, argc);
377 		else if (strcmp(argv[0], "close") == 0)
378 			do_close(dirpath, dictname, argv, argc);
379 		else if (strcmp(argv[0], "codelen") == 0)
380 			do_codelen(dirpath, dictname, argv, argc);
381 		else if (strcmp(argv[0], "maxkey") == 0)
382 			do_maxkey(dirpath, dictname, argv, argc);
383 		else if (strcmp(argv[0], "key2code") == 0)
384 			do_key2code(dirpath, dictname, argv, argc);
385 		else if (strcmp(argv[0], "code2key") == 0)
386 			do_code2key(dirpath, dictname, argv, argc);
387 		else if (strcmp(argv[0], "getprop") == 0)
388 			do_getprop(dirpath, dictname, argv, argc);
389 		else {
390 			err("unknown TEST command: \"%s\"", argv[0]);
391 			Errcount++;
392 		}
393 	}
394 
395 	(void) fclose(fp);
396 
397 	if (Dhp) {
398 		fm_dc_closedict(Dhp);
399 		Dhp = NULL;
400 	}
401 }
402 
403 /* scan a directory, looking for dictionaries to test against */
404 int
405 main(int argc, char *argv[])
406 {
407 	DIR *dirp;
408 	struct dirent *dp;
409 
410 	if ((Myname = strrchr(argv[0], '/')) == NULL)
411 		Myname = argv[0];
412 	else
413 		Myname++;
414 
415 	if (argc != 2) {
416 		(void) fprintf(stderr, "usage: %s test-directory\n", argv[0]);
417 		exit(1);
418 	}
419 
420 	if ((dirp = opendir(argv[1])) == NULL) {
421 		perror(argv[1]);
422 		exit(1);
423 	}
424 
425 	while ((dp = readdir(dirp)) != NULL) {
426 		char *ptr;
427 
428 		if (dp->d_name[0] == '.')
429 			continue;
430 
431 		if ((ptr = strrchr(dp->d_name, '.')) == NULL ||
432 		    strcmp(ptr, ".dict"))
433 			continue;
434 
435 		*ptr = '\0';	/* remove the extension */
436 		testdict(argv[1], dp->d_name);
437 	}
438 	(void) closedir(dirp);
439 
440 	if (Errcount == 0)
441 		(void) printf("%s: All tests passed.\n", Myname);
442 
443 	return (Errcount);
444 }
445