diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d169f29f9..93eac5370 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/devcontainers/spec/main/schemas/devContainer.base.schema.json", "name": "Component Detection", - "image": "mcr.microsoft.com/vscode/devcontainers/dotnet:6.0", + "image": "mcr.microsoft.com/vscode/devcontainers/dotnet:8.0", "runArgs": ["--init"], "extensions": [ "eamodio.gitlens", diff --git a/.editorconfig b/.editorconfig index 70e8ea782..ca24e4001 100644 --- a/.editorconfig +++ b/.editorconfig @@ -679,6 +679,25 @@ dotnet_diagnostic.CA1848.severity = suggestion # JSON002: Probable JSON string detected dotnet_diagnostic.JSON002.severity = suggestion +# IDE0290: Use primary constructor +dotnet_diagnostic.IDE0290.severity = suggestion + +# IDE0305: Simplify collection initialization +dotnet_diagnostic.IDE0305.severity = suggestion + +# SYSLIB1045: Convert to 'GeneratedRegexAttribute'. +dotnet_diagnostic.SYSLIB1045.severity = suggestion + +# CA1859: Use concrete types when possible for improved performance +dotnet_diagnostic.CA1859.severity = suggestion + +# CA1851: Possible multiple enumerations of 'IEnumerable' collection +dotnet_diagnostic.CA1851.severity = suggestion + +# CA1861: Avoid constant arrays as arguments +dotnet_diagnostic.CA1861.severity = suggestion + + # Workaround for https://github.com/dotnet/roslyn-analyzers/issues/5628 [Program.cs] dotnet_diagnostic.ca1812.severity = none diff --git a/.github/workflows/smoke-test.yml b/.github/workflows/smoke-test.yml index ffa6030a5..03863f6b8 100644 --- a/.github/workflows/smoke-test.yml +++ b/.github/workflows/smoke-test.yml @@ -26,7 +26,7 @@ jobs: { name: "Go", repo: "kubernetes/kubernetes" }, { name: "Maven", repo: "apache/kafka" }, { name: "NPM", repo: "axios/axios" }, - { name: "NuGet", repo: "Radarr/Radarr" }, + { name: "NuGet", repo: "dotnet/aspire" }, { name: "Pip", repo: "django/django" }, { name: "Pnpm", repo: "pnpm/pnpm" }, { name: "Poetry", repo: "Textualize/rich" }, @@ -41,9 +41,6 @@ jobs: - name: Checkout Component Detection uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - name: Setup .NET - uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0 - - name: Install Apache Ivy run: curl https://downloads.apache.org/ant/ivy/2.5.2/apache-ivy-2.5.2-bin.tar.gz | tar xOz apache-ivy-2.5.2/ivy-2.5.2.jar > /usr/share/ant/lib/ivy.jar @@ -53,10 +50,21 @@ jobs: repository: ${{ matrix.language.repo }} path: smoke-test-repo + - name: Setup .NET + uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0 + with: + dotnet-version: '8.0.x' + + - name: Setup Python + uses: actions/setup-python@v5 + if: ${{ matrix.language.name == 'Pip'}} + with: + python-version: '3.10' + - name: Restore Smoke Test NuGet Packages if: ${{ matrix.language.name == 'NuGet'}} - working-directory: smoke-test-repo/src - run: dotnet restore + working-directory: smoke-test-repo + run: dotnet restore Aspire.sln - name: Run Smoke Test working-directory: src/Microsoft.ComponentDetection diff --git a/Directory.Build.props b/Directory.Build.props index b5662906e..647ccfd7f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - net6.0 + net8.0 latest true true diff --git a/Directory.Packages.props b/Directory.Packages.props index 4e0e10c64..a8e502f7c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,19 +7,19 @@ - + - - - - - - + + + + + + - + @@ -34,21 +34,21 @@ - + - - + + - + - + - - + + diff --git a/docs/detector-arguments.md b/docs/detector-arguments.md index 74bf2e929..58029c235 100644 --- a/docs/detector-arguments.md +++ b/docs/detector-arguments.md @@ -7,7 +7,7 @@ dotnet run --project "src\Microsoft.ComponentDetection\Microsoft.ComponentDetect ``` --DirectoryExclusionList Filters out specific directories following a - minimatch pattern. + semicolon separated list of minimatch patterns. --IgnoreDirectories Filters out specific directories, providing individual directory paths separated by semicolon. diff --git a/global.json b/global.json index 40a96f29b..8dc113fae 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.422", + "version": "8.0.300", "rollForward": "latestMinor" } } diff --git a/src/Microsoft.ComponentDetection.Common/AsyncExecution.cs b/src/Microsoft.ComponentDetection.Common/AsyncExecution.cs index fb87c1920..72b7a7703 100644 --- a/src/Microsoft.ComponentDetection.Common/AsyncExecution.cs +++ b/src/Microsoft.ComponentDetection.Common/AsyncExecution.cs @@ -21,10 +21,7 @@ public static class AsyncExecution /// Thrown when the execution does not complete within the timeout. public static async Task ExecuteWithTimeoutAsync(Func> toExecute, TimeSpan timeout, CancellationToken cancellationToken) { - if (toExecute == null) - { - throw new ArgumentNullException(nameof(toExecute)); - } + ArgumentNullException.ThrowIfNull(toExecute); var work = Task.Run(toExecute); @@ -48,10 +45,7 @@ public static async Task ExecuteWithTimeoutAsync(Func> toExecute, /// Thrown when the execution does not complete within the timeout. public static async Task ExecuteVoidWithTimeoutAsync(Action toExecute, TimeSpan timeout, CancellationToken cancellationToken) { - if (toExecute == null) - { - throw new ArgumentNullException(nameof(toExecute)); - } + ArgumentNullException.ThrowIfNull(toExecute); var work = Task.Run(toExecute, cancellationToken); var completedInTime = await Task.Run(() => work.Wait(timeout)); diff --git a/src/Microsoft.ComponentDetection.Common/CommandLineInvocationService.cs b/src/Microsoft.ComponentDetection.Common/CommandLineInvocationService.cs index 8107a3dc7..f76cb6bf9 100644 --- a/src/Microsoft.ComponentDetection.Common/CommandLineInvocationService.cs +++ b/src/Microsoft.ComponentDetection.Common/CommandLineInvocationService.cs @@ -19,8 +19,8 @@ public class CommandLineInvocationService : ICommandLineInvocationService /// public async Task CanCommandBeLocatedAsync(string command, IEnumerable additionalCandidateCommands = null, DirectoryInfo workingDirectory = null, params string[] parameters) { - additionalCandidateCommands ??= Enumerable.Empty(); - parameters ??= Array.Empty(); + additionalCandidateCommands ??= []; + parameters ??= []; var allCommands = new[] { command }.Concat(additionalCandidateCommands); if (!this.commandLocatableCache.TryGetValue(command, out var validCommand)) { diff --git a/src/Microsoft.ComponentDetection.Common/ComponentStreamEnumerable.cs b/src/Microsoft.ComponentDetection.Common/ComponentStreamEnumerable.cs index 7afd066fb..d5e6989f5 100644 --- a/src/Microsoft.ComponentDetection.Common/ComponentStreamEnumerable.cs +++ b/src/Microsoft.ComponentDetection.Common/ComponentStreamEnumerable.cs @@ -45,7 +45,7 @@ IEnumerator IEnumerable.GetEnumerator() return this.GetEnumerator(); } - private Stream SafeOpenFile(FileInfo file) + private FileStream SafeOpenFile(FileInfo file) { try { diff --git a/src/Microsoft.ComponentDetection.Common/DependencyGraph/ComponentRecorder.cs b/src/Microsoft.ComponentDetection.Common/DependencyGraph/ComponentRecorder.cs index c913166d9..4abc98007 100644 --- a/src/Microsoft.ComponentDetection.Common/DependencyGraph/ComponentRecorder.cs +++ b/src/Microsoft.ComponentDetection.Common/DependencyGraph/ComponentRecorder.cs @@ -16,7 +16,7 @@ namespace Microsoft.ComponentDetection.Common.DependencyGraph; public class ComponentRecorder : IComponentRecorder { - private readonly ConcurrentBag singleFileRecorders = new ConcurrentBag(); + private readonly ConcurrentBag singleFileRecorders = []; private readonly bool enableManualTrackingOfExplicitReferences; @@ -38,7 +38,7 @@ public IEnumerable GetDetectedComponents() IEnumerable detectedComponents; if (this.singleFileRecorders == null) { - return Enumerable.Empty(); + return []; } detectedComponents = this.singleFileRecorders @@ -68,7 +68,7 @@ public IEnumerable GetSkippedComponents() { if (this.singleFileRecorders == null) { - return Enumerable.Empty(); + return []; } return this.singleFileRecorders @@ -162,10 +162,7 @@ public void RegisterUsage( bool? isDevelopmentDependency = null, DependencyScope? dependencyScope = null) { - if (detectedComponent == null) - { - throw new ArgumentNullException(paramName: nameof(detectedComponent)); - } + ArgumentNullException.ThrowIfNull(detectedComponent); if (detectedComponent.Component == null) { @@ -173,7 +170,7 @@ public void RegisterUsage( } #if DEBUG - if (detectedComponent.DependencyRoots?.Any() ?? false) + if (detectedComponent.DependencyRoots?.Count == 0) { this.logger.LogWarning("Detector should not populate DetectedComponent.DependencyRoots!"); } @@ -195,10 +192,7 @@ public void RegisterUsage( public void RegisterPackageParseFailure(string skippedComponent) { - if (skippedComponent == null) - { - throw new ArgumentNullException(paramName: nameof(skippedComponent)); - } + ArgumentNullException.ThrowIfNull(skippedComponent); _ = this.skippedComponentsInternal[skippedComponent] = default; } diff --git a/src/Microsoft.ComponentDetection.Common/DependencyGraph/DependencyGraph.cs b/src/Microsoft.ComponentDetection.Common/DependencyGraph/DependencyGraph.cs index edfcd4932..59b17ef1c 100644 --- a/src/Microsoft.ComponentDetection.Common/DependencyGraph/DependencyGraph.cs +++ b/src/Microsoft.ComponentDetection.Common/DependencyGraph/DependencyGraph.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Linq; using System.Runtime.CompilerServices; +using System.Text; using Microsoft.ComponentDetection.Contracts; using Microsoft.ComponentDetection.Contracts.BcdeModels; @@ -13,6 +14,8 @@ namespace Microsoft.ComponentDetection.Common.DependencyGraph; internal class DependencyGraph : IDependencyGraph { + private static readonly CompositeFormat MissingNodeFormat = CompositeFormat.Parse(Resources.MissingNodeInDependencyGraph); + private readonly ConcurrentDictionary componentNodes; private readonly bool enableManualTrackingOfExplicitReferences; @@ -27,14 +30,11 @@ public DependencyGraph(bool enableManualTrackingOfExplicitReferences) public void AddComponent(ComponentRefNode componentNode, string parentComponentId = null) { - if (componentNode == null) - { - throw new ArgumentNullException(nameof(componentNode)); - } + ArgumentNullException.ThrowIfNull(componentNode); if (string.IsNullOrWhiteSpace(componentNode.Id)) { - throw new ArgumentNullException(nameof(componentNode.Id), "Invalid component node id"); + throw new ArgumentNullException(nameof(componentNode), "Invalid component node id"); } this.componentNodes.AddOrUpdate(componentNode.Id, componentNode, (key, currentNode) => @@ -77,10 +77,10 @@ public ICollection GetExplicitReferencedDependencyIds(string componentId if (!this.componentNodes.TryGetValue(componentId, out var componentRef)) { - throw new ArgumentException(string.Format(Resources.MissingNodeInDependencyGraph, componentId), paramName: nameof(componentId)); + throw new ArgumentException(string.Format(null, MissingNodeFormat, componentId), paramName: nameof(componentId)); } - IList explicitReferencedDependencyIds = new List(); + IList explicitReferencedDependencyIds = []; this.GetExplicitReferencedDependencies(componentRef, explicitReferencedDependencyIds, new HashSet()); @@ -97,7 +97,7 @@ public void AddAdditionalRelatedFile(string additionalRelatedFile) public HashSet GetAdditionalRelatedFiles() { - return this.AdditionalRelatedFiles.Keys.ToImmutableHashSet().ToHashSet(); + return [.. this.AdditionalRelatedFiles.Keys]; } public bool HasComponents() @@ -129,7 +129,7 @@ public ICollection GetAncestors(string componentId) if (!this.componentNodes.TryGetValue(componentId, out var componentRef)) { // this component isn't in the graph, so it has no ancestors - return new List(); + return []; } // store the component id and the depth we found it at @@ -189,7 +189,7 @@ private void AddDependency(string componentId, string parentComponentId) if (!this.componentNodes.TryGetValue(parentComponentId, out var parentComponentRefNode)) { - throw new ArgumentException(string.Format(Resources.MissingNodeInDependencyGraph, parentComponentId), nameof(parentComponentId)); + throw new ArgumentException(string.Format(null, MissingNodeFormat, parentComponentId), nameof(parentComponentId)); } parentComponentRefNode.DependencyIds.Add(componentId); diff --git a/src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs b/src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs index 9c9742c9d..93f25c3b1 100644 --- a/src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs +++ b/src/Microsoft.ComponentDetection.Common/DockerReference/DockerReferenceUtility.cs @@ -140,7 +140,7 @@ public static DockerReference ParseFamiliarName(string name) remoteName = remainder; } - if (remoteName.ToLower() != remoteName) + if (!remoteName.ToLower().Equals(remoteName)) { throw new ReferenceNameContainsUppercaseException(name); } diff --git a/src/Microsoft.ComponentDetection.Common/DockerService.cs b/src/Microsoft.ComponentDetection.Common/DockerService.cs index 66033f183..9527cb71f 100644 --- a/src/Microsoft.ComponentDetection.Common/DockerService.cs +++ b/src/Microsoft.ComponentDetection.Common/DockerService.cs @@ -147,7 +147,7 @@ public async Task InspectImageAsync(string image, Cancellation CreatedAt = imageInspectResponse.Created, BaseImageDigest = baseImageDigest, BaseImageRef = baseImageRef, - Layers = layers ?? Enumerable.Empty(), + Layers = layers ?? [], }; } catch (Exception e) @@ -188,19 +188,19 @@ private static async Task CreateContainerAsync( NetworkDisabled = true, HostConfig = new HostConfig { - CapDrop = new List - { + CapDrop = + [ "all", - }, - SecurityOpt = new List - { + ], + SecurityOpt = + [ "no-new-privileges", - }, - Binds = new List - { + ], + Binds = + [ $"{Path.GetTempPath()}:/tmp", "/var/run/docker.sock:/var/run/docker.sock", - }, + ], }, }; return await Client.Containers.CreateContainerAsync(parameters, cancellationToken); diff --git a/src/Microsoft.ComponentDetection.Common/EnvironmentVariableService.cs b/src/Microsoft.ComponentDetection.Common/EnvironmentVariableService.cs index 7ce1bed86..1d6a9cc70 100644 --- a/src/Microsoft.ComponentDetection.Common/EnvironmentVariableService.cs +++ b/src/Microsoft.ComponentDetection.Common/EnvironmentVariableService.cs @@ -25,7 +25,7 @@ public string GetEnvironmentVariable(string name) } public List GetListEnvironmentVariable(string name, string delimiter) - => (this.GetEnvironmentVariable(name) ?? string.Empty).Split(delimiter, StringSplitOptions.RemoveEmptyEntries).ToList(); + => [.. (this.GetEnvironmentVariable(name) ?? string.Empty).Split(delimiter, StringSplitOptions.RemoveEmptyEntries)]; public bool IsEnvironmentVariableValueTrue(string name) { diff --git a/src/Microsoft.ComponentDetection.Common/LazyComponentStream.cs b/src/Microsoft.ComponentDetection.Common/LazyComponentStream.cs index 0a1b73bb7..638255682 100644 --- a/src/Microsoft.ComponentDetection.Common/LazyComponentStream.cs +++ b/src/Microsoft.ComponentDetection.Common/LazyComponentStream.cs @@ -56,6 +56,6 @@ private byte[] SafeOpenFile() this.logger.LogWarning(e, "Unhandled exception caught when trying to open {FileName}", this.fileInfo.FullName); } - return Array.Empty(); + return []; } } diff --git a/src/Microsoft.ComponentDetection.Common/PathUtilityService.cs b/src/Microsoft.ComponentDetection.Common/PathUtilityService.cs index b36d6a49b..006d62e77 100644 --- a/src/Microsoft.ComponentDetection.Common/PathUtilityService.cs +++ b/src/Microsoft.ComponentDetection.Common/PathUtilityService.cs @@ -23,12 +23,12 @@ public class PathUtilityService : IPathUtilityService public static bool MatchesPattern(string searchPattern, ref FileSystemEntry fse) { - if (searchPattern.StartsWith("*") && fse.FileName.EndsWith(searchPattern.AsSpan()[1..], StringComparison.OrdinalIgnoreCase)) + if (searchPattern.StartsWith('*') && fse.FileName.EndsWith(searchPattern.AsSpan()[1..], StringComparison.OrdinalIgnoreCase)) { return true; } - if (searchPattern.EndsWith("*") && fse.FileName.StartsWith(searchPattern.AsSpan()[..^1], StringComparison.OrdinalIgnoreCase)) + if (searchPattern.EndsWith('*') && fse.FileName.StartsWith(searchPattern.AsSpan()[..^1], StringComparison.OrdinalIgnoreCase)) { return true; } @@ -49,12 +49,12 @@ public bool IsFileBelowAnother(string aboveFilePath, string belowFilePath) public bool MatchesPattern(string searchPattern, string fileName) { - if (searchPattern.StartsWith("*") && fileName.EndsWith(searchPattern[1..], StringComparison.OrdinalIgnoreCase)) + if (searchPattern.StartsWith('*') && fileName.EndsWith(searchPattern[1..], StringComparison.OrdinalIgnoreCase)) { return true; } - if (searchPattern.EndsWith("*") && fileName.StartsWith(searchPattern[..^1], StringComparison.OrdinalIgnoreCase)) + if (searchPattern.EndsWith('*') && fileName.StartsWith(searchPattern[..^1], StringComparison.OrdinalIgnoreCase)) { return true; } diff --git a/src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs b/src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs index af0bc61d2..8b91d345b 100644 --- a/src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs +++ b/src/Microsoft.ComponentDetection.Common/PatternMatchingUtility.cs @@ -13,24 +13,24 @@ public static class PatternMatchingUtility public static FilePatternMatcher GetFilePatternMatcher(IEnumerable patterns) { var ordinalComparison = Expression.Constant(StringComparison.Ordinal, typeof(StringComparison)); - var asSpan = typeof(MemoryExtensions).GetMethod("AsSpan", BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, new[] { typeof(string) }, Array.Empty()); - var equals = typeof(MemoryExtensions).GetMethod("Equals", BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, new[] { typeof(ReadOnlySpan), typeof(ReadOnlySpan), typeof(StringComparison) }, Array.Empty()); - var startsWith = typeof(MemoryExtensions).GetMethod("StartsWith", BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, new[] { typeof(ReadOnlySpan), typeof(ReadOnlySpan), typeof(StringComparison) }, Array.Empty()); - var endsWith = typeof(MemoryExtensions).GetMethod("EndsWith", BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, new[] { typeof(ReadOnlySpan), typeof(ReadOnlySpan), typeof(StringComparison) }, Array.Empty()); + var asSpan = typeof(MemoryExtensions).GetMethod("AsSpan", BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, [typeof(string)], []); + var equals = typeof(MemoryExtensions).GetMethod("Equals", BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, [typeof(ReadOnlySpan), typeof(ReadOnlySpan), typeof(StringComparison)], []); + var startsWith = typeof(MemoryExtensions).GetMethod("StartsWith", BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, [typeof(ReadOnlySpan), typeof(ReadOnlySpan), typeof(StringComparison)], []); + var endsWith = typeof(MemoryExtensions).GetMethod("EndsWith", BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, [typeof(ReadOnlySpan), typeof(ReadOnlySpan), typeof(StringComparison)], []); var predicates = new List(); var left = Expression.Parameter(typeof(ReadOnlySpan), "fileName"); foreach (var pattern in patterns) { - if (pattern.StartsWith("*")) + if (pattern.StartsWith('*')) { var match = Expression.Constant(pattern[1..], typeof(string)); var right = Expression.Call(null, asSpan, match); var combine = Expression.Call(null, endsWith, left, right, ordinalComparison); predicates.Add(combine); } - else if (pattern.EndsWith("*")) + else if (pattern.EndsWith('*')) { var match = Expression.Constant(pattern[..^1], typeof(string)); var right = Expression.Call(null, asSpan, match); diff --git a/src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs b/src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs index 27458d776..3ccce2e35 100644 --- a/src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs +++ b/src/Microsoft.ComponentDetection.Common/SafeFileEnumerable.cs @@ -42,11 +42,11 @@ public SafeFileEnumerable(DirectoryInfo directory, IEnumerable searchPat } public SafeFileEnumerable(DirectoryInfo directory, Func fileMatchingPredicate, ILogger logger, IPathUtilityService pathUtilityService, ExcludeDirectoryPredicate directoryExclusionPredicate, bool recursivelyScanDirectories = true, HashSet previouslyEnumeratedDirectories = null) - : this(directory, new List { "*" }, logger, pathUtilityService, directoryExclusionPredicate, recursivelyScanDirectories, previouslyEnumeratedDirectories) => this.fileMatchingPredicate = fileMatchingPredicate; + : this(directory, ["*"], logger, pathUtilityService, directoryExclusionPredicate, recursivelyScanDirectories, previouslyEnumeratedDirectories) => this.fileMatchingPredicate = fileMatchingPredicate; public IEnumerator GetEnumerator() { - var previouslyEnumeratedDirectories = this.enumeratedDirectories ?? new HashSet(); + var previouslyEnumeratedDirectories = this.enumeratedDirectories ?? []; var fse = new FileSystemEnumerable( this.directory.FullName, diff --git a/src/Microsoft.ComponentDetection.Common/Telemetry/TelemetryRelay.cs b/src/Microsoft.ComponentDetection.Common/Telemetry/TelemetryRelay.cs index fb72e7ea1..a5ec13bb7 100644 --- a/src/Microsoft.ComponentDetection.Common/Telemetry/TelemetryRelay.cs +++ b/src/Microsoft.ComponentDetection.Common/Telemetry/TelemetryRelay.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.ComponentDetection.Common.Telemetry.Records; @@ -15,8 +14,7 @@ public sealed class TelemetryRelay private IEnumerable telemetryServices; // For things not populating the telemetry services collection, let's not throw. - private TelemetryRelay() => - this.telemetryServices = Enumerable.Empty(); + private TelemetryRelay() => this.telemetryServices = []; /// /// Gets a value indicating whether or not the telemetry relay has been shutdown. @@ -76,7 +74,7 @@ await AsyncExecution.ExecuteVoidWithTimeoutAsync( public void SetTelemetryMode(TelemetryMode mode) { - foreach (var telemetryService in this.telemetryServices ?? Enumerable.Empty()) + foreach (var telemetryService in this.telemetryServices ?? []) { telemetryService.SetMode(mode); } diff --git a/src/Microsoft.ComponentDetection.Contracts/DetectedComponent.cs b/src/Microsoft.ComponentDetection.Contracts/DetectedComponent.cs index d77c5e9aa..eeefd6e10 100644 --- a/src/Microsoft.ComponentDetection.Contracts/DetectedComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/DetectedComponent.cs @@ -18,16 +18,16 @@ public class DetectedComponent public DetectedComponent(TypedComponent.TypedComponent component, IComponentDetector detector = null, int? containerDetailsId = null, int? containerLayerId = null) { this.Component = component; - this.FilePaths = new HashSet(); + this.FilePaths = []; this.DetectedBy = detector; - this.ContainerDetailIds = new HashSet(); + this.ContainerDetailIds = []; this.ContainerLayerIds = new Dictionary>(); if (containerDetailsId.HasValue) { this.ContainerDetailIds.Add(containerDetailsId.Value); if (containerLayerId.HasValue) { - this.ContainerLayerIds.Add(containerDetailsId.Value, new List() { containerLayerId.Value }); + this.ContainerLayerIds.Add(containerDetailsId.Value, [containerLayerId.Value]); } } } diff --git a/src/Microsoft.ComponentDetection.Contracts/FileComponentDetector.cs b/src/Microsoft.ComponentDetection.Contracts/FileComponentDetector.cs index 50fb090fd..2e325e17f 100644 --- a/src/Microsoft.ComponentDetection.Contracts/FileComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Contracts/FileComponentDetector.cs @@ -45,7 +45,7 @@ public abstract class FileComponentDetector : IComponentDetector /// /// Gets the folder names that will be skipped by the Component Detector. /// - protected virtual IList SkippedFolders => new List { }; + protected virtual IList SkippedFolders => []; /// /// Gets or sets the active scan request -- only populated after a ScanDirectoryAsync is invoked. If ScanDirectoryAsync is overridden, @@ -55,12 +55,12 @@ public abstract class FileComponentDetector : IComponentDetector public virtual bool NeedsAutomaticRootDependencyCalculation { get; protected set; } - protected Dictionary Telemetry { get; set; } = new Dictionary(); + protected Dictionary Telemetry { get; set; } = []; /// /// List of any any additional properties as key-value pairs that we would like to capture for the detector. /// - public List<(string PropertyKey, string PropertyValue)> AdditionalProperties { get; set; } = new List<(string PropertyKey, string PropertyValue)>(); + public List<(string PropertyKey, string PropertyValue)> AdditionalProperties { get; set; } = []; protected IObservable ComponentStreams { get; private set; } diff --git a/src/Microsoft.ComponentDetection.Contracts/IndividualDetectorScanResult.cs b/src/Microsoft.ComponentDetection.Contracts/IndividualDetectorScanResult.cs index 8a4e39edc..b6a34e28a 100644 --- a/src/Microsoft.ComponentDetection.Contracts/IndividualDetectorScanResult.cs +++ b/src/Microsoft.ComponentDetection.Contracts/IndividualDetectorScanResult.cs @@ -1,7 +1,6 @@ namespace Microsoft.ComponentDetection.Contracts; using System.Collections.Generic; -using System.Linq; using Microsoft.ComponentDetection.Contracts.BcdeModels; /// @@ -17,7 +16,7 @@ public class IndividualDetectorScanResult /// /// Gets or sets the list of containers found during the scan. /// - public IEnumerable ContainerDetails { get; set; } = Enumerable.Empty(); + public IEnumerable ContainerDetails { get; set; } = []; /// /// Gets or sets any additional telemetry details for the scan. diff --git a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/LinuxComponent.cs b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/LinuxComponent.cs index 89c1a8e23..045cad5be 100644 --- a/src/Microsoft.ComponentDetection.Contracts/TypedComponent/LinuxComponent.cs +++ b/src/Microsoft.ComponentDetection.Contracts/TypedComponent/LinuxComponent.cs @@ -63,26 +63,26 @@ public override PackageURL PackageUrl private bool IsUbuntu() { - return this.Distribution.ToUpperInvariant() == "UBUNTU"; + return this.Distribution.Equals("UBUNTU", System.StringComparison.InvariantCultureIgnoreCase); } private bool IsDebian() { - return this.Distribution.ToUpperInvariant() == "DEBIAN"; + return this.Distribution.Equals("DEBIAN", System.StringComparison.InvariantCultureIgnoreCase); } private bool IsCentOS() { - return this.Distribution.ToUpperInvariant() == "CENTOS"; + return this.Distribution.Equals("CENTOS", System.StringComparison.InvariantCultureIgnoreCase); } private bool IsFedora() { - return this.Distribution.ToUpperInvariant() == "FEDORA"; + return this.Distribution.Equals("FEDORA", System.StringComparison.InvariantCultureIgnoreCase); } private bool IsRHEL() { - return this.Distribution.ToUpperInvariant() == "RED HAT ENTERPRISE LINUX"; + return this.Distribution.Equals("RED HAT ENTERPRISE LINUX", System.StringComparison.InvariantCultureIgnoreCase); } } diff --git a/src/Microsoft.ComponentDetection.Detectors/cocoapods/PodComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/cocoapods/PodComponentDetector.cs index 86f3ec2e6..bb19fd8b3 100644 --- a/src/Microsoft.ComponentDetection.Detectors/cocoapods/PodComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/cocoapods/PodComponentDetector.cs @@ -28,11 +28,11 @@ public PodComponentDetector( public override string Id { get; } = "CocoaPods"; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.CocoaPods) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.CocoaPods)]; - public override IList SearchPatterns { get; } = new List { "Podfile.lock" }; + public override IList SearchPatterns { get; } = ["Podfile.lock"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Pod, ComponentType.Git }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Pod, ComponentType.Git]; public override int Version { get; } = 2; @@ -224,7 +224,7 @@ private void ProcessPodfileLock( foreach (var pod in podDependencies) { // Add all the dependencies to the map, without duplicates - dependenciesMap.TryAdd(pod.Key, new HashSet()); + dependenciesMap.TryAdd(pod.Key, []); foreach (var dependency in pod.Value) { @@ -305,6 +305,8 @@ private void ProcessPodfileLock( private class Pod : IYamlConvertible { + private static readonly char[] PodSeperator = ['(', ')']; + public string Name { get; set; } public string Version { get; set; } @@ -324,7 +326,7 @@ public void Read(IParser parser, Type expectedType, ObjectDeserializer nestedObj } var podInfo = parser.Consume(); - var components = podInfo.Value.Split(new char[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries); + var components = podInfo.Value.Split(PodSeperator, StringSplitOptions.RemoveEmptyEntries); this.Name = components[0].Trim(); this.Version = components[1].Trim(); @@ -348,6 +350,8 @@ public void Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) private class PodDependency : IYamlConvertible { + private static readonly char[] PodSeperator = ['(', ')']; + public string PodName { get; set; } public string PodVersion { get; set; } @@ -359,7 +363,7 @@ private class PodDependency : IYamlConvertible public void Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { var scalar = parser.Consume(); - var components = scalar.Value.Split(new char[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries); + var components = scalar.Value.Split(PodSeperator, StringSplitOptions.RemoveEmptyEntries); this.PodName = components[0].Trim(); this.PodVersion = components.Length > 1 ? components[1].Trim() : null; } diff --git a/src/Microsoft.ComponentDetection.Detectors/conan/ConanLockComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/conan/ConanLockComponentDetector.cs index 48519940a..103ca1238 100644 --- a/src/Microsoft.ComponentDetection.Detectors/conan/ConanLockComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/conan/ConanLockComponentDetector.cs @@ -25,13 +25,13 @@ public ConanLockComponentDetector( public override string Id => "ConanLock"; - public override IList SearchPatterns => new List { "conan.lock" }; + public override IList SearchPatterns => ["conan.lock"]; - public override IEnumerable SupportedComponentTypes => new[] { ComponentType.Conan }; + public override IEnumerable SupportedComponentTypes => [ComponentType.Conan]; public override int Version { get; } = 1; - public override IEnumerable Categories => new List { "Conan" }; + public override IEnumerable Categories => ["Conan"]; protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary detectorArgs) { @@ -51,9 +51,9 @@ protected override async Task OnFileFoundAsync(ProcessRequest processRequest, ID var packagesDictionary = conanLock.GraphLock.Nodes; var explicitReferencedDependencies = new HashSet(); var developmentDependencies = new HashSet(); - if (packagesDictionary.ContainsKey("0")) + + if (packagesDictionary.Remove("0", out var rootNode)) { - packagesDictionary.Remove("0", out var rootNode); if (rootNode?.Requires != null) { explicitReferencedDependencies = new HashSet(rootNode.Requires); diff --git a/src/Microsoft.ComponentDetection.Detectors/conda/CondaDependencyResolver.cs b/src/Microsoft.ComponentDetection.Detectors/conda/CondaDependencyResolver.cs index 60ffb84b2..64a442fc7 100644 --- a/src/Microsoft.ComponentDetection.Detectors/conda/CondaDependencyResolver.cs +++ b/src/Microsoft.ComponentDetection.Detectors/conda/CondaDependencyResolver.cs @@ -28,7 +28,7 @@ public static void RecordDependencyGraphFromFile(CondaLock condaLock, ISingleFil public static void UpdateDirectlyReferencedPackages(ISingleFileComponentRecorder singleFileComponentRecorder) => singleFileComponentRecorder.GetDetectedComponents().Keys.ForEach(componentId => { - if (!singleFileComponentRecorder.DependencyGraph.GetAncestors(componentId).Any()) + if (singleFileComponentRecorder.DependencyGraph.GetAncestors(componentId).Count == 0) { singleFileComponentRecorder.RegisterUsage( singleFileComponentRecorder.GetComponent(componentId), @@ -100,7 +100,7 @@ private static void RegisterPackage(TypedComponent package, string parentCompone /// A list of packages without dependencies. private static List GetPackages(CondaLock condaLock) => condaLock?.Package == null - ? new List() + ? [] : condaLock.Package; /// diff --git a/src/Microsoft.ComponentDetection.Detectors/conda/CondaLockComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/conda/CondaLockComponentDetector.cs index 9ec59cbc6..a0a075a97 100644 --- a/src/Microsoft.ComponentDetection.Detectors/conda/CondaLockComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/conda/CondaLockComponentDetector.cs @@ -26,13 +26,13 @@ public CondaLockComponentDetector( public override string Id => "CondaLock"; - public override IList SearchPatterns { get; } = new List { "conda-lock.yml", "*.conda-lock.yml" }; + public override IList SearchPatterns { get; } = ["conda-lock.yml", "*.conda-lock.yml"]; - public override IEnumerable SupportedComponentTypes => new[] { ComponentType.Conda, ComponentType.Pip }; + public override IEnumerable SupportedComponentTypes => [ComponentType.Conda, ComponentType.Pip]; public override int Version { get; } = 2; - public override IEnumerable Categories => new List { "Python" }; + public override IEnumerable Categories => ["Python"]; /// protected override Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary detectorArgs) diff --git a/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs index c141300f9..85596a7b6 100644 --- a/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/dockerfile/DockerfileComponentDetector.cs @@ -34,11 +34,11 @@ public DockerfileComponentDetector( public override string Id { get; } = "DockerReference"; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.DockerReference) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.DockerReference)]; - public override IList SearchPatterns { get; } = new List { "dockerfile", "dockerfile.*", "*.dockerfile" }; + public override IList SearchPatterns { get; } = ["dockerfile", "dockerfile.*", "*.dockerfile"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.DockerReference }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.DockerReference]; public override int Version => 1; diff --git a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs index 98e9da74b..cedd82770 100644 --- a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentDetector.cs @@ -22,7 +22,9 @@ public class GoComponentDetector : FileComponentDetector @"(?.*)\s+(?.*?)(/go\.mod)?\s+(?.*)", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase); - private readonly HashSet projectRoots = new(); + private static readonly string[] AdjModSearchPatterns = ["go.mod"]; + + private readonly HashSet projectRoots = []; private readonly ICommandLineInvocationService commandLineInvocationService; private readonly IEnvironmentVariableService envVarService; @@ -43,11 +45,11 @@ public GoComponentDetector( public override string Id => "Go"; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.GoMod) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.GoMod)]; - public override IList SearchPatterns { get; } = new List { "go.mod", "go.sum" }; + public override IList SearchPatterns { get; } = ["go.mod", "go.sum"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Go }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Go]; public override int Version => 7; @@ -87,7 +89,7 @@ protected override Task> OnPrepareDetectionAsync( private IEnumerable FindAdjacentGoModComponentStreams(ProcessRequest processRequest) => this.ComponentStreamEnumerableFactory.GetComponentStreams( new FileInfo(processRequest.ComponentStream.Location).Directory, - new[] { "go.mod" }, + AdjModSearchPatterns, (_, _) => false, false) .Select(x => @@ -221,7 +223,7 @@ private async Task UseGoCliToScanAsync(string location, ISingleFileCompone var projectRootDirectory = Directory.GetParent(location); record.ProjectRoot = projectRootDirectory.FullName; - var isGoAvailable = await this.commandLineInvocationService.CanCommandBeLocatedAsync("go", null, workingDirectory: projectRootDirectory, new[] { "version" }); + var isGoAvailable = await this.commandLineInvocationService.CanCommandBeLocatedAsync("go", null, workingDirectory: projectRootDirectory, ["version"]); record.IsGoAvailable = isGoAvailable; if (!isGoAvailable) @@ -233,7 +235,7 @@ private async Task UseGoCliToScanAsync(string location, ISingleFileCompone this.Logger.LogInformation("Go CLI was found in system and will be used to generate dependency graph. " + "Detection time may be improved by activating fallback strategy (https://github.com/microsoft/component-detection/blob/main/docs/detectors/go.md#fallback-detection-strategy). " + "But, it will introduce noise into the detected components."); - var goDependenciesProcess = await this.commandLineInvocationService.ExecuteCommandAsync("go", null, workingDirectory: projectRootDirectory, new[] { "list", "-mod=readonly", "-m", "-json", "all" }); + var goDependenciesProcess = await this.commandLineInvocationService.ExecuteCommandAsync("go", null, workingDirectory: projectRootDirectory, ["list", "-mod=readonly", "-m", "-json", "all"]); if (goDependenciesProcess.ExitCode != 0) { this.Logger.LogError("Go CLI command \"go list -m -json all\" failed with error: {GoDependenciesProcessStdErr}", goDependenciesProcess.StdErr); @@ -305,7 +307,7 @@ private async Task ParseGoModFileAsync( } // Stopping at the first ) restrict the detection to only the require section. - while ((line = await reader.ReadLineAsync()) != null && !line.EndsWith(")")) + while ((line = await reader.ReadLineAsync()) != null && !line.EndsWith(')')) { this.TryRegisterDependencyFromModLine(line, singleFileComponentRecorder); } diff --git a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentWithReplaceDetector.cs b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentWithReplaceDetector.cs index 0eb64a989..a08ab6609 100644 --- a/src/Microsoft.ComponentDetection.Detectors/go/GoComponentWithReplaceDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/go/GoComponentWithReplaceDetector.cs @@ -23,7 +23,7 @@ public class GoComponentWithReplaceDetector : FileComponentDetector, IExperiment @"(?.*)\s+(?.*?)(/go\.mod)?\s+(?.*)", RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase); - private readonly HashSet projectRoots = new(); + private readonly HashSet projectRoots = []; private readonly ICommandLineInvocationService commandLineInvocationService; private readonly IEnvironmentVariableService envVarService; @@ -42,15 +42,15 @@ public GoComponentWithReplaceDetector( this.Logger = logger; } - private IList GoComponents { get; set; } = new List(); + private IList GoComponents { get; set; } = []; public override string Id => "GoWithReplace"; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.GoMod) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.GoMod)]; - public override IList SearchPatterns { get; } = new List { "go.mod", "go.sum" }; + public override IList SearchPatterns { get; } = ["go.mod", "go.sum"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Go }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Go]; public override int Version => 1; @@ -90,7 +90,7 @@ protected override Task> OnPrepareDetectionAsync( private IEnumerable FindAdjacentGoModComponentStreams(ProcessRequest processRequest) => this.ComponentStreamEnumerableFactory.GetComponentStreams( new FileInfo(processRequest.ComponentStream.Location).Directory, - new[] { "go.mod" }, + ["go.mod"], (_, _) => false, false) .Select(x => @@ -224,7 +224,7 @@ private async Task UseGoCliToScanAsync(string location, ISingleFileCompone var projectRootDirectory = Directory.GetParent(location); record.ProjectRoot = projectRootDirectory.FullName; - var isGoAvailable = await this.commandLineInvocationService.CanCommandBeLocatedAsync("go", null, workingDirectory: projectRootDirectory, new[] { "version" }); + var isGoAvailable = await this.commandLineInvocationService.CanCommandBeLocatedAsync("go", null, workingDirectory: projectRootDirectory, ["version"]); record.IsGoAvailable = isGoAvailable; if (!isGoAvailable) @@ -236,7 +236,7 @@ private async Task UseGoCliToScanAsync(string location, ISingleFileCompone this.Logger.LogInformation("Go CLI was found in system and will be used to generate dependency graph. " + "Detection time may be improved by activating fallback strategy (https://github.com/microsoft/component-detection/blob/main/docs/detectors/go.md#fallback-detection-strategy). " + "But, it will introduce noise into the detected components."); - var goDependenciesProcess = await this.commandLineInvocationService.ExecuteCommandAsync("go", null, workingDirectory: projectRootDirectory, new[] { "list", "-mod=readonly", "-m", "-json", "all" }); + var goDependenciesProcess = await this.commandLineInvocationService.ExecuteCommandAsync("go", null, workingDirectory: projectRootDirectory, ["list", "-mod=readonly", "-m", "-json", "all"]); if (goDependenciesProcess.ExitCode != 0) { this.Logger.LogError("Go CLI command \"go list -m -json all\" failed with error: {GoDependenciesProcessStdErr}", goDependenciesProcess.StdErr); @@ -282,15 +282,11 @@ private void ReplaceGoComponents(string line, ISingleFileComponentRecorder singl { if (this.TryToCreateReplacementGoComponentFromModLine(line, out var goComponent)) { - var goComponentsWithReplacementVersion = this.GoComponents.Where(component => component.Name == goComponent.Name); - if (goComponentsWithReplacementVersion.Any()) + foreach (var component in this.GoComponents?.Where(component => component.Name == goComponent.Name)) { - foreach (var component in goComponentsWithReplacementVersion) + if (component.Name == goComponent.Name) { - if (component.Name == goComponent.Name) - { - component.Version = goComponent.Version; - } + component.Version = goComponent.Version; } } } @@ -330,7 +326,7 @@ private async Task ParseGoModFileAsync( inReplaceBlock = true; continue; } - else if (line != null && line.StartsWith(")")) + else if (line != null && line.StartsWith(')')) { inRequireBlock = false; inReplaceBlock = false; diff --git a/src/Microsoft.ComponentDetection.Detectors/gradle/GradleComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/gradle/GradleComponentDetector.cs index c5b3dd24f..d3ed7f3dc 100644 --- a/src/Microsoft.ComponentDetection.Detectors/gradle/GradleComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/gradle/GradleComponentDetector.cs @@ -30,19 +30,19 @@ public GradleComponentDetector( this.Scanner = walkerFactory; this.Logger = logger; - this.devLockfiles = envVarService.GetListEnvironmentVariable(DevLockfilesEnvVar) ?? new List(); - this.devConfigurations = envVarService.GetListEnvironmentVariable(DevConfigurationsEnvVar) ?? new List(); + this.devLockfiles = envVarService.GetListEnvironmentVariable(DevLockfilesEnvVar) ?? []; + this.devConfigurations = envVarService.GetListEnvironmentVariable(DevConfigurationsEnvVar) ?? []; this.Logger.LogDebug("Gradle dev-only lockfiles {Lockfiles}", string.Join(", ", this.devLockfiles)); this.Logger.LogDebug("Gradle dev-only configurations {Configurations}", string.Join(", ", this.devConfigurations)); } public override string Id { get; } = "Gradle"; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Maven) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Maven)]; - public override IList SearchPatterns { get; } = new List { "*.lockfile" }; + public override IList SearchPatterns { get; } = ["*.lockfile"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Maven }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Maven]; public override int Version { get; } = 3; diff --git a/src/Microsoft.ComponentDetection.Detectors/ivy/IvyDetector.cs b/src/Microsoft.ComponentDetection.Detectors/ivy/IvyDetector.cs index dde7f0993..2eadeca42 100644 --- a/src/Microsoft.ComponentDetection.Detectors/ivy/IvyDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/ivy/IvyDetector.cs @@ -42,7 +42,7 @@ public class IvyDetector : FileComponentDetector, IExperimentalDetector internal const string AntVersionArgument = "-version"; - internal static readonly string[] AdditionalValidCommands = { "ant" }; + internal static readonly string[] AdditionalValidCommands = ["ant"]; private readonly ICommandLineInvocationService commandLineInvocationService; @@ -60,13 +60,13 @@ public IvyDetector( public override string Id => "Ivy"; - public override IList SearchPatterns => new List { "ivy.xml" }; + public override IList SearchPatterns => ["ivy.xml"]; - public override IEnumerable SupportedComponentTypes => new[] { ComponentType.Maven }; + public override IEnumerable SupportedComponentTypes => [ComponentType.Maven]; public override int Version => 2; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Maven) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Maven)]; protected override async Task> OnPrepareDetectionAsync(IObservable processRequests, IDictionary detectorArgs) { diff --git a/src/Microsoft.ComponentDetection.Detectors/linux/LinuxContainerDetector.cs b/src/Microsoft.ComponentDetection.Detectors/linux/LinuxContainerDetector.cs index da6b568da..e421e39be 100644 --- a/src/Microsoft.ComponentDetection.Detectors/linux/LinuxContainerDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/linux/LinuxContainerDetector.cs @@ -31,9 +31,9 @@ public LinuxContainerDetector(ILinuxScanner linuxScanner, IDockerService dockerS public string Id => "Linux"; - public IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Linux) }; + public IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Linux)]; - public IEnumerable SupportedComponentTypes => new[] { ComponentType.Linux }; + public IEnumerable SupportedComponentTypes => [ComponentType.Linux]; public int Version => 4; @@ -47,7 +47,7 @@ public async Task ExecuteDetectorAsync(ScanRequest .ToList(); #pragma warning restore CA1308 - if (imagesToProcess == null || !imagesToProcess.Any()) + if (imagesToProcess == null || imagesToProcess.Count == 0) { this.logger.LogInformation("No instructions received to scan docker images."); return EmptySuccessfulScan(); @@ -110,7 +110,7 @@ private static ImageScanningResult EmptyImageScanningResult() return new ImageScanningResult { ContainerDetails = null, - Components = Enumerable.Empty(), + Components = [], }; } @@ -135,13 +135,7 @@ await this.dockerService.TryPullImageAsync(image, cancellationToken))) null); } - var imageDetails = await this.dockerService.InspectImageAsync(image, cancellationToken); - - // Unable to fetch image details - if (imageDetails == null) - { - throw new MissingContainerDetailException(image); - } + var imageDetails = await this.dockerService.InspectImageAsync(image, cancellationToken) ?? throw new MissingContainerDetailException(image); processedImages.TryAdd(imageDetails.ImageId, imageDetails); } diff --git a/src/Microsoft.ComponentDetection.Detectors/linux/LinuxScanner.cs b/src/Microsoft.ComponentDetection.Detectors/linux/LinuxScanner.cs index 84fca1955..f62779dd2 100644 --- a/src/Microsoft.ComponentDetection.Detectors/linux/LinuxScanner.cs +++ b/src/Microsoft.ComponentDetection.Detectors/linux/LinuxScanner.cs @@ -17,12 +17,12 @@ public class LinuxScanner : ILinuxScanner { private const string ScannerImage = "governancecontainerregistry.azurecr.io/syft:v0.100.0@sha256:df7b07bfadff45e0135d74f22478f47b16ac6aff4e8dbd93133fcae3bbbb790d"; - private static readonly IList CmdParameters = new List - { + private static readonly IList CmdParameters = + [ "--quiet", "--scope", "all-layers", "--output", "json", - }; + ]; - private static readonly IEnumerable AllowedArtifactTypes = new[] { "apk", "deb", "rpm" }; + private static readonly IEnumerable AllowedArtifactTypes = ["apk", "deb", "rpm"]; private static readonly SemaphoreSlim DockerSemaphore = new SemaphoreSlim(2); @@ -163,7 +163,7 @@ private string GetLicenseFromArtifactElement(ArtifactElement artifact) } var licenses = artifact.Licenses; - if (licenses != null && licenses.Any()) + if (licenses != null && licenses.Length != 0) { return string.Join(", ", licenses.Select(l => l.Value)); } diff --git a/src/Microsoft.ComponentDetection.Detectors/maven/GraphNode.cs b/src/Microsoft.ComponentDetection.Detectors/maven/GraphNode.cs index faf148649..78e5e90b2 100644 --- a/src/Microsoft.ComponentDetection.Detectors/maven/GraphNode.cs +++ b/src/Microsoft.ComponentDetection.Detectors/maven/GraphNode.cs @@ -12,7 +12,7 @@ public class GraphNode public T Value { get; set; } - public List> Children { get; } = new List>(); + public List> Children { get; } = []; - public List> Parents { get; } = new List>(); + public List> Parents { get; } = []; } diff --git a/src/Microsoft.ComponentDetection.Detectors/maven/MavenCommandService.cs b/src/Microsoft.ComponentDetection.Detectors/maven/MavenCommandService.cs index aac439aac..df3d77b5f 100644 --- a/src/Microsoft.ComponentDetection.Detectors/maven/MavenCommandService.cs +++ b/src/Microsoft.ComponentDetection.Detectors/maven/MavenCommandService.cs @@ -13,7 +13,7 @@ public class MavenCommandService : IMavenCommandService internal const string MvnVersionArgument = "--version"; - internal static readonly string[] AdditionalValidCommands = new[] { "mvn.cmd" }; + internal static readonly string[] AdditionalValidCommands = ["mvn.cmd"]; private readonly ICommandLineInvocationService commandLineInvocationService; private readonly IMavenStyleDependencyGraphParserService parserService; diff --git a/src/Microsoft.ComponentDetection.Detectors/maven/MavenParsingUtilities.cs b/src/Microsoft.ComponentDetection.Detectors/maven/MavenParsingUtilities.cs index 1517a70f4..cd4127fa6 100644 --- a/src/Microsoft.ComponentDetection.Detectors/maven/MavenParsingUtilities.cs +++ b/src/Microsoft.ComponentDetection.Detectors/maven/MavenParsingUtilities.cs @@ -47,7 +47,7 @@ private static (string GroupId, string ArtifactId, string Version, bool? IsDevel { // Six part versions have an entry in their 4th index. We remove it to normalize. E.g.: // var mysteriousSixPartVersionPart = results[3]; - results = new[] { results[0], results[1], results[2], results[4], results[5] }; + results = [results[0], results[1], results[2], results[4], results[5]]; } // 'MavenCompile' is a default scope for maven dependencies. diff --git a/src/Microsoft.ComponentDetection.Detectors/maven/MavenStyleDependencyGraphParser.cs b/src/Microsoft.ComponentDetection.Detectors/maven/MavenStyleDependencyGraphParser.cs index 3598bece1..3883e03da 100644 --- a/src/Microsoft.ComponentDetection.Detectors/maven/MavenStyleDependencyGraphParser.cs +++ b/src/Microsoft.ComponentDetection.Detectors/maven/MavenStyleDependencyGraphParser.cs @@ -8,9 +8,9 @@ namespace Microsoft.ComponentDetection.Detectors.Maven; public class MavenStyleDependencyGraphParser { - private static readonly char[] TrimCharacters = new char[] { '|', ' ' }; + private static readonly char[] TrimCharacters = ['|', ' ']; - private static readonly string[] ComponentSplitters = new[] { "+-", "\\-" }; + private static readonly string[] ComponentSplitters = ["+-", "\\-"]; private readonly Stack> stack = new Stack>(); diff --git a/src/Microsoft.ComponentDetection.Detectors/maven/MvnCliComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/maven/MvnCliComponentDetector.cs index 118d8d441..e06ecd967 100644 --- a/src/Microsoft.ComponentDetection.Detectors/maven/MvnCliComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/maven/MvnCliComponentDetector.cs @@ -32,13 +32,13 @@ public MvnCliComponentDetector( public override string Id => "MvnCli"; - public override IList SearchPatterns => new List { "pom.xml" }; + public override IList SearchPatterns => ["pom.xml"]; - public override IEnumerable SupportedComponentTypes => new[] { ComponentType.Maven }; + public override IEnumerable SupportedComponentTypes => [ComponentType.Maven]; public override int Version => 3; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Maven) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Maven)]; protected override async Task> OnPrepareDetectionAsync(IObservable processRequests, IDictionary detectorArgs) { @@ -59,7 +59,7 @@ await this.RemoveNestedPomXmls(processRequests).ForEachAsync(processRequest => await processPomFile.Completion; - return this.ComponentStreamEnumerableFactory.GetComponentStreams(this.CurrentScanRequest.SourceDirectory, new[] { this.mavenCommandService.BcdeMvnDependencyFileName }, this.CurrentScanRequest.DirectoryExclusionPredicate) + return this.ComponentStreamEnumerableFactory.GetComponentStreams(this.CurrentScanRequest.SourceDirectory, [this.mavenCommandService.BcdeMvnDependencyFileName], this.CurrentScanRequest.DirectoryExclusionPredicate) .Select(componentStream => { // The file stream is going to be disposed after the iteration is finished @@ -126,8 +126,8 @@ private IObservable RemoveNestedPomXmls(IObservable(), - Directories = new List(), + Files = [], + Directories = [], }; } diff --git a/src/Microsoft.ComponentDetection.Detectors/npm/NpmComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/npm/NpmComponentDetector.cs index ef1bf63db..2d978ad65 100644 --- a/src/Microsoft.ComponentDetection.Detectors/npm/NpmComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/npm/NpmComponentDetector.cs @@ -31,11 +31,11 @@ public NpmComponentDetector( public override string Id { get; } = "Npm"; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Npm) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Npm)]; - public override IList SearchPatterns { get; } = new List { "package.json" }; + public override IList SearchPatterns { get; } = ["package.json"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Npm }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Npm]; public override int Version { get; } = 2; diff --git a/src/Microsoft.ComponentDetection.Detectors/npm/NpmComponentUtilities.cs b/src/Microsoft.ComponentDetection.Detectors/npm/NpmComponentUtilities.cs index 1f3859f22..36fb26241 100644 --- a/src/Microsoft.ComponentDetection.Detectors/npm/NpmComponentUtilities.cs +++ b/src/Microsoft.ComponentDetection.Detectors/npm/NpmComponentUtilities.cs @@ -95,7 +95,7 @@ public static bool TryParseNpmRegistryVersion(string packageName, Uri versionStr public static IDictionary> TryGetAllPackageJsonDependencies(Stream stream, out IList yarnWorkspaces) { - yarnWorkspaces = new List(); + yarnWorkspaces = []; using var file = new StreamReader(stream); using var reader = new JsonTextReader(file); diff --git a/src/Microsoft.ComponentDetection.Detectors/npm/NpmLockfileDetectorBase.cs b/src/Microsoft.ComponentDetection.Detectors/npm/NpmLockfileDetectorBase.cs index 05bd0f955..5dc3139f9 100644 --- a/src/Microsoft.ComponentDetection.Detectors/npm/NpmLockfileDetectorBase.cs +++ b/src/Microsoft.ComponentDetection.Detectors/npm/NpmLockfileDetectorBase.cs @@ -46,16 +46,16 @@ protected NpmLockfileDetectorBase( /// Used in scenarios where one file path creates multiple JTokens, a false value indicates processing additional JTokens should be halted, proceed otherwise. protected delegate bool JTokenProcessingDelegate(JToken token); - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Npm) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Npm)]; - public override IList SearchPatterns { get; } = new List { "package-lock.json", "npm-shrinkwrap.json", LernaSearchPattern }; + public override IList SearchPatterns { get; } = ["package-lock.json", "npm-shrinkwrap.json", LernaSearchPattern]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Npm }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Npm]; - private List LernaFiles { get; } = new(); + private List LernaFiles { get; } = []; /// - protected override IList SkippedFolders => new List { "node_modules", "pnpm-store" }; + protected override IList SkippedFolders => ["node_modules", "pnpm-store"]; protected abstract bool IsSupportedLockfileVersion(int lockfileVersion); @@ -94,7 +94,7 @@ protected override Task> OnPrepareDetectionAsync(IOb protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary detectorArgs) { - IEnumerable packageJsonPattern = new List { "package.json" }; + IEnumerable packageJsonPattern = ["package.json"]; var singleFileComponentRecorder = processRequest.SingleFileComponentRecorder; var file = processRequest.ComponentStream; @@ -130,7 +130,7 @@ await this.SafeProcessAllPackageJTokensAsync(file, (token) => }); } - protected Task ProcessAllPackageJTokensAsync(IComponentStream componentStream, JTokenProcessingDelegate jtokenProcessor) + protected async Task ProcessAllPackageJTokensAsync(IComponentStream componentStream, JTokenProcessingDelegate jtokenProcessor) { try { @@ -142,15 +142,15 @@ protected Task ProcessAllPackageJTokensAsync(IComponentStream componentStream, J catch (Exception ex) { this.Logger.LogInformation(ex, "Could not read {ComponentStreamFile} file.", componentStream.Location); - return Task.CompletedTask; + return; } using var file = new StreamReader(componentStream.Stream); using var reader = new JsonTextReader(file); - var o = JToken.ReadFrom(reader); + var o = await JToken.ReadFromAsync(reader); jtokenProcessor(o); - return Task.CompletedTask; + return; } private void ProcessIndividualPackageJTokens(ISingleFileComponentRecorder singleFileComponentRecorder, JToken packageLockJToken, IEnumerable packageJsonComponentStream, bool skipValidation = false) @@ -239,8 +239,8 @@ private IObservable RemoveNodeModuleNestedFiles(IObservable(), - Directories = new List(), + Files = [], + Directories = [], }; } diff --git a/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetComponentDetector.cs index a0bf1e831..0a682bb0b 100644 --- a/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetComponentDetector.cs @@ -17,11 +17,11 @@ namespace Microsoft.ComponentDetection.Detectors.NuGet; public class NuGetComponentDetector : FileComponentDetector { - private static readonly IEnumerable LowConfidencePackages = new[] { "Newtonsoft.Json" }; + private static readonly IEnumerable LowConfidencePackages = ["Newtonsoft.Json"]; public const string NugetConfigFileName = "nuget.config"; - private readonly IList repositoryPathKeyNames = new List { "repositorypath", "globalpackagesfolder" }; + private readonly IList repositoryPathKeyNames = ["repositorypath", "globalpackagesfolder"]; public NuGetComponentDetector( IComponentStreamEnumerableFactory componentStreamEnumerableFactory, @@ -35,11 +35,11 @@ public NuGetComponentDetector( public override string Id { get; } = "NuGet"; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.NuGet) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.NuGet)]; - public override IList SearchPatterns { get; } = new List { "*.nupkg", "*.nuspec", NugetConfigFileName, "paket.lock" }; + public override IList SearchPatterns { get; } = ["*.nupkg", "*.nuspec", NugetConfigFileName, "paket.lock"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.NuGet }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.NuGet]; public override int Version { get; } = 2; diff --git a/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetNuspecUtilities.cs b/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetNuspecUtilities.cs index b0c054e2d..6b858edac 100644 --- a/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetNuspecUtilities.cs +++ b/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetNuspecUtilities.cs @@ -27,20 +27,15 @@ public static async Task GetNuspecBytesAsync(Stream nupkgStream) var nuspecEntry = archive.Entries.FirstOrDefault(x => x.Name.EndsWith(".nuspec", StringComparison.OrdinalIgnoreCase) - && !x.FullName.Contains('/')); - - if (nuspecEntry == null) - { - throw new FileNotFoundException("No nuspec file was found"); - } + && !x.FullName.Contains('/')) ?? throw new FileNotFoundException("No nuspec file was found"); using var nuspecStream = nuspecEntry.Open(); return await GetNuspecBytesFromNuspecStreamAsync(nuspecStream, nuspecEntry.Length); } - catch (InvalidDataException ex) + catch (InvalidDataException) { - throw ex; + throw; } finally { diff --git a/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetPackagesConfigDetector.cs b/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetPackagesConfigDetector.cs index 858cab6a9..fe9fdf35f 100644 --- a/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetPackagesConfigDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetPackagesConfigDetector.cs @@ -32,17 +32,17 @@ public NuGetPackagesConfigDetector( } /// - public override IList SearchPatterns => new[] { "packages.config" }; + public override IList SearchPatterns => ["packages.config"]; /// public override string Id => "NuGetPackagesConfig"; /// public override IEnumerable Categories => - new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.NuGet) }; + [Enum.GetName(typeof(DetectorClass), DetectorClass.NuGet)]; /// - public override IEnumerable SupportedComponentTypes => new[] { ComponentType.NuGet }; + public override IEnumerable SupportedComponentTypes => [ComponentType.NuGet]; /// public override int Version => 1; diff --git a/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetProjectModelProjectCentricComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetProjectModelProjectCentricComponentDetector.cs index dc1e3ab7b..f5534560c 100644 --- a/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetProjectModelProjectCentricComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/nuget/NuGetProjectModelProjectCentricComponentDetector.cs @@ -23,13 +23,13 @@ public class NuGetProjectModelProjectCentricComponentDetector : FileComponentDet private readonly ConcurrentDictionary frameworkComponentsThatWereOmmittedWithCount = new ConcurrentDictionary(); - private readonly List netCoreFrameworkNames = new List { "Microsoft.AspNetCore.App", "Microsoft.AspNetCore.Razor.Design", "Microsoft.NETCore.App" }; + private readonly List netCoreFrameworkNames = ["Microsoft.AspNetCore.App", "Microsoft.AspNetCore.Razor.Design", "Microsoft.NETCore.App"]; // This list is meant to encompass all net standard dependencies, but likely contains some net core app 1.x ones, too. // The specific guidance we got around populating this list is to do so based on creating a dotnet core 1.x app to make sure we had the complete // set of netstandard.library files that could show up in later sdk versions. - private readonly string[] netStandardDependencies = new[] - { + private readonly string[] netStandardDependencies = + [ "Libuv", "Microsoft.CodeAnalysis.Analyzers", "Microsoft.CodeAnalysis.Common", @@ -182,7 +182,7 @@ public class NuGetProjectModelProjectCentricComponentDetector : FileComponentDet "System.Xml.XmlSerializer", "System.Xml.XPath", "System.Xml.XPath.XDocument", - }; + ]; private readonly IFileUtilityService fileUtilityService; @@ -200,11 +200,11 @@ public NuGetProjectModelProjectCentricComponentDetector( public override string Id { get; } = "NuGetProjectCentric"; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.NuGet) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.NuGet)]; - public override IList SearchPatterns { get; } = new List { "project.assets.json" }; + public override IList SearchPatterns { get; } = ["project.assets.json"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.NuGet }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.NuGet]; public override int Version { get; } = 1; @@ -272,7 +272,7 @@ private void NavigateAndRegister( return; } - visited ??= new HashSet(); + visited ??= []; var libraryComponent = new DetectedComponent(new NuGetComponent(library.Name, library.Version.ToNormalizedString())); singleFileComponentRecorder.RegisterUsage(libraryComponent, explicitlyReferencedComponentIds.Contains(libraryComponent.Component.Id), parentComponentId); @@ -426,7 +426,7 @@ private HashSet GetFrameworkComponents(LockFile lockFile) private HashSet GetDependencyComponentIds(LockFile lockFile, LockFileTarget target, IList dependencies, HashSet visited = null) { - visited ??= new HashSet(); + visited ??= []; var currentComponents = new HashSet(); foreach (var dependency in dependencies) { diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipDependencySpecification.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipDependencySpecification.cs index 93f35236d..489b9aece 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipDependencySpecification.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipDependencySpecification.cs @@ -19,8 +19,8 @@ public class PipDependencySpecification /// /// These are packages that we don't want to evaluate in our graph as they are generally python builtins. /// - private static readonly HashSet PackagesToIgnore = new HashSet - { + private static readonly HashSet PackagesToIgnore = + [ "-markerlib", "pip", "pip-tools", @@ -28,7 +28,7 @@ public class PipDependencySpecification "pkg-resources", "setuptools", "wheel", - }; + ]; // Extracts abcd from a string like abcd==1.*,!=1.3 private static readonly Regex PipNameExtractionRegex = new Regex( @@ -108,7 +108,7 @@ public PipDependencySpecification(string packageString, bool requiresDist = fals /// /// Gets or sets the set of dependency specifications that constrain the overall dependency request (ex: ==1.0, >=2.0). /// - public IList DependencySpecifiers { get; set; } = new List(); + public IList DependencySpecifiers { get; set; } = []; private string DebuggerDisplay => $"{this.Name} ({string.Join(';', this.DependencySpecifiers)})"; diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipGraphNode.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipGraphNode.cs index 15f7383f8..a07de6649 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipGraphNode.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipGraphNode.cs @@ -13,7 +13,7 @@ public class PipGraphNode public PipComponent Value { get; set; } - public List Children { get; } = new List(); + public List Children { get; } = []; - public List Parents { get; } = new List(); + public List Parents { get; } = []; } diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipReportGraphNode.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipReportGraphNode.cs index 8b689000a..690e44268 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipReportGraphNode.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipReportGraphNode.cs @@ -17,9 +17,9 @@ public PipReportGraphNode(PipComponent value, bool requested) public PipComponent Value { get; set; } - public List Children { get; } = new List(); + public List Children { get; } = []; - public List Parents { get; } = new List(); + public List Parents { get; } = []; public bool Requested { get; set; } } diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonResolverState.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonResolverState.cs index 0f0ea5160..adae76e70 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonResolverState.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonResolverState.cs @@ -12,5 +12,5 @@ public class PythonResolverState public IDictionary NodeReferences { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); - public IList Roots { get; } = new List(); + public IList Roots { get; } = []; } diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonVersion.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonVersion.cs index a16fbdb0e..8564a6f99 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonVersion.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonVersion.cs @@ -111,10 +111,7 @@ private PythonVersion(string version) public static PythonVersion Create(string version) { - if (version == null) - { - throw new ArgumentNullException(nameof(version)); - } + ArgumentNullException.ThrowIfNull(version); if (Cache.TryGetValue(version, out var cachedVersion)) { diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PipCommandService.cs b/src/Microsoft.ComponentDetection.Detectors/pip/PipCommandService.cs index 13acae112..9bda93947 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/PipCommandService.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/PipCommandService.cs @@ -1,7 +1,6 @@ namespace Microsoft.ComponentDetection.Detectors.Pip; using System; -using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Microsoft.ComponentDetection.Common; @@ -82,7 +81,7 @@ private async Task ResolvePipAsync(string pipPath = null) private async Task CanCommandBeLocatedAsync(string pipPath) { - return await this.commandLineInvocationService.CanCommandBeLocatedAsync(pipPath, new List { "pip3" }, "--version"); + return await this.commandLineInvocationService.CanCommandBeLocatedAsync(pipPath, ["pip3"], "--version"); } public async Task<(PipInstallationReport Report, FileInfo ReportFile)> GenerateInstallationReportAsync(string path, string pipExePath = null) diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PipComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/pip/PipComponentDetector.cs index 23370bf0d..5616b9592 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/PipComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/PipComponentDetector.cs @@ -31,11 +31,11 @@ public PipComponentDetector( public override string Id => "Pip"; - public override IList SearchPatterns => new List { "setup.py", "requirements.txt" }; + public override IList SearchPatterns => ["setup.py", "requirements.txt"]; - public override IEnumerable Categories => new List { "Python" }; + public override IEnumerable Categories => ["Python"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Pip }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Pip]; public override int Version { get; } = 8; diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PipReportComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/pip/PipReportComponentDetector.cs index ead2ade5a..8936dfd25 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/PipReportComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/PipReportComponentDetector.cs @@ -41,11 +41,11 @@ public PipReportComponentDetector( public override string Id => "PipReport"; - public override IList SearchPatterns => new List { "setup.py", "requirements.txt" }; + public override IList SearchPatterns => ["setup.py", "requirements.txt"]; - public override IEnumerable Categories => new List { "Python" }; + public override IEnumerable Categories => ["Python"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Pip }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Pip]; public override int Version { get; } = 1; @@ -192,7 +192,7 @@ private Dictionary BuildGraphFromInstallationReport( } else { - dependenciesByPkg.Add(normalizedPkgName, new List { dependencySpec }); + dependenciesByPkg.Add(normalizedPkgName, [dependencySpec]); } } } @@ -244,7 +244,7 @@ private void RecordComponents( // parentComponentId is guaranteed to exist in the graph or an exception will be thrown. foreach (var node in graph.Values) { - if (!node.Parents.Any()) + if (node.Parents.Count == 0) { continue; } diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PythonCommandService.cs b/src/Microsoft.ComponentDetection.Detectors/pip/PythonCommandService.cs index a60bacb09..2b60ddee0 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/PythonCommandService.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/PythonCommandService.cs @@ -12,6 +12,8 @@ namespace Microsoft.ComponentDetection.Detectors.Pip; public class PythonCommandService : IPythonCommandService { + private static readonly string[] SetupPySeperators = ["',"]; + private readonly ICommandLineInvocationService commandLineInvocationService; private readonly IPathUtilityService pathUtilityService; private readonly ILogger logger; @@ -81,7 +83,7 @@ private async Task> ParseSetupPyFileAsync(string filePath, string if (command.ExitCode != 0) { this.logger.LogDebug("Python: Failed distutils setup with error: {StdErr}", command.StdErr); - return new List(); + return []; } var result = command.StdOut; @@ -91,18 +93,18 @@ private async Task> ParseSetupPyFileAsync(string filePath, string // For Python2 if there are no packages (Result: "None") skip any parsing if (result.Equals("None", StringComparison.OrdinalIgnoreCase) && !command.StdOut.StartsWith('[')) { - return new List(); + return []; } - return result.Split(new string[] { "'," }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim().Trim('\'').Trim()).ToList(); + return result.Split(SetupPySeperators, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim().Trim('\'').Trim()).ToList(); } - private IList<(string PackageString, GitComponent Component)> ParseRequirementsTextFile(string path) + private List<(string PackageString, GitComponent Component)> ParseRequirementsTextFile(string path) { var items = new List<(string, GitComponent)>(); foreach (var line in File.ReadAllLines(path) .Select(x => x.Trim().TrimEnd('\\')) - .Where(x => !x.StartsWith("#") && !x.StartsWith("-") && !string.IsNullOrWhiteSpace(x))) + .Where(x => !x.StartsWith('#') && !x.StartsWith('-') && !string.IsNullOrWhiteSpace(x))) { // We technically shouldn't be ignoring information after the ; // It's used to indicate environment markers like specific python versions @@ -170,6 +172,6 @@ private async Task ResolvePythonAsync(string pythonPath = null) private async Task CanCommandBeLocatedAsync(string pythonPath) { - return await this.commandLineInvocationService.CanCommandBeLocatedAsync(pythonPath, new List { "python3", "python2" }, "--version"); + return await this.commandLineInvocationService.CanCommandBeLocatedAsync(pythonPath, ["python3", "python2"], "--version"); } } diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PythonResolver.cs b/src/Microsoft.ComponentDetection.Detectors/pip/PythonResolver.cs index 5c166b7e5..af5ae8bd0 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/PythonResolver.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/PythonResolver.cs @@ -46,12 +46,12 @@ public async Task> ResolveRootsAsync(ISingleFileComponentRec var result = project.Releases; - if (result is not null && result.Keys.Any()) + if (result is not null && result.Keys.Count != 0) { state.ValidVersionMap[rootPackage.Name] = result; // Grab the latest version as our candidate version - var candidateVersion = state.ValidVersionMap[rootPackage.Name].Keys.Any() + var candidateVersion = state.ValidVersionMap[rootPackage.Name].Keys.Count != 0 ? state.ValidVersionMap[rootPackage.Name].Keys.Last() : null; var node = new PipGraphNode(new PipComponent(rootPackage.Name, candidateVersion, license: this.GetLicenseFromProject(project), author: this.GetSupplierFromProject(project))); @@ -74,7 +74,7 @@ public async Task> ResolveRootsAsync(ISingleFileComponentRec } // Now queue packages for processing - return await this.ProcessQueueAsync(singleFileComponentRecorder, state) ?? new List(); + return await this.ProcessQueueAsync(singleFileComponentRecorder, state) ?? []; } private async Task> ProcessQueueAsync(ISingleFileComponentRecorder singleFileComponentRecorder, PythonResolverState state) @@ -119,10 +119,10 @@ private async Task> ProcessQueueAsync(ISingleFileComponentRe var result = project.Releases; - if (result is not null && result.Keys.Any()) + if (result is not null && result.Keys.Count != 0) { state.ValidVersionMap[dependencyNode.Name] = result; - var candidateVersion = state.ValidVersionMap[dependencyNode.Name].Keys.Any() + var candidateVersion = state.ValidVersionMap[dependencyNode.Name].Keys.Count != 0 ? state.ValidVersionMap[dependencyNode.Name].Keys.Last() : null; this.AddGraphNode(state, state.NodeReferences[currentNode.Name], dependencyNode.Name, candidateVersion, license: this.GetLicenseFromProject(project), author: this.GetSupplierFromProject(project)); @@ -162,7 +162,7 @@ protected override async Task> FetchPackageDep state.ValidVersionMap[spec.Name][candidateVersion].FirstOrDefault(x => string.Equals("bdist_egg", x.PackageType, StringComparison.OrdinalIgnoreCase)); if (packageToFetch == null) { - return new List(); + return []; } return await this.pypiClient.FetchPackageDependenciesAsync(spec.Name, candidateVersion, packageToFetch); diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PythonResolverBase.cs b/src/Microsoft.ComponentDetection.Detectors/pip/PythonResolverBase.cs index e501d8ff2..178acb843 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/PythonResolverBase.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/PythonResolverBase.cs @@ -42,7 +42,8 @@ protected async Task InvalidateAndReprocessAsync( return false; } - var candidateVersion = state.ValidVersionMap[pipComponent.Name].Keys.Any() ? state.ValidVersionMap[pipComponent.Name].Keys.Last() : null; + var candidateVersion = state.ValidVersionMap[pipComponent.Name].Keys.Count != 0 + ? state.ValidVersionMap[pipComponent.Name].Keys.Last() : null; node.Value = new PipComponent(pipComponent.Name, candidateVersion, author: pipComponent.Author, license: pipComponent.License); diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/SimplePipComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/pip/SimplePipComponentDetector.cs index 69de687b4..40e3050cf 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/SimplePipComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/SimplePipComponentDetector.cs @@ -31,11 +31,11 @@ public SimplePipComponentDetector( public override string Id => "SimplePip"; - public override IList SearchPatterns => new List { "setup.py", "requirements.txt" }; + public override IList SearchPatterns => ["setup.py", "requirements.txt"]; - public override IEnumerable Categories => new List { "Python" }; + public override IEnumerable Categories => ["Python"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Pip }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Pip]; public override int Version { get; } = 3; diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/SimplePythonResolver.cs b/src/Microsoft.ComponentDetection.Detectors/pip/SimplePythonResolver.cs index d013b47e1..5cda7b22a 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/SimplePythonResolver.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/SimplePythonResolver.cs @@ -118,12 +118,12 @@ await Parallel.ForEachAsync(initialPackages, async (rootPackage, ct) => { var pythonProject = this.ConvertSimplePypiProjectToSortedDictionary(simplePythonProject, rootPackage); - if (pythonProject.Keys.Any()) + if (pythonProject.Keys.Count != 0) { state.ValidVersionMap[rootPackage.Name] = pythonProject; // Grab the latest version as our candidate version - var candidateVersion = state.ValidVersionMap[rootPackage.Name].Keys.Any() + var candidateVersion = state.ValidVersionMap[rootPackage.Name].Keys.Count != 0 ? state.ValidVersionMap[rootPackage.Name].Keys.Last() : null; @@ -147,7 +147,7 @@ await Parallel.ForEachAsync(initialPackages, async (rootPackage, ct) => }); // Now queue packages for processing - return await this.ProcessQueueAsync(singleFileComponentRecorder, state) ?? new List(); + return await this.ProcessQueueAsync(singleFileComponentRecorder, state) ?? []; } private async Task> ProcessQueueAsync(ISingleFileComponentRecorder singleFileComponentRecorder, PythonResolverState state) @@ -199,10 +199,10 @@ private async Task> ProcessQueueAsync(ISingleFileComponentRe } var result = this.ConvertSimplePypiProjectToSortedDictionary(newProject, dependencyNode); - if (result.Keys.Any()) + if (result.Keys.Count != 0) { state.ValidVersionMap[dependencyNode.Name] = result; - var candidateVersion = state.ValidVersionMap[dependencyNode.Name].Keys.Any() + var candidateVersion = state.ValidVersionMap[dependencyNode.Name].Keys.Count != 0 ? state.ValidVersionMap[dependencyNode.Name].Keys.Last() : null; AddGraphNode(state, state.NodeReferences[currentNode.Name], dependencyNode.Name, candidateVersion); @@ -261,7 +261,7 @@ private SortedDictionary> ConvertSimplePypiP var pythonProjectRelease = new PythonProjectRelease { PythonVersion = version, PackageType = packageType, Size = file.Size, Url = file.Url }; if (!sortedProjectVersions.ContainsKey(version)) { - sortedProjectVersions.Add(version, new List()); + sortedProjectVersions.Add(version, []); } sortedProjectVersions[version].Add(pythonProjectRelease); @@ -295,14 +295,14 @@ protected override async Task> FetchPackageDep state.ValidVersionMap[spec.Name][candidateVersion].FirstOrDefault(x => string.Equals("bdist_egg", x.PackageType, StringComparison.OrdinalIgnoreCase)); if (packageToFetch == null) { - return new List(); + return []; } var packageFileStream = await this.simplePypiClient.FetchPackageFileStreamAsync(packageToFetch.Url); if (packageFileStream.Length == 0) { - return new List(); + return []; } return await this.FetchDependenciesFromPackageStreamAsync(spec.Name, candidateVersion, packageFileStream); diff --git a/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmComponentDetectorFactory.cs b/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmComponentDetectorFactory.cs index 32750124e..ccec149ed 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmComponentDetectorFactory.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmComponentDetectorFactory.cs @@ -34,11 +34,11 @@ public PnpmComponentDetectorFactory( public override string Id { get; } = "Pnpm"; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Npm) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Npm)]; - public override IList SearchPatterns { get; } = new List { "shrinkwrap.yaml", "pnpm-lock.yaml" }; + public override IList SearchPatterns { get; } = ["shrinkwrap.yaml", "pnpm-lock.yaml"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Npm }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Npm]; public override int Version { get; } = 6; diff --git a/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmParsingUtilities.cs b/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmParsingUtilities.cs index 729f287c9..fe107d9ec 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmParsingUtilities.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pnpm/PnpmParsingUtilities.cs @@ -21,10 +21,7 @@ public static string DeserializePnpmYamlFileVersion(string fileContent) public static bool IsPnpmPackageDevDependency(Package pnpmPackage) { - if (pnpmPackage == null) - { - throw new ArgumentNullException(nameof(pnpmPackage)); - } + ArgumentNullException.ThrowIfNull(pnpmPackage); return string.Equals(bool.TrueString, pnpmPackage.Dev, StringComparison.InvariantCultureIgnoreCase); } @@ -136,7 +133,7 @@ public static DetectedComponent CreateDetectedComponentFromPnpmPathV6(string pnp var packageVersion = packageNameParts[^1]; // Check for leading `/` from pnpm. - if (!fullPackageName.StartsWith("/")) + if (!fullPackageName.StartsWith('/')) { throw new FormatException("Found pnpm dependency path not starting with `/`. This case is currently unhandled."); } @@ -158,7 +155,7 @@ public static DetectedComponent CreateDetectedComponentFromPnpmPathV6(string pnp /// A pnpm dependency path for the specified version of the named package. public static string ReconstructPnpmDependencyPathV6(string dependencyName, string dependencyVersion) { - if (dependencyVersion.StartsWith("/")) + if (dependencyVersion.StartsWith('/')) { return dependencyVersion; } diff --git a/src/Microsoft.ComponentDetection.Detectors/poetry/PoetryComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/poetry/PoetryComponentDetector.cs index fe4a7f857..b70c7ac4b 100644 --- a/src/Microsoft.ComponentDetection.Detectors/poetry/PoetryComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/poetry/PoetryComponentDetector.cs @@ -26,13 +26,13 @@ public PoetryComponentDetector( public override string Id => "Poetry"; - public override IList SearchPatterns { get; } = new List { "poetry.lock" }; + public override IList SearchPatterns { get; } = ["poetry.lock"]; - public override IEnumerable SupportedComponentTypes => new[] { ComponentType.Pip }; + public override IEnumerable SupportedComponentTypes => [ComponentType.Pip]; public override int Version { get; } = 3; - public override IEnumerable Categories => new List { "Python" }; + public override IEnumerable Categories => ["Python"]; protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary detectorArgs) { diff --git a/src/Microsoft.ComponentDetection.Detectors/ruby/RubyComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/ruby/RubyComponentDetector.cs index 391a20de0..571909e35 100644 --- a/src/Microsoft.ComponentDetection.Detectors/ruby/RubyComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/ruby/RubyComponentDetector.cs @@ -62,11 +62,11 @@ private enum SectionType public override string Id { get; } = "Ruby"; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.RubyGems) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.RubyGems)]; - public override IList SearchPatterns { get; } = new List { "Gemfile.lock" }; + public override IList SearchPatterns { get; } = ["Gemfile.lock"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.RubyGems }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.RubyGems]; public override int Version { get; } = 3; @@ -135,7 +135,7 @@ private void ParseGemLockFile(ISingleFileComponentRecorder singleFileComponentRe // Nothing in the lockfile tells us where bundler came from var addComponent = new DetectedComponent(new RubyGemsComponent(name, line, "unknown")); components.TryAdd(string.Format("{0}:{1}", name, file.Location), addComponent); - dependencies.TryAdd(string.Format("{0}:{1}", name, file.Location), new List()); + dependencies.TryAdd(string.Format("{0}:{1}", name, file.Location), []); break; default: // We ignore other sections @@ -248,7 +248,7 @@ private void ParseSection(ISingleFileComponentRecorder singleFileComponentRecord else { components.TryAdd(lookupKey, addComponent); - dependencies.Add(lookupKey, new List()); + dependencies.Add(lookupKey, []); } } } @@ -258,7 +258,7 @@ private void ParseSection(ISingleFileComponentRecorder singleFileComponentRecord private bool IsVersionRelative(string version) { - return version.StartsWith("~") || version.StartsWith("="); + return version.StartsWith('~') || version.StartsWith('='); } private class Dependency diff --git a/src/Microsoft.ComponentDetection.Detectors/rust/CargoDependencyData.cs b/src/Microsoft.ComponentDetection.Detectors/rust/CargoDependencyData.cs index 9ce728846..248e131d9 100644 --- a/src/Microsoft.ComponentDetection.Detectors/rust/CargoDependencyData.cs +++ b/src/Microsoft.ComponentDetection.Detectors/rust/CargoDependencyData.cs @@ -6,10 +6,10 @@ public class CargoDependencyData { public CargoDependencyData() { - this.CargoWorkspaces = new HashSet(); - this.CargoWorkspaceExclusions = new HashSet(); - this.NonDevDependencies = new List(); - this.DevDependencies = new List(); + this.CargoWorkspaces = []; + this.CargoWorkspaceExclusions = []; + this.NonDevDependencies = []; + this.DevDependencies = []; } public HashSet CargoWorkspaces { get; set; } diff --git a/src/Microsoft.ComponentDetection.Detectors/rust/DependencySpecification.cs b/src/Microsoft.ComponentDetection.Detectors/rust/DependencySpecification.cs index 1ca080471..000173210 100644 --- a/src/Microsoft.ComponentDetection.Detectors/rust/DependencySpecification.cs +++ b/src/Microsoft.ComponentDetection.Detectors/rust/DependencySpecification.cs @@ -9,14 +9,15 @@ namespace Microsoft.ComponentDetection.Detectors.Rust; public class DependencySpecification { - private readonly IDictionary>> dependencies; + private static readonly char[] CargoVerSeperator = [',']; + private readonly Dictionary>> dependencies; - public DependencySpecification() => this.dependencies = new Dictionary>>(); + public DependencySpecification() => this.dependencies = []; public void Add(string name, string cargoVersionSpecifier) { - ISet ranges = new HashSet(); - var specifiers = cargoVersionSpecifier.Split(new char[] { ',' }); + var ranges = new HashSet(); + var specifiers = cargoVersionSpecifier.Split(CargoVerSeperator); foreach (var specifier in specifiers) { ranges.Add(new Range(specifier.Trim())); diff --git a/src/Microsoft.ComponentDetection.Detectors/rust/InvalidRustTomlFileException.cs b/src/Microsoft.ComponentDetection.Detectors/rust/InvalidRustTomlFileException.cs index a32801de3..d9ce738cd 100644 --- a/src/Microsoft.ComponentDetection.Detectors/rust/InvalidRustTomlFileException.cs +++ b/src/Microsoft.ComponentDetection.Detectors/rust/InvalidRustTomlFileException.cs @@ -1,7 +1,6 @@ namespace Microsoft.ComponentDetection.Detectors.Rust; using System; -using System.Runtime.Serialization; public class InvalidRustTomlFileException : Exception { @@ -18,9 +17,4 @@ public InvalidRustTomlFileException(string message, Exception innerException) : base(message, innerException) { } - - protected InvalidRustTomlFileException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } diff --git a/src/Microsoft.ComponentDetection.Detectors/rust/RustCliDetector.cs b/src/Microsoft.ComponentDetection.Detectors/rust/RustCliDetector.cs index 5aa4408de..041a05842 100644 --- a/src/Microsoft.ComponentDetection.Detectors/rust/RustCliDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/rust/RustCliDetector.cs @@ -61,16 +61,16 @@ public RustCliDetector( public override string Id => "RustCli"; /// - public override IEnumerable Categories { get; } = new[] { "Rust" }; + public override IEnumerable Categories { get; } = ["Rust"]; /// - public override IEnumerable SupportedComponentTypes => new[] { ComponentType.Cargo }; + public override IEnumerable SupportedComponentTypes => [ComponentType.Cargo]; /// public override int Version => 4; /// - public override IList SearchPatterns { get; } = new[] { "Cargo.toml" }; + public override IList SearchPatterns { get; } = ["Cargo.toml"]; /// protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary detectorArgs) @@ -128,12 +128,12 @@ protected override async Task OnFileFoundAsync(ProcessRequest processRequest, ID x => new CargoComponent( x.Name, x.Version, - (x.Authors == null || x.Authors.Any(a => string.IsNullOrWhiteSpace(a)) || !x.Authors.Any()) ? null : string.Join(", ", x.Authors), + (x.Authors == null || x.Authors.Any(a => string.IsNullOrWhiteSpace(a)) || x.Authors.Length == 0) ? null : string.Join(", ", x.Authors), string.IsNullOrWhiteSpace(x.License) ? null : x.License, x.Source)); var root = metadata.Resolve.Root; - HashSet visitedDependencies = new(); + HashSet visitedDependencies = []; // A cargo.toml can be used to declare a workspace and not a package (A Virtual Manifest). // In this case, the root will be null as it will not be pulling in dependencies itself. @@ -145,9 +145,8 @@ protected override async Task OnFileFoundAsync(ProcessRequest processRequest, ID foreach (var dep in metadata.Resolve.Nodes) { var componentKey = $"{dep.Id}"; - if (!visitedDependencies.Contains(componentKey)) + if (visitedDependencies.Add(componentKey)) { - visitedDependencies.Add(componentKey); this.TraverseAndRecordComponents(processRequest.SingleFileComponentRecorder, componentStream.Location, graph, dep.Id, null, null, packages, visitedDependencies, explicitlyReferencedDependency: false); } } @@ -271,9 +270,8 @@ private void TraverseAndRecordComponents( { // include isTomlRoot to ensure that the roots present in the toml are marked as such in circular dependency cases var componentKey = $"{detectedComponent.Component.Id}{dep.Pkg} {isTomlRoot}"; - if (!visitedDependencies.Contains(componentKey)) + if (visitedDependencies.Add(componentKey)) { - visitedDependencies.Add(componentKey); this.TraverseAndRecordComponents(recorder, location, graph, dep.Pkg, shouldRegister ? detectedComponent : null, dep, packagesMetadata, visitedDependencies, explicitlyReferencedDependency: isTomlRoot && explicitlyReferencedDependency); } } @@ -288,7 +286,7 @@ private void TraverseAndRecordComponents( private IComponentStream FindCorrespondingCargoLock(IComponentStream cargoToml, ISingleFileComponentRecorder singleFileComponentRecorder) { var cargoLockLocation = Path.Combine(Path.GetDirectoryName(cargoToml.Location), "Cargo.lock"); - var cargoLockStream = this.ComponentStreamEnumerableFactory.GetComponentStreams(new FileInfo(cargoToml.Location).Directory, new List { "Cargo.lock" }, (name, directoryName) => false, recursivelyScanDirectories: false).FirstOrDefault(); + var cargoLockStream = this.ComponentStreamEnumerableFactory.GetComponentStreams(new FileInfo(cargoToml.Location).Directory, ["Cargo.lock"], (name, directoryName) => false, recursivelyScanDirectories: false).FirstOrDefault(); if (cargoLockStream == null) { return null; @@ -344,7 +342,7 @@ private async Task ProcessCargoLockFallbackAsync(IComponentStream cargoTomlFile, if (!packagesByName.TryGetValue(cargoPackage.Name, out var packageList)) { // First package with this name - packageList = new List<(CargoPackage, CargoComponent)>(); + packageList = []; packagesByName.Add(cargoPackage.Name, packageList); } else if (packageList.Any(p => p.Package.Equals(cargoPackage))) diff --git a/src/Microsoft.ComponentDetection.Detectors/rust/RustCrateDetector.cs b/src/Microsoft.ComponentDetection.Detectors/rust/RustCrateDetector.cs index 7ee6def41..62b9bbce5 100644 --- a/src/Microsoft.ComponentDetection.Detectors/rust/RustCrateDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/rust/RustCrateDetector.cs @@ -35,13 +35,13 @@ public RustCrateDetector( public override string Id => "RustCrateDetector"; - public override IList SearchPatterns => new List { CargoLockSearchPattern }; + public override IList SearchPatterns => [CargoLockSearchPattern]; - public override IEnumerable SupportedComponentTypes => new[] { ComponentType.Cargo }; + public override IEnumerable SupportedComponentTypes => [ComponentType.Cargo]; public override int Version { get; } = 8; - public override IEnumerable Categories => new List { "Rust" }; + public override IEnumerable Categories => ["Rust"]; private static bool ParseDependency(string dependency, out string packageName, out string version, out string source) { @@ -94,7 +94,7 @@ private void ProcessCargoLock(CargoLock cargoLock, ISingleFileComponentRecorder if (!packagesByName.TryGetValue(cargoPackage.Name, out var packageList)) { // First package with this name - packageList = new List<(CargoPackage, CargoComponent)>(); + packageList = []; packagesByName.Add(cargoPackage.Name, packageList); } else if (packageList.Any(p => p.Package.Equals(cargoPackage))) diff --git a/src/Microsoft.ComponentDetection.Detectors/spdx/Spdx22ComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/spdx/Spdx22ComponentDetector.cs index fe710910d..8cb517875 100644 --- a/src/Microsoft.ComponentDetection.Detectors/spdx/Spdx22ComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/spdx/Spdx22ComponentDetector.cs @@ -19,7 +19,7 @@ /// public class Spdx22ComponentDetector : FileComponentDetector, IDefaultOffComponentDetector { - private readonly IEnumerable supportedSPDXVersions = new List { "SPDX-2.2" }; + private readonly IEnumerable supportedSPDXVersions = ["SPDX-2.2"]; public Spdx22ComponentDetector( IComponentStreamEnumerableFactory componentStreamEnumerableFactory, @@ -32,15 +32,15 @@ public Spdx22ComponentDetector( } public override IEnumerable Categories => - new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Spdx) }; + [Enum.GetName(typeof(DetectorClass), DetectorClass.Spdx)]; public override string Id => "SPDX22SBOM"; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Spdx }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Spdx]; public override int Version => 1; - public override IList SearchPatterns => new List { "*.spdx.json" }; + public override IList SearchPatterns => ["*.spdx.json"]; protected override Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary detectorArgs) { @@ -105,7 +105,7 @@ private SpdxComponent ConvertJObjectToSbomComponent(ProcessRequest processReques this.Logger.LogWarning("SPDX file at {ManifestLocation} has more than one element in documentDescribes, first will be selected as root element.", processRequest.ComponentStream.Location); } - if (rootElements != null && !rootElements.Any()) + if (rootElements != null && rootElements.Length == 0) { this.Logger.LogWarning("SPDX file at {ManifestLocation} does not have root elements in documentDescribes section, considering SPDXRef-Document as a root element.", processRequest.ComponentStream.Location); } diff --git a/src/Microsoft.ComponentDetection.Detectors/vcpkg/VcpkgComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/vcpkg/VcpkgComponentDetector.cs index fd4eeeb63..2039221de 100644 --- a/src/Microsoft.ComponentDetection.Detectors/vcpkg/VcpkgComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/vcpkg/VcpkgComponentDetector.cs @@ -14,7 +14,7 @@ namespace Microsoft.ComponentDetection.Detectors.Vcpkg; public class VcpkgComponentDetector : FileComponentDetector, IExperimentalDetector { - private readonly HashSet projectRoots = new HashSet(); + private readonly HashSet projectRoots = []; private readonly ICommandLineInvocationService commandLineInvocationService; private readonly IEnvironmentVariableService envVarService; @@ -35,11 +35,11 @@ public VcpkgComponentDetector( public override string Id { get; } = "Vcpkg"; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Vcpkg) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Vcpkg)]; - public override IList SearchPatterns { get; } = new List { "vcpkg.spdx.json" }; + public override IList SearchPatterns { get; } = ["vcpkg.spdx.json"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Vcpkg }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Vcpkg]; public override int Version => 2; diff --git a/src/Microsoft.ComponentDetection.Detectors/yarn/InvalidYarnLockFileException.cs b/src/Microsoft.ComponentDetection.Detectors/yarn/InvalidYarnLockFileException.cs index 0323c173b..6c6956f11 100644 --- a/src/Microsoft.ComponentDetection.Detectors/yarn/InvalidYarnLockFileException.cs +++ b/src/Microsoft.ComponentDetection.Detectors/yarn/InvalidYarnLockFileException.cs @@ -1,7 +1,6 @@ namespace Microsoft.ComponentDetection.Detectors.Yarn; using System; -using System.Runtime.Serialization; public class InvalidYarnLockFileException : Exception { @@ -18,9 +17,4 @@ public InvalidYarnLockFileException(string message, Exception innerException) : base(message, innerException) { } - - protected InvalidYarnLockFileException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } diff --git a/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnBlock.cs b/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnBlock.cs index c0b91612d..c3278c787 100644 --- a/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnBlock.cs +++ b/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnBlock.cs @@ -17,5 +17,5 @@ public class YarnBlock /// /// Gets child blocks, as dentoed by "{child}:". /// - public IList Children { get; } = new List(); + public IList Children { get; } = []; } diff --git a/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnBlockFile.cs b/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnBlockFile.cs index 5257acf6f..dcfe8dc54 100644 --- a/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnBlockFile.cs +++ b/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnBlockFile.cs @@ -45,7 +45,7 @@ public class YarnBlockFile : IYarnBlockFile private static readonly Regex YarnV2Regex = new Regex("(.*):\\s\"?(.*)", RegexOptions.Compiled); - private readonly IList fileLines = new List(); + private readonly IList fileLines = []; private int fileLineIndex; @@ -73,10 +73,7 @@ private YarnBlockFile(IList parsedFileLines) public static async Task CreateBlockFileAsync(Stream stream) { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } + ArgumentNullException.ThrowIfNull(stream); var fileLines = new List(); using (var reader = new StreamReader(stream)) @@ -111,7 +108,7 @@ private void ReadVersionHeader() do { - if (this.fileLines[this.fileLineIndex].StartsWith("#")) + if (this.fileLines[this.fileLineIndex].StartsWith('#')) { if (this.fileLines[this.fileLineIndex].Contains("yarn lockfile")) { @@ -174,7 +171,7 @@ private YarnBlock ParseBlock(int level = 0) break; } - if (this.fileLines[this.fileLineIndex].EndsWith(":")) + if (this.fileLines[this.fileLineIndex].EndsWith(':')) { block.Children.Add(this.ParseBlock(level + 1)); this.fileLineIndex--; @@ -223,7 +220,7 @@ private bool ReadToNextMajorBlock() line = this.fileLines[this.fileLineIndex]; } } - while (string.IsNullOrWhiteSpace(line) || line.StartsWith(" ") || line.StartsWith("\t") || line.StartsWith("#")); + while (string.IsNullOrWhiteSpace(line) || line.StartsWith(' ') || line.StartsWith('\t') || line.StartsWith('#')); return true; } diff --git a/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnLockParser.cs b/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnLockParser.cs index 51742d656..eb5bfc77e 100644 --- a/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnLockParser.cs +++ b/src/Microsoft.ComponentDetection.Detectors/yarn/Parsers/YarnLockParser.cs @@ -18,7 +18,7 @@ public class YarnLockParser : IYarnLockParser private const string OptionalDependencies = "optionalDependencies"; - private static readonly List SupportedVersions = new List { YarnLockVersion.V1, YarnLockVersion.Berry }; + private static readonly List SupportedVersions = [YarnLockVersion.V1, YarnLockVersion.Berry]; private readonly ILogger logger; @@ -36,13 +36,10 @@ public bool CanParse(YarnLockVersion yarnLockVersion) public YarnLockFile Parse(ISingleFileComponentRecorder singleFileComponentRecorder, IYarnBlockFile fileLines, ILogger logger) { - if (fileLines == null) - { - throw new ArgumentNullException(nameof(fileLines)); - } + ArgumentNullException.ThrowIfNull(fileLines); var file = new YarnLockFile { LockVersion = fileLines.YarnLockVersion, LockfileVersion = fileLines.LockfileVersion }; - IList entries = new List(); + IList entries = []; foreach (var block in fileLines) { diff --git a/src/Microsoft.ComponentDetection.Detectors/yarn/YarnEntry.cs b/src/Microsoft.ComponentDetection.Detectors/yarn/YarnEntry.cs index cb02c5dc0..fbbf7ad47 100644 --- a/src/Microsoft.ComponentDetection.Detectors/yarn/YarnEntry.cs +++ b/src/Microsoft.ComponentDetection.Detectors/yarn/YarnEntry.cs @@ -24,17 +24,17 @@ public class YarnEntry /// /// Gets the satisfied version strings of this entry. /// - public IList Satisfied { get; } = new List(); + public IList Satisfied { get; } = []; /// /// Gets the name@version dependencies that this package requires. /// - public IList Dependencies { get; } = new List(); + public IList Dependencies { get; } = []; /// /// Gets the name@version dependencies that this package requires. /// - public IList OptionalDependencies { get; } = new List(); + public IList OptionalDependencies { get; } = []; /// /// Gets or sets a value indicating whether or not the component is a dev dependency. diff --git a/src/Microsoft.ComponentDetection.Detectors/yarn/YarnLockComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/yarn/YarnLockComponentDetector.cs index f01c291b2..a10993599 100644 --- a/src/Microsoft.ComponentDetection.Detectors/yarn/YarnLockComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/yarn/YarnLockComponentDetector.cs @@ -31,17 +31,17 @@ public YarnLockComponentDetector( public override string Id { get; } = "Yarn"; - public override IList SearchPatterns { get; } = new List { "yarn.lock" }; + public override IList SearchPatterns { get; } = ["yarn.lock"]; - public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Npm }; + public override IEnumerable SupportedComponentTypes { get; } = [ComponentType.Npm]; public override int Version => 8; - public override IEnumerable Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Npm) }; + public override IEnumerable Categories => [Enum.GetName(typeof(DetectorClass), DetectorClass.Npm)]; /// /// "Package" is a more common substring, enclose it with \ to verify it is a folder. - protected override IList SkippedFolders => new List { "node_modules", "pnpm-store", "\\package\\" }; + protected override IList SkippedFolders => ["node_modules", "pnpm-store", "\\package\\"]; protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary detectorArgs) { @@ -193,15 +193,15 @@ private void ParseTreeWithAssignedRoot(YarnEntry root, DictionaryFalse if no package.json file was found at location, otherwise it returns true. private bool TryReadPeerPackageJsonRequestsAsYarnEntries(ISingleFileComponentRecorder singleFileComponentRecorder, string location, Dictionary yarnEntries, out List yarnRoots) { - yarnRoots = new List(); + yarnRoots = []; - var pkgJsons = this.ComponentStreamEnumerableFactory.GetComponentStreams(new FileInfo(location).Directory, new List { "package.json" }, (name, directoryName) => false, recursivelyScanDirectories: false); + var pkgJsons = this.ComponentStreamEnumerableFactory.GetComponentStreams(new FileInfo(location).Directory, ["package.json"], (name, directoryName) => false, recursivelyScanDirectories: false); IDictionary> combinedDependencies = new Dictionary>(); var pkgJsonCount = 0; - IList yarnWorkspaces = new List(); + IList yarnWorkspaces = []; foreach (var pkgJson in pkgJsons) { combinedDependencies = NpmComponentUtilities.TryGetAllPackageJsonDependencies(pkgJson.Stream, out yarnWorkspaces); diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Commands/ScanSettings.cs b/src/Microsoft.ComponentDetection.Orchestrator/Commands/ScanSettings.cs index 1473bc4ac..b10bb39cf 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Commands/ScanSettings.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Commands/ScanSettings.cs @@ -14,7 +14,7 @@ namespace Microsoft.ComponentDetection.Orchestrator.Commands; public class ScanSettings : BaseSettings { [CommandOption("--DirectoryExclusionList")] - [Description("Filters out specific directories following a minimatch pattern.")] + [Description("Filters out specific directories following a semicolon separated list of minimatch patterns.")] [TypeConverter(typeof(SemicolonDelimitedConverter))] public IEnumerable DirectoryExclusionList { get; set; } diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Exceptions/InvalidDetectorCategoriesException.cs b/src/Microsoft.ComponentDetection.Orchestrator/Exceptions/InvalidDetectorCategoriesException.cs index 61bd97649..bb05db7ef 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Exceptions/InvalidDetectorCategoriesException.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Exceptions/InvalidDetectorCategoriesException.cs @@ -1,7 +1,6 @@ namespace Microsoft.ComponentDetection.Orchestrator.Exceptions; using System; -using System.Runtime.Serialization; [Serializable] public class InvalidDetectorCategoriesException : Exception @@ -19,9 +18,4 @@ public InvalidDetectorCategoriesException(string message, Exception innerExcepti : base(message, innerException) { } - - protected InvalidDetectorCategoriesException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Exceptions/InvalidDetectorFilterException.cs b/src/Microsoft.ComponentDetection.Orchestrator/Exceptions/InvalidDetectorFilterException.cs index a00d79668..bc98339de 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Exceptions/InvalidDetectorFilterException.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Exceptions/InvalidDetectorFilterException.cs @@ -1,7 +1,6 @@ namespace Microsoft.ComponentDetection.Orchestrator.Exceptions; using System; -using System.Runtime.Serialization; [Serializable] public class InvalidDetectorFilterException : Exception @@ -19,9 +18,4 @@ public InvalidDetectorFilterException(string message, Exception innerException) : base(message, innerException) { } - - protected InvalidDetectorFilterException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Experiments/DefaultExperimentProcessor.cs b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/DefaultExperimentProcessor.cs index dbe47107f..ee9323d70 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Experiments/DefaultExperimentProcessor.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/DefaultExperimentProcessor.cs @@ -13,6 +13,8 @@ /// public class DefaultExperimentProcessor : IExperimentProcessor { + private static readonly JsonSerializerOptions SerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + private readonly IFileWritingService fileWritingService; private readonly ILogger logger; @@ -34,7 +36,7 @@ public async Task ProcessExperimentAsync(IExperimentConfiguration config, Experi this.logger.LogInformation("Writing experiment {Name} results to {Filename}", config.Name, this.fileWritingService.ResolveFilePath(filename)); - var serializedDiff = JsonSerializer.Serialize(diff, new JsonSerializerOptions { WriteIndented = true }); + var serializedDiff = JsonSerializer.Serialize(diff, SerializerOptions); await this.fileWritingService.WriteFileAsync(filename, serializedDiff); } } diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Experiments/ExperimentService.cs b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/ExperimentService.cs index f372255e9..d21433ba8 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Experiments/ExperimentService.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/ExperimentService.cs @@ -7,7 +7,6 @@ namespace Microsoft.ComponentDetection.Orchestrator.Experiments; using System.Threading.Tasks; using Microsoft.ComponentDetection.Common.DependencyGraph; using Microsoft.ComponentDetection.Contracts; -using Microsoft.ComponentDetection.Contracts.BcdeModels; using Microsoft.ComponentDetection.Orchestrator.Commands; using Microsoft.ComponentDetection.Orchestrator.Experiments.Configs; using Microsoft.ComponentDetection.Orchestrator.Experiments.Models; @@ -77,8 +76,8 @@ public void RecordDetectorRun( var scanResult = this.graphTranslationService.GenerateScanResultFromProcessingResult( new DetectorProcessingResult() { - ComponentRecorders = new[] { (detector, componentRecorder) }, - ContainersDetailsMap = new Dictionary(), + ComponentRecorders = [(detector, componentRecorder)], + ContainersDetailsMap = [], ResultCode = ProcessingResultCode.Success, }, settings, diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentComponent.cs b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentComponent.cs index 9e07fa63f..8ba4a4d66 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentComponent.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentComponent.cs @@ -17,7 +17,7 @@ public ExperimentComponent(ScannedComponent detectedComponent) { this.Id = detectedComponent.Component.Id; this.DevelopmentDependency = detectedComponent.IsDevelopmentDependency ?? false; - this.RootIds = detectedComponent.TopLevelReferrers?.Select(x => x.Id).ToHashSet() ?? new HashSet(); + this.RootIds = detectedComponent.TopLevelReferrers?.Select(x => x.Id).ToHashSet() ?? []; } /// diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentDiff.cs b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentDiff.cs index 1896d3764..53b2a61d8 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentDiff.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentDiff.cs @@ -27,7 +27,7 @@ public ExperimentDiff( { var oldComponentDictionary = controlGroupComponents.DistinctBy(x => x.Id).ToDictionary(x => x.Id); var newComponentDictionary = experimentGroupComponents.DistinctBy(x => x.Id).ToDictionary(x => x.Id); - additionalProperties ??= Array.Empty<(string PropertyKey, string PropertyValue)>(); + additionalProperties ??= []; this.AdditionalProperties = additionalProperties?.Select(kv => new KeyValuePair(kv.PropertyKey, kv.PropertyValue)).ToImmutableList(); this.AddedIds = newComponentDictionary.Keys.Except(oldComponentDictionary.Keys).ToImmutableList(); @@ -74,7 +74,7 @@ public ExperimentDiff( controlDetectorList.Add(new ExperimentDetector(detectorId, detectorRunTime)); } - this.ControlDetectors = controlDetectorList.ToImmutableList(); + this.ControlDetectors = [.. controlDetectorList]; } if (experimentalDetectors != null) @@ -84,7 +84,7 @@ public ExperimentDiff( experimentDetectorList.Add(new ExperimentDetector(detectorId, detectorRunTime)); } - this.ExperimentalDetectors = experimentDetectorList.ToImmutableList(); + this.ExperimentalDetectors = [.. experimentDetectorList]; } this.DevelopmentDependencyChanges = developmentDependencyChanges.AsReadOnly(); diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentResults.cs b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentResults.cs index b3d655f4a..d66df5e24 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentResults.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Models/ExperimentResults.cs @@ -23,7 +23,7 @@ public class ExperimentResults private readonly ConcurrentDictionary experimentalDetectors = new(); - private readonly ConcurrentBag<(string, string)> additionalProperties = new(); + private readonly ConcurrentBag<(string, string)> additionalProperties = []; /// /// The set of components in the control group. diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Extensions/TypeRegistrar.cs b/src/Microsoft.ComponentDetection.Orchestrator/Extensions/TypeRegistrar.cs index 853795ee9..8670b527b 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Extensions/TypeRegistrar.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Extensions/TypeRegistrar.cs @@ -15,7 +15,7 @@ public sealed class TypeRegistrar : ITypeRegistrar, IDisposable public TypeRegistrar(IServiceCollection services) { this.Services = services; - this.BuiltProviders = new List(); + this.BuiltProviders = []; } private IServiceCollection Services { get; } diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Microsoft.ComponentDetection.Orchestrator.csproj b/src/Microsoft.ComponentDetection.Orchestrator/Microsoft.ComponentDetection.Orchestrator.csproj index 81d898362..c9b49a159 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Microsoft.ComponentDetection.Orchestrator.csproj +++ b/src/Microsoft.ComponentDetection.Orchestrator/Microsoft.ComponentDetection.Orchestrator.csproj @@ -2,7 +2,6 @@ - diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Minimatch.cs b/src/Microsoft.ComponentDetection.Orchestrator/Minimatch.cs new file mode 100644 index 000000000..1392651eb --- /dev/null +++ b/src/Microsoft.ComponentDetection.Orchestrator/Minimatch.cs @@ -0,0 +1,859 @@ +/* + This file (and parts of MinimatchTests.cs) is a port of + https://github.com/isaacs/minimatch/commit/cb4be48a55d64b3a40a745d4a8eb4d1b06507277 + + Original license: + The ISC License + + Copyright (c) 2011-2023 Isaac Z. Schlueter and Contributors + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +namespace Microsoft.ComponentDetection.Orchestrator; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +/// +/// A minimal matching utility. +/// +public class Minimatch +{ + // any single thing other than / + // don't need to escape / when using new RegExp() + private const string Qmark = "[^/]"; + + // any single thing other than / + // don't need to escape / when using new RegExp() + private const string Star = Qmark + "*?"; + + // characters that need to be escaped in RegExp. + private static readonly HashSet ReSpecials = new("().*{}+?[]^$\\!".ToCharArray()); + private static readonly Regex SlashSplit = new("/+", RegexOptions.Compiled); + + private static readonly Regex HasBraces = new(@"\{.*\}", RegexOptions.Compiled); + private static readonly Regex NumericSet = new(@"^\{(-?[0-9]+)\.\.(-?[0-9]+)\}", RegexOptions.Compiled); + + // replace stuff like \* with * + private static readonly Regex GlobUnescaper = new(@"\\(.)", RegexOptions.Compiled); + private static readonly Regex EscapeCheck = new(@"((?:\\{2})*)(\\?)\|", RegexOptions.Compiled); + + private readonly bool ignoreCase; + private readonly bool isWindows; + private readonly bool negate; + private readonly bool comment; + private readonly bool empty; + private readonly List> set; + + /// + /// Creates a new Minimatcher instance. + /// + /// The pattern to use for comparision. + /// Ignore casing during comparision. + /// Transform \ to / on both pattern and the input string on comparision. + /// Raised if the pattern is null. + public Minimatch(string pattern, bool ignoreCase, bool allowWindowsPaths) + { + ArgumentNullException.ThrowIfNull(pattern); + + var trimmedPattern = pattern.Trim(); + this.ignoreCase = ignoreCase; + this.isWindows = allowWindowsPaths; + if (allowWindowsPaths) + { + trimmedPattern = trimmedPattern.Replace('\\', '/'); + } + + // empty patterns and comments match nothing. + if (!string.IsNullOrEmpty(trimmedPattern) && trimmedPattern[0] == '#') + { + this.comment = true; + return; + } + + if (string.IsNullOrEmpty(trimmedPattern)) + { + this.empty = true; + return; + } + + // step 1: figure out negation, etc. + var negateOffset = 0; + + for (var i = 0; i < trimmedPattern.Length && trimmedPattern[i] == '!'; i++) + { + this.negate = !this.negate; + negateOffset++; + } + + if (negateOffset > 0) + { + trimmedPattern = trimmedPattern[negateOffset..]; + } + + // step 2: expand braces + var globSet = BraceExpand(trimmedPattern); + + // step 3: now we have a set, so turn each one into a series of path-portion + // matching patterns. + // These will be regexps, except in the case of "**", which is + // set to the GLOBSTAR object for globstar behavior, + // and will not contain any / characters + var globParts = globSet.Select(s => SlashSplit.Split(s)).ToList(); + + // glob --> regexps + this.set = globParts.Select(g => g.Select(t => this.Parse(t, false))) + .Where(g => !g.Contains(null)) + .Select(g => g.Select(t => t.Item1).ToList()) + .ToList(); + } + + /// + /// Compare a string to the pattern given on object creation. + /// + /// String to match against the pattern. + /// True if the input matches the pattern. + public bool IsMatch(string input) + { + if (this.comment) + { + return false; + } + + if (this.empty) + { + return input.Length == 0; + } + + // windows: need to use /, not \ + // On other platforms, \ is a valid (albeit bad) filename char. + if (this.isWindows) + { + input = input.Replace("\\", "/"); + } + + // treat the test path as a set of pathparts. + var segments = SlashSplit.Split(input); + + // just ONE of the pattern sets in this.set needs to match + // in order for it to be valid. If negating, then just one + // match means that we have failed. + // Either way, return on the first hit. + foreach (var pattern in this.set) + { + if (this.MatchOne(segments, pattern)) + { + return !this.negate; + } + } + + return this.negate; + } + + private static IEnumerable BraceExpand(string pattern) + { + if (!HasBraces.IsMatch(pattern)) + { + // shortcut. no need to expand. + return [pattern]; + } + + var escaping = false; + int i; + + // examples and comments refer to this crazy pattern: + // a{b,c{d,e},{f,g}h}x{y,z} + // expected: + // abxy + // abxz + // acdxy + // acdxz + // acexy + // acexz + // afhxy + // afhxz + // aghxy + // aghxz + + // everything before the first \{ is just a prefix. + // So, we pluck that off, and work with the rest, + // and then prepend it to everything we find. + if (pattern[0] != '{') + { + // console.error(pattern) + string prefix = null; + for (i = 0; i < pattern.Length; i++) + { + var c = pattern[i]; + + if (c == '\\') + { + escaping = !escaping; + } + else if (c == '{' && !escaping) + { + prefix = pattern[..i]; + break; + } + } + + // actually no sets, all { were escaped. + if (prefix == null) + { + return [pattern]; + } + + return BraceExpand(pattern[i..]).Select(t => prefix + t); + } + + // now we have something like: + // {b,c{d,e},{f,g}h}x{y,z} + // walk through the set, expanding each part, until + // the set ends. then, we'll expand the suffix. + // If the set only has a single member, then'll put the {} back + + // first, handle numeric sets, since they're easier + var numset = NumericSet.Match(pattern); + if (numset.Success) + { + // console.error("numset", numset[1], numset[2]) + var suf = BraceExpand(pattern[numset.Length..]).ToList(); + int start = int.Parse(numset.Groups[1].Value), + end = int.Parse(numset.Groups[2].Value), + inc = start > end ? -1 : 1; + var retVal = new List(); + for (var w = start; w != end + inc; w += inc) + { + // append all the suffixes + for (var ii = 0; ii < suf.Count; ii++) + { + retVal.Add(w + suf[ii]); + } + } + + return retVal; + } + + // ok, walk through the set + // We hope, somewhat optimistically, that there + // will be a } at the end. + // If the closing brace isn't found, then the pattern is + // interpreted as braceExpand("\\" + pattern) so that + // the leading \{ will be interpreted literally. + var depth = 1; + var set = new List(); + var member = string.Empty; + + for (i = 1; i < pattern.Length && depth > 0; i++) + { + var c = pattern[i]; + + if (escaping) + { + escaping = false; + member += "\\" + c; + } + else + { + switch (c) + { + case '\\': + escaping = true; + continue; + case '{': + depth++; + member += "{"; + continue; + case '}': + depth--; + + // if this closes the actual set, then we're done + if (depth == 0) + { + set.Add(member); + member = string.Empty; + + // pluck off the close-brace + break; + } + + member += c; + continue; + case ',': + if (depth == 1) + { + set.Add(member); + member = string.Empty; + } + else + { + member += c; + } + + continue; + default: + member += c; + continue; + } + } + } + + // now we've either finished the set, and the suffix is + // pattern.substr(i), or we have *not* closed the set, + // and need to escape the leading brace + if (depth != 0) + { + return BraceExpand("\\" + pattern); + } + + // ["b", "c{d,e}","{f,g}h"] -> + // ["b", "cd", "ce", "fh", "gh"] + var addBraces = set.Count == 1; + + set = set.SelectMany(BraceExpand).ToList(); + + if (addBraces) + { + set = set.Select(s => "{" + s + "}").ToList(); + } + + // now attach the suffixes. + // x{y,z} -> ["xy", "xz"] + // console.error("set", set) + // console.error("suffix", pattern.substr(i)) + return BraceExpand(pattern[i..]).SelectMany(s1 => set.Select(s2 => s2 + s1)); + } + + private static string GlobUnescape(string s) => GlobUnescaper.Replace(s, "$1"); + + // parse a component of the expanded set. + // At this point, no pattern may contain "/" in it + // so we're going to return a 2d array, where each entry is the full + // pattern, split on '/', and then turned into a regular expression. + // A regexp is made at the end which joins each array with an + // escaped /, and another full one which joins each regexp with |. + // + // Following the lead of Bash 4.1, note that "**" only has special meaning + // when it is the *only* thing in a path portion. Otherwise, any series + // of * is equivalent to a single *. Globstar behavior is enabled by + // default, and can be disabled by setting options.noglobstar. + private Tuple Parse(string pattern, bool isSub) + { + // shortcuts + if (pattern == "**") + { + return Tuple.Create(GlobStar.Instance, false); + } + + if (pattern.Length == 0) + { + return Tuple.Create(ParseItem.Empty, false); + } + + var re = string.Empty; + var hasMagic = this.ignoreCase; + var escaping = false; + var inClass = false; + + // ? => one single character + var patternListStack = new Stack(); + char plType; + char? stateChar = null; + + int reClassStart = -1, classStart = -1; + + // . and .. never match anything that doesn't start with ., + // even when options.dot is set. + var patternStart = pattern[0] == '.' ? string.Empty // anything not (start or / followed by . or .. followed by / or end) + : "(?!\\.)"; + + void ClearStateChar() + { + if (stateChar != null) + { + // we had some state-tracking character + // that wasn't consumed by this pass. + switch (stateChar) + { + case '*': + re += Star; + hasMagic = true; + break; + case '?': + re += Qmark; + hasMagic = true; + break; + default: + re += "\\" + stateChar; + break; + } + + stateChar = null; + } + } + + for (var i = 0; i < pattern.Length; i++) + { + var c = pattern[i]; + + // skip over any that are escaped. + if (escaping && ReSpecials.Contains(c)) + { + re += "\\" + c; + escaping = false; + continue; + } + + switch (c) + { + case '/': + // completely not allowed, even escaped. + // Should already be path-split by now. + return null; + + case '\\': + ClearStateChar(); + escaping = true; + continue; + + // the various stateChar values + // for the 'extglob' stuff. + case '?': + case '*': + case '+': + case '@': + case '!': + // all of those are literals inside a class, except that + // the glob [!a] means [^a] in regexp + if (inClass) + { + if (c == '!' && i == classStart + 1) + { + c = '^'; + } + + re += c; + continue; + } + + // if we already have a stateChar, then it means + // that there was something like ** or +? in there. + // Handle the stateChar, then proceed with this one. + ClearStateChar(); + stateChar = c; + continue; + case '(': + if (inClass) + { + re += "("; + continue; + } + + if (stateChar == null) + { + re += "\\("; + continue; + } + + plType = stateChar.Value; + patternListStack.Push(new PatternListEntry { Type = plType, Start = i - 1, ReStart = re.Length }); + + // negation is (?:(?!js)[^/]*) + re += stateChar == '!' ? "(?:(?!" : "(?:"; + stateChar = null; + continue; + + case ')': + if (inClass || patternListStack.Count == 0) + { + re += "\\)"; + continue; + } + + hasMagic = true; + re += ')'; + plType = patternListStack.Pop().Type; + + // negation is (?:(?!js)[^/]*) + // The others are (?:) + switch (plType) + { + case '!': + re += "[^/]*?)"; + break; + case '?': + case '+': + case '*': + re += plType; + break; + case '@': + break; // the default anyway + default: + break; + } + + continue; + + case '|': + if (inClass || patternListStack.Count == 0 || escaping) + { + re += "\\|"; + escaping = false; + continue; + } + + re += "|"; + continue; + + // these are mostly the same in regexp and glob + case '[': + // swallow any state-tracking char before the [ + ClearStateChar(); + + if (inClass) + { + re += "\\" + c; + continue; + } + + inClass = true; + classStart = i; + reClassStart = re.Length; + re += c; + continue; + + case ']': + // a right bracket shall lose its special + // meaning and represent itself in + // a bracket expression if it occurs + // first in the list. -- POSIX.2 2.8.3.2 + if (i == classStart + 1 || !inClass) + { + re += "\\" + c; + escaping = false; + continue; + } + + // finish up the class. + hasMagic = true; + inClass = false; + re += c; + continue; + + default: + // swallow any state char that wasn't consumed + ClearStateChar(); + + if (escaping) + { + // no need + escaping = false; + } + else if (ReSpecials.Contains(c) && !(c == '^' && inClass)) + { + re += "\\"; + } + + re += c; + break; + } + } + + // handle the case where we left a class open. + // "[abc" is valid, equivalent to "\[abc" + if (inClass) + { + // split where the last [ was, and escape it + // this is a huge pita. We now have to re-walk + // the contents of the would-be class to re-translate + // any characters that were passed through as-is + var cs = pattern[(classStart + 1)..]; + var sp = this.Parse(cs, true); + re = re[..reClassStart] + "\\[" + sp.Item1.Source; + hasMagic = hasMagic || sp.Item2; + } + + // handle the case where we had a +( thing at the *end* + // of the pattern. + // each pattern list stack adds 3 chars, and we need to go through + // and escape any | chars that were passed through as-is for the regexp. + // Go through and escape them, taking care not to double-escape any + // | chars that were already escaped. + while (patternListStack.Count != 0) + { + var pl = patternListStack.Pop(); + var tail = re[(pl.ReStart + 3)..]; + + // maybe some even number of \, then maybe 1 \, followed by a | + tail = EscapeCheck.Replace(tail, m => + { + var escape = m.Groups[2].Value; + if (string.IsNullOrEmpty(escape)) + { + escape = "\\"; + } + + // need to escape all those slashes *again*, without escaping the + // one that we need for escaping the | character. As it works out, + // escaping an even number of slashes can be done by simply repeating + // it exactly after itself. That's why this trick works. + // + // I am sorry that you have to see this. + return m.Groups[1].Value + m.Groups[1].Value + escape + "|"; + }); + + // console.error("tail=%j\n %s", tail, tail) + var t = pl.Type == '*' ? Star + : pl.Type == '?' ? Qmark + : "\\" + pl.Type; + + hasMagic = true; + re = re.Remove(pl.ReStart) + + t + "\\(" + + tail; + } + + // handle trailing things that only matter at the very end. + ClearStateChar(); + if (escaping) + { + // trailing \\ + re += "\\\\"; + } + + // only need to apply the nodot start if the re starts with + // something that could conceivably capture a dot + var addPatternStart = re[0] switch + { + '.' or '[' or '(' => true, + _ => false, + }; + + // if the re is not string.Empty at this point, then we need to make sure + // it doesn't match against an empty path part. + // Otherwise a/* will match a/, which it should not. + if (re.Length != 0 && hasMagic) + { + re = "(?=.)" + re; + } + + if (addPatternStart) + { + re = patternStart + re; + } + + // parsing just a piece of a larger pattern. + if (isSub) + { + return Tuple.Create(ParseItem.Literal(re), hasMagic); + } + + // skip the regexp for non-magical patterns + // unescape anything in it, though, so that it'll be + // an exact match against a file etc. + if (!hasMagic) + { + return Tuple.Create(ParseItem.Literal(GlobUnescape(pattern)), false); + } + + return new Tuple(new MagicItem(re, this.ignoreCase), false); + } + + private bool MatchOne(IList segments, IList patterns) + { + var segmentIndex = 0; + var patternIndex = 0; + for (; segmentIndex < segments.Count && patternIndex < patterns.Count; segmentIndex++, patternIndex++) + { + var pattern = patterns[patternIndex]; + var file = segments[segmentIndex]; + + // should be impossible. + // some invalid regexp stuff in the set. + if (pattern == null) + { + return false; + } + + if (pattern is GlobStar) + { + // "**" + // a/**/b/**/c would match the following: + // a/b/x/y/z/c + // a/x/y/z/b/c + // a/b/x/b/x/c + // a/b/c + // To do this, take the rest of the pattern after + // the **, and see if it would match the file remainder. + // If so, return success. + // If not, the ** "swallows" a segment, and try again. + // This is recursively awful. + // + // a/**/b/**/c matching a/b/x/y/z/c + // - a matches a + // - doublestar + // - matchOne(b/x/y/z/c, b/**/c) + // - b matches b + // - doublestar + // - matchOne(x/y/z/c, c) -> no + // - matchOne(y/z/c, c) -> no + // - matchOne(z/c, c) -> no + // - matchOne(c, c) yes, hit + var innerPatternIndex = patternIndex + 1; + if (innerPatternIndex == patterns.Count) + { + // a ** at the end will just swallow the rest. + // We have found a match. + // however, it will not swallow /.x, unless + // options.dot is set. + // . and .. are *never* matched by **, for explosively + // exponential reasons. + for (; segmentIndex < segments.Count; segmentIndex++) + { + if (segments[segmentIndex] == "." || segments[segmentIndex] == ".." || + (!string.IsNullOrEmpty(segments[segmentIndex]) && segments[segmentIndex][0] == '.')) + { + return false; + } + } + + return true; + } + + // ok, let's see if we can swallow whatever we can. + for (var i = segmentIndex; i < segments.Count; i++) + { + var swallowee = segments[i]; + + // XXX remove this slice. Just pass the start index. + if (this.MatchOne(segments.Skip(i).ToList(), patterns.Skip(innerPatternIndex).ToList())) + { + // found a match. + return true; + } + + // can't swallow "." or ".." ever. + if (swallowee.StartsWith('.') || swallowee == "..") + { + break; + } + + // ** swallows a segment, and continue. + } + + return false; + } + + // something other than ** + // non-magic patterns just have to match exactly + // patterns with magic have been turned into regexps. + if (!pattern.Match(file, this.ignoreCase)) + { + return false; + } + } + + // Note: ending in / means that we'll get a final string.Empty + // at the end of the pattern. This can only match a + // corresponding string.Empty at the end of the file. + // If the file ends in /, then it can only match a + // a pattern that ends in /, unless the pattern just + // doesn't have any more for it. But, a/b/ should *not* + // match "a/b/*", even though string.Empty matches against the + // [^/]*? pattern, except in partial mode, where it might + // simply not be reached yet. + // However, a/b/ should still satisfy a/* + + // now either we fell off the end of the pattern, or we're done. + if (segmentIndex == segments.Count && patternIndex == patterns.Count) + { + // ran out of pattern and filename at the same time. + // an exact hit! + return true; + } + + if (segmentIndex == segments.Count) + { + // ran out of file, but still had pattern left. + // this is ok if we're doing the match as part of + // a glob fs traversal. + return false; + } + + if (patternIndex == patterns.Count) + { + // ran out of pattern, still have file left. + // this is only acceptable if we're on the very last + // empty segment of a file with a trailing slash. + // a/* should match a/b/ + var emptyFileEnd = segmentIndex == segments.Count - 1 && segments[segmentIndex].Length == 0; + return emptyFileEnd; + } + + throw new InvalidOperationException("This shouldn't happen unless there is a logic bug."); + } + + private abstract class ParseItem + { + public static readonly ParseItem Empty = new LiteralItem(string.Empty); + + public string Source { get; protected init; } + + public static ParseItem Literal(string source) => new LiteralItem(source); + + public abstract bool Match(string input, bool ignoreCase); + } + + private class LiteralItem : ParseItem + { + public LiteralItem(string source) => this.Source = source; + + public override bool Match(string input, bool ignoreCase) => input.Equals(this.Source, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + } + + private class MagicItem : ParseItem + { + private readonly Lazy regex; + + public MagicItem(string source, bool ignoreCase) + { + this.Source = source; + this.regex = new Lazy(() => + { + var regexOptions = ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None; + return new Regex("^" + source + "$", regexOptions); + }); + } + + public override bool Match(string input, bool ignoreCase) => this.regex.Value.IsMatch(input); + } + + private class GlobStar : ParseItem + { + public static readonly ParseItem Instance = new GlobStar(); + + public override bool Match(string input, bool ignoreCase) => throw new NotSupportedException(); + } + + private class PatternListEntry + { + public char Type { get; set; } + + public int Start { get; set; } + + public int ReStart { get; set; } + } +} diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Services/DetectorProcessingService.cs b/src/Microsoft.ComponentDetection.Orchestrator/Services/DetectorProcessingService.cs index 6e827e199..8524dbb0f 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Services/DetectorProcessingService.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Services/DetectorProcessingService.cs @@ -8,7 +8,6 @@ namespace Microsoft.ComponentDetection.Orchestrator.Services; using System.Linq; using System.Threading; using System.Threading.Tasks; -using DotNet.Globbing; using Microsoft.ComponentDetection.Common; using Microsoft.ComponentDetection.Common.DependencyGraph; using Microsoft.ComponentDetection.Common.Telemetry.Records; @@ -217,20 +216,9 @@ public ExcludeDirectoryPredicate GenerateDirectoryExclusionPredicate(string orig }; } - var minimatchers = new Dictionary(); - - var globOptions = new GlobOptions() - { - Evaluation = new EvaluationOptions() - { - CaseInsensitive = ignoreCase, - }, - }; - - foreach (var directoryExclusion in directoryExclusionList) - { - minimatchers.Add(directoryExclusion, Glob.Parse(allowWindowsPaths ? directoryExclusion : /* [] escapes special chars */ directoryExclusion.Replace("\\", "[\\]"), globOptions)); - } + var minimatchers = directoryExclusionList.ToDictionary( + directoryExclusion => directoryExclusion, + directoryExclusion => new Minimatch(directoryExclusion, ignoreCase, allowWindowsPaths)); return (name, directoryName) => { @@ -253,7 +241,7 @@ private IndividualDetectorScanResult CoalesceResult(IndividualDetectorScanResult { individualDetectorScanResult ??= new IndividualDetectorScanResult(); - individualDetectorScanResult.ContainerDetails ??= Enumerable.Empty(); + individualDetectorScanResult.ContainerDetails ??= []; // Additional telemetry details can safely be null return individualDetectorScanResult; @@ -336,13 +324,13 @@ private void LogTabularOutput(ConcurrentDictionary pr AnsiConsole.Write(table); - var tsf = new TabularStringFormat(new Column[] - { + var tsf = new TabularStringFormat( + [ new Column { Header = "Component Detector Id", Width = 30 }, new Column { Header = "Detection Time", Width = 30, Format = "{0:g2} seconds" }, new Column { Header = "# Components Found", Width = 30, }, new Column { Header = "# Explicitly Referenced", Width = 40 }, - }); + ]); var rows = providerElapsedTime.OrderBy(a => a.Key).Select(x => { @@ -356,13 +344,13 @@ private void LogTabularOutput(ConcurrentDictionary pr }; }).ToList(); - rows.Add(new object[] - { + rows.Add( + [ "Total", totalElapsedTime, providerElapsedTime.Sum(x => x.Value.ComponentsFoundCount), providerElapsedTime.Sum(x => x.Value.ExplicitlyReferencedComponentCount), - }); + ]); foreach (var line in tsf.GenerateString(rows).Split(new[] { NewLine }, StringSplitOptions.None)) { diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Services/DetectorRestrictionService.cs b/src/Microsoft.ComponentDetection.Orchestrator/Services/DetectorRestrictionService.cs index 7f5d8a0dc..6d6f80732 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Services/DetectorRestrictionService.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Services/DetectorRestrictionService.cs @@ -9,7 +9,7 @@ public class DetectorRestrictionService : IDetectorRestrictionService { - private readonly IList oldDetectorIds = new List { "MSLicenseDevNpm", "MSLicenseDevNpmList", "MSLicenseNpm", "MSLicenseNpmList" }; + private readonly IList oldDetectorIds = ["MSLicenseDevNpm", "MSLicenseDevNpmList", "MSLicenseNpm", "MSLicenseNpmList"]; private readonly string newDetectorId = "NpmWithRoots"; private readonly ILogger logger; @@ -30,10 +30,10 @@ public IEnumerable ApplyRestrictions(DetectorRestrictions re // If we have retired detectors in the arg specified list and don't have the new detector, add the new detector if (allowedIds.Any(a => this.oldDetectorIds.Contains(a, StringComparer.OrdinalIgnoreCase)) && !allowedIds.Contains(this.newDetectorId, StringComparer.OrdinalIgnoreCase)) { - allowedIds = allowedIds.Concat(new string[] - { + allowedIds = allowedIds.Concat( + [ this.newDetectorId, - }); + ]); } detectors = detectors.Where(d => allowedIds.Contains(d.Id, StringComparer.OrdinalIgnoreCase)).ToList(); diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Services/GraphTranslation/DefaultGraphTranslationService.cs b/src/Microsoft.ComponentDetection.Orchestrator/Services/GraphTranslation/DefaultGraphTranslationService.cs index a3fa0f600..6998bc4d4 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Services/GraphTranslation/DefaultGraphTranslationService.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Services/GraphTranslation/DefaultGraphTranslationService.cs @@ -60,7 +60,7 @@ private void LogComponentScopeTelemetry(List components) }); } - private IEnumerable GatherSetOfDetectedComponentsUnmerged(IEnumerable<(IComponentDetector Detector, ComponentRecorder Recorder)> recorderDetectorPairs, DirectoryInfo rootDirectory, bool updateLocations) + private List GatherSetOfDetectedComponentsUnmerged(IEnumerable<(IComponentDetector Detector, ComponentRecorder Recorder)> recorderDetectorPairs, DirectoryInfo rootDirectory, bool updateLocations) { return recorderDetectorPairs .Where(recorderDetectorPair => recorderDetectorPair.Recorder != null) @@ -76,7 +76,7 @@ private IEnumerable GatherSetOfDetectedComponentsUnmerged(IEn foreach (var component in detectedComponents) { // clone custom locations and make them relative to root. - var declaredRawFilePaths = component.FilePaths ?? new HashSet(); + var declaredRawFilePaths = component.FilePaths ?? []; var componentCustomLocations = JsonConvert.DeserializeObject>(JsonConvert.SerializeObject(declaredRawFilePaths)); component.FilePaths?.Clear(); @@ -242,7 +242,7 @@ private HashSet MakeFilePathsRelative(ILogger logger, DirectoryInfo root try { var relativePath = rootUri.MakeRelativeUri(new Uri(path)).ToString(); - if (!relativePath.StartsWith("/")) + if (!relativePath.StartsWith('/')) { relativePath = "/" + relativePath; } diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Services/GraphTranslation/GraphTranslationUtility.cs b/src/Microsoft.ComponentDetection.Orchestrator/Services/GraphTranslation/GraphTranslationUtility.cs index 7fb2834d1..8259f2626 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Services/GraphTranslation/GraphTranslationUtility.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Services/GraphTranslation/GraphTranslationUtility.cs @@ -23,10 +23,10 @@ public static DependencyGraphCollection AccumulateAndConvertToContract(IEnumerab { model[graphByLocation.Key] = graphWithMetadata = new DependencyGraphWithMetadata { - ExplicitlyReferencedComponentIds = new HashSet(), - Graph = new DependencyGraph(), - DevelopmentDependencies = new HashSet(), - Dependencies = new HashSet(), + ExplicitlyReferencedComponentIds = [], + Graph = [], + DevelopmentDependencies = [], + Dependencies = [], }; } @@ -37,13 +37,13 @@ public static DependencyGraphCollection AccumulateAndConvertToContract(IEnumerab // We set dependencies to null basically to make the serialized output look more consistent (instead of empty arrays). If another location gets merged that has dependencies, it needs to create and set the key to non-null. if (!graphWithMetadata.Graph.TryGetValue(componentId, out var dependencies)) { - dependencies = componentDependencies != null && componentDependencies.Any() ? new HashSet() : null; + dependencies = componentDependencies != null && componentDependencies.Any() ? [] : null; graphWithMetadata.Graph[componentId] = dependencies; } else if (dependencies == null && componentDependencies != null && componentDependencies.Any()) { // The explicit case where new data is found in a later graph for a given component at a location, and it is adding dependencies. - graphWithMetadata.Graph[componentId] = dependencies = new HashSet(); + graphWithMetadata.Graph[componentId] = dependencies = []; } foreach (var dependentComponentId in componentDependencies) diff --git a/src/Microsoft.ComponentDetection/Program.cs b/src/Microsoft.ComponentDetection/Program.cs index 2c9134aec..4f25e99d1 100644 --- a/src/Microsoft.ComponentDetection/Program.cs +++ b/src/Microsoft.ComponentDetection/Program.cs @@ -62,10 +62,8 @@ config.AddCommand("scan") .WithDescription("Initiates a scan"); - config.SetExceptionHandler((e) => - { - logger.LogError(e, "An error occurred while executing the command"); - }); + + config.SetExceptionHandler((e, _) => logger.LogError(e, "An error occurred while executing the command")); }); var result = await app.RunAsync(args).ConfigureAwait(false); diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 6d7eee3be..c4f2aee05 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,6 +2,10 @@ + + true + + diff --git a/test/Microsoft.ComponentDetection.Common.Tests/AsyncExceptionTests.cs b/test/Microsoft.ComponentDetection.Common.Tests/AsyncExceptionTests.cs index 7bd941c4e..82e323e97 100644 --- a/test/Microsoft.ComponentDetection.Common.Tests/AsyncExceptionTests.cs +++ b/test/Microsoft.ComponentDetection.Common.Tests/AsyncExceptionTests.cs @@ -24,13 +24,13 @@ public async Task ExecuteWithTimeoutAsync_ThrowsNullExceptionAsync() [TestMethod] public async Task ExecuteWithoutTimeAsync_ThrowsTimeoutExceptionAsync() { - var toExecute = async () => + static async Task ToExecuteAsync() { await Task.Delay(5000); return 0; - }; + } - var func = async () => await AsyncExecution.ExecuteWithTimeoutAsync(toExecute, TimeSpan.FromSeconds(1), CancellationToken.None); + var func = async () => await AsyncExecution.ExecuteWithTimeoutAsync(ToExecuteAsync, TimeSpan.FromSeconds(1), CancellationToken.None); await func.Should().ThrowAsync(); } @@ -48,9 +48,9 @@ public async Task ExecuteVoidWithTimeoutAsync_ThrowsNullExceptionAsync() [TestMethod] public async Task ExecuteVoidWithTimeoutAsync_ThrowsTimeoutExceptionAsync() { - var toExecute = () => Task.Delay(5000).Wait(); + static void ToExecute() => Task.Delay(5000).Wait(); - var func = async () => await AsyncExecution.ExecuteVoidWithTimeoutAsync(toExecute, TimeSpan.FromSeconds(1), CancellationToken.None); + var func = async () => await AsyncExecution.ExecuteVoidWithTimeoutAsync(ToExecute, TimeSpan.FromSeconds(1), CancellationToken.None); await func.Should().ThrowAsync(); } diff --git a/test/Microsoft.ComponentDetection.Common.Tests/BaseDetectionTelemetryRecordTests.cs b/test/Microsoft.ComponentDetection.Common.Tests/BaseDetectionTelemetryRecordTests.cs index c8709e01f..baa81598e 100644 --- a/test/Microsoft.ComponentDetection.Common.Tests/BaseDetectionTelemetryRecordTests.cs +++ b/test/Microsoft.ComponentDetection.Common.Tests/BaseDetectionTelemetryRecordTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Common.Tests; +namespace Microsoft.ComponentDetection.Common.Tests; using System; using System.Collections.Generic; @@ -41,22 +41,17 @@ public void UniqueRecordNames() recordName.Should().NotBeNullOrEmpty($"RecordName not set for {type.FullName}!"); - if (dic.TryGetValue(recordName, out var value)) - { - Assert.Fail($"Duplicate RecordName:`{recordName}` found for {type.FullName} and {value.FullName}!"); - } - else - { - dic.Add(recordName, type); - } + dic.Should().NotContainKey(recordName, "Duplicate RecordName:`{RecordName}` found for {TypeName}!", recordName, type.FullName); + + dic.Add(recordName, type); } } [TestMethod] public void SerializableProperties() { - var serializableTypes = new HashSet(new[] - { + var serializableTypes = new HashSet( + [ typeof(string), typeof(string[]), typeof(bool), @@ -64,16 +59,15 @@ public void SerializableProperties() typeof(int?), typeof(TimeSpan?), typeof(HttpStatusCode), - }); + ]); foreach (var type in this.recordTypes) { foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { - if (!serializableTypes.Contains(property.PropertyType) && - Attribute.GetCustomAttribute(property.PropertyType, typeof(DataContractAttribute)) == null) + if (!serializableTypes.Contains(property.PropertyType)) { - Assert.Fail( + Attribute.GetCustomAttribute(property.PropertyType, typeof(DataContractAttribute)).Should().NotBeNull( $"Type {property.PropertyType} on {type.Name}.{property.Name} is not allowed! " + "Add it to the list if it serializes properly to JSON!"); } diff --git a/test/Microsoft.ComponentDetection.Common.Tests/CommandLineInvocationServiceTests.cs b/test/Microsoft.ComponentDetection.Common.Tests/CommandLineInvocationServiceTests.cs index 913248af9..b12b05af7 100644 --- a/test/Microsoft.ComponentDetection.Common.Tests/CommandLineInvocationServiceTests.cs +++ b/test/Microsoft.ComponentDetection.Common.Tests/CommandLineInvocationServiceTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Common.Tests; +namespace Microsoft.ComponentDetection.Common.Tests; using System; using System.IO; @@ -31,14 +31,14 @@ public async Task ShowsCmdExeAsExecutableAsync() [SkipTestIfNotWindows] public async Task FallbackWorksIfBadCommandsAreFirstAsync() { - var result = await this.commandLineService.CanCommandBeLocatedAsync("57AB44A4-885A-47F4-866C-41417133B983", new[] { "fakecommandexecutable.exe", "cmd.exe" }, "/C"); + var result = await this.commandLineService.CanCommandBeLocatedAsync("57AB44A4-885A-47F4-866C-41417133B983", ["fakecommandexecutable.exe", "cmd.exe"], "/C"); result.Should().BeTrue(); } [SkipTestIfNotWindows] public async Task ReturnsFalseIfNoValidCommandIsFoundAsync() { - var result = await this.commandLineService.CanCommandBeLocatedAsync("57AB44A4-885A-47F4-866C-41417133B983", new[] { "fakecommandexecutable.exe" }, "/C"); + var result = await this.commandLineService.CanCommandBeLocatedAsync("57AB44A4-885A-47F4-866C-41417133B983", ["fakecommandexecutable.exe"], "/C"); result.Should().BeFalse(); } diff --git a/test/Microsoft.ComponentDetection.Common.Tests/ComponentStreamEnumerableTests.cs b/test/Microsoft.ComponentDetection.Common.Tests/ComponentStreamEnumerableTests.cs index 4dab2cb36..38f0a2cc4 100644 --- a/test/Microsoft.ComponentDetection.Common.Tests/ComponentStreamEnumerableTests.cs +++ b/test/Microsoft.ComponentDetection.Common.Tests/ComponentStreamEnumerableTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Common.Tests; +namespace Microsoft.ComponentDetection.Common.Tests; using System; using System.IO; @@ -27,8 +27,7 @@ public void GetEnumerator_WorksOverExpectedFiles() var tempFileOne = Path.GetTempFileName(); var tempFileTwo = Path.GetTempFileName(); var enumerable = new ComponentStreamEnumerable( - new[] - { + [ new MatchedFile { File = new FileInfo(tempFileOne), @@ -39,7 +38,7 @@ public void GetEnumerator_WorksOverExpectedFiles() File = new FileInfo(tempFileTwo), Pattern = "Some Pattern", }, - }, + ], this.loggerMock.Object); enumerable.Should().HaveCount(2); @@ -68,8 +67,7 @@ public void GetEnumerator_LogsAndBreaksEnumerationWhenFileIsMissing() It.IsAny(), It.IsAny>())); var enumerable = new ComponentStreamEnumerable( - new[] - { + [ new MatchedFile { File = new FileInfo(tempFileOne), @@ -80,7 +78,7 @@ public void GetEnumerator_LogsAndBreaksEnumerationWhenFileIsMissing() File = new FileInfo(tempFileTwo), Pattern = "Some Pattern", }, - }, + ], this.loggerMock.Object).ToList(); enumerable.Should().ContainSingle(); diff --git a/test/Microsoft.ComponentDetection.Common.Tests/DockerServiceTests.cs b/test/Microsoft.ComponentDetection.Common.Tests/DockerServiceTests.cs index 5911079f6..b5934b36f 100644 --- a/test/Microsoft.ComponentDetection.Common.Tests/DockerServiceTests.cs +++ b/test/Microsoft.ComponentDetection.Common.Tests/DockerServiceTests.cs @@ -1,7 +1,6 @@ namespace Microsoft.ComponentDetection.Common.Tests; using System; -using System.Collections.Generic; using System.Threading.Tasks; using FluentAssertions; using Microsoft.ComponentDetection.TestsUtilities; @@ -76,7 +75,7 @@ public async Task DockerService_PopulatesBaseImageAndLayerDetailsAsync() [SkipTestOnWindows] public async Task DockerService_CanCreateAndRunImageAsync() { - var (stdout, stderr) = await this.dockerService.CreateAndRunContainerAsync(TestImage, new List()); + var (stdout, stderr) = await this.dockerService.CreateAndRunContainerAsync(TestImage, []); stdout.Should().StartWith("\nHello from Docker!"); stderr.Should().BeEmpty(); } diff --git a/test/Microsoft.ComponentDetection.Common.Tests/FileEnumerationTests.cs b/test/Microsoft.ComponentDetection.Common.Tests/FileEnumerationTests.cs index c8420d9ec..db38b99cf 100644 --- a/test/Microsoft.ComponentDetection.Common.Tests/FileEnumerationTests.cs +++ b/test/Microsoft.ComponentDetection.Common.Tests/FileEnumerationTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Common.Tests; +namespace Microsoft.ComponentDetection.Common.Tests; using System; using System.Collections.Generic; @@ -20,13 +20,14 @@ public void CanListAllFiles() var testDirectory = Environment.GetEnvironmentVariable("COMPONENT_DETECTION_SYMLINK_TEST"); if (string.IsNullOrWhiteSpace(testDirectory)) { - Assert.Inconclusive("Test directory environment variable isn't set. Not testing"); + // Test directory environment variable isn't set. Not testing. + return; } var loggerMock = new Mock>(); var pathUtility = new PathUtilityService(loggerMock.Object); - var sfe = new SafeFileEnumerable(new DirectoryInfo(Path.Combine(testDirectory, "root")), new[] { "*" }, loggerMock.Object, pathUtility, (name, directoryName) => false, true); + var sfe = new SafeFileEnumerable(new DirectoryInfo(Path.Combine(testDirectory, "root")), ["*"], loggerMock.Object, pathUtility, (name, directoryName) => false, true); var foundFiles = new List(); foreach (var f in sfe) diff --git a/test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs b/test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs index 574863c71..4779fdaff 100644 --- a/test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs +++ b/test/Microsoft.ComponentDetection.Common.Tests/PatternMatchingUtilityTests.cs @@ -14,7 +14,7 @@ public void PatternMatcher_Matches_StartsWith() var pattern = "test*"; var input = "test123"; - var matcher = PatternMatchingUtility.GetFilePatternMatcher(new[] { pattern }); + var matcher = PatternMatchingUtility.GetFilePatternMatcher([pattern]); matcher(input).Should().BeTrue(); matcher("123test").Should().BeFalse(); @@ -26,7 +26,7 @@ public void PatternMatcher_Matches_EndsWith() var pattern = "*test"; var input = "123test"; - var matcher = PatternMatchingUtility.GetFilePatternMatcher(new[] { pattern }); + var matcher = PatternMatchingUtility.GetFilePatternMatcher([pattern]); matcher(input).Should().BeTrue(); matcher("test123").Should().BeFalse(); @@ -38,7 +38,7 @@ public void PatternMatcher_Matches_Exact() var pattern = "test"; var input = "test"; - var matcher = PatternMatchingUtility.GetFilePatternMatcher(new[] { pattern }); + var matcher = PatternMatchingUtility.GetFilePatternMatcher([pattern]); matcher(input).Should().BeTrue(); matcher("123test").Should().BeFalse(); diff --git a/test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs b/test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs index 632217c88..1579128ca 100644 --- a/test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs +++ b/test/Microsoft.ComponentDetection.Common.Tests/SafeFileEnumerableTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Common.Tests; +namespace Microsoft.ComponentDetection.Common.Tests; using System; using System.Collections.Generic; @@ -47,7 +47,7 @@ public void GetEnumerator_WorksOverExpectedFiles() File.Create(file0).Close(); File.Create(subFile0).Close(); - IEnumerable searchPatterns = new List { name }; + IEnumerable searchPatterns = [name]; this.pathUtilityServiceMock.Setup(x => x.ResolvePhysicalPath(It.IsAny())).Returns((s) => s); this.pathUtilityServiceMock.Setup(x => x.MatchesPattern(name, name)).Returns(true); @@ -75,7 +75,7 @@ public void GetEnumerator_IgnoresSubDirectories() File.Create(file0).Close(); File.Create(Path.Combine(this.temporaryDirectory, "SubDir", name)).Close(); - IEnumerable searchPatterns = new List { name }; + IEnumerable searchPatterns = [name]; this.pathUtilityServiceMock.Setup(x => x.MatchesPattern(name, name)).Returns(true); @@ -101,7 +101,7 @@ public void GetEnumerator_CallsSymlinkCode() File.Create(Path.Combine(this.temporaryDirectory, name)).Close(); File.Create(Path.Combine(this.temporaryDirectory, "SubDir", name)).Close(); - IEnumerable searchPatterns = new List { name }; + IEnumerable searchPatterns = [name]; this.pathUtilityServiceMock.Setup(x => x.ResolvePhysicalPath(subDir.FullName)).Returns(subDir.FullName); var enumerable = new SafeFileEnumerable(new DirectoryInfo(this.temporaryDirectory), searchPatterns, this.loggerMock.Object, this.pathUtilityServiceMock.Object, (directoryName, span) => false, true); @@ -132,7 +132,7 @@ public void GetEnumerator_DuplicatePathIgnored() this.pathUtilityServiceMock.Setup(x => x.ResolvePhysicalPath(subDir.FullName)).Returns(subDir.FullName); this.pathUtilityServiceMock.Setup(x => x.ResolvePhysicalPath(symlink)).Returns(subDir.FullName); - IEnumerable searchPatterns = new List { name }; + IEnumerable searchPatterns = [name]; var enumerable = new SafeFileEnumerable(new DirectoryInfo(this.temporaryDirectory), searchPatterns, this.loggerMock.Object, this.pathUtilityServiceMock.Object, (directoryName, span) => false, true); diff --git a/test/Microsoft.ComponentDetection.Common.Tests/TabularStringFormatTests.cs b/test/Microsoft.ComponentDetection.Common.Tests/TabularStringFormatTests.cs index 08457b4fa..8d08dbb65 100644 --- a/test/Microsoft.ComponentDetection.Common.Tests/TabularStringFormatTests.cs +++ b/test/Microsoft.ComponentDetection.Common.Tests/TabularStringFormatTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Common.Tests; +namespace Microsoft.ComponentDetection.Common.Tests; using System; using System.Linq; @@ -17,18 +17,18 @@ public class TabularStringFormatTests [TestInitialize] public void TestInitialize() { - this.columns = new Column[] - { + this.columns = + [ new Column { Header = "ColumnA", Width = 50, Format = null }, new Column { Header = "ColumnB", Width = 60, Format = "prefix{0}suffix" }, new Column { Header = "ColumnC", Width = 30, Format = null }, - }; + ]; - this.rows = new[] - { - // One row - new[] { "a", "b", "c" }, - }; + // One row + this.rows = + [ + ["a", "b", "c"], + ]; this.tsf = new TabularStringFormat(this.columns); } @@ -82,7 +82,7 @@ public void GenerateString_RowContentsAreWritten() public void GenerateString_ThrowsInvalidOperationException() { // add an extra row - this.rows = this.rows.Concat(new[] { new[] { "a", "b", "c", "d" } }).ToArray(); + this.rows = this.rows.Concat([["a", "b", "c", "d"]]).ToArray(); var action = () => this.tsf.GenerateString(this.rows); diff --git a/test/Microsoft.ComponentDetection.Contracts.Tests/ScanResultSerializationTests.cs b/test/Microsoft.ComponentDetection.Contracts.Tests/ScanResultSerializationTests.cs index 526b65868..c5e99c779 100644 --- a/test/Microsoft.ComponentDetection.Contracts.Tests/ScanResultSerializationTests.cs +++ b/test/Microsoft.ComponentDetection.Contracts.Tests/ScanResultSerializationTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Contracts.Tests; +namespace Microsoft.ComponentDetection.Contracts.Tests; using System.Linq; using FluentAssertions; @@ -21,37 +21,37 @@ public void TestInitialize() this.scanResultUnderTest = new ScanResult { ResultCode = ProcessingResultCode.PartialSuccess, - ComponentsFound = new[] - { + ComponentsFound = + [ new ScannedComponent { Component = new NpmComponent("SampleNpmComponent", "1.2.3"), DetectorId = "NpmDetectorId", IsDevelopmentDependency = true, DependencyScope = DependencyScope.MavenCompile, - LocationsFoundAt = new[] - { + LocationsFoundAt = + [ "some/location", - }, - TopLevelReferrers = new[] - { + ], + TopLevelReferrers = + [ new NpmComponent("RootNpmComponent", "4.5.6"), - }, + ], }, - }, - DetectorsInScan = new[] - { + ], + DetectorsInScan = + [ new Detector { DetectorId = "NpmDetectorId", IsExperimental = true, - SupportedComponentTypes = new[] - { + SupportedComponentTypes = + [ ComponentType.Npm, - }, + ], Version = 2, }, - }, + ], SourceDirectory = "D:\\test\\directory", }; } diff --git a/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs b/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs index 3087d3832..27c3fb981 100644 --- a/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs +++ b/test/Microsoft.ComponentDetection.Contracts.Tests/TypedComponentSerializationTests.cs @@ -31,7 +31,7 @@ public void TypedComponent_Serialization_NuGet() { var testComponentName = "SomeNuGetComponent"; var testVersion = "1.2.3"; - string[] testAuthors = { "John Doe", "Jane Doe" }; + string[] testAuthors = ["John Doe", "Jane Doe"]; TypedComponent tc = new NuGetComponent(testComponentName, testVersion, testAuthors); var result = JsonConvert.SerializeObject(tc); var deserializedTC = JsonConvert.DeserializeObject(result); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/ConanLockComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/ConanLockComponentDetectorTests.cs index 69208325b..b509188d6 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/ConanLockComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/ConanLockComponentDetectorTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Detectors.Tests; +namespace Microsoft.ComponentDetection.Detectors.Tests; using System; using System.Collections.Generic; @@ -142,7 +142,7 @@ public async Task TestGraphIsCorrectAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(6); + componentRecorder.GetDetectedComponents().Should().HaveCount(6); var graph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); // There should only be 1 @@ -170,10 +170,10 @@ public async Task TestGraphIsCorrectAsync() graph.GetDependenciesForComponent("libanotherlibrary4 5.6.7#someHashOfLibAnotherLibrary4 - Conan").Should().BeEmpty(); // Verify dependencies for other dependencies - graph.GetDependenciesForComponent("libawesomelibrary 3.2.1#someHashOfLibAwesomeLibrary - Conan").Should().BeEquivalentTo(new[] { "libabc 1.2.12#someHashOfLibAbc - Conan" }); + graph.GetDependenciesForComponent("libawesomelibrary 3.2.1#someHashOfLibAwesomeLibrary - Conan").Should().BeEquivalentTo(["libabc 1.2.12#someHashOfLibAbc - Conan"]); var a = graph.GetDependenciesForComponent("libanotherlibrary1 2.3.4#someHashOfLibAnotherLibrary1 - Conan"); - graph.GetDependenciesForComponent("libanotherlibrary1 2.3.4#someHashOfLibAnotherLibrary1 - Conan").Should().BeEquivalentTo(new[] { "libanotherlibrary2 3.4.5#someHashOfLibAnotherLibrary2 - Conan", "libanotherlibrary4 5.6.7#someHashOfLibAnotherLibrary4 - Conan" }); - graph.GetDependenciesForComponent("libanotherlibrary2 3.4.5#someHashOfLibAnotherLibrary2 - Conan").Should().BeEquivalentTo(new[] { "libanotherlibrary3 4.5.6#someHashOfLibAnotherLibrary3 - Conan" }); + graph.GetDependenciesForComponent("libanotherlibrary1 2.3.4#someHashOfLibAnotherLibrary1 - Conan").Should().BeEquivalentTo(["libanotherlibrary2 3.4.5#someHashOfLibAnotherLibrary2 - Conan", "libanotherlibrary4 5.6.7#someHashOfLibAnotherLibrary4 - Conan"]); + graph.GetDependenciesForComponent("libanotherlibrary2 3.4.5#someHashOfLibAnotherLibrary2 - Conan").Should().BeEquivalentTo(["libanotherlibrary3 4.5.6#someHashOfLibAnotherLibrary3 - Conan"]); } [TestMethod] @@ -184,7 +184,7 @@ public async Task TestDetectionForConanLockFileWithNullValuesForRootNodeAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(1); + componentRecorder.GetDetectedComponents().Should().ContainSingle(); (componentRecorder.GetDetectedComponents().First().Component as ConanComponent).Name.Should().Be("libabc"); (componentRecorder.GetDetectedComponents().First().Component as ConanComponent).Version.Should().Be("1.2.12#someHashOfLibAbc"); @@ -198,7 +198,7 @@ public async Task TestConanDetectorAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(6); + componentRecorder.GetDetectedComponents().Should().HaveCount(6); IDictionary packageVersions = new Dictionary() { diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs index 91525474f..5ce46589e 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentDetectorTests.cs @@ -1,6 +1,7 @@ namespace Microsoft.ComponentDetection.Detectors.Tests; using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -178,7 +179,7 @@ public async Task TestGoModDetector_ComponentsWithMultipleLocations_ReturnsSucce .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(4); + componentRecorder.GetDetectedComponents().Should().HaveCount(4); var dependencyGraphs = componentRecorder.GetDependencyGraphsByLocation(); dependencyGraphs.Keys.Should().HaveCount(2); @@ -203,7 +204,7 @@ four score and seven bugs ago .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -222,7 +223,7 @@ go 1.18 var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("go.mod", goMod) - .WithFile("go.mod", goMod, new[] { "go.mod" }) + .WithFile("go.mod", goMod, ["go.mod"]) .WithFile("go.sum", goSum) .ExecuteDetectorAsync(); @@ -369,6 +370,7 @@ public async Task TestGoDetector_GoGraphCommandThrowsAsync() } [TestMethod] + [SuppressMessage("Performance", "CA1861:Avoid constant arrays as arguments", Justification = "Test file.")] public async Task TestGoDetector_GoGraphHappyPathAsync() { var buildDependencies = @"{ @@ -437,6 +439,7 @@ public async Task TestGoDetector_GoGraphHappyPathAsync() } [TestMethod] + [SuppressMessage("Performance", "CA1861:Avoid constant arrays as arguments", Justification = "Test file.")] public async Task TestGoDetector_GoGraphCyclicDependenciesAsync() { var buildDependencies = @"{ diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentWithReplaceDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentWithReplaceDetectorTests.cs index d2fb19ccc..725500782 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentWithReplaceDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/GoComponentWithReplaceDetectorTests.cs @@ -178,7 +178,7 @@ public async Task TestGoModDetector_ComponentsWithMultipleLocations_ReturnsSucce .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(4); + componentRecorder.GetDetectedComponents().Should().HaveCount(4); var dependencyGraphs = componentRecorder.GetDependencyGraphsByLocation(); dependencyGraphs.Keys.Should().HaveCount(2); @@ -203,7 +203,7 @@ four score and seven bugs ago .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -222,7 +222,7 @@ go 1.18 var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("go.mod", goMod) - .WithFile("go.mod", goMod, new[] { "go.mod" }) + .WithFile("go.mod", goMod, ["go.mod"]) .WithFile("go.sum", goSum) .ExecuteDetectorAsync(); @@ -364,7 +364,7 @@ require github.com/go-sql-driver/mysql v1.7.1 // indirect var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("go.mod", goMod) - .WithFile("go.mod", goMod, new[] { "go.mod" }) + .WithFile("go.mod", goMod, ["go.mod"]) .WithFile("go.sum", goSum) .ExecuteDetectorAsync(); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/GradleComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/GradleComponentDetectorTests.cs index dbe7b1752..2a70a4673 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/GradleComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/GradleComponentDetectorTests.cs @@ -34,7 +34,7 @@ public async Task TestGradleDetectorWithNoFiles_ReturnsSuccessfullyAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -121,7 +121,7 @@ public async Task TestGradleDetectorWithValidFiles_ReturnsSuccessfullyAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(7); + componentRecorder.GetDetectedComponents().Should().HaveCount(7); var dependencyGraphs = componentRecorder.GetDependencyGraphsByLocation(); dependencyGraphs.Keys.Should().HaveCount(2); @@ -166,7 +166,7 @@ public async Task TestGradleDetector_SameComponentDifferentLocations_DifferentLo .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(1); + componentRecorder.GetDetectedComponents().Should().ContainSingle(); componentRecorder.ForOneComponent(componentRecorder.GetDetectedComponents().First().Component.Id, x => { @@ -204,7 +204,7 @@ four score and seven bugs ago .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(5); + componentRecorder.GetDetectedComponents().Should().HaveCount(5); var dependencyGraphs = componentRecorder.GetDependencyGraphsByLocation(); dependencyGraphs.Keys.Should().ContainSingle(); @@ -294,7 +294,7 @@ public async Task TestGradleDetector_DevDependenciesByDevLockfileEnvironmentAsyn var devLockfile2 = @"org.jacoco:org.jacoco.agent:0.8.8"; - this.envVarService.Setup(x => x.GetListEnvironmentVariable("CD_GRADLE_DEV_LOCKFILES", ",")).Returns(new List { "dev1\\gradle.lockfile", "dev2\\gradle.lockfile" }); + this.envVarService.Setup(x => x.GetListEnvironmentVariable("CD_GRADLE_DEV_LOCKFILES", ",")).Returns(["dev1\\gradle.lockfile", "dev2\\gradle.lockfile"]); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("dev1\\gradle.lockfile", devLockfile1) @@ -347,7 +347,7 @@ public async Task TestGradleDetector_DevDependenciesByDevConfigurationEnvironmen org.springframework:spring-core:5.0.5.RELEASE=assembleRelease,testDebugUnitTest org.hamcrest:hamcrest-core:2.2=testReleaseUnitTest"; - this.envVarService.Setup(x => x.GetListEnvironmentVariable("CD_GRADLE_DEV_CONFIGURATIONS", ",")).Returns(new List { "testDebugUnitTest", "testReleaseUnitTest" }); + this.envVarService.Setup(x => x.GetListEnvironmentVariable("CD_GRADLE_DEV_CONFIGURATIONS", ",")).Returns(["testDebugUnitTest", "testReleaseUnitTest"]); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("gradle.lockfile", lockfile) diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/IvyDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/IvyDetectorTests.cs index 03f4236bb..077c209cd 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/IvyDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/IvyDetectorTests.cs @@ -34,7 +34,7 @@ public async Task IfAntIsNotAvailableThenExitDetectorGracefullyAsync() var (detectorResult, componentRecorder) = await this.DetectorTestUtility.ExecuteDetectorAsync(); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); detectorResult.ResultCode.Should().Be(ProcessingResultCode.Success); } @@ -110,16 +110,16 @@ public async Task IvyDependencyGraphAsync() // There is only one graph var dependencyGraph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); - dependencyGraph.GetDependenciesForComponent(d1Id).Should().HaveCount(0); + dependencyGraph.GetDependenciesForComponent(d1Id).Should().BeEmpty(); dependencyGraph.IsComponentExplicitlyReferenced(d1Id).Should().BeTrue(); dependencyGraph.IsDevelopmentDependency(d1Id).Should().BeTrue(); - dependencyGraph.GetDependenciesForComponent(d2Id).Should().HaveCount(1); + dependencyGraph.GetDependenciesForComponent(d2Id).Should().ContainSingle(); dependencyGraph.GetDependenciesForComponent(d2Id).Should().Contain(d3Id); dependencyGraph.IsComponentExplicitlyReferenced(d2Id).Should().BeTrue(); dependencyGraph.IsDevelopmentDependency(d2Id).Should().BeFalse(); - dependencyGraph.GetDependenciesForComponent(d3Id).Should().HaveCount(0); + dependencyGraph.GetDependenciesForComponent(d3Id).Should().BeEmpty(); dependencyGraph.IsComponentExplicitlyReferenced(d3Id).Should().BeFalse(); dependencyGraph.IsDevelopmentDependency(d3Id).Should().BeFalse(); } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/LinuxContainerDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/LinuxContainerDetectorTests.cs index 731509578..94c2287fb 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/LinuxContainerDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/LinuxContainerDetectorTests.cs @@ -25,14 +25,14 @@ public class LinuxContainerDetectorTests private const string NodeLatestDigest = "2a22e4a1a550"; private const string BashPackageId = "Ubuntu 20.04 bash 5.0-6ubuntu1 - Linux"; - private static readonly IEnumerable LinuxComponents = new List - { + private static readonly IEnumerable LinuxComponents = + [ new LayerMappedLinuxComponents { DockerLayer = new DockerLayer(), - LinuxComponents = new List { new LinuxComponent("Ubuntu", "20.04", "bash", "5.0-6ubuntu1") }, + LinuxComponents = [new LinuxComponent("Ubuntu", "20.04", "bash", "5.0-6ubuntu1")], }, - }; + ]; private readonly Mock mockDockerService; private readonly Mock mockLogger; @@ -47,7 +47,7 @@ public LinuxContainerDetectorTests() this.mockDockerService.Setup(service => service.TryPullImageAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(true); this.mockDockerService.Setup(service => service.InspectImageAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new ContainerDetails { Id = 1, ImageId = NodeLatestDigest, Layers = Enumerable.Empty() }); + .ReturnsAsync(new ContainerDetails { Id = 1, ImageId = NodeLatestDigest, Layers = [] }); this.mockLogger = new Mock(); this.mockLinuxContainerDetectorLogger = new Mock>(); @@ -62,7 +62,7 @@ public async Task TestLinuxContainerDetectorAsync() { var componentRecorder = new ComponentRecorder(); - var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, new List { NodeLatestImage }, componentRecorder); + var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, [NodeLatestImage], componentRecorder); var linuxContainerDetector = new LinuxContainerDetector( this.mockSyftLinuxScanner.Object, @@ -87,7 +87,7 @@ public async Task TestLinuxContainerDetector_CantRunLinuxContainersAsync() { var componentRecorder = new ComponentRecorder(); - var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, new List { NodeLatestImage }, componentRecorder); + var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, [NodeLatestImage], componentRecorder); this.mockDockerService.Setup(service => service.CanRunLinuxContainersAsync(It.IsAny())) .ReturnsAsync(false); @@ -144,7 +144,7 @@ public async Task TestLinuxContainerDetector_VerifyLowerCaseAsync() { var componentRecorder = new ComponentRecorder(); - var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, new List { "UPPERCASE" }, componentRecorder); + var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, ["UPPERCASE"], componentRecorder); var linuxContainerDetector = new LinuxContainerDetector( this.mockSyftLinuxScanner.Object, @@ -167,7 +167,7 @@ public async Task TestLinuxContainerDetector_SameImagePassedMultipleTimesAsync() { var componentRecorder = new ComponentRecorder(); - var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, new List { NodeLatestImage, NodeLatestDigest }, componentRecorder); + var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, null, [NodeLatestImage, NodeLatestDigest], componentRecorder); var linuxContainerDetector = new LinuxContainerDetector( this.mockSyftLinuxScanner.Object, @@ -190,7 +190,7 @@ public async Task TestLinuxContainerDetector_SameImagePassedMultipleTimesAsync() public async Task TestLinuxContainerDetector_TimeoutParameterSpecifiedAsync() { var detectorArgs = new Dictionary { { "Linux.ScanningTimeoutSec", "2" } }; - var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, detectorArgs, new List { NodeLatestImage }, new ComponentRecorder()); + var scanRequest = new ScanRequest(new DirectoryInfo(Path.GetTempPath()), (_, __) => false, this.mockLogger.Object, detectorArgs, [NodeLatestImage], new ComponentRecorder()); var linuxContainerDetector = new LinuxContainerDetector( this.mockSyftLinuxScanner.Object, @@ -212,7 +212,7 @@ public async Task TestLinuxContainerDetector_HandlesScratchBaseAsync() this.mockDockerService.Setup(service => service.InspectImageAsync(It.IsAny(), It.IsAny())) // Specify BaseImageRef = scratch to verify that cope - .ReturnsAsync(new ContainerDetails { Id = 1, ImageId = NodeLatestDigest, Layers = Enumerable.Empty(), BaseImageRef = "scratch" }); + .ReturnsAsync(new ContainerDetails { Id = 1, ImageId = NodeLatestDigest, Layers = [], BaseImageRef = "scratch" }); await this.TestLinuxContainerDetectorAsync(); } } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/LinuxScannerTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/LinuxScannerTests.cs index 97ec67fa7..48b1d7f4d 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/LinuxScannerTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/LinuxScannerTests.cs @@ -119,7 +119,7 @@ public async Task TestLinuxScannerAsync(string syftOutput) this.mockDockerService.Setup(service => service.CreateAndRunContainerAsync(It.IsAny(), It.IsAny>(), It.IsAny())) .ReturnsAsync((syftOutput, string.Empty)); - var result = (await this.linuxScanner.ScanLinuxAsync("fake_hash", new[] { new DockerLayer { LayerIndex = 0, DiffId = "sha256:f95fc50d21d981f1efe1f04109c2c3287c271794f5d9e4fdf9888851a174a971" } }, 0)).First().LinuxComponents; + var result = (await this.linuxScanner.ScanLinuxAsync("fake_hash", [new DockerLayer { LayerIndex = 0, DiffId = "sha256:f95fc50d21d981f1efe1f04109c2c3287c271794f5d9e4fdf9888851a174a971" }], 0)).First().LinuxComponents; result.Should().ContainSingle(); var package = result.First(); @@ -138,7 +138,7 @@ public async Task TestLinuxScanner_ReturnsNullAuthorAndLicense_Async(string syft this.mockDockerService.Setup(service => service.CreateAndRunContainerAsync(It.IsAny(), It.IsAny>(), It.IsAny())) .ReturnsAsync((syftOutput, string.Empty)); - var result = (await this.linuxScanner.ScanLinuxAsync("fake_hash", new[] { new DockerLayer { LayerIndex = 0, DiffId = "sha256:f95fc50d21d981f1efe1f04109c2c3287c271794f5d9e4fdf9888851a174a971" } }, 0)).First().LinuxComponents; + var result = (await this.linuxScanner.ScanLinuxAsync("fake_hash", [new DockerLayer { LayerIndex = 0, DiffId = "sha256:f95fc50d21d981f1efe1f04109c2c3287c271794f5d9e4fdf9888851a174a971" }], 0)).First().LinuxComponents; result.Should().ContainSingle(); var package = result.First(); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/MavenParsingUtilitiesTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/MavenParsingUtilitiesTests.cs index 21147bbbf..5c7791fc9 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/MavenParsingUtilitiesTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/MavenParsingUtilitiesTests.cs @@ -1,6 +1,5 @@ namespace Microsoft.ComponentDetection.Detectors.Tests; -using System; using FluentAssertions; using Microsoft.ComponentDetection.Contracts.BcdeModels; using Microsoft.ComponentDetection.Contracts.TypedComponent; diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/MavenStyleDependencyGraphParserTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/MavenStyleDependencyGraphParserTests.cs index 2fa788050..7612f5cd6 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/MavenStyleDependencyGraphParserTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/MavenStyleDependencyGraphParserTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Detectors.Tests; +namespace Microsoft.ComponentDetection.Detectors.Tests; using System.IO; using System.Linq; @@ -80,6 +80,6 @@ public void MavenFormat_WithSingleFileComponentRecorder_ExpectedParse() guavaDependencies.Should().HaveCount(5); guavaDependencies.Should().Contain(animalSnifferAnnotations.Component.Id); - dependencyGraph.GetDependenciesForComponent(animalSnifferAnnotations.Component.Id).Should().HaveCount(0); + dependencyGraph.GetDependenciesForComponent(animalSnifferAnnotations.Component.Id).Should().BeEmpty(); } } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/MvnCliDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/MvnCliDetectorTests.cs index f74e5c205..7adf0feed 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/MvnCliDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/MvnCliDetectorTests.cs @@ -36,7 +36,7 @@ public async Task IfMavenIsNotAvailableThenExitDetectorGracefullyAsync() var (detectorResult, componentRecorder) = await this.DetectorTestUtility .ExecuteDetectorAsync(); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); detectorResult.ResultCode.Should().Be(ProcessingResultCode.Success); } @@ -167,21 +167,21 @@ public async Task MavenDependencyGraphAsync() // There is only one graph var dependencyGraph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); - dependencyGraph.GetDependenciesForComponent(explicitReferencedComponentId).Should().HaveCount(1); + dependencyGraph.GetDependenciesForComponent(explicitReferencedComponentId).Should().ContainSingle(); dependencyGraph.GetDependenciesForComponent(explicitReferencedComponentId).Should().Contain(intermediateParentComponentId); dependencyGraph.IsComponentExplicitlyReferenced(explicitReferencedComponentId).Should().BeTrue(); - dependencyGraph.GetDependenciesForComponent(intermediateParentComponentId).Should().HaveCount(1); + dependencyGraph.GetDependenciesForComponent(intermediateParentComponentId).Should().ContainSingle(); dependencyGraph.GetDependenciesForComponent(intermediateParentComponentId).Should().Contain(leafComponentId); dependencyGraph.IsComponentExplicitlyReferenced(intermediateParentComponentId).Should().BeFalse(); - dependencyGraph.GetDependenciesForComponent(leafComponentId).Should().HaveCount(0); + dependencyGraph.GetDependenciesForComponent(leafComponentId).Should().BeEmpty(); dependencyGraph.IsComponentExplicitlyReferenced(leafComponentId).Should().BeFalse(); } protected bool ShouldBeEquivalentTo(IEnumerable result, IEnumerable expected) { - result.Should().BeEquivalentTo(expected); + result.Should().BeEquivalentTo(expected); return true; } @@ -194,6 +194,6 @@ private void MvnCliHappyPath(string content) this.mavenCommandServiceMock.Setup(x => x.MavenCLIExistsAsync()) .ReturnsAsync(true); this.DetectorTestUtility.WithFile("pom.xml", content) - .WithFile("pom.xml", content, searchPatterns: new[] { bcdeMvnFileName }); + .WithFile("pom.xml", content, searchPatterns: [bcdeMvnFileName]); } } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/NpmDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/NpmDetectorTests.cs index ccfb6eba3..bce143d44 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/NpmDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/NpmDetectorTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Detectors.Tests; +namespace Microsoft.ComponentDetection.Detectors.Tests; using System.Collections.Generic; using System.Linq; @@ -16,7 +16,7 @@ [TestCategory("Governance/ComponentDetection")] public class NpmDetectorTests : BaseDetectorTest { - private readonly List packageJsonSearchPattern = new List { "package.json" }; + private readonly List packageJsonSearchPattern = ["package.json"]; [TestMethod] public async Task TestNpmDetector_NameAndVersionDetectedAsync() diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/NpmDetectorWithRootsTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/NpmDetectorWithRootsTests.cs index 0b9434b3c..f39fe83e4 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/NpmDetectorWithRootsTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/NpmDetectorWithRootsTests.cs @@ -22,8 +22,8 @@ public class NpmDetectorWithRootsTests : BaseDetectorTest packageJsonSearchPattern = new() { "package.json" }; - private readonly List packageLockJsonSearchPatterns = new() { "package-lock.json", "npm-shrinkwrap.json", "lerna.json" }; + private readonly List packageJsonSearchPattern = ["package.json"]; + private readonly List packageLockJsonSearchPatterns = ["package-lock.json", "npm-shrinkwrap.json", "lerna.json"]; private readonly Mock mockPathUtilityService; public NpmDetectorWithRootsTests() @@ -102,7 +102,7 @@ public async Task TestNpmDetector_MismatchedFilesReturnsEmptyAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -115,7 +115,7 @@ public async Task TestNpmDetector_MissingPackageJsonReturnsEmptyAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -267,7 +267,7 @@ public async Task TestNpmDetector_EmptyVersionSkippedAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -320,7 +320,7 @@ public async Task TestNpmDetector_InvalidNameSkippedAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -383,7 +383,7 @@ public async Task TestNpmDetector_LernaDirectoryAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(2); + componentRecorder.GetDetectedComponents().Should().HaveCount(2); } [TestMethod] @@ -603,10 +603,10 @@ public async Task TestNpmDetector_DependencyGraphIsCreatedAsync() var dependencyGraph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); - dependencyGraph.GetDependenciesForComponent(componentAId).Should().HaveCount(1); + dependencyGraph.GetDependenciesForComponent(componentAId).Should().ContainSingle(); dependencyGraph.GetDependenciesForComponent(componentAId).Should().Contain(componentBId); - dependencyGraph.GetDependenciesForComponent(componentBId).Should().HaveCount(1); + dependencyGraph.GetDependenciesForComponent(componentBId).Should().ContainSingle(); dependencyGraph.GetDependenciesForComponent(componentBId).Should().Contain(componentCId); - dependencyGraph.GetDependenciesForComponent(componentCId).Should().HaveCount(0); + dependencyGraph.GetDependenciesForComponent(componentCId).Should().BeEmpty(); } } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/NpmLockfile3DetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/NpmLockfile3DetectorTests.cs index 509beea45..b7ac61f83 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/NpmLockfile3DetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/NpmLockfile3DetectorTests.cs @@ -21,8 +21,8 @@ public class NpmLockfile3DetectorTests : BaseDetectorTest { private readonly string packageLockJsonFileName = "package-lock.json"; private readonly string packageJsonFileName = "package.json"; - private readonly List packageJsonSearchPattern = new() { "package.json" }; - private readonly List packageLockJsonSearchPatterns = new() { "package-lock.json", "npm-shrinkwrap.json", "lerna.json" }; + private readonly List packageJsonSearchPattern = ["package.json"]; + private readonly List packageLockJsonSearchPatterns = ["package-lock.json", "npm-shrinkwrap.json", "lerna.json"]; private readonly Mock mockPathUtilityService; public NpmLockfile3DetectorTests() @@ -280,8 +280,8 @@ public async Task TestNpmDetector_NestedNodeModulesV3Async() var dependencyGraph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); - dependencyGraph.GetDependenciesForComponent(componentAId).Should().HaveCount(1); + dependencyGraph.GetDependenciesForComponent(componentAId).Should().ContainSingle(); dependencyGraph.GetDependenciesForComponent(componentAId).Should().Contain(componentBId); - dependencyGraph.GetDependenciesForComponent(componentBId).Should().HaveCount(0); + dependencyGraph.GetDependenciesForComponent(componentBId).Should().BeEmpty(); } } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/NpmUtilitiesTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/NpmUtilitiesTests.cs index ca3551153..580a970c2 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/NpmUtilitiesTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/NpmUtilitiesTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Detectors.Tests; +namespace Microsoft.ComponentDetection.Detectors.Tests; using System.Linq; using FluentAssertions; @@ -173,14 +173,14 @@ public void TestTraverseAndGetRequirementsAndDependencies() NpmComponentUtilities.TraverseAndRecordComponents(currentDependency, singleFileComponentRecorder1, typedComponent, typedComponent); NpmComponentUtilities.TraverseAndRecordComponents(currentDependency, singleFileComponentRecorder2, typedComponent, typedComponent); - componentRecorder.GetDetectedComponents().Count().Should().Be(1); + componentRecorder.GetDetectedComponents().Should().ContainSingle(); componentRecorder.GetComponent(typedComponent.Id).Should().NotBeNull(); var graph1 = componentRecorder.GetDependencyGraphsByLocation()["/this/is/a/test/path/"]; var graph2 = componentRecorder.GetDependencyGraphsByLocation()["/this/is/a/different/path/"]; - graph1.GetExplicitReferencedDependencyIds(typedComponent.Id).Contains(typedComponent.Id).Should().BeTrue(); - graph2.GetExplicitReferencedDependencyIds(typedComponent.Id).Contains(typedComponent.Id).Should().BeTrue(); + graph1.GetExplicitReferencedDependencyIds(typedComponent.Id).Should().Contain(typedComponent.Id); + graph2.GetExplicitReferencedDependencyIds(typedComponent.Id).Should().Contain(typedComponent.Id); componentRecorder.GetEffectiveDevDependencyValue(typedComponent.Id).GetValueOrDefault(true).Should().BeFalse(); var json1 = @"{ @@ -200,14 +200,14 @@ public void TestTraverseAndGetRequirementsAndDependencies() NpmComponentUtilities.TraverseAndRecordComponents(currentDependency1, singleFileComponentRecorder2, typedComponent1, typedComponent1); - componentRecorder.GetDetectedComponents().Count().Should().Be(2); + componentRecorder.GetDetectedComponents().Should().HaveCount(2); - graph2.GetExplicitReferencedDependencyIds(typedComponent1.Id).Contains(typedComponent1.Id).Should().BeTrue(); + graph2.GetExplicitReferencedDependencyIds(typedComponent1.Id).Should().Contain(typedComponent1.Id); componentRecorder.GetEffectiveDevDependencyValue(typedComponent1.Id).GetValueOrDefault(false).Should().BeTrue(); NpmComponentUtilities.TraverseAndRecordComponents(currentDependency1, singleFileComponentRecorder2, typedComponent, typedComponent1, parentComponentId: typedComponent1.Id); - componentRecorder.GetDetectedComponents().Count().Should().Be(2); + componentRecorder.GetDetectedComponents().Should().HaveCount(2); var explicitlyReferencedDependencyIds = graph2.GetExplicitReferencedDependencyIds(typedComponent.Id); explicitlyReferencedDependencyIds.Should().Contain(typedComponent.Id); explicitlyReferencedDependencyIds.Should().Contain(typedComponent1.Id); @@ -231,7 +231,7 @@ public void AddOrUpdateDetectedComponent_NewComponent_ComponentAdded() addedComponent1.Should().BeEquivalentTo(expectedDetectedComponent, options => options.Excluding(obj => obj.DependencyRoots)); addedComponent2.Should().BeEquivalentTo(expectedDetectedDevComponent, options => options.Excluding(obj => obj.DependencyRoots)); - componentRecorder.GetDetectedComponents().Count().Should().Be(2); + componentRecorder.GetDetectedComponents().Should().HaveCount(2); var nonDevComponent = componentRecorder.GetComponent(expectedDetectedComponent.Component.Id); nonDevComponent.Should().BeEquivalentTo(expectedDetectedComponent.Component); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetComponentDetectorTests.cs index 7fab43336..c58d74bc2 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetComponentDetectorTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Detectors.Tests; +namespace Microsoft.ComponentDetection.Detectors.Tests; using System; using System.Collections.Generic; @@ -23,7 +23,7 @@ public class NuGetComponentDetectorTests : BaseDetectorTest { private static readonly IEnumerable DetectorSearchPattern = - new List { "*.nupkg", "*.nuspec", "nuget.config", "paket.lock" }; + ["*.nupkg", "*.nuspec", "nuget.config", "paket.lock"]; private readonly Mock> mockLogger; @@ -39,7 +39,7 @@ public async Task TestNuGetDetectorWithNoFiles_ReturnsSuccessfullyAsync() var (scanResult, componentRecorder) = await this.DetectorTestUtility.ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -55,7 +55,7 @@ public async Task TestNugetDetector_ReturnsValidNuspecComponentAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success, "Result code does Not match."); - componentRecorder.GetDetectedComponents().Count().Should().Be(1, "Component count does not match"); + componentRecorder.GetDetectedComponents().Should().ContainSingle("Component count does not match"); var detectedComponent = componentRecorder.GetDetectedComponents().First().Component; detectedComponent.Type.Should().Be(ComponentType.NuGet); var nuGetComponent = (NuGetComponent)detectedComponent; @@ -77,7 +77,7 @@ public async Task TestNugetDetector_ReturnsValidNuspecComponent_SingleAuthorAsyn .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success, "Result code does Not match."); - componentRecorder.GetDetectedComponents().Count().Should().Be(1, "Component count does not match"); + componentRecorder.GetDetectedComponents().Should().ContainSingle("Component count does not match"); var detectedComponent = componentRecorder.GetDetectedComponents().First().Component; detectedComponent.Type.Should().Be(ComponentType.NuGet); var nuGetComponent = (NuGetComponent)detectedComponent; @@ -96,7 +96,7 @@ public async Task TestNugetDetector_ReturnsValidNupkgComponentAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(1); + componentRecorder.GetDetectedComponents().Should().ContainSingle(); } [TestMethod] @@ -111,7 +111,7 @@ public async Task TestNugetDetector_ReturnsValidMixedComponentAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(2); + componentRecorder.GetDetectedComponents().Should().HaveCount(2); } [TestMethod] @@ -157,7 +157,7 @@ public async Task TestNugetDetector_ReturnsValidPaketComponentAsync() scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); // While there are 26 lines in the sample, several dependencies are identical, so there are only 11 matches. - componentRecorder.GetDetectedComponents().Count().Should().Be(11); + componentRecorder.GetDetectedComponents().Should().HaveCount(11); // Verify that we stop executing after parsing the paket.lock file. this.mockLogger.Verify( @@ -192,7 +192,7 @@ public async Task TestNugetDetector_HandlesMalformedComponentsInComponentListAsy (Func)It.IsAny())); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(2); + componentRecorder.GetDetectedComponents().Should().HaveCount(2); } [TestMethod] @@ -232,7 +232,7 @@ public async Task TestNugetDetector_AdditionalDirectoriesAsync() Match.Create>(stuff => DetectorSearchPattern.Intersect(stuff).Count() == DetectorSearchPattern.Count()), It.IsAny(), It.IsAny())) - .Returns(Enumerable.Empty()); + .Returns([]); // This is matching the additional directory that is ONLY sourced in the nuget.config. If this works, we would see the component in our results. componentStreamEnumerableFactoryMock.Setup( @@ -268,13 +268,13 @@ public async Task TestNugetDetector_AdditionalDirectoriesAsync() directoryWalkerMock.VerifyAll(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(1); + componentRecorder.GetDetectedComponents().Should().ContainSingle(); } [TestMethod] public async Task TestNugetDetector_LowConfidencePackagesAsync() { - var nupkg = await NugetTestUtilities.ZipNupkgComponentAsync("Newtonsoft.Json.nupkg", NugetTestUtilities.GetValidNuspec("Newtonsoft.Json", "9.0.1", new[] { "JamesNK" })); + var nupkg = await NugetTestUtilities.ZipNupkgComponentAsync("Newtonsoft.Json.nupkg", NugetTestUtilities.GetValidNuspec("Newtonsoft.Json", "9.0.1", ["JamesNK"])); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("Newtonsoft.Json.nupkg", nupkg) diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetNuspecUtilitiesTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetNuspecUtilitiesTests.cs index 880923b88..81a3c85f0 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetNuspecUtilitiesTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetNuspecUtilitiesTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Detectors.Tests; +namespace Microsoft.ComponentDetection.Detectors.Tests; using System; using System.IO; @@ -18,9 +18,8 @@ public async Task GetNuspecBytes_FailsOnEmptyStreamAsync() { using var stream = new MemoryStream(); - async Task ShouldThrow() => await NuGetNuspecUtilities.GetNuspecBytesAsync(stream); - - await Assert.ThrowsExceptionAsync(ShouldThrow); + var action = async () => await NuGetNuspecUtilities.GetNuspecBytesAsync(stream); + await action.Should().ThrowAsync(); // The position should always be reset to 0 stream.Position.Should().Be(0); @@ -38,9 +37,8 @@ public async Task GetNuspecBytes_FailsOnTooSmallStreamAsync() stream.Seek(0, SeekOrigin.Begin); - async Task ShouldThrow() => await NuGetNuspecUtilities.GetNuspecBytesAsync(stream); - - await Assert.ThrowsExceptionAsync(ShouldThrow); + var action = async () => await NuGetNuspecUtilities.GetNuspecBytesAsync(stream); + await action.Should().ThrowAsync(); // The position should always be reset to 0 stream.Position.Should().Be(0); @@ -58,10 +56,10 @@ public async Task GetNuspecBytes_FailsIfNuspecNotPresentAsync() stream.Seek(0, SeekOrigin.Begin); - async Task ShouldThrow() => await NuGetNuspecUtilities.GetNuspecBytesAsync(stream); + var action = async () => await NuGetNuspecUtilities.GetNuspecBytesAsync(stream); // No Nuspec File is in the archive - await Assert.ThrowsExceptionAsync(ShouldThrow); + await action.Should().ThrowAsync(); // The position should always be reset to 0 stream.Position.Should().Be(0); @@ -70,7 +68,7 @@ public async Task GetNuspecBytes_FailsIfNuspecNotPresentAsync() [TestMethod] public async Task GetNuspecBytes_ReadsNuspecBytesAsync() { - byte[] randomBytes = { 0xDE, 0xAD, 0xC0, 0xDE }; + byte[] randomBytes = [0xDE, 0xAD, 0xC0, 0xDE]; using var stream = new MemoryStream(); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetProjectModelProjectCentricComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetProjectModelProjectCentricComponentDetectorTests.cs index ad25eb1a4..bbbb3e9b2 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetProjectModelProjectCentricComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/NuGetProjectModelProjectCentricComponentDetectorTests.cs @@ -52,7 +52,7 @@ public async Task ScanDirectoryAsync_Base_2_2_VerificationAsync() x.Component.Id, y => y.Id == x.Component.Id)); - componentRecorder.ForAllComponents(grouping => Assert.IsTrue(grouping.AllFileLocations.Any(location => location.Contains("Loader.csproj")))); + componentRecorder.ForAllComponents(grouping => grouping.AllFileLocations.Should().Contain(location => location.Contains("Loader.csproj"))); } [TestMethod] @@ -78,7 +78,7 @@ public async Task ScanDirectoryAsync_Base_2_2_additional_VerificationAsync() nugetVersioning.Component.Id, x => x.Name.Contains("NuGet.ProjectModel")).Should().BeTrue(); - componentRecorder.ForAllComponents(grouping => Assert.IsTrue(grouping.AllFileLocations.Any(location => location.Contains("Detectors.csproj")))); + componentRecorder.ForAllComponents(grouping => grouping.AllFileLocations.Should().Contain(location => location.Contains("Detectors.csproj"))); } [TestMethod] @@ -93,7 +93,8 @@ public async Task ScanDirectoryAsync_ExcludedFrameworkComponent_2_2_Verification var omittedComponentsWithCount = JsonConvert.DeserializeObject>(ommittedComponentInformationJson); (omittedComponentsWithCount.Keys.Count > 5).Should().BeTrue("Ommitted framework assemblies are missing. There should be more than ten, but this is a gut check to make sure we have data."); - omittedComponentsWithCount["Microsoft.NETCore.App"].Should().Be(4, "There should be four cases of the NETCore.App library being omitted in the test data."); + + omittedComponentsWithCount.Should().Contain("Microsoft.NETCore.App", 4, "There should be four cases of the NETCore.App library being omitted in the test data."); } [TestMethod] @@ -121,7 +122,7 @@ public async Task ScanDirectoryAsync_DependencyGraph_2_2_additional_Verification expectedDependencyIdsForCompositionTypedParts.Should().HaveSameCount(dependencies); - detectedComponents.Should().HaveCount(graph.GetComponents().Count()); + detectedComponents.Should().HaveSameCount(graph.GetComponents()); // Top level dependencies look like this: // (we expect all non-proj and non-framework to show up as explicit refs, so those will be absent from the check) @@ -195,7 +196,7 @@ public async Task ScanDirectoryAsync_Base_3_1_VerificationAsync() systemTextJson.Component.Id, x => x.Name.Contains("Microsoft.Extensions.DependencyModel")).Should().BeTrue(); - componentRecorder.ForAllComponents(grouping => Assert.IsTrue(grouping.AllFileLocations.Any(location => location.Contains("ExtCore.WebApplication.csproj")))); + componentRecorder.ForAllComponents(grouping => grouping.AllFileLocations.Should().Contain(location => location.Contains("ExtCore.WebApplication.csproj"))); } [TestMethod] @@ -211,7 +212,7 @@ public async Task ScanDirectoryAsync_ExcludedFrameworkComponent_3_1_Verification // With 3.X, we don't expect there to be a lot of these, but there are still netstandard libraries present which can bring things into the graph omittedComponentsWithCount.Keys.Should().HaveCount(4, "Ommitted framework assemblies are missing. There should be more than ten, but this is a gut check to make sure we have data."); - omittedComponentsWithCount["System.Reflection"].Should().Be(1, "There should be one case of the System.Reflection library being omitted in the test data."); + omittedComponentsWithCount.Should().Contain("System.Reflection", 1, "There should be one case of the System.Reflection library being omitted in the test data."); } [TestMethod] @@ -239,7 +240,7 @@ public async Task ScanDirectoryAsync_DependencyGraph_3_1_VerificationAsync() dependencies.Should().Contain(expectedId); } - detectedComponents.Should().HaveCount(graph.GetComponents().Count()); + detectedComponents.Should().HaveSameCount(graph.GetComponents()); // Top level dependencies look like this: // (we expect all non-proj and non-framework to show up as explicit refs, so those will be absent from the check) diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/NugetTestUtilities.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/NugetTestUtilities.cs index 37fa45ce4..913aae839 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/NugetTestUtilities.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/NugetTestUtilities.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Detectors.Tests; +namespace Microsoft.ComponentDetection.Detectors.Tests; using System.IO; using System.IO.Compression; @@ -16,7 +16,7 @@ public static string GetRandomValidNuSpecComponent() var componentName = GetRandomString(); var componentSpecFileName = $"{componentName}.nuspec"; var componentSpecPath = Path.Combine(Path.GetTempPath(), componentSpecFileName); - var template = GetTemplatedNuspec(componentName, NewRandomVersion(), new string[] { GetRandomString(), GetRandomString() }); + var template = GetTemplatedNuspec(componentName, NewRandomVersion(), [GetRandomString(), GetRandomString()]); return template; } @@ -26,7 +26,7 @@ public static IComponentStream GetRandomValidNuSpecComponentStream() var componentName = GetRandomString(); var componentSpecFileName = $"{componentName}.nuspec"; var componentSpecPath = Path.Combine(Path.GetTempPath(), componentSpecFileName); - var template = GetTemplatedNuspec(componentName, NewRandomVersion(), new string[] { GetRandomString(), GetRandomString() }); + var template = GetTemplatedNuspec(componentName, NewRandomVersion(), [GetRandomString(), GetRandomString()]); var mock = new Mock(); mock.SetupGet(x => x.Stream).Returns(template.ToStream()); @@ -51,7 +51,7 @@ public static IComponentStream GetValidNuGetConfig(string repositoryPath) public static string GetRandomValidNuspec() { var componentName = GetRandomString(); - var template = GetTemplatedNuspec(componentName, NewRandomVersion(), new string[] { GetRandomString(), GetRandomString() }); + var template = GetTemplatedNuspec(componentName, NewRandomVersion(), [GetRandomString(), GetRandomString()]); return template; } @@ -81,7 +81,7 @@ public static async Task ZipNupkgComponentAsync(string filename, string public static string GetRandomMalformedNuPkgComponent() { var componentName = GetRandomString(); - var template = GetTemplatedNuspec(componentName, NewRandomVersion(), new string[] { GetRandomString(), GetRandomString() }); + var template = GetTemplatedNuspec(componentName, NewRandomVersion(), [GetRandomString(), GetRandomString()]); template = template.Replace("", ""); return template; } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PipComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PipComponentDetectorTests.cs index 8374abd55..944e47c33 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/PipComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PipComponentDetectorTests.cs @@ -69,8 +69,8 @@ public async Task TestPipDetector_SetupPyAndRequirementsTxtAsync() { this.pythonCommandService.Setup(x => x.PythonExistsAsync(It.IsAny())).ReturnsAsync(true); - var baseSetupPyDependencies = this.ToGitTuple(new List { "a==1.0", "b>=2.0,!=2.1", "c!=1.1" }); - var baseRequirementsTextDependencies = this.ToGitTuple(new List { "d~=1.0", "e<=2.0", "f===1.1" }); + var baseSetupPyDependencies = this.ToGitTuple(["a==1.0", "b>=2.0,!=2.1", "c!=1.1"]); + var baseRequirementsTextDependencies = this.ToGitTuple(["d~=1.0", "e<=2.0", "f===1.1"]); baseRequirementsTextDependencies.Add((null, new GitComponent(new Uri("https://github.com/example/example"), "deadbee"))); this.pythonCommandService.Setup(x => x.ParseFileAsync(Path.Join(Path.GetTempPath(), "setup.py"), null)).ReturnsAsync(baseSetupPyDependencies); @@ -128,8 +128,8 @@ public async Task TestPipDetector_ComponentsDedupedAcrossFilesAsync() { this.pythonCommandService.Setup(x => x.PythonExistsAsync(It.IsAny())).ReturnsAsync(true); - var baseRequirementsTextDependencies = this.ToGitTuple(new List { "d~=1.0", "e<=2.0", "f===1.1", "h==1.3" }); - var baseRequirementsTextDependencies2 = this.ToGitTuple(new List { "D~=1.0", "E<=2.0", "F===1.1", "g==2" }); + var baseRequirementsTextDependencies = this.ToGitTuple(["d~=1.0", "e<=2.0", "f===1.1", "h==1.3"]); + var baseRequirementsTextDependencies2 = this.ToGitTuple(["D~=1.0", "E<=2.0", "F===1.1", "g==2"]); this.pythonCommandService.Setup(x => x.ParseFileAsync(Path.Join(Path.GetTempPath(), "requirements.txt"), null)).ReturnsAsync(baseRequirementsTextDependencies); this.pythonCommandService.Setup(x => x.ParseFileAsync(Path.Join(Path.GetTempPath(), "TEST", "requirements.txt"), null)).ReturnsAsync(baseRequirementsTextDependencies2); @@ -157,7 +157,7 @@ public async Task TestPipDetector_ComponentsDedupedAcrossFilesAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(5); + componentRecorder.GetDetectedComponents().Should().HaveCount(5); } [TestMethod] @@ -168,8 +168,8 @@ public async Task TestPipDetector_ComponentRecorderAsync() const string file1 = "c:\\repo\\setup.py"; const string file2 = "c:\\repo\\lib\\requirements.txt"; - var baseReqs = this.ToGitTuple(new List { "a~=1.0", "b<=2.0", }); - var altReqs = this.ToGitTuple(new List { "c~=1.0", "d<=2.0", "e===1.1" }); + var baseReqs = this.ToGitTuple(["a~=1.0", "b<=2.0",]); + var altReqs = this.ToGitTuple(["c~=1.0", "d<=2.0", "e===1.1"]); this.pythonCommandService.Setup(x => x.ParseFileAsync(file1, null)).ReturnsAsync(baseReqs); this.pythonCommandService.Setup(x => x.ParseFileAsync(file2, null)).ReturnsAsync(altReqs); @@ -189,7 +189,7 @@ public async Task TestPipDetector_ComponentRecorderAsync() rootA.Children.Add(red); rootB.Children.Add(green); - rootC.Children.AddRange(new[] { red, blue, }); + rootC.Children.AddRange([red, blue,]); rootD.Children.Add(cat); green.Children.Add(cat); cat.Children.Add(lion); @@ -198,11 +198,11 @@ public async Task TestPipDetector_ComponentRecorderAsync() this.pythonResolver.Setup(x => x.ResolveRootsAsync(It.IsAny(), It.Is>(p => p.Any(d => d.Name == "a")))) - .ReturnsAsync(new List { rootA, rootB, }); + .ReturnsAsync([rootA, rootB,]); this.pythonResolver.Setup(x => x.ResolveRootsAsync(It.IsAny(), It.Is>(p => p.Any(d => d.Name == "c")))) - .ReturnsAsync(new List { rootC, rootD, rootE, }); + .ReturnsAsync([rootC, rootD, rootE,]); var (result, componentRecorder) = await this.DetectorTestUtility .WithFile("setup.py", string.Empty, fileLocation: file1) @@ -230,12 +230,12 @@ public async Task TestPipDetector_ComponentRecorderAsync() x => x.Id == rootId); } - ComponentRecorderTestUtilities.CheckChild(componentRecorder, "red 0.2 - pip", new[] { "a 1.0 - pip", "c 1.0 - pip", }); - ComponentRecorderTestUtilities.CheckChild(componentRecorder, "green 1.3 - pip", new[] { "b 2.1 - pip", }); - ComponentRecorderTestUtilities.CheckChild(componentRecorder, "blue 0.4 - pip", new[] { "c 1.0 - pip", }); - ComponentRecorderTestUtilities.CheckChild(componentRecorder, "cat 1.8 - pip", new[] { "b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip", }); - ComponentRecorderTestUtilities.CheckChild(componentRecorder, "lion 3.8 - pip", new[] { "b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip", }); - ComponentRecorderTestUtilities.CheckChild(componentRecorder, "dog 2.1 - pip", new[] { "c 1.0 - pip", }); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "red 0.2 - pip", ["a 1.0 - pip", "c 1.0 - pip",]); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "green 1.3 - pip", ["b 2.1 - pip",]); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "blue 0.4 - pip", ["c 1.0 - pip",]); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "cat 1.8 - pip", ["b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip",]); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "lion 3.8 - pip", ["b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip",]); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "dog 2.1 - pip", ["c 1.0 - pip",]); var graphsByLocations = componentRecorder.GetDependencyGraphsByLocation(); graphsByLocations.Should().HaveCount(2); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PipDependencySpecifierTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PipDependencySpecifierTests.cs index 2e55fbd0c..90ebd4cae 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/PipDependencySpecifierTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PipDependencySpecifierTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Detectors.Tests; +namespace Microsoft.ComponentDetection.Detectors.Tests; using System.Collections.Generic; using FluentAssertions; @@ -31,10 +31,10 @@ public void TestPipDependencySpecifierConstruction() { var specs = new List<(string, PipDependencySpecification)> { - ("TestPackage==1.0", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = new List { "==1.0" } }), - ("TestPackage>=1.0,!=1.1", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = new List { ">=1.0", "!=1.1" } }), - ("OtherPackage!=1.2,>=1.0,<=1.9,~=1.4", new PipDependencySpecification { Name = "OtherPackage", DependencySpecifiers = new List { "!=1.2", ">=1.0", "<=1.9", "~=1.4" } }), - ("TestPackage[Optional]<3,>=1.0.0", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = new List { "<3", ">=1.0.0" } }), + ("TestPackage==1.0", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = ["==1.0"] }), + ("TestPackage>=1.0,!=1.1", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = [">=1.0", "!=1.1"] }), + ("OtherPackage!=1.2,>=1.0,<=1.9,~=1.4", new PipDependencySpecification { Name = "OtherPackage", DependencySpecifiers = ["!=1.2", ">=1.0", "<=1.9", "~=1.4"] }), + ("TestPackage[Optional]<3,>=1.0.0", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = ["<3", ">=1.0.0"] }), }; VerifyPipDependencyParsing(specs); @@ -45,12 +45,12 @@ public void TestPipDependencyRequireDist() { var specs = new List<(string, PipDependencySpecification)> { - ("Requires-Dist: TestPackage<1.27.0,>=1.19.5", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = new List { "<1.27.0", ">=1.19.5" } }), - ("Requires-Dist: TestPackage (>=1.0.0) ; sys_platform == \"win32\"", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = new List { ">=1.0.0" } }), - ("Requires-Dist: OtherPackage[Optional] (<3,>=1.0.0)", new PipDependencySpecification { Name = "OtherPackage", DependencySpecifiers = new List { "<3", ">=1.0.0" } }), - ("Requires-Dist: TestPackage (>=3.7.4.3) ; python_version < \"3.8\"", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = new List { ">=3.7.4.3" } }), - ("Requires-Dist: TestPackage ; python_version < \"3.8\"", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = new List() }), - ("Requires-Dist: SpacePackage >=1.16.0", new PipDependencySpecification() { Name = "SpacePackage", DependencySpecifiers = new List() { ">=1.16.0" } }), + ("Requires-Dist: TestPackage<1.27.0,>=1.19.5", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = ["<1.27.0", ">=1.19.5"] }), + ("Requires-Dist: TestPackage (>=1.0.0) ; sys_platform == \"win32\"", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = [">=1.0.0"] }), + ("Requires-Dist: OtherPackage[Optional] (<3,>=1.0.0)", new PipDependencySpecification { Name = "OtherPackage", DependencySpecifiers = ["<3", ">=1.0.0"] }), + ("Requires-Dist: TestPackage (>=3.7.4.3) ; python_version < \"3.8\"", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = [">=3.7.4.3"] }), + ("Requires-Dist: TestPackage ; python_version < \"3.8\"", new PipDependencySpecification { Name = "TestPackage", DependencySpecifiers = [] }), + ("Requires-Dist: SpacePackage >=1.16.0", new PipDependencySpecification() { Name = "SpacePackage", DependencySpecifiers = [">=1.16.0"] }), }; VerifyPipDependencyParsing(specs, true); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PipReportComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PipReportComponentDetectorTests.cs index baf5e5abe..ffc1b48a0 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/PipReportComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PipReportComponentDetectorTests.cs @@ -344,13 +344,13 @@ public async Task TestPipReportDetector_MultiComponent_ComponentRecorder_Async() var setupGraphComponentsWithDeps = new Dictionary { - { "six 1.16.0 - pip", Array.Empty() }, - { "python-dateutil 2.9.0.post0 - pip", new[] { "six 1.16.0 - pip" } }, + { "six 1.16.0 - pip", [] }, + { "python-dateutil 2.9.0.post0 - pip", ["six 1.16.0 - pip"] }, }; var reqGraphComponentsWithDeps = new Dictionary { - { "six 1.16.0 - pip", Array.Empty() }, + { "six 1.16.0 - pip", [] }, }; var setupGraph = graphsByLocations[file1]; @@ -420,11 +420,11 @@ public async Task TestPipReportDetector_SingleRoot_ComplexGraph_ComponentRecorde ComponentRecorderTestUtilities.CheckChild( componentRecorder, "async-lru 2.0.4 - pip", - new[] { "jupyterlab 4.2.0 - pip" }); + ["jupyterlab 4.2.0 - pip"]); ComponentRecorderTestUtilities.CheckChild( componentRecorder, "tinycss2 1.3.0 - pip", - new[] { "jupyterlab 4.2.0 - pip" }); + ["jupyterlab 4.2.0 - pip"]); } } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PipResolverTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PipResolverTests.cs index b3a08ed44..e231815cf 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/PipResolverTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PipResolverTests.cs @@ -58,7 +58,7 @@ public async Task TestPipResolverSimpleGraphAsync() Info = new PythonProjectInfo { AuthorEmail = "Microsoft ", - Classifiers = new List { "License :: OSI Approved :: MIT License" }, + Classifiers = ["License :: OSI Approved :: MIT License"], }, }; @@ -68,7 +68,7 @@ public async Task TestPipResolverSimpleGraphAsync() Info = new PythonProjectInfo { Maintainer = "Microsoft", - Classifiers = new List { "License :: OSI Approved :: MIT License", "License :: OSI Approved :: BSD License" }, + Classifiers = ["License :: OSI Approved :: MIT License", "License :: OSI Approved :: BSD License"], }, }; @@ -76,9 +76,9 @@ public async Task TestPipResolverSimpleGraphAsync() this.pyPiClient.Setup(x => x.GetProjectAsync(b)).ReturnsAsync(bProject); this.pyPiClient.Setup(x => x.GetProjectAsync(c)).ReturnsAsync(cProject); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync(new List { b }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync(new List { c }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.0", cReleases["1.0"].First())).ReturnsAsync(new List { }); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync([b]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync([c]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.0", cReleases["1.0"].First())).ReturnsAsync([]); var dependencies = new List { a }; @@ -135,7 +135,7 @@ public async Task TestPipResolverNonExistantRootAsync() var dneProject = new PythonProject { - Releases = new SortedDictionary>(), + Releases = [], }; this.pyPiClient.Setup(x => x.GetProjectAsync(a)).ReturnsAsync(aProject); @@ -143,9 +143,9 @@ public async Task TestPipResolverNonExistantRootAsync() this.pyPiClient.Setup(x => x.GetProjectAsync(c)).ReturnsAsync(cProject); this.pyPiClient.Setup(x => x.GetProjectAsync(doesNotExist)).ReturnsAsync(dneProject); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync(new List { b }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync(new List { c }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.0", cReleases["1.0"].First())).ReturnsAsync(new List { }); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync([b]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync([c]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.0", cReleases["1.0"].First())).ReturnsAsync([]); var dependencies = new List { a, doesNotExist }; @@ -202,7 +202,7 @@ public async Task TestPipResolverInvalidSpecAsync() var dneProject = new PythonProject { - Releases = new SortedDictionary>(), + Releases = [], }; this.pyPiClient.Setup(x => x.GetProjectAsync(a)).ReturnsAsync(aProject); @@ -210,9 +210,9 @@ public async Task TestPipResolverInvalidSpecAsync() this.pyPiClient.Setup(x => x.GetProjectAsync(c)).ReturnsAsync(cProject); this.pyPiClient.Setup(x => x.GetProjectAsync(doesNotExist)).ReturnsAsync(dneProject); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync(new List { b }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync(new List { c }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.0", cReleases["1.0"].First())).ReturnsAsync(new List { }); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync([b]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync([c]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.0", cReleases["1.0"].First())).ReturnsAsync([]); var dependencies = new List { a, doesNotExist }; @@ -266,15 +266,15 @@ public async Task TestPipResolverNonExistantLeafAsync() var dneProject = new PythonProject { - Releases = new SortedDictionary>(), + Releases = [], }; this.pyPiClient.Setup(x => x.GetProjectAsync(a)).ReturnsAsync(aProject); this.pyPiClient.Setup(x => x.GetProjectAsync(b)).ReturnsAsync(bProject); this.pyPiClient.Setup(x => x.GetProjectAsync(c)).ReturnsAsync(dneProject); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync(new List { b }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync(new List { c }); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync([b]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync([c]); var dependencies = new List { a }; @@ -329,10 +329,10 @@ public async Task TestPipResolverBacktrackAsync() this.pyPiClient.Setup(x => x.GetProjectAsync(b)).ReturnsAsync(bProject); this.pyPiClient.Setup(x => x.GetProjectAsync(c)).ReturnsAsync(cProject); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync(new List { b, c }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync(new List { cAlt }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.1", cReleases["1.1"].First())).ReturnsAsync(new List { }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.0", cReleases["1.0"].First())).ReturnsAsync(new List { }); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync([b, c]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync([cAlt]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.1", cReleases["1.1"].First())).ReturnsAsync([]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.0", cReleases["1.0"].First())).ReturnsAsync([]); var dependencies = new List { a }; @@ -387,7 +387,7 @@ public async Task TestInvalidVersionSpecThrowsAsync() Info = new PythonProjectInfo { AuthorEmail = "Microsoft ", - Classifiers = new List { "License :: OSI Approved :: MIT License" }, + Classifiers = ["License :: OSI Approved :: MIT License"], }, }; @@ -397,7 +397,7 @@ public async Task TestInvalidVersionSpecThrowsAsync() Info = new PythonProjectInfo { Maintainer = "Microsoft", - Classifiers = new List { "License :: OSI Approved :: MIT License", "License :: OSI Approved :: BSD License" }, + Classifiers = ["License :: OSI Approved :: MIT License", "License :: OSI Approved :: BSD License"], }, }; @@ -405,9 +405,9 @@ public async Task TestInvalidVersionSpecThrowsAsync() this.pyPiClient.Setup(x => x.GetProjectAsync(b)).ReturnsAsync(bProject); this.pyPiClient.Setup(x => x.GetProjectAsync(c)).ReturnsAsync(cProject); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync(new List { b }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync(new List { c, c2 }); - this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.0", cReleases["1.0"].First())).ReturnsAsync(new List { }); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("a", "1.0", aReleases["1.0"].First())).ReturnsAsync([b]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("b", "1.0", bReleases["1.0"].First())).ReturnsAsync([c, c2]); + this.pyPiClient.Setup(x => x.FetchPackageDependenciesAsync("c", "1.0", cReleases["1.0"].First())).ReturnsAsync([]); var dependencies = new List { a }; @@ -470,10 +470,7 @@ private SortedDictionary> CreateReleasesDict foreach (var version in versions) { - toReturn.Add(version, new List - { - this.CreatePythonProjectRelease(), - }); + toReturn.Add(version, [this.CreatePythonProjectRelease()]); } return toReturn; diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PnpmDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PnpmDetectorTests.cs index c43b019be..6f94f34aa 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/PnpmDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PnpmDetectorTests.cs @@ -192,7 +192,7 @@ public async Task TestPnpmDetector_SameComponentMergesRootsAndLocationsAcrossMul parentComponent => parentComponent.Name == "some-other-root", parentComponent => parentComponent.Name == "query-string"); - componentRecorder.ForOneComponent(strictUriEncodeComponent.Component.Id, grouping => Assert.AreEqual(2, grouping.AllFileLocations.Count())); + componentRecorder.ForOneComponent(strictUriEncodeComponent.Component.Id, grouping => grouping.AllFileLocations.Should().HaveCount(2)); } [TestMethod] @@ -300,7 +300,7 @@ public async Task TestPnpmDetector_HandlesMalformedYamlAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -330,7 +330,7 @@ public async Task TestPnpmDetector_DependencyGraphIsCreatedAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(4); + componentRecorder.GetDetectedComponents().Should().HaveCount(4); var queryStringComponentId = PnpmParsingUtilities.CreateDetectedComponentFromPnpmPathV5("/query-string/4.3.4").Component.Id; var objectAssignComponentId = PnpmParsingUtilities.CreateDetectedComponentFromPnpmPathV5("/object-assign/4.1.1").Component.Id; diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PodDetectorTest.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PodDetectorTest.cs index 5e9afda14..82142065a 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/PodDetectorTest.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PodDetectorTest.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Detectors.Tests; +namespace Microsoft.ComponentDetection.Detectors.Tests; using System; using System.Collections.Generic; @@ -30,7 +30,7 @@ public async Task TestPodDetector_EmptyPodfileLockAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -688,7 +688,7 @@ public async Task TestPodDetector_DetectorRecognizeComponentsSpecRepoAsync() detectedComponents.Should().ContainSingle(); var firstComponent = detectedComponents.First(); - componentRecorder.ForOneComponent(firstComponent.Component.Id, grouping => Assert.AreEqual(2, Enumerable.Count(grouping.AllFileLocations))); + componentRecorder.ForOneComponent(firstComponent.Component.Id, grouping => grouping.AllFileLocations.Should().HaveCount(2)); } private void AssertPodComponentNameAndVersion(IEnumerable detectedComponents, string name, string version) diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PyPiClientTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PyPiClientTests.cs index 045e8b2f0..08529c4e5 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/PyPiClientTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PyPiClientTests.cs @@ -30,7 +30,7 @@ public class PyPiClientTests [TestMethod] public async Task GetReleases_InvalidSpecVersion_NotThrowAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0", "==1.0.0notvalid" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0", "==1.0.0notvalid"] }; var pythonProject = new PythonProject { @@ -52,7 +52,7 @@ public async Task GetReleases_InvalidSpecVersion_NotThrowAsync() public async Task GetProject_SupportsReleaseCandidatesDependenciesAsync() { const string version = "1.0.0rc4"; - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { $"=={version}" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = [$"=={version}"] }; var pythonProject = new PythonProject { @@ -74,7 +74,7 @@ public async Task GetProject_SupportsReleaseCandidatesDependenciesAsync() [TestMethod] public async Task GetReleases_DuplicateEntries_CallsGetAsync_OnceAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"] }; var pythonProject = new PythonProject { Releases = new SortedDictionary> @@ -102,7 +102,7 @@ public async Task GetReleases_DuplicateEntries_CallsGetAsync_OnceAsync() [TestMethod] public async Task GetReleases_DifferentEntries_CallsGetAsync_OnceAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"] }; var pythonProject = new PythonProject { Releases = new SortedDictionary> @@ -172,7 +172,7 @@ public async Task FetchPackageDependencies_DifferentEntries_CallsGetAsync_OnceAs [TestMethod] public async Task GetReleases_MaxEntriesVariable_CreatesNewCacheAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"] }; var pythonProject = new PythonProject { Releases = new SortedDictionary> @@ -212,7 +212,7 @@ public async Task GetReleases_MaxEntriesVariable_CreatesNewCacheAsync() [TestMethod] public async Task GetReleases_AddsUserAgentHeadersAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"] }; var pythonProject = new PythonProject { Releases = new SortedDictionary> diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PythonVersionTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PythonVersionTests.cs index 17ed3d2f1..3b57b6fbd 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/PythonVersionTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PythonVersionTests.cs @@ -83,8 +83,8 @@ public void TestPythonVersionComplexComparisons() [TestMethod] public void TestVersionValidForSpec() { - IList<(IList, IList, IList)> testCases = new List<(IList, IList, IList)> - { + IList<(IList, IList, IList)> testCases = + [ (new List { "==1.0" }, new List { "1.0" }, new List { "1.0.1", "2.0", "0.1" }), (new List { "== 1.0 " }, new List { "1.0" }, new List { "1.0.1", "2.0", "0.1" }), (new List { "==1.4.*" }, new List { "1.4", "1.4.1", "1.4.2", "1.4.3" }, new List { "1.0.1", "2.0", "0.1", "1.5", "1.5.0" }), @@ -93,7 +93,7 @@ public void TestVersionValidForSpec() (new List { ">1.0", "<1.4" }, new List { "1.1", "1.3" }, new List { "0.9", "1.5", "1.0", "1.4" }), (new List { ">1.0", "<1.4", "!=1.2" }, new List { "1.1", "1.3" }, new List { "0.9", "1.5", "1.0", "1.4", "1.2" }), (new List { "==1.1.1.dev17+gcae73d8.d20200403" }, new List { "1.1.1.dev17", "v1.1.1.dev17", "1.1.1.dev17+gcae73d8.d20200403" }, new List { "1.1.1.dev18", "1.0.1", "1.1.1" }), - }; + ]; foreach (var (specs, validVersions, invalidVersions) in testCases) { @@ -105,17 +105,17 @@ public void TestVersionValidForSpec() [TestMethod] public void TestVersionValidForSpec_VersionIsNotValid_ArgumentExceptionIsThrown() { - Action action = () => PythonVersionUtilities.VersionValidForSpec("notvalid", new List { "==1.0" }); + Action action = () => PythonVersionUtilities.VersionValidForSpec("notvalid", ["==1.0"]); action.Should().Throw(); } [TestMethod] public void TestVersionValidForSpec_SomeSpecIsNotValid_ArgumentExceptionIsThrown() { - Action action = () => PythonVersionUtilities.VersionValidForSpec("1.0.0", new List { "==notvalid" }); + Action action = () => PythonVersionUtilities.VersionValidForSpec("1.0.0", ["==notvalid"]); action.Should().Throw(); - action = () => PythonVersionUtilities.VersionValidForSpec("1.0.0", new List { "==1.1+gcae73d8.d20200403+1.0" }); + action = () => PythonVersionUtilities.VersionValidForSpec("1.0.0", ["==1.1+gcae73d8.d20200403+1.0"]); action.Should().Throw(); } } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/RustCliDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/RustCliDetectorTests.cs index 7932f90c7..790a4801b 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/RustCliDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/RustCliDetectorTests.cs @@ -598,7 +598,7 @@ public async Task RustCliDetector_RespectsFallBackVariableAsync() await writer.FlushAsync(); stream.Position = 0; this.mockComponentStreamEnumerableFactory.Setup(x => x.GetComponentStreams(It.IsAny(), new List { "Cargo.lock" }, It.IsAny(), false)) - .Returns(new[] { new ComponentStream() { Location = "Cargo.toml", Stream = stream } }); + .Returns([new ComponentStream() { Location = "Cargo.toml", Stream = stream }]); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("Cargo.toml", string.Empty) @@ -712,7 +712,7 @@ public async Task RustCliDetector_NotInGraphAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Should().HaveCount(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -762,7 +762,7 @@ public async Task RustCliDetector_InvalidNameAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Should().HaveCount(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -945,7 +945,7 @@ public async Task RustCliDetector_AuthorAndLicenseEmptyStringAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Should().HaveCount(1); + componentRecorder.GetDetectedComponents().Should().ContainSingle(); componentRecorder .GetDetectedComponents() @@ -1006,7 +1006,7 @@ public async Task RustCliDetector_FallBackLogicFailsIfNoCargoLockFoundAsync() .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Should().HaveCount(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -1052,7 +1052,7 @@ public async Task RustCliDetector_FallBackLogicTriggeredOnFailedCargoCommandAsyn await writer.FlushAsync(); stream.Position = 0; this.mockComponentStreamEnumerableFactory.Setup(x => x.GetComponentStreams(It.IsAny(), new List { "Cargo.lock" }, It.IsAny(), false)) - .Returns(new[] { new ComponentStream() { Location = "Cargo.toml", Stream = stream } }); + .Returns([new ComponentStream() { Location = "Cargo.toml", Stream = stream }]); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("Cargo.toml", string.Empty) @@ -1124,7 +1124,7 @@ public async Task RustCliDetector_FallBackLogicTriggeredOnFailedProcessingAsync( await writer.FlushAsync(); stream.Position = 0; this.mockComponentStreamEnumerableFactory.Setup(x => x.GetComponentStreams(It.IsAny(), new List { "Cargo.lock" }, It.IsAny(), false)) - .Returns(new[] { new ComponentStream() { Location = "Cargo.toml", Stream = stream } }); + .Returns([new ComponentStream() { Location = "Cargo.toml", Stream = stream }]); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("Cargo.toml", string.Empty) @@ -1195,14 +1195,14 @@ public async Task RustCliDetector_FallBackLogicSkippedOnWorkspaceErrorAsync() await writer.FlushAsync(); stream.Position = 0; this.mockComponentStreamEnumerableFactory.Setup(x => x.GetComponentStreams(It.IsAny(), new List { "Cargo.lock" }, It.IsAny(), false)) - .Returns(new[] { new ComponentStream() { Location = "Cargo.toml", Stream = stream } }); + .Returns([new ComponentStream() { Location = "Cargo.toml", Stream = stream }]); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("Cargo.toml", string.Empty) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Should().HaveCount(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); return; } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/RustCrateDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/RustCrateDetectorTests.cs index 1339f1ef2..07e7abdc8 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/RustCrateDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/RustCrateDetectorTests.cs @@ -238,7 +238,7 @@ public async Task TestGraphIsCorrectAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(6); + componentRecorder.GetDetectedComponents().Should().HaveCount(6); var graph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); // There should only be 1 @@ -315,7 +315,7 @@ public async Task TestSupportsMultipleCargoV1DefinitionPairsAsync() graph1.GetComponents().Should().BeEquivalentTo(graph2.GetComponents()); // The graphs should have detected the same components // Two Cargo.lock files - componentRecorder.ForAllComponents(x => Enumerable.Count(x.AllFileLocations).Should().Be(2)); + componentRecorder.ForAllComponents(x => x.AllFileLocations.Should().HaveCount(2)); } [TestMethod] @@ -338,7 +338,7 @@ public async Task TestSupportsMultipleCargoV2DefinitionPairsAsync() graph1.GetComponents().Should().BeEquivalentTo(graph2.GetComponents()); // The graphs should have detected the same components // Two Cargo.lock files - componentRecorder.ForAllComponents(x => x.AllFileLocations.Count().Should().Be(2)); + componentRecorder.ForAllComponents(x => x.AllFileLocations.Should().HaveCount(2)); } [TestMethod] @@ -349,7 +349,7 @@ public async Task TestRustDetectorAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(6); + componentRecorder.GetDetectedComponents().Should().HaveCount(6); IDictionary packageVersions = new Dictionary() { @@ -405,7 +405,7 @@ public async Task TestRustV2DetectorAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(7); + componentRecorder.GetDetectedComponents().Should().HaveCount(7); var packageVersions = new List() { @@ -530,7 +530,7 @@ public async Task TestRustV2Detector_DuplicatePackageAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(7); + componentRecorder.GetDetectedComponents().Should().HaveCount(7); var graph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); // There should only be 1 @@ -629,7 +629,7 @@ private async Task TestRustDetector_WorkspacesWithTopLevelDependenciesAsync(stri .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(7); + componentRecorder.GetDetectedComponents().Should().HaveCount(7); var packageVersions = new List() { @@ -696,7 +696,7 @@ private async Task TestRustDetector_WorkspacesNoTopLevelDependenciesAsync(string .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(6); + componentRecorder.GetDetectedComponents().Should().HaveCount(6); } [TestMethod] @@ -720,12 +720,12 @@ private async Task TestRustDetector_WorkspacesWithSubDirectoriesAsync(string loc var componentGraphs = componentRecorder.GetDependencyGraphsByLocation(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(6); + componentRecorder.GetDetectedComponents().Should().HaveCount(6); componentGraphs.Should().ContainSingle(); // Only 1 Cargo.lock is specified // A root Cargo.lock - componentRecorder.ForAllComponents(x => x.AllFileLocations.Count().Should().Be(1)); + componentRecorder.ForAllComponents(x => x.AllFileLocations.Should().ContainSingle()); } [TestMethod] @@ -759,7 +759,7 @@ public async Task TestRustDetector_UnequalButSemverCompatibleRootAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(2); + componentRecorder.GetDetectedComponents().Should().HaveCount(2); var graph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); // There should only be 1 @@ -797,7 +797,7 @@ public async Task TestRustDetector_GitDependencyAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(1); + componentRecorder.GetDetectedComponents().Should().ContainSingle(); var dependencyGraphs = componentRecorder.GetDependencyGraphsByLocation(); dependencyGraphs.Should().ContainSingle(); @@ -835,7 +835,7 @@ public async Task TestRustDetector_MultipleRegistriesAsync() result.ResultCode.Should().Be(ProcessingResultCode.Success); // If registries have identity, this should be 2 - componentRecorder.GetDetectedComponents().Count().Should().Be(1); + componentRecorder.GetDetectedComponents().Should().ContainSingle(); var dependencyGraphs = componentRecorder.GetDependencyGraphsByLocation(); dependencyGraphs.Should().ContainSingle(); @@ -875,7 +875,7 @@ public async Task TestRustV2Detector_StdWorkspaceDependencyAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(1); + componentRecorder.GetDetectedComponents().Should().ContainSingle(); var graph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); // There should only be 1 diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/SPDX22ComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/SPDX22ComponentDetectorTests.cs index 164e32a3e..eccbd4194 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/SPDX22ComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/SPDX22ComponentDetectorTests.cs @@ -111,10 +111,7 @@ public async Task TestSbomDetector_SimpleSbomAsync() var components = detectedComponents.ToList(); var sbomComponent = (SpdxComponent)components.FirstOrDefault()?.Component; - if (sbomComponent is null) - { - throw new AssertFailedException($"{nameof(sbomComponent)} is null"); - } + sbomComponent.Should().NotBeNull(); #pragma warning disable CA5350 // Suppress Do Not Use Weak Cryptographic Algorithms because we use SHA1 intentionally in SPDX format var checksum = BitConverter.ToString(SHA1.HashData(Encoding.UTF8.GetBytes(spdxFile))).Replace("-", string.Empty).ToLower(); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePipComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePipComponentDetectorTests.cs index d0512cb7a..3edeb681c 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePipComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePipComponentDetectorTests.cs @@ -70,8 +70,8 @@ public async Task TestPipDetector_SetupPyAndRequirementsTxtAsync() { this.pythonCommandService.Setup(x => x.PythonExistsAsync(It.IsAny())).ReturnsAsync(true); - var baseSetupPyDependencies = this.ToGitTuple(new List { "a==1.0", "b>=2.0,!=2.1", "c!=1.1" }); - var baseRequirementsTextDependencies = this.ToGitTuple(new List { "d~=1.0", "e<=2.0", "f===1.1" }); + var baseSetupPyDependencies = this.ToGitTuple(["a==1.0", "b>=2.0,!=2.1", "c!=1.1"]); + var baseRequirementsTextDependencies = this.ToGitTuple(["d~=1.0", "e<=2.0", "f===1.1"]); baseRequirementsTextDependencies.Add((null, new GitComponent(new Uri("https://github.com/example/example"), "deadbee"))); this.pythonCommandService.Setup(x => x.ParseFileAsync(Path.Join(Path.GetTempPath(), "setup.py"), null)).ReturnsAsync(baseSetupPyDependencies); @@ -129,8 +129,8 @@ public async Task TestPipDetector_ComponentsDedupedAcrossFilesAsync() { this.pythonCommandService.Setup(x => x.PythonExistsAsync(It.IsAny())).ReturnsAsync(true); - var baseRequirementsTextDependencies = this.ToGitTuple(new List { "d~=1.0", "e<=2.0", "f===1.1", "h==1.3" }); - var baseRequirementsTextDependencies2 = this.ToGitTuple(new List { "D~=1.0", "E<=2.0", "F===1.1", "g==2" }); + var baseRequirementsTextDependencies = this.ToGitTuple(["d~=1.0", "e<=2.0", "f===1.1", "h==1.3"]); + var baseRequirementsTextDependencies2 = this.ToGitTuple(["D~=1.0", "E<=2.0", "F===1.1", "g==2"]); this.pythonCommandService.Setup(x => x.ParseFileAsync(Path.Join(Path.GetTempPath(), "requirements.txt"), null)).ReturnsAsync(baseRequirementsTextDependencies); this.pythonCommandService.Setup(x => x.ParseFileAsync(Path.Join(Path.GetTempPath(), "TEST", "requirements.txt"), null)).ReturnsAsync(baseRequirementsTextDependencies2); @@ -158,7 +158,7 @@ public async Task TestPipDetector_ComponentsDedupedAcrossFilesAsync() .ExecuteDetectorAsync(); result.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(5); + componentRecorder.GetDetectedComponents().Should().HaveCount(5); } [TestMethod] @@ -169,8 +169,8 @@ public async Task TestPipDetector_ComponentRecorderAsync() const string file1 = "c:\\repo\\setup.py"; const string file2 = "c:\\repo\\lib\\requirements.txt"; - var baseReqs = this.ToGitTuple(new List { "a~=1.0", "b<=2.0", }); - var altReqs = this.ToGitTuple(new List { "c~=1.0", "d<=2.0", "e===1.1" }); + var baseReqs = this.ToGitTuple(["a~=1.0", "b<=2.0",]); + var altReqs = this.ToGitTuple(["c~=1.0", "d<=2.0", "e===1.1"]); this.pythonCommandService.Setup(x => x.ParseFileAsync(file1, null)).ReturnsAsync(baseReqs); this.pythonCommandService.Setup(x => x.ParseFileAsync(file2, null)).ReturnsAsync(altReqs); @@ -190,7 +190,7 @@ public async Task TestPipDetector_ComponentRecorderAsync() rootA.Children.Add(red); rootB.Children.Add(green); - rootC.Children.AddRange(new[] { red, blue, }); + rootC.Children.AddRange([red, blue,]); rootD.Children.Add(cat); green.Children.Add(cat); cat.Children.Add(lion); @@ -199,11 +199,11 @@ public async Task TestPipDetector_ComponentRecorderAsync() this.pythonResolver.Setup(x => x.ResolveRootsAsync(It.IsAny(), It.Is>(p => p.Any(d => d.Name == "a")))) - .ReturnsAsync(new List { rootA, rootB, }); + .ReturnsAsync([rootA, rootB,]); this.pythonResolver.Setup(x => x.ResolveRootsAsync(It.IsAny(), It.Is>(p => p.Any(d => d.Name == "c")))) - .ReturnsAsync(new List { rootC, rootD, rootE, }); + .ReturnsAsync([rootC, rootD, rootE,]); var (result, componentRecorder) = await this.DetectorTestUtility .WithFile("setup.py", string.Empty, fileLocation: file1) @@ -231,12 +231,12 @@ public async Task TestPipDetector_ComponentRecorderAsync() x => x.Id == rootId); } - this.CheckChild(componentRecorder, "red 0.2 - pip", new[] { "a 1.0 - pip", "c 1.0 - pip", }); - this.CheckChild(componentRecorder, "green 1.3 - pip", new[] { "b 2.1 - pip", }); - this.CheckChild(componentRecorder, "blue 0.4 - pip", new[] { "c 1.0 - pip", }); - this.CheckChild(componentRecorder, "cat 1.8 - pip", new[] { "b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip", }); - this.CheckChild(componentRecorder, "lion 3.8 - pip", new[] { "b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip", }); - this.CheckChild(componentRecorder, "dog 2.1 - pip", new[] { "c 1.0 - pip", }); + this.CheckChild(componentRecorder, "red 0.2 - pip", ["a 1.0 - pip", "c 1.0 - pip",]); + this.CheckChild(componentRecorder, "green 1.3 - pip", ["b 2.1 - pip",]); + this.CheckChild(componentRecorder, "blue 0.4 - pip", ["c 1.0 - pip",]); + this.CheckChild(componentRecorder, "cat 1.8 - pip", ["b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip",]); + this.CheckChild(componentRecorder, "lion 3.8 - pip", ["b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip",]); + this.CheckChild(componentRecorder, "dog 2.1 - pip", ["c 1.0 - pip",]); var graphsByLocations = componentRecorder.GetDependencyGraphsByLocation(); graphsByLocations.Should().HaveCount(2); @@ -302,7 +302,7 @@ private void CheckGraphStructure(IDependencyGraph graph, Dictionary( + recorder.AssertAllExplicitlyReferencedComponents( childId, parentIds.Select(parentId => new Func(x => x.Id == parentId)).ToArray()); } diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePypiClientTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePypiClientTests.cs index e1b91127c..f46ccb74d 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePypiClientTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePypiClientTests.cs @@ -1,7 +1,6 @@ namespace Microsoft.ComponentDetection.Detectors.Tests; using System; -using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; @@ -46,7 +45,7 @@ private ISimplePyPiClient CreateSimplePypiClient(HttpMessageHandler messageHandl [TestMethod] public async Task GetSimplePypiProject_DuplicateEntries_CallsGetAsync_OnceAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" }, Name = "boto3" }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"], Name = "boto3" }; var pythonProject = this.SampleValidApiJsonResponse("boto3", "0.0.1"); var mockHandler = this.MockHttpMessageHandler(pythonProject, HttpStatusCode.OK); @@ -67,10 +66,10 @@ public async Task GetSimplePypiProject_DuplicateEntries_CallsGetAsync_OnceAsync( [TestMethod] public async Task GetSimplePypiProject_DifferentEntries_CallsGetAsync_TwiceAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"] }; var pythonProject = new SimplePypiProject() { - Files = new List { new SimplePypiProjectRelease() }, + Files = [new SimplePypiProjectRelease()], }; var mockHandler = this.MockHttpMessageHandler(JsonConvert.SerializeObject(pythonProject), HttpStatusCode.OK); @@ -96,15 +95,15 @@ public async Task GetSimplePypiProject_DifferentEntries_CallsGetAsync_TwiceAsync [TestMethod] public async Task GetSimplePypiProject_ReturnsValidSimplePypiProjectAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" }, Name = "boto3" }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"], Name = "boto3" }; var sampleApiResponse = this.SampleValidApiJsonResponse("boto3", "0.0.1"); var expectedResult = new SimplePypiProject() { - Files = new List - { + Files = + [ new SimplePypiProjectRelease() { FileName = "boto3-0.0.1-py2.py3-none-any.whl", Url = new Uri("https://files.pythonhosted.org/packages/3f/95/a24847c245befa8c50a9516cbdca309880bd21b5879e7c895e953217e947/boto3-0.0.1-py2.py3-none-any.whl"), Size = 45469 }, new SimplePypiProjectRelease() { FileName = "boto3-0.0.1.tar.gz", Url = new Uri("https://files.pythonhosted.org/packages/df/18/4e36b93f6afb79b5f67b38f7d235773a21831b193602848c590f8a008608/boto3-0.0.1.tar.gz"), Size = 33415 }, - }, + ], }; var mockHandler = this.MockHttpMessageHandler(sampleApiResponse, HttpStatusCode.OK); @@ -117,7 +116,7 @@ public async Task GetSimplePypiProject_ReturnsValidSimplePypiProjectAsync() [TestMethod] public async Task GetSimplePypiProject_InvalidSpec_NotThrowAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" }, Name = "randomName" }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"], Name = "randomName" }; var mockHandler = this.MockHttpMessageHandler("404 Not Found", HttpStatusCode.NotFound); var simplePypiClient = this.CreateSimplePypiClient(mockHandler.Object, new Mock().Object, new Mock>().Object); @@ -130,7 +129,7 @@ public async Task GetSimplePypiProject_InvalidSpec_NotThrowAsync() [TestMethod] public async Task GetSimplePypiProject_UnexpectedContentTypeReturnedByApi_NotThrowAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"] }; var content = "\r\n\t

Links for boto3

\r\n\tboto3-0.0.1-py2.py3-none-any.whl
"; var mockHandler = this.MockHttpMessageHandler(content, HttpStatusCode.OK); @@ -144,7 +143,7 @@ public async Task GetSimplePypiProject_UnexpectedContentTypeReturnedByApi_NotThr [TestMethod] public async Task GetSimplePypiProject_ShouldRetryAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"] }; var mockHandler = this.MockHttpMessageHandler(string.Empty, HttpStatusCode.InternalServerError); var simplePypiClient = this.CreateSimplePypiClient(mockHandler.Object, new Mock().Object, new Mock>().Object); @@ -164,7 +163,7 @@ public async Task GetSimplePypiProject_ShouldRetryAsync() [TestMethod] public async Task GetSimplePypiProject_ShouldNotRetryAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"] }; var mockHandler = this.MockHttpMessageHandler("some content", HttpStatusCode.MultipleChoices); var simplePypiClient = this.CreateSimplePypiClient(mockHandler.Object, new Mock().Object, new Mock>().Object); @@ -182,7 +181,7 @@ public async Task GetSimplePypiProject_ShouldNotRetryAsync() [TestMethod] public async Task GetSimplePypiProject_AddsCorrectHeadersAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"] }; var pythonProject = this.SampleValidApiJsonResponse("boto3", "0.0.1"); var mockHandler = this.MockHttpMessageHandler(pythonProject, HttpStatusCode.OK); @@ -206,7 +205,7 @@ public async Task GetSimplePypiProject_AddsCorrectHeadersAsync() [TestMethod] public async Task GetSimplePypiProject_MaxEntriesVariable_CreatesNewCacheAsync() { - var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = new List { "==1.0.0" } }; + var pythonSpecs = new PipDependencySpecification { DependencySpecifiers = ["==1.0.0"] }; var pythonProject = this.SampleValidApiJsonResponse("boto3", "0.0.1"); var mockHandler = this.MockHttpMessageHandler(pythonProject, HttpStatusCode.OK); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePythonResolverTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePythonResolverTests.cs index 63216029a..71201aa8d 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePythonResolverTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/SimplePythonResolverTests.cs @@ -49,8 +49,8 @@ public async Task TestPipResolverSimpleGraphAsync() this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("b")))).ReturnsAsync(bReleases); this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("c")))).ReturnsAsync(cReleases); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString(new List() { b }))); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString(new List() { c }))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString([b]))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString([c]))); this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(cReleases.Files.First().Url)).ReturnsAsync(new MemoryStream()); var dependencies = new List { specA }; @@ -95,8 +95,8 @@ public async Task TestPipResolverNonExistantRootAsync() this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("c")))).ReturnsAsync(cReleases); this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("dne")))).ReturnsAsync(this.CreateSimplePypiProject(new List<(string, string)>())); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString(new List() { b }))); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString(new List() { c }))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString([b]))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString([c]))); this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(cReleases.Files.First().Url)).ReturnsAsync(new MemoryStream()); var dependencies = new List { specA, specDne }; @@ -137,8 +137,8 @@ public async Task TestPipResolverNonExistantLeafAsync() this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("b")))).ReturnsAsync(bReleases); this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("c")))).ReturnsAsync(cReleases); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString(new List() { b }))); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString(new List() { c }))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString([b]))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString([c]))); var dependencies = new List { specA }; @@ -179,8 +179,8 @@ public async Task TestPipResolverBacktrackAsync() this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("b")))).ReturnsAsync(bReleases); this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("c") && x.DependencySpecifiers.First().Equals("<=1.1")))).ReturnsAsync(cReleases); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString(new List() { b, c }))); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString(new List() { cAlt }))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString([b, c]))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString([cAlt]))); this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(cReleases.Files.First().Url)).ReturnsAsync(new MemoryStream()); this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(cReleases.Files.Last().Url)).ReturnsAsync(new MemoryStream()); @@ -228,8 +228,8 @@ public async Task TestPipResolverInvalidVersionSpecAsync() this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("b")))).ReturnsAsync(bReleases); this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("c") && x.DependencySpecifiers.First().Equals("<=1.1")))).ReturnsAsync(cReleases); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString(new List() { b, c }))); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString(new List() { cAlt }))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString([b, c]))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString([cAlt]))); var dependencies = new List { specA }; @@ -275,8 +275,8 @@ public async Task TestPipResolverVersionExtractionWithDifferentVersionFormatsAsy this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("b")))).ReturnsAsync(bReleases); this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("c")))).ReturnsAsync(cReleases); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.15.0", this.CreateMetadataString(new List() { b }))); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.19", this.CreateMetadataString(new List() { c }))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.15.0", this.CreateMetadataString([b]))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.19", this.CreateMetadataString([c]))); this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(cReleases.Files.First().Url)).ReturnsAsync(new MemoryStream()); var dependencies = new List { specA }; @@ -318,8 +318,8 @@ public async Task TestPipResolverVersionExtractionWithDifferentPackageTypesAsync this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("b")))).ReturnsAsync(bReleases); this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("c")))).ReturnsAsync(cReleases); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.20", this.CreateMetadataString(new List() { b }))); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0.0", this.CreateMetadataString(new List() { c }))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.20", this.CreateMetadataString([b]))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0.0", this.CreateMetadataString([c]))); this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(cReleases.Files.First().Url)).ReturnsAsync(new MemoryStream()); var dependencies = new List { specA }; @@ -360,8 +360,8 @@ public async Task TestPipResolverBadVersionSpecAsync() this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("b")))).ReturnsAsync(bReleases); this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("c")))).ReturnsAsync(cReleases); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString(new List() { b }))); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString(new List() { c, c2 }))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "1.0", this.CreateMetadataString([b]))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString([c, c2]))); this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(cReleases.Files.First().Url)).ReturnsAsync(new MemoryStream()); var dependencies = new List { specA }; @@ -437,7 +437,7 @@ public async Task TestPipResolverVersionExtractAllValidVersionsAsync() .ReturnsAsync(releases); this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(releases.Files.First().Url)) - .ReturnsAsync(this.CreatePypiZip(componentName, versions[i], this.CreateMetadataString(new List()))); + .ReturnsAsync(this.CreatePypiZip(componentName, versions[i], this.CreateMetadataString([]))); } var resolver = new SimplePythonResolver(this.simplePyPiClient.Object, this.loggerMock.Object); @@ -477,8 +477,8 @@ public async Task TestPipResolverWithMultipleReleasesAsync() this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("b")))).ReturnsAsync(bReleases); this.simplePyPiClient.Setup(x => x.GetSimplePypiProjectAsync(It.Is(x => x.Name.Equals("c")))).ReturnsAsync(cReleases); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "10.0.0", this.CreateMetadataString(new List() { b }))); - this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString(new List() { c }))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(aReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("a", "10.0.0", this.CreateMetadataString([b]))); + this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(bReleases.Files.First().Url)).ReturnsAsync(this.CreatePypiZip("b", "1.0", this.CreateMetadataString([c]))); this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(cReleases.Files.First().Url)).ReturnsAsync(new MemoryStream()); this.simplePyPiClient.Setup(x => x.FetchPackageFileStreamAsync(cReleases.Files.Last().Url)).ReturnsAsync(new MemoryStream()); @@ -530,7 +530,7 @@ private bool CompareGraphs(PipGraphNode a, PipGraphNode b) private SimplePypiProject CreateSimplePypiProject(IList<(string Version, string PackageTypes)> versionAndTypes) { - var toReturn = new SimplePypiProject() { Files = new List() }; + var toReturn = new SimplePypiProject() { Files = [] }; foreach ((var version, var packagetype) in versionAndTypes) { diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/VcpkgComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/VcpkgComponentDetectorTests.cs index 8256b2981..f149aec1b 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/VcpkgComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/VcpkgComponentDetectorTests.cs @@ -73,10 +73,7 @@ public async Task TestNlohmannAsync() var components = detectedComponents.ToList(); var sbomComponent = (VcpkgComponent)components.FirstOrDefault()?.Component; - if (sbomComponent is null) - { - throw new AssertFailedException($"{nameof(sbomComponent)} is null"); - } + sbomComponent.Should().NotBeNull(); components.Should().ContainSingle(); sbomComponent.Id.Should().Be("git+https://github.com/Microsoft/vcpkg#ports/nlohmann-json : nlohmann-json 3.10.4#5 - Vcpkg"); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/YarnBlockFileTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/YarnBlockFileTests.cs index af64b182f..868db27cd 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/YarnBlockFileTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/YarnBlockFileTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Detectors.Tests; +namespace Microsoft.ComponentDetection.Detectors.Tests; using System; using System.IO; @@ -17,9 +17,8 @@ public class YarnBlockFileTests [TestMethod] public async Task BlockFileParserWithNullStream_FailsAsync() { - static async Task Action() => await YarnBlockFile.CreateBlockFileAsync(null); - - await Assert.ThrowsExceptionAsync(Action); + var action = async () => await YarnBlockFile.CreateBlockFileAsync(null); + await action.Should().ThrowAsync(); } [TestMethod] @@ -29,9 +28,8 @@ public async Task BlockFileParserWithClosedStream_FailsAsync() stream.Close(); - async Task Action() => await YarnBlockFile.CreateBlockFileAsync(stream); - - await Assert.ThrowsExceptionAsync(Action); + var action = async () => await YarnBlockFile.CreateBlockFileAsync(stream); + await action.Should().ThrowAsync(); } [TestMethod] diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/YarnLockDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/YarnLockDetectorTests.cs index d45535042..e8d1cd7ed 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/YarnLockDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/YarnLockDetectorTests.cs @@ -33,7 +33,7 @@ public YarnLockDetectorTests() // TODO: Mock all of this correctly var loggerMock = new Mock>(); this.yarnLockParser = new YarnLockParser(loggerMock.Object); - this.yarnLockFileFactory = new YarnLockFileFactory(new[] { this.yarnLockParser }); + this.yarnLockFileFactory = new YarnLockFileFactory([this.yarnLockParser]); var yarnLockFileFactoryMock = new Mock(); var recorderMock = new Mock(); @@ -52,11 +52,11 @@ public async Task WellFormedYarnLockV1WithZeroComponents_FindsNothingAsync() var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLock) - .WithFile("package.json", packageJson, new List { "package.json" }) + .WithFile("package.json", packageJson, ["package.json"]) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -67,11 +67,11 @@ public async Task WellFormedYarnLockV2WithZeroComponents_FindsNothingAsync() var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLock) - .WithFile("package.json", packageJson, new List { "package.json" }) + .WithFile("package.json", packageJson, ["package.json"]) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -96,11 +96,11 @@ public async Task MalformedYarnLockV1WithOneComponent_FindsNoComponentAsync() var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLock) - .WithFile("package.json", packageJsonContent, new List { "package.json" }) + .WithFile("package.json", packageJsonContent, ["package.json"]) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -113,7 +113,7 @@ public async Task MalformedYarnLockV2WithOneComponent_FindsNoComponentAsync() var builder = new StringBuilder(); - builder.AppendLine(this.CreateYarnLockV2FileContent(new List())); + builder.AppendLine(this.CreateYarnLockV2FileContent([])); builder.AppendLine($"{componentName0}@{providedVersion0}"); builder.AppendLine($" version {version0}"); builder.AppendLine($" resolved {resolved0}"); @@ -123,11 +123,11 @@ public async Task MalformedYarnLockV2WithOneComponent_FindsNoComponentAsync() var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLock) - .WithFile("package.json", packageJsonContent, new List { "package.json" }) + .WithFile("package.json", packageJsonContent, ["package.json"]) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); - componentRecorder.GetDetectedComponents().Count().Should().Be(0); + componentRecorder.GetDetectedComponents().Should().BeEmpty(); } [TestMethod] @@ -142,12 +142,12 @@ public async Task WellFormedYarnLockV1WithOneComponent_FindsComponentAsync() ResolvedVersion = "https://resolved0/a/resolved", }; - var yarnLock = this.CreateYarnLockV1FileContent(new List { componentA }); + var yarnLock = this.CreateYarnLockV1FileContent([componentA]); var (packageJsonName, packageJsonContent, packageJsonPath) = NpmTestUtilities.GetPackageJsonOneRoot(componentA.Name, componentA.RequestedVersion); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLock) - .WithFile("package.json", packageJsonContent, new List { "package.json" }) + .WithFile("package.json", packageJsonContent, ["package.json"]) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); @@ -174,12 +174,12 @@ public async Task WellFormedYarnLockV2WithOneComponent_FindsComponentAsync() ResolvedVersion = "https://resolved0/a/resolved", }; - var yarnLock = this.CreateYarnLockV2FileContent(new List { componentA }); + var yarnLock = this.CreateYarnLockV2FileContent([componentA]); var (packageJsonName, packageJsonContent, packageJsonPath) = NpmTestUtilities.GetPackageJsonOneRoot(componentA.Name, componentA.RequestedVersion); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLock) - .WithFile("package.json", packageJsonContent, new List { "package.json" }) + .WithFile("package.json", packageJsonContent, ["package.json"]) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); @@ -208,7 +208,7 @@ public async Task WellFormedYarnLockV1WithWorkspace_FindsComponentAsync() Name = Guid.NewGuid().ToString("N"), }; - var componentStream = YarnTestUtilities.GetMockedYarnLockStream("yarn.lock", this.CreateYarnLockV1FileContent(new List { componentA })); + var componentStream = YarnTestUtilities.GetMockedYarnLockStream("yarn.lock", this.CreateYarnLockV1FileContent([componentA])); var workspaceJson = new { @@ -224,8 +224,8 @@ public async Task WellFormedYarnLockV1WithWorkspace_FindsComponentAsync() var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", componentStream.Stream) - .WithFile("package.json", packageStream.Stream, new[] { "package.json" }) - .WithFile("package.json", workspaceJsonComponentStream.Stream, new[] { "package.json" }, Path.Combine(Path.GetTempPath(), "workspace", "package.json")) + .WithFile("package.json", packageStream.Stream, ["package.json"]) + .WithFile("package.json", workspaceJsonComponentStream.Stream, ["package.json"], Path.Combine(Path.GetTempPath(), "workspace", "package.json")) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); @@ -254,7 +254,7 @@ public async Task WellFormedYarnLockV1WithWorkspace_CheckFilePathsAsync() Name = Guid.NewGuid().ToString("N"), }; - var componentStream = YarnTestUtilities.GetMockedYarnLockStream("yarn.lock", this.CreateYarnLockV1FileContent(new List { componentA })); + var componentStream = YarnTestUtilities.GetMockedYarnLockStream("yarn.lock", this.CreateYarnLockV1FileContent([componentA])); var workspaceJson = new { @@ -270,8 +270,8 @@ public async Task WellFormedYarnLockV1WithWorkspace_CheckFilePathsAsync() var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", componentStream.Stream) - .WithFile("package.json", workspaceJsonComponentStream.Stream, new[] { "package.json" }, Path.Combine(Path.GetTempPath(), "package.json")) - .WithFile("package.json", packageStream.Stream, new[] { "package.json" }, Path.Combine(Path.GetTempPath(), "workspace", "package.json")) + .WithFile("package.json", workspaceJsonComponentStream.Stream, ["package.json"], Path.Combine(Path.GetTempPath(), "package.json")) + .WithFile("package.json", packageStream.Stream, ["package.json"], Path.Combine(Path.GetTempPath(), "workspace", "package.json")) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); @@ -300,7 +300,7 @@ public async Task WellFormedYarnLockV2WithWorkspace_FindsComponentAsync() Name = Guid.NewGuid().ToString("N"), }; - var componentStream = YarnTestUtilities.GetMockedYarnLockStream("yarn.lock", this.CreateYarnLockV2FileContent(new List { componentA })); + var componentStream = YarnTestUtilities.GetMockedYarnLockStream("yarn.lock", this.CreateYarnLockV2FileContent([componentA])); var workspaceJson = new { @@ -316,8 +316,8 @@ public async Task WellFormedYarnLockV2WithWorkspace_FindsComponentAsync() var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", componentStream.Stream) - .WithFile("package.json", packageStream.Stream, new[] { "package.json" }) - .WithFile("package.json", workspaceJsonComponentStream.Stream, new[] { "package.json" }, Path.Combine(Path.GetTempPath(), "workspace", "package.json")) + .WithFile("package.json", packageStream.Stream, ["package.json"]) + .WithFile("package.json", workspaceJsonComponentStream.Stream, ["package.json"], Path.Combine(Path.GetTempPath(), "workspace", "package.json")) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); @@ -346,7 +346,7 @@ public async Task WellFormedYarnLockV1WithWorkspaceAltForm_FindsComponentAsync() Name = Guid.NewGuid().ToString("N"), }; - var componentStream = YarnTestUtilities.GetMockedYarnLockStream("yarn.lock", this.CreateYarnLockV1FileContent(new List { componentA })); + var componentStream = YarnTestUtilities.GetMockedYarnLockStream("yarn.lock", this.CreateYarnLockV1FileContent([componentA])); var workspaceJson = new { @@ -362,8 +362,8 @@ public async Task WellFormedYarnLockV1WithWorkspaceAltForm_FindsComponentAsync() var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", componentStream.Stream) - .WithFile("package.json", packageStream.Stream, new[] { "package.json" }) - .WithFile("package.json", workspaceJsonComponentStream.Stream, new[] { "package.json" }, Path.Combine(Path.GetTempPath(), "workspace", "package.json")) + .WithFile("package.json", packageStream.Stream, ["package.json"]) + .WithFile("package.json", workspaceJsonComponentStream.Stream, ["package.json"], Path.Combine(Path.GetTempPath(), "workspace", "package.json")) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); @@ -392,7 +392,7 @@ public async Task WellFormedYarnLockV2WithWorkspaceAltForm_FindsComponentAsync() Name = Guid.NewGuid().ToString("N"), }; - var componentStream = YarnTestUtilities.GetMockedYarnLockStream("yarn.lock", this.CreateYarnLockV2FileContent(new List { componentA })); + var componentStream = YarnTestUtilities.GetMockedYarnLockStream("yarn.lock", this.CreateYarnLockV2FileContent([componentA])); var workspaceJson = new { @@ -408,8 +408,8 @@ public async Task WellFormedYarnLockV2WithWorkspaceAltForm_FindsComponentAsync() var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", componentStream.Stream) - .WithFile("package.json", packageStream.Stream, new[] { "package.json" }) - .WithFile("package.json", workspaceJsonComponentStream.Stream, new[] { "package.json" }, Path.Combine(Path.GetTempPath(), "workspace", "package.json")) + .WithFile("package.json", packageStream.Stream, ["package.json"]) + .WithFile("package.json", workspaceJsonComponentStream.Stream, ["package.json"], Path.Combine(Path.GetTempPath(), "workspace", "package.json")) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); @@ -447,12 +447,12 @@ public async Task WellFormedYarnLockV1WithMoreThanOneComponent_FindsComponentsAs componentA.Dependencies = new List<(string, string)> { (componentB.Name, componentB.RequestedVersion) }; - var yarnLock = this.CreateYarnLockV1FileContent(new List { componentA, componentB }); + var yarnLock = this.CreateYarnLockV1FileContent([componentA, componentB]); var (packageJsonName, packageJsonContent, packageJsonPath) = NpmTestUtilities.GetPackageJsonOneRoot(componentA.Name, componentA.RequestedVersion); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLock) - .WithFile("package.json", packageJsonContent, new List { "package.json" }) + .WithFile("package.json", packageJsonContent, ["package.json"]) .ExecuteDetectorAsync(); var detectedComponents = componentRecorder.GetDetectedComponents(); @@ -494,12 +494,12 @@ public async Task WellFormedYarnLockV2WithMoreThanOneComponent_FindsComponentsAs componentA.Dependencies = new List<(string, string)> { (componentB.Name, componentB.RequestedVersion) }; - var yarnLock = this.CreateYarnLockV2FileContent(new List { componentA, componentB }); + var yarnLock = this.CreateYarnLockV2FileContent([componentA, componentB]); var (packageJsonName, packageJsonContent, packageJsonPath) = NpmTestUtilities.GetPackageJsonOneRoot(componentA.Name, componentA.RequestedVersion); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLock) - .WithFile("package.json", packageJsonContent, new List { "package.json" }) + .WithFile("package.json", packageJsonContent, ["package.json"]) .ExecuteDetectorAsync(); var detectedComponents = componentRecorder.GetDetectedComponents(); @@ -572,7 +572,7 @@ public async Task WellFormedYarnLockV1WithMultiRootedComponent_FindsAllRootsAsyn var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLock) - .WithFile("package.json", packageJsonContent, new List { "package.json" }) + .WithFile("package.json", packageJsonContent, ["package.json"]) .ExecuteDetectorAsync(); var detectedComponentes = componentRecorder.GetDetectedComponents(); @@ -632,7 +632,7 @@ public async Task WellFormedYarnLockV2WithMultiRootedComponent_FindsAllRootsAsyn var builder = new StringBuilder(); - builder.AppendLine(this.CreateYarnLockV2FileContent(new List())); + builder.AppendLine(this.CreateYarnLockV2FileContent([])); builder.AppendLine($"{componentNameA}@{requestedVersionA}:"); builder.AppendLine($" version: {actualVersionA}"); builder.AppendLine($" resolved: {resolvedA}"); @@ -648,7 +648,7 @@ public async Task WellFormedYarnLockV2WithMultiRootedComponent_FindsAllRootsAsyn var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLock) - .WithFile("package.json", packageJsonContent, new List { "package.json" }) + .WithFile("package.json", packageJsonContent, ["package.json"]) .ExecuteDetectorAsync(); var detectedComponentes = componentRecorder.GetDetectedComponents(); @@ -702,12 +702,12 @@ public async Task DependencyGraphV1IsGeneratedCorrectlyAsync() componentA.Dependencies = new List<(string, string)> { (componentB.Name, componentB.RequestedVersion) }; componentB.Dependencies = new List<(string, string)> { (componentC.Name, componentC.RequestedVersion) }; - var yarnLockFileContent = this.CreateYarnLockV1FileContent(new List { componentA, componentB, componentC }); - var packageJsonFileContent = this.CreatePackageJsonFileContent(new List { componentA, componentB, componentC }); + var yarnLockFileContent = this.CreateYarnLockV1FileContent([componentA, componentB, componentC]); + var packageJsonFileContent = this.CreatePackageJsonFileContent([componentA, componentB, componentC]); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLockFileContent) - .WithFile("package.json", packageJsonFileContent, new List { "package.json" }) + .WithFile("package.json", packageJsonFileContent, ["package.json"]) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); @@ -719,13 +719,13 @@ public async Task DependencyGraphV1IsGeneratedCorrectlyAsync() var dependencyGraph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); - dependencyGraph.GetDependenciesForComponent(componentAId).Should().HaveCount(1); + dependencyGraph.GetDependenciesForComponent(componentAId).Should().ContainSingle(); dependencyGraph.GetDependenciesForComponent(componentAId).Should().Contain(componentBId); - dependencyGraph.GetDependenciesForComponent(componentBId).Should().HaveCount(1); + dependencyGraph.GetDependenciesForComponent(componentBId).Should().ContainSingle(); dependencyGraph.GetDependenciesForComponent(componentBId).Should().Contain(componentCId); - dependencyGraph.GetDependenciesForComponent(componentCId).Should().HaveCount(0); + dependencyGraph.GetDependenciesForComponent(componentCId).Should().BeEmpty(); } [TestMethod] @@ -758,12 +758,12 @@ public async Task DependencyGraphV2IsGeneratedCorrectlyAsync() componentA.Dependencies = new List<(string, string)> { (componentB.Name, componentB.RequestedVersion) }; componentB.Dependencies = new List<(string, string)> { (componentC.Name, componentC.RequestedVersion) }; - var yarnLockFileContent = this.CreateYarnLockV2FileContent(new List { componentA, componentB, componentC }); - var packageJsonFileContent = this.CreatePackageJsonFileContent(new List { componentA, componentB, componentC }); + var yarnLockFileContent = this.CreateYarnLockV2FileContent([componentA, componentB, componentC]); + var packageJsonFileContent = this.CreatePackageJsonFileContent([componentA, componentB, componentC]); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLockFileContent) - .WithFile("package.json", packageJsonFileContent, new List { "package.json" }) + .WithFile("package.json", packageJsonFileContent, ["package.json"]) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); @@ -775,13 +775,13 @@ public async Task DependencyGraphV2IsGeneratedCorrectlyAsync() var dependencyGraph = componentRecorder.GetDependencyGraphsByLocation().Values.First(); - dependencyGraph.GetDependenciesForComponent(componentAId).Should().HaveCount(1); + dependencyGraph.GetDependenciesForComponent(componentAId).Should().ContainSingle(); dependencyGraph.GetDependenciesForComponent(componentAId).Should().Contain(componentBId); - dependencyGraph.GetDependenciesForComponent(componentBId).Should().HaveCount(1); + dependencyGraph.GetDependenciesForComponent(componentBId).Should().ContainSingle(); dependencyGraph.GetDependenciesForComponent(componentBId).Should().Contain(componentCId); - dependencyGraph.GetDependenciesForComponent(componentCId).Should().HaveCount(0); + dependencyGraph.GetDependenciesForComponent(componentCId).Should().BeEmpty(); } [TestMethod] @@ -795,17 +795,17 @@ public async Task MalformedYarnLockV1_DuplicateAsync() var builder = new StringBuilder(); - builder.AppendLine(this.CreateYarnLockV2FileContent(new List())); + builder.AppendLine(this.CreateYarnLockV2FileContent([])); builder.AppendLine($"\"{componentNameA}@{requestedVersionA}\", \"{componentNameB}@{requestedVersionB}\":"); builder.AppendLine($" version: {actualVersion}"); builder.AppendLine(); var yarnLockFileContent = builder.ToString(); - var packageJsonFileContent = this.CreatePackageJsonFileContent(new List()); + var packageJsonFileContent = this.CreatePackageJsonFileContent([]); var (scanResult, componentRecorder) = await this.DetectorTestUtility .WithFile("yarn.lock", yarnLockFileContent) - .WithFile("package.json", packageJsonFileContent, new List { "package.json" }) + .WithFile("package.json", packageJsonFileContent, ["package.json"]) .ExecuteDetectorAsync(); scanResult.ResultCode.Should().Be(ProcessingResultCode.Success); diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/YarnParserTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/YarnParserTests.cs index a144c597a..80d9001f3 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/YarnParserTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/YarnParserTests.cs @@ -92,21 +92,15 @@ public void YarnLockParser_V1_ParsesBlocks() "a@^1.0.0", "1.0.0", "https://a", - new List - { - this.CreateDependencyBlock(new Dictionary { { "xyz", "2" } }), - }, + [this.CreateDependencyBlock(new Dictionary { { "xyz", "2" } })], yarnLockFileVersion), this.CreateBlock( "b@2.4.6", "2.4.6", "https://b", - new List - { - this.CreateDependencyBlock(new Dictionary { { "xyz", "2.4" }, { "a", "^1.0.0" } }), - }, + [this.CreateDependencyBlock(new Dictionary { { "xyz", "2.4" }, { "a", "^1.0.0" } })], yarnLockFileVersion), - this.CreateBlock("xyz@2, xyz@2.4", "2.4.3", "https://xyz", Enumerable.Empty(), yarnLockFileVersion), + this.CreateBlock("xyz@2, xyz@2.4", "2.4.3", "https://xyz", [], yarnLockFileVersion), }; var blockFile = new Mock(); @@ -139,21 +133,15 @@ public void YarnLockParser_Berry_ParsesBlocks() "a@^1.0.0", "1.0.0", "https://a", - new List - { - this.CreateDependencyBlock(new Dictionary { { "xyz", "2" } }), - }, + [this.CreateDependencyBlock(new Dictionary { { "xyz", "2" } })], yarnLockFileVersion), this.CreateBlock( "b@2.4.6", "2.4.6", "https://b", - new List - { - this.CreateDependencyBlock(new Dictionary { { "xyz", "2.4" }, { "a", "^1.0.0" } }), - }, + [this.CreateDependencyBlock(new Dictionary { { "xyz", "2.4" }, { "a", "^1.0.0" } })], yarnLockFileVersion), - this.CreateBlock("xyz@2, xyz@2.4", "2.4.3", "https://xyz", Enumerable.Empty(), yarnLockFileVersion), + this.CreateBlock("xyz@2, xyz@2.4", "2.4.3", "https://xyz", [], yarnLockFileVersion), }; var blockFile = new Mock(); @@ -186,12 +174,11 @@ public void YarnLockParser_Berry_SkipsWorkspaceEntries() "internal-package@npm:0.0.0, internal-package@workspace:packages/internal-package", "0.0.0-use.local", "internal-package@workspace:packages/internal-package", - new List - { + [ this.CreateDependencyBlock(new Dictionary { { "xyz", "2" } }), - }, + ], yarnLockFileVersion), - this.CreateBlock("xyz@2, xyz@2.4", "2.4.3", "https://xyz", Enumerable.Empty(), yarnLockFileVersion), + this.CreateBlock("xyz@2, xyz@2.4", "2.4.3", "https://xyz", [], yarnLockFileVersion), }; var blockFile = new Mock(); @@ -220,14 +207,16 @@ public void YarnLockParser_ParsesNoVersionInTitleBlock() var blocks = new List { - this.CreateBlock("a", "1.0.0", "https://a", new List - { - this.CreateDependencyBlock(new Dictionary { { "xyz", "2" } }), - }), - this.CreateBlock("b", "2.4.6", "https://b", new List - { - this.CreateDependencyBlock(new Dictionary { { "xyz", "2.4" }, { "a", "^1.0.0" } }), - }), + this.CreateBlock( + "a", + "1.0.0", + "https://a", + [this.CreateDependencyBlock(new Dictionary { { "xyz", "2" } })]), + this.CreateBlock( + "b", + "2.4.6", + "https://b", + [this.CreateDependencyBlock(new Dictionary { { "xyz", "2.4" }, { "a", "^1.0.0" } })]), }; var blockFile = new Mock(); diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/DefaultExperimentProcessorTests.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/DefaultExperimentProcessorTests.cs index c719d4a59..80fc50edc 100644 --- a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/DefaultExperimentProcessorTests.cs +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/DefaultExperimentProcessorTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Orchestrator.Tests.Experiments; +namespace Microsoft.ComponentDetection.Orchestrator.Tests.Experiments; using System.Text.Json; using System.Threading.Tasks; @@ -15,6 +15,8 @@ [TestCategory("Governance/ComponentDetection")] public class DefaultExperimentProcessorTests { + private static readonly JsonSerializerOptions SerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + private readonly Mock fileWritingServiceMock; private readonly DefaultExperimentProcessor processor; @@ -35,7 +37,7 @@ public async Task ProcessExperimentAsync_WritesSerializedExperimentDiffToFileAsy ExperimentTestUtils.CreateRandomExperimentComponents(), ExperimentTestUtils.CreateRandomExperimentComponents()); - var serializedDiff = JsonSerializer.Serialize(diff, new JsonSerializerOptions { WriteIndented = true }); + var serializedDiff = JsonSerializer.Serialize(diff, SerializerOptions); await this.processor.ProcessExperimentAsync(config.Object, diff); diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentDiffTests.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentDiffTests.cs index 54c47abed..f1a1fffcd 100644 --- a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentDiffTests.cs +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentDiffTests.cs @@ -1,10 +1,8 @@ namespace Microsoft.ComponentDetection.Orchestrator.Tests.Experiments; -using System.Collections.Generic; using System.Linq; using FluentAssertions; using Microsoft.ComponentDetection.Contracts.BcdeModels; -using Microsoft.ComponentDetection.Contracts.TypedComponent; using Microsoft.ComponentDetection.Orchestrator.Experiments.Models; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -17,7 +15,7 @@ public class ExperimentDiffTests public void ExperimentDiff_DiffsAddedIds() { var testComponents = ExperimentTestUtils.CreateRandomExperimentComponents(); - var diff = new ExperimentDiff(Enumerable.Empty(), testComponents); + var diff = new ExperimentDiff([], testComponents); diff.AddedIds.Should().BeEquivalentTo(testComponents.Select(x => x.Id)); diff.RemovedIds.Should().BeEmpty(); @@ -31,7 +29,7 @@ public void ExperimentDiff_DiffsAddedIds() public void ExperimentDiff_DiffsRemovedIds() { var testComponents = ExperimentTestUtils.CreateRandomExperimentComponents(); - var diff = new ExperimentDiff(testComponents, Enumerable.Empty()); + var diff = new ExperimentDiff(testComponents, []); diff.RemovedIds.Should().BeEquivalentTo(testComponents.Select(x => x.Id)); diff.AddedIds.Should().BeEmpty(); @@ -54,8 +52,8 @@ public void ExperimentDiff_DiffsDevDependencies() componentB.IsDevelopmentDependency = true; var diff = new ExperimentDiff( - new[] { new ExperimentComponent(componentA) }, - new[] { new ExperimentComponent(componentB) }); + [new ExperimentComponent(componentA)], + [new ExperimentComponent(componentB)]); diff.DevelopmentDependencyChanges.Should().ContainSingle(); @@ -79,12 +77,12 @@ public void ExperimentDiff_DiffsAddedRootIds() var componentB = new ScannedComponent() { Component = componentA.Component, - TopLevelReferrers = new HashSet { rootComponent }, + TopLevelReferrers = [rootComponent], }; var diff = new ExperimentDiff( - new[] { new ExperimentComponent(componentA), }, - new[] { new ExperimentComponent(componentB), }); + [new ExperimentComponent(componentA),], + [new ExperimentComponent(componentB),]); diff.AddedRootIds.Should().ContainSingle(); diff.RemovedRootIds.Should().BeEmpty(); @@ -106,12 +104,12 @@ public void ExperimentDiff_DiffsRemovedRootIds() var componentB = new ScannedComponent() { Component = componentA.Component, - TopLevelReferrers = new HashSet { rootComponent }, + TopLevelReferrers = [rootComponent], }; var diff = new ExperimentDiff( - new[] { new ExperimentComponent(componentB), }, - new[] { new ExperimentComponent(componentA), }); + [new ExperimentComponent(componentB),], + [new ExperimentComponent(componentA),]); diff.RemovedRootIds.Should().ContainSingle(); diff.AddedRootIds.Should().BeEmpty(); diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentResultsTests.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentResultsTests.cs index c82f74708..c9a610e15 100644 --- a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentResultsTests.cs +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentResultsTests.cs @@ -46,7 +46,7 @@ public void ExperimentResults_DoesntAddDuplicateIds() }; var experiment = new ExperimentResults(); - experiment.AddComponentsToControlGroup(new[] { componentA, componentB }); + experiment.AddComponentsToControlGroup([componentA, componentB]); experiment.ControlGroupComponents.Should().ContainSingle(); experiment.ExperimentGroupComponents.Should().BeEmpty(); diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentServiceTests.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentServiceTests.cs index 34f0bd466..5921ef039 100644 --- a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentServiceTests.cs +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Experiments/ExperimentServiceTests.cs @@ -3,7 +3,6 @@ namespace Microsoft.ComponentDetection.Orchestrator.Tests.Experiments; using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading.Tasks; using FluentAssertions; using Microsoft.ComponentDetection.Common.DependencyGraph; @@ -70,8 +69,8 @@ public void RecordDetectorRun_AddsComponentsToControlAndExperimentGroup() var components = ExperimentTestUtils.CreateRandomComponents(); var service = new ExperimentService( - new[] { this.experimentConfigMock.Object }, - Enumerable.Empty(), + [this.experimentConfigMock.Object], + [], this.graphTranslationServiceMock.Object, this.loggerMock.Object); this.SetupGraphMock(components); @@ -102,8 +101,8 @@ public async Task RecordDetectorRun_FiltersExperimentsAsync() this.SetupGraphMock(components); var service = new ExperimentService( - new[] { this.experimentConfigMock.Object, filterConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object, filterConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); @@ -128,8 +127,8 @@ public async Task RecordDetectorRun_Respects_DetectorExperiments_EnableAsync() var components = ExperimentTestUtils.CreateRandomComponents(); var service = new ExperimentService( - new[] { this.experimentConfigMock.Object, filterConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object, filterConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); @@ -152,8 +151,8 @@ public async Task FinishAsync_ProcessesExperimentsAsync() this.SetupGraphMock(components); var service = new ExperimentService( - new[] { this.experimentConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); service.RecordDetectorRun(this.detectorMock.Object, this.componentRecorder, this.scanSettingsMock.Object); @@ -177,8 +176,8 @@ public async Task FinishAsync_SwallowsExceptionsAsync() this.SetupGraphMock(components); var service = new ExperimentService( - new[] { this.experimentConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); service.RecordDetectorRun(this.detectorMock.Object, this.componentRecorder, this.scanSettingsMock.Object); @@ -191,8 +190,8 @@ public async Task FinishAsync_SwallowsExceptionsAsync() public async Task FinishAsync_SkipsEmptyExperimentsAsync() { var service = new ExperimentService( - new[] { this.experimentConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); await service.FinishAsync(); @@ -209,8 +208,8 @@ public async Task FinishAsync_AutomaticallyProcessesExperimentsAsync() this.SetupGraphMock(components); var service = new ExperimentService( - new[] { this.experimentConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); service.RecordDetectorRun(this.detectorMock.Object, this.componentRecorder, this.scanSettingsMock.Object); @@ -231,8 +230,8 @@ public async Task FinishAsync_DoesNotAutomaticallyProcessExperimentsAsync() this.SetupGraphMock(components); var service = new ExperimentService( - new[] { this.experimentConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); service.RecordDetectorRun(this.detectorMock.Object, this.componentRecorder, this.scanSettingsMock.Object); @@ -253,8 +252,8 @@ public async Task FinishAsync_Respects_DetectorExperiments_EnableAsync() this.SetupGraphMock(components); var service = new ExperimentService( - new[] { this.experimentConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); service.RecordDetectorRun(this.detectorMock.Object, this.componentRecorder, this.scanSettingsMock.Object); @@ -272,8 +271,8 @@ public async Task RecordDetectorRun_CheckUnwantedDetectors_RemoveExperimentAsync var components = ExperimentTestUtils.CreateRandomComponents(); var service = new ExperimentService( - new[] { this.experimentConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); this.SetupGraphMock(components); @@ -303,8 +302,8 @@ public async Task RecordDetectorRun_CheckUnwantedDetectors_KeepExperimentAsync() var components = ExperimentTestUtils.CreateRandomComponents(); var service = new ExperimentService( - new[] { this.experimentConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); this.SetupGraphMock(components); @@ -332,8 +331,8 @@ public async Task RecordDetectorRun_CheckUnwantedDetectors_KeepExperimentAsync() public async Task InitializeAsync_InitsConfigsAsync() { var service = new ExperimentService( - new[] { this.experimentConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); @@ -348,8 +347,8 @@ public async Task InitializeAsync_SwallowsExceptionsAsync() this.experimentConfigMock.Setup(x => x.InitAsync()).ThrowsAsync(new InvalidOperationException()); var service = new ExperimentService( - new[] { this.experimentConfigMock.Object }, - new[] { this.experimentProcessorMock.Object }, + [this.experimentConfigMock.Object], + [this.experimentProcessorMock.Object], this.graphTranslationServiceMock.Object, this.loggerMock.Object); diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Extensions/CommaDelimitedConverterTests.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Extensions/CommaDelimitedConverterTests.cs index 0abd3bef5..e1f5daf86 100644 --- a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Extensions/CommaDelimitedConverterTests.cs +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Extensions/CommaDelimitedConverterTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Orchestrator.Tests.Extensions; +namespace Microsoft.ComponentDetection.Orchestrator.Tests.Extensions; using System; using FluentAssertions; diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/LoggingEnricherTests.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/LoggingEnricherTests.cs index 2d211c6a4..7de2e67a2 100644 --- a/test/Microsoft.ComponentDetection.Orchestrator.Tests/LoggingEnricherTests.cs +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/LoggingEnricherTests.cs @@ -1,13 +1,11 @@ namespace Microsoft.ComponentDetection.Orchestrator.Tests; using System; -using System.Collections.Generic; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Serilog.Core; using Serilog.Events; -using Serilog.Parsing; [TestClass] [TestCategory("Governance/All")] @@ -48,8 +46,8 @@ private void TestLogEventProperty(string propertyName, T propertyValue, T exp DateTimeOffset.Now, LogEventLevel.Debug, null, - new MessageTemplate("test", Array.Empty()), - new List()); + new MessageTemplate("test", []), + []); this.enricher.Enrich(logEvent, this.propertyFactoryMock.Object); diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/MinimatchTests.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/MinimatchTests.cs new file mode 100644 index 000000000..03e29c7bf --- /dev/null +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/MinimatchTests.cs @@ -0,0 +1,399 @@ +namespace Microsoft.ComponentDetection.Orchestrator.Tests; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +[TestCategory("Governance/All")] +[TestCategory("Governance/ComponentDetection")] +public class MinimatchTests +{ + [TestMethod] + public void Equality_Matches() + { + AssertMinimatchBoth( + "abc", // pattern + ["abc"], // matches + ["ab", "abd", "abcd"]); // does not match + } + + [TestMethod] + public void SingleStar_MatchesWithinSegment() + { + AssertMinimatchBoth( + "xxx.*", // pattern + ["xxx.yyy", "xxx.xxx"], // matches + ["abcxxx.yyy", "xxx.y/z"]); // does not match + } + + [TestMethod] + public void SingleStar_MatchesWholeSegment() + { + AssertMinimatchBoth( + "xxx/*/yyy", // pattern + ["xxx/abc/yyy"], // matches + ["xxx/yyy", "xxx/abc/def/yyy", "xxx/.abc/yyy", "xxx/./yyy", "xxx/../yyy"]); // does not match + } + + [TestMethod] + public void DoubleStarSegment_Matches_AnyDepth() + { + AssertMinimatchBoth( + "xxx/**/yyy", // pattern + ["xxx/yyy", "xxx/abc/yyy", "xxx/abc/def/yyy"], // matches + ["xxx/.abc/yyy", "xxx/./yyy", "xxx/../yyy"]); // does not match + } + + [TestMethod] + public void TrailingDoubleStarSegment_Matches_AnyDepth() + { + AssertMinimatchBoth( + "xxx/**", // pattern + ["xxx/yyy", "xxx/abc/yyy", "xxx/abc/def/yyy"], // matches + ["yyy/xxx", "xxx/.abc/yyy", "xxx/./yyy", "xxx/../yyy"]); // does not match + } + + [TestMethod] + public void DoubleStar_Matches_WithinSegment() + { + AssertMinimatchBoth( + "xxx/**yyy", // pattern + ["xxx/yyy", "xxx/ayyy"], // matches + ["xxx/abc/yyy", "xxx/abc/def/yyy", "xxx/.abc/yyy"]); // does not match + } + + [TestMethod] + public void QuestionMark_Matches_SingleCharacter() + { + AssertMinimatchBoth( + "x?y", // pattern + ["xAy"], // matches + ["xy", "xABy", "x/y"]); // does not match + } + + [TestMethod] + public void Braces_Expands() + { + AssertMinimatchBoth( + "{foo,bar}", // pattern + ["foo", "bar"], // matches + ["baz"]); // does not match + } + + [TestMethod] + public void Braces_Expansion_IncludesStars() + { + AssertMinimatchBoth( + "{x,y/*}/z", // pattern + ["x/z", "y/a/z"], // matches + ["y/z"]); // does not match + } + + [TestMethod] + public void Braces_Expands_Ranges() + { + AssertMinimatchBoth( + "foo{1..3}", // pattern + ["foo1", "foo2", "foo3"], // matches + ["foo", "foo0"]); // does not match + } + + [TestMethod] + public void Braces_Expands_Ranges_Complex() + { + AssertMinimatchBoth( + "a{b,c{d,e},{f,g}h}x{y,z}", // pattern + ["abxy", "abxz", "acdxy", "acdxz", "acexy", "acexz", "afhxy", "afhxz", "aghxy", "aghxz"], // matches + []); // does not match + } + + [TestMethod] + public void Braces_ConsideredLiteral_IfNotClosed() + { + AssertMinimatchBoth( + "a,b}{c,d", // pattern + ["a,b}{c,d"], // matches + ["ac", "ad", "bc", "bd"]); // does not match + } + + [TestMethod] + public void ExclamationMark_Negates_Result() + { + AssertMinimatchBoth( + "!abc", // pattern + ["a", "xyz"], // matches + ["abc"]); // does not match + } + + [TestMethod] + public void ExclamationMark_NegatesGroup_Result() + { + // new[] { "asd.jss.xyz", "asd.sjs.zxy", "asd..xyz" }, // matches + AssertMinimatchBoth( + "*.!(js).!(xy)", // pattern + ["asd.sjs.zxy"], // matches + ["asd.jss.xy", "asd.js.xyz", "asd.js.xy", "asd..xy"]); // does not match + } + + [TestMethod] + public void HashTag_Is_Comment() + { + AssertMinimatchBoth( + "#abc", // pattern + [], // matches + ["abc", "#abc"]); // does not match + } + + [TestMethod] + public void ParanthesisWithoutStateChar_ConsideredLiteral() + { + AssertMinimatchBoth( + "a(xy)", // pattern + ["a(xy)"], // matches + ["axy"]); // does not match + } + + [TestMethod] + public void ExtGlobPlus_Matches_OneOrMore() + { + AssertMinimatchBoth( + "a+(xy)", // pattern + ["axy", "axyxy"], // matches + ["a"]); // does not match + } + + [TestMethod] + public void ExtGlobStar_Matches_ZeroOrMore() + { + AssertMinimatchBoth( + "a*(xy)", // pattern + ["a", "axy", "axyxy"], // matches + ["xy"]); // does not match + } + + [TestMethod] + public void ExtGlobQuestionMark_Matches_ZeroOrOne() + { + AssertMinimatchBoth( + "a?(xy)", // pattern + ["a", "axy"], // matches + ["axyxy"]); // does not match + } + + [TestMethod] + public void ExtGlobAt_Matches_One() + { + AssertMinimatchBoth( + "a@(xy)", // pattern + ["axy"], // matches + ["a", "axyxy"]); // does not match + } + + [TestMethod] + public void ExtGlobExclamationMark_Negates_Pattern() + { + AssertMinimatchBoth( + "a!(xy)", // pattern + ["ax"], // matches + ["axy", "axyz"]); // does not match + } + + [TestMethod] + public void ExtGlobExclamationMark_ConsideredLiteral_IfInside() + { + AssertMinimatchBoth( + "@(!a)", // pattern + ["!a"], // matches + ["a", "bc"]); // does not match + } + + [TestMethod] + public void ExtGlobPipe_Is_Or() + { + AssertMinimatchBoth( + "a@(b|c)", // pattern + ["ab", "ac"], // matches + ["abc"]); // does not match + } + + [TestMethod] + public void ExtGlob_Escaping() + { + AssertMinimatch( + @"a@(d\|\\!e)", // pattern + [@"ad|\!e", @"ad|\!e"], // matches + [@"ad|\\!e", @"ad", @"ad|\f"], // does not match + isWindows: false); + } + + [TestMethod] + public void ExtGlob_ConsideredLiteral_IfNotClosed() + { + AssertMinimatchBoth( + "a@(b|c", // pattern + ["a@(b|c"], // matches + ["ab", "ac"]); // does not match + } + + [TestMethod] + public void SquareBrackets_WorksLikeRegex() + { + AssertMinimatchBoth( + @"[|c-dE-F]", // pattern + ["|", "c", "d", "E", "F"], // matches + ["|c-dE-F", "cd", "C", "D", "e", "f"]); // does not match + } + + [TestMethod] + public void CaseSensitive() + { + AssertMinimatchBoth( + "AbC", // pattern + ["AbC"], // matches + ["ABC", "abc"]); // does not match + } + + [TestMethod] + public void Empty() + { + AssertMinimatchBoth( + string.Empty, // pattern + [string.Empty], // matches + ["A"]); // does not match + } + + [TestMethod] + public void EdgeCase1() + { + AssertMinimatch( + @"\[b-a]*", // pattern + ["[b-a]x"], // matches + ["a[]b", "a]b", "a[]]b", "a[[]b"], // does not match + isWindows: false); + } + + [TestMethod] + public void EdgeCase2() + { + AssertMinimatch( + @"[b-a\]*", // pattern + ["[b-a]x"], // matches + ["a[]b", "a]b", "a[]]b", "a[[]b"], // does not match + isWindows: false); + } + + [TestMethod] + public void EdgeCase3() + { + AssertMinimatchBoth( + "a[]*", // pattern + ["a[]b", "a[]]b"], // matches + ["[b-a]x", "a]b", "a[[]b"]); // does not match + } + + [TestMethod] + public void EdgeCase4() + { + AssertMinimatchBoth( + "a[]]*", // pattern + ["a]b"], // matches + ["a[]b", "[b-a]x", "a[]]b", "a[[]b"]); // does not match + } + + [TestMethod] + public void EdgeCase5() + { + AssertMinimatchBoth( + "a[[]*", // pattern + ["a[]b", "a[]]b", "a[[]b"], // matches + ["[b-a]x", "a]b"]); // does not match + } + + [TestMethod] + public void EdgeCase6() + { + AssertMinimatchBoth( + "a[[]]*", // pattern + ["a[]b", "a[]]b"], // matches + ["[b-a]x", "a]b", "a[[]b"]); // does not match + } + + [TestMethod] + public void PossibleToEscapeSpecialChars() + { + AssertMinimatch( + @"\(\)\.\*\{\}\+\?\[\]\^\$\\\!\@\#", // pattern + [@"().*{}+?[]^$\!@#"], // matches + [], // does not match + isWindows: false); + } + + [TestMethod] + public void Comment_DoesntMatch() + { + AssertMinimatchBoth( + "#abc", // pattern + [], // matches + ["#abc", "abc"]); // does not match + } + + [TestMethod] + public void CaseInsensitive() + { + AssertMinimatchBoth( + "AbC", // pattern + ["AbC", "ABC", "abc"], // matches + ["Ab"], // does not match + ignoreCase: true); + } + + [TestMethod] + public void NullPattern_Throws() + { + var shouldThrow = () => new Minimatch(null, true, true); + _ = shouldThrow.Should().ThrowExactly(); + } + + [TestMethod] + public void ReverseRegexRange_Throws() + { + var minimatch = new Minimatch("[b-a]", true, true); + var shouldThrow = () => minimatch.IsMatch("something"); + _ = shouldThrow.Should().ThrowExactly(); + } + + private static void AssertMinimatchBoth( + string pattern, + string[] matches, + string[] mismatches, + bool ignoreCase = false) + { + AssertMinimatch(pattern, matches, mismatches, false, ignoreCase); + AssertMinimatch(pattern, matches, mismatches, true, ignoreCase); + } + + private static void AssertMinimatch( + string pattern, + IEnumerable matches, + IEnumerable mismatches, + bool isWindows, + bool ignoreCase = false) + { + var divider = isWindows ? @"\" : "/"; + var minimatch = new Minimatch(pattern.Replace("/", divider), ignoreCase, isWindows); + + foreach (var match in matches.Select(x => x.Replace("/", divider))) + { + _ = minimatch.IsMatch(match).Should().BeTrue($"'{pattern}' == '{match}'"); + } + + foreach (var mismatch in mismatches.Select(x => x.Replace("/", divider))) + { + _ = minimatch.IsMatch(mismatch).Should().BeFalse($"'{pattern}' != '{mismatch}'"); + } + } +} diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/BcdeScanExecutionServiceTests.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/BcdeScanExecutionServiceTests.cs index 3fc2b489c..b07d88b8c 100644 --- a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/BcdeScanExecutionServiceTests.cs +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/BcdeScanExecutionServiceTests.cs @@ -50,11 +50,11 @@ public BcdeScanExecutionServiceTests() this.sampleContainerDetails = new ContainerDetails { Id = 1 }; this.graphTranslationService = new DefaultGraphTranslationService(new Mock>().Object); - this.detectedComponents = new[] - { + this.detectedComponents = + [ new DetectedComponent(new NpmComponent("some-npm-component", "1.2.3")), new DetectedComponent(new NuGetComponent("SomeNugetComponent", "1.2.3.4")), - }; + ]; this.serviceUnderTest = new ScanExecutionService( this.detectorsMock.Object, @@ -96,14 +96,14 @@ public async Task DetectComponents_HappyPathAsync() this.componentDetector3Mock.SetupGet(x => x.Version).Returns(10); this.detectedComponents[0].DevelopmentDependency = true; - this.detectedComponents[0].ContainerDetailIds = new HashSet - { + this.detectedComponents[0].ContainerDetailIds = + [ this.sampleContainerDetails.Id, - }; + ]; singleFileComponentRecorder.RegisterUsage(this.detectedComponents[0], isDevelopmentDependency: true); var parentPipComponent = new PipComponent("sample-root", "1.0"); - this.detectedComponents[1].DependencyRoots = new HashSet(new[] { parentPipComponent }); + this.detectedComponents[1].DependencyRoots = new HashSet([parentPipComponent]); this.detectedComponents[1].DevelopmentDependency = null; singleFileComponentRecorder.RegisterUsage(new DetectedComponent(parentPipComponent, detector: new Mock().Object), isExplicitReferencedDependency: true); singleFileComponentRecorder.RegisterUsage(this.detectedComponents[1], parentComponentId: parentPipComponent.Id); @@ -119,7 +119,7 @@ public async Task DetectComponents_HappyPathAsync() restrictions.AllowedDetectorCategories.Should().BeNull(); restrictions.AllowedDetectorIds.Should().BeNull(); }, - new List { componentRecorder }); + [componentRecorder]); result.Result.Should().Be(ProcessingResultCode.Success); this.ValidateDetectedComponents(result.DetectedComponents); @@ -146,8 +146,8 @@ public async Task DetectComponents_DetectOnlyWithIdAndCategoryRestrictionsAsync( { var settings = new ScanSettings { - DetectorCategories = new[] { "Category1", "Category2" }, - DetectorsFilter = new[] { "Detector1", "Detector2" }, + DetectorCategories = ["Category1", "Category2"], + DetectorsFilter = ["Detector1", "Detector2"], SourceDirectory = this.sourceDirectory, }; @@ -163,7 +163,7 @@ public async Task DetectComponents_DetectOnlyWithIdAndCategoryRestrictionsAsync( restrictions.AllowedDetectorCategories.Should().Contain(settings.DetectorCategories); restrictions.AllowedDetectorIds.Should().Contain(settings.DetectorsFilter); }, - new List { componentRecorder }); + [componentRecorder]); result.Result.Should().Be(ProcessingResultCode.Success); this.ValidateDetectedComponents(result.DetectedComponents); @@ -187,7 +187,7 @@ public async Task DetectComponents_DetectOnlyWithNoUrlAsync() restrictions => { }, - new List { componentRecorder }); + [componentRecorder]); result.Result.Should().Be(ProcessingResultCode.Success); this.ValidateDetectedComponents(result.DetectedComponents); @@ -209,7 +209,7 @@ public async Task DetectComponents_ReturnsExperimentalDetectorInformationAsync() singleFileComponentRecorder.RegisterUsage(this.detectedComponents[0]); singleFileComponentRecorder.RegisterUsage(this.detectedComponents[1]); - var result = await this.DetectComponentsHappyPathAsync(settings, restrictions => { }, new List { componentRecorder }); + var result = await this.DetectComponentsHappyPathAsync(settings, restrictions => { }, [componentRecorder]); result.Result.Should().Be(ProcessingResultCode.Success); this.ValidateDetectedComponents(result.DetectedComponents); @@ -233,21 +233,21 @@ public async Task DetectComponents_Graph_Happy_PathAsync() var mockDependencyGraphA = new Mock(); - mockDependencyGraphA.Setup(x => x.GetComponents()).Returns(new[] - { + mockDependencyGraphA.Setup(x => x.GetComponents()).Returns( + [ this.detectedComponents[0].Component.Id, this.detectedComponents[1].Component.Id, - }); + ]); mockDependencyGraphA.Setup(x => x.GetDependenciesForComponent(this.detectedComponents[0].Component.Id)) - .Returns(new[] - { + .Returns( + [ this.detectedComponents[1].Component.Id, - }); + ]); mockDependencyGraphA.Setup(x => x.IsComponentExplicitlyReferenced(this.detectedComponents[0].Component.Id)).Returns(true); mockDependencyGraphA.Setup(x => x.IsDevelopmentDependency(this.detectedComponents[0].Component.Id)).Returns(true); mockDependencyGraphA.Setup(x => x.IsDevelopmentDependency(this.detectedComponents[1].Component.Id)).Returns(false); - var result = await this.DetectComponentsHappyPathAsync(settings, restrictions => { }, new List { componentRecorder }); + var result = await this.DetectComponentsHappyPathAsync(settings, restrictions => { }, [componentRecorder]); result.SourceDirectory.Should().NotBeNull(); result.SourceDirectory.Should().Be(this.sourceDirectory.ToString()); @@ -261,7 +261,7 @@ public async Task DetectComponents_Graph_Happy_PathAsync() var actualGraph = matchingGraph.Value.Graph; actualGraph.Keys.Should().HaveCount(2); - actualGraph[this.detectedComponents[0].Component.Id].Count.Should().Be(1); + actualGraph[this.detectedComponents[0].Component.Id].Should().ContainSingle(); actualGraph[this.detectedComponents[0].Component.Id].Should().Contain(this.detectedComponents[1].Component.Id); actualGraph[this.detectedComponents[1].Component.Id].Should().BeNull(); @@ -286,15 +286,15 @@ public async Task DetectComponents_Graph_AccumulatesGraphsOnSameLocationAsync() var mockDependencyGraphA = new Mock(); - mockDependencyGraphA.Setup(x => x.GetComponents()).Returns(new[] - { + mockDependencyGraphA.Setup(x => x.GetComponents()).Returns( + [ this.detectedComponents[0].Component.Id, this.detectedComponents[1].Component.Id, - }); + ]); mockDependencyGraphA.Setup(x => x.GetDependenciesForComponent(this.detectedComponents[0].Component.Id)) - .Returns(new[] - { + .Returns( + [ this.detectedComponents[1].Component.Id, - }); + ]); mockDependencyGraphA.Setup(x => x.IsComponentExplicitlyReferenced(this.detectedComponents[0].Component.Id)).Returns(true); @@ -304,15 +304,15 @@ public async Task DetectComponents_Graph_AccumulatesGraphsOnSameLocationAsync() var mockDependencyGraphB = new Mock(); - mockDependencyGraphB.Setup(x => x.GetComponents()).Returns(new[] - { + mockDependencyGraphB.Setup(x => x.GetComponents()).Returns( + [ this.detectedComponents[0].Component.Id, this.detectedComponents[1].Component.Id, - }); + ]); mockDependencyGraphB.Setup(x => x.GetDependenciesForComponent(this.detectedComponents[1].Component.Id)) - .Returns(new[] - { + .Returns( + [ this.detectedComponents[0].Component.Id, - }); + ]); mockDependencyGraphB.Setup(x => x.IsComponentExplicitlyReferenced(this.detectedComponents[1].Component.Id)).Returns(true); @@ -320,7 +320,7 @@ public async Task DetectComponents_Graph_AccumulatesGraphsOnSameLocationAsync() singleFileComponentRecorderB.RegisterUsage(this.detectedComponents[1], isExplicitReferencedDependency: true); singleFileComponentRecorderB.RegisterUsage(this.detectedComponents[0], parentComponentId: this.detectedComponents[1].Component.Id); - var result = await this.DetectComponentsHappyPathAsync(settings, restrictions => { }, new List { componentRecorder }); + var result = await this.DetectComponentsHappyPathAsync(settings, restrictions => { }, [componentRecorder]); result.SourceDirectory.Should().NotBeNull(); result.SourceDirectory.Should().Be(this.sourceDirectory.ToString()); @@ -336,9 +336,9 @@ public async Task DetectComponents_Graph_AccumulatesGraphsOnSameLocationAsync() var actualGraph = matchingGraph.Value.Graph; actualGraph.Keys.Should().HaveCount(2); - actualGraph[this.detectedComponents[0].Component.Id].Count.Should().Be(1); + actualGraph[this.detectedComponents[0].Component.Id].Should().ContainSingle(); actualGraph[this.detectedComponents[0].Component.Id].Should().Contain(this.detectedComponents[1].Component.Id); - actualGraph[this.detectedComponents[1].Component.Id].Count.Should().Be(1); + actualGraph[this.detectedComponents[1].Component.Id].Should().ContainSingle(); actualGraph[this.detectedComponents[1].Component.Id].Should().Contain(this.detectedComponents[0].Component.Id); } @@ -361,7 +361,7 @@ public async Task VerifyTranslation_ComponentsAreReturnedWithDevDependencyInfoAs singleFileComponentRecorder.RegisterUsage(detectedComponent2, isDevelopmentDependency: false); singleFileComponentRecorder.RegisterUsage(detectedComponent3); - var results = await this.SetupRecorderBasedScanningAsync(settings, new List { componentRecorder }); + var results = await this.SetupRecorderBasedScanningAsync(settings, [componentRecorder]); var detectedComponents = results.ComponentsFound; @@ -396,7 +396,7 @@ public async Task VerifyTranslation_RootsFromMultipleLocationsAreAgregatedAsync( var detectedComponent2NewLocation = new DetectedComponent(new NpmComponent("test", "2.0.0"), detector: npmDetector.Object); singleFileComponentRecorder.RegisterUsage(detectedComponent2NewLocation, isExplicitReferencedDependency: true); - var results = await this.SetupRecorderBasedScanningAsync(settings, new List { componentRecorder }); + var results = await this.SetupRecorderBasedScanningAsync(settings, [componentRecorder]); var detectedComponents = results.ComponentsFound; @@ -431,7 +431,7 @@ public async Task VerifyTranslation_AncesterFromMultipleLocationsAreAgregatedAsy var detectedComponent2NewLocation = new DetectedComponent(new NpmComponent("test", "2.0.0"), detector: npmDetector.Object); singleFileComponentRecorder.RegisterUsage(detectedComponent2NewLocation, isExplicitReferencedDependency: true); - var results = await this.SetupRecorderBasedScanningAsync(settings, new List { componentRecorder }); + var results = await this.SetupRecorderBasedScanningAsync(settings, [componentRecorder]); var detectedComponents = results.ComponentsFound; @@ -459,7 +459,7 @@ public async Task VerifyTranslation_ComponentsAreReturnedWithRootsAsync() singleFileComponentRecorder.RegisterUsage(detectedComponent1, isExplicitReferencedDependency: true); singleFileComponentRecorder.RegisterUsage(detectedComponent2, parentComponentId: detectedComponent1.Component.Id); - var results = await this.SetupRecorderBasedScanningAsync(settings, new List { componentRecorder }); + var results = await this.SetupRecorderBasedScanningAsync(settings, [componentRecorder]); var detectedComponents = results.ComponentsFound; @@ -489,7 +489,7 @@ public async Task VerifyTranslation_ComponentsAreReturnedWithAncesterAsync() singleFileComponentRecorder.RegisterUsage(detectedComponent1, isExplicitReferencedDependency: true); singleFileComponentRecorder.RegisterUsage(detectedComponent2, parentComponentId: detectedComponent1.Component.Id); - var results = await this.SetupRecorderBasedScanningAsync(settings, new List { componentRecorder }); + var results = await this.SetupRecorderBasedScanningAsync(settings, [componentRecorder]); var detectedComponents = results.ComponentsFound; @@ -542,7 +542,7 @@ public async Task VerifyTranslation_DevDependenciesAreMergedWhenSameComponentInD firstRecorder.RegisterUsage(component, isDevelopmentDependency: isDevDep); } - var results = await this.SetupRecorderBasedScanningAsync(settings, new List { componentRecorder }); + var results = await this.SetupRecorderBasedScanningAsync(settings, [componentRecorder]); var components = results.ComponentsFound; @@ -573,7 +573,7 @@ public async Task VerifyTranslation_LocationsAreMergedWhenSameComponentInDiffere firstRecorder.RegisterUsage(firstComponent); secondRecorder.RegisterUsage(secondComponent); - var results = await this.SetupRecorderBasedScanningAsync(settings, new List { componentRecorder }); + var results = await this.SetupRecorderBasedScanningAsync(settings, [componentRecorder]); var actualComponent = results.ComponentsFound.Single(); @@ -617,7 +617,7 @@ public async Task VerifyTranslation_RootsAreMergedWhenSameComponentInDifferentFi secondRecorder.RegisterUsage(root2, isExplicitReferencedDependency: true); secondRecorder.RegisterUsage(secondComponent, parentComponentId: root2.Component.Id); - var results = await this.SetupRecorderBasedScanningAsync(settings, new List { componentRecorder }); + var results = await this.SetupRecorderBasedScanningAsync(settings, [componentRecorder]); var actualComponent = results.ComponentsFound.First(c => c.Component.Id == firstComponent.Component.Id); actualComponent.TopLevelReferrers.Should().HaveCount(2); @@ -644,12 +644,12 @@ public async Task VerifyTranslation_DetectedComponentExist_UpdateFunctionIsAppli singleFileComponentRecorder.RegisterUsage(detectedComponent, isDevelopmentDependency: true); - var results = await this.SetupRecorderBasedScanningAsync(args, new List { componentRecorder }); + var results = await this.SetupRecorderBasedScanningAsync(args, [componentRecorder]); results.ComponentsFound.Single(component => component.Component.Id == detectedComponent.Component.Id).IsDevelopmentDependency.Should().BeTrue(); singleFileComponentRecorder.RegisterUsage(detectedComponent, isDevelopmentDependency: false); - results = await this.SetupRecorderBasedScanningAsync(args, new List { componentRecorder }); + results = await this.SetupRecorderBasedScanningAsync(args, [componentRecorder]); results.ComponentsFound.Single(component => component.Component.Id == detectedComponent.Component.Id).IsDevelopmentDependency.Should().BeFalse(); } @@ -662,12 +662,12 @@ public async Task VerifyDisabledDetectorsisPopulatedAsync() this.componentDetector2Mock.SetupGet(x => x.Id).Returns("Detector2"); this.componentDetector3Mock.SetupGet(x => x.Id).Returns("Detector3"); - IEnumerable registeredDetectors = new[] - { + IEnumerable registeredDetectors = + [ this.componentDetector2Mock.Object, this.componentDetector3Mock.Object, this.versionedComponentDetector1Mock.Object, - }; + ]; var restrictedDetectors = new[] { this.componentDetector2Mock.Object, this.componentDetector3Mock.Object, @@ -686,7 +686,7 @@ public async Task VerifyDisabledDetectorsisPopulatedAsync() restrictions.AllowedDetectorCategories.Should().BeNull(); restrictions.AllowedDetectorIds.Should().BeNull(); }, - new List { componentRecorder }); + [componentRecorder]); result.DetectorsNotInRun.Should().ContainSingle(); result.DetectorsNotInRun.Single(x => x.DetectorId == "Detector1"); @@ -701,10 +701,10 @@ public async Task VerifyNoDisabledDetectorsisPopulatedAsync() this.componentDetector2Mock.SetupGet(x => x.Id).Returns("Detector2"); this.componentDetector3Mock.SetupGet(x => x.Id).Returns("Detector3"); - IEnumerable registeredDetectors = new[] - { + IEnumerable registeredDetectors = + [ this.componentDetector2Mock.Object, this.componentDetector3Mock.Object, - }; + ]; var restrictedDetectors = new[] { this.componentDetector2Mock.Object, this.componentDetector3Mock.Object, @@ -723,7 +723,7 @@ public async Task VerifyNoDisabledDetectorsisPopulatedAsync() restrictions.AllowedDetectorCategories.Should().BeNull(); restrictions.AllowedDetectorIds.Should().BeNull(); }, - new List { componentRecorder }); + [componentRecorder]); result.DetectorsNotInRun.Should().BeEmpty(); } @@ -783,12 +783,12 @@ private async Task DetectComponentsHappyPathAsync( Action restrictionAsserter = null, IEnumerable componentRecorders = null) { - IEnumerable registeredDetectors = new[] - { + IEnumerable registeredDetectors = + [ this.componentDetector2Mock.Object, this.componentDetector3Mock.Object, this.versionedComponentDetector1Mock.Object, - }; + ]; var restrictedDetectors = new[] { this.componentDetector2Mock.Object, this.componentDetector3Mock.Object, @@ -841,12 +841,12 @@ private async Task SetupRecorderBasedScanningAsync( ScanSettings settings, IEnumerable componentRecorders) { - IEnumerable registeredDetectors = new[] - { + IEnumerable registeredDetectors = + [ this.componentDetector2Mock.Object, this.componentDetector3Mock.Object, this.versionedComponentDetector1Mock.Object, - }; + ]; var restrictedDetectors = new[] { this.componentDetector2Mock.Object, this.componentDetector3Mock.Object, diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DefaultGraphTranslationServiceTests.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DefaultGraphTranslationServiceTests.cs index c2a971779..b3ed0df1a 100644 --- a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DefaultGraphTranslationServiceTests.cs +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DefaultGraphTranslationServiceTests.cs @@ -57,7 +57,7 @@ public void GenerateScanResultFromResult_WithCustomLocations() this.sampleContainerDetails.Id, this.sampleContainerDetails }, }, - ComponentRecorders = new[] { (this.componentDetectorMock.Object, this.componentRecorder) }, + ComponentRecorders = [(this.componentDetectorMock.Object, this.componentRecorder)], }; var expectedNpmComponent = new NpmComponent("npm-component", "1.2.3"); @@ -88,8 +88,8 @@ public void GenerateScanResultFromResult_WithCustomLocations() var resultNpmComponent = result.ComponentsFound.Single(c => c.Component.Type == ComponentType.Npm); var resultNugetComponent = result.ComponentsFound.Single(c => c.Component.Type == ComponentType.NuGet); - resultNpmComponent.LocationsFoundAt.Should().BeEquivalentTo(new[] { npmCustomPath, detectedFilePath, relatedFilePath }); - resultNugetComponent.LocationsFoundAt.Should().BeEquivalentTo(new[] { nugetCustomPath, detectedFilePath, relatedFilePath }); + resultNpmComponent.LocationsFoundAt.Should().BeEquivalentTo([npmCustomPath, detectedFilePath, relatedFilePath]); + resultNugetComponent.LocationsFoundAt.Should().BeEquivalentTo([nugetCustomPath, detectedFilePath, relatedFilePath]); var actualNpmComponent = resultNpmComponent.Component as NpmComponent; var actualNugetComponent = resultNugetComponent.Component as NuGetComponent; diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DetectorProcessingServiceTests.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DetectorProcessingServiceTests.cs index 7da82f6d0..8aed8d70e 100644 --- a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DetectorProcessingServiceTests.cs +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DetectorProcessingServiceTests.cs @@ -82,10 +82,10 @@ private IndividualDetectorScanResult ExpectedResultForDetector(string detectorId [TestMethod] public async Task ProcessDetectorsAsync_HappyPathReturnsDetectedComponentsAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object, - }; + ]; var results = await this.serviceUnderTest.ProcessDetectorsAsync(DefaultArgs, this.detectorsToUse, new DetectorRestrictions()); @@ -118,7 +118,7 @@ public async Task ProcessDetectorsAsync_NullDetectedComponentsReturnIsCoalescedA }; }); - this.detectorsToUse = new[] { mockComponentDetector.Object }; + this.detectorsToUse = [mockComponentDetector.Object]; var results = await this.serviceUnderTest.ProcessDetectorsAsync(DefaultArgs, this.detectorsToUse, new DetectorRestrictions()); results.ResultCode.Should().Be(ProcessingResultCode.Success); @@ -127,10 +127,10 @@ public async Task ProcessDetectorsAsync_NullDetectedComponentsReturnIsCoalescedA [TestMethod] public async Task ProcessDetectorsAsync_HappyPathReturns_DependencyGraphAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object, - }; + ]; var results = await this.serviceUnderTest.ProcessDetectorsAsync(DefaultArgs, this.detectorsToUse, new DetectorRestrictions()); @@ -153,10 +153,10 @@ public async Task ProcessDetectorsAsync_HappyPathReturns_DependencyGraphAsync() [TestMethod] public async Task ProcessDetectorsAsync_AdditionalTelemetryDetailsAreReturnedAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object, - }; + ]; var records = await TelemetryHelper.ExecuteWhileCapturingTelemetryAsync(async () => { @@ -173,12 +173,12 @@ public async Task ProcessDetectorsAsync_AdditionalTelemetryDetailsAreReturnedAsy [TestMethod] public async Task ProcessDetectorsAsync_ExperimentalDetectorsDoNotReturnComponentsAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object, this.experimentalFileComponentDetectorMock.Object, - }; + ]; DetectorProcessingResult results = null; var records = await TelemetryHelper.ExecuteWhileCapturingTelemetryAsync(async () => @@ -198,8 +198,12 @@ public async Task ProcessDetectorsAsync_ExperimentalDetectorsDoNotReturnComponen // We should have all components except the ones that came from our experimental detector this.GetDiscoveredComponentsFromDetectorProcessingResult(results).Should().HaveCount(records.Sum(x => x.DetectedComponentCount ?? 0) - experimentalDetectorRecord.DetectedComponentCount ?? 0); - this.GetDiscoveredComponentsFromDetectorProcessingResult(results).All(x => (x.Component as NuGetComponent)?.Name != experimentalComponent.Name) - .Should().BeTrue("Experimental component should not be in component list"); + + this.GetDiscoveredComponentsFromDetectorProcessingResult(results) + .Select(x => x.Component as NuGetComponent) + .Where(x => x != null) + .Should() + .OnlyContain(x => x.Name != experimentalComponent.Name, "Experimental component should not be in component list"); results.ResultCode.Should().Be(ProcessingResultCode.Success); this.firstFileComponentDetectorMock.Verify(x => x.ExecuteDetectorAsync(It.Is(request => request.SourceDirectory == DefaultArgs.SourceDirectory))); @@ -210,18 +214,18 @@ public async Task ProcessDetectorsAsync_ExperimentalDetectorsDoNotReturnComponen [TestMethod] public async Task ProcessDetectorsAsync_ExperimentalDetectorsDoNormalStuffIfExplicitlyEnabledAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object, this.experimentalFileComponentDetectorMock.Object, - }; + ]; var experimentalDetectorId = this.experimentalFileComponentDetectorMock.Object.Id; DetectorProcessingResult results = null; var records = await TelemetryHelper.ExecuteWhileCapturingTelemetryAsync(async () => { - results = await this.serviceUnderTest.ProcessDetectorsAsync(DefaultArgs, this.detectorsToUse, new DetectorRestrictions { ExplicitlyEnabledDetectorIds = new[] { experimentalDetectorId } }); + results = await this.serviceUnderTest.ProcessDetectorsAsync(DefaultArgs, this.detectorsToUse, new DetectorRestrictions { ExplicitlyEnabledDetectorIds = [experimentalDetectorId] }); }); // We should have all components except the ones that came from our experimental detector @@ -238,11 +242,11 @@ public async Task ProcessDetectorsAsync_ExperimentalDetectorsDoNormalStuffIfExpl [TestMethod] public async Task ProcessDetectorsAsync_ExperimentalDetectorsThrowingDoesntKillDetectionAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object, this.experimentalFileComponentDetectorMock.Object, - }; + ]; this.experimentalFileComponentDetectorMock.Setup(x => x.ExecuteDetectorAsync(It.Is(request => request.SourceDirectory == DefaultArgs.SourceDirectory))) .Throws(new InvalidOperationException("Simulated experimental failure")); @@ -271,14 +275,15 @@ public async Task ProcessDetectorsAsync_ExperimentalDetectorsThrowingDoesntKillD [TestMethod] public async Task ProcessDetectorsAsync_DirectoryExclusionPredicateWorksAsExpectedAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, - }; + ]; if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - Assert.Inconclusive("Test is platform specific and fails on non-windows"); + // Test is platform specific and fails on non-windows + return; } var d1 = new DirectoryInfo(Path.Combine(Environment.CurrentDirectory, "shouldExclude", "stuff")); @@ -301,7 +306,7 @@ public async Task ProcessDetectorsAsync_DirectoryExclusionPredicateWorksAsExpect { SourceDirectory = DefaultSourceDirectory, DetectorArgs = new Dictionary(), - DirectoryExclusionList = new[] { Path.Combine("**", "SomeSource", "**"), Path.Combine("**", "shouldExclude", "**") }, + DirectoryExclusionList = [Path.Combine("**", "SomeSource", "**"), Path.Combine("**", "shouldExclude", "**")], }; // Now exercise the exclusion code @@ -335,7 +340,8 @@ public void GenerateDirectoryExclusionPredicate_IgnoreCaseAndAllowWindowsPathsWo if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - Assert.Inconclusive("Test is inconsistent for non-windows platforms"); + // Test is inconsistent for non-windows platforms. + return; } // This unit test previously depended on defaultArgs. But the author assumed that \Source\ was in the default source path, which may not be true on all developers machines. @@ -346,32 +352,32 @@ public void GenerateDirectoryExclusionPredicate_IgnoreCaseAndAllowWindowsPathsWo var dp = args.SourceDirectory.Parent.FullName.AsSpan(); // Exclusion predicate is case sensitive and allow windows path, the exclusion list follow the windows path structure and has a case mismatch with the directory path, should not exclude - args.DirectoryExclusionList = new[] { @"**\source\**" }; + args.DirectoryExclusionList = [@"**\source\**"]; var exclusionPredicate = this.serviceUnderTest.GenerateDirectoryExclusionPredicate(@"C:\somefake\dir", args.DirectoryExclusionList, args.DirectoryExclusionListObsolete, allowWindowsPaths: true, ignoreCase: false); exclusionPredicate(dn, dp).Should().BeFalse(); // Exclusion predicate is case sensitive and allow windows path, the exclusion list follow the windows path structure and match directory path case, should exclude - args.DirectoryExclusionList = new[] { @"**\Source\**" }; + args.DirectoryExclusionList = [@"**\Source\**"]; exclusionPredicate = this.serviceUnderTest.GenerateDirectoryExclusionPredicate(@"C:\somefake\dir", args.DirectoryExclusionList, args.DirectoryExclusionListObsolete, allowWindowsPaths: true, ignoreCase: false); exclusionPredicate(dn, dp).Should().BeTrue(); // Exclusion predicate is not case sensitive and allow windows path, the exclusion list follow the windows path, should exclude - args.DirectoryExclusionList = new[] { @"**\sOuRce\**" }; + args.DirectoryExclusionList = [@"**\sOuRce\**"]; exclusionPredicate = this.serviceUnderTest.GenerateDirectoryExclusionPredicate(@"C:\somefake\dir", args.DirectoryExclusionList, args.DirectoryExclusionListObsolete, allowWindowsPaths: true, ignoreCase: true); exclusionPredicate(dn, dp).Should().BeTrue(); // Exclusion predicate does not support windows path and the exclusion list define the path as a windows path, should not exclude - args.DirectoryExclusionList = new[] { @"**\Source\**" }; + args.DirectoryExclusionList = [@"**\Source\**"]; exclusionPredicate = this.serviceUnderTest.GenerateDirectoryExclusionPredicate(@"C:\somefake\dir", args.DirectoryExclusionList, args.DirectoryExclusionListObsolete, allowWindowsPaths: false, ignoreCase: true); exclusionPredicate(dn, dp).Should().BeFalse(); // Exclusion predicate support windows path and the exclusion list define the path as a windows path, should exclude - args.DirectoryExclusionList = new[] { @"**\Source\**" }; + args.DirectoryExclusionList = [@"**\Source\**"]; exclusionPredicate = this.serviceUnderTest.GenerateDirectoryExclusionPredicate(@"C:\somefake\dir", args.DirectoryExclusionList, args.DirectoryExclusionListObsolete, allowWindowsPaths: true, ignoreCase: true); exclusionPredicate(dn, dp).Should().BeTrue(); // Exclusion predicate support windows path and the exclusion list does not define a windows path, should exclude - args.DirectoryExclusionList = new[] { @"**/Source/**", @"**/Source\**" }; + args.DirectoryExclusionList = [@"**/Source/**", @"**/Source\**"]; exclusionPredicate = this.serviceUnderTest.GenerateDirectoryExclusionPredicate(@"C:\somefake\dir", args.DirectoryExclusionList, args.DirectoryExclusionListObsolete, allowWindowsPaths: true, ignoreCase: true); exclusionPredicate(dn, dp).Should().BeTrue(); } @@ -379,10 +385,10 @@ public void GenerateDirectoryExclusionPredicate_IgnoreCaseAndAllowWindowsPathsWo [TestMethod] public async Task ProcessDetectorsAsync_DirectoryExclusionPredicateWorksAsExpectedForObsoleteAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, - }; + ]; var sourceDirectory = DefaultSourceDirectory; var args = DefaultArgs; @@ -414,10 +420,10 @@ public async Task ProcessDetectorsAsync_DirectoryExclusionPredicateWorksAsExpect capturedRequest.DirectoryExclusionPredicate(d1.Name.AsSpan(), d1.Parent.FullName.AsSpan()).Should().BeFalse(); // Now exercise the exclusion code - args.DirectoryExclusionListObsolete = new[] { Path.Combine("Child"), Path.Combine("..", "bin") }; + args.DirectoryExclusionListObsolete = [Path.Combine("Child"), Path.Combine("..", "bin")]; await this.serviceUnderTest.ProcessDetectorsAsync( args, - new[] { this.firstFileComponentDetectorMock.Object }, + [this.firstFileComponentDetectorMock.Object], new DetectorRestrictions()); this.directoryWalkerFactory.Reset(); @@ -435,10 +441,10 @@ public async Task ProcessDetectorsAsync_CapturesTelemetryAsync() { var args = DefaultArgs; - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object, - }; + ]; var records = await TelemetryHelper.ExecuteWhileCapturingTelemetryAsync(async () => { @@ -462,13 +468,13 @@ public async Task ProcessDetectorsAsync_CapturesTelemetryAsync() [TestMethod] public async Task ProcessDetectorsAsync_ExecutesMixedCommandAndFileDetectorsAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object, this.firstCommandComponentDetectorMock.Object, this.secondCommandComponentDetectorMock.Object, - }; + ]; DetectorProcessingResult results = null; var records = await TelemetryHelper.ExecuteWhileCapturingTelemetryAsync(async () => @@ -494,10 +500,10 @@ public async Task ProcessDetectorsAsync_ExecutesMixedCommandAndFileDetectorsAsyn [TestMethod] public async Task ProcessDetectorsAsync_FinishesExperimentsAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object, - }; + ]; await this.serviceUnderTest.ProcessDetectorsAsync(DefaultArgs, this.detectorsToUse, new DetectorRestrictions()); @@ -507,10 +513,10 @@ public async Task ProcessDetectorsAsync_FinishesExperimentsAsync() [TestMethod] public async Task ProcessDetectorsAsync_RecordsDetectorRunsAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object, - }; + ]; var firstComponents = new[] { this.componentDictionary[this.firstFileComponentDetectorMock.Object.Id] }; var secondComponents = new[] { this.componentDictionary[this.secondFileComponentDetectorMock.Object.Id] }; @@ -539,10 +545,10 @@ public async Task ProcessDetectorsAsync_RecordsDetectorRunsAsync() [TestMethod] public async Task ProcessDetectorsAsync_InitializesExperimentsAsync() { - this.detectorsToUse = new[] - { + this.detectorsToUse = + [ this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object, - }; + ]; await this.serviceUnderTest.ProcessDetectorsAsync(DefaultArgs, this.detectorsToUse, new DetectorRestrictions()); diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DetectorRestrictionServiceTests.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DetectorRestrictionServiceTests.cs index d692988a7..658334000 100644 --- a/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DetectorRestrictionServiceTests.cs +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/Services/DetectorRestrictionServiceTests.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Orchestrator.Tests.Services; +namespace Microsoft.ComponentDetection.Orchestrator.Tests.Services; using System; using System.Linq; @@ -34,14 +34,14 @@ public void TestInitialize() this.retiredNpmDetector = this.GenerateDetector("MSLicenseDevNpm"); this.newNpmDetector = this.GenerateDetector("NpmWithRoots"); - this.detectors = new[] - { + this.detectors = + [ this.firstDetectorMock.Object, this.secondDetectorMock.Object, this.thirdDetectorMock.Object, this.retiredNpmDetector.Object, this.newNpmDetector.Object, - }; + ]; this.serviceUnderTest = new DetectorRestrictionService(this.logger.Object); } @@ -61,7 +61,7 @@ public void WithRestrictions_RemovesDefaultOff() var r = new DetectorRestrictions(); var detectorMock = this.GenerateDetector("defaultOffDetector"); var defaultOffDetectorMock = detectorMock.As(); - this.detectors = this.detectors.Union(new[] { defaultOffDetectorMock.Object as IComponentDetector }).ToArray(); + this.detectors = this.detectors.Union([defaultOffDetectorMock.Object]).ToArray(); var restrictedDetectors = this.serviceUnderTest.ApplyRestrictions(r, this.detectors); restrictedDetectors .Should().NotContain(defaultOffDetectorMock.Object); @@ -73,8 +73,8 @@ public void WithRestrictions_AllowsDefaultOffWithDetectorRestriction() var r = new DetectorRestrictions(); var detectorMock = this.GenerateDetector("defaultOffDetector"); var defaultOffDetectorMock = detectorMock.As(); - this.detectors = this.detectors.Union(new[] { defaultOffDetectorMock.Object as IComponentDetector }).ToArray(); - r.ExplicitlyEnabledDetectorIds = new[] { "defaultOffDetector" }; + this.detectors = this.detectors.Union([defaultOffDetectorMock.Object]).ToArray(); + r.ExplicitlyEnabledDetectorIds = ["defaultOffDetector"]; var restrictedDetectors = this.serviceUnderTest.ApplyRestrictions(r, this.detectors); restrictedDetectors .Should().Contain(defaultOffDetectorMock.Object); @@ -85,14 +85,14 @@ public void WithRestrictions_FiltersBasedOnDetectorId() { var r = new DetectorRestrictions { - AllowedDetectorIds = new[] { "FirstDetector", "SecondDetector" }, + AllowedDetectorIds = ["FirstDetector", "SecondDetector"], }; var restrictedDetectors = this.serviceUnderTest.ApplyRestrictions(r, this.detectors); restrictedDetectors .Should().Contain(this.firstDetectorMock.Object).And.Contain(this.secondDetectorMock.Object) .And.NotContain(this.thirdDetectorMock.Object); - r.AllowedDetectorIds = new[] { "NotARealDetector" }; + r.AllowedDetectorIds = ["NotARealDetector"]; Action shouldThrow = () => this.serviceUnderTest.ApplyRestrictions(r, this.detectors); shouldThrow.Should().Throw(); } @@ -102,18 +102,18 @@ public void WithRestrictions_CorrectsRetiredDetector() { var r = new DetectorRestrictions { - AllowedDetectorIds = new[] { "MSLicenseDevNpm" }, + AllowedDetectorIds = ["MSLicenseDevNpm"], }; var restrictedDetectors = this.serviceUnderTest.ApplyRestrictions(r, this.detectors); restrictedDetectors .Should().Contain(this.newNpmDetector.Object); - r.AllowedDetectorIds = new[] { "mslicensenpm" }; + r.AllowedDetectorIds = ["mslicensenpm"]; restrictedDetectors = this.serviceUnderTest.ApplyRestrictions(r, this.detectors); restrictedDetectors .Should().Contain(this.newNpmDetector.Object); - r.AllowedDetectorIds = new[] { "mslicensenpm", "NpmWithRoots" }; + r.AllowedDetectorIds = ["mslicensenpm", "NpmWithRoots"]; restrictedDetectors = this.serviceUnderTest.ApplyRestrictions(r, this.detectors); restrictedDetectors .Should().OnlyContain(item => item == this.newNpmDetector.Object); @@ -124,21 +124,21 @@ public void WithRestrictions_FiltersBasedOnCategory() { var r = new DetectorRestrictions { - AllowedDetectorCategories = new[] { "FirstDetectorCategory", "ThirdDetectorCategory" }, + AllowedDetectorCategories = ["FirstDetectorCategory", "ThirdDetectorCategory"], }; var restrictedDetectors = this.serviceUnderTest.ApplyRestrictions(r, this.detectors); restrictedDetectors .Should().Contain(this.firstDetectorMock.Object).And.Contain(this.thirdDetectorMock.Object) .And.NotContain(this.secondDetectorMock.Object); - r.AllowedDetectorCategories = new[] { "AllCategory" }; + r.AllowedDetectorCategories = ["AllCategory"]; restrictedDetectors = this.serviceUnderTest.ApplyRestrictions(r, this.detectors); restrictedDetectors .Should().Contain(this.firstDetectorMock.Object) .And.Contain(this.thirdDetectorMock.Object) .And.Contain(this.secondDetectorMock.Object); - r.AllowedDetectorCategories = new[] { "NoCategory" }; + r.AllowedDetectorCategories = ["NoCategory"]; Action shouldThrow = () => this.serviceUnderTest.ApplyRestrictions(r, this.detectors); shouldThrow.Should().Throw(); } @@ -148,14 +148,14 @@ public void WithRestrictions_AlwaysIncludesDetectorsThatSpecifyAllCategory() { var detectors = new[] { - this.GenerateDetector("1", new[] { "Cat1" }).Object, - this.GenerateDetector("2", new[] { "Cat2" }).Object, - this.GenerateDetector("3", new[] { nameof(DetectorClass.All) }).Object, + this.GenerateDetector("1", ["Cat1"]).Object, + this.GenerateDetector("2", ["Cat2"]).Object, + this.GenerateDetector("3", [nameof(DetectorClass.All)]).Object, }; var r = new DetectorRestrictions { - AllowedDetectorCategories = new[] { "ACategoryWhichDoesntMatch" }, + AllowedDetectorCategories = ["ACategoryWhichDoesntMatch"], }; var restrictedDetectors = this.serviceUnderTest.ApplyRestrictions(r, detectors); restrictedDetectors @@ -163,7 +163,7 @@ public void WithRestrictions_AlwaysIncludesDetectorsThatSpecifyAllCategory() .And.NotContain(detectors[0]) .And.NotContain(detectors[1]); - r.AllowedDetectorCategories = new[] { "Cat1" }; + r.AllowedDetectorCategories = ["Cat1"]; restrictedDetectors = this.serviceUnderTest.ApplyRestrictions(r, detectors); restrictedDetectors .Should().Contain(detectors[0]) @@ -182,7 +182,7 @@ private Mock GenerateDetector(string detectorName, string[] { var mockDetector = new Mock(); mockDetector.SetupGet(x => x.Id).Returns($"{detectorName}"); - categories ??= new[] { $"{detectorName}Category", "AllCategory" }; + categories ??= [$"{detectorName}Category", "AllCategory"]; mockDetector.SetupGet(x => x.Categories).Returns(categories); return mockDetector; diff --git a/test/Microsoft.ComponentDetection.Orchestrator.Tests/TelemetryHelper.cs b/test/Microsoft.ComponentDetection.Orchestrator.Tests/TelemetryHelper.cs index 0ea2d1c66..25a474db8 100644 --- a/test/Microsoft.ComponentDetection.Orchestrator.Tests/TelemetryHelper.cs +++ b/test/Microsoft.ComponentDetection.Orchestrator.Tests/TelemetryHelper.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Orchestrator.Tests; +namespace Microsoft.ComponentDetection.Orchestrator.Tests; using System; using System.Collections.Concurrent; @@ -24,7 +24,7 @@ public static async Task> ExecuteWhileCapturingTelemetryAsync( records.Add(asT); } }); - TelemetryRelay.Instance.Init(new[] { telemetryServiceMock.Object }); + TelemetryRelay.Instance.Init([telemetryServiceMock.Object]); try { diff --git a/test/Microsoft.ComponentDetection.TestsUtilities/Attributes/SkipTestIfNotWindowsAttribute.cs b/test/Microsoft.ComponentDetection.TestsUtilities/Attributes/SkipTestIfNotWindowsAttribute.cs index a9ffa4862..26289d9b2 100644 --- a/test/Microsoft.ComponentDetection.TestsUtilities/Attributes/SkipTestIfNotWindowsAttribute.cs +++ b/test/Microsoft.ComponentDetection.TestsUtilities/Attributes/SkipTestIfNotWindowsAttribute.cs @@ -9,14 +9,14 @@ public override TestResult[] Execute(ITestMethod testMethod) { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - return new[] - { + return + [ new TestResult { Outcome = UnitTestOutcome.Inconclusive, TestFailureException = new AssertInconclusiveException($"Skipped on {RuntimeInformation.OSDescription}."), }, - }; + ]; } return base.Execute(testMethod); diff --git a/test/Microsoft.ComponentDetection.TestsUtilities/Attributes/SkipTestOnWindowsAttribute.cs b/test/Microsoft.ComponentDetection.TestsUtilities/Attributes/SkipTestOnWindowsAttribute.cs index 0604b781c..5a335a938 100644 --- a/test/Microsoft.ComponentDetection.TestsUtilities/Attributes/SkipTestOnWindowsAttribute.cs +++ b/test/Microsoft.ComponentDetection.TestsUtilities/Attributes/SkipTestOnWindowsAttribute.cs @@ -9,14 +9,14 @@ public override TestResult[] Execute(ITestMethod testMethod) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - return new[] - { + return + [ new TestResult { Outcome = UnitTestOutcome.Inconclusive, TestFailureException = new AssertInconclusiveException("Skipped on Windows."), }, - }; + ]; } return base.Execute(testMethod); diff --git a/test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs b/test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs index ea8711d6d..74140abcf 100644 --- a/test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs +++ b/test/Microsoft.ComponentDetection.TestsUtilities/DetectorTestUtilityBuilder.cs @@ -18,7 +18,7 @@ public class DetectorTestUtilityBuilder where T : FileComponentDetector { private readonly List<(string Name, Stream Contents, string Location, IEnumerable SearchPatterns)> - filesToAdd = new(); + filesToAdd = []; private readonly Mock mockComponentStreamEnumerableFactory; private readonly Mock mockObservableDirectoryWalkerFactory; @@ -127,7 +127,7 @@ private ProcessRequest CreateProcessRequest(string pattern, string filePath, Str private void InitializeFileMocks() { - if (!this.filesToAdd.Any()) + if (this.filesToAdd.Count == 0) { this.mockObservableDirectoryWalkerFactory.Setup(x => x.GetFilteredComponentStreamObservable( @@ -137,7 +137,7 @@ private void InitializeFileMocks() .Returns(Enumerable.Empty().ToObservable()); } - if (!this.filesToAdd.Any()) + if (this.filesToAdd.Count == 0) { this.mockComponentStreamEnumerableFactory.Setup(x => x.GetComponentStreams( diff --git a/test/Microsoft.ComponentDetection.TestsUtilities/ExtensionMethods.cs b/test/Microsoft.ComponentDetection.TestsUtilities/ExtensionMethods.cs index 932b8bcd5..6de3e140c 100644 --- a/test/Microsoft.ComponentDetection.TestsUtilities/ExtensionMethods.cs +++ b/test/Microsoft.ComponentDetection.TestsUtilities/ExtensionMethods.cs @@ -38,7 +38,7 @@ public static void CaptureLogOutput(this Mock> mockLogger, ICollec var formatter = invocation.Arguments[4]; var invokeMethod = formatter.GetType().GetMethod("Invoke"); - var logMessage = (string)invokeMethod?.Invoke(formatter, new[] { state, exception }); + var logMessage = (string)invokeMethod?.Invoke(formatter, [state, exception]); logOutput.Add(logMessage); })); diff --git a/test/Microsoft.ComponentDetection.VerificationTests/ComponentDetectionIntegrationTests.cs b/test/Microsoft.ComponentDetection.VerificationTests/ComponentDetectionIntegrationTests.cs index 7370a8700..8dda90017 100644 --- a/test/Microsoft.ComponentDetection.VerificationTests/ComponentDetectionIntegrationTests.cs +++ b/test/Microsoft.ComponentDetection.VerificationTests/ComponentDetectionIntegrationTests.cs @@ -103,9 +103,9 @@ private void CompareDetectedComponents(IEnumerable leftCompone foundComponent.Should().BeTrue($"The component for {this.GetKey(leftComponent)} was not present in the {rightFileName} manifest file. Verify this is expected behavior before proceeding"); } - if (leftComponent.IsDevelopmentDependency != null) + if (leftComponent.IsDevelopmentDependency is not null) { - leftComponent.IsDevelopmentDependency.Should().Be(rightComponent.IsDevelopmentDependency, $"Component: {this.GetKey(rightComponent)} has a different \"DevelopmentDependency\"."); + _ = leftComponent.IsDevelopmentDependency.Should().Be(rightComponent.IsDevelopmentDependency, $"Component: {this.GetKey(rightComponent)} has a different \"DevelopmentDependency\"."); } } } @@ -232,7 +232,7 @@ private void ProcessDetectorVersions() { var oldDetectors = this.oldScanResult.DetectorsInScan; var newDetectors = this.newScanResult.DetectorsInScan; - this.bumpedDetectorVersions = new List(); + this.bumpedDetectorVersions = []; foreach (var cd in oldDetectors) { var newDetector = newDetectors.FirstOrDefault(det => det.DetectorId == cd.DetectorId);