Exemple #1
0
        public void BeforeAddOrUpdate_WhenUnresolvedAndExistsResolvedInSnapshot_ShouldReturnNull()
        {
            var unresolvedDependency = new TestDependency {
                Id = "dependency", Resolved = false
            };
            var resolvedDependency = new TestDependency {
                Id = "dependency", Resolved = true
            };

            var dependencyById = new Dictionary <(string ProviderType, string ModelId), IDependency>
            {
                { (resolvedDependency.ProviderType, resolvedDependency.Id), resolvedDependency }
            };

            var context = new AddDependencyContext(dependencyById);

            var filter = new UnresolvedDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                unresolvedDependency,
                null !,
                null,
                context);

            // Dependency rejected
            Assert.Null(context.GetResult(filter));

            // Nothing else changed
            Assert.False(context.Changed);
        }
Exemple #2
0
        public void BeforeAddOrUpdate_WhenUnresolvedAndNotExistsResolvedInSnapshot_ShouldReturnDependency()
        {
            var unresolvedDependency = new TestDependency {
                Id = "dependency", Resolved = false
            };

            var dependencyById = new Dictionary <string, IDependency>();

            var context = new AddDependencyContext(dependencyById);

            var filter = new UnresolvedDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                null !,
                unresolvedDependency,
                null !,
                null,
                context);

            // Dependency accepted unchanged
            Assert.Same(unresolvedDependency, context.GetResult(filter));

            // Nothing else changed
            Assert.False(context.Changed);
        }
        public void BeforeAddOrUpdate_WhenResolved_ShouldReturnDependency()
        {
            var resolvedDependency = new TestDependency {
                Id = "dependency", Resolved = true
            };

            var worldBuilder = ImmutableDictionary <string, IDependency> .Empty.ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new UnresolvedDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                null,
                resolvedDependency,
                null,
                null,
                context);

            // Dependency accepted unchanged
            Assert.Same(resolvedDependency, context.GetResult(filter));

            // Nothing else changed
            Assert.False(context.Changed);
        }
        public void BeforeAddOrUpdate_WhenUnresolvedAndExistsResolvedInSnapshot_ShouldReturnNull()
        {
            var unresolvedDependency = new TestDependency {
                Id = "dependency", Resolved = false
            };
            var resolvedDependency = new TestDependency {
                Id = "dependency", Resolved = true
            };

            var worldBuilder = new IDependency[] { resolvedDependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new UnresolvedDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                null,
                unresolvedDependency,
                null,
                null,
                context);

            // Dependency rejected
            Assert.Null(context.GetResult(filter));

            // Nothing else changed
            Assert.False(context.Changed);
        }
Exemple #5
0
            public void BeforeAddOrUpdate(
                IDependency dependency,
                AddDependencyContext context)
            {
                (string ProviderType, string Id)key = (dependency.ProviderType, dependency.Id);

                if (_beforeAdd.TryGetValue(key, out (FilterAction Action, IDependency? Dependency)info))
                {
                    if (info.Action == FilterAction.Reject)
                    {
                        context.Reject();

                        if (info.Dependency != null)
                        {
                            context.AddOrUpdate(info.Dependency);
                        }
                    }
                    else if (info.Action == FilterAction.Accept)
                    {
                        context.Accept(info.Dependency ?? dependency);
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }

                    _beforeAdd.Remove(key);
                }
                else
                {
                    throw new ArgumentException("Unexpected dependency: " + key);
                }
            }
