1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18#include <testUtil.h>
19
20#include <assert.h>
21#include <errno.h>
22#include <math.h>
23#include <stdarg.h>
24#include <stdint.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <time.h>
28
29#include <sys/time.h>
30#include <sys/wait.h>
31
32#include <cutils/log.h>
33
34#define ALEN(a) (sizeof(a) / sizeof(a [0]))  // Array length
35typedef unsigned int bool_t;
36#define true (0 == 0)
37#define false (!true)
38
39#define MAXSTR 200
40
41static const char *logCatTag;
42static const unsigned int uSecsPerSec = 1000000;
43static const unsigned int nSecsPerSec = 1000000000;
44
45// struct timespec to double
46double ts2double(const struct timespec *val)
47{
48    double rv;
49
50    rv = val->tv_sec;
51    rv += (double) val->tv_nsec / nSecsPerSec;
52
53    return rv;
54}
55
56// struct timeval to double
57double tv2double(const struct timeval *val)
58{
59    double rv;
60
61    rv = val->tv_sec;
62    rv += (double) val->tv_usec / uSecsPerSec;
63
64    return rv;
65}
66
67// double to struct timespec
68struct timespec double2ts(double amt)
69{
70    struct timespec rv;
71
72    rv.tv_sec = floor(amt);
73    rv.tv_nsec = (amt - rv.tv_sec) * nSecsPerSec;
74    // TODO: Handle cases where amt is negative
75    while ((unsigned) rv.tv_nsec >= nSecsPerSec) {
76        rv.tv_nsec -= nSecsPerSec;
77        rv.tv_sec++;
78    }
79
80    return rv;
81}
82
83// double to struct timeval
84struct timeval double2tv(double amt)
85{
86    struct timeval rv;
87
88    rv.tv_sec = floor(amt);
89    rv.tv_usec = (amt - rv.tv_sec) * uSecsPerSec;
90    // TODO: Handle cases where amt is negative
91    while ((unsigned) rv.tv_usec >= uSecsPerSec) {
92        rv.tv_usec -= uSecsPerSec;
93        rv.tv_sec++;
94    }
95
96    return rv;
97}
98
99// Delta (difference) between two struct timespec.
100// It is expected that the time given by the structure pointed to by
101// second, is later than the time pointed to by first.
102struct timespec tsDelta(const struct timespec *first,
103                        const struct timespec *second)
104{
105    struct timespec rv;
106
107    assert(first != NULL);
108    assert(second != NULL);
109    assert(first->tv_nsec >= 0 && first->tv_nsec < nSecsPerSec);
110    assert(second->tv_nsec >= 0 && second->tv_nsec < nSecsPerSec);
111    rv.tv_sec = second->tv_sec - first->tv_sec;
112    if (second->tv_nsec >= first->tv_nsec) {
113        rv.tv_nsec = second->tv_nsec - first->tv_nsec;
114    } else {
115        rv.tv_nsec = (second->tv_nsec + nSecsPerSec) - first->tv_nsec;
116        rv.tv_sec--;
117    }
118
119    return rv;
120}
121
122// Delta (difference) between two struct timeval.
123// It is expected that the time given by the structure pointed to by
124// second, is later than the time pointed to by first.
125struct timeval tvDelta(const struct timeval *first,
126                       const struct timeval *second)
127{
128    struct timeval rv;
129
130    assert(first != NULL);
131    assert(second != NULL);
132    assert(first->tv_usec >= 0 && first->tv_usec < uSecsPerSec);
133    assert(second->tv_usec >= 0 && second->tv_usec < uSecsPerSec);
134    rv.tv_sec = second->tv_sec - first->tv_sec;
135    if (second->tv_usec >= first->tv_usec) {
136        rv.tv_usec = second->tv_usec - first->tv_usec;
137    } else {
138        rv.tv_usec = (second->tv_usec + uSecsPerSec) - first->tv_usec;
139        rv.tv_sec--;
140    }
141
142    return rv;
143}
144
145void testPrint(FILE *stream, const char *fmt, ...)
146{
147    char line[MAXSTR];
148    va_list args;
149
150    va_start(args, fmt);
151    vsnprintf(line, sizeof(line), fmt, args);
152    if (stream == stderr) {
153        ALOG(LOG_ERROR, logCatTag, "%s", line);
154    } else {
155        ALOG(LOG_INFO, logCatTag, "%s", line);
156    }
157    vfprintf(stream, fmt, args);
158    fputc('\n', stream);
159}
160
161// Set tag used while logging to the logcat error interface
162void testSetLogCatTag(const char *tag)
163{
164    logCatTag = tag;
165}
166
167// Obtain pointer to current log to logcat error interface tag
168const char * testGetLogCatTag(void)
169{
170    return logCatTag;
171}
172
173/*
174 * Random
175 *
176 * Returns a pseudo random number in the range [0:2^32-1].
177 *
178 * Precondition: srand48() called to set the seed of
179 *   the pseudo random number generator.
180 */
181uint32_t testRand(void)
182{
183    uint32_t val;
184
185    // Use lrand48() to obtain 31 bits worth
186    // of randomness.
187    val = lrand48();
188
189    // Make an additional lrand48() call and merge
190    // the randomness into the most significant bits.
191    val ^= lrand48() << 1;
192
193    return val;
194}
195
196/*
197 * Random Modulus
198 *
199 * Pseudo randomly returns unsigned integer in the range [0, mod).
200 *
201 * Precondition: srand48() called to set the seed of
202 *   the pseudo random number generator.
203 */
204uint32_t testRandMod(uint32_t mod)
205{
206    // Obtain the random value
207    // Use lrand48() when it would produce a sufficient
208    // number of random bits, otherwise use testRand().
209    const uint32_t lrand48maxVal = ((uint32_t) 1 << 31) - 1;
210    uint32_t val = (mod <= lrand48maxVal) ? (uint32_t) lrand48() : testRand();
211
212    /*
213     * The contents of individual bytes tend to be less than random
214     * across different seeds.  For example, srand48(x) and
215     * srand48(x + n * 4) cause lrand48() to return the same sequence of
216     * least significant bits.  For small mod values this can produce
217     * noticably non-random sequnces.  For mod values of less than 2
218     * bytes, will use the randomness from all the bytes.
219     */
220    if (mod <= 0x10000) {
221        val = (val & 0xffff) ^ (val >> 16);
222
223        // If mod less than a byte, can further combine down to
224        // a single byte.
225        if (mod <= 0x100) {
226            val = (val & 0xff) ^ (val >> 8);
227        }
228    }
229
230    return val % mod;
231}
232
233/*
234 * Random Boolean
235 *
236 * Pseudo randomly returns 0 (false) or 1 (true).
237 *
238 * Precondition: srand48() called to set the seed of
239 *   the pseudo random number generator.
240 */
241int testRandBool(void)
242{
243    return (testRandMod(2));
244}
245
246/*
247 * Random Fraction
248 *
249 * Pseudo randomly return a value in the range [0.0, 1.0).
250 *
251 * Precondition: srand48() called to set the seed of
252 *   the pseudo random number generator.
253 */
254double testRandFract(void)
255{
256    return drand48();
257}
258
259// Delays for the number of seconds specified by amt or a greater amount.
260// The amt variable is of type float and thus non-integer amounts
261// of time can be specified.  This function automatically handles cases
262// where nanosleep(2) returns early due to reception of a signal.
263void testDelay(float amt)
264{
265    struct timespec   start, current, delta;
266    struct timespec   remaining;
267
268    // Get the time at which we started
269    clock_gettime(CLOCK_MONOTONIC, &start);
270
271    do {
272        // Get current time
273        clock_gettime(CLOCK_MONOTONIC, &current);
274
275        // How much time is left
276        delta = tsDelta(&start, &current);
277        if (ts2double(&delta) > amt) { break; }
278
279        // Request to sleep for the remaining time
280        remaining = double2ts(amt - ts2double(&delta));
281        (void) nanosleep(&remaining, NULL);
282    } while (true);
283}
284
285// Delay spins for the number of seconds specified by amt or a greater
286// amount.  The amt variable is of type float and thus non-integer amounts
287// of time can be specified.  Differs from testDelay() in that
288// testDelaySpin() performs a spin loop, instead of using nanosleep().
289void testDelaySpin(float amt)
290{
291    struct timespec   start, current, delta;
292
293    // Get the time at which we started
294    clock_gettime(CLOCK_MONOTONIC, &start);
295
296    do {
297        // Get current time
298        clock_gettime(CLOCK_MONOTONIC, &current);
299
300        // How much time is left
301        delta = tsDelta(&start, &current);
302        if (ts2double(&delta) > amt) { break; }
303    } while (true);
304}
305
306/*
307 * Hex Dump
308 *
309 * Displays in hex the contents of the memory starting at the location
310 * pointed to by buf, for the number of bytes given by size.
311 * Each line of output is indented by a number of spaces that
312 * can be set by calling xDumpSetIndent().  It is also possible
313 * to offset the displayed address by an amount set by calling
314 * xDumpSetOffset.
315 */
316static uint8_t     xDumpIndent;
317static uint64_t    xDumpOffset;
318void
319testXDump(const void *buf, size_t size)
320{
321    const unsigned int bytesPerLine = 16;
322    int rv;
323    char line[MAXSTR];
324    const unsigned char *ptr = buf, *start = buf;
325    size_t num = size;
326    char *linep = line;
327
328    while (num) {
329        if (((ptr - start) % bytesPerLine) == 0) {
330            if (linep != line) {
331                testPrintE("%s", line);
332            }
333            linep = line;
334            rv = snprintf(linep, ALEN(line) - (linep - line),
335                "%*s%06llx:", xDumpIndent, "",
336                (long long) (ptr - start) + xDumpOffset);
337            linep += rv;
338        }
339
340        // Check that there is at least room for 4
341        // more characters.  The 4 characters being
342        // a space, 2 hex digits and the terminating
343        // '\0'.
344        assert((ALEN(line) - 4) >= (linep - line));
345        rv = snprintf(linep, ALEN(line) - (linep - line),
346            " %02x", *ptr++);
347        linep += rv;
348        num--;
349    }
350    if (linep != line) {
351        testPrintE("%s", line);
352    }
353}
354
355// Set an indent of spaces for each line of hex dump output
356void
357testXDumpSetIndent(uint8_t indent)
358{
359    xDumpIndent = indent;
360}
361
362// Obtain the current hex dump indent amount
363uint8_t
364testXDumpGetIndent(void)
365{
366    return xDumpIndent;
367}
368
369// Set the hex dump address offset amount
370void
371testXDumpSetOffset(uint64_t offset)
372{
373    xDumpOffset = offset;
374}
375
376// Get the current hex dump address offset amount
377uint64_t
378testXDumpGetOffset(void)
379{
380    return xDumpOffset;
381}
382
383/*
384 * Execute Command
385 *
386 * Executes the command pointed to by cmd.  Output from the
387 * executed command is captured and sent to LogCat Info.  Once
388 * the command has finished execution, it's exit status is captured
389 * and checked for an exit status of zero.  Any other exit status
390 * causes diagnostic information to be printed and an immediate
391 * testcase failure.
392 */
393void testExecCmd(const char *cmd)
394{
395    FILE *fp;
396    int rv;
397    int status;
398    char str[MAXSTR];
399
400    // Display command to be executed
401    testPrintI("cmd: %s", cmd);
402
403    // Execute the command
404    fflush(stdout);
405    if ((fp = popen(cmd, "r")) == NULL) {
406        testPrintE("execCmd popen failed, errno: %i", errno);
407        exit(100);
408    }
409
410    // Obtain and display each line of output from the executed command
411    while (fgets(str, sizeof(str), fp) != NULL) {
412        if ((strlen(str) > 1) && (str[strlen(str) - 1] == '\n')) {
413            str[strlen(str) - 1] = '\0';
414        }
415        testPrintI(" out: %s", str);
416    }
417
418    // Obtain and check return status of executed command.
419    // Fail on non-zero exit status
420    status = pclose(fp);
421    if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
422        testPrintE("Unexpected command failure");
423        testPrintE("  status: %#x", status);
424        if (WIFEXITED(status)) {
425            testPrintE("WEXITSTATUS: %i", WEXITSTATUS(status));
426        }
427        if (WIFSIGNALED(status)) {
428            testPrintE("WTERMSIG: %i", WTERMSIG(status));
429        }
430        exit(101);
431    }
432}
433