13e9b6029SEnji Cooper /*-
23e9b6029SEnji Cooper * Copyright (c) 2011 Giorgos Keramidas. All rights reserved.
33e9b6029SEnji Cooper * Copyright (c) 2007 Diomidis Spinellis. All rights reserved.
43e9b6029SEnji Cooper * Redistribution and use in source and binary forms, with or without
53e9b6029SEnji Cooper * modification, are permitted provided that the following conditions
63e9b6029SEnji Cooper * are met:
73e9b6029SEnji Cooper * 1. Redistributions of source code must retain the above copyright
83e9b6029SEnji Cooper * notice, this list of conditions and the following disclaimer.
93e9b6029SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright
103e9b6029SEnji Cooper * notice, this list of conditions and the following disclaimer in the
113e9b6029SEnji Cooper * documentation and/or other materials provided with the distribution.
123e9b6029SEnji Cooper *
133e9b6029SEnji Cooper * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
143e9b6029SEnji Cooper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
153e9b6029SEnji Cooper * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
163e9b6029SEnji Cooper * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
173e9b6029SEnji Cooper * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
183e9b6029SEnji Cooper * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
193e9b6029SEnji Cooper * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
203e9b6029SEnji Cooper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
213e9b6029SEnji Cooper * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
223e9b6029SEnji Cooper * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
233e9b6029SEnji Cooper * SUCH DAMAGE.
243e9b6029SEnji Cooper */
253e9b6029SEnji Cooper
263e9b6029SEnji Cooper #include <sys/types.h>
273e9b6029SEnji Cooper
283e9b6029SEnji Cooper #include <assert.h>
293e9b6029SEnji Cooper #include <errno.h>
303e9b6029SEnji Cooper #include <float.h>
313e9b6029SEnji Cooper #include <limits.h>
323e9b6029SEnji Cooper #include <math.h>
333e9b6029SEnji Cooper #include <stdio.h>
343e9b6029SEnji Cooper #include <stdint.h>
353e9b6029SEnji Cooper #include <stdlib.h>
363e9b6029SEnji Cooper #include <strings.h>
373e9b6029SEnji Cooper #include <syslog.h>
383e9b6029SEnji Cooper #include <time.h>
393e9b6029SEnji Cooper
403e9b6029SEnji Cooper #include <atf-c.h>
413e9b6029SEnji Cooper
423e9b6029SEnji Cooper #define KASSERT(val, msg) assert(val)
433e9b6029SEnji Cooper
443e9b6029SEnji Cooper typedef u_int32_t comp_t;
453e9b6029SEnji Cooper
463e9b6029SEnji Cooper #define AHZ 1000000
473e9b6029SEnji Cooper
483e9b6029SEnji Cooper #include "convert.c"
493e9b6029SEnji Cooper
503e9b6029SEnji Cooper union cf {
513e9b6029SEnji Cooper comp_t c;
523e9b6029SEnji Cooper float f;
533e9b6029SEnji Cooper };
543e9b6029SEnji Cooper
553e9b6029SEnji Cooper static void
check_result(const char * name,float expected,union cf v)563e9b6029SEnji Cooper check_result(const char *name, float expected, union cf v)
573e9b6029SEnji Cooper {
583e9b6029SEnji Cooper double eps;
593e9b6029SEnji Cooper
603e9b6029SEnji Cooper eps = fabs(expected - v.f) / expected;
613e9b6029SEnji Cooper ATF_CHECK(eps <= FLT_EPSILON);
623e9b6029SEnji Cooper if (eps > FLT_EPSILON) {
633e9b6029SEnji Cooper printf("Error in %s\n", name);
643e9b6029SEnji Cooper printf("Got 0x%08x %12g\n", v.c, v.f);
653e9b6029SEnji Cooper v.f = expected;
663e9b6029SEnji Cooper printf("Expected 0x%08x %12g (%.15lg)\n", v.c, v.f, expected);
673e9b6029SEnji Cooper printf("Epsilon=%lg, rather than %g\n", eps, FLT_EPSILON);
683e9b6029SEnji Cooper }
693e9b6029SEnji Cooper }
703e9b6029SEnji Cooper
713e9b6029SEnji Cooper /*
723e9b6029SEnji Cooper * Test case for encoding {0 sec, 0 usec} within a reasonable epsilon.
733e9b6029SEnji Cooper */
743e9b6029SEnji Cooper
753e9b6029SEnji Cooper ATF_TC_WITHOUT_HEAD(encode_tv_zero);
ATF_TC_BODY(encode_tv_zero,tc)763e9b6029SEnji Cooper ATF_TC_BODY(encode_tv_zero, tc)
773e9b6029SEnji Cooper {
783e9b6029SEnji Cooper union cf v;
793e9b6029SEnji Cooper struct timeval tv;
803e9b6029SEnji Cooper
813e9b6029SEnji Cooper tv.tv_sec = 0;
823e9b6029SEnji Cooper tv.tv_usec = 0;
833e9b6029SEnji Cooper v.c = encode_timeval(tv);
843e9b6029SEnji Cooper ATF_CHECK(fabs(v.f - 0.0) < FLT_EPSILON);
853e9b6029SEnji Cooper }
863e9b6029SEnji Cooper
873e9b6029SEnji Cooper /*
883e9b6029SEnji Cooper * Test case for encoding a random long number.
893e9b6029SEnji Cooper */
903e9b6029SEnji Cooper
913e9b6029SEnji Cooper ATF_TC_WITHOUT_HEAD(encode_long);
ATF_TC_BODY(encode_long,tc)923e9b6029SEnji Cooper ATF_TC_BODY(encode_long, tc)
933e9b6029SEnji Cooper {
943e9b6029SEnji Cooper union cf v;
953e9b6029SEnji Cooper long l;
963e9b6029SEnji Cooper
973e9b6029SEnji Cooper l = random();
983e9b6029SEnji Cooper v.c = encode_long(l);
993e9b6029SEnji Cooper check_result(atf_tc_get_ident(tc), l, v);
1003e9b6029SEnji Cooper }
1013e9b6029SEnji Cooper
1023e9b6029SEnji Cooper /*
1033e9b6029SEnji Cooper * Test case for encoding a small number of seconds {1 sec, 0 usec}.
1043e9b6029SEnji Cooper */
1053e9b6029SEnji Cooper
1063e9b6029SEnji Cooper ATF_TC_WITHOUT_HEAD(encode_tv_only_sec);
ATF_TC_BODY(encode_tv_only_sec,tc)1073e9b6029SEnji Cooper ATF_TC_BODY(encode_tv_only_sec, tc)
1083e9b6029SEnji Cooper {
1093e9b6029SEnji Cooper union cf v;
1103e9b6029SEnji Cooper struct timeval tv;
1113e9b6029SEnji Cooper
1123e9b6029SEnji Cooper tv.tv_sec = 1;
1133e9b6029SEnji Cooper tv.tv_usec = 0;
1143e9b6029SEnji Cooper v.c = encode_timeval(tv);
1153e9b6029SEnji Cooper check_result(atf_tc_get_ident(tc),
1163e9b6029SEnji Cooper (float)tv.tv_sec * AHZ + tv.tv_usec, v);
1173e9b6029SEnji Cooper }
1183e9b6029SEnji Cooper
1193e9b6029SEnji Cooper /*
1203e9b6029SEnji Cooper * Test case for encoding a small number of usec {0 sec, 1 usec}.
1213e9b6029SEnji Cooper */
1223e9b6029SEnji Cooper
1233e9b6029SEnji Cooper ATF_TC_WITHOUT_HEAD(encode_tv_only_usec);
ATF_TC_BODY(encode_tv_only_usec,tc)1243e9b6029SEnji Cooper ATF_TC_BODY(encode_tv_only_usec, tc)
1253e9b6029SEnji Cooper {
1263e9b6029SEnji Cooper union cf v;
1273e9b6029SEnji Cooper struct timeval tv;
1283e9b6029SEnji Cooper
1293e9b6029SEnji Cooper tv.tv_sec = 0;
1303e9b6029SEnji Cooper tv.tv_usec = 1;
1313e9b6029SEnji Cooper v.c = encode_timeval(tv);
1323e9b6029SEnji Cooper check_result(atf_tc_get_ident(tc),
1333e9b6029SEnji Cooper (float)tv.tv_sec * AHZ + tv.tv_usec, v);
1343e9b6029SEnji Cooper }
1353e9b6029SEnji Cooper
1363e9b6029SEnji Cooper /*
1373e9b6029SEnji Cooper * Test case for encoding a large number of usec {1 sec, 999.999 usec}.
1383e9b6029SEnji Cooper */
1393e9b6029SEnji Cooper
1403e9b6029SEnji Cooper ATF_TC_WITHOUT_HEAD(encode_tv_many_usec);
ATF_TC_BODY(encode_tv_many_usec,tc)1413e9b6029SEnji Cooper ATF_TC_BODY(encode_tv_many_usec, tc)
1423e9b6029SEnji Cooper {
1433e9b6029SEnji Cooper union cf v;
1443e9b6029SEnji Cooper struct timeval tv;
1453e9b6029SEnji Cooper
1463e9b6029SEnji Cooper tv.tv_sec = 1;
1473e9b6029SEnji Cooper tv.tv_usec = 999999L;
1483e9b6029SEnji Cooper v.c = encode_timeval(tv);
1493e9b6029SEnji Cooper check_result(atf_tc_get_ident(tc),
1503e9b6029SEnji Cooper (float)tv.tv_sec * AHZ + tv.tv_usec, v);
1513e9b6029SEnji Cooper }
1523e9b6029SEnji Cooper
1533e9b6029SEnji Cooper /*
1543e9b6029SEnji Cooper * Test case for encoding a huge number of usec {1 sec, 1.000.000 usec} that
1553e9b6029SEnji Cooper * overflows the usec counter and should show up as an increase in timeval's
1563e9b6029SEnji Cooper * seconds instead.
1573e9b6029SEnji Cooper */
1583e9b6029SEnji Cooper
1593e9b6029SEnji Cooper ATF_TC_WITHOUT_HEAD(encode_tv_usec_overflow);
ATF_TC_BODY(encode_tv_usec_overflow,tc)1603e9b6029SEnji Cooper ATF_TC_BODY(encode_tv_usec_overflow, tc)
1613e9b6029SEnji Cooper {
1623e9b6029SEnji Cooper union cf v;
1633e9b6029SEnji Cooper struct timeval tv;
1643e9b6029SEnji Cooper
1653e9b6029SEnji Cooper tv.tv_sec = 1;
1663e9b6029SEnji Cooper tv.tv_usec = 1000000L;
1673e9b6029SEnji Cooper v.c = encode_timeval(tv);
1683e9b6029SEnji Cooper check_result(atf_tc_get_ident(tc),
1693e9b6029SEnji Cooper (float)tv.tv_sec * AHZ + tv.tv_usec, v);
1703e9b6029SEnji Cooper }
1713e9b6029SEnji Cooper
1723e9b6029SEnji Cooper /*
1733e9b6029SEnji Cooper * Test case for encoding a very large number of seconds, one that is very
1743e9b6029SEnji Cooper * near to the limit of 32-bit signed values. With a usec value of 999.999
1753e9b6029SEnji Cooper * microseconds this should result in the largest value we can represent with
1763e9b6029SEnji Cooper * a timeval struct.
1773e9b6029SEnji Cooper */
1783e9b6029SEnji Cooper
1793e9b6029SEnji Cooper ATF_TC_WITHOUT_HEAD(encode_tv_upper_limit);
ATF_TC_BODY(encode_tv_upper_limit,tc)1803e9b6029SEnji Cooper ATF_TC_BODY(encode_tv_upper_limit, tc)
1813e9b6029SEnji Cooper {
1823e9b6029SEnji Cooper union cf v;
1833e9b6029SEnji Cooper struct timeval tv;
1843e9b6029SEnji Cooper
1853e9b6029SEnji Cooper tv.tv_sec = 2147483647L;
1863e9b6029SEnji Cooper tv.tv_usec = 999999L;
1873e9b6029SEnji Cooper v.c = encode_timeval(tv);
1883e9b6029SEnji Cooper check_result(atf_tc_get_ident(tc),
1893e9b6029SEnji Cooper (float)tv.tv_sec * AHZ + tv.tv_usec, v);
1903e9b6029SEnji Cooper }
1913e9b6029SEnji Cooper
1923e9b6029SEnji Cooper /*
1933e9b6029SEnji Cooper * Test case for encoding a million random timeval objects, and checking that
1943e9b6029SEnji Cooper * the conversion does not diverge too much from the expected values.
1953e9b6029SEnji Cooper */
1963e9b6029SEnji Cooper
1973e9b6029SEnji Cooper ATF_TC_WITHOUT_HEAD(encode_tv_random_million);
ATF_TC_BODY(encode_tv_random_million,tc)1983e9b6029SEnji Cooper ATF_TC_BODY(encode_tv_random_million, tc)
1993e9b6029SEnji Cooper {
2003e9b6029SEnji Cooper union cf v;
2013e9b6029SEnji Cooper struct timeval tv;
2023e9b6029SEnji Cooper long k;
2033e9b6029SEnji Cooper
204*ef5c8d54SEnji Cooper #ifdef __LP64__
205*ef5c8d54SEnji Cooper atf_tc_expect_fail("the testcase violates FLT_EPSILON on 64-bit "
206*ef5c8d54SEnji Cooper "platforms, e.g. amd64");
207*ef5c8d54SEnji Cooper #endif
2083e9b6029SEnji Cooper
2093e9b6029SEnji Cooper ATF_REQUIRE_MSG(unsetenv("TZ") == 0, "unsetting TZ failed; errno=%d", errno);
2103e9b6029SEnji Cooper
2113e9b6029SEnji Cooper for (k = 1; k < 1000000L; k++) {
2123e9b6029SEnji Cooper tv.tv_sec = random();
2133e9b6029SEnji Cooper tv.tv_usec = (random() % 1000000L);
2143e9b6029SEnji Cooper v.c = encode_timeval(tv);
2153e9b6029SEnji Cooper check_result(atf_tc_get_ident(tc),
2163e9b6029SEnji Cooper (float)tv.tv_sec * AHZ + tv.tv_usec, v);
2173e9b6029SEnji Cooper }
2183e9b6029SEnji Cooper }
2193e9b6029SEnji Cooper
2203e9b6029SEnji Cooper /* ---------------------------------------------------------------------
2213e9b6029SEnji Cooper * Main.
2223e9b6029SEnji Cooper * --------------------------------------------------------------------- */
2233e9b6029SEnji Cooper
ATF_TP_ADD_TCS(tp)2243e9b6029SEnji Cooper ATF_TP_ADD_TCS(tp)
2253e9b6029SEnji Cooper {
2263e9b6029SEnji Cooper
2273e9b6029SEnji Cooper ATF_TP_ADD_TC(tp, encode_long);
2283e9b6029SEnji Cooper ATF_TP_ADD_TC(tp, encode_tv_zero);
2293e9b6029SEnji Cooper ATF_TP_ADD_TC(tp, encode_tv_only_sec);
2303e9b6029SEnji Cooper ATF_TP_ADD_TC(tp, encode_tv_only_usec);
2313e9b6029SEnji Cooper ATF_TP_ADD_TC(tp, encode_tv_many_usec);
2323e9b6029SEnji Cooper ATF_TP_ADD_TC(tp, encode_tv_usec_overflow);
2333e9b6029SEnji Cooper ATF_TP_ADD_TC(tp, encode_tv_upper_limit);
2343e9b6029SEnji Cooper ATF_TP_ADD_TC(tp, encode_tv_random_million);
2353e9b6029SEnji Cooper
2363e9b6029SEnji Cooper return atf_no_error();
2373e9b6029SEnji Cooper }
238