public void FromChanges_UpdatesLevelDependencies() { var targetFramework = new TargetFramework("tfm1"); var dependencyPrevious = new TestDependency { ProviderType = "Xxx", Id = "dependency1", OriginalItemSpec = "Dependency1", Caption = "Dependency1", SchemaItemType = "Xxx", Resolved = true }; var dependencyModelAdded = new TestDependencyModel { ProviderType = "Xxx", Id = "dependency1", OriginalItemSpec = "Dependency1", Caption = "Dependency1", SchemaItemType = "Xxx", Resolved = true, Icon = KnownMonikers.Uninstall, ExpandedIcon = KnownMonikers.Uninstall }; var dependencyUpdated = new TestDependency { ProviderType = "Xxx", Id = "dependency1", OriginalItemSpec = "Dependency1", Caption = "Dependency1", SchemaItemType = "Xxx", Resolved = true }; var catalogs = IProjectCatalogSnapshotFactory.Create(); var previousSnapshot = new TargetedDependenciesSnapshot( targetFramework, catalogs, ImmutableArray.Create <IDependency>(dependencyPrevious)); var changes = new DependenciesChangesBuilder(); changes.Added(dependencyModelAdded); var snapshotFilter = new TestDependenciesSnapshotFilter() .BeforeAddAccept("Xxx", "dependency1", dependencyUpdated); var snapshot = TargetedDependenciesSnapshot.FromChanges( previousSnapshot, changes.TryBuildChanges() !, catalogs, ImmutableArray.Create <IDependenciesSnapshotFilter>(snapshotFilter), new Dictionary <string, IProjectDependenciesSubTreeProvider>(), null); Assert.True(snapshotFilter.Completed); Assert.NotSame(previousSnapshot, snapshot); Assert.Same(dependencyUpdated, snapshot.Dependencies.Single()); }
public void FromChanges_ReportedChangesAfterBeforeAddFilterDeclinedChange() { var targetFramework = new TargetFramework("tfm1"); var dependency1 = new TestDependency { ProviderType = "Xxx", Id = "dependency1", OriginalItemSpec = "Dependency1", Caption = "Dependency1", SchemaItemType = "Xxx", Resolved = true }; var dependency2 = new TestDependency { ProviderType = "Xxx", Id = "dependency2", OriginalItemSpec = "Dependency2", Caption = "Dependency2", SchemaItemType = "Xxx", Resolved = true }; var dependencyModelNew1 = new TestDependencyModel { ProviderType = "Xxx", Id = "newdependency1", OriginalItemSpec = "NewDependency1", Caption = "NewDependency1", SchemaItemType = "Xxx", Resolved = true, Icon = KnownMonikers.Uninstall, ExpandedIcon = KnownMonikers.Uninstall }; var catalogs = IProjectCatalogSnapshotFactory.Create(); var previousSnapshot = new TargetedDependenciesSnapshot( targetFramework, catalogs, ImmutableArray.Create <IDependency>(dependency1, dependency2)); var changes = new DependenciesChangesBuilder(); changes.Added(dependencyModelNew1); var filterAddedDependency = new TestDependency { Id = "unexpected" }; var snapshotFilter = new TestDependenciesSnapshotFilter() .BeforeAddReject("Xxx", "newdependency1", addOrUpdate: filterAddedDependency); var snapshot = TargetedDependenciesSnapshot.FromChanges( previousSnapshot, changes.TryBuildChanges() !, catalogs, ImmutableArray.Create <IDependenciesSnapshotFilter>(snapshotFilter), new Dictionary <string, IProjectDependenciesSubTreeProvider>(), null); Assert.True(snapshotFilter.Completed); Assert.NotSame(previousSnapshot, snapshot); Assert.Same(previousSnapshot.TargetFramework, snapshot.TargetFramework); Assert.Same(previousSnapshot.Catalogs, snapshot.Catalogs); AssertEx.CollectionLength(snapshot.Dependencies, 3); Assert.Contains(dependency1, snapshot.Dependencies); Assert.Contains(dependency2, snapshot.Dependencies); Assert.Contains(filterAddedDependency, snapshot.Dependencies); }
public void FromChanges_RemovedAndAddedChanges() { var targetFramework = new TargetFramework("tfm1"); var dependency1 = new TestDependency { ProviderType = "Xxx", Id = "dependency1", OriginalItemSpec = "Dependency1", Caption = "Dependency1", SchemaItemType = "Xxx", Resolved = true }; var dependency2 = new TestDependency { ProviderType = "Xxx", Id = "dependency2", OriginalItemSpec = "Dependency2", Caption = "Dependency2", SchemaItemType = "Xxx", Resolved = true }; var dependencyModelAdded1 = new TestDependencyModel { ProviderType = "Xxx", Id = "addeddependency1", OriginalItemSpec = "AddedDependency1", Caption = "AddedDependency1", SchemaItemType = "Xxx", Resolved = true, Icon = KnownMonikers.Uninstall, ExpandedIcon = KnownMonikers.Uninstall }; var dependencyModelAdded2 = new TestDependencyModel { ProviderType = "Xxx", Id = "addeddependency2", OriginalItemSpec = "AddedDependency2", Caption = "AddedDependency2", SchemaItemType = "Xxx", Resolved = true, Icon = KnownMonikers.Uninstall, ExpandedIcon = KnownMonikers.Uninstall }; var dependencyModelAdded3 = new TestDependencyModel { ProviderType = "Xxx", Id = "addeddependency3", OriginalItemSpec = "AddedDependency3", Caption = "AddedDependency3", SchemaItemType = "Xxx", Resolved = true, Icon = KnownMonikers.Uninstall, ExpandedIcon = KnownMonikers.Uninstall }; var dependencyAdded2Changed = new TestDependency { ProviderType = "Xxx", Id = "addeddependency2", OriginalItemSpec = "AddedDependency2Changed", Caption = "AddedDependency2Changed", SchemaItemType = "Xxx", Resolved = true }; var dependencyRemoved1 = new TestDependency { ProviderType = "Xxx", Id = "Removeddependency1", OriginalItemSpec = "RemovedDependency1", Caption = "RemovedDependency1", SchemaItemType = "Xxx", Resolved = true }; var dependencyInsteadRemoved1 = new TestDependency { ProviderType = "Xxx", Id = "InsteadRemoveddependency1", OriginalItemSpec = "InsteadRemovedDependency1", Caption = "InsteadRemovedDependency1", SchemaItemType = "Xxx", Resolved = true }; var catalogs = IProjectCatalogSnapshotFactory.Create(); var previousSnapshot = new TargetedDependenciesSnapshot( targetFramework, catalogs, ImmutableArray.Create <IDependency>(dependency1, dependency2, dependencyRemoved1)); var changes = new DependenciesChangesBuilder(); changes.Added(dependencyModelAdded1); changes.Added(dependencyModelAdded2); changes.Added(dependencyModelAdded3); changes.Removed("Xxx", "Removeddependency1"); var snapshotFilter = new TestDependenciesSnapshotFilter() .BeforeAddReject("Xxx", "addeddependency1") .BeforeAddAccept("Xxx", "addeddependency2", dependencyAdded2Changed) .BeforeAddAccept("Xxx", "addeddependency3") .BeforeRemoveAccept("Xxx", "Removeddependency1", dependencyInsteadRemoved1); var snapshot = TargetedDependenciesSnapshot.FromChanges( previousSnapshot, changes.TryBuildChanges() !, catalogs, ImmutableArray.Create <IDependenciesSnapshotFilter>(snapshotFilter), new Dictionary <string, IProjectDependenciesSubTreeProvider>(), null); Assert.True(snapshotFilter.Completed); Assert.NotSame(previousSnapshot, snapshot); Assert.Same(previousSnapshot.TargetFramework, snapshot.TargetFramework); Assert.Same(catalogs, snapshot.Catalogs); AssertEx.CollectionLength(snapshot.Dependencies, 5); Assert.Contains(snapshot.Dependencies, dep => dep.Id == "dependency1"); Assert.Contains(snapshot.Dependencies, dep => dep.Id == "dependency2"); Assert.Contains(snapshot.Dependencies, dep => dep.Id == "addeddependency2"); Assert.Contains(snapshot.Dependencies, dep => dep.Id == "InsteadRemoveddependency1"); Assert.Contains(snapshot.Dependencies, dep => dep.Id == "addeddependency3"); }
/// <summary> /// Updates the <see cref="TargetedDependenciesSnapshot"/> corresponding to <paramref name="changedTargetFramework"/>, /// returning either: /// <list type="bullet"> /// <item>An updated <see cref="DependenciesSnapshot"/> object, or</item> /// <item>the immutable <paramref name="previousSnapshot"/> if no changes were made.</item> /// </list> /// </summary> /// <remarks> /// As part of the update, each <see cref="IDependenciesSnapshotFilter"/> in <paramref name="snapshotFilters"/> /// is given a chance to influence the addition and removal of dependency data in the returned snapshot. /// </remarks> /// <returns>An updated snapshot, or <paramref name="previousSnapshot"/> if no changes occured.</returns> public static DependenciesSnapshot FromChanges( DependenciesSnapshot previousSnapshot, ITargetFramework changedTargetFramework, IDependenciesChanges?changes, IProjectCatalogSnapshot?catalogs, ImmutableArray <ITargetFramework> targetFrameworks, ITargetFramework?activeTargetFramework, ImmutableArray <IDependenciesSnapshotFilter> snapshotFilters, IReadOnlyDictionary <string, IProjectDependenciesSubTreeProvider> subTreeProviderByProviderType, IImmutableSet <string>?projectItemSpecs) { Requires.NotNull(previousSnapshot, nameof(previousSnapshot)); Requires.NotNull(changedTargetFramework, nameof(changedTargetFramework)); Requires.Argument(!snapshotFilters.IsDefault, nameof(snapshotFilters), "Cannot be default."); Requires.NotNull(subTreeProviderByProviderType, nameof(subTreeProviderByProviderType)); var builder = previousSnapshot.DependenciesByTargetFramework.ToBuilder(); if (!builder.TryGetValue(changedTargetFramework, out TargetedDependenciesSnapshot previousTargetedSnapshot)) { previousTargetedSnapshot = TargetedDependenciesSnapshot.CreateEmpty(changedTargetFramework, catalogs); } bool builderChanged = false; var newTargetedSnapshot = TargetedDependenciesSnapshot.FromChanges( previousTargetedSnapshot, changes, catalogs, snapshotFilters, subTreeProviderByProviderType, projectItemSpecs); if (!ReferenceEquals(previousTargetedSnapshot, newTargetedSnapshot)) { builder[changedTargetFramework] = newTargetedSnapshot; builderChanged = true; } SyncTargetFrameworks(); activeTargetFramework ??= previousSnapshot.ActiveTargetFramework; if (builderChanged) { // Dependencies-by-target-framework has changed return(new DependenciesSnapshot( activeTargetFramework, builder.ToImmutable())); } if (!activeTargetFramework.Equals(previousSnapshot.ActiveTargetFramework)) { // The active target framework changed return(new DependenciesSnapshot( activeTargetFramework, previousSnapshot.DependenciesByTargetFramework)); } // Nothing has changed, so return the same snapshot return(previousSnapshot); void SyncTargetFrameworks() { // Only sync if a the full list of target frameworks has been provided if (targetFrameworks.IsDefault) { return; } // This is a long-winded way of doing this that minimises allocations // Ensure all required target frameworks are present foreach (ITargetFramework targetFramework in targetFrameworks) { if (!builder.ContainsKey(targetFramework)) { builder.Add(targetFramework, TargetedDependenciesSnapshot.CreateEmpty(targetFramework, catalogs)); builderChanged = true; } } // Remove any extra target frameworks if (builder.Count != targetFrameworks.Length) { // NOTE We need "ToList" here as "Except" is lazy, and attempts to remove from the builder // while iterating will throw "Collection was modified" IEnumerable <ITargetFramework> targetFrameworksToRemove = builder.Keys.Except(targetFrameworks).ToList(); foreach (ITargetFramework targetFramework in targetFrameworksToRemove) { builder.Remove(targetFramework); } builderChanged = true; } } }