winget-cli

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

PortableInstaller.cpp (11371B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "TestCommon.h"
      5 #include <PortableInstaller.h>
      6 #include <Public/AppInstallerArchitecture.h>
      7 #include <winget/Filesystem.h>
      8 #include <winget/Manifest.h>
      9 #include <winget/PathVariable.h>
     10 #include <winget/PortableARPEntry.h>
     11 #include <winget/SQLiteStorageBase.h>
     12 #include <Microsoft/Schema/IPortableIndex.h>
     13 #include <winget/PortableIndex.h>
     14 
     15 using namespace std::string_literals;
     16 using namespace AppInstaller::CLI::Portable;
     17 using namespace AppInstaller::Filesystem;
     18 using namespace AppInstaller::Manifest;
     19 using namespace AppInstaller::Registry::Environment;
     20 using namespace AppInstaller::Repository::Microsoft;
     21 using namespace AppInstaller::SQLite;
     22 using namespace AppInstaller::Repository::Microsoft::Schema;
     23 using namespace AppInstaller::Utility;
     24 using namespace AppInstaller::CLI::Workflow;
     25 using namespace TestCommon;
     26 
     27 TEST_CASE("PortableInstaller_InstallToRegistry", "[PortableInstaller]")
     28 {
     29     TempDirectory tempDirectory = TestCommon::TempDirectory("TempDirectory", false);
     30 
     31     std::vector<PortableFileEntry> desiredTestState;
     32 
     33     TestCommon::TempFile testPortable("testPortable.txt");
     34     std::ofstream file(testPortable, std::ofstream::out);
     35     file.close();
     36 
     37     std::filesystem::path targetPath = tempDirectory.GetPath() / "testPortable.txt";
     38     std::filesystem::path symlinkPath = tempDirectory.GetPath() / "testSymlink.exe";
     39 
     40     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateFileEntry(testPortable.GetPath(), targetPath, {})));
     41     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateSymlinkEntry(symlinkPath, targetPath)));
     42 
     43     PortableInstaller portableInstaller = PortableInstaller(ScopeEnum::User, Architecture::X64, "testProductCode");
     44     portableInstaller.TargetInstallLocation = tempDirectory.GetPath();
     45     portableInstaller.SetDesiredState(desiredTestState);
     46     REQUIRE(portableInstaller.VerifyExpectedState());
     47 
     48     portableInstaller.Install(AppInstaller::CLI::Workflow::OperationType::Install);
     49 
     50     auto entry = portableInstaller.GetAppsAndFeaturesEntry();
     51     REQUIRE(entry.ProductCode == portableInstaller.GetProductCode());
     52 
     53     PortableInstaller portableInstaller2 = PortableInstaller(ScopeEnum::User, Architecture::X64, "testProductCode");
     54     REQUIRE(portableInstaller2.ARPEntryExists());
     55     REQUIRE(std::filesystem::exists(portableInstaller2.PortableTargetFullPath));
     56     REQUIRE(AppInstaller::Filesystem::SymlinkExists(portableInstaller2.PortableSymlinkFullPath));
     57 
     58     portableInstaller2.Uninstall();
     59     REQUIRE_FALSE(std::filesystem::exists(portableInstaller2.PortableTargetFullPath));
     60     REQUIRE_FALSE(AppInstaller::Filesystem::SymlinkExists(portableInstaller2.PortableSymlinkFullPath));
     61     REQUIRE_FALSE(std::filesystem::exists(portableInstaller2.InstallLocation));
     62 }
     63 
     64 TEST_CASE("PortableInstaller_InstallToIndex_CreateInstallRoot", "[PortableInstaller]")
     65 {
     66     TempDirectory installRootDirectory = TestCommon::TempDirectory("PortableInstallRoot", false);
     67 
     68     std::vector<PortableFileEntry> desiredTestState;
     69 
     70     TestCommon::TempFile testPortable("testPortable.txt");
     71     std::ofstream file1(testPortable, std::ofstream::out);
     72     file1.close();
     73 
     74     TestCommon::TempFile testPortable2("testPortable2.txt");
     75     std::ofstream file2(testPortable2, std::ofstream::out);
     76     file2.close();
     77 
     78     TestCommon::TempDirectory testDirectoryFolder("testDirectory", true);
     79 
     80     std::filesystem::path installRootPath = installRootDirectory.GetPath();
     81     std::filesystem::path targetPath = installRootPath / "testPortable.txt";
     82     std::filesystem::path targetPath2 = installRootPath / "testPortable2.txt";
     83     std::filesystem::path symlinkPath = installRootPath / "testSymlink.exe";
     84     std::filesystem::path symlinkPath2 = installRootPath / "testSymlink2.exe";
     85     std::filesystem::path directoryPath = installRootPath / "testDirectory";
     86 
     87     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateFileEntry(testPortable.GetPath(), targetPath, {})));
     88     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateFileEntry(testPortable2.GetPath(), targetPath2, {})));
     89     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateSymlinkEntry(symlinkPath, targetPath)));
     90     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateSymlinkEntry(symlinkPath2, targetPath2)));
     91     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateDirectoryEntry(testDirectoryFolder.GetPath(), directoryPath)));
     92 
     93     PortableInstaller portableInstaller = PortableInstaller(ScopeEnum::User, Architecture::X64, "testProductCode");
     94     portableInstaller.TargetInstallLocation = installRootDirectory.GetPath();
     95     portableInstaller.RecordToIndex = true;
     96     portableInstaller.SetDesiredState(desiredTestState);
     97     REQUIRE(portableInstaller.VerifyExpectedState());
     98 
     99     portableInstaller.Install(AppInstaller::CLI::Workflow::OperationType::Install);
    100 
    101     REQUIRE(std::filesystem::exists(installRootPath / portableInstaller.GetPortableIndexFileName()));
    102     REQUIRE(std::filesystem::exists(targetPath));
    103     REQUIRE(std::filesystem::exists(targetPath2));
    104     REQUIRE(AppInstaller::Filesystem::SymlinkExists(symlinkPath));
    105     REQUIRE(AppInstaller::Filesystem::SymlinkExists(symlinkPath2));
    106     REQUIRE(std::filesystem::exists(directoryPath));
    107 
    108     PortableInstaller portableInstaller2 = PortableInstaller(ScopeEnum::User, Architecture::X64, "testProductCode");
    109     REQUIRE(portableInstaller2.ARPEntryExists());
    110 
    111     portableInstaller2.Uninstall();
    112 
    113     // Install root directory should be removed since it was created.
    114     REQUIRE_FALSE(std::filesystem::exists(installRootPath));
    115     REQUIRE_FALSE(std::filesystem::exists(targetPath));
    116     REQUIRE_FALSE(std::filesystem::exists(targetPath2));
    117     REQUIRE_FALSE(AppInstaller::Filesystem::SymlinkExists(symlinkPath));
    118     REQUIRE_FALSE(AppInstaller::Filesystem::SymlinkExists(symlinkPath2));
    119     REQUIRE_FALSE(std::filesystem::exists(directoryPath));
    120 }
    121 
    122 TEST_CASE("PortableInstaller_InstallToIndex_ExistingInstallRoot", "[PortableInstaller]")
    123 {
    124     TempDirectory installRootDirectory = TestCommon::TempDirectory("PortableInstallRoot", true);
    125 
    126     std::vector<PortableFileEntry> desiredTestState;
    127 
    128     TestCommon::TempFile testPortable("testPortable.txt");
    129     std::ofstream file1(testPortable, std::ofstream::out);
    130     file1.close();
    131 
    132     TestCommon::TempFile testPortable2("testPortable2.txt");
    133     std::ofstream file2(testPortable2, std::ofstream::out);
    134     file2.close();
    135 
    136     TestCommon::TempDirectory testDirectoryFolder("testDirectory", true);
    137 
    138     std::filesystem::path installRootPath = installRootDirectory.GetPath();
    139     std::filesystem::path targetPath = installRootPath / "testPortable.txt";
    140     std::filesystem::path targetPath2 = installRootPath / "testPortable2.txt";
    141     std::filesystem::path symlinkPath = installRootPath / "testSymlink.exe";
    142     std::filesystem::path symlinkPath2 = installRootPath / "testSymlink2.exe";
    143     std::filesystem::path directoryPath = installRootPath / "testDirectory";
    144 
    145     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateFileEntry(testPortable.GetPath(), targetPath, {})));
    146     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateFileEntry(testPortable2.GetPath(), targetPath2, {})));
    147     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateSymlinkEntry(symlinkPath, targetPath)));
    148     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateSymlinkEntry(symlinkPath2, targetPath2)));
    149     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateDirectoryEntry(testDirectoryFolder.GetPath(), directoryPath)));
    150 
    151     PortableInstaller portableInstaller = PortableInstaller(ScopeEnum::User, Architecture::X64, "testProductCode");
    152     portableInstaller.TargetInstallLocation = installRootDirectory.GetPath();
    153     portableInstaller.RecordToIndex = true;
    154     portableInstaller.SetDesiredState(desiredTestState);
    155     REQUIRE(portableInstaller.VerifyExpectedState());
    156 
    157     portableInstaller.Install(AppInstaller::CLI::Workflow::OperationType::Install);
    158 
    159     REQUIRE(std::filesystem::exists(installRootPath / portableInstaller.GetPortableIndexFileName()));
    160     REQUIRE(std::filesystem::exists(targetPath));
    161     REQUIRE(std::filesystem::exists(targetPath2));
    162     REQUIRE(AppInstaller::Filesystem::SymlinkExists(symlinkPath));
    163     REQUIRE(AppInstaller::Filesystem::SymlinkExists(symlinkPath2));
    164     REQUIRE(std::filesystem::exists(directoryPath));
    165 
    166     PortableInstaller portableInstaller2 = PortableInstaller(ScopeEnum::User, Architecture::X64, "testProductCode");
    167     REQUIRE(portableInstaller2.ARPEntryExists());
    168 
    169     portableInstaller2.Uninstall();
    170 
    171     // Install root directory should still exist since it was created previously.
    172     REQUIRE(std::filesystem::exists(installRootPath));
    173     REQUIRE_FALSE(std::filesystem::exists(targetPath));
    174     REQUIRE_FALSE(std::filesystem::exists(targetPath2));
    175     REQUIRE_FALSE(AppInstaller::Filesystem::SymlinkExists(symlinkPath));
    176     REQUIRE_FALSE(AppInstaller::Filesystem::SymlinkExists(symlinkPath2));
    177     REQUIRE_FALSE(std::filesystem::exists(directoryPath));
    178 }
    179 
    180 TEST_CASE("PortableInstaller_UnicodeSymlinkPath", "[PortableInstaller]")
    181 {
    182     TempDirectory tempDirectory = TestCommon::TempDirectory("TempDirectory", false);
    183 
    184     // Modify install location path to include unicode characters.
    185     std::filesystem::path testInstallLocation = tempDirectory.GetPath() / std::filesystem::path{ ConvertToUTF16("романтический") };
    186 
    187     std::vector<PortableFileEntry> desiredTestState;
    188 
    189     TestCommon::TempFile testPortable("testPortable.txt");
    190     std::ofstream file(testPortable, std::ofstream::out);
    191     file.close();
    192 
    193     std::filesystem::path targetPath = testInstallLocation / "testPortable.txt";
    194     std::filesystem::path symlinkPath = tempDirectory.GetPath() / "testSymlink.exe";
    195 
    196     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateFileEntry(testPortable.GetPath(), targetPath, {})));
    197     desiredTestState.emplace_back(std::move(PortableFileEntry::CreateSymlinkEntry(symlinkPath, targetPath)));
    198 
    199     PortableInstaller portableInstaller = PortableInstaller(ScopeEnum::User, Architecture::X64, "testProductCode");
    200     portableInstaller.TargetInstallLocation = testInstallLocation;
    201     portableInstaller.SetDesiredState(desiredTestState);
    202     REQUIRE(portableInstaller.VerifyExpectedState());
    203 
    204     portableInstaller.Install(AppInstaller::CLI::Workflow::OperationType::Install);
    205 
    206     PortableInstaller portableInstaller2 = PortableInstaller(ScopeEnum::User, Architecture::X64, "testProductCode");
    207     REQUIRE(portableInstaller2.ARPEntryExists());
    208     REQUIRE(std::filesystem::exists(portableInstaller2.PortableTargetFullPath));
    209     REQUIRE(AppInstaller::Filesystem::SymlinkExists(portableInstaller2.PortableSymlinkFullPath));
    210 
    211     portableInstaller2.Uninstall();
    212     REQUIRE_FALSE(std::filesystem::exists(portableInstaller2.PortableTargetFullPath));
    213     REQUIRE_FALSE(AppInstaller::Filesystem::SymlinkExists(portableInstaller2.PortableSymlinkFullPath));
    214     REQUIRE_FALSE(std::filesystem::exists(portableInstaller2.InstallLocation));
    215 }