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