Esempio n. 1
0
        public void TargetedDependenciesSnapshot_FromChanges_Empty()
        {
            const string projectPath      = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework  = ITargetFrameworkFactory.Implement("tfm1");
            var          previousSnapshot = ITargetedDependenciesSnapshotFactory.Implement(
                dependenciesWorld: new Dictionary <string, IDependency>(),
                topLevelDependencies: new List <IDependency>());

            var addedNodes   = new List <IDependencyModel>();
            var removedNodes = new List <IDependencyModel>();
            var changes      = IDependenciesChangesFactory.Implement(addedNodes: addedNodes, removedNodes: removedNodes);

            IEnumerable <IDependenciesSnapshotFilter> snapshotFilters = null;

            var catalogs = IProjectCatalogSnapshotFactory.Create();
            var snapshot = TargetedDependenciesSnapshot.FromChanges(
                projectPath,
                targetFramework,
                previousSnapshot,
                changes,
                catalogs,
                snapshotFilters,
                out bool anyChanges);

            Assert.NotNull(snapshot.TargetFramework);
            Assert.Equal("tfm1", snapshot.TargetFramework.Moniker);
            Assert.Equal(projectPath, snapshot.ProjectPath);
            Assert.Equal(catalogs, snapshot.Catalogs);
            Assert.False(anyChanges);
            Assert.Equal(0, snapshot.TopLevelDependencies.Count);
            Assert.Equal(0, snapshot.DependenciesWorld.Count);
        }
Esempio n. 2
0
        public void TargetedDependenciesSnapshot_FromChanges_NoChanges()
        {
            const string projectPath     = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework = ITargetFrameworkFactory.Implement("tfm1");

            var dependencyModelTop1 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""tfm1\\xxx\\topdependency1"",
    ""Name"":""TopDependency1"",
    ""Caption"":""TopDependency1"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelChild1 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""tfm1\\xxx\\childdependency1"",
    ""Name"":""ChildDependency1"",
    ""Caption"":""ChildDependency1"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var previousSnapshot = ITargetedDependenciesSnapshotFactory.Implement(
                dependenciesWorld: new Dictionary <string, IDependency>()
            {
                { dependencyModelTop1.Id, dependencyModelTop1 },
                { dependencyModelChild1.Id, dependencyModelChild1 },
            },
                topLevelDependencies: new List <IDependency>()
            {
                dependencyModelTop1
            });

            var addedNodes   = new List <IDependencyModel>();
            var removedNodes = new List <IDependencyModel>();
            var changes      = IDependenciesChangesFactory.Implement(addedNodes: addedNodes, removedNodes: removedNodes);

            IEnumerable <IDependenciesSnapshotFilter> snapshotFilters = null;

            var catalogs = IProjectCatalogSnapshotFactory.Create();
            var snapshot = TargetedDependenciesSnapshot.FromChanges(
                projectPath,
                targetFramework,
                previousSnapshot,
                changes,
                catalogs,
                snapshotFilters,
                out bool anyChanges);

            Assert.NotNull(snapshot.TargetFramework);
            Assert.Equal("tfm1", snapshot.TargetFramework.Moniker);
            Assert.Equal(projectPath, snapshot.ProjectPath);
            Assert.Equal(catalogs, snapshot.Catalogs);
            Assert.False(anyChanges);
            Assert.Equal(1, snapshot.TopLevelDependencies.Count);
            Assert.Equal(2, snapshot.DependenciesWorld.Count);
        }
        public void TFromChanges_NoChanges()
        {
            const string projectPath     = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework = new TargetFramework("tfm1");

            var dependencyTop1 = new TestDependency
            {
                Id           = @"tfm1\xxx\topdependency1",
                ProviderType = "Xxx",
                Resolved     = true,
                TopLevel     = true
            };

            var catalogs         = IProjectCatalogSnapshotFactory.Create();
            var previousSnapshot = ITargetedDependenciesSnapshotFactory.Implement(
                projectPath: projectPath,
                targetFramework: targetFramework,
                catalogs: catalogs,
                dependenciesWorld: new [] { dependencyTop1 },
                topLevelDependencies: new [] { dependencyTop1 });

            var changes = new DependenciesChangesBuilder();

            var snapshot = TargetedDependenciesSnapshot.FromChanges(
                projectPath,
                previousSnapshot,
                changes.Build(),
                catalogs,
                ImmutableArray <IDependenciesSnapshotFilter> .Empty,
                new Dictionary <string, IProjectDependenciesSubTreeProvider>(),
                null);

            Assert.Same(previousSnapshot, snapshot);
        }
        public void TCheckForUnresolvedDependencies_CircularDependency_DoesNotRecurseInfinitely()
        {
            const string id1          = @"tfm1\xxx\dependency1";
            const string id2          = @"tfm1\xxx\dependency2";
            const string providerType = "Xxx";

            var dependency1 = new TestDependency
            {
                Id            = id1,
                ProviderType  = providerType,
                TopLevel      = true,
                DependencyIDs = ImmutableList.Create(id2)
            };

            var dependency2 = new TestDependency
            {
                Id            = id2,
                ProviderType  = providerType,
                TopLevel      = true,
                DependencyIDs = ImmutableList.Create(id1)
            };

            var snapshot = new TargetedDependenciesSnapshot(
                "ProjectPath",
                TargetFramework.Any,
                catalogs: null,
                dependenciesWorld: new IDependency[] { dependency1, dependency2 }.ToDictionary(d => d.Id).ToImmutableDictionary());

            // verify it doesn't stack overflow
            snapshot.CheckForUnresolvedDependencies(dependency1);
        }
