diff --git a/build/Shared/EqualityUtility.cs b/build/Shared/EqualityUtility.cs index 11c57acaaa2..91fbbd114b0 100644 --- a/build/Shared/EqualityUtility.cs +++ b/build/Shared/EqualityUtility.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -59,6 +59,31 @@ internal static bool SequenceEqualWithNullCheck( return self.SequenceEqual(other, comparer); } + /// + /// Compares two sets for equality, allowing either sequence to be null. + /// If one is null, both have to be null for equality. + /// + internal static bool SetEqualWithNullCheck( + this ISet self, + ISet other, + IEqualityComparer comparer = null) + { + bool identityEquals; + if (TryIdentityEquals(self, other, out identityEquals)) + { + return identityEquals; + } + + if (comparer == null) + { + comparer = EqualityComparer.Default; + } + + ISet set = new HashSet(self, comparer); + + return set.SetEquals(other); + } + internal static bool DictionaryEquals( IDictionary self, IDictionary other, diff --git a/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommandRunner.cs b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommandRunner.cs index d9643c10ba1..445de72cb0a 100644 --- a/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommandRunner.cs +++ b/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommandRunner.cs @@ -138,7 +138,7 @@ public async Task ExecuteCommand(PackageReferenceArgs packageReferenceArgs, } // Ignore the graphs with RID else if (compatibleFrameworks.Count == - restorePreviewResult.Result.CompatibilityCheckResults.Where(r => r.Graph.RuntimeIdentifier == null).Count()) + restorePreviewResult.Result.CompatibilityCheckResults.Where(r => string.IsNullOrEmpty(r.Graph.RuntimeIdentifier)).Count()) { // Package is compatible with all the project TFMs // Add an unconditional package reference to the project diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/PackageSpecificWarningProperties.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/PackageSpecificWarningProperties.cs index f5db18bf2ef..5d0ee79dce1 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/PackageSpecificWarningProperties.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/PackageSpecificWarningProperties.cs @@ -1,11 +1,13 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; +using System.Linq; using NuGet.Common; using NuGet.Frameworks; using NuGet.ProjectModel; +using NuGet.Shared; namespace NuGet.Commands { @@ -13,14 +15,14 @@ namespace NuGet.Commands /// /// Contains Package specific properties for Warnings. /// - public class PackageSpecificWarningProperties + public class PackageSpecificWarningProperties : IEquatable { /// /// Contains Package specific No warn properties. /// NuGetLogCode -> LibraryId -> Set of Frameworks. /// - private IDictionary>> Properties; + public IDictionary>> Properties { get; private set; } /// /// Extracts PackageSpecific WarningProperties from a PackageSpec @@ -36,7 +38,7 @@ public static PackageSpecificWarningProperties CreatePackageSpecificWarningPrope { foreach (var framework in packageSpec.TargetFrameworks) { - warningProperties.AddRange(dependency.NoWarn, dependency.Name, framework.FrameworkName); + warningProperties.AddRangeOfCodes(dependency.NoWarn, dependency.Name, framework.FrameworkName); } } @@ -44,13 +46,42 @@ public static PackageSpecificWarningProperties CreatePackageSpecificWarningPrope { foreach (var dependency in framework.Dependencies) { - warningProperties.AddRange(dependency.NoWarn, dependency.Name, framework.FrameworkName); + warningProperties.AddRangeOfCodes(dependency.NoWarn, dependency.Name, framework.FrameworkName); } } return warningProperties; } + /// + /// Extracts PackageSpecific WarningProperties from a PackageSpec for a specific NuGetFramework + /// + /// PackageSpec containing the Dependencies with WarningProperties + /// NuGetFramework for which the properties should be assessed. + /// PackageSpecific WarningProperties extracted from a PackageSpec for a specific NuGetFramework + public static PackageSpecificWarningProperties CreatePackageSpecificWarningProperties(PackageSpec packageSpec, + NuGetFramework framework) + { + // NuGetLogCode -> LibraryId -> Set of Frameworks. + var warningProperties = new PackageSpecificWarningProperties(); + + foreach (var dependency in packageSpec.Dependencies) + { + warningProperties.AddRangeOfCodes(dependency.NoWarn, dependency.Name, framework); + } + + var targetFrameworkInformation = packageSpec + .TargetFrameworks + .First(tfi => tfi.FrameworkName == framework); + + foreach (var dependency in targetFrameworkInformation.Dependencies) + { + warningProperties.AddRangeOfCodes(dependency.NoWarn, dependency.Name, framework); + } + + return warningProperties; + } + /// /// Adds a NuGetLogCode into the NoWarn Set for the specified library Id and target graph. /// @@ -85,7 +116,7 @@ public void Add(NuGetLogCode code, string libraryId, NuGetFramework framework) /// IEnumerable of NuGetLogCode for which no warning should be thrown. /// Library for which no warning should be thrown. /// Target graph for which no warning should be thrown. - public void AddRange(IEnumerable codes, string libraryId, NuGetFramework framework) + public void AddRangeOfCodes(IEnumerable codes, string libraryId, NuGetFramework framework) { foreach (var code in codes) { @@ -93,6 +124,20 @@ public void AddRange(IEnumerable codes, string libraryId, NuGetFra } } + /// + /// Adds a list of NuGetLogCode into the NoWarn Set for the specified library Id and target graph. + /// + /// NuGetLogCode for which no warning should be thrown. + /// Library for which no warning should be thrown. + /// IEnumerable of Target graph for which no warning should be thrown. + public void AddRangeOfFrameworks(NuGetLogCode code, string libraryId, IEnumerable frameworks) + { + foreach (var framework in frameworks) + { + Add(code, libraryId, framework); + } + } + /// /// Checks if a NugetLogCode is part of the NoWarn list for the specified library Id and target graph. /// @@ -107,5 +152,38 @@ public bool Contains(NuGetLogCode code, string libraryId, NuGetFramework framewo libraryIdsAndFrameworks.TryGetValue(libraryId, out var frameworkSet) && frameworkSet.Contains(framework); } + + public override int GetHashCode() + { + var hashCode = new HashCodeCombiner(); + + // Add a constant hash for all objects + hashCode.AddObject(1); + + return hashCode.CombinedHash; + } + + public override bool Equals(object obj) + { + return Equals(obj as PackageSpecificWarningProperties); + } + + public bool Equals(PackageSpecificWarningProperties other) + { + if (other == null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return EqualityUtility.DictionaryEquals( + Properties, + other.Properties, + (sv1, ov1) => EqualityUtility.DictionaryEquals(sv1, ov1, (sv2, ov2) => EqualityUtility.SetEqualWithNullCheck(sv2, ov2))); + } } } diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/RestoreCollectorLogger.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/RestoreCollectorLogger.cs index 8d63a1b9194..3c0fa78e4ce 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/RestoreCollectorLogger.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/RestoreCollectorLogger.cs @@ -1,11 +1,14 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using NuGet.Common; +using NuGet.ProjectModel; +using NuGet.Shared; namespace NuGet.Commands { @@ -14,12 +17,68 @@ public class RestoreCollectorLogger : LoggerBase, ICollectorLogger private readonly ILogger _innerLogger; private readonly ConcurrentQueue _errors; private readonly bool _hideWarningsAndErrors; + private IEnumerable _restoreTargetGraphs; + private PackageSpec _projectSpec; + private WarningPropertiesCollection _transitiveWarningPropertiesCollection; + + public string ProjectPath => _projectSpec?.RestoreMetadata?.ProjectPath; public IEnumerable Errors => _errors.ToArray(); - public WarningPropertiesCollection WarningPropertiesCollection { get; set; } - - public string ProjectPath { get; set; } + public WarningPropertiesCollection ProjectWarningPropertiesCollection { get; set; } + + public WarningPropertiesCollection TransitiveWarningPropertiesCollection + { + get + { + if (_transitiveWarningPropertiesCollection == null) + { + // Populate TransitiveWarningPropertiesCollection only if it is null and we have RestoreTargetGraphs. + // This will happen at most once and only if we have the project spec with restore metadata. + if (_restoreTargetGraphs != null && + _restoreTargetGraphs.Any() && + _projectSpec != null && + _projectSpec.RestoreMetadata != null) + { + var transitiveNoWarnUtils = new TransitiveNoWarnUtils(); + + TransitiveWarningPropertiesCollection = transitiveNoWarnUtils.CreateTransitiveWarningPropertiesCollection( + _restoreTargetGraphs, + _projectSpec); + } + } + + return _transitiveWarningPropertiesCollection; + } + + set => _transitiveWarningPropertiesCollection = value; + } + + /// + /// Stores a reference to PackageSpec for the project from the restore request. + /// This are used to generate the warning properties for the project. + /// + /// PackageSpec to be stored for reference. + public void ApplyRestoreInputs(PackageSpec projectSpec) + { + _projectSpec = projectSpec; + + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + projectSpec.RestoreMetadata?.ProjectWideWarningProperties, + PackageSpecificWarningProperties.CreatePackageSpecificWarningProperties(projectSpec), + projectSpec.TargetFrameworks.Select(f => f.FrameworkName).AsList().AsReadOnly() + ); + } + + /// + /// Stores a reference to RestoreTargetGraphs from the restore output. + /// These graphs are used to generate the transitive warning properties. + /// + /// RestoreTargetGraphs to be stored for reference. + public void ApplyRestoreOutput(IEnumerable restoreTargetGraphs) + { + _restoreTargetGraphs = restoreTargetGraphs; + } /// /// Initializes an instance of the , while still @@ -67,11 +126,11 @@ public RestoreCollectorLogger(ILogger innerLogger) : this(innerLogger, LogLevel.Debug, hideWarningsAndErrors: false) { } - + public void Log(IRestoreLogMessage message) { - // This will be true only when the Message is a Warning and should be suppressed. - if (WarningPropertiesCollection == null || !WarningPropertiesCollection.ApplyWarningProperties(message)) + // This will be true if the message is not or warning or it is not suppressed. + if (!IsWarningSuppressed(message)) { if (string.IsNullOrEmpty(message.FilePath)) { @@ -92,9 +151,8 @@ public void Log(IRestoreLogMessage message) public Task LogAsync(IRestoreLogMessage message) { - - // This will be true only when the Message is a Warning and should be suppressed. - if (WarningPropertiesCollection == null || !WarningPropertiesCollection.ApplyWarningProperties(message)) + // This will be true if the message is not or warning or it is not suppressed. + if (!IsWarningSuppressed(message)) { if (string.IsNullOrEmpty(message.FilePath)) { @@ -142,6 +200,25 @@ protected bool DisplayMessage(IRestoreLogMessage message) } } + /// + /// This method checks if at least one of the warning properties collections is not null and it suppresses the warning. + /// + /// IRestoreLogMessage to be logged. + /// bool indicating if the message should be suppressed. + private bool IsWarningSuppressed(IRestoreLogMessage message) + { + + if (ProjectWarningPropertiesCollection != null && ProjectWarningPropertiesCollection.ApplyWarningProperties(message)) + { + return true; + } + else + { + // Use transitive warning properties only if the project does not suppress the warning. + return TransitiveWarningPropertiesCollection != null && TransitiveWarningPropertiesCollection.ApplyWarningProperties(message); + } + } + private static IRestoreLogMessage ToRestoreLogMessage(ILogMessage message) { var restoreLogMessage = message as IRestoreLogMessage; diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/TransitiveNoWarnUtils.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/TransitiveNoWarnUtils.cs new file mode 100644 index 00000000000..c83a7bef296 --- /dev/null +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/TransitiveNoWarnUtils.cs @@ -0,0 +1,527 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using NuGet.Common; +using NuGet.Frameworks; +using NuGet.LibraryModel; +using NuGet.ProjectModel; +using NuGet.Shared; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using NuGet.DependencyResolver; + +namespace NuGet.Commands +{ + public class TransitiveNoWarnUtils + { + // static should be fine across multiple calls as this solely depends on the csproj file of the project. + private readonly ConcurrentDictionary> _warningPropertiesPerFrameworkCache = + new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); + + /// + /// Creates a PackageSpecificWarningProperties for a project generated by traversing the dependency graph. + /// + /// Parent project restore target graphs. + /// PackageSpec of the parent project. + /// WarningPropertiesCollection with the project frameworks and the transitive package specific no warn properties. + public WarningPropertiesCollection CreateTransitiveWarningPropertiesCollection( + IEnumerable targetGraphs, + PackageSpec parentProjectSpec) + { + var transitivePackageSpecificProperties = new PackageSpecificWarningProperties(); + var projectFrameworks = new List(); + var parentWarningProperties = new WarningPropertiesCollection( + parentProjectSpec.RestoreMetadata?.ProjectWideWarningProperties, + PackageSpecificWarningProperties.CreatePackageSpecificWarningProperties(parentProjectSpec), + parentProjectSpec.TargetFrameworks.Select(f => f.FrameworkName).AsList().AsReadOnly()); + + foreach (var targetGraph in targetGraphs) + { + if (string.IsNullOrEmpty(targetGraph.RuntimeIdentifier)) + { + var transitiveNoWarnFromTargetGraph = ExtractTransitiveNoWarnProperties( + targetGraph, + parentProjectSpec.RestoreMetadata.ProjectName, + parentWarningProperties); + + projectFrameworks.Add(targetGraph.Framework); + + transitivePackageSpecificProperties = MergePackageSpecificWarningProperties( + transitivePackageSpecificProperties, + transitiveNoWarnFromTargetGraph); + } + } + + return new WarningPropertiesCollection( + projectWideWarningProperties: null, + packageSpecificWarningProperties: transitivePackageSpecificProperties, + projectFrameworks: projectFrameworks + ); + } + + /// + /// Traverses a Dependency grpah starting from the parent project in BF style. + /// + /// Parent project restore target graph. + /// File path of the parent project. + /// WarningPropertiesCollection of the parent project. + /// PackageSpecificWarningProperties containing all the NoWarn's for each package seen in the graph accumulated while traversing the graph. + private PackageSpecificWarningProperties ExtractTransitiveNoWarnProperties( + RestoreTargetGraph targetGraph, + string parentProjectName, + WarningPropertiesCollection parentWarningPropertiesCollection) + { + var dependencyMapping = new Dictionary(StringComparer.OrdinalIgnoreCase); + var queue = new Queue(); + var seen = new HashSet(); + var frameworkReducer = new FrameworkReducer(); + var resultWarningProperties = new PackageSpecificWarningProperties(); + var packageNoWarn = new Dictionary>(StringComparer.OrdinalIgnoreCase); + + // All the packages in parent project's closure. + // Once we have collected data for all of these, we can exit. + var parentPackageDependencies = new HashSet( + targetGraph.Flattened.Where(d => d.Key.Type == LibraryType.Package).Select(d => d.Key.Name)); + + var parentTargetFramework = targetGraph.Framework; + + // Add all dependencies into a dict for a quick transitive lookup + foreach (var dependencyGraphItem in targetGraph.Flattened.OrderBy(d => d.Key.Name)) + { + WarningPropertiesCollection nodeWarningProperties = null; + + if (IsProject(dependencyGraphItem.Key.Type)) + { + var localMatch = dependencyGraphItem.Data.Match as LocalMatch; + var nodeProjectSpec = GetNodePackageSpec(localMatch); + var nearestFramework = frameworkReducer.GetNearest( + parentTargetFramework, + nodeProjectSpec.TargetFrameworks.Select(tfi => tfi.FrameworkName)); + + // Get the WarningPropertiesCollection from the PackageSpec + nodeWarningProperties = GetNodeWarningProperties(nodeProjectSpec, nearestFramework); + } + + var lookUpNode = new LookUpNode() + { + Dependencies = dependencyGraphItem.Data.Dependencies, + WarningPropertiesCollection = nodeWarningProperties + }; + + dependencyMapping[dependencyGraphItem.Key.Name] = lookUpNode; + } + + // Get the direct dependencies for the parent project to seed the queue + var parentDependencies = dependencyMapping[parentProjectName]; + + // Seed the queue with the parent project's direct dependencies + AddDependenciesToQueue(parentDependencies.Dependencies, + queue, + seen, + parentWarningPropertiesCollection); + + // Add the parent project to the seen set to prevent adding it back to the queue + seen.Add(new DependencyNode(id: parentProjectName, + isProject: true, + warningPropertiesCollection: parentWarningPropertiesCollection)); + + // start taking one node from the queue and get all of it's dependencies + while (queue.Count > 0) + { + var node = queue.Dequeue(); + if (!seen.Contains(node)) + { + // Add the node to seen set + seen.Add(node); + + var nodeId = node.Id; + var nodeIsProject = node.IsProject; + var nodeDependencies = dependencyMapping[nodeId].Dependencies; + var nodeWarningProperties = dependencyMapping[nodeId].WarningPropertiesCollection; + var pathWarningProperties = node.WarningPropertiesCollection; + + // If the node is a project then we need to extract the warning properties and + // add those to the warning properties of the current path. + if (nodeIsProject) + { + // Merge the WarningPropertiesCollection to the one in the path + var mergedWarningProperties = MergeWarningPropertiesCollection(pathWarningProperties, + nodeWarningProperties); + + AddDependenciesToQueue(dependencyMapping[nodeId].Dependencies, + queue, + seen, + mergedWarningProperties); + + } + else if (parentPackageDependencies.Contains(nodeId)) + { + // Evaluate the current path for package properties + var packageNoWarnFromPath = ExtractPathNoWarnProperties(pathWarningProperties, nodeId); + + if (packageNoWarn.ContainsKey(nodeId)) + { + // We have seen atleast one path which contained a NoWarn for the package + // We need to update the + packageNoWarn[nodeId].IntersectWith(packageNoWarnFromPath); + } + else + { + packageNoWarn[nodeId] = packageNoWarnFromPath; + } + + // Check if there was any NoWarn in the path + if (packageNoWarn[nodeId].Count == 0) + { + // If the path does not "NoWarn" for this package then remove the path from parentPackageDependencies + // This is done because if there are no "NoWarn" in one path, the the warnings must come through + // We no longer care about this package in the graph + parentPackageDependencies.Remove(nodeId); + + // If parentPackageDependencies is empty then exit the graph traversal + if (parentPackageDependencies.Count == 0) + { + break; + } + } + + AddDependenciesToQueue(dependencyMapping[nodeId].Dependencies, + queue, + seen, + pathWarningProperties); + } + } + } + + // At the end of the graph traversal add the remaining package no warn lists into the result + foreach(var packageId in packageNoWarn.Keys) + { + resultWarningProperties.AddRangeOfCodes(packageNoWarn[packageId], packageId, parentTargetFramework); + } + + return resultWarningProperties; + } + + private WarningPropertiesCollection GetNodeWarningProperties(PackageSpec nodeProjectSpec, NuGetFramework framework) + { + var key = nodeProjectSpec.RestoreMetadata.ProjectPath; + + if (!_warningPropertiesPerFrameworkCache.ContainsKey(key)) + { + _warningPropertiesPerFrameworkCache[key] = + new ConcurrentDictionary(new NuGetFrameworkFullComparer()); + } + + return _warningPropertiesPerFrameworkCache[key].GetOrAdd(framework, + (s) => new WarningPropertiesCollection( + nodeProjectSpec.RestoreMetadata?.ProjectWideWarningProperties, + PackageSpecificWarningProperties.CreatePackageSpecificWarningProperties(nodeProjectSpec, framework), + nodeProjectSpec.TargetFrameworks.Select(f => f.FrameworkName).AsList().AsReadOnly())); + } + + private static void AddDependenciesToQueue(IEnumerable dependencies, + Queue queue, + HashSet seen, + WarningPropertiesCollection pathWarningPropertiesCollection) + { + // Add all the project's dependencies to the Queue with the merged WarningPropertiesCollection + foreach (var dependency in dependencies) + { + var queueNode = new DependencyNode( + dependency.Name, + IsProject(dependency.LibraryRange.TypeConstraint), + pathWarningPropertiesCollection); + + // Add the metadata from the parent project here. + queue.Enqueue(queueNode); + } + } + + private static PackageSpec GetNodePackageSpec(LocalMatch localMatch) + { + return (PackageSpec) localMatch.LocalLibrary.Items[KnownLibraryProperties.PackageSpec]; + } + + public static ISet ExtractPathNoWarnProperties(WarningPropertiesCollection pathWarningProperties, string id) + { + var result = new HashSet(); + if (pathWarningProperties?.ProjectWideWarningProperties?.NoWarn?.Count > 0) + { + result.UnionWith(pathWarningProperties.ProjectWideWarningProperties.NoWarn); + } + + if (pathWarningProperties?.PackageSpecificWarningProperties?.Properties?.Count > 0) + { + foreach(var codeIdCollection in pathWarningProperties.PackageSpecificWarningProperties.Properties) + { + var code = codeIdCollection.Key; + var IdCollection = codeIdCollection.Value; + if (IdCollection.ContainsKey(id)) + { + result.Add(code); + } + } + } + + return result; + } + + /// + /// Merge 2 WarningPropertiesCollection objects. + /// This method will combine the warning properties from both the collections. + /// + /// First Object to be merged. + /// Second Object to be merged. + /// Returns a WarningPropertiesCollection with the combined warning properties. + /// Returns the reference to one of the inputs if the other input is Null. + /// Returns a Null if both the input properties are Null. + public static WarningPropertiesCollection MergeWarningPropertiesCollection( + WarningPropertiesCollection first, + WarningPropertiesCollection second) + { + WarningPropertiesCollection result = null; + + if (TryMergeNullObjects(first, second, out object merged)) + { + result = merged as WarningPropertiesCollection; + } + else + { + // Merge Project Wide Warning Properties + var mergedProjectWideWarningProperties = MergeProjectWideWarningProperties( + first.ProjectWideWarningProperties, + second.ProjectWideWarningProperties); + + // Merge Package Specific Warning Properties + var mergedPackageSpecificWarnings = MergePackageSpecificWarningProperties( + first.PackageSpecificWarningProperties, + second.PackageSpecificWarningProperties); + + // Ignore the project frameworks as the final collection will contain the parent project frameworks + + result = new WarningPropertiesCollection( + mergedProjectWideWarningProperties, + mergedPackageSpecificWarnings, + projectFrameworks: null); + } + + return result; + } + + /// + /// Merge 2 WarningProperties objects. + /// This method will combine the warning properties from both the collections. + /// + /// First Object to be merged. + /// Second Object to be merged. + /// Returns a WarningProperties with the combined warning properties. + /// Returns the reference to one of the inputs if the other input is Null. + /// Returns a Null if both the input properties are Null. + public static WarningProperties MergeProjectWideWarningProperties( + WarningProperties first, + WarningProperties second) + { + WarningProperties result = null; + + if (TryMergeNullObjects(first, second, out object merged)) + { + result = merged as WarningProperties; + } + else + { + // Merge WarningsAsErrors Sets. + // No need to merge warnings as errors as they are not used transitively. + var mergedWarningsAsErrors = new HashSet(); + + // Merge NoWarn Sets. + var mergedNoWarn = new HashSet(); + mergedNoWarn.UnionWith(first.NoWarn); + mergedNoWarn.UnionWith(second.NoWarn); + + // Merge AllWarningsAsErrors. If one project treats all warnigs as errors then the chain will too. + var mergedAllWarningsAsErrors = first.AllWarningsAsErrors || second.AllWarningsAsErrors; + + result = new WarningProperties( + mergedWarningsAsErrors, + mergedNoWarn, + mergedAllWarningsAsErrors); + } + + return result; + } + + /// + /// Merge 2 PackageSpecificWarningProperties objects. + /// This method will combine the warning properties from both the collections. + /// + /// First Object to be merged. + /// Second Object to be merged. + /// Returns a PackageSpecificWarningProperties with the combined warning properties. + /// Will return the reference to one of the inputs if the other input is Null. + /// Returns a Null if both the input properties are Null. + public static PackageSpecificWarningProperties MergePackageSpecificWarningProperties( + PackageSpecificWarningProperties first, + PackageSpecificWarningProperties second) + { + PackageSpecificWarningProperties result = null; + + if (TryMergeNullObjects(first, second, out object merged)) + { + result = merged as PackageSpecificWarningProperties; + } + else + { + result = new PackageSpecificWarningProperties(); + if (first.Properties != null) + { + foreach (var code in first.Properties.Keys) + { + foreach (var libraryId in first.Properties[code].Keys) + { + result.AddRangeOfFrameworks(code, libraryId, first.Properties[code][libraryId]); + } + } + } + + if (second.Properties != null) + { + foreach (var code in second.Properties.Keys) + { + foreach (var libraryId in second.Properties[code].Keys) + { + result.AddRangeOfFrameworks(code, libraryId, second.Properties[code][libraryId]); + } + } + } + } + + return result; + } + + /// + /// Try to merge 2 objects if one or both of them are null. + /// + /// First Object to be merged. + /// Second Object to be merged. + /// Out Merged Object. + /// Returns true if atleast one of the objects was Null. + /// If none of them is null then the returns false, indicating that the merge failed. + public static bool TryMergeNullObjects(object first, object second, out object merged) + { + merged = null; + var result = false; + + if (first == null && second == null) + { + merged = null; + result = true; + } + else if (first == null) + { + merged = second; + result = true; + } + else if (second == null) + { + merged = first; + result = true; + } + + return result; + } + + /// + /// Checks if a LibraryDependencyTarget is a project. + /// + /// LibraryDependencyTarget to be checked. + /// True if a LibraryDependencyTarget is Project or ExternalProject. + private static bool IsProject(LibraryDependencyTarget type) + { + return (type == LibraryDependencyTarget.ExternalProject || type == LibraryDependencyTarget.Project); + } + + /// + /// Checks if a LibraryType is a project. + /// + /// LibraryType to be checked. + /// True if a LibraryType is Project or ExternalProject. + private static bool IsProject(LibraryType type) + { + return (type == LibraryType.ExternalProject || type == LibraryType.Project); + } + + /// + /// A simple node class to hold the outgoing dependency edge during the graph walk. + /// + public class DependencyNode : IEquatable + { + // ID of the Node + public string Id { get; } + + // bool to indicate if the node is a project node + // if false then the node is a package + public bool IsProject { get; } + + // WarningPropertiesCollection of the path taken to the Node + public WarningPropertiesCollection WarningPropertiesCollection { get; } + + public DependencyNode(string id, bool isProject, WarningPropertiesCollection warningPropertiesCollection) + { + Id = id ?? throw new ArgumentNullException(nameof(id)); + WarningPropertiesCollection = warningPropertiesCollection ?? throw new ArgumentNullException(nameof(warningPropertiesCollection)); + IsProject = isProject; + } + + public override int GetHashCode() + { + var hashCode = new HashCodeCombiner(); + + hashCode.AddStringIgnoreCase(Id); + hashCode.AddObject(IsProject); + + return hashCode.CombinedHash; + } + + public override bool Equals(object obj) + { + return Equals(obj as DependencyNode); + } + + public bool Equals(DependencyNode other) + { + if (other == null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return IsProject == other.IsProject && + string.Equals(Id, other.Id, StringComparison.OrdinalIgnoreCase) && + WarningPropertiesCollection.Equals(other.WarningPropertiesCollection); + } + + public override string ToString() + { + return $"{(IsProject ? "Project" : "Package")}/{Id}"; + } + } + + /// + /// A simple node class to hold the outgoing dependency edge for a quick look up. + /// + private class LookUpNode + { + // List of dependencies for this node + public IEnumerable Dependencies { get; set; } + + // If the node is a project then this will hold the + public WarningPropertiesCollection WarningPropertiesCollection { get; set; } + } + } +} diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/WarningPropertiesCollection.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/WarningPropertiesCollection.cs index 1d4327fb994..56997f15c7b 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/WarningPropertiesCollection.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/Logging/WarningPropertiesCollection.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -16,7 +16,7 @@ namespace NuGet.Commands /// /// Class to hold ProjectWide and PackageSpecific WarningProperties. /// - public class WarningPropertiesCollection + public class WarningPropertiesCollection : IEquatable { private readonly ConcurrentDictionary _getFrameworkCache = new ConcurrentDictionary(); @@ -24,18 +24,27 @@ public class WarningPropertiesCollection /// Contains the target frameworks for the project. /// These are used for no warn filtering in case of a log message without a target graph. /// - public IReadOnlyList ProjectFrameworks { get; set; } = new ReadOnlyCollection(new List()); + public IReadOnlyList ProjectFrameworks { get; } /// /// Contains Project wide properties for Warnings. /// - public WarningProperties ProjectWideWarningProperties { get; set; } + public WarningProperties ProjectWideWarningProperties { get; } /// /// Contains Package specific properties for Warnings. /// NuGetLogCode -> LibraryId -> Set of Frameworks. /// - public PackageSpecificWarningProperties PackageSpecificWarningProperties { get; set; } + public PackageSpecificWarningProperties PackageSpecificWarningProperties { get; } + + public WarningPropertiesCollection(WarningProperties projectWideWarningProperties, + PackageSpecificWarningProperties packageSpecificWarningProperties, + IReadOnlyList projectFrameworks) + { + ProjectWideWarningProperties = projectWideWarningProperties; + PackageSpecificWarningProperties = packageSpecificWarningProperties; + ProjectFrameworks = projectFrameworks ?? new ReadOnlyCollection(new List()); + } /// /// Attempts to suppress a warning log message or upgrade it to error log message. @@ -128,5 +137,38 @@ private static NuGetFramework GetNuGetFrameworkFromTargetGraph(string targetGrap return NuGetFramework.Parse(parts[0]); } + + public override int GetHashCode() + { + var hashCode = new HashCodeCombiner(); + + hashCode.AddObject(ProjectWideWarningProperties); + hashCode.AddObject(PackageSpecificWarningProperties); + hashCode.AddSequence(ProjectFrameworks); + + return hashCode.CombinedHash; + } + + public override bool Equals(object obj) + { + return Equals(obj as WarningPropertiesCollection); + } + + public bool Equals(WarningPropertiesCollection other) + { + if (other == null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return EqualityUtility.EqualsWithNullCheck(ProjectWideWarningProperties, other.ProjectWideWarningProperties) && + EqualityUtility.EqualsWithNullCheck(PackageSpecificWarningProperties, other.PackageSpecificWarningProperties) && + EqualityUtility.OrderedEquals(ProjectFrameworks, other.ProjectFrameworks, (fx) => fx.Framework, orderComparer: StringComparer.OrdinalIgnoreCase, sequenceComparer: new NuGetFrameworkFullComparer()); + } } } diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/ProjectRestoreCommand.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/ProjectRestoreCommand.cs index eb99abdd92c..055487fc03b 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/ProjectRestoreCommand.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/ProjectRestoreCommand.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -22,7 +22,7 @@ namespace NuGet.Commands { internal class ProjectRestoreCommand { - private readonly ILogger _logger; + private readonly RestoreCollectorLogger _logger; private readonly ProjectRestoreRequest _request; @@ -32,7 +32,7 @@ public ProjectRestoreCommand(ProjectRestoreRequest request) _request = request; } - public async Task, RuntimeGraph>> TryRestore(LibraryRange projectRange, + public async Task, RuntimeGraph>> TryRestoreAsync(LibraryRange projectRange, IEnumerable frameworkRuntimePairs, HashSet allInstalledPackages, NuGetv3LocalRepository userPackageFolder, @@ -119,6 +119,10 @@ await InstallPackagesAsync(runtimeGraphs, userPackageFolder.ClearCacheForIds(allInstalledPackages.Select(package => package.Name)); } + // Update the logger with the restore target graphs + // This allows lazy initialization for the Transitive Warning Properties + _logger.ApplyRestoreOutput(graphs); + // Warn for all dependencies that do not have exact matches or // versions that have been bumped up unexpectedly. await UnexpectedDependencyMessages.LogAsync(graphs, _request.Project, _logger); diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/ProjectRestoreRequest.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/ProjectRestoreRequest.cs index 4904043172b..f4387524927 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/ProjectRestoreRequest.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/ProjectRestoreRequest.cs @@ -21,7 +21,7 @@ public ProjectRestoreRequest( LockFile existingLockFile, Dictionary runtimeGraphCache, ConcurrentDictionary runtimeGraphCacheByPackage, - ILogger log) + RestoreCollectorLogger log) { CacheContext = request.CacheContext; Log = log; @@ -36,7 +36,7 @@ public ProjectRestoreRequest( } public SourceCacheContext CacheContext { get; } - public ILogger Log { get; } + public RestoreCollectorLogger Log { get; } public string PackagesDirectory { get; } public int MaxDegreeOfConcurrency { get; } public LockFile ExistingLockFile { get; } diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs index 51926959495..ae389998f01 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreCommand.cs @@ -52,18 +52,8 @@ public RestoreCommand(RestoreRequest request) var collectorLoggerHideWarningsAndErrors = request.Project.RestoreSettings.HideWarningsAndErrors || request.HideWarningsAndErrors; - - var collectorLogger = new RestoreCollectorLogger(_request.Log, collectorLoggerHideWarningsAndErrors) - { - ProjectPath = _request.Project.RestoreMetadata?.ProjectPath, - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = request.Project.RestoreMetadata?.ProjectWideWarningProperties, - PackageSpecificWarningProperties = PackageSpecificWarningProperties.CreatePackageSpecificWarningProperties(request.Project), - ProjectFrameworks = request.Project.TargetFrameworks.Select(f => f.FrameworkName).AsList().AsReadOnly() - } - }; - + var collectorLogger = new RestoreCollectorLogger(_request.Log, collectorLoggerHideWarningsAndErrors); + collectorLogger.ApplyRestoreInputs(_request.Project); _logger = collectorLogger; } @@ -568,7 +558,7 @@ private async Task> ExecuteRestoreAsync( var projectRestoreCommand = new ProjectRestoreCommand(projectRestoreRequest); - var result = await projectRestoreCommand.TryRestore( + var result = await projectRestoreCommand.TryRestoreAsync( projectRange, projectFrameworkRuntimePairs, allInstalledPackages, @@ -615,7 +605,7 @@ private async Task> ExecuteRestoreAsync( // Walk additional runtime graphs for supports checks if (_success && _request.CompatibilityProfiles.Any()) { - var compatibilityResult = await projectRestoreCommand.TryRestore( + var compatibilityResult = await projectRestoreCommand.TryRestoreAsync( projectRange, _request.CompatibilityProfiles, allInstalledPackages, diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreSummary.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreSummary.cs index 2328200407b..325c2e3b510 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreSummary.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/RestoreSummary.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; diff --git a/src/NuGet.Core/NuGet.ProjectModel/WarningProperties.cs b/src/NuGet.Core/NuGet.ProjectModel/WarningProperties.cs index a5ab2b1c246..637581435c7 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/WarningProperties.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/WarningProperties.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -16,20 +16,23 @@ public class WarningProperties : IEquatable /// /// List of Warning Codes that should be treated as Errors. /// - public ISet WarningsAsErrors { get; } = new HashSet(); + public ISet WarningsAsErrors { get; } /// /// List of Warning Codes that should be ignored. /// - public ISet NoWarn { get; } = new HashSet(); + public ISet NoWarn { get; } /// /// Indicates if all warnings should be ignored. /// - public bool AllWarningsAsErrors { get; set; } = false; + public bool AllWarningsAsErrors { get; set; } public WarningProperties() { + WarningsAsErrors = new HashSet(); + NoWarn = new HashSet(); + AllWarningsAsErrors = false; } public WarningProperties(ISet warningsAsErrors, ISet noWarn, bool allWarningsAsErrors) @@ -44,7 +47,6 @@ public override int GetHashCode() { var hashCode = new HashCodeCombiner(); - hashCode.AddObject(AllWarningsAsErrors); hashCode.AddSequence(WarningsAsErrors); hashCode.AddSequence(NoWarn); @@ -69,8 +71,8 @@ public bool Equals(WarningProperties other) } return AllWarningsAsErrors == other.AllWarningsAsErrors && - WarningsAsErrors.SetEquals(other.WarningsAsErrors) && - NoWarn.SetEquals(other.NoWarn); + EqualityUtility.SetEqualWithNullCheck(WarningsAsErrors, other.WarningsAsErrors) && + EqualityUtility.SetEqualWithNullCheck(NoWarn, other.NoWarn); } } } diff --git a/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreTransitiveLoggingTests.cs b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreTransitiveLoggingTests.cs new file mode 100644 index 00000000000..fa56c14c1e5 --- /dev/null +++ b/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/RestoreTransitiveLoggingTests.cs @@ -0,0 +1,1273 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using FluentAssertions; +using NuGet.Frameworks; +using NuGet.Test.Utility; +using Test.Utility; +using Xunit; + +namespace NuGet.CommandLine.Test +{ + public class RestoreTransitiveLoggingTests + { + [Fact] + // Tests ProjA -> ProjB[PkgX NoWarn NU1603] -> PkgX[NU1603] + public void GivenAProjectReferenceNoWarnsVerifyNoWarning() + { + + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageX); + projectB.Save(); + + // A -> B + projectA.AddProjectToAllFrameworks(projectB); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().NotContain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB[ProjectWide NoWarn NU1603] -> PkgX[NU1603] + public void GivenAProjectReferenceNoWarnsProjectWideVerifyNoWarning() + { + + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageX); + projectB.Properties.Add("NoWarn", "NU1603"); + projectB.Save(); + + // A -> B + projectA.AddProjectToAllFrameworks(projectB); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().NotContain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB[PkgX NoWarn NU1603] -> PkgX[NU1603] + public void GivenAProjectReferenceWithDifferentFrameworkNoWarnsVerifyNoWarning() + { + + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp1.1")); + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageX); + projectB.Save(); + + // A -> B + projectA.AddProjectToAllFrameworks(projectB); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().NotContain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB -> ProjC[PkgX NoWarn NU1603] -> PkgX[NU1603] + public void GivenATransitiveProjectReferenceNoWarnsVerifyNoWarning() + { + + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectC = SimpleTestProjectContext.CreateNETCore( + "c", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // C -> X + projectC.AddPackageToAllFrameworks(packageX); + projectC.Save(); + + // B -> C + projectB.AddProjectToAllFrameworks(projectC); + projectB.Save(); + + // A -> B + projectA.AddProjectToAllFrameworks(projectB); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().NotContain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB -> ProjC[ProjectWide NoWarn NU1603] -> PkgX[NU1603] + public void GivenATransitiveProjectReferenceNoWarnsProjectWideVerifyNoWarning() + { + + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectC = SimpleTestProjectContext.CreateNETCore( + "c", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // C -> X + projectC.AddPackageToAllFrameworks(packageX); + projectC.Properties.Add("NoWarn", "NU1603"); + projectC.Save(); + + // B -> C + projectB.AddProjectToAllFrameworks(projectC); + projectB.Save(); + + // A -> B + projectA.AddProjectToAllFrameworks(projectB); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().NotContain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB[PkgX NoWarn NU1603] -> PkgX[NU1603] + // -> PkgX[NU1603] + public void GivenAProjectReferenceNoWarnsButDirectReferenceGeneratesWarningVerifyWarning() + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageXWithNoWarn = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageXWithNoWarn); + projectB.Save(); + + // A -> B + // A -> X + projectA.AddProjectToAllFrameworks(projectB); + projectA.AddPackageToAllFrameworks(packageX); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().Contain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB[ProjectWide NoWarn NU1603] -> PkgX[NU1603] + // -> PkgX[NU1603] + public void GivenAProjectReferenceNoWarnsProjectWideButDirectReferenceGeneratesWarningVerifyWarning() + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageX); + projectB.Properties.Add("NoWarn", "NU1603"); + projectB.Save(); + + // A -> B + // A -> X + projectA.AddProjectToAllFrameworks(projectB); + projectA.AddPackageToAllFrameworks(packageX); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().Contain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB[PkgX NoWarn NU1603] -> PkgX[NU1603] + // -> ProjC[PkgX NoWarn NU1603] -> PkgX[NU1603] + public void GivenMultipleProjectReferencesNoWarnVerifyNoWarning() + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectC = SimpleTestProjectContext.CreateNETCore( + "c", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageXWithNoWarn = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageXWithNoWarn); + projectB.Save(); + + // C -> X + projectC.AddPackageToAllFrameworks(packageXWithNoWarn); + projectC.Save(); + + // A -> B + // A -> C + projectA.AddProjectToAllFrameworks(projectB); + projectA.AddProjectToAllFrameworks(projectC); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Projects.Add(projectC); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().NotContain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB[ProjectWide NoWarn NU1603] -> PkgX[NU1603] + // -> ProjC[ProjectWide NoWarn NU1603] -> PkgX[NU1603] + public void GivenMultipleProjectReferencesNoWarnProjectWideVerifyNoWarning() + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectC = SimpleTestProjectContext.CreateNETCore( + "c", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageX); + projectB.Properties.Add("NoWarn", "NU1603"); + projectB.Save(); + + // C -> X + projectC.AddPackageToAllFrameworks(packageX); + projectC.Properties.Add("NoWarn", "NU1603"); + projectC.Save(); + + // A -> B + // A -> C + projectA.AddProjectToAllFrameworks(projectB); + projectA.AddProjectToAllFrameworks(projectC); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Projects.Add(projectC); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().NotContain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB[ProjectWide NoWarn NU1603] -> PkgX[NU1603] + // -> ProjC[ProjectWide NoWarn NU1605] -> PkgX[NU1603] + public void GivenMultipleProjectReferencesNoWarnDifferentWarningsProjectWideVerifyWarning() + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectC = SimpleTestProjectContext.CreateNETCore( + "c", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageX); + projectB.Properties.Add("NoWarn", "NU1603"); + projectB.Save(); + + // C -> X + projectC.AddPackageToAllFrameworks(packageX); + projectC.Properties.Add("NoWarn", "NU1605"); + projectC.Save(); + + // A -> B + // A -> C + projectA.AddProjectToAllFrameworks(projectB); + projectA.AddProjectToAllFrameworks(projectC); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Projects.Add(projectC); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + GetSubstringCount(r.AllOutput, "NU1603", ignoreCase: false).Should().Be(3); + } + } + + [Fact] + // Tests ProjA -> ProjB[ProjectWide NoWarn NU1603] -> PkgX[NU1603] + // -> ProjC[PkgX NoWarn NU1603] -> PkgX[NU1603] + public void GivenMultipleProjectReferencesNoWarnMixedVerifyNoWarning() + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectC = SimpleTestProjectContext.CreateNETCore( + "c", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageXWithNoWarn = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0" + }; + + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageX); + projectB.Properties.Add("NoWarn", "NU1603"); + projectB.Save(); + + // C -> X + projectC.AddPackageToAllFrameworks(packageXWithNoWarn); + projectC.Save(); + + // A -> B + // A -> C + projectA.AddProjectToAllFrameworks(projectB); + projectA.AddProjectToAllFrameworks(projectC); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Projects.Add(projectC); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().NotContain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB[PkgX NoWarn NU1603] -> PkgX[NU1603] + // -> ProjC -> PkgX[NU1603] + public void GivenMultipleProjectReferencesAndOnePathWarnsVerifyNoWarning() + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectC = SimpleTestProjectContext.CreateNETCore( + "c", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageXWithNoWarn = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageXWithNoWarn); + projectB.Save(); + + // C -> X + projectC.AddPackageToAllFrameworks(packageX); + projectC.Save(); + + // A -> B + // A -> C + projectA.AddProjectToAllFrameworks(projectB); + projectA.AddProjectToAllFrameworks(projectC); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Projects.Add(projectC); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().Contain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB[PkgX NoWarn NU1603] -> PkgX[NU1603] + // -> ProjC[PkgX NoWarn NU1603] -> PkgX[NU1603] + // -> PkgX[NU1603] + public void GivenMultipleProjectReferencesNoWarnButDirectReferenceWarnsVerifyWarning() + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectC = SimpleTestProjectContext.CreateNETCore( + "c", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageXWithNoWarn = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageXWithNoWarn); + projectB.Save(); + + // C -> X + projectC.AddPackageToAllFrameworks(packageXWithNoWarn); + projectC.Save(); + + // A -> B + // A -> C + // A -> X + projectA.AddProjectToAllFrameworks(projectB); + projectA.AddProjectToAllFrameworks(projectC); + projectA.AddPackageToAllFrameworks(packageX); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Projects.Add(projectC); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + GetSubstringCount(r.AllOutput, "NU1603", ignoreCase: false).Should().Be(1); + } + } + + [Fact] + // Tests ProjA[PkgX NoWarn NU1603] -> ProjB -> PkgX[NU1603] + // -> ProjC -> PkgX[NU1603] + // -> PkgX[NU1603] + public void GivenMultipleProjectReferencesWarnButDirectReferenceNoWarnsVerifyNoWarning() + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectC = SimpleTestProjectContext.CreateNETCore( + "c", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageXWithNoWarn = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageX); + projectB.Save(); + + // C -> X + projectC.AddPackageToAllFrameworks(packageX); + projectC.Save(); + + // A -> B + // A -> C + // A -> X + projectA.AddProjectToAllFrameworks(projectB); + projectA.AddProjectToAllFrameworks(projectC); + projectA.AddPackageToAllFrameworks(packageXWithNoWarn); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Projects.Add(projectC); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + GetSubstringCount(r.AllOutput, "NU1603", ignoreCase: false).Should().Be(2); + } + } + + [Fact] + // Tests ProjA -> ProjB[PkgX NoWarn NU1603] -> PkgX[NU1603] + // -> ProjC -> ProjB[PkgX NoWarn NU1603] -> PkgX[NU1603] + public void GivenSinglePointOfReferenceNoWarnsVerifyNoWarning() + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectC = SimpleTestProjectContext.CreateNETCore( + "c", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + // Referenced but not created + var packageXWithNoWarn = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageXWithNoWarn); + projectB.Save(); + + // C -> B + projectC.AddProjectToAllFrameworks(projectB); + projectC.Save(); + + // A -> B + // A -> C + // A -> X + projectA.AddProjectToAllFrameworks(projectB); + projectA.AddProjectToAllFrameworks(projectC); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Projects.Add(projectC); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().NotContain("NU1603"); + } + } + + [Fact] + // Tests ProjA -> ProjB[PkgX NoWarn NU1603] -> PkgX[NU1603] + // -> ProjC[PkgX NoWarn NU1603] -> PkgX[NU1603] + // -> ProjD -> ProjE -> ProjF -> PkgX[NU1603] + public void GivenOneLongPathWarnsVerifyWarning() + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projectA = SimpleTestProjectContext.CreateNETCore( + "a", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectB = SimpleTestProjectContext.CreateNETCore( + "b", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectC = SimpleTestProjectContext.CreateNETCore( + "c", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectD = SimpleTestProjectContext.CreateNETCore( + "d", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectE = SimpleTestProjectContext.CreateNETCore( + "e", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + var projectF = SimpleTestProjectContext.CreateNETCore( + "f", + pathContext.SolutionRoot, + NuGetFramework.Parse("netcoreapp2.0")); + + + // Referenced but not created + var packageXWithNoWarn = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Referenced but not created + var packageX = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + // B -> X + projectB.AddPackageToAllFrameworks(packageXWithNoWarn); + projectB.Save(); + + // C -> B + projectC.AddPackageToAllFrameworks(packageXWithNoWarn); + projectC.Save(); + + // F -> X + projectF.AddPackageToAllFrameworks(packageX); + projectF.Save(); + + // E -> F + projectE.AddProjectToAllFrameworks(projectF); + projectE.Save(); + + // D -> E + projectD.AddProjectToAllFrameworks(projectE); + projectD.Save(); + + // A -> B + // A -> C + // A -> D + projectA.AddProjectToAllFrameworks(projectB); + projectA.AddProjectToAllFrameworks(projectC); + projectA.AddProjectToAllFrameworks(projectD); + projectA.Save(); + + solution.Projects.Add(projectA); + solution.Projects.Add(projectB); + solution.Projects.Add(projectC); + solution.Projects.Add(projectD); + solution.Projects.Add(projectE); + solution.Projects.Add(projectF); + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().Contain("NU1603"); + } + } + + + // Densely connected solutions containing 5, 10, 20 and 50 projects + + [Theory] + [InlineData(5)] + [InlineData(10)] + [InlineData(20)] + [InlineData(50)] + public void GivenDenseSolutionWithMultiplePathsVerifyNoWarn(int projectCount) + { + // Arrange + using (var pathContext = new SimpleTestPathContext()) + { + // Set up solution, project, and packages + var solution = new SimpleTestSolutionContext(pathContext.SolutionRoot); + + var projects = new List(); + + var framework = NuGetFramework.Parse("net461"); + + // Referenced but not created + var packageXWithNoWarn = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.0", + NoWarn = "NU1603" + }; + + // Created in the source + var packageX11 = new SimpleTestPackageContext() + { + Id = "x", + Version = "1.0.1" + }; + + SimpleTestPackageUtility.CreatePackages(pathContext.PackageSource, packageX11); + + for (var i = 0; i < projectCount; i++) + { + var project = SimpleTestProjectContext.CreateNETCore( + "project_" + i, + pathContext.SolutionRoot, + framework); + + projects.Add(project); + } + + for (var i = 1; i < projects.Count(); i++) + { + var project = projects[i]; + project.AddPackageToAllFrameworks(packageXWithNoWarn); + } + + for (var i = 0; i < projects.Count() - 1; i++) + { + var projectA = projects[i]; + for (var j = i+1; j < projects.Count(); j++) + { + var projectB = projects[j]; + projectA.AddProjectToAllFrameworks(projectB); + } + } + + foreach (var project in projects) + { + project.Save(); + solution.Projects.Add(project); + } + + solution.Create(pathContext.SolutionRoot); + + // Act + var r = Util.RestoreSolution(pathContext, expectedExitCode: 0); + + // Assert + r.Success.Should().BeTrue(); + r.AllOutput.Should().NotContain("NU1603"); + } + } + + private static int GetSubstringCount(string str, string substr, bool ignoreCase) + { + var splitChars = new char[] { '.', '?', '!', ' ', ';', ':', ',', '\r', '\n' }; + var words = str.Split(splitChars, StringSplitOptions.RemoveEmptyEntries); + var comparisonType = ignoreCase ? + StringComparison.OrdinalIgnoreCase : + StringComparison.Ordinal; + + return words + .Where(word => string.Equals(word, substr, comparisonType)) + .Count(); + } + } +} diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/CollectorLoggerTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/CollectorLoggerTests.cs index 6ddb026a6fc..e7a64ed9eac 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/CollectorLoggerTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/CollectorLoggerTests.cs @@ -114,7 +114,13 @@ public void CollectorLogger_DoesNotPassLogCallsToInnerLoggerByDefaultWithFilePat var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object, LogLevel.Debug, hideWarningsAndErrors: false) { - ProjectPath = projectPath + _projectSpec = new PackageSpec() + { + RestoreMetadata = new ProjectRestoreMetadata() + { + ProjectPath = projectPath + } + } }; // Act @@ -368,10 +374,10 @@ public void CollectorLogger_LogsWarningsAsErrorsErrorsForProjectWideWarnAsErrorS var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + null, + null) }; // Act @@ -402,10 +408,10 @@ public void CollectorLogger_LogsWarningsAsErrorsForProjectAllWarningsAsErrors() var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + null, + null) }; // Act @@ -434,10 +440,10 @@ public void CollectorLogger_LogsWarningsAsErrorsForProjectAllWarningsAsErrorsAnd var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + null, + null) }; // Act @@ -468,10 +474,10 @@ public void CollectorLogger_DoesNotLogsWarningsForProjectWideNoWarnSet() var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + null, + null) }; // Act @@ -506,11 +512,10 @@ public void CollectorLogger_DoesNotLogsWarningsForPackageSpecificNoWarnSet() var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null) }; // Act @@ -545,11 +550,10 @@ public void CollectorLogger_LogsWarningsForPackageSpecificNoWarnSetButWarningsWi var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null) }; // Act @@ -586,11 +590,10 @@ public void CollectorLogger_DoesNotLogsWarningsForPackageSpecificNoWarnSetWithMu var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null) }; // Act @@ -622,16 +625,15 @@ public void CollectorLogger_DoesNotLogsWarningsForPackageSpecificNoWarnSetWithLi var warnAsErrorSet = new HashSet { }; var allWarningsAsErrors = false; var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); - packageSpecificWarningProperties.AddRange(new List { NuGetLogCode.NU1500, NuGetLogCode.NU1601, NuGetLogCode.NU1605}, libraryId, targetFramework); + packageSpecificWarningProperties.AddRangeOfCodes(new List { NuGetLogCode.NU1500, NuGetLogCode.NU1601, NuGetLogCode.NU1605}, libraryId, targetFramework); var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null) }; // Act @@ -663,16 +665,15 @@ public void CollectorLogger_DoesNotLogsWarningsForPackageSpecificNoWarnSetWithLi var warnAsErrorSet = new HashSet { }; var allWarningsAsErrors = false; var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); - packageSpecificWarningProperties.AddRange(new List { NuGetLogCode.NU1500 }, libraryId, targetFramework); + packageSpecificWarningProperties.AddRangeOfCodes(new List { NuGetLogCode.NU1500 }, libraryId, targetFramework); var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null) }; // Act @@ -711,12 +712,10 @@ public void CollectorLogger_DoesNotLogsWarningsForPackageSpecificNoWarnSetForGlo var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List { targetFramework } - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { targetFramework }) }; // Act @@ -753,12 +752,10 @@ public void CollectorLogger_DoesNotLogsWarningsForPackageSpecificNoWarnSetForGlo var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List { targetFramework, netcoreTargetFramework } - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { targetFramework, netcoreTargetFramework }) }; // Act @@ -795,12 +792,10 @@ public void CollectorLogger_DoesNotLogsWarningsForPackageSpecificNoWarnSetWithMu var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List { targetFramework } - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { targetFramework }) }; // Act @@ -841,12 +836,10 @@ public void CollectorLogger_DoesNotLogsWarningsForPackageSpecificNoWarnSetWithMu var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List { targetFramework, netcoreTargetFramework } - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { targetFramework, netcoreTargetFramework }) }; // Act @@ -879,10 +872,10 @@ public void CollectorLogger_DoesNotLogsWarningsForProjectWideNoWarnSetAndAllWarn var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + null, + null) }; // Act @@ -911,10 +904,10 @@ public void CollectorLogger_DoesNotLogsWarningsForProjectWideNoWarnSetAndWarnAsE var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + null, + null) }; // Act @@ -943,10 +936,10 @@ public void CollectorLogger_DoesNotLogsWarningsForPackageSpecificNoWarnSetAndWar var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + null, + null) }; // Act @@ -983,11 +976,10 @@ public void CollectorLogger_DoesNotLogsWarningsForPackageSpecificAndProjectWideN var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null) }; // Act @@ -1026,11 +1018,10 @@ public void CollectorLogger_DoesNotLogsWarningsForPackageSpecificNoWarnSetAndPro var innerLogger = new Mock(); var collector = new RestoreCollectorLogger(innerLogger.Object) { - WarningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - } + ProjectWarningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null) }; // Act diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/TransitiveNoWarnUtilsTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/TransitiveNoWarnUtilsTests.cs new file mode 100644 index 00000000000..ed06ee56d6d --- /dev/null +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/TransitiveNoWarnUtilsTests.cs @@ -0,0 +1,1054 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text; +using NuGet.Common; +using NuGet.Frameworks; +using NuGet.ProjectModel; +using Xunit; +using FluentAssertions; +using System.Diagnostics; + +namespace NuGet.Commands.Test +{ + public class TransitiveNoWarnUtilsTests + { + + // Tests for TransitiveNoWarnUtils.ExtractPathNoWarnProperties + [Fact] + public void ExtractPathNoWarnProperties_ReturnsEmptySetIfPathPropertiesAreNull() + { + // Arrange & Act + var extractedNoWarnSet = TransitiveNoWarnUtils.ExtractPathNoWarnProperties(null, "test_id"); + + // Assert + extractedNoWarnSet.Should().NotBeNull(); + extractedNoWarnSet.Should().BeEmpty(); + } + + [Fact] + public void ExtractPathNoWarnProperties_CorrectlyReadsProjectWideNoWarns() + { + // Arrange + var noWarnSet = new HashSet { NuGetLogCode.NU1601, NuGetLogCode.NU1603 }; + var warningsAsErrorSet = new HashSet { }; + + var projectWideWarningProperties = new WarningProperties( + warningsAsErrors: warningsAsErrorSet, + noWarn: noWarnSet, + allWarningsAsErrors: false + ); + + var warningPropertiesCollection = new WarningPropertiesCollection( + projectWideWarningProperties: projectWideWarningProperties, + packageSpecificWarningProperties: null, + projectFrameworks: null + ); + + // Act + var extractedNoWarnSet = TransitiveNoWarnUtils.ExtractPathNoWarnProperties(warningPropertiesCollection, "test_id"); + + // Assert + extractedNoWarnSet.Should().NotBeNullOrEmpty(); + extractedNoWarnSet.Should().BeEquivalentTo(noWarnSet); + } + + [Fact] + public void ExtractPathNoWarnProperties_CorrectlyReadsPackageSpecificNoWarns() + { + // Arrange + var packageId = "test_package"; + var framework = NuGetFramework.Parse("net461"); + var expectedNoWarnSet = new HashSet { NuGetLogCode.NU1603, NuGetLogCode.NU1605 }; + var noWarnSet = new HashSet { }; + var warningsAsErrorSet = new HashSet { }; + + var projectWideWarningProperties = new WarningProperties( + warningsAsErrors: warningsAsErrorSet, + noWarn: noWarnSet, + allWarningsAsErrors: false + ); + + var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); + packageSpecificWarningProperties.Add(NuGetLogCode.NU1603, packageId, framework); + packageSpecificWarningProperties.Add(NuGetLogCode.NU1605, packageId, framework); + packageSpecificWarningProperties.Add(NuGetLogCode.NU1701, "other_package", framework); + + var warningPropertiesCollection = new WarningPropertiesCollection( + projectWideWarningProperties: projectWideWarningProperties, + packageSpecificWarningProperties: packageSpecificWarningProperties, + projectFrameworks: null + ); + + // Act + var extractedNoWarnSet = TransitiveNoWarnUtils.ExtractPathNoWarnProperties(warningPropertiesCollection, packageId); + + // Assert + extractedNoWarnSet.Should().NotBeNullOrEmpty(); + extractedNoWarnSet.Should().BeEquivalentTo(expectedNoWarnSet); + } + + + [Fact] + public void ExtractPathNoWarnProperties_CorrectlyReadsPackageSpecificAndProjectWideNoWarns() + { + // Arrange + var packageId = "test_package"; + var framework = NuGetFramework.Parse("net461"); + var expectedNoWarnSet = new HashSet { NuGetLogCode.NU1601 , NuGetLogCode.NU1603, NuGetLogCode.NU1605 }; + var noWarnSet = new HashSet { NuGetLogCode.NU1601, NuGetLogCode.NU1605 }; + var warningsAsErrorSet = new HashSet { }; + + var projectWideWarningProperties = new WarningProperties( + warningsAsErrors: warningsAsErrorSet, + noWarn: noWarnSet, + allWarningsAsErrors: false + ); + + var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); + packageSpecificWarningProperties.Add(NuGetLogCode.NU1603, packageId, framework); + packageSpecificWarningProperties.Add(NuGetLogCode.NU1605, packageId, framework); + packageSpecificWarningProperties.Add(NuGetLogCode.NU1701, "other_package", framework); + + var warningPropertiesCollection = new WarningPropertiesCollection( + projectWideWarningProperties: projectWideWarningProperties, + packageSpecificWarningProperties: packageSpecificWarningProperties, + projectFrameworks: null + ); + + // Act + var extractedNoWarnSet = TransitiveNoWarnUtils.ExtractPathNoWarnProperties(warningPropertiesCollection, packageId); + + // Assert + extractedNoWarnSet.Should().NotBeNullOrEmpty(); + extractedNoWarnSet.Should().BeEquivalentTo(expectedNoWarnSet); + } + + + // Tests for TransitiveNoWarnUtils.TryMergeNullObjects + [Fact] + public void TryMergeNullObjects_ReturnsNullIfBothAreNull() + { + // Arrange + object mergedObject; + object first = null; + object second = null; + + // Act + var success = TransitiveNoWarnUtils.TryMergeNullObjects(first, second, out mergedObject); + + // Assert + success.Should().BeTrue(); + mergedObject.Should().BeNull(); + } + + [Fact] + public void TryMergeNullObjects_ReturnsFirstIfNotNull() + { + // Arrange + object mergedObject; + var first = new object(); + object second = null; + + // Act + var success = TransitiveNoWarnUtils.TryMergeNullObjects(first, second, out mergedObject); + + // Assert + success.Should().BeTrue(); + mergedObject.Should().Be(first); + } + + [Fact] + public void TryMergeNullObjects_ReturnsSecondIfNotNull() + { + // Arrange + object mergedObject; + object first = null; + var second = new object(); + + // Act + var success = TransitiveNoWarnUtils.TryMergeNullObjects(first, second, out mergedObject); + + // Assert + success.Should().BeTrue(); + mergedObject.Should().Be(second); + } + + [Fact] + public void TryMergeNullObjects_ReturnsFailureIfNoneNull() + { + // Arrange + object mergedObject; + var first = new object(); + var second = new object(); + + // Act + var success = TransitiveNoWarnUtils.TryMergeNullObjects(first, second, out mergedObject); + + // Assert + success.Should().BeFalse(); + mergedObject.Should().BeNull(); + } + + // Tests for TransitiveNoWarnUtils.MergePackageSpecificWarningProperties + [Fact] + public void MergePackageSpecificWarningProperties_ReturnsNullIfBothAreNull() + { + // Arrange + PackageSpecificWarningProperties first = null; + PackageSpecificWarningProperties second = null; + + // Act + var merged = TransitiveNoWarnUtils.MergePackageSpecificWarningProperties(first, second); + + // Assert + merged.Should().BeNull(); + } + + [Fact] + public void MergePackageSpecificWarningProperties_ReturnsFirstIfNotNull() + { + // Arrange + var first = new PackageSpecificWarningProperties(); + PackageSpecificWarningProperties second = null; + + // Act + var merged = TransitiveNoWarnUtils.MergePackageSpecificWarningProperties(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.Should().Be(first); + } + + [Fact] + public void MergePackageSpecificWarningProperties_ReturnsSecondIfNotNull() + { + // Arrange + PackageSpecificWarningProperties first = null; + var second = new PackageSpecificWarningProperties(); + + // Act + var merged = TransitiveNoWarnUtils.MergePackageSpecificWarningProperties(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.Should().Be(second); + } + + [Fact] + public void MergePackageSpecificWarningProperties_MergesEmptyCollections() + { + // Arrange + var first = new PackageSpecificWarningProperties(); + var second = new PackageSpecificWarningProperties(); + + // Act + var merged = TransitiveNoWarnUtils.MergePackageSpecificWarningProperties(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.Properties.Should().BeNull(); + } + + [Fact] + public void MergePackageSpecificWarningProperties_MergesNonEmptyCollections() + { + // Arrange + var packageId1 = "test_id1"; + var packageId2 = "test_id2"; + var net461 = NuGetFramework.Parse("net461"); + var netcoreapp = NuGetFramework.Parse("netcoreapp2.0"); + var expectedResult = new PackageSpecificWarningProperties(); + expectedResult.AddRangeOfCodes( + new List { NuGetLogCode.NU1601, NuGetLogCode.NU1605 }, + packageId1, + net461); + expectedResult.AddRangeOfFrameworks( + NuGetLogCode.NU1701, + packageId2, + new List { net461, netcoreapp }); + expectedResult.AddRangeOfFrameworks( + NuGetLogCode.NU1701, + packageId1, + new List { net461, netcoreapp }); + expectedResult.AddRangeOfFrameworks( + NuGetLogCode.NU1701, + packageId2, + new List { net461, netcoreapp }); + expectedResult.AddRangeOfFrameworks( + NuGetLogCode.NU1604, + packageId1, + new List { net461, netcoreapp }); + + + var first = new PackageSpecificWarningProperties(); + first.AddRangeOfCodes( + new List { NuGetLogCode.NU1601, NuGetLogCode.NU1605 }, + packageId1, + net461); + first.AddRangeOfFrameworks( + NuGetLogCode.NU1701, + packageId2, + new List { net461, netcoreapp }); + first.AddRangeOfFrameworks( + NuGetLogCode.NU1701, + packageId1, + new List { netcoreapp }); + + var second = new PackageSpecificWarningProperties(); + second.AddRangeOfFrameworks( + NuGetLogCode.NU1701, + packageId2, + new List { net461, netcoreapp }); + second.AddRangeOfFrameworks( + NuGetLogCode.NU1604, + packageId1, + new List { net461, netcoreapp }); + second.AddRangeOfFrameworks( + NuGetLogCode.NU1701, + packageId1, + new List { net461 }); + + + // Act + var merged = TransitiveNoWarnUtils.MergePackageSpecificWarningProperties(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.Properties.Should().NotBeNull(); + merged.ShouldBeEquivalentTo(expectedResult); + } + + // Tests for TransitiveNoWarnUtils.MergeProjectWideWarningProperties + [Fact] + public void MergeProjectWideWarningProperties_ReturnsNullIfBothAreNull() + { + // Arrange + WarningProperties first = null; + WarningProperties second = null; + + // Act + var merged = TransitiveNoWarnUtils.MergeProjectWideWarningProperties(first, second); + + // Assert + merged.Should().BeNull(); + } + + [Fact] + public void MergeProjectWideWarningProperties_ReturnsFirstIfNotNull() + { + // Arrange + var first = new WarningProperties(); + WarningProperties second = null; + + // Act + var merged = TransitiveNoWarnUtils.MergeProjectWideWarningProperties(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.Should().Be(first); + } + + [Fact] + public void MergeProjectWideWarningProperties_ReturnsSecondIfNotNull() + { + // Arrange + WarningProperties first = null; + var second = new WarningProperties(); + + // Act + var merged = TransitiveNoWarnUtils.MergeProjectWideWarningProperties(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.Should().Be(second); + } + + [Fact] + public void MergeProjectWideWarningProperties_MergesEmptyCollections() + { + // Arrange + var first = new WarningProperties(); + var second = new WarningProperties(); + + // Act + var merged = TransitiveNoWarnUtils.MergeProjectWideWarningProperties(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.AllWarningsAsErrors.Should().BeFalse(); + merged.WarningsAsErrors.Should().BeEmpty(); + merged.NoWarn.Should().BeEmpty(); + } + + [Theory] + [InlineData("NU1603, NU1605", "NU1701", true, "", "", false, "NU1603, NU1605", "", true)] + [InlineData( "", "", false, "NU1603, NU1605", "NU1701", true, "NU1603, NU1605", "", true)] + [InlineData("NU1603, NU1701", "", false, "NU1603, NU1701", "", false, "NU1603, NU1701", "", false)] + [InlineData("", "NU1603, NU1701", false, "", "NU1603, NU1701", false, "", "", false)] + [InlineData("NU1601", "NU1602, NU1603", false, "NU1604", "NU1605, NU1701", false, "NU1601, NU1604", "", false)] + [InlineData("NU1601", "NU1602, NU1603", true, "NU1604", "NU1605, NU1701", false, "NU1601, NU1604", "", true)] + [InlineData("", "", false, "", "", false, "", "", false)] + [InlineData("", "", true, "", "", false, "", "", true)] + [InlineData("", "", false, "", "", true, "", "", true)] + [InlineData("", "", true, "", "", true, "", "", true)] + public void MergeProjectWideWarningProperties_MergesNonEmptyCollections( + string firstNoWarn, string firstWarningsAsErrors, bool firstAllWarningsAsErrors, + string secondNoWarn, string secondWarningsAsErrors, bool secondAllWarningsAsErrors, + string expectedNoWarn, string expectedWarningsAsErrors, bool expectedAllWarningsAsErrors) + { + // Arrange + var first = new WarningProperties( + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(firstWarningsAsErrors)), + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(firstNoWarn)), + firstAllWarningsAsErrors); + + var second = new WarningProperties( + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(secondWarningsAsErrors)), + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(secondNoWarn)), + secondAllWarningsAsErrors); + + var expected = new WarningProperties( + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(expectedWarningsAsErrors)), + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(expectedNoWarn)), + expectedAllWarningsAsErrors); + + // Act + var merged = TransitiveNoWarnUtils.MergeProjectWideWarningProperties(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.AllWarningsAsErrors.ShouldBeEquivalentTo(expected.AllWarningsAsErrors); + merged.WarningsAsErrors.Should().BeEmpty(); + merged.NoWarn.ShouldBeEquivalentTo(expected.NoWarn); + merged.ShouldBeEquivalentTo(expected); + } + + // Tests for TransitiveNoWarnUtils.MergeWarningPropertiesCollection + [Fact] + public void MergeWarningPropertiesCollection_ReturnsNullIfBothAreNull() + { + // Arrange + WarningPropertiesCollection first = null; + WarningPropertiesCollection second = null; + + // Act + var merged = TransitiveNoWarnUtils.MergeWarningPropertiesCollection(first, second); + + // Assert + merged.Should().BeNull(); + } + + [Fact] + public void MergeWarningPropertiesCollection_ReturnsFirstIfNotNull() + { + // Arrange + var first = new WarningPropertiesCollection( + projectWideWarningProperties: null, + packageSpecificWarningProperties: null, + projectFrameworks: null + ); + WarningPropertiesCollection second = null; + + // Act + var merged = TransitiveNoWarnUtils.MergeWarningPropertiesCollection(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.Should().Be(first); + } + + [Fact] + public void MergeWarningPropertiesCollection_ReturnsSecondIfNotNull() + { + // Arrange + WarningPropertiesCollection first = null; + var second = new WarningPropertiesCollection( + projectWideWarningProperties: null, + packageSpecificWarningProperties: null, + projectFrameworks: null + ); + + // Act + var merged = TransitiveNoWarnUtils.MergeWarningPropertiesCollection(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.Should().Be(second); + } + + [Fact] + public void MergeWarningPropertiesCollection_MergesEmptyCollections() + { + // Arrange + var first = new WarningPropertiesCollection( + projectWideWarningProperties: null, + packageSpecificWarningProperties: null, + projectFrameworks: null + ); + var second = new WarningPropertiesCollection( + projectWideWarningProperties: null, + packageSpecificWarningProperties: null, + projectFrameworks: null + ); + + // Act + var merged = TransitiveNoWarnUtils.MergeWarningPropertiesCollection(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.ProjectWideWarningProperties.Should().BeNull(); + merged.PackageSpecificWarningProperties.Should().BeNull(); + merged.ProjectFrameworks.Should().BeEmpty(); + } + + [Fact] + public void MergeWarningPropertiesCollection_MergesNonEmptyCollections1() + { + // Arrange + var first = new WarningPropertiesCollection( + projectWideWarningProperties: null, + packageSpecificWarningProperties: null, + projectFrameworks: new List { NuGetFramework.Parse("net461"), NuGetFramework.Parse("netcoreapp1.0") }.AsReadOnly() + ); + var second = new WarningPropertiesCollection( + projectWideWarningProperties: null, + packageSpecificWarningProperties: null, + projectFrameworks: new List { NuGetFramework.Parse("net45"), NuGetFramework.Parse("netcoreapp1.1") }.AsReadOnly() + ); + + // Act + var merged = TransitiveNoWarnUtils.MergeWarningPropertiesCollection(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.ProjectWideWarningProperties.Should().BeNull(); + merged.PackageSpecificWarningProperties.Should().BeNull(); + merged.ProjectFrameworks.Should().BeEmpty(); + } + + [Fact] + public void MergeWarningPropertiesCollection_MergesNonEmptyCollections2() + { + // Arrange + var first = new WarningPropertiesCollection( + projectWideWarningProperties: null, + packageSpecificWarningProperties: null, + projectFrameworks: new List { NuGetFramework.Parse("net461"), NuGetFramework.Parse("netcoreapp1.0") }.AsReadOnly() + ); + var second = new WarningPropertiesCollection( + projectWideWarningProperties: null, + packageSpecificWarningProperties: null, + projectFrameworks: new List { NuGetFramework.Parse("net45"), NuGetFramework.Parse("netcoreapp1.1") }.AsReadOnly() + ); + + // Act + var merged = TransitiveNoWarnUtils.MergeWarningPropertiesCollection(first, second); + + // Assert + merged.Should().NotBeNull(); + merged.ProjectWideWarningProperties.Should().BeNull(); + merged.PackageSpecificWarningProperties.Should().BeNull(); + merged.ProjectFrameworks.Should().BeEmpty(); + } + + // Tests for TransitiveNoWarnUtils.DependencyNode equality + [Fact] + public void DependencyNodeEqualitySucceeds_NodesAreNull() + { + // Arrange + TransitiveNoWarnUtils.DependencyNode first = null; + TransitiveNoWarnUtils.DependencyNode second = null; + + // Act + var seen = new HashSet + { + first, + second + }; + + // Assert + seen.Count.Should().Be(1); + } + + [Fact] + public void DependencyNodeEqualitySucceeds_OneNodeIsNull() + { + // Arrange + var first = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection(null, null, null)); + + TransitiveNoWarnUtils.DependencyNode second = null; + + // Act + var seen = new HashSet + { + first, + second + }; + + // Assert + seen.Count.Should().Be(2); + } + + [Fact] + public void DependencyNodeEqualitySucceeds_NodesAreSame() + { + // Arrange + var first = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection(null, null, null)); + + // Act + var seen = new HashSet + { + first + }; + + // Assert + seen.Count.Should().Be(1); + } + + [Fact] + public void DependencyNodeEqualitySucceeds_NodesHaveSameInternalObjects() + { + // Arrange + var projectWideWarningProperties = new WarningProperties(); + var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); + var projectFrameworks = new List(); + + var first = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + packageSpecificWarningProperties, + projectFrameworks + )); + + var second = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + packageSpecificWarningProperties, + projectFrameworks + )); + + // Act + var seen = new HashSet + { + first, + second + }; + + // Assert + seen.Count.Should().Be(1); + } + + [Theory] + [InlineData("NU1605, NU1701", "NU1602, NU1603", false, "NU1701, NU1605", "NU1603, NU1602", false)] + [InlineData("NU1605, NU1701", "NU1602, NU1603", true, "NU1701, NU1605", "NU1603, NU1602", true)] + [InlineData("", "", false, "", "", false)] + [InlineData("", "", true, "", "", true)] + public void DependencyNodeEqualitySucceeds_NodesHaveEquivalentWarningProperties( + string firstNoWarn, string firstWarningsAsErrors, bool firstAllWarningsAsErrors, + string secondNoWarn, string secondWarningsAsErrors, bool secondAllWarningsAsErrors) + { + // Arrange + var packageId1 = "test_id1"; + var packageId2 = "test_id2"; + var net461 = NuGetFramework.Parse("net461"); + var netcoreapp = NuGetFramework.Parse("netcoreapp2.0"); + + // First + var firstProjectWideWarningProperties = new WarningProperties( + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(firstWarningsAsErrors)), + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(firstNoWarn)), + firstAllWarningsAsErrors); + + var firstPackageSpecificWarningProperties = new PackageSpecificWarningProperties(); + firstPackageSpecificWarningProperties.AddRangeOfCodes( + new List { NuGetLogCode.NU1601, NuGetLogCode.NU1605 }, + packageId1, + net461); + firstPackageSpecificWarningProperties.AddRangeOfFrameworks( + NuGetLogCode.NU1701, + packageId2, + new List { net461, netcoreapp }); + firstPackageSpecificWarningProperties.AddRangeOfFrameworks( + NuGetLogCode.NU1701, + packageId1, + new List { net461 }); + + var firstProjectFrameworks = new List { net461, netcoreapp }; + + // Second + var secondProjectWideWarningProperties = new WarningProperties( + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(secondWarningsAsErrors)), + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(secondNoWarn)), + secondAllWarningsAsErrors); + + var secondPackageSpecificWarningProperties = new PackageSpecificWarningProperties(); + secondPackageSpecificWarningProperties.AddRangeOfFrameworks( + NuGetLogCode.NU1701, + packageId1, + new List { net461 }); + secondPackageSpecificWarningProperties.AddRangeOfCodes( + new List { NuGetLogCode.NU1701, NuGetLogCode.NU1605, NuGetLogCode.NU1601 }, + packageId1, + net461); + + var secondProjectFrameworks = new List { netcoreapp, net461 }; + + var first = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + firstProjectWideWarningProperties, + firstPackageSpecificWarningProperties, + firstProjectFrameworks + )); + + var second = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + firstProjectWideWarningProperties, + firstPackageSpecificWarningProperties, + firstProjectFrameworks + )); + + // Act + var seen = new HashSet + { + first, + second + }; + + // Assert + seen.Count.Should().Be(1); + } + + [Fact] + public void DependencyNodeEqualityFails_NodesHaveDifferentMetaData() + { + // Arrange + var projectWideWarningProperties = new WarningProperties(); + var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); + var projectFrameworks = new List(); + + var first = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + packageSpecificWarningProperties, + projectFrameworks + )); + + var second = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: false, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + packageSpecificWarningProperties, + projectFrameworks + )); + + var third = new TransitiveNoWarnUtils.DependencyNode( + id: "test_other", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + packageSpecificWarningProperties, + projectFrameworks + )); + + // Act + var seen = new HashSet + { + first, + second, + third + }; + + // Assert + seen.Count.Should().Be(3); + } + + [Theory] + [InlineData("NU1605, NU1701", "", false, "", "", false)] + [InlineData("NU1605, NU1701", "", false, "NU1701, NU1603", "", false)] + [InlineData("", "NU1602, NU1603", true, "", "", true)] + [InlineData("", "NU1602, NU1603", true, "", "NU1605, NU1602", true)] + [InlineData("NU1605, NU1701", "NU1602, NU1603", true, "NU1701, NU1605", "NU1603, NU1602", false)] + [InlineData("NU1605, NU1701", "NU1602, NU1603", false, "NU1701, NU1605", "NU1603, NU1602", true)] + [InlineData("", "", true, "", "", false)] + [InlineData("", "", false, "", "", true)] + public void DependencyNodeEqualityFails_NodesHaveDifferentProjectWideWarningProperties( + string firstNoWarn, string firstWarningsAsErrors, bool firstAllWarningsAsErrors, + string secondNoWarn, string secondWarningsAsErrors, bool secondAllWarningsAsErrors) + { + // Arrange + var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); + var projectFrameworks = new List(); + + var firstProjectWideWarningProperties = new WarningProperties( + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(firstWarningsAsErrors)), + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(firstNoWarn)), + firstAllWarningsAsErrors); + + var secondProjectWideWarningProperties = new WarningProperties( + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(secondWarningsAsErrors)), + new HashSet(MSBuildRestoreUtility.GetNuGetLogCodes(secondNoWarn)), + secondAllWarningsAsErrors); + + var first = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + firstProjectWideWarningProperties, + packageSpecificWarningProperties, + projectFrameworks + )); + + var second = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + secondProjectWideWarningProperties, + packageSpecificWarningProperties, + projectFrameworks + )); + + // Act + var seen = new HashSet + { + first, + second + }; + + // Assert + seen.Count.Should().Be(2); + } + + [Fact] + public void DependencyNodeEqualityFails_NodesHaveDifferentFrameworksInPackageSpecificNoWarn() + { + // Arrange + var packageId1 = "test_id1"; + var net461 = NuGetFramework.Parse("net461"); + var netcoreapp = NuGetFramework.Parse("netcoreapp2.0"); + + var projectWideWarningProperties = new WarningProperties(); + var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); + var projectFrameworks = new List { net461, netcoreapp }; + + var firstPackageSpecificWarningProperties = new PackageSpecificWarningProperties(); + firstPackageSpecificWarningProperties.AddRangeOfCodes( + new List { NuGetLogCode.NU1601 }, + packageId1, + net461); + + var secondPackageSpecificWarningProperties = new PackageSpecificWarningProperties(); + secondPackageSpecificWarningProperties.AddRangeOfCodes( + new List { NuGetLogCode.NU1601 }, + packageId1, + netcoreapp); + + var first = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + firstPackageSpecificWarningProperties, + projectFrameworks + )); + + var second = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + secondPackageSpecificWarningProperties, + projectFrameworks + )); + + // Act + var seen = new HashSet + { + first, + second + }; + + // Assert + seen.Count.Should().Be(2); + } + + [Fact] + public void DependencyNodeEqualityFails_NodesHaveDifferentNoWarnCodesInPackageSpecificNoWarn() + { + // Arrange + var packageId1 = "test_id1"; + var net461 = NuGetFramework.Parse("net461"); + + var projectWideWarningProperties = new WarningProperties(); + var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); + var projectFrameworks = new List { net461 }; + + var firstPackageSpecificWarningProperties = new PackageSpecificWarningProperties(); + firstPackageSpecificWarningProperties.AddRangeOfCodes( + new List { NuGetLogCode.NU1601 }, + packageId1, + net461); + + var secondPackageSpecificWarningProperties = new PackageSpecificWarningProperties(); + secondPackageSpecificWarningProperties.AddRangeOfCodes( + new List { NuGetLogCode.NU1602 }, + packageId1, + net461); + + var first = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + firstPackageSpecificWarningProperties, + projectFrameworks + )); + + var second = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + secondPackageSpecificWarningProperties, + projectFrameworks + )); + + // Act + var seen = new HashSet + { + first, + second + }; + + // Assert + seen.Count.Should().Be(2); + } + + [Fact] + public void DependencyNodeEqualityFails_NodesHaveDifferentPackageIdsInPackageSpecificNoWarn() + { + // Arrange + var packageId1 = "test_id1"; + var packageId2 = "test_id2"; + var net461 = NuGetFramework.Parse("net461"); + + var projectWideWarningProperties = new WarningProperties(); + var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); + var projectFrameworks = new List { net461 }; + + var firstPackageSpecificWarningProperties = new PackageSpecificWarningProperties(); + firstPackageSpecificWarningProperties.AddRangeOfCodes( + new List { NuGetLogCode.NU1601 }, + packageId1, + net461); + + var secondPackageSpecificWarningProperties = new PackageSpecificWarningProperties(); + secondPackageSpecificWarningProperties.AddRangeOfCodes( + new List { NuGetLogCode.NU1601 }, + packageId2, + net461); + + var first = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + firstPackageSpecificWarningProperties, + projectFrameworks + )); + + var second = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + secondPackageSpecificWarningProperties, + projectFrameworks + )); + + // Act + var seen = new HashSet + { + first, + second + }; + + // Assert + seen.Count.Should().Be(2); + } + + [Fact] + public void DependencyNodeEqualityFails_NodesHaveDifferentProjectFrameworks() + { + // Arrange + var packageId1 = "test_id1"; + var net461 = NuGetFramework.Parse("net461"); + var net45 = NuGetFramework.Parse("net45"); + var netcoreapp = NuGetFramework.Parse("netcoreapp1.0"); + + var projectWideWarningProperties = new WarningProperties(); + var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); + var firstProjectFrameworks = new List { net461, netcoreapp }; + var secondProjectFrameworks = new List { netcoreapp, net45, net461 }; + + var firstPackageSpecificWarningProperties = new PackageSpecificWarningProperties(); + firstPackageSpecificWarningProperties.AddRangeOfCodes( + new List { NuGetLogCode.NU1601 }, + packageId1, + net461); + + var secondPackageSpecificWarningProperties = new PackageSpecificWarningProperties(); + secondPackageSpecificWarningProperties.AddRangeOfCodes( + new List { NuGetLogCode.NU1601 }, + packageId1, + net461); + + var first = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + firstPackageSpecificWarningProperties, + firstProjectFrameworks + )); + + var second = new TransitiveNoWarnUtils.DependencyNode( + id: "test", + isProject: true, + warningPropertiesCollection: new WarningPropertiesCollection( + projectWideWarningProperties, + secondPackageSpecificWarningProperties, + secondProjectFrameworks + )); + + // Act + var seen = new HashSet + { + first, + second + }; + + // Assert + seen.Count.Should().Be(2); + } + } +} diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/WarningPropertiesCollectionTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/WarningPropertiesCollectionTests.cs index 19f6a35d1da..ad788eeb839 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/WarningPropertiesCollectionTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/WarningPropertiesCollectionTests.cs @@ -21,10 +21,7 @@ public void WarningPropertiesCollection_ProjectPropertiesWithNoWarn() var noWarnSet = new HashSet { NuGetLogCode.NU1500 }; var warnAsErrorSet = new HashSet { }; var allWarningsAsErrors = false; - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - }; + var warningPropertiesCollection = new WarningPropertiesCollection(new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), null, null); var suppressedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1500, "Warning"); var nonSuppressedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1601, "Warning"); @@ -42,10 +39,7 @@ public void WarningPropertiesCollection_ProjectPropertiesWithWarnAsError() var noWarnSet = new HashSet { }; var warnAsErrorSet = new HashSet { NuGetLogCode.NU1500 }; var allWarningsAsErrors = false; - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - }; + var warningPropertiesCollection = new WarningPropertiesCollection(new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), null, null); var upgradedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1500, "Warning"); var nonSuppressedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1601, "Warning"); @@ -64,10 +58,7 @@ public void WarningPropertiesCollection_ProjectPropertiesWithWarnAsErrorAndUndef var noWarnSet = new HashSet { }; var warnAsErrorSet = new HashSet { NuGetLogCode.Undefined }; var allWarningsAsErrors = false; - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - }; + var warningPropertiesCollection = new WarningPropertiesCollection(new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), null, null); var nonSuppressedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.Undefined, "Warning"); var nonSuppressedMessage2 = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1601, "Warning"); @@ -87,10 +78,7 @@ public void WarningPropertiesCollection_ProjectPropertiesWithAllWarningsAsErrors var noWarnSet = new HashSet { }; var warnAsErrorSet = new HashSet { }; var allWarningsAsErrors = true; - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - }; + var warningPropertiesCollection = new WarningPropertiesCollection(new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), null, null); var upgradedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1500, "Warning"); var upgradedMessage2 = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1601, "Warning"); @@ -109,10 +97,7 @@ public void WarningPropertiesCollection_ProjectPropertiesWithAllWarningsAsErrors var noWarnSet = new HashSet { }; var warnAsErrorSet = new HashSet { }; var allWarningsAsErrors = true; - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - }; + var warningPropertiesCollection = new WarningPropertiesCollection(new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), null, null); var upgradedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.Undefined, "Warning"); var upgradedMessage2 = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1601, "Warning"); @@ -132,10 +117,7 @@ public void WarningPropertiesCollection_ProjectPropertiesWithNoWarnAndWarnAsErro var noWarnSet = new HashSet { NuGetLogCode.NU1500 }; var warnAsErrorSet = new HashSet { NuGetLogCode.NU1500 }; var allWarningsAsErrors = false; - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - }; + var warningPropertiesCollection = new WarningPropertiesCollection(new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), null, null); var suppressedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1500, "Warning"); var nonSuppressedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1601, "Warning"); @@ -153,10 +135,7 @@ public void WarningPropertiesCollection_ProjectPropertiesWithNoWarnAndWarnAsErro var noWarnSet = new HashSet { NuGetLogCode.NU1500 }; var warnAsErrorSet = new HashSet { NuGetLogCode.NU1500 }; var allWarningsAsErrors = true; - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - }; + var warningPropertiesCollection = new WarningPropertiesCollection(new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), null, null); var suppressedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1500, "Warning"); var nonSuppressedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1601, "Warning"); @@ -174,10 +153,7 @@ public void WarningPropertiesCollection_ProjectPropertiesWithWarnAsErrorAndAllWa var noWarnSet = new HashSet { }; var warnAsErrorSet = new HashSet { NuGetLogCode.NU1500 }; var allWarningsAsErrors = true; - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors) - }; + var warningPropertiesCollection = new WarningPropertiesCollection(new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), null, null); var upgradedMessage = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1500, "Warning"); var upgradedMessage2 = new RestoreLogMessage(LogLevel.Warning, NuGetLogCode.NU1601, "Warning"); @@ -204,10 +180,7 @@ public void WarningPropertiesCollection_PackagePropertiesWithFrameworkAndWarning var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, targetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - PackageSpecificWarningProperties = packageSpecificWarningProperties - }; + var warningPropertiesCollection = new WarningPropertiesCollection(null, packageSpecificWarningProperties, null); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, frameworkString); var nonSuppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1601, "Warning", libraryId, frameworkString); @@ -233,10 +206,7 @@ public void WarningPropertiesCollection_PackagePropertiesWithATFFrameworkAndWarn var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, targetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - PackageSpecificWarningProperties = packageSpecificWarningProperties - }; + var warningPropertiesCollection = new WarningPropertiesCollection(null, packageSpecificWarningProperties, null); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, frameworkString); @@ -259,10 +229,7 @@ public void WarningPropertiesCollection_PackagePropertiesWithPTFFrameworkAndWarn var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, targetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - PackageSpecificWarningProperties = packageSpecificWarningProperties - }; + var warningPropertiesCollection = new WarningPropertiesCollection(null, packageSpecificWarningProperties, null); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, frameworkString); @@ -285,11 +252,7 @@ public void WarningPropertiesCollection_PackagePropertiesWithoutFrameworkAndWarn var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, targetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List { targetFramework } - }; + var warningPropertiesCollection = new WarningPropertiesCollection(null, packageSpecificWarningProperties, new List { targetFramework }); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId); @@ -312,10 +275,7 @@ public void WarningPropertiesCollection_PackagePropertiesWithoutFrameworkAndWarn var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, targetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - PackageSpecificWarningProperties = packageSpecificWarningProperties - }; + var warningPropertiesCollection = new WarningPropertiesCollection(null, packageSpecificWarningProperties, null); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, "net45"); @@ -342,11 +302,10 @@ public void WarningPropertiesCollection_PackagePropertiesWithNoWarnAndProjectPro var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, targetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, frameworkString); @@ -372,11 +331,10 @@ public void WarningPropertiesCollection_PackagePropertiesAndProjectPropertiesWit var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId); @@ -403,15 +361,10 @@ public void WarningPropertiesCollection_PackagePropertiesWithNoWarnAndProjectPro var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, targetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List - { - targetFramework - } - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { targetFramework }); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, frameworkString); var suppressedMessage2 = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId); @@ -443,15 +396,10 @@ public void WarningPropertiesCollection_PackagePropertiesWithNoWarnAndProjectPro var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, targetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List - { - targetFramework - } - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { targetFramework }); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, frameworkString); var suppressedMessage2 = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId); @@ -485,12 +433,10 @@ public void WarningPropertiesCollection_PackagePropertiesWithNoWarnAndProjectPro var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, targetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List { targetFramework } - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { targetFramework }); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, frameworkString); var suppressedMessage2 = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId); @@ -527,12 +473,10 @@ public void WarningPropertiesCollection_MessageWithNoTargetGraphAndDependencyWit var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, firstTargetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List { firstTargetFramework, secondTargetFramework } - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { firstTargetFramework, secondTargetFramework }); var nonSuppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, firstFrameworkString); @@ -567,12 +511,10 @@ public void WarningPropertiesCollection_MessageWithNoTargetGraphAndDependencyWit packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, firstTargetFramework); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, secondTargetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List { firstTargetFramework, secondTargetFramework } - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { firstTargetFramework, secondTargetFramework }); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId); @@ -603,12 +545,10 @@ public void WarningPropertiesCollection_MessageWithTargetGraphAndDependencyWithN var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, firstTargetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List { firstTargetFramework, secondTargetFramework } - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { firstTargetFramework, secondTargetFramework }); var nonSuppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, new string[] { firstFrameworkString, secondFrameworkString }); @@ -639,12 +579,10 @@ public void WarningPropertiesCollection_MessageWithTargetGraphAndDependencyWithN packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, firstTargetFramework); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, secondTargetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List { firstTargetFramework, secondTargetFramework } - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { firstTargetFramework, secondTargetFramework }); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, new string[] { firstFrameworkString, secondFrameworkString }); @@ -672,12 +610,10 @@ public void WarningPropertiesCollection_MessageWithTargetGraphAndDependencyWithN var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, targetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties, - ProjectFrameworks = new List { targetFramework } - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + new List { targetFramework}); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, new string[] { frameworkString }); @@ -708,11 +644,10 @@ public void WarningPropertiesCollection_MessageWithTargetGraphAndDependencyWithN var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, firstTargetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null); var nonSuppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, new string[] { firstFrameworkString, secondFrameworkString }); @@ -743,11 +678,10 @@ public void WarningPropertiesCollection_MessageWithTargetGraphAndDependencyWithN packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, firstTargetFramework); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, secondTargetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, new string[] { firstFrameworkString, secondFrameworkString }); @@ -775,11 +709,10 @@ public void WarningPropertiesCollection_MessageWithTargetGraphAndDependencyWithN var packageSpecificWarningProperties = new PackageSpecificWarningProperties(); packageSpecificWarningProperties.Add(NuGetLogCode.NU1500, libraryId, targetFramework); - var warningPropertiesCollection = new WarningPropertiesCollection() - { - ProjectWideWarningProperties = new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), - PackageSpecificWarningProperties = packageSpecificWarningProperties - }; + var warningPropertiesCollection = new WarningPropertiesCollection( + new WarningProperties(warnAsErrorSet, noWarnSet, allWarningsAsErrors), + packageSpecificWarningProperties, + null); var suppressedMessage = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1500, "Warning", libraryId, new string[] { frameworkString }); diff --git a/test/NuGet.Core.Tests/NuGet.Common.Test/PackageSpecificWanringPropertiesTests.cs b/test/NuGet.Core.Tests/NuGet.Common.Test/PackageSpecificWarningPropertiesTests.cs similarity index 99% rename from test/NuGet.Core.Tests/NuGet.Common.Test/PackageSpecificWanringPropertiesTests.cs rename to test/NuGet.Core.Tests/NuGet.Common.Test/PackageSpecificWarningPropertiesTests.cs index cf001b9cd24..58bf9074980 100644 --- a/test/NuGet.Core.Tests/NuGet.Common.Test/PackageSpecificWanringPropertiesTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Common.Test/PackageSpecificWarningPropertiesTests.cs @@ -54,7 +54,7 @@ public void PackageSpecificWarningProperties_AddsRangeValueWithGlobalTFM() var libraryId = "test_libraryId"; var targetFramework = NuGetFramework.Parse("net45"); var properties = new PackageSpecificWarningProperties(); - properties.AddRange(codes, libraryId, targetFramework); + properties.AddRangeOfCodes(codes, libraryId, targetFramework); // Assert foreach (var code in codes)