From bec8e6aec85b6e3f875c58bdd59eb15613978358 Mon Sep 17 00:00:00 2001 From: Yong He Date: Fri, 24 Sep 2021 11:33:44 -0700 Subject: Move existing unit tests to a standalone dll. (#1945) --- .../core-test-tool/core-test-tool.vcxproj | 194 +++++++++++++ .../core-test-tool/core-test-tool.vcxproj.filters | 57 ++++ .../gfx-unit-test-tool/gfx-unit-test-tool.vcxproj | 197 +++++++++++++ .../gfx-unit-test-tool.vcxproj.filters | 35 +++ build/visual-studio/slang-test/slang-test.vcxproj | 18 +- .../slang-test/slang-test.vcxproj.filters | 36 --- .../slang-unit-test-tool.vcxproj | 206 +++++++++++++ .../slang-unit-test-tool.vcxproj.filters | 57 ++++ premake5.lua | 12 +- slang.sln | 13 +- tools/gfx-test/compute-smoke.cpp | 145 ---------- tools/gfx-test/compute-smoke.slang | 68 ----- tools/gfx-test/gfx-test-util.cpp | 79 ----- tools/gfx-test/gfx-test-util.h | 38 --- tools/gfx-unit-test/compute-smoke.cpp | 144 +++++++++ tools/gfx-unit-test/compute-smoke.slang | 68 +++++ tools/gfx-unit-test/gfx-test-util.cpp | 86 ++++++ tools/gfx-unit-test/gfx-test-util.h | 41 +++ tools/slang-test/slang-test-main.cpp | 55 +--- tools/slang-test/test-reporter.cpp | 9 +- tools/slang-test/test-reporter.h | 64 +--- tools/slang-test/unit-offset-container.cpp | 119 -------- tools/slang-test/unit-test-byte-encode.cpp | 141 --------- tools/slang-test/unit-test-command-line-args.cpp | 126 -------- tools/slang-test/unit-test-compression.cpp | 190 ------------ tools/slang-test/unit-test-find-type-by-name.cpp | 56 ---- tools/slang-test/unit-test-free-list.cpp | 54 ---- tools/slang-test/unit-test-json.cpp | 321 --------------------- tools/slang-test/unit-test-memory-arena.cpp | 273 ------------------ tools/slang-test/unit-test-path.cpp | 64 ---- tools/slang-test/unit-test-riff.cpp | 180 ------------ tools/slang-test/unit-test-short-list.cpp | 78 ----- tools/slang-test/unit-test-string.cpp | 264 ----------------- tools/slang-unit-test/unit-offset-container.cpp | 117 ++++++++ tools/slang-unit-test/unit-test-byte-encode.cpp | 139 +++++++++ .../unit-test-command-line-args.cpp | 125 ++++++++ tools/slang-unit-test/unit-test-compression.cpp | 189 ++++++++++++ .../unit-test-find-type-by-name.cpp | 55 ++++ tools/slang-unit-test/unit-test-free-list.cpp | 53 ++++ tools/slang-unit-test/unit-test-json.cpp | 320 ++++++++++++++++++++ tools/slang-unit-test/unit-test-memory-arena.cpp | 271 +++++++++++++++++ tools/slang-unit-test/unit-test-path.cpp | 62 ++++ tools/slang-unit-test/unit-test-riff.cpp | 179 ++++++++++++ tools/slang-unit-test/unit-test-short-list.cpp | 77 +++++ tools/slang-unit-test/unit-test-string.cpp | 262 +++++++++++++++++ tools/unit-test/slang-unit-test.cpp | 27 +- tools/unit-test/slang-unit-test.h | 97 +++++-- 47 files changed, 3074 insertions(+), 2387 deletions(-) create mode 100644 build/visual-studio/core-test-tool/core-test-tool.vcxproj create mode 100644 build/visual-studio/core-test-tool/core-test-tool.vcxproj.filters create mode 100644 build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj create mode 100644 build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters create mode 100644 build/visual-studio/slang-unit-test-tool/slang-unit-test-tool.vcxproj create mode 100644 build/visual-studio/slang-unit-test-tool/slang-unit-test-tool.vcxproj.filters delete mode 100644 tools/gfx-test/compute-smoke.cpp delete mode 100644 tools/gfx-test/compute-smoke.slang delete mode 100644 tools/gfx-test/gfx-test-util.cpp delete mode 100644 tools/gfx-test/gfx-test-util.h create mode 100644 tools/gfx-unit-test/compute-smoke.cpp create mode 100644 tools/gfx-unit-test/compute-smoke.slang create mode 100644 tools/gfx-unit-test/gfx-test-util.cpp create mode 100644 tools/gfx-unit-test/gfx-test-util.h delete mode 100644 tools/slang-test/unit-offset-container.cpp delete mode 100644 tools/slang-test/unit-test-byte-encode.cpp delete mode 100644 tools/slang-test/unit-test-command-line-args.cpp delete mode 100644 tools/slang-test/unit-test-compression.cpp delete mode 100644 tools/slang-test/unit-test-find-type-by-name.cpp delete mode 100644 tools/slang-test/unit-test-free-list.cpp delete mode 100644 tools/slang-test/unit-test-json.cpp delete mode 100644 tools/slang-test/unit-test-memory-arena.cpp delete mode 100644 tools/slang-test/unit-test-path.cpp delete mode 100644 tools/slang-test/unit-test-riff.cpp delete mode 100644 tools/slang-test/unit-test-short-list.cpp delete mode 100644 tools/slang-test/unit-test-string.cpp create mode 100644 tools/slang-unit-test/unit-offset-container.cpp create mode 100644 tools/slang-unit-test/unit-test-byte-encode.cpp create mode 100644 tools/slang-unit-test/unit-test-command-line-args.cpp create mode 100644 tools/slang-unit-test/unit-test-compression.cpp create mode 100644 tools/slang-unit-test/unit-test-find-type-by-name.cpp create mode 100644 tools/slang-unit-test/unit-test-free-list.cpp create mode 100644 tools/slang-unit-test/unit-test-json.cpp create mode 100644 tools/slang-unit-test/unit-test-memory-arena.cpp create mode 100644 tools/slang-unit-test/unit-test-path.cpp create mode 100644 tools/slang-unit-test/unit-test-riff.cpp create mode 100644 tools/slang-unit-test/unit-test-short-list.cpp create mode 100644 tools/slang-unit-test/unit-test-string.cpp diff --git a/build/visual-studio/core-test-tool/core-test-tool.vcxproj b/build/visual-studio/core-test-tool/core-test-tool.vcxproj new file mode 100644 index 000000000..3c44ba9f3 --- /dev/null +++ b/build/visual-studio/core-test-tool/core-test-tool.vcxproj @@ -0,0 +1,194 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {0162864E-7651-4B5E-9105-C571105276EA} + true + Win32Proj + core-test-tool + + + + DynamicLibrary + true + Unicode + v142 + + + DynamicLibrary + true + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + + + + + + + + + + + + + + + + + true + ..\..\..\bin\windows-x86\debug\ + ..\..\..\intermediate\windows-x86\debug\core-test-tool\ + core-test-tool + .dll + + + true + ..\..\..\bin\windows-x64\debug\ + ..\..\..\intermediate\windows-x64\debug\core-test-tool\ + core-test-tool + .dll + + + false + ..\..\..\bin\windows-x86\release\ + ..\..\..\intermediate\windows-x86\release\core-test-tool\ + core-test-tool + .dll + + + false + ..\..\..\bin\windows-x64\release\ + ..\..\..\intermediate\windows-x64\release\core-test-tool\ + core-test-tool + .dll + + + + NotUsing + Level3 + _DEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + EditAndContinue + Disabled + MultiThreadedDebug + + + Windows + true + ..\..\..\bin\windows-x86\debug\core-test-tool.lib + + + + + NotUsing + Level3 + _DEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + EditAndContinue + Disabled + MultiThreadedDebug + + + Windows + true + ..\..\..\bin\windows-x64\debug\core-test-tool.lib + + + + + NotUsing + Level3 + NDEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + Full + true + true + false + true + MultiThreaded + + + Windows + true + true + ..\..\..\bin\windows-x86\release\core-test-tool.lib + + + + + NotUsing + Level3 + NDEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + Full + true + true + false + true + MultiThreaded + + + Windows + true + true + ..\..\..\bin\windows-x64\release\core-test-tool.lib + + + + + + + + + + + + + + + + + + + + + + + {F9BE7957-8399-899E-0C49-E714FDDD4B65} + + + + + + \ No newline at end of file diff --git a/build/visual-studio/core-test-tool/core-test-tool.vcxproj.filters b/build/visual-studio/core-test-tool/core-test-tool.vcxproj.filters new file mode 100644 index 000000000..8cf814b3b --- /dev/null +++ b/build/visual-studio/core-test-tool/core-test-tool.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {21EB8090-0D4E-1035-B6D3-48EBA215DCB7} + + + {E9C7FDCE-D52A-8D73-7EB0-C5296AF258F6} + + + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj new file mode 100644 index 000000000..4938b4ef7 --- /dev/null +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj @@ -0,0 +1,197 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {092DAB9F-1DA5-4538-ADD7-1A8D1DBFD519} + true + Win32Proj + gfx-unit-test-tool + + + + DynamicLibrary + true + Unicode + v142 + + + DynamicLibrary + true + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + + + + + + + + + + + + + + + + + true + ..\..\..\bin\windows-x86\debug\ + ..\..\..\intermediate\windows-x86\debug\gfx-unit-test-tool\ + gfx-unit-test-tool + .dll + + + true + ..\..\..\bin\windows-x64\debug\ + ..\..\..\intermediate\windows-x64\debug\gfx-unit-test-tool\ + gfx-unit-test-tool + .dll + + + false + ..\..\..\bin\windows-x86\release\ + ..\..\..\intermediate\windows-x86\release\gfx-unit-test-tool\ + gfx-unit-test-tool + .dll + + + false + ..\..\..\bin\windows-x64\release\ + ..\..\..\intermediate\windows-x64\release\gfx-unit-test-tool\ + gfx-unit-test-tool + .dll + + + + NotUsing + Level3 + _DEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + EditAndContinue + Disabled + MultiThreadedDebug + + + Windows + true + ..\..\..\bin\windows-x86\debug\gfx-unit-test-tool.lib + + + + + NotUsing + Level3 + _DEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + EditAndContinue + Disabled + MultiThreadedDebug + + + Windows + true + ..\..\..\bin\windows-x64\debug\gfx-unit-test-tool.lib + + + + + NotUsing + Level3 + NDEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + Full + true + true + false + true + MultiThreaded + + + Windows + true + true + ..\..\..\bin\windows-x86\release\gfx-unit-test-tool.lib + + + + + NotUsing + Level3 + NDEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + Full + true + true + false + true + MultiThreaded + + + Windows + true + true + ..\..\..\bin\windows-x64\release\gfx-unit-test-tool.lib + + + + + + + + + + + + + + + + + {F9BE7957-8399-899E-0C49-E714FDDD4B65} + + + {DB00DA62-0533-4AFD-B59F-A67D5B3A0808} + + + {222F7498-B40C-4F3F-A704-DDEB91A4484A} + + + {F5ADB74E-02A7-44FB-AA3B-FC02F8AC7A4B} + + + + + + \ No newline at end of file diff --git a/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters new file mode 100644 index 000000000..fcea7e877 --- /dev/null +++ b/build/visual-studio/gfx-unit-test-tool/gfx-unit-test-tool.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {21EB8090-0D4E-1035-B6D3-48EBA215DCB7} + + + {E9C7FDCE-D52A-8D73-7EB0-C5296AF258F6} + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/build/visual-studio/slang-test/slang-test.vcxproj b/build/visual-studio/slang-test/slang-test.vcxproj index 707ecbe2e..b1d5f0b0a 100644 --- a/build/visual-studio/slang-test/slang-test.vcxproj +++ b/build/visual-studio/slang-test/slang-test.vcxproj @@ -177,29 +177,17 @@ - - - - - - - - - - - - - - {F9BE7957-8399-899E-0C49-E714FDDD4B65} - {12C1E89D-F5D0-41D3-8E8D-FB3F358F8126} {DB00DA62-0533-4AFD-B59F-A67D5B3A0808} + + {F9BE7957-8399-899E-0C49-E714FDDD4B65} + {E76ACB11-4A12-4F0A-BE1E-CE0B8836EB7F} diff --git a/build/visual-studio/slang-test/slang-test.vcxproj.filters b/build/visual-studio/slang-test/slang-test.vcxproj.filters index 1e5b6e4af..4b11f896b 100644 --- a/build/visual-studio/slang-test/slang-test.vcxproj.filters +++ b/build/visual-studio/slang-test/slang-test.vcxproj.filters @@ -50,41 +50,5 @@ Source Files - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - \ No newline at end of file diff --git a/build/visual-studio/slang-unit-test-tool/slang-unit-test-tool.vcxproj b/build/visual-studio/slang-unit-test-tool/slang-unit-test-tool.vcxproj new file mode 100644 index 000000000..5b5c0674e --- /dev/null +++ b/build/visual-studio/slang-unit-test-tool/slang-unit-test-tool.vcxproj @@ -0,0 +1,206 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {0162864E-7651-4B5E-9105-C571105276EA} + true + Win32Proj + slang-unit-test-tool + + + + DynamicLibrary + true + Unicode + v142 + + + DynamicLibrary + true + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + DynamicLibrary + false + Unicode + v142 + + + + + + + + + + + + + + + + + + + true + ..\..\..\bin\windows-x86\debug\ + ..\..\..\intermediate\windows-x86\debug\slang-unit-test-tool\ + slang-unit-test-tool + .dll + + + true + ..\..\..\bin\windows-x64\debug\ + ..\..\..\intermediate\windows-x64\debug\slang-unit-test-tool\ + slang-unit-test-tool + .dll + + + false + ..\..\..\bin\windows-x86\release\ + ..\..\..\intermediate\windows-x86\release\slang-unit-test-tool\ + slang-unit-test-tool + .dll + + + false + ..\..\..\bin\windows-x64\release\ + ..\..\..\intermediate\windows-x64\release\slang-unit-test-tool\ + slang-unit-test-tool + .dll + + + + NotUsing + Level3 + _DEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + EditAndContinue + Disabled + MultiThreadedDebug + + + Windows + true + ..\..\..\bin\windows-x86\debug\slang-unit-test-tool.lib + + + + + NotUsing + Level3 + _DEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + EditAndContinue + Disabled + MultiThreadedDebug + + + Windows + true + ..\..\..\bin\windows-x64\debug\slang-unit-test-tool.lib + + + + + NotUsing + Level3 + NDEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + Full + true + true + false + true + MultiThreaded + + + Windows + true + true + ..\..\..\bin\windows-x86\release\slang-unit-test-tool.lib + + + + + NotUsing + Level3 + NDEBUG;SLANG_SHARED_LIBRARY_TOOL;%(PreprocessorDefinitions) + ..\..\..;%(AdditionalIncludeDirectories) + Full + true + true + false + true + MultiThreaded + + + Windows + true + true + ..\..\..\bin\windows-x64\release\slang-unit-test-tool.lib + + + + + + + + + + + + + + + + + + + + + + + {E1EC8075-823E-46E5-BC38-C124CCCDF878} + + + {E76ACB11-4A12-4F0A-BE1E-CE0B8836EB7F} + + + {F9BE7957-8399-899E-0C49-E714FDDD4B65} + + + {12C1E89D-F5D0-41D3-8E8D-FB3F358F8126} + + + {DB00DA62-0533-4AFD-B59F-A67D5B3A0808} + + + + + + \ No newline at end of file diff --git a/build/visual-studio/slang-unit-test-tool/slang-unit-test-tool.vcxproj.filters b/build/visual-studio/slang-unit-test-tool/slang-unit-test-tool.vcxproj.filters new file mode 100644 index 000000000..909229ed2 --- /dev/null +++ b/build/visual-studio/slang-unit-test-tool/slang-unit-test-tool.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {21EB8090-0D4E-1035-B6D3-48EBA215DCB7} + + + {E9C7FDCE-D52A-8D73-7EB0-C5296AF258F6} + + + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/premake5.lua b/premake5.lua index 02f8f3600..c5efe1885 100644 --- a/premake5.lua +++ b/premake5.lua @@ -755,7 +755,7 @@ tool "slang-embed" tool "slang-test" uuid "0C768A18-1D25-4000-9F37-DA5FE99E3B64" includedirs { "." } - links { "core", "compiler-core", "slang", "miniz", "lz4" } + links { "compiler-core", "slang", "core", "miniz", "lz4" } -- We want to set to the root of the project, but that doesn't seem to work with '.'. -- So set a path that resolves to the same place. @@ -1251,11 +1251,17 @@ standardProject("slang", "source/slang") defines { "SLANG_ENABLE_IR_BREAK_ALLOC=1" } filter {} -toolSharedLibrary "gfx-test" +toolSharedLibrary "gfx-unit-test" uuid "092DAB9F-1DA5-4538-ADD7-1A8D1DBFD519" includedirs { "." } addSourceDir "tools/unit-test" - links { "gfx", "gfx-util", "slang", "core" } + links { "core", "slang", "gfx", "gfx-util" } + +toolSharedLibrary "slang-unit-test" + uuid "0162864E-7651-4B5E-9105-C571105276EA" + includedirs { "." } + addSourceDir "tools/unit-test" + links { "lz4", "miniz", "core", "compiler-core", "slang" } if enableProfile then tool "slang-profile" diff --git a/slang.sln b/slang.sln index d5e430ae0..c7dc3950e 100644 --- a/slang.sln +++ b/slang.sln @@ -67,12 +67,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slangc", "build\visual-stud EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test-tool", "test-tool", "{57B5AA5E-C340-1823-CC51-9B17385C7423}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gfx-test-tool", "build\visual-studio\gfx-test-tool\gfx-test-tool.vcxproj", "{092DAB9F-1DA5-4538-ADD7-1A8D1DBFD519}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gfx-unit-test-tool", "build\visual-studio\gfx-unit-test-tool\gfx-unit-test-tool.vcxproj", "{092DAB9F-1DA5-4538-ADD7-1A8D1DBFD519}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "render-test-tool", "build\visual-studio\render-test-tool\render-test-tool.vcxproj", "{61F7EB00-7281-4BF3-9470-7C2EA92620C3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slang-reflection-test-tool", "build\visual-studio\slang-reflection-test-tool\slang-reflection-test-tool.vcxproj", "{C5ACCA6E-C04D-4B36-8516-3752B3C13C2F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slang-unit-test-tool", "build\visual-studio\slang-unit-test-tool\slang-unit-test-tool.vcxproj", "{0162864E-7651-4B5E-9105-C571105276EA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -305,6 +307,14 @@ Global {C5ACCA6E-C04D-4B36-8516-3752B3C13C2F}.Release|Win32.Build.0 = Release|Win32 {C5ACCA6E-C04D-4B36-8516-3752B3C13C2F}.Release|x64.ActiveCfg = Release|x64 {C5ACCA6E-C04D-4B36-8516-3752B3C13C2F}.Release|x64.Build.0 = Release|x64 + {0162864E-7651-4B5E-9105-C571105276EA}.Debug|Win32.ActiveCfg = Debug|Win32 + {0162864E-7651-4B5E-9105-C571105276EA}.Debug|Win32.Build.0 = Debug|Win32 + {0162864E-7651-4B5E-9105-C571105276EA}.Debug|x64.ActiveCfg = Debug|x64 + {0162864E-7651-4B5E-9105-C571105276EA}.Debug|x64.Build.0 = Debug|x64 + {0162864E-7651-4B5E-9105-C571105276EA}.Release|Win32.ActiveCfg = Release|Win32 + {0162864E-7651-4B5E-9105-C571105276EA}.Release|Win32.Build.0 = Release|Win32 + {0162864E-7651-4B5E-9105-C571105276EA}.Release|x64.ActiveCfg = Release|x64 + {0162864E-7651-4B5E-9105-C571105276EA}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -332,5 +342,6 @@ Global {092DAB9F-1DA5-4538-ADD7-1A8D1DBFD519} = {57B5AA5E-C340-1823-CC51-9B17385C7423} {61F7EB00-7281-4BF3-9470-7C2EA92620C3} = {57B5AA5E-C340-1823-CC51-9B17385C7423} {C5ACCA6E-C04D-4B36-8516-3752B3C13C2F} = {57B5AA5E-C340-1823-CC51-9B17385C7423} + {0162864E-7651-4B5E-9105-C571105276EA} = {57B5AA5E-C340-1823-CC51-9B17385C7423} EndGlobalSection EndGlobal diff --git a/tools/gfx-test/compute-smoke.cpp b/tools/gfx-test/compute-smoke.cpp deleted file mode 100644 index bbba72348..000000000 --- a/tools/gfx-test/compute-smoke.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "tools/unit-test/slang-unit-test.h" - -#include "slang-gfx.h" -#include "gfx-test-util.h" -#include "tools/gfx-util/shader-cursor.h" -#include "source/core/slang-basic.h" - -using namespace gfx; - -namespace gfx_test -{ - SlangResult computeSmokeTestImpl(IDevice* device, slang::UnitTestContext* context) - { - Slang::ComPtr transientHeap; - ITransientResourceHeap::Desc transientHeapDesc = {}; - transientHeapDesc.constantBufferSize = 4096; - SLANG_RETURN_ON_FAIL( - device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); - - ComPtr shaderProgram; - slang::ProgramLayout* slangReflection; - SLANG_RETURN_ON_FAIL(loadShaderProgram(device, shaderProgram, context->outputWriter, "compute-smoke", slangReflection)); - - ComputePipelineStateDesc pipelineDesc = {}; - pipelineDesc.program = shaderProgram.get(); - ComPtr pipelineState; - SLANG_RETURN_ON_FAIL( - device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); - - const int numberCount = 4; - float initialData[] = { 0.0f, 1.0f, 2.0f, 3.0f }; - IBufferResource::Desc bufferDesc = {}; - bufferDesc.sizeInBytes = numberCount * sizeof(float); - bufferDesc.format = gfx::Format::Unknown; - bufferDesc.elementSize = sizeof(float); - bufferDesc.allowedStates = ResourceStateSet( - ResourceState::ShaderResource, - ResourceState::UnorderedAccess, - ResourceState::CopyDestination, - ResourceState::CopySource); - bufferDesc.defaultState = ResourceState::UnorderedAccess; - bufferDesc.cpuAccessFlags = AccessFlag::Write | AccessFlag::Read; - - ComPtr numbersBuffer; - SLANG_RETURN_ON_FAIL(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); - - ComPtr bufferView; - IResourceView::Desc viewDesc = {}; - viewDesc.type = IResourceView::Type::UnorderedAccess; - viewDesc.format = Format::Unknown; - SLANG_RETURN_ON_FAIL(device->createBufferView(numbersBuffer, viewDesc, bufferView.writeRef())); - - // We have done all the set up work, now it is time to start recording a command buffer for - // GPU execution. - { - ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; - auto queue = device->createCommandQueue(queueDesc); - - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - - auto rootObject = encoder->bindPipeline(pipelineState); - - slang::TypeReflection* addTransformerType = - slangReflection->findTypeByName("AddTransformer"); - - // Now we can use this type to create a shader object that can be bound to the root object. - ComPtr transformer; - SLANG_RETURN_ON_FAIL(device->createShaderObject( - addTransformerType, ShaderObjectContainerType::None, transformer.writeRef())); - // Set the `c` field of the `AddTransformer`. - float c = 1.0f; - ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); - - ShaderCursor entryPointCursor( - rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. - // Bind buffer view to the entry point. - entryPointCursor.getPath("buffer").setResource(bufferView); - - // Bind the previously created transformer object to root object. - entryPointCursor.getPath("transformer").setObject(transformer); - - encoder->dispatchCompute(1, 1, 1); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - queue->wait(); - } - - return compareComputeResult( - device, - numbersBuffer, - Slang::makeArray(11.0f, 12.0f, 13.0f, 14.0f)); - } - - SlangResult computeSmokeTestAPI(slang::UnitTestContext* context, Slang::RenderApiFlag::Enum api) - { - if ((api & context->enabledApis) == 0) - { - return SLANG_E_NOT_AVAILABLE; - } - Slang::ComPtr device; - IDevice::Desc deviceDesc = {}; - switch (api) - { - case Slang::RenderApiFlag::D3D11: - deviceDesc.deviceType = gfx::DeviceType::DirectX11; - break; - case Slang::RenderApiFlag::D3D12: - deviceDesc.deviceType = gfx::DeviceType::DirectX12; - break; - case Slang::RenderApiFlag::Vulkan: - deviceDesc.deviceType = gfx::DeviceType::Vulkan; - break; - default: - return SLANG_E_NOT_AVAILABLE; - } - deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; - const char* searchPaths[] = { "", "../../tools/gfx-test", "tools/gfx-test" }; - deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); - deviceDesc.slang.searchPaths = searchPaths; - auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); - if (SLANG_FAILED(createDeviceResult)) - { - return SLANG_E_NOT_AVAILABLE; - } - - SLANG_RETURN_ON_FAIL(computeSmokeTestImpl(device, context)); - return SLANG_OK; - } - - SLANG_UNIT_TEST(computeSmokeD3D11) - { - return computeSmokeTestAPI(context, Slang::RenderApiFlag::D3D11); - } - - SLANG_UNIT_TEST(computeSmokeVulkan) - { - return computeSmokeTestAPI(context, Slang::RenderApiFlag::Vulkan); - } - -} diff --git a/tools/gfx-test/compute-smoke.slang b/tools/gfx-test/compute-smoke.slang deleted file mode 100644 index 7ecdb4177..000000000 --- a/tools/gfx-test/compute-smoke.slang +++ /dev/null @@ -1,68 +0,0 @@ -// compute-smoke.slang - -// This is a copy of `shader-object.slang` in `shader-object` example -// for use by compute-smoke gfx unit test. - -// This file implements a simple compute shader that transforms -// input floating point numbers stored in a `RWStructuredBuffer`. -// Specifically, for each number x from input buffer, compute -// f(x) and store the result back in the same buffer. - -// The compute shader supports multiple transformation functions, -// such add(x, c) which returns x+c, or mul(x, c) which returns x*c. -// This functions are implemented as types that conforms to the -// `ITransformer` interface. - -// The main entry point function takes a parameter of `ITransformer` -// type, and applies the transformation to numbers in the input -// buffer. By defining the shader parameter using interfaces, -// we enable the flexiblity to generate either specialized compute -// kernels that performs specific transformation or a general -// kernel that can perform any transformations encoded by the -// parameter at run-time, without changing any shader code or -// host-application logic for setting and preparing shader parameters. - -// Defines the transformer interface, which implements a single -// `transform` operation. -interface ITransformer -{ - float transform(float x); -} - -// Represents a transform function f(x) = x + c. -struct AddTransformer : ITransformer -{ - float c; - float transform(float x) { return x + c + 10.0f; } -}; - -// Represents a transform function f(x) = x * c. -struct MulTransformer : ITransformer -{ - float c; - float transform(float x) { return x * c; } -}; - -// Represents a composite function f(x) = f0(f1(x)); -struct CompositeTransformer : ITransformer -{ - ITransformer func0; - ITransformer func1; - float transform(float x) - { - return func0.transform(func1.transform(x)); - } -}; - -// Main entry-point. Applies the transformation encoded by `transformer` -// to all elements in `buffer`. -[shader("compute")] -[numthreads(4,1,1)] -void computeMain( - uint3 sv_dispatchThreadID : SV_DispatchThreadID, - uniform RWStructuredBuffer buffer, - uniform ITransformer transformer) -{ - var input = buffer[sv_dispatchThreadID.x]; - buffer[sv_dispatchThreadID.x] = transformer.transform(input); -} diff --git a/tools/gfx-test/gfx-test-util.cpp b/tools/gfx-test/gfx-test-util.cpp deleted file mode 100644 index 5e77879a9..000000000 --- a/tools/gfx-test/gfx-test-util.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "gfx-test-util.h" - -#include - -using Slang::ComPtr; - -namespace gfx_test -{ - void diagnoseIfNeeded(ISlangWriter* diagnosticWriter, slang::IBlob* diagnosticsBlob) - { - if (diagnosticsBlob != nullptr) - { - diagnosticWriter->write((const char*)diagnosticsBlob->getBufferPointer(), diagnosticsBlob->getBufferSize()); - } - } - - Slang::Result loadShaderProgram( - gfx::IDevice* device, - Slang::ComPtr& outShaderProgram, - ISlangWriter* diagnosticWriter, - const char* shaderModuleName, - slang::ProgramLayout*& slangReflection) - { - Slang::ComPtr slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - Slang::ComPtr diagnosticsBlob; - slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticWriter, diagnosticsBlob); - if (!module) - return SLANG_FAIL; - - char const* computeEntryPointName = "computeMain"; - ComPtr computeEntryPoint; - SLANG_RETURN_ON_FAIL( - module->findEntryPointByName(computeEntryPointName, computeEntryPoint.writeRef())); - - Slang::List componentTypes; - componentTypes.add(module); - componentTypes.add(computeEntryPoint); - - Slang::ComPtr composedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - composedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticWriter, diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - slangReflection = composedProgram->getLayout(); - - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.pipelineType = gfx::PipelineType::Compute; - programDesc.slangProgram = composedProgram.get(); - - auto shaderProgram = device->createProgram(programDesc); - - outShaderProgram = shaderProgram; - return SLANG_OK; - } - - Slang::Result compareComputeResult(gfx::IDevice* device, gfx::IBufferResource* buffer, uint8_t* expectedResult, size_t expectedBufferSize) - { - // Read back the results. - ComPtr resultBlob; - SLANG_RETURN_ON_FAIL(device->readBufferResource( - buffer, 0, expectedBufferSize, resultBlob.writeRef())); - if (resultBlob->getBufferSize() < expectedBufferSize) - return SLANG_FAIL; - - // Compare results. - auto result = reinterpret_cast(resultBlob->getBufferPointer()); - for (int i = 0; i < expectedBufferSize; i++) - { - if (expectedResult[i] != result[i]) - return SLANG_FAIL; - } - return SLANG_OK; - } -} diff --git a/tools/gfx-test/gfx-test-util.h b/tools/gfx-test/gfx-test-util.h deleted file mode 100644 index 5223ba773..000000000 --- a/tools/gfx-test/gfx-test-util.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "slang-gfx.h" -#include "source/core/slang-basic.h" - -namespace gfx_test -{ - /// Helper function for print out diagnostic messages output by Slang compiler. - void diagnoseIfNeeded(ISlangWriter* diagnosticWriter, slang::IBlob* diagnosticsBlob); - - /// Loads a compute shader module and produces a `gfx::IShaderProgram`. - Slang::Result loadShaderProgram( - gfx::IDevice* device, - Slang::ComPtr& outShaderProgram, - ISlangWriter* diagnosticWriter, - const char* shaderModuleName, - slang::ProgramLayout*& slangReflection); - - /// Reads back the content of `buffer` and compares it against `expectedResult`. - Slang::Result compareComputeResult( - gfx::IDevice* device, - gfx::IBufferResource* buffer, - uint8_t* expectedResult, - size_t expectedBufferSize); - - template - Slang::Result compareComputeResult( - gfx::IDevice* device, - gfx::IBufferResource* buffer, - Slang::Array expectedResult) - { - Slang::List expectedBuffer; - size_t bufferSize = sizeof(T) * count; - expectedBuffer.setCount(bufferSize); - memcpy(expectedBuffer.getBuffer(), expectedResult.begin(), bufferSize); - return compareComputeResult(device, buffer, expectedBuffer.getBuffer(), bufferSize); - } -} diff --git a/tools/gfx-unit-test/compute-smoke.cpp b/tools/gfx-unit-test/compute-smoke.cpp new file mode 100644 index 000000000..b8e027b65 --- /dev/null +++ b/tools/gfx-unit-test/compute-smoke.cpp @@ -0,0 +1,144 @@ +#include "tools/unit-test/slang-unit-test.h" + +#include "slang-gfx.h" +#include "gfx-test-util.h" +#include "tools/gfx-util/shader-cursor.h" +#include "source/core/slang-basic.h" + +using namespace gfx; + +namespace gfx_test +{ + void computeSmokeTestImpl(IDevice* device, UnitTestContext* context) + { + Slang::ComPtr transientHeap; + ITransientResourceHeap::Desc transientHeapDesc = {}; + transientHeapDesc.constantBufferSize = 4096; + GFX_CHECK_CALL_ABORT( + device->createTransientResourceHeap(transientHeapDesc, transientHeap.writeRef())); + + ComPtr shaderProgram; + slang::ProgramLayout* slangReflection; + GFX_CHECK_CALL_ABORT(loadShaderProgram(device, shaderProgram, "compute-smoke", slangReflection)); + + ComputePipelineStateDesc pipelineDesc = {}; + pipelineDesc.program = shaderProgram.get(); + ComPtr pipelineState; + GFX_CHECK_CALL_ABORT( + device->createComputePipelineState(pipelineDesc, pipelineState.writeRef())); + + const int numberCount = 4; + float initialData[] = { 0.0f, 1.0f, 2.0f, 3.0f }; + IBufferResource::Desc bufferDesc = {}; + bufferDesc.sizeInBytes = numberCount * sizeof(float); + bufferDesc.format = gfx::Format::Unknown; + bufferDesc.elementSize = sizeof(float); + bufferDesc.allowedStates = ResourceStateSet( + ResourceState::ShaderResource, + ResourceState::UnorderedAccess, + ResourceState::CopyDestination, + ResourceState::CopySource); + bufferDesc.defaultState = ResourceState::UnorderedAccess; + bufferDesc.cpuAccessFlags = AccessFlag::Write | AccessFlag::Read; + + ComPtr numbersBuffer; + GFX_CHECK_CALL_ABORT(device->createBufferResource( + bufferDesc, + (void*)initialData, + numbersBuffer.writeRef())); + + ComPtr bufferView; + IResourceView::Desc viewDesc = {}; + viewDesc.type = IResourceView::Type::UnorderedAccess; + viewDesc.format = Format::Unknown; + GFX_CHECK_CALL_ABORT(device->createBufferView(numbersBuffer, viewDesc, bufferView.writeRef())); + + // We have done all the set up work, now it is time to start recording a command buffer for + // GPU execution. + { + ICommandQueue::Desc queueDesc = { ICommandQueue::QueueType::Graphics }; + auto queue = device->createCommandQueue(queueDesc); + + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + + auto rootObject = encoder->bindPipeline(pipelineState); + + slang::TypeReflection* addTransformerType = + slangReflection->findTypeByName("AddTransformer"); + + // Now we can use this type to create a shader object that can be bound to the root object. + ComPtr transformer; + GFX_CHECK_CALL_ABORT(device->createShaderObject( + addTransformerType, ShaderObjectContainerType::None, transformer.writeRef())); + // Set the `c` field of the `AddTransformer`. + float c = 1.0f; + ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); + + ShaderCursor entryPointCursor( + rootObject->getEntryPoint(0)); // get a cursor the the first entry-point. + // Bind buffer view to the entry point. + entryPointCursor.getPath("buffer").setResource(bufferView); + + // Bind the previously created transformer object to root object. + entryPointCursor.getPath("transformer").setObject(transformer); + + encoder->dispatchCompute(1, 1, 1); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + queue->wait(); + } + + compareComputeResult( + device, + numbersBuffer, + Slang::makeArray(11.0f, 12.0f, 13.0f, 14.0f)); + } + + void computeSmokeTestAPI(UnitTestContext* context, Slang::RenderApiFlag::Enum api) + { + if ((api & context->enabledApis) == 0) + { + SLANG_IGNORE_TEST + } + Slang::ComPtr device; + IDevice::Desc deviceDesc = {}; + switch (api) + { + case Slang::RenderApiFlag::D3D11: + deviceDesc.deviceType = gfx::DeviceType::DirectX11; + break; + case Slang::RenderApiFlag::D3D12: + deviceDesc.deviceType = gfx::DeviceType::DirectX12; + break; + case Slang::RenderApiFlag::Vulkan: + deviceDesc.deviceType = gfx::DeviceType::Vulkan; + break; + default: + SLANG_IGNORE_TEST + } + deviceDesc.slang.slangGlobalSession = context->slangGlobalSession; + const char* searchPaths[] = { "", "../../tools/gfx-unit-test", "tools/gfx-unit-test" }; + deviceDesc.slang.searchPathCount = (SlangInt)SLANG_COUNT_OF(searchPaths); + deviceDesc.slang.searchPaths = searchPaths; + auto createDeviceResult = gfxCreateDevice(&deviceDesc, device.writeRef()); + if (SLANG_FAILED(createDeviceResult)) + { + SLANG_IGNORE_TEST + } + + computeSmokeTestImpl(device, context); + } + + SLANG_UNIT_TEST(computeSmokeD3D11) + { + computeSmokeTestAPI(unitTestContext, Slang::RenderApiFlag::D3D11); + } + + SLANG_UNIT_TEST(computeSmokeVulkan) + { + computeSmokeTestAPI(unitTestContext, Slang::RenderApiFlag::Vulkan); + } + +} diff --git a/tools/gfx-unit-test/compute-smoke.slang b/tools/gfx-unit-test/compute-smoke.slang new file mode 100644 index 000000000..7ecdb4177 --- /dev/null +++ b/tools/gfx-unit-test/compute-smoke.slang @@ -0,0 +1,68 @@ +// compute-smoke.slang + +// This is a copy of `shader-object.slang` in `shader-object` example +// for use by compute-smoke gfx unit test. + +// This file implements a simple compute shader that transforms +// input floating point numbers stored in a `RWStructuredBuffer`. +// Specifically, for each number x from input buffer, compute +// f(x) and store the result back in the same buffer. + +// The compute shader supports multiple transformation functions, +// such add(x, c) which returns x+c, or mul(x, c) which returns x*c. +// This functions are implemented as types that conforms to the +// `ITransformer` interface. + +// The main entry point function takes a parameter of `ITransformer` +// type, and applies the transformation to numbers in the input +// buffer. By defining the shader parameter using interfaces, +// we enable the flexiblity to generate either specialized compute +// kernels that performs specific transformation or a general +// kernel that can perform any transformations encoded by the +// parameter at run-time, without changing any shader code or +// host-application logic for setting and preparing shader parameters. + +// Defines the transformer interface, which implements a single +// `transform` operation. +interface ITransformer +{ + float transform(float x); +} + +// Represents a transform function f(x) = x + c. +struct AddTransformer : ITransformer +{ + float c; + float transform(float x) { return x + c + 10.0f; } +}; + +// Represents a transform function f(x) = x * c. +struct MulTransformer : ITransformer +{ + float c; + float transform(float x) { return x * c; } +}; + +// Represents a composite function f(x) = f0(f1(x)); +struct CompositeTransformer : ITransformer +{ + ITransformer func0; + ITransformer func1; + float transform(float x) + { + return func0.transform(func1.transform(x)); + } +}; + +// Main entry-point. Applies the transformation encoded by `transformer` +// to all elements in `buffer`. +[shader("compute")] +[numthreads(4,1,1)] +void computeMain( + uint3 sv_dispatchThreadID : SV_DispatchThreadID, + uniform RWStructuredBuffer buffer, + uniform ITransformer transformer) +{ + var input = buffer[sv_dispatchThreadID.x]; + buffer[sv_dispatchThreadID.x] = transformer.transform(input); +} diff --git a/tools/gfx-unit-test/gfx-test-util.cpp b/tools/gfx-unit-test/gfx-test-util.cpp new file mode 100644 index 000000000..d01fcdca3 --- /dev/null +++ b/tools/gfx-unit-test/gfx-test-util.cpp @@ -0,0 +1,86 @@ +#include "gfx-test-util.h" +#include "tools/unit-test/slang-unit-test.h" + +#include + +using Slang::ComPtr; + +namespace gfx_test +{ + void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob) + { + if (diagnosticsBlob != nullptr) + { + getTestReporter()->message(TestMessageType::Info, (const char*)diagnosticsBlob->getBufferPointer()); + } + } + + Slang::Result loadShaderProgram( + gfx::IDevice* device, + Slang::ComPtr& outShaderProgram, + const char* shaderModuleName, + slang::ProgramLayout*& slangReflection) + { + Slang::ComPtr slangSession; + SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); + Slang::ComPtr diagnosticsBlob; + slang::IModule* module = slangSession->loadModule(shaderModuleName, diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; + + char const* computeEntryPointName = "computeMain"; + ComPtr computeEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName(computeEntryPointName, computeEntryPoint.writeRef())); + + Slang::List componentTypes; + componentTypes.add(module); + componentTypes.add(computeEntryPoint); + + Slang::ComPtr composedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + composedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + slangReflection = composedProgram->getLayout(); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.pipelineType = gfx::PipelineType::Compute; + programDesc.slangProgram = composedProgram.get(); + + auto shaderProgram = device->createProgram(programDesc); + + outShaderProgram = shaderProgram; + return SLANG_OK; + } + + void compareComputeResult(gfx::IDevice* device, gfx::IBufferResource* buffer, uint8_t* expectedResult, size_t expectedBufferSize) + { + // Read back the results. + ComPtr resultBlob; + GFX_CHECK_CALL_ABORT(device->readBufferResource( + buffer, 0, expectedBufferSize, resultBlob.writeRef())); + if (resultBlob->getBufferSize() < expectedBufferSize) + { + getTestReporter()->addResult(TestResult::Fail); + return; + } + + // Compare results. + auto result = reinterpret_cast(resultBlob->getBufferPointer()); + for (int i = 0; i < expectedBufferSize; i++) + { + if (expectedResult[i] != result[i]) + { + getTestReporter()->addResult(TestResult::Fail); + return; + } + + } + getTestReporter()->addResult(TestResult::Pass); + } +} diff --git a/tools/gfx-unit-test/gfx-test-util.h b/tools/gfx-unit-test/gfx-test-util.h new file mode 100644 index 000000000..7709512d5 --- /dev/null +++ b/tools/gfx-unit-test/gfx-test-util.h @@ -0,0 +1,41 @@ +#pragma once + +#include "slang-gfx.h" +#include "source/core/slang-basic.h" + +namespace gfx_test +{ + /// Helper function for print out diagnostic messages output by Slang compiler. + void diagnoseIfNeeded(ISlangWriter* diagnosticWriter, slang::IBlob* diagnosticsBlob); + + /// Loads a compute shader module and produces a `gfx::IShaderProgram`. + Slang::Result loadShaderProgram( + gfx::IDevice* device, + Slang::ComPtr& outShaderProgram, + const char* shaderModuleName, + slang::ProgramLayout*& slangReflection); + + /// Reads back the content of `buffer` and compares it against `expectedResult`. + void compareComputeResult( + gfx::IDevice* device, + gfx::IBufferResource* buffer, + uint8_t* expectedResult, + size_t expectedBufferSize); + + template + void compareComputeResult( + gfx::IDevice* device, + gfx::IBufferResource* buffer, + Slang::Array expectedResult) + { + Slang::List expectedBuffer; + size_t bufferSize = sizeof(T) * count; + expectedBuffer.setCount(bufferSize); + memcpy(expectedBuffer.getBuffer(), expectedResult.begin(), bufferSize); + return compareComputeResult(device, buffer, expectedBuffer.getBuffer(), bufferSize); + } + +#define GFX_CHECK_CALL(x) {auto callResult = (x); SLANG_CHECK(!SLANG_FAILED(callResult))} +#define GFX_CHECK_CALL_ABORT(x) {auto callResult = (x); SLANG_CHECK_ABORT(!SLANG_FAILED(callResult))} + +} diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp index 9c194afd4..4f96c3a6a 100644 --- a/tools/slang-test/slang-test-main.cpp +++ b/tools/slang-test/slang-test-main.cpp @@ -3399,25 +3399,23 @@ static SlangResult runUnitTestModule(TestContext* context, TestOptions& testOpti SLANG_RETURN_ON_FAIL(SharedLibrary::load( Path::combine(context->exeDirectoryPath, moduleName).getBuffer(), moduleHandle)); - slang::UnitTestGetModuleFunc getModuleFunc = - (slang::UnitTestGetModuleFunc) SharedLibrary::findSymbolAddressByName( + UnitTestGetModuleFunc getModuleFunc = + (UnitTestGetModuleFunc) SharedLibrary::findSymbolAddressByName( moduleHandle, "slangUnitTestGetModule"); if (!getModuleFunc) return SLANG_FAIL; - slang::IUnitTestModule* testModule = getModuleFunc(); + IUnitTestModule* testModule = getModuleFunc(); if (!testModule) return SLANG_FAIL; - - slang::UnitTestContext unitTestContext; + testModule->setTestReporter(TestReporter::get()); + UnitTestContext unitTestContext; unitTestContext.slangGlobalSession = context->getSession(); unitTestContext.workDirectory = ""; unitTestContext.enabledApis = context->options.enabledApis; auto testCount = testModule->getTestCount(); for (SlangInt i = 0; i < testCount; i++) { - StringBuilder sb; - StringWriter messageWriter(&sb, WriterFlag::Enum::AutoFlush); auto testFunc = testModule->getTestFunc(i); auto testName = testModule->getTestName(i); @@ -3430,22 +3428,13 @@ static SlangResult runUnitTestModule(TestContext* context, TestOptions& testOpti { if (testPassesCategoryMask(context, testOptions)) { - unitTestContext.outputWriter = &messageWriter; - TestReporter::get()->startTest(testOptions.command); - auto result = testFunc(&unitTestContext); - if (sb.getLength()) - TestReporter::get()->message(TestMessageType::Info, sb.ProduceString()); - - if (result == SLANG_E_NOT_AVAILABLE) - TestReporter::get()->addResult(TestResult::Ignored); - else if (SLANG_FAILED(result)) - TestReporter::get()->addResult(TestResult::Fail); - else - TestReporter::get()->addResult(TestResult::Pass); + TestReporter::get()->startTest(testOptions.command.getBuffer()); + testFunc(&unitTestContext); TestReporter::get()->endTest(); } } } + testModule->destroy(); return SLANG_OK; } @@ -3623,40 +3612,16 @@ SlangResult innerMain(int argc, char** argv) TestReporter::set(&reporter); // Run the unit tests - TestRegister* cur = TestRegister::s_first; - while (cur) { - StringBuilder filePath; - filePath << "unit-tests/" << cur->m_name << ".internal"; - TestOptions testOptions; testOptions.categories.add(unitTestCategory); testOptions.categories.add(smokeTestCategory); - testOptions.command = filePath; - - if (shouldRunTest(&context, testOptions.command)) - { - if (testPassesCategoryMask(&context, testOptions)) - { - reporter.startTest(testOptions.command); - // Run the test function - cur->m_func(); - reporter.endTest(); - } - else - { - reporter.addTest(testOptions.command, TestResult::Ignored); - } - } - - // Next - cur = cur->m_next; + runUnitTestModule(&context, testOptions, "slang-unit-test-tool"); } - { TestOptions testOptions; testOptions.categories.add(unitTestCategory); - runUnitTestModule(&context, testOptions, "gfx-test-tool"); + runUnitTestModule(&context, testOptions, "gfx-unit-test-tool"); } TestReporter::set(nullptr); } diff --git a/tools/slang-test/test-reporter.cpp b/tools/slang-test/test-reporter.cpp index 4a7c76c4c..84bcaa32c 100644 --- a/tools/slang-test/test-reporter.cpp +++ b/tools/slang-test/test-reporter.cpp @@ -10,7 +10,6 @@ using namespace Slang; /* static */TestReporter* TestReporter::s_reporter = nullptr; -/* static */TestRegister* TestRegister::s_first; static void appendXmlEncode(char c, StringBuilder& out) { @@ -106,7 +105,7 @@ bool TestReporter::canWriteStdError() const } } -void TestReporter::startTest(const String& testName) +void TestReporter::startTest(const char* testName) { // Must be in a suite assert(m_suiteStack.getCount()); @@ -537,6 +536,12 @@ void TestReporter::messageFormat(TestMessageType type, char const* format, ...) message(type, builder); } +void TestReporter::message(TestMessageType type, const char* messageContent) +{ + message(type, String(messageContent)); +} + + bool TestReporter::didAllSucceed() const { return m_passedTestCount == (m_totalTestCount - m_ignoredTestCount); diff --git a/tools/slang-test/test-reporter.h b/tools/slang-test/test-reporter.h index 1ebce81cd..ecf6fbab4 100644 --- a/tools/slang-test/test-reporter.h +++ b/tools/slang-test/test-reporter.h @@ -7,36 +7,7 @@ #include "../../source/core/slang-platform.h" #include "../../source/core/slang-std-writers.h" #include "../../source/core/slang-dictionary.h" - - -#define SLANG_CHECK(x) TestReporter::get()->addResultWithLocation((x), #x, __FILE__, __LINE__); -#define SLANG_CHECK_ABORT(x) \ - { \ - bool _slang_check_result = (x); \ - TestReporter::get()->addResultWithLocation(_slang_check_result, #x, __FILE__, __LINE__); \ - if (!_slang_check_result) return; \ - } - -struct TestRegister -{ - typedef void (*TestFunc)(); - - TestRegister(const char* name, TestFunc func): - m_next(s_first), - m_name(name), - m_func(func) - { - s_first = this; - } - - TestFunc m_func; - const char* m_name; - TestRegister* m_next; - - static TestRegister* s_first; -}; - -#define SLANG_UNIT_TEST(name, func) static TestRegister s_unitTest##__LINE__(name, func) +#include "tools/unit-test/slang-unit-test.h" enum class TestOutputMode { @@ -48,23 +19,7 @@ enum class TestOutputMode TeamCity, ///< Output suitable for teamcity }; -enum class TestResult -{ - // NOTE! Must keep in order such that combine is meaningful. That is larger values are higher precident - and a series of tests that has lots of passes - // and a fail, is still a fail overall. - Ignored, - Pass, - Fail, -}; - -enum class TestMessageType -{ - Info, ///< General info (may not be shown depending on verbosity setting) - TestFailure, ///< Describes how a test failure took place - RunError, ///< Describes an error that caused a test not to actually correctly run -}; - -class TestReporter +class TestReporter : public ITestReporter { public: @@ -82,7 +37,7 @@ class TestReporter TestScope(TestReporter* reporter, const Slang::String& testName) : m_reporter(reporter) { - reporter->startTest(testName); + reporter->startTest(testName.getBuffer()); } ~TestScope() { @@ -113,12 +68,12 @@ class TestReporter void startSuite(const Slang::String& name); void endSuite(); - void startTest(const Slang::String& testName); - void addResult(TestResult result); - void addResultWithLocation(TestResult result, const char* testText, const char* file, int line); - void addResultWithLocation(bool testSucceeded, const char* testText, const char* file, int line); - void addExecutionTime(double time); - void endTest(); + virtual void startTest(const char* testName) override; + virtual void addResult(TestResult result) override; + virtual void addResultWithLocation(TestResult result, const char* testText, const char* file, int line) override; + virtual void addResultWithLocation(bool testSucceeded, const char* testText, const char* file, int line) override; + virtual void addExecutionTime(double time) override; + virtual void endTest() override; /// Runs start/endTest and outputs the result TestResult addTest(const Slang::String& testName, bool isPass); @@ -128,6 +83,7 @@ class TestReporter // Called for an error in the test-runner (not for an error involving a test itself). void message(TestMessageType type, const Slang::String& errorText); void messageFormat(TestMessageType type, char const* message, ...); + virtual void message(TestMessageType type, char const* message) override; void dumpOutputDifference(const Slang::String& expectedOutput, const Slang::String& actualOutput); diff --git a/tools/slang-test/unit-offset-container.cpp b/tools/slang-test/unit-offset-container.cpp deleted file mode 100644 index d0990d9bb..000000000 --- a/tools/slang-test/unit-offset-container.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// unit-test-path.cpp - -#include "../../source/core/slang-offset-container.h" - -#include "test-context.h" - -using namespace Slang; - -static void _checkEncodeDecode(uint32_t size) -{ - uint8_t encode[OffsetString::kMaxSizeEncodeSize]; - - size_t encodeSize = OffsetString::calcEncodedSize(size, encode); - - size_t decodedSize; - const char* chars = OffsetString::decodeSize((const char*)encode, decodedSize); - - SLANG_CHECK(decodedSize == size); - SLANG_CHECK(chars - (const char*)encode == encodeSize); -} - -namespace { // anonymous - -struct Root -{ - Offset32Array > dirs; - Offset32Ptr name; - float value; -}; - -} // anonymous - -static void offsetContainerUnitTest() -{ - _checkEncodeDecode(253); - - for (int64_t i = 0; i < 0x100000000; i += (i / 2) + 1) - { - _checkEncodeDecode(uint32_t(i)); - } - - { - OffsetContainer container; - - const char* strings[] = - { - "Hello", - "World", - nullptr, - }; - - { - auto& base = container.asBase(); - - Offset32Ptr root = container.newObject(); - - auto array = container.newArray>(SLANG_COUNT_OF(strings)); - for (Int i = 0; i < SLANG_COUNT_OF(strings); ++i) - { - base[array[i]] = container.newString(strings[i]); - } - base[root]->dirs = array; - } - - { - List copy; - copy.addRange(container.getData(), container.getDataCount()); - - MemoryOffsetBase base; - base.set(copy.getBuffer(), copy.getCount()); - - Root* root = (Root*)(copy.getBuffer() + kStartOffset); - - SLANG_CHECK(root->dirs.getCount() == SLANG_COUNT_OF(strings)); - - Int count = root->dirs.getCount(); - for (Int i = 0; i < count; ++i) - { - OffsetString* str = base.asRaw(base.asRaw(root->dirs[i])); - - const char* check = strings[i]; - - if (check) - { - SLANG_CHECK(str != nullptr); - const char* strCstr = str->getCstr(); - SLANG_CHECK(strcmp(strCstr, check) == 0); - } - else - { - SLANG_CHECK(str == nullptr); - } - } - - { - Index index = 0; - for (const auto v : root->dirs) - { - OffsetString* str = base.asRaw(base.asRaw(v)); - const char* check = strings[index]; - if (check) - { - SLANG_CHECK(str != nullptr); - const char* strCstr = str->getCstr(); - SLANG_CHECK(strcmp(strCstr, check) == 0); - } - else - { - SLANG_CHECK(str == nullptr); - } - - index ++; - } - } - } - } -} - -SLANG_UNIT_TEST("OffsetContainer", offsetContainerUnitTest); diff --git a/tools/slang-test/unit-test-byte-encode.cpp b/tools/slang-test/unit-test-byte-encode.cpp deleted file mode 100644 index 8ffac3ee3..000000000 --- a/tools/slang-test/unit-test-byte-encode.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// unit-test-byte-encode.cpp - -#include "../../source/core/slang-byte-encode-util.h" - -#include -#include - -#include "test-context.h" - -#include "../../source/core/slang-random-generator.h" -#include "../../source/core/slang-list.h" - -using namespace Slang; - -static void checkUInt32(uint32_t value) -{ - uint8_t buffer[ByteEncodeUtil::kMaxLiteEncodeUInt32 + 1]; - - int writeLen = ByteEncodeUtil::encodeLiteUInt32(value, buffer); - buffer[writeLen] = 0xcd; - - uint32_t decode; - int readLen = ByteEncodeUtil::decodeLiteUInt32(buffer, &decode); - - SLANG_CHECK(readLen == writeLen && decode == value); -} - -static void byteEncodeUnitTest() -{ - DefaultRandomGenerator randGen(0x5346536a); - - { - SLANG_CHECK(ByteEncodeUtil::calcMsb8(0) == -1); - SLANG_CHECK(ByteEncodeUtil::calcMsb8(1) == 0); - SLANG_CHECK(ByteEncodeUtil::calcMsb8(0x81) == 7); - } - - { - SLANG_CHECK(ByteEncodeUtil::calcMsb32(0) == -1); - SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x81) == 7); - SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00000001) == 0); - SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00000081) == 7); - SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00000181) == 8); - SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00008181) == 15); - SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00018181) == 16); - SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00818181) == 23); - SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x01818181) == 24); - SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x81818181) == 31); - SLANG_CHECK(ByteEncodeUtil::calcMsb32(0xffffffff) == 31); - } - - { - SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00000000) == -1); - SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00000001) == 0); - SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00000081) == 0); - SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00000181) == 1); - SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00008181) == 1); - SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00018181) == 2); - SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00818181) == 2); - SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x01818181) == 3); - SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x81818181) == 3); - SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0xffffffff) == 3); - } - - { - SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00000001) == 0); - SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00000081) == 0); - SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00000181) == 1); - SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00008181) == 1); - SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00018181) == 2); - SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00818181) == 2); - SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x01818181) == 3); - SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x81818181) == 3); - SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0xffffffff) == 3); - } - - { - const int blockSize = 1024; - - List encodedBuffer; - encodedBuffer.setCount(ByteEncodeUtil::kMaxLiteEncodeUInt32 * blockSize); - - List initialBuffer; - initialBuffer.setCount(blockSize); - List decodeBuffer; - decodeBuffer.setCount(blockSize); - // Put in cache? - memset(decodeBuffer.begin(), 0, blockSize * sizeof(uint32_t)); - - for (int i = 0; i < blockSize; i++) - { - const int v = ByteEncodeUtil::calcMsb8(uint32_t((randGen.nextInt32() & 0xf) | 1)); - - // Make the commonality of different numbers that bytes are most common, then shorts etc.. - uint32_t mask; - switch (v) - { - case 0: mask = 0xffffffff; break; - case 1: mask = 0x00ffffff; break; - case 2: mask = 0x0000ffff; break; - case 3: mask = 0x000000ff; break; - } - - initialBuffer[i] = randGen.nextInt32() & mask; - } - - size_t numEncodeBytes = ByteEncodeUtil::encodeLiteUInt32(initialBuffer.begin(), blockSize, encodedBuffer.begin()); - - SLANG_CHECK(ByteEncodeUtil::calcEncodeLiteSizeUInt32(initialBuffer.begin(), blockSize) == numEncodeBytes); - - size_t numEncodeBytes2 = ByteEncodeUtil::decodeLiteUInt32(encodedBuffer.begin(), blockSize, decodeBuffer.begin()); - - SLANG_CHECK(numEncodeBytes2 == numEncodeBytes); - - SLANG_CHECK(memcmp(decodeBuffer.begin(), initialBuffer.begin(), sizeof(uint32_t) * blockSize) == 0); - } - - { - checkUInt32(uint32_t(0)); - checkUInt32(uint32_t(0x7fffff)); - checkUInt32(uint32_t(0x7fff)); - checkUInt32(uint32_t(0x7f)); - checkUInt32(uint32_t(0x7fffffff)); - checkUInt32(uint32_t(0xffffffff)); - -#if 1 - for (int64_t i = 0; i < SLANG_INT64(0x100000000); i += 371) - { - checkUInt32(uint32_t(i)); - } -#else - for (int64_t i = 0; i < SLANG_INT64(0x100000000); i += 1) - { - checkUInt32(uint32_t(i)); - } -#endif - } - -} - -SLANG_UNIT_TEST("ByteEncode", byteEncodeUnitTest); diff --git a/tools/slang-test/unit-test-command-line-args.cpp b/tools/slang-test/unit-test-command-line-args.cpp deleted file mode 100644 index fd50ceeef..000000000 --- a/tools/slang-test/unit-test-command-line-args.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// unit-test-command-line-args.cpp - -#include "../../source/compiler-core/slang-command-line-args.h" - -#include "test-context.h" - -using namespace Slang; - -static void commandLineArgsUnitTest() -{ - RefPtr context = new CommandLineContext; - - - // Simple scoped version - { - CommandLineArgs args(context); - DownstreamArgs downstreamArgs(context); - - DiagnosticSink sink(context->getSourceManager(), nullptr); - - const char* inArgs[] = - { - "-Xa...", - "-blah", - "10", - "-X.", - }; - - args.setArgs(inArgs, SLANG_COUNT_OF(inArgs)); - - SLANG_CHECK(SLANG_SUCCEEDED(downstreamArgs.stripDownstreamArgs(args, DownstreamArgs::Flag::AllowNewNames, &sink))); - - const char* aArgs[] = - { - "-blah", - "10" - }; - - SLANG_CHECK(downstreamArgs.getArgsByName("a").hasArgs(aArgs, SLANG_COUNT_OF(aArgs))); - SLANG_CHECK(args.getArgCount() == 0 && sink.getErrorCount() == 0); - } - - // Leaving off terminating -X. is ok - { - CommandLineArgs args(context); - DownstreamArgs downstreamArgs(context); - - DiagnosticSink sink(context->getSourceManager(), nullptr); - - const char* inArgs[] = - { - "-Xa...", - "-blah", - "10", - }; - - args.setArgs(inArgs, SLANG_COUNT_OF(inArgs)); - - SLANG_CHECK(SLANG_SUCCEEDED(downstreamArgs.stripDownstreamArgs(args, DownstreamArgs::Flag::AllowNewNames, &sink))); - - const char* aArgs[] = - { - "-blah", - "10" - }; - - SLANG_CHECK(downstreamArgs.getArgsByName("a").hasArgs(aArgs, SLANG_COUNT_OF(aArgs))); - SLANG_CHECK(args.getArgCount() == 0 && sink.getErrorCount() == 0); - } - - // Having a nesting - - { - CommandLineArgs args(context); - DownstreamArgs downstreamArgs(context); - - DiagnosticSink sink(context->getSourceManager(), nullptr); - - const char* inArgs[] = - { - "-something", - "andAnother", - "-Xa...", - "-blah", - "-Xb...", - "-hey", - "-X.", - "10", - "-X.", - "-Xc", - "somethingForC", - }; - - args.setArgs(inArgs, SLANG_COUNT_OF(inArgs)); - - SLANG_CHECK(SLANG_SUCCEEDED(downstreamArgs.stripDownstreamArgs(args, DownstreamArgs::Flag::AllowNewNames, &sink))); - - const char* aArgs[] = - { - "-blah", - "-Xb...", - "-hey", - "-X.", - "10" - }; - - const char* cArgs[] = - { - "somethingForC", - }; - - const char* mainArgs[] = - { - "-something", - "andAnother", - }; - - SLANG_CHECK(downstreamArgs.getArgsByName("a").hasArgs(aArgs, SLANG_COUNT_OF(aArgs))); - SLANG_CHECK(downstreamArgs.getArgsByName("c").hasArgs(cArgs, SLANG_COUNT_OF(cArgs))); - - SLANG_CHECK(args.hasArgs(mainArgs, SLANG_COUNT_OF(mainArgs)) && sink.getErrorCount() == 0); - } - -} - -SLANG_UNIT_TEST("CommandLineArgs", commandLineArgsUnitTest); diff --git a/tools/slang-test/unit-test-compression.cpp b/tools/slang-test/unit-test-compression.cpp deleted file mode 100644 index b70bd8545..000000000 --- a/tools/slang-test/unit-test-compression.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// unit-compression.cpp - -#include "test-context.h" - -#include "../../source/core/slang-zip-file-system.h" - -#include "../../source/core/slang-lz4-compression-system.h" -#include "../../source/core/slang-deflate-compression-system.h" - -using namespace Slang; - -static bool _equals(const void* data, size_t size, ISlangBlob* blob) -{ - return blob && blob->getBufferSize() == size && memcmp(blob->getBufferPointer(), data, size) == 0; -} - -template -static bool _equals(const char (&text)[SIZE], ISlangBlob* blob) -{ - return _equals(text, SIZE, blob); -} - -static List _getContents(ISlangFileSystemExt* fileSystem, const char* path) -{ - List objs; - - fileSystem->enumeratePathContents(path, [](SlangPathType pathType, const char* name, void* userData) { - List& out = *(List*)userData; - out.add(name); - }, &objs); - - return objs; -} - -static void compressionUnitTest() -{ - const SlangArchiveType archiveTypes[] = - { - SLANG_ARCHIVE_TYPE_RIFF, - SLANG_ARCHIVE_TYPE_RIFF_DEFLATE, - SLANG_ARCHIVE_TYPE_RIFF_LZ4, - SLANG_ARCHIVE_TYPE_ZIP - }; - - for (auto archiveType : archiveTypes) - { - // Test out archive file systems - RefPtr archiveFileSystem; - SLANG_CHECK(SLANG_SUCCEEDED(createArchiveFileSystem(archiveType, archiveFileSystem))); - - const char contents[] = "I'm compressed"; - const char contents2[] = "Some more stuff"; - const char contents3[] = "Replace it"; - - { - ISlangMutableFileSystem* fileSystem = archiveFileSystem; - - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->createDirectory("hello"))); - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->createDirectory("hello2"))); - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->remove("hello"))); - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->createDirectory("hello"))); - - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->saveFile("file.txt", contents, SLANG_COUNT_OF(contents)))); - - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->saveFile("file2.txt", contents2, SLANG_COUNT_OF(contents2)))); - - ComPtr blob; - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadFile("file.txt", blob.writeRef()))); - SLANG_CHECK(_equals(contents, blob)); - - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadFile("file2.txt", blob.writeRef()))); - SLANG_CHECK(_equals(contents2, blob)); - - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->saveFile("file2.txt", contents3, SLANG_COUNT_OF(contents3)))); - - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadFile("file2.txt", blob.writeRef()))); - SLANG_CHECK(_equals(contents3, blob)); - - // Check the path type - { - SlangPathType pathType; - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->getPathType("file2.txt", &pathType))); - SLANG_CHECK(pathType == SLANG_PATH_TYPE_FILE); - - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->getPathType("hello", &pathType))); - SLANG_CHECK(pathType == SLANG_PATH_TYPE_DIRECTORY); - } - - // Enumerate - { - for (const auto& obj : _getContents(fileSystem, "")) - { - // All of these should exist - SlangPathType pathType; - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->getPathType(obj.getBuffer(), &pathType))); - } - } - - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->saveFile("implicit-path/file2.txt", contents3, SLANG_COUNT_OF(contents3)))); - - { - SlangPathType pathType; - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->getPathType("implicit-path", &pathType))); - - SLANG_CHECK(pathType == SLANG_PATH_TYPE_DIRECTORY); - - List objs = _getContents(fileSystem, "implicit-path"); - - // It contains a file - SLANG_CHECK(objs.getCount() == 1); - - for (const auto& obj : objs) - { - String path = Path::combine("implicit-path", obj); - - // All of these should exist - SlangPathType pathType; - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->getPathType(path.getBuffer(), &pathType))); - } - - // Make an explicit path, and see whe have the same results - fileSystem->createDirectory("implicit-path"); - - objs = _getContents(fileSystem, "implicit-path"); - SLANG_CHECK(objs.getCount() == 1); - } - } - - - // Load and check its okay - - { - ComPtr archiveBlob; - SLANG_CHECK(SLANG_SUCCEEDED(archiveFileSystem->storeArchive(false, archiveBlob.writeRef()))); - - - RefPtr fileSystem; -#if 0 - SLANG_CHECK(SLANG_SUCCEEDED(createArchiveFileSystem(archiveType, fileSystem))); - - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadArchive(archiveBlob->getBufferPointer(), archiveBlob->getBufferSize()))); -#else - SLANG_CHECK(SLANG_SUCCEEDED(loadArchiveFileSystem(archiveBlob->getBufferPointer(), archiveBlob->getBufferSize(), fileSystem))); -#endif - - ComPtr blob; - - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadFile("file.txt", blob.writeRef()))); - SLANG_CHECK(_equals(contents, blob)); - - SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadFile("file2.txt", blob.writeRef()))); - SLANG_CHECK(_equals(contents3, blob)); - } - } - - // Test out compression systems - for (Index i = 0; i < 2; ++i) - { - // Lets try lz4 - - ICompressionSystem* system = nullptr; - if (i == 0) - { - system = LZ4CompressionSystem::getSingleton(); - } - else - { - system = DeflateCompressionSystem::getSingleton(); - } - - const char src[] = "Some text to compress"; - size_t srcSize = sizeof(src); - - ComPtr compressedBlob; - - CompressionStyle style; - - SLANG_CHECK(SLANG_SUCCEEDED(system->compress(&style, src, srcSize, compressedBlob.writeRef()))); - - // Now lets decompress - - List decompressedData; - decompressedData.setCount(srcSize); - - SLANG_CHECK(SLANG_SUCCEEDED(system->decompress(compressedBlob->getBufferPointer(), compressedBlob->getBufferSize(), srcSize, decompressedData.getBuffer()))); - SLANG_CHECK(memcmp(src, decompressedData.getBuffer(), srcSize) == 0); - } -} - -SLANG_UNIT_TEST("Compression", compressionUnitTest); diff --git a/tools/slang-test/unit-test-find-type-by-name.cpp b/tools/slang-test/unit-test-find-type-by-name.cpp deleted file mode 100644 index ebe5f746b..000000000 --- a/tools/slang-test/unit-test-find-type-by-name.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// unit-test-byte-encode.cpp - -#include "../../slang.h" - -#include -#include - -#include "test-context.h" - -using namespace Slang; - -static void findTypeByNameTest() -{ - const char* testSource = - "struct TestStruct {" - " int member0;" - " Texture2D texture1;" - "};"; - auto session = spCreateSession(); - auto request = spCreateCompileRequest(session); - spAddCodeGenTarget(request, SLANG_DXBC); - int tuIndex = spAddTranslationUnit(request, SLANG_SOURCE_LANGUAGE_SLANG, "tu1"); - spAddTranslationUnitSourceString(request, tuIndex, "internalFile", testSource); - spCompile(request); - - auto testBody = [&]() - { - auto reflection = slang::ShaderReflection::get(request); - auto testStruct = reflection->findTypeByName("TestStruct"); - SLANG_CHECK_ABORT(testStruct->getFieldCount() == 2); - auto field0Name = testStruct->getFieldByIndex(0)->getName(); - SLANG_CHECK_ABORT(field0Name != nullptr && strcmp(field0Name, "member0") == 0); - auto field1Name = testStruct->getFieldByIndex(1)->getName(); - SLANG_CHECK_ABORT(field1Name != nullptr && strcmp(field1Name, "texture1") == 0); - - auto intType = reflection->findTypeByName("int"); - auto intTypeName = intType->getName(); - SLANG_CHECK_ABORT(intTypeName && strcmp(intTypeName, "int") == 0); - - auto paramBlockType = reflection->findTypeByName("ParameterBlock"); - SLANG_CHECK_ABORT(paramBlockType != nullptr); - auto paramBlockTypeName = paramBlockType->getName(); - SLANG_CHECK_ABORT(paramBlockTypeName && strcmp(paramBlockTypeName, "ParameterBlock") == 0); - auto paramBlockElementType = paramBlockType->getElementType(); - SLANG_CHECK_ABORT(paramBlockElementType != nullptr); - auto paramBlockElementTypeName = paramBlockElementType->getName(); - SLANG_CHECK_ABORT(paramBlockElementTypeName && strcmp(paramBlockElementTypeName, "TestStruct") == 0); - }; - - testBody(); - - spDestroyCompileRequest(request); - spDestroySession(session); -} - -SLANG_UNIT_TEST("findTypeByName", findTypeByNameTest); diff --git a/tools/slang-test/unit-test-free-list.cpp b/tools/slang-test/unit-test-free-list.cpp deleted file mode 100644 index 28973d9e5..000000000 --- a/tools/slang-test/unit-test-free-list.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// unit-test-free-list.cpp - -#include "../../source/core/slang-free-list.h" - -#include -#include - -#include "test-context.h" - -#include "../../source/core/slang-random-generator.h" -#include "../../source/core/slang-list.h" - -using namespace Slang; - -static void freeListUnitTest() -{ - FreeList freeList; - freeList.init(sizeof(int), sizeof(void*), 10); - - DefaultRandomGenerator randGen(0x24343); - - List allocs; - - for (int i = 0; i < 1000; i++) - { - const int numAlloc = randGen.nextInt32UpTo(20); - - for (int j = 0; j < numAlloc; j++) - { - int* ptr = (int*)freeList.allocate(); - *ptr = i; - allocs.add(ptr); - } - - int numDealloc = randGen.nextInt32UpTo(19); - numDealloc = int(allocs.getCount()) < numDealloc ? int(allocs.getCount()) : numDealloc; - - for (int j = 0; j < numDealloc; j++) - { - const int index = randGen.nextInt32UpTo(int(allocs.getCount())); - - int* alloc = allocs[index]; - - SLANG_CHECK(*alloc <= i); - SLANG_CHECK(*alloc >= 0); - - freeList.deallocate(alloc); - - allocs.fastRemoveAt(index); - } - } -} - -SLANG_UNIT_TEST("FreeList", freeListUnitTest); diff --git a/tools/slang-test/unit-test-json.cpp b/tools/slang-test/unit-test-json.cpp deleted file mode 100644 index dad5153c1..000000000 --- a/tools/slang-test/unit-test-json.cpp +++ /dev/null @@ -1,321 +0,0 @@ - -#include "../../source/compiler-core/slang-json-lexer.h" -#include "../../source/core/slang-string-escape-util.h" -#include "../../source/compiler-core/slang-json-parser.h" -#include "../../source/compiler-core/slang-json-value.h" - -#include "test-context.h" - -using namespace Slang; - -namespace { // anonymous - -struct Element -{ - JSONTokenType type; - const char* value; -}; - -} // anonymous - -static SlangResult _lex(const char* in, DiagnosticSink* sink, List& toks) -{ - SourceManager* sourceManager = sink->getSourceManager(); - - String contents(in); - SourceFile* sourceFile = sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), contents); - SourceView* sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc()); - - JSONLexer lexer; - - lexer.init(sourceView, sink); - - while (lexer.peekType() != JSONTokenType::EndOfFile) - { - if (lexer.peekType() == JSONTokenType::Invalid) - { - toks.add(lexer.peekToken()); - return SLANG_FAIL; - } - - toks.add(lexer.peekToken()); - lexer.advance(); - } - - toks.add(lexer.peekToken()); - - // If we advance from end of file we should still be at EndOfFile - SLANG_ASSERT(lexer.advance() == JSONTokenType::EndOfFile); - - return SLANG_OK; -} - -static SlangResult _parse(const char* in, DiagnosticSink* sink, JSONListener* listener) -{ - SourceManager* sourceManager = sink->getSourceManager(); - - String contents(in); - SourceFile* sourceFile = sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), contents); - SourceView* sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc()); - - JSONLexer lexer; - lexer.init(sourceView, sink); - - JSONParser parser; - SLANG_RETURN_ON_FAIL(parser.parse(&lexer, sourceView, listener, sink)); - return SLANG_OK; -} - -static bool _areEqual(SourceManager* sourceManager, const List& toks, const Element* eles, Index elesCount) -{ - if (toks.getCount() != elesCount) - { - return false; - } - - SourceView* sourceView = toks.getCount() ? sourceManager->findSourceView(toks[0].loc) : nullptr; - const char*const content = sourceView ? sourceView->getContent().begin() : nullptr; - - for (Index i = 0; i < toks.getCount(); ++i) - { - const JSONToken& tok = toks[i]; - const auto& ele = eles[i]; - - if (tok.type != ele.type) - { - return false; - } - - SLANG_ASSERT(sourceView->getRange().contains(tok.loc)); - - const char* start = content + sourceView->getRange().getOffset(tok.loc); - - UnownedStringSlice lexeme(start, tok.length); - - if (lexeme != ele.value) - { - return false; - } - } - - return true; -} - -static void jsonUnitTest() -{ - SourceManager sourceManager; - sourceManager.initialize(nullptr, nullptr); - DiagnosticSink sink(&sourceManager, nullptr); - - { - const char text[] = " { \"Hello\" : [ \"World\", 1, 2.0, -3.0, -435.5345435, 45e-10, 421.00e+20, 17e1] }"; - - const Element eles[] = - { - {JSONTokenType::LBrace, "{" }, - {JSONTokenType::StringLiteral, "\"Hello\""}, - {JSONTokenType::Colon, ":" }, - {JSONTokenType::LBracket, "[" }, - {JSONTokenType::StringLiteral, "\"World\"" }, - {JSONTokenType::Comma, "," }, - {JSONTokenType::IntegerLiteral, "1" }, - {JSONTokenType::Comma, "," }, - {JSONTokenType::FloatLiteral, "2.0" }, - {JSONTokenType::Comma, "," }, - {JSONTokenType::FloatLiteral, "-3.0" }, - {JSONTokenType::Comma, "," }, - {JSONTokenType::FloatLiteral, "-435.5345435" }, - {JSONTokenType::Comma, "," }, - {JSONTokenType::FloatLiteral, "45e-10" }, - {JSONTokenType::Comma, "," }, - {JSONTokenType::FloatLiteral, "421.00e+20" }, - {JSONTokenType::Comma, "," }, - {JSONTokenType::FloatLiteral, "17e1" }, - {JSONTokenType::RBracket, "]" }, - {JSONTokenType::RBrace, "}" }, - {JSONTokenType::EndOfFile, "" }, - }; - - List toks; - SLANG_CHECK(SLANG_SUCCEEDED(_lex(text, &sink, toks))); - - SLANG_CHECK(_areEqual(&sourceManager, toks, eles, SLANG_COUNT_OF(eles))); - } - - { - StringEscapeHandler* handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::JSON); - - - { - const auto slice = UnownedStringSlice::fromLiteral("\n\r\b\f\t \"\\/ Some text..."); - - SLANG_CHECK(handler->isEscapingNeeded(slice)); - SLANG_CHECK(!handler->isEscapingNeeded(UnownedStringSlice::fromLiteral("Hello!"))); - - StringBuilder escaped; - handler->appendEscaped(slice, escaped); - - StringBuilder unescaped; - handler->appendUnescaped(escaped.getUnownedSlice(), unescaped); - - SLANG_CHECK(unescaped == slice); - } - - { - uint32_t v = 0x7f; - - StringBuilder buf; - while (v < 0x10000) - { - char work[10] = "\\u"; - - for (Int i = 0; i < 4; ++i) - { - const uint32_t digitValue = (v >> ((3 - i) * 4)) & 0xf; - - char digitC = (digitValue > 9) ? char(digitValue - 10 + 'a') : char(digitValue + '0'); - work[i + 2] = digitC; - } - - buf << UnownedStringSlice(work, 6); - - v += v; - } - - // Decode it - StringBuilder unescaped; - handler->appendUnescaped(buf.getUnownedSlice(), unescaped); - - // Encode it - StringBuilder escaped; - handler->appendEscaped(unescaped.getUnownedSlice(), escaped); - - SLANG_CHECK(escaped == buf); - } - } - - { - const char in[] = "{ \"Hello\" : \"Json\", \"!\" : 10, \"array\" : [1, 2, 3.0] }"; - - { - auto style = JSONWriter::IndentationStyle::Allman; - - JSONWriter writer(style); - _parse(in, &sink, &writer); - - JSONWriter writerCheck(style); - _parse(writer.getBuilder().getBuffer(), &sink, &writerCheck); - - SLANG_CHECK(writerCheck.getBuilder() == writer.getBuilder()); - } - - { - auto style = JSONWriter::IndentationStyle::KNR; - - JSONWriter writer(style, 80); - _parse(in, &sink, &writer); - - JSONWriter writerCheck(style); - _parse(writer.getBuilder().getBuffer(), &sink, &writerCheck); - - SLANG_CHECK(writerCheck.getBuilder() == writer.getBuilder()); - } - - { - // Let's parse into a Value - RefPtr container = new JSONContainer(&sourceManager); - - JSONValue value; - { - JSONBuilder builder(container); - - SLANG_CHECK(SLANG_SUCCEEDED(_parse(in, &sink, &builder))); - value = builder.getRootValue(); - } - // Let's recreate - JSONValue copy; - { - JSONBuilder builder(container); - container->traverseRecursively(value, &builder); - copy = builder.getRootValue(); - } - - SLANG_CHECK(container->areEqual(value, copy)); - - } - } - - { - // Only need a SourceManager if we are going to store lexemes - RefPtr container = new JSONContainer(nullptr); - - { - List values; - - for (Int i = 0; i < 100; ++i) - { - - values.add(JSONValue::makeInt(i)); - values.add(JSONValue::makeFloat(-double(i))); - } - - JSONValue array = container->createArray(values.getBuffer(), values.getCount()); - - auto arrayView = container->getArray(array); - - SLANG_CHECK(arrayView.getCount() == values.getCount()); - - // Check the values are the same - SLANG_CHECK(container->areEqual(arrayView.getBuffer(), values.getBuffer(), arrayView.getCount())); - - { - JSONWriter writer(JSONWriter::IndentationStyle::KNR, 80); - - container->traverseRecursively(array, &writer); - } - } - { - JSONValue obj = JSONValue::makeEmptyObject(); - - JSONKey key = container->getKey(UnownedStringSlice::fromLiteral("Hello")); - - container->setKeyValue(obj, key, JSONValue::makeNull()); - container->setKeyValue(obj, key, JSONValue::makeInt(10)); - - auto objView = container->getObject(obj); - - SLANG_CHECK(objView.getCount() == 1); - - SLANG_CHECK(objView[0].value.asInteger() == 10); - } - } - - // Check repeated keys works out - // Check out comparison works with different key orders - { - RefPtr container = new JSONContainer(&sourceManager); - const char aText[] = "{ \"a\" : 10, \"b\" : 20.0, \"a\" : \"Hello\" }"; - - - JSONBuilder builder(container); - SLANG_CHECK(SLANG_SUCCEEDED(_parse(aText, &sink, &builder))); - const JSONValue a = builder.getRootValue(); - - builder.reset(); - - const char bText[] = "{ \"b\" : 20.0, \"a\" : \"Hello\"}"; - SLANG_CHECK(SLANG_SUCCEEDED(_parse(bText, &sink, &builder))); - const JSONValue b = builder.getRootValue(); - - SLANG_CHECK(container->areEqual(a, b)); - - JSONBuilder convertBuilder(container, JSONBuilder::Flag::ConvertLexemes); - - SLANG_CHECK(SLANG_SUCCEEDED(_parse(aText, &sink, &convertBuilder))); - const JSONValue c = builder.getRootValue(); - - SLANG_CHECK(container->areEqual(a, c)); - } -} - -SLANG_UNIT_TEST("JSON", jsonUnitTest); diff --git a/tools/slang-test/unit-test-memory-arena.cpp b/tools/slang-test/unit-test-memory-arena.cpp deleted file mode 100644 index 2aa898c9d..000000000 --- a/tools/slang-test/unit-test-memory-arena.cpp +++ /dev/null @@ -1,273 +0,0 @@ -// unit-test-free-list.cpp - -#include "../../source/core/slang-memory-arena.h" - -#include -#include - -#include "test-context.h" - -#include "../../source/core/slang-random-generator.h" -#include "../../source/core/slang-list.h" - -using namespace Slang; - - -namespace // anonymous -{ - -struct Block -{ - void* m_data; - size_t m_size; - uint8_t m_value; -}; - -enum class TestMode -{ - eUnaligned, - eImplicitAligned, ///< Alignment is kept implicitly with Unaligned allocs of the right size - eDefaultAligned, - eExplicitAligned, - eCount, -}; - -} // anonymous - -static size_t getAlignment(TestMode mode) -{ - switch (mode) - { - default: - case TestMode::eUnaligned: - return 1; - case TestMode::eExplicitAligned: - return 16; - case TestMode::eImplicitAligned: - return 32; - case TestMode::eDefaultAligned: - return MemoryArena::kMinAlignment; - } -} - -static bool hasValueShort(const uint8_t* data, size_t size, uint8_t value) -{ - for (size_t i = 0; i < size; ++i) - { - if (data[i] != value) - { - return false; - } - } - return true; -} - -static bool hasValue(const uint8_t* data, size_t size, uint8_t value) -{ - const size_t alignMask = sizeof(size_t) - 1; - - if (size <= sizeof(size_t) * 2) - { - return hasValueShort(data, size, value); - } - - if (size_t(data) & alignMask) - { - size_t firstSize = sizeof(size_t) - (size_t(data) & alignMask); - if (!hasValueShort(data, firstSize, value)) - { - return false; - } - size -= firstSize; - data += firstSize; - - assert((size_t(data) & alignMask) == 0); - } - - // Now do the middle - size_t numWords = size / sizeof(size_t); - - // Expand the byte up to a word size - size_t wordValue = (size_t(value) << 8) | value; - wordValue = (wordValue << 16) | wordValue; - wordValue = (sizeof(size_t) > 4) ? size_t((uint64_t(wordValue) << 32) | wordValue) : wordValue; - - const size_t* wordData = (const size_t*)data; - for (size_t i = 0; i < numWords; ++i) - { - if (wordData[i] != wordValue) - { - return false; - } - } - - // Do the end piece - return hasValueShort(data + sizeof(size_t) * numWords, size & alignMask, value); -} - -static void memoryArenaUnitTest() -{ - DefaultRandomGenerator randGen(0x5346536a); - - { - const size_t blockSize = 1024; - MemoryArena arena; - arena.init(blockSize); - - List blocks; - - blocks.add(arena.allocate(100)); - blocks.add(arena.allocate(blockSize * 2)); - blocks.add(arena.allocate(100)); - blocks.add(arena.allocate(blockSize * 2)); - blocks.add(arena.allocate(100)); - - arena.deallocateAll(); - blocks.add(arena.allocate(100)); - blocks.add(arena.allocate(blockSize * 2)); - - arena.reset(); - - { - uint32_t data[] = { 1, 2, 3 }; - - const uint32_t* copy = arena.allocateAndCopyArray(data, SLANG_COUNT_OF(data)); - - SLANG_CHECK(::memcmp(copy, data, sizeof(data)) == 0); - } - } - - { - int count = 0; - const size_t blockSize = 1024; - - for (TestMode mode = TestMode(0); int(mode) < int(TestMode::eCount); mode = TestMode(int(mode) + 1)) - { - const size_t alignment = getAlignment(mode); - - MemoryArena arena; - arena.init(blockSize, alignment); - - List blocks; - - for (int i = 0; i < 10000; i++) - { - count++; - - const int var = randGen.nextInt32() & 0x3ff; - if (var < 3 && blocks.getCount() > 0) - { - if (var == 1) - { - // Deallocate everything - arena.deallocateAll(); - blocks.clear(); - } - else if (var == 2) - { - arena.reset(); - blocks.clear(); - } - else if (var == 3) - { - arena.rewindToCursor(nullptr); - blocks.clear(); - } - else if (var == 4) - { - // Rewind to a random position - int rewindIndex = randGen.nextInt32UpTo(int32_t(blocks.getCount())); - // rewind to this block - arena.rewindToCursor(blocks[rewindIndex].m_data); - // All the blocks (includign this one) and now deallocated - blocks.setCount(rewindIndex); - - } - else - { - size_t usedMemory = arena.calcTotalMemoryUsed(); - size_t allocatedMemory = arena.calcTotalMemoryAllocated(); - - SLANG_CHECK(allocatedMemory >= usedMemory); - } - } - else - { - size_t sizeInBytes = (randGen.nextInt32() & 255) + 1; - - // Lets go for an oversized block - if ((randGen.nextInt32() & 0xff) < 2) - { - sizeInBytes += blockSize; - } - else if ((randGen.nextInt32() & 0xff) < 2) - { - // Let's try for a block that's awkwardly sized - sizeInBytes = blockSize / 3 + 10; - } - - const uint8_t value = uint8_t(randGen.nextInt32()); - - void* mem = nullptr; - switch (mode) - { - default: - case TestMode::eUnaligned: - { - mem = arena.allocateUnaligned(sizeInBytes); - break; - } - case TestMode::eImplicitAligned: - { - // Fix the size to get implicit alignment - sizeInBytes = (sizeInBytes & ~(alignment - 1)) + alignment; - mem = arena.allocateUnaligned(sizeInBytes); - break; - } - case TestMode::eExplicitAligned: - { - mem = arena.allocateAligned(sizeInBytes, alignment); - break; - } - case TestMode::eDefaultAligned: - { - mem = arena.allocate(sizeInBytes); - break; - } - } - - // Check it is aligned - SLANG_CHECK((size_t(mem) & (alignment - 1)) == 0); - - ::memset(mem, value, sizeInBytes); - - Block block; - - block.m_data = mem; - block.m_size = sizeInBytes; - block.m_value = value; - - blocks.add(block); - } - - // Check the blocks - for (Index j = 0; j < blocks.getCount(); ++j) - { - const Block& block = blocks[j]; - - SLANG_CHECK(arena.isValid(block.m_data, block.m_size)); - - SLANG_CHECK(hasValue((uint8_t*)block.m_data, block.m_size, block.m_value)); - } - } - } - } - { - // Do lots of allocations and test out rewind - - - - } -} - -SLANG_UNIT_TEST("MemoryArena", memoryArenaUnitTest); diff --git a/tools/slang-test/unit-test-path.cpp b/tools/slang-test/unit-test-path.cpp deleted file mode 100644 index 98f44753e..000000000 --- a/tools/slang-test/unit-test-path.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// unit-test-path.cpp - -#include "../../source/core/slang-io.h" - - -#include "test-context.h" - -using namespace Slang; - -static void pathUnitTest() -{ -#if SLANG_WINDOWS_FAMILY - // Disable for now on non windows has some problems on *some* Linux based CI. - { - String path; - SlangResult res = Path::getCanonical("source/slang", path); - SLANG_CHECK(SLANG_SUCCEEDED(res)); - - String parentPath; - res = Path::getCanonical("source", parentPath); - SLANG_CHECK(SLANG_SUCCEEDED(res)); - - String parentPath2 = Path::getParentDirectory(path); - SLANG_CHECK(parentPath == parentPath2); - } -#endif - // Test the paths - { - SLANG_CHECK(Path::simplify(".") == "."); - SLANG_CHECK(Path::simplify("..") == ".."); - SLANG_CHECK(Path::simplify("blah/..") == "."); - - SLANG_CHECK(Path::simplify("blah/.././a") == "a"); - - SLANG_CHECK(Path::simplify("a:/what/.././../is/./../this/.") == "a:/../this"); - - SLANG_CHECK(Path::simplify("a:/what/.././../is/./../this/./") == "a:/../this"); - - SLANG_CHECK(Path::simplify("a:\\what\\..\\.\\..\\is\\.\\..\\this\\.\\") == "a:/../this"); - - SLANG_CHECK(Path::simplify("tests/preprocessor/.\\pragma-once-a.h") == "tests/preprocessor/pragma-once-a.h"); - - - SLANG_CHECK(Path::hasRelativeElement(".")); - SLANG_CHECK(Path::hasRelativeElement("..")); - SLANG_CHECK(Path::hasRelativeElement("blah/..")); - - SLANG_CHECK(Path::hasRelativeElement("blah/.././a")); - SLANG_CHECK(Path::hasRelativeElement("a") == false); - SLANG_CHECK(Path::hasRelativeElement("blah/a") == false); - SLANG_CHECK(Path::hasRelativeElement("a:\\blah/a") == false); - - - SLANG_CHECK(Path::hasRelativeElement("a:/what/.././../is/./../this/.")); - - SLANG_CHECK(Path::hasRelativeElement("a:/what/.././../is/./../this/./")); - - SLANG_CHECK(Path::hasRelativeElement("a:\\what\\..\\.\\..\\is\\.\\..\\this\\.\\")); - - - } -} - -SLANG_UNIT_TEST("Path", pathUnitTest); diff --git a/tools/slang-test/unit-test-riff.cpp b/tools/slang-test/unit-test-riff.cpp deleted file mode 100644 index 0fb81113a..000000000 --- a/tools/slang-test/unit-test-riff.cpp +++ /dev/null @@ -1,180 +0,0 @@ -// unit-test-riff.cpp - -#include "../../source/core/slang-riff.h" - -#include "../../source/core/slang-random-generator.h" - -#include "test-context.h" - -using namespace Slang; - -static void _writeRandom(RandomGenerator* rand, size_t maxSize, RiffContainer& ioContainer, List& ioData) -{ - while (true) - { - const Index oldCount = ioData.getCount(); - - const size_t allocSize = size_t(rand->nextInt32InRange(1, 50)); - - if (allocSize + oldCount > maxSize) - { - break; - } - - ioData.setCount(oldCount + Index(allocSize)); - rand->nextData(ioData.getBuffer() + oldCount, allocSize); - - // Write - ioContainer.write(ioData.getBuffer() + oldCount, allocSize); - } - - // Should be a single block with same data as the List - RiffContainer::DataChunk* dataChunk = as(ioContainer.getCurrentChunk()); - SLANG_ASSERT(dataChunk); -} - -static void riffUnitTest() -{ - typedef RiffContainer::ScopeChunk ScopeChunk; - typedef RiffContainer::Chunk::Kind Kind; - - const FourCC markThings = SLANG_FOUR_CC('T', 'H', 'I', 'N'); - const FourCC markData = SLANG_FOUR_CC('D', 'A', 'T', 'A'); - - { - RiffContainer container; - - { - ScopeChunk scopeContainer(&container, Kind::List, markThings); - { - ScopeChunk scopeChunk(&container, Kind::Data, markData); - - const char hello[] = "Hello "; - const char world[] = "World!"; - - container.write(hello, sizeof(hello)); - container.write(world, sizeof(world)); - } - - { - ScopeChunk scopeChunk(&container, Kind::Data, markData); - - const char test0[] = "Testing... "; - const char test1[] = "Testing!"; - - container.write(test0, sizeof(test0)); - container.write(test1, sizeof(test1)); - } - - { - ScopeChunk innerScopeContainer(&container, Kind::List, markThings); - - { - ScopeChunk scopeChunk(&container, Kind::Data, markData); - - const char another[] = "Another?"; - container.write(another, sizeof(another)); - } - } - } - - SLANG_CHECK(container.isFullyConstructed()); - SLANG_CHECK(RiffContainer::isChunkOk(container.getRoot())); - - { - StringBuilder builder; - { - StringWriter writer(&builder, 0); - RiffUtil::dump(container.getRoot(), &writer); - } - - { - OwnedMemoryStream stream(FileAccess::ReadWrite); - SLANG_CHECK(SLANG_SUCCEEDED(RiffUtil::write(container.getRoot(), true, &stream))); - - stream.seek(SeekOrigin::Start, 0); - - RiffContainer readContainer; - SLANG_CHECK(SLANG_SUCCEEDED(RiffUtil::read(&stream, readContainer))); - - // Dump the read contents - StringBuilder readBuilder; - { - StringWriter writer(&readBuilder, 0); - RiffUtil::dump(readContainer.getRoot(), &writer); - } - - // They should be the same - SLANG_CHECK(readBuilder == builder); - } - } - - } - - // Test writing as a stream only allocates a single data block (as long as there is enough space). - { - RiffContainer container; - - ScopeChunk scopeChunk(&container, Kind::List, markData); - { - ScopeChunk scopeChunk(&container, Kind::Data, markData); - RefPtr rand = RandomGenerator::create(0x345234); - - List data; - _writeRandom(rand, container.getMemoryArena().getBlockPayloadSize() / 2, container, data); - - // Should be a single block with same data as the List - RiffContainer::DataChunk* dataChunk = as(container.getCurrentChunk()); - SLANG_ASSERT(dataChunk); - - // It should be a single block - SLANG_CHECK(dataChunk->getSingleData() != nullptr); - - SLANG_CHECK(dataChunk->isEqual(data.getBuffer(), data.getCount())); - - } - } - - // Test writing across multiple data blocks - { - RefPtr rand = RandomGenerator::create(0x345234); - - for (Int i = 0 ; i < 100; ++i) - { - RiffContainer container; - - const size_t maxSize = rand->nextInt32InRange(1, int32_t(container.getMemoryArena().getBlockPayloadSize() * 3)); - - ScopeChunk scopeChunk(&container, Kind::List, markData); - { - ScopeChunk scopeChunk(&container, Kind::Data, markData); - - List data; - _writeRandom(rand, maxSize, container, data); - - // Should be a single block with same data as the List - RiffContainer::DataChunk* dataChunk = as(container.getCurrentChunk()); - SLANG_CHECK(dataChunk && dataChunk->isEqual(data.getBuffer(), data.getCount())); - } - } - } - -#if 0 - { - RiffContainer container; - { - FileStream readStream("ambient-drop.wav", FileMode::Open, FileAccess::Read, FileShare::ReadWrite); - SLANG_CHECK(SLANG_SUCCEEDED(RiffUtil::read(&readStream, container))); - RiffUtil::dump(container.getRoot(), StdWriters::getOut()); - } - // Write it - { - - FileStream writeStream("check.wav", FileMode::Create, FileAccess::Write, FileShare::ReadWrite); - SLANG_CHECK(SLANG_SUCCEEDED(RiffUtil::write(container.getRoot(), true, &writeStream))); - } - } -#endif -} - -SLANG_UNIT_TEST("Riff", riffUnitTest); diff --git a/tools/slang-test/unit-test-short-list.cpp b/tools/slang-test/unit-test-short-list.cpp deleted file mode 100644 index 0559419bb..000000000 --- a/tools/slang-test/unit-test-short-list.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// unit-test-path.cpp - -#include "test-context.h" - -using namespace Slang; - -template -static bool _checkArrayView(ArrayView v0, ArrayView v1) -{ - if (v0.getCount() != v1.getCount()) - return false; - for (Index i = 0; i < v0.getCount(); i++) - if (v0[i] != v1[i]) - return false; - return true; -} - -static void shortListUnitTest() -{ - { - ShortList shortList = { "a", "b", "c" }; - shortList.add("d"); - auto arrayView = shortList.getArrayView(); - SLANG_CHECK(arrayView.ownsStorage == false); - SLANG_CHECK(_checkArrayView(arrayView.arrayView, - List{"a", "b", "c", "d"}.getArrayView())); - shortList.add("e"); - auto arrayView2 = shortList.getArrayView(); - SLANG_CHECK(arrayView2.ownsStorage == true); - SLANG_CHECK(_checkArrayView(arrayView2.arrayView, - List{"a", "b", "c", "d", "e"}.getArrayView())); - auto arrayView3 = shortList.getArrayView(0, 2); - SLANG_CHECK(arrayView3.ownsStorage == false); - SLANG_CHECK(_checkArrayView(arrayView3.arrayView, - List{"a", "b"}.getArrayView())); - auto arrayView4 = shortList.getArrayView(4, 1); - SLANG_CHECK(arrayView4.ownsStorage == false); - SLANG_CHECK(_checkArrayView(arrayView4.arrayView, - List{"e"}.getArrayView())); - auto arrayView5 = shortList.getArrayView(2, 3); - SLANG_CHECK(arrayView5.ownsStorage == true); - SLANG_CHECK(_checkArrayView(arrayView5.arrayView, - List{"c", "d", "e"}.getArrayView())); - - ShortList copy2; - ShortList copy1; - copy1 = shortList; - for (auto item : copy1) - copy2.add(item); - SLANG_CHECK(_checkArrayView(copy2.getArrayView().arrayView, - List{"a", "b", "c", "d", "e"}.getArrayView())); - - SLANG_CHECK(copy2.indexOf("a") == 0); - SLANG_CHECK(copy2.indexOf("e") == 4); - - SLANG_CHECK(copy2.lastIndexOf("a") == 0); - SLANG_CHECK(copy2.lastIndexOf("e") == 4); - - copy2.compress(); - copy2.add("f"); - copy2.fastRemove("c"); - copy2.compress(); - SLANG_CHECK(_checkArrayView(copy2.getArrayView().arrayView, - List{"a", "b", "f", "d", "e"}.getArrayView())); - - shortList.removeLast(); - shortList.removeLast(); - shortList.compress(); - SLANG_CHECK(_checkArrayView(shortList.getArrayView().arrayView, - List{"a", "b", "c"}.getArrayView())); - shortList.add("d"); - shortList.add("e"); - SLANG_CHECK(_checkArrayView(shortList.getArrayView().arrayView, - List{"a", "b", "c", "d", "e"}.getArrayView())); - } -} - -SLANG_UNIT_TEST("ShortList", shortListUnitTest); diff --git a/tools/slang-test/unit-test-string.cpp b/tools/slang-test/unit-test-string.cpp deleted file mode 100644 index e8a33fbbe..000000000 --- a/tools/slang-test/unit-test-string.cpp +++ /dev/null @@ -1,264 +0,0 @@ -// unit-test-path.cpp - -#include "../../source/core/slang-string-util.h" - -#include "test-context.h" - -//#include - -#include - -using namespace Slang; - -static bool _areEqual(const List& lines, const UnownedStringSlice* checkLines, Int checkLinesCount) -{ - if (checkLinesCount != lines.getCount()) - { - return false; - } - - for (Int i = 0; i < checkLinesCount; ++i) - { - if (lines[i] != checkLines[i]) - { - return false; - } - } - return true; -} - -static bool _checkLines(const UnownedStringSlice& input, const UnownedStringSlice* checkLines, Int checkLinesCount) -{ - List lines; - StringUtil::calcLines(input, lines); - return _areEqual(lines, checkLines, checkLinesCount); -} - -static bool _checkLineParser(const UnownedStringSlice& input) -{ - UnownedStringSlice remaining(input), line; - for (const auto parserLine : LineParser(input)) - { - if (!StringUtil::extractLine(remaining, line) || line != parserLine) - { - return false; - } - } - return StringUtil::extractLine(remaining, line) == false; -} - -static void _append(double v, StringBuilder& buf) -{ - std::ostringstream stream; - stream.imbue(std::locale::classic()); - stream.setf(std::ios::fixed, std::ios::floatfield); - stream.precision(20); - - stream << std::scientific << v; - - buf << stream.str().c_str(); -} - -// Unit of least precision -static int64_t _calcULPDistance(double a, double b) -{ - // Save work if the floats are equal. - // Also handles +0 == -0 - if (a == b) - { - return 0; - } - - const int64_t max = int64_t((~uint64_t(0)) >> 1); - -#if 0 - // Max distance for NaN - if (isnan(a) || isnan(b)) - { - return max; - } - - // If one's infinite and they're not equal, max distance. - if (isinf(a) || isinf(b)) - { - return max; - } -#endif - - int64_t ia, ib; - memcpy(&ia, &a, sizeof(a)); - memcpy(&ib, &b, sizeof(b)); - - // Don't compare differently-signed floats. - if ((ia < 0) != (ib < 0)) - { - return max; - } - - // Return the absolute value of the distance in ULPs. - int64_t distance = ia - ib; - return distance < 0 ? -distance : distance; -} - -static bool _areApproximatelyEqual(double a, double b, double fixedEpsilon = 1e-10, int ulpsEpsilon = 100) -{ - // Handle the near-zero case. - const double difference = abs(a - b); - if (difference <= fixedEpsilon) - { - return true; - } - - return _calcULPDistance(a, b) <= ulpsEpsilon; -} - -static void stringUnitTest() -{ - { - UnownedStringSlice checkLines[] = { UnownedStringSlice::fromLiteral("") }; - SLANG_CHECK(_checkLines(UnownedStringSlice::fromLiteral(""), checkLines, SLANG_COUNT_OF(checkLines))); - } - { - // Will emit no lines - SLANG_CHECK(_checkLines(UnownedStringSlice(nullptr, nullptr), nullptr, 0)); - } - { - // Two lines - both empty - UnownedStringSlice checkLines[] = { UnownedStringSlice(), UnownedStringSlice()}; - SLANG_CHECK(_checkLines(UnownedStringSlice::fromLiteral("\n"), checkLines, SLANG_COUNT_OF(checkLines))); - } - { - UnownedStringSlice checkLines[] = { UnownedStringSlice::fromLiteral("Hello"), UnownedStringSlice::fromLiteral("World!") }; - SLANG_CHECK(_checkLines(UnownedStringSlice::fromLiteral("Hello\nWorld!"), checkLines, SLANG_COUNT_OF(checkLines))); - } - { - UnownedStringSlice checkLines[] = { UnownedStringSlice::fromLiteral("Hello"), UnownedStringSlice::fromLiteral("World!"), UnownedStringSlice() }; - SLANG_CHECK(_checkLines(UnownedStringSlice::fromLiteral("Hello\n\rWorld!\n"), checkLines, SLANG_COUNT_OF(checkLines))); - } - - { - SLANG_CHECK(_checkLineParser(UnownedStringSlice::fromLiteral("Hello\n\rWorld!\n"))); - SLANG_CHECK(_checkLineParser(UnownedStringSlice::fromLiteral("\n"))); - SLANG_CHECK(_checkLineParser(UnownedStringSlice::fromLiteral(""))); - } - { - Int value; - SLANG_CHECK(SLANG_SUCCEEDED(StringUtil::parseInt(UnownedStringSlice("-10"), value)) && value == -10); - SLANG_CHECK(SLANG_SUCCEEDED(StringUtil::parseInt(UnownedStringSlice("0"), value)) && value == 0); - SLANG_CHECK(SLANG_SUCCEEDED(StringUtil::parseInt(UnownedStringSlice("-0"), value)) && value == 0); - - SLANG_CHECK(SLANG_SUCCEEDED(StringUtil::parseInt(UnownedStringSlice("13824"), value)) && value == 13824); - SLANG_CHECK(SLANG_SUCCEEDED(StringUtil::parseInt(UnownedStringSlice("-13824"), value)) && value == -13824); - } - - { - UnownedStringSlice values[] = { UnownedStringSlice("hello"), UnownedStringSlice("world"), UnownedStringSlice("!") }; - ArrayView valuesView(values, SLANG_COUNT_OF(values)); - - List checkValues; - StringBuilder builder; - - { - builder.Clear(); - StringUtil::join(values, 0, ',', builder); - SLANG_CHECK(builder == ""); - } - - { - builder.Clear(); - StringUtil::join(values, 1, ',', builder); - SLANG_CHECK(builder == "hello"); - - StringUtil::split(builder.getUnownedSlice(), ',', checkValues); - SLANG_CHECK(checkValues.getArrayView() == ArrayView(values, 1)); - } - - { - builder.Clear(); - StringUtil::join(values, 2, ',', builder); - SLANG_CHECK(builder == "hello,world"); - - StringUtil::split(builder.getUnownedSlice(), ',', checkValues); - SLANG_CHECK(checkValues.getArrayView() == ArrayView(values, 2)); - } - - { - builder.Clear(); - StringUtil::join(values, 3, UnownedStringSlice("ab"), builder); - SLANG_CHECK(builder == "helloabworldab!"); - - StringUtil::split(builder.getUnownedSlice(), UnownedStringSlice("ab"), checkValues); - SLANG_CHECK(checkValues.getArrayView() == ArrayView(values, 3)); - } - } - { - - List values; - values.add(0.0); - values.add(-0.0); - - for (Index i = -300; i < 300; ++i) - { - double value = pow(10, i); - - values.add(value); - values.add(-value); - - values.addRange(value / 3); - values.addRange(-value / 3); - } - - StringBuilder buf; - - for (auto value : values) - { - buf.Clear(); - _append(value, buf); - - UnownedStringSlice slice = buf.getUnownedSlice(); - - double parsedValue; - SlangResult res = StringUtil::parseDouble(slice, parsedValue); - - auto ulpsParsed = _calcULPDistance(value, parsedValue); - - SLANG_CHECK(SLANG_SUCCEEDED(res)); - - // Check that they are equal - SLANG_CHECK(_areApproximatelyEqual(value, parsedValue)); - } - } - { - List values; - values.add(0); - - for (Index i = 0; i < 63; ++i) - { - auto value = int64_t(1) << i; - - values.add(value); - values.add(-value); - } - - StringBuilder buf; - - for (auto value : values) - { - buf.Clear(); - buf << value; - - - int64_t parsedValue; - - UnownedStringSlice slice = buf.getUnownedSlice(); - SlangResult res = StringUtil::parseInt64(slice, parsedValue); - - SLANG_CHECK(SLANG_SUCCEEDED(res)); - - // Check that they are equal - SLANG_CHECK(value == parsedValue); - } - } -} - -SLANG_UNIT_TEST("String", stringUnitTest); diff --git a/tools/slang-unit-test/unit-offset-container.cpp b/tools/slang-unit-test/unit-offset-container.cpp new file mode 100644 index 000000000..6a179c319 --- /dev/null +++ b/tools/slang-unit-test/unit-offset-container.cpp @@ -0,0 +1,117 @@ +// unit-test-path.cpp + +#include "../../source/core/slang-offset-container.h" + +#include "tools/unit-test/slang-unit-test.h" + +using namespace Slang; + +static void _checkEncodeDecode(uint32_t size) +{ + uint8_t encode[OffsetString::kMaxSizeEncodeSize]; + + size_t encodeSize = OffsetString::calcEncodedSize(size, encode); + + size_t decodedSize; + const char* chars = OffsetString::decodeSize((const char*)encode, decodedSize); + + SLANG_CHECK(decodedSize == size); + SLANG_CHECK(chars - (const char*)encode == encodeSize); +} + +namespace { // anonymous + +struct Root +{ + Offset32Array > dirs; + Offset32Ptr name; + float value; +}; + +} // anonymous + +SLANG_UNIT_TEST(offsetContainer) +{ + _checkEncodeDecode(253); + + for (int64_t i = 0; i < 0x100000000; i += (i / 2) + 1) + { + _checkEncodeDecode(uint32_t(i)); + } + + { + OffsetContainer container; + + const char* strings[] = + { + "Hello", + "World", + nullptr, + }; + + { + auto& base = container.asBase(); + + Offset32Ptr root = container.newObject(); + + auto array = container.newArray>(SLANG_COUNT_OF(strings)); + for (Int i = 0; i < SLANG_COUNT_OF(strings); ++i) + { + base[array[i]] = container.newString(strings[i]); + } + base[root]->dirs = array; + } + + { + List copy; + copy.addRange(container.getData(), container.getDataCount()); + + MemoryOffsetBase base; + base.set(copy.getBuffer(), copy.getCount()); + + Root* root = (Root*)(copy.getBuffer() + kStartOffset); + + SLANG_CHECK(root->dirs.getCount() == SLANG_COUNT_OF(strings)); + + Int count = root->dirs.getCount(); + for (Int i = 0; i < count; ++i) + { + OffsetString* str = base.asRaw(base.asRaw(root->dirs[i])); + + const char* check = strings[i]; + + if (check) + { + SLANG_CHECK(str != nullptr); + const char* strCstr = str->getCstr(); + SLANG_CHECK(strcmp(strCstr, check) == 0); + } + else + { + SLANG_CHECK(str == nullptr); + } + } + + { + Index index = 0; + for (const auto v : root->dirs) + { + OffsetString* str = base.asRaw(base.asRaw(v)); + const char* check = strings[index]; + if (check) + { + SLANG_CHECK(str != nullptr); + const char* strCstr = str->getCstr(); + SLANG_CHECK(strcmp(strCstr, check) == 0); + } + else + { + SLANG_CHECK(str == nullptr); + } + + index ++; + } + } + } + } +} diff --git a/tools/slang-unit-test/unit-test-byte-encode.cpp b/tools/slang-unit-test/unit-test-byte-encode.cpp new file mode 100644 index 000000000..38bd5561d --- /dev/null +++ b/tools/slang-unit-test/unit-test-byte-encode.cpp @@ -0,0 +1,139 @@ +// unit-test-byte-encode.cpp + +#include "../../source/core/slang-byte-encode-util.h" + +#include +#include + +#include "tools/unit-test/slang-unit-test.h" + +#include "../../source/core/slang-random-generator.h" +#include "../../source/core/slang-list.h" + +using namespace Slang; + +static void checkUInt32(uint32_t value) +{ + uint8_t buffer[ByteEncodeUtil::kMaxLiteEncodeUInt32 + 1]; + + int writeLen = ByteEncodeUtil::encodeLiteUInt32(value, buffer); + buffer[writeLen] = 0xcd; + + uint32_t decode; + int readLen = ByteEncodeUtil::decodeLiteUInt32(buffer, &decode); + + SLANG_CHECK(readLen == writeLen && decode == value); +} + +SLANG_UNIT_TEST(byteEncode) +{ + DefaultRandomGenerator randGen(0x5346536a); + + { + SLANG_CHECK(ByteEncodeUtil::calcMsb8(0) == -1); + SLANG_CHECK(ByteEncodeUtil::calcMsb8(1) == 0); + SLANG_CHECK(ByteEncodeUtil::calcMsb8(0x81) == 7); + } + + { + SLANG_CHECK(ByteEncodeUtil::calcMsb32(0) == -1); + SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x81) == 7); + SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00000001) == 0); + SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00000081) == 7); + SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00000181) == 8); + SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00008181) == 15); + SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00018181) == 16); + SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x00818181) == 23); + SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x01818181) == 24); + SLANG_CHECK(ByteEncodeUtil::calcMsb32(0x81818181) == 31); + SLANG_CHECK(ByteEncodeUtil::calcMsb32(0xffffffff) == 31); + } + + { + SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00000000) == -1); + SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00000001) == 0); + SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00000081) == 0); + SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00000181) == 1); + SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00008181) == 1); + SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00018181) == 2); + SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x00818181) == 2); + SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x01818181) == 3); + SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0x81818181) == 3); + SLANG_CHECK(ByteEncodeUtil::calcMsByte32(0xffffffff) == 3); + } + + { + SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00000001) == 0); + SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00000081) == 0); + SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00000181) == 1); + SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00008181) == 1); + SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00018181) == 2); + SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x00818181) == 2); + SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x01818181) == 3); + SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0x81818181) == 3); + SLANG_CHECK(ByteEncodeUtil::calcNonZeroMsByte32(0xffffffff) == 3); + } + + { + const int blockSize = 1024; + + List encodedBuffer; + encodedBuffer.setCount(ByteEncodeUtil::kMaxLiteEncodeUInt32 * blockSize); + + List initialBuffer; + initialBuffer.setCount(blockSize); + List decodeBuffer; + decodeBuffer.setCount(blockSize); + // Put in cache? + memset(decodeBuffer.begin(), 0, blockSize * sizeof(uint32_t)); + + for (int i = 0; i < blockSize; i++) + { + const int v = ByteEncodeUtil::calcMsb8(uint32_t((randGen.nextInt32() & 0xf) | 1)); + + // Make the commonality of different numbers that bytes are most common, then shorts etc.. + uint32_t mask; + switch (v) + { + case 0: mask = 0xffffffff; break; + case 1: mask = 0x00ffffff; break; + case 2: mask = 0x0000ffff; break; + case 3: mask = 0x000000ff; break; + } + + initialBuffer[i] = randGen.nextInt32() & mask; + } + + size_t numEncodeBytes = ByteEncodeUtil::encodeLiteUInt32(initialBuffer.begin(), blockSize, encodedBuffer.begin()); + + SLANG_CHECK(ByteEncodeUtil::calcEncodeLiteSizeUInt32(initialBuffer.begin(), blockSize) == numEncodeBytes); + + size_t numEncodeBytes2 = ByteEncodeUtil::decodeLiteUInt32(encodedBuffer.begin(), blockSize, decodeBuffer.begin()); + + SLANG_CHECK(numEncodeBytes2 == numEncodeBytes); + + SLANG_CHECK(memcmp(decodeBuffer.begin(), initialBuffer.begin(), sizeof(uint32_t) * blockSize) == 0); + } + + { + checkUInt32(uint32_t(0)); + checkUInt32(uint32_t(0x7fffff)); + checkUInt32(uint32_t(0x7fff)); + checkUInt32(uint32_t(0x7f)); + checkUInt32(uint32_t(0x7fffffff)); + checkUInt32(uint32_t(0xffffffff)); + +#if 1 + for (int64_t i = 0; i < SLANG_INT64(0x100000000); i += 371) + { + checkUInt32(uint32_t(i)); + } +#else + for (int64_t i = 0; i < SLANG_INT64(0x100000000); i += 1) + { + checkUInt32(uint32_t(i)); + } +#endif + } + +} diff --git a/tools/slang-unit-test/unit-test-command-line-args.cpp b/tools/slang-unit-test/unit-test-command-line-args.cpp new file mode 100644 index 000000000..a4dc8a16c --- /dev/null +++ b/tools/slang-unit-test/unit-test-command-line-args.cpp @@ -0,0 +1,125 @@ +// unit-test-command-line-args.cpp + +#include "../../source/compiler-core/slang-command-line-args.h" + +#include "tools/unit-test/slang-unit-test.h" + +using namespace Slang; + +SLANG_UNIT_TEST(commandLineArgs) +{ + RefPtr context = new CommandLineContext; + + + // Simple scoped version + { + CommandLineArgs args(context); + DownstreamArgs downstreamArgs(context); + + DiagnosticSink sink(context->getSourceManager(), nullptr); + + const char* inArgs[] = + { + "-Xa...", + "-blah", + "10", + "-X.", + }; + + args.setArgs(inArgs, SLANG_COUNT_OF(inArgs)); + + SLANG_CHECK(SLANG_SUCCEEDED(downstreamArgs.stripDownstreamArgs(args, DownstreamArgs::Flag::AllowNewNames, &sink))); + + const char* aArgs[] = + { + "-blah", + "10" + }; + + SLANG_CHECK(downstreamArgs.getArgsByName("a").hasArgs(aArgs, SLANG_COUNT_OF(aArgs))); + SLANG_CHECK(args.getArgCount() == 0 && sink.getErrorCount() == 0); + } + + // Leaving off terminating -X. is ok + { + CommandLineArgs args(context); + DownstreamArgs downstreamArgs(context); + + DiagnosticSink sink(context->getSourceManager(), nullptr); + + const char* inArgs[] = + { + "-Xa...", + "-blah", + "10", + }; + + args.setArgs(inArgs, SLANG_COUNT_OF(inArgs)); + + SLANG_CHECK(SLANG_SUCCEEDED(downstreamArgs.stripDownstreamArgs(args, DownstreamArgs::Flag::AllowNewNames, &sink))); + + const char* aArgs[] = + { + "-blah", + "10" + }; + + SLANG_CHECK(downstreamArgs.getArgsByName("a").hasArgs(aArgs, SLANG_COUNT_OF(aArgs))); + SLANG_CHECK(args.getArgCount() == 0 && sink.getErrorCount() == 0); + } + + // Having a nesting + + { + CommandLineArgs args(context); + DownstreamArgs downstreamArgs(context); + + DiagnosticSink sink(context->getSourceManager(), nullptr); + + const char* inArgs[] = + { + "-something", + "andAnother", + "-Xa...", + "-blah", + "-Xb...", + "-hey", + "-X.", + "10", + "-X.", + "-Xc", + "somethingForC", + }; + + args.setArgs(inArgs, SLANG_COUNT_OF(inArgs)); + + SLANG_CHECK(SLANG_SUCCEEDED(downstreamArgs.stripDownstreamArgs(args, DownstreamArgs::Flag::AllowNewNames, &sink))); + + const char* aArgs[] = + { + "-blah", + "-Xb...", + "-hey", + "-X.", + "10" + }; + + const char* cArgs[] = + { + "somethingForC", + }; + + const char* mainArgs[] = + { + "-something", + "andAnother", + }; + + SLANG_CHECK(downstreamArgs.getArgsByName("a").hasArgs(aArgs, SLANG_COUNT_OF(aArgs))); + SLANG_CHECK(downstreamArgs.getArgsByName("c").hasArgs(cArgs, SLANG_COUNT_OF(cArgs))); + + SLANG_CHECK(args.hasArgs(mainArgs, SLANG_COUNT_OF(mainArgs)) && sink.getErrorCount() == 0); + } + +} + diff --git a/tools/slang-unit-test/unit-test-compression.cpp b/tools/slang-unit-test/unit-test-compression.cpp new file mode 100644 index 000000000..89716b443 --- /dev/null +++ b/tools/slang-unit-test/unit-test-compression.cpp @@ -0,0 +1,189 @@ +// unit-compression.cpp + +#include "tools/unit-test/slang-unit-test.h" + +#include "source/core/slang-io.h" +#include "../../source/core/slang-zip-file-system.h" + +#include "../../source/core/slang-lz4-compression-system.h" +#include "../../source/core/slang-deflate-compression-system.h" + +using namespace Slang; + +static bool _equals(const void* data, size_t size, ISlangBlob* blob) +{ + return blob && blob->getBufferSize() == size && memcmp(blob->getBufferPointer(), data, size) == 0; +} + +template +static bool _equals(const char (&text)[SIZE], ISlangBlob* blob) +{ + return _equals(text, SIZE, blob); +} + +static List _getContents(ISlangFileSystemExt* fileSystem, const char* path) +{ + List objs; + + fileSystem->enumeratePathContents(path, [](SlangPathType pathType, const char* name, void* userData) { + List& out = *(List*)userData; + out.add(name); + }, &objs); + + return objs; +} + +SLANG_UNIT_TEST(compression) +{ + const SlangArchiveType archiveTypes[] = + { + SLANG_ARCHIVE_TYPE_RIFF, + SLANG_ARCHIVE_TYPE_RIFF_DEFLATE, + SLANG_ARCHIVE_TYPE_RIFF_LZ4, + SLANG_ARCHIVE_TYPE_ZIP + }; + + for (auto archiveType : archiveTypes) + { + // Test out archive file systems + RefPtr archiveFileSystem; + SLANG_CHECK(SLANG_SUCCEEDED(createArchiveFileSystem(archiveType, archiveFileSystem))); + + const char contents[] = "I'm compressed"; + const char contents2[] = "Some more stuff"; + const char contents3[] = "Replace it"; + + { + ISlangMutableFileSystem* fileSystem = archiveFileSystem; + + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->createDirectory("hello"))); + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->createDirectory("hello2"))); + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->remove("hello"))); + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->createDirectory("hello"))); + + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->saveFile("file.txt", contents, SLANG_COUNT_OF(contents)))); + + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->saveFile("file2.txt", contents2, SLANG_COUNT_OF(contents2)))); + + ComPtr blob; + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadFile("file.txt", blob.writeRef()))); + SLANG_CHECK(_equals(contents, blob)); + + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadFile("file2.txt", blob.writeRef()))); + SLANG_CHECK(_equals(contents2, blob)); + + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->saveFile("file2.txt", contents3, SLANG_COUNT_OF(contents3)))); + + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadFile("file2.txt", blob.writeRef()))); + SLANG_CHECK(_equals(contents3, blob)); + + // Check the path type + { + SlangPathType pathType; + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->getPathType("file2.txt", &pathType))); + SLANG_CHECK(pathType == SLANG_PATH_TYPE_FILE); + + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->getPathType("hello", &pathType))); + SLANG_CHECK(pathType == SLANG_PATH_TYPE_DIRECTORY); + } + + // Enumerate + { + for (const auto& obj : _getContents(fileSystem, "")) + { + // All of these should exist + SlangPathType pathType; + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->getPathType(obj.getBuffer(), &pathType))); + } + } + + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->saveFile("implicit-path/file2.txt", contents3, SLANG_COUNT_OF(contents3)))); + + { + SlangPathType pathType; + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->getPathType("implicit-path", &pathType))); + + SLANG_CHECK(pathType == SLANG_PATH_TYPE_DIRECTORY); + + List objs = _getContents(fileSystem, "implicit-path"); + + // It contains a file + SLANG_CHECK(objs.getCount() == 1); + + for (const auto& obj : objs) + { + String path = Path::combine("implicit-path", obj); + + // All of these should exist + SlangPathType pathType; + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->getPathType(path.getBuffer(), &pathType))); + } + + // Make an explicit path, and see whe have the same results + fileSystem->createDirectory("implicit-path"); + + objs = _getContents(fileSystem, "implicit-path"); + SLANG_CHECK(objs.getCount() == 1); + } + } + + + // Load and check its okay + + { + ComPtr archiveBlob; + SLANG_CHECK(SLANG_SUCCEEDED(archiveFileSystem->storeArchive(false, archiveBlob.writeRef()))); + + + RefPtr fileSystem; +#if 0 + SLANG_CHECK(SLANG_SUCCEEDED(createArchiveFileSystem(archiveType, fileSystem))); + + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadArchive(archiveBlob->getBufferPointer(), archiveBlob->getBufferSize()))); +#else + SLANG_CHECK(SLANG_SUCCEEDED(loadArchiveFileSystem(archiveBlob->getBufferPointer(), archiveBlob->getBufferSize(), fileSystem))); +#endif + + ComPtr blob; + + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadFile("file.txt", blob.writeRef()))); + SLANG_CHECK(_equals(contents, blob)); + + SLANG_CHECK(SLANG_SUCCEEDED(fileSystem->loadFile("file2.txt", blob.writeRef()))); + SLANG_CHECK(_equals(contents3, blob)); + } + } + + // Test out compression systems + for (Index i = 0; i < 2; ++i) + { + // Lets try lz4 + + ICompressionSystem* system = nullptr; + if (i == 0) + { + system = LZ4CompressionSystem::getSingleton(); + } + else + { + system = DeflateCompressionSystem::getSingleton(); + } + + const char src[] = "Some text to compress"; + size_t srcSize = sizeof(src); + + ComPtr compressedBlob; + + CompressionStyle style; + + SLANG_CHECK(SLANG_SUCCEEDED(system->compress(&style, src, srcSize, compressedBlob.writeRef()))); + + // Now lets decompress + + List decompressedData; + decompressedData.setCount(srcSize); + + SLANG_CHECK(SLANG_SUCCEEDED(system->decompress(compressedBlob->getBufferPointer(), compressedBlob->getBufferSize(), srcSize, decompressedData.getBuffer()))); + SLANG_CHECK(memcmp(src, decompressedData.getBuffer(), srcSize) == 0); + } +} diff --git a/tools/slang-unit-test/unit-test-find-type-by-name.cpp b/tools/slang-unit-test/unit-test-find-type-by-name.cpp new file mode 100644 index 000000000..d12a0d91f --- /dev/null +++ b/tools/slang-unit-test/unit-test-find-type-by-name.cpp @@ -0,0 +1,55 @@ +// unit-test-byte-encode.cpp + +#include "../../slang.h" + +#include +#include + +#include "tools/unit-test/slang-unit-test.h" + +using namespace Slang; + +SLANG_UNIT_TEST(findTypeByName) +{ + const char* testSource = + "struct TestStruct {" + " int member0;" + " Texture2D texture1;" + "};"; + auto session = spCreateSession(); + auto request = spCreateCompileRequest(session); + spAddCodeGenTarget(request, SLANG_DXBC); + int tuIndex = spAddTranslationUnit(request, SLANG_SOURCE_LANGUAGE_SLANG, "tu1"); + spAddTranslationUnitSourceString(request, tuIndex, "internalFile", testSource); + spCompile(request); + + auto testBody = [&]() + { + auto reflection = slang::ShaderReflection::get(request); + auto testStruct = reflection->findTypeByName("TestStruct"); + SLANG_CHECK_ABORT(testStruct->getFieldCount() == 2); + auto field0Name = testStruct->getFieldByIndex(0)->getName(); + SLANG_CHECK_ABORT(field0Name != nullptr && strcmp(field0Name, "member0") == 0); + auto field1Name = testStruct->getFieldByIndex(1)->getName(); + SLANG_CHECK_ABORT(field1Name != nullptr && strcmp(field1Name, "texture1") == 0); + + auto intType = reflection->findTypeByName("int"); + auto intTypeName = intType->getName(); + SLANG_CHECK_ABORT(intTypeName && strcmp(intTypeName, "int") == 0); + + auto paramBlockType = reflection->findTypeByName("ParameterBlock"); + SLANG_CHECK_ABORT(paramBlockType != nullptr); + auto paramBlockTypeName = paramBlockType->getName(); + SLANG_CHECK_ABORT(paramBlockTypeName && strcmp(paramBlockTypeName, "ParameterBlock") == 0); + auto paramBlockElementType = paramBlockType->getElementType(); + SLANG_CHECK_ABORT(paramBlockElementType != nullptr); + auto paramBlockElementTypeName = paramBlockElementType->getName(); + SLANG_CHECK_ABORT(paramBlockElementTypeName && strcmp(paramBlockElementTypeName, "TestStruct") == 0); + }; + + testBody(); + + spDestroyCompileRequest(request); + spDestroySession(session); +} + diff --git a/tools/slang-unit-test/unit-test-free-list.cpp b/tools/slang-unit-test/unit-test-free-list.cpp new file mode 100644 index 000000000..d6c8b47a7 --- /dev/null +++ b/tools/slang-unit-test/unit-test-free-list.cpp @@ -0,0 +1,53 @@ +// unit-test-free-list.cpp + +#include "../../source/core/slang-free-list.h" + +#include +#include + +#include "tools/unit-test/slang-unit-test.h" + +#include "../../source/core/slang-random-generator.h" +#include "../../source/core/slang-list.h" + +using namespace Slang; + +SLANG_UNIT_TEST(freeList) +{ + FreeList freeList; + freeList.init(sizeof(int), sizeof(void*), 10); + + DefaultRandomGenerator randGen(0x24343); + + List allocs; + + for (int i = 0; i < 1000; i++) + { + const int numAlloc = randGen.nextInt32UpTo(20); + + for (int j = 0; j < numAlloc; j++) + { + int* ptr = (int*)freeList.allocate(); + *ptr = i; + allocs.add(ptr); + } + + int numDealloc = randGen.nextInt32UpTo(19); + numDealloc = int(allocs.getCount()) < numDealloc ? int(allocs.getCount()) : numDealloc; + + for (int j = 0; j < numDealloc; j++) + { + const int index = randGen.nextInt32UpTo(int(allocs.getCount())); + + int* alloc = allocs[index]; + + SLANG_CHECK(*alloc <= i); + SLANG_CHECK(*alloc >= 0); + + freeList.deallocate(alloc); + + allocs.fastRemoveAt(index); + } + } +} + diff --git a/tools/slang-unit-test/unit-test-json.cpp b/tools/slang-unit-test/unit-test-json.cpp new file mode 100644 index 000000000..2d2874cc8 --- /dev/null +++ b/tools/slang-unit-test/unit-test-json.cpp @@ -0,0 +1,320 @@ + +#include "../../source/compiler-core/slang-json-lexer.h" +#include "../../source/core/slang-string-escape-util.h" +#include "../../source/compiler-core/slang-json-parser.h" +#include "../../source/compiler-core/slang-json-value.h" + +#include "tools/unit-test/slang-unit-test.h" + +using namespace Slang; + +namespace { // anonymous + +struct Element +{ + JSONTokenType type; + const char* value; +}; + +} // anonymous + +static SlangResult _lex(const char* in, DiagnosticSink* sink, List& toks) +{ + SourceManager* sourceManager = sink->getSourceManager(); + + String contents(in); + SourceFile* sourceFile = sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), contents); + SourceView* sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc()); + + JSONLexer lexer; + + lexer.init(sourceView, sink); + + while (lexer.peekType() != JSONTokenType::EndOfFile) + { + if (lexer.peekType() == JSONTokenType::Invalid) + { + toks.add(lexer.peekToken()); + return SLANG_FAIL; + } + + toks.add(lexer.peekToken()); + lexer.advance(); + } + + toks.add(lexer.peekToken()); + + // If we advance from end of file we should still be at EndOfFile + SLANG_ASSERT(lexer.advance() == JSONTokenType::EndOfFile); + + return SLANG_OK; +} + +static SlangResult _parse(const char* in, DiagnosticSink* sink, JSONListener* listener) +{ + SourceManager* sourceManager = sink->getSourceManager(); + + String contents(in); + SourceFile* sourceFile = sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), contents); + SourceView* sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc()); + + JSONLexer lexer; + lexer.init(sourceView, sink); + + JSONParser parser; + SLANG_RETURN_ON_FAIL(parser.parse(&lexer, sourceView, listener, sink)); + return SLANG_OK; +} + +static bool _areEqual(SourceManager* sourceManager, const List& toks, const Element* eles, Index elesCount) +{ + if (toks.getCount() != elesCount) + { + return false; + } + + SourceView* sourceView = toks.getCount() ? sourceManager->findSourceView(toks[0].loc) : nullptr; + const char*const content = sourceView ? sourceView->getContent().begin() : nullptr; + + for (Index i = 0; i < toks.getCount(); ++i) + { + const JSONToken& tok = toks[i]; + const auto& ele = eles[i]; + + if (tok.type != ele.type) + { + return false; + } + + SLANG_ASSERT(sourceView->getRange().contains(tok.loc)); + + const char* start = content + sourceView->getRange().getOffset(tok.loc); + + UnownedStringSlice lexeme(start, tok.length); + + if (lexeme != ele.value) + { + return false; + } + } + + return true; +} + +SLANG_UNIT_TEST(json) +{ + SourceManager sourceManager; + sourceManager.initialize(nullptr, nullptr); + DiagnosticSink sink(&sourceManager, nullptr); + + { + const char text[] = " { \"Hello\" : [ \"World\", 1, 2.0, -3.0, -435.5345435, 45e-10, 421.00e+20, 17e1] }"; + + const Element eles[] = + { + {JSONTokenType::LBrace, "{" }, + {JSONTokenType::StringLiteral, "\"Hello\""}, + {JSONTokenType::Colon, ":" }, + {JSONTokenType::LBracket, "[" }, + {JSONTokenType::StringLiteral, "\"World\"" }, + {JSONTokenType::Comma, "," }, + {JSONTokenType::IntegerLiteral, "1" }, + {JSONTokenType::Comma, "," }, + {JSONTokenType::FloatLiteral, "2.0" }, + {JSONTokenType::Comma, "," }, + {JSONTokenType::FloatLiteral, "-3.0" }, + {JSONTokenType::Comma, "," }, + {JSONTokenType::FloatLiteral, "-435.5345435" }, + {JSONTokenType::Comma, "," }, + {JSONTokenType::FloatLiteral, "45e-10" }, + {JSONTokenType::Comma, "," }, + {JSONTokenType::FloatLiteral, "421.00e+20" }, + {JSONTokenType::Comma, "," }, + {JSONTokenType::FloatLiteral, "17e1" }, + {JSONTokenType::RBracket, "]" }, + {JSONTokenType::RBrace, "}" }, + {JSONTokenType::EndOfFile, "" }, + }; + + List toks; + SLANG_CHECK(SLANG_SUCCEEDED(_lex(text, &sink, toks))); + + SLANG_CHECK(_areEqual(&sourceManager, toks, eles, SLANG_COUNT_OF(eles))); + } + + { + StringEscapeHandler* handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::JSON); + + + { + const auto slice = UnownedStringSlice::fromLiteral("\n\r\b\f\t \"\\/ Some text..."); + + SLANG_CHECK(handler->isEscapingNeeded(slice)); + SLANG_CHECK(!handler->isEscapingNeeded(UnownedStringSlice::fromLiteral("Hello!"))); + + StringBuilder escaped; + handler->appendEscaped(slice, escaped); + + StringBuilder unescaped; + handler->appendUnescaped(escaped.getUnownedSlice(), unescaped); + + SLANG_CHECK(unescaped == slice); + } + + { + uint32_t v = 0x7f; + + StringBuilder buf; + while (v < 0x10000) + { + char work[10] = "\\u"; + + for (Int i = 0; i < 4; ++i) + { + const uint32_t digitValue = (v >> ((3 - i) * 4)) & 0xf; + + char digitC = (digitValue > 9) ? char(digitValue - 10 + 'a') : char(digitValue + '0'); + work[i + 2] = digitC; + } + + buf << UnownedStringSlice(work, 6); + + v += v; + } + + // Decode it + StringBuilder unescaped; + handler->appendUnescaped(buf.getUnownedSlice(), unescaped); + + // Encode it + StringBuilder escaped; + handler->appendEscaped(unescaped.getUnownedSlice(), escaped); + + SLANG_CHECK(escaped == buf); + } + } + + { + const char in[] = "{ \"Hello\" : \"Json\", \"!\" : 10, \"array\" : [1, 2, 3.0] }"; + + { + auto style = JSONWriter::IndentationStyle::Allman; + + JSONWriter writer(style); + _parse(in, &sink, &writer); + + JSONWriter writerCheck(style); + _parse(writer.getBuilder().getBuffer(), &sink, &writerCheck); + + SLANG_CHECK(writerCheck.getBuilder() == writer.getBuilder()); + } + + { + auto style = JSONWriter::IndentationStyle::KNR; + + JSONWriter writer(style, 80); + _parse(in, &sink, &writer); + + JSONWriter writerCheck(style); + _parse(writer.getBuilder().getBuffer(), &sink, &writerCheck); + + SLANG_CHECK(writerCheck.getBuilder() == writer.getBuilder()); + } + + { + // Let's parse into a Value + RefPtr container = new JSONContainer(&sourceManager); + + JSONValue value; + { + JSONBuilder builder(container); + + SLANG_CHECK(SLANG_SUCCEEDED(_parse(in, &sink, &builder))); + value = builder.getRootValue(); + } + // Let's recreate + JSONValue copy; + { + JSONBuilder builder(container); + container->traverseRecursively(value, &builder); + copy = builder.getRootValue(); + } + + SLANG_CHECK(container->areEqual(value, copy)); + + } + } + + { + // Only need a SourceManager if we are going to store lexemes + RefPtr container = new JSONContainer(nullptr); + + { + List values; + + for (Int i = 0; i < 100; ++i) + { + + values.add(JSONValue::makeInt(i)); + values.add(JSONValue::makeFloat(-double(i))); + } + + JSONValue array = container->createArray(values.getBuffer(), values.getCount()); + + auto arrayView = container->getArray(array); + + SLANG_CHECK(arrayView.getCount() == values.getCount()); + + // Check the values are the same + SLANG_CHECK(container->areEqual(arrayView.getBuffer(), values.getBuffer(), arrayView.getCount())); + + { + JSONWriter writer(JSONWriter::IndentationStyle::KNR, 80); + + container->traverseRecursively(array, &writer); + } + } + { + JSONValue obj = JSONValue::makeEmptyObject(); + + JSONKey key = container->getKey(UnownedStringSlice::fromLiteral("Hello")); + + container->setKeyValue(obj, key, JSONValue::makeNull()); + container->setKeyValue(obj, key, JSONValue::makeInt(10)); + + auto objView = container->getObject(obj); + + SLANG_CHECK(objView.getCount() == 1); + + SLANG_CHECK(objView[0].value.asInteger() == 10); + } + } + + // Check repeated keys works out + // Check out comparison works with different key orders + { + RefPtr container = new JSONContainer(&sourceManager); + const char aText[] = "{ \"a\" : 10, \"b\" : 20.0, \"a\" : \"Hello\" }"; + + + JSONBuilder builder(container); + SLANG_CHECK(SLANG_SUCCEEDED(_parse(aText, &sink, &builder))); + const JSONValue a = builder.getRootValue(); + + builder.reset(); + + const char bText[] = "{ \"b\" : 20.0, \"a\" : \"Hello\"}"; + SLANG_CHECK(SLANG_SUCCEEDED(_parse(bText, &sink, &builder))); + const JSONValue b = builder.getRootValue(); + + SLANG_CHECK(container->areEqual(a, b)); + + JSONBuilder convertBuilder(container, JSONBuilder::Flag::ConvertLexemes); + + SLANG_CHECK(SLANG_SUCCEEDED(_parse(aText, &sink, &convertBuilder))); + const JSONValue c = builder.getRootValue(); + + SLANG_CHECK(container->areEqual(a, c)); + } +} + diff --git a/tools/slang-unit-test/unit-test-memory-arena.cpp b/tools/slang-unit-test/unit-test-memory-arena.cpp new file mode 100644 index 000000000..b2671160a --- /dev/null +++ b/tools/slang-unit-test/unit-test-memory-arena.cpp @@ -0,0 +1,271 @@ +// unit-test-free-list.cpp + +#include "../../source/core/slang-memory-arena.h" + +#include +#include + +#include "tools/unit-test/slang-unit-test.h" + +#include "../../source/core/slang-random-generator.h" +#include "../../source/core/slang-list.h" + +using namespace Slang; + + +namespace // anonymous +{ + +struct Block +{ + void* m_data; + size_t m_size; + uint8_t m_value; +}; + +enum class TestMode +{ + eUnaligned, + eImplicitAligned, ///< Alignment is kept implicitly with Unaligned allocs of the right size + eDefaultAligned, + eExplicitAligned, + eCount, +}; + +} // anonymous + +static size_t getAlignment(TestMode mode) +{ + switch (mode) + { + default: + case TestMode::eUnaligned: + return 1; + case TestMode::eExplicitAligned: + return 16; + case TestMode::eImplicitAligned: + return 32; + case TestMode::eDefaultAligned: + return MemoryArena::kMinAlignment; + } +} + +static bool hasValueShort(const uint8_t* data, size_t size, uint8_t value) +{ + for (size_t i = 0; i < size; ++i) + { + if (data[i] != value) + { + return false; + } + } + return true; +} + +static bool hasValue(const uint8_t* data, size_t size, uint8_t value) +{ + const size_t alignMask = sizeof(size_t) - 1; + + if (size <= sizeof(size_t) * 2) + { + return hasValueShort(data, size, value); + } + + if (size_t(data) & alignMask) + { + size_t firstSize = sizeof(size_t) - (size_t(data) & alignMask); + if (!hasValueShort(data, firstSize, value)) + { + return false; + } + size -= firstSize; + data += firstSize; + + assert((size_t(data) & alignMask) == 0); + } + + // Now do the middle + size_t numWords = size / sizeof(size_t); + + // Expand the byte up to a word size + size_t wordValue = (size_t(value) << 8) | value; + wordValue = (wordValue << 16) | wordValue; + wordValue = (sizeof(size_t) > 4) ? size_t((uint64_t(wordValue) << 32) | wordValue) : wordValue; + + const size_t* wordData = (const size_t*)data; + for (size_t i = 0; i < numWords; ++i) + { + if (wordData[i] != wordValue) + { + return false; + } + } + + // Do the end piece + return hasValueShort(data + sizeof(size_t) * numWords, size & alignMask, value); +} + +SLANG_UNIT_TEST(memoryArena) +{ + DefaultRandomGenerator randGen(0x5346536a); + + { + const size_t blockSize = 1024; + MemoryArena arena; + arena.init(blockSize); + + List blocks; + + blocks.add(arena.allocate(100)); + blocks.add(arena.allocate(blockSize * 2)); + blocks.add(arena.allocate(100)); + blocks.add(arena.allocate(blockSize * 2)); + blocks.add(arena.allocate(100)); + + arena.deallocateAll(); + blocks.add(arena.allocate(100)); + blocks.add(arena.allocate(blockSize * 2)); + + arena.reset(); + + { + uint32_t data[] = { 1, 2, 3 }; + + const uint32_t* copy = arena.allocateAndCopyArray(data, SLANG_COUNT_OF(data)); + + SLANG_CHECK(::memcmp(copy, data, sizeof(data)) == 0); + } + } + + { + int count = 0; + const size_t blockSize = 1024; + + for (TestMode mode = TestMode(0); int(mode) < int(TestMode::eCount); mode = TestMode(int(mode) + 1)) + { + const size_t alignment = getAlignment(mode); + + MemoryArena arena; + arena.init(blockSize, alignment); + + List blocks; + + for (int i = 0; i < 10000; i++) + { + count++; + + const int var = randGen.nextInt32() & 0x3ff; + if (var < 3 && blocks.getCount() > 0) + { + if (var == 1) + { + // Deallocate everything + arena.deallocateAll(); + blocks.clear(); + } + else if (var == 2) + { + arena.reset(); + blocks.clear(); + } + else if (var == 3) + { + arena.rewindToCursor(nullptr); + blocks.clear(); + } + else if (var == 4) + { + // Rewind to a random position + int rewindIndex = randGen.nextInt32UpTo(int32_t(blocks.getCount())); + // rewind to this block + arena.rewindToCursor(blocks[rewindIndex].m_data); + // All the blocks (includign this one) and now deallocated + blocks.setCount(rewindIndex); + + } + else + { + size_t usedMemory = arena.calcTotalMemoryUsed(); + size_t allocatedMemory = arena.calcTotalMemoryAllocated(); + + SLANG_CHECK(allocatedMemory >= usedMemory); + } + } + else + { + size_t sizeInBytes = (randGen.nextInt32() & 255) + 1; + + // Lets go for an oversized block + if ((randGen.nextInt32() & 0xff) < 2) + { + sizeInBytes += blockSize; + } + else if ((randGen.nextInt32() & 0xff) < 2) + { + // Let's try for a block that's awkwardly sized + sizeInBytes = blockSize / 3 + 10; + } + + const uint8_t value = uint8_t(randGen.nextInt32()); + + void* mem = nullptr; + switch (mode) + { + default: + case TestMode::eUnaligned: + { + mem = arena.allocateUnaligned(sizeInBytes); + break; + } + case TestMode::eImplicitAligned: + { + // Fix the size to get implicit alignment + sizeInBytes = (sizeInBytes & ~(alignment - 1)) + alignment; + mem = arena.allocateUnaligned(sizeInBytes); + break; + } + case TestMode::eExplicitAligned: + { + mem = arena.allocateAligned(sizeInBytes, alignment); + break; + } + case TestMode::eDefaultAligned: + { + mem = arena.allocate(sizeInBytes); + break; + } + } + + // Check it is aligned + SLANG_CHECK((size_t(mem) & (alignment - 1)) == 0); + + ::memset(mem, value, sizeInBytes); + + Block block; + + block.m_data = mem; + block.m_size = sizeInBytes; + block.m_value = value; + + blocks.add(block); + } + + // Check the blocks + for (Index j = 0; j < blocks.getCount(); ++j) + { + const Block& block = blocks[j]; + + SLANG_CHECK(arena.isValid(block.m_data, block.m_size)); + + SLANG_CHECK(hasValue((uint8_t*)block.m_data, block.m_size, block.m_value)); + } + } + } + } + { + // Do lots of allocations and test out rewind + + + + } +} diff --git a/tools/slang-unit-test/unit-test-path.cpp b/tools/slang-unit-test/unit-test-path.cpp new file mode 100644 index 000000000..c27feee9c --- /dev/null +++ b/tools/slang-unit-test/unit-test-path.cpp @@ -0,0 +1,62 @@ +// unit-test-path.cpp + +#include "../../source/core/slang-io.h" + +#include "tools/unit-test/slang-unit-test.h" + +using namespace Slang; + +SLANG_UNIT_TEST(path) +{ +#if SLANG_WINDOWS_FAMILY + // Disable for now on non windows has some problems on *some* Linux based CI. + { + String path; + SlangResult res = Path::getCanonical("source/slang", path); + SLANG_CHECK(SLANG_SUCCEEDED(res)); + + String parentPath; + res = Path::getCanonical("source", parentPath); + SLANG_CHECK(SLANG_SUCCEEDED(res)); + + String parentPath2 = Path::getParentDirectory(path); + SLANG_CHECK(parentPath == parentPath2); + } +#endif + // Test the paths + { + SLANG_CHECK(Path::simplify(".") == "."); + SLANG_CHECK(Path::simplify("..") == ".."); + SLANG_CHECK(Path::simplify("blah/..") == "."); + + SLANG_CHECK(Path::simplify("blah/.././a") == "a"); + + SLANG_CHECK(Path::simplify("a:/what/.././../is/./../this/.") == "a:/../this"); + + SLANG_CHECK(Path::simplify("a:/what/.././../is/./../this/./") == "a:/../this"); + + SLANG_CHECK(Path::simplify("a:\\what\\..\\.\\..\\is\\.\\..\\this\\.\\") == "a:/../this"); + + SLANG_CHECK(Path::simplify("tests/preprocessor/.\\pragma-once-a.h") == "tests/preprocessor/pragma-once-a.h"); + + + SLANG_CHECK(Path::hasRelativeElement(".")); + SLANG_CHECK(Path::hasRelativeElement("..")); + SLANG_CHECK(Path::hasRelativeElement("blah/..")); + + SLANG_CHECK(Path::hasRelativeElement("blah/.././a")); + SLANG_CHECK(Path::hasRelativeElement("a") == false); + SLANG_CHECK(Path::hasRelativeElement("blah/a") == false); + SLANG_CHECK(Path::hasRelativeElement("a:\\blah/a") == false); + + + SLANG_CHECK(Path::hasRelativeElement("a:/what/.././../is/./../this/.")); + + SLANG_CHECK(Path::hasRelativeElement("a:/what/.././../is/./../this/./")); + + SLANG_CHECK(Path::hasRelativeElement("a:\\what\\..\\.\\..\\is\\.\\..\\this\\.\\")); + + + } +} + diff --git a/tools/slang-unit-test/unit-test-riff.cpp b/tools/slang-unit-test/unit-test-riff.cpp new file mode 100644 index 000000000..2902a9af5 --- /dev/null +++ b/tools/slang-unit-test/unit-test-riff.cpp @@ -0,0 +1,179 @@ +// unit-test-riff.cpp + +#include "../../source/core/slang-riff.h" + +#include "../../source/core/slang-random-generator.h" + +#include "tools/unit-test/slang-unit-test.h" + +using namespace Slang; + +static void _writeRandom(RandomGenerator* rand, size_t maxSize, RiffContainer& ioContainer, List& ioData) +{ + while (true) + { + const Index oldCount = ioData.getCount(); + + const size_t allocSize = size_t(rand->nextInt32InRange(1, 50)); + + if (allocSize + oldCount > maxSize) + { + break; + } + + ioData.setCount(oldCount + Index(allocSize)); + rand->nextData(ioData.getBuffer() + oldCount, allocSize); + + // Write + ioContainer.write(ioData.getBuffer() + oldCount, allocSize); + } + + // Should be a single block with same data as the List + RiffContainer::DataChunk* dataChunk = as(ioContainer.getCurrentChunk()); + SLANG_ASSERT(dataChunk); +} + +SLANG_UNIT_TEST(riff) +{ + typedef RiffContainer::ScopeChunk ScopeChunk; + typedef RiffContainer::Chunk::Kind Kind; + + const FourCC markThings = SLANG_FOUR_CC('T', 'H', 'I', 'N'); + const FourCC markData = SLANG_FOUR_CC('D', 'A', 'T', 'A'); + + { + RiffContainer container; + + { + ScopeChunk scopeContainer(&container, Kind::List, markThings); + { + ScopeChunk scopeChunk(&container, Kind::Data, markData); + + const char hello[] = "Hello "; + const char world[] = "World!"; + + container.write(hello, sizeof(hello)); + container.write(world, sizeof(world)); + } + + { + ScopeChunk scopeChunk(&container, Kind::Data, markData); + + const char test0[] = "Testing... "; + const char test1[] = "Testing!"; + + container.write(test0, sizeof(test0)); + container.write(test1, sizeof(test1)); + } + + { + ScopeChunk innerScopeContainer(&container, Kind::List, markThings); + + { + ScopeChunk scopeChunk(&container, Kind::Data, markData); + + const char another[] = "Another?"; + container.write(another, sizeof(another)); + } + } + } + + SLANG_CHECK(container.isFullyConstructed()); + SLANG_CHECK(RiffContainer::isChunkOk(container.getRoot())); + + { + StringBuilder builder; + { + StringWriter writer(&builder, 0); + RiffUtil::dump(container.getRoot(), &writer); + } + + { + OwnedMemoryStream stream(FileAccess::ReadWrite); + SLANG_CHECK(SLANG_SUCCEEDED(RiffUtil::write(container.getRoot(), true, &stream))); + + stream.seek(SeekOrigin::Start, 0); + + RiffContainer readContainer; + SLANG_CHECK(SLANG_SUCCEEDED(RiffUtil::read(&stream, readContainer))); + + // Dump the read contents + StringBuilder readBuilder; + { + StringWriter writer(&readBuilder, 0); + RiffUtil::dump(readContainer.getRoot(), &writer); + } + + // They should be the same + SLANG_CHECK(readBuilder == builder); + } + } + + } + + // Test writing as a stream only allocates a single data block (as long as there is enough space). + { + RiffContainer container; + + ScopeChunk scopeChunk(&container, Kind::List, markData); + { + ScopeChunk scopeChunk(&container, Kind::Data, markData); + RefPtr rand = RandomGenerator::create(0x345234); + + List data; + _writeRandom(rand, container.getMemoryArena().getBlockPayloadSize() / 2, container, data); + + // Should be a single block with same data as the List + RiffContainer::DataChunk* dataChunk = as(container.getCurrentChunk()); + SLANG_ASSERT(dataChunk); + + // It should be a single block + SLANG_CHECK(dataChunk->getSingleData() != nullptr); + + SLANG_CHECK(dataChunk->isEqual(data.getBuffer(), data.getCount())); + + } + } + + // Test writing across multiple data blocks + { + RefPtr rand = RandomGenerator::create(0x345234); + + for (Int i = 0 ; i < 100; ++i) + { + RiffContainer container; + + const size_t maxSize = rand->nextInt32InRange(1, int32_t(container.getMemoryArena().getBlockPayloadSize() * 3)); + + ScopeChunk scopeChunk(&container, Kind::List, markData); + { + ScopeChunk scopeChunk(&container, Kind::Data, markData); + + List data; + _writeRandom(rand, maxSize, container, data); + + // Should be a single block with same data as the List + RiffContainer::DataChunk* dataChunk = as(container.getCurrentChunk()); + SLANG_CHECK(dataChunk && dataChunk->isEqual(data.getBuffer(), data.getCount())); + } + } + } + +#if 0 + { + RiffContainer container; + { + FileStream readStream("ambient-drop.wav", FileMode::Open, FileAccess::Read, FileShare::ReadWrite); + SLANG_CHECK(SLANG_SUCCEEDED(RiffUtil::read(&readStream, container))); + RiffUtil::dump(container.getRoot(), StdWriters::getOut()); + } + // Write it + { + + FileStream writeStream("check.wav", FileMode::Create, FileAccess::Write, FileShare::ReadWrite); + SLANG_CHECK(SLANG_SUCCEEDED(RiffUtil::write(container.getRoot(), true, &writeStream))); + } + } +#endif +} + diff --git a/tools/slang-unit-test/unit-test-short-list.cpp b/tools/slang-unit-test/unit-test-short-list.cpp new file mode 100644 index 000000000..2760d633e --- /dev/null +++ b/tools/slang-unit-test/unit-test-short-list.cpp @@ -0,0 +1,77 @@ +// unit-test-path.cpp + +#include "source/core/slang-basic.h" +#include "tools/unit-test/slang-unit-test.h" + +using namespace Slang; + +template +static bool _checkArrayView(ArrayView v0, ArrayView v1) +{ + if (v0.getCount() != v1.getCount()) + return false; + for (Index i = 0; i < v0.getCount(); i++) + if (v0[i] != v1[i]) + return false; + return true; +} + +SLANG_UNIT_TEST(shortList) +{ + { + ShortList shortList = { "a", "b", "c" }; + shortList.add("d"); + auto arrayView = shortList.getArrayView(); + SLANG_CHECK(arrayView.ownsStorage == false); + SLANG_CHECK(_checkArrayView(arrayView.arrayView, + List{"a", "b", "c", "d"}.getArrayView())); + shortList.add("e"); + auto arrayView2 = shortList.getArrayView(); + SLANG_CHECK(arrayView2.ownsStorage == true); + SLANG_CHECK(_checkArrayView(arrayView2.arrayView, + List{"a", "b", "c", "d", "e"}.getArrayView())); + auto arrayView3 = shortList.getArrayView(0, 2); + SLANG_CHECK(arrayView3.ownsStorage == false); + SLANG_CHECK(_checkArrayView(arrayView3.arrayView, + List{"a", "b"}.getArrayView())); + auto arrayView4 = shortList.getArrayView(4, 1); + SLANG_CHECK(arrayView4.ownsStorage == false); + SLANG_CHECK(_checkArrayView(arrayView4.arrayView, + List{"e"}.getArrayView())); + auto arrayView5 = shortList.getArrayView(2, 3); + SLANG_CHECK(arrayView5.ownsStorage == true); + SLANG_CHECK(_checkArrayView(arrayView5.arrayView, + List{"c", "d", "e"}.getArrayView())); + + ShortList copy2; + ShortList copy1; + copy1 = shortList; + for (auto item : copy1) + copy2.add(item); + SLANG_CHECK(_checkArrayView(copy2.getArrayView().arrayView, + List{"a", "b", "c", "d", "e"}.getArrayView())); + + SLANG_CHECK(copy2.indexOf("a") == 0); + SLANG_CHECK(copy2.indexOf("e") == 4); + + SLANG_CHECK(copy2.lastIndexOf("a") == 0); + SLANG_CHECK(copy2.lastIndexOf("e") == 4); + + copy2.compress(); + copy2.add("f"); + copy2.fastRemove("c"); + copy2.compress(); + SLANG_CHECK(_checkArrayView(copy2.getArrayView().arrayView, + List{"a", "b", "f", "d", "e"}.getArrayView())); + + shortList.removeLast(); + shortList.removeLast(); + shortList.compress(); + SLANG_CHECK(_checkArrayView(shortList.getArrayView().arrayView, + List{"a", "b", "c"}.getArrayView())); + shortList.add("d"); + shortList.add("e"); + SLANG_CHECK(_checkArrayView(shortList.getArrayView().arrayView, + List{"a", "b", "c", "d", "e"}.getArrayView())); + } +} diff --git a/tools/slang-unit-test/unit-test-string.cpp b/tools/slang-unit-test/unit-test-string.cpp new file mode 100644 index 000000000..629ed2373 --- /dev/null +++ b/tools/slang-unit-test/unit-test-string.cpp @@ -0,0 +1,262 @@ +// unit-test-path.cpp + +#include "../../source/core/slang-string-util.h" + +#include "tools/unit-test/slang-unit-test.h" + +//#include + +#include + +using namespace Slang; + +static bool _areEqual(const List& lines, const UnownedStringSlice* checkLines, Int checkLinesCount) +{ + if (checkLinesCount != lines.getCount()) + { + return false; + } + + for (Int i = 0; i < checkLinesCount; ++i) + { + if (lines[i] != checkLines[i]) + { + return false; + } + } + return true; +} + +static bool _checkLines(const UnownedStringSlice& input, const UnownedStringSlice* checkLines, Int checkLinesCount) +{ + List lines; + StringUtil::calcLines(input, lines); + return _areEqual(lines, checkLines, checkLinesCount); +} + +static bool _checkLineParser(const UnownedStringSlice& input) +{ + UnownedStringSlice remaining(input), line; + for (const auto parserLine : LineParser(input)) + { + if (!StringUtil::extractLine(remaining, line) || line != parserLine) + { + return false; + } + } + return StringUtil::extractLine(remaining, line) == false; +} + +static void _append(double v, StringBuilder& buf) +{ + std::ostringstream stream; + stream.imbue(std::locale::classic()); + stream.setf(std::ios::fixed, std::ios::floatfield); + stream.precision(20); + + stream << std::scientific << v; + + buf << stream.str().c_str(); +} + +// Unit of least precision +static int64_t _calcULPDistance(double a, double b) +{ + // Save work if the floats are equal. + // Also handles +0 == -0 + if (a == b) + { + return 0; + } + + const int64_t max = int64_t((~uint64_t(0)) >> 1); + +#if 0 + // Max distance for NaN + if (isnan(a) || isnan(b)) + { + return max; + } + + // If one's infinite and they're not equal, max distance. + if (isinf(a) || isinf(b)) + { + return max; + } +#endif + + int64_t ia, ib; + memcpy(&ia, &a, sizeof(a)); + memcpy(&ib, &b, sizeof(b)); + + // Don't compare differently-signed floats. + if ((ia < 0) != (ib < 0)) + { + return max; + } + + // Return the absolute value of the distance in ULPs. + int64_t distance = ia - ib; + return distance < 0 ? -distance : distance; +} + +static bool _areApproximatelyEqual(double a, double b, double fixedEpsilon = 1e-10, int ulpsEpsilon = 100) +{ + // Handle the near-zero case. + const double difference = abs(a - b); + if (difference <= fixedEpsilon) + { + return true; + } + + return _calcULPDistance(a, b) <= ulpsEpsilon; +} + +SLANG_UNIT_TEST(string) +{ + { + UnownedStringSlice checkLines[] = { UnownedStringSlice::fromLiteral("") }; + SLANG_CHECK(_checkLines(UnownedStringSlice::fromLiteral(""), checkLines, SLANG_COUNT_OF(checkLines))); + } + { + // Will emit no lines + SLANG_CHECK(_checkLines(UnownedStringSlice(nullptr, nullptr), nullptr, 0)); + } + { + // Two lines - both empty + UnownedStringSlice checkLines[] = { UnownedStringSlice(), UnownedStringSlice()}; + SLANG_CHECK(_checkLines(UnownedStringSlice::fromLiteral("\n"), checkLines, SLANG_COUNT_OF(checkLines))); + } + { + UnownedStringSlice checkLines[] = { UnownedStringSlice::fromLiteral("Hello"), UnownedStringSlice::fromLiteral("World!") }; + SLANG_CHECK(_checkLines(UnownedStringSlice::fromLiteral("Hello\nWorld!"), checkLines, SLANG_COUNT_OF(checkLines))); + } + { + UnownedStringSlice checkLines[] = { UnownedStringSlice::fromLiteral("Hello"), UnownedStringSlice::fromLiteral("World!"), UnownedStringSlice() }; + SLANG_CHECK(_checkLines(UnownedStringSlice::fromLiteral("Hello\n\rWorld!\n"), checkLines, SLANG_COUNT_OF(checkLines))); + } + + { + SLANG_CHECK(_checkLineParser(UnownedStringSlice::fromLiteral("Hello\n\rWorld!\n"))); + SLANG_CHECK(_checkLineParser(UnownedStringSlice::fromLiteral("\n"))); + SLANG_CHECK(_checkLineParser(UnownedStringSlice::fromLiteral(""))); + } + { + Int value; + SLANG_CHECK(SLANG_SUCCEEDED(StringUtil::parseInt(UnownedStringSlice("-10"), value)) && value == -10); + SLANG_CHECK(SLANG_SUCCEEDED(StringUtil::parseInt(UnownedStringSlice("0"), value)) && value == 0); + SLANG_CHECK(SLANG_SUCCEEDED(StringUtil::parseInt(UnownedStringSlice("-0"), value)) && value == 0); + + SLANG_CHECK(SLANG_SUCCEEDED(StringUtil::parseInt(UnownedStringSlice("13824"), value)) && value == 13824); + SLANG_CHECK(SLANG_SUCCEEDED(StringUtil::parseInt(UnownedStringSlice("-13824"), value)) && value == -13824); + } + + { + UnownedStringSlice values[] = { UnownedStringSlice("hello"), UnownedStringSlice("world"), UnownedStringSlice("!") }; + ArrayView valuesView(values, SLANG_COUNT_OF(values)); + + List checkValues; + StringBuilder builder; + + { + builder.Clear(); + StringUtil::join(values, 0, ',', builder); + SLANG_CHECK(builder == ""); + } + + { + builder.Clear(); + StringUtil::join(values, 1, ',', builder); + SLANG_CHECK(builder == "hello"); + + StringUtil::split(builder.getUnownedSlice(), ',', checkValues); + SLANG_CHECK(checkValues.getArrayView() == ArrayView(values, 1)); + } + + { + builder.Clear(); + StringUtil::join(values, 2, ',', builder); + SLANG_CHECK(builder == "hello,world"); + + StringUtil::split(builder.getUnownedSlice(), ',', checkValues); + SLANG_CHECK(checkValues.getArrayView() == ArrayView(values, 2)); + } + + { + builder.Clear(); + StringUtil::join(values, 3, UnownedStringSlice("ab"), builder); + SLANG_CHECK(builder == "helloabworldab!"); + + StringUtil::split(builder.getUnownedSlice(), UnownedStringSlice("ab"), checkValues); + SLANG_CHECK(checkValues.getArrayView() == ArrayView(values, 3)); + } + } + { + + List values; + values.add(0.0); + values.add(-0.0); + + for (Index i = -300; i < 300; ++i) + { + double value = pow(10, i); + + values.add(value); + values.add(-value); + + values.addRange(value / 3); + values.addRange(-value / 3); + } + + StringBuilder buf; + + for (auto value : values) + { + buf.Clear(); + _append(value, buf); + + UnownedStringSlice slice = buf.getUnownedSlice(); + + double parsedValue; + SlangResult res = StringUtil::parseDouble(slice, parsedValue); + + auto ulpsParsed = _calcULPDistance(value, parsedValue); + + SLANG_CHECK(SLANG_SUCCEEDED(res)); + + // Check that they are equal + SLANG_CHECK(_areApproximatelyEqual(value, parsedValue)); + } + } + { + List values; + values.add(0); + + for (Index i = 0; i < 63; ++i) + { + auto value = int64_t(1) << i; + + values.add(value); + values.add(-value); + } + + StringBuilder buf; + + for (auto value : values) + { + buf.Clear(); + buf << value; + + + int64_t parsedValue; + + UnownedStringSlice slice = buf.getUnownedSlice(); + SlangResult res = StringUtil::parseInt64(slice, parsedValue); + + SLANG_CHECK(SLANG_SUCCEEDED(res)); + + // Check that they are equal + SLANG_CHECK(value == parsedValue); + } + } +} diff --git a/tools/unit-test/slang-unit-test.cpp b/tools/unit-test/slang-unit-test.cpp index a31614c05..28eba3a1f 100644 --- a/tools/unit-test/slang-unit-test.cpp +++ b/tools/unit-test/slang-unit-test.cpp @@ -5,13 +5,14 @@ struct SlangUnitTest { const char* name; - slang::UnitTestFunc func; + UnitTestFunc func; }; -class SlangUnitTestModule : public slang::IUnitTestModule +class SlangUnitTestModule : public IUnitTestModule { public: Slang::List tests; + ITestReporter* testReporter = nullptr; virtual SlangInt getTestCount() override { @@ -22,10 +23,21 @@ public: return tests[index].name; } - virtual slang::UnitTestFunc getTestFunc(SlangInt index) override + virtual UnitTestFunc getTestFunc(SlangInt index) override { return tests[index].func; } + + virtual void setTestReporter(ITestReporter* reporter) override + { + testReporter = reporter; + } + + virtual void destroy() override + { + tests = decltype(tests)(); + } + }; SlangUnitTestModule* _getTestModule() @@ -34,15 +46,20 @@ SlangUnitTestModule* _getTestModule() return &testModule; } +ITestReporter* getTestReporter() +{ + return _getTestModule()->testReporter; +} + extern "C" { -SLANG_DLL_EXPORT slang::IUnitTestModule* slangUnitTestGetModule() +SLANG_DLL_EXPORT IUnitTestModule* slangUnitTestGetModule() { return _getTestModule(); } } -slang::UnitTestRegisterHelper::UnitTestRegisterHelper(const char* name, UnitTestFunc testFunc) +UnitTestRegisterHelper::UnitTestRegisterHelper(const char* name, UnitTestFunc testFunc) { _getTestModule()->tests.add(SlangUnitTest{ name, testFunc }); } diff --git a/tools/unit-test/slang-unit-test.h b/tools/unit-test/slang-unit-test.h index 7651e6b46..033fab395 100644 --- a/tools/unit-test/slang-unit-test.h +++ b/tools/unit-test/slang-unit-test.h @@ -3,36 +3,73 @@ #include "slang.h" #include "source/core/slang-render-api-util.h" -namespace slang +enum class TestResult { - struct UnitTestContext - { - slang::IGlobalSession* slangGlobalSession; - const char* workDirectory; - ISlangWriter* outputWriter; - Slang::RenderApiFlags enabledApis; - }; - - typedef SlangResult (*UnitTestFunc)(UnitTestContext*); - - class IUnitTestModule - { - public: - virtual SlangInt getTestCount() = 0; - virtual const char* getTestName(SlangInt index) = 0; - virtual UnitTestFunc getTestFunc(SlangInt index) = 0; - }; - - class UnitTestRegisterHelper - { - public: - UnitTestRegisterHelper(const char* name, UnitTestFunc testFunc); - }; - - typedef slang::IUnitTestModule* (*UnitTestGetModuleFunc)(); + // NOTE! Must keep in order such that combine is meaningful. That is larger values are higher precident - and a series of tests that has lots of passes + // and a fail, is still a fail overall. + Ignored, + Pass, + Fail, +}; + +enum class TestMessageType +{ + Info, ///< General info (may not be shown depending on verbosity setting) + TestFailure, ///< Describes how a test failure took place + RunError, ///< Describes an error that caused a test not to actually correctly run +}; + +class ITestReporter +{ +public: + virtual void startTest(const char* testName) = 0; + virtual void addResult(TestResult result) = 0; + virtual void addResultWithLocation(TestResult result, const char* testText, const char* file, int line) = 0; + virtual void addResultWithLocation(bool testSucceeded, const char* testText, const char* file, int line) = 0; + virtual void addExecutionTime(double time) = 0; + virtual void message(TestMessageType type, const char* message) = 0; + virtual void endTest() = 0; +}; + +ITestReporter* getTestReporter(); + +struct UnitTestContext +{ + slang::IGlobalSession* slangGlobalSession; + const char* workDirectory; + Slang::RenderApiFlags enabledApis; +}; + +typedef void (*UnitTestFunc)(UnitTestContext*); + +class IUnitTestModule +{ +public: + virtual SlangInt getTestCount() = 0; + virtual const char* getTestName(SlangInt index) = 0; + virtual UnitTestFunc getTestFunc(SlangInt index) = 0; + virtual void setTestReporter(ITestReporter* reporter) = 0; + virtual void destroy() = 0; +}; + +class UnitTestRegisterHelper +{ +public: + UnitTestRegisterHelper(const char* name, UnitTestFunc testFunc); +}; + +typedef IUnitTestModule* (*UnitTestGetModuleFunc)(); #define SLANG_UNIT_TEST(name) \ - SlangResult name(slang::UnitTestContext* context); \ - slang::UnitTestRegisterHelper _##name##RegisterHelper(#name, name); \ - SlangResult name(slang::UnitTestContext* context) -} +void name(UnitTestContext* unitTestContext); \ +UnitTestRegisterHelper _##name##RegisterHelper(#name, name); \ +void name(UnitTestContext* unitTestContext) + +#define SLANG_CHECK(x) getTestReporter()->addResultWithLocation((x), #x, __FILE__, __LINE__); +#define SLANG_CHECK_ABORT(x) \ + { \ + bool _slang_check_result = (x); \ + getTestReporter()->addResultWithLocation(_slang_check_result, #x, __FILE__, __LINE__); \ + if (!_slang_check_result) return; \ + } +#define SLANG_IGNORE_TEST getTestReporter()->addResult(TestResult::Ignored); return; -- cgit v1.2.3