1 /* test harness for bits.h
2  *
3  * This file is Copyright (c) 2010 by the GPSD project
4  * SPDX-License-Identifier: BSD-2-clause
5  */
6 
7 #include <inttypes.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdint.h>
12 #include <stdbool.h>
13 #include "../bits.h"
14 
15 static unsigned char buf[80];
16 static signed char sb1, sb2;
17 static unsigned char ub1, ub2;
18 static short sw1, sw2;
19 static unsigned short uw1, uw2;
20 static int sl1, sl2;
21 static unsigned int ul1, ul2;
22 static int64_t sL1, sL2;
23 static uint64_t uL1, uL2;
24 static float f1;
25 static double d1;
26 
hexdump(const void * binbuf,size_t len)27 static char *hexdump(const void *binbuf, size_t len)
28 {
29     static char hexbuf[BUFSIZ];
30     size_t i, j = 0;
31     const char *ibuf = (const char *)binbuf;
32     const char *hexchar = "0123456789abcdef";
33 
34     for (i = 0; i < len; i++) {
35 	hexbuf[j++] = hexchar[(ibuf[i] & 0xf0) >> 4];
36 	hexbuf[j++] = hexchar[ibuf[i] & 0x0f];
37     }
38     hexbuf[j] = '\0';
39     return hexbuf;
40 }
41 
bedumpall(void)42 static void bedumpall(void)
43 {
44     (void)printf("getsb: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
45 		 (uint64_t) sb1, (uint64_t) sb2,
46 		 (uint64_t) getsb(buf, 0), (uint64_t) getsb(buf, 8));
47     (void)printf("getub: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
48 		 (uint64_t) ub1, (uint64_t) ub2,
49 		 (uint64_t) getub(buf, 0), (uint64_t) getub(buf, 8));
50     (void)printf("getbes16: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
51 		 (uint64_t) sw1, (uint64_t) sw2,
52 		 (uint64_t) getbes16(buf, 0), (uint64_t) getbes16(buf, 8));
53     (void)printf("getbeu16: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
54 		 (uint64_t) uw1, (uint64_t) uw2,
55 		 (uint64_t) getbeu16(buf, 0), (uint64_t) getbeu16(buf, 8));
56     (void)printf("getbes32: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
57 		 (uint64_t) sl1, (uint64_t) sl2,
58 		 (uint64_t) getbes32(buf, 0), (uint64_t) getbes32(buf, 8));
59     (void)printf("getbeu32: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
60 		 (uint64_t) ul1, (uint64_t) ul2,
61 		 (uint64_t) getbeu32(buf, 0), (uint64_t) getbeu32(buf, 8));
62     (void)printf("getbes64: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
63 		 (uint64_t) sL1, (uint64_t) sL2,
64 		 (uint64_t) getbes64(buf, 0), (uint64_t) getbes64(buf, 8));
65     (void)printf("getbeu64: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
66 		 (uint64_t) uL1, (uint64_t) uL2,
67 		 (uint64_t) getbeu64(buf, 0), (uint64_t) getbeu64(buf, 8));
68     (void)printf("getbef32: %f %f\n", f1, getbef32((const char *)buf, 24));
69     (void)printf("getbed64: %.16f %.16f\n", d1, getbed64((const char *)buf, 16));
70 }
71 
ledumpall(void)72 static void ledumpall(void)
73 {
74     (void)printf("getsb: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
75 		 (uint64_t) sb1, (uint64_t) sb2,
76 		 (uint64_t) getsb(buf, 0), (uint64_t) getsb(buf, 8));
77     (void)printf("getub: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
78 		 (uint64_t) ub1, (uint64_t) ub2,
79 		 (uint64_t) getub(buf, 0), (uint64_t) getub(buf, 8));
80     (void)printf("getles16: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
81 		 (uint64_t) sw1, (uint64_t) sw2,
82 		 (uint64_t) getles16(buf, 0), (uint64_t) getles16(buf, 8));
83     (void)printf("getleu16: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
84 		 (uint64_t) uw1, (uint64_t) uw2,
85 		 (uint64_t) getleu16(buf, 0), (uint64_t) getleu16(buf, 8));
86     (void)printf("getles32: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
87 		 (uint64_t) sl1, (uint64_t) sl2,
88 		 (uint64_t) getles32(buf, 0), (uint64_t) getles32(buf, 8));
89     (void)printf("getleu32: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
90 		 (uint64_t) ul1, (uint64_t) ul2,
91 		 (uint64_t) getleu32(buf, 0), (uint64_t) getleu32(buf, 8));
92     (void)printf("getles64: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
93 		 (uint64_t) sL1, (uint64_t) sL2,
94 		 (uint64_t) getles64(buf, 0), (uint64_t) getles64(buf, 8));
95     (void)printf("getleu64: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n",
96 		 (uint64_t) uL1, (uint64_t) uL2,
97 		 (uint64_t) getleu64(buf, 0), (uint64_t) getleu64(buf, 8));
98     (void)printf("getlef32: %f %f\n", f1, getlef32((const char *)buf, 24));
99     (void)printf("getled64: %.16f %.16f\n", d1, getled64((const char *)buf, 16));
100 }
101 
102 struct unsigned_test
103 {
104     unsigned char *buf;
105     unsigned int start, width;
106     uint64_t expected;
107     bool le;
108     char *description;
109 };
110 
main(int argc,char * argv[])111 int main(int argc, char *argv[])
112 {
113     bool failures = false;
114     bool quiet = (argc > 1) && (strcmp(argv[1], "--quiet") == 0);
115 
116     struct unsigned_test *up, unsigned_tests[] = {
117 	/* tests using the big buffer */
118 	{buf, 0,  1,  0,    false, "first bit of first byte"},
119 	{buf, 0,  8,  0x01, false, "first 8 bits"},
120 	{buf, 32, 7,  0x02, false, "first seven bits of fifth byte (0x05)"},
121 	{buf, 56, 12, 0x8f, false, "12 bits crossing 7th to 8th bytes (0x08ff)"},
122 	{buf, 78, 4,  0xb, false, "4 bits crossing 8th to 9th byte (0xfefd)"},
123 	{buf, 0,  1,  0,    true,  "first bit of first byte"},
124 	{buf, 0,  8,  0x80, true,  "first 8 bits"},
125 	{buf, 32, 7,  0x20, true, "first seven bits of fifth byte (0x05)"},
126 	{buf, 56, 12, 0xf10,true, "12 bits crossing 7th to 8th bytes (0x08ff)"},
127 	{buf, 78, 4,  0xd,  true, "4 bits crossing 8th to 9th byte (0xfefd)"},
128 	/* sporadic tests based on found bugs */
129 	{(unsigned char *)"\x19\x23\f6",
130 	 7, 2, 2, false, "2 bits crossing 1st to 2nd byte (0x1923)"},
131     };
132 
133     memcpy(buf, "\x01\x02\x03\x04\x05\x06\x07\x08", 8);
134     memcpy(buf + 8, "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8", 8);
135     memcpy(buf + 16, "\x40\x09\x21\xfb\x54\x44\x2d\x18", 8);
136     memcpy(buf + 24, "\x40\x49\x0f\xdb", 4);
137 
138     if (!quiet)
139 	(void)printf("Testing bitfield extraction\n");
140 
141     sb1 = getsb(buf, 0);
142     sb2 = getsb(buf, 8);
143     ub1 = getub(buf, 0);
144     ub2 = getub(buf, 8);
145 
146     if (!quiet) {
147 	unsigned char *sp;
148 
149 	(void)fputs("Test data:", stdout);
150 	for (sp = buf; sp < buf + 28; sp++)
151 	    (void)printf(" %02x", *sp);
152 	(void)putc('\n', stdout);
153 
154 	/* big-endian test */
155 	printf("Big-endian:\n");
156 	sw1 = getbes16(buf, 0);
157 	sw2 = getbes16(buf, 8);
158 	uw1 = getbeu16(buf, 0);
159 	uw2 = getbeu16(buf, 8);
160 	sl1 = getbes32(buf, 0);
161 	sl2 = getbes32(buf, 8);
162 	ul1 = getbeu32(buf, 0);
163 	ul2 = getbeu32(buf, 8);
164 	sL1 = getbes64(buf, 0);
165 	sL2 = getbes64(buf, 8);
166 	uL1 = getbeu64(buf, 0);
167 	uL2 = getbeu64(buf, 8);
168 	f1 = getbef32((const char *)buf, 24);
169 	d1 = getbed64((const char *)buf, 16);
170 	bedumpall();
171 
172 	/* little-endian test */
173 	printf("Little-endian:\n");
174 	sw1 = getles16(buf, 0);
175 	sw2 = getles16(buf, 8);
176 	uw1 = getleu16(buf, 0);
177 	uw2 = getleu16(buf, 8);
178 	sl1 = getles32(buf, 0);
179 	sl2 = getles32(buf, 8);
180 	ul1 = getleu32(buf, 0);
181 	ul2 = getleu32(buf, 8);
182 	sL1 = getles64(buf, 0);
183 	sL2 = getles64(buf, 8);
184 	uL1 = getleu64(buf, 0);
185 	uL2 = getleu64(buf, 8);
186 	f1 = getlef32((const char *)buf, 24);
187 	d1 = getled64((const char *)buf, 16);
188 	ledumpall();
189     }
190 
191     if (sb1 != 1)  printf("getsb(buf, 0) FAILED\n");
192     if (sb2 != -1) printf("getsb(buf, 8) FAILED\n");
193     if (ub1 != 1)  printf("getub(buf, 0) FAILED\n");
194     if (ub2 != 0xff) printf("getub(buf, 8) FAILED\n");
195 
196     for (up = unsigned_tests;
197 	 up <
198 	 unsigned_tests + sizeof(unsigned_tests) / sizeof(unsigned_tests[0]);
199 	 up++) {
200 	uint64_t res = ubits((unsigned char *)buf, up->start, up->width, up->le);
201 	bool success = (res == up->expected);
202 	if (!success)
203 	    failures = true;
204 	if (!success || !quiet)
205 	    (void)printf("ubits(%s, %d, %d, %s) %s should be %" PRIx64 ", is %" PRIx64 ": %s\n",
206 			 hexdump(buf, strlen((char *)buf)),
207 			 up->start, up->width, up->le ? "true" : "false",
208 			 up->description, up->expected, res,
209 			 success ? "succeeded" : "FAILED");
210     }
211 
212 
213     shiftleft(buf, 28, 30);
214     if (!quiet)
215 	printf("Left-shifted 30 bits: %s\n", hexdump(buf, 28));
216     /*
217      * After the 24-bit shift, the bit array loses its first three bytes:
218      * 0x0405060708 = 00000100 00000101 00000110 00000111 00001000
219      * By inspection, the results of the 6-bit shift are
220      * 00000001 01000001 10000001 11000010 00
221      */
222 #define LASSERT(n, v) if (buf[n] != v) printf("Expected buf[%d] to be %02x, was %02x\n", n, v, buf[n])
223     LASSERT(0, 0x01);
224     LASSERT(1, 0x41);
225     LASSERT(2, 0x81);
226     LASSERT(3, 0xc1);
227 #undef LASSERT
228 
229 
230     exit(failures ? EXIT_FAILURE : EXIT_SUCCESS);
231 
232 }
233 
234