/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file unit-test.h
* @ingroup testing
* @brief LongBow Unit Test Support.
*
* Every LongBow Test module must include this file as the first included file after
* including the files necessary for the functions under test.
*
*/
#ifndef UNIT_TEST_H_
#define UNIT_TEST_H_
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define longBowUnused(declaration) declaration __attribute__((unused))
/**
* Test Runner setup function called before the invocation of the Test Fixtures associated with this Test Runner.
*
* Every Test Runner has a set-up and tear-down function that are invoked
* just before and just after the execution of each test case function.
* This function performs setup common for all fixtures to use.
* If this function must return a valid `LongBowStatus` value.
*
* @param [in] runnerName A valid identifier for the Test Runner.
*
* @return A LongBowStatus indicating the status of the setup.
*
* Example:
* @code
* // An example of a minimal Test Runner Setup function.
*
* LONGBOW_TEST_RUNNER_SETUP(LongBow)
* {
* return LONGBOW_STATUS_SUCCEEDED;
* }
* @endcode
*
* @see LONGBOW_TEST_RUNNER_TEARDOWN
*/
#define LONGBOW_TEST_RUNNER_SETUP(runnerName) \
LongBowStatus longBowUnitTest_RunnerSetupName(runnerName) (LongBowTestRunner * testRunner); \
LongBowStatus longBowUnitTest_RunnerSetupName(runnerName) (longBowUnused(LongBowTestRunner * testRunner))
/**
* @brief The post-processing for a Test Runner called after all fixtures have been run.
*
* The Test Runner calls this function once after all the Test Fixtures are run.
*
* This function is responsible for resetting or restoring external resources previously setup by the
* Test Runner Setup function and which may have been modified by any test fixture or test case.
* If this function must return a valid LongBowStatus value.
*
* @see LONGBOW_TEST_RUNNER_SETUP
* @param [in] longBowRunnerName A valid identifier for the Test Runner.
*/
#define LONGBOW_TEST_RUNNER_TEARDOWN(longBowRunnerName) \
LongBowStatus longBowUnitTest_RunnerTearDownName(longBowRunnerName) (LongBowTestRunner * testRunner); \
LongBowStatus longBowUnitTest_RunnerTearDownName(longBowRunnerName) (longBowUnused(LongBowTestRunner * testRunner))
/**
* @brief Define a Test Case Runner with the given name.
* The name must be valid syntax for a C identifier and will be used to compose a longer C function name.
*
* The resulting function that this macro defines specifies the parameter `LongBowTestRunner *testRunner`
* which is a pointer to a LongBowTestRunner instance for the Test Runner.
*
* @param [in] testRunnerName A valid identifier for the Test Runner.
*/
#define LONGBOW_TEST_RUNNER(testRunnerName) \
void longBowUnitTest_RunnerName(testRunnerName) (const LongBowTestRunner * testRunner); \
void longBowUnitTest_RunnerName(testRunnerName) (const LongBowTestRunner * testRunner)
/**
* @brief Create an allocated instance of a LongBowTestRunner that must be destroyed via `longBowTestRunner_Destroy`
*
* @param [in] testRunnerName A valid identifier for the Test Runner. (see LONGBOW_TEST_RUNNER)
* @return The return value from longBowTestRunner_Create
*/
#define LONGBOW_TEST_RUNNER_CREATE(testRunnerName) \
longBowTestRunner_Create(#testRunnerName, \
longBowUnitTest_RunnerSetupName(testRunnerName), \
(LongBowTestRunnerRun *) longBowUnitTest_RunnerName(testRunnerName), \
longBowUnitTest_RunnerTearDownName(testRunnerName))
#define LongBowTestRunner_Create(_runnerName_) \
longBowTestRunner_Create(#_runnerName_, longBowUnitTest_RunnerSetupName(_runnerName_), \
longBowUnitTest_RunnerName(_runnerName_), longBowUnitTest_RunnerTearDownName(_runnerName_))
/**
* @brief Run the LongBow test fixture with the specified `fixtureName`.
*
* @param [in] LongBowTestFixtureName A valid C identifier
* @see LONGBOW_TEST_FIXTURE(fixtureName)
*/
#define LONGBOW_RUN_TEST_FIXTURE(LongBowTestFixtureName) \
do { \
extern LONGBOW_TEST_FIXTURE_SETUP(LongBowTestFixtureName); \
extern LONGBOW_TEST_FIXTURE_TEARDOWN(LongBowTestFixtureName); \
extern LongBowUnitTest_FixtureDeclaration(LongBowTestFixtureName); \
extern LongBowTestFixtureConfig longBowUnitTest_FixtureConfigName(LongBowTestFixtureName); \
longBowTestFixture_Run(testRunner, \
#LongBowTestFixtureName, \
&longBowUnitTest_FixtureConfigName(LongBowTestFixtureName), \
longBowUnitTest_FixtureSetupName(LongBowTestFixtureName), \
longBowUnitTest_FixtureName(LongBowTestFixtureName), \
longBowUnitTest_FixtureTearDownName(LongBowTestFixtureName)); \
} while (0)
/**
* @brief Define a test fixture with the given `fixtureName`.
*
* The value for `fixtureName` must be a valid syntax for a C identifier.
*
* @param [in] fixtureName A valid syntax for a C identifier.
*/
#define LongBowUnitTest_FixtureDeclaration(_fixtureName_) \
void longBowUnitTest_FixtureName(_fixtureName_)(longBowUnused(const LongBowTestRunner * testRunner), longBowUnused(const LongBowTestFixture * testFixture))
/**
* @brief The default value for the expected result of a LongBow Fixture.
*/
#define LONGBOW_TEST_FIXTURE_CONFIG_DEFAULT .enabled = true
/**
* @brief Define a test fixture with the given `fixtureName`.
*
* The value for `fixtureName` must be valid syntax for a C identifier.
*
* The resulting function that this macro defines specifies the parameter `LongBowTestFixture *LongBowTestFixture`
* which is a pointer to a `LongBowTestFixture` instance for the Test Fixture.
*
* @param [in] fixtureName
*/
#define LONGBOW_TEST_FIXTURE(fixtureName) \
LONGBOW_TEST_FIXTURE_OPTIONS(fixtureName, LONGBOW_TEST_FIXTURE_CONFIG_DEFAULT)
#define LONGBOW_TEST_FIXTURE_OPTIONS(fixtureName, ...) \
LongBowCompiler_IgnoreInitializerOverrides \
LongBowTestFixtureConfig longBowUnitTest_FixtureConfigName(fixtureName) = { LONGBOW_TEST_FIXTURE_CONFIG_DEFAULT, __VA_ARGS__ }; \
LongBowCompiler_WarnInitializerOverrides \
extern LONGBOW_TEST_FIXTURE_SETUP(fixtureName); \
extern LONGBOW_TEST_FIXTURE_TEARDOWN(fixtureName); \
LongBowUnitTest_FixtureDeclaration(fixtureName); \
LongBowUnitTest_FixtureDeclaration(fixtureName)
/**
* The pre-processing for a test fixture called before each invocation of a test case in the same fixture.
*
* This function is responsible for setting up the common programmatic state for each test case in the same fixture.
* If this function returns `false` the corresponding test case is skipped.
*
* The resulting function that this macro defines specifies the parameters
* `LongBowTestFixture *testFixture` and `LongBowTestCase *testCase`
*
* @param [in] fixtureName
*
* @see LONGBOW_TEST_FIXTURE_TEARDOWN
*/
#define LONGBOW_TEST_FIXTURE_SETUP(fixtureName) \
LongBowStatus longBowUnitTest_FixtureSetupName(fixtureName) (longBowUnused(const LongBowTestRunner * testRunner), longBowUnused(const LongBowTestFixture * testFixture), longBowUnused(const LongBowTestCase * testCase), longBowUnused(LongBowClipBoard * testClipBoard))
/**
* The post-processing for a test fixture called after each invocation of a test case in the same fixture.
*
* This function is responsible for resetting the common programmatic state for each test case in the same fixture.
* If this function returns `false` the corresponding test case is considered passed, but warned.
*
* The resulting function that this macro defines specifies the parameters
* `LongBowTestFixture *testFixture` and `LongBowTestCase *testCase`
*
* @param [in] fixtureName
*
* @see `LONGBOW_TEST_FIXTURE_SETUP`
*/
#define LONGBOW_TEST_FIXTURE_TEARDOWN(fixtureName) \
LongBowStatus longBowUnitTest_FixtureTearDownName(fixtureName) (longBowUnused(const LongBowTestRunner * testRunner), longBowUnused(const LongBowTestFixture * testFixture), longBowUnused(const LongBowTestCase * testCase), longBowUnused(LongBowClipBoard * testClipBoard))
/**
* @brief Defines the canonical name of a LongBow Test Case meta data.
*
* @param fixtureName The name of the Test Fixture that the Test Case belongs to.
* @param testCaseName The name of the Test Case.
*/
#define longBowTestCase_MetaDataDeclaration(_testFixtureName_, _testCaseName_) \
TestCase ## _testFixtureName_ ## _testCaseName_ ## MetaData
/**
* @brief Forward declare a LongBow Test Case.
*
* @param fixtureName The name of the Test Fixture that the Test Case belongs to.
* @param testCaseName The name of the Test Case.
*/
#define longBowUnitTest_TestCaseDeclaration(fixtureName, testCaseName) \
void longBowUnitTest_CaseName(fixtureName, testCaseName) (longBowUnused(const LongBowTestRunner * testRunner), longBowUnused(const LongBowTestFixture * testFixture), longBowUnused(const LongBowTestCase * testCase), longBowUnused(const LongBowClipBoard * testClipBoard), longBowUnused(jmp_buf longBowTestCaseAbort))
/**
* @brief The default value for the expected result of a LongBow Test Case.
*/
#define LongBowUnitTest_TestCaseDefaultExpectedResult .event = NULL, .status = LongBowStatus_DONTCARE
/**
* Define a test case with the given `fixtureName` and `testCaseName`.
*
* The `fixtureName` must be the name of a defined fixture, see `LONGBOW_TEST_FIXTURE`.
* The `testCaseName` must be valid syntax for a C identifier.
*
* @param fixtureName
* @param testCaseName
*
* @code
* LONGBOW_TEST_CASE(MyFixture, MyTestCase)
* {
* assertTrue(true, "It lied to me!");
* }
*/
#define LONGBOW_TEST_CASE(fixtureName, testCaseName) \
LONGBOW_TEST_CASE_EXPECTS(fixtureName, testCaseName, LongBowUnitTest_TestCaseDefaultExpectedResult)
/**
* Define a test case with the given `fixtureName` and `testCaseName` with an explictly specified status.
*
* The `fixtureName` must be the name of a defined fixture, see `LONGBOW_TEST_FIXTURE`.
* The `testCaseName` is the name of the Test Case and must be valid syntax for a C identifier.
* The variable number of subsequent arguments are a comma separated list of structure initialisers for the
* LongBowRuntimeResult structure.
*
* For example, the construct
* @code
* LONGBOW_TEST_CASE_EXPECTS(MyFixture, alwaysWarn, .event = &LongBowAssertEvent)
* @endcode
* defines the Long Bow Test case `alwaysWarn` that is within the Test Fixture named `MyFixture`.
* The expected termination is expected to be a `LongBowAssertEvent`, which means an assertion was triggered.
*
* If the termination status of the test must is equal to the specified status,
* the test will be signaled as `LONGBOW_STATUS_SUCCESS, otherwise it will be LONGBOW_STATUS_FAILED.
*
* @param fixtureName
* @param testCaseName
*/
#define LONGBOW_TEST_CASE_EXPECTS(fixtureName, testCaseName, ...) \
LongBowCompiler_IgnoreInitializerOverrides \
LongBowTestCaseMetaData longBowTestCase_MetaDataDeclaration(fixtureName, testCaseName) = \
{ .fileName = __FILE__, .functionName = #testCaseName, .lineNumber = __LINE__, \
.expectedResult = { LongBowUnitTest_TestCaseDefaultExpectedResult, __VA_ARGS__ } }; \
LongBowCompiler_WarnInitializerOverrides \
longBowUnitTest_TestCaseDeclaration(fixtureName, testCaseName); \
longBowUnitTest_TestCaseDeclaration(fixtureName, testCaseName)
/**
* @brief Run a test case defined for the named fixtureName
and testCaseName
.
*
* This is executed within a LongBow test fixture function and references the function's
* LongBowTestFixture
parameter.
*
* @param [in] fixtureName
* @param [in] testCaseName
*
* @see LONGBOW_TEST_CASE
*/
#define LONGBOW_RUN_TEST_CASE(fixtureName, testCaseName) \
extern longBowUnitTest_TestCaseDeclaration(fixtureName, testCaseName); \
extern LongBowTestCaseMetaData longBowTestCase_MetaDataDeclaration(fixtureName, testCaseName); \
longBowTestCase_Run(#testCaseName, testFixture, longBowUnitTest_CaseName(fixtureName, testCaseName), \
&longBowTestCase_MetaDataDeclaration(fixtureName, testCaseName))
/**
* @brief Configure and run a set of LongBowTestRunner instances
*
* @param [in] argc The number of elements in the @p argv array.
* @param [in] argv An array of nul-terminated C-strings.
*
* Example Usage:
* @code
* int
* main(int argc, char *argv[argc])
* {
* LongBowTestRunner *testRunner1 = LONGBOW_TEST_RUNNER_CREATE(MyTestRunner);
* LongBowTestRunner *testRunner2 = LONGBOW_TEST_RUNNER_CREATE(MyOtherTestRunner);
*
* int exitStatus = longBowMain(argc, argv, testRunner, testRunner2);
*
* longBowTestRunner_Destroy(&testRunner1);
* longBowTestRunner_Destroy(&testRunner2);
* exit(exitStatus);
* }
* @endcode
*/
#ifdef LongBow_DISABLE_ASSERTIONS
/* 77 is the exit status for a skipped test when run with automake generated Makefiles */
# define longBowMain(argc, argv, ...) \
77
#else
# define longBowMain(argc, argv, ...) \
longBowMain_Impl(argc, argv, __VA_ARGS__, NULL)
#endif
/**
* @brief Configure and run a set of `LongBowTestRunner` instances
*
* @param [in] argc The number of elements in the @p argv array.
* @param [in] argv An NULL terminated list of pointers to `LongBowTestRunner` instances.
*
* Example Usage:
* @code
* int
* main(int argc, char *argv[argc])
* {
* LongBowTestRunner *testRunner1 = LONGBOW_TEST_RUNNER_CREATE(MyTestRunner);
* LongBowTestRunner *testRunner2 = LONGBOW_TEST_RUNNER_CREATE(MyOtherTestRunner);
*
* int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner, testRunner2);
*
* longBowTestRunner_Destroy(&testRunner1);
* longBowTestRunner_Destroy(&testRunner2);
* exit(exitStatus);
* }
* @endcode
*/
#define LONGBOW_TEST_MAIN(argc, argv, ...) \
longBowMain(argc, argv, __VA_ARGS__, NULL)
/**
* @brief Skip this test case
*
* @param [in] ... A printf format string followed by a variable number of parameters corresponding to the format string.
*/
#define testSkip(...) do { \
longBowTest(&LongBowTestSkippedEvent, "Skipped " __VA_ARGS__); \
} while (0)
/**
* @brief Terminate the test indicating that the test is unimplemented.
*
* @param [in] ... A printf format string followed by a variable number of parameters corresponding to the format string.
*/
#define testUnimplemented(...) do { \
longBowTest(&LongBowTestUnimplementedEvent, "Unimplemented test " __VA_ARGS__); \
} while (0)
/**
* @brief Issue a warning and terminate with the `LONGBOW_TESTCASE_WARNED` code.
*
* @param [in] ... A printf format string followed by a variable number of parameters corresponding to the format string.
*/
#define testWarn(...) \
do { longBowTest(&LongBowTestEvent, "Warning " __VA_ARGS__); } while (0)
/**
* @brief assert the Equals Contract for the given function.
*
* @param [in] function The function under test.
* @param [in] x The pivotal value which must not be NULL.
* @param [in] y A value that must be perfectly equal to x and z, but neither x nor z.
* @param [in] z A value that must be perfectly equal to x and y, but neither x nor y.
* @param [in] ... A variable number of values that are unequal to x.
*/
#define assertEqualsContract(function, x, y, z, ...) \
assertTrue(longBowUnitTesting_AssertEqualsContract((bool (*)(void *, void *))function, x, y, z, __VA_ARGS__, NULL), "Failed Equals Contract");
/**
* @brief assert the Compare To Contract for the given function.
*
* @param [in] function The function under test.
* @param [in] value The pivotal value under test.
* @param [in] equality A NULL terminated array of values that are all equivalent to `value`.
* @param [in] lesser A NULL terminated array of values that are all less than `value`.
* @param [in] greater A NULL terminated array of values that are all greater than `value`.
* @return `true` if the evalutation is successful.
* @see assertCompareToContract()
*/
#define assertCompareToContract(function, value, equality, lesser, greater) \
assertTrue(longBowUnitTesting_AssertCompareToContract((int (*)(const void *, const void *))function, value, (void *) equality, (void *) lesser, (void *) greater), "Failed CompareTo Contract");
#endif // UNIT_TEST_H_