summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/slang-test/main.cpp73
-rw-r--r--tools/slang-test/os.cpp262
-rw-r--r--tools/slang-test/os.h24
3 files changed, 339 insertions, 20 deletions
diff --git a/tools/slang-test/main.cpp b/tools/slang-test/main.cpp
index 563fc5dab..50716d2c4 100644
--- a/tools/slang-test/main.cpp
+++ b/tools/slang-test/main.cpp
@@ -179,7 +179,7 @@ void parseOptions(int* argc, char** argv)
}
// any arguments left over were positional arguments
- argCount = (int)(writeCursor - argv);
+ argCount = (int)((char**)writeCursor - argv);
argCursor = argv;
argEnd = argCursor + argCount;
@@ -548,14 +548,15 @@ OSError spawnAndWait(String testPath, OSProcessSpawner& spawner)
{
if( options.shouldBeVerbose )
{
- fprintf(stderr, "%s\n", spawner.commandLine_.ToString().begin());
+ String commandLine = spawner.getCommandLine();
+ fprintf(stderr, "%s\n", commandLine.begin());
}
OSError err = spawner.spawnAndWaitForCompletion();
if (err != kOSError_None)
{
// fprintf(stderr, "failed to run test '%S'\n", testPath.ToWString());
- error("failed to run test '%S'", testPath.ToWString());
+ error("failed to run test '%S'", testPath.ToWString().begin());
}
return err;
}
@@ -580,6 +581,8 @@ String getOutput(OSProcessSpawner& spawner)
return actualOutputBuilder.ProduceString();
}
+List<String> gFailedTests;
+
struct TestInput
{
// Path to the input file for the test
@@ -609,7 +612,7 @@ TestResult runSimpleTest(TestInput& input)
OSProcessSpawner spawner;
- spawner.pushExecutablePath(String(options.binDir) + "slangc.exe");
+ spawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix());
spawner.pushArgument(filePath999);
for( auto arg : input.testOptions->args )
@@ -680,7 +683,7 @@ TestResult runEvalTest(TestInput& input)
OSProcessSpawner spawner;
- spawner.pushExecutablePath(String(options.binDir) + "slang-eval-test.exe");
+ spawner.pushExecutablePath(String(options.binDir) + "slang-eval-test" + osGetExecutableSuffix());
spawner.pushArgument(filePath);
for( auto arg : input.testOptions->args )
@@ -754,8 +757,8 @@ TestResult runCrossCompilerTest(TestInput& input)
OSProcessSpawner actualSpawner;
OSProcessSpawner expectedSpawner;
- actualSpawner.pushExecutablePath(String(options.binDir) + "slangc.exe");
- expectedSpawner.pushExecutablePath(String(options.binDir) + "slangc.exe");
+ actualSpawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix());
+ expectedSpawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix());
actualSpawner.pushArgument(filePath);
expectedSpawner.pushArgument(filePath + ".glsl");
@@ -827,7 +830,7 @@ TestResult generateHLSLBaseline(TestInput& input)
auto outputStem = input.outputStem;
OSProcessSpawner spawner;
- spawner.pushExecutablePath(String(options.binDir) + "slangc.exe");
+ spawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix());
spawner.pushArgument(filePath999);
for( auto arg : input.testOptions->args )
@@ -873,7 +876,7 @@ TestResult runHLSLComparisonTest(TestInput& input)
OSProcessSpawner spawner;
- spawner.pushExecutablePath(String(options.binDir) + "slangc.exe");
+ spawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix());
spawner.pushArgument(filePath999);
for( auto arg : input.testOptions->args )
@@ -973,7 +976,7 @@ TestResult doGLSLComparisonTestRun(
OSProcessSpawner spawner;
- spawner.pushExecutablePath(String(options.binDir) + "slangc.exe");
+ spawner.pushExecutablePath(String(options.binDir) + "slangc" + osGetExecutableSuffix());
spawner.pushArgument(filePath999);
if( langDefine )
@@ -1062,7 +1065,7 @@ TestResult doRenderComparisonTestRun(TestInput& input, char const* langOption, c
OSProcessSpawner spawner;
- spawner.pushExecutablePath(String(options.binDir) + "render-test.exe");
+ spawner.pushExecutablePath(String(options.binDir) + "render-test" + osGetExecutableSuffix());
spawner.pushArgument(filePath999);
for( auto arg : input.testOptions->args )
@@ -1217,6 +1220,11 @@ TestResult runHLSLAndGLSLComparisonTest(TestInput& input)
return runHLSLRenderComparisonTestImpl(input, "-hlsl-rewrite", "-glsl-rewrite");
}
+TestResult skipTest(TestInput& input)
+{
+ return kTestResult_Ignored;
+}
+
TestResult runTest(
String const& filePath,
String const& outputStem,
@@ -1230,10 +1238,17 @@ TestResult runTest(
TestCallback callback;
} kTestCommands[] = {
{ "SIMPLE", &runSimpleTest },
+#if SLANG_TEST_SUPPORT_HLSL
{ "COMPARE_HLSL", &runHLSLComparisonTest },
{ "COMPARE_HLSL_RENDER", &runHLSLRenderComparisonTest },
{ "COMPARE_HLSL_CROSS_COMPILE_RENDER", &runHLSLCrossCompileRenderComparisonTest},
{ "COMPARE_HLSL_GLSL_RENDER", &runHLSLAndGLSLComparisonTest },
+#else
+ { "COMPARE_HLSL", &skipTest },
+ { "COMPARE_HLSL_RENDER", &skipTest },
+ { "COMPARE_HLSL_CROSS_COMPILE_RENDER", &skipTest},
+ { "COMPARE_HLSL_GLSL_RENDER", &skipTest },
+#endif
{ "COMPARE_GLSL", &runGLSLComparisonTest },
{ "CROSS_COMPILE", &runCrossCompilerTest },
{ "EVAL", &runEvalTest },
@@ -1265,6 +1280,7 @@ struct TestContext
int totalTestCount;
int passedTestCount;
int failedTestCount;
+ int ignoredTestCount;
};
// deal with the fallout of a test having completed, whether
@@ -1278,6 +1294,7 @@ void handleTestResult(
{
case kTestResult_Fail:
context->failedTestCount++;
+ gFailedTests.Add(testName);
break;
case kTestResult_Pass:
@@ -1285,8 +1302,7 @@ void handleTestResult(
break;
case kTestResult_Ignored:
- // Note that we don't currently add ignored tests into
- // the totals, which is kind of inaccurate.
+ context->ignoredTestCount++;
break;
default:
@@ -1344,7 +1360,7 @@ void handleTestResult(
if( err != kOSError_None )
{
- error("failed to add appveyor test results for '%S'\n", testName.ToWString());
+ error("failed to add appveyor test results for '%S'\n", testName.ToWString().begin());
#if 0
fprintf(stderr, "[%d] TEST RESULT: %s {%d} {%s} {%s}\n", err, spawner.commandLine_.Buffer(),
@@ -1512,6 +1528,7 @@ void runTestsInDirectory(
{
if( shouldRunTest(context, file) )
{
+// fprintf(stderr, "slang-test: found '%s'\n", file.Buffer());
runTestsOnFile(context, file);
}
}
@@ -1571,6 +1588,30 @@ int main(
return 0;
}
- printf("\n===\n%d%% of tests passed (%d/%d)\n===\n\n", (context.passedTestCount*100) / context.totalTestCount, context.passedTestCount, context.totalTestCount);
- return context.passedTestCount == context.totalTestCount ? 0 : 1;
+
+ auto passCount = context.passedTestCount;
+ auto rawTotal = context.totalTestCount;
+ auto ignoredCount = context.ignoredTestCount;
+
+ auto runTotal = rawTotal - ignoredCount;
+
+ printf("\n===\n%d%% of tests passed (%d/%d)", (passCount*100) / runTotal, passCount, runTotal);
+ if(ignoredCount)
+ {
+ printf(", %d tests ingored", ignoredCount);
+ }
+ printf("\n===\n\n");
+
+ if(context.failedTestCount)
+ {
+ printf("failing tests:\n");
+ printf("---\n");
+ for(auto name : gFailedTests)
+ {
+ printf("%s\n", name.Buffer());
+ }
+ printf("---\n");
+ }
+
+ return passCount == runTotal ? 0 : 1;
}
diff --git a/tools/slang-test/os.cpp b/tools/slang-test/os.cpp
index 40fd8afff..18f81318d 100644
--- a/tools/slang-test/os.cpp
+++ b/tools/slang-test/os.cpp
@@ -224,6 +224,11 @@ void OSProcessSpawner::pushArgument(
commandLine_.Append(argument);
}
+Slang::String OSProcessSpawner::getCommandLine()
+{
+ return commandLine_;
+}
+
OSError OSProcessSpawner::spawnAndWaitForCompletion()
{
SECURITY_ATTRIBUTES securityAttributes;
@@ -372,8 +377,263 @@ OSError OSProcessSpawner::spawnAndWaitForCompletion()
return kOSError_None;
}
+char const* osGetExecutableSuffix()
+{
+ return ".exe";
+}
+
#else
-// TODO(tfoley): write a default POSIX implementation
+static bool advance(OSFindFilesResult& result)
+{
+ result.entry_ = readdir(result.directory_);
+ return result.entry_ != NULL;
+}
+
+static bool checkValidResult(OSFindFilesResult& result)
+{
+// fprintf(stderr, "checkValidResullt(%s)\n", result.entry_->d_name);
+
+ if (strcmp(result.entry_->d_name, ".") == 0)
+ return false;
+
+ if (strcmp(result.entry_->d_name, "..") == 0)
+ return false;
+
+ String path = result.directoryPath_
+ + String(result.entry_->d_name);
+
+// fprintf(stderr, "stat(%s)\n", path.Buffer());
+ struct stat fileInfo;
+ if(stat(path.Buffer(), &fileInfo) != 0)
+ return false;
+
+ if(S_ISDIR(fileInfo.st_mode))
+ path = path + "/";
+
+
+ result.filePath_ = path;
+ return true;
+}
+
+static bool adjustToValidResult(OSFindFilesResult& result)
+{
+ for (;;)
+ {
+ if(checkValidResult(result))
+ return true;
+
+ if (!advance(result))
+ return false;
+ }
+}
+
+
+bool OSFindFilesResult::findNextFile()
+{
+// fprintf(stderr, "OSFindFilesResult::findNextFile()\n");
+ if (!advance(*this)) return false;
+ return adjustToValidResult(*this);
+}
+
+OSFindFilesResult osFindFilesInDirectory(
+ Slang::String directoryPath)
+{
+ OSFindFilesResult result;
+
+// fprintf(stderr, "osFindFilesInDirectory(%s)\n", directoryPath.Buffer());
+
+ result.directory_ = opendir(directoryPath.Buffer());
+ if(!result.directory_)
+ {
+ result.entry_ = NULL;
+ return result;
+ }
+
+ result.directoryPath_ = directoryPath;
+ result.findNextFile();
+ return result;
+}
+
+OSFindFilesResult osFindChildDirectories(
+ Slang::String directoryPath)
+{
+ OSFindFilesResult result;
+
+ result.directory_ = opendir(directoryPath.Buffer());
+ if(!result.directory_)
+ {
+ result.entry_ = NULL;
+ return result;
+ }
+
+ // TODO: Set attributes to ignore everything but directories
+
+ result.directoryPath_ = directoryPath;
+ result.findNextFile();
+ return result;
+}
+
+// OSProcessSpawner
+
+void OSProcessSpawner::pushExecutableName(
+ Slang::String executableName)
+{
+ executableName_ = executableName;
+ pushArgument(executableName);
+ isExecutablePath_ = false;
+}
+
+void OSProcessSpawner::pushExecutablePath(
+ Slang::String executablePath)
+{
+ executableName_ = executablePath;
+ pushArgument(executablePath);
+ isExecutablePath_ = true;
+}
+
+void OSProcessSpawner::pushArgument(
+ Slang::String argument)
+{
+ arguments_.Add(argument);
+}
+
+Slang::String OSProcessSpawner::getCommandLine()
+{
+ Slang::UInt argCount = arguments_.Count();
+
+ Slang::StringBuilder sb;
+ for(Slang::UInt ii = 0; ii < argCount; ++ii)
+ {
+ if(ii != 0) sb << " ";
+ sb << arguments_[ii];
+
+ }
+ return sb.ProduceString();
+}
+
+OSError OSProcessSpawner::spawnAndWaitForCompletion()
+{
+ List<char const*> argPtrs;
+ for(auto arg : arguments_)
+ {
+ argPtrs.Add(arg.Buffer());
+ }
+ argPtrs.Add(NULL);
+
+ int stdoutPipe[2];
+ int stderrPipe[2];
+
+ if(pipe(stdoutPipe) == -1)
+ return kOSError_OperationFailed;
+
+ if(pipe(stderrPipe) == -1)
+ return kOSError_OperationFailed;
+
+ pid_t childProcessID = fork();
+ if(childProcessID == 0)
+ {
+ // We are the child process.
+
+ dup2(stdoutPipe[1], STDOUT_FILENO);
+ dup2(stderrPipe[1], STDERR_FILENO);
+
+ close(stdoutPipe[0]);
+ close(stdoutPipe[1]);
+
+ close(stderrPipe[0]);
+ close(stderrPipe[1]);
+
+ execvp(
+ argPtrs[0],
+ (char* const*) &argPtrs[0]);
+
+ // If we get here, then `exec` failed
+ fprintf(stderr, "error: `exec` failed\n");
+ exit(1);
+ }
+ else
+ {
+ // We are the parent process
+
+ close(stdoutPipe[1]);
+ close(stderrPipe[1]);
+
+ int stdoutFD = stdoutPipe[0];
+ int stderrFD = stderrPipe[0];
+
+ int maxFD = stdoutFD > stderrFD ? stdoutFD : stderrFD;
+
+ fd_set readSet;
+ int result;
+
+ int remainingCount = 2;
+ while(remainingCount)
+ {
+ FD_ZERO(&readSet);
+ FD_SET(stdoutFD, &readSet);
+ FD_SET(stderrFD, &readSet);
+
+ result = select(maxFD + 1, &readSet, NULL, NULL, NULL);
+
+ if(result == -1 || errno == EINTR)
+ continue;
+
+ enum { kBufferSize = 1024 };
+ char buffer[kBufferSize];
+
+ if(FD_ISSET(stdoutFD, &readSet))
+ {
+ auto count = read(stdoutFD, buffer, kBufferSize);
+ if(count == 0)
+ remainingCount--;
+
+ standardOutput_.append(
+ buffer, buffer + count);
+ }
+
+ if(FD_ISSET(stderrFD, &readSet))
+ {
+ auto count = read(stderrFD, buffer, kBufferSize);
+ if(count == 0)
+ remainingCount--;
+
+ standardError_.append(
+ buffer, buffer + count);
+ }
+ }
+
+ int childStatus = 0;
+ for(;;)
+ {
+ pid_t terminatedProcessID = wait(&childStatus);
+ if(terminatedProcessID == childProcessID)
+ {
+ if(WIFEXITED(childStatus))
+ {
+ resultCode_ = (int)(int8_t)WEXITSTATUS(childStatus);
+
+ }
+ else
+ {
+ resultCode_ = 1;
+ }
+
+ close(stdoutPipe[0]);
+ close(stderrPipe[0]);
+
+ return kOSError_None;
+ }
+ }
+
+ }
+
+ return kOSError_OperationFailed;
+}
+
+char const* osGetExecutableSuffix()
+{
+ return "";
+}
#endif
diff --git a/tools/slang-test/os.h b/tools/slang-test/os.h
index c6eb8f410..cc1fa4065 100644
--- a/tools/slang-test/os.h
+++ b/tools/slang-test/os.h
@@ -18,6 +18,14 @@
#undef NOMINMAX
#else
+
+#include <dirent.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
#endif
// A simple set of error codes for possible runtime failures
@@ -41,6 +49,8 @@ struct OSFindFilesResult
DWORD disallowedMask_;
OSError error_;
#else
+ DIR* directory_;
+ dirent* entry_;
#endif
bool findNextFile();
@@ -68,6 +78,7 @@ struct OSFindFilesResult
#ifdef WIN32
Iterator result = { findHandle_ ? this : NULL };
#else
+ Iterator result = { entry_ ? this : NULL };
#endif
return result;
}
@@ -138,6 +149,10 @@ struct OSProcessSpawner
void pushArgument(
Slang::String argument);
+ // Get a printable version of the command line
+ // that will be run (can be used for debugging)
+ Slang::String getCommandLine();
+
// Attempt to spawn the process, and wait for it to complete.
// Returns an error if the attempt to spawn and/or wait fails,
// but returns `kOSError_None` if the process is run to completion,
@@ -157,12 +172,15 @@ struct OSProcessSpawner
Slang::String standardOutput_;
Slang::String standardError_;
ResultCode resultCode_;
-#ifdef WIN32
Slang::String executableName_;
+#ifdef WIN32
Slang::StringBuilder commandLine_;
+#else
+ Slang::List<Slang::String> arguments_;
+#endif
// Is the executable specified by path, rather than just by name?
bool isExecutablePath_;
-#else
-#endif
};
+
+char const* osGetExecutableSuffix();