Esempio n. 5
0
        /// <summary>
        /// Builds a sub tree under root: target framework or Dependencies node when there is only one target.
        /// </summary>
        private async Task <IProjectTree> BuildSubTreeAsync(
            IProjectTree rootNode,
            TargetedDependenciesSnapshot targetedSnapshot,
            List <IDependency> dependencies,
            bool isActiveTarget,
            bool shouldCleanup)
        {
            HashSet <IProjectTree>?currentNodes = shouldCleanup
                ? new HashSet <IProjectTree>(capacity: dependencies.Count)
                : null;

            foreach (IDependency dependency in dependencies)
            {
                IProjectTree?dependencyNode      = rootNode.FindChildWithCaption(dependency.Caption);
                bool         isNewDependencyNode = dependencyNode == null;

                if (dependencyNode != null &&
                    dependency.Flags.Contains(DependencyTreeFlags.SupportsHierarchy))
                {
                    if ((dependency.Resolved && dependencyNode.Flags.Contains(DependencyTreeFlags.Unresolved)) ||
                        (!dependency.Resolved && dependencyNode.Flags.Contains(DependencyTreeFlags.Resolved)))
                    {
                        // when transition from unresolved to resolved or vise versa - remove old node
                        // and re-add new  one to allow GraphProvider to recalculate children
                        isNewDependencyNode = true;
                        rootNode            = dependencyNode.Remove();
                        dependencyNode      = null;
                    }
                }

                // NOTE this project system supports multiple implicit configuration dimensions (such as target framework)
                // which is a concept not modelled by DTE/VSLangProj. In order to produce a sensible view of the project
                // via automation, we expose only the active target framework at any given time.
                //
                // This is achieved by using IProjectItemTree for active target framework items, and IProjectTree for inactive
                // target frameworks. CPS only creates automation objects for items with "Reference" flag if they implement
                // IProjectItemTree. See SimpleItemNode.Initialize (in CPS) for details.

                dependencyNode = await CreateOrUpdateNodeAsync(
                    dependencyNode,
                    dependency,
                    targetedSnapshot,
                    isProjectItem : isActiveTarget);

                currentNodes?.Add(dependencyNode);

                IProjectTree?parent = isNewDependencyNode
                    ? rootNode.Add(dependencyNode).Parent
                    : dependencyNode.Parent;

                Assumes.NotNull(parent);

                rootNode = parent !;
            }

            return(currentNodes != null // shouldCleanup
                ? CleanupOldNodes(rootNode, currentNodes)
                : rootNode);
        }
Esempio n. 6
0
        public void TFromChanges_AddingToEmpty()
        {
            const string projectPath     = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework = ITargetFrameworkFactory.Implement("tfm1");

            var catalogs         = IProjectCatalogSnapshotFactory.Create();
            var previousSnapshot = TargetedDependenciesSnapshot.CreateEmpty(projectPath, targetFramework, catalogs);

            var resolvedTop = IDependencyModelFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""dependency1"",
                    ""Name"": ""Dependency1"",
                    ""Caption"": ""Dependency1"",
                    ""Resolved"": ""true"",
                    ""TopLevel"": ""true""
                }",
                                                               icon: KnownMonikers.Uninstall,
                                                               expandedIcon: KnownMonikers.Uninstall);

            var unresolved = IDependencyModelFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""dependency2"",
                    ""Name"": ""Dependency2"",
                    ""Caption"": ""Dependency2"",
                    ""Resolved"": ""false"",
                    ""TopLevel"": ""false""
                }",
                                                              icon: KnownMonikers.Uninstall,
                                                              expandedIcon: KnownMonikers.Uninstall);

            var changes = new DependenciesChanges();

            changes.IncludeAddedChange(resolvedTop);
            changes.IncludeAddedChange(unresolved);

            const string updatedProjectPath = "updatedProjectPath";

            var snapshot = TargetedDependenciesSnapshot.FromChanges(
                updatedProjectPath,
                previousSnapshot,
                changes,
                catalogs,
                Array.Empty <IDependenciesSnapshotFilter>(),
                new Dictionary <string, IProjectDependenciesSubTreeProvider>(),
                null);

            Assert.NotSame(previousSnapshot, snapshot);
            Assert.Same(updatedProjectPath, snapshot.ProjectPath);
            Assert.Same(catalogs, snapshot.Catalogs);
            Assert.True(snapshot.HasUnresolvedDependency);
            AssertEx.CollectionLength(snapshot.DependenciesWorld, 2);
            AssertEx.CollectionLength(snapshot.TopLevelDependencies, 1);
            Assert.True(resolvedTop.Matches(snapshot.TopLevelDependencies.Single(), targetFramework));
            Assert.True(resolvedTop.Matches(snapshot.DependenciesWorld["tfm1\\Xxx\\dependency1"], targetFramework));
            Assert.True(unresolved.Matches(snapshot.DependenciesWorld["tfm1\\Xxx\\dependency2"], targetFramework));
        }
Esempio n. 7
0
        public void TFromChanges_NoChangesAfterBeforeRemoveFilterDeclinedChange()
        {
            const string projectPath     = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework = ITargetFrameworkFactory.Implement("tfm1");

            var dependencyTop1 = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\topdependency1"",
                    ""Name"":""TopDependency1"",
                    ""Caption"":""TopDependency1"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""true""
                }",
                                                             icon: KnownMonikers.Uninstall,
                                                             expandedIcon: KnownMonikers.Uninstall);

            var dependencyChild1 = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\childdependency1"",
                    ""Name"":""ChildDependency1"",
                    ""Caption"":""ChildDependency1"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""false""
                }",
                                                               icon: KnownMonikers.Uninstall,
                                                               expandedIcon: KnownMonikers.Uninstall);

            var catalogs         = IProjectCatalogSnapshotFactory.Create();
            var previousSnapshot = ITargetedDependenciesSnapshotFactory.Implement(
                projectPath: projectPath,
                targetFramework: targetFramework,
                catalogs: catalogs,
                dependenciesWorld: new [] { dependencyTop1, dependencyChild1 },
                topLevelDependencies: new [] { dependencyTop1 });

            var changes = new DependenciesChanges();

            changes.IncludeRemovedChange(dependencyTop1.ProviderType, dependencyTop1.Id);

            var snapshotFilter = new TestDependenciesSnapshotFilter()
                                 .ImplementBeforeRemoveResult(FilterAction.Cancel, @"tfm1\xxx\newdependency1", null);

            var snapshot = TargetedDependenciesSnapshot.FromChanges(
                projectPath,
                previousSnapshot,
                changes,
                catalogs,
                new[] { snapshotFilter },
                new Dictionary <string, IProjectDependenciesSubTreeProvider>(),
                null);

            Assert.Same(previousSnapshot, snapshot);
        }
