]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
g_leapsec.cpp:
authorDamir Tomic <viperus@ntp.org>
Wed, 1 Jul 2015 07:31:35 +0000 (09:31 +0200)
committerDamir Tomic <viperus@ntp.org>
Wed, 1 Jul 2015 07:31:35 +0000 (09:31 +0200)
  Rename: tests/ntpd/leapsec.cpp -> tests/ntpd/g_leapsec.cpp
run-leapsec.c, leapsec.c:
  new file
Makefile.am:
  added /tests/ntpd/ dir
  unity tests
  removed a comment line
g_ntpdtest.h:
  Rename: tests/ntpd/ntpdtest.h -> tests/ntpd/g_ntpdtest.h
Makefile.am:
  added support for unity tests
test-libntp.h:
  added new headers
g_ntpdtest.cpp:
  minor change in the header name
  Rename: tests/ntpd/ntpdtest.cpp -> tests/ntpd/g_ntpdtest.cpp

bk: 55939757LDuYS6xJygO9e0ZD3-1NrQ

tests/Makefile.am
tests/libntp/Makefile.am
tests/libntp/test-libntp.h
tests/ntpd/Makefile.am
tests/ntpd/g_leapsec.cpp [moved from tests/ntpd/leapsec.cpp with 100% similarity]
tests/ntpd/g_ntpdtest.cpp [moved from tests/ntpd/ntpdtest.cpp with 96% similarity]
tests/ntpd/g_ntpdtest.h [moved from tests/ntpd/ntpdtest.h with 100% similarity]
tests/ntpd/leapsec.c [new file with mode: 0644]
tests/ntpd/run-leapsec.c [new file with mode: 0644]

index a9f88bae871a8bb38120e2c25a2d5f3d5572b638..3232bc39b20d68af08d2a9e37fc26ce00547a967 100644 (file)
@@ -2,15 +2,16 @@ NULL =
 SUBDIRS = 
 DIST_SUBDIRS = 
 
-if GTEST_AVAILABLE
-SUBDIRS +=     \
-       ntpd    \
-       $(NULL)
-endif
+#if GTEST_AVAILABLE
+#SUBDIRS +=    \
+#      ntpd    \
+#      $(NULL)
+#endif
 
 SUBDIRS +=             \
        bug-2803        \
        libntp          \
+       ntpd            \
        $(NULL)
 
 DIST_SUBDIRS +=                \
index 288d38c79b7b0f2b0e4513b7f9342767666d5b97..8bf1312fc773bb7adefd8413b017ba13d14f03b2 100644 (file)
@@ -4,7 +4,6 @@ CLEANFILES =
 
 run_unity =    cd $(srcdir) && ruby ../../sntp/unity/auto/generate_test_runner.rb
 
-#removed test-libntp
 check_PROGRAMS =               \
        test-a_md5encrypt       \
        test-atoint             \
index eb113cd52c5332899cb1fb98da4566e4525b54c7..93050b32a1e250c5c5a89763283f9f05f54ce8db 100644 (file)
@@ -1,3 +1,8 @@
+#include "config.h"
+
+#include "ntp_stdlib.h"
+#include "ntp_calendar.h"
+
 time_t timefunc(time_t *ptr);
 void settime(int y, int m, int d, int H, int M, int S);
 time_t nowtime;
index c5df6e4a32c4213fffbec7b4721d4efdd8ebec99..863042fb2cd04313fe810bbe790e46231a1948f1 100644 (file)
@@ -2,10 +2,21 @@ NULL =
 BUILT_SOURCES =
 CLEANFILES =
 
-check_PROGRAMS = tests
+run_unity =    cd $(srcdir) && ruby ../../sntp/unity/auto/generate_test_runner.rb
+
+check_PROGRAMS =               \
+       test-leapsec            \
+       $(NULL)
+
+if GTEST_AVAILABLE
+check_PROGRAMS += tests
+else
+EXTRA_PROGRAMS = tests
+endif
 
 LDADD =                                        \
        $(top_builddir)/libntp/libntp.a \
+       $(top_builddir)/ntpd/libntpd.a  \
        $(LDADD_LIBNTP)                 \
        $(PTHREAD_LIBS)                 \
        $(LDADD_NTP)                    \
@@ -13,26 +24,59 @@ LDADD =                                     \
        $(GTEST_LIBS)                   \
        $(NULL)
 
+unity_tests_LDADD =                            \
+       $(LDADD)                                \
+       $(top_builddir)/sntp/unity/libunity.a   \
+       $(LIBM)                                 \
+       $(NULL)
+
 AM_CFLAGS   = $(CFLAGS_NTP)
 AM_CXXFLAGS = $(GTEST_CXXFLAGS)
 
 AM_CPPFLAGS  = $(NTP_INCS)
 AM_CPPFLAGS += -I$(top_srcdir)/sntp
 AM_CPPFLAGS += -I$(top_srcdir)/ntpd
+AM_CPPFLAGS += -I$(top_srcdir)/tests/libntp
 AM_CPPFLAGS += $(GTEST_CPPFLAGS)
 AM_CPPFLAGS += $(CPPFLAGS_NTP)
 
 AM_LDFLAGS = $(LDFLAGS_NTP)
 
 tests_SOURCES = $(top_srcdir)/sntp/tests_main.cpp      \
-               ntpdtest.cpp            \
+               g_ntpdtest.cpp          \
                $(top_srcdir)/ntpd/ntp_leapsec.c        \
-               leapsec.cpp     \
+               g_leapsec.cpp   \
                $(NULL)
 
-noinst_HEADERS =       ntpdtest.h      \
+BUILT_SOURCES +=                       \
+       $(srcdir)/run-leapsec.c         \
+       $(NULL)
+
+noinst_HEADERS =       g_ntpdtest.h            \
+                       $(srcdir)/../libntp/test-libntp.h       \
                        $(NULL)
 
+###
+
+test_leapsec_CFLAGS =                  \
+       -I$(top_srcdir)/sntp/unity      \
+       $(NULL)
+#probably needs -lpthread in LDADD
+test_leapsec_LDADD =                   \
+       $(unity_tests_LDADD)            \
+       $(NULL)
+
+test_leapsec_SOURCES =                 \
+       leapsec.c                       \
+       run-leapsec.c                   \
+       $(srcdir)/../libntp/test-libntp.c               \
+       $(NULL)
+
+$(srcdir)/run-leapsec.c: $(srcdir)/leapsec.c $(std_unity_list)
+       $(run_unity) leapsec.c run-leapsec.c
+
+###
+
 TESTS =
 
 if !NTP_CROSSCOMPILE
