diff --git a/.github/workflows/msys2-build.yml b/.github/workflows/msys2-build.yml index 9367498..a9b2e06 100644 --- a/.github/workflows/msys2-build.yml +++ b/.github/workflows/msys2-build.yml @@ -9,8 +9,8 @@ permissions: contents: read jobs: - package: - name: Build MSYS2 package (UCRT64) + build: + name: Build on MSYS2 UCRT64 runs-on: windows-latest defaults: @@ -25,91 +25,34 @@ jobs: - name: Check out source uses: actions/checkout@v4 - - name: Verify VERSION matches PKGBUILD - id: version - shell: bash - run: | - version_file="$(tr -d '[:space:]' < VERSION)" - pkg_version="${version_file//-/.}" - - if ! grep -Fq "_distver=\"${version_file}\"" packaging/msys2/PKGBUILD; then - echo "PKGBUILD _distver does not match VERSION (${version_file})" >&2 - exit 1 - fi - - if ! grep -Eq "^pkgver=${pkg_version//./\\.}$" packaging/msys2/PKGBUILD; then - echo "PKGBUILD pkgver does not match VERSION (${pkg_version})" >&2 - exit 1 - fi - - echo "dist_dir=cunit-${version_file}" >> "${GITHUB_OUTPUT}" - echo "dist_file=cunit-${version_file}" >> "${GITHUB_OUTPUT}" - - name: Set up MSYS2 uses: msys2/setup-msys2@v2 with: - msystem: MSYS + msystem: UCRT64 update: true cache: true install: >- base-devel git - - - name: Create source tarball for PKGBUILD - env: - DIST_DIR: ${{ steps.version.outputs.dist_dir }} - DIST_FILE: ${{ steps.version.outputs.dist_file }} - working-directory: packaging/msys2 - run: | - git -C ../.. archive \ - --format=tar.gz \ - --prefix="${DIST_DIR}/" \ - HEAD > "${DIST_FILE}.tar.gz" - - - name: Build package - working-directory: packaging/msys2 - run: MINGW_ARCH=ucrt64 makepkg-mingw -sCLf --noconfirm - - - name: Upload package artifact - uses: actions/upload-artifact@v4 - with: - name: cunit-msys2-ucrt64-pkg - path: packaging/msys2/*.pkg.tar.zst - if-no-files-found: error - - test-package: - name: Test installed MSYS2 package (UCRT64) - runs-on: windows-latest - needs: package - - defaults: - run: - shell: msys2 {0} - - steps: - - name: Set up MSYS2 - uses: msys2/setup-msys2@v2 - with: - msystem: UCRT64 - update: true - cache: true - install: >- + mingw-w64-ucrt-x86_64-autotools mingw-w64-ucrt-x86_64-cc mingw-w64-ucrt-x86_64-pkgconf - - name: Download package artifact - uses: actions/download-artifact@v4 - with: - name: cunit-msys2-ucrt64-pkg - path: pkg + - name: Bootstrap and configure + run: ./bootstrap --configure --prefix "$(pwd)/_install" -- --enable-debug --enable-test + + - name: Build + run: make -j"$(nproc)" - - name: Install package artifact + - name: Run internal self-tests run: | - pacman -U --noconfirm pkg/*.pkg.tar.zst - test -f "${MINGW_PREFIX}/include/CUnit/CUnit.h" - test -f "${MINGW_PREFIX}/lib/libcunit.a" || test -f "${MINGW_PREFIX}/lib/libcunit.dll.a" + ./CUnit/Sources/Test/test_cunit | tee test_cunit.log + grep -q "Failures: 0" test_cunit.log + + - name: Install + run: make install - - name: Smoke test installed package + - name: Smoke test installed package metadata run: | cat > smoke.c <<'EOF' #include @@ -123,5 +66,7 @@ jobs: } EOF + export PATH="$(pwd)/_install/bin:${PATH}" + export PKG_CONFIG_PATH="$(pwd)/_install/lib/pkgconfig" gcc smoke.c -o smoke $(pkgconf --cflags --libs cunit) ./smoke diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e5fba12..bed365e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,12 +1,18 @@ name: CUnit Release on: + workflow_dispatch: + inputs: + release_tag: + description: 'Optional tag name to validate, for example v2.1.3. Defaults to VERSION.' + required: false + type: string push: tags: - 'v*' permissions: - contents: write + contents: read jobs: verify-version: @@ -15,6 +21,7 @@ jobs: outputs: version_file: ${{ steps.verify.outputs.version_file }} pkg_version: ${{ steps.verify.outputs.pkg_version }} + release_tag: ${{ steps.verify.outputs.release_tag }} dist_dir: ${{ steps.verify.outputs.dist_dir }} dist_file: ${{ steps.verify.outputs.dist_file }} @@ -24,39 +31,99 @@ jobs: - name: Verify tag matches VERSION id: verify + env: + INPUT_RELEASE_TAG: ${{ inputs.release_tag }} shell: bash run: | version_file="$(tr -d '[:space:]' < VERSION)" pkg_version="${version_file//-/.}" expected_tag="v${pkg_version}" + release_tag="${GITHUB_REF_NAME}" + + if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then + release_tag="${INPUT_RELEASE_TAG}" + if [ -z "${release_tag}" ]; then + release_tag="${expected_tag}" + fi + fi - if [ "${GITHUB_REF_NAME}" != "${expected_tag}" ]; then + if [ "${release_tag}" != "${expected_tag}" ]; then echo "Tag/version mismatch" >&2 echo " VERSION file: ${version_file}" >&2 echo " Expected tag: ${expected_tag}" >&2 - echo " Actual tag: ${GITHUB_REF_NAME}" >&2 + echo " Actual tag: ${release_tag}" >&2 + exit 1 + fi + + if ! grep -Fq '_distver="$(tr -d' packaging/msys2/PKGBUILD || \ + ! grep -Fq '< ../../VERSION)' packaging/msys2/PKGBUILD; then + echo "PKGBUILD _distver is not read from VERSION" >&2 exit 1 fi - if ! grep -Fq "_distver=\"${version_file}\"" packaging/msys2/PKGBUILD; then - echo "PKGBUILD _distver does not match VERSION (${version_file})" >&2 + if ! grep -Fq 'pkgver=${_distver//-/.}' packaging/msys2/PKGBUILD; then + echo "PKGBUILD pkgver is not derived from _distver" >&2 exit 1 fi - if ! grep -Eq "^pkgver=${pkg_version//./\\.}$" packaging/msys2/PKGBUILD; then - echo "PKGBUILD pkgver does not match VERSION (${pkg_version})" >&2 + if ! grep -Fq 'm4_esyscmd_s([cat VERSION])' configure.in; then + echo "configure.in does not read VERSION for AC_INIT" >&2 exit 1 fi echo "version_file=${version_file}" >> "${GITHUB_OUTPUT}" echo "pkg_version=${pkg_version}" >> "${GITHUB_OUTPUT}" + echo "release_tag=${release_tag}" >> "${GITHUB_OUTPUT}" echo "dist_dir=cunit-${version_file}" >> "${GITHUB_OUTPUT}" echo "dist_file=cunit-${version_file}" >> "${GITHUB_OUTPUT}" + source-dist: + name: Build source dist + runs-on: ubuntu-latest + needs: verify-version + + steps: + - name: Check out source + uses: actions/checkout@v4 + + - name: Install build dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + autoconf \ + automake \ + build-essential \ + libtool + + - name: Bootstrap + run: ./bootstrap --configure --prefix "${RUNNER_TEMP}/cunit-distcheck" -- --enable-debug --enable-test + + - name: Build and check source dist + run: make distcheck DISTCHECK_CONFIGURE_FLAGS="--enable-debug --enable-test" + + - name: Verify source dist contents + env: + DIST_FILE: ${{ needs.verify-version.outputs.dist_file }} + run: | + test -f "${DIST_FILE}.tar.gz" + tar -tzf "${DIST_FILE}.tar.gz" | grep -Fx "${DIST_FILE}/configure" + tar -tzf "${DIST_FILE}.tar.gz" | grep -Fx "${DIST_FILE}/Makefile.in" + tar -tzf "${DIST_FILE}.tar.gz" | grep -Fx "${DIST_FILE}/VERSION" + tar -tzf "${DIST_FILE}.tar.gz" | grep -Fx "${DIST_FILE}/README.md" + + - name: Upload source dist + uses: actions/upload-artifact@v4 + with: + name: cunit-source-dist + path: ${{ needs.verify-version.outputs.dist_file }}.tar.gz + if-no-files-found: error + package: name: Build release assets (UCRT64) runs-on: windows-latest - needs: verify-version + needs: + - verify-version + - source-dist defaults: run: @@ -80,16 +147,11 @@ jobs: base-devel git - - name: Create source tarball for PKGBUILD - env: - DIST_DIR: ${{ needs.verify-version.outputs.dist_dir }} - DIST_FILE: ${{ needs.verify-version.outputs.dist_file }} - working-directory: packaging/msys2 - run: | - git -C ../.. archive \ - --format=tar.gz \ - --prefix="${DIST_DIR}/" \ - HEAD > "${DIST_FILE}.tar.gz" + - name: Download source dist for PKGBUILD + uses: actions/download-artifact@v4 + with: + name: cunit-source-dist + path: packaging/msys2 - name: Build package working-directory: packaging/msys2 @@ -104,6 +166,39 @@ jobs: packaging/msys2/*.tar.gz if-no-files-found: error + test-source-dist-rocky8: + name: Test source dist (Rocky 8) + runs-on: ubuntu-latest + container: rockylinux:8 + needs: + - verify-version + - source-dist + + steps: + - name: Install build dependencies + run: dnf -y install gcc make diffutils findutils tar gzip + + - name: Download source dist + uses: actions/download-artifact@v4 + with: + name: cunit-source-dist + path: . + + - name: Build and test source dist + env: + DIST_FILE: ${{ needs.verify-version.outputs.dist_file }} + run: | + tar -xzf "${DIST_FILE}.tar.gz" + mkdir build + cd build + "../${DIST_FILE}/configure" \ + --prefix=/tmp/cunit-rocky8 \ + --enable-debug \ + --enable-test + make -j"$(nproc)" + ./CUnit/Sources/Test/test_cunit | tee test_cunit.log + grep -q "Failures: 0" test_cunit.log + test-package: name: Test installed release package (UCRT64) runs-on: windows-latest @@ -155,9 +250,14 @@ jobs: publish-release: name: Publish GitHub release + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest + permissions: + contents: write needs: - verify-version + - source-dist + - test-source-dist-rocky8 - test-package steps: @@ -177,8 +277,9 @@ jobs: GH_TOKEN: ${{ github.token }} GH_REPO: ${{ github.repository }} PKG_VERSION: ${{ needs.verify-version.outputs.pkg_version }} + RELEASE_TAG: ${{ needs.verify-version.outputs.release_tag }} run: | - gh release create "${GITHUB_REF_NAME}" \ + gh release create "${RELEASE_TAG}" \ --repo "${GH_REPO}" \ --verify-tag \ --generate-notes \ diff --git a/.gitignore b/.gitignore index 1e43036..c6def10 100644 --- a/.gitignore +++ b/.gitignore @@ -16,12 +16,17 @@ missing *.lo *.o *.la +*.a **/Makefile **/.deps **/.libs +doc/headers/*.h config.log CUnit.spec config.status cunit.pc config.h CUnit/Headers/CUnit.h +CUnit*Dump.xml +stamp-h1 +CUnit/Sources/Test/test_cunit diff --git a/CUnit.spec.in b/CUnit.spec.in index 32cc655..3974a9a 100644 --- a/CUnit.spec.in +++ b/CUnit.spec.in @@ -2,7 +2,7 @@ Summary: A unit testing framework for 'C' Name: @PACKAGE@ Version: @VERSION@ Release: @RELEASE@ -Source: http://www.sourceforge.net/projects/cunit/cunit-@VERSION@-@RELEASE@.tar.gz +Source: http://www.sourceforge.net/projects/cunit/cunit-@DIST_VERSION@.tar.gz Group: Development/Tools License: GPL URL: http://cunit.sourceforge.net @@ -15,7 +15,7 @@ headers, and documentation files. %prep echo "Preparing for Installation." -%setup -q -n cunit-@VERSION@-@RELEASE@ +%setup -q -n cunit-@DIST_VERSION@ %build echo "Preparing for Building." diff --git a/CUnit/Headers/CUnit.h.in b/CUnit/Headers/CUnit.h.in index 1e283cd..6b8b6a5 100644 --- a/CUnit/Headers/CUnit.h.in +++ b/CUnit/Headers/CUnit.h.in @@ -148,6 +148,14 @@ #define CU_FAIL_FATAL(msg) \ { CU_assertImplementation(CU_FALSE, __LINE__, ("CU_FAIL_FATAL(" #msg ")"), __FILE__, "", CU_TRUE); } +/** Skip the current test with a reason, and return from the test function. */ +#define CU_SKIP(reason) \ + { CU_skipImplementation(__LINE__, __FILE__, (reason)); return; } + +/** Skip the current test with a reason if the condition is true, and return from the test function. */ +#define CU_SKIP_IF(value, reason) \ + { if (value) { CU_skipImplementation(__LINE__, __FILE__, (reason)); return; } } + /** Asserts that value is CU_TRUE. * Reports failure with no other action. */ diff --git a/CUnit/Headers/Makefile.in b/CUnit/Headers/Makefile.in index 2145eea..ba9b155 100644 --- a/CUnit/Headers/Makefile.in +++ b/CUnit/Headers/Makefile.in @@ -193,6 +193,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/CUnit/Headers/TestRun.h b/CUnit/Headers/TestRun.h index f8e9429..119a8e0 100644 --- a/CUnit/Headers/TestRun.h +++ b/CUnit/Headers/TestRun.h @@ -113,18 +113,37 @@ typedef struct CU_RunSummary { char PackageName[50]; unsigned int nSuitesRun; /**< Number of suites completed during run. */ - unsigned int nSuitesFailed; /**< Number of suites for which initialization failed. */ + unsigned int nSuitesFailed; /**< Number of suites which failed during run. */ unsigned int nSuitesInactive; /**< Number of suites which were inactive. */ - unsigned int nTestsRun; /**< Number of tests completed during run. */ - unsigned int nTestsFailed; /**< Number of tests containing failed assertions. */ - unsigned int nTestsInactive; /**< Number of tests which were inactive (in active suites). */ + unsigned int nTestsRun; /**< Number of selected active tests entered during run. */ + unsigned int nTestsFailed; /**< Number of tests which failed during run. */ + unsigned int nTestsInactive; /**< Number of selected tests which were inactive. */ unsigned int nAsserts; /**< Number of assertions tested during run. */ unsigned int nAssertsFailed; /**< Number of failed assertions. */ unsigned int nFailureRecords; /**< Number of failure records generated. */ double ElapsedTime; /**< Elapsed time for run in seconds. */ + unsigned int nSuitesSelected; /**< Number of suites selected for the run. */ + unsigned int nTestsSelected; /**< Number of tests selected for the run. */ + unsigned int nTestsSkipped; /**< Number of tests which self-skipped during the run. */ } CU_RunSummary; typedef CU_RunSummary* CU_pRunSummary; /**< Pointer to CU_RunSummary. */ +/* CU_SkipRecord type definition. */ +/** Data type for holding test skip information (linked list). */ +typedef struct CU_SkipRecord +{ + unsigned int uiLineNumber; /**< Line number of skip request. */ + char* strFileName; /**< Name of file where skip occurred. */ + char* strReason; /**< Reason for skipping the test. */ + CU_pTest pTest; /**< Test which skipped. */ + CU_pSuite pSuite; /**< Suite containing skipped test. */ + + struct CU_SkipRecord* pNext; /**< Pointer to next record in linked list. */ + struct CU_SkipRecord* pPrev; /**< Pointer to previous record in linked list. */ + +} CU_SkipRecord; +typedef CU_SkipRecord* CU_pSkipRecord; /**< Pointer to CU_SkipRecord. */ + /*-------------------------------------------------------------------- * Type Definitions for Message Handlers. *--------------------------------------------------------------------*/ @@ -357,14 +376,20 @@ CU_EXPORT CU_BOOL CU_get_fail_on_inactive(void); *--------------------------------------------------------------------*/ CU_EXPORT unsigned int CU_get_number_of_suites_run(void); /**< Retrieves the number of suites completed during the previous run (reset each run). */ +CU_EXPORT unsigned int CU_get_number_of_suites_selected(void); +/**< Retrieves the number of suites selected during the previous run (reset each run). */ CU_EXPORT unsigned int CU_get_number_of_suites_failed(void); -/**< Retrieves the number of suites which failed to initialize during the previous run (reset each run). */ +/**< Retrieves the number of suites which failed during the previous run (reset each run). */ CU_EXPORT unsigned int CU_get_number_of_suites_inactive(void); /**< Retrieves the number of inactive suites found during the previous run (reset each run). */ CU_EXPORT unsigned int CU_get_number_of_tests_run(void); -/**< Retrieves the number of tests completed during the previous run (reset each run). */ +/**< Retrieves the number of selected active tests entered during the previous run (reset each run). */ +CU_EXPORT unsigned int CU_get_number_of_tests_selected(void); +/**< Retrieves the number of tests selected during the previous run (reset each run). */ CU_EXPORT unsigned int CU_get_number_of_tests_failed(void); -/**< Retrieves the number of tests containing failed assertions during the previous run (reset each run). */ +/**< Retrieves the number of tests which failed during the previous run (reset each run). */ +CU_EXPORT unsigned int CU_get_number_of_tests_skipped(void); +/**< Retrieves the number of tests which self-skipped during the previous run (reset each run). */ CU_EXPORT unsigned int CU_get_number_of_tests_inactive(void); /**< Retrieves the number of inactive tests found during the previous run (reset each run). */ CU_EXPORT unsigned int CU_get_number_of_asserts(void); @@ -394,6 +419,19 @@ CU_EXPORT CU_pFailureRecord CU_get_failure_list(void); * when the client initiates a run using CU_run_all_tests(), CU_run_suite(), * or CU_run_test(). */ +CU_EXPORT CU_pSkipRecord CU_get_skip_list(void); +/**< + * Retrieves the head of the linked list of tests which self-skipped during + * the last run (reset each run). Note that the pointer returned is + * invalidated when the client initiates a run using CU_run_all_tests(), + * CU_run_suite(), or CU_run_test(). + */ +CU_EXPORT CU_pSkipRecord CU_get_current_test_skip_record(void); +/**< + * Retrieves the skip record for the currently completing test, or NULL if + * the current test did not self-skip. This is intended for use from a + * test-complete message handler. + */ CU_EXPORT CU_pRunSummary CU_get_run_summary(void); /**< * Retrieves the entire run summary for the last test run (reset each run). @@ -473,6 +511,21 @@ CU_EXPORT CU_BOOL CU_assertImplementation(CU_BOOL bValue, * @return As a convenience, returns the value of the assertion (i.e. bValue). */ +CU_EXPORT void CU_skipImplementation(unsigned int uiLine, + const char *strFile, + const char *strReason); +/**< + * Runtime skip implementation function. + * CU_SKIP and CU_SKIP_IF reduce to a call to this function followed by a + * return from the current test function. It should only be called during + * an active test run (checked by assertion). The skip reason is copied + * by CUnit, so callers may pass dynamically generated strings. + * + * @param uiLine Line number of skip request. + * @param strFile Source file where skip request occurred. + * @param strReason Reason for skipping the test, or NULL. + */ + #ifdef USE_DEPRECATED_CUNIT_NAMES typedef CU_FailureRecord _TestResult; /**< @deprecated Use CU_FailureRecord. */ typedef CU_pFailureRecord PTestResult; /**< @deprecated Use CU_pFailureRecord. */ diff --git a/CUnit/Makefile.in b/CUnit/Makefile.in index f38b2ad..03288c1 100644 --- a/CUnit/Makefile.in +++ b/CUnit/Makefile.in @@ -201,6 +201,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/CUnit/Sources/Automated/Automated.c b/CUnit/Sources/Automated/Automated.c index d78e7bc..040d92a 100644 --- a/CUnit/Sources/Automated/Automated.c +++ b/CUnit/Sources/Automated/Automated.c @@ -318,6 +318,7 @@ static void automated_test_complete_message_handler(const CU_pTest pTest, size_t szTemp_len = 0; size_t cur_len = 0; CU_pFailureRecord pTempFailure = pFailure; + CU_pSkipRecord pSkip = CU_get_current_test_skip_record(); const char *pPackageName = CU_automated_package_name_get(); CU_UNREFERENCED_PARAMETER(pSuite); /* pSuite is not used except in assertion */ @@ -405,6 +406,52 @@ static void automated_test_complete_message_handler(const CU_pTest pTest, fprintf(f_pTestResultFile, " \n"); } /* if */ } + else if (NULL != pSkip) { + if (NULL != pSkip->strReason) { + szTemp_len = CU_translated_strlen(pSkip->strReason) + 1; + szTemp = (char *)CU_MALLOC(szTemp_len); + if (NULL != szTemp) { + CU_translate_special_characters(pSkip->strReason, szTemp, szTemp_len); + } + } + + if (bJUnitXmlOutput == CU_TRUE) { + if ((NULL != szTemp) && ('\0' != szTemp[0])) { + fprintf(f_pTestResultFile, " \n", + pPackageName, + pSuite->pName, + (NULL != pTest->pName) ? pTest->pName : "", + szTemp); + } + else { + fprintf(f_pTestResultFile, " \n", + pPackageName, + pSuite->pName, + (NULL != pTest->pName) ? pTest->pName : ""); + } + } else { + if ((NULL != szTemp) && ('\0' != szTemp[0])) { + fprintf(f_pTestResultFile, + " \n" + " \n" + " %s \n" + " %s \n" + " \n" + " \n", + pTest->pName, + szTemp); + } + else { + fprintf(f_pTestResultFile, + " \n" + " \n" + " %s \n" + " \n" + " \n", + pTest->pName); + } + } + } else { if (bJUnitXmlOutput == CU_TRUE) { fprintf(f_pTestResultFile, " \n", @@ -468,6 +515,7 @@ static void automated_all_tests_complete_message_handler(const CU_pFailureRecord { CU_pTestRegistry pRegistry = CU_get_registry(); CU_pRunSummary pRunSummary = CU_get_run_summary(); + unsigned int nTestsPassed = 0; CU_UNREFERENCED_PARAMETER(pFailure); /* not used */ @@ -475,6 +523,10 @@ static void automated_all_tests_complete_message_handler(const CU_pFailureRecord assert(NULL != pRunSummary); assert(NULL != f_pTestResultFile); + if (pRunSummary->nTestsRun >= pRunSummary->nTestsFailed + pRunSummary->nTestsSkipped) { + nTestsPassed = pRunSummary->nTestsRun - pRunSummary->nTestsFailed - pRunSummary->nTestsSkipped; + } + if ((NULL != f_pRunningSuite) && (CU_TRUE == f_bWriting_CUNIT_RUN_SUITE)) { if (bJUnitXmlOutput == CU_FALSE) { fprintf(f_pTestResultFile, @@ -492,13 +544,16 @@ static void automated_all_tests_complete_message_handler(const CU_pFailureRecord " \n" " %s \n" " %u \n" + " %u \n" " %u \n" " - NA - \n" " %u \n" + " - NA - \n" " %u \n" " \n", _("Suites"), pRegistry->uiNumberOfSuites, + pRunSummary->nSuitesSelected, pRunSummary->nSuitesRun, pRunSummary->nSuitesFailed, pRunSummary->nSuitesInactive); @@ -507,33 +562,41 @@ static void automated_all_tests_complete_message_handler(const CU_pFailureRecord " \n" " %s \n" " %u \n" + " %u \n" " %u \n" " %u \n" " %u \n" + " %u \n" " %u \n" " \n", _("Test Cases"), pRegistry->uiNumberOfTests, + pRunSummary->nTestsSelected, pRunSummary->nTestsRun, - pRunSummary->nTestsRun - pRunSummary->nTestsFailed, + nTestsPassed, pRunSummary->nTestsFailed, + pRunSummary->nTestsSkipped, pRunSummary->nTestsInactive); fprintf(f_pTestResultFile, " \n" " %s \n" " %u \n" + " %s \n" " %u \n" " %u \n" " %u \n" + " %s \n" " %s \n" " \n" " \n", _("Assertions"), pRunSummary->nAsserts, + _("n/a"), pRunSummary->nAsserts, pRunSummary->nAsserts - pRunSummary->nAssertsFailed, pRunSummary->nAssertsFailed, + _("n/a"), _("n/a")); } } diff --git a/CUnit/Sources/Automated/Makefile.in b/CUnit/Sources/Automated/Makefile.in index 69d5521..fa44e8a 100644 --- a/CUnit/Sources/Automated/Makefile.in +++ b/CUnit/Sources/Automated/Makefile.in @@ -191,6 +191,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/CUnit/Sources/Basic/Basic.c b/CUnit/Sources/Basic/Basic.c index e1bc4ab..c8c4ced 100644 --- a/CUnit/Sources/Basic/Basic.c +++ b/CUnit/Sources/Basic/Basic.c @@ -300,12 +300,21 @@ static void basic_test_complete_message_handler(const CU_pTest pTest, const CU_pFailureRecord pFailureList) { CU_pFailureRecord pFailure = pFailureList; + CU_pSkipRecord pSkip = CU_get_current_test_skip_record(); int i; assert(NULL != pSuite); assert(NULL != pTest); - if (NULL == pFailure) { + if (NULL != pSkip) { + if (CU_BRM_VERBOSE == f_run_mode) { + fprintf(stdout, _("skipped")); + if ((NULL != pSkip->strReason) && ('\0' != pSkip->strReason[0])) { + fprintf(stdout, _(" (%s)"), pSkip->strReason); + } + } + } + else if (NULL == pFailure) { if (CU_BRM_VERBOSE == f_run_mode) { fprintf(stdout, _("passed")); } diff --git a/CUnit/Sources/Basic/Makefile.in b/CUnit/Sources/Basic/Makefile.in index 5685f30..50d7d6b 100644 --- a/CUnit/Sources/Basic/Makefile.in +++ b/CUnit/Sources/Basic/Makefile.in @@ -191,6 +191,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/CUnit/Sources/Console/Makefile.in b/CUnit/Sources/Console/Makefile.in index b435d09..bd5181a 100644 --- a/CUnit/Sources/Console/Makefile.in +++ b/CUnit/Sources/Console/Makefile.in @@ -191,6 +191,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/CUnit/Sources/Curses/Makefile.in b/CUnit/Sources/Curses/Makefile.in index 0ed4fbe..831d32e 100644 --- a/CUnit/Sources/Curses/Makefile.in +++ b/CUnit/Sources/Curses/Makefile.in @@ -191,6 +191,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/CUnit/Sources/Framework/Makefile.am b/CUnit/Sources/Framework/Makefile.am index 37c0510..488a92f 100644 --- a/CUnit/Sources/Framework/Makefile.am +++ b/CUnit/Sources/Framework/Makefile.am @@ -15,7 +15,7 @@ libcunitfmk_la_SOURCES = $(SHARED_SOURCES) if ENABLE_TEST TEST_DEFINES = -DCUNIT_BUILD_TESTS -DCUNIT_DO_NOT_DEFINE_UNLESS_BUILDING_TESTS -DMEMTRACE -TEST_INCLUDES = -I../Test +TEST_INCLUDES = -I../Test -I$(top_srcdir)/CUnit/Sources/Test %_test.o: %.c $(COMPILE) $(TEST_INCLUDES) $(TEST_DEFINES) -o $@ -c $< diff --git a/CUnit/Sources/Framework/Makefile.in b/CUnit/Sources/Framework/Makefile.in index cc8f2ce..e1bc4fe 100644 --- a/CUnit/Sources/Framework/Makefile.in +++ b/CUnit/Sources/Framework/Makefile.in @@ -205,6 +205,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ @@ -329,7 +330,7 @@ SHARED_SOURCES = \ noinst_LTLIBRARIES = libcunitfmk.la libcunitfmk_la_SOURCES = $(SHARED_SOURCES) @ENABLE_TEST_TRUE@TEST_DEFINES = -DCUNIT_BUILD_TESTS -DCUNIT_DO_NOT_DEFINE_UNLESS_BUILDING_TESTS -DMEMTRACE -@ENABLE_TEST_TRUE@TEST_INCLUDES = -I../Test +@ENABLE_TEST_TRUE@TEST_INCLUDES = -I../Test -I$(top_srcdir)/CUnit/Sources/Test @ENABLE_TEST_TRUE@TEST_OBJECTS = \ @ENABLE_TEST_TRUE@ CUError_test.o \ @ENABLE_TEST_TRUE@ MyMem_test.o \ diff --git a/CUnit/Sources/Framework/TestRun.c b/CUnit/Sources/Framework/TestRun.c index 752101f..9a67783 100644 --- a/CUnit/Sources/Framework/TestRun.c +++ b/CUnit/Sources/Framework/TestRun.c @@ -96,7 +96,7 @@ static CU_pSuite f_pCurSuite = NULL; /**< Pointer to the suite currentl static CU_pTest f_pCurTest = NULL; /**< Pointer to the test currently being run. */ /** CU_RunSummary to hold results of each test run. */ -static CU_RunSummary f_run_summary = {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static CU_RunSummary f_run_summary = {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /** CU_pFailureRecord to hold head of failure record list of each test run. */ static CU_pFailureRecord f_failure_list = NULL; @@ -104,6 +104,18 @@ static CU_pFailureRecord f_failure_list = NULL; /** CU_pFailureRecord to hold head of failure record list of each test run. */ static CU_pFailureRecord f_last_failure = NULL; +/** CU_pSkipRecord to hold head of skip record list of each test run. */ +static CU_pSkipRecord f_skip_list = NULL; + +/** CU_pSkipRecord to hold the skip record for the current test. */ +static CU_pSkipRecord f_current_skip = NULL; + +/** Flag for whether the current test requested a runtime skip. */ +static CU_BOOL f_current_test_skipped = CU_FALSE; + +/** Number of failures present when the current test started. */ +static unsigned int f_current_test_start_failures = 0; + /** Flag for whether inactive suites/tests are treated as failures. */ static CU_BOOL f_failure_on_inactive = CU_TRUE; @@ -419,6 +431,14 @@ static void cu_capture_stop(int dump){ *=================================================================*/ static void clear_previous_results(CU_pRunSummary pRunSummary, CU_pFailureRecord* ppFailure); static void cleanup_failure_list(CU_pFailureRecord* ppFailure); +static void cleanup_skip_list(CU_pSkipRecord* ppSkip); +static void add_skip(CU_pSkipRecord* ppSkip, + unsigned int uiLineNumber, + const char *szFileName, + const char *szReason, + CU_pSuite pSuite, + CU_pTest pTest); +static void remove_skip(CU_pSkipRecord* ppSkip, CU_pSkipRecord pSkip); static CU_ErrorCode run_single_suite(CU_pSuite pSuite, CU_pRunSummary pRunSummary); static CU_ErrorCode run_single_test(CU_pTest pTest, CU_pRunSummary pRunSummary); static void add_failure(CU_pFailureRecord* ppFailure, @@ -461,6 +481,21 @@ CU_BOOL CU_assertImplementation(CU_BOOL bValue, return bValue; } +/*------------------------------------------------------------------------*/ +void CU_skipImplementation(unsigned int uiLine, + const char *strFile, + const char *strReason) +{ + assert(NULL != f_pCurSuite); + assert(NULL != f_pCurTest); + + if ((NULL == f_current_skip) && + (f_run_summary.nFailureRecords == f_current_test_start_failures)) { + f_current_test_skipped = CU_TRUE; + add_skip(&f_skip_list, uiLine, strFile, strReason, f_pCurSuite, f_pCurTest); + } +} + /*------------------------------------------------------------------------*/ void CU_set_suite_start_handler(CU_SuiteStartMessageHandler pSuiteStartHandler) { @@ -568,6 +603,12 @@ unsigned int CU_get_number_of_suites_run(void) return f_run_summary.nSuitesRun; } +/*------------------------------------------------------------------------*/ +unsigned int CU_get_number_of_suites_selected(void) +{ + return f_run_summary.nSuitesSelected; +} + /*------------------------------------------------------------------------*/ unsigned int CU_get_number_of_suites_failed(void) { @@ -586,12 +627,24 @@ unsigned int CU_get_number_of_tests_run(void) return f_run_summary.nTestsRun; } +/*------------------------------------------------------------------------*/ +unsigned int CU_get_number_of_tests_selected(void) +{ + return f_run_summary.nTestsSelected; +} + /*------------------------------------------------------------------------*/ unsigned int CU_get_number_of_tests_failed(void) { return f_run_summary.nTestsFailed; } +/*------------------------------------------------------------------------*/ +unsigned int CU_get_number_of_tests_skipped(void) +{ + return f_run_summary.nTestsSkipped; +} + /*------------------------------------------------------------------------*/ unsigned int CU_get_number_of_tests_inactive(void) { @@ -639,6 +692,18 @@ CU_pFailureRecord CU_get_failure_list(void) return f_failure_list; } +/*------------------------------------------------------------------------*/ +CU_pSkipRecord CU_get_skip_list(void) +{ + return f_skip_list; +} + +/*------------------------------------------------------------------------*/ +CU_pSkipRecord CU_get_current_test_skip_record(void) +{ + return f_current_skip; +} + /*------------------------------------------------------------------------*/ CU_pRunSummary CU_get_run_summary(void) { @@ -723,7 +788,10 @@ CU_EXPORT CU_ErrorCode CU_run_selected_tests(int argc, char **argv){ result = (CUE_SUCCESS == result) ? CUE_NO_SUITENAME : result; }else if(CU_FALSE == suite->fActive){ fprintf(stderr,"Suite is inactive '%s'\n",suitename); + f_run_summary.nSuitesSelected++; + f_run_summary.nTestsSelected += suite->uiNumberOfTests; f_run_summary.nSuitesInactive++; + f_run_summary.nTestsInactive += suite->uiNumberOfTests; if(CU_FALSE != f_failure_on_inactive){ add_failure(&f_failure_list, &f_run_summary, CUF_SuiteInactive, 0, _("Suite inactive"), _("CUnit System"), suite, NULL @@ -746,6 +814,8 @@ CU_EXPORT CU_ErrorCode CU_run_selected_tests(int argc, char **argv){ }else{ //fprintf(stderr,"Valid test '%s' in suite '%s'\n",n,suitename); /* found a valid suite+test name... run the test! */ + f_run_summary.nSuitesSelected++; + f_run_summary.nTestsSelected++; /* run handler for suite start, if any */ if (NULL != f_pSuiteStartMessageHandler) { @@ -860,7 +930,10 @@ CU_ErrorCode CU_run_test(CU_pSuite pSuite, CU_pTest pTest) result = CUE_NOTEST; } else if (CU_FALSE == pSuite->fActive) { + f_run_summary.nSuitesSelected++; + f_run_summary.nTestsSelected++; f_run_summary.nSuitesInactive++; + f_run_summary.nTestsInactive++; if (CU_FALSE != f_failure_on_inactive) { add_failure(&f_failure_list, &f_run_summary, CUF_SuiteInactive, 0, _("Suite inactive"), _("CUnit System"), pSuite, NULL); @@ -877,6 +950,8 @@ CU_ErrorCode CU_run_test(CU_pSuite pSuite, CU_pTest pTest) f_pCurTest = NULL; f_pCurSuite = pSuite; + f_run_summary.nSuitesSelected++; + f_run_summary.nTestsSelected++; pSuite->uiNumberOfTestsFailed = 0; pSuite->uiNumberOfTestsSuccess = 0; @@ -995,13 +1070,18 @@ CU_EXPORT char * CU_get_run_results_string(void) { CU_pRunSummary pRunSummary = &f_run_summary; CU_pTestRegistry pRegistry = CU_get_registry(); - size_t width[9]; + unsigned int nTestsPassed = 0; + int width[11]; size_t len; char *result; assert(NULL != pRunSummary); assert(NULL != pRegistry); + if (pRunSummary->nTestsRun >= pRunSummary->nTestsFailed + pRunSummary->nTestsSkipped) { + nTestsPassed = pRunSummary->nTestsRun - pRunSummary->nTestsFailed - pRunSummary->nTestsSkipped; + } + width[0] = strlen(_("Run Summary:")); width[1] = CU_MAX(6, CU_MAX(strlen(_("Type")), @@ -1009,73 +1089,90 @@ CU_EXPORT char * CU_get_run_results_string(void) CU_MAX(strlen(_("tests")), strlen(_("asserts")))))) + 1; width[2] = CU_MAX(6, - CU_MAX(strlen(_("Total")), - CU_MAX(CU_number_width(pRegistry->uiNumberOfSuites), - CU_MAX(CU_number_width(pRegistry->uiNumberOfTests), - CU_number_width(pRunSummary->nAsserts))))) + 1; + CU_MAX(strlen(_("Total")), + CU_MAX(CU_number_width(pRegistry->uiNumberOfSuites), + CU_MAX(CU_number_width(pRegistry->uiNumberOfTests), + CU_number_width(pRunSummary->nAsserts))))) + 1; width[3] = CU_MAX(6, + CU_MAX(strlen(_("Selected")), + CU_MAX(CU_number_width(pRunSummary->nSuitesSelected), + CU_MAX(CU_number_width(pRunSummary->nTestsSelected), + strlen(_("n/a")))))) + 1; + width[4] = CU_MAX(6, CU_MAX(strlen(_("Ran")), CU_MAX(CU_number_width(pRunSummary->nSuitesRun), CU_MAX(CU_number_width(pRunSummary->nTestsRun), CU_number_width(pRunSummary->nAsserts))))) + 1; - width[4] = CU_MAX(6, + width[5] = CU_MAX(6, CU_MAX(strlen(_("Passed")), CU_MAX(strlen(_("n/a")), - CU_MAX(CU_number_width(pRunSummary->nTestsRun - pRunSummary->nTestsFailed), + CU_MAX(CU_number_width(nTestsPassed), CU_number_width(pRunSummary->nAsserts - pRunSummary->nAssertsFailed))))) + 1; - width[5] = CU_MAX(6, + width[6] = CU_MAX(6, CU_MAX(strlen(_("Failed")), CU_MAX(CU_number_width(pRunSummary->nSuitesFailed), CU_MAX(CU_number_width(pRunSummary->nTestsFailed), CU_number_width(pRunSummary->nAssertsFailed))))) + 1; - width[6] = CU_MAX(6, + width[7] = CU_MAX(6, + CU_MAX(strlen(_("Skipped")), + CU_MAX(strlen(_("n/a")), + CU_number_width(pRunSummary->nTestsSkipped)))) + 1; + width[8] = CU_MAX(6, CU_MAX(strlen(_("Inactive")), CU_MAX(CU_number_width(pRunSummary->nSuitesInactive), CU_MAX(CU_number_width(pRunSummary->nTestsInactive), strlen(_("n/a")))))) + 1; - width[7] = strlen(_("Elapsed time = ")); - width[8] = strlen(_(" seconds")); + width[9] = strlen(_("Elapsed time = ")); + width[10] = strlen(_(" seconds")); - len = 13 + 4*(width[0] + width[1] + width[2] + width[3] + width[4] + width[5] + width[6]) + width[7] + width[8] + 1; + len = 13 + 4*(width[0] + width[1] + width[2] + width[3] + width[4] + width[5] + width[6] + width[7] + width[8]) + width[9] + width[10] + 1; result = (char *)CU_MALLOC(len); if (NULL != result) { - snprintf(result, len, "%*s%*s%*s%*s%*s%*s%*s\n" /* if you change this, be sure */ - "%*s%*s%*u%*u%*s%*u%*u\n" /* to change the calculation of */ - "%*s%*s%*u%*u%*u%*u%*u\n" /* len above! */ - "%*s%*s%*u%*u%*u%*u%*s\n\n" + snprintf(result, len, "%*s%*s%*s%*s%*s%*s%*s%*s%*s\n" /* if you change this, be sure */ + "%*s%*s%*u%*u%*u%*s%*u%*s%*u\n" /* to change the calculation of */ + "%*s%*s%*u%*u%*u%*u%*u%*u%*u\n" /* len above! */ + "%*s%*s%*u%*s%*u%*u%*u%*s%*s\n\n" "%*s%8.3f%*s", width[0], _("Run Summary:"), width[1], _("Type"), width[2], _("Total"), - width[3], _("Ran"), - width[4], _("Passed"), - width[5], _("Failed"), - width[6], _("Inactive"), + width[3], _("Selected"), + width[4], _("Ran"), + width[5], _("Passed"), + width[6], _("Failed"), + width[7], _("Skipped"), + width[8], _("Inactive"), width[0], " ", width[1], _("suites"), width[2], pRegistry->uiNumberOfSuites, - width[3], pRunSummary->nSuitesRun, - width[4], _("n/a"), - width[5], pRunSummary->nSuitesFailed, - width[6], pRunSummary->nSuitesInactive, + width[3], pRunSummary->nSuitesSelected, + width[4], pRunSummary->nSuitesRun, + width[5], _("n/a"), + width[6], pRunSummary->nSuitesFailed, + width[7], _("n/a"), + width[8], pRunSummary->nSuitesInactive, width[0], " ", width[1], _("tests"), width[2], pRegistry->uiNumberOfTests, - width[3], pRunSummary->nTestsRun, - width[4], pRunSummary->nTestsRun - pRunSummary->nTestsFailed, - width[5], pRunSummary->nTestsFailed, - width[6], pRunSummary->nTestsInactive, + width[3], pRunSummary->nTestsSelected, + width[4], pRunSummary->nTestsRun, + width[5], nTestsPassed, + width[6], pRunSummary->nTestsFailed, + width[7], pRunSummary->nTestsSkipped, + width[8], pRunSummary->nTestsInactive, width[0], " ", width[1], _("asserts"), width[2], pRunSummary->nAsserts, - width[3], pRunSummary->nAsserts, - width[4], pRunSummary->nAsserts - pRunSummary->nAssertsFailed, - width[5], pRunSummary->nAssertsFailed, - width[6], _("n/a"), - width[7], _("Elapsed time = "), CU_get_elapsed_time(), /* makes sure time is updated */ - width[8], _(" seconds") + width[3], _("n/a"), + width[4], pRunSummary->nAsserts, + width[5], pRunSummary->nAsserts - pRunSummary->nAssertsFailed, + width[6], pRunSummary->nAssertsFailed, + width[7], _("n/a"), + width[8], _("n/a"), + width[9], _("Elapsed time = "), CU_get_elapsed_time(), /* makes sure time is updated */ + width[10], _(" seconds") ); result[len-1] = '\0'; } @@ -1174,6 +1271,98 @@ static void add_failure(CU_pFailureRecord* ppFailure, f_last_failure = pFailureNew; } +/*------------------------------------------------------------------------*/ +static void add_skip(CU_pSkipRecord* ppSkip, + unsigned int uiLineNumber, + const char *szFileName, + const char *szReason, + CU_pSuite pSuite, + CU_pTest pTest) +{ + CU_pSkipRecord pSkipNew = NULL; + CU_pSkipRecord pTemp = NULL; + + assert(NULL != ppSkip); + + pSkipNew = (CU_pSkipRecord)CU_MALLOC(sizeof(CU_SkipRecord)); + + if (NULL == pSkipNew) { + return; + } + + pSkipNew->strFileName = NULL; + pSkipNew->strReason = NULL; + if (NULL != szFileName) { + pSkipNew->strFileName = (char*)CU_MALLOC(strlen(szFileName) + 1); + if (NULL == pSkipNew->strFileName) { + CU_FREE(pSkipNew); + return; + } + strcpy(pSkipNew->strFileName, szFileName); + } + + if (NULL != szReason) { + pSkipNew->strReason = (char*)CU_MALLOC(strlen(szReason) + 1); + if (NULL == pSkipNew->strReason) { + if (NULL != pSkipNew->strFileName) { + CU_FREE(pSkipNew->strFileName); + } + CU_FREE(pSkipNew); + return; + } + strcpy(pSkipNew->strReason, szReason); + } + + pSkipNew->uiLineNumber = uiLineNumber; + pSkipNew->pTest = pTest; + pSkipNew->pSuite = pSuite; + pSkipNew->pNext = NULL; + pSkipNew->pPrev = NULL; + + pTemp = *ppSkip; + if (NULL != pTemp) { + while (NULL != pTemp->pNext) { + pTemp = pTemp->pNext; + } + pTemp->pNext = pSkipNew; + pSkipNew->pPrev = pTemp; + } + else { + *ppSkip = pSkipNew; + } + + f_current_skip = pSkipNew; +} + +/*------------------------------------------------------------------------*/ +static void remove_skip(CU_pSkipRecord* ppSkip, CU_pSkipRecord pSkip) +{ + assert(NULL != ppSkip); + + if (NULL == pSkip) { + return; + } + + if (NULL != pSkip->pPrev) { + pSkip->pPrev->pNext = pSkip->pNext; + } + else { + *ppSkip = pSkip->pNext; + } + + if (NULL != pSkip->pNext) { + pSkip->pNext->pPrev = pSkip->pPrev; + } + + if (NULL != pSkip->strReason) { + CU_FREE(pSkip->strReason); + } + if (NULL != pSkip->strFileName) { + CU_FREE(pSkip->strFileName); + } + CU_FREE(pSkip); +} + /* * Local function for result set initialization/cleanup. */ @@ -1203,12 +1392,22 @@ static void clear_previous_results(CU_pRunSummary pRunSummary, CU_pFailureRecord pRunSummary->nAssertsFailed = 0; pRunSummary->nFailureRecords = 0; pRunSummary->ElapsedTime = 0.0; + pRunSummary->nSuitesSelected = 0; + pRunSummary->nTestsSelected = 0; + pRunSummary->nTestsSkipped = 0; if (NULL != *ppFailure) { cleanup_failure_list(ppFailure); } + if (NULL != f_skip_list) { + cleanup_skip_list(&f_skip_list); + } + f_last_failure = NULL; + f_current_skip = NULL; + f_current_test_skipped = CU_FALSE; + f_current_test_start_failures = 0; } /*------------------------------------------------------------------------*/ @@ -1245,6 +1444,39 @@ static void cleanup_failure_list(CU_pFailureRecord* ppFailure) *ppFailure = NULL; } +/*------------------------------------------------------------------------*/ +/** + * Frees all memory allocated for the linked list of test skip + * records. pSkip is reset to NULL after its list is cleaned up. + * + * @param ppSkip Pointer to head of linked list of + * CU_pSkipRecords to clean. + */ +static void cleanup_skip_list(CU_pSkipRecord* ppSkip) +{ + CU_pSkipRecord pCurSkip = NULL; + CU_pSkipRecord pNextSkip = NULL; + + pCurSkip = *ppSkip; + + while (NULL != pCurSkip) { + + if (NULL != pCurSkip->strReason) { + CU_FREE(pCurSkip->strReason); + } + + if (NULL != pCurSkip->strFileName) { + CU_FREE(pCurSkip->strFileName); + } + + pNextSkip = pCurSkip->pNext; + CU_FREE(pCurSkip); + pCurSkip = pNextSkip; + } + + *ppSkip = NULL; +} + /*------------------------------------------------------------------------*/ /** * Runs all tests in a specified suite. @@ -1276,6 +1508,8 @@ static CU_ErrorCode run_single_suite(CU_pSuite pSuite, CU_pRunSummary pRunSummar f_pCurTest = NULL; f_pCurSuite = pSuite; + pRunSummary->nSuitesSelected++; + pRunSummary->nTestsSelected += pSuite->uiNumberOfTests; /* run handler for suite start, if any */ if (NULL != f_pSuiteStartMessageHandler) { @@ -1346,6 +1580,7 @@ static CU_ErrorCode run_single_suite(CU_pSuite pSuite, CU_pRunSummary pRunSummar /* otherwise record inactive suite and failure if appropriate */ else { f_run_summary.nSuitesInactive++; + f_run_summary.nTestsInactive += pSuite->uiNumberOfTests; if (CU_FALSE != f_failure_on_inactive) { add_failure(&f_failure_list, &f_run_summary, CUF_SuiteInactive, 0, _("Suite inactive"), _("CUnit System"), pSuite, NULL); @@ -1415,6 +1650,9 @@ static CU_ErrorCode run_single_test(CU_pTest pTest, CU_pRunSummary pRunSummary) nStartFailures = pRunSummary->nFailureRecords; f_pCurTest = pTest; + f_current_skip = NULL; + f_current_test_skipped = CU_FALSE; + f_current_test_start_failures = nStartFailures; if (NULL != f_pTestStartMessageHandler) { (*f_pTestStartMessageHandler)(f_pCurTest, f_pCurSuite); @@ -1462,6 +1700,11 @@ static CU_ErrorCode run_single_test(CU_pTest pTest, CU_pRunSummary pRunSummary) //fprintf(stderr,"\nFound some failures...\n"); pRunSummary->nTestsFailed++; test_failed = 1; + if (NULL != f_current_skip) { + remove_skip(&f_skip_list, f_current_skip); + f_current_skip = NULL; + } + f_current_test_skipped = CU_FALSE; if(NULL != pLastFailure) { pLastFailure = pLastFailure->pNext; /* was a previous failure, so go to next one */ }else{ @@ -1469,6 +1712,9 @@ static CU_ErrorCode run_single_test(CU_pTest pTest, CU_pRunSummary pRunSummary) } }else{ pLastFailure = NULL; /* no additional failure - set to NULL */ + if (CU_FALSE != f_current_test_skipped) { + pRunSummary->nTestsSkipped++; + } } if(capture_enabled){ cu_capture_stop(test_failed ? 1 : 0); @@ -1483,6 +1729,9 @@ static CU_ErrorCode run_single_test(CU_pTest pTest, CU_pRunSummary pRunSummary) pTest->pJumpBuf = NULL; f_pCurTest = NULL; + f_current_skip = NULL; + f_current_test_skipped = CU_FALSE; + f_current_test_start_failures = 0; return result; } @@ -1826,6 +2075,24 @@ static void do_test_results(unsigned int nSuitesRun, static void test_succeed(void) { CU_TEST(CU_TRUE); } static void test_fail(void) { CU_TEST(CU_FALSE); } +static void test_skip_static(void) { CU_SKIP("static skip reason"); } +static void test_skip_dynamic(void) +{ + char reason[80]; + snprintf(reason, sizeof(reason), "dynamic skip reason %d", 42); + reason[sizeof(reason)-1] = '\0'; + CU_SKIP(reason); +} +static void test_skip_if_true(void) { CU_SKIP_IF(CU_TRUE, "skip-if reason"); } +static void test_skip_if_false(void) { CU_SKIP_IF(CU_FALSE, "should not skip"); CU_TEST(CU_TRUE); } +static void test_fail_then_skip(void) { CU_TEST(CU_FALSE); CU_SKIP("ignored after failure"); } +static void test_skip_null_reason(void) { CU_SKIP(NULL); } +static void test_skip_empty_reason(void) { CU_SKIP(""); } +static void test_skip_twice(void) +{ + CU_skipImplementation(__LINE__, __FILE__, "first skip reason"); + CU_skipImplementation(__LINE__, __FILE__, "second skip reason"); +} static int suite_succeed(void) { return 0; } static int suite_fail(void) { return 1; } @@ -1836,6 +2103,38 @@ static void test_fail_if_not_setup(void) { CU_TEST(SetUp_Passed); } static void suite_setup(void) { SetUp_Passed = CU_TRUE; } static void suite_teardown(void) { SetUp_Passed = CU_FALSE; } +static void suite_teardown_fail(void) { CU_TEST(CU_FALSE); } + +static CU_pSuite f_expected_skip_record_suite = NULL; +static CU_pTest f_expected_skip_record_test = NULL; +static const char *f_expected_skip_record_reason = NULL; +static unsigned int f_nSkipRecordHandlerCalls = 0; + +static void skip_record_test_complete_handler(const CU_pTest pTest, + const CU_pSuite pSuite, + const CU_pFailureRecord pFailure) +{ + CU_pSkipRecord pSkip = CU_get_current_test_skip_record(); + + TEST(NULL == pFailure); + TEST(f_expected_skip_record_suite == pSuite); + TEST(f_expected_skip_record_test == pTest); + TEST(NULL != pSkip); + if (NULL != pSkip) { + TEST(pSuite == pSkip->pSuite); + TEST(pTest == pSkip->pTest); + if (NULL == f_expected_skip_record_reason) { + TEST(NULL == pSkip->strReason); + } + else { + TEST(NULL != pSkip->strReason); + if (NULL != pSkip->strReason) { + TEST(!strcmp(f_expected_skip_record_reason, pSkip->strReason)); + } + } + } + ++f_nSkipRecordHandlerCalls; +} /*-------------------------------------------------*/ @@ -1912,7 +2211,7 @@ static void test_message_handlers(void) TEST(0 == f_nTestEvents); TEST(NULL == f_pFirstEvent); - test_results(2,2,1,4,2,1,4,2,2,6); + test_results(2,2,1,4,2,2,4,2,2,6); /* set handlers to local functions */ CU_set_suite_start_handler(&suite_start_handler); @@ -2078,7 +2377,7 @@ static void test_message_handlers(void) TEST(pEvent->pFailure == CU_get_failure_list()); } - test_results(2,2,1,4,2,1,4,2,2,6); + test_results(2,2,1,4,2,2,4,2,2,6); /* clear handlers and run again */ CU_set_suite_start_handler(NULL); @@ -2104,12 +2403,178 @@ static void test_message_handlers(void) TEST(0 == f_nTestEvents); TEST(NULL == f_pFirstEvent); - test_results(2,2,1,4,2,1,4,2,2,6); + test_results(2,2,1,4,2,2,4,2,2,6); CU_cleanup_registry(); clear_test_events(); } +/*-------------------------------------------------*/ +/* tests CU_SKIP() and CU_SKIP_IF() + */ +static void test_CU_skip(void) +{ + CU_pSuite pSuite = NULL; + CU_pSuite pTeardownSuite = NULL; + CU_pTest pTest1 = NULL; + CU_pTest pTest2 = NULL; + CU_pTest pTest3 = NULL; + CU_pTest pTest5 = NULL; + CU_pTest pTest6 = NULL; + CU_pTest pTest7 = NULL; + CU_pTest pTest8 = NULL; + CU_pTest pTeardownTest = NULL; + CU_pSkipRecord pSkip = NULL; + CU_pSkipRecord pPrevSkip = NULL; + + CU_set_error_action(CUEA_IGNORE); + CU_initialize_registry(); + + pSuite = CU_add_suite("skip_suite", NULL, NULL); + pTest1 = CU_add_test(pSuite, "skip_static", test_skip_static); + pTest2 = CU_add_test(pSuite, "skip_dynamic", test_skip_dynamic); + pTest3 = CU_add_test(pSuite, "skip_if_true", test_skip_if_true); + CU_add_test(pSuite, "skip_if_false", test_skip_if_false); + pTest5 = CU_add_test(pSuite, "fail_then_skip", test_fail_then_skip); + pTest6 = CU_add_test(pSuite, "skip_null_reason", test_skip_null_reason); + pTest7 = CU_add_test(pSuite, "skip_empty_reason", test_skip_empty_reason); + pTest8 = CU_add_test(pSuite, "skip_twice", test_skip_twice); + + TEST_FATAL(CUE_SUCCESS == CU_get_error()); + TEST(CUE_SUCCESS == CU_run_suite(pSuite)); + + TEST(1 == CU_get_number_of_suites_selected()); + TEST(8 == CU_get_number_of_tests_selected()); + TEST(8 == CU_get_number_of_tests_run()); + TEST(6 == CU_get_number_of_tests_skipped()); + TEST(1 == CU_get_number_of_tests_failed()); + TEST(0 == CU_get_number_of_tests_inactive()); + TEST(2 == CU_get_number_of_asserts()); + TEST(1 == CU_get_number_of_failures()); + TEST(1 == CU_get_number_of_failure_records()); + + pSkip = CU_get_skip_list(); + TEST(NULL != pSkip); + if (NULL != pSkip) { + TEST(pSuite == pSkip->pSuite); + TEST(pTest1 == pSkip->pTest); + TEST(NULL != pSkip->strReason); + TEST(!strcmp("static skip reason", pSkip->strReason)); + TEST(NULL == pSkip->pPrev); + TEST(NULL != pSkip->pNext); + pPrevSkip = pSkip; + } + + if (NULL != pSkip) { + pSkip = pSkip->pNext; + } + TEST(NULL != pSkip); + if (NULL != pSkip) { + TEST(pSuite == pSkip->pSuite); + TEST(pTest2 == pSkip->pTest); + TEST(NULL != pSkip->strReason); + TEST(!strcmp("dynamic skip reason 42", pSkip->strReason)); + TEST(pPrevSkip == pSkip->pPrev); + TEST(NULL != pSkip->pNext); + pPrevSkip = pSkip; + } + + if (NULL != pSkip) { + pSkip = pSkip->pNext; + } + TEST(NULL != pSkip); + if (NULL != pSkip) { + TEST(pSuite == pSkip->pSuite); + TEST(pTest3 == pSkip->pTest); + TEST(NULL != pSkip->strReason); + TEST(!strcmp("skip-if reason", pSkip->strReason)); + TEST(pPrevSkip == pSkip->pPrev); + TEST(NULL != pSkip->pNext); + pPrevSkip = pSkip; + } + + if (NULL != pSkip) { + pSkip = pSkip->pNext; + } + TEST(NULL != pSkip); + if (NULL != pSkip) { + TEST(pSuite == pSkip->pSuite); + TEST(pTest6 == pSkip->pTest); + TEST(NULL == pSkip->strReason); + TEST(pPrevSkip == pSkip->pPrev); + TEST(NULL != pSkip->pNext); + pPrevSkip = pSkip; + } + + if (NULL != pSkip) { + pSkip = pSkip->pNext; + } + TEST(NULL != pSkip); + if (NULL != pSkip) { + TEST(pSuite == pSkip->pSuite); + TEST(pTest7 == pSkip->pTest); + TEST(NULL != pSkip->strReason); + if (NULL != pSkip->strReason) { + TEST('\0' == pSkip->strReason[0]); + } + TEST(pPrevSkip == pSkip->pPrev); + TEST(NULL != pSkip->pNext); + pPrevSkip = pSkip; + } + + if (NULL != pSkip) { + pSkip = pSkip->pNext; + } + TEST(NULL != pSkip); + if (NULL != pSkip) { + TEST(pSuite == pSkip->pSuite); + TEST(pTest8 == pSkip->pTest); + TEST(NULL != pSkip->strReason); + TEST(!strcmp("first skip reason", pSkip->strReason)); + TEST(pPrevSkip == pSkip->pPrev); + TEST(NULL == pSkip->pNext); + } + + TEST(CUE_SUCCESS == CU_run_test(pSuite, pTest5)); + TEST(1 == CU_get_number_of_tests_selected()); + TEST(1 == CU_get_number_of_tests_run()); + TEST(0 == CU_get_number_of_tests_skipped()); + TEST(1 == CU_get_number_of_tests_failed()); + TEST(NULL == CU_get_skip_list()); + + f_expected_skip_record_suite = pSuite; + f_expected_skip_record_test = pTest2; + f_expected_skip_record_reason = "dynamic skip reason 42"; + f_nSkipRecordHandlerCalls = 0; + CU_set_test_complete_handler(skip_record_test_complete_handler); + TEST(CUE_SUCCESS == CU_run_test(pSuite, pTest2)); + TEST(1 == f_nSkipRecordHandlerCalls); + TEST(1 == CU_get_number_of_tests_skipped()); + CU_set_test_complete_handler(NULL); + f_expected_skip_record_suite = NULL; + f_expected_skip_record_test = NULL; + f_expected_skip_record_reason = NULL; + + pTeardownSuite = CU_add_suite_with_setup_and_teardown("skip_teardown_fail_suite", + NULL, + NULL, + NULL, + suite_teardown_fail); + pTeardownTest = CU_add_test(pTeardownSuite, "skip_then_teardown_fails", test_skip_static); + TEST_FATAL(CUE_SUCCESS == CU_get_error()); + TEST(CUE_SUCCESS == CU_run_test(pTeardownSuite, pTeardownTest)); + TEST(1 == CU_get_number_of_tests_selected()); + TEST(1 == CU_get_number_of_tests_run()); + TEST(0 == CU_get_number_of_tests_skipped()); + TEST(1 == CU_get_number_of_tests_failed()); + TEST(1 == CU_get_number_of_asserts()); + TEST(1 == CU_get_number_of_failures()); + TEST(1 == CU_get_number_of_failure_records()); + TEST(NULL == CU_get_skip_list()); + + CU_cleanup_registry(); +} + static CU_BOOL f_exit_called = CU_FALSE; /* intercept exit for testing of CUEA_ABORT action */ @@ -2164,20 +2629,20 @@ static void test_CU_fail_on_inactive(void) CU_set_suite_active(pSuite2, CU_FALSE); CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_all_tests()); /* all suites inactive */ - test_results(0,0,2,0,0,0,0,0,0,2); + test_results(0,0,2,0,0,4,0,0,0,2); CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SUCCESS == CU_run_all_tests()); - test_results(0,0,2,0,0,0,0,0,0,0); + test_results(0,0,2,0,0,4,0,0,0,0); CU_set_suite_active(pSuite1, CU_TRUE); CU_set_suite_active(pSuite2, CU_TRUE); CU_set_suite_active(pSuite2, CU_FALSE); CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_all_tests()); /* some suites inactive */ - test_results(1,0,1,2,1,0,2,1,1,2); + test_results(1,0,1,2,1,2,2,1,1,2); CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SUCCESS == CU_run_all_tests()); - test_results(1,0,1,2,1,0,2,1,1,1); + test_results(1,0,1,2,1,2,2,1,1,1); CU_set_suite_active(pSuite2, CU_TRUE); CU_set_test_active(pTest1, CU_FALSE); @@ -2210,10 +2675,10 @@ static void test_CU_fail_on_inactive(void) CU_set_test_active(pTest1, CU_FALSE); CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_TEST_INACTIVE == CU_run_all_tests()); /* some suites & tests inactive */ - test_results(1,0,1,1,1,1,1,0,1,3); + test_results(1,0,1,1,1,3,1,0,1,3); CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SUCCESS == CU_run_all_tests()); - test_results(1,0,1,1,1,1,1,0,1,1); + test_results(1,0,1,1,1,3,1,0,1,1); CU_set_suite_active(pSuite2, CU_TRUE); CU_set_test_active(pTest1, CU_TRUE); @@ -2300,10 +2765,10 @@ static void test_CU_run_all_tests(void) CU_set_suite_active(pSuite4, CU_FALSE); CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SUCCESS == CU_run_all_tests()); /* suites inactive */ - test_results(0,0,4,0,0,0,0,0,0,0); + test_results(0,0,4,0,0,10,0,0,0,0); CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_all_tests()); - test_results(0,0,4,0,0,0,0,0,0,4); + test_results(0,0,4,0,0,10,0,0,0,4); CU_set_suite_active(pSuite1, CU_FALSE); CU_set_suite_active(pSuite2, CU_TRUE); @@ -2311,10 +2776,10 @@ static void test_CU_run_all_tests(void) CU_set_suite_active(pSuite4, CU_FALSE); CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SINIT_FAILED == CU_run_all_tests()); /* some suites inactive */ - test_results(1,1,2,2,1,0,2,1,1,2); + test_results(1,1,2,2,1,6,2,1,1,2); CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_all_tests()); - test_results(1,1,2,2,1,0,2,1,1,4); + test_results(1,1,2,2,1,6,2,1,1,4); CU_set_suite_active(pSuite1, CU_TRUE); CU_set_suite_active(pSuite2, CU_TRUE); @@ -2396,10 +2861,10 @@ static void test_CU_run_all_tests(void) CU_set_suite_active(pSuite4, CU_TRUE); CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SCLEAN_FAILED == CU_run_all_tests()); /* some suites inactive */ - test_results(2,1,2,6,2,0,6,4,2,3); + test_results(2,1,2,6,2,4,6,4,2,3); CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_all_tests()); - test_results(1,0,1,5,2,0,5,3,2,3); + test_results(1,0,1,5,2,2,5,3,2,3); CU_set_suite_active(pSuite1, CU_TRUE); CU_set_suite_active(pSuite2, CU_TRUE); @@ -2493,12 +2958,12 @@ static void test_CU_run_all_tests(void) CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SUCCESS == CU_run_all_tests()); /* no suites active, so no abort() */ TEST(CU_FALSE == f_exit_called); - test_results(0,0,4,0,0,0,0,0,0,0); + test_results(0,0,4,0,0,10,0,0,0,0); f_exit_called = CU_FALSE; CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_all_tests()); TEST(CU_TRUE == f_exit_called); - test_results(0,0,1,0,0,0,0,0,0,1); + test_results(0,0,1,0,0,5,0,0,0,1); CU_set_suite_active(pSuite1, CU_TRUE); CU_set_suite_active(pSuite2, CU_FALSE); @@ -2508,12 +2973,12 @@ static void test_CU_run_all_tests(void) CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SCLEAN_FAILED == CU_run_all_tests()); /* some suites active */ TEST(CU_TRUE == f_exit_called); - test_results(3,1,1,8,3,0,8,5,3,4); + test_results(3,1,1,8,3,2,8,5,3,4); f_exit_called = CU_FALSE; CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_all_tests()); TEST(CU_TRUE == f_exit_called); - test_results(1,0,1,5,2,0,5,3,2,3); + test_results(1,0,1,5,2,2,5,3,2,3); CU_set_suite_active(pSuite1, CU_TRUE); CU_set_suite_active(pSuite2, CU_TRUE); @@ -2696,10 +3161,10 @@ static void test_CU_run_suite(void) CU_set_suite_active(pSuite3, CU_FALSE); CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SUCCESS == CU_run_suite(pSuite3)); /* suite inactive */ - test_results(0,0,1,0,0,0,0,0,0,0); + test_results(0,0,1,0,0,2,0,0,0,0); CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_suite(pSuite3)); - test_results(0,0,1,0,0,0,0,0,0,1); + test_results(0,0,1,0,0,2,0,0,0,1); CU_set_suite_active(pSuite3, CU_TRUE); CU_set_test_active(pTest1, CU_FALSE); @@ -2765,10 +3230,10 @@ static void test_CU_run_suite(void) CU_set_suite_active(pSuite1, CU_FALSE); CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SUCCESS == CU_run_suite(pSuite1)); /* suite inactive */ - test_results(0,0,1,0,0,0,0,0,0,0); + test_results(0,0,1,0,0,5,0,0,0,0); CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_suite(pSuite1)); - test_results(0,0,1,0,0,0,0,0,0,1); + test_results(0,0,1,0,0,5,0,0,0,1); CU_set_suite_active(pSuite1, CU_TRUE); CU_set_test_active(pTest8, CU_FALSE); @@ -2836,12 +3301,12 @@ static void test_CU_run_suite(void) CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SUCCESS == CU_run_suite(pSuite2)); /* suite inactive, but not a failure */ TEST(CU_FALSE == f_exit_called); - test_results(0,0,1,0,0,0,0,0,0,0); + test_results(0,0,1,0,0,2,0,0,0,0); f_exit_called = CU_FALSE; CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_suite(pSuite2)); TEST(CU_TRUE == f_exit_called); - test_results(0,0,1,0,0,0,0,0,0,1); + test_results(0,0,1,0,0,2,0,0,0,1); CU_set_suite_active(pSuite2, CU_TRUE); CU_set_test_active(pTest8, CU_FALSE); @@ -3026,10 +3491,10 @@ static void test_CU_run_test(void) CU_set_suite_active(pSuite1, CU_FALSE); CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SUITE_INACTIVE == CU_run_test(pSuite1, pTest1)); /* suite inactive */ - test_results(0,0,1,0,0,0,0,0,0,0); + test_results(0,0,1,0,0,1,0,0,0,0); CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_test(pSuite1, pTest1)); - test_results(0,0,1,0,0,0,0,0,0,1); + test_results(0,0,1,0,0,1,0,0,0,1); CU_set_suite_active(pSuite1, CU_TRUE); CU_set_test_active(pTest1, CU_FALSE); @@ -3089,10 +3554,10 @@ static void test_CU_run_test(void) CU_set_suite_active(pSuite2, CU_FALSE); CU_set_fail_on_inactive(CU_FALSE); TEST(CUE_SUITE_INACTIVE == CU_run_test(pSuite2, pTest7)); /* suite inactive */ - test_results(0,0,1,0,0,0,0,0,0,0); + test_results(0,0,1,0,0,1,0,0,0,0); CU_set_fail_on_inactive(CU_TRUE); TEST(CUE_SUITE_INACTIVE == CU_run_test(pSuite2, pTest7)); - test_results(0,0,1,0,0,0,0,0,0,1); + test_results(0,0,1,0,0,1,0,0,0,1); CU_set_suite_active(pSuite2, CU_TRUE); CU_set_test_active(pTest7, CU_FALSE); @@ -3172,12 +3637,12 @@ static void test_CU_run_test(void) f_exit_called = CU_FALSE; TEST(CUE_SUITE_INACTIVE == CU_run_test(pSuite2, pTest6)); /* suite inactive */ TEST(CU_TRUE == f_exit_called); - test_results(0,0,1,0,0,0,0,0,0,0); + test_results(0,0,1,0,0,1,0,0,0,0); CU_set_fail_on_inactive(CU_TRUE); f_exit_called = CU_FALSE; TEST(CUE_SUITE_INACTIVE == CU_run_test(pSuite2, pTest6)); TEST(CU_TRUE == f_exit_called); - test_results(0,0,1,0,0,0,0,0,0,1); + test_results(0,0,1,0,0,1,0,0,0,1); CU_set_suite_active(pSuite2, CU_TRUE); CU_set_test_active(pTest6, CU_FALSE); @@ -3350,7 +3815,7 @@ static void test_add_failure(void) CU_pFailureRecord pFailure2 = NULL; CU_pFailureRecord pFailure3 = NULL; CU_pFailureRecord pFailure4 = NULL; - CU_RunSummary run_summary = {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + CU_RunSummary run_summary = {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* test under memory exhaustion */ test_cunit_deactivate_malloc(); @@ -3420,6 +3885,7 @@ void test_cunit_TestRun(void) test_cunit_start_tests("TestRun.c"); test_message_handlers(); + test_CU_skip(); test_CU_fail_on_inactive(); test_CU_run_all_tests(); test_CU_run_suite(); diff --git a/CUnit/Sources/Makefile.am b/CUnit/Sources/Makefile.am index e540f28..03d2b7c 100644 --- a/CUnit/Sources/Makefile.am +++ b/CUnit/Sources/Makefile.am @@ -63,6 +63,10 @@ TEST_OBJECTS = $(TEST_OBJECT_FILES) SUBDIRS = $(COMPILE_DIRS) +EXTRA_DIST = \ + Win/Win.c \ + Win/Win.h \ + Win/resource.h lib_LTLIBRARIES = libcunit.la libcunit_la_SOURCES = @@ -70,7 +74,7 @@ libcunit_la_LIBADD = $(OBJECT_FILES_SHARED) if ENABLE_CURSES libcunit_la_LIBADD += -l$(CURSES_LIB) endif -libcunit_la_LDFLAGS = -version-info @LIBTOOL_CURRENT@:@LIBTOOL_REVISION@:@LIBTOOL_AGE@ +libcunit_la_LDFLAGS = -version-info @LIBTOOL_CURRENT@:@LIBTOOL_REVISION@:@LIBTOOL_AGE@ -no-undefined if ENABLE_TEST diff --git a/CUnit/Sources/Makefile.in b/CUnit/Sources/Makefile.in index 387d1bf..48598e8 100644 --- a/CUnit/Sources/Makefile.in +++ b/CUnit/Sources/Makefile.in @@ -274,6 +274,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ @@ -434,10 +435,15 @@ OBJECT_FILES_SHARED = \ TEST_OBJECTS = $(TEST_OBJECT_FILES) SUBDIRS = $(COMPILE_DIRS) +EXTRA_DIST = \ + Win/Win.c \ + Win/Win.h \ + Win/resource.h + lib_LTLIBRARIES = libcunit.la libcunit_la_SOURCES = libcunit_la_LIBADD = $(OBJECT_FILES_SHARED) $(am__append_1) -libcunit_la_LDFLAGS = -version-info @LIBTOOL_CURRENT@:@LIBTOOL_REVISION@:@LIBTOOL_AGE@ +libcunit_la_LDFLAGS = -version-info @LIBTOOL_CURRENT@:@LIBTOOL_REVISION@:@LIBTOOL_AGE@ -no-undefined @ENABLE_TEST_TRUE@noinst_LIBRARIES = libcunit_test.a @ENABLE_TEST_TRUE@libcunit_test_a_SOURCES = @ENABLE_TEST_TRUE@libcunit_test_a_LIBADD = $(TEST_OBJECTS) diff --git a/CUnit/Sources/Test/Makefile.am b/CUnit/Sources/Test/Makefile.am index ccf28ce..622bd2e 100644 --- a/CUnit/Sources/Test/Makefile.am +++ b/CUnit/Sources/Test/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/CUnit/Headers testdir=${datadir}/@PACKAGE@/Test test_PROGRAMS = test_cunit -test_cunit_SOURCES = test_cunit.c +test_cunit_SOURCES = test_cunit.c test_cunit.h test_cunit_LDADD = ../libcunit_test.a test_cunit_LDFLAGS = -L.. diff --git a/CUnit/Sources/Test/Makefile.in b/CUnit/Sources/Test/Makefile.in index fcc179a..16efea3 100644 --- a/CUnit/Sources/Test/Makefile.in +++ b/CUnit/Sources/Test/Makefile.in @@ -101,7 +101,7 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(testdir)" PROGRAMS = $(test_PROGRAMS) -am__test_cunit_SOURCES_DIST = test_cunit.c +am__test_cunit_SOURCES_DIST = test_cunit.c test_cunit.h @ENABLE_TEST_TRUE@am_test_cunit_OBJECTS = test_cunit.$(OBJEXT) test_cunit_OBJECTS = $(am_test_cunit_OBJECTS) @ENABLE_TEST_TRUE@test_cunit_DEPENDENCIES = ../libcunit_test.a @@ -197,6 +197,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ @@ -312,7 +313,7 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @ENABLE_TEST_TRUE@AM_CPPFLAGS = -I$(top_srcdir)/CUnit/Headers @ENABLE_TEST_TRUE@testdir = ${datadir}/@PACKAGE@/Test -@ENABLE_TEST_TRUE@test_cunit_SOURCES = test_cunit.c +@ENABLE_TEST_TRUE@test_cunit_SOURCES = test_cunit.c test_cunit.h @ENABLE_TEST_TRUE@test_cunit_LDADD = ../libcunit_test.a @ENABLE_TEST_TRUE@test_cunit_LDFLAGS = -L.. @ENABLE_TEST_TRUE@INCLUDES = -DMEMTRACE -DCUNIT_BUILD_TESTS -DCUNIT_DO_NOT_DEFINE_UNLESS_BUILDING_TESTS diff --git a/Examples/AutomatedTest/Makefile.in b/Examples/AutomatedTest/Makefile.in index 26cc6f8..2aef945 100644 --- a/Examples/AutomatedTest/Makefile.in +++ b/Examples/AutomatedTest/Makefile.in @@ -228,6 +228,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/Examples/BasicTest/Makefile.in b/Examples/BasicTest/Makefile.in index 56d583d..2da7d15 100644 --- a/Examples/BasicTest/Makefile.in +++ b/Examples/BasicTest/Makefile.in @@ -230,6 +230,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/Examples/ConsoleTest/Makefile.in b/Examples/ConsoleTest/Makefile.in index b176d63..bedd07a 100644 --- a/Examples/ConsoleTest/Makefile.in +++ b/Examples/ConsoleTest/Makefile.in @@ -228,6 +228,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/Examples/CursesTest/Makefile.in b/Examples/CursesTest/Makefile.in index bd85ed2..c786341 100644 --- a/Examples/CursesTest/Makefile.in +++ b/Examples/CursesTest/Makefile.in @@ -227,6 +227,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/Examples/Makefile.in b/Examples/Makefile.in index 1edcb79..4bad7a7 100644 --- a/Examples/Makefile.in +++ b/Examples/Makefile.in @@ -241,6 +241,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/Makefile.am b/Makefile.am index c4efde4..d9b6e40 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,7 @@ ## Process this file with automake to produce Makefile.in +AUTOMAKE_OPTIONS = foreign + COMPILE_DIRS = CUnit doc Man Share if ENABLE_EXAMPLES @@ -10,7 +12,7 @@ COMPILE_DIRS += $(EXAMPLE_COMPILE_DIR) SUBDIRS = ${COMPILE_DIRS} -DIST_BASENAME=cunit-@VERSION@-@RELEASE@ +DIST_BASENAME=cunit-@DIST_VERSION@ distdir=${DIST_BASENAME} WD=`pwd` @@ -34,7 +36,7 @@ RPM_I686=./RPMS/i686/@PACKAGE@-@VERSION@-@RELEASE@.i686.rpm RPM_K6=./RPMS/athlon/@PACKAGE@-@VERSION@-@RELEASE@.k6.rpm RPM_SRC=./SRPMS/@PACKAGE@-@VERSION@-@RELEASE@.src.rpm -EXTRA_DIST=cunit.pc.in +EXTRA_DIST=VERSION README.md bootstrap cunit.pc.in EXTRA_REMOVE=CUnit-Memory-Dump.lst ${SOURCE_GZIP_FILE} \ *.rpm *.o *.ncb *.plg *.opt *.clw *.ilk *.exe *.pdb *.lib @@ -52,13 +54,14 @@ distclean-all: distclean rm -f ${SOURCE_GZIP_FILE} *.rpm rm -rf ${RPMDIRS} -# Release archives are generated with `git archive` in CI and release tooling. +# Release archives are generated with Automake's `make dist`/`make distcheck` +# in CI and release tooling. # The legacy RPM target is left here commented out for review. # # rpm: rpm-package # # rpm-package: -# # Expects ${SOURCE_GZIP_FILE} from a prior `git archive` step. +# # Expects ${SOURCE_GZIP_FILE} from a prior `make dist` step. # rm -rf ${RPMDIRS} && \ # mkdir -p ${RPMDIRS} && \ # cp ${SPECFILE} ${PACKAGE_TMPSPEC} && \ diff --git a/Man/Makefile.in b/Man/Makefile.in index a3e46a0..07a7f23 100644 --- a/Man/Makefile.in +++ b/Man/Makefile.in @@ -201,6 +201,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ diff --git a/Man/man3/CUnit.3 b/Man/man3/CUnit.3 index 6ea4e6d..b1d241f 100644 --- a/Man/man3/CUnit.3 +++ b/Man/man3/CUnit.3 @@ -271,6 +271,16 @@ Register a success without performing a logical test. Register a failure without performing a logical test. .RE +.P +.B CU_SKIP(reason) +.br +.B CU_SKIP_IF(condition, reason) +.RS 5 +Record the current test as skipped and return from the test function. The +framework copies the reason string for later reporting. If the test has +already recorded a failure, the test remains failed rather than skipped. +.RE + .SH "THE TEST REGISTRY" The test registry is the repository for suites and associated tests. The user normally only needs to initialize the registry before use and @@ -574,30 +584,51 @@ details and results for the user. For more about the primitive functions, see .SS "Test Results" The interfaces present results of test runs, but client code may sometimes need to access the results directly. These results include various run counts, as -well as a linked list of failure records holding the failure details. Test -results must be retrieved before attempting to run other tests, which +well as linked lists of failure and skip records holding the failure and skip +details. Test results must be retrieved before attempting to run other tests, which resets the result information. Functions for accessing the test results are: .P .B #include (included automatically by ) .TP 5 -.B "unsigned int CU_get_number_of_suites_run(void)' +.B "unsigned int CU_get_number_of_suites_run(void)" Retrieve the number of suites run. Suite having initialization functions which fail are not run. To get the total number of registered suites, use .B "CU_get_registry()->uiNumberOfSuites." .TP 5 +.B "unsigned int CU_get_number_of_suites_selected(void)" +Retrieve the number of suites selected by the last run operation before +activation checks were applied. +.TP 5 .B "unsigned int CU_get_number_of_suites_failed(void)" -Retrieve the number of suites which had initialization or cleanup -functions which failed (returned non-NULL). +Retrieve the number of suites which had initialization or cleanup functions +which failed, or inactive suites treated as failures. +.TP 5 +.B "unsigned int CU_get_number_of_suites_inactive(void)" +Retrieve the number of selected suites which were inactive. .TP 5 .B "unsigned int CU_get_number_of_tests_run(void)" -Retrieve the number of tests run. Tests in suites having initialization -functions which fail are not run. To get the total number of registered tests -, use +Retrieve the number of selected active tests entered during the run. Tests in +suites having initialization functions which fail are not run. To get the total +number of registered tests, use .B "CU_get_registry()->uiNumberOfTests." .TP 5 +.B "unsigned int CU_get_number_of_tests_selected(void)" +Retrieve the number of tests selected by the last run operation before +activation checks were applied. +.TP 5 .B "unsigned int CU_get_number_of_tests_failed(void)" -Retrieve the number of tests which contained at least 1 failed assertion. +Retrieve the number of tests which failed during the run. +.TP 5 +.B "unsigned int CU_get_number_of_tests_skipped(void)" +Retrieve the number of selected active tests which self-skipped with +.B CU_SKIP +or +.B CU_SKIP_IF +before recording any failure. Skipped tests are counted as run. +.TP 5 +.B "unsigned int CU_get_number_of_tests_inactive(void)" +Retrieve the number of selected tests which were inactive. .TP 5 .B "unsigned int CU_get_number_of_asserts(void)" Retrieve the number of CUnit assertions made during the test run. @@ -608,7 +639,7 @@ Retrieve the number of assertions which passed. .B "unsigned int CU_get_number_of_failures(void)" Retrieve the number of assertions which failed. .TP 5 -.B "const CU_pRunSummary CU_get_run_summary(void)" +.B "CU_pRunSummary CU_get_run_summary(void)" Retrieve a .B CU_RunSummary containing all the run count information. This data structure is @@ -617,9 +648,11 @@ declared in and includes the (self-explanatory) .I "unsigned int" fields nSuitesRun, nSuitesFailed, nTestsRun, nTestsFailed, nAsserts, -and nAssertsFailed. +and nAssertsFailed, plus PackageName, nSuitesInactive, nTestsInactive, +nFailureRecords, ElapsedTime, nSuitesSelected, nTestsSelected, and +nTestsSkipped. .TP 5 -.B "const CU_pFailureRecord CU_get_failure_list(void)" +.B "CU_pFailureRecord CU_get_failure_list(void)" Retrieve the head of the linked list of failure records for the last run. Each assertion failure or suite init/cleanup function failure is registered in a new @@ -639,6 +672,35 @@ and includes the following fields: .br .B "CU_pSuite pSuite" .RE +.TP 5 +.B "CU_pSkipRecord CU_get_skip_list(void)" +Retrieve the head of the linked list of skip records for the last run. +The list contains tests which called +.B CU_SKIP +or +.B CU_SKIP_IF +and did not record a failure. Each skip record is a +.B CU_SkipRecord +declared in +.B +and includes the following fields: +.br +.RS 10 +.B "unsigned int uiLineNumber" +.br +.B "char* strFileName" +.br +.B "char* strReason" +.br +.B "CU_pTest pTest" +.br +.B "CU_pSuite pSuite" +.RE +.TP 5 +.B "CU_pSkipRecord CU_get_current_test_skip_record(void)" +Retrieve the skip record for the currently completing test, or NULL if the +current test did not self-skip. This is intended for use from a test-complete +message handler. .SS "Automated Interface" The automated interface is non-interactive. The current implementation only @@ -818,4 +880,3 @@ Jerry St.Clair .SH WEBSITE http://cunit.sourceforge.net - diff --git a/Man/man3/Makefile.am b/Man/man3/Makefile.am index 6b40d97..2bd8c29 100644 --- a/Man/man3/Makefile.am +++ b/Man/man3/Makefile.am @@ -1,4 +1,4 @@ ## Process this file with automake to produce Makefile.in -man_MANS = \ +dist_man_MANS = \ CUnit.3 diff --git a/Man/man3/Makefile.in b/Man/man3/Makefile.in index 7ea0b29..3028310 100644 --- a/Man/man3/Makefile.in +++ b/Man/man3/Makefile.in @@ -146,9 +146,9 @@ am__uninstall_files_from_dir = { \ man3dir = $(mandir)/man3 am__installdirs = "$(DESTDIR)$(man3dir)" NROFF = nroff -MANS = $(man_MANS) +MANS = $(dist_man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -am__DIST_COMMON = $(srcdir)/Makefile.in +am__DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ @@ -174,6 +174,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ @@ -287,7 +288,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -man_MANS = \ +dist_man_MANS = \ CUnit.3 all: all-am @@ -328,10 +329,10 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs -install-man3: $(man_MANS) +install-man3: $(dist_man_MANS) @$(NORMAL_INSTALL) @list1=''; \ - list2='$(man_MANS)'; \ + list2='$(dist_man_MANS)'; \ test -n "$(man3dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ @@ -366,7 +367,7 @@ uninstall-man3: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man3dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ - l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.3[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ diff --git a/NEWS b/NEWS index 8b5a8b2..cebcbb8 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1,6 @@ -The latest release for this package can be download from the projects +The latest release for this package can be downloaded from the project's home page located at http://www.sourceforge.net/projects/cunit/ . + +Runtime test skipping is supported with CU_SKIP(reason) and +CU_SKIP_IF(condition, reason). Skip reasons are copied by the framework and +reported separately from inactive tests. diff --git a/README.md b/README.md index 1155da0..1569fba 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,11 @@ conventional structure of test cases bundled into suites which are registered with the framework for running. See the documentation for more about the structure and use of the framework. +Tests can self-skip at runtime with `CU_SKIP(reason)` or +`CU_SKIP_IF(condition, reason)`. Skip reasons are copied by the framework and +reported separately from inactive tests; if a test has already recorded a +failure, it remains failed rather than skipped. + Note: the Windows-specific GUI interface is not yet written. It is still necessary to use either the automated, basic, or console interfaces to CUnit on Windows at this time. @@ -110,6 +115,27 @@ dots, for example `v2.1.3`. If the tag, `VERSION`, and `packaging/msys2/PKGBUILD` version fields do not all match, the release workflow fails before publishing any assets. +For ordinary branch and pull-request work, use the normal build workflows: + +- `CUnit Ubuntu Build` builds from a git checkout on supported Ubuntu runners, + runs the internal self-tests, installs the library, and reports coverage. +- `CUnit MSYS2 Build` builds from a git checkout on MSYS2 UCRT64, runs the + internal self-tests, installs the library, and smoke-tests the installed + `pkgconf` metadata. + +These workflows are checkout builds. They do not validate release tarball +packaging. + +To dry-run the release build without publishing a GitHub release, manually run +the `CUnit Release` workflow from GitHub Actions on the release branch. The +optional `release_tag` input should match the normalized `VERSION` value, such +as `v2.1.3`; if omitted, the workflow derives the expected tag from `VERSION`. +The release workflow builds one source tarball on Ubuntu with Automake +`make distcheck`, then tests that same tarball on Ubuntu, Rocky 8, and MSYS2 +UCRT64. The MSYS2 job builds its package from that tarball, installs the +package, and runs the smoke test. A dry run uploads workflow artifacts only. +The final GitHub release is created only for a pushed `v*` tag. + To publish a release: 1. Update `VERSION` and the packaging metadata. @@ -118,6 +144,7 @@ To publish a release: The release workflow publishes both a source tarball and the MSYS2 UCRT64 `.pkg.tar.zst` package for the tagged commit. The source tarball is named -`cunit-.tar.gz` and extracts into `cunit-/`. Release -tarballs are generated with `git archive`; the old manual `make tarball` -path is intentionally disabled. +`cunit-.tar.gz`, extracts into `cunit-/`, and is generated +with Automake `make distcheck`, so it includes `configure` and the generated +`Makefile.in` files. Building directly from a git checkout still requires +`./bootstrap` before `./configure`. diff --git a/Share/CUnit-Run.dtd b/Share/CUnit-Run.dtd index 580c556..00b8dc9 100644 --- a/Share/CUnit-Run.dtd +++ b/Share/CUnit-Run.dtd @@ -18,20 +18,23 @@ - + + - + + + diff --git a/Share/CUnit-Run.xsl b/Share/CUnit-Run.xsl index 7000dc4..dc262f1 100644 --- a/Share/CUnit-Run.xsl +++ b/Share/CUnit-Run.xsl @@ -86,10 +86,17 @@ - Skipping test ... + Skipping test ... Skipped + + + + + + + @@ -151,23 +158,27 @@

