winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

PromptFlow.cpp (7051B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "WorkflowCommon.h"
      5 #include <Commands/InstallCommand.h>
      6 #include <Workflows/PromptFlow.h>
      7 
      8 using namespace TestCommon;
      9 using namespace AppInstaller::CLI;
     10 using namespace AppInstaller::Settings;
     11 
     12 TEST_CASE("PromptFlow_InteractivityDisabled", "[PromptFlow][workflow]")
     13 {
     14     TestCommon::TempFile installResultPath("TestExeInstalled.txt");
     15     TestCommon::TestUserSettings testSettings;
     16 
     17     std::ostringstream installOutput;
     18     TestContext context{ installOutput, std::cin };
     19     auto previousThreadGlobals = context.SetForCurrentThread();
     20     context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_LicenseAgreement.yaml").GetPath().u8string());
     21 
     22     SECTION("Disabled by setting")
     23     {
     24         testSettings.Set<Setting::InteractivityDisable>(true);
     25     }
     26     SECTION("Disabled by arg")
     27     {
     28         context.Args.AddArg(Execution::Args::Type::DisableInteractivity);
     29     }
     30 
     31     InstallCommand install({});
     32     install.Execute(context);
     33     INFO(installOutput.str());
     34 
     35     // Verify prompt is not shown
     36     REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::PackageAgreementsPrompt).get()) == std::string::npos);
     37 
     38     // Verify installation failed
     39     REQUIRE_TERMINATED_WITH(context, APPINSTALLER_CLI_ERROR_PACKAGE_AGREEMENTS_NOT_ACCEPTED);
     40     REQUIRE_FALSE(std::filesystem::exists(installResultPath.GetPath()));
     41     REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::PackageAgreementsNotAgreedTo).get()) != std::string::npos);
     42 }
     43 
     44 TEST_CASE("PromptFlow_InstallerAbortsTerminal_Proceed", "[PromptFlow][workflow]")
     45 {
     46     TestCommon::TempFile installResultPath("TestExeInstalled.txt");
     47 
     48     // Accept that the installer may abort the terminal by saying "Yes" at the prompt
     49     std::istringstream installInput{ "y" };
     50 
     51     std::ostringstream installOutput;
     52     TestContext context{ installOutput, installInput };
     53     auto previousThreadGlobals = context.SetForCurrentThread();
     54     OverrideForShellExecute(context);
     55     context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_AbortsTerminal.yaml").GetPath().u8string());
     56 
     57     InstallCommand install({});
     58     install.Execute(context);
     59     INFO(installOutput.str());
     60 
     61     // Verify prompt is shown
     62     REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::InstallerAbortsTerminal).get()) != std::string::npos);
     63 
     64     // Verify Installer is called.
     65     REQUIRE(std::filesystem::exists(installResultPath.GetPath()));
     66 }
     67 
     68 TEST_CASE("PromptFlow_InstallerAbortsTerminal_Cancel", "[PromptFlow][workflow]")
     69 {
     70     TestCommon::TempFile installResultPath("TestExeInstalled.txt");
     71 
     72     // Cancel the installation by saying "No" at the prompt that the installer may abort the terminal
     73     std::istringstream installInput{ "n" };
     74 
     75     std::ostringstream installOutput;
     76     TestContext context{ installOutput, installInput };
     77     auto previousThreadGlobals = context.SetForCurrentThread();
     78     context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_AbortsTerminal.yaml").GetPath().u8string());
     79 
     80     InstallCommand install({});
     81     install.Execute(context);
     82     INFO(installOutput.str());
     83 
     84     // Verify prompt is shown
     85     REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::InstallerAbortsTerminal).get()) != std::string::npos);
     86 
     87     // Verify installation failed
     88     REQUIRE_TERMINATED_WITH(context, E_ABORT);
     89     REQUIRE_FALSE(std::filesystem::exists(installResultPath.GetPath()));
     90 }
     91 
     92 TEST_CASE("PromptFlow_InstallLocationRequired", "[PromptFlow][workflow]")
     93 {
     94     TestCommon::TempDirectory installLocation("TempDirectory");
     95     TestCommon::TestUserSettings testSettings;
     96 
     97     std::istringstream installInput;
     98     std::ostringstream installOutput;
     99     TestContext context{ installOutput, installInput };
    100     auto previousThreadGlobals = context.SetForCurrentThread();
    101     OverrideForShellExecute(context);
    102     context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_InstallLocationRequired.yaml").GetPath().u8string());
    103 
    104     bool shouldShowPrompt = false;
    105     std::filesystem::path installResultPath = installLocation.GetPath() / "TestExeInstalled.txt";
    106     SECTION("From argument")
    107     {
    108         context.Args.AddArg(Execution::Args::Type::InstallLocation, installLocation.GetPath().string());
    109     }
    110     SECTION("From settings")
    111     {
    112         testSettings.Set<Setting::InstallDefaultRoot>(installLocation.GetPath().string());
    113 
    114         // When using the default location from settings, the Package ID is appended to the root
    115         auto installLocationWithPackageId = installLocation.GetPath() / "AppInstallerCliTest.TestInstaller";
    116         std::filesystem::create_directory(installLocationWithPackageId);
    117         installResultPath = installLocationWithPackageId / "TestExeInstalled.txt";
    118     }
    119     SECTION("From prompt")
    120     {
    121         installInput.str(installLocation.GetPath().string());
    122         shouldShowPrompt = true;
    123     }
    124 
    125     InstallCommand install({});
    126     install.Execute(context);
    127     INFO(installOutput.str());
    128 
    129     bool promptShown = installOutput.str().find(Resource::LocString(Resource::String::InstallerRequiresInstallLocation).get()) != std::string::npos;
    130     REQUIRE(shouldShowPrompt == promptShown);
    131 
    132     // Verify Installer is called with the right parameters
    133     REQUIRE(std::filesystem::exists(installResultPath));
    134     std::ifstream installResultFile(installResultPath);
    135     REQUIRE(installResultFile.is_open());
    136     std::string installResultStr;
    137     std::getline(installResultFile, installResultStr);
    138     const auto installDirArgument = "/InstallDir " + installLocation.GetPath().string();
    139     REQUIRE(installResultStr.find(installDirArgument) != std::string::npos);
    140 }
    141 
    142 TEST_CASE("PromptFlow_InstallLocationRequired_Missing", "[PromptFlow][workflow]")
    143 {
    144     TestCommon::TempFile installResultPath("TestExeInstalled.txt");
    145 
    146     std::ostringstream installOutput;
    147     TestContext context{ installOutput, std::cin };
    148     auto previousThreadGlobals = context.SetForCurrentThread();
    149     context.Args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_InstallLocationRequired.yaml").GetPath().u8string());
    150     // Disable interactivity so that there is not prompt and we cannot get the required location
    151     context.Args.AddArg(Execution::Args::Type::DisableInteractivity);
    152 
    153     InstallCommand install({});
    154     install.Execute(context);
    155     INFO(installOutput.str());
    156 
    157     // Verify prompt is shown
    158     REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::InstallerRequiresInstallLocation).get()) != std::string::npos);
    159 
    160     // Verify installation failed
    161     REQUIRE_TERMINATED_WITH(context, APPINSTALLER_CLI_ERROR_INSTALL_LOCATION_REQUIRED);
    162     REQUIRE_FALSE(std::filesystem::exists(installResultPath.GetPath()));
    163 }