1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2015 Joyent, Inc.
14  */
15 
16 /*
17  * mergeq testing routines
18  */
19 
20 #include <mergeq.h>
21 #include <stdio.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <stdlib.h>
25 
26 const char *
_umem_debug_init()27 _umem_debug_init()
28 {
29 	return ("default,verbose");
30 }
31 
32 const char *
_umem_logging_init(void)33 _umem_logging_init(void)
34 {
35 	return ("fail,contents");
36 }
37 
38 void *
mergeq_alloc(size_t size)39 mergeq_alloc(size_t size)
40 {
41 	return (malloc(size));
42 }
43 
44 /*ARGSUSED*/
45 void
mergeq_free(void * buf,size_t size)46 mergeq_free(void *buf, size_t size)
47 {
48 	free(buf);
49 }
50 
51 static int
mqt_int(void * first,void * second,void ** outp,void * arg)52 mqt_int(void *first, void *second, void **outp, void *arg)
53 {
54 	uintptr_t a, b, c;
55 	a = (uintptr_t)first;
56 	b = (uintptr_t)second;
57 	c = a + b;
58 	*outp = (void *)c;
59 
60 	return (0);
61 }
62 
63 static int
mqt_append(void * first,void * second,void ** outp,void * arg)64 mqt_append(void *first, void *second, void **outp, void *arg)
65 {
66 	char *out;
67 
68 	/* Yes, this leaks, don't worry about it for the test */
69 	if (asprintf(&out, "%s%s", first, second) != -1) {
70 		*outp = out;
71 		return (0);
72 	}
73 	return (-1);
74 }
75 
76 static int
mqt_fatal(void * first,void * second,void ** outp,void * arg)77 mqt_fatal(void *first, void *second, void **outp, void *arg)
78 {
79 	return (-1);
80 }
81 
82 /*
83  * Test structures and cases. We really want mq_args to be a flexible array
84  * member, but then we cant initialize it. Thus we set a fixed size number of
85  * entries.
86  */
87 typedef struct mq_test {
88 	const char	*mq_desc;	/* test description/name */
89 	mergeq_proc_f	*mq_proc;	/* processing function */
90 	int		mq_rval;	/* mergeq_merge return value */
91 	int		mq_uerr;	/* user error, if any */
92 	boolean_t	mq_strcmp;	/* use strcmp rather than == */
93 	void		*mq_result;	/* expected result */
94 	void		**mq_args;	/* argument array */
95 } mq_test_t;
96 
97 static void *mqt_empty_args[] = { NULL };
98 static void *mqt_single_args[] = { (void *)42, NULL };
99 static void *mqt_double_args[] = { (void *)42, (void *)27, NULL };
100 static void *mqt_wrap_args[] = {
101 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
102 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
103 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
104 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
105 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
106 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
107 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
108 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
109 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
110 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
111 	(void *)1, (void *)1, (void *)1, (void *)1, NULL
112 };
113 static void *mqt_grow_args[] = {
114 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
115 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
116 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
117 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
118 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
119 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
120 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
121 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
122 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
123 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
124 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
125 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
126 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
127 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
128 	(void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
129 	(void *)1, (void *)1, NULL
130 };
131 static void *mqt_order_args[] = { "l", "e", "g", "e", "n", "d", " ", "o", "f",
132 	" ", "z", "e", "l", "d", "a", NULL };
133 
134 
135 static mq_test_t mq_tests[] = {
136 	{ "empty", mqt_int, 0, 0, B_FALSE, NULL, mqt_empty_args },
137 	{ "single", mqt_int, 0, 0, B_FALSE, (void *)42, mqt_single_args },
138 	{ "double", mqt_int, 0, 0, B_FALSE, (void *)69, mqt_double_args },
139 	{ "wrap", mqt_int, 0, 0, B_FALSE, (void *)64, mqt_wrap_args },
140 	{ "grow", mqt_int, 0, 0, B_FALSE, (void *)92, mqt_grow_args },
141 	{ "fatal", mqt_fatal, MERGEQ_UERROR, -1, B_FALSE, NULL,
142 	    mqt_double_args },
143 	{ "order", mqt_append, 0, 0, B_TRUE, "alegend of zeld", mqt_order_args }
144 };
145 
146 #define	NMQ_TESTS (sizeof (mq_tests) / sizeof (mq_test_t))
147 
148 static void
mq_test_run(mergeq_t * mqp,mq_test_t * mqt)149 mq_test_run(mergeq_t *mqp, mq_test_t *mqt)
150 {
151 	int ret, err;
152 	void **itemp = mqt->mq_args;
153 	void *out;
154 
155 	while (*itemp != NULL) {
156 		if ((ret = mergeq_add(mqp, *itemp)) != 0) {
157 			(void) fprintf(stderr,
158 			    "test %s: failed to add item: %s\n",
159 			    mqt->mq_desc, strerror(errno));
160 			exit(1);
161 		}
162 		itemp++;
163 	}
164 
165 	ret = mergeq_merge(mqp, mqt->mq_proc, NULL, &out, &err);
166 	if (ret != mqt->mq_rval) {
167 		(void) fprintf(stderr, "test %s: got incorrect rval. "
168 		    "Expected %d, got %d\n", mqt->mq_desc, mqt->mq_rval, ret);
169 		exit(1);
170 	}
171 
172 	if (ret == MERGEQ_UERROR && err != mqt->mq_uerr) {
173 		(void) fprintf(stderr, "test %s: got incorrect user error. "
174 		    "Expected %d, got %d\n", mqt->mq_desc, mqt->mq_uerr, err);
175 		exit(1);
176 	}
177 
178 	if (ret == 0) {
179 		if (mqt->mq_strcmp == B_TRUE &&
180 		    strcmp(out, mqt->mq_result) != 0) {
181 			(void) fprintf(stderr, "test %s: got unexpected "
182 			    "result: %s, expected %s\n", mqt->mq_desc, out,
183 			    mqt->mq_result);
184 			exit(1);
185 		} else if (mqt->mq_strcmp == B_FALSE && out != mqt->mq_result) {
186 			(void) fprintf(stderr, "test %s: got unexpected "
187 			    "result: %p, expected %p\n", mqt->mq_desc, out,
188 			    mqt->mq_result);
189 			exit(1);
190 		}
191 	}
192 }
193 
194 int
main(void)195 main(void)
196 {
197 	int ret, i, t;
198 	mergeq_t *mqp;
199 	int nthreads[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, -1 };
200 
201 	for (t = 0; nthreads[t] != -1; t++) {
202 		printf("Beginning tests with %d threads\n", nthreads[t]);
203 		if ((ret = mergeq_init(&mqp, nthreads[t])) != 0) {
204 			fprintf(stderr, "failed to init mergeq: %s\n",
205 			    strerror(errno));
206 			return (1);
207 		}
208 
209 		for (i = 0; i < NMQ_TESTS; i++) {
210 			mq_test_run(mqp, &mq_tests[i]);
211 		}
212 
213 		mergeq_fini(mqp);
214 	}
215 
216 	return (0);
217 }
218