Esempio n. 8
0
        protected bool ApplyChangesInternal(
            IGraphContext graphContext,
            IDependency updatedDependency,
            GraphNode dependencyGraphNode,
            ImmutableArray <IDependency> updatedChildren,
            string nodeProjectPath,
            TargetedDependenciesSnapshot targetedSnapshot)
        {
            IEnumerable <string> existingChildModelIds = GetExistingChildren();
            IEnumerable <string> updatedChildModelIds  = updatedChildren.Select(dependency => dependency.Id);

            var diff = new SetDiff <string>(existingChildModelIds, updatedChildModelIds);

            bool anyChanges = false;

            foreach (string childModelIdToRemove in diff.Removed)
            {
                anyChanges = true;
                Builder.RemoveGraphNode(graphContext, nodeProjectPath, childModelIdToRemove, dependencyGraphNode);
            }

            foreach (string childModeIdToAdd in diff.Added)
            {
                if (!targetedSnapshot.DependenciesWorld.TryGetValue(childModeIdToAdd, out IDependency dependency) ||
                    !dependency.Visible)
                {
                    continue;
                }

                anyChanges = true;
                Builder.AddGraphNode(
                    graphContext,
                    nodeProjectPath,
                    dependencyGraphNode,
                    dependency.ToViewModel(targetedSnapshot));
            }

            // Update the node info saved on the 'inputNode'
            dependencyGraphNode.SetValue(DependenciesGraphSchema.DependencyIdProperty, updatedDependency.Id);
            dependencyGraphNode.SetValue(DependenciesGraphSchema.ResolvedProperty, updatedDependency.Resolved);

            return(anyChanges);

            IEnumerable <string> GetExistingChildren()
            {
                foreach (GraphNode childNode in dependencyGraphNode.FindDescendants())
                {
                    string id = childNode.GetValue <string>(DependenciesGraphSchema.DependencyIdProperty);

                    if (!string.IsNullOrEmpty(id))
                    {
                        yield return(id);
                    }
                }
            }
        }
Esempio n. 9
0
 public virtual bool ApplyChanges(
     IGraphContext graphContext,
     string nodeProjectPath,
     IDependency updatedDependency,
     GraphNode dependencyGraphNode,
     TargetedDependenciesSnapshot targetedSnapshot)
 {
     return(ApplyChangesInternal(
                graphContext,
                updatedDependency,
                dependencyGraphNode,
                updatedChildren: targetedSnapshot.GetDependencyChildren(updatedDependency),
                nodeProjectPath: nodeProjectPath,
                targetedSnapshot));
 }
Esempio n. 10
0
        public void TCreateEmpty()
        {
            const string projectPath     = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework = ITargetFrameworkFactory.Implement("tfm1");
            var          catalogs        = IProjectCatalogSnapshotFactory.Create();

            var snapshot = TargetedDependenciesSnapshot.CreateEmpty(projectPath, targetFramework, catalogs);

            Assert.Same(projectPath, snapshot.ProjectPath);
            Assert.Same(catalogs, snapshot.Catalogs);
            Assert.Same(targetFramework, snapshot.TargetFramework);
            Assert.False(snapshot.HasUnresolvedDependency);
            Assert.Empty(snapshot.DependenciesWorld);
            Assert.Empty(snapshot.TopLevelDependencies);
            Assert.False(snapshot.CheckForUnresolvedDependencies("foo"));
            Assert.Empty(snapshot.GetDependencyChildren(new TestDependency()));
        }
        /// <summary>
        /// Builds a sub tree under root: target framework or Dependencies node when there is only one target.
        /// </summary>
        private async Task <IProjectTree> BuildSubTreeAsync(
            IProjectTree rootNode,
            TargetedDependenciesSnapshot targetedSnapshot,
            List <IDependency> dependencies,
            bool isActiveTarget,
            bool shouldCleanup)
        {
            HashSet <IProjectTree>?currentNodes = shouldCleanup
                ? new HashSet <IProjectTree>(capacity: dependencies.Count)
                : null;

            foreach (IDependency dependency in dependencies)
            {
                IProjectTree?dependencyNode      = rootNode.FindChildWithCaption(dependency.Caption);
                bool         isNewDependencyNode = dependencyNode == null;

                // NOTE this project system supports multiple implicit configuration dimensions (such as target framework)
                // which is a concept not modelled by DTE/VSLangProj. In order to produce a sensible view of the project
                // via automation, we expose only the active target framework at any given time.
                //
                // This is achieved by using IProjectItemTree for active target framework items, and IProjectTree for inactive
                // target frameworks. CPS only creates automation objects for items with "Reference" flag if they implement
                // IProjectItemTree. See SimpleItemNode.Initialize (in CPS) for details.

                dependencyNode = await CreateOrUpdateNodeAsync(
                    dependencyNode,
                    dependency,
                    targetedSnapshot,
                    isProjectItem : isActiveTarget);

                currentNodes?.Add(dependencyNode);

                IProjectTree?parent = isNewDependencyNode
                    ? rootNode.Add(dependencyNode).Parent
                    : dependencyNode.Parent;

                Assumes.NotNull(parent);

                rootNode = parent;
            }

            return(currentNodes != null // shouldCleanup
                ? CleanupOldNodes(rootNode, currentNodes)
                : rootNode);
        }
Esempio n. 12
0
        public void TConstructor()
        {
            const string projectPath     = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework = ITargetFrameworkFactory.Implement("tfm1");

            var catalogs = IProjectCatalogSnapshotFactory.Create();
            var snapshot = new TargetedDependenciesSnapshot(
                projectPath,
                targetFramework,
                catalogs,
                ImmutableDictionary <string, IDependency> .Empty);

            Assert.NotNull(snapshot.TargetFramework);
            Assert.Equal("tfm1", snapshot.TargetFramework.FullName);
            Assert.Equal(projectPath, snapshot.ProjectPath);
            Assert.Equal(catalogs, snapshot.Catalogs);
            Assert.Empty(snapshot.TopLevelDependencies);
            Assert.Empty(snapshot.DependenciesWorld);
        }
Esempio n. 13
0
        public void TCheckForUnresolvedDependencies_CircularDependency_DoesNotRecurseInfinitely()
        {
            var dependencyTop1 = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\topdependency1"",
                    ""Name"":""TopDependency1"",
                    ""Caption"":""TopDependency1"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""true"",
                    ""DependencyIDs"": [ ""tfm1\\xxx\\topdependency2"" ]
                }",
                                                             icon: KnownMonikers.Uninstall,
                                                             expandedIcon: KnownMonikers.Uninstall);

            var dependencyTop2 = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\topdependency2"",
                    ""Name"":""TopDependency2"",
                    ""Caption"":""TopDependency2"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""false"",
                    ""DependencyIDs"": [ ""tfm1\\xxx\\topdependency1"" ]
                }",
                                                             icon: KnownMonikers.Uninstall,
                                                             expandedIcon: KnownMonikers.Uninstall);

            var previousSnapshot = new TargetedDependenciesSnapshot(
                "ProjectPath",
                TargetFramework.Any,
                catalogs: null,
                dependenciesWorld: new Dictionary <string, IDependency>()
            {
                { dependencyTop1.Id, dependencyTop1 },
                { dependencyTop2.Id, dependencyTop2 },
            }.ToImmutableDictionary());

            // verify it doesn't stack overflow
            previousSnapshot.CheckForUnresolvedDependencies(dependencyTop1);
        }
