a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/*
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Copyright (C) 2011 Michael Brown <mbrown@fensystems.co.uk>.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync *
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * This program is free software; you can redistribute it and/or
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * modify it under the terms of the GNU General Public License as
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * published by the Free Software Foundation; either version 2 of the
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * License, or any later version.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync *
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * This program is distributed in the hope that it will be useful, but
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * WITHOUT ANY WARRANTY; without even the implied warranty of
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * General Public License for more details.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync *
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * You should have received a copy of the GNU General Public License
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * along with this program; if not, write to the Free Software
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncFILE_LICENCE ( GPL2_OR_LATER );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/** @file
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync *
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Self-test infrastructure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync *
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/* Forcibly enable assertions */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#undef NDEBUG
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#include <stddef.h>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#include <stdio.h>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#include <errno.h>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#include <assert.h>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#include <ipxe/test.h>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#include <ipxe/init.h>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#include <ipxe/image.h>
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/** Current self-test set */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic struct self_test *current_tests;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/**
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Report test result
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync *
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * @v success Test succeeded
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * @v file Test code file
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * @v line Test code line
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncvoid test_ok ( int success, const char *file, unsigned int line ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Sanity check */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync assert ( current_tests != NULL );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Increment test counter */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync current_tests->total++;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Report failure if applicable */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( ! success ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync current_tests->failures++;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "FAILURE: \"%s\" test failed at %s line %d\n",
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync current_tests->name, file, line );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync}
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/**
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Run self-test set
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync *
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic void run_tests ( struct self_test *tests ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync unsigned int old_assertion_failures = assertion_failures;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Sanity check */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync assert ( current_tests == NULL );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Record current test set */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync current_tests = tests;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Run tests */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync tests->exec();
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Clear current test set */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync current_tests = NULL;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Record number of assertion failures */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync tests->assertion_failures =
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync ( assertion_failures - old_assertion_failures );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Print test set summary */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( tests->failures || tests->assertion_failures ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "FAILURE: \"%s\" %d of %d tests failed",
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync tests->name, tests->failures, tests->total );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( tests->assertion_failures ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( " with %d assertion failures",
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync tests->assertion_failures );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "\n" );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync } else {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "OK: \"%s\" %d tests passed\n",
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync tests->name, tests->total );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync}
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/**
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Run all self-tests
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync *
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * @ret rc Return status code
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int run_all_tests ( void ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync struct self_test *tests;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync unsigned int failures = 0;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync unsigned int assertions = 0;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync unsigned int total = 0;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Run all compiled-in self-tests */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "Starting self-tests\n" );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync for_each_table_entry ( tests, SELF_TESTS )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync run_tests ( tests );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Print overall summary */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync for_each_table_entry ( tests, SELF_TESTS ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync total += tests->total;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync failures += tests->failures;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync assertions += tests->assertion_failures;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( failures || assertions ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "FAILURE: %d of %d tests failed",
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync failures, total );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( assertions ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( " with %d assertion failures", assertions );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "\n" );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return -EINPROGRESS;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync } else {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "OK: all %d tests passed\n", total );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return 0;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync}
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int test_image_probe ( struct image *image __unused ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return -ENOTTY;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync}
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int test_image_exec ( struct image *image __unused ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return run_all_tests();
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync}
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic struct image_type test_image_type = {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync .name = "self-tests",
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync .probe = test_image_probe,
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync .exec = test_image_exec,
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync};
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic struct image test_image = {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync .refcnt = REF_INIT ( ref_no_free ),
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync .name = "<TESTS>",
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync .type = &test_image_type,
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync};
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic void test_init ( void ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync int rc;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Register self-tests image */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( ( rc = register_image ( &test_image ) ) != 0 ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync DBG ( "Could not register self-test image: %s\n",
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync strerror ( rc ) );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* No way to report failure */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync}
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/** Self-test initialisation function */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstruct init_fn test_init_fn __init_fn ( INIT_EARLY ) = {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync .initialise = test_init,
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync};