1290904Sngie/*-
2290904Sngie * Copyright (c) 2011 Giorgos Keramidas. All rights reserved.
3290904Sngie * Copyright (c) 2007 Diomidis Spinellis. All rights reserved.
4290904Sngie * Redistribution and use in source and binary forms, with or without
5290904Sngie * modification, are permitted provided that the following conditions
6290904Sngie * are met:
7290904Sngie * 1. Redistributions of source code must retain the above copyright
8290904Sngie *    notice, this list of conditions and the following disclaimer.
9290904Sngie * 2. Redistributions in binary form must reproduce the above copyright
10290904Sngie *    notice, this list of conditions and the following disclaimer in the
11290904Sngie *    documentation and/or other materials provided with the distribution.
12290904Sngie *
13290904Sngie * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14290904Sngie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15290904Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16290904Sngie * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17290904Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18290904Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19290904Sngie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20290904Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21290904Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22290904Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23290904Sngie * SUCH DAMAGE.
24290904Sngie */
25290904Sngie
26290904Sngie#include <sys/cdefs.h>
27290904Sngie__FBSDID("$FreeBSD$");
28290904Sngie
29290904Sngie#include <sys/types.h>
30290904Sngie
31290904Sngie#include <assert.h>
32290904Sngie#include <errno.h>
33290904Sngie#include <float.h>
34290904Sngie#include <limits.h>
35290904Sngie#include <math.h>
36290904Sngie#include <stdio.h>
37290904Sngie#include <stdint.h>
38290904Sngie#include <stdlib.h>
39290904Sngie#include <strings.h>
40290904Sngie#include <syslog.h>
41290904Sngie#include <time.h>
42290904Sngie
43290904Sngie#include <atf-c.h>
44290904Sngie
45290904Sngie#define KASSERT(val, msg) assert(val)
46290904Sngie
47290904Sngietypedef u_int32_t comp_t;
48290904Sngie
49290904Sngie#define AHZ 1000000
50290904Sngie
51290904Sngie#include "convert.c"
52290904Sngie
53290904Sngieunion cf {
54290904Sngie	comp_t c;
55290904Sngie	float f;
56290904Sngie};
57290904Sngie
58290904Sngiestatic void
59290904Sngiecheck_result(const char *name, float expected, union cf v)
60290904Sngie{
61290904Sngie	double eps;
62290904Sngie
63290904Sngie	eps = fabs(expected - v.f) / expected;
64290904Sngie	ATF_CHECK(eps <= FLT_EPSILON);
65290904Sngie	if (eps > FLT_EPSILON) {
66290904Sngie		printf("Error in %s\n", name);
67290904Sngie		printf("Got      0x%08x %12g\n", v.c, v.f);
68290904Sngie		v.f = expected;
69290904Sngie		printf("Expected 0x%08x %12g (%.15lg)\n", v.c, v.f, expected);
70290904Sngie		printf("Epsilon=%lg, rather than %g\n", eps, FLT_EPSILON);
71290904Sngie	}
72290904Sngie}
73290904Sngie
74290904Sngie/*
75290904Sngie * Test case for encoding {0 sec, 0 usec} within a reasonable epsilon.
76290904Sngie */
77290904Sngie
78290904SngieATF_TC_WITHOUT_HEAD(encode_tv_zero);
79290904SngieATF_TC_BODY(encode_tv_zero, tc)
80290904Sngie{
81290904Sngie	union cf v;
82290904Sngie	struct timeval tv;
83290904Sngie
84290904Sngie	tv.tv_sec = 0;
85290904Sngie	tv.tv_usec = 0;
86290904Sngie	v.c = encode_timeval(tv);
87290904Sngie	ATF_CHECK(fabs(v.f - 0.0) < FLT_EPSILON);
88290904Sngie}
89290904Sngie
90290904Sngie/*
91290904Sngie * Test case for encoding a random long number.
92290904Sngie */
93290904Sngie
94290904SngieATF_TC_WITHOUT_HEAD(encode_long);
95290904SngieATF_TC_BODY(encode_long, tc)
96290904Sngie{
97290904Sngie	union cf v;
98290904Sngie	long l;
99290904Sngie
100290904Sngie	l = random();
101290904Sngie	v.c = encode_long(l);
102290904Sngie	check_result(atf_tc_get_ident(tc), l, v);
103290904Sngie}
104290904Sngie
105290904Sngie/*
106290904Sngie * Test case for encoding a small number of seconds {1 sec, 0 usec}.
107290904Sngie */
108290904Sngie
109290904SngieATF_TC_WITHOUT_HEAD(encode_tv_only_sec);
110290904SngieATF_TC_BODY(encode_tv_only_sec, tc)
111290904Sngie{
112290904Sngie	union cf v;
113290904Sngie	struct timeval tv;
114290904Sngie
115290904Sngie	tv.tv_sec = 1;
116290904Sngie	tv.tv_usec = 0;
117290904Sngie	v.c = encode_timeval(tv);
118290904Sngie	check_result(atf_tc_get_ident(tc),
119290904Sngie	    (float)tv.tv_sec * AHZ + tv.tv_usec, v);
120290904Sngie}
121290904Sngie
122290904Sngie/*
123290904Sngie * Test case for encoding a small number of usec {0 sec, 1 usec}.
124290904Sngie */
125290904Sngie
126290904SngieATF_TC_WITHOUT_HEAD(encode_tv_only_usec);
127290904SngieATF_TC_BODY(encode_tv_only_usec, tc)
128290904Sngie{
129290904Sngie	union cf v;
130290904Sngie	struct timeval tv;
131290904Sngie
132290904Sngie	tv.tv_sec = 0;
133290904Sngie	tv.tv_usec = 1;
134290904Sngie	v.c = encode_timeval(tv);
135290904Sngie	check_result(atf_tc_get_ident(tc),
136290904Sngie	    (float)tv.tv_sec * AHZ + tv.tv_usec, v);
137290904Sngie}
138290904Sngie
139290904Sngie/*
140290904Sngie * Test case for encoding a large number of usec {1 sec, 999.999 usec}.
141290904Sngie */
142290904Sngie
143290904SngieATF_TC_WITHOUT_HEAD(encode_tv_many_usec);
144290904SngieATF_TC_BODY(encode_tv_many_usec, tc)
145290904Sngie{
146290904Sngie	union cf v;
147290904Sngie	struct timeval tv;
148290904Sngie
149290904Sngie	tv.tv_sec = 1;
150290904Sngie	tv.tv_usec = 999999L;
151290904Sngie	v.c = encode_timeval(tv);
152290904Sngie	check_result(atf_tc_get_ident(tc),
153290904Sngie	    (float)tv.tv_sec * AHZ + tv.tv_usec, v);
154290904Sngie}
155290904Sngie
156290904Sngie/*
157290904Sngie * Test case for encoding a huge number of usec {1 sec, 1.000.000 usec} that
158290904Sngie * overflows the usec counter and should show up as an increase in timeval's
159290904Sngie * seconds instead.
160290904Sngie */
161290904Sngie
162290904SngieATF_TC_WITHOUT_HEAD(encode_tv_usec_overflow);
163290904SngieATF_TC_BODY(encode_tv_usec_overflow, tc)
164290904Sngie{
165290904Sngie	union cf v;
166290904Sngie	struct timeval tv;
167290904Sngie
168290904Sngie	tv.tv_sec = 1;
169290904Sngie	tv.tv_usec = 1000000L;
170290904Sngie	v.c = encode_timeval(tv);
171290904Sngie	check_result(atf_tc_get_ident(tc),
172290904Sngie	    (float)tv.tv_sec * AHZ + tv.tv_usec, v);
173290904Sngie}
174290904Sngie
175290904Sngie/*
176290904Sngie * Test case for encoding a very large number of seconds, one that is very
177290904Sngie * near to the limit of 32-bit signed values.  With a usec value of 999.999
178290904Sngie * microseconds this should result in the largest value we can represent with
179290904Sngie * a timeval struct.
180290904Sngie */
181290904Sngie
182290904SngieATF_TC_WITHOUT_HEAD(encode_tv_upper_limit);
183290904SngieATF_TC_BODY(encode_tv_upper_limit, tc)
184290904Sngie{
185290904Sngie	union cf v;
186290904Sngie	struct timeval tv;
187290904Sngie
188290904Sngie	tv.tv_sec = 2147483647L;
189290904Sngie	tv.tv_usec = 999999L;
190290904Sngie	v.c = encode_timeval(tv);
191290904Sngie	check_result(atf_tc_get_ident(tc),
192290904Sngie	    (float)tv.tv_sec * AHZ + tv.tv_usec, v);
193290904Sngie}
194290904Sngie
195290904Sngie/*
196290904Sngie * Test case for encoding a million random timeval objects, and checking that
197290904Sngie * the conversion does not diverge too much from the expected values.
198290904Sngie */
199290904Sngie
200290904SngieATF_TC_WITHOUT_HEAD(encode_tv_random_million);
201290904SngieATF_TC_BODY(encode_tv_random_million, tc)
202290904Sngie{
203290904Sngie	union cf v;
204290904Sngie	struct timeval tv;
205290904Sngie	long k;
206290904Sngie
207305228Sngie#ifdef __LP64__
208305228Sngie	atf_tc_expect_fail("the testcase violates FLT_EPSILON on 64-bit "
209305228Sngie	    "platforms, e.g. amd64");
210305228Sngie#endif
211290904Sngie
212290904Sngie	ATF_REQUIRE_MSG(unsetenv("TZ") == 0, "unsetting TZ failed; errno=%d", errno);
213290904Sngie
214290904Sngie	for (k = 1; k < 1000000L; k++) {
215290904Sngie		tv.tv_sec = random();
216290904Sngie		tv.tv_usec = (random() % 1000000L);
217290904Sngie		v.c = encode_timeval(tv);
218290904Sngie		check_result(atf_tc_get_ident(tc),
219290904Sngie		    (float)tv.tv_sec * AHZ + tv.tv_usec, v);
220290904Sngie	}
221290904Sngie}
222290904Sngie
223290904Sngie/* ---------------------------------------------------------------------
224290904Sngie * Main.
225290904Sngie * --------------------------------------------------------------------- */
226290904Sngie
227290904SngieATF_TP_ADD_TCS(tp)
228290904Sngie{
229290904Sngie
230290904Sngie	ATF_TP_ADD_TC(tp, encode_long);
231290904Sngie	ATF_TP_ADD_TC(tp, encode_tv_zero);
232290904Sngie	ATF_TP_ADD_TC(tp, encode_tv_only_sec);
233290904Sngie	ATF_TP_ADD_TC(tp, encode_tv_only_usec);
234290904Sngie	ATF_TP_ADD_TC(tp, encode_tv_many_usec);
235290904Sngie	ATF_TP_ADD_TC(tp, encode_tv_usec_overflow);
236290904Sngie	ATF_TP_ADD_TC(tp, encode_tv_upper_limit);
237290904Sngie	ATF_TP_ADD_TC(tp, encode_tv_random_million);
238290904Sngie
239290904Sngie	return atf_no_error();
240290904Sngie}
241