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 }