1 /*
2 * Unit test for timespec's
3 *
4 * This file is Copyright (c) 2010 by the GPSD project
5 * SPDX-License-Identifier: BSD-2-clause
6 *
7 */
8 /* first so the #defs work */
9 #include "../gpsd_config.h"
10
11 #include <math.h>
12 #include <stdbool.h>
13 #include <stdint.h> /* required by C99, for int32_t */
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19
20 #include "../gpsd.h"
21 #include "../revision.h"
22
23 #define TS_ZERO {0,0}
24 #define TS_ZERO_ONE {0,1}
25 #define TS_ZERO_TWO {0,2}
26 #define TS_ZERO_TREES {0,333333333}
27 #define TS_ZERO_SIXS7 {0,666666667}
28 #define TS_ZERO_NINES {0,999999999}
29 #define TS_ONE {1,0}
30 #define TS_ONE_ONE {1,1}
31 #define TS_TWO {2,0}
32 #define TS_N_ZERO_ONE {0,-1}
33 #define TS_N_ZERO_TWO {0,-2}
34 #define TS_N_ZERO_TREES {0,-333333333}
35 #define TS_N_ZERO_NINES {0,-999999999}
36 #define TS_N_ONE {-1,0}
37
38 /* minutes, hours, days */
39 #define TS_ONEM {60,0} /* one minute */
40 #define TS_ONEM_TREES {60,333333333} /* one minute, threes */
41 #define TS_ONEM_NINES {60,999999999} /* one minute, nines */
42 #define TS_ONEH {3600,0} /* one hour */
43 #define TS_ONEH_TREES {3600,333333333} /* one hour, threes */
44 #define TS_ONEH_NINES {3600,999999999} /* one hour, nines */
45 #define TS_ONED {86400,0} /* one day */
46 #define TS_ONED_TREES {86400,333333333} /* one day, threes */
47 #define TS_ONED_NINES {86400,999999999} /* one day, nines */
48 #define TS_N_ONEM {-60,0} /* negative one minute */
49 #define TS_N_ONEH {-3600,0} /* negative one hour */
50 #define TS_N_ONED {-86400,0} /* negative one day */
51
52 /* Dec 31, 23:59 2037 GMT */
53 #define TS_2037 {2145916799, 0}
54 #define TS_2037_ONE {2145916799, 1}
55 #define TS_2037_TWO {2145916799, 2}
56 #define TS_2037_X {2145916799, 123456789}
57 #define TS_2037_TREES {2145916799, 333333333}
58 #define TS_2037_SIXS7 {2145916799, 666666667}
59 #define TS_2037_NINES {2145916799, 999999999}
60 #define TS_N_2037_TREES {-2145916799, -333333333}
61 #define TS_N_2037_NINES {-2145916799, -999999999}
62
63 /* a 32 bit copy of timespec_diff_ns() to force a 32 bit int */
64 /* used to demonstrate how 32 bit longs can not work */
65 #define timespec_diff_ns32(x, y) \
66 (int32_t)((int32_t)(((x).tv_sec-(y).tv_sec)*NS_IN_SEC)+(x).tv_nsec-(y).tv_nsec)
67
68 /* a 64 bit copy of timespec_diff_ns() to force a 64 bit int */
69 /* used to demonstrate how 64 bit long longs can work */
70 #define timespec_diff_ns64(x, y) \
71 (int64_t)((int64_t)(((x).tv_sec-(y).tv_sec)*NS_IN_SEC)+(x).tv_nsec-(y).tv_nsec)
72
73 /* convert long long ns to a timespec */
74 #define ns_to_timespec(ts, ns) \
75 (ts).tv_sec = ns / NS_IN_SEC; \
76 (ts).tv_nsec = ns % NS_IN_SEC;
77
78 /* convert double to a timespec */
d_str(const double d,char * buf,size_t buf_size)79 static inline void d_str( const double d, char *buf, size_t buf_size)
80 {
81 /* convert to string */
82 if ( 0 <= d ) {
83 (void) snprintf( buf, buf_size, " %.9f", d);
84 } else {
85 (void) snprintf( buf, buf_size, "%.9f", d);
86 }
87 }
88
89 /* a - b should be c */
90 struct subtract_test {
91 struct timespec a;
92 struct timespec b;
93 struct timespec c;
94 bool last; /* last test marker */
95 };
96
97 struct subtract_test subtract_tests[] = {
98 { TS_ZERO, TS_ZERO, TS_ZERO, 0},
99 { TS_ONE, TS_ONE, TS_ZERO, 0},
100 { TS_ZERO_ONE, TS_ZERO_ONE, TS_ZERO, 0},
101 { TS_ONE_ONE, TS_ONE_ONE, TS_ZERO, 0},
102 { TS_N_ONE, TS_N_ONE, TS_ZERO, 0},
103 { TS_N_ZERO_ONE, TS_N_ZERO_ONE, TS_ZERO, 0},
104 { TS_ZERO_TREES, TS_ZERO_TREES, TS_ZERO, 0},
105 { TS_ZERO_NINES, TS_ZERO_NINES, TS_ZERO, 0},
106 { TS_ZERO_TREES, TS_ZERO, TS_ZERO_TREES, 0},
107 { TS_ZERO, TS_N_ONE, TS_ONE, 0},
108 { TS_ONE, TS_ZERO, TS_ONE, 0},
109 { TS_TWO, TS_ONE, TS_ONE, 0},
110 { TS_ONE_ONE, TS_ONE, TS_ZERO_ONE, 0},
111 { TS_ONE, TS_ZERO_TREES, TS_ZERO_SIXS7, 0},
112 { TS_ONE, TS_ZERO_NINES, TS_ZERO_ONE, 0},
113 { TS_ZERO_TWO, TS_ZERO_ONE, TS_ZERO_ONE, 0},
114 { TS_2037_ONE, TS_2037, TS_ZERO_ONE, 0},
115 { TS_ONE_ONE, TS_ZERO_NINES, TS_ZERO_TWO, 0},
116 { TS_ONEM, TS_ZERO, TS_ONEM, 0},
117 { TS_ONEM_TREES, TS_ZERO, TS_ONEM_TREES, 0},
118 { TS_ONEM_NINES, TS_ZERO, TS_ONEM_NINES, 0},
119 { TS_ZERO, TS_ONEM, TS_N_ONEM, 0},
120 { TS_ONEH, TS_ZERO, TS_ONEH, 0},
121 { TS_ONEH_TREES, TS_ZERO, TS_ONEH_TREES, 0},
122 { TS_ONEH_NINES, TS_ZERO, TS_ONEH_NINES, 0},
123 { TS_ZERO, TS_ONEH, TS_N_ONEH, 0},
124 { TS_ONED, TS_ZERO, TS_ONED, 0},
125 { TS_ONED_TREES, TS_ZERO, TS_ONED_TREES, 0},
126 { TS_ONED_NINES, TS_ZERO, TS_ONED_NINES, 0},
127 { TS_ZERO, TS_ONED, TS_N_ONED, 0},
128 { TS_2037_NINES, TS_2037, TS_ZERO_NINES, 0},
129 { TS_2037_TREES, TS_ZERO, TS_2037_TREES, 0},
130 { TS_2037_SIXS7, TS_2037, TS_ZERO_SIXS7, 0},
131 { TS_2037_TREES, TS_2037, TS_ZERO_TREES, 0},
132 { TS_2037_NINES, TS_ZERO, TS_2037_NINES, 0},
133 { TS_ZERO, TS_ONE, TS_N_ONE, 0},
134 { TS_ONE, TS_TWO, TS_N_ONE, 0},
135 { TS_ZERO, TS_ZERO_ONE, TS_N_ZERO_ONE, 0},
136 { TS_ONE, TS_ONE_ONE, TS_N_ZERO_ONE, 0},
137 { TS_ZERO_ONE, TS_ZERO_TWO, TS_N_ZERO_ONE, 0},
138 { TS_2037, TS_2037_ONE, TS_N_ZERO_ONE, 0},
139 { TS_ZERO_NINES, TS_ONE_ONE, TS_N_ZERO_TWO, 0},
140 { TS_2037, TS_2037_NINES, TS_N_ZERO_NINES, 0},
141 { TS_ZERO, TS_2037_NINES, TS_N_2037_NINES, 1},
142 };
143
144 typedef struct format_test {
145 struct timespec input;
146 char *expected;
147 bool last;
148 } format_test_t;
149
150 struct format_test format_tests[] = {
151 { TS_ZERO, " 0.000000000", 0},
152 { TS_ZERO_ONE, " 0.000000001", 0},
153 { TS_ZERO_TWO, " 0.000000002", 0},
154 { TS_ZERO_NINES, " 0.999999999", 0},
155 { TS_ONE, " 1.000000000", 0},
156 { TS_ONE_ONE, " 1.000000001", 0},
157 { TS_TWO, " 2.000000000", 0},
158 { TS_N_ZERO_ONE, "-0.000000001", 0},
159 { TS_N_ZERO_TWO, "-0.000000002", 0},
160 { TS_N_ZERO_NINES, "-0.999999999", 0},
161 { TS_N_ONE, "-1.000000000", 0},
162 { TS_ONEM, " 60.000000000", 0},
163 { TS_ONEM_TREES, " 60.333333333", 0},
164 { TS_ONEH, " 3600.000000000", 0},
165 { TS_ONEH_TREES, " 3600.333333333", 0},
166 { TS_ONED, " 86400.000000000", 0},
167 { TS_ONED_TREES, " 86400.333333333", 0},
168 { TS_N_ONEM, "-60.000000000", 0},
169 { TS_N_ONEH, "-3600.000000000", 0},
170 { TS_N_ONED, "-86400.000000000", 0},
171 { { -1, 1}, "-1.000000001", 0},
172 { { -1, -1}, "-1.000000001", 0},
173 { TS_2037, " 2145916799.000000000", 0},
174 { TS_2037_ONE, " 2145916799.000000001", 0},
175 { TS_2037_TREES, " 2145916799.333333333", 1},
176 { TS_2037_NINES, " 2145916799.999999999", 1},
177 };
178
179 /*
180 * test subtractions using native timespec math: TS_SUB()
181 *
182 */
test_ts_subtract(int verbose)183 static int test_ts_subtract( int verbose )
184 {
185 struct subtract_test *p = subtract_tests;
186 int fail_count = 0;
187
188 while ( 1 ) {
189 char buf_a[TIMESPEC_LEN];
190 char buf_b[TIMESPEC_LEN];
191 char buf_c[TIMESPEC_LEN];
192 char buf_r[TIMESPEC_LEN];
193 struct timespec r;
194
195 TS_SUB(&r, &p->a, &p->b);
196 timespec_str( &p->a, buf_a, sizeof(buf_a) );
197 timespec_str( &p->b, buf_b, sizeof(buf_b) );
198 timespec_str( &p->c, buf_c, sizeof(buf_c) );
199 timespec_str( &r, buf_r, sizeof(buf_r) );
200 if ( (p->c.tv_sec != r.tv_sec) || (p->c.tv_nsec != r.tv_nsec) ) {
201 printf("%21s - %21s = %21s, FAIL s/b %21s\n",
202 buf_a, buf_b, buf_r, buf_c);
203 fail_count++;
204 } else if ( verbose ) {
205 printf("%21s - %21s = %21s\n", buf_a, buf_b, buf_r);
206 }
207
208
209 if ( p->last ) {
210 break;
211 }
212 p++;
213 };
214
215 if ( fail_count ) {
216 printf("timespec subtract test failed %d tests\n", fail_count );
217 } else {
218 puts("timespec subtract test succeeded\n");
219 }
220 return fail_count;
221 }
222
223 /*
224 * test subtractions using timespec_diff_ns()
225 *
226 */
test_ns_subtract(int verbose)227 static int test_ns_subtract( int verbose )
228 {
229 struct subtract_test *p = subtract_tests;
230 int fail_count = 0;
231
232 while ( 1 ) {
233 char buf_a[TIMESPEC_LEN];
234 char buf_b[TIMESPEC_LEN];
235 char buf_c[TIMESPEC_LEN];
236 char buf_r[TIMESPEC_LEN];
237 struct timespec r;
238 long long r_ns;
239
240 r_ns = timespec_diff_ns(p->a, p->b);
241 timespec_str( &p->a, buf_a, sizeof(buf_a) );
242 timespec_str( &p->b, buf_b, sizeof(buf_b) );
243 timespec_str( &p->c, buf_c, sizeof(buf_c) );
244 ns_to_timespec( r, r_ns);
245 timespec_str( &r, buf_r, sizeof(buf_r) );
246 if ( (p->c.tv_sec != r.tv_sec) || (p->c.tv_nsec != r.tv_nsec) ) {
247 printf("%21s - %21s = %21s, FAIL s/b %21s\n",
248 buf_a, buf_b, buf_r, buf_c);
249 fail_count++;
250 } else if ( verbose ) {
251 printf("%21s - %21s = %21s\n", buf_a, buf_b, buf_r);
252 }
253
254
255 if ( p->last ) {
256 break;
257 }
258 p++;
259 };
260
261 if ( fail_count ) {
262 printf("ns subtract test failed %d tests\n", fail_count );
263 } else {
264 puts("ns subtract test succeeded\n");
265 }
266 return fail_count;
267 }
268
test_format(int verbose)269 static int test_format(int verbose )
270 {
271 format_test_t *p = format_tests;
272 int fail_count = 0;
273
274 while ( 1 ) {
275 char buf[TIMESPEC_LEN];
276 int fail;
277
278 timespec_str( &p->input, buf, sizeof(buf) );
279 fail = strncmp( buf, p->expected, TIMESPEC_LEN);
280 if ( fail ) {
281 printf("%21s, FAIL s/b: %21s\n", buf, p->expected);
282 fail_count++;
283 } else if ( verbose ) {
284 printf("%21s\n", buf);
285 }
286
287 if ( p->last ) {
288 break;
289 }
290 p++;
291 };
292
293 if ( fail_count ) {
294 printf("timespec_str test failed %d tests\n", fail_count );
295 } else {
296 puts("timespec_str test succeeded\n");
297 }
298 return fail_count;
299 }
300
301 typedef struct {
302 unsigned short week;
303 int leap_seconds;
304 timespec_t ts_tow;
305 timespec_t ts_exp; // expected result
306 char *exp_s; // expected string
307 bool last;
308 } gpstime_test_t;
309
310 gpstime_test_t gpstime_tests[] = {
311 // GPS time zero
312 {0, 0, TS_ZERO, {315964800, 000000000}, "1980-01-06T00:00:00.000Z", 0},
313 // GPS first roll over
314 {1024, 7, TS_ZERO, {935279993, 000000000}, "1999-08-21T23:59:53.000Z", 0},
315 // GPS first roll over
316 {2048, 18, TS_ZERO, {1554595182, 000000000}, "2019-04-06T23:59:42.000Z", 0},
317 {2076, 18, {239910, 100000000}, {1571769492, 100000000},
318 "2019-10-22T18:38:12.100Z", 1},
319 };
320
test_gpsd_gpstime_resolv(int verbose)321 static int test_gpsd_gpstime_resolv(int verbose)
322 {
323
324 char res_s[128];
325 char buf[20];
326 int fail_count = 0;
327 struct gps_device_t session;
328 struct gps_context_t context;
329 timespec_t ts_res;
330 gpstime_test_t *p = gpstime_tests;
331
332 memset(&session, 0, sizeof(session));
333 memset(&context, 0, sizeof(context));
334 session.context = &context;
335 context.errout.debug = 0; // a handle to change debug level
336
337 while ( 1 ) {
338
339 /* setup preconditions */
340 context.gps_week = p->week;
341 context.leap_seconds = p->leap_seconds;
342 ts_res = gpsd_gpstime_resolv(&session, p->week, p->ts_tow);
343 (void)timespec_to_iso8601(ts_res, res_s, sizeof(res_s));
344
345 if (p->ts_exp.tv_sec != ts_res.tv_sec ||
346 p->ts_exp.tv_nsec != ts_res.tv_nsec ||
347 strcmp(res_s, p->exp_s) ) {
348 // long long for 32-bit OS
349 printf("FAIL %s s/b: %s\n"
350 " %s s/b %s\n",
351 timespec_str(&ts_res, buf, sizeof(buf)),
352 timespec_str(&p->ts_exp, buf, sizeof(buf)),
353 res_s, p->exp_s);
354 fail_count++;
355 } else if ( verbose ) {
356 printf("%s (%s)\n",
357 timespec_str(&p->ts_exp, buf, sizeof(buf)),
358 p->exp_s);
359 }
360 if ( p->last ) {
361 break;
362 }
363 p++;
364 }
365
366 if ( fail_count ) {
367 printf("test_gpsd_gpstime_resolv test failed %d tests\n", fail_count );
368 } else {
369 puts("test_gpsd_gpstime_resolv test succeeded\n");
370 }
371 return fail_count;
372 }
373
ex_subtract_float(void)374 static int ex_subtract_float(void)
375 {
376 struct subtract_test *p = subtract_tests;
377 int fail_count = 0;
378
379 printf( "\n\nsubtract test examples using doubles,floats,longs:\n"
380 " ts: TS_SUB()\n"
381 " l: timespec_to_ns() math\n"
382 " l32: timespec_to_ns() math with 32 bit long\n"
383 " l64: timespec_to_ns() math with 64 bit long\n"
384 " f: float math\n"
385 " d: double float math\n"
386 "\n");
387
388 while ( 1 ) {
389 char buf_a[TIMESPEC_LEN];
390 char buf_b[TIMESPEC_LEN];
391 char buf_c[TIMESPEC_LEN];
392 char buf_r[TIMESPEC_LEN];
393 char buf_l[TIMESPEC_LEN];
394 char buf_l32[TIMESPEC_LEN];
395 char buf_l64[TIMESPEC_LEN];
396 char buf_f[TIMESPEC_LEN];
397 char buf_d[TIMESPEC_LEN];
398 struct timespec ts_r;
399 struct timespec ts_l;
400 struct timespec ts_l32;
401 struct timespec ts_l64;
402 float f_a, f_b, f_r;
403 double d_a, d_b, d_r;
404 long long l;
405 int32_t l32; /* simulate a 32 bit long */
406 int64_t l64; /* simulate a 64 bit long */
407 const char *fail_ts = "";
408 const char *fail_l = "";
409 const char *fail_l32 = "";
410 const char *fail_l64 = "";
411 const char *fail_f = "";
412 const char *fail_d = "";
413
414 /* timespec math */
415 TS_SUB(&ts_r, &p->a, &p->b);
416
417 /* float math */
418 f_a = TSTONS( &p->a );
419 f_b = TSTONS( &p->b );
420 f_r = f_a - f_b;
421
422 /* double float math */
423 d_a = TSTONS( &p->a );
424 d_b = TSTONS( &p->b );
425 d_r = d_a - d_b;
426
427 /* long math */
428 l = timespec_diff_ns( p->a, p->b);
429 l32 = timespec_diff_ns32( p->a, p->b);
430 l64 = timespec_diff_ns64( p->a, p->b);
431
432 /* now convert to strings */
433 timespec_str( &p->a, buf_a, sizeof(buf_a) );
434 timespec_str( &p->b, buf_b, sizeof(buf_b) );
435 timespec_str( &p->c, buf_c, sizeof(buf_c) );
436 timespec_str( &ts_r, buf_r, sizeof(buf_r) );
437
438 ns_to_timespec( ts_l, l );
439 timespec_str( &ts_l, buf_l, sizeof(buf_l) );
440 ns_to_timespec( ts_l32, l32 );
441 timespec_str( &ts_l32, buf_l32, sizeof(buf_l32) );
442 ns_to_timespec( ts_l64, l64);
443 timespec_str( &ts_l64, buf_l64, sizeof(buf_l64) );
444 d_str( f_r, buf_f, sizeof(buf_f) );
445 d_str( d_r, buf_d, sizeof(buf_d) );
446
447 /* test strings */
448 if ( strcmp( buf_r, buf_c) ) {
449 fail_ts = "FAIL";
450 fail_count++;
451 }
452 if ( strcmp( buf_l, buf_c) ) {
453 fail_l = "FAIL";
454 fail_count++;
455 }
456 if ( strcmp( buf_l32, buf_c) ) {
457 fail_l32 = "FAIL";
458 fail_count++;
459 }
460 if ( strcmp( buf_l64, buf_c) ) {
461 fail_l64 = "FAIL";
462 fail_count++;
463 }
464 if ( strcmp( buf_f, buf_c) ) {
465 fail_f = "FAIL";
466 fail_count++;
467 }
468 if ( strcmp( buf_d, buf_c) ) {
469 fail_d = "FAIL";
470 fail_count++;
471 }
472 printf("ts: %21s - %21s = %21s %s\n"
473 "l; %21s - %21s = %21lld %s\n"
474 "l32; %21s - %21s = %21lld %s\n"
475 "l64; %21s - %21s = %21lld %s\n"
476 "f; %21.9f - %21.9f = %21.9f %s\n"
477 "d; %21.9f - %21.9f = %21.9f %s\n"
478 "\n",
479 buf_a, buf_b, buf_r, fail_ts,
480 buf_a, buf_b, l, fail_l,
481 buf_a, buf_b, (long long)l32, fail_l32,
482 buf_a, buf_b, (long long)l64, fail_l64,
483 f_a, f_b, f_r, fail_f,
484 d_a, d_b, d_r, fail_d);
485
486
487 if ( p->last ) {
488 break;
489 }
490 p++;
491 };
492
493 if ( fail_count ) {
494 printf("subtract test failed %d tests\n", fail_count );
495 } else {
496 puts("subtract test succeeded\n");
497 }
498 return fail_count;
499 }
500
501
502 /*
503 * show examples of how integers and floats fail
504 *
505 */
ex_precision(void)506 static void ex_precision(void)
507 {
508 format_test_t *p = format_tests;
509
510 puts( "\n\n Simple conversion examples\n\n"
511 "ts: timespec\n"
512 "l32: 32 bit long\n"
513 "l64: 64 bit long\n"
514 "f: float\n"
515 "d: double\n\n");
516
517 while ( 1 ) {
518 float f;
519 double d;
520 int32_t l32;
521 int64_t l64;
522 char buf_ts[TIMESPEC_LEN];
523 char buf_l32[TIMESPEC_LEN];
524 char buf_l64[TIMESPEC_LEN];
525 char buf_f[TIMESPEC_LEN];
526 char buf_d[TIMESPEC_LEN];
527 const char *fail_ts = "";
528 const char *fail_l32 = "";
529 const char *fail_l64 = "";
530 const char *fail_f = "";
531 const char *fail_d = "";
532
533 struct timespec *v = &(p->input);
534 struct timespec ts_l32;
535 struct timespec ts_l64;
536
537
538 /* convert to test size */
539 l32 = (int32_t)(v->tv_sec * NS_IN_SEC)+(int32_t)v->tv_nsec;
540 l64 = (int64_t)(v->tv_sec * NS_IN_SEC)+(int64_t)v->tv_nsec;
541 f = (float)TSTONS( v );
542 d = TSTONS( v );
543
544 /* now convert to strings */
545 timespec_str( v, buf_ts, sizeof(buf_ts) );
546 ns_to_timespec( ts_l32, l32);
547 timespec_str( &ts_l32, buf_l32, sizeof(buf_l32) );
548 ns_to_timespec( ts_l64, l64);
549 timespec_str( &ts_l64, buf_l64, sizeof(buf_l64) );
550 d_str( f, buf_f, sizeof(buf_f) );
551 d_str( d, buf_d, sizeof(buf_d) );
552
553 /* test strings */
554 if ( strcmp( buf_ts, p->expected) ) {
555 fail_ts = "FAIL";
556 }
557 if ( strcmp( buf_l32, p->expected) ) {
558 fail_l32 = "FAIL";
559 }
560 if ( strcmp( buf_l64, p->expected) ) {
561 fail_l64 = "FAIL";
562 }
563 if ( strcmp( buf_f, p->expected) ) {
564 fail_f = "FAIL";
565 }
566 if ( strcmp( buf_d, p->expected) ) {
567 fail_d = "FAIL";
568 }
569 printf( "ts: %21s %s\n"
570 "l32: %21lld %s\n"
571 "l64: %21lld %s\n"
572 "f: %21.9f %s\n"
573 "d: %21.9f %s\n\n",
574 buf_ts, fail_ts,
575 (long long)l32, fail_l32,
576 (long long)l64, fail_l64,
577 f, fail_f,
578 d, fail_d);
579
580 if ( p->last ) {
581 break;
582 }
583 p++;
584 }
585
586 printf( "\n\nSubtraction examples:\n");
587
588 ex_subtract_float();
589 }
590
main(int argc,char * argv[])591 int main(int argc, char *argv[])
592 {
593 int fail_count = 0;
594 int verbose = 0;
595 int option;
596
597 while ((option = getopt(argc, argv, "h?vV")) != -1) {
598 switch (option) {
599 default:
600 fail_count = 1;
601 /* FALL THROUGH! */
602 case '?':
603 case 'h':
604 (void)fputs("usage: test_timespec [-v] [-V]\n", stderr);
605 exit(fail_count);
606 case 'V':
607 (void)fprintf( stderr, "test_timespec %s\n",
608 VERSION);
609 exit(EXIT_SUCCESS);
610 case 'v':
611 verbose = 1;
612 break;
613 }
614 }
615
616
617 fail_count = test_format(verbose );
618 fail_count += test_ts_subtract(verbose );
619 fail_count += test_ns_subtract(verbose );
620 fail_count += test_gpsd_gpstime_resolv(verbose );
621
622 if ( fail_count ) {
623 printf("timespec tests failed %d tests\n", fail_count );
624 exit(1);
625 }
626 printf("timespec tests succeeded\n");
627
628 if ( verbose ) {
629 ex_precision();
630 }
631 exit(0);
632 }
633