Exemple #6
0
        public void BeforeAddOrUpdate_WhenDependencyNotRecognized_ShouldDoNothing()
        {
            var acceptable = new TestDependency
            {
                Id       = "dependency1",
                TopLevel = true,
                Resolved = true,
                Flags    = DependencyTreeFlags.ProjectNodeFlags
            };

            AssertNoChange(new TestDependency
            {
                ClonePropertiesFrom = acceptable,
                TopLevel            = false
            });

            AssertNoChange(new TestDependency
            {
                ClonePropertiesFrom = acceptable,
                Resolved            = false
            });

            AssertNoChange(new TestDependency
            {
                ClonePropertiesFrom = acceptable,
                Flags = ProjectTreeFlags.Empty
            });

            AssertNoChange(new TestDependency
            {
                ClonePropertiesFrom = acceptable,
                Flags = DependencyTreeFlags.ProjectNodeFlags.Union(DependencyTreeFlags.SharedProjectFlags)
            });

            return;

            void AssertNoChange(IDependency dependency)
            {
                var aggregateSnapshotProvider = IAggregateDependenciesSnapshotProviderFactory.Create();

                var worldBuilder = new[] { dependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

                var context = new AddDependencyContext(worldBuilder);

                var filter = new UnsupportedProjectsSnapshotFilter(aggregateSnapshotProvider);

                filter.BeforeAddOrUpdate(
                    null,
                    dependency,
                    null,
                    null,
                    context);

                // Accepts unchanged dependency
                Assert.Same(dependency, context.GetResult(filter));

                // No other changes made
                Assert.False(context.Changed);
            }
        }
        public void BeforeAddOrUpdate_WhenNeedToApplyImplicit_ShouldSetProperties()
        {
            const string providerType    = "providerType";
            const string projectItemSpec = "projectItemSpec";
            var          implicitIcon    = KnownMonikers.Abbreviation;

            var dependency = new TestDependency
            {
                Id               = "dependency1",
                ProviderType     = providerType,
                Implicit         = false,
                Resolved         = true,
                Flags            = DependencyTreeFlags.GenericResolvedDependencyFlags,
                OriginalItemSpec = projectItemSpec,
                IconSet          = new DependencyIconSet(KnownMonikers.Reference, KnownMonikers.Reference, KnownMonikers.Reference, KnownMonikers.Reference)
            };

            var dependencyById = new Dictionary <(string ProviderType, string ModelId), IDependency>
            {
                { (dependency.ProviderType, dependency.Id), dependency }
            };

            var context = new AddDependencyContext(dependencyById);

            var filter = new ImplicitDependenciesSnapshotFilter();

            var subTreeProvider = IProjectDependenciesSubTreeProviderFactory.ImplementInternal(
                providerType: providerType,
                implicitIcon: implicitIcon);

            filter.BeforeAddOrUpdate(
                dependency,
                new Dictionary <string, IProjectDependenciesSubTreeProvider> {
                { providerType, subTreeProvider }
            },
                ImmutableHashSet <string> .Empty,
                context);

            var acceptedDependency = context.GetResult(filter);

            // Returns changed dependency
            Assert.NotNull(acceptedDependency);
            Assert.NotSame(dependency, acceptedDependency);
            DependencyAssert.Equal(
                new TestDependency
            {
                ClonePropertiesFrom = dependency,
                Implicit            = true,
                IconSet             = new DependencyIconSet(
                    implicitIcon,
                    implicitIcon,
                    KnownMonikers.Reference,
                    KnownMonikers.Reference),
                Flags = DependencyTreeFlags.GenericResolvedDependencyFlags.Except(DependencyTreeFlags.SupportsRemove)
            }, acceptedDependency !);

            // No other changes made
            Assert.False(context.Changed);
        }
Exemple #8
0
        public void BeforeAddOrUpdate_WhenNeedToApplyImplicit_ShouldSetProperties()
        {
            const string providerType    = "providerType";
            const string projectItemSpec = "projectItemSpec";
            var          implicitIcon    = KnownMonikers.Abbreviation;

            var dependency = new TestDependency
            {
                Id               = "dependency1",
                ProviderType     = providerType,
                TopLevel         = true,
                Implicit         = false,
                Resolved         = true,
                Flags            = DependencyTreeFlags.GenericDependencyFlags,
                OriginalItemSpec = projectItemSpec,
                IconSet          = new DependencyIconSet(KnownMonikers.Reference, KnownMonikers.Reference, KnownMonikers.Reference, KnownMonikers.Reference)
            };

            var worldBuilder = new IDependency[] { dependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new ImplicitTopLevelDependenciesSnapshotFilter();

            var subTreeProvider = IProjectDependenciesSubTreeProviderFactory.ImplementInternal(
                providerType: providerType,
                implicitIcon: implicitIcon);

            filter.BeforeAddOrUpdate(
                null,
                null,
                dependency,
                new Dictionary <string, IProjectDependenciesSubTreeProvider> {
                { providerType, subTreeProvider }
            },
                ImmutableHashSet <string> .Empty,
                context);

            var acceptedDependency = context.GetResult(filter);

            // Returns changed dependency
            Assert.NotNull(acceptedDependency);
            Assert.NotSame(dependency, acceptedDependency);

            acceptedDependency.AssertEqualTo(
                new TestDependency
            {
                ClonePropertiesFrom = dependency,
                Implicit            = true,
                IconSet             = new DependencyIconSet(
                    implicitIcon,
                    implicitIcon,
                    KnownMonikers.Reference,
                    KnownMonikers.Reference)
            });

            // No other changes made
            Assert.False(context.Changed);
        }
Exemple #9
0
        public void BeforeAddOrUpdate_WhenThereIsMatchingDependencies_ShouldUpdateCaptionForAll()
        {
            // Both top level
            // Same provider type
            // Same captions
            //   -> Changes caption for both to match alias

            const string providerType = "provider";
            const string caption      = "caption1";

            var dependency = new TestDependency
            {
                Id           = "dependency1",
                Alias        = "dependency1 (dependency1ItemSpec)",
                ProviderType = providerType,
                Caption      = caption,
                TopLevel     = true
            };

            var otherDependency = new TestDependency
            {
                ClonePropertiesFrom = dependency, // clone, with changes

                Id    = "dependency2",
                Alias = "dependency2 (dependency2ItemSpec)"
            };

            var worldBuilder = new IDependency[] { dependency, otherDependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new DuplicatedDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                null,
                null,
                dependency,
                null,
                null,
                context);

            // The context changed, beyond just the filtered dependency
            Assert.True(context.Changed);

            // The filtered dependency had its caption changed to its alias
            var dependencyAfter = context.GetResult(filter);

            dependencyAfter.AssertEqualTo(
                new TestDependency {
                ClonePropertiesFrom = dependency, Caption = dependency.Alias
            });

            // The other dependency had its caption changed to its alias
            Assert.True(context.TryGetDependency(otherDependency.Id, out IDependency otherDependencyAfter));
            otherDependencyAfter.AssertEqualTo(
                new TestDependency {
                ClonePropertiesFrom = otherDependency, Caption = otherDependency.Alias
            });
        }
        public void BeforeAddOrUpdate_WhenThereIsMatchingDependencyWithAliasApplied_ShouldUpdateCaptionForCurrentDependency()
        {
            // Both top level
            // Same provider type
            // Duplicate caption, though with parenthesized text after one instance
            //   -> Changes caption of non-parenthesized

            const string providerType = "provider";
            const string caption      = "caption";

            var dependency = new TestDependency
            {
                Id = "id1",
                OriginalItemSpec = "originalItemSpec1",
                ProviderType     = providerType,
                Caption          = caption,
                TopLevel         = true
            };

            var otherDependency = new TestDependency
            {
                ClonePropertiesFrom = dependency,

                Id = "id2",
                OriginalItemSpec = "originalItemSpec2",
                Caption          = $"{caption} (originalItemSpec2)" // caption already includes alias
            };

            var worldBuilder = new IDependency[] { dependency, otherDependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new DeduplicateCaptionsSnapshotFilter();

            filter.BeforeAddOrUpdate(
                null !,
                dependency,
                null !,
                null,
                context);

            // The context was unchanged, beyond the filtered dependency
            Assert.False(context.Changed);

            // The filtered dependency had its caption changed to its alias
            var dependencyAfter = context.GetResult(filter);

            DependencyAssert.Equal(new TestDependency {
                ClonePropertiesFrom = dependency, Caption = "caption (originalItemSpec1)"
            }, dependencyAfter !);

            // The other dependency had its caption changed to its alias
            Assert.True(context.TryGetDependency(otherDependency.Id, out IDependency otherDependencyAfter));
            DependencyAssert.Equal(new TestDependency {
                ClonePropertiesFrom = otherDependency, Caption = "caption (originalItemSpec2)"
            }, otherDependencyAfter);
        }
        public void BeforeAddOrUpdate_WhenThereIsMatchingDependencies_ShouldUpdateCaptionForAll()
        {
            // Same provider type
            // Same captions
            //   -> Changes caption for both to match alias

            const string providerType = "provider";
            const string caption      = "caption";

            var dependency = new TestDependency
            {
                Id = "id1",
                OriginalItemSpec = "originalItemSpec1",
                ProviderType     = providerType,
                Caption          = caption
            };

            var otherDependency = new TestDependency
            {
                ClonePropertiesFrom = dependency, // clone, with changes

                Id = "id2",
                OriginalItemSpec = "originalItemSpec2"
            };

            var dependencyById = new IDependency[] { dependency, otherDependency }.ToDictionary(d => d.Id);

            var context = new AddDependencyContext(dependencyById);

            var filter = new DeduplicateCaptionsSnapshotFilter();

            filter.BeforeAddOrUpdate(
                null !,
                dependency,
                null !,
                null,
                context);

            // The context changed, beyond just the filtered dependency
            Assert.True(context.Changed);

            // The filtered dependency had its caption changed to its alias
            var dependencyAfter = context.GetResult(filter);

            DependencyAssert.Equal(new TestDependency {
                ClonePropertiesFrom = dependency, Caption = "caption (originalItemSpec1)"
            }, dependencyAfter !);

            // The other dependency had its caption changed to its alias
            Assert.True(context.TryGetDependency(otherDependency.Id, out IDependency otherDependencyAfter));
            DependencyAssert.Equal(new TestDependency {
                ClonePropertiesFrom = otherDependency, Caption = "caption (originalItemSpec2)"
            }, otherDependencyAfter);
        }
Exemple #12
0
        public void BeforeAddOrUpdate_WhenProjectSnapshotFoundAndHasUnresolvedDependencies_ShouldMakeUnresolved()
        {
            const string projectPath = @"c:\project\project.csproj";

            var targetFramework  = ITargetFrameworkFactory.Implement(moniker: "tfm1");
            var targetedSnapshot = ITargetedDependenciesSnapshotFactory.Implement(hasUnresolvedDependency: true);
            var targets          = new Dictionary <ITargetFramework, ITargetedDependenciesSnapshot>
            {
                { targetFramework, targetedSnapshot }
            };
            var snapshot                  = IDependenciesSnapshotFactory.Implement(targets: targets);
            var snapshotProvider          = IDependenciesSnapshotProviderFactory.Implement(currentSnapshot: snapshot);
            var aggregateSnapshotProvider = new Mock <IAggregateDependenciesSnapshotProvider>(MockBehavior.Strict);

            aggregateSnapshotProvider.Setup(x => x.GetSnapshotProvider(projectPath)).Returns(snapshotProvider);

            var targetFrameworkProvider = ITargetFrameworkProviderFactory.Implement(getNearestFramework: targetFramework);

            var dependency = new TestDependency
            {
                Id              = "dependency1",
                TopLevel        = true,
                Resolved        = true,
                Flags           = DependencyTreeFlags.ProjectNodeFlags.Union(DependencyTreeFlags.ResolvedFlags),
                TargetFramework = targetFramework,
                FullPath        = projectPath
            };

            var worldBuilder = ImmutableDictionary <string, IDependency> .Empty.ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new UnsupportedProjectsSnapshotFilter(aggregateSnapshotProvider.Object, targetFrameworkProvider);

            filter.BeforeAddOrUpdate(
                null,
                null,
                dependency,
                null,
                null,
                context);

            // Accepts unresolved version
            var acceptedDependency = context.GetResult(filter);

            acceptedDependency.AssertEqualTo(
                dependency.ToUnresolved(ProjectReference.SchemaName));

            // No other changes made
            Assert.False(context.Changed);

            aggregateSnapshotProvider.VerifyAll();
        }
Exemple #13
0
        public void BeforeAddOrUpdate_WhenSdk_ShouldFindMatchingPackageAndSetProperties()
        {
            var dependencyIDs = ImmutableList.Create("id1", "id2");

            var targetFramework = new TargetFramework("tfm");

            const string sdkName = "sdkName";

            var sdkDependency = new TestDependency
            {
                Id       = "dependency1Id",
                Name     = sdkName,
                TopLevel = true,
                Resolved = false,
                Flags    = DependencyTreeFlags.SdkSubTreeNodeFlags
            };

            var packageDependency = new TestDependency
            {
                Id            = Dependency.GetID(targetFramework, PackageRuleHandler.ProviderTypeString, sdkName),
                Resolved      = true,
                DependencyIDs = dependencyIDs,
                Flags         = DependencyTreeFlags.PackageNodeFlags
            };

            var worldBuilder = new IDependency[] { sdkDependency, packageDependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new SdkAndPackagesDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                null,
                targetFramework,
                sdkDependency,
                null,
                null,
                context);

            var acceptedDependency = context.GetResult(filter);

            // Dependency should be accepted, but converted to resolved state
            Assert.NotNull(acceptedDependency);
            Assert.NotSame(sdkDependency, acceptedDependency);
            acceptedDependency.AssertEqualTo(
                sdkDependency.ToResolved(
                    schemaName: ResolvedSdkReference.SchemaName,
                    dependencyIDs: dependencyIDs));

            // No changes other than the filtered dependency
            Assert.False(context.Changed);
        }
Exemple #14
0
        public void BeforeAddOrUpdate_WhenPackage_ShouldFindMatchingSdkAndSetProperties()
        {
            var dependencyIDs = ImmutableList.Create("id1", "id2");

            var targetFramework = new TargetFramework("tfm");

            const string packageName = "packageName";

            var sdkDependency = new TestDependency
            {
                Id       = Dependency.GetID(targetFramework, SdkRuleHandler.ProviderTypeString, packageName),
                TopLevel = false,
                Resolved = true,
                Flags    = DependencyTreeFlags.PackageNodeFlags.Union(DependencyTreeFlags.UnresolvedFlags) // to see if unresolved is fixed
            };

            var packageDependency = new TestDependency
            {
                Id            = "packageId",
                Name          = packageName,
                Flags         = DependencyTreeFlags.PackageNodeFlags,
                TopLevel      = true,
                Resolved      = true,
                DependencyIDs = dependencyIDs
            };

            var worldBuilder = new IDependency[] { packageDependency, sdkDependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new SdkAndPackagesDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                null,
                targetFramework,
                packageDependency,
                null,
                null,
                context);

            // Accepts unchanged dependency
            Assert.Same(packageDependency, context.GetResult(filter));

            // Other changes made
            Assert.True(context.Changed);

            Assert.True(context.TryGetDependency(sdkDependency.Id, out IDependency sdkDependencyAfter));
            sdkDependencyAfter.AssertEqualTo(
                sdkDependency.ToResolved(
                    schemaName: ResolvedSdkReference.SchemaName,
                    dependencyIDs: dependencyIDs));
        }
Exemple #15
0
        public void BeforeAddOrUpdate_WhenThereIsMatchingDependency_WithSubstringCaption()
        {
            // Both top level
            // Same provider type
            // Duplicate caption prefix
            //   -> No change

            const string providerType = "provider";
            const string caption      = "caption";

            var dependency = new TestDependency
            {
                Id           = "dependency1",
                ProviderType = providerType,
                Caption      = caption,
                TopLevel     = true
            };

            var otherDependency = new TestDependency
            {
                ClonePropertiesFrom = dependency,

                Id = "dependency2",
                OriginalItemSpec = "dependency2ItemSpec",
                Caption          = $"{caption}X" // identical caption prefix
            };

            // TODO test a longer suffix here -- looks like the implementation might not handle it correctly

            var worldBuilder = new IDependency[] { dependency, otherDependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new DuplicatedDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                null,
                null,
                dependency,
                null,
                null,
                context);

            // Accepts unchanged dependency
            Assert.Same(dependency, context.GetResult(filter));

            // No other changes made
            Assert.False(context.Changed);
        }
        public void BeforeAddOrUpdate_WhenPackage_ShouldFindMatchingSdkAndSetProperties()
        {
            var targetFramework = new TargetFramework("tfm");

            const string packageName = "packageName";

            var sdkDependency = new TestDependency
            {
                Id       = Dependency.GetID(targetFramework, SdkRuleHandler.ProviderTypeString, packageName),
                Resolved = true,
                Flags    = DependencyTreeFlags.PackageDependency.Union(DependencyTreeFlags.Unresolved) // to see if unresolved is fixed
            };

            var packageDependency = new TestDependency
            {
                Id       = "packageId",
                Name     = packageName,
                Flags    = DependencyTreeFlags.PackageDependency,
                Resolved = true
            };

            var builder = new IDependency[] { packageDependency, sdkDependency }.ToDictionary(d => d.Id);

            var context = new AddDependencyContext(builder);

            var filter = new SdkAndPackagesDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                targetFramework,
                packageDependency,
                null !,
                null,
                context);

            // Accepts unchanged dependency
            Assert.Same(packageDependency, context.GetResult(filter));

            // Other changes made
            Assert.True(context.Changed);

            Assert.True(context.TryGetDependency(sdkDependency.Id, out IDependency sdkDependencyAfter));
            DependencyAssert.Equal(
                sdkDependency.ToResolved(
                    schemaName: ResolvedSdkReference.SchemaName), sdkDependencyAfter);
        }
Exemple #17
0
        public void BeforeAddOrUpdate_NoDuplicate_ShouldNotUpdateCaption()
        {
            // Both top level
            // Same provider type
            // Different captions
            //   -> No change

            const string providerType = "provider";

            var dependency = new TestDependency
            {
                Id           = "dependency1",
                Caption      = "caption1",
                ProviderType = providerType,
                TopLevel     = true
            };

            var otherDependency = new TestDependency
            {
                Id           = "dependency2",
                Caption      = "caption2",
                ProviderType = providerType,
                TopLevel     = true
            };

            var worldBuilder = new IDependency[] { dependency, otherDependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new DuplicatedDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                null,
                null,
                dependency,
                null,
                null,
                context);

            // Accepts unchanged dependency
            Assert.Same(dependency, context.GetResult(filter));

            // No other changes made
            Assert.False(context.Changed);
        }
        public void BeforeAddOrUpdate_WhenSdk_ShouldFindMatchingPackageAndSetProperties()
        {
            const string sdkName = "sdkName";

            var sdkDependency = new TestDependency
            {
                Id           = sdkName,
                ProviderType = SdkRuleHandler.ProviderTypeString,
                Resolved     = false,
                Flags        = DependencyTreeFlags.SdkDependency
            };

            var packageDependency = new TestDependency
            {
                Id           = sdkName,
                ProviderType = PackageRuleHandler.ProviderTypeString,
                Resolved     = true,
                Flags        = DependencyTreeFlags.PackageDependency
            };

            var builder = new IDependency[] { sdkDependency, packageDependency }.ToDictionary(IDependencyExtensions.GetDependencyId);

            var context = new AddDependencyContext(builder);

            var filter = new SdkAndPackagesDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                sdkDependency,
                null !,
                null,
                context);

            var acceptedDependency = context.GetResult(filter);

            // Dependency should be accepted, but converted to resolved state
            Assert.NotNull(acceptedDependency);
            Assert.NotSame(sdkDependency, acceptedDependency);
            DependencyAssert.Equal(
                sdkDependency.ToResolved(schemaName: ResolvedSdkReference.SchemaName, diagnosticLevel: DiagnosticLevel.None),
                acceptedDependency !);

            // No changes other than the filtered dependency
            Assert.False(context.Changed);
        }
Exemple #19
0
        public void BeforeAddOrUpdate_WhenProjectSnapshotFoundAndNoUnresolvedDependencies_ShouldDoNothing()
        {
            const string projectPath = @"c:\project\project.csproj";

            var targetFramework  = ITargetFrameworkFactory.Implement(moniker: "tfm1");
            var targetedSnapshot = ITargetedDependenciesSnapshotFactory.Implement(hasUnresolvedDependency: false);

            var dependency = new TestDependency
            {
                Id              = "dependency1",
                TopLevel        = true,
                Resolved        = true,
                Flags           = DependencyTreeFlags.ProjectNodeFlags.Union(DependencyTreeFlags.ResolvedFlags),
                FullPath        = projectPath,
                TargetFramework = targetFramework
            };

            var aggregateSnapshotProvider = new Mock <IAggregateDependenciesSnapshotProvider>(MockBehavior.Strict);

            aggregateSnapshotProvider.Setup(x => x.GetSnapshot(dependency)).Returns(targetedSnapshot);

            var worldBuilder = ImmutableDictionary <string, IDependency> .Empty.ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new UnsupportedProjectsSnapshotFilter(aggregateSnapshotProvider.Object);

            filter.BeforeAddOrUpdate(
                null,
                null,
                dependency,
                null,
                null,
                context);

            // Accepts unchanged dependency
            Assert.Same(dependency, context.GetResult(filter));

            // No other changes made
            Assert.False(context.Changed);

            aggregateSnapshotProvider.VerifyAll();
        }
        public void BeforeAddOrUpdate_WhenPackage_ShouldFindMatchingSdkAndSetProperties()
        {
            const string packageName = "packageName";

            var sdkDependency = new TestDependency
            {
                Id           = packageName,
                ProviderType = SdkRuleHandler.ProviderTypeString,
                Resolved     = true,
                Flags        = DependencyTreeFlags.PackageDependency.Union(ProjectTreeFlags.BrokenReference) // to see if unresolved is fixed
            };

            var packageDependency = new TestDependency
            {
                Id           = packageName,
                ProviderType = PackageRuleHandler.ProviderTypeString,
                Flags        = DependencyTreeFlags.PackageDependency,
                Resolved     = true
            };

            var builder = new IDependency[] { packageDependency, sdkDependency }.ToDictionary(IDependencyExtensions.GetDependencyId);

            var context = new AddDependencyContext(builder);

            var filter = new SdkAndPackagesDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                packageDependency,
                null !,
                null,
                context);

            // Accepts unchanged dependency
            Assert.Same(packageDependency, context.GetResult(filter));

            // Other changes made
            Assert.True(context.Changed);

            Assert.True(context.TryGetDependency(sdkDependency.GetDependencyId(), out IDependency sdkDependencyAfter));
            DependencyAssert.Equal(
                sdkDependency.ToResolved(schemaName: ResolvedSdkReference.SchemaName, diagnosticLevel: DiagnosticLevel.None),
                sdkDependencyAfter);
        }
