summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-01-17 17:50:48 -0500
committerGitHub <noreply@github.com>2019-01-17 17:50:48 -0500
commit3c7e1be0098f963225afd0ebe83340a991392892 (patch)
tree4be05c44125c3378cb5278cd8f7615fc280ea0fc
parent668078ac8be89e55c8e13ac429c4b0e63fb604dc (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.h4
-rw-r--r--source/core/hash.h15
-rw-r--r--source/slang/slang-file-system.cpp135
-rw-r--r--source/slang/slang-file-system.h23
-rw-r--r--source/slang/slang.cpp14
-rw-r--r--tests/diagnostics/break-outside-loop.slang2
-rw-r--r--tests/diagnostics/break-outside-loop.slang.expected2
-rw-r--r--tests/diagnostics/global-uniform.slang2
-rw-r--r--tests/preprocessor/pragma-once.slang4
-rw-r--r--tools/slang-test/slang-test-main.cpp182
10 files changed, 260 insertions, 123 deletions
diff --git a/slang.h b/slang.h
index 63438891b..2fe90195d 100644
--- a/slang.h
+++ b/slang.h
@@ -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;