diff options
author | Michele Papalini <micpapal+fdio@cisco.com> | 2017-02-24 08:00:33 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@fd.io> | 2017-02-24 08:00:33 +0000 |
commit | 4df7f4cc98b6288177df256e1db70ddc3f7d00db (patch) | |
tree | 55e71277b419e4830ae641868ab8e751c8b86972 /longbow/src | |
parent | f28308bd99381ef5f1e178e2e1f870f245e35873 (diff) | |
parent | ec688b4723a041044226358bcd4dd6e2da39da49 (diff) |
Merge "Initial commit: cframework. Longbow and Libparc" into cframework/master
Diffstat (limited to 'longbow/src')
174 files changed, 19908 insertions, 0 deletions
diff --git a/longbow/src/CMakeLists.txt b/longbow/src/CMakeLists.txt new file mode 100644 index 00000000..7ed5ddfe --- /dev/null +++ b/longbow/src/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(LongBow) +add_subdirectory(python) diff --git a/longbow/src/LongBow/.gitignore b/longbow/src/LongBow/.gitignore new file mode 100644 index 00000000..6d86de6e --- /dev/null +++ b/longbow/src/LongBow/.gitignore @@ -0,0 +1,2 @@ +*.gcda +*.gcno diff --git a/longbow/src/LongBow/CMakeLists.txt b/longbow/src/LongBow/CMakeLists.txt new file mode 100644 index 00000000..476cc8ab --- /dev/null +++ b/longbow/src/LongBow/CMakeLists.txt @@ -0,0 +1,171 @@ +# Define a few configuration variables that we want accessible in the software +configure_file( + config.h.in + config.h +) + +set(LONGBOW_REPORT_HEADER_FILES + Reporting/longBowReport_Testing.h + Reporting/longBowReport_Runtime.h + ) + +set(LONGBOW_REPORT_BASE_SOURCE_FILES + Reporting/longBowReport_Runtime.c + Reporting/longBowReport_Testing.c + ${LONGBOW_REPORT_HEADER_FILES}) + +source_group(report-base FILES ${LONGBOW_REPORT_BASE_SOURCE_FILES}) + +set(LONGBOW_REPORT_ANSI_SOURCE_FILES + Reporting/ANSITerm/longBowReport_Runtime.c + Reporting/ANSITerm/longBowReport_Runtime.h + Reporting/ANSITerm/longBowReport_Testing.c + Reporting/ANSITerm/longBowReportANSITerminal_About.c + Reporting/ANSITerm/longBowReportANSITerminal_About.h) + +source_group(report-ansiterm FILES ${LONGBOW_REPORT_ANSI_SOURCE_FILES}) + + +if (ANDROID_API) + set(LONGBOW_REPORT_TEXT_RUNTIME_SOURCE_FILE Reporting/Android/longBowReport_Runtime.c) +else() + set(LONGBOW_REPORT_TEXT_RUNTIME_SOURCE_FILE Reporting/TextPlain/longBowReport_Runtime.c) +endif() + + set(LONGBOW_REPORT_TEXT_SOURCE_FILES + ${LONGBOW_REPORT_TEXT_RUNTIME_SOURCE_FILE} + Reporting/TextPlain/longBowReport_Testing.c + Reporting/TextPlain/longBowReportTextPlain_About.c + Reporting/TextPlain/longBowReportTextPlain_About.h) + +source_group(report-textplain FILES ${LONGBOW_REPORT_TEXT_SOURCE_FILES}) + +set(LONGBOW_CONFIG_SOURCE_FILES + command-line/liblongbow-config.c) + +source_group(longbow-config FILES ${LONGBOW_CONFIG_SOURCE_FILES}) + +set(LIBLONGBOW_HEADER_FILES + stubs/execinfo.h + assertions.h + debugging.h + longBow_About.h + longBow_Backtrace.h + longBow_ClipBoard.h + longBow_Compiler.h + longBow_Config.h + longBow_Debug.h + longBow_Event.h + longBow_EventType.h + longBow_Location.h + longBow_Main.h + longBow_MeasureTime.h + longBow_Properties.h + longBow_Runtime.h + longBow_RuntimeResult.h + longBow_Status.h + longBow_SubProcess.h + longBow_TestCase.h + longBow_TestCaseClipBoard.h + longBow_TestCaseMetaData.h + longBow_TestFixture.h + longBow_TestFixtureConfig.h + longBow_TestRunner.h + longBow_UnitTest.h + longBow_UnitTesting.h + runtime.h + testing.h + tests.h + traps.h + unit-test.h + ) + +set(LIBLONGBOW_SOURCE_FILES + private/longBow_ArrayList.h + private/longBow_Memory.h + private/longBow_OpenFile.h + private/longBow_String.h + private/longBow_ArrayList.c + private/longBow_Memory.c + private/longBow_OpenFile.c + private/longBow_String.c + longBow_About.c + longBow_Backtrace.c + longBow_ClipBoard.c + longBow_Config.c + longBow_Debug.c + longBow_Event.c + longBow_EventType.c + longBow_Location.c + longBow_Main.c + longBow_MeasureTime.c + longBow_Properties.c + longBow_Runtime.c + longBow_RuntimeResult.c + longBow_Status.c + longBow_SubProcess.c + longBow_TestCase.c + longBow_TestCaseClipBoard.c + longBow_TestCaseMetaData.c + longBow_TestFixture.c + longBow_TestFixtureConfig.c + longBow_TestRunner.c + longBow_UnitTesting.c + ${LIBLONGBOW_HEADER_FILES}) + +source_group(longbow FILES ${LIBLONGBOW_SOURCE_FILES}) + +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") + set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS} -undefined dynamic_lookup") + message( "-- Set \"-undefined dynamic_lookup\" for shared libraries") +endif() + +add_library(longbow-ansiterm STATIC ${LONGBOW_REPORT_ANSI_SOURCE_FILES} ${LONGBOW_REPORT_BASE_SOURCE_FILES}) +add_library(longbow-ansiterm.shared SHARED ${LONGBOW_REPORT_ANSI_SOURCE_FILES} ${LONGBOW_REPORT_BASE_SOURCE_FILES}) + +set_target_properties(longbow-ansiterm.shared PROPERTIES + SOVERSION 1 + VERSION 1.0 + OUTPUT_NAME longbow-ansiterm) + +add_library(longbow-textplain STATIC ${LONGBOW_REPORT_TEXT_SOURCE_FILES} ${LONGBOW_REPORT_BASE_SOURCE_FILES}) +add_library(longbow-textplain.shared SHARED ${LONGBOW_REPORT_TEXT_SOURCE_FILES} ${LONGBOW_REPORT_BASE_SOURCE_FILES}) + +set_target_properties(longbow-textplain.shared PROPERTIES + SOVERSION 1 + VERSION 1.0 + OUTPUT_NAME longbow-textplain) + +add_library(longbow STATIC ${LIBLONGBOW_SOURCE_FILES}) +add_library(longbow.shared SHARED ${LIBLONGBOW_SOURCE_FILES}) + +set_target_properties(longbow.shared PROPERTIES + SOVERSION 1 + VERSION 1.0 + OUTPUT_NAME longbow) + +add_executable(longbow-config ${LONGBOW_CONFIG_SOURCE_FILES}) + + +set(longbowLibraries + longbow + longbow.shared + longbow-ansiterm + longbow-ansiterm.shared + longbow-textplain + longbow-textplain.shared + ) + +foreach(lib ${longbowLibraries}) + install(TARGETS ${lib} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) +endforeach() + +install(FILES ${LIBLONGBOW_HEADER_FILES} DESTINATION include/LongBow ) +install(FILES ${LONGBOW_REPORT_HEADER_FILES} DESTINATION include/LongBow/Reporting ) + +if(ANDROID_API) + message("############ Detected cross compile for ${CMAKE_SYSTEM_NAME}") + message("############ This build will not include doxygen, tools, or tests") +else() + add_subdirectory(test) +endif() diff --git a/longbow/src/LongBow/Groups.dox b/longbow/src/LongBow/Groups.dox new file mode 100644 index 00000000..758f7abc --- /dev/null +++ b/longbow/src/LongBow/Groups.dox @@ -0,0 +1,47 @@ +/** +\mainpage LongBow + +Software testing, validation, and measurable quality metics are an important +element in modern software development. LongBow is a software framework and +facility for writing software using invariants, runtime validation, +unit testing, and code analysis for the C programming language. + +LongBow is software to help you write better C programs. It provides: + +* A run-time assertion facility to establish strict rules on the state of your program. +* A testing facility based on the xUnit testing model. +* Compile-time assistance for writing code meant to be compiled by compilers with different features. + +LongBow can help you find and manage problems early, establish and maintain + confidence in the correctness of your code, make collaboration easier, +facilitate future change, and improve overall design. + +LongBow allows you to take control and establish invariant pre- and +post-conditions that detect inconsistencies and unexpected results in your +programs in order to find bugs and design deficiencies in the code during +development rather than waiting for your users and customers to find your bugs for you. + + +@defgroup runtime Runtime +@brief LongBow functions and macros for runtime, consisting primarily of assertions and traps. + +@defgroup testing Testing +@brief LongBow functions and macros for writing tests. + +LongBow testing Macros and ancillary functions to implement an xUnit style of writing and running tests. +Test writers create a `LONGBOW_TEST_RUNNER` function which, in turn, +invokes one or more `LONGBOW_TEST_FIXTURE` functions, +each of which invoke a specific `LONGBOW_TEST_CASE`. + +@defgroup internals Internals +@brief LongBow functions and macros used internally. + +@defgroup reporting Reporting +@brief LongBow functions and definitions for writing report libraries. + +@defgroup performance Performance testing +@brief LongBow functions and definitions for writing performance tests. + +@example testAssertion.c +*/ + diff --git a/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.c b/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.c new file mode 100644 index 00000000..e12c7b37 --- /dev/null +++ b/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.c @@ -0,0 +1,44 @@ +// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED. +// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z + +#include "longBowReportANSITerminal_About.h" + +const char *longBowReportANSITerminal_What = "@(#)" "LongBow ANSI Terminal Reporter " RELEASE_VERSION " 2017-02-14T21:39:44.348378" + "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates."; + +const char * +longBowReportANSITerminalAbout_Name(void) +{ + return "LongBow ANSI Terminal Reporter"; +} + +const char * +longBowReportANSITerminalAbout_Version(void) +{ + return RELEASE_VERSION; +} + +const char * +longBowReportANSITerminalAbout_About(void) +{ + return "LongBow ANSI Terminal Reporter "RELEASE_VERSION " 2017-02-14T21:39:44.348378" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowReportANSITerminalAbout_MiniNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowReportANSITerminalAbout_ShortNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowReportANSITerminalAbout_LongNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n\n"; +} + diff --git a/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.h b/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.h new file mode 100755 index 00000000..8dd3230c --- /dev/null +++ b/longbow/src/LongBow/Reporting/ANSITerm/longBowReportANSITerminal_About.h @@ -0,0 +1,54 @@ +// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED. +// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z + +#ifndef longBowReportANSITerminal_About_h +#define longBowReportANSITerminal_About_h +/** + * Embedded string containing information for the what(1) command. + * + */ +extern const char *longBowReportANSITerminal_What; + +/** + * Return the name as a C string. + * + * @return The name as a C string. + */ +const char *longBowReportANSITerminalAbout_Name(void); + +/** + * Return the version as a C string. + * + * @return The version as a C string. + */ +const char *longBowReportANSITerminalAbout_Version(void); + +/** + * Return the About text as a C string. + * + * @return The About text as a C string. + */ +const char *longBowReportANSITerminalAbout_About(void); + +/** + * Return the minimum copyright notice as a C string. + * + * @return The minimum copyright notice as a C string. + */ +const char *longBowReportANSITerminalAbout_MiniNotice(void); + +/** + * Return the short copyright notice as a C string. + * + * @return The short copyright notice as a C string. + */ +const char *longBowReportANSITerminalAbout_ShortNotice(void); + +/** + * Return the long copyright notice as a C string. + * + * @return The long copyright notice as a C string. + */ +const char *longBowReportANSITerminalAbout_LongNotice(void); + +#endif // longBowReportANSITerminal_About_h diff --git a/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.c b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.c new file mode 100644 index 00000000..60ca4d42 --- /dev/null +++ b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.c @@ -0,0 +1,291 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <stdarg.h> +#include <assert.h> + +#include <LongBow/Reporting/ANSITerm/longBowReport_Runtime.h> +#include <LongBow/private/longBow_Memory.h> + +static const char *ansiRed = "\x1b[31m"; +static const char *ansiGreen = "\x1b[32m"; +static const char *ansiYellow = "\x1b[33m"; +static const char *ansiMagenta = "\x1b[35m"; +static const char *ansiReset = "\x1b[0m"; + +static void +_printGreen(void) +{ + printf("%s", ansiGreen); +} + +static void +_printYellow(void) +{ + printf("%s", ansiYellow); +} + +static void +_printMagenta(void) +{ + printf("%s", ansiMagenta); +} + +static void +_printReset(void) +{ + printf("%s", ansiReset); + fflush(stdout); +} + +static void +_longBowReportRuntime_RedPrintf(const char *format, va_list args) +{ + longBowReportRuntime_PrintRed(); + vprintf(format, args); + _printReset(); +} + +static void +_longBowReportRuntime_YellowPrintf(const char *format, va_list args) +{ + _printYellow(); + vprintf(format, args); + _printReset(); +} + +void +longBowReportRuntime_PrintRed(void) +{ + printf("%s", ansiRed); +} + +void +longBowReportRuntime_RedPrintf(const char *format, ...) +{ + va_list args; + va_start(args, format); + _longBowReportRuntime_RedPrintf(format, args); + va_end(args); +} + +void +longBowReportRuntime_GreenPrintf(const char *format, ...) +{ + _printGreen(); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + _printReset(); +} + +void +longBowReportRuntime_MagentaPrintf(const char *format, ...) +{ + _printMagenta(); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + _printReset(); +} + +void +longBowReportRuntime_YellowPrintf(const char *format, ...) +{ + va_list args; + va_start(args, format); + + _longBowReportRuntime_YellowPrintf(format, args); + + va_end(args); +} + +void +longBowReportRuntime_ParseSuppress(LongBowReportConfig *result, const char *key) +{ + for (size_t i = 0; i < strlen(key); i++) { + if (*key == 'X') { + result->suppress_report.untested = 1; + } else if (*key == '.') { + result->suppress_report.succeeded = 1; + } else if (*key == 'S') { + result->suppress_report.skipped = 1; + } else if (*key == 'W') { + result->suppress_report.warned = 1; + } else if (*key == 's') { + result->suppress_report.setup_failed = 1; + } else if (*key == 't') { + result->suppress_report.teardown_failed = 1; + } else if (*key == 'w') { + result->suppress_report.teardown_warned = 1; + } else if (*key == 'F') { + result->suppress_report.failed = 1; + } else if (*key == 'T') { + result->suppress_report.stopped = 1; + } else if (*key == 'U') { + result->suppress_report.unimplemented = 1; + } else { + printf("Unknown suppression key '%c'\n", *key); + } + } +} + +LongBowReportConfig * +longBowReportRuntime_Create(int argc, char *argv[]) +{ + static const char *prefix = "--report"; + size_t prefixLength = strlen(prefix); + + LongBowReportConfig *result = longBowMemory_Allocate(sizeof(LongBowReportConfig)); + + for (int i = 0; i < argc; i++) { + if (strncmp(prefix, argv[i], prefixLength) == 0) { + if (strcmp("--report-suppress", argv[i]) == 0) { + longBowReportRuntime_ParseSuppress(result, argv[i + 1]); + i++; + } + } else if (strcmp("--help", argv[i]) == 0) { + printf("Options for LongBow Report ANSI Terminal\n"); + printf(" --report-suppress [STFU.XWstw] Suppress the display of specific reports.\n"); + printf(" S - suppress the report of a skipped test.\n"); + printf(" T - suppress the report of a stopped test.\n"); + printf(" F - suppress the report of a failed test.\n"); + printf(" U - suppress the report of an unimplemented test.\n"); + printf(" . - suppress the report of a successful test.\n"); + printf(" X - suppress the report of an untested test.\n"); + printf(" W - suppress the report of a warned test.\n"); + printf(" s - suppress the report of a setup failure.\n"); + printf(" t - suppress the report of a tear-down failure.\n"); + printf(" w - suppress the report of a tear-down warning.\n"); + free(result); + return NULL; + } + } + + return result; +} + +void +longBowReportRuntime_Destroy(LongBowReportConfig **reportPtr) +{ + longBowMemory_Deallocate((void **) reportPtr); +} + +static void +_EventPrint(const LongBowEvent *event) +{ + if (longBowEventType_IsSuppressAlert(longBowEvent_GetEventType(event)) == false) { + char *location = longBowLocation_ToString(longBowEvent_GetLocation(event)); + printf("%s %s %s %s\r\n", + longBowEvent_GetName(event), location, longBowEvent_GetKind(event), longBowEvent_GetMessage(event)); + + if (longBowEventType_IsSuppressBacktrace(longBowEvent_GetEventType(event)) == false) { + char **strs = longBowEvent_CreateSymbolicCallstack(event); + if (strs != NULL) { + for (size_t i = 0; i < longBowEvent_GetCallStackLength(event); ++i) { + printf("%s\r\n", strs[i]); + } + free(strs); + } + } + fflush(stdout); + free(location); + } +} + +void +longBowReportRuntime_Event(const LongBowEvent *event) +{ + LongBowStatus status = longBowEventType_GetStatus(longBowEvent_GetEventType(event)); + switch (status) { + case LongBowStatus_DONTCARE: + case LongBowStatus_UNTESTED: + break; + + /* successful */ + case LONGBOW_STATUS_SUCCEEDED: + // If this happens, there is an error in the encoding of the LongBowEventType. + longBowReportRuntime_PrintRed(); + _EventPrint(event); + _printReset(); + break; + + case LongBowStatus_WARNED: + case LongBowStatus_TEARDOWN_WARNED: + case LONGBOW_STATUS_SKIPPED: + case LongBowStatus_UNIMPLEMENTED: + case LongBowStatus_IMPOTENT: + case LONGBOW_STATUS_MEMORYLEAK: + case LONGBOW_STATUS_SETUP_SKIPTESTS: + _printYellow(); + _EventPrint(event); + _printReset(); + break; + + /* failure */ + case LONGBOW_STATUS_FAILED: + case LongBowStatus_STOPPED: + case LONGBOW_STATUS_TEARDOWN_FAILED: + case LONGBOW_STATUS_SETUP_FAILED: + case LongBowStatus_SIGNALLED: + longBowReportRuntime_PrintRed(); + _EventPrint(event); + _printReset(); + break; + + case LongBowStatus_LIMIT: // fall through + default: + _printYellow(); + _EventPrint(event); + _printReset(); + break; + } +} + +void +longBowReportRuntime_Message(const char *format, ...) +{ + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} + +void +longBowReportRuntime_Warning(const char *format, ...) +{ + va_list args; + va_start(args, format); + longBowReportRuntime_YellowPrintf("WARNING "); + _longBowReportRuntime_YellowPrintf(format, args); + va_end(args); +} + +void +longBowReportRuntime_Error(const char *format, ...) +{ + va_list args; + va_start(args, format); + longBowReportRuntime_RedPrintf("FAILURE "); + _longBowReportRuntime_RedPrintf(format, args); + va_end(args); +} diff --git a/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.h b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.h new file mode 100755 index 00000000..2e03f322 --- /dev/null +++ b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Runtime.h @@ -0,0 +1,67 @@ +/* + * 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 ANSITerm/longBowReport_Runtime.h + * @ingroup reporting + * @brief ANSI Terminal Reporting + * + */ +#ifndef LongBow_longBowReport_ANSITerm_Runtime_h +#define LongBow_longBowReport_ANSITerm_Runtime_h + +#include <stdio.h> +#include <stdarg.h> + +#include <LongBow/Reporting/longBowReport_Runtime.h> + +/** + * Begin printing in red. + * + */ +void longBowReportRuntime_PrintRed(void); + +/** + * Print the formatted string in red. + * + */ +void longBowReportRuntime_RedPrintf(const char *format, ...); + +/** + * Print the formatted string in green. + * + */ +void longBowReportRuntime_GreenPrintf(const char *format, ...); + +/** + * Print the formatted string in yellow. + * + */ +void longBowReportRuntime_YellowPrintf(const char *format, ...); + +/** + * Print the formatted string in magenta. + * + */ +void longBowReportRuntime_MagentaPrintf(const char *format, ...); + +/** + * Parse the given key and set the corresponding LongBowReportConfig to suppress reports. + * + * @param [in] config A valid LongBowReportConfig instance. + * @param [in] key A nul-terminated C string consisting of one or more of the characters, X.SWstwFTU + */ +void longBowReportRuntime_ParseSuppress(LongBowReportConfig *config, const char *key); +#endif // LongBow_longBowReport_ANSITerm_Runtime_h diff --git a/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Testing.c b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Testing.c new file mode 100644 index 00000000..d1952210 --- /dev/null +++ b/longbow/src/LongBow/Reporting/ANSITerm/longBowReport_Testing.c @@ -0,0 +1,191 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <stdarg.h> +#include <assert.h> + +#include <LongBow/Reporting/ANSITerm/longBowReport_Runtime.h> +#include <LongBow/Reporting/longBowReport_Testing.h> +#include <LongBow/private/longBow_String.h> + +static const LongBowTestRunner * +_testRunnerSilent(const LongBowTestRunner *testRunner) +{ + LongBowStatus status = longBowTestRunner_GetStatus(testRunner); + if (longBowStatus_IsSuccessful(status)) { + longBowReportRuntime_GreenPrintf("%s %s\n", longBowTestRunner_GetName(testRunner), longBowStatus_ToString(status)); + } else if (longBowStatus_IsSuccessful(status)) { + longBowReportRuntime_YellowPrintf("%s %s\n", longBowTestRunner_GetName(testRunner), longBowStatus_ToString(status)); + } else { + longBowReportRuntime_RedPrintf("%s %s\n", longBowTestRunner_GetName(testRunner), longBowStatus_ToString(status)); + } + return testRunner; +} + +static const LongBowTestRunner * +_testRunnerDetail(const LongBowTestRunner *testRunner) +{ + size_t nFixtures = longBowTestRunner_GetFixtureCount(testRunner); + + printf("\n"); + printf("%s: %zd fixture%s\n", longBowTestRunner_GetName(testRunner), nFixtures, (nFixtures == 1 ? "" : "s")); + + for (size_t i = 0; i < nFixtures; i++) { + LongBowTestFixture *fixture = longBowTestRunner_GetFixture(testRunner, i); + longBowReportTesting_TestFixture(fixture); + } + return testRunner; +} + +const LongBowTestRunner * +longBowReportTesting_TestRunner(const LongBowTestRunner *testRunner) +{ + if (longBowConfig_GetBoolean(longBowTestRunner_GetConfiguration(testRunner), false, "silent")) { + return _testRunnerSilent(testRunner); + } else { + return _testRunnerDetail(testRunner); + } +} + +static unsigned int +_totalSucceeded(const LongBowTestFixtureSummary *summary) +{ + return summary->totalSucceeded + summary->totalWarned + summary->totalTearDownWarned; +} + +static unsigned int +_totalWarned(const LongBowTestFixtureSummary *summary) +{ + return summary->totalWarned + summary->totalTearDownWarned; +} + +static unsigned int +_totalFailed(const LongBowTestFixtureSummary *summary) +{ + return summary->totalFailed + summary->totalSignalled + summary->totalStopped + summary->totalTearDownFailed; +} + +static unsigned int +_totalIncomplete(const LongBowTestFixtureSummary *summary) +{ + return summary->totalSetupFailed + summary->totalSkipped + summary->totalUnimplemented; +} + +static void +_reportSummary(const LongBowTestFixture *testFixture) +{ + const LongBowTestFixtureSummary *summary = longBowTestFixture_GetSummary(testFixture); + + char *fixtureString = longBowTestFixture_ToString(testFixture); + + printf("%s: Ran %u test case%s.", fixtureString, summary->totalTested, summary->totalTested == 1 ? "" : "s"); + free(fixtureString); + + if (summary->totalTested > 0) { + printf(" %d%% (%d) succeeded", _totalSucceeded(summary) * 100 / summary->totalTested, _totalSucceeded(summary)); + + if (_totalWarned(summary) > 0) { + printf(" %d%% (%d) with warnings", _totalWarned(summary) * 100 / _totalSucceeded(summary), _totalWarned(summary)); + } + if (_totalFailed(summary) != 0) { + printf(", %d%% (%d) failed", _totalFailed(summary) * 100 / summary->totalTested, _totalFailed(summary)); + } + if (_totalIncomplete(summary) > 0) { + printf(", %d%% (%d) incomplete", _totalIncomplete(summary) * 100 / summary->totalTested, _totalIncomplete(summary)); + } + } + + printf("\n"); +} + +const LongBowTestFixture * +longBowReportTesting_TestFixture(const LongBowTestFixture *testFixture) +{ + size_t nTestCases = longBowTestFixture_GetTestCaseCount(testFixture); + + _reportSummary(testFixture); + + for (size_t i = 0; i < nTestCases; i++) { + LongBowTestCase *testCase = longBowTestFixture_GetTestCase(testFixture, i); + longBowReportTesting_TestCase(testCase); + } + return testFixture; +} + +const LongBowTestCase * +longBowReportTesting_TestCase(const LongBowTestCase *testCase) +{ + LongBowRuntimeResult *testCaseResult = longBowTestCase_GetActualResult(testCase); + + char *rusageString = longBowReportRuntime_RUsageToString(longBowRuntimeResult_GetRUsage(testCaseResult)); + char *elapsedTimeString = longBowReportRuntime_TimevalToString(longBowRuntimeResult_GetElapsedTime(testCaseResult)); + char *statusString = longBowStatus_ToString(longBowRuntimeResult_GetStatus(testCaseResult)); + char *testCaseString = longBowTestCase_ToString(testCase); + + LongBowString *str = longBowString_CreateFormat("%s %s %s %zd %s\n", + testCaseString, + elapsedTimeString, + rusageString, + longBowRuntimeResult_GetEventEvaluationCount(longBowTestCase_GetActualResult(testCase)), + statusString); + char *string = longBowString_ToString(str); + + if (longBowTestCase_IsFailed(testCase)) { + longBowReportRuntime_RedPrintf("%s", string); + } else if (longBowTestCase_IsWarning(testCase)) { + longBowReportRuntime_YellowPrintf("%s", string); + } else if (longBowTestCase_IsIncomplete(testCase)) { + longBowReportRuntime_YellowPrintf("%s", string); + } else if (longBowTestCase_IsSuccessful(testCase)) { + longBowReportRuntime_GreenPrintf("%s", string); + } else { + longBowReportRuntime_RedPrintf("%s", string); + } + + free(string); + free(testCaseString); + free(statusString); + free(elapsedTimeString); + free(rusageString); + + return testCase; +} + +void +longBowReportTesting_DisplayTestCaseResult(const LongBowTestCase *testCase __attribute__((unused))) +{ +} + +void +longBowReportTesting_Trace(const char *restrict format, ...) +{ + va_list ap; + va_start(ap, format); + char *message; + if (vasprintf(&message, format, ap) == -1) { + va_end(ap); + return; + } + va_end(ap); + + longBowReportRuntime_MagentaPrintf("%s\n", message); + fflush(stdout); + free(message); +} diff --git a/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.c b/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.c new file mode 100644 index 00000000..db31ce82 --- /dev/null +++ b/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.c @@ -0,0 +1,44 @@ +// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED. +// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z + +#include "longBowReportAndroid_About.h" + +const char *longBowReportAndroid_What = "@(#)" "LongBow Android Reporter " RELEASE_VERSION " 2017-02-14T21:38:07.631504" + "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates."; + +const char * +longBowReportAndroidAbout_Name(void) +{ + return "LongBow Android Reporter"; +} + +const char * +longBowReportAndroidAbout_Version(void) +{ + return RELEASE_VERSION; +} + +const char * +longBowReportAndroidAbout_About(void) +{ + return "LongBow Android Reporter "RELEASE_VERSION " 2017-02-14T21:38:07.631504" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowReportAndroidAbout_MiniNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowReportAndroidAbout_ShortNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowReportAndroidAbout_LongNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n\n"; +} + diff --git a/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.h b/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.h new file mode 100755 index 00000000..9a90f17e --- /dev/null +++ b/longbow/src/LongBow/Reporting/Android/longBowReportAndroid_About.h @@ -0,0 +1,54 @@ +// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED. +// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z + +#ifndef longBowReportAndroid_About_h +#define longBowReportAndroid_About_h +/** + * Embedded string containing information for the what(1) command. + * + */ +extern const char *longBowReportAndroid_What; + +/** + * Return the name as a C string. + * + * @return The name as a C string. + */ +const char *longBowReportAndroidAbout_Name(void); + +/** + * Return the version as a C string. + * + * @return The version as a C string. + */ +const char *longBowReportAndroidAbout_Version(void); + +/** + * Return the About text as a C string. + * + * @return The About text as a C string. + */ +const char *longBowReportAndroidAbout_About(void); + +/** + * Return the minimum copyright notice as a C string. + * + * @return The minimum copyright notice as a C string. + */ +const char *longBowReportAndroidAbout_MiniNotice(void); + +/** + * Return the short copyright notice as a C string. + * + * @return The short copyright notice as a C string. + */ +const char *longBowReportAndroidAbout_ShortNotice(void); + +/** + * Return the long copyright notice as a C string. + * + * @return The long copyright notice as a C string. + */ +const char *longBowReportAndroidAbout_LongNotice(void); + +#endif // longBowReportAndroid_About_h diff --git a/longbow/src/LongBow/Reporting/Android/longBowReport_Runtime.c b/longbow/src/LongBow/Reporting/Android/longBowReport_Runtime.c new file mode 100644 index 00000000..4bf13482 --- /dev/null +++ b/longbow/src/LongBow/Reporting/Android/longBowReport_Runtime.c @@ -0,0 +1,92 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <assert.h> + +#include <LongBow/Reporting/longBowReport_Runtime.h> +#include <LongBow/private/longBow_Memory.h> + +LongBowReportConfig * +longBowReportRuntime_Create(int argc, char *argv[argc]) +{ + LongBowReportConfig *result = longBowMemory_Allocate(sizeof(LongBowReportConfig)); + + return result; +} + +void +longBowReportRuntime_Destroy(LongBowReportConfig **reportPtr) +{ + longBowMemory_Deallocate((void **) reportPtr); +} + +void +longBowReportRuntime_Event(const LongBowEvent *event) +{ + if (longBowEventType_IsSuppressAlert(longBowEvent_GetEventType(event)) == false) { + char *location = longBowLocation_ToString(longBowEvent_GetLocation(event)); + printf("%s %s %s %s\r\n", + longBowEvent_GetName(event), location, longBowEvent_GetKind(event), longBowEvent_GetMessage(event)); + + if (longBowEventType_IsSuppressBacktrace(longBowEvent_GetEventType(event)) == false) { + char **strs = longBowEvent_CreateSymbolicCallstack(event); + if (strs != NULL) { + for (size_t i = 0; i < longBowEvent_GetCallStackLength(event); ++i) { + fputs(strs[i], stdout); + fputs("\r\n", stdout); + } + free(strs); + } + } + fflush(stdout); + + free(location); + } +} + +void +longBowReportRuntime_Message(const char *format, ...) +{ + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} + +void +longBowReportRuntime_Warning(const char *format, ...) +{ + printf("WARNING"); + + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} + +void +longBowReportRuntime_Error(const char *format, ...) +{ + printf("ERROR"); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} diff --git a/longbow/src/LongBow/Reporting/Android/longBowReport_Testing.c b/longbow/src/LongBow/Reporting/Android/longBowReport_Testing.c new file mode 100755 index 00000000..dd3835e8 --- /dev/null +++ b/longbow/src/LongBow/Reporting/Android/longBowReport_Testing.c @@ -0,0 +1,198 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <assert.h> + +#ifdef __ANDROID__ +#include <android/log.h> +#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, "CCNx", __VA_ARGS__); +#endif + +#include <LongBow/Reporting/longBowReport_Testing.h> +#include <LongBow/private/longBow_String.h> + +static const LongBowTestRunner * +_testRunnerSilent(const LongBowTestRunner *testRunner) +{ + LongBowStatus status = longBowTestRunner_GetStatus(testRunner); + + printf("%s %s\n", longBowTestRunner_GetName(testRunner), longBowStatus_ToString(status)); + return testRunner; +} + +static const LongBowTestRunner * +_testRunnerDetail(const LongBowTestRunner *testRunner) +{ + size_t nFixtures = longBowTestRunner_GetFixtureCount(testRunner); + + printf("\r\n"); + printf("%s: %zd fixture%s\r\n", longBowTestRunner_GetName(testRunner), nFixtures, (nFixtures == 1 ? "" : "s")); + + for (size_t i = 0; i < nFixtures; i++) { + LongBowTestFixture *fixture = longBowTestRunner_GetFixture(testRunner, i); + longBowReportTesting_TestFixture(fixture); + } + return testRunner; +} + +const LongBowTestRunner * +longBowReportTesting_TestRunner(const LongBowTestRunner *testRunner) +{ + if (longBowConfig_GetBoolean(longBowTestRunner_GetConfiguration(testRunner), false, "silent")) { + return _testRunnerSilent(testRunner); + } else { + return _testRunnerDetail(testRunner); + } +} + +static unsigned int +_totalSucceeded(const LongBowTestFixtureSummary *summary) +{ + return summary->totalSucceeded + summary->totalWarned + summary->totalTearDownWarned; +} + +static unsigned int +_totalWarned(const LongBowTestFixtureSummary *summary) +{ + return summary->totalWarned + summary->totalTearDownWarned; +} + +static unsigned int +_totalFailed(const LongBowTestFixtureSummary *summary) +{ + return summary->totalFailed + summary->totalSignalled + summary->totalStopped + summary->totalTearDownFailed; +} + +static unsigned int +_totalIncomplete(const LongBowTestFixtureSummary *summary) +{ + return summary->totalSetupFailed + summary->totalSkipped + summary->totalUnimplemented; +} + +static void +_reportSummary(const LongBowTestFixture *testFixture) +{ + const LongBowTestFixtureSummary *summary = longBowTestFixture_GetSummary(testFixture); + + char *fixtureString = longBowTestFixture_ToString(testFixture); + + printf("%s: Ran %u test case%s.", fixtureString, summary->totalTested, summary->totalTested == 1 ? "" : "s"); + free(fixtureString); + + if (summary->totalTested > 0) { + printf(" %d%% (%d) succeeded", _totalSucceeded(summary) * 100 / summary->totalTested, _totalSucceeded(summary)); + + if (_totalWarned(summary) > 0) { + printf(" %d%% (%d) with warnings", _totalWarned(summary) * 100 / _totalSucceeded(summary), _totalWarned(summary)); + } + if (_totalFailed(summary) != 0) { + printf(", %d%% (%d) failed", _totalFailed(summary) * 100 / summary->totalTested, _totalFailed(summary)); + } + if (_totalIncomplete(summary) > 0) { + printf(", %d%% (%d) incomplete", _totalIncomplete(summary) * 100 / summary->totalTested, _totalIncomplete(summary)); + } + } + printf("\n"); +} + +const LongBowTestFixture * +longBowReportTesting_TestFixture(const LongBowTestFixture *testFixture) +{ + size_t nTestCases = longBowTestFixture_GetTestCaseCount(testFixture); + + _reportSummary(testFixture); + + for (size_t i = 0; i < nTestCases; i++) { + LongBowTestCase *testCase = longBowTestFixture_GetTestCase(testFixture, i); + longBowReportTesting_TestCase(testCase); + } + return testFixture; +} + +const LongBowTestCase * +longBowReportTesting_TestCase(const LongBowTestCase *testCase) +{ + LongBowRuntimeResult *testCaseResult = longBowTestCase_GetActualResult(testCase); + + char *rusageString = longBowReportRuntime_RUsageToString(longBowRuntimeResult_GetRUsage(testCaseResult)); + + char *elapsedTimeString = longBowReportRuntime_TimevalToString(longBowRuntimeResult_GetElapsedTime(testCaseResult)); + + char *statusString = longBowStatus_ToString(longBowTestCase_GetActualResult(testCase)->status); + char *testCaseString = longBowTestCase_ToString(testCase); + + LongBowString *string = longBowString_CreateFormat("%10s %s %s %zd %s\n", + testCaseString, + elapsedTimeString, + rusageString, + longBowRuntimeResult_GetEventEvaluationCount(longBowTestCase_GetActualResult(testCase)), + statusString); + longBowString_Write(string, stdout); + longBowString_Destroy(&string); + + free(testCaseString); + free(statusString); + free(elapsedTimeString); + free(rusageString); + + return testCase; +} + +void +longBowReportTesting_DisplayTestCaseResult(const LongBowTestCase *testCase) +{ + const LongBowRuntimeResult *testCaseResult = longBowTestCase_GetActualResult(testCase); + + switch (testCaseResult->status) { + case LongBowStatus_UNTESTED: printf("X"); break; + case LONGBOW_STATUS_SUCCEEDED: printf("."); break; + case LONGBOW_STATUS_SKIPPED: printf("S"); break; + case LongBowStatus_WARNED: printf("W"); break; + case LONGBOW_STATUS_SETUP_FAILED: printf("s"); break; + case LONGBOW_STATUS_TEARDOWN_FAILED: printf("t"); break; + case LongBowStatus_TEARDOWN_WARNED: printf("w"); break; + case LONGBOW_STATUS_FAILED: printf("F"); break; + case LongBowStatus_STOPPED: printf("T"); break; + case LongBowStatus_UNIMPLEMENTED: printf("U"); break; + case LongBowStatus_IMPOTENT: printf("I"); break; + default: + if (testCaseResult->status >= LongBowStatus_SIGNALLED) { + printf("K"); + } else { + printf("?"); + } + } + fflush(stdout); +} + +void +longBowReportTesting_Trace(const char *restrict format, ...) +{ + va_list ap; + va_start(ap, format); + char *message; + if (vasprintf(&message, format, ap) == -1) { + return; + } + va_end(ap); + + printf("%s\n", message); + free(message); +} diff --git a/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.c b/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.c new file mode 100644 index 00000000..aa385033 --- /dev/null +++ b/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.c @@ -0,0 +1,44 @@ +// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED. +// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z + +#include "longBowReportTextPlain_About.h" + +const char *longBowReportTextPlain_What = "@(#)" "LongBow Text Plain Reporter " RELEASE_VERSION " 2017-02-14T21:40:52.491677" + "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates."; + +const char * +longBowReportTextPlainAbout_Name(void) +{ + return "LongBow Text Plain Reporter"; +} + +const char * +longBowReportTextPlainAbout_Version(void) +{ + return RELEASE_VERSION; +} + +const char * +longBowReportTextPlainAbout_About(void) +{ + return "LongBow Text Plain Reporter "RELEASE_VERSION " 2017-02-14T21:40:52.491677" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowReportTextPlainAbout_MiniNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowReportTextPlainAbout_ShortNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowReportTextPlainAbout_LongNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n\n"; +} + diff --git a/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.h b/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.h new file mode 100755 index 00000000..08f69eb2 --- /dev/null +++ b/longbow/src/LongBow/Reporting/TextPlain/longBowReportTextPlain_About.h @@ -0,0 +1,54 @@ +// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED. +// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z + +#ifndef longBowReportTextPlain_About_h +#define longBowReportTextPlain_About_h +/** + * Embedded string containing information for the what(1) command. + * + */ +extern const char *longBowReportTextPlain_What; + +/** + * Return the name as a C string. + * + * @return The name as a C string. + */ +const char *longBowReportTextPlainAbout_Name(void); + +/** + * Return the version as a C string. + * + * @return The version as a C string. + */ +const char *longBowReportTextPlainAbout_Version(void); + +/** + * Return the About text as a C string. + * + * @return The About text as a C string. + */ +const char *longBowReportTextPlainAbout_About(void); + +/** + * Return the minimum copyright notice as a C string. + * + * @return The minimum copyright notice as a C string. + */ +const char *longBowReportTextPlainAbout_MiniNotice(void); + +/** + * Return the short copyright notice as a C string. + * + * @return The short copyright notice as a C string. + */ +const char *longBowReportTextPlainAbout_ShortNotice(void); + +/** + * Return the long copyright notice as a C string. + * + * @return The long copyright notice as a C string. + */ +const char *longBowReportTextPlainAbout_LongNotice(void); + +#endif // longBowReportTextPlain_About_h diff --git a/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Runtime.c b/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Runtime.c new file mode 100755 index 00000000..b5cb4dfc --- /dev/null +++ b/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Runtime.c @@ -0,0 +1,95 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <assert.h> + +#include <LongBow/Reporting/longBowReport_Runtime.h> +#include <LongBow/private/longBow_Memory.h> + +LongBowReportConfig * +longBowReportRuntime_Create(int argc, char *argv[argc]) +{ + LongBowReportConfig *result = longBowMemory_Allocate(sizeof(LongBowReportConfig)); + + return result; +} + +void +longBowReportRuntime_Destroy(LongBowReportConfig **reportPtr) +{ + longBowMemory_Deallocate((void **) reportPtr); +} + +void +longBowReportRuntime_Event(const LongBowEvent *event) +{ + if (longBowEventType_IsSuppressAlert(longBowEvent_GetEventType(event)) == false) { + char *location = strdup(""); + if (longBowEvent_GetLocation(event) != NULL) { + free(location); + location = longBowLocation_ToString(longBowEvent_GetLocation(event)); + } + printf("%s %s %s %s\r\n", + longBowEvent_GetName(event), location, longBowEvent_GetKind(event), longBowEvent_GetMessage(event)); + + if (longBowEventType_IsSuppressBacktrace(longBowEvent_GetEventType(event)) == false) { + char **strs = longBowEvent_CreateSymbolicCallstack(event); + if (strs != NULL) { + for (size_t i = 0; i < longBowEvent_GetCallStackLength(event); ++i) { + fputs(strs[i], stdout); + fputs("\r\n", stdout); + } + free(strs); + } + } + fflush(stdout); + + free(location); + } +} + +void +longBowReportRuntime_Message(const char *format, ...) +{ + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} + +void +longBowReportRuntime_Warning(const char *format, ...) +{ + va_list args; + va_start(args, format); + printf("WARNING "); + vprintf(format, args); + va_end(args); +} + +void +longBowReportRuntime_Error(const char *format, ...) +{ + va_list args; + va_start(args, format); + printf("ERROR "); + vprintf(format, args); + va_end(args); +} diff --git a/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Testing.c b/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Testing.c new file mode 100755 index 00000000..3bed5cac --- /dev/null +++ b/longbow/src/LongBow/Reporting/TextPlain/longBowReport_Testing.c @@ -0,0 +1,193 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <assert.h> + +#include <LongBow/Reporting/longBowReport_Testing.h> +#include <LongBow/private/longBow_String.h> + +static const LongBowTestRunner * +_testRunnerSilent(const LongBowTestRunner *testRunner) +{ + LongBowStatus status = longBowTestRunner_GetStatus(testRunner); + + printf("%s %s\n", longBowTestRunner_GetName(testRunner), longBowStatus_ToString(status)); + return testRunner; +} + +static const LongBowTestRunner * +_testRunnerDetail(const LongBowTestRunner *testRunner) +{ + size_t nFixtures = longBowTestRunner_GetFixtureCount(testRunner); + + printf("\r\n"); + printf("%s: %zd fixture%s\r\n", longBowTestRunner_GetName(testRunner), nFixtures, (nFixtures == 1 ? "" : "s")); + + for (size_t i = 0; i < nFixtures; i++) { + LongBowTestFixture *fixture = longBowTestRunner_GetFixture(testRunner, i); + longBowReportTesting_TestFixture(fixture); + } + return testRunner; +} + +const LongBowTestRunner * +longBowReportTesting_TestRunner(const LongBowTestRunner *testRunner) +{ + if (longBowConfig_GetBoolean(longBowTestRunner_GetConfiguration(testRunner), false, "silent")) { + return _testRunnerSilent(testRunner); + } else { + return _testRunnerDetail(testRunner); + } +} + +static unsigned int +_totalSucceeded(const LongBowTestFixtureSummary *summary) +{ + return summary->totalSucceeded + summary->totalWarned + summary->totalTearDownWarned; +} + +static unsigned int +_totalWarned(const LongBowTestFixtureSummary *summary) +{ + return summary->totalWarned + summary->totalTearDownWarned; +} + +static unsigned int +_totalFailed(const LongBowTestFixtureSummary *summary) +{ + return summary->totalFailed + summary->totalSignalled + summary->totalStopped + summary->totalTearDownFailed; +} + +static unsigned int +_totalIncomplete(const LongBowTestFixtureSummary *summary) +{ + return summary->totalSetupFailed + summary->totalSkipped + summary->totalUnimplemented; +} + +static void +_reportSummary(const LongBowTestFixture *testFixture) +{ + const LongBowTestFixtureSummary *summary = longBowTestFixture_GetSummary(testFixture); + + char *fixtureString = longBowTestFixture_ToString(testFixture); + + printf("%s: Ran %u test case%s.", fixtureString, summary->totalTested, summary->totalTested == 1 ? "" : "s"); + free(fixtureString); + + if (summary->totalTested > 0) { + printf(" %d%% (%d) succeeded", _totalSucceeded(summary) * 100 / summary->totalTested, _totalSucceeded(summary)); + + if (_totalWarned(summary) > 0) { + printf(" %d%% (%d) with warnings", _totalWarned(summary) * 100 / _totalSucceeded(summary), _totalWarned(summary)); + } + if (_totalFailed(summary) != 0) { + printf(", %d%% (%d) failed", _totalFailed(summary) * 100 / summary->totalTested, _totalFailed(summary)); + } + if (_totalIncomplete(summary) > 0) { + printf(", %d%% (%d) incomplete", _totalIncomplete(summary) * 100 / summary->totalTested, _totalIncomplete(summary)); + } + } + printf("\n"); +} + +const LongBowTestFixture * +longBowReportTesting_TestFixture(const LongBowTestFixture *testFixture) +{ + size_t nTestCases = longBowTestFixture_GetTestCaseCount(testFixture); + + _reportSummary(testFixture); + + for (size_t i = 0; i < nTestCases; i++) { + LongBowTestCase *testCase = longBowTestFixture_GetTestCase(testFixture, i); + longBowReportTesting_TestCase(testCase); + } + return testFixture; +} + +const LongBowTestCase * +longBowReportTesting_TestCase(const LongBowTestCase *testCase) +{ + LongBowRuntimeResult *testCaseResult = longBowTestCase_GetActualResult(testCase); + + char *rusageString = longBowReportRuntime_RUsageToString(longBowRuntimeResult_GetRUsage(testCaseResult)); + + char *elapsedTimeString = longBowReportRuntime_TimevalToString(longBowRuntimeResult_GetElapsedTime(testCaseResult)); + + char *statusString = longBowStatus_ToString(longBowTestCase_GetActualResult(testCase)->status); + char *testCaseString = longBowTestCase_ToString(testCase); + + LongBowString *string = longBowString_CreateFormat("%10s %s %s %zd %s\n", + testCaseString, + elapsedTimeString, + rusageString, + longBowRuntimeResult_GetEventEvaluationCount(longBowTestCase_GetActualResult(testCase)), + statusString); + longBowString_Write(string, stdout); + longBowString_Destroy(&string); + + free(testCaseString); + free(statusString); + free(elapsedTimeString); + free(rusageString); + + return testCase; +} + +void +longBowReportTesting_DisplayTestCaseResult(const LongBowTestCase *testCase) +{ + const LongBowRuntimeResult *testCaseResult = longBowTestCase_GetActualResult(testCase); + + switch (testCaseResult->status) { + case LongBowStatus_UNTESTED: printf("X"); break; + case LONGBOW_STATUS_SUCCEEDED: printf("."); break; + case LONGBOW_STATUS_SKIPPED: printf("S"); break; + case LongBowStatus_WARNED: printf("W"); break; + case LONGBOW_STATUS_SETUP_FAILED: printf("s"); break; + case LONGBOW_STATUS_TEARDOWN_FAILED: printf("t"); break; + case LongBowStatus_TEARDOWN_WARNED: printf("w"); break; + case LONGBOW_STATUS_FAILED: printf("F"); break; + case LongBowStatus_STOPPED: printf("T"); break; + case LongBowStatus_UNIMPLEMENTED: printf("U"); break; + case LongBowStatus_IMPOTENT: printf("I"); break; + default: + if (testCaseResult->status >= LongBowStatus_SIGNALLED) { + printf("K"); + } else { + printf("?"); + } + } + fflush(stdout); +} + +void +longBowReportTesting_Trace(const char *restrict format, ...) +{ + va_list ap; + va_start(ap, format); + char *message; + if (vasprintf(&message, format, ap) == -1) { + return; + } + va_end(ap); + + printf("%s\n", message); + free(message); +} diff --git a/longbow/src/LongBow/Reporting/longBowReport_Runtime.c b/longbow/src/LongBow/Reporting/longBowReport_Runtime.c new file mode 100755 index 00000000..2671cf31 --- /dev/null +++ b/longbow/src/LongBow/Reporting/longBowReport_Runtime.c @@ -0,0 +1,50 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> + +#include <LongBow/Reporting/longBowReport_Runtime.h> + +char * +longBowReportRuntime_TimevalToString(const struct timeval time) +{ + char *string = NULL; + if (asprintf(&string, "%ld.%06lds", time.tv_sec, (long) time.tv_usec) == -1) { + return NULL; + } + return string; +} + +char * +longBowReportRuntime_RUsageToString(const struct rusage *rusage) +{ + char *string; + + char *ru_utime = longBowReportRuntime_TimevalToString(rusage->ru_utime); + char *ru_stime = longBowReportRuntime_TimevalToString(rusage->ru_stime); + + if (asprintf(&string, "%s %s", ru_utime, ru_stime) == -1) { + return NULL; + } + + free(ru_utime); + free(ru_stime); + + return string; +} diff --git a/longbow/src/LongBow/Reporting/longBowReport_Runtime.h b/longbow/src/LongBow/Reporting/longBowReport_Runtime.h new file mode 100755 index 00000000..5682be15 --- /dev/null +++ b/longbow/src/LongBow/Reporting/longBowReport_Runtime.h @@ -0,0 +1,146 @@ +/* + * 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 Reporting/longBowReport_Runtime.h + * @ingroup reporting + * @brief The LongBow Runtime Report Generator. + * + * This header specifies the interface for an implementation of a LongBow Test Report generator. + * Different implementations of a Test Report generator are used to connect to external environments to hook in + * LongBow unit tests within a larger framework like an IDE or continuous integration system. + * + * There may be many different ways to report the summary of a LongBow Unit Test, + * and the different ways implement the functions prescribed here. + * The resulting object files are then linked with the unit-test according to the kind of report needed. + * + */ +#ifndef LONGBOW_REPORT_RUNTIME_H_ +#define LONGBOW_REPORT_RUNTIME_H_ + +#include <LongBow/longBow_Event.h> + +#include <LongBow/runtime.h> +#include <LongBow/unit-test.h> + +struct longbow_report_config; +/** + * @brief Configuration for a LongBow Test. + */ +typedef struct longbow_report_config LongBowReportConfig; + +/** + * @struct longbow_report_config + * @brief The configuration information for a LongBow Test Report. + */ +struct longbow_report_config { + struct { + unsigned int untested : 1; + unsigned int succeeded : 1; + unsigned int warned : 1; + unsigned int teardown_warned : 1; + unsigned int skipped : 1; + unsigned int unimplemented : 1; + unsigned int failed : 1; + unsigned int stopped : 1; + unsigned int teardown_failed : 1; + unsigned int setup_failed : 1; + unsigned int signalled : 1; + } suppress_report; /**< Bit fields representing which report to suppress. */ +}; + +/** + * Create a LongBowReportConfiguration from a set of parameters. + * + * @param [in] argc The number of parameters in the argv array. + * @param [in] argv An array of C strings. + * + * @return An allocated LongBowReportConfiguration instance that must be dellocted via longBowReport_Destroy. + * + * Example: + * @code + * { + * char *argv[2] = { "arg1", "arg2" }; + * LongBowReportConfig *report = longBowReport_Create(2, argv); + * } + * @endcode + */ +LongBowReportConfig *longBowReportRuntime_Create(int argc, char *argv[]); + +/** + * Destroy a LongBowReportConfig instance. + * + * @param [in,out] configPtr A pointer to a LongBowReportConfig pointer. The value of configPtr will be set to zero. + * + * Example: + * @code + * { + * char *argv[2] = { "arg1", "arg2" }; + * LongBowReportConfig *report = longBowReport_Create(2, argv); + * LongBowReport_Destroy(&report); + * } + * @endcode + */ +void longBowReportRuntime_Destroy(LongBowReportConfig **configPtr); + +/** + * Report a LongBowEvent. + * + * @param [in] event A pointer to a valid LongBowEvent instance. + */ +void longBowReportRuntime_Event(const LongBowEvent *event); + +/** + * Report a message. + * + * @param [in] message A pointer to a nul-terminated C string. + */ +void longBowReportRuntime_Message(const char *message, ...); + +/** + * Report an error message. + * + * An error message reports an unrecoverable error. + * + * @param [in] message A pointer to a nul-terminated C string. + */ +void longBowReportRuntime_Error(const char *message, ...); + +/** + * Report an error message. + * + * An error message reports an recoverable warning. + * + * @param [in] message A pointer to a nul-terminated C string. + */ +void longBowReportRuntime_Warning(const char *message, ...); + +/** + * Format a struct timeval structure. + * + * @param [in] time A struct timeval value. + * + * @return An allocated nul-terminated C string that must be freed via stdlib free(3). + */ +char *longBowReportRuntime_TimevalToString(const struct timeval time); + +/** + * Format a struct rusage struture. + * + * @param [in] rusage A pointer to a valid `struct rusage` instance. + * @return An allocated nul-terminated C string that must be freed via stdlib free(3). + */ +char *longBowReportRuntime_RUsageToString(const struct rusage *rusage); +#endif // LONGBOW_REPORT_RUNTIME_H_ diff --git a/longbow/src/LongBow/Reporting/longBowReport_Testing.c b/longbow/src/LongBow/Reporting/longBowReport_Testing.c new file mode 100755 index 00000000..646a7a05 --- /dev/null +++ b/longbow/src/LongBow/Reporting/longBowReport_Testing.c @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> + +#include <LongBow/Reporting/longBowReport_Testing.h> diff --git a/longbow/src/LongBow/Reporting/longBowReport_Testing.h b/longbow/src/LongBow/Reporting/longBowReport_Testing.h new file mode 100755 index 00000000..b4b2eaf8 --- /dev/null +++ b/longbow/src/LongBow/Reporting/longBowReport_Testing.h @@ -0,0 +1,71 @@ +/* + * 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 longBowReport_Testing.h + * @ingroup reporting + * @brief The LongBow Test Report Generator. + * + * This header specifies the interface for an implementation of a LongBow Test Report generator. + * Different implementations of a Test Report generator are used to connect to external environments to hook in + * LongBow unit tests within a larger framework like an IDE or continuous integration system. + * + */ +#ifndef LONGBOW_REPORT_TESTING_H_ +#define LONGBOW_REPORT_TESTING_H_ + +#include <LongBow/Reporting/longBowReport_Runtime.h> + +#include <LongBow/runtime.h> +#include <LongBow/unit-test.h> + +/** + * Produce a summary report for the given LongBowTestRunner. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @return The given LongBowTestRunner. + */ +const LongBowTestRunner *longBowReportTesting_TestRunner(const LongBowTestRunner *testRunner); + +/** + * Produce a summary report for the given LongBowTestFixture. + * + * @param [in] testFixture A pointer to a LongBowTestFixture instance. + * @return The given LongBowTestFixture. + */ +const LongBowTestFixture *longBowReportTesting_TestFixture(const LongBowTestFixture *testFixture); + +/** + * Produce a summary report for the given LongBowTestCase. + * + * @param [in] testCase A pointer to a LongBowTestCase instance. + * @return The pointer to the given LongBowTestCase. + */ +const LongBowTestCase *longBowReportTesting_TestCase(const LongBowTestCase *testCase); + +/** + * Produce a single character displaying the status of an individual test case. + * + * @param [in] testCase A pointer to a LongBowTestCase instance. + */ +void longBowReportTesting_DisplayTestCaseResult(const LongBowTestCase *testCase); + +/** + * Make a trace report. + * + * @param [in] format A printf-style format string. + */ +void longBowReportTesting_Trace(const char *restrict format, ...); +#endif // LONGBOW_REPORT_TESTING_H_ diff --git a/longbow/src/LongBow/assertions.h b/longbow/src/LongBow/assertions.h new file mode 100644 index 00000000..c175bb1d --- /dev/null +++ b/longbow/src/LongBow/assertions.h @@ -0,0 +1,152 @@ +/* + * 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 assertions.h + * @ingroup runtime + * @brief Runtime and Test Assertions + * + */ +#ifndef LongBow_assertions_h +#define LongBow_assertions_h + +#ifndef LongBow_runtime_h +#error "Do not include LongBow/assertions.h directly. Include LongBow/runtime.h" +#endif + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> + +#include <LongBow/traps.h> +#include <LongBow/tests.h> + +#include <LongBow/longBow_Location.h> +#include <LongBow/longBow_Event.h> + +/** + * @def assertTrue + * @brief Assert that a condition is true. + * + * @param condition If false, the assertion triggers. + * @param ... A printf formatting string (required) and parameters (optional). + * + * Example: + * @code + * { + * assertTrue(2 + 2 == 4, "Adding 2 + 2 did not equal 4."); + * } + * @endcode + */ +#define assertTrue(condition, ...) longBowAssert(&LongBowAssertEvent, (condition), __VA_ARGS__) + +/** + * @def assertFalse + * @brief Assert that a condition is false. + * + * @param condition If true, the assertion triggers. + * @param ... A printf formatting string (required) and parameters (optional). + * Example: + * @code + * { + * assertFalse(2 + 2 == 5, "Adding 2 + 2 must not equal 5."); + * } + * @endcode + */ +#define assertFalse(condition, ...) longBowAssert(&LongBowAssertEvent, !(condition), __VA_ARGS__) + +/** + * @def assertNotNull + * @brief Assert that the given value is not NULL. + * + * @param x If the value is NULL, the assertion triggers. + * @param ... A printf formatting string (required) and parameters (optional). + * Example: + * @code + * void + * function(char *p) + * { + * assertNotNull(p, "Parameter must not be NULL"); + * } + * @endcode + */ +#define assertNotNull(x, ...) longBowAssert(&LongBowAssertEvent, (x) != NULL, __VA_ARGS__) + +/** + * @def assertNull + * @brief Assert that the given value is NULL. + * + * @param x The value to test. + * @param ... A printf formatting string (required) and parameters (optional). + * Example: + * @code + * void + * function(char *p) + * { + * assertNull(p, "Parameter must be NULL"); + * } + * @endcode + */ +#define assertNull(x, ...) longBowAssert(&LongBowAssertEvent, (x) == NULL, __VA_ARGS__) + +/** + * @def assertAligned + * @brief Assert that the given address is aligned according to `alignment`. + * + * Return true of the given address is aligned according to alignment. + * The value for alignment must be a power of 2. + * + * @param address A pointer to memory + * @param alignment A power of 2 representing the memory alignment of address. + * @param ... A printf formatting string (required) and parameters (optional). + * + * Example: + * @code + * void + * function(void *p) + * { + * assertAligned(p, 4, "Parameter must be aligned on 4 byte boundaries"); + * } + * @endcode + */ +#define assertAligned(address, alignment, ...) \ + longBowAssert(&LongBowAssertEvent, longBowRuntime_TestAddressIsAligned((address), (alignment)), __VA_ARGS__) + +/** + * @def assertEqualStrings + * @brief Assert that two strings are equal. + * + * @param expected + * @param actual + * @param ... A printf formatting string (required) and parameters (optional). + * + * Example: + * @code + * { + * assertEqualStrings("hello", "world"); + * } + * @endcode + */ +#define assertEqualStrings(expected, actual) \ + longBowAssert(&LongBowAssertEvent, strcmp((expected), (actual)) == 0, "Expected '%s' actual '%s'", (expected), (actual)) + +/** + * @def assertEqual + * @brief Assert that two values are equal, using a canonical string message. + */ +#define assertEqual(expected, actual, format) \ + assertTrue((expected) == (actual), "Expected=" format " actual=" format, (expected), (actual)) +#endif /* ASSERTIONS_H_ */ + diff --git a/longbow/src/LongBow/command-line/.gitignore b/longbow/src/LongBow/command-line/.gitignore new file mode 100644 index 00000000..c12b3061 --- /dev/null +++ b/longbow/src/LongBow/command-line/.gitignore @@ -0,0 +1,2 @@ +liblongbow-config +*dSYM diff --git a/longbow/src/LongBow/command-line/liblongbow-config.c b/longbow/src/LongBow/command-line/liblongbow-config.c new file mode 100755 index 00000000..5e7bf6cc --- /dev/null +++ b/longbow/src/LongBow/command-line/liblongbow-config.c @@ -0,0 +1,58 @@ +/* + * 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. + */ + +/** + */ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <string.h> + +#define stringify(x) "" #x "" + +void +printLoaderDirectory(void) +{ + printf("%s\n", LIB_INSTALL_DIR); +} + +void +printIncludeDirectory(void) +{ +} + +void +printVersion(void) +{ +} + +int +main(int argc, char *argv[]) +{ + for (int i = 1; i < argc; i++) { + if (strcmp("-I", argv[i]) == 0) { + printIncludeDirectory(); + } else if (strcmp("-L", argv[i]) == 0) { + printLoaderDirectory(); + } else if (strcmp("-v", argv[i]) == 0) { + printVersion(); + } else { + printf("unknown option '%s'\n", argv[i]); + } + } + return 0; +} diff --git a/longbow/src/LongBow/config.h.in b/longbow/src/LongBow/config.h.in new file mode 100644 index 00000000..75a5edc2 --- /dev/null +++ b/longbow/src/LongBow/config.h.in @@ -0,0 +1,11 @@ +// +// Created by Ignacio Solis on 12/1/15. +// + +#ifndef LONGBOW_CONFIGURATION_H +#define LONGBOW_CONFIGURATION_H + +#define LIB_INSTALL_DIR "@CMAKE_INSTALL_PREFIX@" + +#endif //LONGBOW_CONFIGURATION_H + diff --git a/longbow/src/LongBow/debugging.h b/longbow/src/LongBow/debugging.h new file mode 100755 index 00000000..b19ca486 --- /dev/null +++ b/longbow/src/LongBow/debugging.h @@ -0,0 +1,51 @@ +/* + * 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 debugging.h + * @brief Debugging Utilities + * + */ +#ifndef LongBow_debugging_h +#define LongBow_debugging_h + +#include <LongBow/longBow_Debug.h> + +#include <LongBow/longBow_MeasureTime.h> + +/** + * @def longBow_function + * @brief The compile time function name. + */ +#if __STDC_VERSION__ >= 199901L +# define longBow_function __func__ +#else +# define longBow_function ((const char *) 0) +#endif + +/** + * @def longBowDebug + * @brief Print a debugging message. + * + * @param ... A printf-style format string followed by a variable number of parameters supplying values for the format string. + */ +#ifndef LONGBOW_DEBUG_DISABLED +# define longBowDebug(...) \ + do { longBowDebug_Message(NULL, longBowLocation_Create(__FILE__, longBow_function, __LINE__), __VA_ARGS__); } while (0) +#else +# define longBowDebug(...) \ + do { } while (0) +#endif +#endif diff --git a/longbow/src/LongBow/longBow_About.c b/longbow/src/LongBow/longBow_About.c new file mode 100644 index 00000000..1a29eacf --- /dev/null +++ b/longbow/src/LongBow/longBow_About.c @@ -0,0 +1,44 @@ +// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED. +// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z + +#include "longBow_About.h" + +const char *longBow_What = "@(#)" "longBow " RELEASE_VERSION " 2017-02-14T21:35:02.945622" + "@(#)" "\tCopyright (c) 2017 Cisco and/or its affiliates."; + +const char * +longBowAbout_Name(void) +{ + return "longBow"; +} + +const char * +longBowAbout_Version(void) +{ + return RELEASE_VERSION; +} + +const char * +longBowAbout_About(void) +{ + return "longBow "RELEASE_VERSION " 2017-02-14T21:35:02.945622" "\nCopyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowAbout_MiniNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowAbout_ShortNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\n"; +} + +const char * +longBowAbout_LongNotice(void) +{ + return "Copyright (c) 2017 Cisco and/or its affiliates.\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n\n"; +} + diff --git a/longbow/src/LongBow/longBow_About.h b/longbow/src/LongBow/longBow_About.h new file mode 100755 index 00000000..5941aa6a --- /dev/null +++ b/longbow/src/LongBow/longBow_About.h @@ -0,0 +1,54 @@ +// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED. +// longbow-generate-about 1.0.20170214.46e2c73a 2017-02-14T20:35:31Z + +#ifndef longBow_About_h +#define longBow_About_h +/** + * Embedded string containing information for the what(1) command. + * + */ +extern const char *longBow_What; + +/** + * Return the name as a C string. + * + * @return The name as a C string. + */ +const char *longBowAbout_Name(void); + +/** + * Return the version as a C string. + * + * @return The version as a C string. + */ +const char *longBowAbout_Version(void); + +/** + * Return the About text as a C string. + * + * @return The About text as a C string. + */ +const char *longBowAbout_About(void); + +/** + * Return the minimum copyright notice as a C string. + * + * @return The minimum copyright notice as a C string. + */ +const char *longBowAbout_MiniNotice(void); + +/** + * Return the short copyright notice as a C string. + * + * @return The short copyright notice as a C string. + */ +const char *longBowAbout_ShortNotice(void); + +/** + * Return the long copyright notice as a C string. + * + * @return The long copyright notice as a C string. + */ +const char *longBowAbout_LongNotice(void); + +#endif // longBow_About_h diff --git a/longbow/src/LongBow/longBow_Backtrace.c b/longbow/src/LongBow/longBow_Backtrace.c new file mode 100755 index 00000000..19625eed --- /dev/null +++ b/longbow/src/LongBow/longBow_Backtrace.c @@ -0,0 +1,136 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <LongBow/longBow_Backtrace.h> +#include <LongBow/private/longBow_Memory.h> + +#if defined(_WIN64) +# define backtrace(...) (0) +# define backtrace_symbols(...) 0 +# define backtrace_symbols_fd(...) ((void) 0) +#elif defined(_WIN32) +# define backtrace(...) (0) +# define backtrace_symbols(...) 0 +# define backtrace_symbols_fd(...) ((void) 0) +#elif defined(__ANDROID__) +# define backtrace(...) (0) +# define backtrace_symbols(...) 0 +# define backtrace_symbols_fd(...) ((void) 0) +#elif defined(__APPLE__) +# include <execinfo.h> +#elif defined(__linux) +# include <execinfo.h> +#elif defined(__unix) // all unices not caught above +# define backtrace(...) (0) +# define backtrace_symbols(...) 0 +# define backtrace_symbols_fd(...) ((void) 0) +#elif defined(__posix) +# include <execinfo.h> +#endif + +struct longbow_backtrace { + void *callstack; + unsigned int frames; + unsigned int offset; +}; + +LongBowBacktrace * +longBowBacktrace_Create(uint32_t maximumFrames, uint32_t offset) +{ + LongBowBacktrace *result = longBowMemory_Allocate(sizeof(LongBowBacktrace)); + + if (maximumFrames > 0) { + void **stackTrace = longBowMemory_Allocate(sizeof(stackTrace[0]) * ((size_t) maximumFrames + offset)); + + unsigned int frames = (unsigned int) backtrace(stackTrace, (int) (maximumFrames + offset)); + if (frames > offset) { + unsigned int actualFrames = frames - offset; + + if (actualFrames > maximumFrames) { + actualFrames = maximumFrames; + } + + // Shift out the first 'offset' number of frames in the stack trace. + memmove(&stackTrace[0], &stackTrace[offset], actualFrames * sizeof(stackTrace[0])); + + result->callstack = stackTrace; + result->frames = actualFrames; + result->offset = 0; + } + } + + return result; +} + +unsigned int +longBowBacktrace_GetFrameCount(const LongBowBacktrace *backtrace) +{ + return backtrace->frames; +} + +void +longBowBacktrace_Destroy(LongBowBacktrace **backtracePtr) +{ + LongBowBacktrace *backtrace = *backtracePtr; + longBowMemory_Deallocate(&backtrace->callstack); + longBowMemory_Deallocate((void **) backtracePtr); +} + +char ** +longBowBacktrace_Symbols(const LongBowBacktrace *backtrace) +{ + char **result = NULL; + if (backtrace != NULL) { + result = backtrace_symbols(backtrace->callstack, (int) backtrace->frames); + } + + return result; +} + +char * +longBowBacktrace_ToString(const LongBowBacktrace *backtrace) +{ + char *result = NULL; + + char **lines = longBowBacktrace_Symbols(backtrace); + + if (lines == NULL) { + result = longBowMemory_StringCopy("(backtrace symbols not supported)"); + } else { + size_t sum = 0; + for (int i = 0; i < backtrace->frames; i++) { + sum += strlen(lines[i]) + 1; + } + result = longBowMemory_Allocate(sum + 1 * sizeof(char)); + + char *offset = result; + for (int i = 0; i < backtrace->frames; i++) { + strcpy(offset, lines[i]); + offset += strlen(lines[i]); + *offset++ = '\n'; + } + *offset = 0; + } + + return result; +} diff --git a/longbow/src/LongBow/longBow_Backtrace.h b/longbow/src/LongBow/longBow_Backtrace.h new file mode 100755 index 00000000..b7b12bef --- /dev/null +++ b/longbow/src/LongBow/longBow_Backtrace.h @@ -0,0 +1,80 @@ +/* + * 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 longBow_Backtrace.h + * @ingroup internals + * @brief Support for Stack Traces + * + */ +#ifndef LongBow_longBow_Backtrace_h +#define LongBow_longBow_Backtrace_h +#include <stdint.h> + +struct longbow_backtrace; +/** + * @typedef LongBowBacktrace + * @brief A Backtrace representation. + */ +typedef struct longbow_backtrace LongBowBacktrace; + +/** + * Create a `LongBowBacktrace`. + * + * The backtrace includes depth number of elements from the stack. + * + * @param [in] depth The number of elements from the stack to include. + * @param [in] offset The offset of the stack to start the Backtrace. + * @return A pointer to an allocated LongBowBacktrace instance. + */ +LongBowBacktrace *longBowBacktrace_Create(uint32_t depth, uint32_t offset); + +/** + * Get the array of symbols from the given `LongBowBacktrace instance`. + * + * @param [in] backtrace A pointer to a valid LongBowBacktrace instance. + * + * @return An array of nul-terminated, C strings each containing a symbolic representatino of the corresponding stack frame. + * + * Example: + * @code + * { + * <#example#> + * } + * @endcode + */ +char **longBowBacktrace_Symbols(const LongBowBacktrace *backtrace); +/** + * Get the number of frames in the given LongBowBacktrace instance. + * + * @param [in] backtrace A pointer to a valid LongBowBacktrace instance. + * + * @return The number of frames in the LongBowBacktrace. + */ +unsigned int longBowBacktrace_GetFrameCount(const LongBowBacktrace *backtrace); + +/** + * + * @param [in,out] backtracePtr A pointer to a pointer to a valid LongBowBacktrace instance. + */ +void longBowBacktrace_Destroy(LongBowBacktrace **backtracePtr); + +/** + * + * @param [in] backtrace A pointer to a valid LongBowBacktrace instance. + * @return An allocated C string that must be deallocated via longBowMemory_Deallocate(). + */ +char *longBowBacktrace_ToString(const LongBowBacktrace *backtrace); +#endif diff --git a/longbow/src/LongBow/longBow_ClipBoard.c b/longbow/src/LongBow/longBow_ClipBoard.c new file mode 100644 index 00000000..a3264d44 --- /dev/null +++ b/longbow/src/LongBow/longBow_ClipBoard.c @@ -0,0 +1,155 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <LongBow/longBow_ClipBoard.h> + +#include <LongBow/private/longBow_Memory.h> +#include <LongBow/private/longBow_ArrayList.h> + +struct LongBowClipBoard { + LongBowArrayList *list; +}; + +typedef struct Property { + const char *name; + char *value; +} _Property; + +static void +_property_Destroy(_Property **pointer) +{ + _Property *property = *pointer; + longBowMemory_Deallocate((void **) &property->name); + longBowMemory_Deallocate((void **) property); +} + +void +longBowClipBoard_Destroy(LongBowClipBoard **pointer) +{ + LongBowClipBoard *clipboard = *pointer; + + longBowArrayList_Destroy(&clipboard->list); + longBowMemory_Deallocate((void **) pointer); +} + +LongBowClipBoard * +longBowClipBoard_Create(void) +{ + LongBowClipBoard *result = longBowMemory_Allocate(sizeof(LongBowClipBoard)); + + if (result != NULL) { + result->list = longBowArrayList_Create((void (*)(void **))_property_Destroy); + } + + return result; +} + +static _Property * +_longBowClipBoard_Get(const LongBowClipBoard *clipBoard, const char *name) +{ + _Property *result = NULL; + + for (size_t index = 0; index < longBowArrayList_Length(clipBoard->list); index++) { + _Property *property = longBowArrayList_Get(clipBoard->list, index); + if (strcmp(property->name, name) == 0) { + result = property; + break; + } + } + return result; +} + +void * +longBowClipBoard_Get(const LongBowClipBoard *clipBoard, const char *name) +{ + _Property *property = _longBowClipBoard_Get(clipBoard, name); + + if (property != NULL) { + return property->value; + } + + return NULL; +} + +char * +longBowClipBoard_GetAsCString(const LongBowClipBoard *clipBoard, const char *name) +{ + return (char *) longBowClipBoard_Get(clipBoard, name); +} + +uint64_t +longBowClipBoard_GetAsInt(const LongBowClipBoard *clipBoard, const char *name) +{ + return (uint64_t) longBowClipBoard_Get(clipBoard, name); +} + +void * +longBowClipBoard_Set(LongBowClipBoard *clipBoard, const char *name, void *value) +{ + void *result = NULL; + + _Property *property = _longBowClipBoard_Get(clipBoard, name); + if (property == NULL) { + property = longBowMemory_Allocate(sizeof(_Property)); + property->name = longBowMemory_StringCopy(name); + property->value = value; + longBowArrayList_Add(clipBoard->list, property); + } else { + result = property->value; + property->value = value; + } + return result; +} + +void * +longBowClipBoard_SetInt(LongBowClipBoard *clipBoard, const char *name, uint64_t value) +{ + return longBowClipBoard_Set(clipBoard, name, (void *) (uintptr_t) value); +} + +void * +longBowClipBoard_SetCString(LongBowClipBoard *clipBoard, const char *name, char *value) +{ + return longBowClipBoard_Set(clipBoard, name, (char *) value); +} + +bool +longBowClipBoard_Exists(const LongBowClipBoard *clipBoard, const char *name) +{ + return (_longBowClipBoard_Get(clipBoard, name) != NULL); +} + +bool +longBowClipBoard_Delete(LongBowClipBoard *clipBoard, const char *name) +{ + bool result = false; + + for (size_t index = 0; index < longBowArrayList_Length(clipBoard->list); index++) { + _Property *property = longBowArrayList_Get(clipBoard->list, index); + if (strcmp(property->name, name) == 0) { + longBowArrayList_RemoveAtIndex(clipBoard->list, index); + result = true; + } + } + + return result; +} diff --git a/longbow/src/LongBow/longBow_ClipBoard.h b/longbow/src/LongBow/longBow_ClipBoard.h new file mode 100755 index 00000000..86781953 --- /dev/null +++ b/longbow/src/LongBow/longBow_ClipBoard.h @@ -0,0 +1,52 @@ +/* + * 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 longBow_ClipBoard.h + * @brief <#Brief Description#> + * + * <#Detailed Description#> + * + */ +#ifndef longBow_ClipBoard_h +#define longBow_ClipBoard_h + +#include <stdbool.h> +#include <stdint.h> + +struct LongBowClipBoard; +typedef struct LongBowClipBoard LongBowClipBoard; + +void longBowClipBoard_Destroy(LongBowClipBoard **pointer); + +LongBowClipBoard *longBowClipBoard_Create(void); + +void *longBowClipBoard_Get(const LongBowClipBoard *clipBoard, const char *name); + +char *longBowClipBoard_GetAsCString(const LongBowClipBoard *clipBoard, const char *name); + +uint64_t longBowClipBoard_GetAsInt(const LongBowClipBoard *clipBoard, const char *name); + +void *longBowClipBoard_Set(LongBowClipBoard *clipBoard, const char *name, void *value); + +void *longBowClipBoard_SetInt(LongBowClipBoard *clipBoard, const char *name, uint64_t value); + +void *longBowClipBoard_SetCString(LongBowClipBoard *clipBoard, const char *name, char *value); + +bool longBowClipBoard_Exists(const LongBowClipBoard *clipBoard, const char *name); + +bool longBowClipBoard_Delete(LongBowClipBoard *clipBoard, const char *name); + +#endif /* longBow_ClipBoard_h */ diff --git a/longbow/src/LongBow/longBow_Compiler.h b/longbow/src/LongBow/longBow_Compiler.h new file mode 100755 index 00000000..197e1e8c --- /dev/null +++ b/longbow/src/LongBow/longBow_Compiler.h @@ -0,0 +1,302 @@ +/* + * 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 longBow_Compiler.h + * @ingroup compiling + * @brief LongBow compile time functionality. + * + */ +#ifndef LongBow_compiling_h +#define LongBow_compiling_h + +/** + * @def LONGBOW_GNUC_EXACTLY + * + * Compile-time test to determine if the compiler is the GNU C compiler with the specfied + * version, revision and patch levels. + * + * @param [in] major The required major version number of the compiler. + * @param [in] minor The required minor version number of the compiler. + * @param [in] patch The required patch number of the compiler. + * + * @return true If the current compiler matches the requirements. + * + * Example: + * @code + * #if LONGBOW_GNUC_EXACTLY(4,2,1) + * printf("Hello GNU compiler 4.2.1\n"); + * #endif + * @endcode + * + * @see LONGBOW_GNUC_ATLEAST + */ +#ifdef __GNUC__ +# define LONGBOW_GNUC_EXACTLY(major, minor, patch) \ + (__GNUC__ == major) && (__GNUC_MINOR__ = minor) && (__GNUC_PATCHLEVEL__ == patch) +#else +# define LONGBOW_GNUC_EXACTLY(major, minor, patch) \ + (0) +#endif + +/** + * @def LONGBOW_GNUC_ATLEAST + * + * Compile-time test to determine if the compiler is the GNU C compiler with at least the specfied + * version, revision and patch levels. + * + * @param [in] major The minimum required major version number of the compiler. + * @param [in] minor The minimum required minor version number of the compiler. + * @param [in] patch The minimum required patch number of the compiler. + * + * @return true If the current compiler matches the requirements. + * @return false If the current compiler fails to match the requirements. + * + * Example: + * @code + * #if LONGBOW_GNUC_ATLEAST(4,0,0) + * printf("Hello GNU compiler 4.x\n"); + * #endif + * @endcode + * + * @see LONGBOW_GNUC_EXACTLY + */ +#ifdef __GNUC__ +# define LONGBOW_GNUC_ATLEAST(major, minor, patch) \ + (__GNUC__ >= major) && (__GNUC_MINOR__ > minor) && (__GNUC_PATCHLEVEL__ >= patch) +#else +# define LONGBOW_GNUC_ATLEAST(major, minor, patch) \ + (0) +#endif + +/** + * @def LONGBOW_CLANG_EXACTLY + * + * Compile-time test to determine if the compiler is the Clang C compiler with the specfied + * version, revision and patch levels. + * + * @param [in] major The required major version number of the compiler. + * @param [in] minor The required minor version number of the compiler. + * @param [in] patch The required patch number of the compiler. + * + * @return true If the current compiler matches the requirements. + * + * Example: + * @code + * #if LONGBOW_CLANG_EXACTLY(5,0,0) + * printf("Hello Clang 5.0.0\n"); + * #endif + * @endcode + * + * @see LONGBOW_CLANG_ATLEAST + */ +#ifdef __clang__ +# define LONGBOW_CLANG_EXACTLY(major, minor, patch) \ + (__clang_major__ == major) && (__clang_major__ = minor) && (__clang_patchlevel__ == patch) +#else +# define LONGBOW_CLANG_EXACTLY(major, minor, patch) \ + (0) +#endif + +/** + * @def LONGBOW_CLANG_ATLEAST + * + * Compile-time test to determine if the compiler is the GNU C compiler with at least the specfied + * version, revision and patch levels. + * + * @param [in] major The minimum required major version number of the compiler. + * @param [in] minor The minimum required minor version number of the compiler. + * @param [in] patch The minimum required patch number of the compiler. + * + * @return true If the current compiler matches the requirements. + * @return false If the current compiler fails to match the requirements. + * + * Example: + * @code + * #if LONGBOW_CLANG_ATLEAST(5,0,0) + * printf("Hello Clang compiler 5.x\n"); + * #endif + * @endcode + * + * @see LONGBOW_CLANG_EXACTLY + */ +#ifdef __clang__ +# define LONGBOW_CLANG_ATLEAST(major, minor, patch) \ + (__clang_major__ >= major) && (__clang_major__ > minor) && (__clang_patchlevel__ >= patch) +#else +# define LONGBOW_CLANG_ATLEAST(major, minor, patch) \ + (0) +#endif + +/** + * @def LONGBOW_START_DEPRECATED_WARNINGS + * + * Compile-time preprocessing to signal the compiler to not report the use of deprecated functions. + * + * Example: + * @code + * LONGBOW_STOP_DEPRECATED_WARNINGS + * someDeprecatedFunction(); + * @endcode + * + * @see LONBOW_STOP_DEPRECATED_WARNINGS + */ + +/** + * @def LONGBOW_STOP_DEPRECATED_WARNINGS + * + * Compile-time preprocessing to signal the compiler to report the use of deprecated functions. + * + * Example: + * @code + * LONGBOW_STOP_DEPRECATED_WARNINGS + * someDeprecatedFunction(); + * @endcode + * + * @see LONBOW_START_DEPRECATED_WARNINGS + */ +#if LONGBOW_CLANG_ATLEAST(5, 0, 0) || LONGBOW_GNUC_ATLEAST(4, 6, 0) +# define LONGBOW_STOP_DEPRECATED_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") + +# define LONGBOW_START_DEPRECATED_WARNINGS \ + _Pragma("GCC diagnostic pop") + +#elif __clang__ || __GNUC__ + +# define LONGBOW_STOP_DEPRECATED_WARNINGS \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") + +# define LONGBOW_START_DEPRECATED_WARNINGS \ + _Pragma("GCC diagnostic warning \"-Wdeprecated-declarations\"") + +#else + +# define LONGBOW_STOP_DEPRECATED_WARNINGS /* nothing */ + +# define LONGBOW_START_DEPRECATED_WARNINGS /* nothing */ +#endif + +/** + * @def LongBowCompiler_IgnoreInitializerOverrides + * + * Compile-time preprocessing to signal the compiler to not report the use of structure initializer overrides. + * + * Example: + * @code + * LongBowCompiler_IgnoreInitializerOverrides + * struct foo { + * int a; + * } instance = { + * .a = 1, + * .a = 1 + * }; + * LongBowCompiler_WarnInitializerOverrides + * @endcode + * + * @see LongBowCompiler_WarnInitializerOverrides + */ +#if LONGBOW_CLANG_ATLEAST(5, 0, 0) +# define LongBowCompiler_IgnoreInitializerOverrides \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Winitializer-overrides\"") + +# define LongBowCompiler_WarnInitializerOverrides \ + _Pragma("GCC diagnostic pop") + +#elif LONGBOW_GNUC_ATLEAST(4, 6, 0) +# define LongBowCompiler_IgnoreInitializerOverrides \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Woverride-init\"") + +# define LongBowCompiler_WarnInitializerOverrides \ + _Pragma("GCC diagnostic pop") + +#elif __clang__ || __GNUC__ +# define LongBowCompiler_IgnoreInitializerOverrides \ + _Pragma("GCC diagnostic ignored \"-Woverride-init\"") + +# define LongBowCompiler_WarnInitializerOverrides \ + _Pragma("GCC diagnostic warning \"-Woverride-init\"") + +#else + +# define LongBowCompiler_IgnoreInitializerOverrides /* nothing */ + +# define LongBowCompiler_WarnInitializerOverrides /* nothing */ +#endif + +/** + * @def LONGBOW_STOPWARNINGS_UnusedVariable + * + * Compile-time preprocessing to signal the compiler to report unused variables. + * + * Example: + * @code + * LONGBOW_STOPWARNINGS_UnusedVariable + * void + * foo(int unusedVariable) + * { + * return; + * } + * LONGBOW_STARTWARNINGS_UnusedVariable + * @endcode + * + * @see LONGBOW_STARTWARNINGS_UnusedVariable + * + * @def LONGBOW_STARTWARNINGS_UnusedVariable + * + * Compile-time preprocessing to signal the compiler to report unused variables. + * + * Example: + * @code + * LONGBOW_STOPWARNINGS_UnusedVariable + * void + * foo(int unusedVariable) + * { + * return; + * } + * LONGBOW_STARTWARNINGS_UnusedVariable + * @endcode + * + * @see LONGBOW_STARTWARNINGS_UnusedVariable + */ +#if LONGBOW_CLANG_ATLEAST(5, 0, 0) +# define LONGBOW_STOPWARNINGS_UnusedVariable \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wunused-variable\"") +# define LONGBOW_STARTWARNINGS_UnusedVariable \ + _Pragma("GCC diagnostic pop") +#elif LONGBOW_GNUC_ATLEAST(4, 6, 0) +# define LONGBOW_STOPWARNINGS_UnusedVariable \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wunused-variable\"") +# define LONGBOW_STARTWARNINGS_UnusedVariable \ + _Pragma("GCC diagnostic pop") +#elif __clang__ || __GNUC__ +# define LONGBOW_STOPWARNINGS_UnusedVariable \ + _Pragma("GCC diagnostic ignored \"-Wunused-variable\"") +# define LONGBOW_STARTWARNINGS_UnusedVariable \ + _Pragma("GCC diagnostic warning \"-Wunused-variable\"") +#else + +# define LONGBOW_STOPWARNINGS_UnusedVariable /* nothing */ + +# define LONGBOW_STARTWARNINGS_UnusedVariable /* nothing */ +#endif + + +#endif // LongBow_compiling_h diff --git a/longbow/src/LongBow/longBow_Config.c b/longbow/src/LongBow/longBow_Config.c new file mode 100755 index 00000000..f650661f --- /dev/null +++ b/longbow/src/LongBow/longBow_Config.c @@ -0,0 +1,252 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> +#include <stdio.h> +#include <inttypes.h> + +#include <LongBow/private/longBow_ArrayList.h> +#include <LongBow/private/longBow_Memory.h> +#include <LongBow/private/longBow_String.h> + +#include <LongBow/longBow_Properties.h> + +#include <LongBow/longBow_Config.h> +#include <LongBow/Reporting/longBowReport_Runtime.h> +#include <LongBow/longBow_About.h> + +/** @cond private */ +struct longbow_configuration { + LongBowReportConfig *reportConfiguration; + LongBowProperties *properties; +}; +/** @endcond */ + +static void +_longBowConfig_SetupEnvironment(const LongBowConfig *config) +{ +} + +static void +_longBowConfig_Show(const LongBowConfig *configuration) +{ + char *string = longBowProperties_ToString(configuration->properties); + ssize_t nwritten = write(1, string, strlen(string)); + if (nwritten != strlen(string)) { + fprintf(stderr, "Failed to write to file descriptor 1.\n"); + exit(-1); + } + longBowMemory_Deallocate((void **) &string); +} + +static bool +_longBowConfig_Set(LongBowConfig *configuration, const char *expression) +{ + bool result = false; + + LongBowArrayList *tokens = longBowString_Tokenise(expression, "="); + if (tokens != NULL) { + if (longBowArrayList_Length(tokens) == 2) { + char *name = longBowArrayList_Get(tokens, 0); + char *value = longBowArrayList_Get(tokens, 1); + result = longBowConfig_SetProperty(configuration, name, value); + longBowArrayList_Destroy(&tokens); + } + } + + return result; +} + +LongBowConfig * +longBowConfig_Create(int argc, char *argv[], const char *mainFileName) +{ + LongBowConfig *result = longBowMemory_Allocate(sizeof(LongBowConfig)); + + result->properties = longBowProperties_Create(); + longBowProperties_Set(result->properties, "trace", "false"); + longBowProperties_Set(result->properties, "silent", "false"); + longBowProperties_Set(result->properties, "run-forked", "false"); + + for (int i = 1; i < argc; i++) { + if (longBowString_Equals("--help", argv[i]) || longBowString_Equals("-h", argv[i])) { + // If the option is "--help", + // then let all of the sub-systems that also take arguments process that option also. + printf("LongBow %s\n", longBowAbout_Version()); + printf("%s\n", longBowAbout_MiniNotice()); + printf("Options\n"); + //printf(" --main Print the name of the main test runner source file.\n"); + printf(" --help Print this help message.\n"); + printf(" --run-forked Run the tests as forked processes.\n"); + printf(" --run-nonforked Run the tests in the same process (default).\n"); + printf(" --version Print the version of LongBow used for this test.\n"); + printf(" --core-dump Produce a core file upon the first failed assertion.\n"); + printf(" --set name=value Set a configuration property name to the specified value\n"); + longBowTestRunner_ConfigHelp(); + longBowTestFixture_ConfigHelp(); + longBowTestCase_ConfigHelp(); + longBowReportRuntime_Create(argc, argv); + longBowConfig_Destroy(&result); + printf("\n"); + return NULL; + } else if (longBowString_Equals("--main", argv[i])) { + printf("%s\n", mainFileName); + longBowConfig_Destroy(&result); + return NULL; + } else if (longBowString_Equals("--version", argv[i])) { + printf("%s\n", longBowAbout_Version()); + longBowConfig_Destroy(&result); + return NULL; + } else if (longBowString_Equals("--run-nonforked", argv[i])) { + longBowProperties_Set(result->properties, "run-forked", "false"); + } else if (longBowString_Equals("--run-forked", argv[i])) { + printf("?\n"); + longBowProperties_Set(result->properties, "run-forked", "true"); + } else if (longBowString_Equals("--trace", argv[i])) { + longBowProperties_Set(result->properties, "trace", "true"); + } else if (longBowString_Equals("--silent", argv[i])) { + longBowProperties_Set(result->properties, "silent", "true"); + } else if (longBowString_Equals("--core-dump", argv[i])) { + longBowProperties_Set(result->properties, "core-dump", "true"); + } else if (longBowString_StartsWith(argv[i], "--set")) { + char *parameter = argv[++i]; + if (_longBowConfig_Set(result, parameter) == false) { + printf("Could not set parameter: %s\n", parameter); + } + } else if (longBowString_StartsWith(argv[i], "--show")) { + _longBowConfig_Show(result); + } else { + printf("Unknown option '%s'\n", argv[i]); + } + } + + LongBowReportConfig *reportConfiguration = longBowReportRuntime_Create(argc, argv); + + if (reportConfiguration == NULL) { + longBowConfig_Destroy(&result); + result = NULL; + } else { + if (result == NULL) { + // nothing to do. + } else { + result->reportConfiguration = reportConfiguration; + } + } + + if (result != NULL) { + _longBowConfig_SetupEnvironment(result); + } + return result; +} + +void +longBowConfig_Destroy(LongBowConfig **configPtr) +{ + LongBowConfig *config = *configPtr; + + if (config != NULL) { + if (config->reportConfiguration != NULL) { + longBowReportRuntime_Destroy(&config->reportConfiguration); + } + longBowProperties_Destroy(&config->properties); + longBowMemory_Deallocate((void **) configPtr); + } +} + +bool +longBowConfig_IsRunForked(const LongBowConfig *config) +{ + return longBowConfig_GetBoolean(config, false, "run-forked"); +} + +bool +longBowConfig_IsTrace(const LongBowConfig *config) +{ + return longBowConfig_GetBoolean(config, false, "trace"); +} + +static const char * +_longBowConfig_GetProperty(const LongBowConfig *config, const char *format, va_list ap) +{ + const char *result = NULL; + + char *propertyName; + if (vasprintf(&propertyName, format, ap) != -1) { + if (config != NULL && config->properties != NULL) { + result = longBowProperties_Get(config->properties, propertyName); + } + free(propertyName); + } + + return result; +} + +const char * +longBowConfig_GetProperty(const LongBowConfig *config, const char *format, ...) +{ + const char *result = NULL; + + if (config != NULL && config->properties != NULL) { + va_list ap; + va_start(ap, format); + result = _longBowConfig_GetProperty(config, format, ap); + va_end(ap); + } + + return result; +} + +bool +longBowConfig_SetProperty(const LongBowConfig *config, const char *name, const char *value) +{ + bool result = false; + + if (config != NULL && config->properties != NULL) { + result = longBowProperties_Set(config->properties, name, value); + } + + return result; +} + +bool +longBowConfig_GetBoolean(const LongBowConfig *config, bool defaultValue, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + const char *value = _longBowConfig_GetProperty(config, format, ap); + va_end(ap); + + bool result = defaultValue; + if (value != NULL) { + result = (strcasecmp(value, "true") == 0); + } + return result; +} + +uint32_t +longBowConfig_GetUint32(const LongBowConfig *config, uint32_t defaultValue, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + const char *value = _longBowConfig_GetProperty(config, format, ap); + va_end(ap); + + uint32_t result = defaultValue; + if (value != NULL) { + result = (uint32_t) strtoul(value, NULL, 10); + } + return result; +} diff --git a/longbow/src/LongBow/longBow_Config.h b/longbow/src/LongBow/longBow_Config.h new file mode 100755 index 00000000..003497b4 --- /dev/null +++ b/longbow/src/LongBow/longBow_Config.h @@ -0,0 +1,126 @@ +/* + * 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 longBow_Config.h + * @ingroup internals + * @brief Support for LongBow Configuration + * + */ +#ifndef LONGBOWCONFIGURATION_H_ +#define LONGBOWCONFIGURATION_H_ +#include <stdbool.h> +#include <stdint.h> + +struct longbow_configuration; + +/** + * @typedef LongBowConfig + * @brief The LongBow Configuration + */ +typedef struct longbow_configuration LongBowConfig; + +/** + * Destroy a LongBowConfig instance. + * + * @param [in,out] configPtr A pointer to a LongBowConfig instance pointer. + */ +void longBowConfig_Destroy(LongBowConfig **configPtr); + +/** + * Create a LongBowConfig structure instance from the given array of parameters. + * + * The function parses argv style arguments and composes a LongBowConfig structure. + * + * The argv-style arguments may include parameters not related to creating a LongBowConfig structure. + * + * For example, the arguments may only be `--help` and prints a help message but doesn't create a `LongBowConfig` structure. + * + * @param [in] argc The number of elements in the `argv` array. + * @param [in] argv An array of nul-terminated C strings. + * @param [in] mainFileName The string printed for the `--main` option. + * + * @return non-NULL A LongBowConfig structure instance suitable for running a test + * @return NULL Nothing suitable for running a test (not an error). + */ +LongBowConfig *longBowConfig_Create(int argc, char *argv[], const char *mainFileName); + +/** + * Get a property stored in the configuration. + * @param [in] config A pointer to a valid LongBowConfig instance. + * @param [in] format A pointer to a valid, nul-terminated format string. + * + * @return non-NULL A pointer to nul-terminated, C string. + */ +const char *longBowConfig_GetProperty(const LongBowConfig *config, const char *format, ...); + +/** + * Set the property @p name to @p value + * + * @param [in] config A pointer to a valid LongBowConfig instance. + * + * @return true + * @return true + */ +bool longBowConfig_SetProperty(const LongBowConfig *config, const char *name, const char *value); + +/** + * Get the property @p name interpreted as a 32-bit integer. + * + * @param [in] config A pointer to a valid LongBowConfig instance. + * + * @return The property @p name interpreted as a 32-bit integer. + */ +uint32_t longBowConfig_GetUint32(const LongBowConfig *config, uint32_t defaultValue, const char *format, ...); + +/** + * Get the value of the configuration property named by the formatted property name. + * If the given LongBowConfig instance is not available, or the property is not present, the default value is returned. + * + * @param [in] config A pointer to a valid LongBowConfig instance. + * @param [in] defaultValue Either true or false. + * @param [in] format A printf format string followed by appropriate parameters used to construct the property name. + * + * @return true The property was present with the value true, or the property was not present and the default value is true. + * @return false The property was present with the value false, or the property was not present and the default value is false. + */ +bool longBowConfig_GetBoolean(const LongBowConfig *config, bool defaultValue, const char *format, ...); + +/** + * Return `true` if the given `LongBowConfig` instance specifies that test cases are to be run in a sub-process. + * + * @param [in] config A pointer to a valid LongBowConfig instance. + * @return true if the given specification stipulates tests are to run in a sub-process. + */ +bool longBowConfig_IsRunForked(const LongBowConfig *config); + +/** + * Indicate if the given configuration is specifying the 'trace' flag. + * + * @param [in] config A pointer to a valid LongBowConfig instance. + * + * @return true The given configuration is specifying the 'trace' flag. + * @return false The given configuration is not specifying the 'trace' flag. + * + * Example: + * @code + * if (longBowConfig_IsTrace(longBowRunner_GetConfiguration(testRunner)) { + * longBowTrace_Report(testRunner->configuration); + * } + * @endcode + */ +bool longBowConfig_IsTrace(const LongBowConfig *config); + +#endif // LONGBOWCONFIGURATION_H_ diff --git a/longbow/src/LongBow/longBow_Debug.c b/longbow/src/LongBow/longBow_Debug.c new file mode 100755 index 00000000..6a72603f --- /dev/null +++ b/longbow/src/LongBow/longBow_Debug.c @@ -0,0 +1,140 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <sys/stat.h> +#include <fcntl.h> +#include <ctype.h> +#include <string.h> +#include <stdio.h> + +#include <LongBow/longBow_Debug.h> +#include <LongBow/Reporting/longBowReport_Runtime.h> + +/** @cond */ +struct longbow_debug_criteria { + bool enabled; +}; +/** @endcond */ + +static struct longbow_debug_criteria LongBowDebug_StaticCriteria = { + .enabled = true +}; + +static LongBowDebugCriteria *LongBowDebug_CurrentCriteria = &LongBowDebug_StaticCriteria; + +LongBowDebugCriteria * +longBowDebug_CurrentCriteria(void) +{ + return LongBowDebug_CurrentCriteria; +} + +static void +_longBowDebug_MemoryDumpLine(const char *memory, size_t offset, size_t length) +{ + int bytesPerLine = 16; + char accumulator[bytesPerLine + 1]; + memset(accumulator, ' ', bytesPerLine); + accumulator[bytesPerLine] = 0; + + printf("%5zd: ", offset); + + for (size_t i = 0; i < bytesPerLine; i++) { + if (offset + i >= length) { + printf(" "); + accumulator[i] = ' '; + } else { + char c = memory[offset + i]; + printf("%02x ", c & 0xFF); + if (isprint(c)) { + accumulator[i] = c; + } else { + accumulator[i] = '.'; + } + } + } + printf(" %s\n", accumulator); +} + +void +longBowDebug_MemoryDump(const char *memory, size_t length) +{ + size_t bytesPerLine = 16; + + for (size_t offset = 0; offset < length; offset += bytesPerLine) { + _longBowDebug_MemoryDumpLine(memory, offset, length); + } +} + +void +longBowDebug_Message(LongBowDebugCriteria *criteria, const LongBowLocation *location, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + + char *message; + int status = vasprintf(&message, format, ap); + va_end(ap); + if (status != -1) { +#if 1 + char *locationString = longBowLocation_ToString(location); + longBowReportRuntime_Message("%s %s\r\n", locationString, message); + + free(locationString); +#else + longBowReportRuntime_Message(location, message); +#endif + free(message); + } +} + +ssize_t +longBowDebug_WriteFile(const char *fileName, const char *data, size_t length) +{ + ssize_t result = 0; + + int fd = open(fileName, O_CREAT | O_TRUNC | O_WRONLY, 0600); + if (fd == -1) { + perror(fileName); + } else { + result = write(fd, data, length); + } + close(fd); + return result; +} + +ssize_t +longBowDebug_ReadFile(const char *fileName, char **data) +{ + ssize_t result = -1; + struct stat statbuf; + char *buffer; + + int fd = open(fileName, O_RDONLY); + if (fd == -1) { + perror(fileName); + } else { + if (fstat(fd, &statbuf) != -1) { + buffer = malloc((unsigned long) statbuf.st_size + 1); + result = read(fd, buffer, (unsigned long) statbuf.st_size); + buffer[statbuf.st_size] = 0; + *data = buffer; + } + } + return result; +} diff --git a/longbow/src/LongBow/longBow_Debug.h b/longbow/src/LongBow/longBow_Debug.h new file mode 100755 index 00000000..f92df876 --- /dev/null +++ b/longbow/src/LongBow/longBow_Debug.h @@ -0,0 +1,98 @@ +/* + * 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 longBow_Debug.h + * @ingroup internals + * @brief Support for LongBow and Application Debugging. + * + */ +#ifndef LongBow_longBow_Debug_h +#define LongBow_longBow_Debug_h + +#include <stdint.h> +#include <string.h> +#include <sys/types.h> + +#include <LongBow/longBow_Location.h> + +typedef struct longbow_debug_criteria LongBowDebugCriteria; + +/** + * Pretty print memory on standard output. + * + * @param [in] memory A pointer to memory. + * @param [in] length The number of bytes to display. + */ +void longBowDebug_MemoryDump(const char *memory, size_t length); + +/** + * Generate and send a message to the specified location. + * + * @param [in] criteria Debug criteria. + * @param [in] location The location to which the message is sent. + * @param [in] format The format string for the message. + * @param [in] ... Remaining arguments for the message string. + */ +void longBowDebug_Message(LongBowDebugCriteria *criteria, const LongBowLocation *location, const char *format, ...); + +/** + * Write data in an array to a file. + * + * Data is written to the specified file from the supplied array. + * + * @param [in] fileName The name of the to write to. + * @param [in] data A pointer to an array of bytes to write. + * @param [in] length The number of bytes to write. + * + * @return The number of bytes written. + * + * Example: + * @code + * { + * size_t numBytesWritten = longBowDebug_WriteFile("log.out", "error", 6); + * } + * @endcode + * + * @see longBowDebug_ReadFile + */ +ssize_t longBowDebug_WriteFile(const char *fileName, const char *data, size_t length); + +/** + * Read data from a file into an allocated array. + * + * Data is read from the specified file into an allocated byte array which must be deallocated by the caller via {stdlib free()}. + * + * For convenience the allocate buffer exceeds the size of the file by one byte, which is set to zero. + * This permits using the result directly as a nul-terminated C string. + * + * @param [in] fileName The name of the file to read from. + * @param [in] data A pointer to a character pointer that will be updated with the address of the read data. + * + * @return The number of bytes read, or -1 if there was an error. + * + * Example: + * @code + * { + * char *buffer = NULL; + * size_t numBytesRead = longBowDebug_ReadFile("log.out", &buffer); + * // use buffer as needed + * } + * @endcode + * + * @see longBowDebug_WriteFile + */ +ssize_t longBowDebug_ReadFile(const char *fileName, char **data); +#endif diff --git a/longbow/src/LongBow/longBow_Event.c b/longbow/src/LongBow/longBow_Event.c new file mode 100755 index 00000000..a24d45bf --- /dev/null +++ b/longbow/src/LongBow/longBow_Event.c @@ -0,0 +1,122 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <LongBow/longBow_Event.h> +#include <LongBow/longBow_EventType.h> +#include <LongBow/longBow_Backtrace.h> +#include <LongBow/longBow_Location.h> +#include <LongBow/longBow_Status.h> +#include <LongBow/private/longBow_Memory.h> + +/** @cond private */ +struct longbow_event { + const LongBowEventType *type; + const LongBowLocation *location; + const char *kind; + const char *message; + const LongBowBacktrace *backtrace; +}; +/** @endcond */ + +const char * +longBowEvent_GetName(const LongBowEvent *event) +{ + return longBowEventType_GetName(event->type); +} + +LongBowEvent * +longBowEvent_Create(const LongBowEventType *eventType, const LongBowLocation *location, const char *kind, const char *message, const LongBowBacktrace *backtrace) +{ + LongBowEvent *result = longBowMemory_Allocate(sizeof(LongBowEvent)); + if (result != NULL) { + result->type = eventType; + result->location = location; + result->kind = kind; + result->message = strndup(message, strlen(message)); + result->backtrace = backtrace; + } + + return result; +} + +void +longBowEvent_Destroy(LongBowEvent **assertionPtr) +{ + LongBowEvent *assertion = *assertionPtr; + + if (assertion->location != NULL) { + longBowLocation_Destroy((LongBowLocation **) &assertion->location); + } + if (assertion->message != NULL) { + free((void *) assertion->message); + } + + if (assertion->backtrace != NULL) { + longBowBacktrace_Destroy((LongBowBacktrace **) &assertion->backtrace); + } + longBowMemory_Deallocate((void **) assertionPtr); +} + +const LongBowLocation * +longBowEvent_GetLocation(const LongBowEvent *event) +{ + return event->location; +} + +const LongBowEventType * +longBowEvent_GetEventType(const LongBowEvent *event) +{ + return event->type; +} + +const char * +longBowEvent_GetKind(const LongBowEvent *event) +{ + return event->kind; +} + +const char * +longBowEvent_GetMessage(const LongBowEvent *event) +{ + return event->message; +} + +const LongBowBacktrace * +longBowEvent_GetBacktrace(const LongBowEvent *event) +{ + return event->backtrace; +} + +char ** +longBowEvent_CreateSymbolicCallstack(const LongBowEvent *event) +{ + char **result = longBowBacktrace_Symbols(event->backtrace); + + return result; +} + +size_t +longBowEvent_GetCallStackLength(const LongBowEvent *event) +{ + return longBowBacktrace_GetFrameCount(event->backtrace); +} diff --git a/longbow/src/LongBow/longBow_Event.h b/longbow/src/LongBow/longBow_Event.h new file mode 100755 index 00000000..12f903c0 --- /dev/null +++ b/longbow/src/LongBow/longBow_Event.h @@ -0,0 +1,152 @@ +/* + * 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 longBow_Event.h + * @ingroup internals + * @brief LongBow Event Support. + * + * LongBow assertions, traps and tests induce "events" which are experienced by the programme runtime as signals or long-jumps. + * + */ +#ifndef LongBow_longBow_Event_h +#define LongBow_longBow_Event_h + +#include <stdlib.h> +#include <stdbool.h> + +#include <LongBow/longBow_EventType.h> +#include <LongBow/longBow_Location.h> +#include <LongBow/longBow_Backtrace.h> + +struct longbow_event; + +/** + * @typedef LongBowEvent + */ +typedef struct longbow_event LongBowEvent; + +/** + * Get the `LongBowEventType` of a LongBowEvent. + * + * @param [in] event A `LongBowEvent` instance. + * + * @return A pointer to the LongBowEventType of the event. + * + * Example: + * @code + * { + * LongBowEvent *event = ... + * LongBowEventType type = longBowEvent_GetEventType(event); + * } + * @endcode + */ +const LongBowEventType *longBowEvent_GetEventType(const LongBowEvent *event); + +/** + * Create a `LongBowEvent`. + * + * Creating a `LongBowEvent` records runtime data and used by report facilities. + * This does not actually cause the process to assert the assertion. + * + * @param [in] eventType The LongBowEventType for this event. + * @param [in] location A LongBowLocation instance recording the location of the event. + * @param [in] kind A string representing the kind of event. + * @param [in] message A message to display. This will be freed via free(3). + * @param [in] backtrace A pointer to a valid LongBowBacktrace instance. + * + * @return An allocated LongBowEvent which must be destroyed via `longBowEvent_Destroy()`. + */ +LongBowEvent *longBowEvent_Create(const LongBowEventType *eventType, const LongBowLocation *location, const char *kind, const char *message, const LongBowBacktrace *backtrace); + +/** + * Destroy a `LongBowEvent`. + * + * The value pointed to by `eventPtr`, is set to `NULL. + * + * @param [in,out] eventPtr The `LongBowEvent` instance to destroy and NULLify. + */ +void longBowEvent_Destroy(LongBowEvent **eventPtr); + +/** + * Get the `LongBowLocation` associated with this `LongBowEvent` instance. + * + * @param [in] event A `LongBowEvent` instance. + * + * @return A pointer to the `LongBowLocation` instance for the given `LongBowEvent`. + */ +const LongBowLocation *longBowEvent_GetLocation(const LongBowEvent *event); + +/** + * Get the name. + * + * @param [in] event A `LongBowEvent` instance. + * + * @return The name of the given LongBowEvent. + */ +const char *longBowEvent_GetName(const LongBowEvent *event); + +/** + * Get a pointer to the string representing the kind of this event. + * + * Currently the kind is only a static string set when creating a `LongBowEvent`. + * + * @param [in] event A pointer to a `LongBowEvent` instance. + * + * @return non-NULL The pointer to the string representing the kind of this event. + * @return NULL The kind was not set. + * + * @see longBowEvent_Create + */ +const char *longBowEvent_GetKind(const LongBowEvent *event); + +/** + * Retrieve the message associated with this `LongBowEvent` instance. + * + * @param [in] event A `LongBowEvent` instance. + * + * @return The message associated with the given `LongBowEvent`. + */ +const char *longBowEvent_GetMessage(const LongBowEvent *event); + +/** + * Get the `LongBowBacktrace` instance for the given `LongBowEvent` instance. + * + * @param [in] event A pointer to a valid LongBowEvent instance. + * + * @return A pointer to a LongBowBacktrace instance. + */ +const LongBowBacktrace *longBowEvent_GetBacktrace(const LongBowEvent *event); + +/** + * Get an array of nul-terminated C strings containing the symbolic representation of the given `LongBowEvent` stack backtrace. + * The length of the array is provided by `longBowEvent_GetCallStackLength` + * + * @param [in] event A pointer to a valid `LongBowEvent` instance. + * + * @return non-NULL An array of nul-terminated C strings + * @see longBowEvent_GetCallStackLength + */ +char **longBowEvent_CreateSymbolicCallstack(const LongBowEvent *event); + +/** + * Retrieve the call stack length associated with this `LongBowEvent` instance. + * + * @param [in] event A `LongBowEvent` instance. + * + * @return The length of the call stack. + */ +size_t longBowEvent_GetCallStackLength(const LongBowEvent *event); +#endif // LongBow_longBow_Event_h diff --git a/longbow/src/LongBow/longBow_EventType.c b/longbow/src/LongBow/longBow_EventType.c new file mode 100755 index 00000000..7a99b0c3 --- /dev/null +++ b/longbow/src/LongBow/longBow_EventType.c @@ -0,0 +1,224 @@ +/* + * 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. + */ + +/** + * + */ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <signal.h> + +#include <LongBow/longBow_Status.h> +#include <LongBow/longBow_EventType.h> + +/** @cond private */ +struct longbow_event_type { + const char *kind; + const char *name; + LongBowStatus statusCode; + bool suppressBacktrace; + bool suppressAlert; +}; +/** @endcond */ + +#define _eventType(_kind, _name, _code, _suppressBacktrace, _suppressAlert) { \ + .kind = _kind, \ + .name = _name, \ + .statusCode = _code, \ + .suppressBacktrace = _suppressBacktrace, \ + .suppressAlert = _suppressAlert \ +} + +LongBowEventType LongBowAssertEvent = _eventType("Assert", "Assert", LONGBOW_STATUS_FAILED, false, false); + +LongBowEventType LongBowTrapEvent = _eventType("Trap", "Trap", LONGBOW_STATUS_FAILED, false, false); + +LongBowEventType LongBowTrapOutOfBounds = _eventType("Trap", "OutOfBounds", LONGBOW_STATUS_FAILED, false, false); + +LongBowEventType LongBowTrapIllegalValue = _eventType("Trap", "IllegalValue", LONGBOW_STATUS_FAILED, false, false); + +LongBowEventType LongBowTrapInvalidValue = _eventType("Trap", "InvalidValue", LONGBOW_STATUS_FAILED, false, false); + +LongBowEventType LongBowTrapUnrecoverableState = _eventType("Trap", "UnrecoverableState", LONGBOW_STATUS_FAILED, false, false); + +LongBowEventType LongBowTrapNotImplemented = _eventType("Trap", "Implemented", LONGBOW_STATUS_FAILED, false, false); + +LongBowEventType LongBowTrapOutOfMemoryEvent = _eventType("Trap", "Out of Memory", LONGBOW_STATUS_FAILED, false, false); + +LongBowEventType LongBowTrapCannotObtainLockEvent = _eventType("Trap", "Cannot obtain lock", LONGBOW_STATUS_FAILED, false, false); + +LongBowEventType LongBowTrapUnexpectedStateEvent = _eventType("Trap", "Unexpected State", LONGBOW_STATUS_FAILED, false, false); + +LongBowEventType LongBowTestSkippedEvent = _eventType("Test", "Skipped", LONGBOW_STATUS_SKIPPED, true, false); + +LongBowEventType LongBowTestUnimplementedEvent = _eventType("Test", "Unimplemented", LongBowStatus_UNIMPLEMENTED, true, true); + +LongBowEventType LongBowEventSIGHUP = _eventType("Signal", "SIGHUP", LongBowStatus_SIGNAL(SIGHUP), false, false); + +LongBowEventType LongBowEventSIGINT = _eventType("Signal", "SIGINT", LongBowStatus_SIGNAL(SIGINT), false, false); + +LongBowEventType LongBowEventSIGQUIT = _eventType("Signal", "SIGQUIT", LongBowStatus_SIGNAL(SIGQUIT), false, false); + +LongBowEventType LongBowEventSIGILL = _eventType("Signal", "SIGILL", LongBowStatus_SIGNAL(SIGILL), false, false); + +LongBowEventType LongBowEventSIGTRAP = _eventType("Signal", "SIGTRAP", LongBowStatus_SIGNAL(SIGTRAP), false, false); + +LongBowEventType LongBowEventSIGABRT = _eventType("Signal", "SIGABRT", LongBowStatus_SIGNAL(SIGABRT), false, false); + +#ifdef _DARWIN_C_SOURCE +LongBowEventType LongBowEventSIGEMT = _eventType("Signal", "SIGEMT", LongBowStatus_SIGNAL(SIGEMT), false, false); +#else +LongBowEventType LongBowEventSIGEMT = _eventType("Signal", "SIGBUS", LongBowStatus_SIGNAL(SIGBUS), false, false); +#endif + +LongBowEventType LongBowEventSIGFPE = _eventType("Signal", "SIGFPE", LongBowStatus_SIGNAL(SIGFPE), false, false); + +LongBowEventType LongBowEventSIGKILL = _eventType("Signal", "SIGKILL", LongBowStatus_SIGNAL(SIGKILL), false, false); + +LongBowEventType LongBowEventSIGBUS = _eventType("Signal", "SIGBUS", LongBowStatus_SIGNAL(SIGBUS), false, false); + +LongBowEventType LongBowEventSIGSEGV = _eventType("Signal", "SIGSEGV", LongBowStatus_SIGNAL(SIGSEGV), false, false); + +LongBowEventType LongBowEventSIGSYS = _eventType("Signal", "SIGSYS", LongBowStatus_SIGNAL(SIGSYS), false, false); + +LongBowEventType LongBowEventSIGPIPE = _eventType("Signal", "SIGPIPE", LongBowStatus_SIGNAL(SIGPIPE), false, false); + +LongBowEventType LongBowEventSIGALRM = _eventType("Signal", "SIGALRM", LongBowStatus_SIGNAL(SIGALRM), false, false); + +LongBowEventType LongBowEventSIGTERM = _eventType("Signal", "SIGTERM", LongBowStatus_SIGNAL(SIGTERM), false, false); + +LongBowEventType LongBowEventSIGURG = _eventType("Signal", "SIGURG", LongBowStatus_SIGNAL(SIGURG), false, false); + +LongBowEventType LongBowEventSIGSTOP = _eventType("Signal", "SIGSTOP", LongBowStatus_SIGNAL(SIGSTOP), false, false); + +LongBowEventType LongBowEventSIGTSTP = _eventType("Signal", "SIGTSTP", LongBowStatus_SIGNAL(SIGTSTP), false, false); + +LongBowEventType LongBowEventSIGCONT = _eventType("Signal", "SIGCONT", LongBowStatus_SIGNAL(SIGCONT), false, false); + +LongBowEventType LongBowEventSIGCHLD = _eventType("Signal", "SIGCHLD", LongBowStatus_SIGNAL(SIGCHLD), false, false); + +LongBowEventType LongBowEventSIGTTIN = _eventType("Signal", "SIGTTIN", LongBowStatus_SIGNAL(SIGTTIN), false, false); + +LongBowEventType LongBowEventSIGTTOU = _eventType("Signal", "SIGTTOU", LongBowStatus_SIGNAL(SIGTTOU), false, false); + +LongBowEventType LongBowEventSIGIO = _eventType("Signal", "SIGIO", LongBowStatus_SIGNAL(SIGIO), false, false); + +LongBowEventType LongBowEventSIGXCPU = _eventType("Signal", "SIGXCPU", LongBowStatus_SIGNAL(SIGXCPU), false, false); + +LongBowEventType LongBowEventSIGXFSZ = _eventType("Signal", "SIGXFSZ", LongBowStatus_SIGNAL(SIGXFSZ), false, false); + +LongBowEventType LongBowEventSIGVTALRM = _eventType("Signal", "SIGVTALRM", LongBowStatus_SIGNAL(SIGVTALRM), false, false); + +LongBowEventType LongBowEventSIGPROF = _eventType("Signal", "SIGPROF", LongBowStatus_SIGNAL(SIGPROF), false, false); + +LongBowEventType LongBowEventSIGWINCH = _eventType("Signal", "SIGWINCH", LongBowStatus_SIGNAL(SIGWINCH), false, false); + +#if (!defined (_ANDROID_) && (!defined(_POSIX_C_SOURCE)) || defined(_DARWIN_C_SOURCE)) +LongBowEventType LongBowEventSIGINFO = _eventType("Signal", "SIGINFO", LongBowStatus_SIGNAL(SIGINFO), false, false); +#else +LongBowEventType LongBowEventSIGINFO = _eventType("Signal", "SIGIO", LongBowStatus_SIGNAL(SIGIO), false, false); +#endif + +LongBowEventType LongBowEventSIGUSR1 = _eventType("Signal", "SIGUSR1", LongBowStatus_SIGNAL(SIGUSR1), false, false); + +LongBowEventType LongBowEventSIGUSR2 = _eventType("Signal", "SIGUSR2", LongBowStatus_SIGNAL(SIGUSR2), false, false); + +LongBowEventType LongBowTestEvent = _eventType("Test", "Test", LongBowStatus_WARNED, false, false); + +static LongBowEventType *signalToEventType[NSIG] = { + NULL, + &LongBowEventSIGHUP /* 1 */, + &LongBowEventSIGINT /* 2 */, + &LongBowEventSIGQUIT /* 3 */, + &LongBowEventSIGILL /* 4 */, + &LongBowEventSIGTRAP /* 5 */, + &LongBowEventSIGABRT /* 6 */, + &LongBowEventSIGEMT /* 7 */, + &LongBowEventSIGFPE /* 8 */, + &LongBowEventSIGKILL /* 9 */, + &LongBowEventSIGBUS /* 10 */, + &LongBowEventSIGSEGV /* 11 */, + &LongBowEventSIGSYS /* 12 */, + &LongBowEventSIGPIPE /* 13 */, + &LongBowEventSIGALRM /* 14 */, + &LongBowEventSIGTERM /* 15 */, + &LongBowEventSIGURG /* 16 */, + &LongBowEventSIGSTOP /* 17 */, + &LongBowEventSIGTSTP /* 18 */, + &LongBowEventSIGCONT /* 19 */, + &LongBowEventSIGCHLD /* 20 */, + &LongBowEventSIGTTIN /* 21 */, + &LongBowEventSIGTTOU /* 22 */, + &LongBowEventSIGIO /* 23 */, + &LongBowEventSIGXCPU /* 24 */, + &LongBowEventSIGXFSZ /* 25 */, + &LongBowEventSIGVTALRM /* 26 */, + &LongBowEventSIGPROF /* 27 */, + &LongBowEventSIGWINCH /* 28 */, + &LongBowEventSIGINFO /* 29 */, + &LongBowEventSIGUSR1 /* 30 */, + &LongBowEventSIGUSR2 /* 31 */ +}; + +const char * +longBowEventType_GetName(const LongBowEventType *eventType) +{ + return eventType->name; +} + +LongBowStatus +longBowEventType_GetStatus(const LongBowEventType *eventType) +{ + return eventType->statusCode; +} + +bool +longBowEventType_IsSuppressBacktrace(const LongBowEventType *eventType) +{ + return eventType->suppressBacktrace; +} + +bool +longBowEventType_IsSuppressAlert(const LongBowEventType *eventType) +{ + return eventType->suppressAlert; +} + +bool +longBowEventType_Equals(const LongBowEventType *x, const LongBowEventType *y) +{ + if (x == y) { + return true; + } + if (x == NULL || y == NULL) { + return false; + } + + if (strcmp(x->name, y->name) == 0) { + return true; + } + return false; +} + +LongBowEventType * +longBowEventType_GetEventTypeForSignal(const int signal) +{ + return signalToEventType[signal]; +} + diff --git a/longbow/src/LongBow/longBow_EventType.h b/longbow/src/LongBow/longBow_EventType.h new file mode 100755 index 00000000..03774abd --- /dev/null +++ b/longbow/src/LongBow/longBow_EventType.h @@ -0,0 +1,409 @@ +/* + * 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 longBow_EventType.h + * @ingroup internals + * @ingroup runtime + * @ingroup testing + * @brief LongBow Events and Support. + * + */ +#ifndef LongBow_longBow_EventType_h +#define LongBow_longBow_EventType_h + +#include <LongBow/longBow_Status.h> + +struct longbow_event_type; +/** + * @typedef LongBowEventType + * + * A LongBowEventType identifies a specific Event induced or generated by a running programme. + */ +typedef struct longbow_event_type LongBowEventType; + +/** + * @var LongBowAssertEvent + */ +extern LongBowEventType LongBowAssertEvent; + +/** + * @var LongBowTestEvent + */ +extern LongBowEventType LongBowTestEvent; + +/** + * @var LongBowTestSkippedEvent + */ +extern LongBowEventType LongBowTestSkippedEvent; + +/** + * @var LongBowTestUnimplementedEvent + */ +extern LongBowEventType LongBowTestUnimplementedEvent; + +/** + * @var LongBowTrapOutOfMemoryEvent + */ +extern LongBowEventType LongBowTrapOutOfMemoryEvent; + +/** + * @var LongBowTrapUnexpectedStateEvent + */ +extern LongBowEventType LongBowTrapUnexpectedStateEvent; + +/** + * @var LongBowTrapEvent + */ +extern LongBowEventType LongBowTrapEvent; + +/** + * @var LongBowTrapOutOfBounds + */ +extern LongBowEventType LongBowTrapOutOfBounds; + +/** + * @var LongBowTrapIllegalValue + */ +extern LongBowEventType LongBowTrapIllegalValue; + +/** + * @var LongBowTrapInvalidValue + */ +extern LongBowEventType LongBowTrapInvalidValue; + +/** + * @var LongBowTrapUnrecoverableState + */ +extern LongBowEventType LongBowTrapUnrecoverableState; + +/** + * @var LongBowTrapNotImplemented + */ +extern LongBowEventType LongBowTrapNotImplemented; + +/** + * @var LongBowTrapCannotObtainLockEvent + */ +extern LongBowEventType LongBowTrapCannotObtainLockEvent; + +/** + * @var LongBowEventSIGHUP + */ +extern LongBowEventType LongBowEventSIGHUP; + +/** + * @var LongBowEventSIGINT + */ +extern LongBowEventType LongBowEventSIGINT; + +/** + * @var LongBowEventSIGQUIT + */ +extern LongBowEventType LongBowEventSIGQUIT; + +/** + * @var LongBowEventSIGILL + */ +extern LongBowEventType LongBowEventSIGILL; + +/** + * @var LongBowEventSIGTRAP + */ +extern LongBowEventType LongBowEventSIGTRAP; + +/** + * @var LongBowEventSIGABRT + */ +extern LongBowEventType LongBowEventSIGABRT; + +/** + * @var LongBowEventSIGIOT + */ +extern LongBowEventType LongBowEventSIGIOT; + +/** + * @var LongBowEventSIGEMT + */ +extern LongBowEventType LongBowEventSIGEMT; + +/** + * @var LongBowEventSIGFPE + */ +extern LongBowEventType LongBowEventSIGFPE; + +/** + * @var LongBowEventSIGKILL + */ +extern LongBowEventType LongBowEventSIGKILL; + +/** + * @var LongBowEventSIGBUS + */ +extern LongBowEventType LongBowEventSIGBUS; + +/** + * @var LongBowEventSIGSEGV + */ +extern LongBowEventType LongBowEventSIGSEGV; + +/** + * @var LongBowEventSIGSYS + */ +extern LongBowEventType LongBowEventSIGSYS; + +/** + * @var LongBowEventSIGPIPE + */ +extern LongBowEventType LongBowEventSIGPIPE; + +/** + * @var LongBowEventSIGALRM + */ +extern LongBowEventType LongBowEventSIGALRM; + +/** + * @var LongBowEventSIGTERM + */ +extern LongBowEventType LongBowEventSIGTERM; + +/** + * @var LongBowEventSIGURG + */ +extern LongBowEventType LongBowEventSIGURG; + +/** + * @var LongBowEventSIGSTOP + */ +extern LongBowEventType LongBowEventSIGSTOP; + +/** + * @var LongBowEventSIGTSTP + */ +extern LongBowEventType LongBowEventSIGTSTP; + +/** + * @var LongBowEventSIGCONT + */ +extern LongBowEventType LongBowEventSIGCONT; + +/** + * @var LongBowEventSIGCHLD + */ +extern LongBowEventType LongBowEventSIGCHLD; + +/** + * @var LongBowEventSIGTTIN + */ +extern LongBowEventType LongBowEventSIGTTIN; + +/** + * @var LongBowEventSIGTTOU + */ +extern LongBowEventType LongBowEventSIGTTOU; + +/** + * @var LongBowEventSIGIO + */ +extern LongBowEventType LongBowEventSIGIO; + +/** + * @var LongBowEventSIGXCPU + */ +extern LongBowEventType LongBowEventSIGXCPU; + +/** + * @var LongBowEventSIGXFSZ + */ +extern LongBowEventType LongBowEventSIGXFSZ; + +/** + * @var LongBowEventSIGVTALRM + */ +extern LongBowEventType LongBowEventSIGVTALRM; + +/** + * @var LongBowEventSIGPROF + */ +extern LongBowEventType LongBowEventSIGPROF; + +/** + * @var LongBowEventSIGWINCH + */ +extern LongBowEventType LongBowEventSIGWINCH; + +/** + * @var LongBowEventSIGINFO + */ +extern LongBowEventType LongBowEventSIGINFO; + +/** + * @var LongBowEventSIGUSR1 + */ +extern LongBowEventType LongBowEventSIGUSR1; + +/** + * @var LongBowEventSIGUSR2 + */ +extern LongBowEventType LongBowEventSIGUSR2; + +/** + * Determine if two `LongBowEventType` instances are equal. + * + * The following equivalence relations on non-null `LongBowEventType` instances are maintained: + * + * * It is reflexive: for any non-null reference value x, `longBowEventType_Equals(x, x)` must return true. + * + * * It is symmetric: for any non-null reference values x and y, `longBowEventType_Equals(x, y)` must return true if and only if + * `longBowEventType_Equals(y x)` returns true. + * + * * It is transitive: for any non-null reference values x, y, and z, if + * `longBowEventType_Equals(x, y)` returns true and + * `longBowEventType_Equals(y, z)` returns true, + * then `longBowEventType_Equals(x, z)` must return true. + * + * * It is consistent: for any non-null reference values x and y, multiple invocations of `longBowEventType_Equals(x, y)` + * consistently return true or consistently return false. + * + * * For any non-null reference value x, `longBowEventType_Equals(x, NULL)` must return false. + * + * + * @param [in] x A pointer to a `LongBowEventType` instance. + * @param [in] y A pointer to a `LongBowEventType` instance. + * + * @return true `LongBowEventType` x and y are equal. + * @return false `LongBowEventType` x and y are not equal. + * + * Example: + * @code + * { + * LongBowEventType *e1 = LongBowAssertEvent; + * LongBowEventType *e2 = LongBowAssertEvent; + * + * if (longBowEventType_Equals(bufferA, bufferB)) { + * printf("The events are equal.\n"); + * } else { + * printf("The events are NOT equal.\n"); + * } + * } + * @endcode + */ +bool longBowEventType_Equals(const LongBowEventType *x, const LongBowEventType *y); + +/** + * Produce a nul-terminated C string representation of this `LongBowEventType` instance. + * + * @param [in] eventType A pointer to a `LongBowEventType` instance. + * + * @return The C string name of the given LongBowEventType. + * + * Example: + * @code + * { + * LongBowEventType *event = LongBowAssertEvent; + * + * printf("Event = %s\n", longBowEventType_GetName(event)); + * } + * @endcode + */ +const char *longBowEventType_GetName(const LongBowEventType *eventType); + +/** + * Test if a `LongBowEventType` is specified to not report a stack backtrace. + * + * @param [in] eventType A pointer to a `LongBowEventType` instance. + * + * @return true if the LongBowEventType indicates that a backtrace report is not to be printed. + * + * Example: + * @code + * { + * LongBowEvent *event = ... + * + * if (longBowEventType_IsSuppressBacktrace(longBowEvent_GetEventType(event)) == false) { + * char **strs = longBowEvent_CreateSymbolicCallstack(event); + * if (strs != NULL) { + * for (size_t i = 0; i < longBowEvent_GetCallStackLength(event); ++i) { + * printf("%s\r\n", strs[i]); + * } + * free(strs); + * } + * } + * } + * @endcode + */ +bool longBowEventType_IsSuppressBacktrace(const LongBowEventType *eventType); + +/** + * Test if a LongBowEventType is specified to not report an alert. + * + * @param [in] eventType A pointer to a `LongBowEventType` instance. + * + * @return true if the LongBowEventType is specified to not report an alert. + * + * Example: + * @code + * { + * LongBowEvent *event = ... + * + * if (longBowEventType_IsSuppressAlert(longBowEvent_GetEventType(event)) == false) { + * char *location = longBowLocation_ToString(longBowEvent_GetLocation(event)); + * printf("%s %s %s %s\r\n", + * longBowEvent_GetName(event), location, longBowEvent_GetKind(event), longBowEvent_GetMessage(event)); + * + * ... + * } + * + * } + * @endcode + */ +bool longBowEventType_IsSuppressAlert(const LongBowEventType *eventType); + +/** + * Get the status of the specified `LongBowEventType` instance. + * + * @param [in] eventType A pointer to a `LongBowEventType` instance. + * + * @return The LongBowStatus associated with the given LongBowEventType. + * + * Example: + * @code + * { + * LongBowEvent *event = ... + * + * LongBowStatus status = longBowEventType_GetStatus(event); + * // use the status as needed + * } + * @endcode + */ +LongBowStatus longBowEventType_GetStatus(const LongBowEventType *eventType); + +/** + * Get the LongBowEventType corresponding to the given signal. + * + * @param [in] signal The signal to index. + * + * @return the LongBowEventType corresponding to the given signal. + * + * Example: + * @code + * { + * LongBowEventType *type = longBowEventType_GetEventTypeForSignal(1); + * // type is equal to LongBowEventSIGHUP + * } + * @endcode + */ +LongBowEventType *longBowEventType_GetEventTypeForSignal(const int signal); +#endif // LongBow_longBow_EventType_h diff --git a/longbow/src/LongBow/longBow_Location.c b/longbow/src/LongBow/longBow_Location.c new file mode 100755 index 00000000..3d58a11c --- /dev/null +++ b/longbow/src/LongBow/longBow_Location.c @@ -0,0 +1,88 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +#include <LongBow/longBow_Location.h> + +#include <LongBow/private/longBow_Memory.h> + +/** @cond private */ +struct longbow_location { + char *fileName; + char *functionName; + uint32_t lineNumber; +}; +/** @endcond */ + +LongBowLocation * +longBowLocation_Create(const char *fileName, const char *functionName, uint32_t lineNumber) +{ + LongBowLocation *result = longBowMemory_Allocate(sizeof(LongBowLocation)); + + if (result != NULL) { + result->fileName = (fileName == NULL) ? NULL : strdup(fileName); + result->functionName = (functionName == NULL) ? NULL : strdup(functionName); + result->lineNumber = lineNumber; + } + + return result; +} + +void +longBowLocation_Destroy(LongBowLocation **locationPtr) +{ + assert(locationPtr != NULL); + + LongBowLocation *location = *locationPtr; + + if (location->fileName != NULL) { + free(location->fileName); + } + if (location->functionName != NULL) { + free(location->functionName); + } + longBowMemory_Deallocate((void **) locationPtr); +} + +char * +longBowLocation_ToString(const LongBowLocation *location) +{ + assert(location != NULL); + + char *result; + + if (location->functionName == 0) { + int status = asprintf(&result, "%s:%u", location->fileName, location->lineNumber); + if (status == -1) { + return NULL; + } + } else { + int status = asprintf(&result, "%s:%u %s()", location->fileName, location->lineNumber, location->functionName); + if (status == -1) { + return NULL; + } + } + + return result; +} diff --git a/longbow/src/LongBow/longBow_Location.h b/longbow/src/LongBow/longBow_Location.h new file mode 100755 index 00000000..a1e271c3 --- /dev/null +++ b/longbow/src/LongBow/longBow_Location.h @@ -0,0 +1,88 @@ +/* + * 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 longBow_Location.h + * @ingroup internals + * @brief LongBow Source File Location + * + * LongBow records events during execution and insofar that it's possible, + * it records the source code location information for reporting. + * + */ +#ifndef LongBow_longBow_Location_h +#define LongBow_longBow_Location_h + +#include <stdint.h> + +struct longbow_location; +/** + * @typedef LongBowLocation + */ +typedef struct longbow_location LongBowLocation; + +/** + * Create a new LongBow location within a source code file. + * + * @param [in] fileName The file target of the location. + * @param [in] functionName The function target of the location. + * @param [in] lineNumber The exact line number within the target file. + * + * @return A pointer to an allocated LongBowLocation instance that must be deallocated via `longBowLocation_Destroy()`. + * + * Example: + * @code + * { + * LongBowLocation *location = longBowLocation_Create("test.c", "main", 101); + * } + * @endcode + */ +LongBowLocation *longBowLocation_Create(const char *fileName, const char *functionName, uint32_t lineNumber); + +/** + * Destroy the `LongBowLocation` instance. + * + * @param [in,out] locationPtr A pointer to the `LongBowLocation` instance to be destroyed. + * + * Example: + * @code + * { + * LongBowLocation *location = longBowLocation_Create("test.c", "main", 101); + * ... + * longBowLocation_Destroy(&location); + * } + * @endcode + */ +void longBowLocation_Destroy(LongBowLocation **locationPtr); + +/** + * Create a human readable representation of the `LongBowLocation` instance. + * + * @param [in] location The `LongBowLocation` instance from which to generate the string representation. + * + * @return An allocated, null-terminated C string that must be freed via free(). + * + * Example: + * @code + * { + * LongBowLocation *location = longBowLocation_Create("test.c", "main", 101); + * char *stringRep = longBowLocation_ToString(location); + * ... + * longBowLocation_Destroy(&location); + * } + * @endcode + */ +char *longBowLocation_ToString(const LongBowLocation *location); +#endif // LongBow_longBow_Location_h diff --git a/longbow/src/LongBow/longBow_Main.c b/longbow/src/LongBow/longBow_Main.c new file mode 100755 index 00000000..7b3e5c01 --- /dev/null +++ b/longbow/src/LongBow/longBow_Main.c @@ -0,0 +1,59 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <stdarg.h> + +#include <LongBow/longBow_Main.h> + +#include <LongBow/unit-test.h> +#include <LongBow/Reporting/longBowReport_Testing.h> +#include <LongBow/longBow_Config.h> + +int +longBowMain_Impl(int argc, char *argv[argc], ...) +{ + LongBowStatus exitStatus = LONGBOW_STATUS_SUCCEEDED; + + // Perform some processing on the input parameters. + + LongBowConfig *config = longBowConfig_Create(argc, argv, NULL); + if (config == NULL) { + return LONGBOW_STATUS_FAILED; + } + va_list ap; + va_start(ap, argv); + + for (LongBowTestRunner *testRunner = va_arg(ap, LongBowTestRunner *); testRunner != NULL; testRunner = va_arg(ap, LongBowTestRunner *)) { + if (testRunner != NULL) { + longBowTestRunner_SetConfiguration(testRunner, config); + longBowTestRunner_Run(testRunner); + longBowReportTesting_TestRunner(testRunner); + + if (!longBowTestRunner_IsSuccessful(testRunner)) { + exitStatus = longBowTestRunner_GetStatus(testRunner); + } + } + } + va_end(ap); + + longBowConfig_Destroy(&config); + + return (int) exitStatus; +} diff --git a/longbow/src/LongBow/longBow_Main.h b/longbow/src/LongBow/longBow_Main.h new file mode 100755 index 00000000..a3e35a8d --- /dev/null +++ b/longbow/src/LongBow/longBow_Main.h @@ -0,0 +1,52 @@ +/* + * 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 longBow_Main.h + * @ingroup testing + * @brief A main() function to run one or more LongBow Test Runners. + * + * The functions in this file provide execution time support for running LongBow Tests. + * + */ +#ifndef LONGBOWMAIN_H_ +#define LONGBOWMAIN_H_ + +/** + * Run one or more LongBow Test Runners. + * + * The encapsulating function creates one or more `LongBowTestRunner` instances and supplies + * these as a NULL terminated variable argument list to the longBowMain function. + * The return value from longBowMain is suitable as an exit status from an executable as zero is success. + * + * @param [in] argc The number of elements in argv. + * @param [in] argv An array of C string arguments. + * + * @return 0 All tests for all LongBowTestRunners were successful. Otherwise one of `LongBowStatus`. + * + * Example Usage: + * @code + * int + * main(int argc, char *argv[argc]) + * { + * LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(MyTestRunner); + * int exitStatus = longBowMain(argc, argv, testRunner, NULL); + * longBowTestRunner_Destroy(&testRunner); + * exit(exitStatus); + * } + * @endcode + */ +int longBowMain_Impl(int argc, char *argv[], ...); +#endif /* LONGBOWMAIN_H_ */ diff --git a/longbow/src/LongBow/longBow_MeasureTime.c b/longbow/src/LongBow/longBow_MeasureTime.c new file mode 100755 index 00000000..2fc566a5 --- /dev/null +++ b/longbow/src/LongBow/longBow_MeasureTime.c @@ -0,0 +1,96 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> +#include <stdio.h> +#include <sys/time.h> + +#include <LongBow/longBow_MeasureTime.h> +#include <LongBow/private/longBow_Memory.h> + +struct longBowMeasureTime { + struct timeval start; + struct timeval stop; + unsigned int iterations; +}; + +LongBowMeasureTime * +longBowMeasureTime_Start(unsigned int iterations) +{ + LongBowMeasureTime *result = longBowMemory_Allocate(sizeof(LongBowMeasureTime)); + + if (result != NULL) { + gettimeofday(&result->start, NULL); + result->iterations = iterations; + result->stop = (struct timeval) { .tv_sec = 0, .tv_usec = 0 }; + } + + return result; +} + +LongBowMeasureTime * +longBowMeasureTime_Stop(LongBowMeasureTime *measure) +{ + if (measure != NULL) { + gettimeofday(&measure->stop, NULL); + } + + return measure; +} + +uint64_t +longBowMeasureTime_GetMicroseconds(const LongBowMeasureTime *measure) +{ + struct timeval result; + timersub(&(measure->stop), &(measure->start), &result); + + return ((uint64_t) result.tv_sec * 1000000ULL) + ((uint64_t) result.tv_usec); +} + +uint64_t +longBowMeasureTime_GetNanoseconds(const LongBowMeasureTime *measure) +{ + struct timeval result; + timersub(&(measure->stop), &(measure->start), &result); + + return ((uint64_t) result.tv_sec * 1000000000ULL) + ((uint64_t) result.tv_usec * 1000); +} + +unsigned int +longBowMeasureTime_CountDown(LongBowMeasureTime *measure) +{ + return measure->iterations--; +} + +bool +longBowMeasureTime_Report(LongBowMeasureTime *measure, const char *file, const char *function, unsigned int line) +{ + struct timeval result; + if (measure->stop.tv_sec == 0 && measure->stop.tv_usec == 0) { + longBowMeasureTime_Stop(measure); + } + + timersub(&(measure->stop), &(measure->start), &result); + printf("%s %s %d %ld.%06ld\n", file, function, line, result.tv_sec, (long) result.tv_usec); + return true; +} + +void +longBowMeasureTime_Destroy(LongBowMeasureTime **instancePtr) +{ + longBowMemory_Deallocate((void **) instancePtr); +} diff --git a/longbow/src/LongBow/longBow_MeasureTime.h b/longbow/src/LongBow/longBow_MeasureTime.h new file mode 100644 index 00000000..5e2931e0 --- /dev/null +++ b/longbow/src/LongBow/longBow_MeasureTime.h @@ -0,0 +1,95 @@ +/* + * 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 longBow_MeasureTime.h + * + * Measure elapsed time, providing various fetching and reporting mechanisms. + * + */ +#ifndef __LongBow__longBow_Measure__ +#define __LongBow__longBow_Measure__ +#include <stdint.h> +#include <stdbool.h> + +#ifdef LongBow_DISABLE_MEASUREMENTS +# define longBowMeasureTime(_iterations_) +#else +# define longBowMeasureTime(_iterations_) for (LongBowMeasureTime *_measure = longBowMeasureTime_Start(_iterations_); \ + longBowMeasureTime_CountDown(_measure) ? true : (longBowMeasureTime_Report(_measure, __FILE__, __func__, __LINE__), longBowMeasureTime_Destroy(&_measure), false); ) + +#endif + +struct longBowMeasureTime; +typedef struct longBowMeasureTime LongBowMeasureTime; + +/** + * Create and start a `LongBowMeasureTime` instance. + * + * @param [in] iterations The number of iterations to perform when used with `longBowMeasureTime_CountDown` + * + * @return non-NULL A pointer to a valid LongBowMeasureTime instance that must be destroyed by `longBowMeasureTime_Destroy` + */ +LongBowMeasureTime *longBowMeasureTime_Start(unsigned int iterations); + +/** + * Report on the `LongBowMeasureTime` instance. + * + * @param [in] measure A pointer to a valid LongBowMeasureTime instance. + * @param [in] file A pointer to a nul-terminated C string representing the file name causing the report. + * @param [in] function A pointer to a nul-terminated C string representing the function name causing the report. + * @param [in] line An unsigned integer representing the line number of the file causing the report. + * + * @return true The report was successful. + */ +bool longBowMeasureTime_Report(LongBowMeasureTime *measure, const char *file, const char *function, unsigned int line); + +/** + * A simple count-down supporting measurement iterations. + * + * See {@link longBowMeasureTime} for an example. + * + * @param [in] measure A pointer to a valid LongBowMeasureTime instance. + * + * @return The current value of the counter. + */ +unsigned int longBowMeasureTime_CountDown(LongBowMeasureTime *measure); + +/** + * Get the total number of microseconds represented by the `LongBowMeasureTime` instance. + * + * @param [in] measure A pointer to a valid LongBowMeasureTime instance. + * + * @return The number of microseconds represented by the `LongBowMeasureTime` instance. + */ +uint64_t longBowMeasureTime_GetMicroseconds(const LongBowMeasureTime *measure); + +/** + * Get the total number of nanoseconds represented by the `LongBowMeasureTime` instance. + * + * @param [in] measure A pointer to a valid LongBowMeasureTime instance. + * + * @return The number of nanoseconds represented by the `LongBowMeasureTime` instance. + */ +uint64_t longBowMeasureTime_GetNanoseconds(const LongBowMeasureTime *measure); + +/** + * Destroy a valid `LongBowMeasureTime` instance. + * + * @param [in,out] instancePtr A pointer to a pointer to a valid LongBowMeasureTime instance, that will be set to zero. + */ +void longBowMeasureTime_Destroy(LongBowMeasureTime **instancePtr); + +#endif /* defined(__LongBow__longBow_Measure__) */ diff --git a/longbow/src/LongBow/longBow_Properties.c b/longbow/src/LongBow/longBow_Properties.c new file mode 100644 index 00000000..bf5a9da4 --- /dev/null +++ b/longbow/src/LongBow/longBow_Properties.c @@ -0,0 +1,153 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <string.h> + +#include <LongBow/private/longBow_String.h> +#include <LongBow/longBow_Properties.h> +#include <LongBow/private/longBow_ArrayList.h> +#include <LongBow/private/longBow_Memory.h> + +struct LongBowProperties { + LongBowArrayList *list; +}; + +typedef struct Property { + const char *name; + const char *value; +} _Property; + +static void +_property_Destroy(_Property **pointer) +{ + _Property *property = *pointer; + longBowMemory_Deallocate((void **) &property->name); + longBowMemory_Deallocate((void **) &property->value); + longBowMemory_Deallocate((void **) property); +} + +LongBowProperties * +longBowProperties_Create(void) +{ + LongBowProperties *result = longBowMemory_Allocate(sizeof(LongBowProperties)); + + if (result != NULL) { + result->list = longBowArrayList_Create((void (*)(void **))_property_Destroy); + } + + return result; +} + +static _Property * +_longBowProperties_Get(const LongBowProperties *properties, const char *name) +{ + _Property *result = NULL; + + for (size_t index = 0; index < longBowArrayList_Length(properties->list); index++) { + _Property *property = longBowArrayList_Get(properties->list, index); + if (strcmp(property->name, name) == 0) { + result = property; + break; + } + } + return result; +} + +const char * +longBowProperties_Get(const LongBowProperties *properties, const char *name) +{ + _Property *property = _longBowProperties_Get(properties, name); + + if (property != NULL) { + return property->value; + } + + return NULL; +} + +bool +longBowProperties_Set(LongBowProperties *properties, const char *name, const char *value) +{ + bool result = false; + + _Property *property = _longBowProperties_Get(properties, name); + if (property == NULL) { + property = longBowMemory_Allocate(sizeof(_Property)); + property->name = longBowMemory_StringCopy(name); + property->value = longBowMemory_StringCopy(value); + longBowArrayList_Add(properties->list, property); + result = true; + } else { + longBowMemory_Deallocate((void **) &property->value); + property->value = longBowMemory_StringCopy(value); + } + return result; +} + +bool +longBowProperties_Exists(const LongBowProperties *properties, const char *name) +{ + return (_longBowProperties_Get(properties, name) == NULL) ? false : true; +} + +bool +longBowProperties_Delete(LongBowProperties *properties, const char *name) +{ + bool result = false; + + for (size_t index = 0; index < longBowArrayList_Length(properties->list); index++) { + _Property *property = longBowArrayList_Get(properties->list, index); + if (strcmp(property->name, name) == 0) { + longBowArrayList_RemoveAtIndex(properties->list, index); + result = true; + } + } + + return result; +} + +size_t +longBowProperties_Length(const LongBowProperties *properties) +{ + return longBowArrayList_Length(properties->list); +} + +char * +longBowProperties_ToString(const LongBowProperties *properties) +{ + LongBowString *string = longBowString_Create(128); + + for (size_t index = 0; index < longBowArrayList_Length(properties->list); index++) { + _Property *property = longBowArrayList_Get(properties->list, index); + longBowString_Format(string, "%s=%s\n", property->name, property->value); + } + + char *result = longBowString_ToString(string); + longBowString_Destroy(&string); + + return result; +} + +void +longBowProperties_Destroy(LongBowProperties **propertiesPtr) +{ + LongBowProperties *properties = *propertiesPtr; + longBowArrayList_Destroy(&properties->list); + longBowMemory_Deallocate((void **) propertiesPtr); +} diff --git a/longbow/src/LongBow/longBow_Properties.h b/longbow/src/LongBow/longBow_Properties.h new file mode 100755 index 00000000..493ce00e --- /dev/null +++ b/longbow/src/LongBow/longBow_Properties.h @@ -0,0 +1,46 @@ +/* + * 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 longBow_Properties.h + * @brief A simple properties store. + * + */ +#ifndef __LongBow__longBow_Properties__ +#define __LongBow__longBow_Properties__ + +#include <stdbool.h> +#include <stdlib.h> + +struct LongBowProperties; +typedef struct LongBowProperties LongBowProperties; + +LongBowProperties *longBowProperties_Create(void); + +const char *longBowProperties_Get(const LongBowProperties *properties, const char *name); + +size_t longBowProperties_Length(const LongBowProperties *properties); + +bool longBowProperties_Set(LongBowProperties *properties, const char *name, const char *value); + +bool longBowProperties_Exists(const LongBowProperties *properties, const char *name); + +bool longBowProperties_Delete(LongBowProperties *properties, const char *name); + +void longBowProperties_Destroy(LongBowProperties **propertiesPtr); + +char *longBowProperties_ToString(const LongBowProperties *properties); + +#endif /* defined(__LongBow__longBow_Properties__) */ diff --git a/longbow/src/LongBow/longBow_Runtime.c b/longbow/src/LongBow/longBow_Runtime.c new file mode 100755 index 00000000..c283b743 --- /dev/null +++ b/longbow/src/LongBow/longBow_Runtime.c @@ -0,0 +1,268 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <stdint.h> +#include <signal.h> +#include <errno.h> + +#include <LongBow/longBow_Runtime.h> +#include <LongBow/longBow_Backtrace.h> +#include <LongBow/longBow_Location.h> +#include <LongBow/longBow_Event.h> +#include <LongBow/longBow_Config.h> + +#include <LongBow/Reporting/longBowReport_Runtime.h> + +#include <LongBow/private/longBow_Memory.h> + +static unsigned int longBowStackTraceDepth = 128; + +struct longbow_runtime { + LongBowConfig *config; + LongBowRuntimeResult expectedResult; + LongBowRuntimeResult actualResult; +}; + +static LongBowRuntime longBowRuntimeGlobal; + +static LongBowRuntime *longBowCurrentRuntime = &longBowRuntimeGlobal; + + +static char * +_longBowRuntime_FormatErrnoMessage(void) +{ + char *result = NULL; + if (errno != 0) { + if (asprintf(&result, "%s: ", strerror(errno)) == -1) { + return NULL; + } + } + return result; +} + +static char * +_longBowRuntime_FormatMessage(const char *format, va_list args) +{ + char *errnoMessage = _longBowRuntime_FormatErrnoMessage(); + + char *string; + if (vasprintf(&string, format, args) == -1) { + return NULL; + } + + char *result = NULL; + + if (errnoMessage != NULL) { + int check = asprintf(&result, "%s%s", errnoMessage, string); + free(errnoMessage); + if (check == -1) { + return NULL; + } + } else { + result = strndup(string, strlen(string)); + } + + free(string); + + return result; +} + +LongBowRuntime * +longBowRuntime_Create(const LongBowRuntimeResult *expectedResultTemplate, LongBowConfig *config) +{ + assert(expectedResultTemplate != NULL); + + LongBowRuntime *result = longBowMemory_Allocate(sizeof(LongBowRuntime)); + if (result != NULL) { + result->expectedResult = *expectedResultTemplate; + result->config = config; + } + return result; +} + +size_t +longBowRuntime_GetActualEventEvaluationCount(LongBowRuntime *runtime) +{ + return longBowRuntimeResult_GetEventEvaluationCount(longBowRuntime_GetActualTestCaseResult(runtime)); +} + +void +longBowRuntime_Destroy(LongBowRuntime **runtimePtr) +{ + longBowMemory_Deallocate((void **) runtimePtr); +} + +LongBowRuntimeResult * +longBowRuntime_GetExpectedTestCaseResult(const LongBowRuntime *const runtime) +{ + return (LongBowRuntimeResult *) &(runtime->expectedResult); +} + +LongBowRuntimeResult * +longBowRuntime_GetActualTestCaseResult(const LongBowRuntime *runtime) +{ + return (LongBowRuntimeResult *) &(runtime->actualResult); +} + +LongBowRuntime * +longBowRuntime_SetCurrentRuntime(LongBowRuntime *runtime) +{ + LongBowRuntime *result = longBowCurrentRuntime; + longBowCurrentRuntime = runtime; + return result; +} + +LongBowRuntime * +longBowRuntime_GetCurrentRuntime(void) +{ + return longBowCurrentRuntime; +} + +LongBowConfig * +longBowRuntime_GetCurrentConfig(void) +{ + return longBowCurrentRuntime->config; +} + +void +longBowRuntime_SetCurrentConfig(LongBowConfig *config) +{ + longBowCurrentRuntime->config = config; +} + +LongBowEventType * +longBowRuntime_GetActualEventType(const LongBowRuntime *runtime) +{ + return runtime->actualResult.event; +} + +LongBowEventType * +longBowRuntime_GetExpectedEventType(const LongBowRuntime *runtime) +{ + return runtime->expectedResult.event; +} + +void +longBowRuntime_SetActualEventType(LongBowRuntime *runtime, LongBowEventType *eventType) +{ + runtime->actualResult.event = eventType; +} + +bool +longBowRuntime_EventEvaluation(const LongBowEventType *type) +{ + longBowCurrentRuntime->actualResult.eventEvaluationCount++; + return true; +} + +unsigned int +longBowRuntime_SetStackTraceDepth(unsigned int newDepth) +{ + unsigned int previousValue = longBowStackTraceDepth; + longBowStackTraceDepth = newDepth; + return previousValue; +} + +unsigned int +longBowRuntime_GetStackTraceDepth(void) +{ + return longBowStackTraceDepth; +} + +bool +longBowRuntime_EventTrigger(LongBowEventType *eventType, LongBowLocation *location, const char *kind, const char *format, ...) +{ + LongBowRuntime *runtime = longBowRuntime_GetCurrentRuntime(); + + longBowRuntime_SetActualEventType(runtime, eventType); + + if (runtime->expectedResult.status == LONGBOW_STATUS_FAILED) { + return true; + } + + if (longBowEventType_Equals(longBowRuntime_GetActualEventType(runtime), longBowRuntime_GetExpectedEventType(runtime))) { + return true; + } + + va_list args; + va_start(args, format); + + char *messageString = _longBowRuntime_FormatMessage(format, args); + + va_end(args); + + LongBowBacktrace *stackTrace = longBowBacktrace_Create(longBowRuntime_GetStackTraceDepth(), 2); + + LongBowEvent *event = longBowEvent_Create(eventType, location, kind, messageString, stackTrace); + + free(messageString); + longBowReportRuntime_Event(event); + longBowEvent_Destroy(&event); + return true; +} + +void +longBowRuntime_StackTrace(int fileDescriptor) +{ + LongBowBacktrace *backtrace = longBowBacktrace_Create(longBowRuntime_GetStackTraceDepth(), 1); + char *string = longBowBacktrace_ToString(backtrace); + fwrite(string, strlen(string), 1, stdout); + longBowMemory_Deallocate((void **) &string); + longBowBacktrace_Destroy(&backtrace); +} + +bool +longBowRuntime_TestAddressIsAligned(const void *address, size_t alignment) +{ + if ((alignment & (~alignment + 1)) == alignment) { + return (((uintptr_t) address) % alignment) == 0 ? true : false; + } + return false; +} + +void +longBowRuntime_CoreDump(void) +{ + struct rlimit coreDumpLimit; + + coreDumpLimit.rlim_cur = RLIM_INFINITY; + coreDumpLimit.rlim_max = RLIM_INFINITY; + + if (setrlimit(RLIMIT_CORE, &coreDumpLimit) < 0) { + fprintf(stderr, "setrlimit: %s\n", strerror(errno)); + exit(1); + } + kill(0, SIGTRAP); +} + +void +longBowRuntime_Abort(void) +{ + bool coreDump = longBowConfig_GetBoolean(longBowRuntime_GetCurrentConfig(), false, "core-dump"); + if (coreDump == false) { + abort(); + } else { + longBowRuntime_CoreDump(); + } +} diff --git a/longbow/src/LongBow/longBow_Runtime.h b/longbow/src/LongBow/longBow_Runtime.h new file mode 100644 index 00000000..ff5527eb --- /dev/null +++ b/longbow/src/LongBow/longBow_Runtime.h @@ -0,0 +1,206 @@ +/* + * 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 longBow_Runtime.h + * @ingroup runtime + * @brief The LongBow Runtime support. + * + */ +#ifndef LongBow_longBow_Runtime_h +#define LongBow_longBow_Runtime_h + +#include <LongBow/longBow_Event.h> +#include <LongBow/longBow_RuntimeResult.h> +#include <LongBow/longBow_Config.h> + +struct longbow_runtime; +typedef struct longbow_runtime LongBowRuntime; + +/** + * Create and return a new `LongBowRuntime` instance with the specified `LongBowRuntimeResult` instance. + * + * @param [in] expectedResultTemplate A `LongBowRuntimeResult` instance. + * + * @return A pointer to an allocated LongBowRuntime instance that must be deallocated via longBowRuntime_Destroy + */ +LongBowRuntime *longBowRuntime_Create(const LongBowRuntimeResult *expectedResultTemplate, LongBowConfig *config); + +/** + * Destroy the `LongBowRuntime` instance. + * + * @param [in,out] runtimePtr A pointer to a `LongBowRuntime` instance. + */ +void longBowRuntime_Destroy(LongBowRuntime **runtimePtr); + +/** + * Get the expected test case result from the `LongBowRuntime` instance. + * + * @param [in] runtime A `LongBowRuntime` instance. + * + * @return A pointer to the expected LongBowRuntimeResult. + */ +LongBowRuntimeResult *longBowRuntime_GetExpectedTestCaseResult(const LongBowRuntime *runtime); + +/** + * Get the actual test case result from the `LongBowRuntime` instance. + * + * @param [in] runtime A `LongBowRuntime` instance. + * + * @return A pointer to the actual LongBowRuntimeResult. + */ +LongBowRuntimeResult *longBowRuntime_GetActualTestCaseResult(const LongBowRuntime *runtime); + +/** + * Get the number of events that were evalutated. + * + * @param [in] runtime A `LongBowRuntime` instance. + * + * @return The number of events that were evalutated. + */ +size_t longBowRuntime_GetActualEventEvaluationCount(LongBowRuntime *runtime); + +/** + * Get the LongBowEventType of the given LongBowRuntime. + * + * @param [in] runtime A `LongBowRuntime` instance. + * + * @return The LongBowEventType of the given LongBowRuntime. + */ +LongBowEventType *longBowRuntime_GetActualEventType(const LongBowRuntime *runtime); + +/** + * Get the expected EventType from the given LongBowRuntime. + * + * When testing, a test may set a LongBowEventType that is expected to be triggered. + * This function simply gets the expected LongBowEventType from the given LongBowRuntime instance. + * + * @param [in] runtime A pointer to a LongBowRuntime instance. + * + * @return The expected EventType in the LongBowRuntime. + */ +LongBowEventType *longBowRuntime_GetExpectedEventType(const LongBowRuntime *runtime); + +/** + * Set the "actual" LongBowEventType of the given LongBowRuntime. + * + * @param [in] runtime A `LongBowRuntime` instance. + * @param [in] eventType A `LongBowEventType` instance. + */ +void longBowRuntime_SetActualEventType(LongBowRuntime *runtime, LongBowEventType *eventType); + +/** + * Set the current `LongBowRuntime`. + * + * @param [in] runtime A `LongBowRuntime` instance. + * + * @return The previous LongBowRuntime + */ +LongBowRuntime *longBowRuntime_SetCurrentRuntime(LongBowRuntime *runtime); + +/** + * Retrieve the current `LongBowRuntime`. + * + * @return The current global LongBowRuntime. + */ +LongBowRuntime *longBowRuntime_GetCurrentRuntime(void); + +/** + * Retrieve the `LongBowConfig` instance of the current global runtime. + * + * @return The `LongBowConfig` instance of the current global runtime. + */ +LongBowConfig *longBowRuntime_GetCurrentConfig(void); + +/** + * Set the `LongBowConfig` instance of the current global runtime. + * + * @param [in] config The new `LongBowConfig` instance of the current global runtime. + */ +void longBowRuntime_SetCurrentConfig(LongBowConfig *config); + +/** + * Trigger a LongBow event. + * + * The event will be reported via the longBowReport_Event. + * + * @param [in] eventType The type of event. + * @param [in] location The LongBowLocation of the event (this will be destroyed). + * @param [in] kind A string indicating the kind of event this is triggering. + * @param [in] format A printf format string. + * @param [in] ... Parameters associated with the printf format string. + * + * @return true Always return true. + */ +bool longBowRuntime_EventTrigger(LongBowEventType *eventType, + LongBowLocation *location, + const char *kind, + const char *format, ...) __attribute__((__format__(__printf__, 4, 5))); +/** + * Record an event evaluation. + * + * This only records the fact of the evaluation, not the results of the evaluation. + * + * @param [in] type A pointer to the LongBowEventType being evaluated. + * + * @return true Always returns true. + * + * Example: + * @code + * { + * longBowRuntime_EventEvaluation(&LongBowAssertEvent); + * } + * @endcode + */ +bool longBowRuntime_EventEvaluation(const LongBowEventType *type); + +/** + * Set the current value for the depth of printed stack trace. + * + * If the depth is less than 1, no stack trace is displayed. + * + * @param [in] newDepth The new value to set. + * + * @return The previous value. + */ +unsigned int longBowRuntime_SetStackTraceDepth(unsigned int newDepth); + +/** + * Get the current value for the depth of printed stack trace. + * + * @return The current stack-trace depth. + */ +unsigned int longBowRuntime_GetStackTraceDepth(void); + +/** + * Print a formatted stack trace to the current output file descriptor. + * + * @param [in] fileDescriptor A valid file descriptor. + */ +void longBowRuntime_StackTrace(int fileDescriptor); + +/** + * Abort the running process using the current runtime environment. + * If the configuration is set to produce a core dump, this function simply returns. + * This permits the caller to use the form: + * <code> + * longBowRuntime_Abort(), kill(0, SIGTRACE) + * </code> + * To generate a core image. + * + * See the assertion macros for how this is used. + */ +void longBowRuntime_Abort(void); +#endif // LongBow_longBow_Runtime_h diff --git a/longbow/src/LongBow/longBow_RuntimeResult.c b/longbow/src/LongBow/longBow_RuntimeResult.c new file mode 100755 index 00000000..f91dfe1e --- /dev/null +++ b/longbow/src/LongBow/longBow_RuntimeResult.c @@ -0,0 +1,75 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <sys/time.h> + +#include <LongBow/longBow_RuntimeResult.h> + +size_t +longBowRuntimeResult_GetEventEvaluationCount(const LongBowRuntimeResult *testCaseResult) +{ + return testCaseResult->eventEvaluationCount; +} + +LongBowEventType * +longBowRuntimeResult_GetEvent(const LongBowRuntimeResult *testCaseResult) +{ + return testCaseResult->event; +} + +void +longBowRuntimeResult_SetEvent(LongBowRuntimeResult *testCaseResult, LongBowEventType *eventType) +{ + testCaseResult->event = eventType; +} + +void +longBowRuntimeResult_SetStatus(LongBowRuntimeResult *testCaseResult, LongBowStatus status) +{ + testCaseResult->status = status; +} +void +longBowRuntimeResult_SetElapsedTime(LongBowRuntimeResult *testCaseResult, struct timeval *elapsedTime) +{ + testCaseResult->elapsedTime = *elapsedTime; +} + +struct rusage * +longBowRuntimeResult_GetRUsage(LongBowRuntimeResult *testCaseResult) +{ + return &testCaseResult->resources; +} + +void +longBowRuntimeResult_SetRUsage(LongBowRuntimeResult *testCaseResult, struct rusage *resources) +{ + testCaseResult->resources = *resources; +} + +LongBowStatus +longBowRuntimeResult_GetStatus(const LongBowRuntimeResult *testCaseResult) +{ + return testCaseResult->status; +} + +struct timeval +longBowRuntimeResult_GetElapsedTime(const LongBowRuntimeResult *testCaseResult) +{ + return testCaseResult->elapsedTime; +} diff --git a/longbow/src/LongBow/longBow_RuntimeResult.h b/longbow/src/LongBow/longBow_RuntimeResult.h new file mode 100755 index 00000000..367ad1ae --- /dev/null +++ b/longbow/src/LongBow/longBow_RuntimeResult.h @@ -0,0 +1,138 @@ +/* + * 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 longBow_RuntimeResult.h + * @ingroup internals + * @brief LongBow Test Case Results + * + * LongBow Test Cases have expected and actual results. + * The expected results are typically a statically created instance of {@link LongBowRuntimeResult} + * which is used when the Test Case is executed to compare with the actual results. + * This permits, for example, a Test Case to indicate that it is expected to induce a specific LongBowEvent. + * In which case, the actual LongBowEvent must equal the expected event for the Test Case to be considered a success. + * + */ +#ifndef LongBow_longBow_CaseResult_h +#define LongBow_longBow_CaseResult_h + +#include <stdlib.h> +#include <stdint.h> +#include <sys/resource.h> + +#include <LongBow/longBow_Status.h> +#include <LongBow/longBow_Event.h> + +struct longbow_testcase_result; + +/** + * @typedef LongBowRuntimeResult + * @brief The expected and actual result of a LongBow Test. + */ +typedef struct longbow_testcase_result LongBowRuntimeResult; + +/** + * @struct longbow_testcase_result + * @brief The expected and actual result of a LongBow Test. + */ +struct longbow_testcase_result { + /** + * The number of event evaluations performed. + * These asserts and traps with conditions that were evaluated. + */ + size_t eventEvaluationCount; + LongBowStatus status; /**< The resulting status of the test case. */ + struct timeval elapsedTime; /**< The elapsed time of the test case. */ + struct rusage resources; /**< The resulting resource usage of the test case. */ + LongBowEventType *event; /**< The expected or actual event. */ +}; + +/** + * Return the event evaluation count associated with the given `LongBowRuntimeResult` instance. + * + * @param [in] testCaseResult A `LongBowRuntimeResult` instance. + * + * @return The number of Event evaluations. + */ +size_t longBowRuntimeResult_GetEventEvaluationCount(const LongBowRuntimeResult *testCaseResult); + +/** + * Retrieve the event type associated with the given `LongBowRuntimeResult` instance. + * + * @param [in] testCaseResult A `LongBowRuntimeResult` instance. + * + * @return The LongBowEventType for the given LongBowRuntimeResult. + */ +LongBowEventType *longBowRuntimeResult_GetEvent(const LongBowRuntimeResult *testCaseResult); + +/** + * Set the event type associated with the given `LongBowRuntimeResult` instance. + * + * @param [in] testCaseResult A `LongBowRuntimeResult` instance. + * @param [in] eventType A new `LongBowEventType` instance. + */ +void longBowRuntimeResult_SetEvent(LongBowRuntimeResult *testCaseResult, LongBowEventType *eventType); + +/** + * Get the LongBowStatus type from the given `LongBowRuntimeResult` instance. + * + * @param [in] testCaseResult A `LongBowRuntimeResult` instance. + * + * @return The LongBowStatus of the given LongBowRuntimeResult. + */ +LongBowStatus longBowRuntimeResult_GetStatus(const LongBowRuntimeResult *testCaseResult); + +/** + * Set the LongBowStatus type for the given `LongBowRuntimeResult` instance. + * + * @param [in] testCaseResult A `LongBowRuntimeResult` instance. + * @param [in] status A `LongBowStatus` value. + */ +void longBowRuntimeResult_SetStatus(LongBowRuntimeResult *testCaseResult, LongBowStatus status); + +/** + * Set the elapsed time for the given `LongBowRuntimeResult` instance. + * + * @param [in] testCaseResult A `LongBowRuntimeResult` instance. + * @param [in] elapsedTime A `struct timeval` instance. + */ +void longBowRuntimeResult_SetElapsedTime(LongBowRuntimeResult *testCaseResult, struct timeval *elapsedTime); + +/** + * Get the elapsed time associated with the given `LongBowRuntimeResult` instance. + * + * @param [in] testCaseResult A `LongBowRuntimeResult` instance. + * + * @return A copy of the timeval of the given LongBowRuntimeResult. + */ +struct timeval longBowRuntimeResult_GetElapsedTime(const LongBowRuntimeResult *testCaseResult); + +/** + * Retrieve the RUsage struct from the given `LongBowRuntimeResult` instance. + * + * @param [in] testCaseResult A `LongBowRuntimeResult` instance. + * + * @return A pointer to the struct rusage instance in the given LongBowRuntimeResult. + */ +struct rusage *longBowRuntimeResult_GetRUsage(LongBowRuntimeResult *testCaseResult); + +/** + * Set the RUsage struct for the given `LongBowRuntimeResult` instance. + * + * @param [in] testCaseResult A `LongBowRuntimeResult` instance. + * @param [in] rusage A `struct rusage` instance. + */ +void longBowRuntimeResult_SetRUsage(LongBowRuntimeResult *testCaseResult, struct rusage *rusage); +#endif diff --git a/longbow/src/LongBow/longBow_Status.c b/longbow/src/LongBow/longBow_Status.c new file mode 100644 index 00000000..200a2aea --- /dev/null +++ b/longbow/src/LongBow/longBow_Status.c @@ -0,0 +1,146 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> + +#include <LongBow/longBow_Status.h> +#include <LongBow/unit-test.h> + +bool +longBowStatus_IsSuccessful(LongBowStatus status) +{ + if (status == LONGBOW_STATUS_SUCCEEDED || longBowStatus_IsWarning(status) || longBowStatus_IsIncomplete(status)) { + return true; + } + return false; +} + +bool +longBowStatus_IsFailed(LongBowStatus status) +{ + switch (status) { + case LONGBOW_STATUS_FAILED: + case LONGBOW_STATUS_MEMORYLEAK: + case LongBowStatus_STOPPED: + case LONGBOW_STATUS_TEARDOWN_FAILED: + case LONGBOW_STATUS_SETUP_FAILED: + return true; + + default: + if (status >= LongBowStatus_SIGNALLED) { + return true; + } + return false; + } +} + +bool +longBowStatus_IsWarning(LongBowStatus status) +{ + switch (status) { + case LongBowStatus_WARNED: + case LongBowStatus_TEARDOWN_WARNED: + return true; + + default: + return false; + } +} + +bool +longBowStatus_IsIncomplete(LongBowStatus status) +{ + switch (status) { + case LONGBOW_STATUS_SKIPPED: + case LongBowStatus_UNIMPLEMENTED: + case LongBowStatus_IMPOTENT: + return true; + + default: + return false; + } +} + +bool +longBowStatus_IsSignalled(LongBowStatus status) +{ + return status >= LongBowStatus_SIGNALLED; +} + +static struct toString { + LongBowStatus status; + char *string; +} toString[] = { + { LONGBOW_STATUS_SUCCEEDED, "Succeeded" }, + { LongBowStatus_WARNED, "Warning" }, + { LongBowStatus_TEARDOWN_WARNED, "Tear Down Warning" }, + { LONGBOW_STATUS_SKIPPED, "Skipped" }, + { LongBowStatus_UNIMPLEMENTED, "Unimplemented" }, + { LongBowStatus_IMPOTENT, "Impotent" }, + { LONGBOW_STATUS_FAILED, "Failed" }, + { LongBowStatus_STOPPED, "Stopped" }, + { LONGBOW_STATUS_TEARDOWN_FAILED, "Tear Down Failed" }, + { LONGBOW_STATUS_SETUP_FAILED, "Setup Failed" }, + { LONGBOW_STATUS_MEMORYLEAK, "Memory Leak" }, + { 0, NULL }, +}; + +static const char * +_longBowStatus_StatusToString(const LongBowStatus status) +{ + const char *result = NULL; + for (const struct toString *element = &toString[0]; element->string != NULL; element++) { + if (element->status == status) { + result = element->string; + break; + } + } + return result; +} + +char * +longBowStatus_ToString(const LongBowStatus status) +{ + char *result = (char *) _longBowStatus_StatusToString(status); + + if (result == NULL) { + if (status >= LongBowStatus_SIGNALLED) { + int signalNumber = status - LongBowStatus_SIGNALLED; + char *signalName = strsignal(signalNumber); + int check; + if (signalName == NULL) { + check = asprintf(&result, "Signaled %d.", signalNumber); + } else { + check = asprintf(&result, "Signaled %s.", signalName); + } + if (check == -1) { + return NULL; + } + } else { + int check = asprintf(&result, "Unknown status: %d. This is a bug.", status); + if (check == -1) { + return NULL; + } + } + } else { + result = strdup(result); + } + + return result; +} diff --git a/longbow/src/LongBow/longBow_Status.h b/longbow/src/LongBow/longBow_Status.h new file mode 100755 index 00000000..de45ae6d --- /dev/null +++ b/longbow/src/LongBow/longBow_Status.h @@ -0,0 +1,235 @@ +/* + * 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 longBow_Status.h + * @ingroup testing + * @brief A simple status representation for a LongBow Test Case. + * + */ +#ifndef LongBow_longBow_Status_h +#define LongBow_longBow_Status_h + +#include <stdbool.h> +#include <stdint.h> + +/** + * @typedef LongBowStatus + * @brief The status of an individual Test Case, and aggregate Test Fixture, or Test Runner. + * + * Status is either successful or not and each has a subset of qualifiers. + * + * A successful status is an outright success, or a qualified success. + * + * Qualified success is a test that issued an explicit warning (via <code>testWarn(...)</code>), + * was purposefully skipped (via <code>testSkip(...)</code>), + * or is unimplemented (via <code>testUnimplemented(...)</code>). + * + * Correspondingly, an unsuccessful test is outright failure, + * or a qualified failure. + * Qualified values indicate that the test process received a signal during the test, + * or either the Test Fixture set-up or tear-down steps signaled failure. + * + */ +enum LongBowStatus { + /** + * Used for expressing the expected status. + */ + LongBowStatus_DONTCARE = -2, + + /** + * The test was not run (initial state). + */ + LongBowStatus_UNTESTED = -1, + + /* successful */ + /** + * The test was successful. + */ + LONGBOW_STATUS_SUCCEEDED = 0, + /** + * The test was successful, but with a warning. + */ + + LongBowStatus_WARNED = 10, + /** + * The test was successful, but the tear down issued a warning. + */ + + LongBowStatus_TEARDOWN_WARNED = 11, + + /** + * The test was purposefully skipped by the test implementor. + */ + LONGBOW_STATUS_SKIPPED = 21, + + /** + * The test was incomplete because it signals that it is not implemented. + */ + LongBowStatus_UNIMPLEMENTED = 22, + + /** + * The test ran but evaluated nothing. + */ + LongBowStatus_IMPOTENT = 23, + + /** + * The setup function signals that all of the subordinate test cases must be skipped. + */ + LONGBOW_STATUS_SETUP_SKIPTESTS = 24, + + /* failures */ + /** + * The tests failed. + */ + LONGBOW_STATUS_FAILED = 1, + + /** + * The test failed because it was stopped by a signal. + */ + LongBowStatus_STOPPED = 3, + + /** + * The tear down of the test failed. + * + * This doesn't imply that the test failed. + */ + LONGBOW_STATUS_TEARDOWN_FAILED = 4, + + /** + * The test was incomplete because the setup for the test failed. + */ + LONGBOW_STATUS_SETUP_FAILED = 5, + + /** + * The test was incomplete because a memory leak was detected. + */ + LONGBOW_STATUS_MEMORYLEAK = 6, + + /** + * The test failed due to an uncaught signal. + */ + LongBowStatus_SIGNALLED = 100, + + /** + * The limit of LongBowStatus values + */ + LongBowStatus_LIMIT = 200, +}; +typedef enum LongBowStatus LongBowStatus; + +/** + * Compose a LongBowStatus from the given signalNumber. + */ +#define LongBowStatus_SIGNAL(signalNumber) (LongBowStatus_SIGNALLED + signalNumber) + +/** + * Generate a human readable, nul-terminated C string representation of the `LongBowStatus` value. + * + * @param [in] status A `LongBowStatus` value + * + * @return A pointer to an allocated C string that must be freed via stdlib.h free(3). + * + * Example: + * @code + * { + * LongBowStatus status = LONGBOW_STATUS_SUCCEEDED; + * printf("Status = %s\n", longBowStatus_ToString(status)); + * } + * @endcode + */ +char *longBowStatus_ToString(LongBowStatus status); + +/** + * Return `true` if the given status indicates an outright or qualified success. + * + * Success, outright or qualified, encompasses `LONGBOW_STATUS_SUCCEEDED`, + * longBowStatus_IsWarning(status), or + * longBowStatus_IsIncomplete(status) + * + * @param [in] status A `LongBowStatus` value. + * + * @return `true` if the given status indicated an outright or qualified success. + * + * Example: + * @code + * { + * LongBowStatus status = LONGBOW_STATUS_SUCCEEDED; + * printf("Is success? = %d\n", longBowStatus_IsSuccessful(status)); + * } + * @endcode + */ +bool longBowStatus_IsSuccessful(LongBowStatus status); + +/** + * Return <code>true</code> if the given status indicates a failure. + * + * @param [in] status A `LongBowStatus` value. + * + * @return `true` if the given status indicated a failure. + * + * Example: + * @code + * { + * LongBowStatus status = LONGBOW_STATUS_FAILED; + * printf("Is warned? = %d\n", longBowStatus_IsFailed(status)); + * } + * @endcode + */ +bool longBowStatus_IsFailed(LongBowStatus status); + +/** + * Return <code>true</code> if the given status indicates a warning. + * + * @param [in] status A `LongBowStatus` value. + * + * @return Return `true` if the given status indicate a warning. + */ +bool longBowStatus_IsWarning(LongBowStatus status); + +/** + * Return <code>true</code> if the given status indicates a test was incomplete. + * + * @param [in] status A `LongBowStatus` value. + * + * @return `true` if the given status indicated it was incomplete. + * + * Example: + * @code + * { + * LongBowStatus status = LONGBOW_STATUS_SKIPPED; + * printf("Is incomplete? = %d\n", longBowStatus_IsIncomplete(status)); + * } + * @endcode + */ +bool longBowStatus_IsIncomplete(LongBowStatus status); + +/** + * Return <code>true</code> if the given status indicated a test induced a signal. + * + * @param [in] status A `LongBowStatus` value. + * + * @return `true` if the given status indicated a test induced a signal. + * + * Example: + * @code + * { + * LongBowStatus status = LongBowStatus_SIGNALLED; + * printf("Is signalled? = %d\n", longBowStatus_IsSignalled(status)); + * } + * @endcode + */ +bool longBowStatus_IsSignalled(LongBowStatus status); +#endif // LONGBOWSTATUS_H_ diff --git a/longbow/src/LongBow/longBow_SubProcess.c b/longbow/src/LongBow/longBow_SubProcess.c new file mode 100755 index 00000000..2bd91dd5 --- /dev/null +++ b/longbow/src/LongBow/longBow_SubProcess.c @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +# include "longBow_SubProcess_Darwin_x86_64.c" diff --git a/longbow/src/LongBow/longBow_SubProcess.h b/longbow/src/LongBow/longBow_SubProcess.h new file mode 100755 index 00000000..83aac8c8 --- /dev/null +++ b/longbow/src/LongBow/longBow_SubProcess.h @@ -0,0 +1,145 @@ +/* + * 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 longBow_SubProcess.h + * @ingroup testing + * @brief Facilities for running and managing subprocesses. + * + */ +#ifndef LongBow_longBow_SubProcess_h +#define LongBow_longBow_SubProcess_h + +#include <stdbool.h> + +struct longbow_subprocess; +typedef struct longbow_subprocess LongBowSubProcess; + +/** + * Start a subprocess. + * + * @param [in] path The pathname, either absolute or relative to the current directory, of the program to execute. + * @param [in] ... A NULL terminated parameter list consisting of the parameters of the executable starting at `argv[0]`. + * + * @return A pointer to a `LongBowSubProcess` instance. + * + * Example: + * @code + * { + * LongBowSubProcess *process = longBowSubProcess_Exec("/bin/pwd", "pwd", NULL); + * } + * @endcode + * + * @see longBowSubProcess_Wait + * @see longBowSubProcess_Signal + * @see longBowSubProcess_Terminate + * @see longBowSubProcess_Wait + */ +LongBowSubProcess *longBowSubProcess_Exec(const char *path, ... /*, (char *)0 */); + +/** + * Destroy a `LongBowSubProcess` + * + * If the process is still running it is sent the SIGKILL signal. + * + * @param [in] subProcessPtr A pointer to a `LongBowSubProcess` instance. + * + * Example: + * @code + * { + * LongBowSubProcess *process = longBowSubProcess_Exec("/bin/pwd", "pwd", NULL); + * + * longBowSubProcess_Destroy(&process); + * } + * @endcode + * + * @see longBowSubProcess_Exec + */ +void longBowSubProcess_Destroy(LongBowSubProcess **subProcessPtr); + +/** + * Send a signal to a LongBowSubProcess + * + * @param [in] subProcess The LongBowSubProcess to receive the signal. + * @param [in] signalNumber The signal to send. + * + * @return true The signal was successfully sent. + * @return false The signal was not successfully sent. + * + * Example: + * @code + * { + * longBowSubProcess_Signal(subProcess, SIGTERM); + * } + * @endcode + * + * @see longBowSubProcess_Terminate + */ +bool longBowSubProcess_Signal(LongBowSubProcess *subProcess, int signalNumber); + +/** + * Send a SIGTERM to a LongBowSubProcess + * + * @param [in] subProcess The LongBowSubProcess to receive the signal. + * + * @return true The signal was successfully sent. + * @return false The signal was not successfully sent. + * + * Example: + * @code + * { + * longBowSubProcess_Signal(subProcess, SIGTERM); + * } + * @endcode + * + * @see longBowSubProcess_Terminate + */ +bool longBowSubProcess_Terminate(LongBowSubProcess *subProcess); + +/** + * Wait for a `LongBowSubProcess` to stop or terminate + * + * @param [in] subProcess The LongBowSubProcess to wait for. + * + * Example: + * @code + * { + * <#example#> + * } + * @endcode + * + */ +void longBowSubProcess_Wait(LongBowSubProcess *subProcess); + +/** + * Print a human readable representation of the given `LongBowSubProcess`. + * + * @param [in] indentation The level of indentation to use to pretty-print the output. + * @param [in] subprocess A pointer to the instance to display. + * + * Example: + * @code + * { + * LongBowSubProcess *process = longBowSubProcess_Exec("/bin/pwd", "pwd", NULL); + * + * longBowSubProcess_Display(process, 0); + * + * longBowSubProcess_Destroy(&process); + * } + * @endcode + * + */ +void longBowSubProcess_Display(const LongBowSubProcess *subprocess, int indentation); +#endif diff --git a/longbow/src/LongBow/longBow_SubProcess_Darwin_x86_64.c b/longbow/src/LongBow/longBow_SubProcess_Darwin_x86_64.c new file mode 100755 index 00000000..6c0a0f7a --- /dev/null +++ b/longbow/src/LongBow/longBow_SubProcess_Darwin_x86_64.c @@ -0,0 +1,136 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <unistd.h> +#include <stdarg.h> +#include <stdlib.h> +#include <signal.h> + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/wait.h> + +#include <LongBow/longBow_SubProcess.h> +#include <LongBow/private/longBow_Memory.h> + +struct longbow_subprocess { + const char *path; + char **arguments; + pid_t pid; + int exitStatus; + struct rusage rusage; +}; + +static void +_resetAllSignals(void) +{ + struct sigaction signalAction; + signalAction.sa_handler = SIG_DFL; + signalAction.sa_flags = SA_SIGINFO; + sigemptyset(&signalAction.sa_mask); + + for (int i = 1; i < NSIG; i++) { + sigaction(i, &signalAction, NULL); + } +} + +LongBowSubProcess * +longBowSubProcess_Exec(const char *path, ... /*, (char *)0 */) +{ + va_list ap; + va_start(ap, path); + + size_t count = 0; + for (char *arg = va_arg(ap, char *); arg != NULL; arg = va_arg(ap, char *)) { + count++; + } + + LongBowSubProcess *result = longBowMemory_Allocate(sizeof(LongBowSubProcess)); + + result->path = path; + longBowMemory_Allocate(sizeof(char *) * count + 1); + va_end(ap); + // This relies on the last element being all zeros. + va_start(ap, path); + + for (size_t i = 0; i < count; i++) { + result->arguments[i] = va_arg(ap, char *); + } + va_end(ap); + + result->pid = fork(); + if (result->pid == 0) { + _resetAllSignals(); + printf("Exec %s\n", result->path); + int error = execv(result->path, result->arguments); + printf("Error %d\n", error); + perror(path); + exit(1); + } + + printf("Process group child=%d, parent=%d\n", getpgid(result->pid), getpgrp()); + return result; +} + +void +longBowSubProcess_Destroy(LongBowSubProcess **processPtr) +{ + LongBowSubProcess *process = *processPtr; + + if (process->pid) { + longBowSubProcess_Signal(process, SIGKILL); + } + + longBowMemory_Deallocate((void **) process->arguments); + longBowMemory_Deallocate((void **) processPtr); +} + +bool +longBowSubProcess_Terminate(LongBowSubProcess *subProcess) +{ + return longBowSubProcess_Signal(subProcess, SIGTERM); +} + +bool +longBowSubProcess_Signal(LongBowSubProcess *subProcess, int signalNumber) +{ + return kill(subProcess->pid, signalNumber) == 0; +} + +void +longBowSubProcess_Wait(LongBowSubProcess *subProcess) +{ + wait4(subProcess->pid, &subProcess->exitStatus, 0, &subProcess->rusage); + subProcess->pid = 0; +} + +void +longBowSubProcess_Display(const LongBowSubProcess *subprocess, int indentation) +{ + printf("%*s%s: ", indentation, "", subprocess->path); + if (subprocess->pid == 0) { + printf("not running .exitStatus=%d ", subprocess->exitStatus); + } else { + printf(".pid=%d", subprocess->pid); + } + + printf("\n"); +} diff --git a/longbow/src/LongBow/longBow_TestCase.c b/longbow/src/LongBow/longBow_TestCase.c new file mode 100644 index 00000000..ca506ae8 --- /dev/null +++ b/longbow/src/LongBow/longBow_TestCase.c @@ -0,0 +1,643 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <unistd.h> +#include <setjmp.h> +#include <assert.h> +#include <errno.h> + +#include <LongBow/unit-test.h> + +#include <LongBow/Reporting/longBowReport_Testing.h> + +#include <LongBow/longBow_Config.h> +#include <LongBow/longBow_TestCaseClipBoard.h> +#include <LongBow/private/longBow_Memory.h> +#include <LongBow/private/longBow_String.h> + + +/** + * @struct longbow_testcase + * @brief The specification of a LongBow Test Case. + * + */ +struct longbow_testcase { + /** + * The name of the test case as a C string. + */ + const char *testCaseName; + + const LongBowTestCaseMetaData *metaData; + + char *fullName; + + /** + * The fixture that is running this test case. + */ + const LongBowTestFixture *fixture; + + /** + * The function to execute the test case. + */ + LongBowTestCaseFunction *testCase; + + /** + * The runtime characteristics consisting of the expected and actual results. + */ + LongBowRuntime *runtime; +}; + + +void +longBowTestCase_ConfigHelp(void) +{ + printf("Test Case options:\n"); + printf(" --set <runnerName>/<fixtureName>/iterations=<integer> Run the named test case <integer> times.\n"); +} + +LongBowTestCase * +longBowTestCase_Create(const char *testCaseName, + const LongBowTestFixture *testFixture, + LongBowTestCaseFunction *testCase, + const LongBowTestCaseMetaData *metaData) +{ + assert(testCaseName != NULL); + + LongBowTestCase *result = longBowMemory_Allocate(sizeof(LongBowTestCase)); + if (result != NULL) { + result->testCaseName = testCaseName; + int status = asprintf(&result->fullName, "%s/%s", longBowTestFixture_GetFullName(testFixture), testCaseName); + assert(status != -1); + result->fixture = testFixture; + result->testCase = testCase; + result->runtime = longBowRuntime_Create(&metaData->expectedResult, + longBowTestRunner_GetConfiguration(longBowTestFixture_GetRunner(testFixture))); + result->metaData = metaData; + } + return result; +} + +const char * +longBowTestCase_GetFullName(const LongBowTestCase *testCase) +{ + assert(testCase != NULL); + return testCase->fullName; +} + +void +longBowTestCase_Destroy(LongBowTestCase **testCaseP) +{ + LongBowTestCase *testCase = *testCaseP; + + longBowRuntime_Destroy(&(testCase->runtime)); + + longBowMemory_Deallocate((void **) testCaseP); +} + +/* + * Given the exit status of a test as returned by wait(2), return the corresponding {@link LongBowStatus}. + * + * @param [in] waitStatus + * @return LongBowStatus + */ +static LongBowStatus +_longBowTestCase_ParseWaitStatus(int waitStatus) +{ + LongBowStatus result = LongBowStatus_WARNED; + if (WIFSIGNALED(waitStatus)) { + int exitSignal = WTERMSIG(waitStatus); + if (exitSignal == SIGABRT) { + result = LONGBOW_STATUS_FAILED; + } else { + result = LongBowStatus_SIGNALLED + exitSignal; + } + } else if (WIFEXITED(waitStatus)) { + result = (LongBowStatus) WEXITSTATUS(waitStatus); + } else { + result = LongBowStatus_STOPPED; + } + + return result; +} + +LongBowLocation * +longBowTestCase_CreateLocation(const LongBowTestCase *testCase) +{ + LongBowLocation *result = longBowLocation_Create(testCase->metaData->fileName, testCase->fullName, testCase->metaData->lineNumber); + return result; +} + +const char * +longBowTestCase_GetName(const LongBowTestCase *testCase) +{ + return testCase->testCaseName; +} + +LongBowTestFixture * +longBowTestCase_GetFixture(const LongBowTestCase *testCase) +{ + return (LongBowTestFixture *) testCase->fixture; +} + +LongBowRuntimeResult * +longBowTestCase_GetExpectedResult(const LongBowTestCase *testCase) +{ + return longBowRuntime_GetExpectedTestCaseResult(testCase->runtime); +} + +LongBowRuntimeResult * +longBowTestCase_GetActualResult(const LongBowTestCase *testCase) +{ + return longBowRuntime_GetActualTestCaseResult(testCase->runtime); +} + +size_t +longBowTestCase_GetEventEvaluationCount(const LongBowTestCase *testCase) +{ + return longBowRuntime_GetActualEventEvaluationCount(testCase->runtime); +} + +static jmp_buf longBowTestCaseAbort; + +/* + * The process running the Test Case receives a signal. + * + * A regular, passing Test Case induces no signal and as a result does not pass through this function. + * A Test Case that fails an assertion will induce the SIGABRT signal which does pass through this function. + * Any other signal is because the Test Case either purposefully sent itself a signal, (including calling abort()), + * or it induced one through some implicit behaviour (like a SIGSEGV). + * + * In all remaining cases, encode the signal received into a return value for the + * corresponding setjmp() and invoke the longjmp(). + */ +__attribute__((noreturn)) +static void +_longBowTestCase_ReceiveSignal(int signal, siginfo_t *siginfo __attribute__((unused)), void *data __attribute__((unused))) +{ + if (signal == SIGINT) { + printf("Howdy\n"); + } + longjmp(longBowTestCaseAbort, signal); +} + +/** + * Return true or false, if LongBow should capture a signal, or not. + * + * LongBow captures signals in order to report on the success or failure of a test. + * Some signals do not indicate that a test failed, + * only that the environment changed, + * or some other event that is unrelated to success or failure. + * Unless, of course, the test is checking for the event (this is not yet supported). + */ +static bool +_longBowTestCase_MustCaptureSignal(const int signal) +{ + switch (signal) { + case SIGTRAP: + return false; + + case SIGCHLD: + return false; + + case SIGKILL: + return false; + + case SIGSTOP: + return false; + + case SIGWINCH: + return false; + + default: + return true; + } +} + +/** + * Setup signals to point to the testCaseSignalAction handler for all signals possible. + */ +static void +_longBowTestCase_TestInitSignals(void) +{ + struct sigaction signalAction; + signalAction.sa_sigaction = _longBowTestCase_ReceiveSignal; + signalAction.sa_flags = SA_SIGINFO; + sigemptyset(&signalAction.sa_mask); + + struct sigaction oldSignals[NSIG]; + for (int i = 1; i < NSIG; i++) { + if (_longBowTestCase_MustCaptureSignal(i)) { + sigaction(i, &signalAction, &oldSignals[i]); + } + } +} + +/** + * Setup signals to their default behaviour. + */ +static void +_longBowTestCase_TestFiniSignals(void) +{ + struct sigaction signalAction; + signalAction.sa_handler = SIG_DFL; + signalAction.sa_flags = SA_SIGINFO; + sigemptyset(&signalAction.sa_mask); + + for (int i = 1; i < NSIG; i++) { + if (_longBowTestCase_MustCaptureSignal(i)) { + sigaction(i, &signalAction, NULL); + } + } +} + +/* + * Determine the status of the given LongBowTestCase. + * + * If the actual event recorded in the test case is equal to the expected event, + * then return LONGBOW_STATUS_SUCCEEDED. + * If the actual event is NULL and the expected event is not, then return LONGBOW_STATUS_FAILED. + * Otherwise, the result is the actual event. + */ +static LongBowStatus +_longBowTestCase_ExpectedVsActualEvent(const LongBowTestCase *testCase) +{ + LongBowStatus result = LONGBOW_STATUS_FAILED; + LongBowEventType *expectedEvent = longBowRuntimeResult_GetEvent(longBowTestCase_GetExpectedResult(testCase)); + LongBowEventType *actualEvent = longBowRuntimeResult_GetEvent(longBowTestCase_GetActualResult(testCase)); + + if (longBowEventType_Equals(expectedEvent, actualEvent)) { + result = LONGBOW_STATUS_SUCCEEDED; + } else if (actualEvent == NULL && expectedEvent != NULL) { + LongBowString *messageString = longBowString_CreateFormat("failed to induce an expected %s event.", + longBowEventType_GetName(expectedEvent)); + + LongBowLocation *location = longBowTestCase_CreateLocation(testCase); + LongBowEvent *event = longBowEvent_Create(expectedEvent, location, "", longBowString_ToString(messageString), NULL); + + longBowReportRuntime_Event(event); + longBowEvent_Destroy(&event); + longBowString_Destroy(&messageString); + + result = LONGBOW_STATUS_FAILED; + } else { + result = longBowEventType_GetStatus(actualEvent); + } + + return result; +} + +/* + * Invoke the test case function and see if it succeeds. + * + * The technique here is to assume the test case will succeed, + * setup a longjmp back to this function + * and then setup signal handling and invoke the test case. + * This essentially wraps the test function an catches and handles the abort() + * (SIGABRT) that results from the LongBow assertion or trap. + * + * If the test case simply returns (ie. the longjmp was never executed), + * then it was successful. + * Otherwise, the longjmp contains a code indicating the status captured by + * the signal handler that was invoked when the test code executed the abort() function. + * Extract relevant information from the current runtime context + * (which is always present whether in a unit test case or not) + * + * Note that it's actually not necessary for the test code to execute an abort(), + * it could invoke the longjmp() directly. + * Something that might be advantagous in the future. + */ +static LongBowStatus +_longBowTestCase_Execute(LongBowTestCase *testCase) +{ + LongBowStatus result = LONGBOW_STATUS_SUCCEEDED; + + if (longBowConfig_IsTrace(longBowTestCase_GetConfiguration(testCase))) { + longBowReportTesting_Trace(" %s/%s/%s", + longBowTestRunner_GetName(longBowTestFixture_GetRunner(longBowTestCase_GetFixture(testCase))), + longBowTestFixture_GetName(longBowTestCase_GetFixture(testCase)), + longBowTestCase_GetName(testCase)); + } + + int receivedSignal = setjmp(longBowTestCaseAbort); + if (receivedSignal == 0) { + _longBowTestCase_TestInitSignals(); + + errno = 0; + + LongBowClipBoard *testClipBoard = longBowTestFixture_GetClipBoard(longBowTestCase_GetFixture(testCase)); + + (testCase->testCase)(longBowTestFixture_GetRunner(longBowTestCase_GetFixture(testCase)), + longBowTestCase_GetFixture(testCase), + testCase, + testClipBoard, + longBowTestCaseAbort); + } else { + // We get here as the result of an extraordinary abort from the testCase invoked just above. + // Sort out the meaning of the received signal here. + // + // If an SIGABRT is received, we expect that the Global Runtime contains a valid LongBowEventType. + // If not, then an old-timey <assert.h> assert() was used and the programmer should be warned, + // or the system under test actually uses SIGABRT and the programmer is warned that this + // incompatible with LongBow. + + LongBowEventType *event = NULL; + if (receivedSignal == SIGABRT) { + if (longBowRuntime_GetActualEventType(longBowRuntime_GetCurrentRuntime()) == NULL) { + char *testCaseString = longBowTestCase_ToString(testCase); + longBowReportRuntime_Warning("Warning: %s commingling LongBow with assert(3) or with SIGABRT will not work.\n", testCaseString); + free(testCaseString); + } + + event = longBowRuntime_GetActualEventType(longBowRuntime_GetCurrentRuntime()); + } else if (receivedSignal == SIGTERM) { + char *testCaseString = longBowTestCase_ToString(testCase); + longBowReportRuntime_Warning("\nWarning: %s premature termination.\n", testCaseString); + free(testCaseString); + event = longBowEventType_GetEventTypeForSignal(receivedSignal); + } else if (receivedSignal == SIGINT) { + char *testCaseString = longBowTestCase_ToString(testCase); + longBowReportRuntime_Warning("\nWarning: %s interrupted.\n", testCaseString); + free(testCaseString); + event = longBowEventType_GetEventTypeForSignal(receivedSignal); + } else { + event = longBowEventType_GetEventTypeForSignal(receivedSignal); + } + + longBowRuntimeResult_SetEvent(longBowTestCase_GetActualResult(testCase), event); + } + + result = _longBowTestCase_ExpectedVsActualEvent(testCase); + + if (result == LONGBOW_STATUS_SUCCEEDED) { + if (longBowTestCase_GetEventEvaluationCount(testCase) == 0) { + result = LongBowStatus_IMPOTENT; + } + } else if (longBowStatus_IsFailed(result)) { + ; + } + + memset(&longBowTestCaseAbort, 0, sizeof(longBowTestCaseAbort)); + + _longBowTestCase_TestFiniSignals(); + + return result; +} + +static LongBowStatus +_longBowTestCase_ExecuteOnce(LongBowTestCase *testCase) +{ + LongBowStatus result = LONGBOW_STATUS_FAILED; + + LongBowTestFixture *fixture = longBowTestCase_GetFixture(testCase); + + LongBowStatus setupStatus = longBowTestFixture_Setup(fixture, testCase); + + if (longBowStatus_IsSuccessful(setupStatus) == true) { + LongBowStatus testCaseStatus = _longBowTestCase_Execute(testCase); + + LongBowStatus tearDownStatus = longBowTestFixture_TearDown(fixture, testCase); + + // Ensure that things only go from "bad" to "worse." If a test case is indicating a failure + // and yet the tear-down is also indicating something NOT successful (like a warning), don't + // demote the status from LONGBOW_STATUS_FAILED to LONGBOW_STATUS_TEARDOWN_WARNING. + // This is messy. Perhaps a better approach would be to structure status as an ordered arrangement of status. + + result = testCaseStatus; + + if (testCaseStatus == LONGBOW_STATUS_SUCCEEDED) { + if (tearDownStatus != LONGBOW_STATUS_SUCCEEDED) { + result = tearDownStatus; + } + } + } + + return result; +} + +static LongBowStatus +_longBowTestCase_Iterate(LongBowTestCase *testCase) +{ + LongBowStatus result = LONGBOW_STATUS_SUCCEEDED; + + LongBowConfig *config = longBowTestCase_GetConfiguration(testCase); + + uint32_t iterations = longBowConfig_GetUint32(config, 1, "%s/iterations", longBowTestCase_GetFullName(testCase)); + + for (uint32_t i = 0; i < iterations && longBowStatus_IsSuccessful(result); i++) { + LongBowRuntime *previousRuntime = longBowRuntime_SetCurrentRuntime(testCase->runtime); + result = _longBowTestCase_ExecuteOnce(testCase); + longBowRuntime_SetCurrentRuntime(previousRuntime); + } + + return result; +} + +/* + * Run a LongBowTestCase in a forked process. + * + * @param testCase The LongBowTestCase to run. + * @return 0 + */ +static int +_longBowTestCase_RunForked(LongBowTestCase *testCase) +{ + struct timeval startTime; + gettimeofday(&startTime, NULL); + + pid_t pid = fork(); + if (pid == 0) { + exit(_longBowTestCase_Iterate(testCase)); + } else { + // Rummage around in various things to obtain the post-mortem + // results of the test that was run in a separate process. + int waitStatus; + struct rusage rusage; +#ifndef _ANDROID_ + wait3(&waitStatus, 0, &rusage); +#else + wait4(-1, &waitStatus, 0, &rusage); +#endif + struct timeval endTime; + gettimeofday(&endTime, NULL); + + struct timeval elapsedTime; + timersub(&endTime, &startTime, &elapsedTime); + + longBowRuntimeResult_SetElapsedTime(longBowTestCase_GetActualResult(testCase), &elapsedTime); + longBowRuntimeResult_SetRUsage(longBowTestCase_GetActualResult(testCase), &rusage); + longBowRuntimeResult_SetStatus(longBowTestCase_GetActualResult(testCase), _longBowTestCase_ParseWaitStatus(waitStatus)); + } + return 0; +} + +/* + * Run a LongBowTestCase in this address space (ie. not a forked process). + * + * @param testCase The LongBowTestCase to run. + * @return 0 + */ +static int +_longBowTestCase_RunNonForked(LongBowTestCase *testCase) +{ + struct timeval startTime; + gettimeofday(&startTime, NULL); + + LongBowStatus status = _longBowTestCase_Iterate(testCase); + + struct timeval endTime; + gettimeofday(&endTime, NULL); + + struct timeval elapsedTime; + timersub(&endTime, &startTime, &elapsedTime); + + longBowRuntimeResult_SetElapsedTime(longBowTestCase_GetActualResult(testCase), &elapsedTime); + longBowRuntimeResult_SetStatus(longBowTestCase_GetActualResult(testCase), status); + + return 0; +} + +LongBowStatus +longBowTestCase_GetExpectedStatus(const LongBowTestCase *testCase) +{ + return longBowRuntimeResult_GetStatus(longBowTestCase_GetExpectedResult(testCase)); +} + +LongBowTestCase * +longBowTestCase_Run(const char *testCaseName, + const LongBowTestFixture *fixture, + LongBowTestCaseFunction *testCase, + const LongBowTestCaseMetaData *testCaseMetaData) +{ + LongBowTestCase *result = longBowTestCase_Create(testCaseName, fixture, testCase, testCaseMetaData); + + if (result != NULL) { + if (longBowConfig_IsRunForked(longBowTestRunner_GetConfiguration(longBowTestFixture_GetRunner(fixture)))) { + _longBowTestCase_RunForked(result); + } else { + _longBowTestCase_RunNonForked(result); + } + + longBowTestFixture_AddTestCase(fixture, result); + longBowReportTesting_DisplayTestCaseResult(result); + } + return result; +} + +LongBowStatus +longBowTestCase_GetStatus(const LongBowTestCase *testCase) +{ + return longBowRuntimeResult_GetStatus(longBowTestCase_GetActualResult(testCase)); +} + +static LongBowClipBoard * +_longBowTestCase_GetClipBoard(const LongBowTestCase *testCase) +{ + return longBowTestFixture_GetClipBoard(testCase->fixture); +} + +void * +longBowTestCase_SetClipBoardData(const LongBowTestCase *testCase, void *data) +{ + return longBowClipBoard_Set(_longBowTestCase_GetClipBoard(testCase), "testCase", data); +} + +void * +longBowTestCase_GetClipBoardData(const LongBowTestCase *testCase) +{ + return longBowClipBoard_Get(_longBowTestCase_GetClipBoard(testCase), "testCase"); +} + +void * +longBowTestCase_Set(const LongBowTestCase *testCase, const char *name, void *value) +{ + return longBowClipBoard_Set(_longBowTestCase_GetClipBoard(testCase), name, value); +} + +void * +longBowTestCase_Get(const LongBowTestCase *testCase, const char *name) +{ + return longBowClipBoard_Get(_longBowTestCase_GetClipBoard(testCase), name); +} + +char * +longBowClipBoard_GetCString(const LongBowTestCase *testCase, const char *name) +{ + return longBowClipBoard_GetAsCString(_longBowTestCase_GetClipBoard(testCase), name); +} + +void * +longBowTestCase_SetInt(const LongBowTestCase *testCase, const char *name, int value) +{ + return longBowClipBoard_SetInt(_longBowTestCase_GetClipBoard(testCase), name, (uint64_t) value); +} + +void * +longBowTestCase_SetCString(const LongBowTestCase *testCase, const char *name, char *value) +{ + return longBowClipBoard_SetCString(_longBowTestCase_GetClipBoard(testCase), name, value); +} + +int +longBowTestCase_GetInt(const LongBowTestCase *testCase, const char *name) +{ + return (intptr_t) longBowTestCase_Get(testCase, name); +} + +LongBowConfig * +longBowTestCase_GetConfiguration(const LongBowTestCase *testCase) +{ + return longBowTestRunner_GetConfiguration(longBowTestFixture_GetRunner(longBowTestCase_GetFixture(testCase))); +} + +char * +longBowTestCase_ToString(const LongBowTestCase *testCase) +{ + return strdup(longBowTestCase_GetFullName(testCase)); +} + +bool +longBowTestCase_IsSuccessful(const LongBowTestCase *testCase) +{ + return longBowStatus_IsSuccessful(longBowTestCase_GetStatus(testCase)); +} + +bool +longBowTestCase_IsFailed(const LongBowTestCase *testCase) +{ + return longBowStatus_IsFailed(longBowTestCase_GetStatus(testCase)); +} + +bool +longBowTestCase_IsWarning(const LongBowTestCase *testCase) +{ + return longBowStatus_IsWarning(longBowTestCase_GetStatus(testCase)); +} + +bool +longBowTestCase_IsIncomplete(const LongBowTestCase *testCase) +{ + return longBowStatus_IsIncomplete(longBowTestCase_GetStatus(testCase)); +} diff --git a/longbow/src/LongBow/longBow_TestCase.h b/longbow/src/LongBow/longBow_TestCase.h new file mode 100755 index 00000000..670adc84 --- /dev/null +++ b/longbow/src/LongBow/longBow_TestCase.h @@ -0,0 +1,247 @@ +/* + * 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 longBow_TestCase.h + * @ingroup internals + * @brief The interface and supporting functionality of a LongBow Test Case. + * + */ +#ifndef LONGBOWTESTCASE_H_ +#define LONGBOWTESTCASE_H_ + +#include <setjmp.h> + +struct longbow_testcase; +typedef struct longbow_testcase LongBowTestCase; + +#include <LongBow/longBow_TestCaseClipBoard.h> +#include <LongBow/longBow_ClipBoard.h> + +#include <LongBow/longBow_TestRunner.h> +#include <LongBow/longBow_TestFixture.h> +#include <LongBow/longBow_RuntimeResult.h> +#include <LongBow/longBow_TestCaseMetaData.h> + +typedef void (LongBowTestCaseFunction)(const LongBowTestRunner *, const LongBowTestFixture *, const LongBowTestCase *, const LongBowClipBoard *c, jmp_buf); + +/** + * Get the name of the given LongBowTestCase. + * + * @param [in] testCase A pointer to a `LongBowTestCase` instance. + * + * @return A pointer to an immutable C string. + * + * Example: + * @code + * const char *name = longBowTestCase_GetName(testCase); + * @endcode + */ +const char *longBowTestCase_GetName(const LongBowTestCase *testCase); + +/** + * Get the corresponding LongBowTestFixture for the given LongBowTestCase. + * + * @param [in] testCase A pointer to a LongBowTestCase instance. + * + * @return A pointer to the corresponding LongBowTestFixture. + * + * Example: + * @code + * <#example#> + * @endcode + */ +LongBowTestFixture *longBowTestCase_GetFixture(const LongBowTestCase *testCase); + +/** + * Create a LongBowTestCase instance. + * + * @param [in] testCaseName A nul-terminated C string of the test case name. + * @param [in] fixture A pointer to a valid LongBowTestFixture instance. + * @param [in] testCase A pointer to a test case function. + * @param [in] metaData A pointer to a LongBowTestCaseMetaData instance. + * @return A pointer to an allocated LongBowTestCase instance, that must be destroyed via longBowTestCase_Destroy(). + */ +LongBowTestCase *longBowTestCase_Create(const char *testCaseName, + const LongBowTestFixture *fixture, + LongBowTestCaseFunction *testCase, + const LongBowTestCaseMetaData *metaData); + +/** + * Print command line and configuration help applicable to a Long Bow Test Case. + * + */ +void longBowTestCase_ConfigHelp(void); + +/** + * @param [in,out] testCasePtr A pointer to a pointer to a LongBowTestCase instance. + */ +void longBowTestCase_Destroy(LongBowTestCase **testCasePtr); + +/** + * Get the fully qualified name of the given `LongBowTestCase`. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * + * @return A constant nul-terminated, C string. + */ +const char *longBowTestCase_GetFullName(const LongBowTestCase *testCase); + +/** + * + * @param [in] testCaseName A nul-terminated C string of the test case name. + * @param [in] fixture A pointer to a valid LongBowTestFixture instance. + * @param [in] testCase A pointer to a test case function. + * @param [in] testCaseMetaData A pointer to a LongBowTestCaseMetaData instance. + * @return return + */ +LongBowTestCase *longBowTestCase_Run(const char *testCaseName, + const LongBowTestFixture *fixture, + LongBowTestCaseFunction *testCase, + const LongBowTestCaseMetaData *testCaseMetaData); + +/** + * Get the string representation of the given LongBowTestCase. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return An allocated, nul-terminated C string that must be deallocated via free(3) + */ +char *longBowTestCase_ToString(const LongBowTestCase *testCase); + +/** + * Return the LongBowStatus of the given test case. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return The LongBowStatus of the given test case. + */ +LongBowStatus longBowTestCase_GetStatus(const LongBowTestCase *testCase); + +/** + * Get the LongBowStatus value for the expected status of the given LongBowTestCase. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return A LongBowStatus value for the expected status of the given LongBowTestCase. + */ +LongBowStatus longBowTestCase_GetExpectedStatus(const LongBowTestCase *testCase); + +/** + * Get a pointer to the expected LongBowRuntimeResult value for the given LongBowTestCase. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return A LongBowStatus value for the expected status of the given LongBowTestCase. + */ +LongBowRuntimeResult *longBowTestCase_GetExpectedResult(const LongBowTestCase *testCase); + +/** + * Get the count of event evaluations performed during the execution of a LongBow Test Case. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * + * @return The count of event evaluations performed during the execution of a LongBow Test Case. + */ +size_t longBowTestCase_GetEventEvaluationCount(const LongBowTestCase *testCase); + +/** + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return A LongBowRuntimeResult pointer. + */ +LongBowRuntimeResult *longBowTestCase_GetActualResult(const LongBowTestCase *testCase); + +/** + * Return <code>true</code> if the given test case was successful. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return <code>true</code> if the given test case succeeded. + */ +bool longBowTestCase_IsSuccessful(const LongBowTestCase *testCase); + +/** + * Return <code>true</code> if the given test case issued a warning. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return <code>true</code> if the given test case issued a warning. + */ +bool longBowTestCase_IsWarning(const LongBowTestCase *testCase); + +/** + * Return <code>true</code> if the given test case was incomplete. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return <code>true</code> if the given test case was incomplete. + */ +bool longBowTestCase_IsIncomplete(const LongBowTestCase *testCase); + +/** + * Return <code>true</code> if the given test case failed. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return <code>true</code> if the given test case failed. + */ +bool longBowTestCase_IsFailed(const LongBowTestCase *testCase); + +///** +// * Place a value on the Test Case "clipboard" +// * +// * Every Test Case has an associated "clipboard" which is shared between the Test Fixture Setup, +// * Test Case, and Test Fixture Tear Down. +// * +// * @param [in] testCase A pointer to a valid LongBowTestCase instance. +// * @param [in] data The value to share on the clipboard. +// * @return The previous value on the "clipboard", or NULL if no previous value was set. +// */ +//void *longBowTestCase_SetClipBoard(const LongBowTestCase *testCase, const char *name, void *data); + +///** +// * Get the named clipboard data from the given `LongBowTestCase`. +// * +// * @param [in] testCase A pointer to a valid LongBowTestCase instance. +// * @param [in] name A nul-terminate, C string of the name of the clipboard entry. +// */ +//void *longBowTestCase_GetClipBoard(const LongBowTestCase *testCase, const char *name); + +/** + * Get the LongBowConfig instance for the given LongBowTestCase instance. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * + * @return non-NULL The LongBowConfig instance for the given LongBowTestCase instance. + * @return NULL No LongBowConfig instance for the given LongBowTestCase. + */ +LongBowConfig *longBowTestCase_GetConfiguration(const LongBowTestCase *testCase); + +/** + * Get the clipboard data from the given `LongBowTestCase`. + * + * NOTE: Use `longBowTestCase_GetClipBoard`. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + */ +void *longBowTestCase_GetClipBoardData(const LongBowTestCase *testCase); + +void *longBowTestCase_SetClipBoardData(const LongBowTestCase *testCase, void *data); + +void *longBowTestCase_Set(const LongBowTestCase *testCase, const char *name, void *value); + +void *longBowTestCase_Get(const LongBowTestCase *testCase, const char *name); + +char *longBowClipBoard_GetCString(const LongBowTestCase *testCase, const char *name); + +void *longBowTestCase_SetInt(const LongBowTestCase *testCase, const char *name, int value); + +void *longBowTestCase_SetCString(const LongBowTestCase *testCase, const char *name, char *value); + +int longBowTestCase_GetInt(const LongBowTestCase *testCase, const char *name); +#endif // LONGBOWTESTCASE_H_ diff --git a/longbow/src/LongBow/longBow_TestCaseClipBoard.c b/longbow/src/LongBow/longBow_TestCaseClipBoard.c new file mode 100755 index 00000000..acdf4c3d --- /dev/null +++ b/longbow/src/LongBow/longBow_TestCaseClipBoard.c @@ -0,0 +1,58 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdlib.h> + +#include <LongBow/longBow_TestCaseClipBoard.h> +#include <LongBow/private/longBow_Memory.h> + +struct longbow_testcase_clipboard { + /** + * A pointer to arbitrary data shared between the setup, test case, and teardown. + */ + void *shared; +}; + +LongBowTestCaseClipBoard * +longBowTestCaseClipBoard_Create(void *shared) +{ + LongBowTestCaseClipBoard *result = longBowMemory_Allocate(sizeof(LongBowTestCaseClipBoard)); + longBowTestCaseClipBoard_Set(result, shared); + return result; +} + +void +longBowTestCaseClipBoard_Destroy(LongBowTestCaseClipBoard **clipBoardPtr) +{ + longBowMemory_Deallocate((void **) clipBoardPtr); +} + +void * +longBowTestCaseClipBoard_Get(const LongBowTestCaseClipBoard *clipBoard) +{ + return clipBoard->shared; +} + +LongBowTestCaseClipBoard * +longBowTestCaseClipBoard_Set(LongBowTestCaseClipBoard *clipBoard, void *shared) +{ + void *previousValue = clipBoard->shared; + clipBoard->shared = shared; + return previousValue; +} diff --git a/longbow/src/LongBow/longBow_TestCaseClipBoard.h b/longbow/src/LongBow/longBow_TestCaseClipBoard.h new file mode 100755 index 00000000..4b8da1aa --- /dev/null +++ b/longbow/src/LongBow/longBow_TestCaseClipBoard.h @@ -0,0 +1,62 @@ +/* + * 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 longBow_TestCaseClipboard.h + * @ingroup testing + * @brief LongBow Clipboard shared between the setup, test case, and teardown. + * + */ +#ifndef LongBow_longBowTestCaseClipBoard_h +#define LongBow_longBowTestCaseClipBoard_h + +struct longbow_testcase_clipboard; + +/** + * @typedef LongBowTestCaseClipBoard + */ +typedef struct longbow_testcase_clipboard LongBowTestCaseClipBoard; + +/** + * Create a `LongBowTestCaseClipBoard` containing the shared data pointer. + * + * @param [in] shared A pointer to a value that is shared between the setup, test-case, and tear-down functions. + * @return A pointer to a valid LongBowTestCaseClipBoard instance. + * + * @see longBowTestCaseClipBoard_Destroy + */ +LongBowTestCaseClipBoard *longBowTestCaseClipBoard_Create(void *shared); + +/** + * + * @param [in,out] clipBoardPtr A pointer to a pointer to a LongBowTestCaseClipBoard instance. + */ +void longBowTestCaseClipBoard_Destroy(LongBowTestCaseClipBoard **clipBoardPtr); + +/** + * + * @param [in] clipBoard A pointer to a valid LongBowTestCaseClipBoard instance. + * @param [in] shared A pointer to a value that is shared between the setup, test-case, and tear-down functions. + * @return The previous value of the "clipboard", or NULL if there was no previous value. + */ +LongBowTestCaseClipBoard *longBowTestCaseClipBoard_Set(LongBowTestCaseClipBoard *clipBoard, void *shared); + +/** + * + * @param [in] clipBoard A pointer to a valid LongBowTestCaseClipBoard instance. + * @return The value currently stored on the clipboard. + */ +void *longBowTestCaseClipBoard_Get(const LongBowTestCaseClipBoard *clipBoard); +#endif diff --git a/longbow/src/LongBow/longBow_TestCaseMetaData.c b/longbow/src/LongBow/longBow_TestCaseMetaData.c new file mode 100755 index 00000000..1596d60c --- /dev/null +++ b/longbow/src/LongBow/longBow_TestCaseMetaData.c @@ -0,0 +1,18 @@ +/* + * 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. + */ + +/** + */ +#include <LongBow/longBow_TestCaseMetaData.h> diff --git a/longbow/src/LongBow/longBow_TestCaseMetaData.h b/longbow/src/LongBow/longBow_TestCaseMetaData.h new file mode 100755 index 00000000..589b90ec --- /dev/null +++ b/longbow/src/LongBow/longBow_TestCaseMetaData.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/** + */ +#ifndef longBow_TestCaseMetaData_h +#define longBow_TestCaseMetaData_h + +#include <stdint.h> + +#include <LongBow/longBow_RuntimeResult.h> + +struct LongBowTestCaseMetaData { + const char *fileName; + const char *functionName; + uint32_t lineNumber; + LongBowRuntimeResult expectedResult; +}; + +typedef struct LongBowTestCaseMetaData LongBowTestCaseMetaData; + +#endif /* longBow_TestCaseMetaData_h */ diff --git a/longbow/src/LongBow/longBow_TestFixture.c b/longbow/src/LongBow/longBow_TestFixture.c new file mode 100644 index 00000000..d4efc86f --- /dev/null +++ b/longbow/src/LongBow/longBow_TestFixture.c @@ -0,0 +1,449 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> +#include <stdio.h> + +#include <LongBow/private/longBow_ArrayList.h> +#include <LongBow/private/longBow_Memory.h> +#include <LongBow/private/longBow_String.h> + +#include <LongBow/longBow_TestFixture.h> +#include <LongBow/longBow_TestFixtureConfig.h> +#include <LongBow/longBow_TestCase.h> +#include <LongBow/longBow_RuntimeResult.h> + +#include <LongBow/unit-test.h> + +/** + * @struct longbow_fixture + * @brief The LongBow Test Fixture. + * + * This structure is created and initialized by the LongBow Test Runner. + * When the Test Fixture represented by this structure is executed, + * this structure is updated with the results of each LongBow Test Case that belongs to this Fixture. + */ +struct longbow_fixture { + /** + * The name of this test fixture. + */ + const char *name; + + /** + * The fully qualified name of this test fixture. + */ + char *fullName; + + /** + * + */ + LongBowTestFixtureConfig *config; + + /** + * The Test Runner of this test fixture. + */ + LongBowTestRunner *runner; + + /** + * The `LongBowTestFixtureSummary` of this test fixture. + */ + LongBowTestFixtureSummary summary; + + /** + * A list of `LongBowTestCase` structures, one for each executed test case. + */ + LongBowArrayList *testCases; + + /** + * The function to call to setup the Test Fixture. + * + * This function is called before each Test Case is run. + * @param testCase The LongBow Test Case that is being set-up. + */ + LongBowTestFixtureSetupFunction *setUp; + + /** + * The function to call to execute the Test Fixture. + * + * @param testFixture A pointer to this `struct longbow_fixture` structure. + */ + LongBowTestFixtureFunction *fixture; + + /** + * The function to call to tear-down the Test Fixture. + * + * This function is called after each Test Case is run. + * @param testCase The LongBow Test Case that is being torn-down. + */ + LongBowTestFixtureTearDownFunction *tearDown; +}; + +static void +_longBowTestFixture_TestSucceeded(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalSucceeded++; +} + +static void +_longBowTestFixture_TestFailed(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalFailed++; +} + +static void +_longBowTestFixture_TestLeakedResources(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalFailed++; +} + +static void +_longBowTestFixture_TestSkipped(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalSkipped++; +} + +static void +_longBowTestFixture_TestSkipTests(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalSkipped++; +} + +static void +_longBowTestFixture_TestWarned(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalWarned++; +} + +static void +_longBowTestFixture_TestSetupFailed(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalSetupFailed++; +} + +static void +_longBowTestFixture_TestSignalled(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalSignalled++; +} + +static void +_longBowTestFixture_TestStopped(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalStopped++; +} + +static void +_longBowTestFixture_TestUnimplemented(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalUnimplemented++; +} + +static void +_longBowTestFixture_TestImpotent(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalUnimplemented++; +} + +static void +_longBowTestFixture_Untested(LongBowTestFixtureSummary *summary __attribute__((unused))) +{ +} + +static void +_longBowTestFixture_TearDownFailed(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalTearDownFailed++; +} + +static void +_longBowTestFixture_TearDownWarned(LongBowTestFixtureSummary *summary) +{ + summary->totalTested++; + summary->totalTearDownWarned++; +} + +void +longBowTestFixture_ConfigHelp(void) +{ + printf("Test Fixture options:\n"); + printf(" --set <runnerName>/<fixtureName>/iterations=<integer> Run the named test fixture <integer> times.\n"); + printf(" --set <runnerName>/<fixtureName>/enable=(true|false) Enable or disable execution of the named test fixture.\n"); +} + +bool +longBowTestFixture_Config(LongBowConfig *config, const char *parameter) +{ + bool result = false; + return result; +} + +LongBowTestFixture * +longBowTestFixture_Create(const LongBowTestRunner *testRunner, + const char *fixtureName, + LongBowTestFixtureSetupFunction *setup, + LongBowTestFixtureFunction *fixtureFunction, + LongBowTestFixtureTearDownFunction *tearDown) +{ + LongBowTestFixture *fixture = longBowMemory_Allocate(sizeof(LongBowTestFixture)); + if (fixture != NULL) { + fixture->runner = (LongBowTestRunner *) testRunner; + fixture->name = fixtureName; + + int status = asprintf(&fixture->fullName, "%s/%s", longBowTestRunner_GetName(testRunner), fixtureName); + if (status == -1) { + return NULL; + } + + fixture->testCases = longBowArrayList_Create((void (*)(void **))longBowTestCase_Destroy); + fixture->setUp = setup; + fixture->fixture = fixtureFunction; + fixture->tearDown = tearDown; + } + + return fixture; +} + +void +longBowTestFixture_Destroy(LongBowTestFixture **fixturePtr) +{ + LongBowTestFixture *fixture = *fixturePtr; + + free(fixture->fullName); + + longBowArrayList_Destroy(&fixture->testCases); + longBowMemory_Deallocate((void **) fixturePtr); +} + +const char * +longBowTestFixture_GetFullName(const LongBowTestFixture *testFixture) +{ + return testFixture->fullName; +} + +void +longBowTestFixture_UpdateSummary(LongBowTestCase *longBowTestCase) +{ + switch (longBowRuntimeResult_GetStatus(longBowTestCase_GetActualResult(longBowTestCase))) { + case LONGBOW_STATUS_SUCCEEDED: + _longBowTestFixture_TestSucceeded(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LONGBOW_STATUS_SKIPPED: + _longBowTestFixture_TestSkipped(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LongBowStatus_WARNED: + _longBowTestFixture_TestWarned(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LONGBOW_STATUS_SETUP_FAILED: + _longBowTestFixture_TestSetupFailed(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LONGBOW_STATUS_SETUP_SKIPTESTS: + _longBowTestFixture_TestSkipTests(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LONGBOW_STATUS_TEARDOWN_FAILED: + _longBowTestFixture_TearDownFailed(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LongBowStatus_TEARDOWN_WARNED: + _longBowTestFixture_TearDownWarned(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LONGBOW_STATUS_FAILED: + _longBowTestFixture_TestFailed(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LongBowStatus_STOPPED: + _longBowTestFixture_TestStopped(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LongBowStatus_UNIMPLEMENTED: + _longBowTestFixture_TestUnimplemented(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LongBowStatus_IMPOTENT: + _longBowTestFixture_TestImpotent(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LongBowStatus_UNTESTED: + _longBowTestFixture_Untested(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + case LONGBOW_STATUS_MEMORYLEAK: + _longBowTestFixture_TestLeakedResources(&longBowTestCase_GetFixture(longBowTestCase)->summary); + break; + + default: + if (longBowTestCase_GetActualResult(longBowTestCase)->status >= LongBowStatus_SIGNALLED) { + _longBowTestFixture_TestSignalled(&longBowTestCase_GetFixture(longBowTestCase)->summary); + } else { + printf("longBowTestFixture_UpdateSummary: unhandled status %d\n", + longBowTestCase_GetActualResult(longBowTestCase)->status); + } + } +} + +void +longBowTestFixture_AddTestCase(const LongBowTestFixture *fixture, LongBowTestCase *longBowTestCase) +{ + longBowTestFixture_UpdateSummary(longBowTestCase); + + longBowArrayList_Add(fixture->testCases, longBowTestCase); +} + +LongBowTestCase * +longBowTestFixture_GetTestCase(const LongBowTestFixture *fixture, size_t index) +{ + LongBowTestCase *testCase = longBowArrayList_Get(fixture->testCases, index); + + return testCase; +} + +const char * +longBowTestFixture_GetName(const LongBowTestFixture *fixture) +{ + return fixture->name; +} + +const LongBowTestFixtureSummary * +longBowTestFixture_GetSummary(const LongBowTestFixture *fixture) +{ + return &(fixture->summary); +} + +size_t +longBowTestFixture_GetTestCaseCount(const LongBowTestFixture *fixture) +{ + return longBowArrayList_Length(fixture->testCases); +} + +LongBowStatus +longBowTestFixture_Setup(LongBowTestFixture *fixture, LongBowTestCase *testCase) +{ + if (longBowConfig_IsTrace(longBowTestRunner_GetConfiguration(longBowTestFixture_GetRunner(fixture)))) { + longBowReportTesting_Trace(" %s/%s: setup", + longBowTestRunner_GetName(longBowTestFixture_GetRunner(fixture)), + longBowTestFixture_GetName(fixture)); + } + LongBowClipBoard *testClipBoard = longBowTestFixture_GetClipBoard(fixture); + LongBowStatus result = (longBowTestCase_GetFixture(testCase)->setUp)(longBowTestFixture_GetRunner(fixture), fixture, testCase, testClipBoard); + return result; +} + +LongBowStatus +longBowTestFixture_TearDown(LongBowTestFixture *fixture, LongBowTestCase *testCase) +{ + if (longBowConfig_IsTrace(longBowTestRunner_GetConfiguration(longBowTestFixture_GetRunner(fixture)))) { + longBowReportTesting_Trace(" %s/%s: tearDown", + longBowTestRunner_GetName(longBowTestFixture_GetRunner(fixture)), + longBowTestFixture_GetName(fixture)); + } + LongBowClipBoard *testClipBoard = longBowTestFixture_GetClipBoard(fixture); + LongBowStatus result = (longBowTestCase_GetFixture(testCase)->tearDown)(longBowTestFixture_GetRunner(fixture), fixture, testCase, testClipBoard); + return result; +} + +LongBowStatus +longBowTestFixture_GetStatus(const LongBowTestFixture *fixture) +{ + size_t nTestCases = longBowTestFixture_GetTestCaseCount(fixture); + + LongBowStatus result = LONGBOW_STATUS_SUCCEEDED; + + // Just return the status of the first non-successful test case. + for (size_t i = 0; i < nTestCases; i++) { + LongBowTestCase *testCase = longBowTestFixture_GetTestCase(fixture, i); + if (!longBowTestCase_IsSuccessful(testCase)) { + result = longBowTestCase_GetStatus(testCase); + break; + } + } + return result; +} + +bool +longBowTestFixture_IsSuccessful(const LongBowTestFixture *testFixture) +{ + return longBowStatus_IsSuccessful(longBowTestFixture_GetStatus(testFixture)); +} + +char * +longBowTestFixture_ToString(const LongBowTestFixture *fixture) +{ + char *runnerString = longBowTestRunner_ToString(longBowTestFixture_GetRunner(fixture)); + + char *string; + if (asprintf(&string, "%s/%s", runnerString, longBowTestFixture_GetName(fixture)) == -1) { + return NULL; + } + + free(runnerString); + + return string; +} + +LongBowTestFixture * +longBowTestFixture_Run(const LongBowTestRunner *testRunner, + const char *fixtureName, + const LongBowTestFixtureConfig *config, + LongBowTestFixtureSetupFunction *setup, + LongBowTestFixtureFunction *fixtureRun, + LongBowTestFixtureTearDownFunction *tearDown) +{ + LongBowTestFixture *testFixture = longBowTestFixture_Create(testRunner, fixtureName, setup, fixtureRun, tearDown); + + LongBowConfig *configuration = longBowTestRunner_GetConfiguration(testRunner); + + bool enabled = longBowConfig_GetBoolean(configuration, config->enabled, "%s/enabled", longBowTestFixture_GetFullName(testFixture)); + unsigned long iterations = longBowConfig_GetUint32(configuration, 1, "%s/iterations", longBowTestFixture_GetFullName(testFixture)); + + if (enabled) { + for (unsigned long i = 0; i < iterations; i++) { + (*testFixture->fixture)(testRunner, testFixture); + } + longBowTestRunner_AddFixture(testFixture->runner, testFixture); + } + + return testFixture; +} + +LongBowTestRunner * +longBowTestFixture_GetRunner(const LongBowTestFixture *fixture) +{ + return fixture->runner; +} + +LongBowClipBoard * +longBowTestFixture_GetClipBoard(const LongBowTestFixture *fixture) +{ + return longBowTestRunner_GetClipBoard(fixture->runner); +} diff --git a/longbow/src/LongBow/longBow_TestFixture.h b/longbow/src/LongBow/longBow_TestFixture.h new file mode 100644 index 00000000..926f3e03 --- /dev/null +++ b/longbow/src/LongBow/longBow_TestFixture.h @@ -0,0 +1,274 @@ +/* + * 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 longBow_TestFixture.h + * @ingroup internals + * @brief Manage the execution of Test Cases. + * + * A Test Fixture manages the individual execution of Test Cases. + * + */ +#ifndef LongBowTestFixture_H_ +#define LongBowTestFixture_H_ + +#include <string.h> + +struct longbow_fixture; + +/** + * @typedef LongBowTestFixture + * @brief The LongBow Test Fixture. + * + * This structure is created and initialized by the LongBow Test Runner. + * When the Test Fixture represented by this structure is executed, + * this structure is updated with the results of each LongBow Test Case that belongs to this Fixture. + */ +typedef struct longbow_fixture LongBowTestFixture; + +#include <LongBow/longBow_ClipBoard.h> +#include <LongBow/longBow_TestRunner.h> +#include <LongBow/longBow_TestCase.h> +#include <LongBow/longBow_TestFixtureConfig.h> + +typedef void (LongBowTestFixtureFunction)(const LongBowTestRunner *testRunner, const LongBowTestFixture *testFixture); + +typedef int (LongBowTestFixtureSetupFunction)(const LongBowTestRunner *, const LongBowTestFixture *, const LongBowTestCase *, LongBowClipBoard *); + +typedef int (LongBowTestFixtureTearDownFunction)(const LongBowTestRunner *, const LongBowTestFixture *, const LongBowTestCase *, LongBowClipBoard *); + +/** + * @typedef LongBowTestFixtureSummary + * @brief The summary for a test fixture. + */ +typedef struct longbow_fixture_summary { + /** + * The total number of test cases executed. + */ + unsigned int totalTested; + /** + * The number of test cases that succeeded. + */ + unsigned int totalSucceeded; + /** + * The number of test cases that failed. + */ + unsigned int totalFailed; + /** + * The number of test cases that were skipped. + */ + unsigned int totalSkipped; + /** + * The number of test cases that issued a warning. + */ + unsigned int totalWarned; + /** + * The number of test cases that setup failed. + */ + unsigned int totalSetupFailed; + /** + * The number of test cases that failed due to an signal. + */ + unsigned int totalSignalled; + /** + * The number of test cases that failed due to a stop signal. + */ + unsigned int totalStopped; + /** + * The number of test cases in which the tear-down failed. + */ + unsigned int totalTearDownFailed; + /** + * The number of test cases in which the tear-down issued a warning. + */ + unsigned int totalTearDownWarned; + /** + * The number of test cases that existed but indicated they were unimplemented. + */ + unsigned int totalUnimplemented; +} LongBowTestFixtureSummary; + +/** + * Update the summary information from the given LongBowTestCase. + * + * @param testCase A pointer to a valid LongBowTestCase instance. + */ +void longBowTestFixture_UpdateSummary(LongBowTestCase *testCase); + +/** + * + * @param testFixture A pointer to a valid LongBowTestFixture instance. + * @param testCase A pointer to a valid LongBowTestCase instance. + */ +void longBowTestFixture_AddTestCase(const LongBowTestFixture *testFixture, LongBowTestCase *testCase); + +/** + * + * @param testFixture A pointer to a valid LongBowTestFixture instance. + * @param index The index of the instance to get. + * @return A pointer to the LongBowTestCase instance at the given index. + */ +LongBowTestCase *longBowTestFixture_GetTestCase(const LongBowTestFixture *testFixture, size_t index); + +/** + * + * @param testFixture A pointer to a valid LongBowTestFixture instance. + * @return A pointer ot the LongBowTestRunner instance of the given LongBowTestFixture. + */ +LongBowTestRunner *longBowTestFixture_GetRunner(const LongBowTestFixture *testFixture); + +/** + * + * @param testFixture A pointer to a valid LongBowTestFixture instance. + * @return A pointer to the C string of the name of the given LongBowTestFixture. + */ +const char *longBowTestFixture_GetName(const LongBowTestFixture *testFixture); + +/** + * + * @param testFixture A pointer to a valid LongBowTestFixture instance. + * @return The number of LongBow Test Cases in the given LongBowTestFixture. + */ +size_t longBowTestFixture_GetTestCaseCount(const LongBowTestFixture *testFixture); + +/** + * Initialise a {@link LongBowTestFixture} structure with the given parameters. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @param [in] fixtureName The name of this Test Fixture. + * @param [in] setup A pointer to the function to call before invoking the first Test Case. + * @param [in] fixtureFunction A pointer to the function to call that will run each Test Case. + * @param [in] tearDown A pointer to the function to call after invoking the last Test Case. + * @return A pointer to an allocated LongBowTestFixture instance that must be deallocated via LongBowTestFixture_Destroy. + */ +LongBowTestFixture *longBowTestFixture_Create(const LongBowTestRunner *testRunner, + const char *fixtureName, + LongBowTestFixtureSetupFunction *setup, + LongBowTestFixtureFunction *fixtureFunction, + + LongBowTestFixtureTearDownFunction *tearDown); + +/** + * Destroy a LongBowTestFixture structure. + * + * @param fixturePtr A pointer to a LongBowTestFixture structure pointer. + */ +void longBowTestFixture_Destroy(LongBowTestFixture **fixturePtr); + +/** + * Get the fully qualified name of the given `LongBowTestFixture`. + * + * @param [in] testFixture A pointer to a valid LongBowTestCase instance. + * + * @return A constant nul-terminated, C string. + */ +const char *longBowTestFixture_GetFullName(const LongBowTestFixture *testFixture); + +void longBowTestFixture_ConfigHelp(void); + +bool longBowTestFixture_Config(LongBowConfig *config, const char *parameter); + +/** + * Execute a LongBow Test Fixture. + * + * The Test Fixture will execute Test Cases in the order they appear in the Test Fixture function. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @param [in] fixtureName The name of this Test Fixture. + * @param [in] config A pointer to a LongBowTestFixtureConfig to use when running the Test Fixture. + * @param [in] setup A pointer to the function to call before invoking the first Test Case. + * @param [in] fixtureRun A pointer to the function to call that will run each Test Case. + * @param [in] tearDown A pointer to the function to call after invoking the last Test Case. + * @return An allocated structure representing this Test Fixture. + * + * Example: + * @code + * <#example#> + * @endcode + * + * @see LONGBOW_TEST_FIXTURE + */ +LongBowTestFixture *longBowTestFixture_Run(const LongBowTestRunner *testRunner, + const char *fixtureName, + const LongBowTestFixtureConfig *config, + LongBowTestFixtureSetupFunction *setup, + LongBowTestFixtureFunction *fixtureRun, + LongBowTestFixtureTearDownFunction *tearDown); + +/** + * Get the status of the given LongBow Test Fixture. + * + * @param testFixture A pointer to a valid LongBowTestFixture instance. + * @return The `LongBowStatus` of the given Test Fixture. + */ +LongBowStatus longBowTestFixture_GetStatus(const LongBowTestFixture *testFixture); + +/** + * Return <code>true</code> if the given test case was successful. + * + * @param testFixture A pointer to a valid LongBowTestFixture instance. + * @return `true` if the given test case was successful. + */ +bool longBowTestFixture_IsSuccessful(const LongBowTestFixture *testFixture); + +/** + * Get a pointer to {@link LongBowTestFixtureSummary} for the given Test Fixture. + * + * @param testFixture A pointer to a valid LongBowTestFixture instance. + * @return A pointer to {@link LongBowTestFixtureSummary} for the given Test Fixture. + */ +const LongBowTestFixtureSummary *longBowTestFixture_GetSummary(const LongBowTestFixture *testFixture); + +/** + * Perform a test case setup. + * + * @param [in] testFixture A pointer to a valid LongBowTestFixture instance. + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return The `LongBowStatus` returned from the setup function. + */ +LongBowStatus longBowTestFixture_Setup(LongBowTestFixture *testFixture, LongBowTestCase *testCase); + +/** + * Perform a test case teardown. + * + * @param testFixture A pointer to a valid LongBowTestFixture instance. + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return The `LongBowStatus` returned from the teardown function. + */ +LongBowStatus longBowTestFixture_TearDown(LongBowTestFixture *testFixture, LongBowTestCase *testCase); + +/** + * Get the clipboard that belongs to the given Test Fixture. + * + * Every LongBow test fixure has an associated "clipboard" that is specific to that fixture and + * is shared between the test runner setup and tear down functions. + * Test Runner setup may store things on the test fixture's clipboard, + * the test fixture may access them and the tear down destroy them. + * + * @param [in] testFixture A pointer to a valid LongBowTestFixture instance. + * @return The `LongBowTestCaseClipBoard` for the given `LongBowTestFixture`. + * + * @see longBowTestCase_GetClipBoard + */ +LongBowClipBoard *longBowTestFixture_GetClipBoard(const LongBowTestFixture *testFixture); + +/** + * Compose a C string representing the current state of the given `LongBowTestFixture`. + * + * @param [in] testFixture A pointer to a valid LongBowTestFixture instance. + * @return An allocated, nul-terminated C string that must be deallocated via free(3) + */ +char *longBowTestFixture_ToString(const LongBowTestFixture *testFixture); +#endif // LongBowTestFixture_H_ diff --git a/longbow/src/LongBow/longBow_TestFixtureConfig.c b/longbow/src/LongBow/longBow_TestFixtureConfig.c new file mode 100755 index 00000000..756c908a --- /dev/null +++ b/longbow/src/LongBow/longBow_TestFixtureConfig.c @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/** + */ +#include <stdio.h> + +#include <LongBow/longBow_TestFixtureConfig.h> +#include <LongBow/private/longBow_Memory.h> + +LongBowTestFixtureConfig * +longBowTestFixtureConfig_Create(const char *name, bool enabled) +{ + LongBowTestFixtureConfig *result = longBowMemory_Allocate(sizeof(LongBowTestFixtureConfig)); + + result->name = longBowMemory_StringCopy(name); + result->enabled = enabled; + + return result; +} + +void +longBowTestFixtureConfig_Destroy(LongBowTestFixtureConfig **configPtr) +{ + LongBowTestFixtureConfig *config = *configPtr; + + longBowMemory_Deallocate((void **) &config->name); + longBowMemory_Deallocate((void **) configPtr); +} diff --git a/longbow/src/LongBow/longBow_TestFixtureConfig.h b/longbow/src/LongBow/longBow_TestFixtureConfig.h new file mode 100755 index 00000000..0ccaf538 --- /dev/null +++ b/longbow/src/LongBow/longBow_TestFixtureConfig.h @@ -0,0 +1,68 @@ +/* + * 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 longBow_TestFixtureConfig.h + * @ingroup testing + * @brief The Test Fixture configuration interface + * + */ +#ifndef LongBow_longBow_FixtureConfig_h +#define LongBow_longBow_FixtureConfig_h +#include <stdbool.h> + +struct longbow_fixture_config { + char *name; + + bool enabled; +}; +typedef struct longbow_fixture_config LongBowTestFixtureConfig; + +/** + * Create and initialise a LongBowTestFixtureConfig instance. + * + * @param [in] name The name of the Test Fixture + * @param [in] enabled True if the fixture is enabled, false otherwise. + * + * @return non-NULL A pointer to an allocated `LongBowTestFixtureConfig` isntance that must be destroyed via `longBowTestFixtureConfig_Destroy`. + * @return NULL An error occurred. + * + * Example: + * @code + * { + * <#example#> + * } + * @endcode + * + * @see longBowTestFixtureConfig_Destroy + */ +LongBowTestFixtureConfig *longBowTestFixtureConfig_Create(const char *name, bool enabled); + +/** + * Destroy a LongBowTestFixtureConfig intance. + * + * @param [in,out] configPtr A pointer to a pointer to a `LongBowTestFixtureConfig` instance. + * + * Example: + * @code + * { + * <#example#> + * } + * @endcode + * + * @see longBowTestFixtureConfig_Create + */ +void longBowTestFixtureConfig_Destroy(LongBowTestFixtureConfig **configPtr); +#endif // LongBow_longBow_FixtureConfig_h diff --git a/longbow/src/LongBow/longBow_TestRunner.c b/longbow/src/LongBow/longBow_TestRunner.c new file mode 100644 index 00000000..730333f4 --- /dev/null +++ b/longbow/src/LongBow/longBow_TestRunner.c @@ -0,0 +1,256 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <assert.h> +#include <inttypes.h> + +#include <LongBow/unit-test.h> + +#include <LongBow/longBow_TestRunner.h> +#include <LongBow/longBow_Properties.h> + +#include <LongBow/private/longBow_String.h> +#include <LongBow/private/longBow_Memory.h> +#include <LongBow/private/longBow_ArrayList.h> + +struct LongBowTestRunner { + const char *name; /**< The name of this LongBow test runner. */ + + LongBowStatus (*testRunnerSetup)(LongBowTestRunner *); /**< The Test Runner Setup function */ + + void (*testRunner)(LongBowTestRunner *); /**< The Test Case Runner function */ + + LongBowStatus (*testRunnerTearDown)(LongBowTestRunner *); /**< The Test Runner TearDown function */ + + LongBowArrayList *fixtures; /**< The LongBowTestFixtures of this Test Runner */ + + LongBowConfig *configuration; /**< The LongBowConfiguration for this Test Runner. */ + + /** + * The clipboard of information shared between the fixture setup, + * the test case, and the fixture tear-down. + */ + LongBowClipBoard *clipBoard; +}; + +void +longBowTestRunner_ConfigHelp(void) +{ + printf("Test Runner options:\n"); + printf(" --set <testRunnerName>/iterations=<count> Run the named test runner <count> times\n"); +} + +bool +longBowTestRunner_Config(LongBowConfig *config, const char *parameter) +{ + bool result = false; + LongBowArrayList *tokens = longBowString_Tokenise(parameter, "-="); + if (tokens != NULL) { + if (longBowArrayList_Length(tokens) == 2) { + result = longBowConfig_SetProperty(config, longBowArrayList_Get(tokens, 0), longBowArrayList_Get(tokens, 1)); + } + longBowArrayList_Destroy(&tokens); + } + return result; +} + +const char * +longBowTestRunner_GetName(const LongBowTestRunner *testRunner) +{ + assert(testRunner != NULL); + return testRunner->name; +} + +void +longBowTestRunner_AddFixture(LongBowTestRunner *testRunner, LongBowTestFixture *testFixture) +{ + longBowArrayList_Add(testRunner->fixtures, testFixture); +} + +LongBowTestRunner * +longBowTestRunner_Create(const char *name, + LongBowTestRunnerSetUp *setup, + LongBowTestRunnerRun *runner, + LongBowTestRunnerTearDown *tearDown) +{ + LongBowTestRunner *testRunner = longBowMemory_Allocate(sizeof(LongBowTestRunner)); + + if (testRunner != NULL) { + testRunner->name = name; + testRunner->testRunnerSetup = setup; + testRunner->testRunner = runner; + testRunner->testRunnerTearDown = tearDown; + testRunner->fixtures = longBowArrayList_Create((void (*)(void **))longBowTestFixture_Destroy); + testRunner->clipBoard = longBowClipBoard_Create(); + } + return testRunner; +} + +void +longBowTestRunner_Destroy(LongBowTestRunner **testRunnerPtr) +{ + if (testRunnerPtr != NULL) { + LongBowTestRunner *testRunner = *testRunnerPtr; + + longBowArrayList_Destroy(&testRunner->fixtures); + if (testRunner->clipBoard) { + longBowClipBoard_Destroy(&testRunner->clipBoard); + } + if (testRunner != NULL) { + longBowMemory_Deallocate((void **) testRunnerPtr); + } + } +} + +LongBowTestRunner * +longBowTestRunner_Run(LongBowTestRunner *testRunner) +{ + LongBowConfig *configuration = longBowTestRunner_GetConfiguration(testRunner); + unsigned long iterations = longBowConfig_GetUint32(configuration, 1, + "%s/iterations", longBowTestRunner_GetName(testRunner)); + + if (longBowConfig_IsTrace(configuration)) { + longBowReportTesting_Trace("%s: setup", longBowTestRunner_GetName(testRunner)); + } + LongBowStatus setupStatus = (*testRunner->testRunnerSetup)(testRunner); + + if (setupStatus != LONGBOW_STATUS_SETUP_SKIPTESTS) { + if (!longBowStatus_IsSuccessful(setupStatus)) { + char *statusString = longBowStatus_ToString(setupStatus); + printf("Warning: %s setup returned: %s.\n", testRunner->name, statusString); + free(statusString); + return testRunner; + } + + for (unsigned long i = 0; i < iterations; i++) { + if (longBowConfig_IsTrace(configuration)) { + longBowReportTesting_Trace("%s: run", longBowTestRunner_GetName(testRunner)); + } + (*testRunner->testRunner)(testRunner); + } + + if (longBowConfig_IsTrace(configuration)) { + longBowReportTesting_Trace("%s: tear-down", longBowTestRunner_GetName(testRunner)); + } + + LongBowStatus tearDownStatus = (*testRunner->testRunnerTearDown)(testRunner); + if (!longBowStatus_IsSuccessful(tearDownStatus)) { + char *statusString = longBowStatus_ToString(tearDownStatus); + printf("Warning: %s tear-down returned: %s.\n", testRunner->name, statusString); + free(statusString); + return testRunner; + } + } + + return testRunner; +} + +char * +longBowTestRunner_ToString(const LongBowTestRunner *runner) +{ + LongBowString *string = longBowString_CreateFormat("%s", longBowTestRunner_GetName(runner)); + + char *cString = longBowString_ToString(string); + longBowString_Destroy(&string); + return cString; +} + +LongBowTestFixture * +longBowTestRunner_GetFixture(const LongBowTestRunner *testRunner, size_t index) +{ + return longBowArrayList_Get(testRunner->fixtures, index); +} + +size_t +longBowTestRunner_GetFixtureCount(const LongBowTestRunner *testRunner) +{ + return longBowArrayList_Length(testRunner->fixtures); +} + +LongBowConfig * +longBowTestRunner_GetConfiguration(const LongBowTestRunner *testRunner) +{ + return testRunner->configuration; +} + +LongBowStatus +longBowTestRunner_GetStatus(const LongBowTestRunner *testRunner) +{ + LongBowStatus result = LONGBOW_STATUS_SUCCEEDED; + + // Just return the status of the first non-successful Test Fixture. + size_t nTestFixtures = longBowTestRunner_GetFixtureCount(testRunner); + for (size_t i = 0; i < nTestFixtures; i++) { + LongBowTestFixture *fixture = longBowTestRunner_GetFixture(testRunner, i); + if (!longBowTestFixture_IsSuccessful(fixture)) { + result = longBowTestFixture_GetStatus(fixture); + break; + } + } + return result; +} + +bool +longBowTestRunner_IsSuccessful(const LongBowTestRunner *testRunner) +{ + return longBowStatus_IsSuccessful(longBowTestRunner_GetStatus(testRunner)); +} + +bool +longBowTestRunner_IsFailed(const LongBowTestCase *testCase) +{ + return longBowStatus_IsFailed(longBowTestCase_GetStatus(testCase)); +} + +bool +longBowTestRunner_IsWarning(const LongBowTestRunner *testCase) +{ + return longBowStatus_IsWarning(longBowTestRunner_GetStatus(testCase)); +} + +bool +longBowTestRunner_IsIncomplete(const LongBowTestCase *testCase) +{ + return longBowStatus_IsIncomplete(longBowTestCase_GetStatus(testCase)); +} + +void +longBowTestRunner_SetConfiguration(LongBowTestRunner *testRunner, LongBowConfig *config) +{ + testRunner->configuration = config; +} + +LongBowClipBoard * +longBowTestRunner_GetClipBoard(const LongBowTestRunner *testRunner) +{ + return testRunner->clipBoard; +} + +bool +longBowTestRunner_SetClipBoardData(const LongBowTestRunner *testRunner, void *shared) +{ + return longBowClipBoard_Set(longBowTestRunner_GetClipBoard(testRunner), "testRunner", shared); +} + +void * +longBowTestRunner_GetClipBoardData(const LongBowTestRunner *testRunner) +{ + return longBowClipBoard_Get(longBowTestRunner_GetClipBoard(testRunner), "testRunner"); +} diff --git a/longbow/src/LongBow/longBow_TestRunner.h b/longbow/src/LongBow/longBow_TestRunner.h new file mode 100644 index 00000000..d787a17c --- /dev/null +++ b/longbow/src/LongBow/longBow_TestRunner.h @@ -0,0 +1,269 @@ +/* + * 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 longBow_TestRunner.h + * @ingroup testing + * @brief LongBow Test Runner Support. + * + */ +#ifndef LONGBOWRUNNER_H_ +#define LONGBOWRUNNER_H_ + +#include <stdbool.h> + +struct LongBowTestRunner; +/** + * @typedef LongBowRunner + * @brief The LongBow Test Runner + */ +typedef struct LongBowTestRunner LongBowRunner; + +typedef struct LongBowTestRunner LongBowTestRunner; + +#include <LongBow/longBow_Config.h> +#include <LongBow/longBow_Status.h> +#include <LongBow/longBow_TestCase.h> +#include <LongBow/longBow_TestFixture.h> + +/** + * The function prototype for a LongBow Test Runner set-up function. + * + * @param testRunner A pointer to the associated LongBowTestRunner. + * @return A LongBowStatus value indicating the result of the set-up. + */ +typedef LongBowStatus (LongBowTestRunnerSetUp)(LongBowTestRunner *testRunner); + +/** + * The function prototype for a LongBow Test Runner function. + * + * @param testRunner A pointer to the associated LongBowTestRunner. + */ +typedef void (LongBowTestRunnerRun)(LongBowTestRunner *testRunner); + +/** + * The function prototype for a LongBow Test Runner tear-down function. + * + * @param testRunner A pointer to the associated LongBowTestRunner. + * @return A LongBowStatus value indicating the result of the tear-down. + */ +typedef LongBowStatus (LongBowTestRunnerTearDown)(LongBowTestRunner *testRunner); + +/** + * Allocate and initialise a LongBowTestRunner structure with the given parameters. + * + * See <code>longBowTestRunner_Destroy</code> to destroy the result. + * + * The parameters may be static values (ie. not allocated) supplied by the caller + * and they are not subject to free in <code>longBowTestRunner_Destroy</code>. + * + * @param [in] name The name of the LongBow test runner as a null-terminated string. + * @param [in] setup The setup function for the Test Runner + * @param [in] testRunner The function to call to execute the Test Runner. + * @param [in] tearDown The function to call to tear-down the Test Runner. + * @return An allocated LongBowTestRunner structure representing a Test Runner. + */ +LongBowTestRunner *longBowTestRunner_Create(const char *name, + LongBowTestRunnerSetUp *setup, + LongBowTestRunnerRun *testRunner, + LongBowTestRunnerTearDown *tearDown); + +/** + * Destroy a previously allocated LongBowTestRunner structure. + * + * @param [in,out] testRunnerPtr A pointer to a previously allocated LongBowTestRunner structure. + */ +void longBowTestRunner_Destroy(LongBowTestRunner **testRunnerPtr); + +/** + * Get the name of the given LongBowTestRunner. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @return The name of the Test Runner. + */ +const char *longBowTestRunner_GetName(const LongBowTestRunner *testRunner); + +/** + * Get the `LongBowClipBoard` for the given LongBowTestRunner. + * + * Every LongBow test case has an associated "clipboard" that is specific to a test case + * and is shared between the fixture setup and tear down functions. + * Fixture setup may store things on the clipboard, + * the test case may access them and the tear down destroy them. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @return The LongBowClipBoard for the given LongBowTestCase. + */ +LongBowClipBoard *longBowTestRunner_GetClipBoard(const LongBowTestRunner *testRunner); + +/** + * Place a value on the Test Runner "clipboard" + * + * Every Test Runner has an associated "clipboard" which is shared between the Test Runner + * Setup and Test Runner Tear Down and is accessible to all Test Fixtures and Test Cases. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @param [in] shared The value to share on the clipboard. + * @return True if the value was set. + */ +bool longBowTestRunner_SetClipBoardData(const LongBowTestRunner *testRunner, void *shared); + +/** + * Get the clipboard data from the given `LongBowTestRunner`. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + */ +void *longBowTestRunner_GetClipBoardData(const LongBowTestRunner *testRunner); + +/** + * Execute a LongBow Test Runner. + * + * The Test Runner will have zero or more Test Fixtures executed in the order + * they are specified in the Test Runner function. + * See LONGBOW_TEST_RUNNER() + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @return The given LongBowTestRunner + */ +LongBowTestRunner *longBowTestRunner_Run(LongBowTestRunner *testRunner); + +/** + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @return An allocated, nul-terminated C string that must be deallocated via free(3) + */ +char *longBowTestRunner_ToString(const LongBowTestRunner *testRunner); + +/** + * Add the supplied LongBowTestFixture to the list of Test Fixtures for the given Test Runner. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @param [in] testFixture A pointer to a valid LongBowTestFixture instance. + */ +void longBowTestRunner_AddFixture(LongBowTestRunner *testRunner, LongBowTestFixture *testFixture); + +/** + * Get the number of Test Fixtures in the given Test Runner. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @return the number of Test Fixtures in the given Test Runner. + */ +size_t longBowTestRunner_GetFixtureCount(const LongBowTestRunner *testRunner); + +/** + * Get a pointer to the Test Fixture indexed by <code>index</code> in this Test Runner. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @param [in] index The index of the LongBowTestFixture to get. + * @return The corresponding LongBowTestFixture. + */ +LongBowTestFixture *longBowTestRunner_GetFixture(const LongBowTestRunner *testRunner, size_t index); + +/** + * Get the status of the given LongBow Test Fixture. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @return The LongBowStatus of the given LongBowTestRunner + */ +LongBowStatus longBowTestRunner_GetStatus(const LongBowTestRunner *testRunner); + +/** + * Get a pointer to the LongBowConfig structure for the given Test Runner. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @return A pointer to the LongBowConfig structure for the given runner. + */ +LongBowConfig *longBowTestRunner_GetConfiguration(const LongBowTestRunner *testRunner); + +/** + * Return `true` if the given Test Runner was successful. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @return true if the status of the LongBowTestRunner was successful. + */ +bool longBowTestRunner_IsSuccessful(const LongBowTestRunner *testRunner); + +/** + * Return `true` if the given Test Runner was a failure. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return true if the status of the LongBowTestRunner is as a failure. + */ +bool longBowTestRunner_IsFailed(const LongBowTestCase *testCase); + +/** + * Return `true` if the given Test Runner was a warning. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @return true if the status of the LongBowTestRunner was a warning. + */ +bool longBowTestRunner_IsWarning(const LongBowTestRunner *testRunner); + +/** + * Return `true` if the given Test Runner was incomplete. + * + * @param [in] testCase A pointer to a valid LongBowTestCase instance. + * @return true if the status of the LongBowTestRunner was incomplete. + */ +bool longBowTestRunner_IsIncomplete(const LongBowTestCase *testCase); + +/** + * Get the LongBowClipBoard for the given LongBowTestRunner. + * + * Every LongBow test runner has an associated "clipboard" that is specific to a test runner + * and is shared between the runner setup and tear down functions. + * The Test Runner setup may store things on the clipboard, + * the test fixtures and test cases may access them and the test runner tear down destroy them. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @return The LongBowClipBoard for the given LongBowTestRunner. + */ +LongBowClipBoard *longBowTestRunner_GetClipBoard(const LongBowTestRunner *testRunner); + +/** + * Set the configuration for the given LongBowTestRunner. + * + * The <code>LongBowConfig</code> pointed to by <code>configuration</code> is borrowed. + * If it is deallocated, reused, or overwritten results are unpredicable. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + * @param [in] configuration A pointer to a valid LongBowConfig instance. + */ +void longBowTestRunner_SetConfiguration(LongBowTestRunner *testRunner, LongBowConfig *configuration); + +/** + * Get the clipboard data from the given `LongBowTestRunner`. + * + * @param [in] testRunner A pointer to a valid LongBowTestRunner instance. + */ +void *longBowTestRunner_GetClipBoardData(const LongBowTestRunner *testRunner); + +/** + * Update the LongBowConfig instance with information indicated by @p parameter. + * + * @param [in] config A pointer to a valid LongBowConfig instance. + * @param [in] parameter A pointer to nul-terminated C string. + * + * @return true A valid parameter. + * @return false The value of @p parameter is invalid. + */ +bool longBowTestRunner_Config(LongBowConfig *config, const char *parameter); + +/** + * Print command line and configuration help applicable to a Long Bow Test Runner. + * + */ +void longBowTestRunner_ConfigHelp(void); +#endif /* LONGBOWRUNNER_H_ */ diff --git a/longbow/src/LongBow/longBow_UnitTest.h b/longbow/src/LongBow/longBow_UnitTest.h new file mode 100755 index 00000000..340c6fd1 --- /dev/null +++ b/longbow/src/LongBow/longBow_UnitTest.h @@ -0,0 +1,103 @@ +/* + * 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 longBow_UnitTest.h + * @ingroup testing + * @brief Unit Testing Support. + * + */ +#ifndef __LongBow__longBow_UnitTest__ +#define __LongBow__longBow_UnitTest__ + +/** + * Compose the C function name prefix for a Test Runner. + * + * @param [in] _testRunnerName_ A valid identifier for the Test Runner. + */ +#define longBowUnitTest_RunnerName(_testRunnerName_) \ + LongBowTestRunner_ ## _testRunnerName_ + +/** + * Compose the C function name for a Test Runner Setup function. + * + * @param [in] _testRunnerName_ A valid identifier for the Test Runner. + */ +#define longBowUnitTest_RunnerSetupName(_testRunnerName_) \ + LongBowTestRunner_ ## _testRunnerName_ ## _Setup + +/** + * @brief Compose the C function name for a Test Runner Tear-Down function. + * + * @param [in] _testRunnerName_ A valid identifier for the Test Runner. + */ +#define longBowUnitTest_RunnerTearDownName(_testRunnerName_) \ + LongBowTestRunner_ ## _testRunnerName_ ## _TearDown + +/** + * @brief Compose the C function name for a Test Runner function. + * + * @param [in] _testRunnerName_ A valid identifier for the Test Runner. + */ +#define longBowUnitTest_RunnerRunName(_testRunnerName_) \ + LongBowTestRunner_ ## _testRunnerName_ ## _Run + +/** + * @defined longBowUnitTest_FixtureName + * @brief Compose a Test Fixture name. + * @param [in] _testFixtureName_ A valid identifier fragment for the Test Fixture. + */ +#define longBowUnitTest_FixtureName(_testFixtureName_) \ + LongBowTestFixture_ ## _testFixtureName_ + +/** + * @brief Compose the C function name for a Test Fixture function. + * + * @param [in] _testFixtureName_ A valid identifier for the Test Fixture. + */ +#define longBowUnitTest_FixtureRunName(_testFixtureName_) \ + LongBowTestFixture_ ## _testFixtureName_ ## _Run + +/** + * Compose the C function name for a Test Fixture Setup function. + * + * @param [in] _testFixtureName_ A valid identifier for the Test Fixture. + */ +#define longBowUnitTest_FixtureSetupName(_testFixtureName_) \ + LongBowTestFixture_ ## _testFixtureName_ ## _Setup + +/** + * @brief Compose the C function name for a Test Fixture Tear-Down function. + * + * @param [in] _testFixtureName_ A valid identifier for the Test Fixture. + */ +#define longBowUnitTest_FixtureTearDownName(_testFixtureName_) \ + LongBowTestFixture_ ## _testFixtureName_ ## _TearDown + +/** + * @brief Compose the C name for a Test Fixture Configuration structure. + * + * @param [in] _testFixtureName_ A valid identifier for the Test Fixture. + */ +#define longBowUnitTest_FixtureConfigName(_testFixtureName_) \ + LongBowTestFixture_ ## _testFixtureName_ ## _Config + +/** + * + */ +#define longBowUnitTest_CaseName(_testFixtureName_, _testCaseName_) \ + LongBowTestCase_ ## _testFixtureName_ ## _ ## _testCaseName_ + +#endif /* defined(__LongBow__longBow_UnitTest__) */ diff --git a/longbow/src/LongBow/longBow_UnitTesting.c b/longbow/src/LongBow/longBow_UnitTesting.c new file mode 100755 index 00000000..a33846ce --- /dev/null +++ b/longbow/src/LongBow/longBow_UnitTesting.c @@ -0,0 +1,121 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <inttypes.h> +#include <poll.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/param.h> + +#include <LongBow/private/longBow_ArrayList.h> +#include <LongBow/unit-test.h> + +#include <LongBow/longBow_UnitTesting.h> + +bool +longBowUnitTesting_AssertEqualsContract(bool (*equalsFunction)(void *a, void *b), void *x, void *y, void *z, ...) +{ + va_list ap; + va_start(ap, z); + + assertNotNull(x, "The value of x cannot be NULL."); + assertNotNull(y, "The value of y cannot be NULL."); + assertNotNull(z, "The value of z cannot be NULL."); + + assertFalse(x == y, "The value x cannot be the same as y"); + assertFalse(x == z, "The value x cannot be the same as z"); + assertFalse(y == z, "The value y cannot be the same as z"); + + assertTrue(equalsFunction(NULL, NULL), "Equality failed: Equals(NULL, NULL) must be true"); + + assertFalse(equalsFunction(x, NULL), "Equality failed: The value of x must not be Equal to NULL."); + assertFalse(equalsFunction(NULL, x), "Equality failed: NULL must not be equal to the value of x."); + + assertTrue(equalsFunction(x, x), + "Reflexive failed: for any non-null reference value x, equals(x, x) must return true."); + + assertTrue(equalsFunction(x, y), + "Equality failed: The values of x and y must be Equal."); + assertTrue(equalsFunction(x, z), + "Equality failed: The values of x and z must be Equal."); + + assertTrue(equalsFunction(x, y) == equalsFunction(y, x), + "Symmetric equality failed: equals(x, y) == equals(y, x) must true."); + + assertTrue((equalsFunction(x, y) == equalsFunction(y, z)) == equalsFunction(z, x), + "Transitive equality failed: equals(x, y) == equals(y, z) == equals(z, x) must true."); + + int index = 0; + for (void *value = va_arg(ap, void *); value != 0; value = va_arg(ap, void *)) { + assertFalse(equalsFunction(x, value), "Value %d (@%p) must not be equal to x", index, value); + assertTrue(equalsFunction(x, value) == equalsFunction(value, x), + "Symmetric equality failed: equals(x, value) == equals(value, x) must true."); + index++; + } + + va_end(ap); + return true; +} + +bool +longBowUnitTesting_AssertCompareToContract(int (*compareTo)(const void *a, const void *b), + void *exemplar, + void **equivalent, + void **lesser, + void **greater) +{ + assertNotNull(exemplar, "Parameter exemplar must not be NULL"); + assertNotNull(equivalent, "Parameter equivalent must not be NULL"); + assertNotNull(lesser, "Parameter less must not be NULL"); + assertNotNull(greater, "Parameter greater must not be NULL"); + + assertTrue(compareTo(NULL, NULL) == 0, + "Comparison of null values must be 0."); + + assertTrue(compareTo(exemplar, NULL) > 0, + "Comparison of a non-null value to a null value must be > 0."); + + assertTrue(compareTo(NULL, exemplar) < 0, + "Comparison of null value to a non-null value must be < 0."); + + assertTrue(compareTo(exemplar, exemplar) == 0, + "Comparison of a value to itself must == 0"); + + for (int i = 0; equivalent[i] != NULL; i++) { + assertTrue(compareTo(exemplar, equivalent[i]) == 0, + "Comparison of the value to equivalent[%d] must == 0", i); + assertTrue(compareTo(exemplar, equivalent[i]) == -compareTo(equivalent[i], exemplar), + "Requires sgn(compareTo(value, equivalent[%d])) == -sgn(equivalent[%d], value)", i, i); + } + for (int i = 0; lesser[i] != NULL; i++) { + assertTrue(compareTo(exemplar, lesser[i]) > 0, + "Compare of value to lesser[%d] must be > 0", i); + assertTrue(compareTo(exemplar, lesser[i]) == -compareTo(lesser[i], exemplar), + "Requires sgn(compareTo(value, lesser[%d])) == -sgn(lesser[%d], value)", i, i); + } + for (int i = 0; greater[i] != NULL; i++) { + assertTrue(compareTo(exemplar, greater[i]) < 0, + "Compare to greater[%d] must be > 0", i); + assertTrue(compareTo(exemplar, greater[i]) == -compareTo(greater[i], exemplar), + "Requires sgn(compareTo(value, greater[%d])) == -sgn(greater[%d], value)", i, i); + } + + return true; +} diff --git a/longbow/src/LongBow/longBow_UnitTesting.h b/longbow/src/LongBow/longBow_UnitTesting.h new file mode 100755 index 00000000..b03b2f88 --- /dev/null +++ b/longbow/src/LongBow/longBow_UnitTesting.h @@ -0,0 +1,91 @@ +/* + * 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 longBow_UnitTesting.h + * @ingroup testing + * @brief Unit Testing Support. + * + */ +#ifndef LongBow_longBow_UnitTesting_h +#define LongBow_longBow_UnitTesting_h + +#include <stdbool.h> +#include <stdarg.h> + +/** + * Test a that a function implements the Equals contract. + * + * The equality function that this evaluates must implement the following equivalence relations on non-null instances: + * + * * It is reflexive: for any non-null reference value x, equals(x, x) must return true. + * + * * It is symmetric: for any non-null reference values x and y, equals(x, y) must return true if and only if + * equals(y x) returns true. + * + * * It is transitive: for any non-null reference values x, y, and z, if + * equals(x, y) returns true and + * equals(y, z) returns true, + * then equals(x, z) must return true. + * + * * It is consistent: for any non-null reference values x and y, multiple invocations of equals(x, y) + * consistently return true or consistently return false. + * + * * For any non-null reference value x, equals(x, NULL)) must return false. + * + * @param [in] equalsFunction A pointer to a function that will be called to determine if it conforms to the Equals contract. + * @param [in] x A pointer to a value that will be used as the base comparision for remaining parameters. + * @param [in] y A pointer to a value that is known to be equal to @p x, but is not @p x. + * @param [in] z A pointer to a value that is known to be equal to @p x and to @p y, but is neither @p x nor @p y. + * @param [in] ... A NULL terminated list of pointers to values that are known to be not equal to @p x, @p y, or @p z. + * @return true if the function conforms to the Equals contract. + * @see assertEqualsContract() + */ +bool longBowUnitTesting_AssertEqualsContract(bool (*equalsFunction)(void *a, void *b), void *x, void *y, void *z, ...); + +/** + * Compares instance <code>a</code> with instance <code>b</code> for order. + * + * The comparison function that this evaluates <i>sgn(a - b)</i> required to return a negative integer, + * zero, or a positive integer as <code>a</code> is less than, + * equal to, or greater than <code>b</code>. + * + * The function must ensure that: + * <ul> + * <li>sgn(compareTo(a, b)) == -sgn(b, a) for all values of a and b.</li> + * <li>the relation is transitive: (compareTo(x, y)>0 && compareTo(y, z)>0) implies compareTo(x, z)>0.</li> + * <li>compareTo(x, y)== 0 implies that sgn(compareTo(x, z)) == sgn(compareTo(y, z)), for all values of z.</li> + * </ul> + * + * This also stipulates that + * <code>compareTo(NULL, NULL)) == 0</code>, + * <code>compareTo(not-NULL, NULL)) > 0</code>, + * <code>compareTo(NULL, not-NULL)) < 0</code>. + * + * It is strongly recommended, but not strictly required that relation(compareTo(x, y)==0) == equals(x, y)) is true. + * Any module that implements the compareTo function and violates this condition + * should clearly indicate this fact. + * For example, "Note: this implementation has a natural ordering that is inconsistent with equals." + * + * @param [in] compareTo A pointer to a function implementing the CompareTo function signature. + * @param [in] value The pivotal value under test. + * @param [in] equivalent A NULL terminated array of values that are all equivalent to <code>value</code>. + * @param [in] lesser A NULL terminated array of values that are all less than <code>value</code>. + * @param [in] greater A NULL terminated array of values that are all greater than <code>value</code>. + * @return <code>true</code> if the evalutation is successful. + * @see assertCompareToContract() + */ +bool longBowUnitTesting_AssertCompareToContract(int (*compareTo)(const void *a, const void *b), void *value, void **equivalent, void **lesser, void **greater); +#endif // LongBow_longBow_UnitTesting_h diff --git a/longbow/src/LongBow/private/longBow_ArrayList.c b/longbow/src/LongBow/private/longBow_ArrayList.c new file mode 100755 index 00000000..91cf02b9 --- /dev/null +++ b/longbow/src/LongBow/private/longBow_ArrayList.c @@ -0,0 +1,277 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <stdbool.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#include <LongBow/runtime.h> +#include <LongBow/private/longBow_ArrayList.h> +#include <LongBow/private/longBow_Memory.h> + +struct longbow_array_list { + void **array; + size_t numberOfElements; + size_t limit; + void (*destroyElement)(void **elementAddress); +}; + +static LongBowArrayList *_longBowArrayList_EnsureRemaining(LongBowArrayList *array, size_t remnant); +static LongBowArrayList *_longBowArrayList_EnsureCapacity(LongBowArrayList *array, size_t newCapacity); + +void +longBowArrayList_AssertValid(const LongBowArrayList *array) +{ + if (array == NULL) { + printf("Parameter must be a non-null pointer to a LongBowArrayList instance\n"); + abort(); + } +} + +LongBowArrayList * +longBowArrayList_Add(LongBowArrayList *array, const void *pointer) +{ + longBowArrayList_AssertValid(array); + + if (_longBowArrayList_EnsureRemaining(array, 1) == NULL) { + return NULL; + } + array->array[array->numberOfElements++] = (void *) pointer; + + return array; +} + +static size_t +_longBowArrayList_Remaining(const LongBowArrayList *array) +{ + longBowArrayList_AssertValid(array); + + return array->limit - array->numberOfElements; +} + +static LongBowArrayList * +_longBowArrayList_EnsureCapacity(LongBowArrayList *array, size_t newCapacity) +{ + longBowArrayList_AssertValid(array); + + void *newArray = longBowMemory_Reallocate(array->array, newCapacity * sizeof(void *)); + + if (newArray == NULL) { + return NULL; + } + array->array = newArray; + array->limit = newCapacity; + + return array; +} + +static LongBowArrayList * +_longBowArrayList_EnsureRemaining(LongBowArrayList *array, size_t remnant) +{ + longBowArrayList_AssertValid(array); + + if (_longBowArrayList_Remaining(array) < remnant) { + size_t newCapacity = longBowArrayList_Length(array) + remnant; + return _longBowArrayList_EnsureCapacity(array, newCapacity); + } + return array; +} + +bool +longBowArrayList_Equals(const LongBowArrayList *a, const LongBowArrayList *b) +{ + if (a != b) { + if (a == NULL || b == NULL) { + return false; + } + if (a->numberOfElements == b->numberOfElements) { + for (size_t i = 0; i < a->numberOfElements; i++) { + if (a->array[i] != b->array[i]) { + return false; + } + } + } + } + + return true; +} + +void * +longBowArrayList_Get(const LongBowArrayList *array, size_t index) +{ + longBowArrayList_AssertValid(array); + + assert(index < array->numberOfElements); + + return array->array[index]; +} + +size_t +longBowArrayList_Length(const LongBowArrayList *array) +{ + longBowArrayList_AssertValid(array); + + return array->numberOfElements; +} + +LongBowArrayList * +longBowArrayList_Create(void (*destroyElement)(void **elementAddress)) +{ + LongBowArrayList *result = longBowMemory_Allocate(sizeof(LongBowArrayList)); + + if (result != NULL) { + result->numberOfElements = 0; + result->limit = 0; + result->array = NULL; + result->destroyElement = destroyElement; + } + + return result; +} + +LongBowArrayList * +longBowArrayList_Create_Capacity(void (*destroyElement)(void **elementAddress), size_t size) +{ + LongBowArrayList *result = longBowArrayList_Create(destroyElement); + if (result != NULL) { + _longBowArrayList_EnsureRemaining(result, size); + } + + return result; +} + +void +longBowArrayList_Destroy(LongBowArrayList **arrayPtr) +{ + assertNotNull(arrayPtr, "Parameter must be a non-null pointer to a LongBow_ArrayList pointer."); + + LongBowArrayList *array = *arrayPtr; + + longBowArrayList_AssertValid(array); + + assertTrue(array->numberOfElements == 0 ? true : array->array != NULL, "LongBow_ArrayList is inconsistent."); + + if (array->destroyElement != NULL) { + for (size_t i = 0; i < array->numberOfElements; i++) { + array->destroyElement(&array->array[i]); + array->array[i] = NULL; + } + } + + if (array->array != NULL) { + longBowMemory_Deallocate((void **) &array->array); + } + + longBowMemory_Deallocate((void **) arrayPtr); +} + +void ** +longBowArrayList_GetArray(const LongBowArrayList *array) +{ + longBowArrayList_AssertValid(array); + return array->array; +} + +LongBowArrayList * +longBowArrayList_Copy(const LongBowArrayList *original) +{ + longBowArrayList_AssertValid(original); + + LongBowArrayList *result = longBowMemory_Allocate(sizeof(LongBowArrayList)); + + if (result != NULL) { + for (size_t i = 0; i < original->numberOfElements; i++) { + longBowArrayList_Add(result, original->array[i]); + } + } + + return result; +} + +void +longBowArrayList_StdlibFreeFunction(void **elementPtr) +{ + if (elementPtr != NULL) { + free(*elementPtr); + *elementPtr = 0; + } +} + +LongBowArrayList * +longBowArrayList_RemoveAtIndex(LongBowArrayList *array, size_t index) +{ + longBowArrayList_AssertValid(array); + + size_t length = longBowArrayList_Length(array); + assertTrue(index < length, "Index must be ( 0 <= index < %zd). Actual=%zd", length, index); + + if (index < length) { + // Destroy the element at the given index. + if (array->destroyElement != NULL) { + array->destroyElement(&array->array[index]); + } + + // Adjust the list to elide the element. + for (size_t i = index; i < length; i++) { + array->array[i] = array->array[i + 1]; + } + array->numberOfElements--; + } + + return array; +} + +LongBowArrayList * +longBowArrayList_Add_AtIndex(LongBowArrayList *array, const void *pointer, size_t index) +{ + longBowArrayList_AssertValid(array); + size_t length = longBowArrayList_Length(array); + + if (index > array->limit) { + // We need to grow the array to fit this element. + _longBowArrayList_EnsureCapacity(array, index + 1); + array->numberOfElements = index + 1; + } else { + // Create space and grow the array if needed + _longBowArrayList_EnsureRemaining(array, length + 1); + for (size_t i = index; i < length; i++) { + array->array[i + 1] = array->array[i]; + } + array->numberOfElements++; + } + + array->array[index] = (void *) pointer; + + + return array; +} + +bool +longBowArrayList_Replace(LongBowArrayList *array, const void *old, void *new) +{ + for (size_t i = 0; i < longBowArrayList_Length(array); i++) { + if (array->array[i] == old) { + array->array[i] = new; + return true; + } + } + return false; +} diff --git a/longbow/src/LongBow/private/longBow_ArrayList.h b/longbow/src/LongBow/private/longBow_ArrayList.h new file mode 100644 index 00000000..71eeb2b9 --- /dev/null +++ b/longbow/src/LongBow/private/longBow_ArrayList.h @@ -0,0 +1,225 @@ +/* + * 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 longBow_ArrayList.h + * @ingroup internals + * @brief A simple, list implementation using a dynamic array. + * + */ +#ifndef LongBow_ARRAYLIST_H +#define LongBow_ARRAYLIST_H + +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> + +/** + * @struct longbow_array_list + * @brief A LongBow_ArrayList is a (dynamic) array of <code>void *</code> pointers; + */ +struct longbow_array_list; + +/** + * @typedef LongBowArrayList + * @brief The struct longbow_array_list + */ +typedef struct longbow_array_list LongBowArrayList; + +/** + * Assert that a LongBowArrayList instance is valid. + * + * @param [in] array A pointer to a valid LongBowArrayList instance. + * + */ +void longBowArrayList_AssertValid(const LongBowArrayList *array); +/** + * Add a pointer to an element to the given LongBowArrayList. + * + * If the list was constructed with a destroyer, + * the pointer will be destroyed when element is removed or the list is destroyed. + * + * @param [in] array A pointer to a LongBowArrayList instance. + * @param [in] pointer An arbitrary value to store. + * + * @return The input array pointer. + */ +LongBowArrayList *longBowArrayList_Add(LongBowArrayList *array, const void *pointer); + +/** + * Remove an element at a specific index from an Array List. + * + * The element is destroyed via the function provided when calling <code>longBowArrayList_Create</code>. + * + * @param [in] array A pointer to a LongBowArrayList instance. + * @param [in] index The index of the element to remove. + * + * @return A pointer to the modified LongBowArrayList. + */ +LongBowArrayList *longBowArrayList_RemoveAtIndex(LongBowArrayList *array, size_t index); + +/** + * Add an element at the index location. Elements will be moved up if required. + * If the index is higher than the current Length the Array will be grown to that size + * + * @param [in] array A pointer to a LongBowArrayList instance. + * @param [in] pointer An arbitrary value to store. + * @param [in] index The position that the value will be stored after. + * @return A pointer to the modified LongBowArrayList. + */ +LongBowArrayList *longBowArrayList_Add_AtIndex(LongBowArrayList *array, const void *pointer, size_t index); + +/** + * Create an instance of an empty LongBowArrayList. + * + * @param [in] destroyElement + * A pointer to a function that will destroy (or equivalent) the element pointed to by <code>element</code> + * @return A pointer to a LongBowArrayList instance, or NULL if no memory could be allocated. + */ +LongBowArrayList *longBowArrayList_Create(void (*destroyElement)(void **elementAddress)); + +/** + * Create an instance of a LongBowArrayList pre-provisioned to contain the specified number of elements. + * + * @param [in] size + * The number of initial elements to provision for. + * @param [in] destroyElement + * A pointer to a function that will destroy (or equivalent) the element pointed to by <code>element</code> + * @return A pointer to a LongBowArrayList instance, or NULL if no memory could be allocated. + */ +LongBowArrayList *longBowArrayList_Create_Capacity(void (*destroyElement)(void **elementAddress), size_t size); + +/** + * Get an array of void * pointers. + * Return a pointer to an array of void * pointers contained in this Array List. + * The returned value may be the actual backing array for the Array List. + * + * @param [in] array The LongBow_ArrayList + * @return A pointer to an array of void * pointers contained in this Array List. + * + */ +void **longBowArrayList_GetArray(const LongBowArrayList *array); + +/** + * Copy a LongBowArrayList instance. + * Create a new LongBowArrayList instance with the same structure and content as the original. + * + * @param [in] array A pointer to a LongBowArrayList instance to copy. + * @return A pointer to a LongBowArrayList instance with a copy of the original, or NULL if no memory could be allocated. + */ +LongBowArrayList *longBowArrayList_Copy(const LongBowArrayList *array); + +/** + * Destroy a LongBowArrayList instance. + * + * Destroy the given LongBowArrayList by freeing all memory used by it. + * + * @param [in,out] arrayPtr A pointer to a LongBowArrayList pointer. + */ +void longBowArrayList_Destroy(LongBowArrayList **arrayPtr); + +/** + * Get an element from the given list at a specified index. + * The index must be 0 <= index < length. + * + * @return A pointer (void *) to the element in the list. + * + * @param [in] array A pointer to a LongBowArrayList instance. + * @param [in] index The index of the required element. + */ +void *longBowArrayList_Get(const LongBowArrayList *array, size_t index); + +/** + * Return the number of elements in the given LongBowArrayList. + * + * @param [in] array A pointer to a LongBowArrayList instance. + * @return A size_t of the number of elements in the given LongBowArrayList. + */ +size_t longBowArrayList_Length(const LongBowArrayList *array); + + +/** + * Determine if two LongBowArrayList instances are equal. + * + * Two LongBowArrayList instances are equal if, and only if, they both contain the same pointers in the same order. + * + * The following equivalence relations on non-null `LongBowArrayList` instances are maintained: + * + * * It is reflexive: for any non-null reference value x, `LongBowArrayList_Equals(x, x)` + * must return true. + * + * * It is symmetric: for any non-null reference values x and y, + * `longBowArrayList_Equals(x, y)` must return true if and only if + * `longBowArrayList_Equals(y, x)` returns true. + * + * * It is transitive: for any non-null reference values x, y, and z, if + * `longBowArrayList_Equals(x, y)` returns true and + * `longBowArrayList_Equals(y, z)` returns true, + * then `longBowArrayList_Equals(x, z)` must return true. + * + * * It is consistent: for any non-null reference values x and y, multiple + * invocations of `longBowArrayList_Equals(x, y)` consistently return true or + * consistently return false. + * + * * For any non-null reference value x, `longBowArrayList_Equals(x, NULL)` must + * return false. + * + * @param a A pointer to a `LongBowArrayList` instance. + * @param b A pointer to a `LongBowArrayList` instance. + * @return true if the two `LongBowArrayList` instances are equal. + * + * Example: + * @code + * { + * LongBowArrayList *a = longBowArrayList_Create(); + * LongBowArrayList *b = longBowArrayList_Create(); + * + * if (longBowArrayList_Equals(a, b)) { + * // true + * } else { + * // false + * } + * } + * @endcode + */ + +bool longBowArrayList_Equals(const LongBowArrayList *a, const LongBowArrayList *b); + +/** + * Standard library free(3) wrapper for use as a destructor function for elements of a LongBowArrayList. + * + * The create functions for LongBowArrayList have an input parameter that is a pointer to a function that + * will be called for each element when the Array List is destroyed, and when an element is removed via longBowArrayList_RemoveAtIndex. + * This destroy function has a different calling signature than the standard library's free(3) function. + * This function is a wrapper providing the correct facade for the standard library free(3) function. + * + * @param [in,out] element A pointer to the pointer to an element to be destroyed. + */ +void longBowArrayList_StdlibFreeFunction(void **element); + +/** + * Replace the first occurance of an existing element in the given LongBowArrayList. + * + * Paragraphs Of Explanation + * + * @param [in] array A pointer to a LongBowArrayList instance. + * @param [in] old A pointer to an element in the list to replace. + * @param [in] new A pointer to an element that will replace old. + * + * @return true If the element was found and replaced. + * @return false If the element was not found. + */ +bool longBowArrayList_Replace(LongBowArrayList *array, const void *old, void *new); +#endif // LongBow_ARRAYLIST_H diff --git a/longbow/src/LongBow/private/longBow_Memory.c b/longbow/src/LongBow/private/longBow_Memory.c new file mode 100644 index 00000000..1c20101e --- /dev/null +++ b/longbow/src/LongBow/private/longBow_Memory.c @@ -0,0 +1,95 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <LongBow/private/longBow_Memory.h> + +#if HAVE_REALLOC == 0 +static void * +_LongBow_rplRealloc(void *oldAlloc, size_t newSize) +{ + if (newSize == 0) { + newSize = 1; + } + + char *newAlloc = malloc(newSize); + + if (oldAlloc != NULL) { + memcpy(newAlloc, oldAlloc, newSize); + free(oldAlloc); + } + return newAlloc; +} +#endif + +static uint64_t _outstandingAllocations; + +void * +longBowMemory_Allocate(const size_t size) +{ + _outstandingAllocations++; + return calloc(1, size); +} + +void * +longBowMemory_Reallocate(void *oldAllocation, const size_t newSize) +{ +#if HAVE_REALLOC + void *result = realloc(oldAllocation, newSize); +#else + void *result = _LongBow_rplRealloc(oldAllocation, newSize); +#endif + + if (oldAllocation == NULL) { + _outstandingAllocations++; + } + + return result; +} + +void +longBowMemory_Deallocate(void **pointerPointer) +{ + free(*pointerPointer); + _outstandingAllocations--; + *pointerPointer = NULL; +} + +uint64_t +longBowMemory_OutstandingAllocations(void) +{ + return _outstandingAllocations; +} + +char * +longBowMemory_StringCopy(const char *string) +{ + char *result = NULL; + + if (string != NULL) { + size_t length = strlen(string); + result = longBowMemory_Allocate(length + 1); + strcpy(result, string); + result[length] = 0; + } + return result; +} diff --git a/longbow/src/LongBow/private/longBow_Memory.h b/longbow/src/LongBow/private/longBow_Memory.h new file mode 100755 index 00000000..173491dc --- /dev/null +++ b/longbow/src/LongBow/private/longBow_Memory.h @@ -0,0 +1,93 @@ +/* + * 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 longBow_Memory.c + * @ingroup internal + * @brief Memory allocation and deallocation support. + * + */ +#ifndef LongBow_longBow_Memory_h +#define LongBow_longBow_Memory_h + +#include <stdint.h> + +/** + * Allocate `size` bytes of memory. + * + * @param [in] size The number of bytes to allocate + * + * @return non-NULL A pointer to allocated memory that must be deallocated via `longBowMemory_Deallocate` + * @return NULL Memory could not be allocated. + * @see longBowMemory_Deallocate + */ +void *longBowMemory_Allocate(const size_t size); + +/** + * Reallocate memory adjusting to a new size. + * + * @param [in] oldAllocation A pointer to memory previously allocated by `longBowMemory_Allocate` or `longBowMemory_Reallocate` + * @param [in] newSize The number of bytes to allocate + * + * @return non-NULL A pointer to allocated memory that must be deallocated via `longBowMemory_Deallocate` + * @return NULL Memory could not be allocated. + * @see longBowMemory_Allocate + */ +void *longBowMemory_Reallocate(void *oldAllocation, const size_t newSize); + +/** + * Deallocate previously allocated memory. + * + * @param [in,out] pointerPointer A pointer to a pointer to allocated memory that will set to NULL. + * + * @see longBowMemory_Allocate + */ +void longBowMemory_Deallocate(void **pointerPointer); + +/** + * Duplicate a nul-terminated C string in allocated memory. + * + * @param [in] string The nul-terminated string to duplicate + * + * @return non-NULL A pointer to allocated memory that must be deallocated via `longBowMemory_Deallocate` + * @return NULL Memory could not be allocated. + * + * Example: + * @code + * { + * char *copy = longBowMemory_StringCopy("Hello World"); + * + * longBowMemory_Deallocate((void **) ©); + * } + * @endcode + * + * @see longBowMemory_Deallocate + */ +char *longBowMemory_StringCopy(const char *string); + +/** + * Get the count of outstanding memory allocations. + * + * @return The number of outstanding memory allocations. + * + * Example: + * @code + * { + * <#example#> + * } + * @endcode + */ +uint64_t longBowMemory_OutstandingAllocations(void); +#endif diff --git a/longbow/src/LongBow/private/longBow_OpenFile.c b/longbow/src/LongBow/private/longBow_OpenFile.c new file mode 100644 index 00000000..6b82069f --- /dev/null +++ b/longbow/src/LongBow/private/longBow_OpenFile.c @@ -0,0 +1,151 @@ +/* + * 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. + */ + +/** + */ +#include <config.h> + +#include <stdio.h> +#include <inttypes.h> +#include <stdlib.h> +#include <poll.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/param.h> +#include <sys/resource.h> +#include <string.h> + +#include <LongBow/private/longBow_OpenFile.h> +#include <LongBow/private/longBow_Memory.h> +#include <LongBow/private/longBow_String.h> + +struct longbow_openfile { + char *fullPathName; + struct stat statbuf; + int fd; +}; + +#if defined(_WIN64) +static char * +_getFullPathNameFromFd(int fd) +{ + return strdup("./"); +} +#elif defined(_WIN32) +static char * +_getFullPathNameFromFd(int fd) +{ + return strdup("./"); +} +#elif defined(__APPLE__) +static char * +_getFullPathNameFromFd(int fd) +{ + char filePath[PATH_MAX]; + + if (fcntl(fd, F_GETPATH, filePath) != -1) { + return strdup(filePath); + } + return NULL; +} +#elif defined(__linux) +static char * +_getFullPathNameFromFd(int fd) +{ + return strdup("./"); +} +#elif defined(__unix) // all unices not caught above +static char * +_getFullPathNameFromFd(int fd) +{ + return strdup("./"); +} +#elif defined(__posix) +static char * +_getFullPathNameFromFd(int fd) +{ + return strdup("./"); +} +#endif + +LongBowOpenFile * +longBowOpenFile_Create(int fd) +{ + LongBowOpenFile *result = longBowMemory_Allocate(sizeof(LongBowOpenFile)); + if (result != NULL) { + result->fd = fd; + + if (fstat(fd, &result->statbuf) == 0) { + result->fullPathName = _getFullPathNameFromFd(fd); + } + } + return result; +} + +void +longBowOpenFile_Destroy(LongBowOpenFile **openFilePtr) +{ + longBowMemory_Deallocate((void **) openFilePtr); +} + +char * +longBowOpenFile_StructStatToString(const struct stat *statbuf) +{ + LongBowString *string = longBowString_CreateFormat("0x%" PRIx16 " %3ld %10d %10d %6lld", + statbuf->st_mode, + (long) statbuf->st_nlink, + statbuf->st_uid, + statbuf->st_gid, + (long long) statbuf->st_size); + char *result = longBowString_ToString(string); + + return result; +} + +char * +longBowOpenFile_ToString(LongBowOpenFile *openFile) +{ + char *statString = longBowOpenFile_StructStatToString(&(openFile->statbuf)); + LongBowString *string = longBowString_CreateFormat("%d %s %s", openFile->fd, statString, openFile->fullPathName); + free(statString); + char *result = longBowString_ToString(string); + + return result; +} + +LongBowArrayList * +longBowOpenFile_CurrentlyOpen(void) +{ + struct rlimit rlimit; + + bool success = getrlimit(RLIMIT_NOFILE, &rlimit) == 0; + if (!success) { + return NULL; + } + // Here is a potential problem: struct rlimit specifies rlim_cur as a 64 bit value (rlim_t), but poll only takes an + // unsigned int's worth of file descriptors. + + LongBowArrayList *list = longBowArrayList_Create(longBowArrayList_StdlibFreeFunction); + + for (nfds_t i = 0; i < (nfds_t) rlimit.rlim_cur; i++) { + int flags = fcntl((int) i, F_GETFD); + if (flags != -1) { + LongBowOpenFile *openFile = longBowOpenFile_Create((int) i); + longBowArrayList_Add(list, openFile); + } + } + + return list; +} diff --git a/longbow/src/LongBow/private/longBow_OpenFile.h b/longbow/src/LongBow/private/longBow_OpenFile.h new file mode 100755 index 00000000..10756ba5 --- /dev/null +++ b/longbow/src/LongBow/private/longBow_OpenFile.h @@ -0,0 +1,70 @@ +/* + * 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 longBow_OpenFile.h + * @ingroup testing + * @brief LongBow support for files and file descriptors. + * + */ +#ifndef LongBow_longBow_Files_h +#define LongBow_longBow_Files_h + +#include <sys/stat.h> + +#include <LongBow/private/longBow_ArrayList.h> + +struct longbow_openfile; +/** + * @typedef LongBowOpenFile + * @brief A representation of an open file. + */ +typedef struct longbow_openfile LongBowOpenFile; + +/** + * @param [in] fd The file descriptor. + * @return An allocated LongBowOpenFile instance that must be destroyed via longBowOpenFile_Destroy(). + */ +LongBowOpenFile *longBowOpenFile_Create(int fd); + +/** + * + * @param [in,out] openFilePtr A pointer to a pointer to a valid LongBowOpenFile instance. + */ +void longBowOpenFile_Destroy(LongBowOpenFile **openFilePtr); + +/** + * + * @param [in] openFile A pointer to a valid LongBowOpenFile instance. + * @return A nul-terminate C string that must be freed via free(3). + */ +char *longBowOpenFile_ToString(LongBowOpenFile *openFile); + +/** + * Create a list of the currently open files. + * + * @return A list of LongBowOpenFile instances for each open file. + */ +LongBowArrayList *longBowOpenFile_CurrentlyOpen(void); + +/** + * Return a nul-terminated C string representing the given `struct stat` pointed to by @p statbuf. + * + * @param [in] statbuf A pointer to a valid `struct stat` instance. + * + * @return non-NULL A nul-terminated C string that must be deallocated via longBowMemory_Deallocate. + */ +char *longBowOpenFile_StructStatToString(const struct stat *statbuf); +#endif diff --git a/longbow/src/LongBow/private/longBow_String.c b/longbow/src/LongBow/private/longBow_String.c new file mode 100644 index 00000000..1def87a1 --- /dev/null +++ b/longbow/src/LongBow/private/longBow_String.c @@ -0,0 +1,180 @@ +/* + * 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. + */ + +/** + */ +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#include <LongBow/private/longBow_String.h> +#include <LongBow/private/longBow_Memory.h> + +struct longbow_string { + char *buffer; + size_t cursor; // always the index of the nul terminating byte of the stored string. + size_t end; // always the index of the very last byte in buffer; +}; + +static size_t +_longBowString_RemainingSpace(const LongBowString *string) +{ + size_t result = string->end - string->cursor; + + return result; +} + +LongBowString * +longBowString_Create(const size_t initialSize) +{ + LongBowString *result = longBowMemory_Allocate(sizeof(LongBowString)); + result->end = initialSize; + result->buffer = longBowMemory_Allocate(initialSize); + result->cursor = 0; + + return result; +} + +LongBowString * +longBowString_CreateString(const char *string) +{ + LongBowString *result = longBowMemory_Allocate(sizeof(LongBowString)); + result->end = strlen(string) + 1; + result->buffer = longBowMemory_StringCopy(string); + result->cursor = result->end - 1; + result->buffer[result->cursor] = 0; + + return result; +} + +LongBowString * +longBowString_CreateFormat(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + char *cString; + if (vasprintf(&cString, format, ap) == -1) { + return NULL; + } + va_end(ap); + + LongBowString *string = longBowString_CreateString(cString); + + free(cString); + + return string; +} + +void +longBowString_Destroy(LongBowString **stringPtr) +{ + LongBowString *string = *stringPtr; + if (string != NULL) { + longBowMemory_Deallocate((void **) &string->buffer); + longBowMemory_Deallocate((void **) stringPtr); + } +} + +LongBowString * +longBowString_Append(LongBowString *string, const char *value) +{ + size_t length = strlen(value) + 1; + + if (_longBowString_RemainingSpace(string) < length) { + size_t size = string->end + length; + string->buffer = longBowMemory_Reallocate(string->buffer, size); + string->end = size - 1; + } + strcpy(&string->buffer[string->cursor], value); + string->cursor += (length - 1); + string->buffer[string->cursor] = 0; + + return string; +} + +LongBowString * +longBowString_Format(LongBowString *string, const char *format, ...) +{ + LongBowString *result = NULL; + + va_list ap; + va_start(ap, format); + + char *cString; + int status = vasprintf(&cString, format, ap); + va_end(ap); + if (status != -1) { + result = longBowString_Append(string, cString); + free(cString); + } else { + result = NULL; + } + + return result; +} + +char * +longBowString_ToString(const LongBowString *string) +{ + char *result = strndup(string->buffer, string->end); + return result; +} + +bool +longBowString_StartsWith(const char *string, const char *prefix) +{ + bool result = strncmp(string, prefix, strlen(prefix)) == 0; + return result; +} + +bool +longBowString_Equals(const char *string, const char *other) +{ + return strcmp(string, other) == 0; +} + +bool +longBowString_Write(const LongBowString *string, FILE *fp) +{ + bool result = false; + size_t nwrite = string->end; + + if (fwrite(string->buffer, sizeof(char), string->end, fp) == nwrite) { + result = true; + } + + return result; +} + +LongBowArrayList * +longBowString_Tokenise(const char *string, const char *separators) +{ + LongBowArrayList *result = longBowArrayList_Create(longBowMemory_Deallocate); + if (string != NULL) { + char *workingCopy = longBowMemory_StringCopy(string); + + char *p = strtok(workingCopy, separators); + while (p) { + longBowArrayList_Add(result, longBowMemory_StringCopy(p)); + p = strtok(NULL, separators); + } + + longBowMemory_Deallocate((void **) &workingCopy); + } + + return result; +} diff --git a/longbow/src/LongBow/private/longBow_String.h b/longbow/src/LongBow/private/longBow_String.h new file mode 100755 index 00000000..463dfbd8 --- /dev/null +++ b/longbow/src/LongBow/private/longBow_String.h @@ -0,0 +1,151 @@ +/* + * 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 longBow_String.h + * @brief <#Brief Description#> + * + * <#Detailed Description#> + * + */ +#ifndef __LongBow__longBow_String__ +#define __LongBow__longBow_String__ + +#include <stdbool.h> +#include <stdio.h> + +#include <LongBow/private/longBow_ArrayList.h> + +struct longbow_String; +typedef struct longbow_string LongBowString; + +/** + * Create a LongBowString + * + * <#Paragraphs Of Explanation#> + * + * @param [in] initialSize The initial buffer size to allocate for the string. + * + * @return non-NULL A pointer to a valid LongBowString instance. + * @return NULL Memory could not be allocated. + * + */ +LongBowString *longBowString_Create(const size_t initialSize); + +/** + * Create a `LongBowString` instance containing the formatted result of the given format string and parameters. + * + * @param [in] format A pointer to a valid LongBowString instance. + * + * @return The a LongBowString instance that must be deallocated via longBowString_Deallocate. + */ +LongBowString *longBowString_CreateFormat(const char *format, ...) __attribute__((format(printf, 1, 2))); + +/** + * Destroy a LongBowString instance. + * + * The pointer will be set to zero on return. + * + * @param [in,out] stringPtr A pointer to a valid LongBowString instance. + */ +void longBowString_Destroy(LongBowString **stringPtr); + +/** + * Append to the given LongBowString instance the formatted result of the given format string and parameters. + * + * @param [in] string A pointer to a valid LongBowString instance. + * + * @return The value of @p string + */ +LongBowString *longBowString_Format(LongBowString *string, const char *format, ...) __attribute__((format(printf, 2, 3))); + +/** + * Determine if a string begins with a specific prefix. + * + * @param [in] string A nul-terminated C string. + * @param [in] prefix A nul-terminated C string. + * + * @return true The value of @p string starts with @p prefix. + * @return false The value of @p string does not start with @p prefix. + * + * Example: + * @code + * { + * bool result = longBowString_StartsWith("Hello World", "Hello"); + * } + * @endcode + */ +bool longBowString_StartsWith(const char *string, const char *prefix); + +/** + * Determine if a nul-terminated C string is equal to another. + * + * @param [in] string A nul-terminated C string. + * @param [in] other A nul-terminated C string. + * + * @return true The value of @p string starts with @p prefix. + * @return false The value of @p string does not start with @p prefix. + * + * Example: + * @code + * { + * bool result = longBowString_StartsWith("Hello World", "Hello"); + * } + * @endcode + */ +bool longBowString_Equals(const char *string, const char *other); + +/** + * Produce a LongBowArrayList containing the tokens for the given @p string + * where each token is separated by characters in the string @p separators. + * + * @param [in] string A nul-terminated C string. + * @param [in] separators A nul-terminated C string containing the characters that separate the tokens. + * + * @return non-NULL A valid LongBowArrayList containing the tokens of the string. + * @return NULL Memory could not be allocated. + * + * Example: + * @code + * { + * LongBowArrayList *result = longBowString_Tokenise("Hello World", " "); + * .... + * longBowArrayList_Destroy(&result); + * } + * @endcode + */ +LongBowArrayList *longBowString_Tokenise(const char *string, const char *separators); + +/** + * Produce a nul-terminated C string from the given LongBowString instance. + * + * @param [in] string A pointer to a valid LongBowString instance. + * + * @return non-NULL A pointer to a nul-terminated C string that must be deallocated via free(3). + */ +char *longBowString_ToString(const LongBowString *string); + +/** + * Write the contents of the given LongBowString instance to the specified FILE output stream. + * + * @param [in] string A pointer to a valid LongBowString instance. + * @param [in] fp A pointer to a valid FILE instance. + * + * @return true All of the string was successfully written. + * @return false All of the string was not successfully written. + */ +bool longBowString_Write(const LongBowString *string, FILE *fp); + +#endif /* defined(__LongBow__longBow_String__) */ diff --git a/longbow/src/LongBow/runtime.h b/longbow/src/LongBow/runtime.h new file mode 100644 index 00000000..5acd790d --- /dev/null +++ b/longbow/src/LongBow/runtime.h @@ -0,0 +1,110 @@ +/* + * 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 runtime.h + * @ingroup runtime + * @brief LongBow Runtime Support + * + */ +#ifndef LongBow_runtime_h +#define LongBow_runtime_h + +#include <signal.h> + +#include <LongBow/longBow_Runtime.h> + +/** + * @def longBowIsFalse + * @brief Indicate true if a condition is false. + * + * @param [in] condition The condition to test. + */ +#if __GNUC__ +# define longBowIsFalse(condition) __builtin_expect(!(condition), 0) +#else +# define longBowIsFalse(condition) (!(condition)) +#endif + +#if __STDC_VERSION__ < 199901L +# define __func__ ((const char *) 0) +#endif + +/** + * @def longBowEvent + * @brief If the condition is true record the given event and abort the running programme. + * + * @param [in] eventPointer + * @param [in] condition A boolean value that is expected to be true. + * @param [in] location A pointer to a LongBowLocation instance. + * @param [in] ... A printf format string following corresponding parameters. + */ +#ifdef LongBow_DISABLE_ASSERTIONS +#define longBowEvent(eventPointer, condition, location, ...) if (0 && condition) for (; false; ) +#else +#define longBowEvent(eventPointer, condition, location, ...) \ + if (longBowRuntime_EventEvaluation(eventPointer) && longBowIsFalse(condition) && \ + longBowRuntime_EventTrigger(eventPointer, location, #condition, __VA_ARGS__)) \ + for (; true; longBowRuntime_Abort(), kill(0, SIGTRAP)) +#endif + +/** + * @def longBowAssert + * @brief Assert a condition, abort the running programme recording the given event if the condition is false. + * + * @param [in] eventPointer + * @param [in] condition A boolean value that is expected to be true. + * @param [in] ... A printf format string following corresponding parameters. + */ + +# define longBowAssert(eventPointer, condition, ...) \ + longBowEvent(eventPointer, condition, longBowLocation_Create(__FILE__, __func__, __LINE__), __VA_ARGS__) + +/** + * @def longBowTrap + * @brief Abort the running programme recording the given trap. + * + * @param [in] eventPointer + * @param [in] ... A printf format string following corresponding parameters. + */ +#define longBowTrap(eventPointer, ...) \ + longBowRuntime_EventEvaluation(eventPointer); \ + if (longBowRuntime_EventTrigger(eventPointer, \ + longBowLocation_Create(__FILE__, __func__, __LINE__), longBowEventType_GetName(eventPointer), __VA_ARGS__), true) \ + for (; true; abort()) + + +#define longBowTrapIf(eventPointer, condition, ...) \ + longBowEvent(eventPointer, (!(condition)), longBowLocation_Create(__FILE__, __func__, __LINE__), __VA_ARGS__) + +/** + * @def longBowTest + * @brief Terminate a LongBow Test Case signaling the given event if the condition is false. + * + * @param [in] testEventPointer + * @param [in] ... A printf format string following corresponding parameters. + */ +# define longBowTest(testEventPointer, ...) do { \ + longBowRuntime_EventEvaluation(testEventPointer); \ + longBowRuntime_EventTrigger(testEventPointer, \ + longBowLocation_Create(__FILE__, __func__, __LINE__), \ + "Test", __VA_ARGS__); \ + longjmp(longBowTestCaseAbort, SIGABRT); \ +} while (0) + +#include <LongBow/assertions.h> +#include <LongBow/debugging.h> +#include <LongBow/traps.h> +#endif // LongBow_runtime_h diff --git a/longbow/src/LongBow/stubs/execinfo.h b/longbow/src/LongBow/stubs/execinfo.h new file mode 100755 index 00000000..a6d6d407 --- /dev/null +++ b/longbow/src/LongBow/stubs/execinfo.h @@ -0,0 +1,23 @@ +/* + * 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. + */ + +#ifndef LongBow_execinfo_h +#define LongBow_execinfo_h + +#define backtrace(...) (1) +#define backtrace_symbols(...) 0 +#define backtrace_symbols_fd(...) ((void) 0) + +#endif // LongBow_execinfo_h diff --git a/longbow/src/LongBow/test/.gitignore b/longbow/src/LongBow/test/.gitignore new file mode 100644 index 00000000..182506bc --- /dev/null +++ b/longbow/src/LongBow/test/.gitignore @@ -0,0 +1,30 @@ +*.gcda +*.gcno +*.gcov +*.longbow +*.log +test_longBow_ArrayList +test_longBow_Backtrace +test_longBow_Config +test_longBow_Debug +test_longBow_Fixture +test_longBow_Memory +test_longBow_Main +test_longBow_OpenFile +test_longBow_Report +test_longBow_Runner +test_longBow_Runtime +test_longBow_Status +test_longBow_TestCase +test_longBow_TestCaseClipBoard +test_longBow_Properties +test_longBow_UnitTesting +test_longBow_Empty +test_longBow_File +test_longBow_String +test_longBow_Thread +test_longBow_CommandLineOptions +test_longBow_Expected +test_assertions +test_longBow_Properties +test_longBow_MeasureTime diff --git a/longbow/src/LongBow/test/CMakeLists.txt b/longbow/src/LongBow/test/CMakeLists.txt new file mode 100644 index 00000000..5eba0444 --- /dev/null +++ b/longbow/src/LongBow/test/CMakeLists.txt @@ -0,0 +1,52 @@ +# Enable gcov output for the tests +add_definitions(--coverage) +set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage") + + +macro(AddTest testFile) + add_executable(${ARGV0} ${ARGV0}.c) + target_link_libraries(${ARGV0} longbow longbow-ansiterm) + add_test(${ARGV0} ${ARGV0}) + set_target_properties(${ARGV0} PROPERTIES FOLDER Test) +endmacro(AddTest) + +set(TestsExpectedToFail + test_longBow_Expected; +) + +# test_assertions; + +set(TestsExpectedToPass + test_MemoryLeaks; + test_longBow_ArrayList; + test_longBow_Config; + test_longBow_Fixture; + test_longBow_Memory; + test_longBow_Location; + test_fixtureConfiguration; + test_longBow_Backtrace; + test_longBow_CommandLineOptions; + test_longBow_Debug; + test_longBow_Main; + test_longBow_MeasureTime; + test_longBow_OpenFile; + test_longBow_Properties; + test_longBow_Runner; + test_longBow_Runtime; + test_longBow_Status; + test_longBow_String; + test_longBow_TestCase; + test_longBow_TestCaseClipBoard; + test_longBow_UnitTesting + ) + +foreach(test ${TestsExpectedToPass}) + AddTest(${test}) +endforeach() + +foreach(test ${TestsExpectedToFail}) + AddTest(${test}) + set_tests_properties(${test} PROPERTIES WILL_FAIL TRUE) +endforeach() + + diff --git a/longbow/src/LongBow/test/test_MemoryLeaks.c b/longbow/src/LongBow/test/test_MemoryLeaks.c new file mode 100755 index 00000000..f5eb4160 --- /dev/null +++ b/longbow/src/LongBow/test/test_MemoryLeaks.c @@ -0,0 +1,76 @@ +/* + * 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. + */ + +/** * + */ +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> + +#include <inttypes.h> + +#include "../private/longBow_Memory.h" + +LONGBOW_TEST_RUNNER(test_MemoryLeaks) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(test_MemoryLeaks) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_MemoryLeaks) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ +// LONGBOW_RUN_TEST_CASE(Global, myTest); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, myTest) +{ +} + +int +main(int argc, char *argv[argc]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_MemoryLeaks); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + assertTrue(longBowMemory_OutstandingAllocations() == 0, "Memory leaks %" PRId64, longBowMemory_OutstandingAllocations()); + + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_assertions.c b/longbow/src/LongBow/test/test_assertions.c new file mode 100755 index 00000000..f20d0e5b --- /dev/null +++ b/longbow/src/LongBow/test/test_assertions.c @@ -0,0 +1,23 @@ +/* + * 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. + */ + +#include <LongBow/runtime.h> +#include <stdbool.h> + +int +main(int argc, char *argv[argc]) +{ + assertTrue(false, "Must fail."); +} diff --git a/longbow/src/LongBow/test/test_fixtureConfiguration.c b/longbow/src/LongBow/test/test_fixtureConfiguration.c new file mode 100755 index 00000000..92023f48 --- /dev/null +++ b/longbow/src/LongBow/test/test_fixtureConfiguration.c @@ -0,0 +1,70 @@ +/* + * 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. + */ + +/** * + */ +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> + +LONGBOW_TEST_RUNNER(test_fixtureConfiguration) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(test_fixtureConfiguration) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_fixtureConfiguration) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_OPTIONS(Global, .enabled = false) +{ + LONGBOW_RUN_TEST_CASE(Global, myTest); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, myTest) +{ +} + +int +main(int argc, char *argv[argc]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_fixtureConfiguration); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_ArrayList.c b/longbow/src/LongBow/test/test_longBow_ArrayList.c new file mode 100644 index 00000000..5ce70885 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_ArrayList.c @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#include <LongBow/testing.h> + +#include <stdio.h> +#include <stdint.h> +#include <inttypes.h> + +#include "../private/longBow_ArrayList.h" +#include "../private/longBow_Memory.h" + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +LONGBOW_TEST_RUNNER(longBow_ArrayList) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_ArrayList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_ArrayList) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, CreateDestroy); + LONGBOW_RUN_TEST_CASE(Global, longBowArrayList_Add); +} + +uint64_t _setupAllocations; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + _setupAllocations = longBowMemory_OutstandingAllocations(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint64_t leaks = longBowMemory_OutstandingAllocations() - _setupAllocations; + if (leaks != 0) { + printf("leaks %" PRId64 " allocations.\n", leaks); + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, CreateDestroy) +{ + LongBowArrayList *list = longBowArrayList_Create((void (*)(void **))longBowMemory_Deallocate); + + longBowArrayList_Destroy(&list); +} + +LONGBOW_TEST_CASE(Global, longBowArrayList_Add) +{ + LongBowArrayList *list = longBowArrayList_Create((void (*)(void **))longBowMemory_Deallocate); + + char *thing = longBowMemory_StringCopy("name"); + longBowArrayList_Add(list, thing); + + longBowArrayList_Destroy(&list); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_ArrayList); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Backtrace.c b/longbow/src/LongBow/test/test_longBow_Backtrace.c new file mode 100755 index 00000000..40582b85 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Backtrace.c @@ -0,0 +1,106 @@ +/* + * 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. + */ + +#include "../longBow_Backtrace.h" + +#include <stdio.h> +#include "../testing.h" +#include <LongBow/private/longBow_Memory.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +LONGBOW_TEST_RUNNER(longBow_Backtrace) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_Backtrace) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Backtrace) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, LongBowBacktrace_ToString); + LONGBOW_RUN_TEST_CASE(Global, longBowBacktrace_Create); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, LongBowBacktrace_ToString) +{ + LongBowBacktrace *backtrace = longBowBacktrace_Create(100, 0); + char *result = longBowBacktrace_ToString(backtrace); + + assertNotNull(result, "Expected non-null result from LongBowBacktrace_ToString()"); + + longBowMemory_Deallocate((void **) &result); + longBowBacktrace_Destroy(&backtrace); +} + +LONGBOW_TEST_CASE(Global, longBowBacktrace_Create) +{ + LongBowBacktrace *backtrace = longBowBacktrace_Create(100, 0); + assertNotNull(backtrace, "Expected non-null result from longBowBacktrace_Create()"); + longBowBacktrace_Destroy(&backtrace); + assertNull(backtrace, "Expected LongBowBacktrace_Destroy() to set the pointer to null"); + + backtrace = longBowBacktrace_Create(100, 1); + longBowBacktrace_Destroy(&backtrace); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Backtrace); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_CommandLineOptions.c b/longbow/src/LongBow/test/test_longBow_CommandLineOptions.c new file mode 100755 index 00000000..b63375fe --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_CommandLineOptions.c @@ -0,0 +1,73 @@ +/* + * 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. + */ + +/** * + */ +#include <stdio.h> + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> + +LONGBOW_TEST_RUNNER(test_longBow_CommandLineOptions) +{ + printf("test_longBow_CommandLineOptions\n"); + + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(testFixture); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(test_longBow_CommandLineOptions) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_longBow_CommandLineOptions) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(testFixture) +{ + printf(" testFixture\n"); + LONGBOW_RUN_TEST_CASE(testFixture, testCase); +} + +LONGBOW_TEST_FIXTURE_SETUP(testFixture) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(testFixture) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(testFixture, testCase) +{ + printf(" testCase\n"); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_longBow_CommandLineOptions); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Config.c b/longbow/src/LongBow/test/test_longBow_Config.c new file mode 100755 index 00000000..98589d32 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Config.c @@ -0,0 +1,98 @@ +/* + * 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. + */ + +#include <LongBow/testing.h> + +#include <stdio.h> +#include <inttypes.h> + +#include <LongBow/longBow_Config.h> +#include "../private/longBow_Memory.h" + +LONGBOW_TEST_RUNNER(longBow_Config) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_Config) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Config) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, CreateDestroy); +} + +uint64_t _setupAllocations; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + _setupAllocations = longBowMemory_OutstandingAllocations(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint64_t leaks = longBowMemory_OutstandingAllocations() - _setupAllocations; + if (leaks != 0) { + printf("leaks %" PRId64 " allocations.\n", leaks); + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, CreateDestroy) +{ + LongBowConfig *config = longBowConfig_Create(0, NULL, NULL); + + longBowConfig_Destroy(&config); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Config); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + if (longBowMemory_OutstandingAllocations() != 0) { + printf("%" PRId64 " allocation leaks.", longBowMemory_OutstandingAllocations()); + } + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Debug.c b/longbow/src/LongBow/test/test_longBow_Debug.c new file mode 100755 index 00000000..30805d4a --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Debug.c @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#include <LongBow/testing.h> + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +LONGBOW_TEST_RUNNER(longBow_Debug) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_Debug) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Debug) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Debug); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Expected.c b/longbow/src/LongBow/test/test_longBow_Expected.c new file mode 100755 index 00000000..7b49cb89 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Expected.c @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#include <LongBow/testing.h> + +LONGBOW_TEST_RUNNER(longBow_Expected) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_Expected) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Expected) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ExpectFailure); + LONGBOW_RUN_TEST_CASE(Global, ExpectSuccess); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE_EXPECTS(Global, ExpectSuccess, .event = &LongBowAssertEvent) +{ + assertTrue(false, "This must be successful by failing."); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, ExpectFailure, .event = &LongBowAssertEvent) +{ + assertNull(NULL, "This must fail to fail."); +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Expected); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Fixture.c b/longbow/src/LongBow/test/test_longBow_Fixture.c new file mode 100644 index 00000000..599b4be5 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Fixture.c @@ -0,0 +1,141 @@ +/* + * 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. + */ + +#include <stdio.h> +#include <inttypes.h> +#include <LongBow/testing.h> +#include <LongBow/private/longBow_Memory.h> + +LONGBOW_TEST_RUNNER(longBow_Fixture) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(CreateDestroy); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_Fixture) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Fixture) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(CreateDestroy) +{ + LONGBOW_RUN_TEST_CASE(CreateDestroy, LongBowTestFixture_Create_Destroy); +} + +LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(CreateDestroy, LongBowTestFixture_Create_Destroy) +{ + uint64_t allocations = longBowMemory_OutstandingAllocations(); + LongBowTestRunner *runner = longBowTestRunner_Create("runner", NULL, NULL, NULL); + + LongBowTestFixture *fixture = longBowTestFixture_Create(runner, "fixture", NULL, NULL, NULL); + assertNotNull(fixture, "Expected non-null result from LongBowTestFixture_Create"); + longBowTestFixture_Destroy(&fixture); + longBowTestRunner_Destroy(&runner); + assertTrue(longBowMemory_OutstandingAllocations() == allocations, + "Memory leaks %" PRId64, longBowMemory_OutstandingAllocations()); +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, longBowTestFixture_GetRunner); + LONGBOW_RUN_TEST_CASE(Global, longBowTestFixture_GetClipBoard); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + LongBowTestRunner *runner = longBowTestRunner_Create("testRunner", NULL, NULL, NULL); + LongBowTestFixture *fixture = longBowTestFixture_Create(runner, "testFixture", NULL, NULL, NULL); + + longBowClipBoard_Set(testClipBoard, "runner", runner); + longBowClipBoard_Set(testClipBoard, "fixture", fixture); + longBowTestCase_SetClipBoardData(testCase, fixture); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + LongBowTestFixture *fixture = longBowTestCase_GetClipBoardData(testCase); + + LongBowTestRunner *runner = longBowTestFixture_GetRunner(fixture); + + longBowTestRunner_Destroy(&runner); + longBowTestFixture_Destroy(&fixture); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, longBowTestFixture_GetRunner) +{ + LongBowTestRunner *xrunner = longBowClipBoard_Get(testClipBoard, "runner"); + LongBowTestFixture *xfixture = longBowClipBoard_Get(testClipBoard, "fixture"); + LongBowTestFixture *fixture = longBowTestCase_GetClipBoardData(testCase); + LongBowTestRunner *runner = longBowTestFixture_GetRunner(fixture); + + assertTrue(xrunner == runner, "Expected runner to be equal."); + assertTrue(xfixture == fixture, "Expected runner to be equal."); + + assertNotNull(runner, "Expected the test runner to not be null"); +} + +LONGBOW_TEST_CASE(Global, longBowTestFixture_GetClipBoard) +{ + LongBowTestFixture *fixture = longBowTestCase_GetClipBoardData(testCase); + LongBowClipBoard *clipboard = longBowTestFixture_GetClipBoard(fixture); + assertNotNull(clipboard, "Expected non-null result from longBowTestFixture_GetClipBoard"); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Fixture); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Location.c b/longbow/src/LongBow/test/test_longBow_Location.c new file mode 100755 index 00000000..9ed77079 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Location.c @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#include <LongBow/testing.h> + +LONGBOW_TEST_RUNNER(longBow_Location) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_Location) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Location) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Location); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Main.c b/longbow/src/LongBow/test/test_longBow_Main.c new file mode 100755 index 00000000..f8be93ed --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Main.c @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#include <stdio.h> +#include <LongBow/testing.h> + +LONGBOW_TEST_RUNNER(longBow_Main) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_Main) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Main) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, longBowMain); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, longBowMain) +{ + LongBowStatus expected = LONGBOW_STATUS_SUCCEEDED; + + int actual = longBowMain(0, NULL, NULL); + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Main); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_MeasureTime.c b/longbow/src/LongBow/test/test_longBow_MeasureTime.c new file mode 100644 index 00000000..294c7c60 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_MeasureTime.c @@ -0,0 +1,155 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Runner. +#include "../longBow_MeasureTime.c" + +#include <stdint.h> +#include <inttypes.h> +#include <LongBow/private/longBow_Memory.h> +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(longBow_MeasureTime) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified here, but every test must be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Static); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_MeasureTime) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_MeasureTime) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime_CountDown); + LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime_Report); + LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime_Start); + LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime_Stop); + LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime_Destroy); + LONGBOW_RUN_TEST_CASE(Global, longBowMeasureTime); +} + +uint64_t _setupAllocations; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + _setupAllocations = longBowMemory_OutstandingAllocations(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint64_t leaks = longBowMemory_OutstandingAllocations() - _setupAllocations; + if (leaks != 0) { + printf("%s leaks %" PRId64 " allocations.\n", longBowTestCase_GetFullName(testCase), leaks); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, longBowMeasureTime_CountDown) +{ + LongBowMeasureTime *measure = longBowMeasureTime_Start(1); + assertTrue(measure->iterations == 1, "Expected iterations to be 1, actual %d", measure->iterations); + + longBowMeasureTime_CountDown(measure); + assertTrue(measure->iterations == 0, "Expected iterations to be 0, actual %d", measure->iterations); + + longBowMeasureTime_Destroy(&measure); +} + +LONGBOW_TEST_CASE(Global, longBowMeasureTime_Report) +{ + LongBowMeasureTime *measure = longBowMeasureTime_Start(1); + assertTrue(measure->iterations == 1, "Expected iterations to be 1, actual %d", measure->iterations); + + longBowMeasureTime_Report(measure, __FILE__, __func__, __LINE__); + + longBowMeasureTime_Destroy(&measure); +} + +LONGBOW_TEST_CASE(Global, longBowMeasureTime_Start) +{ + LongBowMeasureTime *measure = longBowMeasureTime_Start(1); + assertNotNull(measure, "Expected longBowMeasureTime_Start to return non-NULL result."); + + longBowMeasureTime_Destroy(&measure); +} + +LONGBOW_TEST_CASE(Global, longBowMeasureTime_Stop) +{ + LongBowMeasureTime *measure = longBowMeasureTime_Start(1); + assertNotNull(measure, "Expected longBowMeasureTime_Start to return non-NULL result."); + sleep(2); + longBowMeasureTime_Stop(measure); + + uint64_t nanos = longBowMeasureTime_GetNanoseconds(measure); + assertTrue(nanos >= 1000000000ULL, "Expected more than 1,000,000 ns to have elapsed."); + + longBowMeasureTime_Destroy(&measure); +} + +LONGBOW_TEST_CASE(Global, longBowMeasureTime_Destroy) +{ + LongBowMeasureTime *measure = longBowMeasureTime_Start(1); + assertNotNull(measure, "Expected longBowMeasureTime_Start to return non-NULL result."); + + longBowMeasureTime_Destroy(&measure); + assertNull(measure, "Expected longBowMeasureTime_Destroy to NULL the pointer."); +} + +LONGBOW_TEST_CASE(Global, longBowMeasureTime) +{ + longBowMeasureTime(1) + { + sleep(2); + } +} + +LONGBOW_TEST_FIXTURE(Static) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_MeasureTime); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Memory.c b/longbow/src/LongBow/test/test_longBow_Memory.c new file mode 100755 index 00000000..d1943860 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Memory.c @@ -0,0 +1,113 @@ +/* + * 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. + */ + +/** + */ +#include "../private/longBow_Memory.c" + +#include <LongBow/unit-test.h> +#include <LongBow/debugging.h> + +LONGBOW_TEST_RUNNER(test_longBow_Memory) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(test_longBow_Memory) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_longBow_Memory) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, longBowMemory_Allocate); + LONGBOW_RUN_TEST_CASE(Global, longBowMemory_Reallocate); + LONGBOW_RUN_TEST_CASE(Global, longBowMemory_StringCopy); +} + +static uint64_t _setupAllocations; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + _setupAllocations = longBowMemory_OutstandingAllocations(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (longBowMemory_OutstandingAllocations() != _setupAllocations) { + printf("%s Memory leak\n", longBowTestCase_GetFullName(testCase)); + return LONGBOW_STATUS_MEMORYLEAK; + } + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, longBowMemory_Allocate) +{ + void *memory = longBowMemory_Allocate(10); + assertNotNull(memory, "Return value from longBowMemory_Allocate(10) cannot be NULL."); + longBowMemory_Deallocate((void **) &memory); + assertNull(memory, "longBowMemory_Deallocated must NULL the pointer."); +} + +LONGBOW_TEST_CASE(Global, longBowMemory_Reallocate) +{ + void *memory = longBowMemory_Allocate(10); + assertNotNull(memory, "Return value from longBowMemory_Allocate(10) cannot be NULL."); + + memory = longBowMemory_Reallocate(memory, 100); + assertNotNull(memory, "Return value from longBowMemory_Reallocate cannot be NULL."); + + longBowMemory_Deallocate((void **) &memory); + assertNull(memory, "longBowMemory_Deallocated must NULL the pointer."); +} + +LONGBOW_TEST_CASE(Global, longBowMemory_Reallocate_NULL) +{ + void *memory = longBowMemory_Reallocate(NULL, 100); + assertNotNull(memory, "Return value from longBowMemory_Reallocate cannot be NULL."); + + longBowMemory_Deallocate((void **) &memory); + assertNull(memory, "longBowMemory_Deallocated must NULL the pointer."); +} + +LONGBOW_TEST_CASE(Global, longBowMemory_StringCopy) +{ + char *expected = "Hello World"; + + char *actual = longBowMemory_StringCopy(expected); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + longBowMemory_Deallocate((void **) &actual); +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_longBow_Memory); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_OpenFile.c b/longbow/src/LongBow/test/test_longBow_OpenFile.c new file mode 100755 index 00000000..2a881fdb --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_OpenFile.c @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#include <LongBow/testing.h> +#include "../private/longBow_ArrayList.h" +#include "../private/longBow_OpenFile.h" + +LONGBOW_TEST_RUNNER(longBow_Files) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_Files) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Files) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, longBow_OpenFiles); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, longBow_OpenFiles) +{ + LongBowArrayList *list = longBowOpenFile_CurrentlyOpen(); + assertTrue(longBowArrayList_Length(list) > 0, "Expected the number of open files to be > 0"); + + longBowArrayList_Destroy(&list); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Files); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Properties.c b/longbow/src/LongBow/test/test_longBow_Properties.c new file mode 100755 index 00000000..736a8141 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Properties.c @@ -0,0 +1,137 @@ +/* + * 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. + */ + +/** * + */ +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Framework. + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> + +#include <stdio.h> +#include <inttypes.h> + +#include <LongBow/longBow_Properties.h> +#include "../private/longBow_Memory.h" + +LONGBOW_TEST_RUNNER(test_longBow_Properties) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(test_longBow_Properties) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(test_longBow_Properties) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, CreateDestroy); + LONGBOW_RUN_TEST_CASE(Global, longBowProperties_Set); + LONGBOW_RUN_TEST_CASE(Global, longBowProperties_Get); + LONGBOW_RUN_TEST_CASE(Global, longBowProperties_Length); + LONGBOW_RUN_TEST_CASE(Global, longBowProperties_Exists); +} + +static uint64_t _setupAllocations; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + _setupAllocations = longBowMemory_OutstandingAllocations(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + uint64_t leaks = longBowMemory_OutstandingAllocations() - _setupAllocations; + if (leaks != 0) { + printf("%s leaks %" PRId64 " allocations.\n", longBowTestCase_GetFullName(testCase), leaks); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, CreateDestroy) +{ + LongBowProperties *properties = longBowProperties_Create(); + longBowProperties_Destroy(&properties); +} + +LONGBOW_TEST_CASE(Global, longBowProperties_Set) +{ + LongBowProperties *properties = longBowProperties_Create(); + longBowProperties_Set(properties, "name", "value"); + longBowProperties_Destroy(&properties); +} + +LONGBOW_TEST_CASE(Global, longBowProperties_Get) +{ + LongBowProperties *properties = longBowProperties_Create(); + char *expected = "value"; + longBowProperties_Set(properties, "name", expected); + + const char *actual = longBowProperties_Get(properties, "name"); + + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); + longBowProperties_Destroy(&properties); +} + +LONGBOW_TEST_CASE(Global, longBowProperties_Length) +{ + LongBowProperties *properties = longBowProperties_Create(); + assertTrue(longBowProperties_Length(properties) == 0, "Expected empty longBowProperties to be 0 length"); + + char *expected = "value"; + longBowProperties_Set(properties, "name", expected); + assertTrue(longBowProperties_Length(properties) == 1, "Expected longBowProperties to be 1 length"); + + const char *actual = longBowProperties_Get(properties, "name"); + + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); + longBowProperties_Destroy(&properties); +} + +LONGBOW_TEST_CASE(Global, longBowProperties_Exists) +{ + char *expected = "value"; + + LongBowProperties *properties = longBowProperties_Create(); + assertFalse(longBowProperties_Exists(properties, expected), "Expected longBowProperties_Exists to be false"); + + longBowProperties_Set(properties, "name", expected); + assertTrue(longBowProperties_Exists(properties, "name"), "Expected longBowProperties_Exists to be true"); + + longBowProperties_Destroy(&properties); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_longBow_Properties); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Runner.c b/longbow/src/LongBow/test/test_longBow_Runner.c new file mode 100755 index 00000000..7d7492e9 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Runner.c @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#include <LongBow/testing.h> + +LONGBOW_TEST_RUNNER(longBow_Runner) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_Runner) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Runner) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Runner); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Runtime.c b/longbow/src/LongBow/test/test_longBow_Runtime.c new file mode 100755 index 00000000..b9d963e9 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Runtime.c @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#include <LongBow/testing.h> + +LONGBOW_TEST_RUNNER(longBow_Runtime) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_Runtime) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Runtime) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, longBowRuntime_StackTrace); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, longBowRuntime_StackTrace) +{ + longBowRuntime_StackTrace(1); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Runtime); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_Status.c b/longbow/src/LongBow/test/test_longBow_Status.c new file mode 100755 index 00000000..a1c01eb2 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_Status.c @@ -0,0 +1,140 @@ +/* + * 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. + */ + +#include <LongBow/testing.h> + +LONGBOW_TEST_RUNNER(longBow_Status) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_Status) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_Status) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, longBowStatus_ToString); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, longBowStatus_ToString) +{ + char *expected; + char *actual; + + expected = "Succeeded"; + actual = longBowStatus_ToString(LONGBOW_STATUS_SUCCEEDED); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + free(actual); + + expected = "Warning"; + actual = longBowStatus_ToString(LongBowStatus_WARNED); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + free(actual); + + expected = "Tear Down Warning"; + actual = longBowStatus_ToString(LongBowStatus_TEARDOWN_WARNED); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + free(actual); + + expected = "Skipped"; + actual = longBowStatus_ToString(LONGBOW_STATUS_SKIPPED); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + free(actual); + + expected = "Unimplemented"; + actual = longBowStatus_ToString(LongBowStatus_UNIMPLEMENTED); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + free(actual); + + expected = "Impotent"; + actual = longBowStatus_ToString(LongBowStatus_IMPOTENT); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + free(actual); + + expected = "Failed"; + actual = longBowStatus_ToString(LONGBOW_STATUS_FAILED); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + free(actual); + + expected = "Stopped"; + actual = longBowStatus_ToString(LongBowStatus_STOPPED); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + free(actual); + + expected = "Tear Down Failed"; + actual = longBowStatus_ToString(LONGBOW_STATUS_TEARDOWN_FAILED); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + free(actual); + + expected = "Setup Failed"; + actual = longBowStatus_ToString(LONGBOW_STATUS_SETUP_FAILED); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + free(actual); + + expected = "Memory Leak"; + actual = longBowStatus_ToString(LONGBOW_STATUS_MEMORYLEAK); + assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual); + free(actual); + + actual = longBowStatus_ToString(LongBowStatus_SIGNALLED + 1); + assertNotNull(actual, "Expected longBowStatus_ToString to return non-null value"); + free(actual); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_Status); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_String.c b/longbow/src/LongBow/test/test_longBow_String.c new file mode 100755 index 00000000..96750706 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_String.c @@ -0,0 +1,192 @@ +/* + * 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. + */ + + +// Include the file(s) containing the functions to be tested. +// This permits internal static functions to be visible to this Test Runner. +#include <stdio.h> +#include <inttypes.h> + +#include "../private/longBow_String.c" + +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(longBow_String) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified here, but every test must be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Static); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_String) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_String) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, longBowString_Create); + LONGBOW_RUN_TEST_CASE(Global, longBowString_Append); + LONGBOW_RUN_TEST_CASE(Global, longBowString_Append_Append); + LONGBOW_RUN_TEST_CASE(Global, longBowString_Format); + + LONGBOW_RUN_TEST_CASE(Global, longBowString_StartsWith_True); + LONGBOW_RUN_TEST_CASE(Global, longBowString_StartsWith_False); + LONGBOW_RUN_TEST_CASE(Global, longBowString_Tokenise); + LONGBOW_RUN_TEST_CASE(Global, longBowString_Tokenise_empty); + LONGBOW_RUN_TEST_CASE(Global, longBowString_Tokenise_NULL); + LONGBOW_RUN_TEST_CASE(Global, longBowString_CoreDump); +} + +static uint64_t _outstandingAllocations; + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + _outstandingAllocations = longBowMemory_OutstandingAllocations(); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + if (longBowMemory_OutstandingAllocations() > _outstandingAllocations) { + printf("%s: memory leak\n", longBowTestCase_GetName(testCase)); + return LONGBOW_STATUS_MEMORYLEAK; + } + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, longBowString_Create) +{ + LongBowString *string = longBowString_Create(128); + assertNotNull(string, "Expected non-NULL result from longBowString_Create"); + + longBowString_Destroy(&string); + assertNull(string, "Expected the instance pointer to be NULL after longBowString_Destroy"); +} + +LONGBOW_TEST_CASE(Global, longBowString_Append) +{ + char *expected = "Hello World"; + LongBowString *string = longBowString_Create(0); + longBowString_Append(string, expected); + + assertTrue(strcmp(expected, string->buffer) == 0, + "Expected buffer to contain '%s', actual '%s'", expected, string->buffer); + longBowString_Destroy(&string); +} + +LONGBOW_TEST_CASE(Global, longBowString_Append_Append) +{ + char *expected = "Hello World"; + LongBowString *string = longBowString_Create(0); + longBowString_Append(string, "Hello"); + longBowString_Append(string, " "); + longBowString_Append(string, "World"); + + assertTrue(strcmp(expected, string->buffer) == 0, + "Expected buffer to contain '%s', actual '%s'", expected, string->buffer); + longBowString_Destroy(&string); +} + +LONGBOW_TEST_CASE(Global, longBowString_Format) +{ + char *expected = "Hello World"; + LongBowString *string = longBowString_Create(0); + longBowString_Format(string, "%s", expected); + + assertTrue(strcmp(expected, string->buffer) == 0, + "Expected buffer to contain '%s', actual '%s'", expected, string->buffer); + longBowString_Destroy(&string); +} + +LONGBOW_TEST_CASE(Global, longBowString_StartsWith_True) +{ + bool actual = longBowString_StartsWith("abcde", "abc"); + assertTrue(actual, "Expected true"); +} + +LONGBOW_TEST_CASE(Global, longBowString_StartsWith_False) +{ + bool actual = longBowString_StartsWith("abcde", "ayz"); + + assertFalse(actual, "Expected false"); +} + +LONGBOW_TEST_CASE(Global, longBowString_Tokenise) +{ + LongBowArrayList *actual = longBowString_Tokenise("--t.x=10", "-="); + + assertTrue(strcmp("t.x", longBowArrayList_Get(actual, 0)) == 0, + "Expected first token to be t.x, actual %s", (char *) longBowArrayList_Get(actual, 0)); + assertTrue(strcmp("10", longBowArrayList_Get(actual, 1)) == 0, + "Expected first token to be 10, actual %s", (char *) longBowArrayList_Get(actual, 1)); + + longBowArrayList_Destroy(&actual); +} + +LONGBOW_TEST_CASE(Global, longBowString_Tokenise_empty) +{ + LongBowArrayList *actual = longBowString_Tokenise("", "-="); + + assertTrue(longBowArrayList_Length(actual) == 0, "Expected zero length LongBowArrayList, actual %zd", longBowArrayList_Length(actual)); + + longBowArrayList_Destroy(&actual); +} + +LONGBOW_TEST_CASE(Global, longBowString_Tokenise_NULL) +{ + LongBowArrayList *actual = longBowString_Tokenise(NULL, "-="); + + assertTrue(longBowArrayList_Length(actual) == 0, "Expected zero length LongBowArrayList, actual %zd", longBowArrayList_Length(actual)); + + longBowArrayList_Destroy(&actual); +} + +LONGBOW_TEST_CASE(Global, longBowString_CoreDump) +{ + //assertFalse(true, "foo"); +} + +LONGBOW_TEST_FIXTURE(Static) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_String); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_TestCase.c b/longbow/src/LongBow/test/test_longBow_TestCase.c new file mode 100755 index 00000000..3fe6c8e1 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_TestCase.c @@ -0,0 +1,79 @@ +/* + * 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. + */ + +#include <LongBow/testing.h> + +LONGBOW_TEST_RUNNER(longBow_TestCase) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_TestCase) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_TestCase) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, ExpectEvent); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, ExpectEvent) +{ +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_TestCase); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_TestCaseClipBoard.c b/longbow/src/LongBow/test/test_longBow_TestCaseClipBoard.c new file mode 100755 index 00000000..521a817b --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_TestCaseClipBoard.c @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#include <inttypes.h> +#include <LongBow/testing.h> +#include <LongBow/private/longBow_Memory.h> + +LONGBOW_TEST_RUNNER(longBow_TestCaseClipBoard) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_TestCaseClipBoard) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_TestCaseClipBoard) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, longBowTestCaseClipBoard_CreateDestroy); + LONGBOW_RUN_TEST_CASE(Global, longBowTestCaseClipBoard_Get); + LONGBOW_RUN_TEST_CASE(Global, longBowTestCaseClipBoard_Set); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, longBowTestCaseClipBoard_CreateDestroy) +{ + uint64_t allocations = longBowMemory_OutstandingAllocations(); + char *shared = longBowMemory_StringCopy("shared data"); + + LongBowTestCaseClipBoard *clipboard = longBowTestCaseClipBoard_Create(shared); + assertNotNull(clipboard, "Expected non-null result from longBowTestCaseClipBoard_Create"); + + longBowTestCaseClipBoard_Destroy(&clipboard); + longBowMemory_Deallocate((void **) &shared); + + assertTrue(longBowMemory_OutstandingAllocations() == allocations, + "Memory leaks %" PRId64, longBowMemory_OutstandingAllocations()); +} + +LONGBOW_TEST_CASE(Global, longBowTestCaseClipBoard_Get) +{ + char *shared = longBowMemory_StringCopy("shared data"); + + LongBowTestCaseClipBoard *clipboard = longBowTestCaseClipBoard_Create(shared); + + char *actual = longBowTestCaseClipBoard_Get(clipboard); + assertTrue(strcmp(shared, actual) == 0, "Expected %s, actual %s", shared, actual); + + longBowTestCaseClipBoard_Destroy(&clipboard); + longBowMemory_Deallocate((void **) &shared); +} + +LONGBOW_TEST_CASE(Global, longBowTestCaseClipBoard_Set) +{ + char *shared = longBowMemory_StringCopy("shared data"); + + LongBowTestCaseClipBoard *clipboard = longBowTestCaseClipBoard_Create(shared); + + char *expected = longBowMemory_StringCopy("expected"); + + longBowTestCaseClipBoard_Set(clipboard, expected); + char *actual = longBowTestCaseClipBoard_Get(clipboard); + assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual); + + longBowTestCaseClipBoard_Destroy(&clipboard); + longBowMemory_Deallocate((void **) &shared); + longBowMemory_Deallocate((void **) &expected); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_TestCaseClipBoard); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/test/test_longBow_UnitTesting.c b/longbow/src/LongBow/test/test_longBow_UnitTesting.c new file mode 100755 index 00000000..de0f9c56 --- /dev/null +++ b/longbow/src/LongBow/test/test_longBow_UnitTesting.c @@ -0,0 +1,115 @@ +/* + * 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. + */ + +#include "../testing.h" + +LONGBOW_TEST_RUNNER(longBow_UnitTesting) +{ + // The following Test Fixtures will run their corresponding Test Cases. + // Test Fixtures are run in the order specified, but all tests should be idempotent. + // Never rely on the execution order of tests or share state between them. + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +// The Test Runner calls this function once before any Test Fixtures are run. +LONGBOW_TEST_RUNNER_SETUP(longBow_UnitTesting) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +// The Test Runner calls this function once after all the Test Fixtures are run. +LONGBOW_TEST_RUNNER_TEARDOWN(longBow_UnitTesting) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, longBowUnitTesting_AssertCompareToContract); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +static int +compareTo(const void *a, const void *b) +{ + if (a == NULL) { + if (b == NULL) { + return 0; + } + return -1; + } else { + if (b == NULL) { + return 1; + } + } + + return strcmp(a, b); +} + +LONGBOW_TEST_CASE(Global, longBowUnitTesting_AssertCompareToContract) +{ + char *exemplar = "exemplar"; + void *equivalent[] = { + "exemplar", + NULL, + }; + void *lesser[] = { + "exempla", + NULL, + }; + void *greater[] = { + "exemplarr", + "fexemplarr", + NULL, + }; + + bool expected = true; + bool actual = longBowUnitTesting_AssertCompareToContract(compareTo, exemplar, equivalent, lesser, greater); + + assertTrue(expected == actual, "Expected %d, actual %d", expected, actual); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(longBow_UnitTesting); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/LongBow/testing.h b/longbow/src/LongBow/testing.h new file mode 100755 index 00000000..d789094c --- /dev/null +++ b/longbow/src/LongBow/testing.h @@ -0,0 +1,29 @@ +/* + * 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 testing.h + * @ingroup testing + * @brief LongBow testing functionality. + * + */ +#ifndef LongBow_testing_h +#define LongBow_testing_h + +#include <LongBow/longBow_Compiler.h> +#include <LongBow/longBow_ClipBoard.h> +#include <LongBow/longBow_Properties.h> +#include <LongBow/unit-test.h> +#endif // LongBow_testing_h diff --git a/longbow/src/LongBow/tests.h b/longbow/src/LongBow/tests.h new file mode 100644 index 00000000..24146d4c --- /dev/null +++ b/longbow/src/LongBow/tests.h @@ -0,0 +1,47 @@ +/* + * 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 tests.h + * @brief LongBow Utility Tests + * + * + */ +#ifndef LongBow_tests_h +#define LongBow_tests_h + +#include <stdbool.h> +#include <stdlib.h> + +/** + * Test if an address is aligned. + * + * Return true of the given address is aligned according to alignment. + * The value for alignment must be a power of 2. + * + * @param [in] address The adddress to test. + * @param [in] alignment A power of 2 greater than or equal to sizeof(void *). + * + * @return true if the address is aligned. + * @return false if the address is not aligned. + */ +bool longBowRuntime_TestAddressIsAligned(const void *address, size_t alignment); + +/** + * Induce a core-dump + * + */ +void longBowRuntime_CoreDump(void); +#endif // LongBow_tests_h diff --git a/longbow/src/LongBow/traps.h b/longbow/src/LongBow/traps.h new file mode 100755 index 00000000..e6c68d65 --- /dev/null +++ b/longbow/src/LongBow/traps.h @@ -0,0 +1,164 @@ +/* + * 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 traps.h + * @ingroup runtime + * @brief Runtime and Test Traps + * + */ +#ifndef LongBow_traps_h +#define LongBow_traps_h + +/** + * @def trapUnrecoverableState + * @brief Lay a trap to report an unrecoverable state in program execution. + * + * @param ... A printf(3) format string of explanitory text and values + */ +#define trapUnrecoverableState(...) \ + longBowTrap(&LongBowTrapUnrecoverableState, "Unrecoverable State: " __VA_ARGS__) + +/** + * @def trapNotImplemented + * @brief Lay a trap to report and abort an unimplemented capability. + * + * @param ... A printf(3) format string of explanitory text and values + */ +#define trapNotImplemented(...) \ + longBowTrap(&LongBowTrapNotImplemented, "Feature not implemented: " __VA_ARGS__) + +/** + * @def trapIllegalValue + * @brief Trap an illegal value. + * + * To used for capturing parameter validation, for example. + * + * @param [in] argumentName A name that is displayed in the report message. + * @param [in] ... A printf format string and associated parameters. + */ +#define trapIllegalValue(argumentName, ...) \ + longBowTrap(&LongBowTrapIllegalValue, "Illegal value for '" #argumentName "': " __VA_ARGS__) + +/** + * @def trapIllegalValueIf + * @brief Trap an illegal value if a condition is met. + * + * To used for the case where the value is valid + * (eg. it is the correct type) but is an illegal value to be used in the context in which it was attempted to be applied. + * + * @param [in] condition A logical expression that if true, induces this trap. + * @param [in] ... A printf format string and associated parameters. + */ +#define trapIllegalValueIf(condition, ...) \ + longBowTrapIf(&LongBowTrapIllegalValue, condition, "Illegal value: " __VA_ARGS__) + +/** + * @def trapInvalidValueIf + * @brief Trap an invalid value if a condition is met. + * + * Used for capturing parameter validation. + * For example, a composite value (C struct) has an internally invalid state for example. + * + * @param [in] condition A logical expression that if true, induces this trap. + * @param [in] ... A printf format string and associated parameters. + */ +#define trapInvalidValueIf(condition, ...) \ + longBowTrapIf(&LongBowTrapInvalidValue, condition, "Invalid value: " __VA_ARGS__) + +/** + * @def trapOutOfBounds + * @brief Trap an out-of-bounds condition on an index. + * + * @param [in] index The index that is out of bounds. + * @param [in] ... A printf format string and associated parameters. + */ +#define trapOutOfBounds(index, ...) \ + longBowTrap(&LongBowTrapOutOfBounds, "Element out of bounds, " #index ": " __VA_ARGS__) + +/** + * @def trapOutOfBoundsIf + * @brief Trap an out-of-bounds condition for a specific value. + * + * @param [in] condition A logical expression that if true, induces this trap. + * @param [in] ... A printf format string and associated parameters. + */ +#define trapOutOfBoundsIf(condition, ...) \ + longBowTrapIf(&LongBowTrapOutOfBounds, condition, "Out of bounds: " __VA_ARGS__) + +/** + * @def trapOutOfMemory + * @brief Signal that no more memory could be allocated. + * + * @param ... A printf format string and accompanying parameters. + */ +#define trapOutOfMemory(...) \ + longBowTrap(&LongBowTrapOutOfMemoryEvent, "Out of memory. " __VA_ARGS__) + +/** + * @def trapOutOfMemoryIf + * @brief Signal that no more memory could be allocated. + * + * @param [in] condition A logical expression that if true, induces this trap. + * @param [in] ... A printf format string and associated parameters. + */ +#define trapOutOfMemoryIf(condition, ...) \ + longBowTrapIf(&LongBowTrapOutOfMemoryEvent, condition, "Out of memory. " __VA_ARGS__) + +/** + * @def trapUnexpectedState + * @brief Signal that an unexpected or inconsistent state was encountered. + * + * @param ... A printf format string and accompanying parameters. + */ +#define trapUnexpectedState(...) \ + longBowTrap(&LongBowTrapUnexpectedStateEvent, "Unexpected state. " __VA_ARGS__) + +/** + * @def trapUnexpectedStateIf + * @brief If the given condition is true, signal that an unexpected state was encountered . + * + * @param [in] condition A logical expression that if true, induces this trap. + * @param [in] ... A printf format string and associated parameters. + */ +#define trapUnexpectedStateIf(condition, ...) \ + longBowTrapIf(&LongBowTrapUnexpectedStateEvent, condition, "Unexpected state: " __VA_ARGS__) + +/** + * @def trapCoreDump + * @brief Send a SIGTRAP to the current process. + */ +#define trapCoreDump() \ + kill(0, SIGTRAP); + +/** + * @def trapCannotObtainLock + * @brief Signal that a lock could not be obtained. + * + * @param ... A printf format string and accompanying parameters. + */ +#define trapCannotObtainLock(...) \ + longBowTrap(&LongBowTrapCannotObtainLockEvent, "Cannot obtain lock " __VA_ARGS__) + +/** + * @def trapCannotObtainLock + * @brief Signal that a lock could not be obtained. + * + * @param ... A printf format string and accompanying parameters. + */ +#define trapCannotObtainLockIf(condition, ...) \ + longBowTrapIf(&LongBowTrapCannotObtainLockEvent, condition, "Cannot obtain lock " __VA_ARGS__) + +#endif diff --git a/longbow/src/LongBow/unit-test.h b/longbow/src/LongBow/unit-test.h new file mode 100644 index 00000000..3f282671 --- /dev/null +++ b/longbow/src/LongBow/unit-test.h @@ -0,0 +1,413 @@ +/* + * 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 <em>after</em> + * including the files necessary for the functions under test. + * + */ +#ifndef UNIT_TEST_H_ +#define UNIT_TEST_H_ + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <setjmp.h> +#include <unistd.h> + +#include <LongBow/runtime.h> + +#include <LongBow/longBow_Compiler.h> +#include <LongBow/longBow_UnitTest.h> +#include <LongBow/longBow_Status.h> +#include <LongBow/longBow_Config.h> +#include <LongBow/longBow_UnitTesting.h> +#include <LongBow/longBow_Runtime.h> +#include <LongBow/longBow_Main.h> +#include <LongBow/longBow_TestRunner.h> +#include <LongBow/longBow_TestFixture.h> +#include <LongBow/longBow_TestCase.h> +#include <LongBow/longBow_SubProcess.h> +#include <LongBow/longBow_TestCaseMetaData.h> +#include <LongBow/Reporting/longBowReport_Testing.h> + +#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 <code>fixtureName</code> and <code>testCaseName</code>. + * + * This is executed within a LongBow test fixture function and references the function's + * <code>LongBowTestFixture</code> 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_ diff --git a/longbow/src/examples/.gitignore b/longbow/src/examples/.gitignore new file mode 100644 index 00000000..1b4775c8 --- /dev/null +++ b/longbow/src/examples/.gitignore @@ -0,0 +1,5 @@ +*.gcno +*.gcda +*.dSYM +*.gcov +testLongBow diff --git a/longbow/src/examples/example1.c b/longbow/src/examples/example1.c new file mode 100755 index 00000000..31bbadbf --- /dev/null +++ b/longbow/src/examples/example1.c @@ -0,0 +1,42 @@ +/* + * 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. + */ + +/* + * example1.c + * + */ + +#include <unistd.h> +#include <stdbool.h> +#include <signal.h> + +int +alwaysTrue() +{ + return true; +} + +int +alwaysFalse() +{ + return false; +} + +int +alwaysSignalled() +{ + kill(getpid(), SIGTERM); + return true; +} diff --git a/longbow/src/examples/minimal.c b/longbow/src/examples/minimal.c new file mode 100755 index 00000000..47f7e7fe --- /dev/null +++ b/longbow/src/examples/minimal.c @@ -0,0 +1,25 @@ +/* + * 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. + */ + +/* + * minimal.c + * + */ + +int +alwaysSucceed() +{ + return 1; +} diff --git a/longbow/src/examples/pointer.c b/longbow/src/examples/pointer.c new file mode 100755 index 00000000..0a0fef95 --- /dev/null +++ b/longbow/src/examples/pointer.c @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include <LongBow/runtime.h> +#include <unistd.h> +#include <string.h> + +void +function(char *pointer) +{ + assertNotNull(pointer, "The pointer cannot be NULL."); + + write(1, pointer, strlen(pointer)); +} + +int +main(int argc, char *argv[]) +{ + function(0); +} diff --git a/longbow/src/examples/require.c b/longbow/src/examples/require.c new file mode 100755 index 00000000..31055aa8 --- /dev/null +++ b/longbow/src/examples/require.c @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#include <stdio.h> +#include "../runtime.h" + +# define longBowAssert(eventPointer, condition, ...) \ + longBowRuntime_EventEvaluation(eventPointer); \ + if (longBowIsFalse(condition) && \ + (longBowRuntime_EventTrigger(eventPointer, longBowLocation_Create(__FILE__, longBow_function, __LINE__), #condition, __VA_ARGS__), true)) \ + for (; true; abort()) + + +int +main(int argc, char *argv[argc]) +{ + int condition = 1; + + longBowAssert(&LongBowAssertEvent, condition == 1, "Message %d", 2) + { + printf("Should not have Triggered\n"); + }; + longBowAssert(&LongBowAssertEvent, condition == 0, "Message %d", 2) + { + printf("Triggered\n"); + }; + + longBowAssert(&LongBowAssertEvent, condition == 0, "Message %d", 2); +} diff --git a/longbow/src/examples/testAssertion.c b/longbow/src/examples/testAssertion.c new file mode 100755 index 00000000..eb60db91 --- /dev/null +++ b/longbow/src/examples/testAssertion.c @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "../runtime.h" + +int +main(int argc, char *argv[]) +{ + assertTrue(0, "Force this assertion."); +} diff --git a/longbow/src/examples/testClipboard.c b/longbow/src/examples/testClipboard.c new file mode 100755 index 00000000..1e6a5b94 --- /dev/null +++ b/longbow/src/examples/testClipboard.c @@ -0,0 +1,71 @@ +/* + * 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. + */ + +/** + * + */ +#include <stdio.h> +#include <string.h> + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> + +LONGBOW_TEST_RUNNER(testClipboard) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(testClipboard) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(testClipboard) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, testClipboard); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + char *testData = strdup("Hello World"); + longBowTestCase_SetClipBoardData(testCase, testData, free); + + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, testClipboard) +{ + char *testData = longBowTestCase_GetClipBoardData(testCase); + printf("Shared state '%s'\n", testData); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(testClipboard); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/examples/testExample1.c b/longbow/src/examples/testExample1.c new file mode 100755 index 00000000..d26294a1 --- /dev/null +++ b/longbow/src/examples/testExample1.c @@ -0,0 +1,97 @@ +/* + * 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. + */ + +#include <stdio.h> +#include "../unit-test.h" + +#include "example1.c" + +LONGBOW_TEST_RUNNER(example1) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Local); +} + +LONGBOW_TEST_RUNNER_SETUP(example1) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(example1) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, strlen); + LONGBOW_RUN_TEST_CASE(Global, alwaysFail); + LONGBOW_RUN_TEST_CASE(Global, alwaysSignalled); + LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, alwaysFail) +{ + assertTrue(alwaysFalse(), "This test must always fail.") + { + printf("And this is extra code that is executed when the assertion fails"); + } +} + +LONGBOW_TEST_CASE(Global, alwaysSignalled) +{ + kill(getpid(), SIGTERM); +} + +LONGBOW_TEST_CASE(Global, alwaysSucceed) +{ + assertTrue(alwaysTrue(), "This test must always succeed."); +} + +LONGBOW_TEST_CASE(Global, strlen) +{ + assertNotNull(NULL, "Parameter must be a non-null char pointer."); +} + +LONGBOW_TEST_FIXTURE(Local) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Local) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(example1); + exit(longBowMain(argc, argv, testRunner, NULL)); +} diff --git a/longbow/src/examples/testLongBow.c b/longbow/src/examples/testLongBow.c new file mode 100755 index 00000000..7c1fd949 --- /dev/null +++ b/longbow/src/examples/testLongBow.c @@ -0,0 +1,152 @@ +/* + * 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. + */ + +/* + * test_LongBow.c + * + */ + +#include <stdio.h> +#include <sys/types.h> +#include <signal.h> +#include <sys/errno.h> + +#include "../unit-test.h" + + +LONGBOW_TEST_RUNNER(LongBow) +{ + LONGBOW_RUN_TEST_FIXTURE(LongBowFixture); +} + +LONGBOW_TEST_RUNNER_SETUP(LongBow) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(LongBow) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(LongBowFixture) +{ + LONGBOW_RUN_TEST_CASE(LongBowFixture, alwaysSucceed); + LONGBOW_RUN_TEST_CASE(LongBowFixture, alwaysUnimplemented); + LONGBOW_RUN_TEST_CASE(LongBowFixture, alwaysImpotent); +} + +LONGBOW_TEST_FIXTURE_SETUP(LongBowFixture) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(LongBowFixture) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(LongBowFixture, testErrno) +{ + errno = ENOENT; + assertTrue(0, "Errno test"); +} + +LONGBOW_TEST_CASE(LongBowFixture, alwaysSucceed) +{ + assertTrue(1, "alwaysSucceed"); +} + +LONGBOW_TEST_CASE(LongBowFixture, alwaysImpotent) +{ +} + +LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, testEvent, .event = &LongBowAssertEvent) +{ + assertTrue(0, "testEvent"); +} + +LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, alwaysFail, .status = LONGBOW_STATUS_FAILED, .event = &LongBowAssertEvent) +{ + assertTrue(0, "alwaysFail"); +} + +LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, alwaysSigTERM, .status = LONGBOW_STATUS_SIGNAL(SIGTERM)) +{ + kill(getpid(), SIGTERM); +} + +LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, alwaysSEGV, .event = &LongBowEventSIGSEGV) +{ + int *p = 0; + int i = *p; + printf("not used %d\n", i); +} + +LONGBOW_TEST_CASE(LongBowFixture, alwaysUnimplemented) +{ + testUnimplemented("alwaysUnimplemented"); +} + +LONGBOW_TEST_CASE(LongBowFixture, alwaysWarn) +{ + testWarn("alwaysWarn"); +} + +LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, alwaysSkip, .event = &LongBowTestSkippedEvent) +{ + testSkip("alwaysSkip"); +} + +LONGBOW_TEST_CASE_EXPECTS(LongBowFixture, alwaysTrap, .status = LONGBOW_STATUS_FAILED) +{ + trapNotImplemented("alwaysTrap"); +} + +LONGBOW_TEST_FIXTURE(TestTearDownWarning) +{ + LONGBOW_RUN_TEST_CASE(TestTearDownWarning, alwaysFail); + LONGBOW_RUN_TEST_CASE(TestTearDownWarning, alwaysSucceed); +} + +LONGBOW_TEST_FIXTURE_SETUP(TestTearDownWarning) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(TestTearDownWarning) +{ + return LONGBOW_STATUS_TEARDOWN_WARNED; +} + +LONGBOW_TEST_CASE(TestTearDownWarning, alwaysFail) +{ + assertTrue(0, "alwaysFail"); +} + +LONGBOW_TEST_CASE(TestTearDownWarning, alwaysSucceed) +{ + assertTrue(1, "alwaysSucceed"); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(LongBow); + int status = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + + exit(status); +} diff --git a/longbow/src/examples/testRunnerSkipped.c b/longbow/src/examples/testRunnerSkipped.c new file mode 100755 index 00000000..f071678d --- /dev/null +++ b/longbow/src/examples/testRunnerSkipped.c @@ -0,0 +1,68 @@ +/* + * 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. + */ + +/** + */ + +#include <stdio.h> + +#include <LongBow/unit-test.h> + +LONGBOW_TEST_RUNNER(Example1) +{ + LONGBOW_RUN_TEST_FIXTURE(FixtureA); +} + +LONGBOW_TEST_RUNNER_SETUP(Example1) +{ + return LONGBOW_STATUS_SETUP_SKIPTESTS; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(Example1) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(FixtureA) +{ + LONGBOW_RUN_TEST_CASE(FixtureA, alwaysSucceed); +} + +LONGBOW_TEST_FIXTURE_SETUP(FixtureA) +{ + assertTrue(0, "This should have been skipped and never be called."); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(FixtureA) +{ + assertTrue(0, "This should have been skipped and never be called."); + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(FixtureA, alwaysSucceed) +{ + assertTrue(0, "This should have been skipped and never be called."); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(Example1); + int status = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + + exit(status); +} diff --git a/longbow/src/examples/testTearDown.c b/longbow/src/examples/testTearDown.c new file mode 100755 index 00000000..183563d9 --- /dev/null +++ b/longbow/src/examples/testTearDown.c @@ -0,0 +1,90 @@ +/* + * 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. + */ + +/** + * + */ +#include <stdio.h> +#include <string.h> + +#include <LongBow/testing.h> +#include <LongBow/debugging.h> + +LONGBOW_TEST_RUNNER(testTearDown) +{ + LONGBOW_RUN_TEST_FIXTURE(Succeeded); + LONGBOW_RUN_TEST_FIXTURE(Warned); +} + +LONGBOW_TEST_RUNNER_SETUP(testTearDown) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(testTearDown) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Succeeded) +{ + LONGBOW_RUN_TEST_CASE(Succeeded, testTearDown); +} + +LONGBOW_TEST_FIXTURE_SETUP(Succeeded) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Succeeded) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Succeeded, testTearDown) +{ + assertTrue(true, ""); +} + + +LONGBOW_TEST_FIXTURE(Warned) +{ + LONGBOW_RUN_TEST_CASE(Warned, alwaysWarn); +} + +LONGBOW_TEST_FIXTURE_SETUP(Warned) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Warned) +{ + return LONGBOW_STATUS_TEARDOWN_WARNED; +} + +LONGBOW_TEST_CASE(Warned, alwaysWarn) +{ + assertTrue(true, ""); +} + + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(testTearDown); + int exitStatus = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} diff --git a/longbow/src/examples/testUnimplemented.c b/longbow/src/examples/testUnimplemented.c new file mode 100755 index 00000000..3ccf18d1 --- /dev/null +++ b/longbow/src/examples/testUnimplemented.c @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#include "../unit-test.h" + +LONGBOW_TEST_RUNNER(Unimplemented) +{ + LONGBOW_RUN_TEST_FIXTURE(Unimplemented); +} + +LONGBOW_TEST_RUNNER_SETUP(Unimplemented) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(Unimplemented) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Unimplemented) +{ + LONGBOW_RUN_TEST_CASE(Unimplemented, Unimplemented); +} + +LONGBOW_TEST_FIXTURE_SETUP(Unimplemented) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Unimplemented) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Unimplemented, Unimplemented) +{ + testUnimplemented("Unimplemented"); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(Unimplemented); + int status = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + + exit(status); +} diff --git a/longbow/src/examples/test_minimal.c b/longbow/src/examples/test_minimal.c new file mode 100755 index 00000000..5089071c --- /dev/null +++ b/longbow/src/examples/test_minimal.c @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#include "../unit-test.h" + +#include "minimal.c" + +LONGBOW_TEST_RUNNER(Example1) +{ + LONGBOW_RUN_TEST_FIXTURE(FixtureA); +} + +LONGBOW_TEST_RUNNER_SETUP(Example1) +{ + return true; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(Example1) +{ + return true; +} + +LONGBOW_TEST_FIXTURE(FixtureA) +{ + LONGBOW_RUN_TEST_CASE(FixtureA, alwaysSucceed); +} + +LONGBOW_TEST_FIXTURE_SETUP(FixtureA) +{ + return true; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(FixtureA) +{ + return true; +} + +LONGBOW_TEST_CASE(FixtureA, alwaysSucceed) +{ + assertTrue(alwaysSucceed(), "This must always succeed."); +} + +int +main(int argc, char *argv[]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(Example1); + int status = longBowMain(argc, argv, testRunner, NULL); + longBowTestRunner_Destroy(&testRunner); + + exit(status); +} diff --git a/longbow/src/examples/tutorial/.gitignore b/longbow/src/examples/tutorial/.gitignore new file mode 100644 index 00000000..fb63b40b --- /dev/null +++ b/longbow/src/examples/tutorial/.gitignore @@ -0,0 +1,3 @@ +test_tutorial11 +test_tutorial12 +test_tutorial13 diff --git a/longbow/src/examples/tutorial/test_tutorial1.c b/longbow/src/examples/tutorial/test_tutorial1.c new file mode 100644 index 00000000..311b5357 --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial1.c @@ -0,0 +1,18 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" diff --git a/longbow/src/examples/tutorial/test_tutorial10.c b/longbow/src/examples/tutorial/test_tutorial10.c new file mode 100644 index 00000000..2eb62dc4 --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial10.c @@ -0,0 +1,68 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> + + +LONGBOW_TEST_RUNNER(myTutorialTest) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, alwaysSucceed) +{ + bool result = alwaysSucceed(); + + assertTrue(result, "This test must always succeed."); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(myTutorialTest); + int status = LONGBOW_TEST_MAIN(argc, argv, testRunner); + + longBowTestRunner_Destroy(&testRunner); + exit(status); +} diff --git a/longbow/src/examples/tutorial/test_tutorial11.c b/longbow/src/examples/tutorial/test_tutorial11.c new file mode 100644 index 00000000..58d44ed4 --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial11.c @@ -0,0 +1,76 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> + + +LONGBOW_TEST_RUNNER(myTutorialTest) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed); + LONGBOW_RUN_TEST_CASE(Global, alwaysFail); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, alwaysSucceed) +{ + bool result = alwaysSucceed(); + + assertTrue(result, "This test must always succeed."); +} + +LONGBOW_TEST_CASE(Global, alwaysFail) +{ + bool result = alwaysFail(); + + assertTrue(result, "This test will fail."); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(myTutorialTest); + int status = LONGBOW_TEST_MAIN(argc, argv, testRunner); + + longBowTestRunner_Destroy(&testRunner); + exit(status); +} diff --git a/longbow/src/examples/tutorial/test_tutorial12.c b/longbow/src/examples/tutorial/test_tutorial12.c new file mode 100644 index 00000000..63a2dc52 --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial12.c @@ -0,0 +1,100 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> + + +LONGBOW_TEST_RUNNER(myTutorialTest) +{ + LONGBOW_RUN_TEST_FIXTURE(Static); + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed); + LONGBOW_RUN_TEST_CASE(Global, alwaysFail); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, alwaysSucceed) +{ + bool result = alwaysSucceed(); + + assertTrue(result, "This test must always succeed."); +} + +LONGBOW_TEST_CASE(Global, alwaysFail) +{ + bool result = alwaysFail(); + + assertTrue(result, "This test will fail."); +} + + +LONGBOW_TEST_FIXTURE(Static) +{ + LONGBOW_RUN_TEST_CASE(Static, _privateFunction); +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Static, _privateFunction) +{ + bool result = _privateFunction(); + + assertTrue(result, "This test must always succeed."); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(myTutorialTest); + int status = LONGBOW_TEST_MAIN(argc, argv, testRunner); + + longBowTestRunner_Destroy(&testRunner); + exit(status); +} diff --git a/longbow/src/examples/tutorial/test_tutorial13.c b/longbow/src/examples/tutorial/test_tutorial13.c new file mode 100644 index 00000000..6d35c9b6 --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial13.c @@ -0,0 +1,108 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> + + +LONGBOW_TEST_RUNNER(myTutorialTest) +{ + LONGBOW_RUN_TEST_FIXTURE(Static); + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed); + LONGBOW_RUN_TEST_CASE(Global, alwaysFail); + LONGBOW_RUN_TEST_CASE(Global, blowUp); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, alwaysSucceed) +{ + bool result = alwaysSucceed(); + + assertTrue(result, "This test must always succeed."); +} + +LONGBOW_TEST_CASE(Global, alwaysFail) +{ + bool result = alwaysFail(); + + assertTrue(result, "This test will fail."); +} + +LONGBOW_TEST_CASE_EXPECTS(Global, blowUp, .event = &LongBowEventSIGSEGV) +{ + blowUp(); + + assertTrue(false, "This will not be executed"); +} + + +LONGBOW_TEST_FIXTURE(Static) +{ + LONGBOW_RUN_TEST_CASE(Static, _privateFunction); +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Static, _privateFunction) +{ + bool result = _privateFunction(); + + assertTrue(result, "This test must always succeed."); +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(myTutorialTest); + int status = LONGBOW_TEST_MAIN(argc, argv, testRunner); + + longBowTestRunner_Destroy(&testRunner); + exit(status); +} diff --git a/longbow/src/examples/tutorial/test_tutorial2.c b/longbow/src/examples/tutorial/test_tutorial2.c new file mode 100644 index 00000000..68e1d39a --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial2.c @@ -0,0 +1,20 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> diff --git a/longbow/src/examples/tutorial/test_tutorial3.c b/longbow/src/examples/tutorial/test_tutorial3.c new file mode 100644 index 00000000..fb635846 --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial3.c @@ -0,0 +1,25 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> + + +LONGBOW_TEST_RUNNER(myTutorialTest) +{ +} diff --git a/longbow/src/examples/tutorial/test_tutorial4.c b/longbow/src/examples/tutorial/test_tutorial4.c new file mode 100644 index 00000000..b8461fe4 --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial4.c @@ -0,0 +1,35 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> + + +LONGBOW_TEST_RUNNER(myTutorialTest) +{ +} + +LONGBOW_TEST_RUNNER_SETUP(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} diff --git a/longbow/src/examples/tutorial/test_tutorial5.c b/longbow/src/examples/tutorial/test_tutorial5.c new file mode 100644 index 00000000..c51ba7ac --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial5.c @@ -0,0 +1,36 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> + + +LONGBOW_TEST_RUNNER(myTutorialTest) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} diff --git a/longbow/src/examples/tutorial/test_tutorial6.c b/longbow/src/examples/tutorial/test_tutorial6.c new file mode 100644 index 00000000..a87c2466 --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial6.c @@ -0,0 +1,40 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> + + +LONGBOW_TEST_RUNNER(myTutorialTest) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ +} diff --git a/longbow/src/examples/tutorial/test_tutorial7.c b/longbow/src/examples/tutorial/test_tutorial7.c new file mode 100644 index 00000000..25601997 --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial7.c @@ -0,0 +1,50 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> + + +LONGBOW_TEST_RUNNER(myTutorialTest) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} diff --git a/longbow/src/examples/tutorial/test_tutorial8.c b/longbow/src/examples/tutorial/test_tutorial8.c new file mode 100644 index 00000000..35fad611 --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial8.c @@ -0,0 +1,52 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> + + +LONGBOW_TEST_RUNNER(myTutorialTest) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + diff --git a/longbow/src/examples/tutorial/test_tutorial9.c b/longbow/src/examples/tutorial/test_tutorial9.c new file mode 100644 index 00000000..c92fc459 --- /dev/null +++ b/longbow/src/examples/tutorial/test_tutorial9.c @@ -0,0 +1,58 @@ +/* + * 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. + */ + +* / + +#include "tutorial.c" + +#include <LongBow/unit-test.h> + + +LONGBOW_TEST_RUNNER(myTutorialTest) +{ + LONGBOW_RUN_TEST_FIXTURE(Global); +} + +LONGBOW_TEST_RUNNER_SETUP(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(myTutorialTest) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, alwaysSucceed); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Global, alwaysSucceed) +{ + bool result = alwaysSucceed(); + + assertTrue(result, "This test must always succeed."); +} diff --git a/longbow/src/examples/tutorial/tutorial.c b/longbow/src/examples/tutorial/tutorial.c new file mode 100755 index 00000000..ff296423 --- /dev/null +++ b/longbow/src/examples/tutorial/tutorial.c @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#include <unistd.h> +#include <stdbool.h> +#include <signal.h> + +static bool +_privateFunction() +{ + return true; +} + +bool +alwaysSucceed() +{ + return _privateFunction(); +} + +bool +alwaysFail() +{ + return false; +} + +bool +blowUp() +{ + char *p = 0; + *p = 0; + + return true; +} diff --git a/longbow/src/python/.gitignore b/longbow/src/python/.gitignore new file mode 100644 index 00000000..34921562 --- /dev/null +++ b/longbow/src/python/.gitignore @@ -0,0 +1,3 @@ +longbow-generate-about +longbow-code +longbow-preprocess diff --git a/longbow/src/python/.project b/longbow/src/python/.project new file mode 100644 index 00000000..fd327b61 --- /dev/null +++ b/longbow/src/python/.project @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>LongBow-Python</name> + <comment></comment> + <projects> + <project>Longbow</project> + </projects> + <buildSpec> + <buildCommand> + <name>org.python.pydev.PyDevBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.python.pydev.pythonNature</nature> + </natures> +</projectDescription> diff --git a/longbow/src/python/.pydevproject b/longbow/src/python/.pydevproject new file mode 100644 index 00000000..f4a65975 --- /dev/null +++ b/longbow/src/python/.pydevproject @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?eclipse-pydev version="1.0"?> + +<pydev_project> +<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property> +<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property> +</pydev_project> diff --git a/longbow/src/python/CMakeLists.txt b/longbow/src/python/CMakeLists.txt new file mode 100644 index 00000000..157cda21 --- /dev/null +++ b/longbow/src/python/CMakeLists.txt @@ -0,0 +1,29 @@ +add_subdirectory(site-packages) + +install( FILES parc_uncrustify.cfg DESTINATION ${CMAKE_INSTALL_PREFIX}/etc ) + +macro(AddLongBowPythonScript scriptFile) + configure_file(${ARGV0}.py ${ARGV0} @ONLY) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${ARGV0} DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +endmacro(AddLongBowPythonScript) + +set(ScriptList + longbow-doxygen-report + longbow-generate-about + longbow-preprocess + longbow-code + longbow-complexity-report + longbow-coverage-report + longbow-bytearray + longbow-ansigcov + longbow-name-report + longbow-size-report + longbow-style-report + longbow-test-run + longbow-test-suite + longbow-vocabulary-report + ) + +foreach(script ${ScriptList}) + AddLongBowPythonScript(${script}) +endforeach() diff --git a/longbow/src/python/longbow-ansigcov.py b/longbow/src/python/longbow-ansigcov.py new file mode 100755 index 00000000..c677ab2c --- /dev/null +++ b/longbow/src/python/longbow-ansigcov.py @@ -0,0 +1,85 @@ +#! /usr/bin/env python +# 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. +# + +# +import sys +import os +import subprocess +''' +This programme takes a previously generated LongBow production (see longbow-preprocess.py) as input +and generates corresponding C code as a template for a complete test runner for that production. +''' + +ansiRed = "\x1b[31m"; +ansiGreen = "\x1b[32m"; +ansiYellow = "\x1b[33;1m"; +ansiOrange = "\x1b[33m"; +ansiReset = "\x1b[0m"; + + +def ANSITerminal_printchars(color, chars): + if color == "red": + return ansiRed + chars + ansiReset + if color == "green": + return ansiGreen + chars + ansiReset + if color == "yellow": + return ansiYellow + chars + ansiReset + if color == "orange": + return ansiOrange + chars + ansiReset + return chars + + +class LongBowAnsi: + def __init__(self, input=sys.stdin): + self.input = input + return + + def tokenise(self, line): + fields = line.split(":", 2) + fields[0] = fields[0].strip() + return fields + + def colourise(self): + lines = self.input.read().splitlines() + for line in lines: + fields = self.tokenise(line) + if len(fields) == 3: + if fields[0] == "#####": + print ANSITerminal_printchars("red", fields[1]), ANSITerminal_printchars("red", fields[2]) + pass + elif fields[0] == "$$$$$": + print ANSITerminal_printchars("yellow", fields[1]), ANSITerminal_printchars("yellow", fields[2]) + pass + else: + print ANSITerminal_printchars("green", fields[1]), ANSITerminal_printchars("green", fields[2]) + pass + pass + pass + return + + +if __name__ == '__main__': + outputFileName = None + + if len(sys.argv) != 2: + print "Usage: longbow-ansigov.py file.gcov" + sys.exit(1) + + with open(sys.argv[1], 'r') as f: + longBowAnsi = LongBowAnsi(f) + longBowAnsi.colourise() + f.close() + + pass diff --git a/longbow/src/python/longbow-bytearray.py b/longbow/src/python/longbow-bytearray.py new file mode 100755 index 00000000..30adfda3 --- /dev/null +++ b/longbow/src/python/longbow-bytearray.py @@ -0,0 +1,54 @@ +#! /usr/bin/env python +# 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. +# + +# +import sys +import os + +def indent(count): + for i in range(0, count/2): + print " ", + return + +def print_interstitialspace(index): + if ((index + 1) % 8) == 0: + print " ", + if ((index + 1) % 16) == 0: + print "" + indent(4) + pass + +def printarray(array): + i = 0 + for c in array: + print "0x%02x," % (c), + print_interstitialspace(i) + i = i + 1 + pass + + return + +if __name__ == '__main__': + with open(sys.argv[1], 'r') as f: + + bytes = bytearray(f.read()) + print len(bytes) + print "unsigned char bytes[] = {" + indent(4) + printarray(bytes) + print "\n};"; + pass + + f.close() diff --git a/longbow/src/python/longbow-code.py b/longbow/src/python/longbow-code.py new file mode 100755 index 00000000..8d5a72b6 --- /dev/null +++ b/longbow/src/python/longbow-code.py @@ -0,0 +1,208 @@ +#! /usr/bin/env python +# 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. +# + +# +import sys +import os +import subprocess +''' +This programme takes a previously generated LongBow production (see longbow-preprocess.py) as input +and generates corresponding C code as a template for a complete test runner for that production. +''' + +def sourceFileNameToShortName(sourceFileName): + ''' + Given a path to a source file, return the name without any path components or suffix after the first '.' (inclusive). + ''' + name = os.path.basename(sourceFileName) + return name.split(".")[0] + +def canonicalizeFunctionName(functionName): + ''' + Given a function name that contains the initial '_' character, + strip it and return a canonicalised form of the same name suitable for invoking from a C source file. + + This used to translate the typical function name mangling by the C compiler, + where foo() becomes _foo in the object file symbol table. + ''' + if functionName[0] == "_": + functionName = functionName[1:] + return functionName + +class LongBowTestGenerator: + def __init__(self, output=sys.stdout): + self.output = output + return + + def generateCode(self, testProduction): + testRunnerName = testProduction["name"] + sourceFileName = testProduction["files"]["sourceFile"] + objectFileName = testProduction["files"]["objectFile"] + + self.filePrologue() + self.testRunnerPrologue(sourceFileName, objectFileName, testRunnerName, testProduction["testFixtures"]) + + for testFixture in testProduction["testFixtures"]: + fixtures = self.generateTestFixture(testProduction, testFixture) + pass + + self.testRunnerEpilogue(sourceFileName, objectFileName, testRunnerName, testProduction["testFixtures"]) + return + + def filePrologue(self): + self.output.write("/*\n") + self.output.write(" *\n") + self.output.write(" */\n") + self.output.write("\n") + return + + def testRunnerPrologue(self, sourceFileName, objectFileName, testRunnerName, testFixtures): + self.output.write("// Include the file(s) containing the functions to be tested.\n") + self.output.write("// This permits internal static functions to be visible to this Test Runner.\n") + self.output.write("#include \"%s\"\n" % (sourceFileName)) + self.output.write("\n") + self.output.write("#include <LongBow/unit-test.h>\n") + self.output.write("\n") + self.output.write("LONGBOW_TEST_RUNNER(%s)\n" % (testRunnerName)) + self.output.write("{\n") + self.output.write(" // The following Test Fixtures will run their corresponding Test Cases.\n") + self.output.write(" // Test Fixtures are run in the order specified here, but every test must be idempotent.\n") + self.output.write(" // Never rely on the execution order of tests or share state between them.\n") + for testFixture in testFixtures: + self.output.write(" LONGBOW_RUN_TEST_FIXTURE(%s);\n" % (testFixture["name"])) + pass + self.output.write("}\n") + self.output.write("\n" ) + self.output.write("// The Test Runner calls this function once before any Test Fixtures are run.\n") + self.output.write("LONGBOW_TEST_RUNNER_SETUP(%s)\n" % (testRunnerName)) + self.output.write("{\n") + self.output.write(" return LONGBOW_STATUS_SUCCEEDED;\n") + self.output.write("}\n") + self.output.write("\n") + self.output.write("// The Test Runner calls this function once after all the Test Fixtures are run.\n") + self.output.write("LONGBOW_TEST_RUNNER_TEARDOWN(%s)\n" % (testRunnerName)) + self.output.write("{\n") + self.output.write(" return LONGBOW_STATUS_SUCCEEDED;\n") + self.output.write("}\n") + self.output.write("\n") + return + + def testRunnerEpilogue(self, sourceFileName, objectFileName, testRunnerName, testFixtures): + self.output.write("int\n") + self.output.write("main(int argc, char *argv[])\n") + self.output.write("{\n") + self.output.write(" LongBowTestRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(%s);\n" % (testRunnerName)) + self.output.write(" int exitStatus = longBowMain(argc, argv, testRunner, NULL);\n"); + self.output.write(" longBowTestRunner_Destroy(&testRunner);\n"); + self.output.write(" exit(exitStatus);\n"); + self.output.write("}\n") + return + + def generateTestFixture(self, testProduction, testFixture): + testFixtureName = testFixture["name"] + + sourceFileName = testProduction["files"]["sourceFile"] + objectFileName = testProduction["files"]["objectFile"] + + self.testFixturePrologue(sourceFileName, objectFileName, testFixtureName, testFixture["testSuites"]) + + for testSuite in testFixture["testSuites"]: + self.generateTestSuite(testProduction, testFixture, testSuite) + pass + + self.testFixtureEpilogue(testProduction, testFixture, testSuite) + return [ testFixtureName ] + + def testFixturePrologue(self, sourceFileName, objectFileName, testFixtureName, testSuites): + self.output.write("LONGBOW_TEST_FIXTURE(%s)\n" % (testFixtureName)) + self.output.write("{\n") + for testSuite in testSuites: + for testCase in testSuite["testCases"]: + self.output.write(" LONGBOW_RUN_TEST_CASE(%s, %s);\n" % (testFixtureName, testCase)) + pass + pass + self.output.write("}\n") + self.output.write("\n") + self.output.write("LONGBOW_TEST_FIXTURE_SETUP(%s)\n" % (testFixtureName)) + self.output.write("{\n") + self.output.write(" return LONGBOW_STATUS_SUCCEEDED;\n") + self.output.write("}\n") + self.output.write("\n") + self.output.write( "LONGBOW_TEST_FIXTURE_TEARDOWN(%s)\n" % (testFixtureName)) + self.output.write("{\n") + self.output.write(" return LONGBOW_STATUS_SUCCEEDED;\n") + self.output.write("}\n") + self.output.write("\n") + return + + def testFixtureEpilogue(self, testProduction, testFixture, testSuite): + return + + def generateTestSuite(self, testProduction, testFixture, testSuite): + for testCase in testSuite["testCases"]: + self.generateTestCase(testProduction, testFixture, testCase) + return + + def generateTestCase(self, testProduction, testFixture, testCase): + self.output.write("LONGBOW_TEST_CASE(%s, %s)\n" % (testFixture["name"], testCase)) + self.output.write("{\n") + self.output.write(" testUnimplemented(\"\");\n") + self.output.write("}\n") + self.output.write("\n") + return + +def getProductionSchema(fileName): + ''' + Get the "production" schema produced by the preprocessor. + ''' + f = open(fileName, "r") + text = f.read() + f.close() + return eval(text) + +def canonicalOutputFileName(production): + outputFileName = "test_" + sourceFileNameToShortName(production["files"]["sourceFile"]) + ".c" + return outputFileName + +def canonicalOutput(outputFileName): + if outputFileName == None: + return sys.stdout + open(outputFileName) + +if __name__ == '__main__': + ''' +@(#) longbow-code @VERSION@ @DATE@ +@(#) All Rights Reserved. Use is subject to license terms. + ''' + outputFileName = None + + if len(sys.argv) != 2: + print "Usage: longbow-code file.longbow" + sys.exit(1) + + production = getProductionSchema(sys.argv[1]) + + if outputFileName == None: + outputFileName = canonicalOutputFileName(production) + + if os.path.exists(outputFileName): + print "Refusing to overwrite the existing '%s'." % (outputFileName) + sys.exit(1) + + outputFile = open(outputFileName, 'w') + + generator = LongBowTestGenerator(outputFile) + generator.generateCode(production) + pass diff --git a/longbow/src/python/longbow-complexity-report.py b/longbow/src/python/longbow-complexity-report.py new file mode 100755 index 00000000..81ddcf72 --- /dev/null +++ b/longbow/src/python/longbow-complexity-report.py @@ -0,0 +1,213 @@ +#! /usr/bin/env python +# 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. +# + +# + +import sys +import argparse +import itertools +sys.path.append("@INSTALL_PYTHON_DIR@") +sys.path.append("@DEPENDENCY_PYTHON_DIR@") +import LongBow +try: + import hfcca +except ImportError: + print "HFCCA not found. You need to download hfcca.py and place it in a location" + print "where this script (python) can find it." + print "You can find a compatible version of hfcca at: " + print " https://headerfile-free-cyclomatic-complexity-analyzer.googlecode.com/files/hfcca.py" + print "And place it at: @INSTALL_PYTHON_DIR@" + print + print "... however, you should have run the ccnx-post-install script" + print " (from the ccnx distribution you got this from)" + sys.exit(1) + +def computeComplexityScore(complexity): + score = min(100.0 * abs(1.0 - float(complexity - 5) / 50.0), 100.0) + return score + +def csvFunctionResult(file, function): + score = computeComplexityScore(function.cyclomatic_complexity) + string = "complexity,%s,%s,%d,%d,%.2f" % (file.filename, function.name, function.start_line, function.cyclomatic_complexity, score) + + LongBow.scorePrinter([90, 80], score, string) + return function.cyclomatic_complexity + +def csvFileComplexity(file): + score = computeComplexityScore(file.average_CCN) + string = "complexity,%s,,,%.2f,%.2f" % (file.filename, file.average_CCN, score) + LongBow.scorePrinter([90, 80], score, string) + return + +def csvFunction(fileInformationList): + for fileInformation in fileInformationList: + complexities = map(lambda function: csvFunctionResult(fileInformation, function), fileInformation) + return + +def csvSummary(fileInformationList): + map(lambda file: csvFileComplexity(file), fileInformationList) + return + + +def textFunctionResult(file, function, maxFileNameLength, maxFunctionNameLength): + score = computeComplexityScore(function.cyclomatic_complexity) + format = "%-" + str(maxFileNameLength) + "s %-" + str(maxFunctionNameLength) + "s %6d %2d %6.2f" + string = format % (file.filename, function.name, function.start_line, function.cyclomatic_complexity, score) + + LongBow.scorePrinter([90, 80], score, string) + return function.cyclomatic_complexity + +def textFileComplexity(file, maxFileNameLength): + score = computeComplexityScore(file.average_CCN) + string = ("%-" + str(maxFileNameLength) + "s %6.2f %6.2f") % (file.filename, file.average_CCN, score) + LongBow.scorePrinter([90, 80], score, string) + return + +def computeMaxFileNameLength(fileInformationList): + result = 0 + for fileInformation in fileInformationList: + if len(fileInformation.filename) > result: + result = len(fileInformation.filename) + return result + +def computeMaxFunctionNameLength(fileInformationList): + result = 0 + for fileInformation in fileInformationList: + if len(fileInformation.filename) > result: + result = len(fileInformation.filename) + return result + +def textFunction(fileInformationList): + maxFileNameLength = max(map(lambda fileInformation: len(fileInformation.filename), fileInformationList)) + maxFunctionNameLength = max(map(lambda fileInformation: max(map(lambda function: len(function.name), fileInformation)), fileInformationList)) + + for fileInformation in fileInformationList: + complexities = map(lambda function: textFunctionResult(fileInformation, function, maxFileNameLength, maxFunctionNameLength), fileInformation) + return + +def textSummary(fileInformationList): + maxFileNameLength = max(map(lambda fileInformation: len(fileInformation.filename), fileInformationList)) + map(lambda file: textFileComplexity(file, maxFileNameLength), fileInformationList) + return +# +# Recompute the file's average complexity as a floating point number. +def recomputeFileComplexity(fileInformation): + complexities = map(lambda function: function.cyclomatic_complexity, fileInformation) + if len(complexities) > 0: + sum = reduce(lambda sum, complex: sum + complex, complexities) + fileInformation.average_CCN = float(sum) / len(fileInformation) + else: + fileInformation.average_CCN = 0 + return fileInformation.average_CCN + +def recomputeFilesComplexity(fileInformationList): + return map(lambda fileInformation: recomputeFileComplexity(fileInformation), fileInformationList) + +def computeAverage(fileInformationList): + cyclomaticComplexity = map(lambda fileInformation : fileInformation.average_CCN, fileInformationList) + sum = reduce(lambda sum, x: sum + x, cyclomaticComplexity) + return float(sum) / float(len(cyclomaticComplexity)) + +def main(argv): + desc = '''longbow-complexity-report @VERSION@ @DATE@ + All Rights Reserved. Use is subject to license terms. + +Print the cyclomatic complexity of functions and files. + +The option --function displays the file name, function name, +line number of the function, the cyclomatic complexity and a score ranging from 0 to 100. + +The default option --summary displays the file name, +the average cyclomatic complexity of all functions in the file and +a score ranging from 0 to 100. + +Input is either from a list of files supplied as command line parameters, +or as a list of newline separated file names read from standard input. +Output is a plain text (default) or comma-separated-value (CSV). + +Examples: + +% longbow-complexity-report *.[ch] + +Report conformance of the .c and .h files specified as command line parameters. + +% longbow-complexity-report - +Report conformance of the .c and .h files read from standard input, one line per file. + +$ longbow-complexity-report parc_JSON.c +parc_JSON.c 2.27 100.00 +$ +$ echo parc_JSON.c | longbow-complexity-report -o csv - +complexity,parc_JSON.c,,,2.27,100.00 +$ +''' + + parser = argparse.ArgumentParser(prog='longbow-complexity-report', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc) + parser.add_argument('-s', '--summary', default=False, action="store_true", help="print the average complexity of each target file.") + parser.add_argument('-f', '--function', default=False, action="store_true", help="print the complexity of each function in each target file.") + parser.add_argument('-', '--stdin', default=False, action="store_true", required=False, help="read the list of files from standard input rather than the command line.") + parser.add_argument('-a', '--average', default=False, action="store_true", required=False, help="display only the simple average of the average complexity of each target file.") + parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="the output format: \"text\" or \"csv\"") + parser.add_argument("files", help="Files to check", nargs="*") + + args = parser.parse_args() + + targets = [] + + if args.stdin: + for line in sys.stdin: + t = line.strip() + if (len(t) > 0): + targets.append(t) + else: + targets = args.files + + if (len(targets) == 0): + print >> sys.stderr, "Error: No files to analyze. See %s -h" % (sys.argv[0]) + sys.exit(1) + + # If nothing was specified, print the summary as a default + if args.summary == False and args.function == False and args.average == False: + args.summary = True + + options, arguments = hfcca.createHfccaCommandLineParser().parse_args(args=[argv[0]]) + result = hfcca.analyze(targets, options) + + # Convert from that iterator to a simple list... + fileInformationList = map(lambda x : x, result) + + recomputeFilesComplexity(fileInformationList) + + if args.function: + if args.output == "text": + textFunction(fileInformationList) + else: + csvFunction(fileInformationList) + + if args.summary: + if args.output == "text": + textSummary(fileInformationList) + else: + csvSummary(fileInformationList) + + if args.average: + print "%.2f" % computeAverage(fileInformationList) + +if __name__ == "__main__": + ''' +@(#) longbow-complexity-report @VERSION@ @DATE@ +@(#) All Rights Reserved. Use is subject to license terms. +''' + main(sys.argv) diff --git a/longbow/src/python/longbow-coverage-report.py b/longbow/src/python/longbow-coverage-report.py new file mode 100755 index 00000000..4a0a86ab --- /dev/null +++ b/longbow/src/python/longbow-coverage-report.py @@ -0,0 +1,87 @@ +#! /usr/bin/env python +# 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. +# + +# +import sys +import argparse + +sys.path.append("@INSTALL_PYTHON_DIR@") +sys.path.append("@DEPENDENCY_PYTHON_DIR@") +sys.path.append("../site-packages/longbow/") +import CoverageReport + + +if __name__ == '__main__': + ''' +@(#) longbow-coverage-report @VERSION@ @DATE@ +@(#) All Rights Reserved. Use is subject to license terms. +''' + description = ''' +longbow-coverage-report @VERSION@ @DATE@ +All Rights Reserved. Use is subject to license terms. + +Report on the code coverage of tests. + +The source files or executables to analyse are supplied as command line parameters, +or as a list of newline separated file names read from standard input. + +Output is plain-text (default --output text) or a CSV file (--output csv) +reporting the results. + +Results are: + An average of all files specified (--average) + A one line summary of all files specified (--summary) + A listing of the original source file, colorized showing tested and non-tested lines. + ''' + parser = argparse.ArgumentParser(prog='longbow-coverage-report', + formatter_class=argparse.RawDescriptionHelpFormatter, + description=description) + parser.add_argument('-', '--stdin', default=False, action="store_true", required=False, + help="Read the list of files from standard input.") + parser.add_argument('-s', '--summary', default=False, action="store_true", required=False, + help="Display the score for each file (excluding test source files).") + parser.add_argument('-a', '--average', default=False, action="store_true", required=False, + help="Display the average score for all C source files (excluding test source files).") + parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, + help="Set the output format: \"text\" or \"csv\"") + parser.add_argument('-v', '--visual', default=False, action="store_true", required=False, + help="Colorize the original source code showing coverage") + parser.add_argument('-x', '--explain', default=False, action="store_true", required=False, + help="Display information about the collection of coverage information (guru mode).") + parser.add_argument('-d', '--distribution', default="[95, 90]", action="store", required=False, type=str, + help="A list containing the score distributions for pretty-printing. Default [95, 90]") + parser.add_argument('-T', '--includeTestSources', default=False, action="store_true", required=False, + help="Include analysis of the test sources. Default False") + parser.add_argument('-t', '--testDir', default="", action="store", required=False, type=str, + help="Directory hint for locating test files.") + + parser.add_argument("files", help="Files to check", nargs="*") + + args = parser.parse_args() + + if not args.summary and not args.average and not args.visual and not args.explain: + args.summary = True + + fileNames = [] + + if args.stdin: + for line in sys.stdin: + t = line.strip() + if len(t) > 0: + fileNames.append(t) + else: + fileNames = args.files + + CoverageReport.commandLineMain(args, fileNames, args.testDir) diff --git a/longbow/src/python/longbow-doxygen-report.py b/longbow/src/python/longbow-doxygen-report.py new file mode 100755 index 00000000..1b303f91 --- /dev/null +++ b/longbow/src/python/longbow-doxygen-report.py @@ -0,0 +1,166 @@ +#! /usr/bin/env python +# 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. +# + +# + +import sys +import os +import pprint +import subprocess +import difflib +import csv +import argparse +sys.path.append("@INSTALL_PYTHON_DIR@") +sys.path.append("@DEPENDENCY_PYTHON_DIR@") +import LongBow + +def concatenateContinuationLines(lines): + ''' + Parse doxygen log lines. + Lines that are indented by a space are continutations of the previous line. + ''' + result = list() + accumulator = "" + for line in lines: + line = line.rstrip() + if line.startswith(" ") == False and line.startswith(" ") == False: + if len(accumulator) > 0: + result.append(accumulator) + accumulator = line + else: + accumulator = accumulator + " " + line.lstrip() + + result.append(accumulator) + + return result + +def parseLine(line): + result = None + if not line.startswith("<"): + fields = line.split(":") + if len(fields) >= 4: + result = { "fileName" : fields[0].strip(), + "lineNumber" : int(fields[1].strip()), + "type" : "documentation", + "severity" : fields[2].strip(), + "message" : " ".join(fields[3:]).strip()} + elif line.startswith("error"): + print line + elif len(line) > 0: + print "Consider using doxygen -s:", line + + return result + +def canonicalize(lines): + lines = concatenateContinuationLines(lines) + parsedLines = map(lambda line: parseLine(line), lines) + parsedLines = filter(lambda line: line != None, parsedLines) + return parsedLines + +def organize(entries): + result = dict() + + for entry in entries: + if not entry["fileName"] in result: + result[entry["fileName"]] = dict() + + entryByFile = result[entry["fileName"]] + + if not str(entry["lineNumber"]) in entryByFile: + entryByFile[str(entry["lineNumber"])] = list() + if not entry in entryByFile[str(entry["lineNumber"])]: + entryByFile[str(entry["lineNumber"])].append(entry) + + return result + +def textualSummary(distribution, documentation): + maxWidth = 0 + for entry in documentation: + if len(entry) > maxWidth: + maxWidth = len(entry) + + formatString ="%-" + str(maxWidth) + "s %8d %8d %.2f%%" + for entry in documentation: + badLines = len(documentation[entry]) + totalLines = LongBow.countLines(entry) + score = float(totalLines - badLines) / float(totalLines) * 100.0 + LongBow.scorePrinter(distribution, score, formatString % (entry, totalLines, badLines, score)) + return + +def textualAverage(distribution, documentation, format): + sum = 0.0 + + for entry in documentation: + badLines = len(documentation[entry]) + totalLines = LongBow.countLines(entry) + score = float(totalLines - badLines) / float(totalLines) * 100.0 + sum = sum + score + + if len(documentation) == 0: + averageScore = 100.0 + else: + averageScore = sum / float(len(documentation)) + + LongBow.scorePrinter(distribution, averageScore, format % averageScore) + +def csvSummary(distribution, documentation): + formatString ="documentation,%s,%d,%d,%.2f%%" + for entry in documentation: + badLines = len(documentation[entry]) + totalLines = LongBow.countLines(entry) + score = float(totalLines - badLines) / float(totalLines) * 100.0 + LongBow.scorePrinter(distribution, score, formatString % (entry, totalLines, badLines, score)) + return + +def main(argv): + parser = argparse.ArgumentParser(prog='longbow-doxygen-report', formatter_class=argparse.RawDescriptionHelpFormatter, description="") + parser.add_argument('-l', '--doxygenlog', default=False, action="store", required=True, type=str, help="The doxygen output log to use.") + parser.add_argument('-s', '--summary', default=False, action="store_true", required=False, help="Produce the score for each file") + parser.add_argument('-a', '--average', default=False, action="store_true", required=False, help="Produce the simple average of all scores.") + parser.add_argument('-d', '--distribution', default="[100, 95]", action="store", required=False, type=str, help="A list containing the score distributions for pretty-printing") + parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="The required output format. text, csv") + + args = parser.parse_args() + + if not args.summary and not args.average: + args.summary = True + + with open(args.doxygenlog, 'r') as f: + lines = f.readlines() + + lines = canonicalize(lines) + + result = organize(lines) + + pp = pprint.PrettyPrinter(indent=4) + #pp.pprint(result) + + distribution = eval(args.distribution) + if args.summary: + if args.output == "text": + textualSummary(distribution, result) + else: + csvSummary(distribution, result) + + if args.average: + textualAverage(distribution, result, "%.2f") + + +if __name__ == '__main__': + ''' +@(#) longbow-doxygen-report @VERSION@ @DATE@ +@(#) All Rights Reserved. Use is subject to license terms. + ''' + main(sys.argv) diff --git a/longbow/src/python/longbow-generate-about.py b/longbow/src/python/longbow-generate-about.py new file mode 100755 index 00000000..437102a3 --- /dev/null +++ b/longbow/src/python/longbow-generate-about.py @@ -0,0 +1,289 @@ +#! /usr/bin/env python +# 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. +# + +# +import os +import sys +import string +import datetime +import argparse +sys.path.append("@INSTALL_PYTHON_DIR@") +sys.path.append("@DEPENDENCY_PYTHON_DIR@") +import FileUtil + +whatLineToken = "@(#)" + +def translateCCharacter(character): + result = character + + if character == '\t': + result = "\\t" + elif character == "\n": + result = "\\n" + elif character == "\"": + result = "\\\"" + elif character == "\'": + result = "\\'" + + return result + + +def makeWhatLine(line): + return "@(#)" + line + +def createCString(string): + if string is None: + result = "None" + else: + result = "".join(map(lambda character: translateCCharacter(character), string)) + return result + +def createQuotedCString(string): + return "\"%s\"" % createCString(string) + +def cIdentifier(name): + translation = string.maketrans("-!@#$%^&*()_-+=[]{}|;:<>,./?", "____________________________") + return name.translate(translation) + + +def validateArgument(arg): + ''' + If the given parameter is equal to '-' return None, otherwise return the parameter. + ''' + if arg == "-": + return None + return arg + + +class LongBowGenerateAboutHFile: + def __init__(self, prefix): + self.prefix = prefix + return + + def headerdocFunction(self, functionName, OneLineDescription, returns): + result = "/**\n" + result += " * %s\n" % OneLineDescription + result += " *\n" + result += " * @return %s\n" % returns + result += " */\n" + return result + + def FileName(self): + return self.prefix + "_About.h" + + def Name(self): + functionName = "%sAbout_Name" % self.prefix + result = self.headerdocFunction(functionName, "Return the name as a C string.", "The name as a C string.") + result += "const char *%s(void);\n" % functionName + return result + + def Version(self): + functionName = "%sAbout_Version" % self.prefix + result = self.headerdocFunction(functionName, "Return the version as a C string.", "The version as a C string.") + result += "const char *%s(void);\n" % functionName + return result + + def About(self): + functionName = "%sAbout_About" % self.prefix + result = self.headerdocFunction(functionName, "Return the About text as a C string.", "The About text as a C string.") + result += "const char *%s(void);\n" % functionName + return result + + def MiniNotice(self): + functionName = "%sAbout_MiniNotice" % self.prefix + result = self.headerdocFunction(functionName, + "Return the minimum copyright notice as a C string.", + "The minimum copyright notice as a C string.") + result += "const char *%s(void);\n" % functionName + return result + + def ShortNotice(self): + functionName = "%sAbout_ShortNotice" % self.prefix + result = self.headerdocFunction(functionName, + "Return the short copyright notice as a C string.", + "The short copyright notice as a C string.") + result += "const char *%s(void);\n" % functionName + return result + + def LongNotice(self): + functionName = "%sAbout_LongNotice" % self.prefix + result = self.headerdocFunction(functionName, + "Return the long copyright notice as a C string.", + "The long copyright notice as a C string.") + result += "const char *%s(void);\n" % functionName + return result + + def WhatString(self): + result = "/**\n" + result += " * Embedded string containing information for the what(1) command.\n" + result += " *\n" + result += " */\n" + result += "extern const char *%s_What;\n" % (self.prefix) + return result + + def __str__(self): + result = "// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.\n" + result += "// longbow-generate-about @VERSION@ @DATE@\n\n" + result += "#ifndef %s_About_h\n" % (self.prefix) + result += "#define %s_About_h\n" % (cIdentifier(self.prefix)) + result += self.WhatString() + "\n" + result += self.Name() + "\n" + result += self.Version() + "\n" + result += self.About() + "\n" + result += self.MiniNotice() + "\n" + result += self.ShortNotice() + "\n" + result += self.LongNotice() + "\n" + result += "#endif // %s_About_h\n" % (cIdentifier(self.prefix)) + return result + + def writeFile(self): + with open(self.FileName(), "w") as myfile: + myfile.write(str(self)) + return + +class LongBowGenerateAboutCFile: + def __init__(self, args): + self.prefix = args.prefix + self.name = args.name + self.version = validateArgument(args.version) + self.miniNotice = "" + self.shortNotice = "" + self.longNotice = "" + self.about = None + self.what = None + + self.args = args + + self.miniNotice = FileUtil.readFileString(args.miniNotice) + self.shortNotice = FileUtil.readFileString(args.shortNotice) + self.longNotice = FileUtil.readFileString(args.longNotice) + + self.buildDate = datetime.datetime.utcnow().isoformat() + + if self.version == None: + self.version = " RELEASE_VERSION " + + if self.about == None: + self.about = createQuotedCString("%s " % (self.name)) + \ + self.version + \ + createQuotedCString(" %s" % (self.buildDate)) + " " + \ + createQuotedCString("\n%s" % (self.miniNotice)) + + if self.what == None: + if self.miniNotice != None: + notice = "\n".join(map(lambda line: "\t" + line, self.miniNotice.split("\n")[:-1])) + else: + notice = "" + self.what = createQuotedCString(whatLineToken) + " " + \ + createQuotedCString(self.name + " ") + " " + \ + self.version + " " + \ + createQuotedCString(" " + self.buildDate) + "\n" + \ + createQuotedCString(whatLineToken) + " " + \ + createQuotedCString(notice) + return + + def FileName(self): + return self.prefix + "_About.c" + + def Name(self): + functionName = "%sAbout_Name" % self.prefix + return self.boilerPlateFunction(functionName, createQuotedCString(self.name)) + + def Version(self): + functionName = "%sAbout_Version" % self.prefix + return self.boilerPlateFunction(functionName, self.version) + + def About(self): + functionName = "%sAbout_About" % self.prefix + return self.boilerPlateFunction(functionName, self.about) + + def MiniNotice(self): + functionName = "%sAbout_MiniNotice" % self.prefix + return self.boilerPlateFunction(functionName, createQuotedCString(self.miniNotice)) + + def ShortNotice(self): + functionName = "%sAbout_ShortNotice" % self.prefix + return self.boilerPlateFunction(functionName, createQuotedCString(self.shortNotice)) + + def LongNotice(self): + functionName = "%sAbout_LongNotice" % self.prefix + return self.boilerPlateFunction(functionName, createQuotedCString(self.longNotice)) + + def WhatString(self): + return "const char *%s_What = %s;\n" % (self.prefix, self.what) + + def boilerPlateFunction(self, functionName, string): + result = "const char *\n%s(void)\n" % functionName + result += "{\n" + result += " return %s;\n" % string + result += "}\n" + return result + + def __str__(self): + result = "// DO NOT EDIT THIS FILE. IT IS AUTOMATICALLY GENERATED.\n" + result += "// longbow-generate-about @VERSION@ @DATE@\n\n" + result += "#include \"%s_About.h\"\n\n" % self.prefix + result += self.WhatString() + "\n" + result += self.Name() + "\n" + result += self.Version() + "\n" + result += self.About() + "\n" + result += self.MiniNotice() + "\n" + result += self.ShortNotice() + "\n" + result += self.LongNotice() + "\n" + return result + + def writeFile(self): + with open(self.FileName(), "w") as myfile: + myfile.write(str(self)) + return + +if __name__ == '__main__': + desc = ''' +@(#) longbow-generate-about @VERSION@ @DATE@ +@(#) All Rights Reserved. Use is subject to license terms. + +Generate C code conforming to the About contract. + +Create a .c and .h file pair with the specified prefix. +For the prefix 'xyzzy', the file names are 'xyzzy_About.c' and 'xyzzy_About.h' respectively. + +The functions defined are: + +const char *xyzzyAbout_Name(void) +const char *xyzzyAbout_Version(void) +const char *xyzzyAbout_About(void) +const char *xyzzyAbout_MiniNotice(void) +const char *xyzzyAbout_ShortNotice(void) +const char *xyzzyAbout_LongNotice(void) + +And the constant string const char *xyzzy_What; + ''' + + parser = argparse.ArgumentParser(prog='longbow-generate-about', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc) + + parser.add_argument("prefix", help="The file name and function name prefix.") + parser.add_argument("name", help="The name of the entity this is about.") + parser.add_argument("version", help="The version of the entity this is about.") + parser.add_argument("miniNotice", help="The name of the file containing the smallest copyright or attribution notice.") + parser.add_argument("shortNotice", help="The name of the file containing a short copyright or attribution notice.") + parser.add_argument("longNotice", help="The name of the file containing a full copyright or attribution notice.") + + args = parser.parse_args() + + hfile = LongBowGenerateAboutHFile(args.prefix) + hfile.writeFile() + + cfile = LongBowGenerateAboutCFile(args) + cfile.writeFile() diff --git a/longbow/src/python/longbow-name-report.py b/longbow/src/python/longbow-name-report.py new file mode 100755 index 00000000..3daca949 --- /dev/null +++ b/longbow/src/python/longbow-name-report.py @@ -0,0 +1,91 @@ +#! /usr/bin/env python +# 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. +# + +# + +import os +import sys +import argparse + +sys.path.append("../site-packages/longbow/") +sys.path.append("@INSTALL_PYTHON_DIR@") +import NameReport + +if __name__ == '__main__': + ''' + @(#) name-report @VERSION@ @DATE@ + @(#) All Rights Reserved. Use is subject to license terms. + ''' + desc = ''' +Print a score representing the percentage of compliance with the naming conventions for one or more C source and object files. + +$ ./longbow-name-report parc_Object.c +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-names 100.00 enum-names 100.0 typedef-names 100.0 +$ +$ echo parc_Object.c | ./parc-name-grade - +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-names 100.00 enum-names 100.0 typedef-names 100.0 +$ + +Default Output (--summary): +namespace, module-name[, topic, score] + +namespace: Namespace of the file, like `parc` +module-name: The name of the file, like `parc_ArrayList.c` +topic: The name of the topic: valid-name, function-name-conformance, or enum-name-conformance +score: A context-sensitive value related to the topic (valid-name: True/False, function/enum-name-conformance: 0-100) + +Finegrain Output (--finegrain): +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-names 100.00 enum-names 100.0 typedef-names 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Acquire 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_AssertValid 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Compare 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Copy 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Create 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Display 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Equals 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_GetReferenceCount 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_HashCode 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_Release 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_TestAcquireContractRaw 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object function-name parcObject_ToJSON 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/LibpgetEnumerationsFromFilesarc/parc/algol parc_Object function-name parcObject_ToString 100.0 +/Users/cwood/Projects/DistilleryBranches/Case1073/Libparc/parc/algol parc_Object typedef-name _ObjectHeader 100.0 +''' + + parser = argparse.ArgumentParser(prog='longbow-name-report', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc) + parser.add_argument('-a', '--average', default=False, action="store_true", help="Print an average summary of the naming conformance results for all modules") + parser.add_argument('-s', '--summary', default=False, action="store_true", help="Print a summary of the naming conformance results for each module") + parser.add_argument('-f', '--finegrain', default=False, action="store_true", help="Print the individual results for each function, typedef, and enumeration in each module.") + parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="the output format: \"text\" or \"csv\"") + parser.add_argument('-d', '--distribution', default="[99, 90]", action="store", required=False, type=str, help="a list containing the score distributions for pretty-printing. Default [99, 90]") + parser.add_argument('-t', '--trace', default=False, action="store_true", help="Turn on exception tracing to debug an issue with the tool.") + parser.add_argument('-', '--stdin', default=False, action="store_true", required=False, help="Read the list of files from standard input.") + parser.add_argument('-p', '--opath', default="", action="store", required=False, type=str, help="Specify the path for object files, can be a path to a static library.") + parser.add_argument("files", help="Files to check", nargs="*") + + args = parser.parse_args() + + targets = [] + if args.stdin: + for line in sys.stdin: + targets.append(line.strip()) + else: + targets = args.files + + if (len(targets) == 0): + parser.print_usage() + sys.exit(1) + + NameReport.commandLineMain(args, targets, args.opath) diff --git a/longbow/src/python/longbow-preprocess.py b/longbow/src/python/longbow-preprocess.py new file mode 100755 index 00000000..12c01c2a --- /dev/null +++ b/longbow/src/python/longbow-preprocess.py @@ -0,0 +1,153 @@ +#! /usr/bin/env python +# 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. +# + +# + +import sys +import os +import subprocess +import pprint + +def sourceFileNameToName(sourceFileName): + ''' + Given the path to a source file, return the name without any path components or trailing suffix. + ''' + name = os.path.basename(sourceFileName) + return name.split(".")[0] + +def canonicalizeFunctionName(functionName): + ''' + Given a function name that contains the initial '_' character, + strip it and return a canonicalised form of the same name suitable for a source file. + ''' + if functionName[0] == "_": + functionName = functionName[1:] + return functionName + +def isReservedName(functionName): + ''' + Given a canonicalized name, determine if it is a reserved name according to ISO/IEC 9899:2011 and ANSI Sec. 4.1.2.1, + identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use. + ''' + if functionName[0] == '_' and functionName[1] == '_': + return True + elif functionName[0] == '_' and functionName[1].isupper(): + return True + + return False + + +def getDarwinTestableFunctions(sourceFileName, objectFileName): + ''' + ''' + command = [ "/usr/bin/nm", "-Um", objectFileName ] + + output = subprocess.check_output(command) + lines = output.splitlines() + + external = [] + internal = [] + for line in lines: + fields = line.split(" ") + if fields[1] == "(__TEXT,__text)": + functionName = canonicalizeFunctionName(fields[3]) + + if isReservedName(functionName): + print "Ignoring function with a ISO/IEC 9899:2011 and ANSI Sec. 4.1.2.1 reserved name: ", functionName + else: + if fields[2] == "external": + external.append( ( functionName ) ) + else: + internal.append( ( functionName ) ) + pass + pass + pass + + external.sort() + internal.sort() + return { "Static": internal, "Global" : external } + +def testCases(functionList): + ''' + ''' + return { "testCases" : functionList } + +def testSuite(testCases): + ''' + A Test Suite is comprised of one or more Test Cases + ''' + if testCases == None or len(testCases) == 0: + return None + return [ testCases ] + +def testFixture(testFixtureName, testSuites): + ''' + A Test Fixture contains an initial setup function, one or more Test Suites, and a final tear-down function. + ''' + if testSuites == None: + return None + return { "name" : testFixtureName, "testSuites" : testSuites } + +def testRunner(testRunnerName, files, testFixtures): + ''' + A Test Runner contains one or more Test Fixtures. + ''' + testFixtures = [x for x in testFixtures if x is not None] + return { "name" : testRunnerName, "files" : files, "testFixtures" : testFixtures } + +def computeFileNames(argv): + """ Given an argument list, compute the file names to use for code generation. + + + """ + if (argv[1].endswith(".c")): + return (argv[1], argv[2], sourceFileNameToName(argv[1]) + ".longbow") + + return (argv[1]+".c", argv[1]+".o", sourceFileNameToName(argv[1]) + ".longbow") + +if __name__ == '__main__': + ''' + @(#) longbow-preprocess @VERSION@ @DATE@ + @(#) All Rights Reserved. Use is subject to license terms. +''' + if len(sys.argv) <= 1: + print "Usage: longbow-preprocess (sourceFileName objectFileName) | (fileNamePrefix)" + print + print "Generate a plain-text intermediate form for a LongBow test case generated from" + print "a specified source and object file. Use longbow-code to produce a LongBow" + print "test runner based upon the intermediate form." + sys.exit(1) + + fileNames = computeFileNames(sys.argv) + + sourceFileName = fileNames[0] + objectFileName = fileNames[1] + outputFileName = fileNames[2] + + functionDictionary = getDarwinTestableFunctions(sourceFileName, objectFileName) + + testRunnerName = sourceFileNameToName(sourceFileName) + + testFixtures = map(lambda(fixtureType): + testFixture(fixtureType, testSuite(testCases(functionDictionary[fixtureType]))), functionDictionary) + + files = { "sourceFile" : sourceFileName, "objectFile" : objectFileName } + result = testRunner(testRunnerName, files, testFixtures) + + out = open(outputFileName, "w") + pp = pprint.PrettyPrinter(indent=4, width=132, depth=None, stream=out) + pp.pprint(result) + out.close() + pass diff --git a/longbow/src/python/longbow-size-report.py b/longbow/src/python/longbow-size-report.py new file mode 100755 index 00000000..fd4ae76c --- /dev/null +++ b/longbow/src/python/longbow-size-report.py @@ -0,0 +1,131 @@ +#! /usr/bin/env python +# 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. +# + +# + +import sys +import os +import subprocess +import difflib +import csv +import argparse +sys.path.append("@INSTALL_PYTHON_DIR@") +import LongBow +from pprint import pprint + +def textOutputFile(file, maximumFileNameLength): + format = "%-" + str(maximumFileNameLength) + "s %6d" + print format % (file[0], file[1]) + return + +def textSummary(files): + maximumFileNameLength = max(map(lambda file: len(file[0]), files)) + map(lambda file: textOutputFile(file, maximumFileNameLength), files) + return + +def csvOutputFile(file): + format = "size,%s,%d" + print format % (file[0], file[1]) + return + +def csvSummary(files): + map(lambda file: csvOutputFile(file), files) + return + +def textTotal(files): + total = sum(map(lambda file: file[1], files)) + print total + return + +def csvTotal(files): + total = sum(map(lambda file: file[1], files)) + print total + return + +def main(): + desc = ''' +Report on number of lines of one or more C source or header files. + +Input is either from a list of files supplied as command line parameters, +or as a list of newline separated file names read from standard input. +Output is a plain text (default) or a CSV file reporting +the file name and the total number of lines in the file. + +Usage: + +% longbow-size-report *.[ch] + +Report the number of lines in .c and .h files specified as command line parameters. + +% longbow-size-report - +Read the lists of files from standard input, one file per line. + +$ longbow-size-report parc_JSON.c +parc_JSON.c 239 +$ +$ +$ echo parc_JSON.c | longbow-size-report -o csv - +parc_JSON.c,239 +$ +''' + + parser = argparse.ArgumentParser(prog='longbow-size-report', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc) + parser.add_argument('-', '--stdin', default=False, action="store_true", required=False, help="read the list of files from standard input.") + parser.add_argument('-s', '--summary', default=False, action="store_true", required=False, help="display the number of lines for each file") + parser.add_argument('-t', '--total', default=False, action="store_true", required=False, help="display the total number of lines for all files") + parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="the output format: \"text\" or \"csv\"") + + parser.add_argument("files", help="Files to check", nargs="*") + + args = parser.parse_args() + + if args.summary == False and args.total == False: + args.summary = True + + targets = [] + + if args.stdin: + for line in sys.stdin: + t = line.strip() + if len(t) > 0: + targets.append(t) + else: + targets = args.files + + if len(targets) == 0: + parser.print_usage() + sys.exit(1) + + files = map(lambda fileName: [ fileName, LongBow.countLines(fileName)], targets) + total = sum(map(lambda element: element[1], files)) + + if args.summary: + if args.output == "text": + textSummary(files) + else: + csvSummary(files) + + if args.total: + if args.output == "text": + textTotal(files) + else: + csvTotal(files) + +if __name__ == '__main__': + ''' + @(#) longbow-size-report @VERSION@ @DATE@ + @(#) All Rights Reserved. Use is subject to license terms. + ''' + main() diff --git a/longbow/src/python/longbow-style-report.py b/longbow/src/python/longbow-style-report.py new file mode 100755 index 00000000..05b8fbde --- /dev/null +++ b/longbow/src/python/longbow-style-report.py @@ -0,0 +1,99 @@ +#! /usr/bin/env python +# 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. +# + +# + +import sys +import argparse + +sys.path.append("@INSTALL_PYTHON_DIR@") +sys.path.append("@DEPENDENCY_PYTHON_DIR@") +sys.path.append("../site-packages/longbow/") +import StyleReport + +if __name__ == '__main__': + ''' +@(#) longbow-code @VERSION@ @DATE@ + @(#) All Rights Reserved. Use is subject to license terms. +''' + desc = ''' +Report on style conformance for one or more C source or header files. + +Input is either from a list of files supplied as command line parameters, +or as a list of newline separated file names read from standard input. +Reports are: +--summary A one line per file report of the file name, number of lines, number of non-compliant lines, and a score. +--average A single line output of the average of all scores. +--total A single line of output of the percentage of all compliant lines to the total number of lines in all files. +--visual A visual representation of the style check. + +For each of these reports, the output format is specified by: +--output text Display text on standard output +--output csv Display a list of comma-separated values on standard output. +--output gui Use a graphical user interface if possible. + +The visual report displays either a colorized, line by line output of +the differences between the original source file it's exemplar (-o text), +or displays a file-merge application for interactive use ()-o gui) + +Example: + +% longbow-style-report *.[ch] + +Report conformance of the .c and .h files specified as command line parameters. + +% longbow-style-report - +Report conformance of the .c and .h files read from standard input, one line per file. + +$ longbow-style-report parc_JSON.c +parc_JSON.c 239 0 100.00$ +$ +$ echo parc_JSON.c | longbow-style-report - +parc_JSON.c,239,0,100.00 +$ +''' + + parser = argparse.ArgumentParser(prog='longbow-style-report', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc) + parser.add_argument('-', '--stdin', default=False, action="store_true", required=False, help="read the list of files from standard input only.") + parser.add_argument('-s', '--summary', default=False, action="store_true", required=False, help="Display the score for each file.") + parser.add_argument('-a', '--average', default=False, action="store_true", required=False, help="Display the simple average of all scores.") + parser.add_argument('-t', '--total', default=False, action="store_true", required=False, help="Display the percentage of all compliant lines to the total number of lines in all files.") + parser.add_argument('-d', '--distribution', default="[95, 90]", action="store", required=False, type=str, help="a list containing the score distributions for pretty-printing. Default '[95, 90]' (green >= 95, yellow >= 90, red < 90).") + parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="the output format: 'text', 'csv', or 'gui'.") + parser.add_argument('-v', '--visual', default=False, action="store_true", required=False, help="Display a visual representation of the style check.") + parser.add_argument('-k', '--key', default="name", action="store", required=False, type=str, help="The sort key: Type '--key help' for the list.") + parser.add_argument('-e', '--exclude', default="", action="store", required=False, type=str, help="Exclude a comma separated set of one or more of: 'red', 'yellow', 'green'.") + + parser.add_argument("files", help="Files to check", nargs="*") + + args = parser.parse_args() + + if args.summary == False and args.average == False and args.total == False and args.visual == False: + args.summary = True + + targets = [] + + if args.stdin: + for line in sys.stdin: + t = line.strip() + if len(t) > 0: + targets.append(t) + else: + targets = args.files + + UNCRUSTIFY = "@UNCRUSTIFY_BIN@" + UNCRUSTIFY_CONFIG = "@UNCRUSTIFY_CONFIG@" + + StyleReport.commandLineMain(args, targets, UNCRUSTIFY, UNCRUSTIFY_CONFIG) diff --git a/longbow/src/python/longbow-test-run.py b/longbow/src/python/longbow-test-run.py new file mode 100755 index 00000000..77ed1f98 --- /dev/null +++ b/longbow/src/python/longbow-test-run.py @@ -0,0 +1,172 @@ +#! /usr/bin/env python +# 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. +# + +# +import os +import sys +import re +import pprint +import subprocess +import argparse +import json + +class TokenParser: + def __init__(self, tokens=[]): + self.index = 0 + self.tokens = tokens + + def nextToken(self): + result = self.tokens[self.index] + self.index = self.index + 1 + return result + + def previousToken(self): + self.index = self.index - 1 + result = self.tokens[self.index - 1] + return result + + def expectedToken(self, expected): + token = self.nextToken() + if token == expected: + return True + self.index = self.index - 1 + print "expectedToken(%s) is not the actual %s" % (expected, token) + return False + + def end(self): + if self.index == len(self.tokens): + return True + return False + +class LongBowCodeCoverage: + def __init__(self): + return + + def run(self, executableFile): + lines = subprocess.check_output([ "gcov", "-f", executableFile ]) + token = map(lambda x : x.strip("'"), re.split("[ :\n]+", lines)) + return self.parse(token) + + def parseFunction(self, parser): + functionName = parser.nextToken() + parser.expectedToken("Lines") + parser.expectedToken("executed") + coverage = parser.nextToken() + return { "function" : functionName, "coverage" : coverage } + + def parseFile(self, parser): + fileName = parser.nextToken() + parser.expectedToken("Lines") + parser.expectedToken("executed") + coverage = parser.nextToken() + return { "file" : fileName, "coverage" : coverage } + + def parse(self, tokens): + parser = TokenParser(tokens) + functions = [ ] + + while not parser.end(): + token = parser.nextToken() + if (token == "Function"): + function = self.parseFunction(parser) + functions.append(function) + elif (token == "File"): + file = self.parseFile(parser) + pass + + self.detailCoverage = { "file" : file, "functions" : functions } + return self.detailCoverage + + def getCoverage(self): + result["file"]["coverage"] + + def getDetailCoverage(self): + return self.detailCoverage + + +class LongBowTestRun: + def __init__(self, options=[]): + self.options = options + self.mainFileName = None + self.exitStatus = 0 + return + + def setOptions(self, options=[]): + self.options = options + return + + def getMainFileName(self): + return self.mainFileName + + def run(self, testRunner): + self.mainFileName = testRunner + self.exitStatus = 0 + + try: + try: + os.remove(testRunner + ".gcda") + except: + pass + lines = subprocess.check_output([ testRunner ]) + lines = re.split("[ :]+", lines) + self.exitStatus = 0 + except subprocess.CalledProcessError, e: + self.exitStatus = e.returncode + + return self.exitStatus + + def report(self, detailedOutput=False, jsonOutput=False): + result = "" + if self.exitStatus == 0: + coverage = LongBowCodeCoverage() + result = coverage.run(testRunner.getMainFileName()) + + if detailedOutput: + if jsonOutput: + result = json.dumps(result, sort_keys=False, indent=4, separators=(',', ': ')) + else: + pp = str(result) + pass + else: + if jsonOutput: + result = json.dumps(result["file"], sort_keys=False, indent=4, separators=(',', ': ')) + else: + result = "PASS " + result["file"]["file"] + " " + result["file"]["coverage"] + else: + result = "FAIL " + args.testRunner + pass + + return result + + +if __name__ == '__main__': + testRunners = [] + if len(sys.argv) < 2: + print "Usage: longbow-test-run.py testExecutable" + print "Run a LongBow test" + sys.exit(1) + + parser = argparse.ArgumentParser(description='Run a LongBow Test') + parser.add_argument("--json", help="Produce JSON output instead of a Python dictionary.", action="store_true") + parser.add_argument("--detailed", help="Produce detailed output.", action="store_true") + parser.add_argument("testRunner", help="The name of the test executable.", nargs='+') + args = parser.parse_args() + + testRunner = LongBowTestRun([ "--run-nonforked" ]) + + for test in args.testRunner: + exitStatus = testRunner.run(test) + print testRunner.report(args.detailed, args.json) + diff --git a/longbow/src/python/longbow-test-suite.py b/longbow/src/python/longbow-test-suite.py new file mode 100755 index 00000000..5a6d67e5 --- /dev/null +++ b/longbow/src/python/longbow-test-suite.py @@ -0,0 +1,55 @@ +#! /usr/bin/env python +# 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. +# + +# +import sys +from subprocess import call + +class LongBowTestSuite: + def __init__(self): + self.options = [] + return + + def setOptions(self, options=[]): + self.options = options + return + + def run(self, testRunners=[]): + result = 0 + for test in testRunners: + outputFileName = test + ".log" + outputFile = open(outputFileName, 'w') + command = [ test ] + self.options + print command + status = call(command, stdout=outputFile) + if result == 0: + result = status + pass + outputFile.close() + pass + return result + + +if __name__ == '__main__': + testRunners = [] + if len(sys.argv) < 2: + print "Usage: longbow-test-suite.py testExecutable ..." + print "Run one or more LongBow test runners as indpendant processes" + sys.exit(1) + testRunners = testRunners + sys.argv[1:] + + testSuite = LongBowTestSuite() + testSuite.setOptions([ "--run-nonforked" ]) + exitStatus = testSuite.run(testRunners) diff --git a/longbow/src/python/longbow-vocabulary-report.py b/longbow/src/python/longbow-vocabulary-report.py new file mode 100755 index 00000000..25004428 --- /dev/null +++ b/longbow/src/python/longbow-vocabulary-report.py @@ -0,0 +1,66 @@ +#! /usr/bin/env python +# 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. +# + +# + +import sys +import argparse + +sys.path.append("@INSTALL_PYTHON_DIR@") +sys.path.append("@DEPENDENCY_PYTHON_DIR@") +sys.path.append("../site-packages/longbow/") +import VocabularyReport +import hfcca + +def main(argv): + desc = ''' +Print the vocabulary (number of tokens) of functions and files. + +The option --function displays the file name, function name, +line number of the function, the number of tokens + +The default option --summary displays the file name, the average vocabulary +of all functions in the file and a score ranging from 0 to 100. + +Usage: +$ longbow-vocabulary-report parc_JSON.c +parc_JSON.c 51.00 100.00 +$ +$ echo parc_JSON.c | longbow-vocabulary-report --function -o csv - +vocabulary,parc_JSON.c,parcJSON_Create,49,50,100.00 +... +$ + +''' + + parser = argparse.ArgumentParser(prog='longbow-vocabulary-report', formatter_class=argparse.RawDescriptionHelpFormatter, description=desc) + parser.add_argument('-s', '--summary', default=False, action="store_true", help="print the average vocabulary of each target file.") + parser.add_argument('-f', '--function', default=False, action="store_true", help="print the vocabulary of each function in each target file.") + parser.add_argument('-', '--stdin', default=False, action="store_true", required=False, help="read the list of files from standard input rather than the command line.") + parser.add_argument('-a', '--average', default=False, action="store_true", required=False, help="display only the simple average of the average vocabulary of each target file.") + parser.add_argument('-o', '--output', default="text", action="store", required=False, type=str, help="the output format: \"text\" or \"csv\"") + parser.add_argument("files", help="Files to check", nargs="*") + + args = parser.parse_args() + + VocabularyReport.commandLineMain(args, hfcca) + + +if __name__ == "__main__": + ''' +@(#) longbow-vocabulary-report @VERSION@ @DATE@ +@(#) All Rights Reserved. Use is subject to license terms. + ''' + main(sys.argv) diff --git a/longbow/src/python/parc_uncrustify.cfg b/longbow/src/python/parc_uncrustify.cfg new file mode 100755 index 00000000..475d8049 --- /dev/null +++ b/longbow/src/python/parc_uncrustify.cfg @@ -0,0 +1,115 @@ +# 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. +# + + +indent_with_tabs = 0 # 1=indent to level only, 2=indent with tabs +input_tab_size = 4 # original tab size +output_tab_size = 4 # new tab size +indent_columns = output_tab_size +indent_label = 2 # pos: absolute col, neg: relative column +# indent_align_string = False # align broken strings +# indent_brace = 0 + +nl_if_leave_one_liners = false # Don't split one-line if/else statements - 'if(a) b++;' (false/true) + +nl_enum_brace = remove # (ignore/add/remove/force) newline between 'enum' and '{' +nl_union_brace = remove # "union {" vs "union \n {" +nl_struct_brace = remove # "struct {" vs "struct \n {" +nl_do_brace = remove # "do {" vs "do \n {" +nl_if_brace = remove # "if () {" vs "if () \n {" +nl_for_brace = remove # "for () {" vs "for () \n {" +nl_else_brace = remove # "else {" vs "else \n {" +nl_while_brace = remove # "while () {" vs "while () \n {" +nl_switch_brace = remove # "switch () {" vs "switch () \n {" +# nl_func_var_def_blk = 1 +# nl_before_case = 1 +nl_fcall_brace = add # "foo() {" vs "foo()\n{" +nl_fdef_brace = add # "int foo() {" vs "int foo()\n{" +# nl_after_return = TRUE +nl_brace_while = remove +nl_brace_else = remove +nl_squeeze_ifdef = TRUE +nl_func_type_name = add # (ignore/add/remove/force) newline between return type and function name in a function definition + + +# The span for aligning struct initializer values (0=don't align) +align_struct_init_span = 4 # number + +# Spaces to indent 'case' from 'switch' +# Usually 0 or indent_columns. +indent_switch_case = 4 # number + +# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if. +# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed. +mod_full_brace_if_chain = false # false/true +# mod_paren_on_return = add # "return 1;" vs "return (1);" +mod_full_brace_if = add # "if (a) a--;" vs "if (a) { a--; }" +mod_full_brace_for = add # "for () a--;" vs "for () { a--; }" +mod_full_brace_do = add # "do a--; while ();" vs "do { a--; } while ();" +mod_full_brace_while = add # "while (a) a--;" vs "while (a) { a--; }" +mod_remove_empty_return = true # Remove a void 'return;' that appears as the last statement in a function. (false/true) + +sp_after_ptr_star = remove # (ignore/add/remove/force) space after pointer star '*', if followed by a word. +sp_func_proto_paren = remove # (ignore/add/remove/force) A space between function name and '(' on function declaration +sp_return_paren = force # (ignore/add/remove/force) a space between 'return' and '(' +sp_before_semi = remove +sp_paren_paren = remove # space between (( and )) +sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)" +sp_before_sparen = force # "if (" vs "if(" +sp_after_sparen = force # "if () {" vs "if (){" +sp_after_cast = add # "(int) a" vs "(int)a" +sp_inside_braces = force # "{ 1 }" vs "{1}" +sp_inside_braces_struct = force # "{ 1 }" vs "{1}" +sp_inside_braces_enum = force # "{ 1 }" vs "{1}" +sp_inside_paren = remove # "( 1 )" vs "(1)" +sp_inside_fparen = remove # "( 1 )" vs "(1)" - functions +sp_inside_sparen = remove # "( 1 )" vs "(1)" - if/for/etc +sp_type_func = add # ignore/add/remove/force A space between return type and function name +sp_assign = force +sp_arith = force +sp_bool = force +sp_compare = force +sp_after_comma = force +sp_func_def_paren = remove # "int foo (){" vs "int foo(){" +sp_func_call_paren = remove # "foo (" vs "foo(" +sp_func_proto_paren = remove # "int foo ();" vs "int foo();" +sp_paren_brace = add # Force a space between ')' and '{' +sp_else_brace = add # Add or remove space between 'else' and '{' if on the same line (ignore/add/remove/force) +sp_brace_else = force # Add or remove space between '}' and 'else' if on the same line (ignore/add/remove/force) + +# align_with_tabs = FALSE # use tabs to align +# align_on_tabstop = FALSE # align on tabstops +# align_enum_equ_span = 4 +# align_nl_cont = TRUE +# align_var_def_span = 2 +# align_var_def_inline = TRUE +# align_var_def_star = TRUE +# align_var_def_colon = TRUE +# align_assign_span = 1 +# align_struct_init_span = 3 +# align_var_struct_span = 3 +# align_right_cmt_span = 3 +# align_pp_define_span = 3 +# align_pp_define_gap = 4 +# align_number_left = TRUE +# align_typedef_span = 5 +# align_typedef_gap = 3 + +cmt_star_cont = TRUE # put a star on subsequent comment lines + +eat_blanks_before_close_brace = TRUE +eat_blanks_after_open_brace = TRUE + +# Add or remove space between pointer stars '*' +sp_between_ptr_star = remove diff --git a/longbow/src/python/site-packages/CMakeLists.txt b/longbow/src/python/site-packages/CMakeLists.txt new file mode 100644 index 00000000..fab750f7 --- /dev/null +++ b/longbow/src/python/site-packages/CMakeLists.txt @@ -0,0 +1,12 @@ +install(FILES longbow.pth DESTINATION ${INSTALL_BASE_PYTHON_DIR}) +install(FILES longbow/LongBow.py DESTINATION ${INSTALL_PYTHON_DIR}) +install(FILES longbow/FileUtil.py DESTINATION ${INSTALL_PYTHON_DIR}) +install(FILES longbow/GCov.py DESTINATION ${INSTALL_PYTHON_DIR}) +install(FILES longbow/GCovSummary.py DESTINATION ${INSTALL_PYTHON_DIR}) +install(FILES longbow/ANSITerm.py DESTINATION ${INSTALL_PYTHON_DIR}) +install(FILES longbow/SymbolTable.py DESTINATION ${INSTALL_PYTHON_DIR}) +install(FILES longbow/Language_C.py DESTINATION ${INSTALL_PYTHON_DIR}) +install(FILES longbow/StyleReport.py DESTINATION ${INSTALL_PYTHON_DIR}) +install(FILES longbow/CoverageReport.py DESTINATION ${INSTALL_PYTHON_DIR}) +install(FILES longbow/VocabularyReport.py DESTINATION ${INSTALL_PYTHON_DIR}) +install(FILES longbow/NameReport.py DESTINATION ${INSTALL_PYTHON_DIR}) diff --git a/longbow/src/python/site-packages/longbow.pth b/longbow/src/python/site-packages/longbow.pth new file mode 100755 index 00000000..9f0d4f64 --- /dev/null +++ b/longbow/src/python/site-packages/longbow.pth @@ -0,0 +1,18 @@ +# 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. +# + +# +# +# longbow package configuration +longbow diff --git a/longbow/src/python/site-packages/longbow/.gitignore b/longbow/src/python/site-packages/longbow/.gitignore new file mode 100644 index 00000000..0d20b648 --- /dev/null +++ b/longbow/src/python/site-packages/longbow/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/longbow/src/python/site-packages/longbow/ANSITerm.py b/longbow/src/python/site-packages/longbow/ANSITerm.py new file mode 100755 index 00000000..8594c949 --- /dev/null +++ b/longbow/src/python/site-packages/longbow/ANSITerm.py @@ -0,0 +1,62 @@ +#! /usr/bin/env python +# 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. +# + +# +import os +import subprocess +import re +import sys +import pprint + +ansiRed = "\x1b[31m"; +ansiGreen = "\x1b[32m"; +ansiYellow = "\x1b[33m"; +ansiBlue = "\x1b[34m"; +ansiMagenta = "\x1b[35m"; +ansiCyan = "\x1b[36m"; +ansiReset = "\x1b[0m"; + +def colorize(color, chars): + + result = chars + if color == "red": + result = ansiRed + chars + ansiReset + elif color == "green": + result = ansiGreen + chars + ansiReset + elif color == "yellow": + result = ansiYellow + chars + ansiReset + elif color == "blue": + result = ansiBlue + chars + ansiReset + elif color == "magenta": + result = ansiMagenta + chars + ansiReset + elif color == "cyan": + result = ansiCyan + chars + ansiReset + else: + print >> sys.stderr, "Bad color name:", color + + return result + + +def printColorized(color, string): + print colorize(color, string) + return + + +class ANSITerm: + def __init__(self): + return + + def printColorized(self, color, string): + print colorize(color, string) diff --git a/longbow/src/python/site-packages/longbow/CoverageReport.py b/longbow/src/python/site-packages/longbow/CoverageReport.py new file mode 100755 index 00000000..c18ae056 --- /dev/null +++ b/longbow/src/python/site-packages/longbow/CoverageReport.py @@ -0,0 +1,262 @@ +#! /usr/bin/env python +# 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. +# + +# +import sys +import os +import re +import subprocess +import difflib +import csv +# import argparse +import pprint +# sys.path.append("${INSTALL_PYTHON_DIR}") +# sys.path.append("${DEPENDENCY_PYTHON_DIR}") +# sys.path.append("../site-packages/longbow/") +import LongBow +import GCov +import GCovSummary +import FileUtil +import ANSITerm +import Language_C + +def checkTestExecutable(executableFileName): + result = False + + if not os.path.exists(executableFileName): + return result + + path = os.path.dirname(executableFileName) + pattern = os.path.basename(executableFileName)+'*.gcda' + if not Language_C.findFiles(path, pattern): + return result + + pattern = os.path.basename(executableFileName)+'*.gcno' + if not Language_C.findFiles(path, pattern): + return result + + result = True + return result + +def findTestExecutable(fileName, hints=[]): + ''' +Given a file name, look in the canonical places for a corresponding LongBow test file. + ''' + directoryName = os.path.dirname(fileName) + if len(directoryName) == 0: + directoryName = "." + + file = Language_C.Module(fileName) + + possibleTestFiles = list() + for hint in hints: + possibleTestFiles.append(hint + "/" + file.getExecutableName()) + possibleTestFiles.append(hint + "/" + file.getTestExecutableName()) + possibleTestFiles.append(directoryName + "/" + file.getExecutableName()) + possibleTestFiles.append(directoryName + "/" + file.getTestExecutableName()) + possibleTestFiles.append(directoryName + "/test/" + file.getTestExecutableName()) + + result = None + for possibleTestFile in possibleTestFiles: + if checkTestExecutable(possibleTestFile) == True: + result = os.path.abspath(possibleTestFile) + break + + return result + + +def textSummary(args, filesAndTests, gCovResults, prefix=""): + + summary = GCov.computeSummary(filesAndTests, gCovResults) + + if not args.includeTestSources: + summary = GCovSummary.removeTestSourceFiles(summary) + + if len(summary) == 0: + return + + if args.explain: + pp = pprint.PrettyPrinter(indent=2, width=150) + pp.pprint(summary) + + maximumFileLength = max(map(lambda entry: len(entry), summary)) + + format = "%s%-" + str(maximumFileLength) + "s %6s" + print format % (prefix, "File Path", "Score") + + format = "%s%-" + str(maximumFileLength) + "s %6.2f" + for testedFile in sorted(summary.keys()): + string = format % (prefix, testedFile, summary[testedFile]["coverage"]) + if summary[testedFile]["direct"] == "indirect": + ANSITerm.printColorized("magenta", string) + else: + LongBow.scorePrinter(eval(args.distribution), summary[testedFile]["coverage"], string) + + return + + +def textAverage(args, filesAndTests, gcovResults): + summary = GCov.computeSummary(filesAndTests, gcovResults) + + if not args.includeTestSources: + summary = GCovSummary.removeTestSourceFiles(summary) + + score = GCovSummary.averageCoverage(summary) + + LongBow.scorePrinter(eval(args.distribution), score, "%.2f" % (score)) + return score + + +def csvSummary(args, filesAndTests, gCovResults): + summary = GCov.computeSummary(filesAndTests, gCovResults) + + if not args.includeTestSources: + summary = GCovSummary.removeTestSourceFiles(summary) + + if len(summary) > 0: + for testedFile in sorted(summary.keys()): + outputString = "%s,%.2f" % (testedFile, summary[testedFile]["coverage"]) + LongBow.scorePrinter(eval(args.distribution), summary[testedFile]["coverage"], outputString) + + return + + +def csvAverage(args, filesAndTests, gcovResults): + summary = GCov.computeSummary(filesAndTests, gcovResults) + + if not args.includeTestSources: + summary = GCovSummary.removeTestSourceFiles(summary) + + score = GCovSummary.averageCoverage(summary) + + LongBow.scorePrinter(eval(args.distribution), score, "%.2f" % (score)) + return + + +def textVisualDisplayGcovLine(line): + token = line.split(":", 2) + if len(token) == 3: + if token[0] == "#####": + print ANSITerm.colorize("red", token[1] + " " + token[2]) + elif token[0] == "$$$$$": + print ANSITerm.colorize("yellow", token[1] + " " + token[2]) + else: + print ANSITerm.colorize("green", token[1] + " " + token[2]) + + return + + +def textVisual(args, filesAndTests, gcovResults): + + summary = GCov.computeSummary(filesAndTests, gcovResults) + if args.explain: + pp = pprint.PrettyPrinter(indent=2, width=150) + pp.pprint(summary) + pp.pprint(filesAndTests) + + for entry in filesAndTests: + print entry[0] + try: + gcovLines = summary[entry[0]]["gcovLines"] + map(lambda line: textVisualDisplayGcovLine(line.strip()), gcovLines) + except KeyError: + print >> sys.stderr, "No coverage information for", entry[0] + + return + + +def displaySummary(args, filesAndTests, newGCovResults): + if args.output == "text": + textSummary(args, filesAndTests, newGCovResults) + elif args.output == "csv": + csvSummary(args, filesAndTests, newGCovResults) + else: + print >> sys.stderr, "Unsupported output type" + return + + +def displayAverage(args, filesAndTests, gcovResults): + if args.output == "text": + textAverage(args, filesAndTests, gcovResults) + elif args.output == "csv": + csvAverage(args, filesAndTests, gcovResults) + else: + print >> sys.stderr, "Unsupported output type" + return + + +def explain(args, filesAndTests, gcovResults): + + pp = pprint.PrettyPrinter(indent=2, width=150) + pp.pprint(gcovResults) + + return + +def getFilesAndTests(fileNames, testDirs=[]): + namesAndPaths = map(lambda fileName: [fileName, os.path.abspath(fileName)], fileNames) + filesAndTests = map(lambda nameAndPath: [ nameAndPath[0], findTestExecutable(nameAndPath[1], testDirs) ], namesAndPaths) + return filesAndTests + + +def gradeAndPrint(targets, testDirs=[], problemsOnly=False, prefix=""): + filesAndTests = getFilesAndTests(targets, testDirs) + newGCovResults = map(lambda fileAndTestFile: GCov.getCoverage(fileAndTestFile[1]), filesAndTests) + + summarys = GCov.computeSummary(filesAndTests, newGCovResults) + if len(summarys) < 1: + print "%sNo GCov Results - Please be sure to run 'make check' first" % prefix + return False + summarys = GCovSummary.removeTestSourceFiles(summarys) + + paths = summarys.keys() + if problemsOnly: + paths = filter(lambda key: summarys[key]["coverage"] < 100, paths) + + distribution=[99,90] + maximumFileLength = max(map(lambda entry: len(os.path.relpath(entry)), paths)) + format = "%s%-" + str(maximumFileLength) + "s %6s" + print format % (prefix, "File Path", "Score") + format = "%s%-" + str(maximumFileLength) + "s %6.2f" + for path in sorted(paths): + string = format % (prefix, os.path.relpath(path), summarys[path]["coverage"]) + LongBow.scorePrinter(distribution, summarys[path]["coverage"], string) + + return True + +def commandLineMain(args, fileNames, testDir=""): + + testDirs = [] + if testDir: + testDirs.append(testDir) + fileNames = map(lambda fileName: os.path.abspath(fileName), fileNames) + filesAndTests = map(lambda fileName: [fileName, findTestExecutable(fileName, testDirs)], fileNames) + + filesWithNoTest = filter(lambda fileAndTest: fileAndTest[1] == None, filesAndTests) + if len(filesWithNoTest) != 0: + outputFormat = "%s has no corresponding test executable or coverage data.\n" + map(lambda filesAndTests: sys.stderr.write(outputFormat % (filesAndTests[0])), filesWithNoTest) + + gCovResults = map(lambda fileAndTestFile: GCov.getCoverage(fileAndTestFile[1]), filesAndTests) + + if args.summary is True: + displaySummary(args, filesAndTests, gCovResults) + elif args.average is True: + displayAverage(args, filesAndTests, gCovResults) + elif args.visual is True: + textVisual(args, filesAndTests, gCovResults) + elif args.explain is True: + explain(args, filesAndTests, gCovResults) + + return True diff --git a/longbow/src/python/site-packages/longbow/DoxygenReport.py b/longbow/src/python/site-packages/longbow/DoxygenReport.py new file mode 100755 index 00000000..46edf047 --- /dev/null +++ b/longbow/src/python/site-packages/longbow/DoxygenReport.py @@ -0,0 +1,161 @@ +#! /usr/bin/env python +# 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. +# + +# + +import sys +import os +import pprint +import subprocess +import difflib +import csv +import LongBow + +def concatenateContinuationLines(lines): + ''' + Parse doxygen log lines. + Lines that are indented by a space are continutations of the previous line. + ''' + result = list() + accumulator = "" + for line in lines: + line = line.rstrip() + if line.startswith(" ") == False and line.startswith(" ") == False: + if len(accumulator) > 0: + result.append(accumulator) + accumulator = line + else: + accumulator = accumulator + " " + line.lstrip() + + result.append(accumulator) + + return result + +def parseLine(line): + result = None + if not line.startswith("<"): + fields = line.split(":") + if len(fields) >= 4: + result = { "fileName" : fields[0].strip(), + "lineNumber" : int(fields[1].strip()), + "type" : "documentation", + "severity" : fields[2].strip(), + "message" : " ".join(fields[3:]).strip()} + elif line.startswith("error"): + print line + elif len(line) > 0: + print "Consider using doxygen -s:", line + + return result + +def canonicalize(lines): + lines = concatenateContinuationLines(lines) + parsedLines = map(lambda line: parseLine(line), lines) + parsedLines = filter(lambda line: line != None, parsedLines) + return parsedLines + +def organize(entries): + result = dict() + + for entry in entries: + if not entry["fileName"] in result: + result[entry["fileName"]] = dict() + + entryByFile = result[entry["fileName"]] + + if not str(entry["lineNumber"]) in entryByFile: + entryByFile[str(entry["lineNumber"])] = list() + if not entry in entryByFile[str(entry["lineNumber"])]: + entryByFile[str(entry["lineNumber"])].append(entry) + + return result + +def textualSummary(distribution, documentation): + maxWidth = 0 + for entry in documentation: + if len(entry) > maxWidth: + maxWidth = len(entry) + + formatString ="%-" + str(maxWidth) + "s %8d %8d %.2f%%" + for entry in documentation: + badLines = len(documentation[entry]) + totalLines = LongBow.countLines(entry) + score = float(totalLines - badLines) / float(totalLines) * 100.0 + LongBow.scorePrinter(distribution, score, formatString % (entry, totalLines, badLines, score)) + return + +def textualAverage(distribution, documentation, format): + sum = 0.0 + + for entry in documentation: + badLines = len(documentation[entry]) + totalLines = LongBow.countLines(entry) + score = float(totalLines - badLines) / float(totalLines) * 100.0 + sum = sum + score + + if len(documentation) == 0: + averageScore = 100.0 + else: + averageScore = sum / float(len(documentation)) + + LongBow.scorePrinter(distribution, averageScore, format % averageScore) + +def csvSummary(distribution, documentation): + formatString ="documentation,%s,%d,%d,%.2f%%" + for entry in documentation: + badLines = len(documentation[entry]) + totalLines = LongBow.countLines(entry) + score = float(totalLines - badLines) / float(totalLines) * 100.0 + LongBow.scorePrinter(distribution, score, formatString % (entry, totalLines, badLines, score)) + return + + +def gradeAndPrint(targets, doxLogfile, problemsOnly=False, prefix=""): + with open(doxLogfile, 'r') as f: + lines = f.readlines() + + lines = canonicalize(lines) + + result = organize(lines) + + pp = pprint.PretyPrinter(intent=len(prefix)) + + distribution=[100, 95] + textualSummary(distribution, result) + return True + +def commandLineMain(args, fileNames): + if not args.summary and not args.average: + args.summary = True + + with open(args.doxygenlog, 'r') as f: + lines = f.readlines() + + lines = canonicalize(lines) + + result = organize(lines) + + pp = pprint.PrettyPrinter(indent=4) + #pp.pprint(result) + + distribution = eval(args.distribution) + if args.summary: + if args.output == "text": + textualSummary(distribution, result) + else: + csvSummary(distribution, result) + + if args.average: + textualAverage(distribution, result, "%.2f") diff --git a/longbow/src/python/site-packages/longbow/FileUtil.py b/longbow/src/python/site-packages/longbow/FileUtil.py new file mode 100755 index 00000000..ae3113f6 --- /dev/null +++ b/longbow/src/python/site-packages/longbow/FileUtil.py @@ -0,0 +1,102 @@ +#! /usr/bin/env python +# 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. +# + +# + +import sys +import os +import csv +import subprocess + +def readFileLines(fileName): + ''' + Get the entire file into memory as a list of lines. + ''' + result = None + + with open(fileName, "r") as file: + result = file.readlines() + + return result + +def readFileString(fileName): + ''' + Get the entire file into memory as a python string. + ''' + result = None + + if fileName != None and len(fileName) > 0: + with open (fileName, "r") as file: + result = file.read() + + return result + +def sourceFileNameToName(sourceFileName): + ''' + Given the path to a source file, return the name without any path components or trailing suffix. + ''' + name = os.path.basename(sourceFileName) + return name.split(".")[0] + +def canonicalizeFunctionName(functionName): + ''' + Given a function name that contains the initial '_' character, + strip it and return a canonicalised form of the same name suitable for a source file. + ''' + if functionName[0] == "_": + functionName = functionName[1:] + return functionName + +def isReservedName(functionName): + ''' + Given a canonicalized name, determine if it is a reserved name according to ISO/IEC 9899:2011 and ANSI Sec. 4.1.2.1, + identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use. + ''' + if functionName[0] == '_' and functionName[1] == '_': + return True + elif functionName[0] == '_' and functionName[1].isupper(): + return True + return False + +def getDarwinTestableFunctions(objectFileName): + ''' + Retrieve a set of local and global function names within a file. + ''' + command = [ "/usr/bin/nm", "-gUm", objectFileName ] + + output = subprocess.check_output(command) + lines = output.splitlines() + + external = [] + internal = [] + for line in lines: + if line: + fields = line.split(" ") + if (len(fields) > 1) and (fields[1] == "(__TEXT,__text)"): + functionName = canonicalizeFunctionName(fields[3]) + + if not isReservedName(functionName): + if fields[2] == "external": + external.append( ( functionName ) ) + else: + internal.append( ( functionName ) ) + pass + pass + pass + pass + + external.sort() + internal.sort() + return { "Local": internal, "Global" : external } diff --git a/longbow/src/python/site-packages/longbow/GCov.py b/longbow/src/python/site-packages/longbow/GCov.py new file mode 100755 index 00000000..c2705fda --- /dev/null +++ b/longbow/src/python/site-packages/longbow/GCov.py @@ -0,0 +1,232 @@ +#! /usr/bin/env python +# 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. +# + +# +import os +import subprocess +import re +import sys +import pprint +import FileUtil +import Language_C + +class GCov: + def __init__(self): + return + +def canonicalizeLines(lines): + result = [] + accumulatedLine = "" + for line in lines: + line = line.strip() + if len(line) == 0: + if len(accumulatedLine.strip()) > 0: + result.append(accumulatedLine.strip()) + accumulatedLine = "" + elif "creating" in line: + if len(accumulatedLine.strip()) > 0: + result.append(accumulatedLine.strip()) + accumulatedLine = "" + result.append(line) + else: + accumulatedLine = accumulatedLine + " " + line + return result + +def executeGCovCommand(testExecutableFileName): + currentDirectory = os.getcwd() + targetDirectory = os.path.dirname(os.path.abspath(testExecutableFileName)) + testExecutableBaseName = os.path.basename(testExecutableFileName) + + os.chdir(targetDirectory) + objects = Language_C.findFiles("./", testExecutableBaseName+"*.o") + if not objects: + return + objdir = os.path.dirname(objects[0]) + gcdas = Language_C.findFiles("./", testExecutableBaseName+"*.gcda") + if not gcdas: + return + gcda = gcdas[0] + gcnos = Language_C.findFiles("./", testExecutableBaseName+"*.gcno") + if not gcnos: + return + gcno = gcnos[0] + proc = subprocess.Popen(['gcov', '-af', '-o='+objdir, '-gcda='+gcda, '-gcno='+gcno, testExecutableBaseName], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + os.chdir(currentDirectory) + + inputLines = map(lambda line: line.strip(), proc.stdout) + + return canonicalizeLines(inputLines) + +def parseFunctionLine(line): + # Function 'TestFixture_Global_TearDown' Lines executed:71.43% of 7" + search = re.search("Function '(.*)' Lines executed:(.*)% of (.*)", line, re.IGNORECASE) + + result = [] + if search: + functionName = search.group(1) + percentage = search.group(2) + totalLines = search.group(3) + result = { functionName : { "coverage" : float(percentage), "numberOfLines" : int(totalLines) } } + + return result + +def parseFileLine(testExecutableDirectoryName, line): + # File './../parc_Buffer.c' Lines executed:92.69% of 424 + search = re.search("File '(.*)' Lines executed:(.*)% of (.*)", line, re.IGNORECASE) + + result = { } + if search: + baseName = os.path.basename(search.group(1)); + fileName = os.path.abspath(testExecutableDirectoryName + "/" + baseName) + percentage = search.group(2) + totalLines = search.group(3) + result = { fileName : { "coverage" : float(percentage), "totalLines" : int(totalLines) } } + + return result + +def parseCreatingLine(testExecutableDirectoryName, line): + search = re.search("(.*):creating '(.*)'", line, re.IGNORECASE) + + result = None + if search: + baseName = os.path.basename(search.group(1)); + fileName = os.path.abspath(testExecutableDirectoryName + "/" + baseName) + baseName = os.path.basename(search.group(2)); + gcovFileName = os.path.abspath(testExecutableDirectoryName + "/" + baseName) + + result = { "fileName" : fileName, "gcovFileName" : gcovFileName, "gcovLines" : FileUtil.readFileLines(gcovFileName) } + + return result + + +def computeCoverageFromGCovLines(testExecutableDirectoryName, testExecutableFileName, lines): + ''' + This produces a dictionary consisting of: + + 'testedFiles' : dictionary containing as keys 'functions' and the name of a file that was tested + + The value of the key that is the name of a file that was tested is a dictionary containing the keys, + 'coverage', 'gcovFileName', and 'gcovLines' + + 'coverage' is the percentage of code executed + + 'testedFunctions' is a list containing lists consisting of the function name, the percent executed, and the number of lines in the function. + ''' + testedFiles = { } + testedFunctions = { } + gcovFileNames = [] + for line in lines: + if line.startswith("Function"): + element = parseFunctionLine(line) + testedFunctions.update(element) + elif line.startswith("File"): + element = parseFileLine(testExecutableDirectoryName, line) + testedFiles.update(element) + else: + element = parseCreatingLine(testExecutableDirectoryName, line) + if element != None: + fileName = element["fileName"] + del element["fileName"] + testedFiles[fileName].update(element) + pass + + result = { testExecutableFileName : { "testedFunctions" : testedFunctions, "testedFiles" : testedFiles } } + + return result + + +def noCoverage(): + result = { "testedFiles" : { }, "testedFunctions" : { } } + return result + +def getCoverage(testExecutableFileName): + ''' + ''' + if testExecutableFileName == None: + return None + + testExecutableFileName = os.path.abspath(testExecutableFileName) + testExecutableDirectoryName = os.path.dirname(testExecutableFileName) + gcovLines = executeGCovCommand(testExecutableFileName) + + return computeCoverageFromGCovLines(testExecutableDirectoryName, testExecutableFileName, gcovLines) + + +def selectGreaterCoverage(testedFileA, testedFileB): + result = testedFileB + if testedFileA["coverage"] >= testedFileB["coverage"]: + result = testedFileA + + return result + +def computeSummary(filesAndTests, newGCovResults): + ''' + First, for each target file named in the gcov results, find the corresponding testedFile and report the maximum coverage. + + If the target file is not in any of the testedFiles + + { targetFileName : { "coverage": percent, "veracity" : "direct" / "indirect" } } + ''' + + newGCovResults = filter(lambda entry: entry != None, newGCovResults) + + result = dict() + for entry in newGCovResults: + for testExecutableName in entry: + testExecutableCSourceName = Language_C.Module(testExecutableName).getCSourceName() + + for testedFileName in entry[testExecutableName]["testedFiles"]: + testedFile = entry[testExecutableName]["testedFiles"][testedFileName] + + if Language_C.Module(testedFileName).getTestExecutableName() == os.path.basename(testExecutableName): + result[testedFileName] = testedFile + result[testedFileName]["direct"] = "direct" + elif testedFileName in result: + bestCoverage = selectGreaterCoverage(testedFile, result[testedFileName]) + if result[testedFileName] != bestCoverage: + result[testedFileName] = bestCoverage + result[testedFileName]["direct"] = "indirect" + else: + result[testedFileName] = testedFile + result[testedFileName]["direct"] = "indirect" + + return result + +def computeAverage(filesAndTests, gcovResults): + summary = computeSuperSummary(filesAndTests, gcovResults) + + filesToAverage = removeTestSourceFiles(summary) + + score = 0.0 + + if len(filesToAverage) > 0: + sum = reduce(lambda x, y: x + y, map(lambda entry: summary[entry]["coverage"], filesToAverage)) + score = sum / float(len(filesToAverage)) + + return score + + +if __name__ == '__main__': + pp = pprint.PrettyPrinter(indent=4, width=132) + if True: + gcovResult = getCoverage("/Users/gscott/Documents/workspace/Distillery/Libparc/parc/algol/test/test_parc_JSON") + else: + lines = sys.stdin.readlines() + lines = canonicalizeLines(lines) + pp.pprint(lines) + + gcovResult = computeCoverageFromGCovLines("/Users/gscott/Documents/workspace/Distillery/Libparc/parc/algol/test/", lines) + + pp.pprint(gcovResult) diff --git a/longbow/src/python/site-packages/longbow/GCovSummary.py b/longbow/src/python/site-packages/longbow/GCovSummary.py new file mode 100755 index 00000000..bfa6710a --- /dev/null +++ b/longbow/src/python/site-packages/longbow/GCovSummary.py @@ -0,0 +1,42 @@ +#! /usr/bin/env python +# 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. +# + +# +import os +import subprocess +import re +import sys +import pprint +import FileUtil +import Language_C + + +def removeTestSourceFiles(gcovSummary): + deleteThese = filter(lambda entry: Language_C.Module(entry).isTestSourceName(), gcovSummary) + + for entry in deleteThese: + del gcovSummary[entry] + + return gcovSummary + + +def averageCoverage(summary): + score = 0.0 + + if len(summary) > 0: + sum = reduce(lambda x, y: x + y, map(lambda entry: summary[entry]["coverage"], summary)) + score = sum / float(len(summary)) + + return score diff --git a/longbow/src/python/site-packages/longbow/Language_C.py b/longbow/src/python/site-packages/longbow/Language_C.py new file mode 100755 index 00000000..85183133 --- /dev/null +++ b/longbow/src/python/site-packages/longbow/Language_C.py @@ -0,0 +1,202 @@ +#! /usr/bin/env python +# 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. +# + +# +import os +import glob + +import fnmatch +import subprocess + +def findFiles(startDir, pattern): + matches = [] + for root, dirnames, filenames in os.walk(startDir): + for filename in fnmatch.filter(filenames, pattern): + matches.append(os.path.join(root, filename)) + + return matches + +def getLibPathForObject(libraryPath, filename): + ''' + Returns a path to an object file suitable for nm + ''' + result = '' + + command = ['/usr/bin/ar', '-t', libraryPath] + output = subprocess.check_output(command) + lines = output.splitlines() + + for line in lines: + tokens = line.split('.') + if tokens[0] == filename: + result = libraryPath + '(' + line + ')' + break + + return result + +class Module: + '''Represent a C language module. + A module consists of the file names of the C source, C header file, object file, and an executable file + def __init__(self, srcPath, objectDirs=[]): + self.path = self.initialzePath(srcPath) + if not objectDirs: + objectDirs = [self.path] + split = srcPath.split("/") + self.originalName = split[len(split) - 1] + self.originalBaseName = os.path.basename(srcPath) + tokens = self.originalBaseName.split('.') + self.fileName = tokens[0].replace("/","") + + if self.fileName.startswith("test_"): + self.fileName = self.fileName[5:] + + # Search for an appropriate object + self.objectPath = ""; + for objectDir in objectDirs: + if objectDir.endswith(".a"): + self.objectPath = getLibPathForObject(objectDir, self.fileName) + if self.objectPath: + break + else: + objectSearchPath = os.path.join(objectDir, self.fileName) + "*.o*" + ofiles = glob.glob(objectSearchPath); + if ofiles: + # if we've found some matches, assume we want the first. + self.objectPath = ofiles[0]; + break + return + + def isTestExecutableName(self): + return self.getTestExecutableName() == self.originalBaseName + + def isTestSourceName(self): + return self.getTestSourceName() == self.originalBaseName + + def isCSourceName(self): + return self.getCSourceName() == self.originalBaseName + + def isCHeaderName(self): + return self.getCHeaderName() == self.originalBaseName + + def getCSourceName(self): + return self.fileName + ".c" + + def getCHeaderName(self): + return self.fileName + ".h" + + def getPathToObjectFile(self): + return self.objectPath; + + def getExecutableName(self): + return self.fileName + + def getTestExecutableName(self): + return "test_" + self.fileName + + def getTestSourceName(self): + return self.getTestExecutableName() + ".c" + + def getNamespace(self): + sourceFileName = self.getCSourceName() + if (sourceFileName.find("_") >= 0): + stripped = sourceFileName[0:sourceFileName.index("_")] + return stripped + else: + return None + + def getModuleName(self): + sourceFileName = self.getCSourceName() + split = sourceFileName.split("/") + sourceFileName = split[len(split) - 1] + if (sourceFileName.find(".") >= 0): + stripped = sourceFileName[0:sourceFileName.index(".")] + return stripped + else: + return None + + def getModulePrefix(self): + sourceFileName = self.getCSourceName() + squashed = sourceFileName.replace("_", "") + if (squashed.find(".") >= 0): + return squashed[0:squashed.index(".")] + else: + return None + + def getTypeName(self): + sourceFileName = self.getCSourceName() + if (sourceFileName.find(".") >= 0 and sourceFileName.find("_") >= 0): + stripped = sourceFileName[(sourceFileName.index("_") + 1):sourceFileName.index(".")] + return stripped + else: + return None + + def getModulePath(self): + return self.path + + def initialzePath(self, sourceFileName): + parts = sourceFileName.split("/") + parts = parts[0:len(parts) - 1] + return '/'.join(map(str, parts)) + +if __name__ == '__main__': + cFile = Module("file.c.gcov") + if cFile.getCSourceName() != "file.c": + print "getCSourceName failed", cFile.getCSourceName() + + if cFile.getCHeaderName() != "file.h": + print "getCHeaderName failed", cFile.getCHeaderName() + + if cFile.getTestSourceName() != "test_file.c": + print "getTestSourceName failed", cFile.getTestSourceName() + + if cFile.getTestExecutableName() != "test_file": + print "getTestExecutableName failed", cFile.getTestExecutableName() + + if cFile.getNamespace() != None: + print "getNamespace failed", cFile.getNamespace() + + if cFile.getModuleName() != "file": + print "getModuleName failed", cFile.getModuleName() + + if cFile.getModulePrefix() != "file": + print "getModulePrefix failed", cFile.getModulePrefix() + + if cFile.getTypeName() != None: + print "getTypeName failed", cFile.getTypeName() + + cFile = Module("parc_Object.c.gcov") + if cFile.getCSourceName() != "parc_Object.c": + print "getCSourceName failed", cFile.getCSourceName() + + if cFile.getCHeaderName() != "parc_Object.h": + print "getCHeaderName failed", cFile.getCHeaderName() + + if cFile.getTestSourceName() != "test_parc_Object.c": + print "getTestSourceName failed", cFile.getTestSourceName() + + if cFile.getTestExecutableName() != "test_parc_Object": + print "getTestExecutableName failed", cFile.getTestExecutableName() + + if cFile.getNamespace() != "parc": + print "getNamespace failed", cFile.getNamespace() + + if cFile.getModuleName() != "parc_Object": + print "getModuleName failed", cFile.getModuleName() + + if cFile.getModulePrefix() != "parcObject": + print "getModulePrefix failed", cFile.getModulePrefix() + + if cFile.getTypeName() != "Object": + print "getTypeName failed", cFile.getTypeName() diff --git a/longbow/src/python/site-packages/longbow/LongBow.py b/longbow/src/python/site-packages/longbow/LongBow.py new file mode 100755 index 00000000..d1f0e77a --- /dev/null +++ b/longbow/src/python/site-packages/longbow/LongBow.py @@ -0,0 +1,96 @@ +#! /usr/bin/env python +# 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. +# + +# +import sys + +ansiRed = "\x1b[31m"; +ansiGreen = "\x1b[32m"; +ansiYellow = "\x1b[33m"; +ansiMagenta = "\x1b[35m"; +ansiReset = "\x1b[0m"; + + +def buildRed(string): + if sys.stdout.isatty(): + return ansiRed + string + ansiReset + else: + return string + + +def buildGreen(string): + if sys.stdout.isatty(): + return ansiGreen + string + ansiReset + else: + return string + + +def buildYellow(string): + if sys.stdout.isatty(): + return ansiYellow + string + ansiReset + else: + return string + + +def score(distribution, score): + result = "red" + + if (score > distribution[0]): + result = "green" + elif (score > distribution[1]): + result = "yellow" + + return result + + +def scoreBuilder(distribution, score, string): + ''' + scores is a list of 2 decreasing values. + The first is the minimum score for green, the second is the minimum score for yellow. + The rest art red + ''' + if (score > distribution[0]): + return buildGreen(string) + elif (score > distribution[1]): + return buildYellow(string) + else: + return buildRed(string) + + +def scorePrinter(distribution, score, string): + print scoreBuilder(distribution, score, string) + + +def countLines(fileName): + i = 0 + with open(fileName) as f: + for i, l in enumerate(f): + pass + return i + 1 + + +def CFileNameToFunctionPrefix(fileName): + ''' + Given the name of a C source file or header file, + return the canonical name prefix for functions within that file. + For example, the input name "parc_Buffer.c" results in "parcBuffer_" + ''' + fileName = os.path.basename(fileName); + fileNameSpace = os.path.splitext(fileName)[0] + parts = fileNameSpace.partition("_") + result = None + if len(parts) == 3: + result = parts[0] + parts[2] + "_" + return result diff --git a/longbow/src/python/site-packages/longbow/NameReport.py b/longbow/src/python/site-packages/longbow/NameReport.py new file mode 100755 index 00000000..1d38b4ec --- /dev/null +++ b/longbow/src/python/site-packages/longbow/NameReport.py @@ -0,0 +1,818 @@ +#! /usr/bin/env python +# 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. +# + +# + +import sys +import os +import subprocess +import argparse +import csv +import traceback + +import LongBow +from Language_C import Module +from FileUtil import * +from pprint import pprint + +class NoObjectFileException(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + + +# Global error string formatting map +conformanceErrorFormatMap = { + "NAMESPACE_MISMATCH" : "Function signature %s does not have the correct namespace prefix (%s)", + "MODULE_MISMATCH" : "Function signature %s does not have the correct module prefix (%s)", + "INVALID_STATIC_NAME" : "Local function signature %s must begin with an underscore '_'.", + "INVALID_GLOBAL_ENUM_NAME" : "Global enumeration prefix %s must match the module namespace %s.", + "INVALID_STATIC_ENUM_NAME" : "Local enumeration prefix %s must begin with an underscore '_'.", + "INVALID_GLOBAL_ENUM_VALUE_NAME" : "Global enumeration value prefix %s must match the enum name %s.", + "INVALID_GLOBAL_TYPEDEF_NAME" : "Global typedef prefix %s must match the module namespace %s.", + "INVALID_STATIC_TYPEDEF_NAME" : "Local typedef prefix %s must begin with an underscore '_'.", +} + +def tuplesListToCSV(points): + ''' + Convert a list of tuples -- data points -- to a list of CSV-formatted strings. + ''' + lines = [] + for point in points: + line = "" + for i in range(len(point) - 1): + line = line + str(point[i]) + "," + line = line + str(point[-1]) + lines.append(line) + return lines + +def tuplesListToPrettyText(points, distribution = [99, 90]): + ''' + Convert a list of tuples -- data points -- to a list of colorized strings based + on the provided distribution. + ''' + lines = [] + for point in points: + line = "" + for i in range(len(point) - 1): + line = line + str(point[i]) + " " + line = line + str(point[-1]) + lines.append(LongBow.scoreBuilder(distribution, point[-1], line)) + return lines + +def writeListToStream(llist, fileHandle, appendNewLine = True): + ''' + Write the list of lines to the given file stream handle, appending a new line after + every line if told to do so. + ''' + for line in llist: + fileHandle.write(line) + if appendNewLine: + fileHandle.write("\n") + +def isValidModuleName(namespace, typeName, moduleName): + ''' + Determine if a given module name is valid (conforming) given the namespace and typename. + + For example, a module in the `parc` namespace with typename `JSON` must be named `parc_JSON`. + ''' + constructedName = namespace + "_" + typeName + return (moduleName == constructedName) + +def isValidFunctionName(namespace, modulePrefix, functionName, scope): + ''' + Determine if a given function name is valid (conforming) given the namespace and typename. + ''' + if (scope != "Local"): + if(not functionName.startswith(namespace)): + return False, conformanceErrorFormatMap["NAMESPACE_MISMATCH"] % ('"' + functionName + '"', namespace) + elif (not functionName.startswith(modulePrefix)): + return False, conformanceErrorFormatMap["MODULE_MISMATCH"] % ('"' + functionName + '"', modulePrefix) + else: + return True, "" + elif (scope == "Local" and not functionName.startswith("_")): + return False, conformanceErrorFormatMap["INVALID_STATIC_NAME"] % ('"' + functionName + '"') + else: + return True, "" + +def isValidTypedefName(typePrefix, name, static): + ''' + Determine if a given typedef name is valid (conforming) given the namespace and typename. + ''' + originalName = name + originalTypePrefix = typePrefix + + name = name.lower() + typePrefix = typePrefix.lower() + + if ((not static) and name.startswith(typePrefix)) and originalName[0].isupper(): + return True, "" + elif ((not static) and (not name.startswith(typePrefix))): + return False, conformanceErrorFormatMap["INVALID_GLOBAL_TYPEDEF_NAME"] % ('"' + originalName + '"', originalTypePrefix) + elif (static and name.startswith('_')): + return True, "" + else: + return False, conformanceErrorFormatMap["INVALID_STATIC_TYPEDEF_NAME"] % ('"' + originalName + '"') + +def isValidEnumName(typePrefix, name, values, static): + ''' + Determine if a given enumeration name is valid (conforming) given the namespace and typename. + ''' + originalName = name + originalTypePrefix = typePrefix + + name = name.lower() + typePrefix = typePrefix.lower() + + if ((not static) and name.startswith(typePrefix)) and originalName[0].isupper(): + pass + elif ((not static) and (not name.startswith(typePrefix))): + return False, conformanceErrorFormatMap["INVALID_GLOBAL_ENUM_NAME"] % ('"' + originalName + '"', originalTypePrefix) + elif (static and name.startswith('_')): + pass + else: + return False, conformanceErrorFormatMap["INVALID_STATIC_ENUM_NAME"] % ('"' + originalName + '"') + + for enumVal in values: + if ((not static) and not enumVal.startswith(originalName)): + return False, conformanceErrorFormatMap["INVALID_GLOBAL_ENUM_VALUE_NAME"] % ('"' + enumVal + '"', originalName) + return True, "" + +def getTypedefs(path, source): + ''' + Retrieve the names of typedefs (excluding enums) in a given file by parsing the file for + typedef specifications. This walks over every line in the file searching for each one, + since we cannot extract enum names nicely using linux tools. + ''' + typedefs = [] + pathToFile = os.path.join(path, source) + if os.path.isfile(pathToFile): + fin = open(os.path.join(path, source), 'r') + lines = fin.readlines() + i = 0 # LC + while (i < len(lines)): + line = lines[i].strip() + if not line.startswith("//"): + values = [] + if "typedef" in line and "enum" not in line: # go to the end of the typedef + if "{" in line: + while "}" not in line: + i = i + 1 + line = lines[i].strip() + name = line.replace("}","").replace(";","").strip() + typedefs.append(name) + else: + splits = line.split(" ") + if "struct" in splits[1]: + name = splits[3].replace(";","") + typedefs.append(name.strip()) + else: + pass + i = i + 1 + return typedefs + +def getEnumerations(path, source): + ''' + Retrieve the names of enumerations in a given file by parsing the file for enum specifications. + This walks over every line in the file searching for enums, since we cannot extract enum names + nicely using linux tools. + ''' + enums = [] + pathToFile = os.path.join(path, source) + if os.path.isfile(pathToFile): + fin = open(os.path.join(path, source), 'r') + lines = fin.readlines() + i = 0 # LC + while (i < len(lines)): + line = lines[i].strip() + if not line.startswith("//"): + values = [] + if "typedef enum" in line: # go to the end of the enumeration + while (i + 1 < len(lines) and line.find("}") < 0): + i = i + 1 + line = lines[i].strip() + values.append(line) # append each string value + if (line.find("}") >= 0): + name = line.replace("}","").replace(";","") + values.pop(len(values) - 1) + enums.append((name.strip(), values)) + i = i + 1 + return enums + +def getTypedefsFromFiles(fileInfoList): + ''' + Get the typedefs from each file in the fileInfoList. + + Each element in fileInfoList is a tuple of the form (path, filename, staticTag), + where staticTag is a flag used to indicate if the typedefs in said file should + be treated as static. + ''' + allTypedefs = [] + for (path, fileName, staticTag) in fileInfoList: + typedefs = getTypedefs(path, fileName) + for typedef in typedefs: + allTypedefs.append((typedef, staticTag)) + return allTypedefs + +def getEnumerationsFromFiles(fileInfoList): + ''' + Get the enums from each file in the fileInfoList. + + Each element in fileInfoList is a tuple of the form (path, filename, staticTag), + where staticTag is a flag used to indicate if the enums in said file should + be treated as static. + ''' + allEnums = [] + for (path, fileName, staticTag) in fileInfoList: + enums = getEnumerations(path, fileName) + for (enumName, values) in enums: + allEnums.append((enumName, values, staticTag)) + return allEnums + +class FunctionConformanceContainer(): + def __init__(self, module): + self.path = module.getModulePath() + self.module = module + self.failedFunctions = [] + self.passedFunctions = [] + + if (len(self.path) > 0): + self.fullPath = self.path + os.sep + module.getCSourceName() + else: + self.fullPath = module.getCSourceName() + + self.computeConformance() + + def computeConformance(self): + functionDictionary = {} + objectFileName = self.module.getPathToObjectFile() + sourceFileName = os.path.join(self.path, self.module.getCSourceName()) + temp = objectFileName + if '.a' in temp: # If this is a path into an archive + temp = temp.split('(')[0] + if not os.path.isfile(temp): + raise NoObjectFileException("You must compile " + str(sourceFileName) + " to generate a corresponding object or provide a special object file path") + + try: + functionDictionary = getDarwinTestableFunctions(objectFileName) + except: + raise Exception("You must compile " + str(sourceFileName) + " to generate a corresponding object or provide a special object file path") + + namespace = self.module.getNamespace() + modulePrefix = self.module.getModulePrefix() + + # Find all passing/failing functions + if (namespace != None and modulePrefix != None): + for scope in functionDictionary: + for functionName in functionDictionary[scope]: + isValid, reason = isValidFunctionName(namespace, modulePrefix, functionName, scope) + if isValid: + self.addPassedFunction(functionName) + else: + self.addFailedFunction(functionName, reason) + + def containsMainFunction(self): + for (functionName, reason) in self.failedFunctions: + if (functionName.strip() == "main" or functionName.strip().startswith("main")): + return True + for functionName in self.passedFunctions: + if (functionName.strip() == "main" or functionName.strip().startswith("main")): + return True + return False + + @staticmethod + def getType(): + return "function-names" + + def addFailedFunction(self, function, reason): + self.failedFunctions.append((function, reason)) + + def getFailedFunctions(self): + return self.failedFunctions + + def addPassedFunction(self, function): + self.passedFunctions.append(function) + + def getPassedFunctions(self): + return self.passedFunctions + + def analyzeConformance(self): + ''' + Convert the raw pass/fail function results into a set of individual + data points (finegrain results) and overall percentage. + ''' + numPassed = len(self.passedFunctions) + numFailed = len(self.failedFunctions) + + self.percentage = 100.0 + self.points = [] + + if (numPassed + numFailed > 0): # skip invalid entries + self.percentage = float(float(numPassed) / float(numFailed + numPassed)) * 100.0 + + # Data point schema: + # namespace, moduleName, targetName, topic, line, col, score + for fname in self.passedFunctions: + data = ["function-name", fname, 100.0] + self.points.append(data) + + for (fname, reason) in self.failedFunctions: + data = ["function-name", fname, reason, 0.0] + self.points.append(data) + + def getNumberOfPassed(self): + return len(self.passedFunctions) + + def getNumberOfFailed(self): + return len(self.failedFunctions) + + def totalCSV(self): + return tuplesListToCSV(map(lambda point : [self.fullPath] + point, self.points)) + + def totalText(self, distribution): + formattedLines = tuplesListToPrettyText(self.points, distribution) + return map(lambda formattedLine : self.fullPath + " " + formattedLine, formattedLines) + + def summaryCSV(self): + line = [(self.getType(), self.percentage)] + return tuplesListToCSV(line) + + def summaryText(self, distribution): + line = [(self.getType(), self.percentage)] + return tuplesListToPrettyText(line, distribution) + + def getScore(self): + return (self.getType(), self.percentage) + + +class EnumConformanceContainer(): + def __init__(self, module): + self.path = module.getModulePath() + self.module = module + self.failedEnums = [] + self.passedEnums = [] + + if (len(self.path) > 0): + self.fullPath = self.path + os.sep + module.getCSourceName() + else: + self.fullPath = module.getCSourceName() + + self.computeConformance() + + def computeConformance(self): + sourceFileName = self.module.getCSourceName() + headerFileName = self.module.getCHeaderName() + + enums = getEnumerationsFromFiles([(self.path, sourceFileName, True), (self.path, headerFileName, False)]) + modulePrefix = self.module.getModulePrefix() + if (modulePrefix != None): + for (enumName, values, staticTag) in enums: + isValid, reason = isValidEnumName(modulePrefix, enumName, values, staticTag) + if isValid: + self.addPassedEnum(enumName) + else: + self.addFailedEnum(enumName, reason) + + @staticmethod + def getType(): + return "enum-names" + + def addFailedEnum(self, enum, reason): + self.failedEnums.append((enum, reason)) + + def getFailedEnums(self): + return self.failedEnums + + def addPassedEnum(self, enum): + self.passedEnums.append(enum) + + def getPassedEnums(self): + return self.passedEnums + + def analyzeConformance(self): + ''' + Convert the raw pass/fail enum results into a set of individual + data points (finegrain results) and overall percentage. + ''' + self.enumPercentage = 100.0 + self.points = [] + numPassed = len(self.passedEnums) + numFailed = len(self.failedEnums) + + if (numPassed + numFailed > 0): + self.enumPercentage = float((float(numPassed) / float(numPassed + numFailed)) * 100) + + for ename in self.passedEnums: + data = ["enum-name", ename, 100.0] + self.points.append(data) + + for (ename, reason) in self.failedEnums: + data = ["enum-name", ename, reason, 0.0] + self.points.append(data) + + def getNumberOfPassed(self): + return len(self.passedEnums) + + def getNumberOfFailed(self): + return len(self.failedEnums) + + def totalCSV(self): + return tuplesListToCSV(map(lambda point : [self.fullPath] + point, self.points)) + + def totalText(self, distribution): + formattedLines = tuplesListToPrettyText(self.points, distribution) + return map(lambda formattedLine : self.fullPath + " " + formattedLine, formattedLines) + + def summaryCSV(self): + line = [(self.getType(), self.enumPercentage)] + return tuplesListToCSV(line) + + def summaryText(self, distribution): + line = [(self.getType(), self.enumPercentage)] + return tuplesListToPrettyText(line, distribution) + + def getScore(self): + return (self.getType(), self.enumPercentage) + +class TypedefConformanceContainer(): + def __init__(self, module): + self.path = module.getModulePath() + self.module = module + self.failedTypedefs = [] + self.passedTypedefs = [] + + if (len(self.path) > 0): + self.fullPath = self.path + os.sep + module.getCSourceName() + else: + self.fullPath = module.getCSourceName() + + self.computeConformance() + + def computeConformance(self): + sourceFileName = self.module.getCSourceName() + headerFileName = self.module.getCHeaderName() + + typedefs = getTypedefsFromFiles([(self.path, sourceFileName, True), (self.path, headerFileName, False)]) + + modulePrefix = self.module.getModulePrefix() + if (modulePrefix != None): + for (typedefName, staticTag) in typedefs: + isValid, reason = isValidTypedefName(modulePrefix, typedefName, staticTag) + if isValid: + self.addPassedTypedef(typedefName) + else: + self.addFailedTypedef(typedefName, reason) + + @staticmethod + def getType(): + return "typedef-names" + + def addFailedTypedef(self, typedef, reason): + self.failedTypedefs.append((typedef, reason)) + + def getFailedTypedefs(self): + return self.failedTypedefs + + def addPassedTypedef(self, typedef): + self.passedTypedefs.append(typedef) + + def getPassedTypedefs(self): + return self.passedTypedefs + + def analyzeConformance(self): + ''' + Convert the raw pass/fail typedef results into a set of individual + data points (finegrain results) and overall percentage. + ''' + self.points = [] + self.typedefPercentage = 100.0 + numPassed = len(self.passedTypedefs) + numFailed = len(self.failedTypedefs) + if (numPassed + numFailed > 0): + self.typedefPercentage = float(float(numPassed) / float(numFailed + numPassed)) * 100 + + for tName in self.passedTypedefs: + data = ["typedef-name", tName, 100.0] + self.points.append(data) + + for (tName, reason) in self.failedTypedefs: + data = ["typedef-name", tName, reason, 0.0] + self.points.append(data) + + def getNumberOfPassed(self): + return len(self.passedTypedefs) + + def getNumberOfFailed(self): + return len(self.failedTypedefs) + + def totalCSV(self): + return tuplesListToCSV(map(lambda point : [self.fullPath] + point, self.points)) + + def totalText(self, distribution): + formattedLines = tuplesListToPrettyText(self.points, distribution) + return map(lambda formattedLine : self.fullPath + " " + formattedLine, formattedLines) + + def summaryCSV(self): + line = [(self.getType(), self.typedefPercentage)] + return tuplesListToCSV(line) + + def summaryText(self, distribution): + line = [(self.getType(), self.typedefPercentage)] + return tuplesListToPrettyText(line, distribution) + + def getScore(self): + return (self.getType(), self.typedefPercentage) + +class ModuleConformanceContainer(): + ''' + This conformance container stores a collection of individual type naming + conformance results within a particular module, and uses the information + contained therein to provide total finegrain and summarized + results of the conformance results for each type. + ''' + + def __init__(self, module): + self.conformanceContainers = [] + self.path = module.getModulePath() + self.module = module + self.validName = False + self.process = True + + if (len(self.path) > 0): + self.fullPath = self.path + os.sep + module.getCSourceName() + else: + self.fullPath = module.getCSourceName() + + def setProcess(self, value): + self.process = value + + def processModule(self): + return self.process + + def addConformanceContainer(self, complianceContainer): + self.conformanceContainers.append(complianceContainer) + + def analyzeConformance(self): + for container in self.conformanceContainers: + container.analyzeConformance() + + def getNumberOfPassed(self): + tuples = [] + for container in self.conformanceContainers: + tuples.append((container.getType(), container.getNumberOfPassed())) + return tuples # list of (topic, # of passed) + + def getNumberOfFailed(self): + tuples = [] + for container in self.conformanceContainers: + tuples.append((container.getType(), container.getNumberOfFailed())) + return tuples # list of (topic, # of failed) + + def totalCSV(self): + csvTuples = [] + for container in self.conformanceContainers: + csvTuples = csvTuples + container.totalCSV() + return csvTuples + + def totalText(self, distribution): + textTuples = [] + for container in self.conformanceContainers: + textTuples = textTuples + container.totalText(distribution) + return textTuples + + def summaryCSV(self): + singleTuple = [self.fullPath] + for container in self.conformanceContainers: + csvGroup = container.summaryCSV() + singleTuple = singleTuple + [csvGroup[-1]] + return tuplesListToCSV([tuple(singleTuple)]) + + def summaryText(self, distribution, divider=' '): + formattedLine = self.fullPath + for container in self.conformanceContainers: + lineGroup = container.summaryText(distribution)[0].split(" ") + formattedLine = formattedLine + divider + lineGroup[-2] + ' ' + lineGroup[-1] + return [formattedLine] + + def getScores(self): + scores = {} + for container in self.conformanceContainers: + scoreKey, scoreVal = container.getScore() + scores[scoreKey] = scoreVal + return scores + +class ModuleSetConformanceContainer(): + ''' + This conformance container stores a collection of individual module naming + conformance results, and uses the information contained therein to provide + summaries of conformance results. + ''' + + def __init__(self): + self.conformanceList = [] + + def addConformanceContainer(self, container): + self.conformanceList.append(container) + + def analyzeConformance(self): + passed = {} # passed type-number bucket + failed = {} # failed type-number bucket + + for container in self.conformanceList: + passedSet = container.getNumberOfPassed() + for (conformanceType, number) in passedSet: + if (conformanceType in passed): + passed[conformanceType] = passed[conformanceType] + number + else: + passed[conformanceType] = number + failedSet = container.getNumberOfFailed() + for (conformanceType, number) in failedSet: + if (conformanceType in failed): + failed[conformanceType] = failed[conformanceType] + number + else: + failed[conformanceType] = number + + self.typeConformancePercentages = {} + for conformanceType in passed: + total = passed[conformanceType] + failed[conformanceType] + percentage = 100.0 + if (total > 0): + percentage = (float(passed[conformanceType]) / float(total)) * 100.0 + self.typeConformancePercentages[conformanceType] = percentage + + def summaryCSV(self): + collatedTuple = ["average-scores"] + for conformanceType in self.typeConformancePercentages: + collatedTuple.append(conformanceType) # append type + collatedTuple.append(self.typeConformancePercentages[conformanceType]) # append percentage + return tuplesListToCSV([tuple(collatedTuple)]) + + def summaryText(self, distribution): + formattedLine = "average-scores" + for conformanceType in self.typeConformancePercentages: + prettyTypeText = tuplesListToPrettyText([(conformanceType, self.typeConformancePercentages[conformanceType])])[0] + formattedLine = formattedLine + " " + prettyTypeText + return [formattedLine] + +def computeModuleNameConformance(module): + ''' + Compute the module name conformance. There is no container for this result + since it's a simple boolean. + ''' + namespace = module.getNamespace() + moduleName = module.getModuleName() + typeName = module.getTypeName() + + if (namespace != None and moduleName != None and typeName != None): + return isValidModuleName(namespace, typeName, moduleName) + else: + return False + +def computeModuleConformance(module): + ''' + Compute the naming conformance results for an entire module, + which includes conformance results for all types contained therein. + ''' + moduleContainer = ModuleConformanceContainer(module) + + # Get the compliance results for functions, memorizing whether or not a main function was seen + functionContainer = FunctionConformanceContainer(module) + moduleContainer.addConformanceContainer(functionContainer) + moduleContainer.setProcess(not functionContainer.containsMainFunction()) + + # Now handle enums, typedefs, etc. + moduleContainer.addConformanceContainer(EnumConformanceContainer(module)) + moduleContainer.addConformanceContainer(TypedefConformanceContainer(module)) + moduleContainer.setValidName = computeModuleNameConformance(module) + + # Now that we have the data, run over it to generate the results + moduleContainer.analyzeConformance() + + return moduleContainer + +def getConformanceHeaders(): + headers = [FunctionConformanceContainer.getType(), EnumConformanceContainer.getType(), TypedefConformanceContainer.getType()] + return headers + +def gradeAndPrint(targets, objectDirs, problemsOnly=False, printPrefix=""): + if len(targets) < 1: + print "No Files To Grade" + return + + distribution = [99, 90] + maxFileNameLength = max(max(map(lambda target: len(target), targets)), len("File Name")) + + moduleConformanceSet = ModuleSetConformanceContainer() + headers = getConformanceHeaders() + pformat = '{prefix}{:<{maxFileNameLength}}' + nformat = pformat + for header in headers: + nformat = nformat + '{:>15}' + print nformat.format('File Name', *headers, prefix=printPrefix, maxFileNameLength=maxFileNameLength) + + + for target in targets: + module = Module(target, objectDirs) + if module.isTestSourceName(): + continue + fileNamePrefix = module.getModuleName() + path = module.getModulePath() + try: + moduleConformance = computeModuleConformance(module) + if not moduleConformance.processModule(): + pass + else: + moduleConformanceSet.addConformanceContainer(moduleConformance) + scores = moduleConformance.getScores() + minScore = 100.0 + for key in scores: + score = scores[key] + if score < minScore: + minScore = score + scores[key] = '%3.1f'%score + if problemsOnly and minScore == 100.0: + continue + printVals=[] + for hval in headers: + score = 'N/A' + if hval in scores: + score = scores[hval] + printVals.append(score) + line = nformat.format(target, *printVals, prefix=printPrefix, maxFileNameLength=maxFileNameLength) + LongBow.scorePrinter(distribution, minScore, line) + except NoObjectFileException as e: + eformat = pformat + "Could Not Grade: No .o file found for file" + line = eformat.format(target, prefix=printPrefix, maxFileNameLength=maxFileNameLength, msg=e) + print LongBow.buildRed(line) + pass + except Exception as e: + eformat = pformat + "Could Not Grade: {msg}" + line = eformat.format(target, prefix=printPrefix, maxFileNameLength=maxFileNameLength, msg=e) + print LongBow.buildRed(line) + pass + moduleConformanceSet.analyzeConformance() + + +def commandLineMain(args, targets, objectDir): + distribution = eval(args.distribution) + moduleConformanceSet = ModuleSetConformanceContainer() + + summary = args.summary + average = args.average + finegrain = args.finegrain + if not (summary or average or finegrain): + summary = True + + objectDirs = [objectDir] + for i in range(len(targets)): + module = Module(targets[i], objectDirs) + prefix = module.getModuleName() + path = module.getModulePath() + + tb = None + try: + moduleConformance = computeModuleConformance(module) + if not moduleConformance.processModule(): + print >> sys.stderr, "Skipping module " + str(prefix) + ": contains a `main` function" + else: + moduleConformanceSet.addConformanceContainer(moduleConformance) + + if summary: + if args.output == "text": + writeListToStream(moduleConformance.summaryText(distribution), sys.stdout) + else: + writeListToStream(moduleConformance.summaryCSV(), sys.stdout) + + if finegrain: + if args.output == "text": + writeListToStream(moduleConformance.totalText(distribution), sys.stdout) + else: + writeListToStream(moduleConformance.totalCSV(), sys.stdout) + + except Exception as e: + tb = traceback.format_exc() + print >> sys.stderr, "Error: can't analyze conformance of " + os.path.join(path, prefix) + ": " + str(e) + finally: + if tb != None and args.trace: + print tb + pass + + moduleConformanceSet.analyzeConformance() + if average: + if args.output == "text": + writeListToStream(moduleConformanceSet.summaryText(distribution), sys.stdout) + else: + writeListToStream(moduleConformanceSet.summaryCSV(), sys.stdout) diff --git a/longbow/src/python/site-packages/longbow/StyleReport.py b/longbow/src/python/site-packages/longbow/StyleReport.py new file mode 100755 index 00000000..7e8d72e0 --- /dev/null +++ b/longbow/src/python/site-packages/longbow/StyleReport.py @@ -0,0 +1,382 @@ +#! /usr/bin/env python +# 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. +# + +# + +import sys +import os +import tempfile +import subprocess +import difflib +import csv +import argparse + +import LongBow +import ANSITerm +import FileUtil +import pprint + +def getExemplar(fileName, command, config): + """Create the exemplar formatted file into memory as a string""" + + with open(fileName) as inputFile: + result = subprocess.check_output([command, "-q", "-c", config], stdin=inputFile) + return result; + + +def diff(exemplar, fileName): + d = difflib.Differ() + differ = d.compare(exemplar.splitlines(), fileName.splitlines()) + return differ + + +class Ratchet: + def __init__(self): + self.currentValue = 0 + self.signal = 0 + + def value(self): + return self.currentValue + + def toggle(self, signal): + if self.signal == "-": + if signal == "-": + self.currentValue = self.currentValue + 1 + elif signal == "?": + self.currentValue = self.currentValue + 1 + self.signal = 0 + else: + self.currentValue = self.currentValue + 1 + self.signal = 0 + pass + elif self.signal == "+": + if signal == "-": + self.currentValue = self.currentValue + 1 + elif signal == "?": + self.currentValue = self.currentValue + 1 + self.signal = 0 + else: + self.currentValue = self.currentValue + 1 + self.signal = 0 + pass + else: + self.signal = signal; + + return self.currentValue + + +def computeNonCompliantLines(differ): + lines = 0 + changes = Ratchet() + + for l in differ: + if l.startswith('-'): + changes.toggle(l[0]) + lines = lines - 1 + elif l.startswith('+'): + changes.toggle(l[0]) + lines = lines + 1 + elif l.startswith('?'): + pass + elif l.startswith(' '): + lines = lines +1 + else: + print "What is this:", l + + return changes.value() + + +def reportWhy(differ): + print '\n'.join(diff) + return + + +class SyntaxCompliance: + def __init__(self, fileName, exemplarCommand, exemplarConfig): + self.fileName = fileName + self.nonCompliantLines = 0 + self.score = 0 + self.exemplarCommand = exemplarCommand + self.exemplarConfig = exemplarConfig + try: + self.fileData = FileUtil.readFileString(self.fileName) + self.totalLines = len(self.fileData.splitlines()) + except IOError, e: + print >> sys.stderr, e + sys.exit(1) + pass + + def check(self): + self.exemplarData = getExemplar(self.fileName, self.exemplarCommand, self.exemplarConfig) + differ = diff(self.fileData, self.exemplarData) + + self.nonCompliantLines = computeNonCompliantLines(differ) + + return self + + def report(self): + result = { "fileName" : self.fileName, + "label": "style", + "score": self.getScore(), + "totalLines" : self.getTotalLines(), + "nonCompliantLines" : self.getNonCompliantLines() + } + return result + + def getFileName(self): + return self.fileName + + def getExemplarCommand(self): + return self.exemplarCommand; + + def getExemplarConfig(self): + return self.exemplarConfig; + + def getScore(self): + result = 0 + try: + result = int(100 * (1.0 - (float(self.getNonCompliantLines()) / float(self.getTotalLines())))) + except ZeroDivisionError: + pass + return result + + def getTotalLines(self): + return self.totalLines + + def getNonCompliantLines(self): + return self.nonCompliantLines + + def explain(self): + self.exemplarData = getExemplar(self.fileName, self.exemplarCommand, self.exemplarConfig) + differ = diff(self.fileData, self.exemplarData) + + ansiTerm = ANSITerm.ANSITerm() + + for l in differ: + if l[0] == '-': + ansiTerm.printColorized("red", l) + elif l[0] == '+': + ansiTerm.printColorized("green", l) + elif l[0] == '?': + ansiTerm.printColorized("yellow", l[0:len(l)-1]) + else: + print l + pass + return + + +def csvScore(distribution, report): + string = "style,%s,%d,%d,%.2f" % (report["fileName"], report["totalLines"], report["nonCompliantLines"], report["score"]) + LongBow.scorePrinter(distribution, report["score"], string) + return + + +def csvAverage(distribution, complianceList): + scores = map(lambda target: target.getScore(), complianceList) + sum = reduce(lambda sum, score : sum + score, scores) + value = float(sum) / float(len(complianceList)) + LongBow.scorePrinter(distribution, value, "%.2f" % (value)) + return + + +def csvTotal(distribution, complianceList): + totalLines = reduce(lambda sum, x: sum + x, map(lambda element : element.getTotalLines(), complianceList)) + totalNonCompliantLines = reduce(lambda sum, x: sum + x, map(lambda element : element.getNonCompliantLines(), complianceList)) + value = 100.0 - (100.0 * float(totalNonCompliantLines) / float(totalLines)) + LongBow.scorePrinter(distribution, value, "%.2f" % (value)) + return + + +def csvSummary(distribution, complianceList): + map(lambda target: csvScore(distribution, target.report()), complianceList) + return + + +def textScore(distribution, report, maxFileNameLength, prefix=""): + ''' + + ''' + format = "%s%-*s %6d %6d %6.2f" + string = format % (prefix, maxFileNameLength, report["fileName"], report["totalLines"], report["nonCompliantLines"], report["score"]) + LongBow.scorePrinter(distribution, report["score"], string) + return + + +def textAverage(distribution, complianceList): + scores = map(lambda target: target.getScore(), complianceList) + sum = reduce(lambda sum, score : sum + score, scores) + value = float(sum) / float(len(complianceList)) + LongBow.scorePrinter(distribution, value, "%.2f" % (value)) + return + + +def textTotal(distribution, complianceList): + totalLines = reduce(lambda sum, x: sum + x, map(lambda element : element.getTotalLines(), complianceList)) + totalNonCompliantLines = reduce(lambda sum, x: sum + x, map(lambda element : element.getNonCompliantLines(), complianceList)) + value = 100.0 - (100.0 * float(totalNonCompliantLines) / float(totalLines)) + LongBow.scorePrinter(distribution, value, "%.2f" % (value)) + return + + +def textSummary(distribution, complianceList, prefix=""): + if len(complianceList) > 0: + maxFileNameLength = max(max(map(lambda target: len(target.getFileName()), complianceList)), len("File Name")) + + print "%s%-*s %6s %6s %6s" % (prefix, maxFileNameLength, "File Name", "Lines", "Errors", "Score") + map(lambda target: textScore(distribution, target.report(), maxFileNameLength, prefix), complianceList) + + return + + +def textVisual(complianceList): + map(lambda target: target.explain(), complianceList) + return + + +def openDiff(sourceFile, exemplarCommand, exemplarConfig): + exemplar = getExemplar(sourceFile, exemplarCommand, exemplarConfig); + temporaryExemplarFile = tempfile.NamedTemporaryFile(suffix=".c", delete=False) + try: + with open(temporaryExemplarFile.name, "w") as exemplarOutput: + exemplarOutput.write(exemplar) + + subprocess.check_output(["opendiff", sourceFile, temporaryExemplarFile.name, "-merge", sourceFile]) + finally: + pass + + return + + +def displaySummary(args, complianceList): + distribution = eval(args.distribution) + + if args.output == "text": + textSummary(distribution, complianceList) + elif args.output == "gui": + textSummary(distribution, complianceList) + else: + csvSummary(distribution, complianceList) + return + + +def displayAverage(args, complianceList): + + distribution = eval(args.distribution) + + if args.output == "text": + textAverage(distribution, complianceList) + elif args.output == "gui": + textAverage(distribution, complianceList) + else: + csvAverage(distribution, complianceList) + return + + +def displayTotal(args, complianceList): + distribution = eval(args.distribution) + + if args.output == "text": + textTotal(distribution, complianceList) + elif args.output == "gui": + textTotal(distribution, complianceList) + else: + csvTotal(distribution, complianceList) + return + + +def guiVisual(args, complianceList): + map(lambda target: openDiff(target.getFileName(), target.getExemplarCommand(), target.getExemplarConfig()), complianceList) + return + + +def displayVisual(args, complianceList): + if args.output == "text": + textVisual(complianceList) + elif args.output == "gui": + guiVisual(args, complianceList) + else: + print >> sys.stderr, "Unsupported output format '%s'. Expected 'text' or 'gui'." % (args.output) + sys.exit(1) + return + + +def sortComplianceList(args, complianceList): + + sorter = { + "name" : { "function" : lambda k: k.getFileName(), "reverse" : False }, + "descending-name" : { "function" : lambda k: k.getFileName(), "reverse" : True }, + "score" : { "function" : lambda k: k.getScore(), "reverse" : False }, + "descending-score" : { "function" : lambda k: k.getScore(), "reverse" : True }, + "size" : { "function" : lambda k: k.getTotalLines(), "reverse" : False }, + "descending-size" : { "function" : lambda k: k.getTotalLines(), "reverse" : True }, + } + + if args.key == "help": + print >> sys.stderr, "Supported sort keys:" + map(lambda k: sys.stderr.write("'" + k + "' "), sorted(sorter)) + print + sys.exit(1) + + if args.key in sorter: + complianceList = sorted(complianceList, key=sorter[args.key]["function"], reverse=sorter[args.key]["reverse"]) + else: + print >> sys.stderr, "Unsupported sort key '%s'. Type '--key help'" % (args.key) + sys.exit(1) + + return complianceList + + +def exclude(args, complianceList): + excluded = map(lambda token : token.strip(), args.exclude.split(",")) + complianceList = filter(lambda entry: LongBow.score(eval(args.distribution), entry.getScore()) not in excluded, complianceList) + + return complianceList + + +def gradeAndPrint(targets, exemplarCommand, exemplarConfig, problemsOnly=False, prefix=""): + complianceList = [] + problemList = [] + for target in targets: + try: + complianceList.append(SyntaxCompliance(target, exemplarCommand, exemplarConfig).check()) + except: + problemList.append(target) + pass + complianceList = sorted(complianceList, key=lambda k: k.getFileName()) + if problemsOnly: + complianceList = filter(lambda entry: entry.getScore() < 100, complianceList) + distribution=[99,90] + textSummary(distribution, complianceList, prefix) + + for target in problemList: + print LongBow.buildRed("%s%s could not be evaluated" % (prefix, target)) + + +def commandLineMain(args, targets, exemplarCommand, exemplarConfig): + complianceList = map(lambda target: SyntaxCompliance(target, exemplarCommand, exemplarConfig).check(), targets) + + complianceList = sortComplianceList(args, complianceList) + + complianceList = exclude(args, complianceList) + + if args.summary: + displaySummary(args, complianceList) + elif args.average: + displayAverage(args, complianceList) + elif args.total: + displayTotal(args, complianceList) + elif args.visual: + displayVisual(args, complianceList) + return diff --git a/longbow/src/python/site-packages/longbow/SymbolTable.py b/longbow/src/python/site-packages/longbow/SymbolTable.py new file mode 100755 index 00000000..20a909d7 --- /dev/null +++ b/longbow/src/python/site-packages/longbow/SymbolTable.py @@ -0,0 +1,87 @@ +#! /usr/bin/env python +# 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. +# + +# +import os +import subprocess +import re +import sys +import pprint + +def parseLocation(location): + token = location.split("[") + objectFileName = location + + if len(token) > 1: + libraryName = token[0] + objectFileName = token[1].split("]")[0] + else: + libraryName = None + + objectFileName = objectFileName.split(":")[0] + return (libraryName, objectFileName) + +def parseDarwinOutput(lines, accumulator = { }): + + for line in lines: + token = line.split(" ") + fullName = token[0] + + libraryName, objectFileName = parseLocation(token[0]) + name = token[1] + type = token[2] + if fullName in accumulator: + if type == "U": + accumulator[fullName]["undefined"].append({ "name" : name }) + elif type == "T": + accumulator[fullName]["defined"].append({ "name" : name }) + elif type == "D": + accumulator[fullName]["globalData"].append({ "name" : name }) + else: + accumulator[fullName] = { "fullName" : fullName, "libraryName" : libraryName, "objectFileName" : objectFileName, "defined" : [], "undefined" : [], "globalData" : [] } + + return accumulator + +def getDarwinSymbolTable(objectFileName, accumulator = { }): + command = [ "/usr/bin/nm", "-PAog", objectFileName ] + + output = subprocess.check_output(command) + lines = output.splitlines() + return parseDarwinOutput(lines, accumulator) + + +def getSymbolTable(objectFileName, accumulator = { }): + ''' + { + fullName : { "defined" : list of dictionaries, + "undefined": list of dictionaries, + "globalData" : list of dictionaries, + "libraryName" : string + "objectFileName : string + }, + } + ''' + return getDarwinSymbolTable(objectFileName, accumulator) + + +if __name__ == '__main__': + + table = dict() + for f in sys.argv: + table = getSymbolTable(f, table) + + pp = pprint.PrettyPrinter(indent=4, width=132) + + pp.pprint(table) diff --git a/longbow/src/python/site-packages/longbow/VocabularyReport.py b/longbow/src/python/site-packages/longbow/VocabularyReport.py new file mode 100755 index 00000000..5609db11 --- /dev/null +++ b/longbow/src/python/site-packages/longbow/VocabularyReport.py @@ -0,0 +1,162 @@ +#! /usr/bin/env python +# 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. +# + +# + +import sys +import itertools + +import LongBow + +def computeVocabularyScore(tokenCount): + return 100.0 + + +def csvFunctionResult(file, function): + score = computeVocabularyScore(file.token_count) + string = "vocabulary,%s,%s,%d,%d,%.2f" % (file.filename, function.name, function.start_line, function.token_count, score) + + LongBow.scorePrinter([90, 80], score, string) + return function.token_count + + +def csvFileVocabulary(file): + score = computeVocabularyScore(file.token_count) + string = "vocabulary,%s,,,%.2f,%.2f" % (file.filename, file.average_token, score) + LongBow.scorePrinter([90, 80], score, string) + return + + +def csvFunction(fileInformationList): + for fileInformation in fileInformationList: + complexities = map(lambda function: csvFunctionResult(fileInformation, function), fileInformation) + return + + +def csvSummary(fileInformationList): + map(lambda file: csvFileVocabulary(file), fileInformationList) + return + + +def textFunctionResult(file, function, maxFileNameLength, maxFunctionNameLength): + score = computeVocabularyScore(function.token_count) + format = "%-" + str(maxFileNameLength) + "s %-" + str(maxFunctionNameLength) + "s %3d %3d %6.2f" + string = format % (file.filename, function.name, function.start_line, function.token_count, score) + + LongBow.scorePrinter([90, 80], score, string) + return function.cyclomatic_complexity + + +def textFileVocabulary(file, maxFileNameLength, printFormat=""): + score = computeVocabularyScore(file.average_CCN) + if printFormat == "": + printFormat = "%-" + str(maxFileNameLength) + "s %6.2f %6.2f" + string = printFormat % (file.filename, file.average_token, score) + LongBow.scorePrinter([90, 80], score, string) + return + + +def computeMaxFileNameLength(fileInformationList): + result = 0 + for fileInformation in fileInformationList: + if len(fileInformation.filename) > result: + result = len(fileInformation.filename) + return result + + +def computeMaxFunctionNameLength(fileInformationList): + result = 0 + for fileInformation in fileInformationList: + if len(fileInformation.filename) > result: + result = len(fileInformation.filename) + return result + + +def textFunction(fileInformationList): + maxFileNameLength = max(map(lambda fileInformation: len(fileInformation.filename), fileInformationList)) + maxFunctionNameLength = max(map(lambda fileInformation: max(map(lambda function: len(function.name), fileInformation)), fileInformationList)) + + for fileInformation in fileInformationList: + complexities = map(lambda function: textFunctionResult(fileInformation, function, maxFileNameLength, maxFunctionNameLength), fileInformation) + return + + +def textSummary(fileInformationList, prefix=""): + if len(fileInformationList) < 1: + print "%sNo Files To Grade" % prefix + return + maxFileNameLength = max(map(lambda fileInformation: len(fileInformation.filename), fileInformationList)) + printFormat = prefix + "%-" + str(maxFileNameLength) + "s %10s %6s" + print printFormat % ("File Path", "Ave Token", "Score") + printFormat = prefix + "%-" + str(maxFileNameLength) + "s %10.2f %6.2f" + map(lambda file: textFileVocabulary(file, maxFileNameLength, printFormat), fileInformationList) + return + + +def computeAverage(fileInformationList): + vocabulary = map(lambda fileInformation : fileInformation.average_token, fileInformationList) + sum = reduce(lambda sum, x: sum + x, vocabulary) + return float(sum) / float(len(vocabulary)) + + +def gradeAndPrint(fileList, hfcca, problemsOnly=False, prefix=""): + options, arguments = hfcca.createHfccaCommandLineParser().parse_args(args=["foo"]) + result = hfcca.analyze(fileList, options) + + # Convert from that iterator to a simple list... + fileInformationList = map(lambda x : x, result) + if problemsOnly: + fileInformationList = filter(lambda item: computeVocabularyScore(item.average_CCN) < 100, fileInformationList) + + textSummary(fileInformationList, prefix) + +def commandLineMain(args, hfcca): + targets = [] + + if args.stdin: + for line in sys.stdin: + t = line.strip() + if (len(t) > 0): + targets.append(t) + else: + targets = args.files + + if (len(targets) == 0): + print >> sys.stderr, "Error: target list cannot be empty" + + # If nothing was specified, print the summary as a default + if args.summary == False and args.function == False and args.average == False: + args.summary = True + + options, arguments = hfcca.createHfccaCommandLineParser().parse_args(args=["VocabularyReport"]) + result = hfcca.analyze(targets, options) + + # Convert from that iterator to a simple list... + fileInformationList = map(lambda x : x, result) + + if args.function: + if args.output == "text": + textFunction(fileInformationList) + else: + csvFunction(fileInformationList) + + if args.summary: + if args.output == "text": + textSummary(fileInformationList) + else: + csvSummary(fileInformationList) + + if args.average: + print "%.2f" % computeAverage(fileInformationList) |