Exemple #21
0
        public void BeforeAddOrUpdate_WhenSdkAndPackageUnresolved_ShouldDoNothing()
        {
            var targetFramework = new TargetFramework("tfm");

            const string sdkName = "sdkName";

            var sdkDependency = new TestDependency
            {
                Id       = "dependency1",
                Name     = sdkName,
                TopLevel = false,
                Resolved = true,
                Flags    = DependencyTreeFlags.SdkSubTreeNodeFlags
            };

            var packageDependency = new TestDependency
            {
                Id       = Dependency.GetID(targetFramework, PackageRuleHandler.ProviderTypeString, sdkName),
                Resolved = false,
                Flags    = DependencyTreeFlags.PackageNodeFlags
            };

            var worldBuilder = new IDependency[] { sdkDependency, packageDependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = new SdkAndPackagesDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                null,
                targetFramework,
                sdkDependency,
                null,
                null,
                context);

            // Accepts unchanged dependency
            Assert.Same(sdkDependency, context.GetResult(filter));

            // No other changes made
            Assert.False(context.Changed);
        }
        private protected void VerifyUnchangedOnAdd(IDependency dependency, IImmutableSet <string> projectItemSpecs = null)
        {
            var worldBuilder = new[] { dependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

            var context = new AddDependencyContext(worldBuilder);

            var filter = CreateFilter();

            filter.BeforeAddOrUpdate(
                null,
                dependency,
                null,
                projectItemSpecs,
                context);

            // Accepts unchanged dependency
            Assert.Same(dependency, context.GetResult(filter));

            // No other changes made
            Assert.False(context.Changed);
        }
        public void BeforeAddOrUpdate_NoDuplicate_ShouldNotUpdateCaption()
        {
            // Same provider type
            // Different captions
            //   -> No change

            const string providerType = "provider";

            var dependency = new TestDependency
            {
                Id           = "dependency1",
                Caption      = "caption1",
                ProviderType = providerType
            };

            var otherDependency = new TestDependency
            {
                Id           = "dependency2",
                Caption      = "caption2",
                ProviderType = providerType
            };

            var dependencyById = new IDependency[] { dependency, otherDependency }.ToDictionary(IDependencyExtensions.GetDependencyId);

            var context = new AddDependencyContext(dependencyById);

            var filter = new DeduplicateCaptionsSnapshotFilter();

            filter.BeforeAddOrUpdate(
                dependency,
                null !,
                null,
                context);

            // Accepts unchanged dependency
            Assert.Same(dependency, context.GetResult(filter));

            // No other changes made
            Assert.False(context.Changed);
        }
        public void BeforeAddOrUpdate_WhenSdkAndPackageUnresolved_ShouldDoNothing()
        {
            const string sdkName = "sdkName";

            var sdkDependency = new TestDependency
            {
                Id               = "dependency1",
                ProviderType     = SdkRuleHandler.ProviderTypeString,
                OriginalItemSpec = sdkName,
                Resolved         = true,
                Flags            = DependencyTreeFlags.SdkDependency
            };

            var packageDependency = new TestDependency
            {
                Id           = sdkName,
                ProviderType = PackageRuleHandler.ProviderTypeString,
                Resolved     = false,
                Flags        = DependencyTreeFlags.PackageDependency
            };

            var builder = new IDependency[] { sdkDependency, packageDependency }.ToDictionary(IDependencyExtensions.GetDependencyId);

            var context = new AddDependencyContext(builder);

            var filter = new SdkAndPackagesDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                sdkDependency,
                null !,
                null,
                context);

            // Accepts unchanged dependency
            Assert.Same(sdkDependency, context.GetResult(filter));

            // No other changes made
            Assert.False(context.Changed);
        }
        public void BeforeAddOrUpdate_WhenResolved_ShouldReturnDependency()
        {
            var resolvedDependency = new TestDependency {
                Id = "dependency", Resolved = true
            };

            var dependencyById = new Dictionary <DependencyId, IDependency>();

            var context = new AddDependencyContext(dependencyById);

            var filter = new UnresolvedDependenciesSnapshotFilter();

            filter.BeforeAddOrUpdate(
                resolvedDependency,
                context);

            // Dependency accepted unchanged
            Assert.Same(resolvedDependency, context.GetResult(filter));

            // Nothing else changed
            Assert.False(context.Changed);
        }
        private protected void VerifyUnchangedOnAdd(IDependency dependency, IImmutableSet <string>?projectItemSpecs = null)
        {
            var dependencyById = new Dictionary <(string ProviderType, string ModelId), IDependency>
            {
                { (dependency.ProviderType, dependency.Id), dependency }
            };

            var context = new AddDependencyContext(dependencyById);

            var filter = CreateFilter();

            filter.BeforeAddOrUpdate(
                dependency,
                null !,
                projectItemSpecs,
                context);

            // Accepts unchanged dependency
            Assert.Same(dependency, context.GetResult(filter));

            // No other changes made
            Assert.False(context.Changed);
        }
            static void AssertNoChange(IDependency dependency)
            {
                var aggregateSnapshotProvider = IAggregateDependenciesSnapshotProviderFactory.Create();

                var worldBuilder = new[] { dependency }.ToImmutableDictionary(d => d.Id).ToBuilder();

                var context = new AddDependencyContext(worldBuilder);

                var filter = new UnresolvedProjectReferenceSnapshotFilter(aggregateSnapshotProvider);

                filter.BeforeAddOrUpdate(
                    null !,
                    dependency,
                    null !,
                    null,
                    context);

                // Accepts unchanged dependency
                Assert.Same(dependency, context.GetResult(filter));

                // No other changes made
                Assert.False(context.Changed);
            }
        /// <summary>
        /// Applies changes to <paramref name="previousSnapshot"/> and produces a new snapshot if required.
        /// If no changes are made, <paramref name="previousSnapshot"/> is returned unmodified.
        /// </summary>
        /// <returns>An updated snapshot, or <paramref name="previousSnapshot"/> if no changes occurred.</returns>
        public static TargetedDependenciesSnapshot FromChanges(
            TargetedDependenciesSnapshot previousSnapshot,
            IDependenciesChanges?changes,
            IProjectCatalogSnapshot?catalogs,
            ImmutableArray <IDependenciesSnapshotFilter> snapshotFilters)
        {
            Requires.NotNull(previousSnapshot, nameof(previousSnapshot));
            Requires.Argument(!snapshotFilters.IsDefault, nameof(snapshotFilters), "Cannot be default.");

            bool anyChanges = false;

            TargetFramework targetFramework = previousSnapshot.TargetFramework;

            var dependencyById = previousSnapshot.Dependencies.ToDictionary(IDependencyExtensions.GetDependencyId);

            if (changes != null && changes.RemovedNodes.Count != 0)
            {
                foreach (IDependencyModel removed in changes.RemovedNodes)
                {
                    dependencyById.Remove(removed.GetDependencyId());
                }

                anyChanges = true;
            }

            if (changes != null && changes.AddedNodes.Count != 0)
            {
                var context = new AddDependencyContext(dependencyById);

                foreach (IDependencyModel added in changes.AddedNodes)
                {
#pragma warning disable CS0618 // Type or member is obsolete
                    // NOTE we still need to check this in case extensions (eg. WebTools) provide us with top level items that need to be filtered out
                    if (!added.TopLevel)
                    {
                        continue;
                    }
#pragma warning restore CS0618 // Type or member is obsolete

                    Add(context, added);
                }
            }

            // Also factor in any changes to path/framework/catalogs
            anyChanges =
                anyChanges ||
                !targetFramework.Equals(previousSnapshot.TargetFramework) ||
                !Equals(catalogs, previousSnapshot.Catalogs);

            if (anyChanges)
            {
                return(new TargetedDependenciesSnapshot(
                           targetFramework,
                           catalogs,
                           dependencyById.ToImmutableValueArray()));
            }

            return(previousSnapshot);

            void Add(AddDependencyContext context, IDependencyModel dependencyModel)
            {
                // Create the unfiltered dependency
                IDependency?dependency = new Dependency(dependencyModel);

                context.Reset();

                foreach (IDependenciesSnapshotFilter filter in snapshotFilters)
                {
                    filter.BeforeAddOrUpdate(
                        dependency,
                        context);

                    dependency = context.GetResult(filter);

                    if (dependency == null)
                    {
                        break;
                    }
                }

                if (dependency != null)
                {
                    // A dependency was accepted
                    DependencyId id = dependencyModel.GetDependencyId();
                    dependencyById.Remove(id);
                    dependencyById.Add(id, dependency);
                    anyChanges = true;
                }
                else
                {
                    // Even though the dependency was rejected, it's possible that filters made
                    // changes to other dependencies.
                    anyChanges |= context.Changed;
                }
            }
        }
        /// <summary>
        /// Applies changes to <paramref name="previousSnapshot"/> and produces a new snapshot if required.
        /// If no changes are made, <paramref name="previousSnapshot"/> is returned unmodified.
        /// </summary>
        /// <returns>An updated snapshot, or <paramref name="previousSnapshot"/> if no changes occured.</returns>
        public static TargetedDependenciesSnapshot FromChanges(
            string projectPath,
            TargetedDependenciesSnapshot previousSnapshot,
            IDependenciesChanges changes,
            IProjectCatalogSnapshot?catalogs,
            ImmutableArray <IDependenciesSnapshotFilter> snapshotFilters,
            IReadOnlyDictionary <string, IProjectDependenciesSubTreeProvider> subTreeProviderByProviderType,
            IImmutableSet <string>?projectItemSpecs)
        {
            Requires.NotNullOrWhiteSpace(projectPath, nameof(projectPath));
            Requires.NotNull(previousSnapshot, nameof(previousSnapshot));
            Requires.NotNull(changes, nameof(changes));
            Requires.Argument(!snapshotFilters.IsDefault, nameof(snapshotFilters), "Cannot be default.");
            Requires.NotNull(subTreeProviderByProviderType, nameof(subTreeProviderByProviderType));

            bool anyChanges = false;

            ITargetFramework targetFramework = previousSnapshot.TargetFramework;

            var worldBuilder = previousSnapshot.DependenciesWorld.ToBuilder();

            if (changes.RemovedNodes.Count != 0)
            {
                var context = new RemoveDependencyContext(worldBuilder);

                foreach (IDependencyModel removed in changes.RemovedNodes)
                {
                    Remove(context, removed);
                }
            }

            if (changes.AddedNodes.Count != 0)
            {
                var context = new AddDependencyContext(worldBuilder);

                foreach (IDependencyModel added in changes.AddedNodes)
                {
                    Add(context, added);
                }
            }

            // Also factor in any changes to path/framework/catalogs
            anyChanges =
                anyChanges ||
                !StringComparers.Paths.Equals(projectPath, previousSnapshot.ProjectPath) ||
                !targetFramework.Equals(previousSnapshot.TargetFramework) ||
                !Equals(catalogs, previousSnapshot.Catalogs);

            if (anyChanges)
            {
                return(new TargetedDependenciesSnapshot(
                           projectPath,
                           targetFramework,
                           catalogs,
                           worldBuilder.ToImmutable()));
            }

            return(previousSnapshot);

            void Remove(RemoveDependencyContext context, IDependencyModel dependencyModel)
            {
                string dependencyId = Dependency.GetID(
                    targetFramework, dependencyModel.ProviderType, dependencyModel.Id);

                if (!context.TryGetDependency(dependencyId, out IDependency dependency))
                {
                    return;
                }

                context.Reset();

                foreach (IDependenciesSnapshotFilter filter in snapshotFilters)
                {
                    filter.BeforeRemove(
                        targetFramework,
                        dependency,
                        context);

                    anyChanges |= context.Changed;

                    if (!context.GetResult(filter))
                    {
                        // TODO breaking here denies later filters the opportunity to modify builders
                        return;
                    }
                }

                worldBuilder.Remove(dependencyId);
                anyChanges = true;
            }

            void Add(AddDependencyContext context, IDependencyModel dependencyModel)
            {
                // Create the unfiltered dependency
                IDependency?dependency = new Dependency(dependencyModel, targetFramework, projectPath);

                context.Reset();

                foreach (IDependenciesSnapshotFilter filter in snapshotFilters)
                {
                    filter.BeforeAddOrUpdate(
                        targetFramework,
                        dependency,
                        subTreeProviderByProviderType,
                        projectItemSpecs,
                        context);

                    dependency = context.GetResult(filter);

                    if (dependency == null)
                    {
                        break;
                    }
                }

                if (dependency != null)
                {
                    // A dependency was accepted
                    worldBuilder.Remove(dependency.Id);
                    worldBuilder.Add(dependency.Id, dependency);
                    anyChanges = true;
                }
                else
                {
                    // Even though the dependency was rejected, it's possible that filters made
                    // changes to other dependencies.
                    anyChanges |= context.Changed;
                }
            }
        }
        /// <summary>
        /// Applies changes to <paramref name="previousSnapshot"/> and produces a new snapshot if required.
        /// If no changes are made, <paramref name="previousSnapshot"/> is returned unmodified.
        /// </summary>
        /// <returns>An updated snapshot, or <paramref name="previousSnapshot"/> if no changes occured.</returns>
        public static TargetedDependenciesSnapshot FromChanges(
            TargetedDependenciesSnapshot previousSnapshot,
            IDependenciesChanges?changes,
            IProjectCatalogSnapshot?catalogs,
            ImmutableArray <IDependenciesSnapshotFilter> snapshotFilters,
            IReadOnlyDictionary <string, IProjectDependenciesSubTreeProvider> subTreeProviderByProviderType,
            IImmutableSet <string>?projectItemSpecs)
        {
            Requires.NotNull(previousSnapshot, nameof(previousSnapshot));
            Requires.Argument(!snapshotFilters.IsDefault, nameof(snapshotFilters), "Cannot be default.");
            Requires.NotNull(subTreeProviderByProviderType, nameof(subTreeProviderByProviderType));

            bool anyChanges = false;

            ITargetFramework targetFramework = previousSnapshot.TargetFramework;

            var dependencyById = previousSnapshot.Dependencies.ToDictionary(d => d.Id, StringComparers.DependencyTreeIds);

            if (changes != null && changes.RemovedNodes.Count != 0)
            {
                var context = new RemoveDependencyContext(dependencyById);

                foreach (IDependencyModel removed in changes.RemovedNodes)
                {
                    Remove(context, removed);
                }
            }

            if (changes != null && changes.AddedNodes.Count != 0)
            {
                var context = new AddDependencyContext(dependencyById);

                foreach (IDependencyModel added in changes.AddedNodes)
                {
#pragma warning disable CS0618 // Type or member is obsolete
                    // NOTE we still need to check this in case extensions (eg. WebTools) provide us with top level items that need to be filtered out
                    if (!added.TopLevel)
                    {
                        continue;
                    }
#pragma warning restore CS0618 // Type or member is obsolete

                    Add(context, added);
                }
            }

            // Also factor in any changes to path/framework/catalogs
            anyChanges =
                anyChanges ||
                !targetFramework.Equals(previousSnapshot.TargetFramework) ||
                !Equals(catalogs, previousSnapshot.Catalogs);

            if (anyChanges)
            {
                return(new TargetedDependenciesSnapshot(
                           targetFramework,
                           catalogs,
                           dependencyById.ToImmutableValueArray()));
            }

            return(previousSnapshot);

            void Remove(RemoveDependencyContext context, IDependencyModel dependencyModel)
            {
                string dependencyId = Dependency.GetID(
                    targetFramework, dependencyModel.ProviderType, dependencyModel.Id);

                if (!context.TryGetDependency(dependencyId, out IDependency dependency))
                {
                    return;
                }

                context.Reset();

                foreach (IDependenciesSnapshotFilter filter in snapshotFilters)
                {
                    filter.BeforeRemove(
                        targetFramework,
                        dependency,
                        context);

                    anyChanges |= context.Changed;

                    if (!context.GetResult(filter))
                    {
                        // TODO breaking here denies later filters the opportunity to modify builders
                        return;
                    }
                }

                dependencyById.Remove(dependencyId);
                anyChanges = true;
            }

            void Add(AddDependencyContext context, IDependencyModel dependencyModel)
            {
                // Create the unfiltered dependency
                IDependency?dependency = new Dependency(dependencyModel, targetFramework);

                context.Reset();

                foreach (IDependenciesSnapshotFilter filter in snapshotFilters)
                {
                    filter.BeforeAddOrUpdate(
                        targetFramework,
                        dependency,
                        subTreeProviderByProviderType,
                        projectItemSpecs,
                        context);

                    dependency = context.GetResult(filter);

                    if (dependency == null)
                    {
                        break;
                    }
                }

                if (dependency != null)
                {
                    // A dependency was accepted
                    dependencyById.Remove(dependency.Id);
                    dependencyById.Add(dependency.Id, dependency);
                    anyChanges = true;
                }
                else
                {
                    // Even though the dependency was rejected, it's possible that filters made
                    // changes to other dependencies.
                    anyChanges |= context.Changed;
                }
            }
        }