diff options
56 files changed, 806 insertions, 349 deletions
diff --git a/tests/diagnostics/attribute-error.slang b/tests/diagnostics/attribute-error.slang index b913d3d4a..9cc24437a 100644 --- a/tests/diagnostics/attribute-error.slang +++ b/tests/diagnostics/attribute-error.slang @@ -2,7 +2,7 @@ // Tests reflection of user defined attributes. -//TEST:REFLECTION:-stage compute -entry main -target hlsl +//DIAGNOSTIC_TEST:REFLECTION:-stage compute -entry main -target hlsl [__AttributeUsage(_AttributeTargets.Struct)] struct MyStructAttribute diff --git a/tests/diagnostics/break-outside-loop.slang b/tests/diagnostics/break-outside-loop.slang index 0de64e2c5..28db144e8 100644 --- a/tests/diagnostics/break-outside-loop.slang +++ b/tests/diagnostics/break-outside-loop.slang @@ -1,5 +1,5 @@ -//TEST:SIMPLE: -//TEST:COMMAND_LINE_SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: +//DIAGNOSTIC_TEST:COMMAND_LINE_SIMPLE: // `break` where it isn't allowed diff --git a/tests/diagnostics/call-argument-type.slang b/tests/diagnostics/call-argument-type.slang index b4f7e7477..93446265d 100644 --- a/tests/diagnostics/call-argument-type.slang +++ b/tests/diagnostics/call-argument-type.slang @@ -1,4 +1,4 @@ -//TEST(smoke):SIMPLE: +//DIAGNOSTIC_TEST(smoke):SIMPLE: // call function with wrong argument type struct A {}; diff --git a/tests/diagnostics/command-line/duplicate-output.slang b/tests/diagnostics/command-line/duplicate-output.slang index 794a8717b..bb6a63070 100644 --- a/tests/diagnostics/command-line/duplicate-output.slang +++ b/tests/diagnostics/command-line/duplicate-output.slang @@ -1,3 +1,3 @@ // duplicate-output.slang -//TEST:SIMPLE:-entry main -stage compute -o myKernel.dxbc -o myKernel.dxbc +//DIAGNOSTIC_TEST:SIMPLE:-entry main -stage compute -o myKernel.dxbc -o myKernel.dxbc diff --git a/tests/diagnostics/command-line/duplicate-target.slang b/tests/diagnostics/command-line/duplicate-target.slang index 44bbc62c7..a9ec96d0f 100644 --- a/tests/diagnostics/command-line/duplicate-target.slang +++ b/tests/diagnostics/command-line/duplicate-target.slang @@ -1,3 +1,3 @@ // duplicate-target.slang -//TEST:SIMPLE:-target hlsl -target hlsl +//DIAGNOSTIC_TEST:SIMPLE:-target hlsl -target hlsl diff --git a/tests/diagnostics/command-line/entry-point-conflicting-stage.slang b/tests/diagnostics/command-line/entry-point-conflicting-stage.slang index 89cf5cba0..c6c517258 100644 --- a/tests/diagnostics/command-line/entry-point-conflicting-stage.slang +++ b/tests/diagnostics/command-line/entry-point-conflicting-stage.slang @@ -1,5 +1,5 @@ // entry-point-conflicting-stage.slang -//TEST:SIMPLE:-stage vertex -stage fragment +//DIAGNOSTIC_TEST:SIMPLE:-stage vertex -stage fragment -//TEST:SIMPLE:-entry vsMain -stage compute -stage vertex +//DIAGNOSTIC_TEST:SIMPLE:-entry vsMain -stage compute -stage vertex diff --git a/tests/diagnostics/command-line/entry-point-redundant-stage.slang b/tests/diagnostics/command-line/entry-point-redundant-stage.slang index 903d696c7..9507b1ea0 100644 --- a/tests/diagnostics/command-line/entry-point-redundant-stage.slang +++ b/tests/diagnostics/command-line/entry-point-redundant-stage.slang @@ -1,5 +1,5 @@ // entry-point-redundant-stage.slang -//TEST:SIMPLE:-stage vertex -stage vertex +//DIAGNOSTIC_TEST:SIMPLE:-stage vertex -stage vertex -//TEST:SIMPLE:-entry vsMain -stage vertex -stage vertex +//DIAGNOSTIC_TEST:SIMPLE:-entry vsMain -stage vertex -stage vertex diff --git a/tests/diagnostics/command-line/explicit-implicit-stage-mismatch.vert b/tests/diagnostics/command-line/explicit-implicit-stage-mismatch.vert index 0ea731470..ec1f17887 100644 --- a/tests/diagnostics/command-line/explicit-implicit-stage-mismatch.vert +++ b/tests/diagnostics/command-line/explicit-implicit-stage-mismatch.vert @@ -1,3 +1,3 @@ // explicit-implicit-stage-mismatch.vert -//TEST:SIMPLE:-stage fragment +//DIAGNOSTIC_TEST:SIMPLE:-stage fragment diff --git a/tests/diagnostics/command-line/option-missing-argument.slang b/tests/diagnostics/command-line/option-missing-argument.slang index e62b37ba6..9af53301a 100644 --- a/tests/diagnostics/command-line/option-missing-argument.slang +++ b/tests/diagnostics/command-line/option-missing-argument.slang @@ -2,6 +2,6 @@ // Missing argument for an option: -//TEST:SIMPLE:-target -profile ps_4_0 +//DIAGNOSTIC_TEST:SIMPLE:-target -profile ps_4_0 -//TEST:SIMPLE:-profile ps_4_0 -target +//DIAGNOSTIC_TEST:SIMPLE:-profile ps_4_0 -target diff --git a/tests/diagnostics/command-line/output-no-entry-point.slang b/tests/diagnostics/command-line/output-no-entry-point.slang index 869dcabc4..891e4387a 100644 --- a/tests/diagnostics/command-line/output-no-entry-point.slang +++ b/tests/diagnostics/command-line/output-no-entry-point.slang @@ -1,3 +1,3 @@ // output-no-entry-point.slang -//TEST:SIMPLE:-o something.dxbc -entry vsMain -stage vertex -entry fsMain -stage fragment +//DIAGNOSTIC_TEST:SIMPLE:-o something.dxbc -entry vsMain -stage vertex -entry fsMain -stage fragment diff --git a/tests/diagnostics/command-line/output-no-target.slang b/tests/diagnostics/command-line/output-no-target.slang index 32921a8f0..a4c38f52d 100644 --- a/tests/diagnostics/command-line/output-no-target.slang +++ b/tests/diagnostics/command-line/output-no-target.slang @@ -1,3 +1,3 @@ // output-no-target.slang -//TEST:SIMPLE:-target dxbc -target spirv -entry main -stage compute -o bad.hlsl +//DIAGNOSTIC_TEST:SIMPLE:-target dxbc -target spirv -entry main -stage compute -o bad.hlsl diff --git a/tests/diagnostics/command-line/pass-through-no-stage.hlsl b/tests/diagnostics/command-line/pass-through-no-stage.hlsl index eabdadf10..e510d811c 100644 --- a/tests/diagnostics/command-line/pass-through-no-stage.hlsl +++ b/tests/diagnostics/command-line/pass-through-no-stage.hlsl @@ -5,4 +5,4 @@ // compilers don't support inferring the stage from // an attribute. -//TEST:SIMPLE:-pass-through fxc -entry main +//DIAGNOSTIC_TEST:SIMPLE:-pass-through fxc -entry main diff --git a/tests/diagnostics/command-line/profile-ignored.slang b/tests/diagnostics/command-line/profile-ignored.slang index 8a6590690..8c5a3de11 100644 --- a/tests/diagnostics/command-line/profile-ignored.slang +++ b/tests/diagnostics/command-line/profile-ignored.slang @@ -5,10 +5,10 @@ // Case 1: multiple (conflicting) profiles, so we can't infer a single stage // -//TEST:SIMPLE:-profile sm_5_0 -profile glsl_450 +//DIAGNOSTIC_TEST:SIMPLE:-profile sm_5_0 -profile glsl_450 // Case 2: a `-profile` option before any `-target`, possibly because // the user is specifying things in the wrong order. // -//TEST:SIMPLE:-profile sm_5_0 -target dxbc -profile glsl_450 -target spirv +//DIAGNOSTIC_TEST:SIMPLE:-profile sm_5_0 -target dxbc -profile glsl_450 -target spirv diff --git a/tests/diagnostics/command-line/stage-ignored.slang b/tests/diagnostics/command-line/stage-ignored.slang index 6d28c52bc..56a822d6f 100644 --- a/tests/diagnostics/command-line/stage-ignored.slang +++ b/tests/diagnostics/command-line/stage-ignored.slang @@ -6,4 +6,4 @@ // A `-stage` option before any `-entry`, possibly because // the user is specifying things in the wrong order. // -//TEST:SIMPLE:-stage vertex -entry vsMain -stage fragment -entry psMain +//DIAGNOSTIC_TEST:SIMPLE:-stage vertex -entry vsMain -stage fragment -entry psMain diff --git a/tests/diagnostics/command-line/unknown-codegen-target.slang b/tests/diagnostics/command-line/unknown-codegen-target.slang index 57015601d..1a5485176 100644 --- a/tests/diagnostics/command-line/unknown-codegen-target.slang +++ b/tests/diagnostics/command-line/unknown-codegen-target.slang @@ -1,3 +1,3 @@ // unknown-codegen-target.slang -//TEST:SIMPLE:-target z80 +//DIAGNOSTIC_TEST:SIMPLE:-target z80 diff --git a/tests/diagnostics/command-line/unknown-line-directive-mode.slang b/tests/diagnostics/command-line/unknown-line-directive-mode.slang index 7e61df3f9..078adc1ee 100644 --- a/tests/diagnostics/command-line/unknown-line-directive-mode.slang +++ b/tests/diagnostics/command-line/unknown-line-directive-mode.slang @@ -1,3 +1,3 @@ // unknown-line-directive-mode.slang -//TEST:SIMPLE:-line-directive-mode quizzical +//DIAGNOSTIC_TEST:SIMPLE:-line-directive-mode quizzical diff --git a/tests/diagnostics/command-line/unknown-option.slang b/tests/diagnostics/command-line/unknown-option.slang index 52320d758..dd69aa2a5 100644 --- a/tests/diagnostics/command-line/unknown-option.slang +++ b/tests/diagnostics/command-line/unknown-option.slang @@ -1,3 +1,3 @@ // unknown-option.slang -//TEST:SIMPLE:-destroy-all-humans +//DIAGNOSTIC_TEST:SIMPLE:-destroy-all-humans diff --git a/tests/diagnostics/command-line/unknown-output-format.slang b/tests/diagnostics/command-line/unknown-output-format.slang index 05f59022b..63f026130 100644 --- a/tests/diagnostics/command-line/unknown-output-format.slang +++ b/tests/diagnostics/command-line/unknown-output-format.slang @@ -1,3 +1,3 @@ // unknown-output-format.slang -//TEST:SIMPLE:-o cookies.jar +//DIAGNOSTIC_TEST:SIMPLE:-o cookies.jar diff --git a/tests/diagnostics/command-line/unknown-pass-through-target.slang b/tests/diagnostics/command-line/unknown-pass-through-target.slang index 7b86f62d6..1e71e93b0 100644 --- a/tests/diagnostics/command-line/unknown-pass-through-target.slang +++ b/tests/diagnostics/command-line/unknown-pass-through-target.slang @@ -1,3 +1,3 @@ // unknown-pass-through-target.slang -//TEST:SIMPLE:-pass-through subcon +//DIAGNOSTIC_TEST:SIMPLE:-pass-through subcon diff --git a/tests/diagnostics/command-line/unknown-profile.slang b/tests/diagnostics/command-line/unknown-profile.slang index f96363058..9b58bc7af 100644 --- a/tests/diagnostics/command-line/unknown-profile.slang +++ b/tests/diagnostics/command-line/unknown-profile.slang @@ -1,3 +1,3 @@ // unknown-profile.slang -//TEST:SIMPLE:-profile thunder_kiss_65 +//DIAGNOSTIC_TEST:SIMPLE:-profile thunder_kiss_65 diff --git a/tests/diagnostics/command-line/unknown-source-language.slang b/tests/diagnostics/command-line/unknown-source-language.slang index c39a3ae4f..3ea80c606 100644 --- a/tests/diagnostics/command-line/unknown-source-language.slang +++ b/tests/diagnostics/command-line/unknown-source-language.slang @@ -2,4 +2,4 @@ // Unknown source file extension (can't deduce language) -//TEST:SIMPLE:batmobile.car +//DIAGNOSTIC_TEST:SIMPLE:batmobile.car diff --git a/tests/diagnostics/command-line/unknown-stage.slang b/tests/diagnostics/command-line/unknown-stage.slang index 1645e5998..5342936d4 100644 --- a/tests/diagnostics/command-line/unknown-stage.slang +++ b/tests/diagnostics/command-line/unknown-stage.slang @@ -1,3 +1,3 @@ // unknown-stage.slang -//TEST:SIMPLE:-stage green_hills_zone +//DIAGNOSTIC_TEST:SIMPLE:-stage green_hills_zone diff --git a/tests/diagnostics/constexpr-error.slang b/tests/diagnostics/constexpr-error.slang index 6006450a1..f0de9280d 100644 --- a/tests/diagnostics/constexpr-error.slang +++ b/tests/diagnostics/constexpr-error.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // Failure to pass compile-time-constant data // where it is expected. diff --git a/tests/diagnostics/continue-outside-loop.slang b/tests/diagnostics/continue-outside-loop.slang index cad9dce6e..ea8f36fea 100644 --- a/tests/diagnostics/continue-outside-loop.slang +++ b/tests/diagnostics/continue-outside-loop.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // `continue` where it isn't allowed void foo() { continue; } diff --git a/tests/diagnostics/entry-point-no-stage.slang b/tests/diagnostics/entry-point-no-stage.slang index 99ff8193c..042298e0f 100644 --- a/tests/diagnostics/entry-point-no-stage.slang +++ b/tests/diagnostics/entry-point-no-stage.slang @@ -4,7 +4,7 @@ // compiling an entry point without any // stage specified. -//TEST:SIMPLE:-entry main +//DIAGNOSTIC_TEST:SIMPLE:-entry main void main() {} diff --git a/tests/diagnostics/entry-point-stage-mismatch.slang b/tests/diagnostics/entry-point-stage-mismatch.slang index 0f143c676..caa8d3e4b 100644 --- a/tests/diagnostics/entry-point-stage-mismatch.slang +++ b/tests/diagnostics/entry-point-stage-mismatch.slang @@ -3,7 +3,7 @@ // Confirm that we diagnose when stage specified via command // line doesn't match what was specified via attribute. -//TEST:SIMPLE:-entry main -stage vertex +//DIAGNOSTIC_TEST:SIMPLE:-entry main -stage vertex [shader("compute")] void main() diff --git a/tests/diagnostics/enum-implicit-conversion.slang b/tests/diagnostics/enum-implicit-conversion.slang index d3f3d1d28..fc4757f7e 100644 --- a/tests/diagnostics/enum-implicit-conversion.slang +++ b/tests/diagnostics/enum-implicit-conversion.slang @@ -1,6 +1,6 @@ // enum-implicit-conversion.slang -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // Confirm that suitable error messages are // generated for code that relies on implicit diff --git a/tests/diagnostics/expected-token-eof.slang b/tests/diagnostics/expected-token-eof.slang index 99ab161ec..45d234339 100644 --- a/tests/diagnostics/expected-token-eof.slang +++ b/tests/diagnostics/expected-token-eof.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // expected one token, but got EOF int foo() diff --git a/tests/diagnostics/expected-token.slang b/tests/diagnostics/expected-token.slang index db85e7b92..8978bc97c 100644 --- a/tests/diagnostics/expected-token.slang +++ b/tests/diagnostics/expected-token.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // expected one token, but got another int foo() diff --git a/tests/diagnostics/gh-38-vs.hlsl b/tests/diagnostics/gh-38-vs.hlsl index 92e0e957e..bb97482c4 100644 --- a/tests/diagnostics/gh-38-vs.hlsl +++ b/tests/diagnostics/gh-38-vs.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE: -profile sm_5_0 -entry main -stage vertex tests/diagnostics/gh-38-fs.hlsl -entry main -stage fragment +//DIAGNOSTIC_TEST:SIMPLE: -profile sm_5_0 -entry main -stage vertex tests/diagnostics/gh-38-fs.hlsl -entry main -stage fragment // Ensure that we catch errors with overlapping or conflicting parameter bindings. diff --git a/tests/diagnostics/global-uniform.slang b/tests/diagnostics/global-uniform.slang index 6d3189cbc..6b17016f2 100644 --- a/tests/diagnostics/global-uniform.slang +++ b/tests/diagnostics/global-uniform.slang @@ -1,6 +1,6 @@ // global-uniform.slang -//TEST:SIMPLE:-target hlsl -//TEST:COMMAND_LINE_SIMPLE:-target hlsl +//DIAGNOSTIC_TEST:SIMPLE:-target hlsl +//DIAGNOSTIC_TEST:COMMAND_LINE_SIMPLE:-target hlsl // Any attempt to declare a global variable that actually declares a // global uniform should be diagnosed as unsupported. diff --git a/tests/diagnostics/illegal-character.slang b/tests/diagnostics/illegal-character.slang index 5915e861f..9831bb93e 100644 --- a/tests/diagnostics/illegal-character.slang +++ b/tests/diagnostics/illegal-character.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // illegal character ` diff --git a/tests/diagnostics/implicit-cast-lvalue.slang b/tests/diagnostics/implicit-cast-lvalue.slang index 4bf3c13b0..79b619443 100644 --- a/tests/diagnostics/implicit-cast-lvalue.slang +++ b/tests/diagnostics/implicit-cast-lvalue.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // Passing an argument for an `out` parameter such // that implicit conversion would be required in diff --git a/tests/diagnostics/local-used-before-declared.slang b/tests/diagnostics/local-used-before-declared.slang index 96d68b9eb..bd17666b6 100644 --- a/tests/diagnostics/local-used-before-declared.slang +++ b/tests/diagnostics/local-used-before-declared.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-target dxbc -profile ps_5_0 -entry main +//DIAGNOSTIC_TEST:SIMPLE:-target dxbc -profile ps_5_0 -entry main // Early versions of the front-end had bugs when local // variables were used before their definition, or diff --git a/tests/diagnostics/local-used-in-own-declaration.slang b/tests/diagnostics/local-used-in-own-declaration.slang index 9802acbb9..d95ef12e0 100644 --- a/tests/diagnostics/local-used-in-own-declaration.slang +++ b/tests/diagnostics/local-used-in-own-declaration.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-target dxbc -profile ps_5_0 +//DIAGNOSTIC_TEST:SIMPLE:-target dxbc -profile ps_5_0 // Early versions of the front-end had bugs when local // variables were used before their definition, or diff --git a/tests/diagnostics/missing-include-file.slang b/tests/diagnostics/missing-include-file.slang index 9e0f99b9c..ee49e2cbe 100644 --- a/tests/diagnostics/missing-include-file.slang +++ b/tests/diagnostics/missing-include-file.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // trying to include a non-existant file #include "does-not-exist.h" diff --git a/tests/diagnostics/missing-return.slang b/tests/diagnostics/missing-return.slang index 83f5f9dc1..988d706d5 100644 --- a/tests/diagnostics/missing-return.slang +++ b/tests/diagnostics/missing-return.slang @@ -1,6 +1,6 @@ // missing-return.slang -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // Non-`void` function that fails to return diff --git a/tests/diagnostics/missing-semicolon-after-semantic.slang b/tests/diagnostics/missing-semicolon-after-semantic.slang index 00fc3aa6c..d2eb12825 100644 --- a/tests/diagnostics/missing-semicolon-after-semantic.slang +++ b/tests/diagnostics/missing-semicolon-after-semantic.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // Forgetting to put in the `;` after declaraing a variable/field // with a semantic used to put the compiler into an infinite loop. diff --git a/tests/diagnostics/packoffset.slang b/tests/diagnostics/packoffset.slang index 31ee63bbd..b5669c410 100644 --- a/tests/diagnostics/packoffset.slang +++ b/tests/diagnostics/packoffset.slang @@ -1,5 +1,5 @@ // packoffset.slang -//TEST:SIMPLE:-target hlsl +//DIAGNOSTIC_TEST:SIMPLE:-target hlsl // use of `packoffset` (not supported): cbuffer B diff --git a/tests/diagnostics/parameter-already-defined.slang b/tests/diagnostics/parameter-already-defined.slang index 860b17e65..312b3d8b0 100644 --- a/tests/diagnostics/parameter-already-defined.slang +++ b/tests/diagnostics/parameter-already-defined.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // re-use parameter name int foo( int a, float a ) { return 0; } diff --git a/tests/diagnostics/recursive-import.slang b/tests/diagnostics/recursive-import.slang index ff74025f8..b74e55be4 100644 --- a/tests/diagnostics/recursive-import.slang +++ b/tests/diagnostics/recursive-import.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // A file that recursively imports itself // (including transitive cases) should be diagnosed. diff --git a/tests/diagnostics/register-bindings.slang b/tests/diagnostics/register-bindings.slang index 188d22bf5..263329bf6 100644 --- a/tests/diagnostics/register-bindings.slang +++ b/tests/diagnostics/register-bindings.slang @@ -1,5 +1,5 @@ // register-bindings.slang -//TEST:SIMPLE:-target hlsl +//DIAGNOSTIC_TEST:SIMPLE:-target hlsl // Various bad forms for register bindings diff --git a/tests/diagnostics/setter-method.slang b/tests/diagnostics/setter-method.slang index 58e7c3417..c1e6019d0 100644 --- a/tests/diagnostics/setter-method.slang +++ b/tests/diagnostics/setter-method.slang @@ -1,6 +1,6 @@ // setter-method.slang -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // Make sure we provide a user a diagnostic if they // try to declare a setter method without `mutating` diff --git a/tests/diagnostics/single-shader-record.slang b/tests/diagnostics/single-shader-record.slang index 4dbf65daa..0c6657f2f 100644 --- a/tests/diagnostics/single-shader-record.slang +++ b/tests/diagnostics/single-shader-record.slang @@ -1,5 +1,5 @@ // single-shader-record.slang -//TEST:SIMPLE: -profile sm_6_3 -stage closesthit -entry main -target spirv-assembly +//DIAGNOSTIC_TEST:SIMPLE: -profile sm_6_3 -stage closesthit -entry main -target spirv-assembly struct ReflectionRay { diff --git a/tests/diagnostics/static-ref-to-nonstatic-member.slang b/tests/diagnostics/static-ref-to-nonstatic-member.slang index 485a0ed67..828cf46b1 100644 --- a/tests/diagnostics/static-ref-to-nonstatic-member.slang +++ b/tests/diagnostics/static-ref-to-nonstatic-member.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: struct Color diff --git a/tests/diagnostics/undefined-identifier.slang b/tests/diagnostics/undefined-identifier.slang index 6c5a59f75..88633bf07 100644 --- a/tests/diagnostics/undefined-identifier.slang +++ b/tests/diagnostics/undefined-identifier.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // use of undefined identifier void foo() diff --git a/tests/diagnostics/undefined-in-preprocessor-conditional.slang b/tests/diagnostics/undefined-in-preprocessor-conditional.slang index d46c68d33..100468703 100644 --- a/tests/diagnostics/undefined-in-preprocessor-conditional.slang +++ b/tests/diagnostics/undefined-in-preprocessor-conditional.slang @@ -1,4 +1,4 @@ -//TEST(smoke):SIMPLE: +//DIAGNOSTIC_TEST(smoke):SIMPLE: // Use an undefined identifier in a preprocessor conditional diff --git a/tests/diagnostics/unreachable-code.slang b/tests/diagnostics/unreachable-code.slang index 493ccc81f..6c54fcec3 100644 --- a/tests/diagnostics/unreachable-code.slang +++ b/tests/diagnostics/unreachable-code.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // "Obviously" unreachable code. diff --git a/tests/diagnostics/variable-void-type.slang b/tests/diagnostics/variable-void-type.slang index 926e6401d..57f16cc22 100644 --- a/tests/diagnostics/variable-void-type.slang +++ b/tests/diagnostics/variable-void-type.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // variable with `void` type void foo() diff --git a/tests/diagnostics/vk-bindings.slang b/tests/diagnostics/vk-bindings.slang index a329fcdde..c0a3ca7f8 100644 --- a/tests/diagnostics/vk-bindings.slang +++ b/tests/diagnostics/vk-bindings.slang @@ -1,6 +1,6 @@ // vk-bindings.slang -//TEST:SIMPLE:-target spirv +//DIAGNOSTIC_TEST:SIMPLE:-target spirv // D3D `register` without VK binding Texture2D t : register(t0); diff --git a/tests/diagnostics/while-predicate-type.slang b/tests/diagnostics/while-predicate-type.slang index 14ce45533..ec1d55b47 100644 --- a/tests/diagnostics/while-predicate-type.slang +++ b/tests/diagnostics/while-predicate-type.slang @@ -1,4 +1,4 @@ -//TEST:SIMPLE: +//DIAGNOSTIC_TEST:SIMPLE: // bad type for `while` predicate struct S {}; diff --git a/tools/render-test/options.cpp b/tools/render-test/options.cpp index 9d5ff35c8..2277a6ad7 100644 --- a/tools/render-test/options.cpp +++ b/tools/render-test/options.cpp @@ -151,6 +151,10 @@ SlangResult parseOptions(int argc, const char*const* argv, Slang::WriterHelper s { gOptions.useDXIL = true; } + else if (strcmp(arg, "-only-startup") == 0) + { + gOptions.onlyStartup = true; + } else if (strcmp(arg, "-adapter") == 0) { if (argCursor == argEnd) diff --git a/tools/render-test/options.h b/tools/render-test/options.h index 104906f42..0214c66e7 100644 --- a/tools/render-test/options.h +++ b/tools/render-test/options.h @@ -55,6 +55,7 @@ struct Options int slangArgCount = 0; bool useDXIL = false; + bool onlyStartup = false; Slang::List<Slang::String> renderFeatures; /// Required render features for this test to run diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp index 2bc6cd8f8..34e041473 100644 --- a/tools/render-test/render-test-main.cpp +++ b/tools/render-test/render-test-main.cpp @@ -555,6 +555,7 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe return SLANG_FAIL; } + StringBuilder rendererName; rendererName << "[" << RendererUtil::toText(gOptions.rendererType) << "] "; if (gOptions.adapter.Length()) @@ -565,7 +566,10 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe if (!renderer) { - fprintf(stderr, "Unable to create renderer %s\n", rendererName.Buffer()); + if (!gOptions.onlyStartup) + { + fprintf(stderr, "Unable to create renderer %s\n", rendererName.Buffer()); + } return SLANG_FAIL; } @@ -578,11 +582,20 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe SlangResult res = renderer->initialize(desc, (HWND)window->getHandle()); if (SLANG_FAILED(res)) { - fprintf(stderr, "Unable to initialize renderer %s\n", rendererName.Buffer()); + if (!gOptions.onlyStartup) + { + fprintf(stderr, "Unable to initialize renderer %s\n", rendererName.Buffer()); + } return res; } } + // If the only test is we can startup, then we are done + if (gOptions.onlyStartup) + { + return SLANG_OK; + } + { for (const auto& feature : gOptions.renderFeatures) { diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp index 9119c3224..e475d4b5a 100644 --- a/tools/slang-test/slang-test-main.cpp +++ b/tools/slang-test/slang-test-main.cpp @@ -21,31 +21,48 @@ using namespace Slang; #define STB_IMAGE_IMPLEMENTATION #include "external/stb/stb_image.h" -#ifdef _WIN32 -#define SLANG_TEST_SUPPORT_HLSL 1 -#include <d3dcompiler.h> -#endif - #include <assert.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> + // Options for a particular test struct TestOptions { + enum Type + { + Normal, ///< A regular test + Diagnostic, ///< Diagnostic tests will always run (as form of failure is being tested) + }; + + Type type = Type::Normal; + String command; List<String> args; // The categories that this test was assigned to List<TestCategory*> categories; + + bool isSynthesized = false; +}; + +struct TestDetails +{ + TestDetails() {} + explicit TestDetails(const TestOptions& inOptions): + options(inOptions) + {} + + TestOptions options; ///< The options for the test + TestRequirements requirements; ///< The requirements for the test to work }; // Information on tests to run for a particular file struct FileTestList { - List<TestOptions> tests; + List<TestDetails> tests; }; enum class SpawnType @@ -68,9 +85,6 @@ struct TestInput // as command line args) TestOptions const* testOptions; - // The list of tests that will be run on this file - FileTestList const* testList; - // Determines how the test will be spawned SpawnType spawnType; }; @@ -79,6 +93,9 @@ typedef TestResult(*TestCallback)(TestContext* context, TestInput& input); // Globals +// Pre declare +static void _addRenderTestOptions(const Options& options, OSProcessSpawner& spawner); + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! Functions !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ bool match(char const** ioCursor, char const* expected) @@ -165,16 +182,13 @@ String collectRestOfLine(char const** ioCursor) } - -TestResult gatherTestOptions( +static TestResult _gatherTestOptions( TestCategorySet* categorySet, char const** ioCursor, - FileTestList* testList) + TestOptions& outOptions) { char const* cursor = *ioCursor; - TestOptions testOptions; - // Right after the `TEST` keyword, the user may specify // one or more categories for the test. if(*cursor == '(') @@ -206,7 +220,7 @@ TestResult gatherTestOptions( } - testOptions.categories.Add(category); + outOptions.categories.Add(category); if( *categoryEnd == ',' ) { @@ -226,9 +240,9 @@ TestResult gatherTestOptions( } // If no categories were specified, then add the default category - if(testOptions.categories.Count() == 0) + if(outOptions.categories.Count() == 0) { - testOptions.categories.Add(categorySet->defaultCategory); + outOptions.categories.Add(categorySet->defaultCategory); } if(*cursor == ':') @@ -259,7 +273,7 @@ TestResult gatherTestOptions( } char const* commandEnd = cursor; - testOptions.command = getString(commandStart, commandEnd); + outOptions.command = getString(commandStart, commandEnd); if(*cursor == ':') cursor++; @@ -280,7 +294,6 @@ TestResult gatherTestOptions( { case 0: case '\r': case '\n': skipToEndOfLine(&cursor); - testList->tests.Add(testOptions); return TestResult::Pass; default: @@ -306,7 +319,7 @@ TestResult gatherTestOptions( char const* argEnd = cursor; assert(argBegin != argEnd); - testOptions.args.Add(getString(argBegin, argEnd)); + outOptions.args.Add(getString(argBegin, argEnd)); } } @@ -343,8 +356,23 @@ TestResult gatherTestsForFile( } else if(match(&cursor, "//TEST")) { - if(gatherTestOptions(categorySet, &cursor, testList) != TestResult::Pass) + TestDetails testDetails; + + if(_gatherTestOptions(categorySet, &cursor, testDetails.options) != TestResult::Pass) + return TestResult::Fail; + + testList->tests.Add(testDetails); + } + else if (match(&cursor, "//DIAGNOSTIC_TEST")) + { + TestDetails testDetails; + + if (_gatherTestOptions(categorySet, &cursor, testDetails.options) != TestResult::Pass) return TestResult::Fail; + + // Mark that it is a diagnostic test + testDetails.options.type = TestOptions::Type::Diagnostic; + testList->tests.Add(testDetails); } else { @@ -445,6 +473,324 @@ OSError spawnAndWaitSharedLibrary(TestContext* context, const String& testPath, return kOSError_OperationFailed; } + +static SlangResult _extractArg(const List<String>& args, const String& argName, String& outValue) +{ + SLANG_ASSERT(argName.Length() > 0 && argName[0] == '-'); + + const UInt count = args.Count(); + for (UInt i = 0; i < count - 1; ++i) + { + if (args[i] == argName) + { + outValue = args[i + 1]; + return SLANG_OK; + } + } + return SLANG_FAIL; +} + +static bool _hasOption(const List<String>& args, const String& argName) +{ + return args.IndexOf(argName) != UInt(-1); +} + +static BackendType _toBackendType(const UnownedStringSlice& slice) +{ + if (slice == "dxc") + { + return BackendType::Dxc; + } + else if (slice == "fxc") + { + return BackendType::Fxc; + } + else if (slice == "glslang") + { + return BackendType::Glslang; + } + return BackendType::Unknown; +} + +static BackendFlags _getBackendFlagsForTarget(SlangCompileTarget target) +{ + switch (target) + { + case SLANG_TARGET_UNKNOWN: + case SLANG_HLSL: + case SLANG_GLSL: + { + return 0; + } + case SLANG_DXBC: + case SLANG_DXBC_ASM: + { + return BackendFlag::Fxc; + } + case SLANG_SPIRV: + case SLANG_SPIRV_ASM: + { + return BackendFlag::Glslang; + } + case SLANG_DXIL: + case SLANG_DXIL_ASM: + { + return BackendFlag::Dxc; + } + default: + { + SLANG_ASSERT(!"Unknown type"); + return 0; + } + } +} + +static BackendType _toBackendTypeFromPassThroughType(SlangPassThrough passThru) +{ + switch (passThru) + { + case SLANG_PASS_THROUGH_DXC: return BackendType::Dxc; + case SLANG_PASS_THROUGH_FXC: return BackendType::Fxc; + case SLANG_PASS_THROUGH_GLSLANG: return BackendType::Glslang; + default: return BackendType::Unknown; + } +} + +static SlangCompileTarget _getCompileTarget(const UnownedStringSlice& name) +{ +#define CASE(NAME, TARGET) if(name == NAME) return SLANG_##TARGET; + + CASE("hlsl", HLSL) + CASE("glsl", GLSL) + CASE("dxbc", DXBC) + CASE("dxbc-assembly", DXBC_ASM) + CASE("dxbc-asm", DXBC_ASM) + CASE("spirv", SPIRV) + CASE("spirv-assembly", SPIRV_ASM) + CASE("spirv-asm", SPIRV_ASM) + CASE("dxil", DXIL) + CASE("dxil-assembly", DXIL_ASM) + CASE("dxil-asm", DXIL_ASM) +#undef CASE + + return SLANG_TARGET_UNKNOWN; +} + +static SlangResult _extractRenderTestRequirements(OSProcessSpawner& spawner, TestRequirements* ioRequirements) +{ + const auto& args = spawner.argumentList_; + + // TODO(JS): + // This is rather convoluted in that it has to work out from the command line parameters passed + // to render-test what renderer will be used. + // That a similar logic has to be kept inside the implementation of render-test and both this + // and render-test will have to be kept in sync. + + bool useDxil = _hasOption(args, "-use-dxil"); + + bool usePassthru = false; + + // Work out what kind of render will be used + RenderApiType renderApiType; + { + RenderApiType foundRenderApiType = RenderApiType::Unknown; + RenderApiType foundLanguageRenderType = RenderApiType::Unknown; + + for (const auto& arg: args) + { + Slang::UnownedStringSlice argSlice = arg.getUnownedSlice(); + if (argSlice.size() && argSlice[0] == '-') + { + // Look up the rendering API if set + UnownedStringSlice argName = UnownedStringSlice(argSlice.begin() + 1, argSlice.end()); + RenderApiType renderApiType = RenderApiUtil::findApiTypeByName(argName); + + if (renderApiType != RenderApiType::Unknown) + { + foundRenderApiType = renderApiType; + + // There should be only one explicit api + SLANG_ASSERT(ioRequirements->explicitRenderApi == RenderApiType::Unknown || ioRequirements->explicitRenderApi == renderApiType); + + // Set the explicitly set render api + ioRequirements->explicitRenderApi = renderApiType; + continue; + } + + // Lookup the target language type + RenderApiType languageRenderType = RenderApiUtil::findImplicitLanguageRenderApiType(argName); + if (languageRenderType != RenderApiType::Unknown) + { + foundLanguageRenderType = languageRenderType; + + // Use the pass thru compiler if these are the sources + usePassthru |= (argName == "hlsl" || argName == "glsl"); + + continue; + } + } + } + + // If a render option isn't set use defaultRenderType + renderApiType = (foundRenderApiType == RenderApiType::Unknown) ? foundLanguageRenderType : foundRenderApiType; + } + + // The native language for the API + SlangSourceLanguage nativeLanguage = SLANG_SOURCE_LANGUAGE_UNKNOWN; + SlangCompileTarget target = SLANG_TARGET_NONE; + SlangPassThrough passThru = SLANG_PASS_THROUGH_NONE; + + switch (renderApiType) + { + case RenderApiType::D3D11: + target = SLANG_DXBC; + nativeLanguage = SLANG_SOURCE_LANGUAGE_HLSL; + passThru = SLANG_PASS_THROUGH_FXC; + break; + case RenderApiType::D3D12: + target = SLANG_DXBC; + nativeLanguage = SLANG_SOURCE_LANGUAGE_HLSL; + passThru = SLANG_PASS_THROUGH_FXC; + if (useDxil) + { + target = SLANG_DXIL; + passThru = SLANG_PASS_THROUGH_DXC; + } + break; + + case RenderApiType::OpenGl: + target = SLANG_GLSL; + nativeLanguage = SLANG_SOURCE_LANGUAGE_GLSL; + passThru = SLANG_PASS_THROUGH_GLSLANG; + break; + case RenderApiType::Vulkan: + target = SLANG_SPIRV; + nativeLanguage = SLANG_SOURCE_LANGUAGE_GLSL; + passThru = SLANG_PASS_THROUGH_GLSLANG; + break; + } + + SlangSourceLanguage sourceLanguage = nativeLanguage; + if (!usePassthru) + { + sourceLanguage = SLANG_SOURCE_LANGUAGE_SLANG; + passThru = SLANG_PASS_THROUGH_NONE; + } + + if (passThru == SLANG_PASS_THROUGH_NONE) + { + // Work out backends needed based on the target + ioRequirements->addUsedBackends(_getBackendFlagsForTarget(target)); + } + else + { + ioRequirements->addUsed(_toBackendTypeFromPassThroughType(passThru)); + } + + // Add the render api used + ioRequirements->addUsed(renderApiType); + + return SLANG_OK; +} + +static SlangResult _extractSlangCTestRequirements(OSProcessSpawner& spawner, TestRequirements* ioRequirements) +{ + // This determines what the requirements are for a slangc like command line + const auto& args = spawner.argumentList_; + + // First check pass through + { + String passThrough; + if (SLANG_SUCCEEDED(_extractArg(args, "-pass-through", passThrough))) + { + ioRequirements->addUsed(_toBackendType(passThrough.getUnownedSlice())); + } + } + + // The target if set will also imply a backend + { + String targetName; + if (SLANG_SUCCEEDED(_extractArg(args, "-target", targetName))) + { + const SlangCompileTarget target = _getCompileTarget(targetName.getUnownedSlice()); + ioRequirements->addUsedBackends(_getBackendFlagsForTarget(target)); + } + } + return SLANG_OK; + +} + +static SlangResult _extractReflectionTestRequirements(OSProcessSpawner& spawner, TestRequirements* ioRequirements) +{ + // There are no specialized constraints for a reflection test + return SLANG_OK; +} + +static SlangResult _extractTestRequirements(OSProcessSpawner& spawner, TestRequirements* ioInfo) +{ + String exeName = Path::GetFileNameWithoutEXT(spawner.executableName_); + + if (exeName == "render-test") + { + return _extractRenderTestRequirements(spawner, ioInfo); + } + else if (exeName == "slangc") + { + return _extractSlangCTestRequirements(spawner, ioInfo); + } + else if (exeName == "slang-reflection-test") + { + return _extractReflectionTestRequirements(spawner, ioInfo); + } + + SLANG_ASSERT(!"Unknown tool type"); + return SLANG_FAIL; +} + +static RenderApiFlags _getAvailableRenderApiFlags(TestContext* context) +{ + // Only evaluate if it hasn't already been evaluated (the actual evaluation is slow...) + if (!context->isAvailableRenderApiFlagsValid) + { + // Call the render-test tool asking it only to startup a specified render api + // (taking into account adapter options) + + RenderApiFlags availableRenderApiFlags = 0; + for (int i = 0; i < int(RenderApiType::CountOf); ++i) + { + const RenderApiType apiType = RenderApiType(i); + + // See if it's possible the api is available + if (RenderApiUtil::calcHasApi(apiType)) + { + // Try starting up the device + OSProcessSpawner spawner; + spawner.pushExecutablePath(String(context->options.binDir) + "render-test" + osGetExecutableSuffix()); + _addRenderTestOptions(context->options, spawner); + // We just want to see if the device can be started up + spawner.pushArgument("-only-startup"); + + // Select what api to use + StringBuilder builder; + builder << "-" << RenderApiUtil::getApiName(apiType); + spawner.pushArgument(builder); + + // Run the render-test tool and see if the device could startup + if (spawnAndWaitSharedLibrary(context, "device-startup", spawner) == OSError::kOSError_None + && TestToolUtil::getReturnCodeFromInt(spawner.resultCode_) == ToolReturnCode::Success) + { + availableRenderApiFlags |= RenderApiFlags(1) << int(apiType); + } + } + } + + context->availableRenderApiFlags = availableRenderApiFlags; + context->isAvailableRenderApiFlagsValid = true; + } + + return context->availableRenderApiFlags; +} + ToolReturnCode getReturnCode(OSProcessSpawner& spawner) { return TestToolUtil::getReturnCodeFromInt(spawner.getResultCode()); @@ -452,6 +798,17 @@ ToolReturnCode getReturnCode(OSProcessSpawner& spawner) ToolReturnCode spawnAndWait(TestContext* context, const String& testPath, SpawnType spawnType, OSProcessSpawner& spawner) { + if (context->isCollectingRequirements()) + { + // If we just want info... don't bother running anything + const SlangResult res = _extractTestRequirements(spawner, context->testRequirements); + // Keep compiler happy on release + SLANG_UNUSED(res); + SLANG_ASSERT(SLANG_SUCCEEDED(res)); + + return ToolReturnCode::Success; + } + const auto& options = context->options; OSError spawnResult = kOSError_OperationFailed; @@ -581,9 +938,14 @@ TestResult runSimpleTest(TestContext* context, TestInput& input) { spawner.pushArgument(arg); } - + TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, spawner)); + if (context->isCollectingRequirements()) + { + return TestResult::Pass; + } + String actualOutput = getOutput(spawner); String expectedOutputPath = outputStem + ".expected"; @@ -655,6 +1017,11 @@ TestResult runReflectionTest(TestContext* context, TestInput& input) TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, spawner)); + if (context->isCollectingRequirements()) + { + return TestResult::Pass; + } + String actualOutput = getOutput(spawner); String expectedOutputPath = outputStem + ".expected"; @@ -718,28 +1085,6 @@ String getExpectedOutput(String const& outputStem) return expectedOutput; } -static SlangCompileTarget _getCompileTarget(const UnownedStringSlice& name) -{ -#define CASE(NAME, TARGET) if(name == NAME) return SLANG_##TARGET; - - CASE("hlsl", HLSL) - CASE("glsl", GLSL) - CASE("dxbc", DXBC) - CASE("dxbc-assembly", DXBC_ASM) - CASE("dxbc-asm", DXBC_ASM) - CASE("spirv", SPIRV) - CASE("spirv-assembly", SPIRV_ASM) - CASE("spirv-asm", SPIRV_ASM) - CASE("dxil", DXIL) - CASE("dxil-assembly", DXIL_ASM) - CASE("dxil-asm", DXIL_ASM) -#undef CASE - - return SLANG_TARGET_UNKNOWN; -} - - - TestResult runCrossCompilerTest(TestContext* context, TestInput& input) { // need to execute the stand-alone Slang compiler on the file @@ -755,7 +1100,9 @@ TestResult runCrossCompilerTest(TestContext* context, TestInput& input) _initSlangCompiler(context, expectedSpawner); actualSpawner.pushArgument(filePath); - + + // TODO(JS): This should no longer be needed with TestInfo accumulated for a test + const auto& args = input.testOptions->args; const UInt targetIndex = args.IndexOf("-target"); @@ -802,20 +1149,29 @@ TestResult runCrossCompilerTest(TestContext* context, TestInput& input) } TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, expectedSpawner)); - - String expectedOutput = getOutput(expectedSpawner); - String expectedOutputPath = outputStem + ".expected"; - try - { - Slang::File::WriteAllText(expectedOutputPath, expectedOutput); - } - catch (Slang::IOException) + + String expectedOutput; + if (context->isExecuting()) { - return TestResult::Fail; + expectedOutput = getOutput(expectedSpawner); + String expectedOutputPath = outputStem + ".expected"; + try + { + Slang::File::WriteAllText(expectedOutputPath, expectedOutput); + } + catch (Slang::IOException) + { + return TestResult::Fail; + } } TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, actualSpawner)); + if (context->isCollectingRequirements()) + { + return TestResult::Pass; + } + String actualOutput = getOutput(actualSpawner); TestResult result = TestResult::Pass; @@ -849,8 +1205,6 @@ TestResult runCrossCompilerTest(TestContext* context, TestInput& input) return result; } - -#ifdef SLANG_TEST_SUPPORT_HLSL TestResult generateHLSLBaseline(TestContext* context, TestInput& input) { auto filePath999 = input.filePath; @@ -873,6 +1227,11 @@ TestResult generateHLSLBaseline(TestContext* context, TestInput& input) TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, spawner)); + if (context->isCollectingRequirements()) + { + return TestResult::Pass; + } + String expectedOutput = getOutput(spawner); String expectedOutputPath = outputStem + ".expected"; try @@ -918,6 +1277,11 @@ TestResult runHLSLComparisonTest(TestContext* context, TestInput& input) TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, spawner)); + if (context->isCollectingRequirements()) + { + return TestResult::Pass; + } + // We ignore output to stdout, and only worry about what the compiler // wrote to stderr. @@ -985,7 +1349,6 @@ TestResult runHLSLComparisonTest(TestContext* context, TestInput& input) return result; } -#endif TestResult doGLSLComparisonTestRun(TestContext* context, TestInput& input, @@ -1024,6 +1387,11 @@ TestResult doGLSLComparisonTestRun(TestContext* context, TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, spawner)); + if (context->isCollectingRequirements()) + { + return TestResult::Pass; + } + OSProcessSpawner::ResultCode resultCode = spawner.getResultCode(); String standardOuptut = spawner.getStandardOutput(); @@ -1058,6 +1426,11 @@ TestResult runGLSLComparisonTest(TestContext* context, TestInput& input) TestResult hlslResult = doGLSLComparisonTestRun(context, input, "__GLSL__", "glslang", ".expected", &expectedOutput); TestResult slangResult = doGLSLComparisonTestRun(context, input, "__SLANG__", nullptr, ".actual", &actualOutput); + if (context->isCollectingRequirements()) + { + return TestResult::Pass; + } + // If either is ignored, the whole test is if (hlslResult == TestResult::Ignored || slangResult == TestResult::Ignored) @@ -1096,12 +1469,6 @@ TestResult runComputeComparisonImpl(TestContext* context, TestInput& input, cons auto filePath999 = input.filePath; auto outputStem = input.outputStem; - const String referenceOutput = findExpectedPath(input, ".expected.txt"); - if (referenceOutput.Length() <= 0) - { - return TestResult::Fail; - } - OSProcessSpawner spawner; spawner.pushExecutablePath(String(context->options.binDir) + "render-test" + osGetExecutableSuffix()); @@ -1122,11 +1489,25 @@ TestResult runComputeComparisonImpl(TestContext* context, TestInput& input, cons auto actualOutputFile = outputStem + ".actual.txt"; spawner.pushArgument(actualOutputFile); - // clear the stale actual output file first. This will allow us to detect error if render-test fails and outputs nothing. - File::WriteAllText(actualOutputFile, ""); + if (context->isExecuting()) + { + // clear the stale actual output file first. This will allow us to detect error if render-test fails and outputs nothing. + File::WriteAllText(actualOutputFile, ""); + } TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, spawner)); + if (context->isCollectingRequirements()) + { + return TestResult::Pass; + } + + const String referenceOutput = findExpectedPath(input, ".expected.txt"); + if (referenceOutput.Length() <= 0) + { + return TestResult::Fail; + } + auto actualOutput = getOutput(spawner); auto expectedOutput = getExpectedOutput(outputStem); if (actualOutput != expectedOutput) @@ -1224,6 +1605,11 @@ TestResult doRenderComparisonTestRun(TestContext* context, TestInput& input, cha TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, spawner)); + if (context->isCollectingRequirements()) + { + return TestResult::Pass; + } + OSProcessSpawner::ResultCode resultCode = spawner.getResultCode(); String standardOutput = spawner.getStandardOutput(); @@ -1429,6 +1815,11 @@ TestResult runHLSLRenderComparisonTestImpl( return slangResult; } + if (context->isCollectingRequirements()) + { + return TestResult::Pass; + } + Slang::File::WriteAllText(outputStem + ".expected", expectedOutput); Slang::File::WriteAllText(outputStem + ".actual", actualOutput); @@ -1471,168 +1862,61 @@ TestResult skipTest(TestContext* /* context */, TestInput& /*input*/) return TestResult::Ignored; } -static bool hasRenderOption(RenderApiType apiType, const List<String>& options) +// based on command name, dispatch to an appropriate callback +struct TestCommandInfo { - SLANG_ASSERT(apiType != RenderApiType::Unknown); - if (apiType == RenderApiType::Unknown) - { - return false; - } - - const RenderApiUtil::Info& info = RenderApiUtil::getInfo(apiType); - - List<UnownedStringSlice> namesList; - - for (UInt i = 0; i < options.Count(); ++i) - { - const String& option = options[i]; - - if (option.StartsWith("-")) - { - const UnownedStringSlice parameter(option.Buffer() + 1, option.Buffer() + option.Length()); - const RenderApiType paramType = RenderApiUtil::findApiTypeByName(parameter); - - // Found it - if (apiType == paramType) - { - return true; - } - } - } - - return false; -} - -bool hasRenderOption(RenderApiType apiType, const TestOptions& options) -{ - return hasRenderOption(apiType, options.args); -} - -bool hasRenderOption(RenderApiType apiType, const FileTestList& testList) -{ - const int numTests = int(testList.tests.Count()); - for (int i = 0; i < numTests; i++) - { - if (hasRenderOption(apiType, testList.tests[i].args)) - { - return true; - } - } - return false; -} - -bool isHLSLTest(const String& command) -{ - return command == "COMPARE_HLSL" || - command == "COMPARE_HLSL_RENDER" || - command == "COMPARE_HLSL_CROSS_COMPILE_RENDER" || - command == "COMPARE_HLSL_GLSL_RENDER"; -} - -bool isRenderTest(const String& command) -{ - return command == "COMPARE_COMPUTE" || - command == "COMPARE_COMPUTE_EX" || - command == "HLSL_COMPUTE" || - command == "COMPARE_RENDER_COMPUTE" || - command == "COMPARE_HLSL_RENDER" || - command == "COMPARE_HLSL_CROSS_COMPILE_RENDER" || - command == "COMPARE_HLSL_GLSL_RENDER"; -} - -static bool canIgnoreTestWithDisabledRenderer(const TestOptions& testOptions, const Options& appOptions) -{ - for (int i = 0; i < int(RenderApiType::CountOf); ++i) - { - RenderApiType apiType = RenderApiType(i); - RenderApiFlag::Enum apiFlag = RenderApiFlag::Enum(1 << i); - - if (hasRenderOption(apiType, testOptions) && (appOptions.enabledApis & apiFlag) == 0) - { - return true; - } - } + char const* name; + TestCallback callback; +}; - return false; -} +static const TestCommandInfo s_testCommandInfos[] = +{ + { "SIMPLE", &runSimpleTest}, + { "REFLECTION", &runReflectionTest}, + { "COMMAND_LINE_SIMPLE", &runSimpleCompareCommandLineTest}, + { "COMPARE_HLSL", &runHLSLComparisonTest}, + { "COMPARE_HLSL_RENDER", &runHLSLRenderComparisonTest}, + { "COMPARE_HLSL_CROSS_COMPILE_RENDER", &runHLSLCrossCompileRenderComparisonTest}, + { "COMPARE_HLSL_GLSL_RENDER", &runHLSLAndGLSLRenderComparisonTest}, + { "COMPARE_COMPUTE", &runSlangComputeComparisonTest}, + { "COMPARE_COMPUTE_EX", &runSlangComputeComparisonTestEx}, + { "HLSL_COMPUTE", &runHLSLComputeTest}, + { "COMPARE_RENDER_COMPUTE", &runSlangRenderComputeComparisonTest}, + { "COMPARE_GLSL", &runGLSLComparisonTest}, + { "CROSS_COMPILE", &runCrossCompilerTest}, +}; TestResult runTest( TestContext* context, String const& filePath, String const& outputStem, - TestOptions const& testOptions, - FileTestList const& testList) + String const& testName, + TestOptions const& testOptions) { - // If this test can be ignored - if (canIgnoreTestWithDisabledRenderer(testOptions, context->options)) + // If we are collecting requirements and it's diagnostic test, we always run + // (ie no requirements need to be captured - effectively it has 'no requirements') + if (context->isCollectingRequirements() && testOptions.type == TestOptions::Diagnostic) { - return TestResult::Ignored; + return TestResult::Pass; } - - // based on command name, dispatch to an appropriate callback - struct TestCommands - { - char const* name; - TestCallback callback; - }; - - static const TestCommands kTestCommands[] = - { - { "SIMPLE", &runSimpleTest}, - { "REFLECTION", &runReflectionTest}, - { "COMMAND_LINE_SIMPLE", &runSimpleCompareCommandLineTest}, -#if SLANG_TEST_SUPPORT_HLSL - { "COMPARE_HLSL", &runHLSLComparisonTest}, - { "COMPARE_HLSL_RENDER", &runHLSLRenderComparisonTest}, - { "COMPARE_HLSL_CROSS_COMPILE_RENDER", &runHLSLCrossCompileRenderComparisonTest}, - { "COMPARE_HLSL_GLSL_RENDER", &runHLSLAndGLSLRenderComparisonTest }, - { "COMPARE_COMPUTE", runSlangComputeComparisonTest}, - { "COMPARE_COMPUTE_EX", runSlangComputeComparisonTestEx}, - { "HLSL_COMPUTE", runHLSLComputeTest}, - { "COMPARE_RENDER_COMPUTE", &runSlangRenderComputeComparisonTest }, - -#else - { "COMPARE_HLSL", &skipTest }, - { "COMPARE_HLSL_RENDER", &skipTest }, - { "COMPARE_HLSL_CROSS_COMPILE_RENDER", &skipTest}, - { "COMPARE_HLSL_GLSL_RENDER", &skipTest }, - { "COMPARE_COMPUTE", &skipTest}, - { "COMPARE_COMPUTE_EX", &skipTest}, - { "HLSL_COMPUTE", &skipTest}, - { "COMPARE_RENDER_COMPUTE", &skipTest }, -#endif - { "COMPARE_GLSL", &runGLSLComparisonTest }, - { "CROSS_COMPILE", &runCrossCompilerTest }, - { nullptr, nullptr }, - }; const SpawnType defaultSpawnType = context->options.useExes ? SpawnType::UseExe : SpawnType::UseSharedLibrary; - for( auto ii = kTestCommands; ii->name; ++ii ) + for( const auto& command : s_testCommandInfos) { - if(testOptions.command != ii->name) + if(testOptions.command != command.name) continue; TestInput testInput; testInput.filePath = filePath; testInput.outputStem = outputStem; testInput.testOptions = &testOptions; - testInput.testList = &testList; testInput.spawnType = defaultSpawnType; - { - TestReporter* reporter = context->reporter; - TestReporter::TestScope scope(reporter, outputStem); - - TestResult testResult = ii->callback(context, testInput); - reporter->addResult(testResult); - - return testResult; - } + return command.callback(context, testInput); } // No actual test runner found! - return TestResult::Fail; } @@ -1674,7 +1958,7 @@ bool testPassesCategoryMask( return false; } - // Otherwise inclue any test the user asked for + // Otherwise include any test the user asked for for( auto testCategory : test.categories ) { if(testCategoryMatches(testCategory, context->options.includeCategories)) @@ -1685,74 +1969,79 @@ bool testPassesCategoryMask( return false; } -static RenderApiType _findRenderApi(const List<String>& args, bool onlyExplicit) +static void _calcSynthesizedTests(TestContext* context, RenderApiType synthRenderApiType, const List<TestDetails>& srcTests, List<TestDetails>& ioSynthTests) { - RenderApiType targetLanguageRenderer = RenderApiType::Unknown; - - for (const auto& arg: args) + // Add the explicit parameter + for (const auto& testDetails: srcTests) { - const UnownedStringSlice argSlice = arg.getUnownedSlice(); - if (argSlice.size() && argSlice[0] == '-' && !argSlice.startsWith(UnownedStringSlice::fromLiteral("--"))) - { - UnownedStringSlice argName(argSlice.begin() + 1, argSlice.end()); + const auto& requirements = testDetails.requirements; - RenderApiType renderType = RenderApiUtil::findRenderApiType(argName); - if (renderType != RenderApiType::Unknown) - { - return renderType; - } + // Render tests use renderApis... + // If it's an explicit test, we don't synth from it now - if (!onlyExplicit) - { - RenderApiType implicitRenderType = RenderApiUtil::findImplicitLanguageRenderApiType(argName); - if (implicitRenderType != RenderApiType::Unknown) - { - targetLanguageRenderer = implicitRenderType; - } - } + // TODO(JS): Arguably we should synthesize from explicit tests. In principal we can remove the explicit api apply another + // although that may not always work. + if (requirements.usedRenderApiFlags == 0 || + requirements.explicitRenderApi != RenderApiType::Unknown) + { + continue; } - } - - return targetLanguageRenderer; -} -static void _addSynthesizedTest(RenderApiType rendererType, const List<TestOptions>& renderTests, List<TestOptions>& outSynthesizedTests) -{ - for (const auto& test : renderTests) - { - // If doesn't have an explicit render api, add one and add to the synthesized tests - RenderApiType explicitRenderer = _findRenderApi(test.args, true); - - if (explicitRenderer == RenderApiType::Unknown) - { - // Add the explicit parameter + TestDetails synthTestDetails(testDetails.options); + TestOptions& synthOptions = synthTestDetails.options; - TestOptions options(test); + // Mark as synthesized + synthOptions.isSynthesized = true; - StringBuilder builder; - builder << "-"; - builder << RenderApiUtil::getApiName(rendererType); + StringBuilder builder; + builder << "-"; + builder << RenderApiUtil::getApiName(synthRenderApiType); - options.args.Add(builder); + synthOptions.args.Add(builder); - // If the target is vulkan remove the -hlsl option - if (rendererType == RenderApiType::Vulkan) + // If the target is vulkan remove the -hlsl option + if (synthRenderApiType == RenderApiType::Vulkan) + { + UInt index = synthOptions.args.IndexOf("-hlsl"); + if (index != UInt(-1)) { - UInt index = options.args.IndexOf("-hlsl"); - if (index != UInt(-1)) - { - options.args.RemoveAt(index); - } + synthOptions.args.RemoveAt(index); } + } - // Add to the tests - outSynthesizedTests.Add(options); + // Work out the info about this tests + context->testRequirements = &synthTestDetails.requirements; + runTest(context, "", "", "", synthOptions); + context->testRequirements = nullptr; - return; - } + // It does set the explicit render target + SLANG_ASSERT(synthTestDetails.requirements.explicitRenderApi == synthRenderApiType); + // Add to the tests + ioSynthTests.Add(synthTestDetails); } } +static bool _canIgnore(TestContext* context, + const TestRequirements& requirements) +{ + // Work out what render api flags are available + const RenderApiFlags availableRenderApiFlags = requirements.usedRenderApiFlags ? _getAvailableRenderApiFlags(context) : 0; + + // Are all the required backends available? + if (((requirements.usedBackendFlags & context->availableBackendFlags) != requirements.usedBackendFlags)) + { + return true; + } + + // Are all the required rendering apis available? + if ((requirements.usedRenderApiFlags & availableRenderApiFlags) != requirements.usedRenderApiFlags) + { + return true; + } + + return false; +} + void runTestsOnFile( TestContext* context, String filePath) @@ -1773,73 +2062,132 @@ void runTestsOnFile( return; } - // If synthesized tests are wanted look into adding them - if (context->options.synthesizedTestApis) + RenderApiFlags apiUsedFlags = 0; + RenderApiFlags explictUsedApiFlags = 0; + { - List<TestOptions> synthesizedTests; + // We can get the test info for each of them + for (auto& testDetails : testList.tests) + { + auto& requirements = testDetails.requirements; - // Lets find all tests which are render tests - RenderApiFlags apisUsed = 0; - List<TestOptions> renderTests; + // Collect what the test needs (by setting restRequirements the test isn't actually run) + context->testRequirements = &requirements; + runTest(context, filePath, filePath, filePath, testDetails.options); - const int numTests = int(testList.tests.Count()); - for (int i = 0; i < numTests; i++) - { - const TestOptions& testOptions = testList.tests[i]; - if (isRenderTest(testOptions.command)) - { - RenderApiType renderType = _findRenderApi(testOptions.args, false); - if (renderType != RenderApiType::Unknown) - { - apisUsed |= (1 << int(renderType)); - } - renderTests.Add(testOptions); - } + // + apiUsedFlags |= requirements.usedRenderApiFlags; + explictUsedApiFlags |= (requirements.explicitRenderApi != RenderApiType::Unknown) ? (RenderApiFlags(1) << int(requirements.explicitRenderApi)) : 0; } + context->testRequirements = nullptr; + } + + SLANG_ASSERT((apiUsedFlags & explictUsedApiFlags) == explictUsedApiFlags); + + const RenderApiFlags availableRenderApiFlags = apiUsedFlags ? _getAvailableRenderApiFlags(context) : 0; + + // If synthesized tests are wanted look into adding them + if (context->options.synthesizedTestApis && availableRenderApiFlags) + { + List<TestDetails> synthesizedTests; + // What render options do we want to synthesize - RenderApiFlags missingApis = (~apisUsed) & context->options.synthesizedTestApis; - - // We can only synthesize if if there isn't an explicit render option + RenderApiFlags missingApis = (~apiUsedFlags) & (context->options.synthesizedTestApis & availableRenderApiFlags); + + const UInt numInitialTests = testList.tests.Count(); while (missingApis) { const int index = ByteEncodeUtil::calcMsb8(missingApis); SLANG_ASSERT(index >= 0 && index <= int(RenderApiType::CountOf)); - _addSynthesizedTest(RenderApiType(index), renderTests, synthesizedTests); + const RenderApiType synthRenderApiType = RenderApiType(index); + _calcSynthesizedTests(context, synthRenderApiType, testList.tests, synthesizedTests); + // Disable the bit missingApis &= ~(RenderApiFlags(1) << index); } - // Add any tests that were synthesized - for (UInt i = 0; i < synthesizedTests.Count(); ++i) - { - testList.tests.Add(synthesizedTests[i]); - } + // Add all the synthesized tests + testList.tests.AddRange(synthesizedTests); } // We have found a test to run! int subTestCount = 0; - for( auto& tt : testList.tests ) + for( auto& testDetails : testList.tests ) { int subTestIndex = subTestCount++; // Check that the test passes our current category mask - if(!testPassesCategoryMask(context, tt)) + if(!testPassesCategoryMask(context, testDetails.options)) { continue; } - String outputStem = filePath; - if(subTestIndex != 0) + // Work out the test stem + + StringBuilder outputStem; + outputStem << filePath; + if (subTestIndex != 0) + { + outputStem << "." << subTestIndex; + } + + // Work out the test name - taking into account render api / if synthesized + StringBuilder testName(outputStem); + + if (testDetails.options.isSynthesized) { - outputStem = outputStem + "." + String(subTestIndex); + testName << " syn"; } - /* TestResult result = */ runTest(context, filePath, outputStem, tt, testList); + const auto& requirements = testDetails.requirements; - // Could determine if to continue or not here... based on result + // Display list of used apis on render test + if (requirements.usedRenderApiFlags) + { + RenderApiFlags usedFlags = requirements.usedRenderApiFlags; + testName << " ("; + bool isPrev = false; + while (usedFlags) + { + const int index = ByteEncodeUtil::calcMsb8(usedFlags); + const RenderApiType renderApiType = RenderApiType(index); + if (isPrev) + { + testName << ","; + } + testName << RenderApiUtil::getApiName(renderApiType); + + // Disable bit + usedFlags &= ~(RenderApiFlags(1) << index); + isPrev = true; + } + testName << ")"; + } + + // Report the test and run/ignore + { + auto reporter = context->reporter; + TestReporter::TestScope scope(reporter, testName); + + TestResult testResult = TestResult::Fail; + + // If this test can be ignored + if (_canIgnore(context, testDetails.requirements)) + { + testResult = TestResult::Ignored; + } + else + { + testResult = runTest(context, filePath, outputStem, testName, testDetails.options); + } + + reporter->addResult(testResult); + + // Could determine if to continue or not here... based on result + } } } @@ -1911,6 +2259,7 @@ void runTestsInDirectory( } } + SlangResult innerMain(int argc, char** argv) { auto stdWriters = StdWriters::initDefaultSingleton(); @@ -1964,6 +2313,22 @@ SlangResult innerMain(int argc, char** argv) // An un-categorized test will always belong to the `full` category categorySet.defaultCategory = fullTestCategory; + // Work out what backends are available + { + SlangSession* session = context.getSession(); + const SlangPassThrough passThrus[] = { SLANG_PASS_THROUGH_DXC, SLANG_PASS_THROUGH_FXC, SLANG_PASS_THROUGH_GLSLANG }; + for (auto passThru: passThrus) + { + if (SLANG_SUCCEEDED(spSessionCheckPassThroughSupport(session, passThru))) + { + context.availableBackendFlags |= BackendFlags(1) << int(_toBackendTypeFromPassThroughType(passThru)); + } + } + } + + // Working out what renderApis is worked on on demand through + // _getAvailableRenderApiFlags() + { // We can set the slangc command line tool, to just use the function defined here context.setInnerMainFunc("slangc", &SlangCTool::innerMain); diff --git a/tools/slang-test/test-context.h b/tools/slang-test/test-context.h index b07ca94e6..95b46fe6e 100644 --- a/tools/slang-test/test-context.h +++ b/tools/slang-test/test-context.h @@ -8,16 +8,78 @@ #include "../../source/core/slang-std-writers.h" #include "../../source/core/dictionary.h" #include "../../source/core/slang-test-tool-util.h" +#include "../../source/core/slang-render-api-util.h" #include "options.h" +enum class BackendType +{ + Unknown = -1, + Dxc, + Fxc, + Glslang, + CountOf, +}; + +typedef uint32_t BackendFlags; +struct BackendFlag +{ + enum Enum : uint32_t + { + Dxc = 1 << int(BackendType::Dxc), + Fxc = 1 << int(BackendType::Fxc), + Glslang = 1 << int(BackendType::Glslang), + }; +}; + +/// Structure that describes requirements needs to run - such as rendering APIs or +/// back-end availability +struct TestRequirements +{ + TestRequirements& addUsed(BackendType type) + { + if (type != BackendType::Unknown) + { + usedBackendFlags |= BackendFlags(1) << int(type); + } + return *this; + } + TestRequirements& addUsed(Slang::RenderApiType type) + { + using namespace Slang; + if (type != RenderApiType::Unknown) + { + usedRenderApiFlags |=RenderApiFlags(1) << int(type); + } + return *this; + } + TestRequirements& addUsedBackends(BackendFlags flags) + { + usedBackendFlags |= flags; + return *this; + } + TestRequirements& addUsedRenderApis(Slang::RenderApiFlags flags) + { + usedRenderApiFlags |= flags; + return *this; + } + /// True if has this render api as used + bool isUsed(Slang::RenderApiType apiType) const + { + return (apiType != Slang::RenderApiType::Unknown) && ((usedRenderApiFlags & (Slang::RenderApiFlags(1) << int(apiType))) != 0); + } + + Slang::RenderApiType explicitRenderApi = Slang::RenderApiType::Unknown; ///< The render api explicitly specified + BackendFlags usedBackendFlags = 0; ///< Used backends + Slang::RenderApiFlags usedRenderApiFlags = 0; ///< Used render api flags (some might be implied) +}; + class TestContext { public: typedef Slang::TestToolUtil::InnerMainFunc InnerMainFunc; - /// Get the slang session SlangSession* getSession() const { return m_session; } @@ -28,6 +90,11 @@ class TestContext /// Set the function for the shared library void setInnerMainFunc(const Slang::String& name, InnerMainFunc func); + /// If true tests aren't being run just the information on testing is being accumulated + bool isCollectingRequirements() const { return testRequirements != nullptr; } + /// If set, then tests are executed + bool isExecuting() const { return testRequirements == nullptr; } + /// Ctor TestContext(); /// Dtor @@ -37,6 +104,13 @@ class TestContext TestReporter* reporter = nullptr; TestCategorySet categorySet; + /// If set then tests are not run, but their requirements are set + TestRequirements* testRequirements = nullptr; + + BackendFlags availableBackendFlags = 0; + Slang::RenderApiFlags availableRenderApiFlags = 0; + bool isAvailableRenderApiFlagsValid = false; + protected: struct SharedLibraryTool { |
