/* * Copyright (C) 2020-2022 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "shared/offline_compiler/source/decoder/helper.h" #include "shared/offline_compiler/source/ocloc_api.h" #include "shared/offline_compiler/source/ocloc_concat.h" #include "shared/offline_compiler/source/ocloc_error_code.h" #include "shared/offline_compiler/source/queries.h" #include "shared/offline_compiler/source/utilities/get_git_version_info.h" #include "shared/source/device_binary_format/ar/ar_decoder.h" #include "shared/source/device_binary_format/ar/ar_encoder.h" #include "shared/source/device_binary_format/elf/elf_decoder.h" #include "shared/source/device_binary_format/elf/ocl_elf.h" #include "shared/source/helpers/file_io.h" #include "shared/test/common/helpers/variable_backup.h" #include "environment.h" #include "gtest/gtest.h" #include "hw_cmds_default.h" #include #include #include #include extern Environment *gEnvironment; using namespace std::string_literals; void mockedAbortOclocExecution(int errorCode) { throw std::runtime_error{"mockedAbortOclocExecution() called with error code = " + std::to_string(errorCode)}; } TEST(OclocApiTests, WhenOclocVersionIsCalledThenCurrentOclocVersionIsReturned) { EXPECT_EQ(ocloc_version_t::OCLOC_VERSION_CURRENT, oclocVersion()); } TEST(OclocApiTests, WhenGoodArgsAreGivenThenSuccessIsReturned) { std::string clFileName(clFiles + "copybuffer.cl"); const char *argv[] = { "ocloc", "-file", clFileName.c_str(), "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS); EXPECT_EQ(std::string::npos, output.find("Command was: ocloc -file test_files/copybuffer.cl -device "s + argv[4])); EXPECT_NE(std::string::npos, output.find("Build succeeded.\n")); } TEST(OclocApiTests, GivenQuietModeAndValidArgumentsWhenRunningOclocThenSuccessIsReturnedAndBuildSucceededMessageIsNotPrinted) { std::string clFileName(clFiles + "copybuffer.cl"); const char *argv[] = { "ocloc", "-file", clFileName.c_str(), "-q", "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(NEO::OclocErrorCode::SUCCESS, retVal); EXPECT_EQ(std::string::npos, output.find("Command was: ocloc -file test_files/copybuffer.cl -device "s + argv[4])); EXPECT_EQ(std::string::npos, output.find("Build succeeded.\n")); } TEST(OclocApiTests, GivenNeoRevisionQueryWhenQueryingThenNeoRevisionIsReturned) { uint32_t numOutputs; uint64_t *lenOutputs; uint8_t **dataOutputs; char **nameOutputs; const char *argv[] = { "ocloc", "query", NEO::Queries::queryNeoRevision.data()}; unsigned int argc = sizeof(argv) / sizeof(const char *); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, &numOutputs, &dataOutputs, &lenOutputs, &nameOutputs); EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS); EXPECT_EQ(numOutputs, 2u); int queryOutputIndex = -1; for (uint32_t i = 0; i < numOutputs; ++i) { if (strcmp(NEO::Queries::queryNeoRevision.data(), nameOutputs[i]) == 0) { queryOutputIndex = i; } } ASSERT_NE(-1, queryOutputIndex); NEO::ConstStringRef queryOutput(reinterpret_cast(dataOutputs[queryOutputIndex]), static_cast(lenOutputs[queryOutputIndex])); EXPECT_STREQ(NEO::getRevision().c_str(), queryOutput.data()); oclocFreeOutput(&numOutputs, &dataOutputs, &lenOutputs, &nameOutputs); } TEST(OclocApiTests, GivenOclDriverVersionQueryWhenQueryingThenNeoRevisionIsReturned) { uint32_t numOutputs; uint64_t *lenOutputs; uint8_t **dataOutputs; char **nameOutputs; const char *argv[] = { "ocloc", "query", NEO::Queries::queryOCLDriverVersion.data()}; unsigned int argc = sizeof(argv) / sizeof(const char *); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, &numOutputs, &dataOutputs, &lenOutputs, &nameOutputs); EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS); EXPECT_EQ(numOutputs, 2u); int queryOutputIndex = -1; for (uint32_t i = 0; i < numOutputs; ++i) { if (strcmp(NEO::Queries::queryOCLDriverVersion.data(), nameOutputs[i]) == 0) { queryOutputIndex = i; } } ASSERT_NE(-1, queryOutputIndex); NEO::ConstStringRef queryOutput(reinterpret_cast(dataOutputs[queryOutputIndex]), static_cast(lenOutputs[queryOutputIndex])); EXPECT_STREQ(NEO::getOclDriverVersion().c_str(), queryOutput.data()); oclocFreeOutput(&numOutputs, &dataOutputs, &lenOutputs, &nameOutputs); } TEST(OclocApiTests, GivenNoQueryWhenQueryingThenErrorIsReturned) { const char *argv[] = { "ocloc", "query"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(retVal, NEO::OclocErrorCode::INVALID_COMMAND_LINE); EXPECT_STREQ("Error: Invalid command line. Expected ocloc query ", output.c_str()); } TEST(OclocApiTests, GivenInvalidQueryWhenQueryingThenErrorIsReturned) { const char *argv[] = { "ocloc", "query", "unknown_query"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(retVal, NEO::OclocErrorCode::INVALID_COMMAND_LINE); EXPECT_STREQ("Error: Invalid command line. Unknown argument unknown_query.", output.c_str()); } TEST(OclocApiTests, givenNoAcronymWhenIdsCommandIsInvokeThenErrorIsReported) { const char *argv[] = { "ocloc", "ids"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(retVal, NEO::OclocErrorCode::INVALID_COMMAND_LINE); EXPECT_STREQ("Error: Invalid command line. Expected ocloc ids .\n", output.c_str()); } TEST(OclocApiTests, givenUnknownAcronymWhenIdsCommandIsInvokeThenErrorIsReported) { const char *argv[] = { "ocloc", "ids", "unk"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(retVal, NEO::OclocErrorCode::INVALID_COMMAND_LINE); EXPECT_STREQ("Error: Invalid command line. Unknown acronym unk.\n", output.c_str()); } TEST(OclocApiTests, WhenGoodFamilyNameIsProvidedThenSuccessIsReturned) { std::string clFileName(clFiles + "copybuffer.cl"); std::unique_ptr argHelper = std::make_unique(); auto allSupportedDeviceConfigs = argHelper->productConfigHelper->getDeviceAotInfo(); if (allSupportedDeviceConfigs.empty()) { GTEST_SKIP(); } std::string family(""); for (const auto &config : allSupportedDeviceConfigs) { if (config.hwInfo->platform.eProductFamily == NEO::DEFAULT_PLATFORM::hwInfo.platform.eProductFamily) { family = ProductConfigHelper::getAcronymForAFamily(config.family).str(); break; } } if (family.empty()) { GTEST_SKIP(); } const char *argv[] = { "ocloc", "-file", clFileName.c_str(), "-device", family.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS); EXPECT_EQ(std::string::npos, output.find("Command was: ocloc -file " + clFileName + " -device " + family)); } TEST(OclocApiTests, WhenArgsWithMissingFileAreGivenThenErrorMessageIsProduced) { const char *argv[] = { "ocloc", "-q", "-file", "test_files/IDoNotExist.cl", "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(retVal, NEO::OclocErrorCode::INVALID_FILE); EXPECT_NE(std::string::npos, output.find("Command was: ocloc -q -file test_files/IDoNotExist.cl -device "s + argv[5])); } TEST(OclocApiTests, givenInputOptionsAndInternalOptionsWhenCmdlineIsPrintedThenBothAreInQuotes) { const char *argv[] = { "ocloc", "-q", "-file", "test_files/IDoNotExist.cl", "-device", gEnvironment->devicePrefix.c_str(), "-options", "-D DEBUG -cl-kernel-arg-info", "-internal_options", "-internalOption1 -internal-option-2"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_NE(retVal, NEO::OclocErrorCode::SUCCESS); EXPECT_TRUE(output.find("Command was: ocloc -q -file test_files/IDoNotExist.cl -device "s + gEnvironment->devicePrefix.c_str() + " -options \"-D DEBUG -cl-kernel-arg-info\" -internal_options \"-internalOption1 -internal-option-2\"") != std::string::npos); size_t quotesCount = std::count(output.begin(), output.end(), '\"'); EXPECT_EQ(quotesCount, 4u); } TEST(OclocApiTests, givenInputOptionsCalledOptionsWhenCmdlineIsPrintedThenQuotesAreCorrect) { const char *argv[] = { "ocloc", "-q", "-file", "test_files/IDoNotExist.cl", "-device", gEnvironment->devicePrefix.c_str(), "-options", "-options", "-internal_options", "-internalOption"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_NE(retVal, NEO::OclocErrorCode::SUCCESS); EXPECT_TRUE(output.find("Command was: ocloc -q -file test_files/IDoNotExist.cl -device "s + gEnvironment->devicePrefix.c_str() + " -options \"-options\" -internal_options \"-internalOption\"") != std::string::npos); size_t quotesCount = std::count(output.begin(), output.end(), '\"'); EXPECT_EQ(quotesCount, 4u); } TEST(OclocApiTests, givenInvalidInputOptionsAndInternalOptionsFilesWhenCmdlineIsPrintedThenTheyArePrinted) { ASSERT_TRUE(fileExists(clFiles + "shouldfail.cl")); ASSERT_TRUE(fileExists(clFiles + "shouldfail_options.txt")); ASSERT_TRUE(fileExists(clFiles + "shouldfail_internal_options.txt")); std::string clFileName(clFiles + "shouldfail.cl"); const char *argv[] = { "ocloc", "-q", "-file", clFileName.c_str(), "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_NE(retVal, NEO::OclocErrorCode::SUCCESS); EXPECT_TRUE(output.find("Compiling options read from file were:\n" "-shouldfailOptions") != std::string::npos); EXPECT_TRUE(output.find("Internal options read from file were:\n" "-shouldfailInternalOptions") != std::string::npos); } TEST(OclocApiTests, GivenInvalidOptionsAndInternalOptionsCommandArgumentsWhenCmdlineIsPrintedThenTheyAreNotPrinted) { std::string clFileName(clFiles + "shouldfail.cl"); ASSERT_TRUE(fileExists(clFileName)); const char *argv[] = { "ocloc", "-q", "-options", "-invalid_option", "-internal_options", "-invalid_internal_option", "-file", clFileName.c_str(), "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_NE(NEO::OclocErrorCode::SUCCESS, retVal); EXPECT_FALSE(output.find("Compiling options read from file were:\n" "-shouldfailOptions") != std::string::npos); EXPECT_FALSE(output.find("Internal options read from file were:\n" "-shouldfailInternalOptions") != std::string::npos); } TEST(OclocApiTests, givenInvalidOclocOptionsFileWhenCmdlineIsPrintedThenTheyArePrinted) { ASSERT_TRUE(fileExists(clFiles + "valid_kernel.cl")); ASSERT_TRUE(fileExists(clFiles + "valid_kernel_ocloc_options.txt")); std::string clFileName(clFiles + "valid_kernel.cl"); const char *argv[] = { "ocloc", "-q", "-file", clFileName.c_str(), "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_NE(retVal, NEO::OclocErrorCode::SUCCESS); EXPECT_TRUE(output.find("Failed with ocloc options from file:\n" "-invalid_ocloc_option") != std::string::npos); EXPECT_FALSE(output.find("Building with ocloc options:") != std::string::npos); } TEST(OclocApiTests, GivenIncludeHeadersWhenCompilingThenPassesToFclHeadersPackedAsElf) { auto prevFclDebugVars = NEO::getFclDebugVars(); auto debugVars = prevFclDebugVars; std::string receivedInput; debugVars.receivedInput = &receivedInput; setFclDebugVars(debugVars); const char *argv[] = { "ocloc", "-file", "main.cl", "-device", gEnvironment->devicePrefix.c_str()}; unsigned int argc = sizeof(argv) / sizeof(const char *); const char *headerA = R"===( void foo() {} )==="; const char *headerB = R"===( void bar() {} )==="; const char *main = R"===( #include "includeA.h" #include "includeB.h" __kernel void k(){ foo(); bar(); } )==="; const char *sourcesNames[] = {"main.cl"}; const uint8_t *sources[] = {reinterpret_cast(main)}; const uint64_t sourcesLen[] = {strlen(main) + 1}; const char *headersNames[] = {"includeA.h", "includeB.h"}; const uint8_t *headers[] = {reinterpret_cast(headerA), reinterpret_cast(headerB)}; const uint64_t headersLen[] = {strlen(headerA) + 1, strlen(headerB) + 1}; uint32_t numOutputs = 0U; uint8_t **outputs = nullptr; uint64_t *outputsLen = nullptr; char **ouputsNames = nullptr; oclocInvoke(argc, argv, 1, sources, sourcesLen, sourcesNames, 2, headers, headersLen, headersNames, &numOutputs, &outputs, &outputsLen, &ouputsNames); NEO::setFclDebugVars(prevFclDebugVars); std::string decodeErr, decodeWarn; ArrayRef rawElf(reinterpret_cast(receivedInput.data()), receivedInput.size()); auto elf = NEO::Elf::decodeElf(rawElf, decodeErr, decodeWarn); ASSERT_NE(nullptr, elf.elfFileHeader) << decodeWarn << " " << decodeErr; EXPECT_EQ(NEO::Elf::ET_OPENCL_SOURCE, elf.elfFileHeader->type); using SectionT = std::remove_reference_t; const SectionT *sourceSection, *headerASection, *headerBSection; ASSERT_NE(NEO::Elf::SHN_UNDEF, elf.elfFileHeader->shStrNdx); auto sectionNamesSection = elf.sectionHeaders.begin() + elf.elfFileHeader->shStrNdx; auto elfStrings = sectionNamesSection->data.toArrayRef(); for (const auto §ion : elf.sectionHeaders) { if (NEO::Elf::SHT_OPENCL_SOURCE == section.header->type) { sourceSection = §ion; } else if (NEO::Elf::SHT_OPENCL_HEADER == section.header->type) { auto sectionName = elfStrings.begin() + section.header->name; if (0 == strcmp("includeA.h", sectionName)) { headerASection = §ion; } else if (0 == strcmp("includeB.h", sectionName)) { headerBSection = §ion; } else { EXPECT_FALSE(true) << sectionName; } } } ASSERT_NE(nullptr, sourceSection); EXPECT_EQ(sourcesLen[0], sourceSection->data.size()); EXPECT_STREQ(main, reinterpret_cast(sourceSection->data.begin())); ASSERT_NE(nullptr, headerASection); EXPECT_EQ(sourcesLen[0], sourceSection->data.size()); EXPECT_STREQ(headerA, reinterpret_cast(headerASection->data.begin())); ASSERT_NE(nullptr, headerBSection); EXPECT_EQ(sourcesLen[0], sourceSection->data.size()); EXPECT_STREQ(headerB, reinterpret_cast(headerBSection->data.begin())); } TEST(OclocApiTests, GivenHelpParameterWhenDecodingThenHelpMsgIsPrintedAndSuccessIsReturned) { const char *argv[] = { "ocloc", "disasm", "--help"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_FALSE(output.empty()); EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS); } TEST(OclocApiTests, GivenNonExistingFileWhenDecodingThenAbortIsCalled) { VariableBackup oclocAbortBackup{&abortOclocExecution, &mockedAbortOclocExecution}; const char *argv[] = { "ocloc", "disasm", "-file", "nonexistent_file_that_should_fail", "-dump", "test_files/created"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); const auto retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); const auto output = testing::internal::GetCapturedStdout(); EXPECT_NE(std::string::npos, output.find("mockedAbortOclocExecution() called with error code = 1")); EXPECT_EQ(-1, retVal); } TEST(OclocApiTests, GivenMissingFileNameWhenDecodingThenErrorIsReturned) { const char *argv[] = { "ocloc", "disasm", "-file"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); const auto retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); const auto output = testing::internal::GetCapturedStdout(); EXPECT_NE(std::string::npos, output.find("Unknown argument -file\n")); EXPECT_EQ(-1, retVal); } TEST(OclocApiTests, GivenHelpParameterWhenEncodingThenHelpMsgIsPrintedAndSuccessIsReturned) { const char *argv[] = { "ocloc", "asm", "--help"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_FALSE(output.empty()); EXPECT_EQ(retVal, NEO::OclocErrorCode::SUCCESS); } TEST(OclocApiTests, GivenMissingDumpFileNameWhenEncodingThenErrorIsReturned) { const char *argv[] = { "ocloc", "asm", "-dump"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); const auto retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); const auto output = testing::internal::GetCapturedStdout(); EXPECT_NE(std::string::npos, output.find("Unknown argument -dump\n")); EXPECT_EQ(-1, retVal); } TEST(OclocApiTests, GivenValidArgumentsAndMissingPtmFileWhenEncodingThenErrorIsReturned) { const char *argv[] = { "ocloc", "asm", "-dump", "test_files/dump", "-out", "test_files/binary_gen.bin"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); const auto retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); const auto output = testing::internal::GetCapturedStdout(); EXPECT_NE(std::string::npos, output.find("Error! Couldn't find PTM.txt")); EXPECT_EQ(-1, retVal); } TEST(OclocApiTests, GiveMultiCommandHelpArgumentsWhenInvokingOclocThenHelpIsPrinted) { const char *argv[] = { "ocloc", "multi", "--help"}; unsigned int argc = sizeof(argv) / sizeof(const char *); testing::internal::CaptureStdout(); const auto retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); const auto output = testing::internal::GetCapturedStdout(); EXPECT_FALSE(output.empty()); EXPECT_EQ(-1, retVal); } TEST(OclocApiTests, GivenNonexistentFileWhenValidateIsInvokedThenErrorIsPrinted) { const char *argv[] = { "ocloc", "validate", "-file", "some_special_nonexistent_file.gen"}; unsigned int argc = sizeof(argv) / sizeof(argv[0]); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); const auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(-1, retVal); const std::string expectedErrorMessage{"Error : Input file missing : some_special_nonexistent_file.gen\n"}; EXPECT_EQ(expectedErrorMessage, output); } TEST(OclocApiTests, GivenZeroArgumentsWhenOclocIsInvokedThenHelpIsPrinted) { testing::internal::CaptureStdout(); int retVal = oclocInvoke(0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); const auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(NEO::OclocErrorCode::INVALID_COMMAND_LINE, retVal); EXPECT_FALSE(output.empty()); } TEST(OclocApiTests, GivenCommandWithoutArgsWhenOclocIsInvokedThenHelpIsPrinted) { const char *argv[] = { "ocloc"}; unsigned int argc = sizeof(argv) / sizeof(argv[0]); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); const auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(NEO::OclocErrorCode::SUCCESS, retVal); EXPECT_FALSE(output.empty()); } TEST(OclocApiTests, GivenHelpArgumentWhenOclocIsInvokedThenHelpIsPrinted) { constexpr std::array flagsToTest = {"-h", "--help"}; for (const auto helpFlag : flagsToTest) { const char *argv[] = { "ocloc", helpFlag}; unsigned int argc = sizeof(argv) / sizeof(argv[0]); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); const auto output = testing::internal::GetCapturedStdout(); EXPECT_EQ(NEO::OclocErrorCode::SUCCESS, retVal); EXPECT_FALSE(output.empty()); } } TEST(OclocApiTests, GivenHelpParameterWhenLinkingThenHelpMsgIsPrintedAndSuccessIsReturned) { const char *argv[] = { "ocloc", "link", "--help"}; unsigned int argc = sizeof(argv) / sizeof(argv[0]); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_FALSE(output.empty()); EXPECT_EQ(NEO::OclocErrorCode::SUCCESS, retVal); } TEST(OclocApiTests, GivenInvalidParameterWhenLinkingThenErrorIsReturned) { const char *argv[] = { "ocloc", "link", "--dummy_param"}; unsigned int argc = sizeof(argv) / sizeof(argv[0]); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(NEO::OclocErrorCode::INVALID_COMMAND_LINE, retVal); const std::string expectedInitError{"Invalid option (arg 2): --dummy_param\n"}; const std::string expectedExecuteError{"Error: Linker cannot be executed due to unsuccessful initialization!\n"}; const std::string expectedErrorMessage = expectedInitError + expectedExecuteError; EXPECT_EQ(expectedErrorMessage, output); } TEST(OclocApiTests, GivenInvalidCommandLineWhenConcatenatingThenErrorIsReturned) { const char *argv[] = { "ocloc", "concat"}; unsigned int argc = sizeof(argv) / sizeof(argv[0]); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(NEO::OclocErrorCode::INVALID_COMMAND_LINE, retVal); const std::string emptyCommandLineError = "No files to concatenate were provided.\n"; const std::string expectedErrorMessage = emptyCommandLineError + NEO::OclocConcat::helpMessage.str(); EXPECT_EQ(expectedErrorMessage, output); } TEST(OclocApiTests, GivenValidCommandLineAndFatBinariesWhenConcatenatingThenNewFatBinaryIsCreated) { std::vector file1(32, 0x0); std::vector file2(32, 0x10); const std::string file1Name = "file1"; const std::string file2Name = "file2"; std::vector fatBinary1; { NEO::Ar::ArEncoder arEncoder(true); arEncoder.appendFileEntry(file1Name, ArrayRef::fromAny(file1.data(), file1.size())); fatBinary1 = arEncoder.encode(); } std::vector fatBinary2; { NEO::Ar::ArEncoder arEncoder(true); arEncoder.appendFileEntry(file2Name, ArrayRef::fromAny(file2.data(), file2.size())); fatBinary2 = arEncoder.encode(); } const uint8_t *sourcesData[2] = {fatBinary1.data(), fatBinary2.data()}; const uint64_t sourcesLen[2] = {fatBinary1.size(), fatBinary2.size()}; const char *sourcesName[2] = {"fatBinary1.ar", "fatBinary2.ar"}; uint32_t numOutputs; uint8_t **outputData; uint64_t *outputLen; char **outputName; const char *argv[] = { "ocloc", "concat", "fatBinary1.ar", "fatBinary2.ar", "-out", "catFatBinary.ar"}; unsigned int argc = sizeof(argv) / sizeof(argv[0]); testing::internal::CaptureStdout(); int retVal = oclocInvoke(argc, argv, 2, sourcesData, sourcesLen, sourcesName, 0, nullptr, nullptr, nullptr, &numOutputs, &outputData, &outputLen, &outputName); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(NEO::OclocErrorCode::SUCCESS, retVal); EXPECT_TRUE(output.empty()); uint32_t fatBinaryIdx = std::numeric_limits::max(); for (uint32_t i = 0; i < numOutputs; i++) { if (strcmp(argv[argc - 1], outputName[i]) == 0) { fatBinaryIdx = i; break; } } ASSERT_NE(std::numeric_limits::max(), fatBinaryIdx); std::string errors, warnings; auto ar = NEO::Ar::decodeAr(ArrayRef::fromAny(outputData[fatBinaryIdx], static_cast(outputLen[fatBinaryIdx])), errors, warnings); EXPECT_TRUE(errors.empty()); EXPECT_TRUE(warnings.empty()); bool hasFatBinary1 = false; bool hasFatBinary2 = false; for (auto &file : ar.files) { if (file.fileName == file1Name) { hasFatBinary1 = true; ASSERT_EQ(file1.size(), file.fileData.size()); EXPECT_EQ(0, memcmp(file1.data(), file.fileData.begin(), file1.size())); } else if (file.fileName == file2Name) { hasFatBinary2 = true; ASSERT_EQ(file2.size(), file.fileData.size()); EXPECT_EQ(0, memcmp(file2.data(), file.fileData.begin(), file2.size())); } } EXPECT_TRUE(hasFatBinary1); EXPECT_TRUE(hasFatBinary2); oclocFreeOutput(&numOutputs, &outputData, &outputLen, &outputName); }