Esempio n. 14
0
        private static HashSet <IDependency> GetMatchingResultsForDependency(
            IDependency rootDependency,
            TargetedDependenciesSnapshot snapshot,
            HashSet <IDependency> flatMatchingDependencies,
            Dictionary <string, HashSet <IDependency> > cachedPositiveResults)
        {
            var matchingNodes = new HashSet <IDependency>(DependencyIdComparer.Instance);

            foreach (string childDependency in rootDependency.DependencyIDs)
            {
                if (!snapshot.DependenciesWorld.TryGetValue(childDependency, out IDependency childDependencyMetadata))
                {
                    continue;
                }

                if (flatMatchingDependencies.Contains(childDependencyMetadata))
                {
                    matchingNodes.Add(childDependencyMetadata);
                }

                if (cachedPositiveResults.TryGetValue(childDependency, out HashSet <IDependency> cachedResults))
                {
                    matchingNodes.AddRange(cachedResults);
                    continue;
                }

                HashSet <IDependency> children = GetMatchingResultsForDependency(
                    childDependencyMetadata,
                    snapshot,
                    flatMatchingDependencies,
                    cachedPositiveResults);

                cachedPositiveResults[childDependency] = children;

                if (children.Count > 0)
                {
                    matchingNodes.AddRange(children);
                }
            }

            return(matchingNodes);
        }
Esempio n. 15
0
        private async Task <IProjectTree> CreateOrUpdateNodeAsync(
            IProjectTree?node,
            IDependency dependency,
            TargetedDependenciesSnapshot targetedSnapshot,
            bool isProjectItem,
            ProjectTreeFlags?additionalFlags = null,
            ProjectTreeFlags?excludedFlags   = null)
        {
            IRule?browseObjectProperties = dependency.Flags.Contains(DependencyTreeFlags.SupportsRuleProperties)
                ? await _treeServices.GetBrowseObjectRuleAsync(dependency, targetedSnapshot.Catalogs)
                : null;

            return(CreateOrUpdateNode(
                       node,
                       dependency.ToViewModel(targetedSnapshot),
                       browseObjectProperties,
                       isProjectItem,
                       additionalFlags,
                       excludedFlags));
        }
Esempio n. 16
0
        public void TFromChanges_Empty()
        {
            const string projectPath      = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework  = ITargetFrameworkFactory.Implement("tfm1");
            var          catalogs         = IProjectCatalogSnapshotFactory.Create();
            var          previousSnapshot = TargetedDependenciesSnapshot.CreateEmpty(projectPath, targetFramework, catalogs);

            var changes = new DependenciesChanges();

            var snapshot = TargetedDependenciesSnapshot.FromChanges(
                projectPath,
                previousSnapshot,
                changes,
                catalogs,
                Array.Empty <IDependenciesSnapshotFilter>(),
                new Dictionary <string, IProjectDependenciesSubTreeProvider>(),
                null);

            Assert.Same(previousSnapshot, snapshot);
        }
        public override bool ApplyChanges(
            IGraphContext graphContext,
            string nodeProjectPath,
            IDependency updatedDependency,
            GraphNode dependencyGraphNode,
            TargetedDependenciesSnapshot targetedSnapshot)
        {
            TargetedDependenciesSnapshot?referencedProjectSnapshot = _aggregateSnapshotProvider.GetSnapshot(updatedDependency);

            if (referencedProjectSnapshot == null)
            {
                return(false);
            }

            return(ApplyChangesInternal(
                       graphContext,
                       updatedDependency,
                       dependencyGraphNode,
                       // Project references list all top level dependencies as direct children
                       updatedChildren: referencedProjectSnapshot.TopLevelDependencies,
                       // Pass the path of the referenced project
                       nodeProjectPath: updatedDependency.FullPath,
                       targetedSnapshot: referencedProjectSnapshot));
        }
Esempio n. 18
0
 public IDependencyViewModel CreateTargetViewModel(TargetedDependenciesSnapshot snapshot)
 {
     return(new TargetDependencyViewModel(snapshot));
 }
Esempio n. 19
0
        /// <summary>
        /// Builds all available sub trees under root: target framework or Dependencies node
        /// when there is only one target.
        /// </summary>
        private async Task <IProjectTree> BuildSubTreesAsync(
            IProjectTree rootNode,
            ITargetFramework activeTarget,
            TargetedDependenciesSnapshot targetedSnapshot,
            Func <IProjectTree, HashSet <IProjectTree>, IProjectTree> syncFunc)
        {
            var groupedByProviderType = new Dictionary <string, List <IDependency> >(StringComparers.DependencyProviderTypes);

            foreach (IDependency dependency in targetedSnapshot.TopLevelDependencies)
            {
                if (!dependency.Visible)
                {
                    // If a dependency is not visible we will still register a top-level group if it
                    // has the ShowEmptyProviderRootNode flag.
                    if (!dependency.Flags.Contains(DependencyTreeFlags.ShowEmptyProviderRootNode))
                    {
                        // No such flag, so skip it completely.
                        continue;
                    }
                }

                if (!groupedByProviderType.TryGetValue(dependency.ProviderType, out List <IDependency> dependencies))
                {
                    dependencies = new List <IDependency>();
                    groupedByProviderType.Add(dependency.ProviderType, dependencies);
                }

                // Only add visible dependencies. See note above.
                if (dependency.Visible)
                {
                    dependencies.Add(dependency);
                }
            }

            var currentNodes = new HashSet <IProjectTree>(capacity: groupedByProviderType.Count);

            bool isActiveTarget = targetedSnapshot.TargetFramework.Equals(activeTarget);

            foreach ((string providerType, List <IDependency> dependencies) in groupedByProviderType)
            {
                IDependencyViewModel?subTreeViewModel = _viewModelFactory.CreateRootViewModel(
                    providerType,
                    targetedSnapshot.CheckForUnresolvedDependencies(providerType));

                if (subTreeViewModel == null)
                {
                    // In theory this should never happen, as it means we have a dependency model of a type
                    // that no provider claims. https://github.com/dotnet/project-system/issues/3653
                    continue;
                }

                IProjectTree?subTreeNode      = rootNode.FindChildWithCaption(subTreeViewModel.Caption);
                bool         isNewSubTreeNode = subTreeNode == null;

                ProjectTreeFlags excludedFlags = targetedSnapshot.TargetFramework.Equals(TargetFramework.Any)
                    ? ProjectTreeFlags.Create(ProjectTreeFlags.Common.BubbleUp)
                    : ProjectTreeFlags.Empty;

                subTreeNode = CreateOrUpdateNode(
                    subTreeNode,
                    subTreeViewModel,
                    browseObjectProperties: null,
                    isProjectItem: false,
                    excludedFlags: excludedFlags);

                subTreeNode = await BuildSubTreeAsync(
                    subTreeNode,
                    targetedSnapshot,
                    dependencies,
                    isActiveTarget,
                    shouldCleanup : !isNewSubTreeNode);

                currentNodes.Add(subTreeNode);

                rootNode = isNewSubTreeNode
                    ? rootNode.Add(subTreeNode).Parent !
                    : subTreeNode.Parent !;

                Assumes.NotNull(rootNode);
            }

            return(syncFunc(rootNode, currentNodes));
        }
Esempio n. 20
0
 public TargetDependencyViewModel(TargetedDependenciesSnapshot snapshot)
 {
     Caption = snapshot.TargetFramework.FriendlyName;
     Flags   = DependencyTreeFlags.TargetNode.Add($"$TFM:{snapshot.TargetFramework.FullName}");
     _hasUnresolvedDependency = snapshot.HasReachableVisibleUnresolvedDependency;
 }
Esempio n. 21
0
 public abstract void BuildGraph(
     IGraphContext graphContext,
     string projectPath,
     IDependency dependency,
     GraphNode dependencyGraphNode,
     TargetedDependenciesSnapshot targetedSnapshot);
Esempio n. 22
0
        /// <summary>
        /// Generates search graph containing nodes matching search criteria in Solution Explorer
        /// and attaches it to correct top level node.
        /// </summary>
        private void Search(IGraphContext graphContext)
        {
            string searchParametersTypeName            = typeof(ISolutionSearchParameters).GUID.ToString();
            ISolutionSearchParameters searchParameters = graphContext.GetValue <ISolutionSearchParameters>(searchParametersTypeName);

            string?searchTerm = searchParameters?.SearchQuery.SearchString;

            if (searchTerm == null)
            {
                return;
            }

            var cachedDependencyToMatchingResultsMap = new Dictionary <string, HashSet <IDependency> >(StringComparer.OrdinalIgnoreCase);
            var searchResultsPerContext = new Dictionary <string, HashSet <IDependency> >(StringComparer.OrdinalIgnoreCase);

            System.Collections.Generic.IReadOnlyCollection <DependenciesSnapshot> snapshots = AggregateSnapshotProvider.GetSnapshots();

            foreach (DependenciesSnapshot snapshot in snapshots)
            {
                searchResultsPerContext[snapshot.ProjectPath] = SearchFlat(searchTerm, snapshot);
            }

            foreach (DependenciesSnapshot snapshot in snapshots)
            {
                IEnumerable <IDependency> allTopLevelDependencies = snapshot.GetFlatTopLevelDependencies();
                HashSet <IDependency>     matchedDependencies     = searchResultsPerContext[snapshot.ProjectPath];

                using var scope = new GraphTransactionScope();

                foreach (IDependency topLevelDependency in allTopLevelDependencies)
                {
                    TargetedDependenciesSnapshot targetedSnapshot = snapshot.DependenciesByTargetFramework[topLevelDependency.TargetFramework];

                    if (!cachedDependencyToMatchingResultsMap.TryGetValue(
                            topLevelDependency.Id,
                            out HashSet <IDependency>?topLevelDependencyMatches))
                    {
                        IDependenciesGraphViewProvider?viewProvider = FindViewProvider(topLevelDependency);

                        if (viewProvider == null)
                        {
                            continue;
                        }

                        if (!viewProvider.MatchSearchResults(
                                topLevelDependency,
                                searchResultsPerContext,
                                out topLevelDependencyMatches))
                        {
                            if (matchedDependencies.Count == 0)
                            {
                                continue;
                            }

                            topLevelDependencyMatches = GetMatchingResultsForDependency(
                                topLevelDependency,
                                targetedSnapshot,
                                matchedDependencies,
                                cachedDependencyToMatchingResultsMap);
                        }

                        cachedDependencyToMatchingResultsMap[topLevelDependency.Id] = topLevelDependencyMatches;
                    }

                    if (topLevelDependencyMatches.Count == 0)
                    {
                        continue;
                    }

                    GraphNode topLevelNode = _builder.AddTopLevelGraphNode(
                        graphContext,
                        snapshot.ProjectPath,
                        topLevelDependency.ToViewModel(targetedSnapshot));

                    foreach (IDependency matchedDependency in topLevelDependencyMatches)
                    {
                        GraphNode matchedDependencyNode = _builder.AddGraphNode(
                            graphContext,
                            snapshot.ProjectPath,
                            topLevelNode,
                            matchedDependency.ToViewModel(targetedSnapshot));

                        graphContext.Graph.Links.GetOrCreate(
                            topLevelNode,
                            matchedDependencyNode,
                            label: null,
                            GraphCommonSchema.Contains);
                    }

                    if (topLevelNode != null)
                    {
                        // 'node' is a GraphNode for top level dependency (which is part of solution explorer tree)
                        // Setting ProjectItem category (and correct GraphNodeId) ensures that search graph appears
                        // under right solution explorer hierarchy item
                        topLevelNode.AddCategory(CodeNodeCategories.ProjectItem);
                    }
                }

                scope.Complete();
            }

            graphContext.OnCompleted();
        }
