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