1/*	$NetBSD: leapsec.c,v 1.3 2020/05/25 20:47:36 christos Exp $	*/
2
3//#include "ntpdtest.h"
4#include "config.h"
5
6
7#include "ntp.h"
8#include "ntp_calendar.h"
9#include "ntp_stdlib.h"
10#include "ntp_leapsec.h"
11#include "lib_strbuf.h"
12
13#include "unity.h"
14
15#include <string.h>
16
17extern	void	setUp(void);
18extern	void	tearDown(void);
19
20#include "test-libntp.h"
21
22static const char leap1 [] =
23    "#\n"
24    "#@ 	3610569600\n"
25    "#\n"
26    "2272060800 10	# 1 Jan 1972\n"
27    "2287785600	11	# 1 Jul 1972\n"
28    "2303683200	12	# 1 Jan 1973\n"
29    "2335219200	13	# 1 Jan 1974\n"
30    "2366755200	14	# 1 Jan 1975\n"
31    "2398291200	15	# 1 Jan 1976\n"
32    "2429913600	16	# 1 Jan 1977\n"
33    "2461449600	17	# 1 Jan 1978\n"
34    "2492985600	18	# 1 Jan 1979\n"
35    "2524521600	19	# 1 Jan 1980\n"
36    "   \t  \n"
37    "2571782400	20	# 1 Jul 1981\n"
38    "2603318400	21	# 1 Jul 1982\n"
39    "2634854400	22	# 1 Jul 1983\n"
40    "2698012800	23	# 1 Jul 1985\n"
41    "2776982400	24	# 1 Jan 1988\n"
42    "2840140800	25	# 1 Jan 1990\n"
43    "2871676800	26	# 1 Jan 1991\n"
44    "2918937600	27	# 1 Jul 1992\n"
45    "2950473600	28	# 1 Jul 1993\n"
46    "2982009600	29	# 1 Jul 1994\n"
47    "3029443200	30	# 1 Jan 1996\n"
48    "3076704000	31	# 1 Jul 1997\n"
49    "3124137600	32	# 1 Jan 1999\n"
50    "3345062400	33	# 1 Jan 2006\n"
51    "3439756800	34	# 1 Jan 2009\n"
52    "3550089600	35	# 1 Jul 2012\n"
53    "#\n"
54    "#h	dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n"
55    "#\n";
56
57static const char leap2 [] =
58    "#\n"
59    "#@ 	2950473700\n"
60    "#\n"
61    "2272060800 10	# 1 Jan 1972\n"
62    "2287785600	11	# 1 Jul 1972\n"
63    "2303683200	12	# 1 Jan 1973\n"
64    "2335219200	13	# 1 Jan 1974\n"
65    "2366755200	14	# 1 Jan 1975\n"
66    "2398291200	15	# 1 Jan 1976\n"
67    "2429913600	16	# 1 Jan 1977\n"
68    "2461449600	17	# 1 Jan 1978\n"
69    "2492985600	18	# 1 Jan 1979\n"
70    "2524521600	19	# 1 Jan 1980\n"
71    "2571782400	20	# 1 Jul 1981\n"
72    "2603318400	21	# 1 Jul 1982\n"
73    "2634854400	22	# 1 Jul 1983\n"
74    "2698012800	23	# 1 Jul 1985\n"
75    "2776982400	24	# 1 Jan 1988\n"
76    "2840140800	25	# 1 Jan 1990\n"
77    "2871676800	26	# 1 Jan 1991\n"
78    "2918937600	27	# 1 Jul 1992\n"
79    "2950473600	28	# 1 Jul 1993\n"
80    "#\n";
81
82// Faked table with a leap second removal at 2009
83static const char leap3 [] =
84    "#\n"
85    "#@ 	3610569600\n"
86    "#\n"
87    "2272060800 10	# 1 Jan 1972\n"
88    "2287785600	11	# 1 Jul 1972\n"
89    "2303683200	12	# 1 Jan 1973\n"
90    "2335219200	13	# 1 Jan 1974\n"
91    "2366755200	14	# 1 Jan 1975\n"
92    "2398291200	15	# 1 Jan 1976\n"
93    "2429913600	16	# 1 Jan 1977\n"
94    "2461449600	17	# 1 Jan 1978\n"
95    "2492985600	18	# 1 Jan 1979\n"
96    "2524521600	19	# 1 Jan 1980\n"
97    "2571782400	20	# 1 Jul 1981\n"
98    "2603318400	21	# 1 Jul 1982\n"
99    "2634854400	22	# 1 Jul 1983\n"
100    "2698012800	23	# 1 Jul 1985\n"
101    "2776982400	24	# 1 Jan 1988\n"
102    "2840140800	25	# 1 Jan 1990\n"
103    "2871676800	26	# 1 Jan 1991\n"
104    "2918937600	27	# 1 Jul 1992\n"
105    "2950473600	28	# 1 Jul 1993\n"
106    "2982009600	29	# 1 Jul 1994\n"
107    "3029443200	30	# 1 Jan 1996\n"
108    "3076704000	31	# 1 Jul 1997\n"
109    "3124137600	32	# 1 Jan 1999\n"
110    "3345062400	33	# 1 Jan 2006\n"
111    "3439756800	32	# 1 Jan 2009\n"
112    "3550089600	33	# 1 Jul 2012\n"
113    "#\n";
114
115// short table with good hash
116static const char leap_ghash [] =
117    "#\n"
118    "#@ 	3610569600\n"
119    "#$ 	3610566000\n"
120    "#\n"
121    "2272060800 10	# 1 Jan 1972\n"
122    "2287785600	11	# 1 Jul 1972\n"
123    "2303683200	12	# 1 Jan 1973\n"
124    "2335219200	13	# 1 Jan 1974\n"
125    "2366755200	14	# 1 Jan 1975\n"
126    "2398291200	15	# 1 Jan 1976\n"
127    "2429913600	16	# 1 Jan 1977\n"
128    "2461449600	17	# 1 Jan 1978\n"
129    "2492985600	18	# 1 Jan 1979\n"
130    "2524521600	19	# 1 Jan 1980\n"
131    "#\n"
132    "#h 4b304e10 95642b3f c10b91f9 90791725 25f280d0\n"
133    "#\n";
134
135// short table with bad hash
136static const char leap_bhash [] =
137    "#\n"
138    "#@ 	3610569600\n"
139    "#$ 	3610566000\n"
140    "#\n"
141    "2272060800 10	# 1 Jan 1972\n"
142    "2287785600	11	# 1 Jul 1972\n"
143    "2303683200	12	# 1 Jan 1973\n"
144    "2335219200	13	# 1 Jan 1974\n"
145    "2366755200	14	# 1 Jan 1975\n"
146    "2398291200	15	# 1 Jan 1976\n"
147    "2429913600	16	# 1 Jan 1977\n"
148    "2461449600	17	# 1 Jan 1978\n"
149    "2492985600	18	# 1 Jan 1979\n"
150    "2524521600	19	# 1 Jan 1980\n"
151    "#\n"
152    "#h	dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n"
153    "#\n";
154
155// short table with malformed hash
156static const char leap_mhash [] =
157    "#\n"
158    "#@ 	3610569600\n"
159    "#$ 	3610566000\n"
160    "#\n"
161    "2272060800 10	# 1 Jan 1972\n"
162    "2287785600	11	# 1 Jul 1972\n"
163    "2303683200	12	# 1 Jan 1973\n"
164    "2335219200	13	# 1 Jan 1974\n"
165    "2366755200	14	# 1 Jan 1975\n"
166    "2398291200	15	# 1 Jan 1976\n"
167    "2429913600	16	# 1 Jan 1977\n"
168    "2461449600	17	# 1 Jan 1978\n"
169    "2492985600	18	# 1 Jan 1979\n"
170    "2524521600	19	# 1 Jan 1980\n"
171    "#\n"
172    "#h f2349a02 788b9534 a8f2e141 f2029Q6d 4064a7ee\n"
173    "#\n";
174
175// short table with only 4 hash groups
176static const char leap_shash [] =
177    "#\n"
178    "#@ 	3610569600\n"
179    "#$ 	3610566000\n"
180    "#\n"
181    "2272060800 10	# 1 Jan 1972\n"
182    "2287785600	11	# 1 Jul 1972\n"
183    "2303683200	12	# 1 Jan 1973\n"
184    "2335219200	13	# 1 Jan 1974\n"
185    "2366755200	14	# 1 Jan 1975\n"
186    "2398291200	15	# 1 Jan 1976\n"
187    "2429913600	16	# 1 Jan 1977\n"
188    "2461449600	17	# 1 Jan 1978\n"
189    "2492985600	18	# 1 Jan 1979\n"
190    "2524521600	19	# 1 Jan 1980\n"
191    "#\n"
192    "#h f2349a02 788b9534 a8f2e141 f2029Q6d\n"
193    "#\n";
194
195// table with good hash and truncated/missing leading zeros
196static const char leap_gthash [] = {
197    "#\n"
198    "#$	 3535228800\n"
199    "#\n"
200    "#	Updated through IERS Bulletin C46\n"
201    "#	File expires on:  28 June 2014\n"
202    "#\n"
203    "#@	3612902400\n"
204    "#\n"
205    "2272060800	10	# 1 Jan 1972\n"
206    "2287785600	11	# 1 Jul 1972\n"
207    "2303683200	12	# 1 Jan 1973\n"
208    "2335219200	13	# 1 Jan 1974\n"
209    "2366755200	14	# 1 Jan 1975\n"
210    "2398291200	15	# 1 Jan 1976\n"
211    "2429913600	16	# 1 Jan 1977\n"
212    "2461449600	17	# 1 Jan 1978\n"
213    "2492985600	18	# 1 Jan 1979\n"
214    "2524521600	19	# 1 Jan 1980\n"
215    "2571782400	20	# 1 Jul 1981\n"
216    "2603318400	21	# 1 Jul 1982\n"
217    "2634854400	22	# 1 Jul 1983\n"
218    "2698012800	23	# 1 Jul 1985\n"
219    "2776982400	24	# 1 Jan 1988\n"
220    "2840140800	25	# 1 Jan 1990\n"
221    "2871676800	26	# 1 Jan 1991\n"
222    "2918937600	27	# 1 Jul 1992\n"
223    "2950473600	28	# 1 Jul 1993\n"
224    "2982009600	29	# 1 Jul 1994\n"
225    "3029443200	30	# 1 Jan 1996\n"
226    "3076704000	31	# 1 Jul 1997\n"
227    "3124137600	32	# 1 Jan 1999\n"
228    "3345062400	33	# 1 Jan 2006\n"
229    "3439756800	34	# 1 Jan 2009\n"
230    "3550089600	35	# 1 Jul 2012\n"
231    "#\n"
232    "#h	1151a8f e85a5069 9000fcdb 3d5e5365 1d505b37"
233};
234
235static const uint32_t lsec2006 = 3345062400u; // +33, 1 Jan 2006, 00:00:00 utc
236static const uint32_t lsec2009 = 3439756800u; // +34, 1 Jan 2009, 00:00:00 utc
237static const uint32_t lsec2012 = 3550089600u; // +35, 1 Jul 2012, 00:00:00 utc
238static const uint32_t lsec2015 = 3644697600u; // +36, 1 Jul 2015, 00:00:00 utc
239
240static int stringreader(void* farg)
241{
242	const char ** cpp = (const char**)farg;
243
244	if (**cpp)
245		return *(*cpp)++;
246	else
247		return EOF;
248}
249
250static int/*BOOL*/
251setup_load_table(
252	const char * cp,
253	int          blim)
254{
255	int            rc;
256	leap_table_t * pt = leapsec_get_table(0);
257
258	rc = (pt != NULL) && leapsec_load(pt, stringreader, &cp, blim);
259	rc = rc && leapsec_set_table(pt);
260	return rc;
261}
262
263static int/*BOOL*/
264setup_clear_table(void)
265{
266	int            rc;
267	leap_table_t * pt = leapsec_get_table(0);
268
269	if (pt)
270		leapsec_clear(pt);
271	rc = leapsec_set_table(pt);
272	return rc;
273}
274
275#if 0 /* formatting & compare currently not used... */
276static const char *
277CalendarToString(const struct calendar cal)
278{
279	char * str;
280
281	LIB_GETBUF(str);
282	snprintf(str, LIB_BUFLENGTH,
283		 "%04hu-%02hhu-%02hhu (%hu) %02hhu:%02hhu:%02hhu",
284		 cal.year, cal.month, cal.monthday, cal.yearday,
285		 cal.hour, cal.minute, cal.second);
286	return str;
287}
288
289static int
290IsEqual(const struct calendar expected, const struct calendar actual)
291{
292
293	if (   expected.year == actual.year
294	    && (   expected.yearday == actual.yearday
295		|| (   expected.month == actual.month
296		    && expected.monthday == actual.monthday))
297	    && expected.hour == actual.hour
298	    && expected.minute == actual.minute
299	    && expected.second == actual.second) {
300		return TRUE;
301	} else {
302		const char *p_exp = CalendarToString(expected);
303		const char *p_act = CalendarToString(actual);
304		printf("expected: %s but was %s", p_exp, p_act);
305		return FALSE;
306	}
307}
308#endif /*0*/
309
310//-------------------------
311
312void
313setUp(void)
314{
315    ntpcal_set_timefunc(timefunc);
316    settime(1970, 1, 1, 0, 0, 0);
317    leapsec_ut_pristine();
318}
319
320void
321tearDown(void)
322{
323    ntpcal_set_timefunc(NULL);
324}
325
326// =====================================================================
327// VALIDATION TESTS
328// =====================================================================
329
330// ----------------------------------------------------------------------
331extern void test_ValidateGood(void);
332void test_ValidateGood(void)
333{
334	const char *cp = leap_ghash;
335	int         rc = leapsec_validate(stringreader, &cp);
336
337	TEST_ASSERT_EQUAL(LSVALID_GOODHASH, rc);
338}
339
340// ----------------------------------------------------------------------
341extern void test_ValidateNoHash(void);
342void test_ValidateNoHash(void)
343{
344	const char *cp = leap2;
345	int         rc = leapsec_validate(stringreader, &cp);
346
347	TEST_ASSERT_EQUAL(LSVALID_NOHASH, rc);
348}
349
350// ----------------------------------------------------------------------
351extern void test_ValidateBad(void);
352void test_ValidateBad(void)
353{
354	const char *cp = leap_bhash;
355	int         rc = leapsec_validate(stringreader, &cp);
356
357	TEST_ASSERT_EQUAL(LSVALID_BADHASH, rc);
358}
359
360// ----------------------------------------------------------------------
361extern void test_ValidateMalformed(void);
362void test_ValidateMalformed(void)
363{
364	const char *cp = leap_mhash;
365	int         rc = leapsec_validate(stringreader, &cp);
366
367	TEST_ASSERT_EQUAL(LSVALID_BADFORMAT, rc);
368}
369
370// ----------------------------------------------------------------------
371extern void test_ValidateMalformedShort(void);
372void test_ValidateMalformedShort(void)
373{
374	const char *cp = leap_shash;
375	int         rc = leapsec_validate(stringreader, &cp);
376
377	TEST_ASSERT_EQUAL(LSVALID_BADFORMAT, rc);
378}
379
380// ----------------------------------------------------------------------
381extern void test_ValidateNoLeadZero(void);
382void test_ValidateNoLeadZero(void)
383{
384	const char *cp = leap_gthash;
385	int         rc = leapsec_validate(stringreader, &cp);
386
387	TEST_ASSERT_EQUAL(LSVALID_GOODHASH, rc);
388}
389
390// =====================================================================
391// BASIC FUNCTIONS
392// =====================================================================
393
394// ----------------------------------------------------------------------
395// test table selection
396extern void test_tableSelect(void);
397void test_tableSelect(void)
398{
399    leap_table_t *pt1, *pt2, *pt3;
400
401	pt1 = leapsec_get_table(0);
402	pt2 = leapsec_get_table(0);
403	TEST_ASSERT_EQUAL_MESSAGE(pt1, pt2,"first");
404
405	pt1 = leapsec_get_table(1);
406	pt2 = leapsec_get_table(1);
407	TEST_ASSERT_EQUAL_MESSAGE(pt1, pt2,"second");
408
409	pt1 = leapsec_get_table(1);
410	pt2 = leapsec_get_table(0);
411	TEST_ASSERT_NOT_EQUAL(pt1, pt2);
412
413	pt1 = leapsec_get_table(0);
414	pt2 = leapsec_get_table(1);
415	TEST_ASSERT_NOT_EQUAL(pt1, pt2);
416
417	leapsec_set_table(pt1);
418	pt2 = leapsec_get_table(0);
419	pt3 = leapsec_get_table(1);
420	TEST_ASSERT_EQUAL(pt1, pt2);
421	TEST_ASSERT_NOT_EQUAL(pt2, pt3);
422
423	pt1 = pt3;
424	leapsec_set_table(pt1);
425	pt2 = leapsec_get_table(0);
426	pt3 = leapsec_get_table(1);
427	TEST_ASSERT_EQUAL(pt1, pt2);
428	TEST_ASSERT_NOT_EQUAL(pt2, pt3);
429}
430
431// ----------------------------------------------------------------------
432// load file & check expiration
433extern void test_loadFileExpire(void);
434void test_loadFileExpire(void)
435{
436	const char *cp = leap1;
437	int rc;
438	leap_table_t * pt = leapsec_get_table(0);
439
440	rc =   leapsec_load(pt, stringreader, &cp, FALSE)
441	    && leapsec_set_table(pt);
442	TEST_ASSERT_EQUAL_MESSAGE(1, rc,"first");
443	rc = leapsec_expired(3439756800u, NULL);
444	TEST_ASSERT_EQUAL(0, rc);
445	rc = leapsec_expired(3610569601u, NULL);
446	TEST_ASSERT_EQUAL(1, rc);
447}
448
449// ----------------------------------------------------------------------
450// load file & check time-to-live
451extern void test_loadFileTTL(void);
452void test_loadFileTTL(void)
453{
454	const char     *cp = leap1;
455	int		rc;
456	leap_table_t  * pt = leapsec_get_table(0);
457	time_t		pivot = 0x70000000u;
458	const uint32_t	limit = 3610569600u;
459
460	rc =   leapsec_load(pt, stringreader, &cp, FALSE)
461	    && leapsec_set_table(pt);
462	TEST_ASSERT_EQUAL(1, rc); //
463
464	// exactly 1 day to live
465	rc = leapsec_daystolive(limit - 86400, &pivot);
466	TEST_ASSERT_EQUAL( 1, rc);
467	// less than 1 day to live
468	rc = leapsec_daystolive(limit - 86399, &pivot);
469	TEST_ASSERT_EQUAL( 0, rc);
470	// hit expiration exactly
471	rc = leapsec_daystolive(limit, &pivot);
472	TEST_ASSERT_EQUAL( 0, rc);
473	// expired since 1 sec
474	rc = leapsec_daystolive(limit + 1, &pivot);
475	TEST_ASSERT_EQUAL(-1, rc);
476}
477
478// =====================================================================
479// RANDOM QUERY TESTS
480// =====================================================================
481
482// ----------------------------------------------------------------------
483// test query in pristine state (bug#2745 misbehaviour)
484extern void test_lsQueryPristineState(void);
485void test_lsQueryPristineState(void)
486{
487	int            rc;
488	leap_result_t  qr;
489
490	rc = leapsec_query(&qr, lsec2012, NULL);
491	TEST_ASSERT_EQUAL(FALSE, rc);
492	TEST_ASSERT_EQUAL(0,             qr.warped   );
493	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
494}
495
496// ----------------------------------------------------------------------
497// ad-hoc jump: leap second at 2009.01.01 -60days
498extern void test_ls2009faraway(void);
499void test_ls2009faraway(void)
500{
501	int            rc;
502	leap_result_t  qr;
503
504	rc = setup_load_table(leap1,FALSE);
505	TEST_ASSERT_EQUAL(1, rc);
506
507	// test 60 days before leap. Nothing scheduled or indicated.
508	rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
509	TEST_ASSERT_EQUAL(FALSE, rc);
510	TEST_ASSERT_EQUAL(33, qr.tai_offs);
511	TEST_ASSERT_EQUAL(0,  qr.tai_diff);
512	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
513}
514
515// ----------------------------------------------------------------------
516// ad-hoc jump: leap second at 2009.01.01 -1week
517extern void test_ls2009weekaway(void);
518void test_ls2009weekaway(void)
519{
520	int            rc;
521	leap_result_t  qr;
522
523	rc = setup_load_table(leap1,FALSE);
524	TEST_ASSERT_EQUAL(1, rc);
525
526	// test 7 days before leap. Leap scheduled, but not yet indicated.
527	rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
528	TEST_ASSERT_EQUAL(FALSE, rc);
529	TEST_ASSERT_EQUAL(33, qr.tai_offs);
530	TEST_ASSERT_EQUAL(1,  qr.tai_diff);
531	TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
532}
533
534// ----------------------------------------------------------------------
535// ad-hoc jump: leap second at 2009.01.01 -1hr
536extern void test_ls2009houraway(void);
537void test_ls2009houraway(void)
538{
539	int            rc;
540	leap_result_t  qr;
541
542	rc = setup_load_table(leap1,FALSE);
543	TEST_ASSERT_EQUAL(1, rc);
544
545	// test 1 hour before leap. 61 true seconds to go.
546	rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
547	TEST_ASSERT_EQUAL(FALSE, rc);
548	TEST_ASSERT_EQUAL(33, qr.tai_offs);
549	TEST_ASSERT_EQUAL(1,  qr.tai_diff);
550	TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
551}
552
553// ----------------------------------------------------------------------
554// ad-hoc jump: leap second at 2009.01.01 -1sec
555extern void test_ls2009secaway(void);
556void test_ls2009secaway(void)
557{
558	int            rc;
559	leap_result_t  qr;
560
561	rc = setup_load_table(leap1,FALSE);
562	TEST_ASSERT_EQUAL(1, rc);
563
564	// test 1 second before leap (last boundary...) 2 true seconds to go.
565	rc = leapsec_query(&qr, lsec2009 - 1, NULL);
566	TEST_ASSERT_EQUAL(FALSE, rc);
567	TEST_ASSERT_EQUAL(33, qr.tai_offs);
568	TEST_ASSERT_EQUAL(1,  qr.tai_diff);
569	TEST_ASSERT_EQUAL(LSPROX_ALERT, qr.proximity);
570}
571
572// ----------------------------------------------------------------------
573// ad-hoc jump to leap second at 2009.01.01
574extern void test_ls2009onspot(void);
575void test_ls2009onspot(void)
576{
577	int            rc;
578	leap_result_t  qr;
579
580	rc = setup_load_table(leap1,FALSE);
581	TEST_ASSERT_EQUAL(1, rc);
582
583	// test on-spot: treat leap second as already gone.
584	rc = leapsec_query(&qr, lsec2009, NULL);
585	TEST_ASSERT_EQUAL(FALSE, rc);
586	TEST_ASSERT_EQUAL(34, qr.tai_offs);
587	TEST_ASSERT_EQUAL(0,  qr.tai_diff);
588	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
589}
590
591// ----------------------------------------------------------------------
592// test handling of the leap second at 2009.01.01 without table
593extern void test_ls2009nodata(void);
594void test_ls2009nodata(void)
595{
596	int            rc;
597	leap_result_t  qr;
598
599	rc = setup_clear_table();
600	TEST_ASSERT_EQUAL(1, rc);
601
602	// test on-spot with empty table
603	rc = leapsec_query(&qr, lsec2009, NULL);
604	TEST_ASSERT_EQUAL(FALSE, rc);
605	TEST_ASSERT_EQUAL(0,  qr.tai_offs);
606	TEST_ASSERT_EQUAL(0,  qr.tai_diff);
607	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
608}
609
610// ----------------------------------------------------------------------
611// test handling of the leap second at 2009.01.01 with culled data
612extern void test_ls2009limdata(void);
613void test_ls2009limdata(void)
614{
615	int            rc;
616	leap_result_t  qr;
617
618	rc = setup_load_table(leap1, TRUE);
619	TEST_ASSERT_EQUAL(1, rc);
620
621	// test on-spot with limited table - this is tricky.
622	// The table used ends 2012; depending on the build date, the 2009 entry
623	// might be included or culled. The resulting TAI offset must be either
624	// 34 or 35 seconds, depending on the build date of the test.
625	rc = leapsec_query(&qr, lsec2009, NULL);
626	TEST_ASSERT_EQUAL(FALSE, rc);
627	TEST_ASSERT_TRUE(34 <= qr.tai_offs);
628	TEST_ASSERT_TRUE(35 >= qr.tai_offs);
629	TEST_ASSERT_EQUAL(0,  qr.tai_diff);
630	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
631}
632
633// ----------------------------------------------------------------------
634// Far-distance forward jump into a transiton window.
635extern void test_qryJumpFarAhead(void);
636void test_qryJumpFarAhead(void)
637{
638	int		rc;
639	leap_result_t	qr;
640	int		mode;
641
642	for (mode=0; mode < 2; ++mode) {
643		leapsec_ut_pristine();
644		rc = setup_load_table(leap1, FALSE);
645		TEST_ASSERT_EQUAL(1, rc);
646		leapsec_electric(mode);
647
648		rc = leapsec_query(&qr, lsec2006, NULL);
649		TEST_ASSERT_EQUAL(FALSE, rc);
650
651		rc = leapsec_query(&qr, lsec2012, NULL);
652		TEST_ASSERT_EQUAL(FALSE, rc);
653	}
654}
655
656// ----------------------------------------------------------------------
657// Forward jump into the next transition window
658extern void test_qryJumpAheadToTransition(void);
659void test_qryJumpAheadToTransition(void)
660{
661	int		rc;
662	leap_result_t	qr;
663	int		mode;
664
665	for (mode=0; mode < 2; ++mode) {
666		leapsec_ut_pristine();
667		rc = setup_load_table(leap1, FALSE);
668		TEST_ASSERT_EQUAL(1, rc);
669		leapsec_electric(mode);
670
671		rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL);
672		TEST_ASSERT_EQUAL(FALSE, rc);
673
674		rc = leapsec_query(&qr, lsec2009+1, NULL);
675		TEST_ASSERT_EQUAL(TRUE, rc);
676	}
677}
678
679// ----------------------------------------------------------------------
680// Forward jump over the next transition window
681extern void test_qryJumpAheadOverTransition(void);
682void test_qryJumpAheadOverTransition(void)
683{
684	int		rc;
685	leap_result_t	qr;
686	int		mode;
687
688	for (mode=0; mode < 2; ++mode) {
689		leapsec_ut_pristine();
690		rc = setup_load_table(leap1, FALSE);
691		TEST_ASSERT_EQUAL(1, rc);
692		leapsec_electric(mode);
693
694		rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL);
695		TEST_ASSERT_EQUAL(FALSE, rc);
696
697		rc = leapsec_query(&qr, lsec2009+5, NULL);
698		TEST_ASSERT_EQUAL(FALSE, rc);
699	}
700}
701
702// =====================================================================
703// TABLE MODIFICATION AT RUNTIME
704// =====================================================================
705
706// ----------------------------------------------------------------------
707// add dynamic leap second (like from peer/clock)
708extern void test_addDynamic(void);
709void test_addDynamic(void)
710{
711	int            rc;
712
713	static const uint32_t insns[] = {
714		2982009600u,	//	29	# 1 Jul 1994
715		3029443200u,	//	30	# 1 Jan 1996
716		3076704000u,	//	31	# 1 Jul 1997
717		3124137600u,	//	32	# 1 Jan 1999
718		3345062400u,	//	33	# 1 Jan 2006
719		3439756800u,	//	34	# 1 Jan 2009
720		3550089600u,	//	35	# 1 Jul 2012
721		0 // sentinel
722	};
723
724	rc = setup_load_table(leap2, FALSE);
725	TEST_ASSERT_EQUAL(1, rc);
726
727	int		idx;
728
729	for (idx=1; insns[idx]; ++idx) {
730		rc = leapsec_add_dyn(TRUE, insns[idx] - 20*SECSPERDAY - 100, NULL);
731		TEST_ASSERT_EQUAL(TRUE, rc);
732	}
733	// try to slip in a previous entry
734	rc = leapsec_add_dyn(TRUE, insns[0] - 20*SECSPERDAY - 100, NULL);
735	TEST_ASSERT_EQUAL(FALSE, rc);
736	//leap_table_t  * pt = leapsec_get_table(0);
737	//leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
738}
739
740// ----------------------------------------------------------------------
741// add fixed leap seconds (like from network packet)
742#if 0 /* currently unused -- possibly revived later */
743extern void no_test_addFixed(void);
744void no_test_addFixed(void)
745{
746	int            rc;
747	leap_result_t  qr;
748
749	static const struct { uint32_t tt; int of; } insns[] = {
750		{2982009600u, 29},//	# 1 Jul 1994
751		{3029443200u, 30},//	# 1 Jan 1996
752		{3076704000u, 31},//	# 1 Jul 1997
753		{3124137600u, 32},//	# 1 Jan 1999
754		{3345062400u, 33},//	# 1 Jan 2006
755		{3439756800u, 34},//	# 1 Jan 2009
756		{3550089600u, 35},//	# 1 Jul 2012
757		{0,0} // sentinel
758	};
759
760	rc = setup_load_table(leap2, FALSE);
761	TEST_ASSERT_EQUAL(1, rc);
762
763	int idx;
764	// try to get in BAD time stamps...
765	for (idx=0; insns[idx].tt; ++idx) {
766	    rc = leapsec_add_fix(
767		insns[idx].of,
768		insns[idx].tt - 20*SECSPERDAY - 100,
769		insns[idx].tt + SECSPERDAY,
770		NULL);
771		TEST_ASSERT_EQUAL(FALSE, rc);
772	}
773	// now do it right
774	for (idx=0; insns[idx].tt; ++idx) {
775		rc = leapsec_add_fix(
776		    insns[idx].of,
777		    insns[idx].tt,
778		    insns[idx].tt + SECSPERDAY,
779		    NULL);
780		TEST_ASSERT_EQUAL(TRUE, rc);
781	}
782	// try to slip in a previous entry
783	rc = leapsec_add_fix(
784	    insns[0].of,
785	    insns[0].tt,
786	    insns[0].tt + SECSPERDAY,
787	    NULL);
788	TEST_ASSERT_EQUAL(FALSE, rc);
789	//leap_table_t * pt = leapsec_get_table(0);
790	//leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
791}
792#endif
793
794// ----------------------------------------------------------------------
795// add fixed leap seconds (like from network packet)
796#if 0 /* currently unused -- possibly revived later */
797extern void no_test_addFixedExtend(void);
798void no_test_addFixedExtend(void)
799{
800	int            rc;
801	leap_result_t  qr;
802	int            last, idx;
803
804	static const struct { uint32_t tt; int of; } insns[] = {
805		{2982009600u, 29},//	# 1 Jul 1994
806		{3029443200u, 30},//	# 1 Jan 1996
807		{0,0} // sentinel
808	};
809
810	rc = setup_load_table(leap2, FALSE);
811	TEST_ASSERT_EQUAL(1, rc);
812
813	for (last=idx=0; insns[idx].tt; ++idx) {
814		last = idx;
815		rc = leapsec_add_fix(
816		    insns[idx].of,
817		    insns[idx].tt,
818		    insns[idx].tt + SECSPERDAY,
819		    NULL);
820		TEST_ASSERT_EQUAL(TRUE, rc);
821	}
822
823	// try to extend the expiration of the last entry
824	rc = leapsec_add_fix(
825	    insns[last].of,
826	    insns[last].tt,
827	    insns[last].tt + 128*SECSPERDAY,
828	    NULL);
829	TEST_ASSERT_EQUAL(TRUE, rc);
830
831	// try to extend the expiration of the last entry with wrong offset
832	rc = leapsec_add_fix(
833	    insns[last].of+1,
834	    insns[last].tt,
835	    insns[last].tt + 129*SECSPERDAY,
836	    NULL);
837	TEST_ASSERT_EQUAL(FALSE, rc);
838	//leap_table_t * pt = leapsec_get_table(FALSE);
839	//leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
840}
841#endif
842
843// ----------------------------------------------------------------------
844// add fixed leap seconds (like from network packet) in an otherwise
845// empty table and test queries before / between /after the tabulated
846// values.
847#if 0 /* currently unused -- possibly revived later */
848extern void no_test_setFixedExtend(void);
849void no_test_setFixedExtend(void)
850{
851	int            rc;
852	leap_result_t  qr;
853	int            last, idx;
854
855	static const struct { uint32_t tt; int of; } insns[] = {
856		{2982009600u, 29},//	# 1 Jul 1994
857		{3029443200u, 30},//	# 1 Jan 1996
858		{0,0} // sentinel
859	};
860
861	for (last=idx=0; insns[idx].tt; ++idx) {
862		last = idx;
863		rc = leapsec_add_fix(
864		    insns[idx].of,
865		    insns[idx].tt,
866		    insns[idx].tt + 128*SECSPERDAY,
867		    NULL);
868		TEST_ASSERT_EQUAL(TRUE, rc);
869	}
870
871	rc = leapsec_query(&qr, insns[0].tt - 86400, NULL);
872	TEST_ASSERT_EQUAL(28, qr.tai_offs);
873
874	rc = leapsec_query(&qr, insns[0].tt + 86400, NULL);
875	TEST_ASSERT_EQUAL(29, qr.tai_offs);
876
877	rc = leapsec_query(&qr, insns[1].tt - 86400, NULL);
878	TEST_ASSERT_EQUAL(29, qr.tai_offs);
879
880	rc = leapsec_query(&qr, insns[1].tt + 86400, NULL);
881	TEST_ASSERT_EQUAL(30, qr.tai_offs);
882
883	//leap_table_t * pt = leapsec_get_table(0);
884	//leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
885}
886#endif
887
888// =====================================================================
889// AUTOKEY LEAP TRANSFER TESTS
890// =====================================================================
891
892// ----------------------------------------------------------------------
893// Check if the offset can be applied to an empty table ONCE
894extern void test_taiEmptyTable(void);
895void test_taiEmptyTable(void)
896{
897	int rc;
898
899	rc = leapsec_autokey_tai(35, lsec2015-30*86400, NULL);
900	TEST_ASSERT_EQUAL(TRUE, rc);
901
902	rc = leapsec_autokey_tai(35, lsec2015-29*86400, NULL);
903	TEST_ASSERT_EQUAL(FALSE, rc);
904}
905
906// ----------------------------------------------------------------------
907// Check that with fixed entries the operation fails
908extern void test_taiTableFixed(void);
909void test_taiTableFixed(void)
910{
911	int rc;
912
913	rc = setup_load_table(leap1, FALSE);
914	TEST_ASSERT_EQUAL(1, rc);
915
916	rc = leapsec_autokey_tai(35, lsec2015-30*86400, NULL);
917	TEST_ASSERT_EQUAL(FALSE, rc);
918}
919
920// ----------------------------------------------------------------------
921// test adjustment with a dynamic entry already there
922extern void test_taiTableDynamic(void);
923void test_taiTableDynamic(void)
924{
925	int        rc;
926	leap_era_t era;
927
928	rc = leapsec_add_dyn(TRUE, lsec2015-20*SECSPERDAY, NULL);
929	TEST_ASSERT_EQUAL(TRUE, rc);
930
931	leapsec_query_era(&era, lsec2015-10, NULL);
932	TEST_ASSERT_EQUAL(0, era.taiof);
933	leapsec_query_era(&era, lsec2015+10, NULL);
934	TEST_ASSERT_EQUAL(1, era.taiof);
935
936	rc = leapsec_autokey_tai(35, lsec2015-19*86400, NULL);
937	TEST_ASSERT_EQUAL(TRUE, rc);
938
939	rc = leapsec_autokey_tai(35, lsec2015-19*86400, NULL);
940	TEST_ASSERT_EQUAL(FALSE, rc);
941
942	leapsec_query_era(&era, lsec2015-10, NULL);
943	TEST_ASSERT_EQUAL(35, era.taiof);
944	leapsec_query_era(&era, lsec2015+10, NULL);
945	TEST_ASSERT_EQUAL(36, era.taiof);
946}
947
948// ----------------------------------------------------------------------
949// test adjustment with a dynamic entry already there in dead zone
950extern void test_taiTableDynamicDeadZone(void);
951void test_taiTableDynamicDeadZone(void)
952{
953	int rc;
954
955	rc = leapsec_add_dyn(TRUE, lsec2015-20*SECSPERDAY, NULL);
956	TEST_ASSERT_EQUAL(TRUE, rc);
957
958	rc = leapsec_autokey_tai(35, lsec2015-5, NULL);
959	TEST_ASSERT_EQUAL(FALSE, rc);
960
961	rc = leapsec_autokey_tai(35, lsec2015+5, NULL);
962	TEST_ASSERT_EQUAL(FALSE, rc);
963}
964
965
966// =====================================================================
967// SEQUENCE TESTS
968// =====================================================================
969
970// ----------------------------------------------------------------------
971// leap second insert at 2009.01.01, electric mode
972extern void test_ls2009seqInsElectric(void);
973void test_ls2009seqInsElectric(void)
974{
975	int            rc;
976	leap_result_t  qr;
977
978	rc = setup_load_table(leap1,FALSE);
979	TEST_ASSERT_EQUAL(1, rc);
980	leapsec_electric(1);
981	TEST_ASSERT_EQUAL(1, leapsec_electric(-1));
982
983	rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
984	TEST_ASSERT_EQUAL(FALSE, rc);
985	TEST_ASSERT_EQUAL(0,             qr.warped   );
986	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
987
988	rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
989	TEST_ASSERT_EQUAL(FALSE, rc);
990	TEST_ASSERT_EQUAL(0,               qr.warped   );
991	TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
992
993	rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
994	TEST_ASSERT_EQUAL(FALSE, rc);
995	TEST_ASSERT_EQUAL(0,               qr.warped   );
996	TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
997
998	rc = leapsec_query(&qr, lsec2009 - 1, NULL);
999	TEST_ASSERT_EQUAL(FALSE, rc);
1000	TEST_ASSERT_EQUAL(0,               qr.warped   );
1001	TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
1002
1003	rc = leapsec_query(&qr, lsec2009, NULL);
1004	TEST_ASSERT_EQUAL(TRUE, rc);
1005	TEST_ASSERT_EQUAL(0,             qr.warped   );
1006	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1007
1008	// second call, same time frame: no trigger!
1009	rc = leapsec_query(&qr, lsec2009, NULL);
1010	TEST_ASSERT_EQUAL(FALSE, rc);
1011	TEST_ASSERT_EQUAL(0,             qr.warped   );
1012	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1013}
1014
1015// ----------------------------------------------------------------------
1016// leap second insert at 2009.01.01, dumb mode
1017extern void test_ls2009seqInsDumb(void);
1018void test_ls2009seqInsDumb(void)
1019{
1020	int            rc;
1021	leap_result_t  qr;
1022
1023	rc = setup_load_table(leap1,FALSE);
1024	TEST_ASSERT_EQUAL(1, rc);
1025	TEST_ASSERT_EQUAL(0, leapsec_electric(-1));
1026
1027	rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
1028	TEST_ASSERT_EQUAL(FALSE, rc);
1029	TEST_ASSERT_EQUAL(0,             qr.warped   );
1030	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1031
1032	rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
1033	TEST_ASSERT_EQUAL(FALSE, rc);
1034	TEST_ASSERT_EQUAL(0,               qr.warped   );
1035	TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
1036
1037	rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
1038	TEST_ASSERT_EQUAL(FALSE, rc);
1039	TEST_ASSERT_EQUAL(0,               qr.warped   );
1040	TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
1041
1042	rc = leapsec_query(&qr, lsec2009 - 1, NULL);
1043	TEST_ASSERT_EQUAL(FALSE, rc);
1044	TEST_ASSERT_EQUAL(0,               qr.warped   );
1045	TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
1046
1047	rc = leapsec_query(&qr, lsec2009, NULL);
1048	TEST_ASSERT_EQUAL(FALSE, rc);
1049	TEST_ASSERT_EQUAL(0,               qr.warped   );
1050	TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
1051
1052	rc = leapsec_query(&qr, lsec2009+1, NULL);
1053	TEST_ASSERT_EQUAL(TRUE, rc);
1054	TEST_ASSERT_EQUAL(-1,             qr.warped   );
1055	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1056
1057	// second call, same time frame: no trigger!
1058	rc = leapsec_query(&qr, lsec2009, NULL);
1059	TEST_ASSERT_EQUAL(FALSE, rc);
1060	TEST_ASSERT_EQUAL(0,             qr.warped   );
1061	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1062}
1063
1064// ----------------------------------------------------------------------
1065// fake leap second remove at 2009.01.01, electric mode
1066extern void test_ls2009seqDelElectric(void);
1067void test_ls2009seqDelElectric(void)
1068{
1069	int            rc;
1070	leap_result_t  qr;
1071
1072	rc = setup_load_table(leap3,FALSE);
1073	TEST_ASSERT_EQUAL(1, rc);
1074	leapsec_electric(1);
1075	TEST_ASSERT_EQUAL(1, leapsec_electric(-1));
1076
1077	rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
1078	TEST_ASSERT_EQUAL(FALSE, rc);
1079	TEST_ASSERT_EQUAL(0,             qr.warped   );
1080	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1081
1082	rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
1083	TEST_ASSERT_EQUAL(FALSE, rc);
1084	TEST_ASSERT_EQUAL(0,               qr.warped   );
1085	TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
1086
1087	rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
1088	TEST_ASSERT_EQUAL(FALSE, rc);
1089	TEST_ASSERT_EQUAL(0,               qr.warped   );
1090	TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
1091
1092	rc = leapsec_query(&qr, lsec2009 - 1, NULL);
1093	TEST_ASSERT_EQUAL(FALSE, rc);
1094	TEST_ASSERT_EQUAL(0,               qr.warped   );
1095	TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
1096
1097	rc = leapsec_query(&qr, lsec2009, NULL);
1098	TEST_ASSERT_EQUAL(TRUE, rc);
1099	TEST_ASSERT_EQUAL(0,             qr.warped   );
1100	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1101
1102	// second call, same time frame: no trigger!
1103	rc = leapsec_query(&qr, lsec2009, NULL);
1104	TEST_ASSERT_EQUAL(FALSE, rc);
1105	TEST_ASSERT_EQUAL(0,             qr.warped   );
1106	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1107}
1108
1109// ----------------------------------------------------------------------
1110// fake leap second remove at 2009.01.01. dumb mode
1111extern void test_ls2009seqDelDumb(void);
1112void test_ls2009seqDelDumb(void)
1113{
1114	int            rc;
1115	leap_result_t  qr;
1116
1117	rc = setup_load_table(leap3,FALSE);
1118	TEST_ASSERT_EQUAL(1, rc);
1119	TEST_ASSERT_EQUAL(0, leapsec_electric(-1));
1120
1121	rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
1122	TEST_ASSERT_EQUAL(FALSE, rc);
1123	TEST_ASSERT_EQUAL(0,             qr.warped   );
1124	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1125
1126	rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
1127	TEST_ASSERT_EQUAL(FALSE, rc);
1128	TEST_ASSERT_EQUAL(0,               qr.warped   );
1129	TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
1130
1131	rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
1132	TEST_ASSERT_EQUAL(FALSE, rc);
1133	TEST_ASSERT_EQUAL(0,               qr.warped   );
1134	TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
1135
1136	rc = leapsec_query(&qr, lsec2009 - 2, NULL);
1137	TEST_ASSERT_EQUAL(FALSE, rc);
1138	TEST_ASSERT_EQUAL(0,               qr.warped   );
1139	TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
1140
1141	rc = leapsec_query(&qr, lsec2009 - 1, NULL);
1142	TEST_ASSERT_EQUAL(TRUE, rc);
1143	TEST_ASSERT_EQUAL(1,             qr.warped   );
1144	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1145
1146	// second call, same time frame: no trigger!
1147	rc = leapsec_query(&qr, lsec2009, NULL);
1148	TEST_ASSERT_EQUAL(FALSE, rc);
1149	TEST_ASSERT_EQUAL(0,             qr.warped   );
1150	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1151}
1152
1153// ----------------------------------------------------------------------
1154// leap second insert at 2012.07.01, electric mode
1155extern void test_ls2012seqInsElectric(void);
1156void test_ls2012seqInsElectric(void)
1157{
1158	int            rc;
1159	leap_result_t  qr;
1160
1161	rc = setup_load_table(leap1,FALSE);
1162	TEST_ASSERT_EQUAL(1, rc);
1163	leapsec_electric(1);
1164	TEST_ASSERT_EQUAL(1, leapsec_electric(-1));
1165
1166	rc = leapsec_query(&qr, lsec2012 - 60*SECSPERDAY, NULL);
1167	TEST_ASSERT_EQUAL(FALSE, rc);
1168	TEST_ASSERT_EQUAL(0,             qr.warped   );
1169	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1170
1171	rc = leapsec_query(&qr, lsec2012 - 7*SECSPERDAY, NULL);
1172	TEST_ASSERT_EQUAL(FALSE, rc);
1173	TEST_ASSERT_EQUAL(0,               qr.warped   );
1174	TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
1175
1176	rc = leapsec_query(&qr, lsec2012 - SECSPERHR, NULL);
1177	TEST_ASSERT_EQUAL(FALSE, rc);
1178	TEST_ASSERT_EQUAL(0,               qr.warped   );
1179	TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
1180
1181	rc = leapsec_query(&qr, lsec2012 - 1, NULL);
1182	TEST_ASSERT_EQUAL(FALSE, rc);
1183	TEST_ASSERT_EQUAL(0,               qr.warped   );
1184	TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
1185
1186	rc = leapsec_query(&qr, lsec2012, NULL);
1187	TEST_ASSERT_EQUAL(TRUE, rc);
1188	TEST_ASSERT_EQUAL(0,            qr.warped   );
1189	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1190
1191	// second call, same time frame: no trigger!
1192	rc = leapsec_query(&qr, lsec2012, NULL);
1193	TEST_ASSERT_EQUAL(FALSE, rc);
1194	TEST_ASSERT_EQUAL(0,             qr.warped   );
1195	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1196}
1197
1198// ----------------------------------------------------------------------
1199// leap second insert at 2012.07.01, dumb mode
1200extern void test_ls2012seqInsDumb(void);
1201void test_ls2012seqInsDumb(void)
1202{
1203	int            rc;
1204	leap_result_t  qr;
1205
1206	rc = setup_load_table(leap1,FALSE);
1207	TEST_ASSERT_EQUAL(1, rc);
1208	TEST_ASSERT_EQUAL(0, leapsec_electric(-1));
1209
1210	rc = leapsec_query(&qr, lsec2012 - 60*SECSPERDAY, NULL);
1211	TEST_ASSERT_EQUAL(FALSE, rc);
1212	TEST_ASSERT_EQUAL(0,             qr.warped   );
1213	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1214
1215	rc = leapsec_query(&qr, lsec2012 - 7*SECSPERDAY, NULL);
1216	TEST_ASSERT_EQUAL(FALSE, rc);
1217	TEST_ASSERT_EQUAL(0,               qr.warped   );
1218	TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
1219
1220	rc = leapsec_query(&qr, lsec2012 - SECSPERHR, NULL);
1221	TEST_ASSERT_EQUAL(FALSE, rc);
1222	TEST_ASSERT_EQUAL(0,               qr.warped   );
1223	TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
1224
1225	rc = leapsec_query(&qr, lsec2012 - 1, NULL);
1226	TEST_ASSERT_EQUAL(FALSE, rc);
1227	TEST_ASSERT_EQUAL(0,               qr.warped   );
1228	TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
1229
1230	// This is just 1 sec before transition!
1231	rc = leapsec_query(&qr, lsec2012, NULL);
1232	TEST_ASSERT_EQUAL(FALSE, rc);
1233	TEST_ASSERT_EQUAL(0,            qr.warped   );
1234	TEST_ASSERT_EQUAL(LSPROX_ALERT, qr.proximity);
1235
1236	// NOW the insert/backwarp must happen
1237	rc = leapsec_query(&qr, lsec2012+1, NULL);
1238	TEST_ASSERT_EQUAL(TRUE, rc);
1239	TEST_ASSERT_EQUAL(-1,            qr.warped   );
1240	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1241
1242	// second call with transition time: no trigger!
1243	rc = leapsec_query(&qr, lsec2012, NULL);
1244	TEST_ASSERT_EQUAL(FALSE, rc);
1245	TEST_ASSERT_EQUAL(0,             qr.warped   );
1246	TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1247}
1248
1249// ----------------------------------------------------------------------
1250// test repeated query on empty table in dumb mode
1251extern void test_lsEmptyTableDumb(void);
1252void test_lsEmptyTableDumb(void)
1253{
1254	int            rc;
1255	leap_result_t  qr;
1256
1257	const time_t   pivot = lsec2012;
1258	const uint32_t t0 = lsec2012 - 10;
1259	const uint32_t tE = lsec2012 + 10;
1260
1261	TEST_ASSERT_EQUAL(0, leapsec_electric(-1));
1262
1263	uint32_t t;
1264	for (t = t0; t != tE; ++t) {
1265		rc = leapsec_query(&qr, t, &pivot);
1266		TEST_ASSERT_EQUAL(FALSE, rc);
1267		TEST_ASSERT_EQUAL(0,             qr.warped   );
1268		TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1269	}
1270}
1271
1272// ----------------------------------------------------------------------
1273// test repeated query on empty table in electric mode
1274extern void test_lsEmptyTableElectric(void);
1275void test_lsEmptyTableElectric(void)
1276{
1277	int            rc;
1278	leap_result_t  qr;
1279
1280	leapsec_electric(1);
1281	TEST_ASSERT_EQUAL(1, leapsec_electric(-1));
1282
1283	const time_t   pivot = lsec2012;
1284	const uint32_t t0 = lsec2012 - 10;
1285	const uint32_t tE = lsec2012 + 10;
1286
1287	time_t t;
1288	for (t = t0; t != tE; ++t) {
1289		rc = leapsec_query(&qr, t, &pivot);
1290		TEST_ASSERT_EQUAL(FALSE, rc);
1291		TEST_ASSERT_EQUAL(0,             qr.warped   );
1292		TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
1293	}
1294}
1295