Esempio n. 23
0
        public void TFromChanges_UpdatesTopLevelDependencies()
        {
            const string projectPath     = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework = ITargetFrameworkFactory.Implement("tfm1");

            var dependencyTopPrevious = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\topdependency1"",
                    ""Name"": ""TopDependency1"",
                    ""Caption"": ""TopDependency1"",
                    ""SchemaItemType"": ""Xxx"",
                    ""Resolved"": ""true""
                }",
                                                                    icon: KnownMonikers.Uninstall,
                                                                    expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelTopAdded = IDependencyModelFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""topdependency1"",
                    ""Name"": ""TopDependency1"",
                    ""Caption"": ""TopDependency1"",
                    ""SchemaItemType"": ""Xxx"",
                    ""Resolved"": ""true""
                }",
                                                                           icon: KnownMonikers.Uninstall,
                                                                           expandedIcon: KnownMonikers.Uninstall);

            var dependencyTopUpdated = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\topdependency1"",
                    ""Name"": ""TopDependency1"",
                    ""Caption"": ""TopDependency1"",
                    ""SchemaItemType"": ""Xxx"",
                    ""Resolved"": ""true""
                }",
                                                                   icon: KnownMonikers.Uninstall,
                                                                   expandedIcon: KnownMonikers.Uninstall);

            var catalogs         = IProjectCatalogSnapshotFactory.Create();
            var previousSnapshot = ITargetedDependenciesSnapshotFactory.Implement(
                projectPath: projectPath,
                targetFramework: targetFramework,
                catalogs: catalogs,
                dependenciesWorld: new[] { dependencyTopPrevious },
                topLevelDependencies: new[] { dependencyTopPrevious });

            var changes = new DependenciesChanges();

            changes.IncludeAddedChange(dependencyModelTopAdded);

            var snapshotFilter = new TestDependenciesSnapshotFilter()
                                 .ImplementBeforeAddResult(FilterAction.ShouldBeAdded, @"tfm1\xxx\topdependency1", dependencyTopUpdated);

            var snapshot = TargetedDependenciesSnapshot.FromChanges(
                projectPath,
                previousSnapshot,
                changes,
                catalogs,
                new[] { snapshotFilter },
                new Dictionary <string, IProjectDependenciesSubTreeProvider>(),
                null);

            Assert.NotSame(previousSnapshot, snapshot);
            Assert.Same(dependencyTopUpdated, snapshot.TopLevelDependencies.Single());
        }
        public void TFromChanges_RemovedAndAddedChanges()
        {
            const string projectPath     = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework = new TargetFramework("tfm1");

            var dependencyTop1 = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\topdependency1"",
                    ""Name"":""TopDependency1"",
                    ""Caption"":""TopDependency1"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""true""
                }",
                                                             icon: KnownMonikers.Uninstall,
                                                             expandedIcon: KnownMonikers.Uninstall);

            var dependencyChild1 = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\childdependency1"",
                    ""Name"":""ChildDependency1"",
                    ""Caption"":""ChildDependency1"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""false""
                }",
                                                               icon: KnownMonikers.Uninstall,
                                                               expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelAdded1 = IDependencyModelFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""addeddependency1"",
                    ""Name"":""AddedDependency1"",
                    ""Caption"":""AddedDependency1"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""false""
                }",
                                                                         icon: KnownMonikers.Uninstall,
                                                                         expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelAdded2 = IDependencyModelFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""addeddependency2"",
                    ""Name"":""AddedDependency2"",
                    ""Caption"":""AddedDependency2"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""false""
                }",
                                                                         icon: KnownMonikers.Uninstall,
                                                                         expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelAdded3 = IDependencyModelFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""addeddependency3"",
                    ""Name"":""AddedDependency3"",
                    ""Caption"":""AddedDependency3"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""false""
                }",
                                                                         icon: KnownMonikers.Uninstall,
                                                                         expandedIcon: KnownMonikers.Uninstall);

            var dependencyAdded2Changed = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\addeddependency2"",
                    ""Name"":""AddedDependency2Changed"",
                    ""Caption"":""AddedDependency2Changed"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""true""
                }",
                                                                      icon: KnownMonikers.Uninstall,
                                                                      expandedIcon: KnownMonikers.Uninstall);

            var dependencyRemoved1 = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\Removeddependency1"",
                    ""Name"":""RemovedDependency1"",
                    ""Caption"":""RemovedDependency1"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""false""
                }",
                                                                 icon: KnownMonikers.Uninstall,
                                                                 expandedIcon: KnownMonikers.Uninstall);

            var dependencyInsteadRemoved1 = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\InsteadRemoveddependency1"",
                    ""Name"":""InsteadRemovedDependency1"",
                    ""Caption"":""InsteadRemovedDependency1"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""false""
                }",
                                                                        icon: KnownMonikers.Uninstall,
                                                                        expandedIcon: KnownMonikers.Uninstall);

            Assert.True(dependencyTop1.TopLevel);
            Assert.False(dependencyChild1.TopLevel);
            Assert.False(dependencyRemoved1.TopLevel);

            var catalogs         = IProjectCatalogSnapshotFactory.Create();
            var previousSnapshot = ITargetedDependenciesSnapshotFactory.Implement(
                projectPath: projectPath,
                targetFramework: targetFramework,
                catalogs: catalogs,
                dependenciesWorld: new [] { dependencyTop1, dependencyChild1, dependencyRemoved1 },
                topLevelDependencies: new [] { dependencyTop1 });

            var changes = new DependenciesChangesBuilder();

            changes.Added(dependencyModelAdded1);
            changes.Added(dependencyModelAdded2);
            changes.Added(dependencyModelAdded3);
            changes.Removed("Xxx", "Removeddependency1");

            var snapshotFilter = new TestDependenciesSnapshotFilter()
                                 .BeforeAddReject(@"tfm1\xxx\addeddependency1")
                                 .BeforeAddAccept(@"tfm1\xxx\addeddependency2", dependencyAdded2Changed)
                                 .BeforeAddAccept(@"tfm1\xxx\addeddependency3")
                                 .BeforeRemoveAccept(@"tfm1\xxx\Removeddependency1", dependencyInsteadRemoved1);

            var snapshot = TargetedDependenciesSnapshot.FromChanges(
                projectPath,
                previousSnapshot,
                changes.Build(),
                catalogs,
                ImmutableArray.Create <IDependenciesSnapshotFilter>(snapshotFilter),
                new Dictionary <string, IProjectDependenciesSubTreeProvider>(),
                null);

            Assert.NotSame(previousSnapshot, snapshot);

            Assert.Same(previousSnapshot.TargetFramework, snapshot.TargetFramework);
            Assert.Same(projectPath, snapshot.ProjectPath);
            Assert.Same(catalogs, snapshot.Catalogs);
            AssertEx.CollectionLength(snapshot.TopLevelDependencies, 2);
            Assert.Contains(snapshot.TopLevelDependencies, x => x.Id.Equals(@"tfm1\xxx\topdependency1"));
            Assert.Contains(snapshot.TopLevelDependencies, x => x.Id.Equals(@"tfm1\xxx\addeddependency2") && x.Caption.Equals("AddedDependency2Changed"));
            AssertEx.CollectionLength(snapshot.DependenciesWorld, 5);
            Assert.True(snapshot.DependenciesWorld.ContainsKey(@"tfm1\xxx\topdependency1"));
            Assert.True(snapshot.DependenciesWorld.ContainsKey(@"tfm1\xxx\childdependency1"));
            Assert.True(snapshot.DependenciesWorld.ContainsKey(@"tfm1\xxx\addeddependency2"));
            Assert.True(snapshot.DependenciesWorld.ContainsKey(@"tfm1\xxx\InsteadRemoveddependency1"));
            Assert.True(snapshot.DependenciesWorld.ContainsKey(@"tfm1\xxx\addeddependency3"));
        }
