123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <AzCore/UnitTest/TestTypes.h>
- #include <AzFramework/Process/ProcessWatcher.h>
- #include <AzFramework/Process/ProcessCommunicator.h>
- #include <AzCore/std/containers/vector.h>
- #include <AzCore/std/string/string.h>
- #include <AzCore/std/containers/unordered_map.h>
- #include <AzCore/StringFunc/StringFunc.h>
- #include <AzCore/IO/Path/Path.h>
- // this is an intentional relative local include so that it can be shared between two unrelated projects
- // namely this one test file as well as the one shot executable that these tests invoke.
- #include "ProcessLaunchTestTokens.h"
- namespace UnitTest
- {
- class ProcessLaunchParseTests
- : public LeakDetectionFixture
- {
- public:
- using ParsedArgMap = AZStd::unordered_map<AZStd::string, AZStd::vector<AZStd::string>>;
- static ParsedArgMap ParseParameters(const AZStd::string& processOutput);
- };
- ProcessLaunchParseTests::ParsedArgMap ProcessLaunchParseTests::ParseParameters(const AZStd::string& processOutput)
- {
- ParsedArgMap parsedArgs;
- AZStd::string currentSwitch;
- bool inSwitches{ false };
- AZStd::vector<AZStd::string> parsedLines;
- AZ::StringFunc::Tokenize(processOutput.c_str(), parsedLines, "\r\n");
- for (const AZStd::string& thisLine : parsedLines)
- {
- if (thisLine == "Switch List:")
- {
- inSwitches = true;
- continue;
- }
- else if (thisLine == "End Switch List:")
- {
- inSwitches = false;
- continue;
- }
- if (thisLine.empty())
- {
- continue;
- }
-
- if(inSwitches)
- {
- if (thisLine[0] != ' ')
- {
- currentSwitch = thisLine;
- }
- else
- {
- parsedArgs[currentSwitch].push_back(thisLine.substr(1));
- }
- }
- }
- return parsedArgs;
- }
- TEST_F(ProcessLaunchParseTests, ProcessLauncher_LaunchBasicProcess_Success)
- {
- AzFramework::ProcessOutput processOutput;
- AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
- processLaunchInfo.m_commandlineParameters.emplace<AZStd::string>((AZ::IO::Path(AZ::Test::GetCurrentExecutablePath()) / "ProcessLaunchTest").Native());
- processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath();
- processLaunchInfo.m_showWindow = false;
- bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput);
- EXPECT_EQ(launchReturn, true);
- EXPECT_EQ(processOutput.outputResult.empty(), false);
- }
- TEST_F(ProcessLaunchParseTests, LaunchProcessAndRetrieveOutput_LargeDataNoError_ContainsEntireOutput)
- {
- using namespace ProcessLaunchTestInternal;
- AzFramework::ProcessOutput processOutput;
- AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
- processLaunchInfo.m_commandlineParameters.emplace<AZStd::vector<AZStd::string>>(
- AZStd::vector<AZStd::string>{(AZ::IO::Path(AZ::Test::GetCurrentExecutablePath()) / "ProcessLaunchTest").Native(), "-plentyOfOutput"});
- processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath();
- processLaunchInfo.m_showWindow = false;
- bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput);
- EXPECT_TRUE(launchReturn);
- EXPECT_FALSE(processOutput.outputResult.empty());
- EXPECT_FALSE(processOutput.HasError());
- const auto& output = processOutput.outputResult;
- EXPECT_EQ(output.length(), s_numOutputBytesInPlentyMode);
- EXPECT_TRUE(output.starts_with(s_beginToken));
- EXPECT_TRUE(output.ends_with(s_endToken));
- }
-
- // this also tests that it can separately read error and stdout, and that the stream way of doing it works.
- TEST_F(ProcessLaunchParseTests, LaunchProcessAndRetrieveOutput_LargeDataWithError_ContainsEntireOutput)
- {
- using namespace ProcessLaunchTestInternal;
- AzFramework::ProcessOutput processOutput;
- AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
- processLaunchInfo.m_commandlineParameters.emplace<AZStd::vector<AZStd::string>>(
- AZStd::vector<AZStd::string>{(AZ::IO::Path(AZ::Test::GetCurrentExecutablePath()) / "ProcessLaunchTest").Native(), "-plentyOfOutput", "-exitCode", "1"});
- processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath();
- processLaunchInfo.m_showWindow = false;
- bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput);
- EXPECT_TRUE(launchReturn);
- EXPECT_TRUE(processOutput.HasOutput());
- EXPECT_TRUE(processOutput.HasError());
- EXPECT_EQ(processOutput.outputResult.length(), s_numOutputBytesInPlentyMode);
- EXPECT_TRUE(processOutput.outputResult.starts_with(s_beginToken));
- EXPECT_TRUE(processOutput.outputResult.ends_with(s_endToken));
- EXPECT_EQ(processOutput.errorResult.length(), s_numOutputBytesInPlentyMode);
- EXPECT_TRUE(processOutput.errorResult.starts_with(s_beginToken));
- EXPECT_TRUE(processOutput.errorResult.ends_with(s_endToken));
- }
-
- TEST_F(ProcessLaunchParseTests, ProcessLauncher_BasicParameter_Success)
- {
- ProcessLaunchParseTests::ParsedArgMap argMap;
- AzFramework::ProcessOutput processOutput;
- AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
- processLaunchInfo.m_commandlineParameters.emplace<AZStd::vector<AZStd::string>>(
- AZStd::vector<AZStd::string>{(AZ::IO::Path(AZ::Test::GetCurrentExecutablePath()) / "ProcessLaunchTest").Native(), "-param1", "param1val", "-param2", "param2val"});
- processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath();
- processLaunchInfo.m_showWindow = false;
- bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput);
- EXPECT_EQ(launchReturn, true);
- argMap = ProcessLaunchParseTests::ParseParameters(processOutput.outputResult);
- auto param1itr = argMap.find("param1");
- EXPECT_NE(param1itr, argMap.end());
- AZStd::vector<AZStd::string> param1{ param1itr->second };
- EXPECT_EQ(param1.size(), 1);
- EXPECT_EQ(param1[0], "param1val");
- auto param2itr = argMap.find("param2");
- EXPECT_NE(param2itr, argMap.end());
- AZStd::vector<AZStd::string> param2{ param2itr->second };
- EXPECT_EQ(param2.size(), 1);
- EXPECT_EQ(param2[0], "param2val");
- }
- TEST_F(ProcessLaunchParseTests, ProcessLauncher_WithCommas_Success)
- {
- ProcessLaunchParseTests::ParsedArgMap argMap;
- AzFramework::ProcessOutput processOutput;
- AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
- processLaunchInfo.m_commandlineParameters.emplace<AZStd::vector<AZStd::string>>(
- AZStd::vector<AZStd::string>{(AZ::IO::Path(AZ::Test::GetCurrentExecutablePath()) / "ProcessLaunchTest").Native(), "-param1", "param,1val", "-param2", "param2v,al"});
- processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath();
- processLaunchInfo.m_showWindow = false;
- bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput);
- EXPECT_EQ(launchReturn, true);
- argMap = ProcessLaunchParseTests::ParseParameters(processOutput.outputResult);
- auto param1itr = argMap.find("param1");
- EXPECT_NE(param1itr, argMap.end());
- AZStd::vector<AZStd::string> param1{ param1itr->second };
- EXPECT_EQ(param1.size(), 2);
- EXPECT_EQ(param1[0], "param");
- EXPECT_EQ(param1[1], "1val");
- auto param2itr = argMap.find("param2");
- EXPECT_NE(param2itr, argMap.end());
- AZStd::vector<AZStd::string> param2{ param2itr->second };
- EXPECT_EQ(param2.size(), 2);
- EXPECT_EQ(param2[0], "param2v");
- EXPECT_EQ(param2[1], "al");
- }
- TEST_F(ProcessLaunchParseTests, ProcessLauncher_WithSpaces_Success)
- {
- ProcessLaunchParseTests::ParsedArgMap argMap;
- AzFramework::ProcessOutput processOutput;
- AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
- processLaunchInfo.m_commandlineParameters.emplace<AZStd::vector<AZStd::string>>(AZStd::vector<AZStd::string>{
- (AZ::IO::Path(AZ::Test::GetCurrentExecutablePath()) / "ProcessLaunchTest").Native(), "-param1", R"("param 1val")", R"(-param2="param2v al")" });
- processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath();
- processLaunchInfo.m_showWindow = false;
- bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput);
- EXPECT_EQ(launchReturn, true);
- argMap = ProcessLaunchParseTests::ParseParameters(processOutput.outputResult);
- auto param1itr = argMap.find("param1");
- EXPECT_NE(param1itr, argMap.end());
- AZStd::vector<AZStd::string> param1{ param1itr->second };
- EXPECT_EQ(param1.size(), 1);
- EXPECT_EQ(param1[0], "param 1val");
- auto param2itr = argMap.find("param2");
- EXPECT_NE(param2itr, argMap.end());
- AZStd::vector<AZStd::string> param2{ param2itr->second };
- EXPECT_EQ(param2.size(), 1);
- EXPECT_EQ(param2[0], "param2v al");
- }
- TEST_F(ProcessLaunchParseTests, ProcessLauncher_WithSpacesAndComma_Success)
- {
- ProcessLaunchParseTests::ParsedArgMap argMap;
- AzFramework::ProcessOutput processOutput;
- AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
- processLaunchInfo.m_commandlineParameters.emplace<AZStd::vector<AZStd::string>>(AZStd::vector<AZStd::string>{
- (AZ::IO::Path(AZ::Test::GetCurrentExecutablePath()) / "ProcessLaunchTest").Native(), "-param1", R"("param, 1val")", R"(-param2="param,2v al")" });
- processLaunchInfo.m_workingDirectory = AZ::Test::GetCurrentExecutablePath();
- processLaunchInfo.m_showWindow = false;
- bool launchReturn = AzFramework::ProcessWatcher::LaunchProcessAndRetrieveOutput(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT, processOutput);
- EXPECT_EQ(launchReturn, true);
- argMap = ProcessLaunchParseTests::ParseParameters(processOutput.outputResult);
- auto param1itr = argMap.find("param1");
- EXPECT_NE(param1itr, argMap.end());
- AZStd::vector<AZStd::string> param1{ param1itr->second };
- EXPECT_EQ(param1.size(), 1);
- EXPECT_EQ(param1[0], "param, 1val");
- auto param2itr = argMap.find("param2");
- EXPECT_NE(param2itr, argMap.end());
- AZStd::vector<AZStd::string> param2{ param2itr->second };
- EXPECT_EQ(param2.size(), 1);
- EXPECT_EQ(param2[0], "param,2v al");
- }
- } // namespace UnitTest
|