1 /*  test/hts_endian.c -- hts_endian.h unit tests
2 
3     Copyright (C) 2017 Genome Research Ltd.
4 
5     Author: Rob Davies <rmd@sanger.ac.uk>
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.  */
23 
24 #include <config.h>
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdint.h>
30 #include <inttypes.h>
31 
32 #include "../htslib/hts_endian.h"
33 
34 typedef struct {
35     uint8_t u8[2];
36     uint8_t u8_unaligned[3];
37     int16_t  i16;
38     uint16_t u16;
39 } Test16;
40 
41 typedef struct {
42     uint8_t u8[4];
43     uint8_t u8_unaligned[5];
44     int32_t  i32;
45     uint32_t u32;
46 } Test32;
47 
48 typedef struct {
49     uint8_t u8[8];
50     uint8_t u8_unaligned[9];
51     int64_t  i64;
52     uint64_t u64;
53 } Test64;
54 
55 typedef struct {
56     uint8_t u8[4];
57     uint8_t u8_unaligned[5];
58     float f;
59 } Test_float;
60 
61 typedef struct {
62     uint8_t u8[8];
63     uint8_t u8_unaligned[9];
64     double d;
65 } Test_double;
66 
67 #define T16(b0, b1, sgn, unsgn) { { b0, b1 }, { 0x00, b0, b1 }, sgn, unsgn }
68 
69 Test16 tests_16_bit[] = {
70     T16(0x00, 0x00,      0,     0),
71     T16(0x01, 0x00,      1,     1),
72     T16(0x00, 0x01,    256,   256),
73     T16(0xff, 0x7f,  32767, 32767),
74     T16(0x00, 0x80, -32768, 32768),
75     T16(0xff, 0xff,     -1, 65535),
76 };
77 
78 #define T32(b0, b1, b2, b3, sgn, unsgn) { \
79      { b0, b1, b2, b3 },                  \
80      { 0x00, b0, b1, b2, b3 },            \
81      sgn, unsgn                           \
82 }
83 
84 Test32 tests_32_bit[] = {
85     T32(0x00, 0x00, 0x00, 0x00,           0,              0),
86     T32(0x01, 0x00, 0x00, 0x00,           1,              1),
87     T32(0x00, 0x01, 0x00, 0x00,         256,            256),
88     T32(0x00, 0x00, 0x01, 0x00,       65536,          65536),
89     T32(0xff, 0xff, 0xff, 0x7f,  2147483647,     2147483647),
90     // Odd coding of signed result below avoids a compiler warning
91     // as 2147483648 can't fit in a signed 32-bit number
92     T32(0x00, 0x00, 0x00, 0x80, -2147483647 - 1, 2147483648U),
93     T32(0xff, 0xff, 0xff, 0xff,          -1,     4294967295U),
94 };
95 
96 #define T64(b0, b1, b2, b3, b4, b5, b6, b7, sgn, unsgn) { \
97      { b0, b1, b2, b3, b4, b5, b6, b7 },                  \
98      { 0x00, b0, b1, b2, b3, b4, b5, b6, b7 },            \
99      sgn, unsgn                                           \
100 }
101 
102 
103 Test64 tests_64_bit[] = {
104     T64(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0),
105     T64(0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1, 1),
106     T64(0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 256, 256),
107     T64(0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 65536, 65536),
108     T64(0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 4294967296LL, 4294967296ULL),
109     T64(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
110         9223372036854775807LL, 9223372036854775807ULL),
111     // Odd coding of signed result below avoids a compiler warning
112     // as 9223372036854775808 can't fit in a signed 64-bit number
113     T64(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
114         -9223372036854775807LL - 1LL, 9223372036854775808ULL),
115     T64(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
116         -1, 18446744073709551615ULL),
117 };
118 
119 #define TF(b0, b1, b2, b3, f) { { b0, b1, b2, b3 }, { 0x00, b0, b1, b2, b3}, f }
120 
121 Test_float tests_float[] = {
122     TF(0x00, 0x00, 0x00, 0x00,  0.0f),
123     TF(0x00, 0x00, 0x80, 0x3f,  1.0f),
124     TF(0x00, 0x00, 0x80, 0xbf, -1.0f),
125     TF(0x00, 0x00, 0x20, 0x41, 10.0f),
126     TF(0xd0, 0x0f, 0x49, 0x40,  3.14159f),
127     TF(0xa8, 0x0a, 0xff, 0x66,  6.022e23f),
128     TF(0xcd, 0x84, 0x03, 0x13,  1.66e-27f),
129 };
130 
131 #define TD(b0, b1, b2, b3, b4, b5, b6, b7, d) { \
132     { b0, b1, b2, b3, b4, b5, b6, b7 },         \
133     { 0x00, b0, b1, b2, b3, b4, b5, b6, b7 },   \
134     d                                           \
135 }
136 
137 Test_double tests_double[] = {
138     TD(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0.0),
139     TD(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f,  1.0),
140     TD(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xbf, -1.0),
141     TD(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 10.0),
142     TD(0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40,  3.141592653589793),
143     TD(0x2b, 0x08, 0x0c, 0xd3, 0x85, 0xe1, 0xdf, 0x44,  6.022140858e23),
144     TD(0x55, 0xfa, 0x81, 0x74, 0xf7, 0x71, 0x60, 0x3a,  1.66053904e-27),
145 };
146 
147 #define NELE(x) (sizeof(x)/sizeof(x[0]))
148 
to_hex(uint8_t * buf,int len)149 static char * to_hex(uint8_t *buf, int len) {
150     static char str[64];
151     int i, o;
152 
153     for (i = 0, o = 0; i < len; i++, o += 3) {
154         snprintf(str + o, sizeof(str) - o, "%02x ", buf[i]);
155     }
156     return str;
157 }
158 
t16_bit(int verbose)159 static int t16_bit(int verbose) {
160     uint8_t buf[9];
161     size_t i;
162     int errors = 0;
163 
164     for (i = 0; i < NELE(tests_16_bit); i++) {
165         uint16_t u16;
166         int16_t  i16;
167 
168         if (verbose) {
169             fprintf(stderr, "%s %6"PRId16" %6"PRId16"\n",
170                     to_hex(tests_16_bit[i].u8, 2),
171                     tests_16_bit[i].i16, tests_16_bit[i].u16);
172         }
173 
174         u16 = le_to_u16(tests_16_bit[i].u8);
175         if (u16 != tests_16_bit[i].u16) {
176             fprintf(stderr, "Failed %s => %"PRIu16"; expected %"PRIu16"\n",
177                     to_hex(tests_16_bit[i].u8, 2), u16, tests_16_bit[i].u16);
178             errors++;
179         }
180 
181         i16 = le_to_i16(tests_16_bit[i].u8);
182         if (i16 != tests_16_bit[i].i16) {
183             fprintf(stderr, "Failed %s => %"PRId16"; expected %"PRId16"\n",
184                     to_hex(tests_16_bit[i].u8, 2), i16, tests_16_bit[i].i16);
185             errors++;
186         }
187 
188         u16 = le_to_u16(tests_16_bit[i].u8_unaligned + 1);
189         if (u16 != tests_16_bit[i].u16) {
190             fprintf(stderr,
191                     "Failed unaligned %s => %"PRIu16"; expected %"PRIu16"\n",
192                     to_hex(tests_16_bit[i].u8_unaligned + 1, 2),
193                     u16, tests_16_bit[i].u16);
194             errors++;
195         }
196 
197         i16 = le_to_i16(tests_16_bit[i].u8_unaligned + 1);
198         if (i16 != tests_16_bit[i].i16) {
199             fprintf(stderr,
200                     "Failed unaligned %s => %"PRId16"; expected %"PRId16"\n",
201                     to_hex(tests_16_bit[i].u8_unaligned + 1, 2),
202                     i16, tests_16_bit[i].i16);
203             errors++;
204         }
205 
206         u16_to_le(tests_16_bit[i].u16, buf);
207         if (memcmp(buf, tests_16_bit[i].u8, 2) != 0) {
208             fprintf(stderr, "Failed %"PRIu16" => %s; expected %s\n",
209                     tests_16_bit[i].u16,
210                     to_hex(buf, 2), to_hex(tests_16_bit[i].u8, 2));
211             errors++;
212         }
213 
214         i16_to_le(tests_16_bit[i].i16, buf);
215         if (memcmp(buf, tests_16_bit[i].u8, 2) != 0) {
216             fprintf(stderr, "Failed %"PRId16" => %s; expected %s\n",
217                     tests_16_bit[i].i16,
218                     to_hex(buf, 2), to_hex(tests_16_bit[i].u8, 2));
219             errors++;
220         }
221 
222         u16_to_le(tests_16_bit[i].u16, buf + 1);
223         if (memcmp(buf + 1, tests_16_bit[i].u8, 2) != 0) {
224             fprintf(stderr, "Failed unaligned %"PRIu16" => %s; expected %s\n",
225                     tests_16_bit[i].u16,
226                     to_hex(buf + 1, 2), to_hex(tests_16_bit[i].u8, 2));
227             errors++;
228         }
229 
230         i16_to_le(tests_16_bit[i].i16, buf + 1);
231         if (memcmp(buf + 1, tests_16_bit[i].u8, 2) != 0) {
232             fprintf(stderr, "Failed unaligned %"PRId16" => %s; expected %s\n",
233                     tests_16_bit[i].i16,
234                     to_hex(buf + 1, 2), to_hex(tests_16_bit[i].u8, 2));
235             errors++;
236         }
237     }
238 
239     return errors;
240 }
241 
t32_bit(int verbose)242 static int t32_bit(int verbose) {
243     uint8_t buf[9];
244     size_t i;
245     int errors = 0;
246 
247     for (i = 0; i < NELE(tests_32_bit); i++) {
248         uint32_t u32;
249         int32_t  i32;
250 
251         if (verbose) {
252             fprintf(stderr, "%s %11"PRId32" %11"PRIu32"\n",
253                     to_hex(tests_32_bit[i].u8, 4),
254                     tests_32_bit[i].i32, tests_32_bit[i].u32);
255         }
256 
257         u32 = le_to_u32(tests_32_bit[i].u8);
258         if (u32 != tests_32_bit[i].u32) {
259             fprintf(stderr, "Failed %s => %"PRIu32"; expected %"PRIu32"\n",
260                     to_hex(tests_32_bit[i].u8, 4), u32, tests_32_bit[i].u32);
261             errors++;
262         }
263         i32 = le_to_i32(tests_32_bit[i].u8);
264         if (i32 != tests_32_bit[i].i32) {
265             fprintf(stderr, "Failed %s => %"PRId32"; expected %"PRId32"\n",
266                     to_hex(tests_32_bit[i].u8, 4), i32, tests_32_bit[i].i32);
267             errors++;
268         }
269 
270         u32 = le_to_u32(tests_32_bit[i].u8_unaligned + 1);
271         if (u32 != tests_32_bit[i].u32) {
272             fprintf(stderr,
273                     "Failed unaligned %s => %"PRIu32"; expected %"PRIu32"\n",
274                     to_hex(tests_32_bit[i].u8_unaligned + 1, 4),
275                     u32, tests_32_bit[i].u32);
276             errors++;
277         }
278         i32 = le_to_i32(tests_32_bit[i].u8_unaligned + 1);
279         if (i32 != tests_32_bit[i].i32) {
280             fprintf(stderr,
281                     "Failed unaligned %s => %"PRId32"; expected %"PRId32"\n",
282                     to_hex(tests_32_bit[i].u8_unaligned + 1, 4),
283                     i32, tests_32_bit[i].i32);
284             errors++;
285         }
286 
287         u32_to_le(tests_32_bit[i].u32, buf);
288         if (memcmp(buf, tests_32_bit[i].u8, 4) != 0) {
289             fprintf(stderr, "Failed %"PRIu32" => %s; expected %s\n",
290                     tests_32_bit[i].u32,
291                     to_hex(buf, 4), to_hex(tests_32_bit[i].u8, 4));
292             errors++;
293         }
294 
295         i32_to_le(tests_32_bit[i].i32, buf);
296         if (memcmp(buf, tests_32_bit[i].u8, 4) != 0) {
297             fprintf(stderr, "Failed %"PRId32" => %s; expected %s\n",
298                     tests_32_bit[i].i32,
299                     to_hex(buf, 4), to_hex(tests_32_bit[i].u8, 4));
300             errors++;
301         }
302 
303         u32_to_le(tests_32_bit[i].u32, buf + 1);
304         if (memcmp(buf + 1, tests_32_bit[i].u8, 4) != 0) {
305             fprintf(stderr, "Failed unaligned %"PRIu32" => %s; expected %s\n",
306                     tests_32_bit[i].u32,
307                     to_hex(buf + 1, 4), to_hex(tests_32_bit[i].u8, 4));
308             errors++;
309         }
310 
311         i32_to_le(tests_32_bit[i].i32, buf + 1);
312         if (memcmp(buf + 1, tests_32_bit[i].u8, 4) != 0) {
313             fprintf(stderr, "Failed unaligned %"PRId32" => %s; expected %s\n",
314                     tests_32_bit[i].i32,
315                     to_hex(buf + 1, 4), to_hex(tests_32_bit[i].u8, 4));
316             errors++;
317         }
318     }
319 
320     return errors;
321 }
322 
t64_bit(int verbose)323 static int t64_bit(int verbose) {
324     uint8_t buf[9];
325     size_t i;
326     int errors = 0;
327 
328     for (i = 0; i < NELE(tests_64_bit); i++) {
329         uint64_t u64;
330         int64_t  i64;
331 
332         if (verbose) {
333             fprintf(stderr, "%s %20"PRId64" %20"PRIu64"\n",
334                     to_hex(tests_64_bit[i].u8, 8),
335                     tests_64_bit[i].i64, tests_64_bit[i].u64);
336         }
337 
338         u64 = le_to_u64(tests_64_bit[i].u8);
339         if (u64 != tests_64_bit[i].u64) {
340             fprintf(stderr, "Failed %s => %"PRIu64"; expected %"PRIu64"\n",
341                     to_hex(tests_64_bit[i].u8, 8), u64, tests_64_bit[i].u64);
342             errors++;
343         }
344 
345         i64 = le_to_i64(tests_64_bit[i].u8);
346         if (i64 != tests_64_bit[i].i64) {
347             fprintf(stderr, "Failed %s => %"PRId64"; expected %"PRId64"\n",
348                     to_hex(tests_64_bit[i].u8, 8), i64, tests_64_bit[i].i64);
349             errors++;
350         }
351 
352         u64 = le_to_u64(tests_64_bit[i].u8_unaligned + 1);
353         if (u64 != tests_64_bit[i].u64) {
354             fprintf(stderr,
355                     "Failed unaligned %s => %"PRIu64"; expected %"PRIu64"\n",
356                     to_hex(tests_64_bit[i].u8_unaligned + 1, 8),
357                     u64, tests_64_bit[i].u64);
358             errors++;
359         }
360 
361         i64 = le_to_i64(tests_64_bit[i].u8_unaligned + 1);
362         if (i64 != tests_64_bit[i].i64) {
363             fprintf(stderr,
364                     "Failed unaligned %s => %"PRId64"; expected %"PRId64"\n",
365                     to_hex(tests_64_bit[i].u8_unaligned + 1, 8),
366                     i64, tests_64_bit[i].i64);
367             errors++;
368         }
369 
370         u64_to_le(tests_64_bit[i].u64, buf);
371         if (memcmp(buf, tests_64_bit[i].u8, 8) != 0) {
372             fprintf(stderr, "Failed %"PRIu64" => %s; expected %s\n",
373                     tests_64_bit[i].u64,
374                     to_hex(buf, 8), to_hex(tests_64_bit[i].u8, 8));
375             errors++;
376         }
377 
378         i64_to_le(tests_64_bit[i].i64, buf);
379         if (memcmp(buf, tests_64_bit[i].u8, 8) != 0) {
380             fprintf(stderr, "Failed %"PRId64" => %s; expected %s\n",
381                     tests_64_bit[i].i64,
382                     to_hex(buf, 8), to_hex(tests_64_bit[i].u8, 8));
383             errors++;
384         }
385 
386         u64_to_le(tests_64_bit[i].u64, buf + 1);
387         if (memcmp(buf + 1, tests_64_bit[i].u8, 8) != 0) {
388             fprintf(stderr, "Failed unaligned %"PRIu64" => %s; expected %s\n",
389                     tests_64_bit[i].u64,
390                     to_hex(buf + 1, 8), to_hex(tests_64_bit[i].u8, 8));
391             errors++;
392         }
393 
394         i64_to_le(tests_64_bit[i].i64, buf + 1);
395         if (memcmp(buf + 1, tests_64_bit[i].u8, 8) != 0) {
396             fprintf(stderr, "Failed unaligned %"PRId64" => %s; expected %s\n",
397                     tests_64_bit[i].i64,
398                     to_hex(buf + 1, 8), to_hex(tests_64_bit[i].u8, 8));
399             errors++;
400         }
401     }
402 
403     return errors;
404 }
405 
t_float(int verbose)406 int t_float(int verbose) {
407     uint8_t buf[9];
408     size_t i;
409     int errors = 0;
410 
411     for (i = 0; i < NELE(tests_float); i++) {
412         float f;
413 
414         if (verbose) {
415             fprintf(stderr, "%s %g\n",
416                     to_hex(tests_float[i].u8, 4), tests_float[i].f);
417         }
418 
419         f = le_to_float(tests_float[i].u8);
420         if (f != tests_float[i].f) {
421             fprintf(stderr, "Failed %s => %g; expected %g\n",
422                     to_hex(tests_float[i].u8, 4), f, tests_float[i].f);
423             errors++;
424         }
425 
426         f = le_to_float(tests_float[i].u8_unaligned + 1);
427         if (f != tests_float[i].f) {
428             fprintf(stderr, "Failed unaligned %s => %g; expected %g\n",
429                     to_hex(tests_float[i].u8_unaligned + 1, 4),
430                     f, tests_float[i].f);
431             errors++;
432         }
433 
434         float_to_le(tests_float[i].f, buf);
435         if (memcmp(tests_float[i].u8, buf, 4) != 0) {
436             fprintf(stderr, "Failed %g => %s; expected %s\n",
437                     tests_float[i].f,
438                     to_hex(buf, 4), to_hex(tests_float[i].u8, 4));
439         }
440 
441         float_to_le(tests_float[i].f, buf + 1);
442         if (memcmp(tests_float[i].u8, buf + 1, 4) != 0) {
443             fprintf(stderr, "Failed unaligned %g => %s; expected %s\n",
444                     tests_float[i].f,
445                     to_hex(buf + 1, 4), to_hex(tests_float[i].u8, 4));
446         }
447     }
448     return errors;
449 }
450 
t_double(int verbose)451 int t_double(int verbose) {
452     uint8_t buf[9];
453     size_t i;
454     int errors = 0;
455 
456     for (i = 0; i < NELE(tests_double); i++) {
457         double f;
458 
459         if (verbose) {
460             fprintf(stderr, "%s %.15g\n",
461                     to_hex(tests_double[i].u8, 8), tests_double[i].d);
462         }
463 
464         f = le_to_double(tests_double[i].u8);
465         if (f != tests_double[i].d) {
466             fprintf(stderr, "Failed %s => %.15g; expected %.15g\n",
467                     to_hex(tests_double[i].u8, 8), f, tests_double[i].d);
468             errors++;
469         }
470 
471         f = le_to_double(tests_double[i].u8_unaligned + 1);
472         if (f != tests_double[i].d) {
473             fprintf(stderr, "Failed unaligned %s => %.15g; expected %.15g\n",
474                     to_hex(tests_double[i].u8_unaligned + 1, 8),
475                     f, tests_double[i].d);
476             errors++;
477         }
478 
479         double_to_le(tests_double[i].d, buf);
480         if (memcmp(tests_double[i].u8, buf, 8) != 0) {
481             fprintf(stderr, "Failed %.15g => %s; expected %s\n",
482                     tests_double[i].d,
483                     to_hex(buf, 8), to_hex(tests_double[i].u8, 8));
484         }
485 
486         double_to_le(tests_double[i].d, buf + 1);
487         if (memcmp(tests_double[i].u8, buf + 1, 8) != 0) {
488             fprintf(stderr, "Failed unaligned %.15g => %s; expected %s\n",
489                     tests_double[i].d,
490                     to_hex(buf + 1, 8), to_hex(tests_double[i].u8, 8));
491         }
492     }
493     return errors;
494 }
495 
main(int argc,char ** argv)496 int main(int argc, char **argv) {
497     int verbose = 0;
498     int errors = 0;
499 
500     if (argc > 1 && strcmp(argv[1], "-v") == 0) verbose = 1;
501 
502     errors += t16_bit(verbose);
503     errors += t32_bit(verbose);
504     errors += t64_bit(verbose);
505     errors += t_float(verbose);
506     errors += t_double(verbose);
507     if (errors) {
508         fprintf(stderr, "%d errors\n", errors);
509         return EXIT_FAILURE;
510     }
511 
512     return EXIT_SUCCESS;
513 }
514