// unit-test-ir-blob.cpp #include "slang-com-ptr.h" #include "slang.h" #include "unit-test/slang-unit-test.h" #include #include #include using namespace Slang; // Test the slang_loadModuleFromIRBlob and slang_loadModuleInfoFromIRBlob functions SLANG_UNIT_TEST(irBlob) { // Test source code for creating IR data const char* testModuleSource = R"( module test_ir_module; public struct TestStruct { float x, y, z; } public void testFunction(TestStruct input) { // Simple function } public static const float PI = 3.14159; )"; ComPtr globalSession; SLANG_CHECK(slang_createGlobalSession(SLANG_API_VERSION, globalSession.writeRef()) == SLANG_OK); slang::SessionDesc sessionDesc = {}; sessionDesc.targetCount = 1; slang::TargetDesc targetDesc = {}; targetDesc.format = SLANG_SPIRV; targetDesc.profile = globalSession->findProfile("spirv_1_5"); sessionDesc.targets = &targetDesc; ComPtr session; SLANG_CHECK(globalSession->createSession(sessionDesc, session.writeRef()) == SLANG_OK); // Create IR data by serializing a module ComPtr irBlob; { ComPtr module; ComPtr diagnostics; module = session->loadModuleFromSourceString( "test_ir_module", "test_ir_module.slang", testModuleSource, diagnostics.writeRef()); SLANG_CHECK(module != nullptr); if (diagnostics && diagnostics->getBufferSize() > 0) { // Log diagnostics if any printf( "Module compilation diagnostics: %.*s\n", (int)diagnostics->getBufferSize(), (const char*)diagnostics->getBufferPointer()); } // Serialize the module to create IR data SLANG_CHECK(module->serialize(irBlob.writeRef()) == SLANG_OK); SLANG_CHECK(irBlob != nullptr); SLANG_CHECK(irBlob->getBufferSize() > 0); } // Test 1: Test slang_loadModuleFromIRBlob with valid IR data { ComPtr loadedModule; ComPtr diagnostics; loadedModule = slang_loadModuleFromIRBlob( session, "test_ir_module_loaded", "test_ir_module_loaded.slang", irBlob->getBufferPointer(), irBlob->getBufferSize(), diagnostics.writeRef()); SLANG_CHECK(loadedModule != nullptr); if (diagnostics && diagnostics->getBufferSize() > 0) { // Log diagnostics if any printf( "IR blob loading diagnostics: %.*s\n", (int)diagnostics->getBufferSize(), (const char*)diagnostics->getBufferPointer()); } // Verify the loaded module is valid SLANG_CHECK(loadedModule != nullptr); } // Test 2: Test slang_loadModuleInfoFromIRBlob with valid IR data { SlangInt moduleVersion; const char* moduleCompilerVersion; const char* moduleName; SlangResult result = slang_loadModuleInfoFromIRBlob( session, irBlob->getBufferPointer(), irBlob->getBufferSize(), moduleVersion, moduleCompilerVersion, moduleName); SLANG_CHECK(result == SLANG_OK); SLANG_CHECK(moduleName != nullptr); SLANG_CHECK(strcmp(moduleName, "test_ir_module") == 0); SLANG_CHECK(moduleCompilerVersion != nullptr); SLANG_CHECK(moduleVersion >= 0); } // Test 3: Test slang_loadModuleFromIRBlob with invalid parameters { ComPtr module; ComPtr diagnostics; // Test with null session module = slang_loadModuleFromIRBlob( nullptr, "testModule", "test.slang", irBlob->getBufferPointer(), irBlob->getBufferSize(), diagnostics.writeRef()); SLANG_CHECK(module == nullptr); // Test with null moduleName module = slang_loadModuleFromIRBlob( session, nullptr, "test.slang", irBlob->getBufferPointer(), irBlob->getBufferSize(), diagnostics.writeRef()); SLANG_CHECK(module == nullptr); // Test with null path module = slang_loadModuleFromIRBlob( session, "testModule", nullptr, irBlob->getBufferPointer(), irBlob->getBufferSize(), diagnostics.writeRef()); SLANG_CHECK(module == nullptr); // Test with null source module = slang_loadModuleFromIRBlob( session, "testModule", "test.slang", nullptr, irBlob->getBufferSize(), diagnostics.writeRef()); SLANG_CHECK(module == nullptr); // Test with zero size module = slang_loadModuleFromIRBlob( session, "testModule", "test.slang", irBlob->getBufferPointer(), 0, diagnostics.writeRef()); SLANG_CHECK(module == nullptr); } // Test 4: Test slang_loadModuleInfoFromIRBlob with invalid parameters { SlangInt moduleVersion; const char* moduleCompilerVersion; const char* moduleName; // Test with null session SlangResult result = slang_loadModuleInfoFromIRBlob( nullptr, irBlob->getBufferPointer(), irBlob->getBufferSize(), moduleVersion, moduleCompilerVersion, moduleName); SLANG_CHECK(result == SLANG_E_INVALID_ARG); // Test with null source result = slang_loadModuleInfoFromIRBlob( session, nullptr, irBlob->getBufferSize(), moduleVersion, moduleCompilerVersion, moduleName); SLANG_CHECK(result == SLANG_E_INVALID_ARG); // Test with zero size result = slang_loadModuleInfoFromIRBlob( session, irBlob->getBufferPointer(), 0, moduleVersion, moduleCompilerVersion, moduleName); SLANG_CHECK(result == SLANG_E_INVALID_ARG); } // Test 5: Test with corrupted/invalid IR data { ComPtr module; ComPtr diagnostics; // Create some invalid data const char* invalidData = "This is not valid IR data"; size_t invalidDataSize = strlen(invalidData); module = slang_loadModuleFromIRBlob( session, "testModule", "test.slang", invalidData, invalidDataSize, diagnostics.writeRef()); // This might return nullptr or a module with diagnostics if (module == nullptr) { // If it failed, that's expected for invalid data SLANG_CHECK(true); } else { // If it succeeded, there should be diagnostics if (diagnostics && diagnostics->getBufferSize() > 0) { SLANG_CHECK(true); } } } // Test 6: Test slang_loadModuleInfoFromIRBlob with corrupted/invalid IR data { SlangInt moduleVersion; const char* moduleCompilerVersion; const char* moduleName; // Create some invalid data const char* invalidData = "This is not valid IR data"; size_t invalidDataSize = strlen(invalidData); SlangResult result = slang_loadModuleInfoFromIRBlob( session, invalidData, invalidDataSize, moduleVersion, moduleCompilerVersion, moduleName); // This should fail with invalid data SLANG_CHECK(result != SLANG_OK); } // Test 7: Test round-trip serialization and loading { // Load the module from IR ComPtr loadedModule; ComPtr diagnostics; loadedModule = slang_loadModuleFromIRBlob( session, "test_round_trip", "test_round_trip.slang", irBlob->getBufferPointer(), irBlob->getBufferSize(), diagnostics.writeRef()); SLANG_CHECK(loadedModule != nullptr); if (loadedModule) { // Serialize the loaded module again ComPtr roundTripBlob; SLANG_CHECK(loadedModule->serialize(roundTripBlob.writeRef()) == SLANG_OK); SLANG_CHECK(roundTripBlob != nullptr); SLANG_CHECK(roundTripBlob->getBufferSize() > 0); // Load it again ComPtr roundTripModule; roundTripModule = slang_loadModuleFromIRBlob( session, "test_round_trip_2", "test_round_trip_2.slang", roundTripBlob->getBufferPointer(), roundTripBlob->getBufferSize(), diagnostics.writeRef()); SLANG_CHECK(roundTripModule != nullptr); } } // Test 8: Test multiple modules with different IR data { // Create a second module with different content const char* testModuleSource2 = R"( module test_ir_module_2; public struct AnotherStruct { int a, b, c; } public void anotherFunction(AnotherStruct input) { // Another function } )"; ComPtr module2; ComPtr diagnostics2; ComPtr irBlob2; module2 = session->loadModuleFromSourceString( "test_ir_module_2", "test_ir_module_2.slang", testModuleSource2, diagnostics2.writeRef()); SLANG_CHECK(module2 != nullptr); SLANG_CHECK(module2->serialize(irBlob2.writeRef()) == SLANG_OK); // Load both modules ComPtr loadedModule1; ComPtr loadedModule2; ComPtr diagnostics; loadedModule1 = slang_loadModuleFromIRBlob( session, "test_ir_module_1_loaded", "test_ir_module_1_loaded.slang", irBlob->getBufferPointer(), irBlob->getBufferSize(), diagnostics.writeRef()); loadedModule2 = slang_loadModuleFromIRBlob( session, "test_ir_module_2_loaded", "test_ir_module_2_loaded.slang", irBlob2->getBufferPointer(), irBlob2->getBufferSize(), diagnostics.writeRef()); SLANG_CHECK(loadedModule1 != nullptr); SLANG_CHECK(loadedModule2 != nullptr); // Verify both modules loaded successfully SLANG_CHECK(loadedModule1 != nullptr); SLANG_CHECK(loadedModule2 != nullptr); } }