winget-cli

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

MsiExecArguments.cpp (8327B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "TestCommon.h"
      5 #include <winget/MsiExecArguments.h>
      6 #include <AppInstallerErrors.h>
      7 
      8 using namespace std::string_view_literals;
      9 using namespace AppInstaller;
     10 
     11 TEST_CASE("MsiExecArgs_ParseEmpty", "[msiexec]")
     12 {
     13     std::vector<std::string_view> emptyArguments = { ""sv, "  ", "\t" };
     14 
     15     for (const auto argString : emptyArguments)
     16     {
     17         auto args = Msi::ParseMSIArguments(argString);
     18         REQUIRE(!args.LogFile.has_value());
     19         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
     20         REQUIRE(args.Properties.empty());
     21     }
     22 }
     23 
     24 TEST_CASE("MsiExecArgs_ParseUILevel", "[msiexec]")
     25 {
     26     {
     27         auto args = Msi::ParseMSIArguments("/qn"sv);
     28         REQUIRE(!args.LogFile.has_value());
     29         REQUIRE(args.UILevel == (INSTALLUILEVEL_NONE | INSTALLUILEVEL_UACONLY));
     30         REQUIRE(args.Properties.empty());
     31     }
     32 
     33     {
     34         auto args = Msi::ParseMSIArguments("/qb+"sv);
     35         REQUIRE(!args.LogFile.has_value());
     36         REQUIRE(args.UILevel == (INSTALLUILEVEL_BASIC | INSTALLUILEVEL_ENDDIALOG));
     37         REQUIRE(args.Properties.empty());
     38     }
     39 
     40     {
     41         auto args = Msi::ParseMSIArguments("/q"sv);
     42         REQUIRE(!args.LogFile.has_value());
     43         REQUIRE(args.UILevel == (INSTALLUILEVEL_NONE | INSTALLUILEVEL_UACONLY));
     44         REQUIRE(args.Properties.empty());
     45     }
     46 
     47     {
     48         auto args = Msi::ParseMSIArguments("/qr"sv);
     49         REQUIRE(!args.LogFile.has_value());
     50         REQUIRE(args.UILevel == (INSTALLUILEVEL_REDUCED));
     51         REQUIRE(args.Properties.empty());
     52     }
     53 
     54     REQUIRE_THROWS_HR(Msi::ParseMSIArguments("/qr-"sv), APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT);
     55     REQUIRE_THROWS_HR(Msi::ParseMSIArguments("/q arg"sv), APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT);
     56 }
     57 
     58 TEST_CASE("MsiExecArgs_ParseLogMode", "[msiexec]")
     59 {
     60     {
     61         auto args = Msi::ParseMSIArguments("/l file.txt"sv);
     62         REQUIRE(args.LogMode == Msi::DefaultLogMode);
     63         REQUIRE(args.LogAttributes == 0);
     64         REQUIRE(args.LogFile == L"file.txt"sv);
     65         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
     66         REQUIRE(args.Properties.empty());
     67     }
     68 
     69     {
     70         auto args = Msi::ParseMSIArguments("/le errors.txt"sv);
     71         REQUIRE(args.LogMode == INSTALLLOGMODE_ERROR);
     72         REQUIRE(args.LogAttributes == 0);
     73         REQUIRE(args.LogFile == L"errors.txt"sv);
     74         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
     75         REQUIRE(args.Properties.empty());
     76     }
     77 
     78     {
     79         auto args = Msi::ParseMSIArguments("/l! flush.txt"sv);
     80         REQUIRE(args.LogMode == Msi::DefaultLogMode);
     81         REQUIRE(args.LogAttributes == INSTALLLOGATTRIBUTES_FLUSHEACHLINE);
     82         REQUIRE(args.LogFile == L"flush.txt"sv);
     83         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
     84         REQUIRE(args.Properties.empty());
     85     }
     86 
     87     {
     88         auto args = Msi::ParseMSIArguments("/l\"i\" \"quoted path.txt\""sv);
     89         REQUIRE(args.LogMode == INSTALLLOGMODE_INFO);
     90         REQUIRE(args.LogAttributes == 0);
     91         REQUIRE(args.LogFile == L"quoted path.txt"sv);
     92         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
     93         REQUIRE(args.Properties.empty());
     94     }
     95 
     96     {
     97         auto args = Msi::ParseMSIArguments("/liwpx+! log.txt"sv);
     98         REQUIRE(args.LogMode == (INSTALLLOGMODE_INFO | INSTALLLOGMODE_WARNING | INSTALLLOGMODE_PROPERTYDUMP | INSTALLLOGMODE_EXTRADEBUG));
     99         REQUIRE(args.LogAttributes == (INSTALLLOGATTRIBUTES_FLUSHEACHLINE | INSTALLLOGATTRIBUTES_APPEND));
    100         REQUIRE(args.LogFile == L"log.txt"sv);
    101         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
    102         REQUIRE(args.Properties.empty());
    103     }
    104 
    105     {
    106         auto args = Msi::ParseMSIArguments("/l* all.txt"sv);
    107         REQUIRE(args.LogMode == Msi::AllLogMode);
    108         REQUIRE(args.LogAttributes == 0);
    109         REQUIRE(args.LogFile == L"all.txt"sv);
    110         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
    111         REQUIRE(args.Properties.empty());
    112     }
    113 
    114     {
    115         auto args = Msi::ParseMSIArguments("/l* \"without closing quote.txt"sv);
    116         REQUIRE(args.LogMode == Msi::AllLogMode);
    117         REQUIRE(args.LogAttributes == 0);
    118         REQUIRE(args.LogFile == L"without closing quote.txt"sv);
    119         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
    120         REQUIRE(args.Properties.empty());
    121     }
    122 
    123     REQUIRE_THROWS_HR(Msi::ParseMSIArguments("/l"sv), APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT);
    124     REQUIRE_THROWS_HR(Msi::ParseMSIArguments("/lz log.txt"sv), APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT);
    125 }
    126 
    127 TEST_CASE("MsiExecArgs_ParseProperties", "[msiexec]")
    128 {
    129     {
    130         auto args = Msi::ParseMSIArguments("PROPERTY=value"sv);
    131         REQUIRE(!args.LogFile.has_value());
    132         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
    133         REQUIRE(args.Properties == L" PROPERTY=value"sv);
    134     }
    135 
    136     {
    137         auto args = Msi::ParseMSIArguments("EMPTY="sv);
    138         REQUIRE(!args.LogFile.has_value());
    139         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
    140         REQUIRE(args.Properties == L" EMPTY="sv);
    141     }
    142 
    143     {
    144         auto args = Msi::ParseMSIArguments("PROPERTY=\"quoted value\""sv);
    145         REQUIRE(!args.LogFile.has_value());
    146         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
    147         REQUIRE(args.Properties == L" PROPERTY=\"quoted value\""sv);
    148     }
    149 
    150     {
    151         auto args = Msi::ParseMSIArguments("PROPERTY=\"escaped \"\" quotes\""sv);
    152         REQUIRE(!args.LogFile.has_value());
    153         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
    154         REQUIRE(args.Properties == L" PROPERTY=\"escaped \"\" quotes\""sv);
    155     }
    156 
    157     {
    158         auto args = Msi::ParseMSIArguments("PROPERTY1=value1       PROPERTY2=value2"sv);
    159         REQUIRE(!args.LogFile.has_value());
    160         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
    161         REQUIRE(args.Properties == L" PROPERTY1=value1 PROPERTY2=value2"sv);
    162     }
    163 
    164     REQUIRE_THROWS_HR(Msi::ParseMSIArguments("NOSEPARATOR"sv), APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT);
    165     REQUIRE_THROWS_HR(Msi::ParseMSIArguments("$NOTAPROPERTY=value"sv), APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT);
    166     REQUIRE_THROWS_HR(Msi::ParseMSIArguments("PROPERTY=not quoted"sv), APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT);
    167     REQUIRE_THROWS_HR(Msi::ParseMSIArguments("PROPERTY=\"bad \"internal\" quotes\""sv), APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT);
    168     REQUIRE_THROWS_HR(Msi::ParseMSIArguments("PROPERTY=\"mismatched quote"sv), APPINSTALLER_CLI_ERROR_INVALID_MSIEXEC_ARGUMENT);
    169 }
    170 
    171 TEST_CASE("MsiExecArgs_ParseMultipleOptions", "[msiexec]")
    172 {
    173     {
    174         auto args = Msi::ParseMSIArguments("/li first.txt /le second.txt"sv);
    175         REQUIRE(args.LogMode == INSTALLLOGMODE_ERROR);
    176         REQUIRE(args.LogAttributes == 0);
    177         REQUIRE(args.LogFile == L"second.txt"sv);
    178         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
    179         REQUIRE(args.Properties.empty());
    180     }
    181 
    182     {
    183         auto args = Msi::ParseMSIArguments("PROPERTY1=value1 /qb  PROPERTY2= /lw file.txt"sv);
    184         REQUIRE(args.LogMode == INSTALLLOGMODE_WARNING);
    185         REQUIRE(args.LogAttributes == 0);
    186         REQUIRE(args.LogFile == L"file.txt"sv);
    187         REQUIRE(args.UILevel == INSTALLUILEVEL_BASIC);
    188         REQUIRE(args.Properties == L" PROPERTY1=value1 PROPERTY2=");
    189     }
    190 }
    191 
    192 TEST_CASE("MsiExecArgs_ParseLongOptions", "[msiexec]")
    193 {
    194     {
    195         auto args = Msi::ParseMSIArguments("/quiet"sv);
    196         REQUIRE(!args.LogFile.has_value());
    197         REQUIRE(args.UILevel == (INSTALLUILEVEL_NONE | INSTALLUILEVEL_UACONLY));
    198         REQUIRE(args.Properties.empty());
    199     }
    200 
    201     {
    202         auto args = Msi::ParseMSIArguments("/passive"sv);
    203         REQUIRE(!args.LogFile.has_value());
    204         REQUIRE(args.UILevel == (INSTALLUILEVEL_BASIC | INSTALLUILEVEL_PROGRESSONLY | INSTALLUILEVEL_HIDECANCEL));
    205         REQUIRE(args.Properties == L" REBOOTPROMPT=S"sv);
    206     }
    207 
    208     {
    209         auto args = Msi::ParseMSIArguments("/NoRestart"sv);
    210         REQUIRE(!args.LogFile.has_value());
    211         REQUIRE(args.UILevel == INSTALLUILEVEL_DEFAULT);
    212         REQUIRE(args.Properties == L" REBOOT=ReallySuppress"sv);
    213     }
    214 }