Commit a01439a7 authored by Juergen Haug's avatar Juergen Haug
Browse files

added etUnit2 API with "etunit" module prefix

parent 2a869e81
......@@ -13,114 +13,16 @@
*******************************************************************************/
/**
* \file etUnit.h
*
* a collection of methods for unit testing. The component uses a very simple file output format
* which is translated into JUnit xml format by a separate tool written in Java and also part of the
* eTrice project
*
* \author Thomas Schuetz
* etUnit API without module prefix
*/
#ifndef _ETUNIT_H_
#define _ETUNIT_H_
#include "etDatatypes.h"
#include <string.h>
#include "etUnit2.h"
ET_EXTERN_C_BEGIN
// compile time evaluated
#define ETUNIT_FILENAME (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__))
typedef void (*etUnit_WriteFunction)(void* handle, const char* format, ...);
/**
* opens a file to protocol the test results
*
* \param testResultPath the file path
* \param testFileName the file name
*/
void etUnit_open(const char* testResultPath, const char* testFileName);
/**
* closes the protocol file
*/
void etUnit_close(void);
/**
* opens a test suite which is a collection of test cases
*
* \param testSuiteName the name of the suite
*/
void etUnit_openTestSuite(const char* testSuiteName);
/**
* closes the currently open test suite
*/
void etUnit_closeTestSuite(void);
/**
* enable support for parallel test cases (default false)
*/
void etUnit_setParallelTestCases(etBool enabled);
/**
* write etunit output to callback
*/
void etUnit_setWriteFunction(etUnit_WriteFunction fct);
/**
* opens a test case. Multiple test cases can be open at a time
*
* \param testCaseName the name of the test case
*
* \return in case of parallel testing an id which has to be used as an identifier
* for the expects and other methods, otherwise zero
*/
etInt16 etUnit_openTestCase(const char* testCaseName);
/**
* closes a test case
*
* \param id the test case id
*/
void etUnit_closeTestCase(etInt16 id);
/**
* skips a test case
*
* \param id the test case id
* \param msg the message or reason
*/
void etUnit_skipTestCase(etInt16 id, const char* msg);
/**
* indicate success of a test case
*
* \param id the test case id
*/
etBool etUnit_isSuccess(etInt16 id);
/**
* releases the \ref etRuntime_getTerminateSemaphore() and thus makes the program terminate
*
* \param id (unused)
*/
void etUnit_testFinished(etInt16 id);
/* functions for more convenience for model and generator tests */
/**
* opens a file, test suite and test case
*
* \param testResultPath the file path
* \param testFileName the file name
* \param testSuiteName the name of the suite
* \param testCaseName the name of the test case
*
* \return an id for the test case which has to be used as an identifier
* for the expect... and other methods
*/
etInt16 etUnit_openAll(const char* testResultPath, const char* testFileName, const char* testSuiteName, const char* testCaseName);
/**
* closes test case, suite and file
*
* \param id the test case id
*/
void etUnit_closeAll(etInt16 id);
/*
* boolean values
*/
......@@ -194,283 +96,6 @@ void etUnit_closeAll(etInt16 id);
/** calls \ref expectOrderEnd() */
#define EXPECT_ORDER_END(id, msg, val) expectOrderEnd(id, msg, val, ETUNIT_FILENAME, __LINE__)
/*
* Alternative expects omitting id argument (without parallel testing)
*/
#define ETUNIT_TRUE(msg, condition) expectTrue(0, msg, condition, ETUNIT_FILENAME, __LINE__)
#define ETUNIT_FALSE(msg, condition) expectFalse(0, msg, condition, ETUNIT_FILENAME, __LINE__)
#define ETUNIT_FAIL(msg) expectFail(0, msg, ETUNIT_FILENAME, __LINE__)
#define ETUNIT_EQUAL_INT(msg, expected, actual) expectEqualInt32(0, msg, expected, actual, ETUNIT_FILENAME, __LINE__)
#define ETUNIT_EQUAL_UINT(msg, expected, actual) expectEqualUInt32(0, msg, expected, actual, ETUNIT_FILENAME, __LINE__)
#ifdef ET_FLOAT32
#define ETUNIT_EQUAL_FLOAT32(msg, expected, actual, precision) expectEqualFloat32(0, msg, expected, actual, precision, ETUNIT_FILENAME, __LINE__)
#define ETUNIT_RANGE_FLOAT32(msg, min, max, actual) expectRangeFloat32(0, msg, min, max, actual, ETUNIT_FILENAME, __LINE__)
#endif
#ifdef ET_FLOAT64
#define ETUNIT_EQUAL_FLOAT64(msg, expected, actual, precision) expectEqualFloat64(0, msg, expected, actual, precision, ETUNIT_FILENAME, __LINE__)
#define ETUNIT_RANGE_FLOAT64(msg, min, max, actual) expectRangeFloat64(0, msg, min, max, actual, ETUNIT_FILENAME, __LINE__)
#endif
#define ETUNIT_EQUAL_PTR(msg, expected, actual) \
expect_equal_void_ptr(ETUNIT_SINGLETON_TEST_CASE_ID, msg, (const void*) expected, (const void*) actual, ETUNIT_FILENAME, __LINE__)
#define ETUNIT_EQUAL_STR(msg, expected, actual) expectEqualStr(0, msg, expected, actual, ETUNIT_FILENAME, __LINE__)
#define ETUNIT_ORDER_START(list, size) expectOrderStart(0, list, size, ETUNIT_FILENAME, __LINE__)
#define ETUNIT_ORDER(msg, val) expectOrder(0, msg, val, ETUNIT_FILENAME, __LINE__)
#define ETUNIT_ORDER_END(msg, val) expectOrderEnd(0, msg, val, ETUNIT_FILENAME, __LINE__)
/*
* Helpers for adding test cases
*/
/**
* code block with calls \ref etUnit_openTestCase() followed by a call to the passed
* test case followed by a call to \ref etUnit_closeTestCase
*
* \param testcase the name of a test case method
*/
#define ADD_TESTCASE(testcase) \
{ etInt16 id = etUnit_openTestCase(#testcase); \
testcase(id); \
etUnit_closeTestCase(id);}
/*
* function prototypes, use above macros to call them
*/
/**
* reports an error if the condition is <code>false</code>
*
* \param id the test case id
* \param msg the result message
* \param condition the condition that is expected to be <code>true</code>
* \param file the file name with the test case
* \param line the line
*/
void expectTrue(etInt16 id, const char* msg, etBool condition, const char* file, int line);
/**
* reports an error if the condition is <code>true</code>
*
* \param id the test case id
* \param msg the result message
* \param condition the condition that is expected to be <code>false</code>
* \param file the file name with the test case
* \param line the line
*/
void expectFalse(etInt16 id, const char* msg, etBool condition, const char* file, int line);
/**
* reports an fail
*
* \param id the test case id
* \param msg the result message
* \param file the file name with the test case
* \param line the line
*/
void expectFail(etInt16 id, const char* msg, const char* file, int line);
/**
* reports an error if two integers aren't equal
*
* \param id the test case id
* \param msg the result message
* \param expected the expected value
* \param actual the actual value
* \param file the file name with the test case
* \param line the line
*/
void expectEqualInt8(etInt16 id, const char* msg, etInt8 expected, etInt8 actual, const char* file, int line);
/**
* reports an error if a value is not inside a range e.g. [2, 123]
*
* \param id the test case id
* \param msg the result message
* \param min the lower limit (inclusive)
* \param max the upper limit (inclusive)
* \param actual the actual value
* \param file the file name with the test case
* \param line the line
*/
void expectRangeInt8(etInt16 id, const char* msg, etInt8 min, etInt8 max, etInt8 actual, const char* file, int line);
/**
* reports an error if two integers aren't equal
*
* \param id the test case id
* \param msg the result message
* \param expected the expected value
* \param actual the actual value
* \param file the file name with the test case
* \param line the line
*/
void expectEqualInt16(etInt16 id, const char* msg, etInt16 expected, etInt16 actual, const char* file, int line);
/**
* reports an error if two integers aren't equal
*
* \param id the test case id
* \param msg the result message
* \param expected the expected value
* \param actual the actual value
* \param file the file name with the test case
* \param line the line
*/
void expectEqualInt32(etInt16 id, const char* msg, etInt32 expected, etInt32 actual, const char* file, int line);
/**
* reports an error if two integers aren't equal
*
* \param id the test case id
* \param msg the result message
* \param expected the expected value
* \param actual the actual value
* \param file the file name with the test case
* \param line the line
*/
void expectEqualUInt8(etInt16 id, const char* msg, etUInt8 expected, etUInt8 actual, const char* file, int line);
/**
* reports an error if two integers aren't equal
*
* \param id the test case id
* \param msg the result message
* \param expected the expected value
* \param actual the actual value
* \param file the file name with the test case
* \param line the line
*/
void expectEqualUInt16(etInt16 id, const char* msg, etUInt16 expected, etUInt16 actual, const char* file, int line);
/**
* reports an error if two integers aren't equal
*
* \param id the test case id
* \param msg the result message
* \param expected the expected value
* \param actual the actual value
* \param file the file name with the test case
* \param line the line
*/
void expectEqualUInt32(etInt16 id, const char* msg, etUInt32 expected, etUInt32 actual, const char* file, int line);
/**
* reports an error if two floats aren't equal
*
* \param id the test case id
* \param msg the result message
* \param expected the expected value
* \param actual the actual value
* \param precision expected +/- precision defines the window for acceptance of an actual value
* \param file the file name with the test case
* \param line the line
*/
#ifdef ET_FLOAT32
void expectEqualFloat32(etInt16 id, const char* msg, etFloat32 expected, etFloat32 actual, etFloat32 precision, const char* file, int line);
#endif
/**
* reports an error if two floats aren't equal
*
* \param id the test case id
* \param msg the result message
* \param expected the expected value
* \param actual the actual value
* \param precision expected +/- precision defines the window for acceptance of an actual value
* \param file the file name with the test case
* \param line the line
*/
#ifdef ET_FLOAT64
void expectEqualFloat64(etInt16 id, const char* msg, etFloat64 expected, etFloat64 actual, etFloat64 precision, const char* file, int line);
#endif
/**
* reports an error if a value is not inside a range e.g. [-5.1, +3.0]
*
* \param id the test case id
* \param msg the result message
* \param min the lower limit (inclusive)
* \param max the upper limit (inclusive)
* \param actual the actual value
* \param file the file name with the test case
* \param line the line
*/
#ifdef ET_FLOAT32
void expectRangeFloat32(etInt16 id, const char* message, etFloat32 min, etFloat32 max, etFloat32 actual, const char* file, int line) ;
#endif
/**
* reports an error if a value is not inside a range e.g. [-5.1, +3.0]
*
* \param id the test case id
* \param msg the result message
* \param min the lower limit (inclusive)
* \param max the upper limit (inclusive)
* \param actual the actual value
* \param file the file name with the test case
* \param line the line
*/
#ifdef ET_FLOAT64
void expectRangeFloat64(etInt16 id, const char* message, etFloat64 min, etFloat64 max, etFloat64 actual, const char* file, int line) ;
#endif
/**
* reports an error if two pointers aren't equal
*
* \param id the test case id
* \param msg the result message
* \param expected the expected value
* \param actual the actual value
* \param file the file name with the test case
* \param line the line
*/
void expect_equal_void_ptr(etInt16 id, const char* msg, const void* expected, const void* actual, const char* file, int line);
/**
* reports an error if two strings aren't equal
*
* \param id the test case id
* \param msg the result message
* \param expected the expected value
* \param actual the actual value
* \param file the file name with the test case
* \param line the line
*/
void expectEqualStr(etInt16 id, const char* msg, const char* expected, const char* actual, const char* file, int line);
/**
* start of a comparison of an expected order. Initially with this method
* a list of integers is passed. Later calls of \ref expectOrder(etInt16, const char* msg, etInt16, const char* int)
* are compared against the next value in the list and the list pointer is incremented
*
* \param id the test case id
* \param list the list of expected values
* \param size the size of the list
* \param file the file name with the test case
* \param line the line
*/
void expectOrderStart(etInt16 id, const etInt16* list, etInt16 size, const char* file, int line);
/**
* reports an error if the identifier doesn't match the next value in the list
*
* \param id the test case id
* \param msg the result message
* \param identifier the expected next value
* \param file the file name with the test case
* \param line the line
*/
void expectOrder(etInt16 id, const char* msg, etInt16 identifier, const char* file, int line);
/**
* reports an error if the identifier doesn't match the next value in the list which
* is expected to be the last one
*
* \param id the test case id
* \param msg the result message
* \param identifier the expected next value
* \param file the file name with the test case
* \param line the line
*/
void expectOrderEnd(etInt16 id, const char* msg, etInt16 identifier, const char* file, int line);
ET_EXTERN_C_END
#endif /* _ETUNIT_H_ */
......
/*******************************************************************************
* Copyright (c) 2011 protos software gmbh (http://www.protos.de).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* CONTRIBUTORS:
* Thomas Schuetz (initial contribution)
*
*******************************************************************************/
#include "etUnit/etUnit2.h"
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <assert.h>
#include "debugging/etLogger.h"
#include "osal/etSema.h"
#include "runtime/etRuntime.h"
#include "helpers/etTimeHelpers.h"
/*** member variables */
/* file handling */
static FILE* etUnit_reportfile = NULL;
/* counters */
static etInt16 etUnit_nextCaseId;
static etInt32 etUnit_errorCounter;
static etBool etUnit_parallelTestCases = ET_FALSE;
#define ETUNIT_MAX_PARALLEL_TEST_CASES 5
static etBool etUnit_testcaseSuccess[ETUNIT_MAX_PARALLEL_TEST_CASES];
static etBool etUnit_testcaseOpen[ETUNIT_MAX_PARALLEL_TEST_CASES];
#define ETUNIT_FAILURE_TEXT_LEN 256
/* time measuring */
static etTime etUnit_startTime;
static etTime etUnit_lastTestCaseTime;
/*
* Returns index to store current test case state
* - 'caseId' for parallel test cases
* - 0 for singleton test case
*/
static etInt16 getParallelIndex(etInt16 caseId) {
etInt16 idx = (etUnit_parallelTestCases) ? caseId - 1 : 0;
assert(idx >= 0 && idx < ETUNIT_MAX_PARALLEL_TEST_CASES);
return idx;
}
/* Lookup valid open test case id */
static etInt16 getOpenTestCaseId(etInt16 id) {
etInt16 caseId;
if (etUnit_parallelTestCases) {
// index is id of parallel test case
assert(id > 0);
caseId = id;
} else {
// index is 0, return current open test case
assert(id == 0);
caseId = etUnit_nextCaseId - 1;
}
if(!etUnit_testcaseOpen[getParallelIndex(caseId)]) {
etLogger_logErrorF("Test case was not opened");
}
return caseId;
}
/* order */
#define ETUNIT_ORDER_MAX 16
typedef struct OrderInfo {
etInt16 id;
etInt16 currentIndex;
etInt16 size;
const etInt16* list;
} OrderInfo;
static OrderInfo etUnit_orderInfo[ETUNIT_ORDER_MAX];
static OrderInfo* getOrderInfo(etInt16 id) {
etInt16 caseId = getOpenTestCaseId(id);
for (int i = 0; i < ETUNIT_ORDER_MAX; ++i)
if (etUnit_orderInfo[i].id == caseId)
return etUnit_orderInfo + i;
return NULL;
}
/* float measuring */
#if defined (ET_FLOAT32) || defined (ET_FLOAT64)
#define ETUNIT_FLOAT
#ifdef ET_FLOAT64
typedef etFloat64 etUnitFloat;
#else
typedef etFloat32 etUnitFloat;
#endif
#endif
/* forward declarations of private functions */
static void expect_equal_int(etInt16 id, const char* message, etInt32 expected, etInt32 actual, const char* file, int line);
/* currently not used
static void expect_range_int(etInt16 id, const char* message, etInt32 min, etInt32 max, etInt32 actual, const char* file, int line);
*/
static void expect_equal_uint(etInt16 id, const char* message, etUInt32 expected, etUInt32 actual, const char* file, int line);
/* currently not used
static void expect_range_uint(etInt16 id, const char* message, etUInt32 min, etUInt32 max, etUInt32 actual, const char* file, int line);
*/
#ifdef ETUNIT_FLOAT
static void expect_equal_float(etInt16 id, const char* message, etUnitFloat expected, etUnitFloat actual, etUnitFloat precision, const char* file, int line);
static void expect_range_float(etInt16 id, const char* message, etUnitFloat min, etUnitFloat max, etUnitFloat actual, const char* file, int line);
#endif
static void etUnit_handleExpect(etInt16 id, etBool result, const char *trace, const char* expected, const char* actual, const char* file, int line);
/* configuration functions */
void etUnit_setParallelTestCases(etBool enabled) {
etUnit_parallelTestCases = enabled;
}
/* public functions */
void etUnit_open(const char* testResultPath, const char* testFileName) {
etLogger_logInfoF("************* TEST START (%s) **************", testFileName);
{
char filename[ETUNIT_FAILURE_TEXT_LEN];
if (testResultPath != NULL)
snprintf(filename, sizeof(filename), "%s/%s.etu", testResultPath, testFileName);
else
snprintf(filename, sizeof(filename),"%s.etu", testFileName);
/* init global data */
for (int i = 0; i < ETUNIT_ORDER_MAX; ++i) {
etUnit_orderInfo[i].id = 0;
}
for (int i = 0; i < ETUNIT_MAX_PARALLEL_TEST_CASES; ++i) {
etUnit_testcaseSuccess[i] = ET_TRUE;
etUnit_testcaseOpen[i] = ET_FALSE;
}
etUnit_errorCounter = 0;
etUnit_nextCaseId = 1;
if (etUnit_reportfile == NULL) {
etUnit_reportfile = etLogger_fopen(filename, "w+");
if (etUnit_reportfile != NULL) {
etLogger_fprintf(etUnit_reportfile, "etUnit report\n");
} else {
etLogger_logErrorF("Unable to open file %s", filename);
}
}
}
/* prepare time measurement */
getTimeFromTarget(&etUnit_startTime);
}
void etUnit_close(void) {
etTime endTime;
if (etUnit_reportfile != NULL) {
etLogger_fclose(etUnit_reportfile);
etUnit_reportfile = NULL;
}
getTimeFromTarget(&endTime);
etTimeHelpers_subtract(&endTime, &etUnit_startTime);
etLogger_logInfoF("Elapsed Time: %ld ms", etTimeHelpers_convertToMSec(&endTime));
if (etUnit_errorCounter == 0)
etLogger_logInfoF("Error Counter: %ld", etUnit_errorCounter);
else
etLogger_logErrorF("Error Counter: %ld", etUnit_errorCounter);
etLogger_logInfoF("************* TEST END **************");
}
void etUnit_openTestSuite(const char* testSuiteName) {
if (etUnit_reportfile != NULL) {
etLogger_fprintf(etUnit_reportfile, "ts start: %s\n", testSuiteName);
}
}
void etUnit_closeTestSuite(void) {
}
/* Opens new test case, if parallel is activated returns new test case id otherwise 0*/
etInt16 etUnit_openTestCase(const char* testCaseName) {
if(etUnit_nextCaseId >= INT16_MAX) {
etLogger_logErrorF("Too many test cases. Maximum number is %d", INT16_MAX);
exit(-1);
}
etInt16 caseId = etUnit_nextCaseId++;
etInt16 idx = getParallelIndex(caseId);<