- + - - - - - - + + + + + + + + + + diff --git a/Share/Makefile.am b/Share/Makefile.am index 9366ee4..c07309c 100644 --- a/Share/Makefile.am +++ b/Share/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -pkgdata_DATA = \ +dist_pkgdata_DATA = \ CUnit-List.dtd \ CUnit-List.xsl \ CUnit-Run.dtd \ diff --git a/Share/Makefile.in b/Share/Makefile.in index 7c1f7c3..ef58fda 100644 --- a/Share/Makefile.in +++ b/Share/Makefile.in @@ -93,7 +93,8 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +DIST_COMMON = $(srcdir)/Makefile.am $(dist_pkgdata_DATA) \ + $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = @@ -145,7 +146,7 @@ am__uninstall_files_from_dir = { \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(pkgdatadir)" -DATA = $(pkgdata_DATA) +DATA = $(dist_pkgdata_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -173,6 +174,7 @@ CURSES_LIB = @CURSES_LIB@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DIST_VERSION = @DIST_VERSION@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ @@ -286,7 +288,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -pkgdata_DATA = \ +dist_pkgdata_DATA = \ CUnit-List.dtd \ CUnit-List.xsl \ CUnit-Run.dtd \ @@ -332,9 +334,9 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs -install-pkgdataDATA: $(pkgdata_DATA) +install-dist_pkgdataDATA: $(dist_pkgdata_DATA) @$(NORMAL_INSTALL) - @list='$(pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ + @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \ @@ -348,9 +350,9 @@ install-pkgdataDATA: $(pkgdata_DATA) $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \ done -uninstall-pkgdataDATA: +uninstall-dist_pkgdataDATA: @$(NORMAL_UNINSTALL) - @list='$(pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ + @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir) tags TAGS: @@ -449,7 +451,7 @@ info: info-am info-am: -install-data-am: install-pkgdataDATA +install-data-am: install-dist_pkgdataDATA install-dvi: install-dvi-am @@ -493,21 +495,22 @@ ps: ps-am ps-am: -uninstall-am: uninstall-pkgdataDATA +uninstall-am: uninstall-dist_pkgdataDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-pkgdataDATA install-ps \ - install-ps-am install-strip installcheck installcheck-am \ - installdirs maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ - ps ps-am tags-am uninstall uninstall-am uninstall-pkgdataDATA + install install-am install-data install-data-am \ + install-dist_pkgdataDATA install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ + uninstall-am uninstall-dist_pkgdataDATA .PRECIOUS: Makefile diff --git a/VERSION b/VERSION index f2bc758..9030a97 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2-4 +2.3-0 diff --git a/configure.in b/configure.in index ef738b6..d4dbe4c 100644 --- a/configure.in +++ b/configure.in @@ -1,14 +1,25 @@ dnl Applied patch to handle AC_ARG_ENABLE targets (Patch 1250604) - Provided by Andrew Kephart 5.1. Synopsis (included automatically by <CUnit/CUnit.h>)
   unsigned int CU_get_number_of_suites_run(void)
+  unsigned int CU_get_number_of_suites_selected(void)
   unsigned int CU_get_number_of_suites_failed(void)
+  unsigned int CU_get_number_of_suites_inactive(void)
   unsigned int CU_get_number_of_tests_run(void)
+  unsigned int CU_get_number_of_tests_selected(void)
   unsigned int CU_get_number_of_tests_failed(void)
+  unsigned int CU_get_number_of_tests_skipped(void)
+  unsigned int CU_get_number_of_tests_inactive(void)
   unsigned int CU_get_number_of_asserts(void)
   unsigned int CU_get_number_of_successes(void)
   unsigned int CU_get_number_of_failures(void)
 
   typedef struct CU_RunSummary
-  typedef CU_Runsummary* CU_pRunSummary
-  const CU_pRunSummary CU_get_run_summary(void)
+  typedef CU_RunSummary* CU_pRunSummary
+  CU_pRunSummary CU_get_run_summary(void)
 
   typedef struct CU_FailureRecord
   typedef CU_FailureRecord*  CU_pFailureRecord
-  const CU_pFailureRecord CU_get_failure_list(void)
+  CU_pFailureRecord CU_get_failure_list(void)
   unsigned int CU_get_number_of_failure_records(void)
 
+  typedef struct CU_SkipRecord
+  typedef CU_SkipRecord*  CU_pSkipRecord
+  CU_pSkipRecord CU_get_skip_list(void)
+  CU_pSkipRecord CU_get_current_test_skip_record(void)
+
   void CU_set_fail_on_inactive(CU_BOOL new_inactive)
   CU_BOOL CU_get_fail_on_inactive(void)
 
@@ -80,7 +90,8 @@

5.1. Synopsis

5.2. Running Tests in CUnit

CUnit supports running all tests in all registered suites, but individual tests or suites can also be run. During each run, the framework keeps track of the -number of suites, tests, and assertions run, passed, and failed. Note that the +number of suites and tests selected, run, skipped, inactive, passed, and failed, +as well as the number of assertions passed and failed. Note that the previous results are cleared each time a test run is initiated (even if it fails). Individual suites or tests can be deactivated if the client wishes to exclude them from a particular test run. However, it is @@ -262,7 +273,8 @@

5.7. Modifying General Runtime Behavior

5.8. Getting Test Results

The interfaces present results of test runs, but client code may sometimes need to access the results directly. These results include various run counts, as -well as a linked list of failure records holding the failure details. Note that +well as linked lists of failure and skip records holding the failure and skip +details. Note that test results are overwritten each time a new test run is started, or when the registry is initialized or cleaned up. @@ -271,29 +283,38 @@

5.8. Getting Test Results

unsigned int CU_get_number_of_suites_run(void)
+ unsigned int CU_get_number_of_suites_selected(void)
unsigned int CU_get_number_of_suites_failed(void)
+ unsigned int CU_get_number_of_suites_inactive(void)
unsigned int CU_get_number_of_tests_run(void)
+ unsigned int CU_get_number_of_tests_selected(void)
unsigned int CU_get_number_of_tests_failed(void)
+ unsigned int CU_get_number_of_tests_skipped(void)
+ unsigned int CU_get_number_of_tests_inactive(void)
unsigned int CU_get_number_of_asserts(void)
unsigned int CU_get_number_of_successes(void)
unsigned int CU_get_number_of_failures(void)

These functions report the number of suites, tests, and -assertions that ran or failed during the last run. A suite is considered failed -if its initialization or cleanup function returned non-NULL, or if -it was inactive and the framework was set to treat -inactive suites/tests as failures. A test fails if any of its assertions -failed or if it was inactive under the same conditions. The last 3 functions -all refer to individual assertions. An inactive suite (or test) is not counted -among the number of suites (tests) run. A consequence of this is that a suite -(or test) can fail even though it is not reported as having been run. +assertions selected, run, skipped, inactive, or failed during the last run. A +selected suite or test is one requested by the run operation before activation +checks are applied. An inactive suite or test is selected but disabled, and is +not counted as run. A skipped test is selected, active, and entered, but called +CU_SKIP or +CU_SKIP_IF before recording any failure. +A skipped test is counted as run and skipped. A suite is considered failed if +its initialization or cleanup function returned non-zero, or if it was inactive +and the framework was set to treat inactive +suites/tests as failures. A test fails if any of its assertions failed or +if it was inactive under the same conditions. The last 3 functions all refer to +individual assertions.

To retrieve the total number of registered suites and tests, use CU_get_registry()−>uiNumberOfSuites and CU_get_registry()−>uiNumberOfTests, respectively.

-

const CU_pRunSummary CU_get_run_summary(void)

+

CU_pRunSummary CU_get_run_summary(void)

Retrieves all test result counts at once. The return value is a pointer to a saved structure containing the counts. This data type is defined in <CUnit/TestRun.h> (included automatically by @@ -302,24 +323,31 @@

5.8. Getting Test Results

 typedef struct CU_RunSummary
 {
+  char PackageName[50];
   unsigned int nSuitesRun;
   unsigned int nSuitesFailed;
+  unsigned int nSuitesInactive;
   unsigned int nTestsRun;
   unsigned int nTestsFailed;
+  unsigned int nTestsInactive;
   unsigned int nAsserts;
   unsigned int nAssertsFailed;
   unsigned int nFailureRecords;
+  double       ElapsedTime;
+  unsigned int nSuitesSelected;
+  unsigned int nTestsSelected;
+  unsigned int nTestsSkipped;
 } CU_RunSummary;
 
 
-typedef CU_Runsummary* CU_pRunSummary;
+typedef CU_RunSummary* CU_pRunSummary;
 

The structure variable associated with the returned pointer is owned by the framework, so the user should not free or otherwise change it. Note that the pointer may be invalidated once another test run is initiated.

-

const CU_pFailureRecord CU_get_failure_list(void)

+

CU_pFailureRecord CU_get_failure_list(void)

Retrieves a linked list recording any failures occurring during the last test run (NULL for no failures). The data type of the return value is declared in <CUnit/TestRun.h> (included @@ -347,6 +375,41 @@

5.8. Getting Test Results

pointer may be invalidated once another test run is initiated.

+

+ CU_pSkipRecord CU_get_skip_list(void)
+ CU_pSkipRecord CU_get_current_test_skip_record(void) +

+

Retrieves a linked list recording any tests that self-skipped +during the last test run (NULL for no skipped tests). The current +test skip record accessor is intended for use from a test-complete message +handler while the skipped test is being reported. The data type of the return +value is declared in <CUnit/TestRun.h> +(included automatically by <CUnit/CUnit.h>). +Each skip record contains information about the location and reason for the skip: +

+
+typedef struct CU_SkipRecord
+{
+  unsigned int  uiLineNumber;
+  char*         strFileName;
+  char*         strReason;
+  CU_pTest      pTest;
+  CU_pSuite     pSuite;
+
+  struct CU_SkipRecord* pNext;
+  struct CU_SkipRecord* pPrev;
+
+} CU_SkipRecord;
+
+typedef CU_SkipRecord*  CU_pSkipRecord;
+
+

The framework copies the skip reason passed to +CU_SKIP() or CU_SKIP_IF(), so the caller may use a +dynamically generated string. The structure variable and its strings are owned +by the framework, so the user should not free or otherwise change them. Note +that the pointer may be invalidated once another test run is initiated. +

+

unsigned int CU_get_number_of_failure_records(void)

@@ -404,4 +467,3 @@

5.9. Deprecated v1 Data Types & Functions

- diff --git a/doc/writing_tests.html b/doc/writing_tests.html index 78ab660..d11bf5a 100644 --- a/doc/writing_tests.html +++ b/doc/writing_tests.html @@ -59,6 +59,14 @@

2.2. CUnit Assertions

FATAL assertion fails. The normal suite cleanup function is not affected, however, and will be run in either case.

+Tests may also mark themselves as skipped by calling CU_SKIP +or CU_SKIP_IF. These macros record a skip reason and return +from the current void test(void) function. This is useful when a +test was selected and is active, but cannot complete because a local dependency, +platform feature, or temporary precondition is missing. A skipped test is counted +as skipped only if no failure has already been recorded for that test; a test that +has failed remains failed. +

There are also special "assertions" for registering a pass or fail with the framework without performing a logical test. These are useful for testing flow @@ -253,6 +261,18 @@

2.2. CUnit Assertions

Register a failed assertion with the specified message. No logical test is performed. +
+ + +
Cumulative Summary for Run Cumulative Summary for Run
Type Total Run Succeeded Failed Inactive Type Total Selected Run Succeeded Failed Skipped Inactive
+ + CU_SKIP(reason)
+ CU_SKIP_IF(condition, reason) +
+
+ Record the current test as skipped, copy the reason string, and return from the test + function. If the test has already recorded a failure, it remains failed. +

2.3. Depecated v1 Assertions

diff --git a/libcunit_dll.def b/libcunit_dll.def index e559c4c..daf8bae 100644 --- a/libcunit_dll.def +++ b/libcunit_dll.def @@ -1,9 +1,11 @@ EXPORTS CU_add_suite +CU_add_suite_with_setup_and_teardown CU_add_test CU_assertImplementation CU_automated_run_tests CU_basic_get_mode +CU_basic_run_selected_tests CU_basic_run_suite CU_basic_run_test CU_basic_run_tests @@ -14,10 +16,13 @@ CU_clear_previous_results CU_compare_strings CU_console_run_tests CU_create_new_registry +CU_curses_run_tests CU_destroy_existing_registry +CU_dump_memory_usage CU_get_all_test_complete_handler CU_get_current_suite CU_get_current_test +CU_get_current_test_skip_record CU_get_elapsed_time CU_get_error CU_get_error_action @@ -27,11 +32,17 @@ CU_get_failure_list CU_get_number_of_asserts CU_get_number_of_failure_records CU_get_number_of_failures +CU_get_number_of_suites_inactive +CU_get_number_of_suites_selected CU_get_number_of_successes CU_get_number_of_suites_failed CU_get_number_of_suites_run +CU_get_number_of_tests_inactive +CU_get_number_of_tests_selected CU_get_number_of_tests_failed +CU_get_number_of_tests_skipped CU_get_number_of_tests_run +CU_get_skip_list CU_get_registry CU_get_run_results_string CU_get_run_summary @@ -50,17 +61,20 @@ CU_get_test_at_pos CU_get_test_by_index CU_get_test_by_name CU_get_test_complete_handler -CU_get_test_ignored_handler CU_get_test_pos CU_get_test_pos_by_name +CU_get_test_skipped_handler CU_get_test_start_handler CU_initialize_registry CU_is_test_running CU_list_tests_to_file +CU_number_width CU_print_run_results CU_register_nsuites +CU_registry_initialized CU_register_suites CU_run_all_tests +CU_run_selected_tests CU_run_suite CU_run_test CU_set_all_test_complete_handler @@ -80,11 +94,13 @@ CU_set_suite_start_handler CU_set_test_active CU_set_test_complete_handler CU_set_test_func -CU_set_test_ignored_handler CU_set_test_name +CU_set_test_output_capture +CU_set_test_skipped_handler CU_set_test_start_handler +CU_skipImplementation +CU_translated_strlen CU_translate_special_characters CU_trim CU_trim_left CU_trim_right - diff --git a/packaging/msys2/002-fix-shared.patch b/packaging/msys2/002-fix-shared.patch deleted file mode 100644 index 908cf23..0000000 --- a/packaging/msys2/002-fix-shared.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/CUnit/Sources/Makefile.am b/CUnit/Sources/Makefile.am -index d8588ce..626eff9 100644 ---- a/CUnit/Sources/Makefile.am -+++ b/CUnit/Sources/Makefile.am -@@ -70,7 +70,7 @@ if ENABLE_CURSES - libcunit_la_LIBADD += -l$(CURSES_LIB) - endif --libcunit_la_LDFLAGS = -version-info @LIBTOOL_CURRENT@:@LIBTOOL_REVISION@:@LIBTOOL_AGE@ -+libcunit_la_LDFLAGS = -version-info @LIBTOOL_CURRENT@:@LIBTOOL_REVISION@:@LIBTOOL_AGE@ -no-undefined - - - if ENABLE_TEST diff --git a/packaging/msys2/PKGBUILD b/packaging/msys2/PKGBUILD index 4ba7937..9daeb1a 100644 --- a/packaging/msys2/PKGBUILD +++ b/packaging/msys2/PKGBUILD @@ -3,41 +3,31 @@ _realname=cunit pkgbase=mingw-w64-${_realname} pkgname=("${MINGW_PACKAGE_PREFIX}-${_realname}") -_distver="2.2-4" +_distver="$(tr -d '[:space:]' < ../../VERSION)" _srcname="cunit" _distdir="${_srcname}-${_distver}" -pkgver=2.2.4 +pkgver=${_distver//-/.} pkgrel=6 pkgdesc="Lightweight system for writing, administering, and running unit tests in C (mingw-w64)" arch=('any') mingw_arch=('mingw32' 'mingw64' 'ucrt64' 'clang64' 'clangarm64') url='https://github.com/ascend4/cunit' license=('LGPL2.1') -makedepends=("${MINGW_PACKAGE_PREFIX}-autotools" "${MINGW_PACKAGE_PREFIX}-cc") -source=("${_distdir}.tar.gz" - "002-fix-shared.patch") -sha256sums=('SKIP' - '03aa848d6cd7464f24efacccfffb4d3942515bde0b36c3ef5ea0d7141d663269') - -prepare() { - cd "${srcdir}/${_distdir}" - patch -Np1 -i "${srcdir}/002-fix-shared.patch" - - ./bootstrap -} +makedepends=("${MINGW_PACKAGE_PREFIX}-cc") +source=("${_distdir}.tar.gz") +sha256sums=('SKIP') build() { cd "${srcdir}" rm -rf "build-${MSYSTEM}" || true mkdir -p "build-${MSYSTEM}" - cp -Rf "${_distdir}/"* "build-${MSYSTEM}/" cd "build-${MSYSTEM}" # These checks fail with some MinGW targets unless we pin the known result. export ac_cv_func_time=yes export ac_cv_func_ctime=yes - ./configure \ + "../${_distdir}/configure" \ --prefix="${MINGW_PREFIX}" \ --build="${MINGW_CHOST}" \ --host="${MINGW_CHOST}" \ @@ -59,6 +49,6 @@ check() { package() { cd "${srcdir}/build-${MSYSTEM}" make DESTDIR="${pkgdir}" install - install -Dm644 COPYING "${pkgdir}${MINGW_PREFIX}/share/licenses/${_realname}/COPYING" + install -Dm644 "${srcdir}/${_distdir}/COPYING" "${pkgdir}${MINGW_PREFIX}/share/licenses/${_realname}/COPYING" find "${pkgdir}" -name '*.la' -delete }