Esempio n. 25
0
        public void TFromChanges_ReportedChangesAfterBeforeAddFilterDeclinedChange()
        {
            const string projectPath     = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework = ITargetFrameworkFactory.Implement("tfm1");

            var dependencyModelTop1 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""tfm1\\xxx\\topdependency1"",
    ""Name"":""TopDependency1"",
    ""Caption"":""TopDependency1"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelChild1 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""tfm1\\xxx\\childdependency1"",
    ""Name"":""ChildDependency1"",
    ""Caption"":""ChildDependency1"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelNew1 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""newdependency1"",
    ""Name"":""NewDependency1"",
    ""Caption"":""NewDependency1"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);
            var previousSnapshot    = ITargetedDependenciesSnapshotFactory.Implement(
                dependenciesWorld: new Dictionary <string, IDependency>()
            {
                { dependencyModelTop1.Id, dependencyModelTop1 },
                { dependencyModelChild1.Id, dependencyModelChild1 },
            },
                topLevelDependencies: new List <IDependency>()
            {
                dependencyModelTop1
            });

            var addedNodes = new List <IDependencyModel> {
                dependencyModelNew1
            };
            var removedNodes = new List <IDependencyModel>();
            var changes      = IDependenciesChangesFactory.Implement(addedNodes: addedNodes, removedNodes: removedNodes);

            var snapshotFilter = new TestDependenciesSnapshotFilter()
                                 .ImplementBeforeAddResult(FilterAction.Cancel, @"tfm1\xxx\newdependency1", null)
                                 .ImplementFilterAnyChanges(true);

            var catalogs = IProjectCatalogSnapshotFactory.Create();
            var snapshot = TargetedDependenciesSnapshot.FromChanges(
                projectPath,
                targetFramework,
                previousSnapshot,
                changes,
                catalogs,
                new[] { snapshotFilter },
                null,
                null,
                out bool anyChanges);

            Assert.NotNull(snapshot.TargetFramework);
            Assert.Equal("tfm1", snapshot.TargetFramework.FullName);
            Assert.Equal(projectPath, snapshot.ProjectPath);
            Assert.Equal(catalogs, snapshot.Catalogs);
            Assert.True(anyChanges);
            Assert.Single(snapshot.TopLevelDependencies);
            AssertEx.CollectionLength(snapshot.DependenciesWorld, 2);
        }
Esempio n. 26
0
        public override void BuildGraph(
            IGraphContext graphContext,
            string projectPath,
            IDependency dependency,
            GraphNode dependencyGraphNode,
            TargetedDependenciesSnapshot targetedSnapshot)
        {
            // store refreshed dependency info
            dependencyGraphNode.SetValue(DependenciesGraphSchema.DependencyIdProperty, dependency.Id);
            dependencyGraphNode.SetValue(DependenciesGraphSchema.ResolvedProperty, dependency.Resolved);

            ImmutableArray <IDependency> children = targetedSnapshot.GetDependencyChildren(dependency);

            if (children.IsEmpty)
            {
                return;
            }

            var regularChildren      = new List <IDependency>();
            var fxAssembliesChildren = new List <IDependency>();

            foreach (IDependency childDependency in children)
            {
                if (!childDependency.Visible)
                {
                    continue;
                }

                if (childDependency.Flags.Contains(DependencyTreeFlags.FxAssemblyDependency))
                {
                    fxAssembliesChildren.Add(childDependency);
                }
                else
                {
                    regularChildren.Add(childDependency);
                }
            }

            bool isFxAssembliesFolder = dependencyGraphNode.GetValue <bool>(DependenciesGraphSchema.IsFrameworkAssemblyFolderProperty);

            if (isFxAssembliesFolder)
            {
                foreach (IDependency fxAssembly in fxAssembliesChildren)
                {
                    Builder.AddGraphNode(
                        graphContext,
                        projectPath,
                        dependencyGraphNode,
                        fxAssembly.ToViewModel(targetedSnapshot));
                }
            }
            else
            {
                foreach (IDependency childDependency in regularChildren)
                {
                    Builder.AddGraphNode(
                        graphContext,
                        projectPath,
                        dependencyGraphNode,
                        childDependency.ToViewModel(targetedSnapshot));
                }

                if (fxAssembliesChildren.Count > 0)
                {
                    GraphNode fxAssembliesNode = Builder.AddGraphNode(graphContext, projectPath, dependencyGraphNode, PackageFrameworkAssembliesViewModel.Instance);
                    fxAssembliesNode.SetValue(DgmlNodeProperties.ContainsChildren, true);
                    fxAssembliesNode.SetValue(DependenciesGraphSchema.IsFrameworkAssemblyFolderProperty, true);
                    fxAssembliesNode.SetValue(DependenciesGraphSchema.DependencyIdProperty, dependency.Id);
                    fxAssembliesNode.SetValue(DependenciesGraphSchema.ResolvedProperty, dependency.Resolved);
                }
            }
        }
