diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2019-01-17 17:50:48 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-01-17 17:50:48 -0500 |
| commit | 3c7e1be0098f963225afd0ebe83340a991392892 (patch) | |
| tree | 4be05c44125c3378cb5278cd8f7615fc280ea0fc | |
| parent | 668078ac8be89e55c8e13ac429c4b0e63fb604dc (diff) | |
Feature/hash for source identity (#786)
* * Added COMMAND_LINE_SIMPLE test type
* Made how spawning works controllable by paramter/type SpawnType
* Made break-outside-loop and global-uniform run command line slangc
* calcRelativePath -> calcCombinedPath
* Add 64 bit version of GetHash.
* Add support for Hash based mode for CacheFileSystem.
| -rw-r--r-- | slang.h | 4 | ||||
| -rw-r--r-- | source/core/hash.h | 15 | ||||
| -rw-r--r-- | source/slang/slang-file-system.cpp | 135 | ||||
| -rw-r--r-- | source/slang/slang-file-system.h | 23 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 14 | ||||
| -rw-r--r-- | tests/diagnostics/break-outside-loop.slang | 2 | ||||
| -rw-r--r-- | tests/diagnostics/break-outside-loop.slang.expected | 2 | ||||
| -rw-r--r-- | tests/diagnostics/global-uniform.slang | 2 | ||||
| -rw-r--r-- | tests/preprocessor/pragma-once.slang | 4 | ||||
| -rw-r--r-- | tools/slang-test/slang-test-main.cpp | 182 |
10 files changed, 260 insertions, 123 deletions
@@ -798,7 +798,7 @@ extern "C" const char* path, ISlangBlob** canonicalPathOut) = 0; - /** Get a path relative to a 'from' path. + /** Calculate a path combining the 'fromPath' with 'path' The client must ensure the blob be released when no longer used, otherwise memory will leak. @@ -808,7 +808,7 @@ extern "C" @param pathOut Holds the string which is the relative path. The string is held in the blob zero terminated. @returns A `SlangResult` to indicate success or failure in loading the file. */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcRelativePath( + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath( SlangPathType fromPathType, const char* fromPath, const char* path, diff --git a/source/core/hash.h b/source/core/hash.h index ca6172fc7..fc0bca737 100644 --- a/source/core/hash.h +++ b/source/core/hash.h @@ -43,7 +43,18 @@ namespace Slang } return hash; } - + + inline uint64_t GetHashCode64(const char * buffer, size_t numChars) + { + // Use uints because hash requires wrap around behavior and int is undefined on over/underflows + uint64_t hash = 0; + for (size_t i = 0; i < numChars; ++i) + { + hash = uint64_t(int64_t(buffer[i])) + (hash << 6) + (hash << 16) - hash; + } + return hash; + } + template<int IsInt> class Hash { @@ -111,4 +122,4 @@ namespace Slang } } -#endif
\ No newline at end of file +#endif diff --git a/source/slang/slang-file-system.cpp b/source/slang/slang-file-system.cpp index ef77dbf33..caaa9f56d 100644 --- a/source/slang/slang-file-system.cpp +++ b/source/slang/slang-file-system.cpp @@ -14,8 +14,8 @@ static const Guid IID_ISlangUnknown = SLANG_UUID_ISlangUnknown; static const Guid IID_ISlangFileSystem = SLANG_UUID_ISlangFileSystem; static const Guid IID_ISlangFileSystemExt = SLANG_UUID_ISlangFileSystemExt; -// Cacluate a relative path, just using Path:: string processing -static SlangResult _calcRelativePath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +// Cacluate a combined path, just using Path:: string processing +static SlangResult _calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) { String relPath; switch (fromPathType) @@ -60,9 +60,9 @@ SlangResult DefaultFileSystem::getCanoncialPath(const char* path, ISlangBlob** c return SLANG_OK; } -SlangResult DefaultFileSystem::calcRelativePath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +SlangResult DefaultFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) { - return _calcRelativePath(fromPathType, fromPath, path, pathOut); + return _calcCombinedPath(fromPathType, fromPath, path, pathOut); } SlangResult SLANG_MCALL DefaultFileSystem::getPathType( @@ -127,12 +127,25 @@ ISlangUnknown* CacheFileSystem::getInterface(const Guid& guid) return _getInterface(this, guid); } -CacheFileSystem::CacheFileSystem(ISlangFileSystem* fileSystem, bool useSimplifyForCanonicalPath) : +CacheFileSystem::CacheFileSystem(ISlangFileSystem* fileSystem, CanonicalMode canonicalMode) : m_fileSystem(fileSystem), - m_useSimplifyForCanonicalPath(useSimplifyForCanonicalPath) + m_canonicalMode(canonicalMode) { // Try to get the more sophisticated interface fileSystem->queryInterface(IID_ISlangFileSystemExt, (void**)m_fileSystemExt.writeRef()); + + switch (canonicalMode) + { + case CanonicalMode::Default: + case CanonicalMode::FileSystemExt: + { + m_canonicalMode = m_fileSystemExt ? CanonicalMode::FileSystemExt : CanonicalMode::Hash; + break; + } + default: break; + } + // It can't be default + SLANG_ASSERT(m_canonicalMode != CanonicalMode::Default); } CacheFileSystem::~CacheFileSystem() @@ -143,45 +156,95 @@ CacheFileSystem::~CacheFileSystem() } } -CacheFileSystem::PathInfo* CacheFileSystem::_getPathInfo(const String& relPath) +CacheFileSystem::PathInfo* CacheFileSystem::_getPathInfoFromCanonical(const String& canonicalPath) { - PathInfo** infoPtr = m_pathMap.TryGetValue(relPath); + // First see if we have it.. if not add it + PathInfo** infoPtr = m_canonicalMap.TryGetValue(canonicalPath); if (infoPtr) { return *infoPtr; } - - String canonicalPath; - if (m_fileSystemExt) - { - // Try getting the canonical path - // Okay request from the underlying file system the canonical path - ComPtr<ISlangBlob> canonicalBlob; - if (SLANG_FAILED(m_fileSystemExt->getCanoncialPath(relPath.Buffer(), canonicalBlob.writeRef()))) - { - // Write in result as being null ptr so not tried again - m_pathMap.Add(relPath, nullptr); - return nullptr; - } - // Get the path as a string - canonicalPath = StringUtil::getString(canonicalBlob); - } else { - canonicalPath = m_useSimplifyForCanonicalPath ? Path::Simplify(relPath.getUnownedSlice()) : relPath; + // Create and add to canonical path + PathInfo* pathInfo = new PathInfo(canonicalPath); + m_canonicalMap.Add(canonicalPath, pathInfo); + return pathInfo; } +} - PathInfo* pathInfo; - infoPtr = m_canonicalMap.TryGetValue(canonicalPath); +CacheFileSystem::PathInfo* CacheFileSystem::_getPathInfo(const String& relPath) +{ + PathInfo** infoPtr = m_pathMap.TryGetValue(relPath); if (infoPtr) { - pathInfo = *infoPtr; + return *infoPtr; } - else + + PathInfo* pathInfo = nullptr; + switch (m_canonicalMode) { - // Create and add to canonical path - pathInfo = new PathInfo(canonicalPath); - m_canonicalMap.Add(canonicalPath, pathInfo); + case CanonicalMode::FileSystemExt: + { + // Try getting the canonical path + // Okay request from the underlying file system the canonical path + ComPtr<ISlangBlob> canonicalBlob; + if (SLANG_FAILED(m_fileSystemExt->getCanoncialPath(relPath.Buffer(), canonicalBlob.writeRef()))) + { + // Write in result as being null ptr so not tried again + m_pathMap.Add(relPath, nullptr); + return nullptr; + } + // Get the path as a string + String canonicalPath = StringUtil::getString(canonicalBlob); + pathInfo = _getPathInfoFromCanonical(canonicalPath); + break; + } + case CanonicalMode::Path: + { + pathInfo = _getPathInfoFromCanonical(relPath); + break; + } + case CanonicalMode::SimplifiedPath: + { + pathInfo = _getPathInfoFromCanonical(Path::Simplify(relPath.getUnownedSlice())); + break; + } + case CanonicalMode::Hash: + { + // I can only see if this is the same file as already loaded by loading the file and doing a hash + ComPtr<ISlangBlob> fileBlob; + Result res = m_fileSystem->loadFile(relPath.Buffer(), fileBlob.writeRef()); + if (SLANG_FAILED(res) || fileBlob == nullptr) + { + // Write in result as being null ptr so not tried again + m_pathMap.Add(relPath, nullptr); + return nullptr; + } + + // Calculate the hash on the contents + const uint64_t hash = GetHashCode64((const char*)fileBlob->getBufferPointer(), fileBlob->getBufferSize()); + + String hashString = Path::GetFileName(relPath); + hashString = hashString.ToLower(); + + hashString.append(':'); + + // The canonical name is.. combination of name and hash + hashString.append(hash, 16); + // We'll use the 'hashString' as the canonical path + pathInfo = _getPathInfoFromCanonical(hashString); + + // We have the contents, so store it on the PathInfo, along with the result + if (pathInfo->m_loadFileResult == CompressedResult::Uninitialized) + { + // Save the contents of the saved file + pathInfo->m_loadFileResult = toCompressedResult(res); + pathInfo->m_fileBlob = fileBlob; + } + + break; + } } // Add the relPath @@ -224,17 +287,17 @@ SlangResult CacheFileSystem::getCanoncialPath(const char* path, ISlangBlob** can return SLANG_OK; } -SlangResult CacheFileSystem::calcRelativePath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +SlangResult CacheFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) { // Just defer to contained implementation if (m_fileSystemExt) { - return m_fileSystemExt->calcRelativePath(fromPathType, fromPath, path, pathOut); + return m_fileSystemExt->calcCombinedPath(fromPathType, fromPath, path, pathOut); } else { // Just use the default implementation - return _calcRelativePath(fromPathType, fromPath, path, pathOut); + return _calcCombinedPath(fromPathType, fromPath, path, pathOut); } } @@ -272,4 +335,4 @@ SlangResult CacheFileSystem::getPathType(const char* pathIn, SlangPathType* path return toResult(info->m_getPathTypeResult); } -}
\ No newline at end of file +} diff --git a/source/slang/slang-file-system.h b/source/slang/slang-file-system.h index b22dc4cb9..c949c66ff 100644 --- a/source/slang/slang-file-system.h +++ b/source/slang/slang-file-system.h @@ -30,7 +30,7 @@ public: const char* path, ISlangBlob** canonicalPathOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcRelativePath( + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath( SlangPathType fromPathType, const char* fromPath, const char* path, @@ -68,6 +68,15 @@ class CacheFileSystem: public ISlangFileSystemExt, public RefObject { public: + enum CanonicalMode + { + Default, ///< If passed, will default to the others depending on what kind of ISlangFileSystem is passed in + Path, ///< Just use the path as is + SimplifiedPath, ///< Use the input path 'simplified' (ie removing . and .. aspects) + Hash, ///< Use hashing + FileSystemExt, ///< Use the file system extended interface. + }; + /* Cannot change order/add members without changing s_compressedResultToResult */ enum class CompressedResult: uint8_t { @@ -92,7 +101,7 @@ class CacheFileSystem: public ISlangFileSystemExt, public RefObject const char* path, ISlangBlob** canonicalPathOut) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcRelativePath( + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath( SlangPathType fromPathType, const char* fromPath, const char* path, @@ -103,7 +112,7 @@ class CacheFileSystem: public ISlangFileSystemExt, public RefObject SlangPathType* pathTypeOut) SLANG_OVERRIDE; /// Ctor - CacheFileSystem(ISlangFileSystem* fileSystem, bool useSimplifyForCanonicalPath = false); + CacheFileSystem(ISlangFileSystem* fileSystem, CanonicalMode canonicalMode = CanonicalMode::Default); /// Dtor virtual ~CacheFileSystem(); @@ -123,6 +132,8 @@ protected: m_loadFileResult = CompressedResult::Uninitialized; m_getPathTypeResult = CompressedResult::Uninitialized; + + m_pathType = SLANG_PATH_TYPE_FILE; } ~PathInfo() { @@ -140,6 +151,8 @@ protected: /// For a given relPath gets a PathInfo PathInfo* _getPathInfo(const String& relPath); + /// Get path from a canonical path + PathInfo* _getPathInfoFromCanonical(const String& canonicalPath); /* TODO: This may be improved by mapping to a ISlangBlob. This makes output fast and easy, and if constructed as a StringBlob, we can just static_cast to get as a string to use internally, instead of constantly converting. @@ -149,7 +162,7 @@ protected: Dictionary<String, PathInfo*> m_pathMap; ///< Maps a path to a canonical path Dictionary<String, PathInfo*> m_canonicalMap; ///< Maps a canonical path to a files contents. This OWNs the PathInfo. - bool m_useSimplifyForCanonicalPath; ///< If set will use Path::Simplify to create 'canonical' paths + CanonicalMode m_canonicalMode; ///< Determines how 'canonicalPath' is produced. Cannot be Default in usage. ComPtr<ISlangFileSystem> m_fileSystem; ///< Must always be set ComPtr<ISlangFileSystemExt> m_fileSystemExt; ///< Optionally set -> if not will fall back on the m_fileSystem @@ -157,4 +170,4 @@ protected: } -#endif // SLANG_FILE_SYSTEM_H_INCLUDED
\ No newline at end of file +#endif // SLANG_FILE_SYSTEM_H_INCLUDED diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 38b417960..23f7a4e47 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -102,16 +102,16 @@ struct IncludeHandlerImpl : IncludeHandler ISlangFileSystemExt* fileSystemExt = _getFileSystemExt(); // Get relative path - ComPtr<ISlangBlob> relPathBlob; - SLANG_RETURN_ON_FAIL(fileSystemExt->calcRelativePath(fromPathType, fromPath.begin(), path.begin(), relPathBlob.writeRef())); - String relPath(StringUtil::getString(relPathBlob)); - if (relPath.Length() <= 0) + ComPtr<ISlangBlob> combinedPathBlob; + SLANG_RETURN_ON_FAIL(fileSystemExt->calcCombinedPath(fromPathType, fromPath.begin(), path.begin(), combinedPathBlob.writeRef())); + String combinedPath(StringUtil::getString(combinedPathBlob)); + if (combinedPath.Length() <= 0) { return SLANG_FAIL; } SlangPathType pathType; - SLANG_RETURN_ON_FAIL(fileSystemExt->getPathType(relPath.begin(), &pathType)); + SLANG_RETURN_ON_FAIL(fileSystemExt->getPathType(combinedPath.begin(), &pathType)); if (pathType != SLANG_PATH_TYPE_FILE) { return SLANG_E_NOT_FOUND; @@ -119,7 +119,7 @@ struct IncludeHandlerImpl : IncludeHandler // Get the canonical path ComPtr<ISlangBlob> canonicalPathBlob; - SLANG_RETURN_ON_FAIL(fileSystemExt->getCanoncialPath(relPath.begin(), canonicalPathBlob.writeRef())); + SLANG_RETURN_ON_FAIL(fileSystemExt->getCanoncialPath(combinedPath.begin(), canonicalPathBlob.writeRef())); // If the rel path exists -> the canonical path MUST exists too String canonicalPath(StringUtil::getString(canonicalPathBlob)); @@ -130,7 +130,7 @@ struct IncludeHandlerImpl : IncludeHandler } pathInfoOut.type = PathInfo::Type::Normal; - pathInfoOut.foundPath = relPath; + pathInfoOut.foundPath = combinedPath; pathInfoOut.canonicalPath = canonicalPath; return SLANG_OK; } diff --git a/tests/diagnostics/break-outside-loop.slang b/tests/diagnostics/break-outside-loop.slang index f86b0bad6..0de64e2c5 100644 --- a/tests/diagnostics/break-outside-loop.slang +++ b/tests/diagnostics/break-outside-loop.slang @@ -1,4 +1,6 @@ //TEST:SIMPLE: +//TEST:COMMAND_LINE_SIMPLE: + // `break` where it isn't allowed void foo() { break; } diff --git a/tests/diagnostics/break-outside-loop.slang.expected b/tests/diagnostics/break-outside-loop.slang.expected index 80d79537b..94af34382 100644 --- a/tests/diagnostics/break-outside-loop.slang.expected +++ b/tests/diagnostics/break-outside-loop.slang.expected @@ -1,6 +1,6 @@ result code = -1 standard error = { -tests/diagnostics/break-outside-loop.slang(4): error 30003: 'break' must appear inside loop constructs. +tests/diagnostics/break-outside-loop.slang(6): error 30003: 'break' must appear inside loop constructs. } standard output = { } diff --git a/tests/diagnostics/global-uniform.slang b/tests/diagnostics/global-uniform.slang index a3f17e536..6d3189cbc 100644 --- a/tests/diagnostics/global-uniform.slang +++ b/tests/diagnostics/global-uniform.slang @@ -1,6 +1,6 @@ // global-uniform.slang //TEST:SIMPLE:-target hlsl - +//TEST:COMMAND_LINE_SIMPLE:-target hlsl // Any attempt to declare a global variable that actually declares a // global uniform should be diagnosed as unsupported. diff --git a/tests/preprocessor/pragma-once.slang b/tests/preprocessor/pragma-once.slang index fe805f82f..02db6e3b3 100644 --- a/tests/preprocessor/pragma-once.slang +++ b/tests/preprocessor/pragma-once.slang @@ -27,6 +27,10 @@ #include "pragma-once-a.h" #include "pragma-once-b.h" +// Make sure relative paths are handled +#include "./pragma-once-a.h" +#include "./pragma-once-a.h" + // Now let's use both the function and the // macro, to confirm that they are both // defined as expected. diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp index 9039dbf2b..06c2aaf67 100644 --- a/tools/slang-test/slang-test-main.cpp +++ b/tools/slang-test/slang-test-main.cpp @@ -47,6 +47,12 @@ struct FileTestList List<TestOptions> tests; }; +enum class SpawnType +{ + UseExe, + UseSharedLibrary, +}; + struct TestInput { // Path to the input file for the test @@ -63,6 +69,9 @@ struct TestInput // The list of tests that will be run on this file FileTestList const* testList; + + // Determines how the test will be spawned + SpawnType spawnType; }; typedef TestResult(*TestCallback)(TestContext* context, TestInput& input); @@ -345,92 +354,111 @@ TestResult gatherTestsForFile( return TestResult::Pass; } -OSError spawnAndWait(TestContext* context, const String& testPath, OSProcessSpawner& spawner) +OSError spawnAndWaitExe(TestContext* context, const String& testPath, OSProcessSpawner& spawner) { const auto& options = context->options; - - if (!options.useExes) - { - String exeName = Path::GetFileNameWithoutEXT(spawner.executableName_); - if (options.shouldBeVerbose) - { - StringBuilder builder; + if (options.shouldBeVerbose) + { + String commandLine = spawner.getCommandLine(); + context->reporter->messageFormat(TestMessageType::Info, "%s\n", commandLine.begin()); + } - builder << "slang-test"; + OSError err = spawner.spawnAndWaitForCompletion(); + if (err != kOSError_None) + { + // fprintf(stderr, "failed to run test '%S'\n", testPath.ToWString()); + context->reporter->messageFormat(TestMessageType::RunError, "failed to run test '%S'", testPath.ToWString().begin()); + } + return err; +} - if (options.binDir) - { - builder << " -bindir " << options.binDir; - } +OSError spawnAndWaitSharedLibrary(TestContext* context, const String& testPath, OSProcessSpawner& spawner) +{ + const auto& options = context->options; + String exeName = Path::GetFileNameWithoutEXT(spawner.executableName_); - builder << " " << exeName; + if (options.shouldBeVerbose) + { + StringBuilder builder; - // TODO(js): Potentially this should handle escaping parameters for the command line if need be - const auto& argList = spawner.argumentList_; - for (UInt i = 0; i < argList.Count(); ++i) - { - builder << " " << argList[i]; - } + builder << "slang-test"; - context->reporter->messageFormat(TestMessageType::Info, "%s\n", builder.begin()); + if (options.binDir) + { + builder << " -bindir " << options.binDir; } - auto func = context->getInnerMainFunc(String(context->options.binDir), exeName); - if (func) + builder << " " << exeName; + + // TODO(js): Potentially this should handle escaping parameters for the command line if need be + const auto& argList = spawner.argumentList_; + for (UInt i = 0; i < argList.Count(); ++i) { - StringBuilder stdErrorString; - StringBuilder stdOutString; + builder << " " << argList[i]; + } - // Say static so not released - StringWriter stdError(&stdErrorString, WriterFlag::IsConsole | WriterFlag::IsStatic); - StringWriter stdOut(&stdOutString, WriterFlag::IsConsole | WriterFlag::IsStatic); + context->reporter->messageFormat(TestMessageType::Info, "%s\n", builder.begin()); + } - StdWriters* prevStdWriters = StdWriters::getSingleton(); + auto func = context->getInnerMainFunc(String(context->options.binDir), exeName); + if (func) + { + StringBuilder stdErrorString; + StringBuilder stdOutString; - StdWriters stdWriters; - stdWriters.setWriter(SLANG_WRITER_CHANNEL_STD_ERROR, &stdError); - stdWriters.setWriter(SLANG_WRITER_CHANNEL_STD_OUTPUT, &stdOut); + // Say static so not released + StringWriter stdError(&stdErrorString, WriterFlag::IsConsole | WriterFlag::IsStatic); + StringWriter stdOut(&stdOutString, WriterFlag::IsConsole | WriterFlag::IsStatic); - if (exeName == "slangc") - { - stdWriters.setWriter(SLANG_WRITER_CHANNEL_DIAGNOSTIC, &stdError); - } - - List<const char*> args; - args.Add(exeName.Buffer()); - for (int i = 0; i < int(spawner.argumentList_.Count()); ++i) - { - args.Add(spawner.argumentList_[i].Buffer()); - } + StdWriters* prevStdWriters = StdWriters::getSingleton(); - SlangResult res = func(&stdWriters, context->getSession(), int(args.Count()), args.begin()); + StdWriters stdWriters; + stdWriters.setWriter(SLANG_WRITER_CHANNEL_STD_ERROR, &stdError); + stdWriters.setWriter(SLANG_WRITER_CHANNEL_STD_OUTPUT, &stdOut); - StdWriters::setSingleton(prevStdWriters); + if (exeName == "slangc") + { + stdWriters.setWriter(SLANG_WRITER_CHANNEL_DIAGNOSTIC, &stdError); + } - spawner.standardError_ = stdErrorString; - spawner.standardOutput_ = stdOutString; + List<const char*> args; + args.Add(exeName.Buffer()); + for (int i = 0; i < int(spawner.argumentList_.Count()); ++i) + { + args.Add(spawner.argumentList_[i].Buffer()); + } - spawner.resultCode_ = TestToolUtil::getReturnCode(res); + SlangResult res = func(&stdWriters, context->getSession(), int(args.Count()), args.begin()); - return kOSError_None; - } - } + StdWriters::setSingleton(prevStdWriters); - if (options.shouldBeVerbose) - { - String commandLine = spawner.getCommandLine(); - context->reporter->messageFormat(TestMessageType::Info, "%s\n", commandLine.begin()); + spawner.standardError_ = stdErrorString; + spawner.standardOutput_ = stdOutString; + + spawner.resultCode_ = TestToolUtil::getReturnCode(res); + + return kOSError_None; } + return kOSError_OperationFailed; +} - OSError err = spawner.spawnAndWaitForCompletion(); - if (err != kOSError_None) + +OSError spawnAndWait(TestContext* context, const String& testPath, SpawnType spawnType, OSProcessSpawner& spawner) +{ + switch (spawnType) { -// fprintf(stderr, "failed to run test '%S'\n", testPath.ToWString()); - context->reporter->messageFormat(TestMessageType::RunError, "failed to run test '%S'", testPath.ToWString().begin()); + case SpawnType::UseExe: + { + return spawnAndWaitExe(context, testPath, spawner); + } + case SpawnType::UseSharedLibrary: + { + return spawnAndWaitSharedLibrary(context, testPath, spawner); + } } - return err; + return kOSError_OperationFailed; } String getOutput(OSProcessSpawner& spawner) @@ -491,6 +519,7 @@ String findExpectedPath(const TestInput& input, const char* postFix) return ""; } + TestResult runSimpleTest(TestContext* context, TestInput& input) { // need to execute the stand-alone Slang compiler on the file, and compare its output to what we expect @@ -508,7 +537,7 @@ TestResult runSimpleTest(TestContext* context, TestInput& input) spawner.pushArgument(arg); } - if (spawnAndWait(context, outputStem, spawner) != kOSError_None) + if (spawnAndWait(context, outputStem, input.spawnType, spawner) != kOSError_None) { return TestResult::Fail; } @@ -555,6 +584,17 @@ TestResult runSimpleTest(TestContext* context, TestInput& input) return result; } +TestResult runSimpleCompareCommandLineTest(TestContext* context, TestInput& input) +{ + TestInput workInput(input); + // Use the original files input to compare with + workInput.outputStem = input.filePath; + // Force to using exes + workInput.spawnType = SpawnType::UseExe; + + return runSimpleTest(context, workInput); +} + TestResult runReflectionTest(TestContext* context, TestInput& input) { const auto& options = context->options; @@ -571,7 +611,7 @@ TestResult runReflectionTest(TestContext* context, TestInput& input) spawner.pushArgument(arg); } - if (spawnAndWait(context, outputStem, spawner) != kOSError_None) + if (spawnAndWait(context, outputStem, input.spawnType, spawner) != kOSError_None) { return TestResult::Fail; } @@ -720,7 +760,7 @@ TestResult runCrossCompilerTest(TestContext* context, TestInput& input) expectedSpawner.pushArgument(arg); } - if (spawnAndWait(context, outputStem, expectedSpawner) != kOSError_None) + if (spawnAndWait(context, outputStem, input.spawnType, expectedSpawner) != kOSError_None) { return TestResult::Fail; } @@ -736,7 +776,7 @@ TestResult runCrossCompilerTest(TestContext* context, TestInput& input) return TestResult::Fail; } - if (spawnAndWait(context, outputStem, actualSpawner) != kOSError_None) + if (spawnAndWait(context, outputStem, input.spawnType, actualSpawner) != kOSError_None) { return TestResult::Fail; } @@ -794,7 +834,7 @@ TestResult generateHLSLBaseline(TestContext* context, TestInput& input) spawner.pushArgument("-pass-through"); spawner.pushArgument("fxc"); - if (spawnAndWait(context, outputStem, spawner) != kOSError_None) + if (spawnAndWait(context, outputStem, input.spawnType, spawner) != kOSError_None) { return TestResult::Fail; } @@ -842,7 +882,7 @@ TestResult runHLSLComparisonTest(TestContext* context, TestInput& input) spawner.pushArgument("-target"); spawner.pushArgument("dxbc-assembly"); - if (spawnAndWait(context, outputStem, spawner) != kOSError_None) + if (spawnAndWait(context, outputStem, input.spawnType, spawner) != kOSError_None) { return TestResult::Fail; } @@ -951,7 +991,7 @@ TestResult doGLSLComparisonTestRun(TestContext* context, spawner.pushArgument(arg); } - if (spawnAndWait(context, outputStem, spawner) != kOSError_None) + if (spawnAndWait(context, outputStem, input.spawnType, spawner) != kOSError_None) { return TestResult::Fail; } @@ -1040,7 +1080,7 @@ TestResult runComputeComparisonImpl(TestContext* context, TestInput& input, cons // clear the stale actual output file first. This will allow us to detect error if render-test fails and outputs nothing. File::WriteAllText(actualOutputFile, ""); - if (spawnAndWait(context, outputStem, spawner) != kOSError_None) + if (spawnAndWait(context, outputStem, input.spawnType, spawner) != kOSError_None) { printf("error spawning render-test\n"); return TestResult::Fail; @@ -1139,7 +1179,7 @@ TestResult doRenderComparisonTestRun(TestContext* context, TestInput& input, cha spawner.pushArgument("-o"); spawner.pushArgument(outputStem + outputKind + ".png"); - if (spawnAndWait(context, outputStem, spawner) != kOSError_None) + if (spawnAndWait(context, outputStem, input.spawnType, spawner) != kOSError_None) { return TestResult::Fail; } @@ -1499,6 +1539,7 @@ TestResult runTest( { { "SIMPLE", &runSimpleTest}, { "REFLECTION", &runReflectionTest}, + { "COMMAND_LINE_SIMPLE", &runSimpleCompareCommandLineTest}, #if SLANG_TEST_SUPPORT_HLSL { "COMPARE_HLSL", &runHLSLComparisonTest}, { "COMPARE_HLSL_RENDER", &runHLSLRenderComparisonTest}, @@ -1524,6 +1565,8 @@ TestResult runTest( { nullptr, nullptr }, }; + const SpawnType defaultSpawnType = context->options.useExes ? SpawnType::UseExe : SpawnType::UseSharedLibrary; + for( auto ii = kTestCommands; ii->name; ++ii ) { if(testOptions.command != ii->name) @@ -1534,6 +1577,7 @@ TestResult runTest( testInput.outputStem = outputStem; testInput.testOptions = &testOptions; testInput.testList = &testList; + testInput.spawnType = defaultSpawnType; { TestReporter* reporter = context->reporter; |
