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