Esempio n. 27
0
        public void TFromChanges_RemovedAndAddedChanges()
        {
            const string projectPath     = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework = ITargetFrameworkFactory.Implement("tfm1");

            var dependencyModelTop1 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""topdependency1"",
    ""Name"":""TopDependency1"",
    ""Caption"":""TopDependency1"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelChild1 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""childdependency1"",
    ""Name"":""ChildDependency1"",
    ""Caption"":""ChildDependency1"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelAdded1 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""addeddependency1"",
    ""Name"":""AddedDependency1"",
    ""Caption"":""AddedDependency1"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelAdded2 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""addeddependency2"",
    ""Name"":""AddedDependency2"",
    ""Caption"":""AddedDependency2"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelAdded3 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""addeddependency3"",
    ""Name"":""AddedDependency3"",
    ""Caption"":""AddedDependency3"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true"",
    ""TopLevel"":""false""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var dependencyAdded2Changed = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""tfm1\\xxx\\addeddependency2"",
    ""Name"":""AddedDependency2Changed"",
    ""Caption"":""AddedDependency2Changed"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var dependencyRemoved1 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""tfm1\\xxx\\Removeddependency1"",
    ""Name"":""RemovedDependency1"",
    ""Caption"":""RemovedDependency1"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelRemoved1 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""Removeddependency1"",
    ""Name"":""RemovedDependency1"",
    ""Caption"":""RemovedDependency1"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var dependencyInsteadRemoved1 = IDependencyFactory.FromJson(@"
{
    ""ProviderType"": ""Xxx"",
    ""Id"": ""tfm1\\xxx\\InsteadRemoveddependency1"",
    ""Name"":""InsteadRemovedDependency1"",
    ""Caption"":""InsteadRemovedDependency1"",
    ""SchemaItemType"":""Xxx"",
    ""Resolved"":""true""
}", icon: KnownMonikers.Uninstall, expandedIcon: KnownMonikers.Uninstall);

            var previousSnapshot = ITargetedDependenciesSnapshotFactory.Implement(
                dependenciesWorld: new Dictionary <string, IDependency>()
            {
                { @"tfm1\xxx\topdependency1", dependencyModelTop1 },
                { @"tfm1\xxx\childdependency1", dependencyModelChild1 },
                { @"tfm1\xxx\Removeddependency1", dependencyRemoved1 },
            },
                topLevelDependencies: new List <IDependency>()
            {
                dependencyModelTop1
            });

            var addedNodes = new List <IDependencyModel> {
                dependencyModelAdded1, dependencyModelAdded2, dependencyModelAdded3
            };
            var removedNodes = new List <IDependencyModel> {
                dependencyModelRemoved1
            };
            var changes = IDependenciesChangesFactory.Implement(addedNodes: addedNodes, removedNodes: removedNodes);

            var snapshotFilter = new TestDependenciesSnapshotFilter()
                                 .ImplementBeforeAddResult(FilterAction.Cancel, @"tfm1\xxx\addeddependency1", null)
                                 .ImplementBeforeAddResult(FilterAction.ShouldBeAdded, @"tfm1\xxx\addeddependency2", dependencyAdded2Changed)
                                 .ImplementBeforeRemoveResult(FilterAction.ShouldBeAdded, @"tfm1\xxx\Removeddependency1", dependencyInsteadRemoved1);

            var catalogs = IProjectCatalogSnapshotFactory.Create();
            var snapshot = TargetedDependenciesSnapshot.FromChanges(
                projectPath,
                targetFramework,
                previousSnapshot,
                changes,
                catalogs,
                new[] { snapshotFilter },
                null,
                null,
                out bool anyChanges);

            Assert.NotNull(snapshot.TargetFramework);
            Assert.Equal("tfm1", snapshot.TargetFramework.FullName);
            Assert.Equal(projectPath, snapshot.ProjectPath);
            Assert.Equal(catalogs, snapshot.Catalogs);
            Assert.True(anyChanges);
            AssertEx.CollectionLength(snapshot.TopLevelDependencies, 2);
            Assert.Contains(snapshot.TopLevelDependencies, x => x.Id.Equals(@"topdependency1"));
            Assert.Contains(snapshot.TopLevelDependencies, x => x.Id.Equals(@"tfm1\xxx\addeddependency2") && x.Caption.Equals("AddedDependency2Changed"));
            AssertEx.CollectionLength(snapshot.DependenciesWorld, 5);
            Assert.True(snapshot.DependenciesWorld.ContainsKey(@"tfm1\xxx\topdependency1"));
            Assert.True(snapshot.DependenciesWorld.ContainsKey(@"tfm1\xxx\childdependency1"));
            Assert.True(snapshot.DependenciesWorld.ContainsKey(@"tfm1\xxx\addeddependency2"));
            Assert.True(snapshot.DependenciesWorld.ContainsKey(@"tfm1\xxx\InsteadRemoveddependency1"));
            Assert.True(snapshot.DependenciesWorld.ContainsKey(@"tfm1\xxx\addeddependency3"));
        }
        public void TFromChanges_ReportedChangesAfterBeforeAddFilterDeclinedChange()
        {
            const string projectPath     = @"c:\somefolder\someproject\a.csproj";
            var          targetFramework = new TargetFramework("tfm1");

            var dependencyTop1 = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\topdependency1"",
                    ""Name"":""TopDependency1"",
                    ""Caption"":""TopDependency1"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""true""
                }",
                                                             icon: KnownMonikers.Uninstall,
                                                             expandedIcon: KnownMonikers.Uninstall);

            var dependencyChild1 = IDependencyFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""tfm1\\xxx\\childdependency1"",
                    ""Name"":""ChildDependency1"",
                    ""Caption"":""ChildDependency1"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true"",
                    ""TopLevel"":""false""
                }",
                                                               icon: KnownMonikers.Uninstall,
                                                               expandedIcon: KnownMonikers.Uninstall);

            var dependencyModelNew1 = IDependencyModelFactory.FromJson(@"
                {
                    ""ProviderType"": ""Xxx"",
                    ""Id"": ""newdependency1"",
                    ""Name"":""NewDependency1"",
                    ""Caption"":""NewDependency1"",
                    ""SchemaItemType"":""Xxx"",
                    ""Resolved"":""true""
                }",
                                                                       icon: KnownMonikers.Uninstall,
                                                                       expandedIcon: KnownMonikers.Uninstall);

            var catalogs         = IProjectCatalogSnapshotFactory.Create();
            var previousSnapshot = ITargetedDependenciesSnapshotFactory.Implement(
                projectPath: projectPath,
                targetFramework: targetFramework,
                catalogs: catalogs,
                dependenciesWorld: new [] { dependencyTop1, dependencyChild1 },
                topLevelDependencies: new [] { dependencyTop1 });

            var changes = new DependenciesChangesBuilder();

            changes.Added(dependencyModelNew1);

            var filterAddedDependency = new TestDependency {
                Id = "unexpected", TopLevel = true
            };

            var snapshotFilter = new TestDependenciesSnapshotFilter()
                                 .BeforeAddReject(@"tfm1\xxx\newdependency1", addOrUpdate: filterAddedDependency);

            var snapshot = TargetedDependenciesSnapshot.FromChanges(
                projectPath,
                previousSnapshot,
                changes.Build(),
                catalogs,
                ImmutableArray.Create <IDependenciesSnapshotFilter>(snapshotFilter),
                new Dictionary <string, IProjectDependenciesSubTreeProvider>(),
                null);

            Assert.NotSame(previousSnapshot, snapshot);

            Assert.Same(previousSnapshot.TargetFramework, snapshot.TargetFramework);
            Assert.Same(previousSnapshot.ProjectPath, snapshot.ProjectPath);
            Assert.Same(previousSnapshot.Catalogs, snapshot.Catalogs);

            AssertEx.CollectionLength(snapshot.TopLevelDependencies, 2);
            Assert.Contains(dependencyTop1, snapshot.TopLevelDependencies);
            Assert.Contains(filterAddedDependency, snapshot.TopLevelDependencies);

            AssertEx.CollectionLength(snapshot.DependenciesWorld, 3);
            Assert.Contains(dependencyTop1, snapshot.DependenciesWorld.Values);
            Assert.Contains(dependencyChild1, snapshot.DependenciesWorld.Values);
            Assert.Contains(filterAddedDependency, snapshot.DependenciesWorld.Values);
        }