winget-cli

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

Dependencies.cpp (10742B)


      1 #include "pch.h"
      2 #include "TestCommon.h"
      3 #include "TestSource.h"
      4 #include "DependenciesTestSource.h"
      5 #include <winget/DependenciesGraph.h>
      6 #include <Workflows/DependencyNodeProcessor.h>
      7 #include <AppInstallerErrors.h>
      8 #include <AppInstallerRuntime.h>
      9 #include <AppInstallerStrings.h>
     10 #include <Workflows/DependenciesFlow.h>
     11 #include <Workflows/WorkflowBase.h>
     12 #include <winget/ManifestYamlParser.h>
     13 #include <winget/PathVariable.h>
     14 #include <winget/RepositorySource.h>
     15 #include <Resources.h>
     16 
     17 using namespace winrt::Windows::Foundation;
     18 using namespace winrt::Windows::Management::Deployment;
     19 using namespace TestCommon;
     20 using namespace AppInstaller::CLI;
     21 using namespace AppInstaller::CLI::Execution;
     22 using namespace AppInstaller::CLI::Workflow;
     23 using namespace AppInstaller::Logging;
     24 using namespace AppInstaller::Manifest;
     25 using namespace AppInstaller::Repository;
     26 using namespace AppInstaller::Settings;
     27 using namespace AppInstaller::Utility;
     28 using namespace AppInstaller::Utility::literals;
     29 
     30 TEST_CASE("DependencyGraph_BFirst", "[dependencyGraph][dependencies]")
     31 {
     32     TestCommon::TempFile installResultPath("TestExeInstalled.txt");
     33     std::vector<Dependency> installationOrder;
     34 
     35     const auto& manifest = CreateFakeManifestWithDependencies("NeedsToInstallBFirst");
     36     const auto& installers = manifest.Installers;
     37     const Dependency& rootAsDependency = Dependency(DependencyType::Package, manifest.Id);
     38     DependencyList rootDependencies;
     39     std::for_each(installers.begin(), installers.end(), [&](ManifestInstaller installer) { rootDependencies.Add(installer.Dependencies); });
     40 
     41     DependencyGraph graph(rootAsDependency, rootDependencies, [&](Dependency)
     42         {
     43             DependencyList dependencyList;
     44             auto dependencyManifest = CreateFakeManifestWithDependencies(manifest.Id);
     45 
     46             for (auto installer : dependencyManifest.Installers)
     47             {
     48                 dependencyList.Add(installer.Dependencies);
     49             }
     50 
     51             return dependencyList;
     52         });
     53 
     54     graph.BuildGraph();
     55 
     56     installationOrder = graph.GetInstallationOrder();
     57 
     58     REQUIRE(installationOrder.size() == 3);
     59     REQUIRE(installationOrder.at(0).Id() == "C");
     60     REQUIRE(installationOrder.at(1).Id() == "B");
     61     REQUIRE(installationOrder.at(2).Id() == "NeedsToInstallBFirst");
     62 }
     63 
     64 TEST_CASE("DependencyGraph_InStackNoLoop", "[dependencyGraph][dependencies]")
     65 {
     66     TestCommon::TempFile installResultPath("TestExeInstalled.txt");
     67     std::vector<Dependency> installationOrder;
     68 
     69     const auto& manifest = CreateFakeManifestWithDependencies("DependencyAlreadyInStackButNoLoop");
     70     const auto& installers = manifest.Installers;
     71     const Dependency& rootAsDependency = Dependency(DependencyType::Package, manifest.Id);
     72     DependencyList rootDependencies;
     73     std::for_each(installers.begin(), installers.end(), [&](ManifestInstaller installer) { rootDependencies.Add(installer.Dependencies); });
     74 
     75     DependencyGraph graph(rootAsDependency, rootDependencies, [&](Dependency)
     76         {
     77             DependencyList dependencyList;
     78             auto dependencyManifest = CreateFakeManifestWithDependencies(manifest.Id);
     79 
     80             for (auto installer : dependencyManifest.Installers)
     81             {
     82                 dependencyList.Add(installer.Dependencies);
     83             }
     84 
     85             return dependencyList;
     86         });
     87 
     88     graph.BuildGraph();
     89 
     90     installationOrder = graph.GetInstallationOrder();
     91 
     92     REQUIRE(installationOrder.size() == 3);
     93     REQUIRE(installationOrder.at(0).Id() == "F");
     94     REQUIRE(installationOrder.at(1).Id() == "C");
     95     REQUIRE(installationOrder.at(2).Id() == "DependencyAlreadyInStackButNoLoop");
     96 }
     97 
     98 TEST_CASE("DependencyGraph_EasyToSeeLoop", "[dependencyGraph][dependencies]")
     99 {
    100     TestCommon::TempFile installResultPath("TestExeInstalled.txt");
    101     std::vector<Dependency> installationOrder;
    102 
    103     const auto& manifest = CreateFakeManifestWithDependencies("EasyToSeeLoop");
    104     const auto& installers = manifest.Installers;
    105     const Dependency& rootAsDependency = Dependency(DependencyType::Package, manifest.Id);
    106     DependencyList rootDependencies;
    107     std::for_each(installers.begin(), installers.end(), [&](ManifestInstaller installer) { rootDependencies.Add(installer.Dependencies); });
    108 
    109     DependencyGraph graph(rootAsDependency, rootDependencies, [&](Dependency) {
    110         DependencyList dependencyList;
    111         auto dependencyManifest = CreateFakeManifestWithDependencies(manifest.Id);
    112 
    113         for (auto installer : dependencyManifest.Installers)
    114         {
    115             dependencyList.Add(installer.Dependencies);
    116         }
    117 
    118         return dependencyList;
    119         });
    120 
    121     graph.BuildGraph();
    122 
    123     installationOrder = graph.GetInstallationOrder();
    124 
    125     bool hasLoop = graph.HasLoop();
    126 
    127     REQUIRE(hasLoop);
    128 
    129     REQUIRE(installationOrder.size() == 2);
    130     REQUIRE(installationOrder.at(0).Id() == "D");
    131     REQUIRE(installationOrder.at(1).Id() == "EasyToSeeLoop");
    132 }
    133 
    134 TEST_CASE("DependencyNodeProcessor_SkipInstalled", "[dependencies]")
    135 {
    136     TestCommon::TempFile installResultPath("TestExeInstalled.txt");
    137 
    138     std::ostringstream installOutput;
    139     Context context{ installOutput, std::cin };
    140 
    141     Manifest manifest = CreateFakeManifestWithDependencies("installed1");
    142 
    143     context.Add<Execution::Data::DependencySource>(Source{ std::make_shared<DependenciesTestSource>() });
    144     DependencyNodeProcessor nodeProcessor(context);
    145 
    146     Dependency rootAsDependency(DependencyType::Package, manifest.Id);
    147 
    148     DependencyNodeProcessorResult result = nodeProcessor.EvaluateDependencies(rootAsDependency);
    149     REQUIRE(result == DependencyNodeProcessorResult::Skipped);
    150 }
    151 
    152 TEST_CASE("DependencyNodeProcessor_NoInstallers", "[dependencies]")
    153 {
    154     TestCommon::TempFile installResultPath("TestExeInstalled.txt");
    155 
    156     std::ostringstream installOutput;
    157     Context context { installOutput, std::cin };
    158 
    159     Manifest manifest = CreateFakeManifestWithDependencies("withoutInstallers");
    160 
    161     context.Add<Execution::Data::DependencySource>(Source{ std::make_shared<DependenciesTestSource>() });
    162     DependencyNodeProcessor nodeProcessor(context);
    163 
    164     Dependency rootAsDependency(DependencyType::Package, manifest.Id);
    165 
    166     DependencyNodeProcessorResult result = nodeProcessor.EvaluateDependencies(rootAsDependency);
    167     REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::DependenciesFlowNoInstallerFound("withoutInstallers"_liv))) != std::string::npos);
    168     REQUIRE(result == DependencyNodeProcessorResult::Error);
    169 }
    170 
    171 TEST_CASE("DependencyNodeProcessor_StackOrderIsOk", "[dependencies]")
    172 {
    173     TestCommon::TempFile installResultPath("TestExeInstalled.txt");
    174 
    175     std::ostringstream installOutput;
    176     Context context{ installOutput, std::cin };
    177 
    178     Manifest manifest = CreateFakeManifestWithDependencies("StackOrderIsOk");
    179 
    180     context.Add<Execution::Data::DependencySource>(Source{ std::make_shared<DependenciesTestSource>() });
    181     DependencyNodeProcessor nodeProcessor(context);
    182 
    183     Dependency rootAsDependency(DependencyType::Package, manifest.Id);
    184 
    185     DependencyNodeProcessorResult result = nodeProcessor.EvaluateDependencies(rootAsDependency);
    186     auto dependencyList = nodeProcessor.GetDependencyList();
    187     REQUIRE(dependencyList.Size() == 1);
    188     REQUIRE(dependencyList.HasDependency(Dependency(DependencyType::Package, "C")));
    189     REQUIRE(result == DependencyNodeProcessorResult::Success);
    190 }
    191 
    192 TEST_CASE("DependencyNodeProcessor_NoMatches", "[dependencies]")
    193 {
    194     TestCommon::TempFile installResultPath("TestExeInstalled.txt");
    195 
    196     std::ostringstream installOutput;
    197     Context context{ installOutput, std::cin };
    198 
    199     Manifest manifest = CreateFakeManifestWithDependencies("NoMatches");
    200 
    201     context.Add<Execution::Data::DependencySource>(Source{ std::make_shared<DependenciesTestSource>() });
    202     DependencyNodeProcessor nodeProcessor(context);
    203 
    204     Dependency rootAsDependency(DependencyType::Package, manifest.Id);
    205 
    206     DependencyNodeProcessorResult result = nodeProcessor.EvaluateDependencies(rootAsDependency);
    207     auto dependencyList = nodeProcessor.GetDependencyList();
    208     REQUIRE(dependencyList.Size() == 0);
    209     REQUIRE(installOutput.str().find(Resource::LocString(Resource::String::DependenciesFlowNoMatches)) != std::string::npos);
    210     REQUIRE(result == DependencyNodeProcessorResult::Error);
    211 }
    212 
    213 TEST_CASE("DependencyList_Add_MinVersion", "[dependencies]")
    214 {
    215     DependencyType type = DependencyType::Package;
    216     std::string identifier = "Identifier";
    217 
    218     DependencyList list;
    219     Dependency dependencyWithoutMinVersion{ type, identifier };
    220     Dependency dependencyWithLowerMinVersion{ type, identifier, "1.0" };
    221     Dependency dependencyWithHigherMinVersion{ type, identifier, "3.0" };
    222 
    223     Dependency dependencyToAdd{ type, identifier, "2.0" };
    224 
    225     SECTION("Existing dependency has no min version, added does")
    226     {
    227         list.Add(dependencyWithoutMinVersion);
    228         list.Add(dependencyToAdd);
    229 
    230         const Dependency* dependency = list.HasDependency(dependencyToAdd);
    231         REQUIRE(dependency != nullptr);
    232         REQUIRE(dependency->MinVersion.has_value());
    233         REQUIRE(dependency->MinVersion == dependencyToAdd.MinVersion);
    234     }
    235     SECTION("Existing dependency has lower min version")
    236     {
    237         list.Add(dependencyWithLowerMinVersion);
    238         list.Add(dependencyToAdd);
    239 
    240         const Dependency* dependency = list.HasDependency(dependencyToAdd);
    241         REQUIRE(dependency != nullptr);
    242         REQUIRE(dependency->MinVersion.has_value());
    243         REQUIRE(dependency->MinVersion == dependencyToAdd.MinVersion);
    244     }
    245     SECTION("Existing dependency has higher min version")
    246     {
    247         list.Add(dependencyWithHigherMinVersion);
    248         list.Add(dependencyToAdd);
    249 
    250         const Dependency* dependency = list.HasDependency(dependencyToAdd);
    251         REQUIRE(dependency != nullptr);
    252         REQUIRE(dependency->MinVersion.has_value());
    253         REQUIRE(dependency->MinVersion == dependencyWithHigherMinVersion.MinVersion);
    254     }
    255     SECTION("Existing dependency has no min version, neither does added")
    256     {
    257         list.Add(dependencyWithoutMinVersion);
    258         list.Add(dependencyWithoutMinVersion);
    259 
    260         const Dependency* dependency = list.HasDependency(dependencyToAdd);
    261         REQUIRE(dependency != nullptr);
    262         REQUIRE(!dependency->MinVersion.has_value());
    263     }
    264     SECTION("Existing dependency has min version, added does not")
    265     {
    266         list.Add(dependencyWithHigherMinVersion);
    267         list.Add(dependencyWithoutMinVersion);
    268 
    269         const Dependency* dependency = list.HasDependency(dependencyToAdd);
    270         REQUIRE(dependency != nullptr);
    271         REQUIRE(dependency->MinVersion.has_value());
    272         REQUIRE(dependency->MinVersion == dependencyWithHigherMinVersion.MinVersion);
    273     }
    274 }