Settings.cpp (8145B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "TestCommon.h" 5 6 #include <AppInstallerRuntime.h> 7 #include <AppInstallerStrings.h> 8 #include <winget/Settings.h> 9 10 using namespace AppInstaller::Runtime; 11 using namespace AppInstaller::Settings; 12 using namespace AppInstaller::Utility; 13 14 TEST_CASE("ReadEmptySetting", "[settings]") 15 { 16 StreamDefinition name{ Type::Standard, "nonexistentsetting" }; 17 18 auto result = Stream{ name }.Get(); 19 REQUIRE(!result); 20 } 21 22 TEST_CASE("SetAndReadSetting", "[settings]") 23 { 24 StreamDefinition name{ Type::Standard, "testsettingname" }; 25 std::string value = "This is the test setting value"; 26 27 Stream stream{ name }; 28 REQUIRE(stream.Set(value)); 29 30 auto result = stream.Get(); 31 REQUIRE(static_cast<bool>(result)); 32 33 std::string settingValue = ReadEntireStream(*result); 34 REQUIRE(value == settingValue); 35 } 36 37 TEST_CASE("SetAndReadSettingInContainer", "[settings]") 38 { 39 StreamDefinition name{ Type::Standard, "testcontainer/testsettingname" }; 40 std::string value = "This is the test setting value from inside a container"; 41 42 Stream stream{ name }; 43 REQUIRE(stream.Set(value)); 44 45 auto result = stream.Get(); 46 REQUIRE(static_cast<bool>(result)); 47 48 std::string settingValue = ReadEntireStream(*result); 49 REQUIRE(value == settingValue); 50 } 51 52 TEST_CASE("RemoveSetting", "[settings]") 53 { 54 StreamDefinition name{ Type::Standard, "testsettingname" }; 55 std::string value = "This is the test setting value to be removed"; 56 57 Stream stream{ name }; 58 REQUIRE(stream.Set(value)); 59 60 { 61 auto result = stream.Get(); 62 REQUIRE(static_cast<bool>(result)); 63 64 std::string settingValue = ReadEntireStream(*result); 65 REQUIRE(value == settingValue); 66 } 67 68 stream.Remove(); 69 70 auto result = stream.Get(); 71 REQUIRE(!static_cast<bool>(result)); 72 } 73 74 TEST_CASE("SetAndReadUserFileSetting", "[settings]") 75 { 76 StreamDefinition name{ Type::UserFile, "userfilesetting" }; 77 std::string value = "This is the test setting value for a user file"; 78 79 Stream stream{ name }; 80 REQUIRE(stream.Set(value)); 81 82 auto result = stream.Get(); 83 REQUIRE(static_cast<bool>(result)); 84 85 std::string settingValue = ReadEntireStream(*result); 86 REQUIRE(value == settingValue); 87 } 88 89 TEST_CASE("ReadEmptySecureSetting", "[settings]") 90 { 91 StreamDefinition name{ Type::Secure, "secure_nonexistentsetting" }; 92 93 auto result = Stream{ name }.Get(); 94 REQUIRE(!result); 95 } 96 97 TEST_CASE("SetAndReadSecureSetting", "[settings]") 98 { 99 StreamDefinition name{ Type::Secure, "secure_testsettingname" }; 100 std::string value = "This is the test setting value"; 101 102 Stream stream{ name }; 103 REQUIRE(stream.Set(value)); 104 105 auto result = stream.Get(); 106 REQUIRE(static_cast<bool>(result)); 107 108 std::string settingValue = ReadEntireStream(*result); 109 REQUIRE(value == settingValue); 110 } 111 112 TEST_CASE("SetAndReadSecureSettingInContainer", "[settings]") 113 { 114 StreamDefinition name{ Type::Secure, "testcontainer/secure_testsettingname" }; 115 std::string value = "This is the test setting value from inside a container"; 116 117 Stream stream{ name }; 118 REQUIRE(stream.Set(value)); 119 120 auto result = stream.Get(); 121 REQUIRE(static_cast<bool>(result)); 122 123 std::string settingValue = ReadEntireStream(*result); 124 REQUIRE(value == settingValue); 125 } 126 127 TEST_CASE("RemoveSecureSetting", "[settings]") 128 { 129 StreamDefinition name{ Type::Secure, "secure_testsettingname" }; 130 std::string value = "This is the test setting value to be removed"; 131 132 Stream stream{ name }; 133 REQUIRE(stream.Set(value)); 134 135 { 136 auto result = stream.Get(); 137 REQUIRE(static_cast<bool>(result)); 138 139 std::string settingValue = ReadEntireStream(*result); 140 REQUIRE(value == settingValue); 141 } 142 143 stream.Remove(); 144 145 auto result = stream.Get(); 146 REQUIRE(!static_cast<bool>(result)); 147 } 148 149 TEST_CASE("SetAndReadSecureSetting_SecureDataRemoved", "[settings]") 150 { 151 StreamDefinition name{ Type::Secure, "secure_testsettingname" }; 152 std::string value = "This is the test setting value"; 153 154 Stream stream{ name }; 155 REQUIRE(stream.Set(value)); 156 157 auto result = stream.Get(); 158 REQUIRE(static_cast<bool>(result)); 159 160 std::string settingValue = ReadEntireStream(*result); 161 REQUIRE(value == settingValue); 162 163 std::filesystem::remove(GetPathTo(PathName::SecureSettingsForRead) / name.Name); 164 165 REQUIRE_THROWS_HR(stream.Get(), SPAPI_E_FILE_HASH_NOT_IN_CATALOG); 166 } 167 168 TEST_CASE("SetAndReadSecureSetting_DataTampered", "[settings]") 169 { 170 StreamDefinition name{ Type::Secure, "secure_testsettingname" }; 171 std::string value = "This is the test setting value"; 172 173 Stream stream{ name }; 174 REQUIRE(stream.Set(value)); 175 176 auto result = stream.Get(); 177 REQUIRE(static_cast<bool>(result)); 178 179 std::string settingValue = ReadEntireStream(*result); 180 REQUIRE(value == settingValue); 181 182 StreamDefinition insecureName = name; 183 insecureName.Type = Type::Standard; 184 185 REQUIRE(Stream{ insecureName }.Set("Tampered data")); 186 187 REQUIRE_THROWS_HR(stream.Get(), HRESULT_FROM_WIN32(ERROR_DATA_CHECKSUM_ERROR)); 188 } 189 190 TEST_CASE("SetChangeAndReadSetting", "[settings]") 191 { 192 StreamDefinition name{ Type::Standard, "testsettingname" }; 193 std::string value1 = "This is the test setting value1"; 194 std::string value2 = "This is the test setting value2, which is different"; 195 std::string value3 = "This is the test setting value3; also different"; 196 197 name.Type = GENERATE(Type::Standard, Type::Secure); 198 INFO(ToString(name.Type)); 199 200 // Set the value on stream 1 201 Stream stream1{ name }; 202 REQUIRE(stream1.Set(value1)); 203 204 // Read the value on stream 2 to verify 205 { 206 Stream stream2{ name }; 207 208 auto result = stream2.Get(); 209 REQUIRE(static_cast<bool>(result)); 210 211 std::string settingValue = ReadEntireStream(*result); 212 REQUIRE(value1 == settingValue); 213 214 // Set the value on stream 2 215 REQUIRE(stream2.Set(value2)); 216 } 217 218 // Attempt to set the value on stream 1 again 219 REQUIRE(!stream1.Set(value3)); 220 221 // Attempting to set again should still not work 222 REQUIRE(!stream1.Set(value3)); 223 224 // Ensure that the value remains value 2 225 auto result = stream1.Get(); 226 REQUIRE(static_cast<bool>(result)); 227 228 std::string settingValue = ReadEntireStream(*result); 229 REQUIRE(value2 == settingValue); 230 231 // Now that we have read it, we can update it 232 REQUIRE(stream1.Set(value3)); 233 234 result = stream1.Get(); 235 REQUIRE(static_cast<bool>(result)); 236 237 settingValue = ReadEntireStream(*result); 238 REQUIRE(value3 == settingValue); 239 } 240 241 TEST_CASE("AttemptSetOnNewValue", "[settings]") 242 { 243 StreamDefinition name{ Type::Standard, "testsettingname" }; 244 std::string value1 = "This is the test setting value1"; 245 std::string value2 = "This is the test setting value2, which is different"; 246 247 name.Type = GENERATE(Type::Standard, Type::Secure); 248 INFO(ToString(name.Type)); 249 250 // Remove the stream 251 Stream{ name }.Remove(); 252 253 Stream stream1{ name }; 254 REQUIRE(!stream1.Get()); 255 256 // Set the value on stream 2 257 { 258 Stream stream2{ name }; 259 REQUIRE(stream2.Set(value1)); 260 } 261 262 // Attempt to set the value on stream 1 again 263 REQUIRE(!stream1.Set(value2)); 264 265 // Attempting to set again should still not work 266 REQUIRE(!stream1.Set(value2)); 267 268 // Ensure that the value remains value 2 269 auto result = stream1.Get(); 270 REQUIRE(static_cast<bool>(result)); 271 272 std::string settingValue = ReadEntireStream(*result); 273 REQUIRE(value1 == settingValue); 274 275 // Now that we have read it, we can update it 276 REQUIRE(stream1.Set(value2)); 277 278 result = stream1.Get(); 279 REQUIRE(static_cast<bool>(result)); 280 281 settingValue = ReadEntireStream(*result); 282 REQUIRE(value2 == settingValue); 283 }