diff --git a/test/define.yaml b/test/define.yaml index 7337a06ba..0e402c1d2 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -631,6 +631,19 @@ unit: - build/postgres/parse - build/postgres/render + # ******************************************************************************************************************************** + - name: test + + test: + # ---------------------------------------------------------------------------------------------------------------------------- + - name: test + total: 3 + + coverage: + - test/command/test/build + - test/command/test/define + - test/command/test/test + # ******************************************************************************************************************************** - name: info diff --git a/test/lib/pgBackRestTest/Common/CoverageTest.pm b/test/lib/pgBackRestTest/Common/CoverageTest.pm index 31311facb..5bd0b600f 100644 --- a/test/lib/pgBackRestTest/Common/CoverageTest.pm +++ b/test/lib/pgBackRestTest/Common/CoverageTest.pm @@ -39,7 +39,7 @@ sub coverageLCovConfigGenerate my $bCoverageSummary = shift; my $strBranchFilter = - 'OBJECT_DEFINE_[A-Z0-9_]+\(|\s{4}[A-Z][A-Z0-9_]+\([^\?]*\)|\s{4}(ASSERT|CHECK|assert|switch\s)\(|\{\+{0,1}' . + 'OBJECT_DEFINE_[A-Z0-9_]+\(|\s{4}[A-Z][A-Z0-9_]+\([^\?]*\)|\s{4}(ASSERT|CHECK|CHECK_FMT|assert|switch\s)\(|\{\+{0,1}' . ($bCoverageSummary ? 'uncoverable_branch' : 'uncover(ed|able)_branch'); my $strLineFilter = '\{\+{0,1}' . ($bCoverageSummary ? 'uncoverable' : '(uncover(ed|able)' . ($bContainer ? '' : '|vm_covered') . ')') . '[^_]'; @@ -124,6 +124,12 @@ sub coverageExtract foreach my $strCoveredModule (@stryCoveredModule) { my $strModuleName = testRunName($strCoveredModule, false); + + if ($strModuleName =~ /^test/mg) + { + $strModuleName =~ s/^test/src/mg; + } + my $strModuleOutName = $strModuleName; my $bTest = false; @@ -134,10 +140,21 @@ sub coverageExtract } # Generate lcov reports - my $strModulePath = - "${strWorkPath}/repo/" . - (${strModuleOutName} =~ /^test\// ? - 'test/src/module/' . substr(${strModuleOutName}, 5) : "src/${strModuleOutName}"); + my $strModulePath = "${strWorkPath}/repo/"; + + if (${strModuleOutName} =~ /^src\//) + { + $strModulePath .= 'test/src/' . substr(${strModuleOutName}, 4); + } + elsif (${strModuleOutName} =~ /^test\//) + { + $strModulePath .= 'test/src/module/' . substr(${strModuleOutName}, 5); + } + else + { + $strModulePath .= "src/${strModuleOutName}"; + } + my $strLCovFile = "${strTestResultCoveragePath}/raw/${strModuleOutName}.lcov"; my $strLCovTotal = "${strWorkTmpPath}/all.lcov"; my $bInc = $strModuleName =~ '\.vendor$' || $strModuleName =~ '\.auto$'; @@ -297,6 +314,7 @@ sub coverageValidateAndGenerate foreach my $strCodeModule (sort(keys(%{$hCoverageActual}))) { my $strCoverageFile = $strCodeModule; + $strCoverageFile =~ s/^test/src/mg; $strCoverageFile =~ s/^module/test/mg; $strCoverageFile = "${strTestResultCoveragePath}/raw/${strCoverageFile}.lcov"; diff --git a/test/src/command/test/build.c b/test/src/command/test/build.c index 39fa7c9b7..0bda249c8 100644 --- a/test/src/command/test/build.c +++ b/test/src/command/test/build.c @@ -129,9 +129,13 @@ testBldShim(const String *const shimC, const StringList *const functionList) { strCatChr(result, ' '); strCat(result, in); + unsigned int scanIdx = inIdx + 1; - for (unsigned int scanIdx = inIdx + 1; scanIdx < strLstSize(inList); scanIdx++) + while (true) { + // In a properly formatted C file the end of the list can never be reached + ASSERT(scanIdx < strLstSize(inList)); + const String *const scan = strLstGet(inList, scanIdx); if (strEqZ(scan, "{")) @@ -141,6 +145,7 @@ testBldShim(const String *const shimC, const StringList *const functionList) strCatChr(result, ' '); strCat(result, strTrim(strDup(scan))); + scanIdx++; } strCatZ(result, "; "); @@ -198,8 +203,30 @@ testBldWrite(const Storage *const storage, StringList *const fileList, const cha /*********************************************************************************************************************************** Generate a relative path from the compare path to the base path +***********************************************************************************************************************************/ +static String * +cmdBldPathModule(const String *const moduleName) +{ + FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_LOG_PARAM(STRING, moduleName); + FUNCTION_LOG_END(); -??? This function has not been hardened for edge cases, e.g. paths are equal. Probably this should he moved to the storage module. + String *const result = strNew(); + + MEM_CONTEXT_TEMP_BEGIN() + { + if (strBeginsWithZ(moduleName, "test/")) + strCatFmt(result, "test/src%s", strZ(strSub(moduleName, 4))); + else + strCatFmt(result, "src/%s", strZ(moduleName)); + } + MEM_CONTEXT_TEMP_END(); + + FUNCTION_LOG_RETURN(STRING, result); +} + +/*********************************************************************************************************************************** +Generate a relative path from the compare path to the base path ***********************************************************************************************************************************/ static String * cmdBldPathRelative(const String *const base, const String *const compare) @@ -211,6 +238,7 @@ cmdBldPathRelative(const String *const base, const String *const compare) ASSERT(base != NULL); ASSERT(compare != NULL); + ASSERT(!strEq(base, compare)); String *const result = strNew(); @@ -243,7 +271,16 @@ cmdBldPathRelative(const String *const base, const String *const compare) // Add remaining path for (unsigned int pathIdx = compareIdx; pathIdx < strLstSize(compareList); pathIdx++) - strCatFmt(result, "/%s", strZ(strLstGet(compareList, pathIdx))); + { + // If first is still set then compare must be a subpath of base (i.e. there were no .. parts) + if (!first) + { + strCatChr(result, '/'); + first = false; + } + + strCat(result, strLstGet(compareList, pathIdx)); + } } MEM_CONTEXT_TEMP_END(); @@ -279,7 +316,7 @@ testBldUnit(TestBuild *const this) for (unsigned int shimIdx = 0; shimIdx < lstSize(module->shimList); shimIdx++) { const TestDefShim *const shim = lstGet(module->shimList, shimIdx); - const String *const shimFile = strNewFmt("src/%s.c", strZ(shim->name)); + const String *const shimFile = strNewFmt("%s.c", strZ(cmdBldPathModule(shim->name))); String *const shimC = strCatBuf( strNew(), @@ -309,8 +346,8 @@ testBldUnit(TestBuild *const this) const String *const include = strLstGet(harness->includeList, includeIdx); strCatFmt( - includeReplace, "%s#include \"%s/src/%s.c\"", includeIdx == 0 ? "" : "\n", - lstExists(module->shimList, &include) ? strZ(pathUnit) : strZ(pathRepo), strZ(include)); + includeReplace, "%s#include \"%s/%s.c\"", includeIdx == 0 ? "" : "\n", + lstExists(module->shimList, &include) ? strZ(pathUnit) : strZ(pathRepo), strZ(cmdBldPathModule(include))); strLstAdd(harnessIncludeList, include); } @@ -396,7 +433,7 @@ testBldUnit(TestBuild *const this) if (strLstExists(harnessIncludeList, depend)) continue; - strCatFmt(mesonBuild, " '%s/src/%s.c',\n", strZ(pathRepoRel), strZ(depend)); + strCatFmt(mesonBuild, " '%s/%s.c',\n", strZ(pathRepoRel), strZ(cmdBldPathModule(depend))); } // Add harnesses @@ -524,24 +561,19 @@ testBldUnit(TestBuild *const this) // Files to test/include StringList *const testIncludeFileList = strLstNew(); - if (module->coverageList != NULL) + for (unsigned int coverageIdx = 0; coverageIdx < lstSize(module->coverageList); coverageIdx++) { - for (unsigned int coverageIdx = 0; coverageIdx < lstSize(module->coverageList); coverageIdx++) - { - const TestDefCoverage *const coverage = lstGet(module->coverageList, coverageIdx); + const TestDefCoverage *const coverage = lstGet(module->coverageList, coverageIdx); - if (coverage->coverable && !coverage->included) - strLstAdd(testIncludeFileList, coverage->name); - } + if (coverage->coverable && !coverage->included) + strLstAdd(testIncludeFileList, coverage->name); } - if (module->includeList != NULL) - { - for (unsigned int includeIdx = 0; includeIdx < strLstSize(module->includeList); includeIdx++) - strLstAdd(testIncludeFileList, strLstGet(module->includeList, includeIdx)); - } + for (unsigned int includeIdx = 0; includeIdx < strLstSize(module->includeList); includeIdx++) + strLstAdd(testIncludeFileList, strLstGet(module->includeList, includeIdx)); - String *const testIncludeFile = strNew(); + StringList *const testIncludeFile = strLstNew(); + StringList *const harnessIncluded = strLstNew(); for (unsigned int testIncludeFileIdx = 0; testIncludeFileIdx < strLstSize(testIncludeFileList); testIncludeFileIdx++) { @@ -556,16 +588,19 @@ testBldUnit(TestBuild *const this) break; } - if (testIncludeFileIdx != 0) - strCatChr(testIncludeFile, '\n'); - if (harnessIdx != lstSize(module->harnessList)) - strCatFmt(testIncludeFile, "#include \"%s\"", strZ(strLstGet(harnessList, harnessIdx))); + { + if (!strLstExists(harnessIncluded, strLstGet(harnessList, harnessIdx))) + { + strLstAddFmt(testIncludeFile, "#include \"%s\"", strZ(strLstGet(harnessList, harnessIdx))); + strLstAdd(harnessIncluded, strLstGet(harnessList, harnessIdx)); + } + } else - strCatFmt(testIncludeFile, "#include \"%s/src/%s.c\"", strZ(pathRepoRel), strZ(include)); + strLstAddFmt(testIncludeFile, "#include \"%s/%s.c\"", strZ(pathRepoRel), strZ(cmdBldPathModule(include))); } - strReplace(testC, STRDEF("{[C_INCLUDE]}"), testIncludeFile); + strReplace(testC, STRDEF("{[C_INCLUDE]}"), strLstJoin(testIncludeFile, "\n")); // Test path strReplace(testC, STRDEF("{[C_TEST_PATH]}"), storagePathP(storageTestId, NULL)); diff --git a/test/src/command/test/define.c b/test/src/command/test/define.c index 6ffd5887b..f80905016 100644 --- a/test/src/command/test/define.c +++ b/test/src/command/test/define.c @@ -47,8 +47,7 @@ testDefParseModuleList(Yaml *const yaml, List *const moduleList) // Check if next is db for integration tests bool pgRequired = false; - if (type == testDefTypeIntegration && yamlEventPeek(yaml).type == yamlEventTypeScalar && - strEqZ(yamlEventPeek(yaml).value, "db")) + if (type == testDefTypeIntegration && strEqZ(yamlEventPeek(yaml).value, "db")) { yamlScalarNextCheckZ(yaml, "db"); pgRequired = yamlBoolParse(yamlScalarNext(yaml)); @@ -99,8 +98,8 @@ testDefParseModuleList(Yaml *const yaml, List *const moduleList) { testDefCoverage.coverable = true; } - else if (!strEqZ(type, "noCode")) - THROW_FMT(FormatError, "invalid coverage type '%s'", strZ(type)); + else + CHECK_FMT(AssertError, strEqZ(type, "noCode"), "invalid coverage type %s", strZ(type)); } YAML_MAP_END(); } @@ -204,15 +203,14 @@ testDefParseModuleList(Yaml *const yaml, List *const moduleList) { testDefModule.name = strNewFmt("%s/%s", strZ(moduleName), strZ(yamlScalarNext(yaml).value)); } - else if (strEqZ(subModuleDef.value, "total")) - { - testDefModule.total = cvtZToUInt(strZ(yamlScalarNext(yaml).value)); - } else { - THROW_FMT( - FormatError, "unexpected scalar '%s' at line %zu, column %zu", strZ(subModuleDef.value), - subModuleDef.line, subModuleDef.column); + CHECK_FMT( + FormatError, strEqZ(subModuleDef.value, "total"), + "unexpected keyword '%s' at line %zu, column %zu", + strZ(subModuleDef.value), subModuleDef.line, subModuleDef.column); + + testDefModule.total = cvtZToUInt(strZ(yamlScalarNext(yaml).value)); } } YAML_MAP_END(); @@ -224,11 +222,8 @@ testDefParseModuleList(Yaml *const yaml, List *const moduleList) { const String *const depend = strLstGet(globalDependList, dependIdx); - if ((coverageList == NULL || !lstExists(coverageList, &depend)) && - (includeList == NULL || !strLstExists(includeList, depend))) - { + if (!lstExists(coverageList, &depend) && !strLstExists(includeList, depend)) strLstAdd(dependList, depend); - } } // Add test module diff --git a/test/src/command/test/test.c b/test/src/command/test/test.c index cdec6d245..8d1b8a6af 100644 --- a/test/src/command/test/test.c +++ b/test/src/command/test/test.c @@ -28,12 +28,11 @@ cmdTestExec(const String *const command) if (system(zNewFmt("%s > %s 2>&1", strZ(command), strZ(cmdTestExecLog))) != 0) { - const Buffer *const buffer = storageGetP( - storageNewReadP(storagePosixNewP(FSLASH_STR), cmdTestExecLog, .ignoreMissing = true)); + const Buffer *const buffer = storageGetP(storageNewReadP(storagePosixNewP(FSLASH_STR), cmdTestExecLog)); THROW_FMT( - ExecuteError, "unable to execute: %s > %s 2>&1:%s", strZ(command), strZ(cmdTestExecLog), - buffer == NULL || bufEmpty(buffer) ? " no log output" : zNewFmt("\n%s", strZ(strNewBuf(buffer)))); + ExecuteError, "unable to execute: %s > %s 2>&1:\n%s", strZ(command), strZ(cmdTestExecLog), + zNewFmt("\n%s", strZ(strTrim(strNewBuf(buffer))))); } FUNCTION_LOG_RETURN_VOID(); @@ -73,15 +72,15 @@ cmdTestPathCreate(const Storage *const storage, const String *const path) void cmdTest( const String *const pathRepo, const String *const pathTest, const String *const vm, const unsigned int vmId, - const StringList *moduleFilterList, const unsigned int test, const uint64_t scale, const LogLevel logLevel, - const bool logTime, const String *const timeZone, const bool coverage, const bool profile, const bool optimize) + const String *moduleName, const unsigned int test, const uint64_t scale, const LogLevel logLevel, const bool logTime, + const String *const timeZone, const bool coverage, const bool profile, const bool optimize) { FUNCTION_LOG_BEGIN(logLevelDebug); FUNCTION_LOG_PARAM(STRING, pathRepo); FUNCTION_LOG_PARAM(STRING, pathTest); FUNCTION_LOG_PARAM(STRING, vm); FUNCTION_LOG_PARAM(UINT, vmId); - FUNCTION_LOG_PARAM(STRING_LIST, moduleFilterList); + FUNCTION_LOG_PARAM(STRING, moduleName); FUNCTION_LOG_PARAM(UINT, test); FUNCTION_LOG_PARAM(UINT64, scale); FUNCTION_LOG_PARAM(ENUM, logLevel); @@ -98,14 +97,12 @@ cmdTest( cmdTestExecLog = strNewFmt("%s/exec-%u.log", strZ(pathTest), vmId); // Find test - ASSERT(!strLstEmpty(moduleFilterList)); + ASSERT(moduleName != NULL); const TestDef testDef = testDefParse(storagePosixNewP(pathRepo)); - const String *const moduleName = strLstGet(moduleFilterList, 0); const TestDefModule *const module = lstFind(testDef.moduleList, &moduleName); - if (module == NULL) - THROW_FMT(ParamInvalidError, "'%s' is not a valid test", strZ(moduleName)); + CHECK_FMT(ParamInvalidError, module != NULL, "'%s' is not a valid test", strZ(moduleName)); // Build test bool buildRetry = false; diff --git a/test/src/command/test/test.h b/test/src/command/test/test.h index da9bb3275..72c28fe27 100644 --- a/test/src/command/test/test.h +++ b/test/src/command/test/test.h @@ -13,7 +13,7 @@ Perform a test. Functions ***********************************************************************************************************************************/ void cmdTest( - const String *pathRepo, const String *pathTest, const String *const vm, unsigned int vmId, const StringList *moduleFilterList, + const String *pathRepo, const String *pathTest, const String *const vm, unsigned int vmId, const String *moduleName, unsigned int test, uint64_t scale, LogLevel logLevel, bool logTime, const String *timeZone, bool coverage, bool profile, bool optimize); diff --git a/test/src/main.c b/test/src/main.c index 12af15891..eb2ad9c13 100644 --- a/test/src/main.c +++ b/test/src/main.c @@ -72,10 +72,11 @@ main(int argListSize, const char *argList[]) { cmdTest( cfgOptionStr(cfgOptRepoPath), cfgOptionStr(cfgOptTestPath), cfgOptionStr(cfgOptVm), - cfgOptionUInt(cfgOptVmId), cfgCommandParam(), cfgOptionTest(cfgOptTest) ? cfgOptionUInt(cfgOptTest) : 0, - cfgOptionUInt64(cfgOptScale), logLevelEnum(cfgOptionStrId(cfgOptLogLevelTest)), - cfgOptionBool(cfgOptLogTimestamp), cfgOptionStrNull(cfgOptTz), cfgOptionBool(cfgOptCoverage), - cfgOptionBool(cfgOptProfile), cfgOptionBool(cfgOptOptimize)); + cfgOptionUInt(cfgOptVmId), strLstGet(cfgCommandParam(), 0), + cfgOptionTest(cfgOptTest) ? cfgOptionUInt(cfgOptTest) : 0, cfgOptionUInt64(cfgOptScale), + logLevelEnum(cfgOptionStrId(cfgOptLogLevelTest)), cfgOptionBool(cfgOptLogTimestamp), + cfgOptionStrNull(cfgOptTz), cfgOptionBool(cfgOptCoverage), cfgOptionBool(cfgOptProfile), + cfgOptionBool(cfgOptOptimize)); break; } diff --git a/test/src/module/test/testTest.c b/test/src/module/test/testTest.c new file mode 100644 index 000000000..0f5c05e76 --- /dev/null +++ b/test/src/module/test/testTest.c @@ -0,0 +1,872 @@ +/*********************************************************************************************************************************** +Test Test Command +***********************************************************************************************************************************/ +#include "storage/posix/storage.h" + +#include "common/harnessStorage.h" + +/*********************************************************************************************************************************** +Build list of test files to compare +***********************************************************************************************************************************/ +static StringList * +testStorageList(const Storage *const storage) +{ + StringList *const result = strLstNew(); + + MEM_CONTEXT_TEMP_BEGIN() + { + StorageIterator *storageItr = storageNewItrP(storage, NULL, .sortOrder = sortOrderAsc, .recurse = true); + + while (storageItrMore(storageItr)) + { + const StorageInfo info = storageItrNext(storageItr); + + if (info.type == storageTypeFile && !strBeginsWithZ(info.name, "build/")) + strLstAdd(result, info.name); + } + } + MEM_CONTEXT_TEMP_END(); + + return result; +} + +/*********************************************************************************************************************************** +Copy a list of files from the repo to the test repo +***********************************************************************************************************************************/ +#define TEST_COPY(source, destination, ...) \ + do \ + { \ + const char *const copyList[] = {__VA_ARGS__}; \ + \ + for (unsigned int copyIdx = 0; copyIdx < LENGTH_OF(copyList); copyIdx++) \ + { \ + HRN_STORAGE_PUT( \ + destination, zNewFmt("repo/%s", copyList[copyIdx]), storageGetP(storageNewReadP(source, STR(copyList[copyIdx])))); \ + } \ + } \ + while (0) + +/*********************************************************************************************************************************** +Test Run +***********************************************************************************************************************************/ +static void +testRun(void) +{ + FUNCTION_HARNESS_VOID(); + + const Storage *const storageRepo = storagePosixNewP(STRDEF(HRN_PATH_REPO)); + const Storage *const storageTest = storagePosixNewP(STRDEF(TEST_PATH), .write = true); + + // ***************************************************************************************************************************** + if (testBegin("cmdBldPathRelative()")) + { + TEST_ERROR(cmdBldPathRelative(STRDEF("/tmp"), STRDEF("/tmp")), AssertError, "assertion '!strEq(base, compare)' failed"); + + TEST_RESULT_STR_Z(cmdBldPathRelative(STRDEF("/tmp/sub"), STRDEF("/tmp")), "..", "compare is sub of base"); + TEST_RESULT_STR_Z(cmdBldPathRelative(STRDEF("/tmp"), STRDEF("/tmp/sub")), "sub", "base is sub of compare"); + } + + // ***************************************************************************************************************************** + if (testBegin("cmdTestExec()")) + { + cmdTestExecLog = STRDEF(TEST_PATH "/error.log"); + bool error = false; + + // The error will vary by OS so just make sure an error was thrown + TRY_BEGIN() + { + cmdTestExec(STRDEF("/bogus/bogus")); + } + CATCH(ExecuteError) + { + error = true; + } + TRY_END(); + + TEST_RESULT_BOOL(error, true, "an error should be thrown"); + + cmdTestExecLog = NULL; + } + + // ***************************************************************************************************************************** + if (testBegin("TestDef and TestBuild")) + { + // meson_options.txt + // ------------------------------------------------------------------------------------------------------------------------- + const char *const mesonOption = strZ(strNewBuf(storageGetP(storageNewReadP(storageRepo, STRDEF("meson_options.txt"))))); + HRN_STORAGE_PUT_Z(storageTest, "repo/meson_options.txt", mesonOption); + + // Root meson.build + // ------------------------------------------------------------------------------------------------------------------------- + String *const mesonBuildRoot = strCat( + strNew(), strNewBuf(storageGetP(storageNewReadP(storageRepo, STRDEF("meson.build"))))); + + HRN_STORAGE_PUT_Z(storageTest, "repo/meson.build", strZ(mesonBuildRoot)); + strReplace(mesonBuildRoot, STRDEF("subdir('"), STRDEF("# subdir('")); + + strCatZ( + mesonBuildRoot, + "\n" + MESON_COMMENT_BLOCK "\n" + "# Write configuration\n" + MESON_COMMENT_BLOCK "\n" + "configure_file(output: 'build.auto.h', configuration: configuration)\n" + "\n" + "add_global_arguments('-DFN_EXTERN=extern', language : 'c')\n" + "add_global_arguments('-DVR_EXTERN_DECLARE=extern', language : 'c')\n" + "add_global_arguments('-DVR_EXTERN_DEFINE=', language : 'c')\n" + "add_global_arguments('-DERROR_MESSAGE_BUFFER_SIZE=131072', language : 'c')\n"); + + // harnessError.c + // ------------------------------------------------------------------------------------------------------------------------- + String *const harnessErrorC = strCat( + strNew(), strNewBuf(storageGetP(storageNewReadP(storageRepo, STRDEF("test/src/common/harnessError.c"))))); + + strReplace(harnessErrorC, STRDEF("{[SHIM_MODULE]}"), STRDEF("#include \"" TEST_PATH "/repo/src/common/error.c\"")); + + // Unit test harness + // ------------------------------------------------------------------------------------------------------------------------- + String *const testC = strCat(strNew(), strNewBuf(storageGetP(storageNewReadP(storageRepo, STRDEF("test/src/test.c"))))); + + strReplace(testC, STRDEF("{[C_HRN_PATH]}"), STRDEF(TEST_PATH "/test/data-3")); + strReplace(testC, STRDEF("{[C_HRN_PATH_REPO]}"), STRDEF(TEST_PATH "/repo")); + strReplace(testC, STRDEF("{[C_LOG_LEVEL_TEST]}"), STRDEF("logLevelDebug")); + strReplace(testC, STRDEF("{[C_TEST_GROUP]}"), STRDEF(TEST_GROUP)); + strReplace(testC, STRDEF("{[C_TEST_GROUP_ID]}"), STRDEF(TEST_GROUP_ID_Z)); + strReplace(testC, STRDEF("{[C_TEST_GROUP_ID_Z]}"), STRDEF("\"" TEST_GROUP_ID_Z "\"")); + strReplace(testC, STRDEF("{[C_TEST_IDX]}"), STRDEF("3")); + strReplace(testC, STRDEF("{[C_TEST_PATH]}"), STRDEF(TEST_PATH "/test/test-3")); + strReplace(testC, STRDEF("{[C_TEST_PGB_PATH]}"), STRDEF("../../../../repo")); + strReplace(testC, STRDEF("{[C_TEST_SCALE]}"), STRDEF("1")); + strReplace(testC, STRDEF("{[C_TEST_TIMING]}"), STRDEF("true")); + strReplace(testC, STRDEF("{[C_TEST_USER]}"), STRDEF(TEST_USER)); + strReplace(testC, STRDEF("{[C_TEST_USER_ID]}"), STRDEF(TEST_USER_ID_Z)); + strReplace(testC, STRDEF("{[C_TEST_USER_ID_Z]}"), STRDEF("\"" TEST_USER_ID_Z "\"")); + + // Test definition + // ------------------------------------------------------------------------------------------------------------------------- + HRN_STORAGE_PUT_Z( + storageTest, "repo/test/define.yaml", + "unit:\n" + " - name: common\n" + " test:\n" + " - name: pre\n" + " total: 1\n" + "\n" + " - name: error\n" + " total: 9\n" + " feature: error\n" + " harness:\n" + " name: error\n" + " shim:\n" + " common/error: ~\n" + " coverage:\n" + " - common/error\n" + " - common/error.auto: noCode\n" + " - common/error.inc: included\n" + " depend:\n" + " - common/stackTrace\n" + "\n" + " - name: stack-trace\n" + " total: 4\n" + " feature: stackTrace\n" + " coverage:\n" + " - common/stackTrace\n" + " depend:\n" + " - common/debug\n" + "\n" + " - name: test\n" + " test:\n" + " - name: shim\n" + " binReq: true\n" + " containerReq: true\n" + " total: 1\n" + " define: -DNDEBUG\n" + " harness: noShim\n" + " harness:\n" + " name: shim\n" + " shim:\n" + " test/common/shim:\n" + " function:\n" + " - shimFunc\n" + " - shimFunc2\n" + " test/common/shim2: ~\n" + " coverage:\n" + " - test/common/shim\n" + " - test/common/shim2\n" + " include:\n" + " - common/error\n" + " - test/common/include\n" + "\n" + "integration:\n" + " - name: mock\n" + " test:\n" + " - name: all\n" + " total: 2\n" + "\n" + " - name: real\n" + " db: true\n" + " test:\n" + " - name: all\n" + " total: 2\n" + "\n" + "performance:\n" + " - name: performance\n" + " test:\n" + " - name: type\n" + " total: 1\n"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("Test common/stack-trace"); + + TEST_COPY( + storageRepo, storageTest, + "src/common/assert.h", + "src/common/debug.c", + "src/common/debug.h", + "src/common/error.auto.c.inc", + "src/common/error.auto.h", + "src/common/error.c", + "src/common/error.h", + "src/common/logLevel.h", + "src/common/macro.h", + "src/common/stackTrace.c", + "src/common/stackTrace.h", + "src/common/type/convert.h", + "src/common/type/param.h", + "src/common/type/stringZ.h", + "test/src/common/harnessDebug.h", + "test/src/common/harnessLog.h", + "test/src/common/harnessError.c", + "test/src/common/harnessError.h", + "test/src/common/harnessTest.c", + "test/src/common/harnessTest.h", + "test/src/common/harnessTest.intern.h", + "test/src/module/common/stackTraceTest.c", + "test/src/test.c"); + + TEST_RESULT_VOID( + cmdTest( + STRDEF(TEST_PATH "/repo"), storagePathP(storageTest, STRDEF("test")), STRDEF("none"), 3, + STRDEF("common/stack-trace"), 0, 1, logLevelDebug, true, NULL, false, false, false), + "new build"); + + const Storage *storageUnit = storagePosixNewP(STRDEF(TEST_PATH "/test/unit-3/none")); + StringList *fileList = testStorageList(storageUnit); + + TEST_RESULT_STRLST_Z( + fileList, + "meson.build\n" + "meson_options.txt\n" + "test/src/common/harnessError.c\n" + "test.c\n", + "check files"); + + for (unsigned int fileIdx = 0; fileIdx < strLstSize(fileList); fileIdx++) + { + const String *const file = strLstGet(fileList, fileIdx); + + if (strEqZ(file, "meson.build")) + { + TEST_STORAGE_GET( + storageUnit, strZ(file), + zNewFmt( + "%s" + "add_global_arguments('-DHRN_INTEST_STACKTRACE', language : 'c')\n" + "add_global_arguments('-DHRN_FEATURE_ERROR', language : 'c')\n" + "\n" + MESON_COMMENT_BLOCK "\n" + "# Unit test\n" + MESON_COMMENT_BLOCK "\n" + "src_unit = files(\n" + " '../../../repo/src/common/debug.c',\n" + " 'test/src/common/harnessError.c',\n" + " '../../../repo/test/src/common/harnessTest.c',\n" + " 'test.c',\n" + ")\n" + "\n" + "executable(\n" + " 'test-unit',\n" + " sources: src_unit,\n" + " include_directories:\n" + " include_directories(\n" + " '.',\n" + " '../../../repo/src',\n" + " '../../../repo/test/src',\n" + " ),\n" + " dependencies: [\n" + " lib_bz2,\n" + " lib_openssl,\n" + " lib_lz4,\n" + " lib_pq,\n" + " lib_xml,\n" + " lib_yaml,\n" + " lib_z,\n" + " lib_zstd,\n" + " ],\n" + ")\n", + strZ(mesonBuildRoot))); + } + else if (strEqZ(file, "meson_options.txt")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), mesonOption); + } + else if (strEqZ(file, "test/src/common/harnessError.c")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(harnessErrorC)); + } + else if (strEqZ(file, "test.c")) + { + String *const testCDup = strCat(strNew(), testC); + + strReplace(testCDup, STRDEF("{[C_TEST_CONTAINER]}"), STRDEF("false")); + strReplace(testCDup, STRDEF("{[C_TEST_DEBUG_TEST_TRACE]}"), STRDEF("#define DEBUG_TEST_TRACE")); + strReplace(testCDup, STRDEF("{[C_TEST_PATH_BUILD]}"), STRDEF(TEST_PATH "/test/unit-3/none/build")); + strReplace(testCDup, STRDEF("{[C_TEST_PROFILE]}"), STRDEF("false")); + strReplace(testCDup, STRDEF("{[C_TEST_PROJECT_EXE]}"), STRDEF(TEST_PATH "/test/build/none/src/pgbackrest")); + strReplace(testCDup, STRDEF("{[C_TEST_TZ]}"), STRDEF("// No timezone specified")); + + strReplace(testCDup, STRDEF("{[C_INCLUDE]}"), STRDEF("#include \"../../../repo/src/common/stackTrace.c\"")); + strReplace( + testCDup, STRDEF("{[C_TEST_INCLUDE]}"), + STRDEF("#include \"../../../repo/test/src/module/common/stackTraceTest.c\"")); + strReplace( + testCDup, STRDEF("{[C_TEST_LIST]}"), + STRDEF( + "hrnAdd( 1, true);\n" + " hrnAdd( 2, true);\n" + " hrnAdd( 3, true);\n" + " hrnAdd( 4, true);")); + + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(testCDup)); + } + else + THROW_FMT(TestError, "no test for '%s'", strZ(file)); + } + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("Test common/error"); + + TEST_COPY( + storageRepo, storageTest, + "test/src/common/harnessFork.h", + "test/src/module/common/errorTest.c"); + + TEST_RESULT_VOID( + cmdTest( + STRDEF(TEST_PATH "/repo"), storagePathP(storageTest, STRDEF("test")), STRDEF("none"), 3, + STRDEF("common/error"), 5, 1, logLevelDebug, true, NULL, false, false, false), + "new build"); + + fileList = testStorageList(storageUnit); + + TEST_RESULT_STRLST_Z( + fileList, + "meson.build\n" + "meson_options.txt\n" + "test/src/common/harnessError.c\n" + "test.c\n", + "check files"); + + for (unsigned int fileIdx = 0; fileIdx < strLstSize(fileList); fileIdx++) + { + const String *const file = strLstGet(fileList, fileIdx); + + if (strEqZ(file, "meson.build")) + { + TEST_STORAGE_GET( + storageUnit, strZ(file), + zNewFmt( + "%s" + "add_global_arguments('-DHRN_INTEST_ERROR', language : 'c')\n" + "\n" + MESON_COMMENT_BLOCK "\n" + "# Unit test\n" + MESON_COMMENT_BLOCK "\n" + "src_unit = files(\n" + " '../../../repo/src/common/stackTrace.c',\n" + " '../../../repo/test/src/common/harnessTest.c',\n" + " 'test.c',\n" + ")\n" + "\n" + "executable(\n" + " 'test-unit',\n" + " sources: src_unit,\n" + " include_directories:\n" + " include_directories(\n" + " '.',\n" + " '../../../repo/src',\n" + " '../../../repo/test/src',\n" + " ),\n" + " dependencies: [\n" + " lib_bz2,\n" + " lib_openssl,\n" + " lib_lz4,\n" + " lib_pq,\n" + " lib_xml,\n" + " lib_yaml,\n" + " lib_z,\n" + " lib_zstd,\n" + " ],\n" + ")\n", + strZ(mesonBuildRoot))); + } + else if (strEqZ(file, "meson_options.txt")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), mesonOption); + } + else if (strEqZ(file, "test/src/common/harnessError.c")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(harnessErrorC)); + } + else if (strEqZ(file, "test.c")) + { + String *const testCDup = strCat(strNew(), testC); + + strReplace(testCDup, STRDEF("{[C_TEST_CONTAINER]}"), STRDEF("false")); + strReplace(testCDup, STRDEF("{[C_TEST_DEBUG_TEST_TRACE]}"), STRDEF("#define DEBUG_TEST_TRACE")); + strReplace(testCDup, STRDEF("{[C_TEST_PATH_BUILD]}"), STRDEF(TEST_PATH "/test/unit-3/none/build")); + strReplace(testCDup, STRDEF("{[C_TEST_PROFILE]}"), STRDEF("false")); + strReplace(testCDup, STRDEF("{[C_TEST_PROJECT_EXE]}"), STRDEF(TEST_PATH "/test/build/none/src/pgbackrest")); + strReplace(testCDup, STRDEF("{[C_TEST_TZ]}"), STRDEF("// No timezone specified")); + + strReplace( + testCDup, STRDEF("{[C_INCLUDE]}"), + STRDEF("#include \"test/src/common/harnessError.c\"")); + strReplace( + testCDup, STRDEF("{[C_TEST_INCLUDE]}"), + STRDEF("#include \"../../../repo/test/src/module/common/errorTest.c\"")); + strReplace( + testCDup, STRDEF("{[C_TEST_LIST]}"), + STRDEF( + "hrnAdd( 1, false);\n" + " hrnAdd( 2, false);\n" + " hrnAdd( 3, false);\n" + " hrnAdd( 4, false);\n" + " hrnAdd( 5, true);\n" + " hrnAdd( 6, false);\n" + " hrnAdd( 7, false);\n" + " hrnAdd( 8, false);\n" + " hrnAdd( 9, false);")); + + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(testCDup)); + } + else + THROW_FMT(TestError, "no test for '%s'", strZ(file)); + } + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("Test test/shim"); + + String *const shimC = strCatZ( + strNew(), + "int\n" + "shimFunc(void)\n" + "{\n" + " return 777;\n" + "}\n" + "\n" + "static int\n" + "shimFunc2(\n" + " int param1,\n" + " int param2)\n" + "{\n" + " return 777 + param1 + param2;\n" + "}\n"); + + HRN_STORAGE_PUT_Z(storageTest, "repo/test/src/common/shim.c", strZ(shimC)); + HRN_STORAGE_PUT_Z( + storageTest, "repo/test/src/common/shim2.c", + "int noShimFunc3(void)\n" + "{\n" + " return 888;\n" + "}\n"); + + strReplace(shimC, STRDEF("int\nshimFunc(void)"), STRDEF("int\nshimFunc_SHIMMED(void)")); + strReplace( + shimC, STRDEF("static int\nshimFunc2("), + STRDEF("static int shimFunc2(int param1, int param2); static int\nshimFunc2_SHIMMED(")); + + String *const harnessShimC = strCatZ( + strNew(), + "{[SHIM_MODULE]}\n" + "\n" + "static int\n" + "shimFunc(void)\n" + "{\n" + " return shimFunc_SHIMMED() + 1;\n" + " (void)shimFunc2; // To suppress unused warnings\n" + "}\n" + "\n" + "static int\n" + "shimFunc2(int param1, int param2)\n" + "{\n" + " return shimFunc2_SHIMMED(param1, param2) + 2;\n" + " (void)shimFunc; // To suppress unused warnings\n" + "}\n"); + + HRN_STORAGE_PUT_Z(storageTest, "repo/test/src/common/harnessShim.c", strZ(harnessShimC)); + HRN_STORAGE_PUT_EMPTY(storageTest, "repo/test/src/common/harnessShim/sub.c"); + HRN_STORAGE_PUT_EMPTY(storageTest, "repo/test/src/common/harnessNoShim.c"); + HRN_STORAGE_PUT_EMPTY(storageTest, "repo/test/src/common/include.c"); + + strReplace( + harnessShimC, STRDEF("{[SHIM_MODULE]}"), + STRDEF( + "#include \"" TEST_PATH "/test/unit-3/uXX/test/src/common/shim.c\"\n" + "#include \"" TEST_PATH "/repo/test/src/common/shim2.c\"")); + + HRN_STORAGE_PUT_Z( + storageTest, "repo/test/src/module/test/shimTest.c", + "static void\n" + "testRun(void)\n" + "{\n" + " FUNCTION_HARNESS_VOID();\n" + "\n" + " if (testBegin(\"shims\"))\n" + " {\n" + " TEST_RESULT_INT(shimFunc_SHIMMED(), 777, \"shimFunc()\");\n" + " TEST_RESULT_INT(shimFunc(), 778, \"shimFunc()\");\n" + "\n" + " TEST_RESULT_INT(shimFunc2_SHIMMED(111, 112), 1000, \"shimFunc2()\");\n" + " TEST_RESULT_INT(shimFunc2(111, 112), 1002, \"shimFunc2()\");\n" + "\n" + " TEST_RESULT_INT(noShimFunc3(), 888, \"noShimFunc3()\");\n" + " }\n" + "\n" + " FUNCTION_HARNESS_RETURN_VOID();\n" + "}\n"); + + HRN_STORAGE_PUT_EMPTY(storageTest, TEST_PATH "/test/unit-3/uXX/cleanme.txt"); + + TEST_RESULT_VOID( + cmdTest( + STRDEF(TEST_PATH "/repo"), storagePathP(storageTest, STRDEF("test")), STRDEF("uXX"), 3, + STRDEF("test/shim"), 0, 1, logLevelDebug, true, NULL, true, true, true), + "new build"); + + storageUnit = storagePosixNewP(STRDEF(TEST_PATH "/test/unit-3/uXX")); + fileList = testStorageList(storageUnit); + + TEST_RESULT_STRLST_Z( + fileList, + "meson.build\n" + "meson_options.txt\n" + "test/src/common/harnessError.c\n" + "test/src/common/harnessShim.c\n" + "test/src/common/shim.c\n" + "test.c\n", + "check files"); + + for (unsigned int fileIdx = 0; fileIdx < strLstSize(fileList); fileIdx++) + { + const String *const file = strLstGet(fileList, fileIdx); + + if (strEqZ(file, "meson.build")) + { + TEST_STORAGE_GET( + storageUnit, strZ(file), + zNewFmt( + "%s" + "add_global_arguments('-DHRN_FEATURE_ERROR', language : 'c')\n" + "add_global_arguments('-DHRN_FEATURE_STACKTRACE', language : 'c')\n" + "add_global_arguments('-DNDEBUG', language : 'c')\n" + "add_global_arguments('-DDEBUG_COVERAGE', language : 'c')\n" + "add_global_arguments('-DTEST_CONTAINER_REQUIRED', language : 'c')\n" + "\n" + MESON_COMMENT_BLOCK "\n" + "# Unit test\n" + MESON_COMMENT_BLOCK "\n" + "src_unit = files(\n" + " '../../../repo/src/common/stackTrace.c',\n" + " '../../../repo/src/common/debug.c',\n" + " '../../../repo/test/src/common/harnessNoShim.c',\n" + " '../../../repo/test/src/common/harnessShim/sub.c',\n" + " '../../../repo/test/src/common/harnessTest.c',\n" + " 'test.c',\n" + ")\n" + "\n" + "executable(\n" + " 'test-unit',\n" + " sources: src_unit,\n" + " c_args: [\n" + " '-O2',\n" + " '-pg',\n" + " '-no-pie',\n" + " ],\n" + " link_args: [\n" + " '-pg',\n" + " '-no-pie',\n" + " ],\n" + " include_directories:\n" + " include_directories(\n" + " '.',\n" + " '../../../repo/src',\n" + " '../../../repo/test/src',\n" + " ),\n" + " dependencies: [\n" + " lib_bz2,\n" + " lib_openssl,\n" + " lib_lz4,\n" + " lib_pq,\n" + " lib_xml,\n" + " lib_yaml,\n" + " lib_z,\n" + " lib_zstd,\n" + " ],\n" + ")\n", + strZ(mesonBuildRoot))); + } + else if (strEqZ(file, "meson_options.txt")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), mesonOption); + } + else if (strEqZ(file, "test/src/common/harnessError.c")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(harnessErrorC)); + } + else if (strEqZ(file, "test/src/common/harnessShim.c")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(harnessShimC)); + } + else if (strEqZ(file, "test/src/common/shim.c")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(shimC)); + } + else if (strEqZ(file, "test.c")) + { + String *const testCDup = strCat(strNew(), testC); + + strReplace(testCDup, STRDEF("{[C_TEST_CONTAINER]}"), STRDEF("true")); + strReplace(testCDup, STRDEF("{[C_TEST_DEBUG_TEST_TRACE]}"), STRDEF("// Debug test trace not enabled")); + strReplace(testCDup, STRDEF("{[C_TEST_PATH_BUILD]}"), STRDEF(TEST_PATH "/test/unit-3/uXX/build")); + strReplace(testCDup, STRDEF("{[C_TEST_PROFILE]}"), STRDEF("true")); + strReplace(testCDup, STRDEF("{[C_TEST_PROJECT_EXE]}"), STRDEF(TEST_PATH "/test/bin/uXX/pgbackrest")); + strReplace(testCDup, STRDEF("{[C_TEST_TZ]}"), STRDEF("// No timezone specified")); + + strReplace( + testCDup, + STRDEF("{[C_INCLUDE]}"), + STRDEF( + "#include \"test/src/common/harnessShim.c\"\n" + "#include \"test/src/common/harnessError.c\"\n" + "#include \"../../../repo/test/src/common/include.c\"")); + strReplace( + testCDup, STRDEF("{[C_TEST_INCLUDE]}"), STRDEF("#include \"../../../repo/test/src/module/test/shimTest.c\"")); + strReplace( + testCDup, STRDEF("{[C_TEST_LIST]}"), + STRDEF( + "hrnAdd( 1, true);")); + + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(testCDup)); + } + else + THROW_FMT(TestError, "no test for '%s'", strZ(file)); + } + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("Run test/shim and build again to cleanup coverage data"); + + HRN_SYSTEM(TEST_PATH "/test/unit-3/uXX/build/test-unit"); + + TEST_RESULT_VOID( + cmdTest( + STRDEF(TEST_PATH "/repo"), storagePathP(storageTest, STRDEF("test")), STRDEF("uXX"), 3, + STRDEF("test/shim"), 0, 1, logLevelDebug, true, NULL, true, true, true), + "new build"); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("Test performance/type"); + + HRN_STORAGE_PUT_Z( + storageTest, "repo/test/src/module/performance/typeTest.c", + "static void\n" + "testRun(void)\n" + "{\n" + " FUNCTION_HARNESS_VOID();\n" + "\n" + " if (testBegin(\"type\"))\n" + " {\n" + " }\n" + "\n" + " FUNCTION_HARNESS_RETURN_VOID();\n" + "}\n"); + + HRN_SYSTEM("chmod 000 " TEST_PATH "/test/unit-3/uXX/build"); + + TEST_RESULT_VOID( + cmdTest( + STRDEF(TEST_PATH "/repo"), storagePathP(storageTest, STRDEF("test")), STRDEF("uXX"), 3, + STRDEF("performance/type"), 0, 1, logLevelDebug, true, STRDEF("America/New_York"), false, true, false), + "new build"); + + TEST_RESULT_LOG( + "P00 WARN: build failed for unit performance/type -- will retry: unable to list file info for path '" TEST_PATH + "/test/unit-3/uXX/build': [13] Permission denied"); + + storageUnit = storagePosixNewP(STRDEF(TEST_PATH "/test/unit-3/uXX")); + fileList = testStorageList(storageUnit); + + TEST_RESULT_STRLST_Z( + fileList, + "meson.build\n" + "meson_options.txt\n" + "test/src/common/harnessError.c\n" + "test/src/common/harnessShim.c\n" + "test/src/common/shim.c\n" + "test.c\n", + "check files"); + + for (unsigned int fileIdx = 0; fileIdx < strLstSize(fileList); fileIdx++) + { + const String *const file = strLstGet(fileList, fileIdx); + + if (strEqZ(file, "meson.build")) + { + TEST_STORAGE_GET( + storageUnit, strZ(file), + zNewFmt( + "%s" + "add_global_arguments('-DHRN_FEATURE_ERROR', language : 'c')\n" + "add_global_arguments('-DHRN_FEATURE_STACKTRACE', language : 'c')\n" + "add_global_arguments('-DTEST_CONTAINER_REQUIRED', language : 'c')\n" + "\n" + MESON_COMMENT_BLOCK "\n" + "# Unit test\n" + MESON_COMMENT_BLOCK "\n" + "src_unit = files(\n" + " '../../../repo/src/common/stackTrace.c',\n" + " '../../../repo/src/common/debug.c',\n" + " 'test/src/common/harnessError.c',\n" + " '../../../repo/test/src/common/harnessNoShim.c',\n" + " '../../../repo/test/src/common/harnessShim/sub.c',\n" + " 'test/src/common/harnessShim.c',\n" + " '../../../repo/test/src/common/harnessTest.c',\n" + " 'test.c',\n" + ")\n" + "\n" + "executable(\n" + " 'test-unit',\n" + " sources: src_unit,\n" + " c_args: [\n" + " '-O2',\n" + " '-pg',\n" + " '-no-pie',\n" + " ],\n" + " link_args: [\n" + " '-pg',\n" + " '-no-pie',\n" + " ],\n" + " include_directories:\n" + " include_directories(\n" + " '.',\n" + " '../../../repo/src',\n" + " '../../../repo/test/src',\n" + " ),\n" + " dependencies: [\n" + " lib_bz2,\n" + " lib_openssl,\n" + " lib_lz4,\n" + " lib_pq,\n" + " lib_xml,\n" + " lib_yaml,\n" + " lib_z,\n" + " lib_zstd,\n" + " ],\n" + ")\n", + strZ(mesonBuildRoot))); + } + else if (strEqZ(file, "meson_options.txt")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), mesonOption); + } + else if (strEqZ(file, "test/src/common/harnessError.c")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(harnessErrorC)); + } + else if (strEqZ(file, "test/src/common/harnessShim.c")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(harnessShimC)); + } + else if (strEqZ(file, "test/src/common/shim.c")) + { + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(shimC)); + } + else if (strEqZ(file, "test.c")) + { + String *const testCDup = strCat(strNew(), testC); + + strReplace(testCDup, STRDEF("{[C_TEST_CONTAINER]}"), STRDEF("true")); + strReplace(testCDup, STRDEF("{[C_TEST_DEBUG_TEST_TRACE]}"), STRDEF("// Debug test trace not enabled")); + strReplace(testCDup, STRDEF("{[C_TEST_PATH_BUILD]}"), STRDEF(TEST_PATH "/test/unit-3/uXX/build")); + strReplace(testCDup, STRDEF("{[C_TEST_PROFILE]}"), STRDEF("true")); + strReplace(testCDup, STRDEF("{[C_TEST_PROJECT_EXE]}"), STRDEF(TEST_PATH "/test/bin/uXX/pgbackrest")); + strReplace(testCDup, STRDEF("{[C_TEST_TZ]}"), STRDEF("setenv(\"TZ\", \"America/New_York\", true);")); + + strReplace(testCDup, STRDEF("{[C_INCLUDE]}"), STRDEF("")); + strReplace( + testCDup, STRDEF("{[C_TEST_INCLUDE]}"), + STRDEF("#include \"../../../repo/test/src/module/performance/typeTest.c\"")); + strReplace( + testCDup, STRDEF("{[C_TEST_LIST]}"), + STRDEF( + "hrnAdd( 1, true);")); + + TEST_STORAGE_GET(storageUnit, strZ(file), strZ(testCDup)); + } + else + THROW_FMT(TestError, "no test for '%s'", strZ(file)); + } + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("Test performance/type with profiling off for coverage"); + + TEST_RESULT_VOID( + cmdTest( + STRDEF(TEST_PATH "/repo"), storagePathP(storageTest, STRDEF("test")), STRDEF("uXX"), 3, + STRDEF("performance/type"), 0, 1, logLevelDebug, true, STRDEF("America/New_York"), false, false, false), + "new build"); + + storageUnit = storagePosixNewP(STRDEF(TEST_PATH "/test/unit-3/uXX")); + + // Test one file to make sure profiling was not enabled + String *const testCDup = strCat(strNew(), testC); + + strReplace(testCDup, STRDEF("{[C_TEST_CONTAINER]}"), STRDEF("true")); + strReplace(testCDup, STRDEF("{[C_TEST_DEBUG_TEST_TRACE]}"), STRDEF("// Debug test trace not enabled")); + strReplace(testCDup, STRDEF("{[C_TEST_PATH_BUILD]}"), STRDEF(TEST_PATH "/test/unit-3/uXX/build")); + strReplace(testCDup, STRDEF("{[C_TEST_PROFILE]}"), STRDEF("false")); + strReplace(testCDup, STRDEF("{[C_TEST_PROJECT_EXE]}"), STRDEF(TEST_PATH "/test/bin/uXX/pgbackrest")); + strReplace(testCDup, STRDEF("{[C_TEST_TZ]}"), STRDEF("setenv(\"TZ\", \"America/New_York\", true);")); + + strReplace(testCDup, STRDEF("{[C_INCLUDE]}"), STRDEF("")); + strReplace( + testCDup, STRDEF("{[C_TEST_INCLUDE]}"), + STRDEF("#include \"../../../repo/test/src/module/performance/typeTest.c\"")); + strReplace( + testCDup, STRDEF("{[C_TEST_LIST]}"), + STRDEF( + "hrnAdd( 1, true);")); + + TEST_STORAGE_GET(storageUnit, "test.c", strZ(testCDup)); + + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("Fatal test error"); + + HRN_SYSTEM("chmod 000 " TEST_PATH "/repo/meson.build"); + + TEST_ERROR( + cmdTest( + STRDEF(TEST_PATH "/repo"), storagePathP(storageTest, STRDEF("test")), STRDEF("uXX"), 3, + STRDEF("performance/type"), 0, 1, logLevelDebug, true, STRDEF("America/New_York"), false, false, false), + FileOpenError, + "build failed for unit performance/type: unable to open file '" TEST_PATH "/repo/meson.build' for read: [13] Permission" + " denied"); + + TEST_RESULT_LOG( + "P00 WARN: build failed for unit performance/type -- will retry: unable to open file '" TEST_PATH "/repo/meson.build'" + " for read: [13] Permission denied"); + } + + FUNCTION_HARNESS_RETURN_VOID(); +} diff --git a/test/src/test.c b/test/src/test.c index 5cdad9bc9..4ee7bc757 100644 --- a/test/src/test.c +++ b/test/src/test.c @@ -30,6 +30,7 @@ The test code is included directly so it can freely interact with the included C #include #include #include +#include #ifdef HRN_FEATURE_ERROR #include "common/error.h"