corecrypto/corecrypto_test/lib/testenv.c

356 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Copyright (c) (2012,2014-2020) Apple Inc. All rights reserved.
*
* corecrypto is licensed under Apple Inc.s Internal Use License Agreement (which
* is contained in the License.txt file distributed with corecrypto) and only to
* people who accept that license. IMPORTANT: Any license rights granted to you by
* Apple Inc. (if any) are limited to internal use within your organization only on
* devices and computers you own or control, for the sole purpose of verifying the
* security characteristics and correct functioning of the Apple Software. You may
* not, directly or indirectly, redistribute the Apple Software or any portions thereof.
*/
#include "cc_config.h"
#if CC_LINUX
#define _GNU_SOURCE // For Dl_info
#endif
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdbool.h>
#if defined(_WIN32)
static int optind = 1;
#else
#include <unistd.h>
#include <dlfcn.h>
#endif
#include "testmore.h"
#include "testenv.h"
#include <corecrypto/cc_macros.h>
#include <corecrypto/ccrng.h>
#include "../corecrypto_test/include/testbyteBuffer.h"
static int tests_printall(void);
#ifdef __ANDROID_API__
#include <android/log.h>
#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, "corecrypto", __VA_ARGS__);
#define fprintf(FILE, ...) __android_log_print(ANDROID_LOG_DEBUG, "corecrypto", __VA_ARGS__);
#endif // __ANDROID_API__
static int
tests_summary(int verbose) {
int failed_tests = 0;
int todo_tests = 0;
int actual_tests = 0;
int planned_tests = 0;
int warning_tests = 0;
uint64_t duration_tests = 0;
// First compute the totals to help decide if we need to print headers or not.
for (int i = 0; testlist[i].name; ++i) {
if (testlist[i].executed) {
failed_tests += testlist[i].failed_tests;
todo_tests += testlist[i].todo_tests;
actual_tests += testlist[i].actual_tests;
planned_tests += testlist[i].planned_tests;
warning_tests += testlist[i].warning_tests;
duration_tests += testlist[i].duration;
}
}
fprintf(stdout, "\n[SUMMARY]\n");
// -v makes the summary verbose as well.
if (verbose || failed_tests || actual_tests != planned_tests || todo_tests || warning_tests) {
fprintf(stdout, "Test name failed warning todo ran planned\n");
fprintf(stdout, "============================================================================================\n");
}
for (int i = 0; testlist[i].name; ++i) {
if (testlist[i].executed) {
const char *token = NULL;
if (testlist[i].failed_tests) {
token = "FAIL";
} else if (testlist[i].actual_tests != testlist[i].planned_tests
|| (testlist[i].todo_tests)
|| (testlist[i].warning_tests)) {
token = "WARN";
} else if (verbose) {
token = "PASS";
}
if (token) {
fprintf(stdout, "[%s] %-49s %6d %6d %6d %6d %6d\n", token,
testlist[i].name,
testlist[i].failed_tests, testlist[i].warning_tests,
testlist[i].todo_tests,
testlist[i].actual_tests, testlist[i].planned_tests);
}
}
}
if (verbose || failed_tests || warning_tests || todo_tests || actual_tests != planned_tests) {
fprintf(stdout, "============================================================================================\n");
}
else {
fprintf(stdout, "Test name failed warning todo ran planned\n");
}
fprintf(stdout, "Totals (%6llus) %6d %6d %6d %6d %6d\n", duration_tests/1000, failed_tests, warning_tests, todo_tests, actual_tests, planned_tests);
return failed_tests;
}
#if defined(_WIN32)
static int tests_run_index(int i, int argc, char * const *argv, byteBuffer seed)
{
fprintf(stderr, "\n[BEGIN] %s\n", testlist[i].name);
run_one_test(&testlist[i], argc, argv, seed->len, seed->bytes);
if(testlist[i].failed_tests) {
fprintf(stderr, "[FAIL] %s\n", testlist[i].name);
} else {
fprintf(stderr, "duration: %llu ms\n", testlist[i].duration);
fprintf(stderr, "[PASS] %s\n", testlist[i].name);
}
return 0;
}
#else
static void usage(const char *progname)
{
fprintf(stderr, "usage: %s [-L][-v][-s seed][-w][testname [-v] ...]\n", progname);
fprintf(stderr, "\t-v verbose\n");
fprintf(stderr, "\t-s <seed> to provide a specific seed (ex 8686b151ec2aa17c4ec41a59e496d2ff), reused for each sub-test.\n");
fprintf(stderr, "\t-w sleep(100)\n");
fprintf(stderr, "\t-L list supported tests by test names\n");
fprintf(stderr, "Here is the list of supported tests:\n");
tests_printall();
exit(1);
}
static int tests_run_index(int i, int argc, char * const *argv, byteBuffer seed)
{
int verbose = 0;
int ch;
while ((ch = getopt(argc, argv, "v")) != -1) {
switch (ch) {
case 'v':
verbose++;
break;
default:
usage(argv[0]);
}
}
fprintf(stderr, "\n[BEGIN] %s\n", testlist[i].name);
run_one_test(&testlist[i], argc, argv, seed->len, seed->bytes);
if (testlist[i].failed_tests) {
fprintf(stderr, "[FAIL] %s\n", testlist[i].name);
} else {
fprintf(stderr, "duration: %llu ms\n", testlist[i].duration);
fprintf(stderr, "[PASS] %s\n", testlist[i].name);
}
return 0;
}
static int tests_named_index(const char *testcase)
{
int i;
for (i = 0; testlist[i].name; ++i) {
if (strcmp(testlist[i].name, testcase) == 0) {
return i;
}
}
return -1;
}
#endif
static int tests_printall(void)
{
for (int i = 0; testlist[i].name; ++i) {
fprintf(stdout, "%s\n", testlist[i].name);
}
return 0;
}
static int tests_run_all(int argc, char * const *argv, byteBuffer seed)
{
int curroptind = optind;
int i;
for (i = 0; testlist[i].name; ++i) {
tests_run_index(i, argc, argv,seed);
optind = curroptind;
}
return 0;
}
#if CC_DARWIN || CC_LINUX
static off_t fsize(const char *fname)
{
struct stat st;
return (stat(fname, &st) == 0)? st.st_size:-1;
}
static void print_lib_path(void)
{
Dl_info dl_info;
if( dladdr((void *)cc_clear, &dl_info) != 0){
fprintf(stderr, "corecrypto loaded: %s\nDYLIB size %lld bytes\n\n", dl_info.dli_fname, fsize(dl_info.dli_fname));
}
}
#elif defined(_MSC_VER)
static void print_lib_path(void) {}
#endif
static int tests_init(byteBuffer *pSeedBuffer,const char *seedInput) {
printf("[TEST] === corecrypto ===\n");
print_lib_path();
int status=-1;
// Set a seed for reproducibility
if (seedInput!=NULL) {
*pSeedBuffer=hexStringToBytes(seedInput);
if (*pSeedBuffer) {
printByteBuffer(*pSeedBuffer,"\nInput seed value:");
status=0;
}
else{
printf("Error with input seed value: %s",seedInput);
}
} else {
// If the seed is not in the argument, we generate one
size_t entropy_size=16; // Default size of the seed
cc_require((*pSeedBuffer=mallocByteBuffer(entropy_size))!=NULL,errOut);
struct ccrng_state *rng = ccrng(&status);
cc_require(rng!=NULL, errOut);
cc_require((status=ccrng_generate(rng, (*pSeedBuffer)->len, (*pSeedBuffer)->bytes))==0, errOut);
printByteBuffer(*pSeedBuffer,"\nRandom seed value:");
printf("Seed used for every subtest. To reproduce a failure, you can run with '-s <seed> <subtest>'\n");
}
errOut:
return status;
}
#if defined(_WIN32)
int
tests_begin(int argc, char * const *argv)
{
const char *seed=NULL;
byteBuffer seedBuffer=NULL; //seed for test drbg
int list = 0;
int retval;
int verbose = 0;
printf("Command-line options are currently not supported on Windows.\n");
if ((retval=tests_init(&seedBuffer, seed)) != 0) {
printf("%08x unable to initialize tests", retval);
return -1;
}
tests_run_all(argc, argv, seedBuffer);
if (list) {
tests_printall();
retval = 0;
}
else {
retval = tests_summary(verbose);
}
/* Cleanups */
free(seedBuffer);
retval = tests_summary(verbose);
return retval;
}
#else
int
tests_begin(int argc, char * const *argv)
{
const char *seed=NULL;
byteBuffer seedBuffer=NULL;
int retval;
int verbose = 0;
const char *testcase = NULL;
bool initialized = false;
int testix = -1;
int ch;
for (;;) {
while (!testcase && (ch = getopt(argc, argv, "Lvws:")) != -1) {
switch (ch) {
case 's': // seed provided
// The same seed is reused for all of the tests
seed = optarg;
break;
case 'w': // wait
sleep(100);
break;
case 'v': // verbose
verbose=1;
break;
case 'L': // List test for test discovery
tests_printall();
exit(0);
case '?':
default:
printf("invalid option %c\n",ch);
usage(argv[0]);
}
}
if (optind < argc) {
testix = tests_named_index(argv[optind]);
if (testix < 0) {
printf("invalid test %s\n",argv[optind]);
usage(argv[0]);
}
testcase = argv[optind];
argc -= optind;
argv += optind;
optind = 1;
}
if (testix < 0) {
// Not test specified or reached end of list
if (!initialized) {
// Not test specified
if (tests_init(&seedBuffer, seed) != 0) {
return -1;
}
tests_run_all(argc, argv, seedBuffer);
}
break;
} else {
if (!initialized) {
if (tests_init(&seedBuffer, seed) != 0) {
return -1;
}
initialized = true;
}
tests_run_index(testix, argc, argv,seedBuffer);
testix = -1;
}
}
/* Cleanups */
free(seedBuffer);
retval=tests_summary(verbose);
return retval;
}
#endif