diff options
| author | pepper <peppersclothescult@gmail.com> | 2015-01-10 21:32:32 -0800 |
|---|---|---|
| committer | pepper <peppersclothescult@gmail.com> | 2015-01-10 21:32:32 -0800 |
| commit | d53fa8a169832563c62262078b8d2ffe5cab8473 (patch) | |
| tree | b911d06d357d009c976709780f10e92ce915228a /test/unit/ApplicationRunner.c | |
first
Diffstat (limited to 'test/unit/ApplicationRunner.c')
| -rw-r--r-- | test/unit/ApplicationRunner.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/test/unit/ApplicationRunner.c b/test/unit/ApplicationRunner.c new file mode 100644 index 0000000..54b4812 --- /dev/null +++ b/test/unit/ApplicationRunner.c @@ -0,0 +1,297 @@ +#include <stdio.h> +#include <stdarg.h> + +#include "ApplicationRunner.h" +#include "base/File.h" +#include "base/PlatformInfo.h" +#include "analysis/AnalyzeFile.h" + +const char *kDefaultTestOutputFileType = "pcm"; +static const char *kApplicationRunnerOutputFolder = "out"; +static const int kApplicationRunnerWaitTimeoutInMs = 1000; + +CharString buildTestArgumentString(const char *arguments, ...) +{ + CharString formattedArguments; + va_list argumentList; + va_start(argumentList, arguments); + formattedArguments = newCharStringWithCapacity(kCharStringLengthLong); + vsnprintf(formattedArguments->data, formattedArguments->capacity, arguments, argumentList); + va_end(argumentList); + return formattedArguments; +} + +CharString getTestResourceFilename(const char *resourcesPath, const char *resourceType, const char *resourceName) +{ + CharString filename = newCharString(); + snprintf(filename->data, filename->capacity, "%s%c%s%c%s", + resourcesPath, PATH_DELIMITER, resourceType, PATH_DELIMITER, resourceName); + return filename; +} + +CharString getTestOutputFilename(const char *testName, const char *fileExtension) +{ + CharString filename = newCharString(); + char *space; + char *spacePtr; + + snprintf(filename->data, filename->capacity, "%s%c%s.%s", + kApplicationRunnerOutputFolder, PATH_DELIMITER, testName, fileExtension); + spacePtr = filename->data; + + do { + space = strchr(spacePtr + 1, ' '); + + if (space == NULL || (unsigned int)(space - filename->data) > strlen(filename->data)) { + break; + } else { + *space = '-'; + } + } while (true); + + return filename; +} + +static CharString _getTestPluginResourcesPath(const char *resourcesPath) +{ + CharString pluginRoot = newCharString(); + PlatformInfo platform = newPlatformInfo(); + snprintf(pluginRoot->data, pluginRoot->capacity, "%s%cvst%c%s", + resourcesPath, PATH_DELIMITER, PATH_DELIMITER, platform->shortName->data); + freePlatformInfo(platform); + return pluginRoot; +} + +static CharString _getDefaultArguments(TestEnvironment testEnvironment, const char *testName, const char *outputFilename) +{ + CharString outString = newCharStringWithCapacity(kCharStringLengthLong); + CharString logfileName = getTestOutputFilename(testName, "txt"); + CharString resourcesPath = _getTestPluginResourcesPath(testEnvironment->resourcesPath); + snprintf(outString->data, outString->capacity, + "--log-file \"%s\" --verbose --output \"%s\" --plugin-root \"%s\"", + logfileName->data, outputFilename, resourcesPath->data); + freeCharString(logfileName); + freeCharString(resourcesPath); + return outString; +} + +static void _removeOutputFile(const char *argument) +{ + CharString outputFilename = newCharStringWithCString(argument); + File outputFile = newFileWithPath(outputFilename); + + if (fileExists(outputFile)) { + fileRemove(outputFile); + } + + freeCharString(outputFilename); + freeFile(outputFile); +} + +static void _removeOutputFiles(const char *testName) +{ + // Remove all possible output files generated during testing + CharString outputFilename; + + outputFilename = getTestOutputFilename(testName, "aif"); + _removeOutputFile(outputFilename->data); + freeCharString(outputFilename); + outputFilename = getTestOutputFilename(testName, "flac"); + _removeOutputFile(outputFilename->data); + freeCharString(outputFilename); + outputFilename = getTestOutputFilename(testName, "pcm"); + _removeOutputFile(outputFilename->data); + freeCharString(outputFilename); + outputFilename = getTestOutputFilename(testName, "wav"); + _removeOutputFile(outputFilename->data); + freeCharString(outputFilename); + outputFilename = getTestOutputFilename(testName, "txt"); + _removeOutputFile(outputFilename->data); + freeCharString(outputFilename); +} + +static const char *_getResultCodeString(const int resultCode) +{ + switch (resultCode) { + case RETURN_CODE_SUCCESS: + return "Success"; + + case RETURN_CODE_NOT_RUN: + return "Not run"; + + case RETURN_CODE_INVALID_ARGUMENT: + return "Invalid argument"; + + case RETURN_CODE_MISSING_REQUIRED_OPTION: + return "Missing required option"; + + case RETURN_CODE_IO_ERROR: + return "I/O error"; + + case RETURN_CODE_PLUGIN_ERROR: + return "Plugin error"; + + case RETURN_CODE_INVALID_PLUGIN_CHAIN: + return "Invalid plugin chain"; + + case RETURN_CODE_UNSUPPORTED_FEATURE: + return "Unsupported feature"; + + case RETURN_CODE_INTERNAL_ERROR: + return "Internal error"; + + case RETURN_CODE_SIGNAL: + return "Caught signal"; + + default: + return "Unknown"; + } +} + +void runIntegrationTest(const TestEnvironment testEnvironment, + const char *testName, CharString testArguments, + ReturnCodes expectedResultCode, const char *outputFileType) +{ + int result = -1; + ReturnCodes resultCode = (ReturnCodes)result; + CharString arguments = newCharStringWithCapacity(kCharStringLengthLong); + CharString defaultArguments; + CharString failedAnalysisFunctionName = newCharString(); + ChannelCount failedAnalysisChannel; + SampleCount failedAnalysisFrame; + File outputFolder = NULL; + CharString outputFilename = getTestOutputFilename(testName, + outputFileType == NULL ? kDefaultTestOutputFileType : outputFileType); + +#if WINDOWS + STARTUPINFOA startupInfo; + PROCESS_INFORMATION processInfo; +#endif + + // Remove files from a previous test run + outputFolder = newFileWithPathCString(kApplicationRunnerOutputFolder); + + if (fileExists(outputFolder)) { + _removeOutputFiles(testName); + } else { + fileCreate(outputFolder, kFileTypeDirectory); + } + + // Create the command line argument + charStringAppendCString(arguments, "\""); + charStringAppendCString(arguments, testEnvironment->applicationPath); + charStringAppendCString(arguments, "\""); + charStringAppendCString(arguments, " "); + defaultArguments = _getDefaultArguments(testEnvironment, testName, outputFilename->data); + charStringAppend(arguments, defaultArguments); + charStringAppendCString(arguments, " "); + charStringAppend(arguments, testArguments); + + if (!testEnvironment->results->onlyPrintFailing) { + printTestName(testName); + } + +#if WINDOWS + memset(&startupInfo, 0, sizeof(startupInfo)); + memset(&processInfo, 0, sizeof(processInfo)); + startupInfo.cb = sizeof(startupInfo); + result = CreateProcessA((LPCSTR)(testEnvironment->applicationPath), (LPSTR)(arguments->data), + 0, 0, false, CREATE_DEFAULT_ERROR_MODE, 0, 0, &startupInfo, &processInfo); + + if (result) { + // TODO: Check return codes for these calls + WaitForSingleObject(processInfo.hProcess, kApplicationRunnerWaitTimeoutInMs); + GetExitCodeProcess(processInfo.hProcess, (LPDWORD)&resultCode); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } else { + logCritical("Could not launch process, got error %s", stringForLastError(GetLastError())); + return; + } + +#else + result = system(arguments->data); + resultCode = (ReturnCodes)WEXITSTATUS(result); +#endif + + if (resultCode == RETURN_CODE_FORK_FAILED || + resultCode == RETURN_CODE_SHELL_FAILED || + resultCode == RETURN_CODE_LAUNCH_FAILED_OTHER) { + if (testEnvironment->results->onlyPrintFailing) { + printTestName(testName); + } + + printTestFail(); + logCritical("Could not launch shell, got return code %d\n\ +Please check the executable path specified in the --mrswatson-path argument.", + resultCode); + testEnvironment->results->numFail++; + } else if (resultCode == expectedResultCode) { + if (outputFileType != NULL) { + if (analyzeFile(outputFilename->data, failedAnalysisFunctionName, + &failedAnalysisChannel, &failedAnalysisFrame)) { + testEnvironment->results->numSuccess++; + + if (!testEnvironment->results->keepFiles) { + _removeOutputFiles(testName); + } + + if (!testEnvironment->results->onlyPrintFailing) { + printTestSuccess(); + } + } else { + if (testEnvironment->results->onlyPrintFailing) { + printTestName(testName); + } + + fprintf(stderr, "Audio analysis check for %s failed at channel %d, frame %lu. ", + failedAnalysisFunctionName->data, failedAnalysisChannel, failedAnalysisFrame); + printTestFail(); + testEnvironment->results->numFail++; + } + } else { + testEnvironment->results->numSuccess++; + + if (!testEnvironment->results->keepFiles) { + _removeOutputFiles(testName); + } + + if (!testEnvironment->results->onlyPrintFailing) { + printTestSuccess(); + } + } + } else { + if (testEnvironment->results->onlyPrintFailing) { + printTestName(testName); + } + + fprintf(stderr, "Expected result code %d (%s), got %d (%s). ", + expectedResultCode, _getResultCodeString(expectedResultCode), + resultCode, _getResultCodeString(resultCode)); + printTestFail(); + testEnvironment->results->numFail++; + } + + freeCharString(outputFilename); + freeCharString(arguments); + freeCharString(defaultArguments); + freeCharString(testArguments); + freeCharString(failedAnalysisFunctionName); +} + +void freeTestEnvironment(TestEnvironment self) +{ + if (self != NULL) { + freeTestSuite(self->results); + free(self); + } +} + +TestEnvironment newTestEnvironment(char *applicationPath, char *resourcesPath) +{ + TestEnvironment testEnvironment = (TestEnvironment)malloc(sizeof(TestEnvironmentMembers)); + testEnvironment->applicationPath = applicationPath; + testEnvironment->resourcesPath = resourcesPath; + testEnvironment->results = newTestSuite("Results", NULL, NULL); + return testEnvironment; +} |