@@ -42,8 +86,8 @@ endif
 ## check-libntp.mf - automake fragment
 ## slightly adapted for deeper directory
 
-BUILT_SOURCES  += check-libntp
-CLEANFILES     += check-libntp
+BUILT_SOURCES  += check-libntp check-libunity check-libntpd
+CLEANFILES     += check-libntp check-libunity check-libntpd
 
 check-libntp: ../../libntp/libntp.a
        @echo stamp > $@
@@ -51,5 +95,17 @@ check-libntp: ../../libntp/libntp.a
 ../../libntp/libntp.a:
        cd ../../libntp && $(MAKE) $(AM_MAKEFLAGS) libntp.a
 
+check-libntpd: ../../ntpd/libntpd.a
+       @echo stamp > $@
+
+../../ntpd/libntpd.a:
+       cd ../../ntpd && $(MAKE) $(AM_MAKEFLAGS) libntpd.a
+
+check-libunity: ../../sntp/unity/libunity.a
+       @echo stamp > $@
+
+../../sntp/unity/libunity.a:
+       cd ../../sntp/unity && $(MAKE) $(AM_MAKEFLAGS) libunity.a
+
 include $(top_srcdir)/depsver.mf
 include $(top_srcdir)/includes.mf
similarity index 96%
rename from tests/ntpd/ntpdtest.cpp
rename to tests/ntpd/g_ntpdtest.cpp
index 76b3b1a254bcf36c25ce15b471e49980c9f0dad8..759989643892d8dac676d8fb6461382e0a2d9ed0 100644 (file)
@@ -1,4 +1,4 @@
-#include "ntpdtest.h"
+#include "g_ntpdtest.h"
 
 /* This file contains various constants that libntp needs to be set
  *  and that is normally defined in ntpd/ntpq/...
diff --git a/tests/ntpd/leapsec.c b/tests/ntpd/leapsec.c
new file mode 100644 (file)
index 0000000..a196b39
--- /dev/null
@@ -0,0 +1,1230 @@
+//#include "ntpdtest.h"
+#include "config.h"
+
+//maybe ntp_stdlib and the other one? types? 
+
+#include "ntp.h"
+#include "ntp_calendar.h"
+#include "ntp_stdlib.h"
+#include "ntp_leapsec.h"
+
+#include "unity.h"
+
+#include <string.h>
+//#include <sstream>
+
+static const char leap1 [] =
+    "#\n"
+    "#@        3610569600\n"
+    "#\n"
+    "2272060800 10     # 1 Jan 1972\n"
+    "2287785600        11      # 1 Jul 1972\n"
+    "2303683200        12      # 1 Jan 1973\n"
+    "2335219200        13      # 1 Jan 1974\n"
+    "2366755200        14      # 1 Jan 1975\n"
+    "2398291200        15      # 1 Jan 1976\n"
+    "2429913600        16      # 1 Jan 1977\n"
+    "2461449600        17      # 1 Jan 1978\n"
+    "2492985600        18      # 1 Jan 1979\n"
+    "2524521600        19      # 1 Jan 1980\n"
+    "   \t  \n"
+    "2571782400        20      # 1 Jul 1981\n"
+    "2603318400        21      # 1 Jul 1982\n"
+    "2634854400        22      # 1 Jul 1983\n"
+    "2698012800        23      # 1 Jul 1985\n"
+    "2776982400        24      # 1 Jan 1988\n"
+    "2840140800        25      # 1 Jan 1990\n"
+    "2871676800        26      # 1 Jan 1991\n"
+    "2918937600        27      # 1 Jul 1992\n"
+    "2950473600        28      # 1 Jul 1993\n"
+    "2982009600        29      # 1 Jul 1994\n"
+    "3029443200        30      # 1 Jan 1996\n"
+    "3076704000        31      # 1 Jul 1997\n"
+    "3124137600        32      # 1 Jan 1999\n"
+    "3345062400        33      # 1 Jan 2006\n"
+    "3439756800        34      # 1 Jan 2009\n"
+    "3550089600        35      # 1 Jul 2012\n"
+    "#\n"
+    "#h        dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n"
+    "#\n";
+
+static const char leap2 [] =
+    "#\n"
+    "#@        2950473700\n"
+    "#\n"
+    "2272060800 10     # 1 Jan 1972\n"
+    "2287785600        11      # 1 Jul 1972\n"
+    "2303683200        12      # 1 Jan 1973\n"
+    "2335219200        13      # 1 Jan 1974\n"
+    "2366755200        14      # 1 Jan 1975\n"
+    "2398291200        15      # 1 Jan 1976\n"
+    "2429913600        16      # 1 Jan 1977\n"
+    "2461449600        17      # 1 Jan 1978\n"
+    "2492985600        18      # 1 Jan 1979\n"
+    "2524521600        19      # 1 Jan 1980\n"
+    "2571782400        20      # 1 Jul 1981\n"
+    "2603318400        21      # 1 Jul 1982\n"
+    "2634854400        22      # 1 Jul 1983\n"
+    "2698012800        23      # 1 Jul 1985\n"
+    "2776982400        24      # 1 Jan 1988\n"
+    "2840140800        25      # 1 Jan 1990\n"
+    "2871676800        26      # 1 Jan 1991\n"
+    "2918937600        27      # 1 Jul 1992\n"
+    "2950473600        28      # 1 Jul 1993\n"
+    "#\n";
+
+// Faked table with a leap second removal at 2009 
+static const char leap3 [] =
+    "#\n"
+    "#@        3610569600\n"
+    "#\n"
+    "2272060800 10     # 1 Jan 1972\n"
+    "2287785600        11      # 1 Jul 1972\n"
+    "2303683200        12      # 1 Jan 1973\n"
+    "2335219200        13      # 1 Jan 1974\n"
+    "2366755200        14      # 1 Jan 1975\n"
+    "2398291200        15      # 1 Jan 1976\n"
+    "2429913600        16      # 1 Jan 1977\n"
+    "2461449600        17      # 1 Jan 1978\n"
+    "2492985600        18      # 1 Jan 1979\n"
+    "2524521600        19      # 1 Jan 1980\n"
+    "2571782400        20      # 1 Jul 1981\n"
+    "2603318400        21      # 1 Jul 1982\n"
+    "2634854400        22      # 1 Jul 1983\n"
+    "2698012800        23      # 1 Jul 1985\n"
+    "2776982400        24      # 1 Jan 1988\n"
+    "2840140800        25      # 1 Jan 1990\n"
+    "2871676800        26      # 1 Jan 1991\n"
+    "2918937600        27      # 1 Jul 1992\n"
+    "2950473600        28      # 1 Jul 1993\n"
+    "2982009600        29      # 1 Jul 1994\n"
+    "3029443200        30      # 1 Jan 1996\n"
+    "3076704000        31      # 1 Jul 1997\n"
+    "3124137600        32      # 1 Jan 1999\n"
+    "3345062400        33      # 1 Jan 2006\n"
+    "3439756800        32      # 1 Jan 2009\n"
+    "3550089600        33      # 1 Jul 2012\n"
+    "#\n";
+
+// short table with good hash
+static const char leap_ghash [] =
+    "#\n"
+    "#@        3610569600\n"
+    "#$        3610566000\n"
+    "#\n"
+    "2272060800 10     # 1 Jan 1972\n"
+    "2287785600        11      # 1 Jul 1972\n"
+    "2303683200        12      # 1 Jan 1973\n"
+    "2335219200        13      # 1 Jan 1974\n"
+    "2366755200        14      # 1 Jan 1975\n"
+    "2398291200        15      # 1 Jan 1976\n"
+    "2429913600        16      # 1 Jan 1977\n"
+    "2461449600        17      # 1 Jan 1978\n"
+    "2492985600        18      # 1 Jan 1979\n"
+    "2524521600        19      # 1 Jan 1980\n"
+    "#\n"
+    "#h 4b304e10 95642b3f c10b91f9 90791725 25f280d0\n"
+    "#\n";
+
+// short table with bad hash
+static const char leap_bhash [] =
+    "#\n"
+    "#@        3610569600\n"
+    "#$        3610566000\n"
+    "#\n"
+    "2272060800 10     # 1 Jan 1972\n"
+    "2287785600        11      # 1 Jul 1972\n"
+    "2303683200        12      # 1 Jan 1973\n"
+    "2335219200        13      # 1 Jan 1974\n"
+    "2366755200        14      # 1 Jan 1975\n"
+    "2398291200        15      # 1 Jan 1976\n"
+    "2429913600        16      # 1 Jan 1977\n"
+    "2461449600        17      # 1 Jan 1978\n"
+    "2492985600        18      # 1 Jan 1979\n"
+    "2524521600        19      # 1 Jan 1980\n"
+    "#\n"
+    "#h        dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n"
+    "#\n";
+
+// short table with malformed hash
+static const char leap_mhash [] =
+    "#\n"
+    "#@        3610569600\n"
+    "#$        3610566000\n"
+    "#\n"
+    "2272060800 10     # 1 Jan 1972\n"
+    "2287785600        11      # 1 Jul 1972\n"
+    "2303683200        12      # 1 Jan 1973\n"
+    "2335219200        13      # 1 Jan 1974\n"
+    "2366755200        14      # 1 Jan 1975\n"
+    "2398291200        15      # 1 Jan 1976\n"
+    "2429913600        16      # 1 Jan 1977\n"
+    "2461449600        17      # 1 Jan 1978\n"
+    "2492985600        18      # 1 Jan 1979\n"
+    "2524521600        19      # 1 Jan 1980\n"
+    "#\n"
+    "#h f2349a02 788b9534 a8f2e141 f2029Q6d 4064a7ee\n"
+    "#\n";
+
+// short table with only 4 hash groups
+static const char leap_shash [] =
+    "#\n"
+    "#@        3610569600\n"
+    "#$        3610566000\n"
+    "#\n"
+    "2272060800 10     # 1 Jan 1972\n"
+    "2287785600        11      # 1 Jul 1972\n"
+    "2303683200        12      # 1 Jan 1973\n"
+    "2335219200        13      # 1 Jan 1974\n"
+    "2366755200        14      # 1 Jan 1975\n"
+    "2398291200        15      # 1 Jan 1976\n"
+    "2429913600        16      # 1 Jan 1977\n"
+    "2461449600        17      # 1 Jan 1978\n"
+    "2492985600        18      # 1 Jan 1979\n"
+    "2524521600        19      # 1 Jan 1980\n"
+    "#\n"
+    "#h f2349a02 788b9534 a8f2e141 f2029Q6d\n"
+    "#\n";
+
+// table with good hash and truncated/missing leading zeros
+static const char leap_gthash [] = {
+    "#\n"
+    "#$         3535228800\n"
+    "#\n"
+    "# Updated through IERS Bulletin C46\n"
+    "# File expires on:  28 June 2014\n"
+    "#\n"
+    "#@        3612902400\n"
+    "#\n"
+    "2272060800        10      # 1 Jan 1972\n"
+    "2287785600        11      # 1 Jul 1972\n"
+    "2303683200        12      # 1 Jan 1973\n"
+    "2335219200        13      # 1 Jan 1974\n"
+    "2366755200        14      # 1 Jan 1975\n"
+    "2398291200        15      # 1 Jan 1976\n"
+    "2429913600        16      # 1 Jan 1977\n"
+    "2461449600        17      # 1 Jan 1978\n"
+    "2492985600        18      # 1 Jan 1979\n"
+    "2524521600        19      # 1 Jan 1980\n"
+    "2571782400        20      # 1 Jul 1981\n"
+    "2603318400        21      # 1 Jul 1982\n"
+    "2634854400        22      # 1 Jul 1983\n"
+    "2698012800        23      # 1 Jul 1985\n"
+    "2776982400        24      # 1 Jan 1988\n"
+    "2840140800        25      # 1 Jan 1990\n"
+    "2871676800        26      # 1 Jan 1991\n"
+    "2918937600        27      # 1 Jul 1992\n"
+    "2950473600        28      # 1 Jul 1993\n"
+    "2982009600        29      # 1 Jul 1994\n"
+    "3029443200        30      # 1 Jan 1996\n"
+    "3076704000        31      # 1 Jul 1997\n"
+    "3124137600        32      # 1 Jan 1999\n"
+    "3345062400        33      # 1 Jan 2006\n"
+    "3439756800        34      # 1 Jan 2009\n"
+    "3550089600        35      # 1 Jul 2012\n"
+    "#\n"
+    "#h        1151a8f e85a5069 9000fcdb 3d5e5365 1d505b37"
+};
+
+static const uint32_t lsec2006 = 3345062400u; // +33, 1 Jan 2006, 00:00:00 utc
+static const uint32_t lsec2009 = 3439756800u; // +34, 1 Jan 2009, 00:00:00 utc
+static const uint32_t lsec2012 = 3550089600u; // +35, 1 Jul 2012, 00:00:00 utc
+static const uint32_t lsec2015 = 3644697600u; // +36, 1 Jul 2015, 00:00:00 utc
+
+int stringreader(void* farg)
+{
+       const char ** cpp = (const char**)farg;
+       if (**cpp)
+               return *(*cpp)++;
+       else
+               return EOF;
+}
+
+static int/*BOOL*/
+setup_load_table(
+       const char * cp,
+       int          blim)
+{
+       int            rc;
+       leap_table_t * pt = leapsec_get_table(0);
+       rc = (pt != NULL) && leapsec_load(pt, stringreader, &cp, blim);
+       rc = rc && leapsec_set_table(pt);
+       return rc;
+}
+
+static int/*BOOL*/
+setup_clear_table()
+{
+       int            rc;
+       leap_table_t * pt = leapsec_get_table(0);
+       if (pt)
+               leapsec_clear(pt);
+       rc = leapsec_set_table(pt);
+       return rc;
+}
+
+
+char * CalendarToString(const struct calendar cal) {
+       char * ss = malloc (sizeof (char) * 100);
+       
+       char buffer[100] ="";
+       sprintf(buffer, "%u", cal.year);
+       strcat(ss,buffer);
+       strcat(ss,"-");
+       sprintf(buffer, "%u", (u_int)cal.month);
+       strcat(ss,buffer);
+       strcat(ss,"-");
+       sprintf(buffer, "%u", (u_int)cal.monthday);
+       strcat(ss,buffer);
+       strcat(ss," (");
+       sprintf(buffer, "%u", (u_int) cal.yearday);
+       strcat(ss,buffer);
+       strcat(ss,") ");
+       sprintf(buffer, "%u", (u_int)cal.hour);
+       strcat(ss,buffer);
+       strcat(ss,":");
+       sprintf(buffer, "%u", (u_int)cal.minute);
+       strcat(ss,buffer);
+       strcat(ss,":");
+       sprintf(buffer, "%u", (u_int)cal.second);
+       strcat(ss,buffer);
+       //ss << cal.year << "-" << (u_int)cal.month << "-" << (u_int)cal.monthday << " (" << cal.yearday << ") " << (u_int)cal.hour << ":" << (u_int)cal.minute << ":" << (u_int)cal.second;
+       return ss;
+}
+
+
+int IsEqual(const struct calendar expected, const struct calendar actual) {
+       if (expected.year == actual.year &&
+               (expected.yearday == actual.yearday ||
+                (expected.month == actual.month &&
+                 expected.monthday == actual.monthday)) &&
+               expected.hour == actual.hour &&
+               expected.minute == actual.minute &&
+               expected.second == actual.second) {
+               return TRUE;
+       } else {
+               printf("expected: %s but was %s", CalendarToString(expected) ,CalendarToString(actual));
+               return FALSE;
+                       
+       }
+}
+
+//-------------------------
+
+void setUp()
+{
+       //init_lib();
+       //init_auth();
+extern time_t timefunc;
+    ntpcal_set_timefunc(timefunc);
+    settime(1970, 1, 1, 0, 0, 0);
+    leapsec_ut_pristine();
+}
+
+void tearDown()
+{
+    ntpcal_set_timefunc(NULL);
+}
+
+// =====================================================================
+// VALIDATION TESTS
+// =====================================================================
+
+// ----------------------------------------------------------------------
+void test_ValidateGood() {
+       const char *cp = leap_ghash;
+       int         rc = leapsec_validate(stringreader, &cp);
+       TEST_ASSERT_EQUAL(LSVALID_GOODHASH, rc);
+}
+
+// ----------------------------------------------------------------------
+void test_ValidateNoHash() {
+       const char *cp = leap2;
+       int         rc = leapsec_validate(stringreader, &cp);
+       TEST_ASSERT_EQUAL(LSVALID_NOHASH, rc);
+}
+
+// ----------------------------------------------------------------------
+void test_ValidateBad() {
+       const char *cp = leap_bhash;
+       int         rc = leapsec_validate(stringreader, &cp);
+       TEST_ASSERT_EQUAL(LSVALID_BADHASH, rc);
+}
+
+// ----------------------------------------------------------------------
+void test_ValidateMalformed() {
+       const char *cp = leap_mhash;
+       int         rc = leapsec_validate(stringreader, &cp);
+       TEST_ASSERT_EQUAL(LSVALID_BADFORMAT, rc);
+}
+
+// ----------------------------------------------------------------------
+void test_ValidateMalformedShort() {
+       const char *cp = leap_shash;
+       int         rc = leapsec_validate(stringreader, &cp);
+       TEST_ASSERT_EQUAL(LSVALID_BADFORMAT, rc);
+}
+
+// ----------------------------------------------------------------------
+void test_ValidateNoLeadZero() {
+       const char *cp = leap_gthash;
+       int         rc = leapsec_validate(stringreader, &cp);
+       TEST_ASSERT_EQUAL(LSVALID_GOODHASH, rc);
+}
+
+// =====================================================================
+// BASIC FUNCTIONS
+// =====================================================================
+
+// ----------------------------------------------------------------------
+// test table selection
+void test_tableSelect() {
+       leap_table_t *pt1, *pt2, *pt3, *pt4;
+
+       pt1 = leapsec_get_table(0);
+       pt2 = leapsec_get_table(0);
+       TEST_ASSERT_EQUAL(pt1, pt2);
+
+       pt1 = leapsec_get_table(1);
+       pt2 = leapsec_get_table(1);
+       TEST_ASSERT_EQUAL(pt1, pt2);
+
+       pt1 = leapsec_get_table(1);
+       pt2 = leapsec_get_table(0);
+       TEST_ASSERT_NOT_EQUAL(pt1, pt2);
+
+       pt1 = leapsec_get_table(0);
+       pt2 = leapsec_get_table(1);
+       TEST_ASSERT_NOT_EQUAL(pt1, pt2);
+
+       leapsec_set_table(pt1);
+       pt2 = leapsec_get_table(0);
+       pt3 = leapsec_get_table(1);
+       TEST_ASSERT_EQUAL(pt1, pt2);
+       TEST_ASSERT_NOT_EQUAL(pt2, pt3);
+
+       pt1 = pt3;
+       leapsec_set_table(pt1);
+       pt2 = leapsec_get_table(0);
+       pt3 = leapsec_get_table(1);
+       TEST_ASSERT_EQUAL(pt1, pt2);
+       TEST_ASSERT_NOT_EQUAL(pt2, pt3);
+}
+
+// ----------------------------------------------------------------------
+// load file & check expiration
+void test_loadFileExpire() {
+       const char *cp = leap1;
+       int rc;
+       leap_table_t * pt = leapsec_get_table(0);
+
+       rc =   leapsec_load(pt, stringreader, &cp, FALSE)
+           && leapsec_set_table(pt);
+       TEST_ASSERT_EQUAL(1, rc);
+       rc = leapsec_expired(3439756800u, NULL);
+       TEST_ASSERT_EQUAL(0, rc);
+       rc = leapsec_expired(3610569601u, NULL);
+       TEST_ASSERT_EQUAL(1, rc);
+}
+
+// ----------------------------------------------------------------------
+// load file & check time-to-live
+void test_loadFileTTL() {
+       const char *cp = leap1;
+       int rc;
+       leap_table_t * pt = leapsec_get_table(0);
+       time_t         pivot = 0x70000000u;
+
+       const uint32_t limit = 3610569600u;
+
+       rc =   leapsec_load(pt, stringreader, &cp, FALSE)
+           && leapsec_set_table(pt);
+       TEST_ASSERT_EQUAL(1, rc); //
+
+       // exactly 1 day to live
+       rc = leapsec_daystolive(limit - 86400, &pivot);
+       TEST_ASSERT_EQUAL( 1, rc);      
+       // less than 1 day to live
+       rc = leapsec_daystolive(limit - 86399, &pivot);
+       TEST_ASSERT_EQUAL( 0, rc);      
+       // hit expiration exactly
+       rc = leapsec_daystolive(limit, &pivot);
+       TEST_ASSERT_EQUAL( 0, rc);      
+       // expired since 1 sec
+       rc = leapsec_daystolive(limit + 1, &pivot);
+       TEST_ASSERT_EQUAL(-1, rc);      
+}
+
+// =====================================================================
+// RANDOM QUERY TESTS
+// =====================================================================
+
+// ----------------------------------------------------------------------
+// test query in pristine state (bug#2745 misbehaviour)
+void test_lsQueryPristineState() {
+       int            rc;
+       leap_result_t  qr;
+       
+       rc = leapsec_query(&qr, lsec2012, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// ad-hoc jump: leap second at 2009.01.01 -60days
+void test_ls2009faraway() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap1,FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+
+       // test 60 days before leap. Nothing scheduled or indicated.
+       rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(33, qr.tai_offs);
+       TEST_ASSERT_EQUAL(0,  qr.tai_diff);
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// ad-hoc jump: leap second at 2009.01.01 -1week
+void test_ls2009weekaway() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap1,FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+
+       // test 7 days before leap. Leap scheduled, but not yet indicated.
+       rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(33, qr.tai_offs);
+       TEST_ASSERT_EQUAL(1,  qr.tai_diff);
+       TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// ad-hoc jump: leap second at 2009.01.01 -1hr
+void test_ls2009houraway() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap1,FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+
+       // test 1 hour before leap. 61 true seconds to go.
+       rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(33, qr.tai_offs);
+       TEST_ASSERT_EQUAL(1,  qr.tai_diff);
+       TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// ad-hoc jump: leap second at 2009.01.01 -1sec
+void test_ls2009secaway() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap1,FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+
+       // test 1 second before leap (last boundary...) 2 true seconds to go.
+       rc = leapsec_query(&qr, lsec2009 - 1, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(33, qr.tai_offs);
+       TEST_ASSERT_EQUAL(1,  qr.tai_diff);
+       TEST_ASSERT_EQUAL(LSPROX_ALERT, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// ad-hoc jump to leap second at 2009.01.01
+void test_ls2009onspot() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap1,FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+
+       // test on-spot: treat leap second as already gone.
+       rc = leapsec_query(&qr, lsec2009, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(34, qr.tai_offs);
+       TEST_ASSERT_EQUAL(0,  qr.tai_diff);
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// test handling of the leap second at 2009.01.01 without table
+void test_ls2009nodata() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_clear_table();
+       TEST_ASSERT_EQUAL(1, rc);
+
+       // test on-spot with empty table
+       rc = leapsec_query(&qr, lsec2009, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,  qr.tai_offs);
+       TEST_ASSERT_EQUAL(0,  qr.tai_diff);
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// test handling of the leap second at 2009.01.01 with culled data
+void test_ls2009limdata() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap1, TRUE);
+       TEST_ASSERT_EQUAL(1, rc);
+
+       // test on-spot with limited table - this is tricky.
+       // The table used ends 2012; depending on the build date, the 2009 entry
+       // might be included or culled. The resulting TAI offset must be either
+       // 34 or 35 seconds, depending on the build date of the test. 
+       rc = leapsec_query(&qr, lsec2009, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_TRUE(34 <= qr.tai_offs);
+       TEST_ASSERT_TRUE(35 >= qr.tai_offs);
+       TEST_ASSERT_EQUAL(0,  qr.tai_diff);
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// Far-distance forward jump into a transiton window.
+void test_qryJumpFarAhead() {
+       int            rc;
+       leap_result_t  qr;
+       int            last, idx;
+       int             mode;
+
+       for (mode=0; mode < 2; ++mode) {
+               leapsec_ut_pristine();
+               rc = setup_load_table(leap1, FALSE);
+               TEST_ASSERT_EQUAL(1, rc);
+               leapsec_electric(mode);
+
+               rc = leapsec_query(&qr, lsec2006, NULL);
+               TEST_ASSERT_EQUAL(FALSE, rc);
+
+               rc = leapsec_query(&qr, lsec2012, NULL);
+               TEST_ASSERT_EQUAL(FALSE, rc);
+       }
+}
+
+// ----------------------------------------------------------------------
+// Forward jump into the next transition window
+void test_qryJumpAheadToTransition() {
+       int            rc;
+       leap_result_t  qr;
+       int            last, idx;
+       int             mode;
+
+       for (mode=0; mode < 2; ++mode) {
+               leapsec_ut_pristine();
+               rc = setup_load_table(leap1, FALSE);
+               TEST_ASSERT_EQUAL(1, rc);
+               leapsec_electric(mode);
+
+               rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL);
+               TEST_ASSERT_EQUAL(FALSE, rc);
+
+               rc = leapsec_query(&qr, lsec2009+1, NULL);
+               TEST_ASSERT_EQUAL(TRUE, rc);
+       }
+}
+
+// ----------------------------------------------------------------------
+// Forward jump over the next transition window
+void test_qryJumpAheadOverTransition() {
+       int            rc;
+       leap_result_t  qr;
+       int            last, idx;
+       int             mode;
+
+       for (mode=0; mode < 2; ++mode) {
+               leapsec_ut_pristine();
+               rc = setup_load_table(leap1, FALSE);
+               TEST_ASSERT_EQUAL(1, rc);
+               leapsec_electric(mode);
+
+               rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL);
+               TEST_ASSERT_EQUAL(FALSE, rc);
+
+               rc = leapsec_query(&qr, lsec2009+5, NULL);
+               TEST_ASSERT_EQUAL(FALSE, rc);
+       }
+}
+
+// =====================================================================
+// TABLE MODIFICATION AT RUNTIME
+// =====================================================================
+
+// ----------------------------------------------------------------------
+// add dynamic leap second (like from peer/clock)
+void test_addDynamic() {
+       int            rc;
+       leap_result_t  qr;
+
+       static const uint32_t insns[] = {
+               2982009600u,    //      29      # 1 Jul 1994
+               3029443200u,    //      30      # 1 Jan 1996
+               3076704000u,    //      31      # 1 Jul 1997
+               3124137600u,    //      32      # 1 Jan 1999
+               3345062400u,    //      33      # 1 Jan 2006
+               3439756800u,    //      34      # 1 Jan 2009
+               3550089600u,    //      35      # 1 Jul 2012
+               0 // sentinel
+       };
+
+       rc = setup_load_table(leap2, FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+
+       leap_table_t * pt = leapsec_get_table(0);
+       int             idx;
+
+       for (idx=1; insns[idx]; ++idx) {
+               rc = leapsec_add_dyn(TRUE, insns[idx] - 20*SECSPERDAY - 100, NULL);
+               TEST_ASSERT_EQUAL(TRUE, rc);
+       }
+       // try to slip in a previous entry
+       rc = leapsec_add_dyn(TRUE, insns[0] - 20*SECSPERDAY - 100, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
+}
+
+// ----------------------------------------------------------------------
+// add fixed leap seconds (like from network packet)
+#if 0 /* currently unused -- possibly revived later */
+void FAILtest_addFixed() {
+       int            rc;
+       leap_result_t  qr;
+
+       static const struct { uint32_t tt; int of; } insns[] = {
+               {2982009600u, 29},//    # 1 Jul 1994
+               {3029443200u, 30},//    # 1 Jan 1996
+               {3076704000u, 31},//    # 1 Jul 1997
+               {3124137600u, 32},//    # 1 Jan 1999
+               {3345062400u, 33},//    # 1 Jan 2006
+               {3439756800u, 34},//    # 1 Jan 2009
+               {3550089600u, 35},//    # 1 Jul 2012
+               {0,0} // sentinel
+       };
+
+       rc = setup_load_table(leap2, FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+       int idx;
+       leap_table_t * pt = leapsec_get_table(0);
+       // try to get in BAD time stamps...
+       for (idx=0; insns[idx].tt; ++idx) {
+           rc = leapsec_add_fix(
+               insns[idx].of,
+               insns[idx].tt - 20*SECSPERDAY - 100,
+               insns[idx].tt + SECSPERDAY,
+               NULL);
+               TEST_ASSERT_EQUAL(FALSE, rc);
+       }
+       // now do it right
+       for (idx=0; insns[idx].tt; ++idx) {
+               rc = leapsec_add_fix(
+                   insns[idx].of,
+                   insns[idx].tt,
+                   insns[idx].tt + SECSPERDAY,
+                   NULL);
+               TEST_ASSERT_EQUAL(TRUE, rc);
+       }
+       // try to slip in a previous entry
+       rc = leapsec_add_fix(
+           insns[0].of,
+           insns[0].tt,
+           insns[0].tt + SECSPERDAY,
+           NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
+}
+#endif
+
+// ----------------------------------------------------------------------
+// add fixed leap seconds (like from network packet)
+#if 0 /* currently unused -- possibly revived later */
+void FAILtest_addFixedExtend() {
+       int            rc;
+       leap_result_t  qr;
+       int            last, idx;
+
+       static const struct { uint32_t tt; int of; } insns[] = {
+               {2982009600u, 29},//    # 1 Jul 1994
+               {3029443200u, 30},//    # 1 Jan 1996
+               {0,0} // sentinel
+       };
+
+       rc = setup_load_table(leap2, FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+
+       leap_table_t * pt = leapsec_get_table(FALSE);
+       for (last=idx=0; insns[idx].tt; ++idx) {
+               last = idx;
+               rc = leapsec_add_fix(
+                   insns[idx].of,
+                   insns[idx].tt,
+                   insns[idx].tt + SECSPERDAY,
+                   NULL);
+               TEST_ASSERT_EQUAL(TRUE, rc);
+       }
+       
+       // try to extend the expiration of the last entry
+       rc = leapsec_add_fix(
+           insns[last].of,
+           insns[last].tt,
+           insns[last].tt + 128*SECSPERDAY,
+           NULL);
+       TEST_ASSERT_EQUAL(TRUE, rc);
+       
+       // try to extend the expiration of the last entry with wrong offset
+       rc = leapsec_add_fix(
+           insns[last].of+1,
+           insns[last].tt,
+           insns[last].tt + 129*SECSPERDAY,
+           NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
+}
+#endif
+
+// ----------------------------------------------------------------------
+// add fixed leap seconds (like from network packet) in an otherwise
+// empty table and test queries before / between /after the tabulated
+// values.
+#if 0 /* currently unused -- possibly revived later */
+void FAILtest_setFixedExtend() {
+       int            rc;
+       leap_result_t  qr;
+       int            last, idx;
+
+       static const struct { uint32_t tt; int of; } insns[] = {
+               {2982009600u, 29},//    # 1 Jul 1994
+               {3029443200u, 30},//    # 1 Jan 1996
+               {0,0} // sentinel
+       };
+
+       leap_table_t * pt = leapsec_get_table(0);
+       for (last=idx=0; insns[idx].tt; ++idx) {
+               last = idx;
+               rc = leapsec_add_fix(
+                   insns[idx].of,
+                   insns[idx].tt,
+                   insns[idx].tt + 128*SECSPERDAY,
+                   NULL);
+               TEST_ASSERT_EQUAL(TRUE, rc);
+       }
+       
+       rc = leapsec_query(&qr, insns[0].tt - 86400, NULL);
+       TEST_ASSERT_EQUAL(28, qr.tai_offs);
+
+       rc = leapsec_query(&qr, insns[0].tt + 86400, NULL);
+       TEST_ASSERT_EQUAL(29, qr.tai_offs);
+
+       rc = leapsec_query(&qr, insns[1].tt - 86400, NULL);
+       TEST_ASSERT_EQUAL(29, qr.tai_offs);
+
+       rc = leapsec_query(&qr, insns[1].tt + 86400, NULL);
+       TEST_ASSERT_EQUAL(30, qr.tai_offs);
+
+       //leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
+}
+#endif
+
+// =====================================================================
+// AUTOKEY LEAP TRANSFER TESTS
+// =====================================================================
+
+// ----------------------------------------------------------------------
+// Check if the offset can be applied to an empty table ONCE
+void test_taiEmptyTable() {
+       int rc;
+
+       rc = leapsec_autokey_tai(35, lsec2015-30*86400, NULL);  
+       TEST_ASSERT_EQUAL(TRUE, rc);
+
+       rc = leapsec_autokey_tai(35, lsec2015-29*86400, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+}
+
+// ----------------------------------------------------------------------
+// Check that with fixed entries the operation fails
+void test_taiTableFixed() {
+       int rc;
+
+       rc = setup_load_table(leap1, FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+
+       rc = leapsec_autokey_tai(35, lsec2015-30*86400, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+}
+
+// ----------------------------------------------------------------------
+// test adjustment with a dynamic entry already there
+void test_taiTableDynamic() {
+       int        rc;
+       leap_era_t era;
+
+       rc = leapsec_add_dyn(TRUE, lsec2015-20*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(TRUE, rc);
+
+       leapsec_query_era(&era, lsec2015-10, NULL);
+       TEST_ASSERT_EQUAL(0, era.taiof);
+       leapsec_query_era(&era, lsec2015+10, NULL);
+       TEST_ASSERT_EQUAL(1, era.taiof);
+
+       rc = leapsec_autokey_tai(35, lsec2015-19*86400, NULL);  
+       TEST_ASSERT_EQUAL(TRUE, rc);
+
+       rc = leapsec_autokey_tai(35, lsec2015-19*86400, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+
+       leapsec_query_era(&era, lsec2015-10, NULL);
+       TEST_ASSERT_EQUAL(35, era.taiof);
+       leapsec_query_era(&era, lsec2015+10, NULL);
+       TEST_ASSERT_EQUAL(36, era.taiof);
+}
+
+// ----------------------------------------------------------------------
+// test adjustment with a dynamic entry already there in dead zone
+void test_taiTableDynamicDeadZone() {
+       int rc;
+
+       rc = leapsec_add_dyn(TRUE, lsec2015-20*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(TRUE, rc);
+
+       rc = leapsec_autokey_tai(35, lsec2015-5, NULL); 
+       TEST_ASSERT_EQUAL(FALSE, rc);
+
+       rc = leapsec_autokey_tai(35, lsec2015+5, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+}
+
+
+// =====================================================================
+// SEQUENCE TESTS
+// =====================================================================
+
+// ----------------------------------------------------------------------
+// leap second insert at 2009.01.01, electric mode
+void test_ls2009seqInsElectric() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap1,FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+       leapsec_electric(1);
+       TEST_ASSERT_EQUAL(1, leapsec_electric(-1));
+
+       rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - 1, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009, NULL);
+       TEST_ASSERT_EQUAL(TRUE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       // second call, same time frame: no trigger!
+       rc = leapsec_query(&qr, lsec2009, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// leap second insert at 2009.01.01, dumb mode
+void test_ls2009seqInsDumb() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap1,FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+       TEST_ASSERT_EQUAL(0, leapsec_electric(-1));
+
+       rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - 1, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009+1, NULL);
+       TEST_ASSERT_EQUAL(TRUE, rc);
+       TEST_ASSERT_EQUAL(-1,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       // second call, same time frame: no trigger!
+       rc = leapsec_query(&qr, lsec2009, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+}
+
+
+// ----------------------------------------------------------------------
+// fake leap second remove at 2009.01.01, electric mode
+void test_ls2009seqDelElectric() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap3,FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+       leapsec_electric(1);
+       TEST_ASSERT_EQUAL(1, leapsec_electric(-1));
+
+       rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - 1, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009, NULL);
+       TEST_ASSERT_EQUAL(TRUE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       // second call, same time frame: no trigger!
+       rc = leapsec_query(&qr, lsec2009, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// fake leap second remove at 2009.01.01. dumb mode
+void test_ls2009seqDelDumb() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap3,FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+       TEST_ASSERT_EQUAL(0, leapsec_electric(-1));
+
+       rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - 2, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2009 - 1, NULL);
+       TEST_ASSERT_EQUAL(TRUE, rc);
+       TEST_ASSERT_EQUAL(1,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       // second call, same time frame: no trigger!
+       rc = leapsec_query(&qr, lsec2009, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// leap second insert at 2012.07.01, electric mode
+void test_ls2012seqInsElectric() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap1,FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+       leapsec_electric(1);
+       TEST_ASSERT_EQUAL(1, leapsec_electric(-1));
+
+       rc = leapsec_query(&qr, lsec2012 - 60*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2012 - 7*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2012 - SECSPERHR, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2012 - 1, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2012, NULL);
+       TEST_ASSERT_EQUAL(TRUE, rc);
+       TEST_ASSERT_EQUAL(0,            qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       // second call, same time frame: no trigger!
+       rc = leapsec_query(&qr, lsec2012, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// leap second insert at 2012.07.01, dumb mode
+void test_ls2012seqInsDumb() {
+       int            rc;
+       leap_result_t  qr;
+
+       rc = setup_load_table(leap1,FALSE);
+       TEST_ASSERT_EQUAL(1, rc);
+       TEST_ASSERT_EQUAL(0, leapsec_electric(-1));
+
+       rc = leapsec_query(&qr, lsec2012 - 60*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2012 - 7*SECSPERDAY, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_SCHEDULE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2012 - SECSPERHR, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ANNOUNCE, qr.proximity);
+
+       rc = leapsec_query(&qr, lsec2012 - 1, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,               qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ALERT,    qr.proximity);
+
+       // This is just 1 sec before transition!
+       rc = leapsec_query(&qr, lsec2012, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,            qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_ALERT, qr.proximity);
+
+       // NOW the insert/backwarp must happen
+       rc = leapsec_query(&qr, lsec2012+1, NULL);
+       TEST_ASSERT_EQUAL(TRUE, rc);
+       TEST_ASSERT_EQUAL(-1,            qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+
+       // second call with transition time: no trigger!
+       rc = leapsec_query(&qr, lsec2012, NULL);
+       TEST_ASSERT_EQUAL(FALSE, rc);
+       TEST_ASSERT_EQUAL(0,             qr.warped   );
+       TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// test repeated query on empty table in dumb mode
+void test_lsEmptyTableDumb() {
+       int            rc;
+       leap_result_t  qr;
+
+       //const
+       time_t pivot;
+       pivot = lsec2012;
+       //      const 
+       //time_t   pivot(lsec2012);             
+       const uint32_t t0 = lsec2012 - 10;
+       const uint32_t tE = lsec2012 + 10;
+
+       TEST_ASSERT_EQUAL(0, leapsec_electric(-1));
+
+       uint32_t t;
+       for (t = t0; t != tE; ++t) {
+               rc = leapsec_query(&qr, t, &pivot);
+               TEST_ASSERT_EQUAL(FALSE, rc);
+               TEST_ASSERT_EQUAL(0,             qr.warped   );
+               TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+       }
+}
+
+// ----------------------------------------------------------------------
+// test repeated query on empty table in electric mode
+void test_lsEmptyTableElectric() {
+       int            rc;
+       leap_result_t  qr;
+       
+       leapsec_electric(1);
+       TEST_ASSERT_EQUAL(1, leapsec_electric(-1));
+
+       //const 
+       time_t   pivot;//(lsec2012);
+       pivot = lsec2012;       
+       const uint32_t t0 = lsec2012 - 10;
+       const uint32_t tE = lsec2012 + 10;
+
+       time_t t;
+       for (t = t0; t != tE; ++t) {
+               rc = leapsec_query(&qr, t, &pivot);
+               TEST_ASSERT_EQUAL(FALSE, rc);
+               TEST_ASSERT_EQUAL(0,             qr.warped   );
+               TEST_ASSERT_EQUAL(LSPROX_NOWARN, qr.proximity);
+       }
+}
diff --git a/tests/ntpd/run-leapsec.c b/tests/ntpd/run-leapsec.c
new file mode 100644 (file)
index 0000000..42cf08d
--- /dev/null
@@ -0,0 +1,116 @@
+/* AUTOGENERATED FILE. DO NOT EDIT. */
+
+//=======Test Runner Used To Run Each Test Below=====
+#define RUN_TEST(TestFunc, TestLineNum) \
+{ \
+  Unity.CurrentTestName = #TestFunc; \
+  Unity.CurrentTestLineNumber = TestLineNum; \
+  Unity.NumberOfTests++; \
+  if (TEST_PROTECT()) \
+  { \
+      setUp(); \
+      TestFunc(); \
+  } \
+  if (TEST_PROTECT() && !TEST_IS_IGNORED) \
+  { \
+    tearDown(); \
+  } \
+  UnityConcludeTest(); \
+}
+
+//=======Automagically Detected Files To Include=====
+#include "unity.h"
+#include <setjmp.h>
+#include <stdio.h>
+
+//=======External Functions This Runner Calls=====
+extern void setUp(void);
+extern void tearDown(void);
+void resetTest(void);
+extern void test_ValidateGood();
+extern void test_ValidateNoHash();
+extern void test_ValidateBad();
+extern void test_ValidateMalformed();
+extern void test_ValidateMalformedShort();
+extern void test_ValidateNoLeadZero();
+extern void test_tableSelect();
+extern void test_loadFileExpire();
+extern void test_loadFileTTL();
+extern void test_lsQueryPristineState();
+extern void test_ls2009faraway();
+extern void test_ls2009weekaway();
+extern void test_ls2009houraway();
+extern void test_ls2009secaway();
+extern void test_ls2009onspot();
+extern void test_ls2009nodata();
+extern void test_ls2009limdata();
+extern void test_qryJumpFarAhead();
+extern void test_qryJumpAheadToTransition();
+extern void test_qryJumpAheadOverTransition();
+extern void test_addDynamic();
+extern void test_taiEmptyTable();
+extern void test_taiTableFixed();
+extern void test_taiTableDynamic();
+extern void test_taiTableDynamicDeadZone();
+extern void test_ls2009seqInsElectric();
+extern void test_ls2009seqInsDumb();
+extern void test_ls2009seqDelElectric();
+extern void test_ls2009seqDelDumb();
+extern void test_ls2012seqInsElectric();
+extern void test_ls2012seqInsDumb();
+extern void test_lsEmptyTableDumb();
+extern void test_lsEmptyTableElectric();
+
+
+//=======Test Reset Option=====
+void resetTest()
+{
+  tearDown();
+  setUp();
+}
+
+char *progname;
+
+
+//=======MAIN=====
+int main(int argc, char *argv[])
+{
+  progname = argv[0];
+  Unity.TestFile = "leapsec.c";
+  UnityBegin("leapsec.c");
+  RUN_TEST(test_ValidateGood, 334);
+  RUN_TEST(test_ValidateNoHash, 341);
+  RUN_TEST(test_ValidateBad, 348);
+  RUN_TEST(test_ValidateMalformed, 355);
+  RUN_TEST(test_ValidateMalformedShort, 362);
+  RUN_TEST(test_ValidateNoLeadZero, 369);
+  RUN_TEST(test_tableSelect, 381);
+  RUN_TEST(test_loadFileExpire, 416);
+  RUN_TEST(test_loadFileTTL, 432);
+  RUN_TEST(test_lsQueryPristineState, 464);
+  RUN_TEST(test_ls2009faraway, 476);
+  RUN_TEST(test_ls2009weekaway, 493);
+  RUN_TEST(test_ls2009houraway, 510);
+  RUN_TEST(test_ls2009secaway, 527);
+  RUN_TEST(test_ls2009onspot, 544);
+  RUN_TEST(test_ls2009nodata, 561);
+  RUN_TEST(test_ls2009limdata, 578);
+  RUN_TEST(test_qryJumpFarAhead, 599);
+  RUN_TEST(test_qryJumpAheadToTransition, 621);
+  RUN_TEST(test_qryJumpAheadOverTransition, 643);
+  RUN_TEST(test_addDynamic, 669);
+  RUN_TEST(test_taiEmptyTable, 847);
+  RUN_TEST(test_taiTableFixed, 859);
+  RUN_TEST(test_taiTableDynamic, 871);
+  RUN_TEST(test_taiTableDynamicDeadZone, 897);
+  RUN_TEST(test_ls2009seqInsElectric, 917);
+  RUN_TEST(test_ls2009seqInsDumb, 960);
+  RUN_TEST(test_ls2009seqDelElectric, 1008);
+  RUN_TEST(test_ls2009seqDelDumb, 1051);
+  RUN_TEST(test_ls2012seqInsElectric, 1093);
+  RUN_TEST(test_ls2012seqInsDumb, 1136);
+  RUN_TEST(test_lsEmptyTableDumb, 1185);
+  RUN_TEST(test_lsEmptyTableElectric, 1210);
+
+  return (UnityEnd());
+}