From dcb06e064d88ba6c286cbbb18b84a51904f94e65 Mon Sep 17 00:00:00 2001 From: Michelle Chamberlin Date: Thu, 16 Jul 2026 16:59:12 -0700 Subject: [PATCH 1/3] add acceptance tests to track nullable enabled additions --- .../API/NullableEnabledDirectories.cs | 195 ++++++++++++++++++ ...llableEnable.CompletedFolders.approved.txt | 54 +++++ ...lableEnable.IncompleteFolders.approved.txt | 171 +++++++++++++++ .../Features/FeatureFactory.cs | 1 + .../Features/IFeatureStartupTaskController.cs | 1 + .../Hosting/HostingComponent.Configuration.cs | 1 + .../Hosting/HostingComponent.Settings.cs | 1 + .../DiagnosticSettingsExtensions.cs | 1 + .../Hosting/StartupDiagnostics/Host.cs | 1 + .../HostStartupDiagnosticsWriter.cs | 1 + .../HostStartupDiagnosticsWriterFactory.cs | 1 + .../StartupDiagnostics/JsonPrettyPrinter.cs | 1 + .../StartupDiagnosticEntries.cs | 1 + src/NServiceBus.Core/IdGeneration/CombGuid.cs | 1 + .../MessageInterfaces/IMessageMapper.cs | 1 + .../Reflection/ConcreteProxyCreator.cs | 1 + .../MessageMapper/Reflection/MessageMapper.cs | 1 + .../SystemJson/JsonMessageSerializer.cs | 1 + .../SystemJsonConfigurationExtensions.cs | 1 + .../SystemJson/SystemJsonSerializer.cs | 1 + .../SystemJsonSerializerSettings.cs | 1 + .../MessageHandlerRegistrationExtensions.cs | 1 + 22 files changed, 439 insertions(+) create mode 100644 src/NServiceBus.Core.Tests/API/NullableEnabledDirectories.cs create mode 100644 src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.CompletedFolders.approved.txt create mode 100644 src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.IncompleteFolders.approved.txt diff --git a/src/NServiceBus.Core.Tests/API/NullableEnabledDirectories.cs b/src/NServiceBus.Core.Tests/API/NullableEnabledDirectories.cs new file mode 100644 index 00000000000..9d0e1b5b265 --- /dev/null +++ b/src/NServiceBus.Core.Tests/API/NullableEnabledDirectories.cs @@ -0,0 +1,195 @@ +namespace NServiceBus.Core.Tests.API; + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using NUnit.Framework; + +[TestFixture] +public class NullableEnabledDirectories +{ + [Test] + public void EnsureFilesInCompletedDirectoriesAreAnnotated() + { + var sourceRoot = FindSourceRoot(); + var completedDirectories = ReadCompletedDirectories(sourceRoot); + + var violations = new StringBuilder(); + + foreach (var relativeDirectory in completedDirectories) + { + var directory = Path.Combine(sourceRoot, relativeDirectory); + + if (!Directory.Exists(directory)) + { + violations.AppendLine($"{relativeDirectory} (directory listed in {ApprovedFileName} no longer exists)"); + continue; + } + + foreach (var file in Directory.EnumerateFiles(directory, "*.cs", SearchOption.TopDirectoryOnly)) + { + if (!IsAnnotated(file)) + { + violations.AppendLine(Path.GetRelativePath(sourceRoot, file).Replace('\\', '/')); + } + } + } + + if (violations.Length > 0) + { + Assert.Fail( + $"The following files are missing the '#nullable enable' annotation, followed by a blank line, " + + $"even though they live in a directory listed as fully migrated in {ApprovedFileName}. Either fix " + + $"the file or, if the directory is no longer fully migrated, remove it from {ApprovedFileName}:{Environment.NewLine}{violations}"); + } + } + + [Test] + public void EnsureIncompleteDirectoriesSnapshotIsUpToDate() + { + var sourceRoot = FindSourceRoot(); + var approvalFilesDirectory = Path.Combine(sourceRoot, "NServiceBus.Core.Tests", "ApprovalFiles"); + var approvedFilePath = Path.Combine(approvalFilesDirectory, IncompleteApprovedFileName); + var receivedFilePath = Path.Combine(approvalFilesDirectory, IncompleteReceivedFileName); + + var received = BuildIncompleteDirectoriesReport(sourceRoot); + var approved = File.Exists(approvedFilePath) ? File.ReadAllText(approvedFilePath) : ""; + + if (Normalize(received) == Normalize(approved)) + { + File.Delete(receivedFilePath); + return; + } + + File.WriteAllText(receivedFilePath, received); + + var differences = DescribeDifferences(approved, received); + + Assert.Fail( + $"{IncompleteApprovedFileName} is out of date: the current annotated/total ratios no longer match. " + + $"This can happen when a file's annotation state changes, or when a directory reaches 100% and " + + $"should instead move to {ApprovedFileName}. Compare {receivedFilePath} against {approvedFilePath} " + + $"and update the approved file to match. Differing directories:{Environment.NewLine}{differences}"); + } + + static string DescribeDifferences(string approvedText, string receivedText) + { + var approvedEntries = ParseDirectoryRatios(approvedText); + var receivedEntries = ParseDirectoryRatios(receivedText); + + var allDirectories = approvedEntries.Keys + .Union(receivedEntries.Keys, StringComparer.Ordinal) + .OrderBy(directory => directory, StringComparer.Ordinal); + + var builder = new StringBuilder(); + + foreach (var directory in allDirectories) + { + var hasApproved = approvedEntries.TryGetValue(directory, out var approvedRatio); + var hasReceived = receivedEntries.TryGetValue(directory, out var receivedRatio); + + if (!hasApproved) + { + builder.AppendLine($" + {directory}\t{receivedRatio} (newly incomplete - not in {IncompleteApprovedFileName})"); + } + else if (!hasReceived) + { + builder.AppendLine($" - {directory}\t{approvedRatio} (no longer has any missing annotations - remove from {IncompleteApprovedFileName}, and add to {ApprovedFileName} if fully migrated)"); + } + else if (approvedRatio != receivedRatio) + { + builder.AppendLine($" ~ {directory}\t{approvedRatio} -> {receivedRatio}"); + } + } + + return builder.ToString(); + } + + static Dictionary ParseDirectoryRatios(string text) => + text + .Split('\n') + .Select(line => line.TrimEnd('\r')) + .SkipWhile(line => line != "-----") + .Skip(1) + .Where(line => !string.IsNullOrWhiteSpace(line)) + .Select(line => line.Split('\t')) + .ToDictionary(parts => parts[0], parts => parts[1]); + + static string BuildIncompleteDirectoriesReport(string sourceRoot) + { + var builder = new StringBuilder() + .AppendLine("The following directories have at least one .cs file that is NOT annotated with #nullable enable.") + .AppendLine("Format: directoryannotated/total files.") + .AppendLine("-----"); + + var directories = Directory.EnumerateFiles(sourceRoot, "*.cs", SearchOption.AllDirectories) + .Where(file => !IsBinOrObj(file)) + .GroupBy(file => Path.GetDirectoryName(file)!) + .Select(group => new + { + Directory = Path.GetRelativePath(sourceRoot, group.Key).Replace('\\', '/'), + Total = group.Count(), + Annotated = group.Count(IsAnnotated) + }) + .Where(entry => entry.Annotated < entry.Total) + .OrderBy(entry => entry.Directory, StringComparer.Ordinal); + + foreach (var entry in directories) + { + builder.AppendLine($"{entry.Directory}\t{entry.Annotated}/{entry.Total}"); + } + + return builder.ToString(); + } + + static bool IsAnnotated(string file) + { + var firstTwoLines = File.ReadLines(file).Take(2).ToArray(); + var firstLine = firstTwoLines.ElementAtOrDefault(0); + var secondLine = firstTwoLines.ElementAtOrDefault(1); + + return firstLine == "#nullable enable" && secondLine == ""; + } + + static bool IsBinOrObj(string path) + { + var normalized = path.Replace('\\', '/'); + return normalized.Contains("/bin/") || normalized.Contains("/obj/"); + } + + static string Normalize(string text) => text.Replace("\r\n", "\n"); + + static string[] ReadCompletedDirectories(string sourceRoot) + { + var approvedFilePath = Path.Combine(sourceRoot, "NServiceBus.Core.Tests", "ApprovalFiles", ApprovedFileName); + + return File.ReadAllLines(approvedFilePath) + .SkipWhile(line => line != "-----") + .Skip(1) + .Where(line => !string.IsNullOrWhiteSpace(line)) + .ToArray(); + } + + static string FindSourceRoot() + { + var directory = TestContext.CurrentContext.TestDirectory; + + while (directory != null) + { + if (Directory.GetFiles(directory, "*.csproj").Length == 1) + { + return Directory.GetParent(directory)!.FullName; + } + + directory = Directory.GetParent(directory)?.FullName; + } + + throw new InvalidOperationException("Could not find the src directory."); + } + + const string ApprovedFileName = "NullableEnable.CompletedFolders.approved.txt"; + const string IncompleteApprovedFileName = "NullableEnable.IncompleteFolders.approved.txt"; + const string IncompleteReceivedFileName = "NullableEnable.IncompleteFolders.received.txt"; +} diff --git a/src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.CompletedFolders.approved.txt b/src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.CompletedFolders.approved.txt new file mode 100644 index 00000000000..97aa7ee44fc --- /dev/null +++ b/src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.CompletedFolders.approved.txt @@ -0,0 +1,54 @@ +The following directories have every .cs file annotated with #nullable enable. +Changes that remove a directory from this list, or add a directory whose files are not +all annotated, should not be approved. New files added to a listed directory must also +be annotated with #nullable enable. +----- +NServiceBus.AcceptanceTests/Core/LoggingIntegration +NServiceBus.Core.Analyzer/Features +NServiceBus.Core.Tests/Receiving +NServiceBus.Core.Tests/Utils +NServiceBus.Core/Audit +NServiceBus.Core/Causation +NServiceBus.Core/CircuitBreakers +NServiceBus.Core/Conventions +NServiceBus.Core/Correlation +NServiceBus.Core/CriticalError +NServiceBus.Core/DelayedDelivery +NServiceBus.Core/Envelopes +NServiceBus.Core/Extensibility +NServiceBus.Core/Features +NServiceBus.Core/Hosting +NServiceBus.Core/Hosting/Helpers +NServiceBus.Core/Hosting/KeyedServices +NServiceBus.Core/Hosting/StartupDiagnostics +NServiceBus.Core/IdGeneration +NServiceBus.Core/Installation +NServiceBus.Core/Licensing +NServiceBus.Core/Logging +NServiceBus.Core/MessageInterfaces +NServiceBus.Core/MessageInterfaces/MessageMapper +NServiceBus.Core/MessageInterfaces/MessageMapper/Reflection +NServiceBus.Core/MessageMutators +NServiceBus.Core/MessageMutators/MutateInstanceMessage +NServiceBus.Core/MessageMutators/MutateTransportMessage +NServiceBus.Core/Notifications +NServiceBus.Core/OpenTelemetry +NServiceBus.Core/OpenTelemetry/Metrics +NServiceBus.Core/OpenTelemetry/Tracing +NServiceBus.Core/Performance/MessageProcessingOptimizations +NServiceBus.Core/Performance/Statistics +NServiceBus.Core/Performance/TimeToBeReceived +NServiceBus.Core/Persistence +NServiceBus.Core/Persistence/Learning +NServiceBus.Core/Persistence/Learning/SagaPersister +NServiceBus.Core/Pipeline +NServiceBus.Core/Pipeline/Incoming +NServiceBus.Core/Pipeline/Outgoing +NServiceBus.Core/Receiving +NServiceBus.Core/Recoverability +NServiceBus.Core/Recoverability/DelayedRetries +NServiceBus.Core/Recoverability/ImmediateRetries +NServiceBus.Core/Recoverability/Settings +NServiceBus.Core/Serializers/SystemJson +NServiceBus.Core/Support +NServiceBus.Core/Unicast/Config diff --git a/src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.IncompleteFolders.approved.txt b/src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.IncompleteFolders.approved.txt new file mode 100644 index 00000000000..f3734508590 --- /dev/null +++ b/src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.IncompleteFolders.approved.txt @@ -0,0 +1,171 @@ +The following directories have at least one .cs file that is NOT annotated with #nullable enable. +Format: directoryannotated/total files. +----- +NServiceBus.AcceptanceTesting 0/6 +NServiceBus.AcceptanceTesting/AcceptanceTestingPersistence 0/4 +NServiceBus.AcceptanceTesting/AcceptanceTestingPersistence/Outbox 0/3 +NServiceBus.AcceptanceTesting/AcceptanceTestingPersistence/SagaPersister 0/2 +NServiceBus.AcceptanceTesting/AcceptanceTestingPersistence/SubscriptionStorage 0/2 +NServiceBus.AcceptanceTesting/AcceptanceTestingTransport 0/2 +NServiceBus.AcceptanceTesting/Customization 0/4 +NServiceBus.AcceptanceTesting/Support 0/37 +NServiceBus.AcceptanceTests 0/8 +NServiceBus.AcceptanceTests/Audit 0/6 +NServiceBus.AcceptanceTests/Core 0/1 +NServiceBus.AcceptanceTests/Core/Audit 0/2 +NServiceBus.AcceptanceTests/Core/AutomaticSubscriptions 0/5 +NServiceBus.AcceptanceTests/Core/BestPractices 0/8 +NServiceBus.AcceptanceTests/Core/Causation 0/4 +NServiceBus.AcceptanceTests/Core/Conventions 0/6 +NServiceBus.AcceptanceTests/Core/CriticalError 0/2 +NServiceBus.AcceptanceTests/Core/DelayedDelivery 0/1 +NServiceBus.AcceptanceTests/Core/DependencyInjection 0/16 +NServiceBus.AcceptanceTests/Core/Diagnostics 0/8 +NServiceBus.AcceptanceTests/Core/FakeTransport 0/5 +NServiceBus.AcceptanceTests/Core/FakeTransport/CriticalError 0/1 +NServiceBus.AcceptanceTests/Core/FakeTransport/ProcessingOptimizations 0/1 +NServiceBus.AcceptanceTests/Core/Feature 0/6 +NServiceBus.AcceptanceTests/Core/Hosting 0/5 +NServiceBus.AcceptanceTests/Core/Installers 0/15 +NServiceBus.AcceptanceTests/Core/JsonSerializer 0/3 +NServiceBus.AcceptanceTests/Core/Mutators 0/5 +NServiceBus.AcceptanceTests/Core/OpenTelemetry 0/5 +NServiceBus.AcceptanceTests/Core/OpenTelemetry/Metrics 0/6 +NServiceBus.AcceptanceTests/Core/OpenTelemetry/Traces 0/22 +NServiceBus.AcceptanceTests/Core/Outbox 0/4 +NServiceBus.AcceptanceTests/Core/Persistence 0/8 +NServiceBus.AcceptanceTests/Core/Pipeline 0/21 +NServiceBus.AcceptanceTests/Core/PublishSubscribe 0/4 +NServiceBus.AcceptanceTests/Core/Recoverability 0/20 +NServiceBus.AcceptanceTests/Core/Reliability/SynchronizedStorage 0/1 +NServiceBus.AcceptanceTests/Core/Routing 0/9 +NServiceBus.AcceptanceTests/Core/Routing/AutomaticSubscriptions 0/1 +NServiceBus.AcceptanceTests/Core/Routing/MessageDrivenSubscriptions 0/3 +NServiceBus.AcceptanceTests/Core/Sagas 0/15 +NServiceBus.AcceptanceTests/Core/SelfVerification 0/4 +NServiceBus.AcceptanceTests/Core/Stopping 1/5 +NServiceBus.AcceptanceTests/Core/SubscriptionMigration 0/6 +NServiceBus.AcceptanceTests/Core/Transactions 0/1 +NServiceBus.AcceptanceTests/Core/TransportSeam 0/7 +NServiceBus.AcceptanceTests/Core/UnitOfWork/TransactionScope 0/4 +NServiceBus.AcceptanceTests/Correlation 0/2 +NServiceBus.AcceptanceTests/DelayedDelivery 0/4 +NServiceBus.AcceptanceTests/EndpointTemplates 0/8 +NServiceBus.AcceptanceTests/Feature 0/2 +NServiceBus.AcceptanceTests/Forwarding 0/1 +NServiceBus.AcceptanceTests/MessageId 0/2 +NServiceBus.AcceptanceTests/Outbox 0/8 +NServiceBus.AcceptanceTests/Pipeline 0/6 +NServiceBus.AcceptanceTests/Recoverability 0/19 +NServiceBus.AcceptanceTests/Registrations/Handlers 0/3 +NServiceBus.AcceptanceTests/Registrations/Sagas 0/5 +NServiceBus.AcceptanceTests/Routing 0/23 +NServiceBus.AcceptanceTests/Routing/MessageDrivenSubscriptions 0/8 +NServiceBus.AcceptanceTests/Routing/NativePublishSubscribe 0/6 +NServiceBus.AcceptanceTests/Sagas 0/33 +NServiceBus.AcceptanceTests/Satellites 0/1 +NServiceBus.AcceptanceTests/ScenarioDescriptors 0/1 +NServiceBus.AcceptanceTests/Serialization 0/16 +NServiceBus.AcceptanceTests/TimeToBeReceived 0/4 +NServiceBus.AcceptanceTests/Tx 0/5 +NServiceBus.AcceptanceTests/Tx/ImmediateDispatch 0/3 +NServiceBus.AcceptanceTests/Versioning 0/1 +NServiceBus.Core 16/48 +NServiceBus.Core.Analyzer 5/17 +NServiceBus.Core.Analyzer.Fixes 0/4 +NServiceBus.Core.Analyzer.Fixes/Handlers 0/5 +NServiceBus.Core.Analyzer.Fixes/Sagas 0/2 +NServiceBus.Core.Analyzer.Tests.Roslyn5 0/6 +NServiceBus.Core.Analyzer.Tests.Roslyn5/ForwardCancellationToken 0/3 +NServiceBus.Core.Analyzer.Tests.Roslyn5/Handlers 1/10 +NServiceBus.Core.Analyzer.Tests.Roslyn5/Helpers 0/1 +NServiceBus.Core.Analyzer.Tests.Roslyn5/Sagas 0/8 +NServiceBus.Core.Analyzer.Tests.Roslyn5/UniformSessionStubs 0/2 +NServiceBus.Core.Analyzer/Handlers 10/19 +NServiceBus.Core.Analyzer/Sagas 8/20 +NServiceBus.Core.Analyzer/Utility 3/9 +NServiceBus.Core.Tests 1/12 +NServiceBus.Core.Tests/API 1/7 +NServiceBus.Core.Tests/API/Infra 0/4 +NServiceBus.Core.Tests/AssemblyScanner 0/14 +NServiceBus.Core.Tests/Audit 0/1 +NServiceBus.Core.Tests/Causation 0/2 +NServiceBus.Core.Tests/Config 0/4 +NServiceBus.Core.Tests/DelayedDelivery 0/1 +NServiceBus.Core.Tests/Envelopes 0/1 +NServiceBus.Core.Tests/Fakes 0/6 +NServiceBus.Core.Tests/Features 0/12 +NServiceBus.Core.Tests/Handlers 0/1 +NServiceBus.Core.Tests/Helpers 2/3 +NServiceBus.Core.Tests/Hosting 6/10 +NServiceBus.Core.Tests/IdGeneration 0/1 +NServiceBus.Core.Tests/Licensing 0/1 +NServiceBus.Core.Tests/Logging 1/4 +NServiceBus.Core.Tests/MessageMapper 2/5 +NServiceBus.Core.Tests/MessageMutators 0/1 +NServiceBus.Core.Tests/MessageMutators/MutateInstanceMessage 0/2 +NServiceBus.Core.Tests/MessageMutators/MutateTransportMessage 0/2 +NServiceBus.Core.Tests/OpenTelemetry 2/12 +NServiceBus.Core.Tests/OpenTelemetry/Helpers 0/2 +NServiceBus.Core.Tests/Performance/TimeToBeReceived 0/1 +NServiceBus.Core.Tests/Persistence 0/2 +NServiceBus.Core.Tests/Pipeline 0/15 +NServiceBus.Core.Tests/Pipeline/Incoming 0/3 +NServiceBus.Core.Tests/Pipeline/Outgoing 0/7 +NServiceBus.Core.Tests/Recoverability 0/9 +NServiceBus.Core.Tests/Reliability/Outbox 0/2 +NServiceBus.Core.Tests/Routing 0/22 +NServiceBus.Core.Tests/Routing/MessageDrivenSubscriptions 0/5 +NServiceBus.Core.Tests/Routing/Routers 0/6 +NServiceBus.Core.Tests/Sagas 0/10 +NServiceBus.Core.Tests/Serializers 0/1 +NServiceBus.Core.Tests/Serializers/SystemTextJson 0/1 +NServiceBus.Core.Tests/Serializers/XML 0/24 +NServiceBus.Core.Tests/ServicePlatform/Retries 0/1 +NServiceBus.Core.Tests/Settings 0/1 +NServiceBus.Core.Tests/Timeout 0/1 +NServiceBus.Core.Tests/Transports 0/10 +NServiceBus.Core.Tests/Transports/Learning 0/3 +NServiceBus.Core.Tests/Unicast 0/6 +NServiceBus.Core.Tests/Unicast/Config 0/1 +NServiceBus.Core.Tests/Unicast/Contexts 0/3 +NServiceBus.Core.Tests/Unicast/Messages 0/4 +NServiceBus.Core.Tests/Unicast/Messages/ANamespace 0/1 +NServiceBus.Core.Tests/Unicast/Messages/ANamespace/ASubNamespace 0/1 +NServiceBus.Core.Tests/Utils/Reflection 0/3 +NServiceBus.Core/Properties 0/1 +NServiceBus.Core/Recoverability/Faults 7/8 +NServiceBus.Core/Reliability/Outbox 0/10 +NServiceBus.Core/Reliability/SynchronizedStorage 0/5 +NServiceBus.Core/Routing 2/46 +NServiceBus.Core/Routing/AutomaticSubscriptions 0/3 +NServiceBus.Core/Routing/MessageDrivenSubscriptions 0/19 +NServiceBus.Core/Routing/MessagingBestPractices 6/8 +NServiceBus.Core/Routing/Routers 1/4 +NServiceBus.Core/Routing/SubscriptionMigrationMode 0/5 +NServiceBus.Core/Sagas 22/47 +NServiceBus.Core/Serialization 0/8 +NServiceBus.Core/Serializers 1/3 +NServiceBus.Core/Serializers/XML 0/6 +NServiceBus.Core/Serializers/XML/Config 0/1 +NServiceBus.Core/ServicePlatform/Retries 1/3 +NServiceBus.Core/Settings 0/2 +NServiceBus.Core/StaticHeaders 0/4 +NServiceBus.Core/Transports 4/34 +NServiceBus.Core/Transports/Learning 1/15 +NServiceBus.Core/Unicast 1/6 +NServiceBus.Core/Unicast/Messages 0/3 +NServiceBus.Core/Unicast/Queuing 0/1 +NServiceBus.Core/Unicast/Transport 0/1 +NServiceBus.Core/UnitOfWork 0/2 +NServiceBus.Core/UnitOfWork/TransactionScopes 0/2 +NServiceBus.Core/Utils 5/8 +NServiceBus.Core/Utils/Reflection 3/5 +NServiceBus.Learning.AcceptanceTests 0/5 +NServiceBus.PersistenceTests 0/6 +NServiceBus.PersistenceTests/Outbox 0/1 +NServiceBus.PersistenceTests/Sagas 0/28 +NServiceBus.Testing.Fakes 0/35 +NServiceBus.TransportTests 0/42 +Shared 0/1 +msbuild 0/1 diff --git a/src/NServiceBus.Core/Features/FeatureFactory.cs b/src/NServiceBus.Core/Features/FeatureFactory.cs index c60e2fc380c..404618d9554 100644 --- a/src/NServiceBus.Core/Features/FeatureFactory.cs +++ b/src/NServiceBus.Core/Features/FeatureFactory.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus.Features; using System; diff --git a/src/NServiceBus.Core/Features/IFeatureStartupTaskController.cs b/src/NServiceBus.Core/Features/IFeatureStartupTaskController.cs index f51783acd40..c41efed38de 100644 --- a/src/NServiceBus.Core/Features/IFeatureStartupTaskController.cs +++ b/src/NServiceBus.Core/Features/IFeatureStartupTaskController.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus.Features; using System; diff --git a/src/NServiceBus.Core/Hosting/HostingComponent.Configuration.cs b/src/NServiceBus.Core/Hosting/HostingComponent.Configuration.cs index 4ed38527c71..21a9e7c736b 100644 --- a/src/NServiceBus.Core/Hosting/HostingComponent.Configuration.cs +++ b/src/NServiceBus.Core/Hosting/HostingComponent.Configuration.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System; diff --git a/src/NServiceBus.Core/Hosting/HostingComponent.Settings.cs b/src/NServiceBus.Core/Hosting/HostingComponent.Settings.cs index f46a6101f05..f0692adf5cd 100644 --- a/src/NServiceBus.Core/Hosting/HostingComponent.Settings.cs +++ b/src/NServiceBus.Core/Hosting/HostingComponent.Settings.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System; diff --git a/src/NServiceBus.Core/Hosting/StartupDiagnostics/DiagnosticSettingsExtensions.cs b/src/NServiceBus.Core/Hosting/StartupDiagnostics/DiagnosticSettingsExtensions.cs index dd136baf126..221e7bcea8b 100644 --- a/src/NServiceBus.Core/Hosting/StartupDiagnostics/DiagnosticSettingsExtensions.cs +++ b/src/NServiceBus.Core/Hosting/StartupDiagnostics/DiagnosticSettingsExtensions.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System; diff --git a/src/NServiceBus.Core/Hosting/StartupDiagnostics/Host.cs b/src/NServiceBus.Core/Hosting/StartupDiagnostics/Host.cs index bec5e59e01a..cb6b5ce44cb 100644 --- a/src/NServiceBus.Core/Hosting/StartupDiagnostics/Host.cs +++ b/src/NServiceBus.Core/Hosting/StartupDiagnostics/Host.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System; diff --git a/src/NServiceBus.Core/Hosting/StartupDiagnostics/HostStartupDiagnosticsWriter.cs b/src/NServiceBus.Core/Hosting/StartupDiagnostics/HostStartupDiagnosticsWriter.cs index 1b71d976129..d7692d49074 100644 --- a/src/NServiceBus.Core/Hosting/StartupDiagnostics/HostStartupDiagnosticsWriter.cs +++ b/src/NServiceBus.Core/Hosting/StartupDiagnostics/HostStartupDiagnosticsWriter.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System; diff --git a/src/NServiceBus.Core/Hosting/StartupDiagnostics/HostStartupDiagnosticsWriterFactory.cs b/src/NServiceBus.Core/Hosting/StartupDiagnostics/HostStartupDiagnosticsWriterFactory.cs index 68b7ee00785..a17b15fac02 100644 --- a/src/NServiceBus.Core/Hosting/StartupDiagnostics/HostStartupDiagnosticsWriterFactory.cs +++ b/src/NServiceBus.Core/Hosting/StartupDiagnostics/HostStartupDiagnosticsWriterFactory.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System; diff --git a/src/NServiceBus.Core/Hosting/StartupDiagnostics/JsonPrettyPrinter.cs b/src/NServiceBus.Core/Hosting/StartupDiagnostics/JsonPrettyPrinter.cs index 8ae2d000fae..c48c8888ccd 100644 --- a/src/NServiceBus.Core/Hosting/StartupDiagnostics/JsonPrettyPrinter.cs +++ b/src/NServiceBus.Core/Hosting/StartupDiagnostics/JsonPrettyPrinter.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System.Text.Encodings.Web; diff --git a/src/NServiceBus.Core/Hosting/StartupDiagnostics/StartupDiagnosticEntries.cs b/src/NServiceBus.Core/Hosting/StartupDiagnostics/StartupDiagnosticEntries.cs index 23fa7eed86a..6a6fea09f87 100644 --- a/src/NServiceBus.Core/Hosting/StartupDiagnostics/StartupDiagnosticEntries.cs +++ b/src/NServiceBus.Core/Hosting/StartupDiagnostics/StartupDiagnosticEntries.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System.Collections.Generic; diff --git a/src/NServiceBus.Core/IdGeneration/CombGuid.cs b/src/NServiceBus.Core/IdGeneration/CombGuid.cs index 619ef8d1b4f..6e7a5e5ef01 100644 --- a/src/NServiceBus.Core/IdGeneration/CombGuid.cs +++ b/src/NServiceBus.Core/IdGeneration/CombGuid.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System; diff --git a/src/NServiceBus.Core/MessageInterfaces/IMessageMapper.cs b/src/NServiceBus.Core/MessageInterfaces/IMessageMapper.cs index a94f53915f9..f2277466392 100644 --- a/src/NServiceBus.Core/MessageInterfaces/IMessageMapper.cs +++ b/src/NServiceBus.Core/MessageInterfaces/IMessageMapper.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus.MessageInterfaces; using System; diff --git a/src/NServiceBus.Core/MessageInterfaces/MessageMapper/Reflection/ConcreteProxyCreator.cs b/src/NServiceBus.Core/MessageInterfaces/MessageMapper/Reflection/ConcreteProxyCreator.cs index ddf7d80d4dd..be1ebfcef4e 100644 --- a/src/NServiceBus.Core/MessageInterfaces/MessageMapper/Reflection/ConcreteProxyCreator.cs +++ b/src/NServiceBus.Core/MessageInterfaces/MessageMapper/Reflection/ConcreteProxyCreator.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System; diff --git a/src/NServiceBus.Core/MessageInterfaces/MessageMapper/Reflection/MessageMapper.cs b/src/NServiceBus.Core/MessageInterfaces/MessageMapper/Reflection/MessageMapper.cs index 0a6343a3c68..6c8db4b311b 100644 --- a/src/NServiceBus.Core/MessageInterfaces/MessageMapper/Reflection/MessageMapper.cs +++ b/src/NServiceBus.Core/MessageInterfaces/MessageMapper/Reflection/MessageMapper.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus.MessageInterfaces.MessageMapper.Reflection; using System; diff --git a/src/NServiceBus.Core/Serializers/SystemJson/JsonMessageSerializer.cs b/src/NServiceBus.Core/Serializers/SystemJson/JsonMessageSerializer.cs index 6d66c49504b..60847618f43 100644 --- a/src/NServiceBus.Core/Serializers/SystemJson/JsonMessageSerializer.cs +++ b/src/NServiceBus.Core/Serializers/SystemJson/JsonMessageSerializer.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus.Serializers.SystemJson; using System; diff --git a/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonConfigurationExtensions.cs b/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonConfigurationExtensions.cs index e4e73fb88e8..f83208317cf 100644 --- a/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonConfigurationExtensions.cs +++ b/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonConfigurationExtensions.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System; diff --git a/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonSerializer.cs b/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonSerializer.cs index a2fcae51aa8..651384b9805 100644 --- a/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonSerializer.cs +++ b/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonSerializer.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System; diff --git a/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonSerializerSettings.cs b/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonSerializerSettings.cs index dd0b2720acd..7fa26fbba7f 100644 --- a/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonSerializerSettings.cs +++ b/src/NServiceBus.Core/Serializers/SystemJson/SystemJsonSerializerSettings.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus.Serializers.SystemJson; using System.Text.Json; diff --git a/src/NServiceBus.Core/Unicast/Config/MessageHandlerRegistrationExtensions.cs b/src/NServiceBus.Core/Unicast/Config/MessageHandlerRegistrationExtensions.cs index 5949ed20ca5..714222917f6 100644 --- a/src/NServiceBus.Core/Unicast/Config/MessageHandlerRegistrationExtensions.cs +++ b/src/NServiceBus.Core/Unicast/Config/MessageHandlerRegistrationExtensions.cs @@ -1,4 +1,5 @@ #nullable enable + namespace NServiceBus; using System; From 1aa6e12575fd125bc0cb87fecc9577d0b350383e Mon Sep 17 00:00:00 2001 From: Michelle Chamberlin Date: Mon, 20 Jul 2026 17:51:47 -0700 Subject: [PATCH 2/3] add NullabilityWarnings.cs in the style of TrimmabilityWarnings.cs --- .../API/NullabilityWarnings.cs | 149 +++++++ ...gs.ApproveNullabilityWarnings.approved.txt | 362 ++++++++++++++++++ 2 files changed, 511 insertions(+) create mode 100644 src/NServiceBus.Core.Tests/API/NullabilityWarnings.cs create mode 100644 src/NServiceBus.Core.Tests/ApprovalFiles/NullabilityWarnings.ApproveNullabilityWarnings.approved.txt diff --git a/src/NServiceBus.Core.Tests/API/NullabilityWarnings.cs b/src/NServiceBus.Core.Tests/API/NullabilityWarnings.cs new file mode 100644 index 00000000000..a2f73e53aa6 --- /dev/null +++ b/src/NServiceBus.Core.Tests/API/NullabilityWarnings.cs @@ -0,0 +1,149 @@ +namespace NServiceBus.Core.Tests.API; + +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using Particular.Approvals; + +// As part of the nullable reference type migration effort, individual folders are annotated with +// #nullable enable one at a time (tracked in NullableEnable.CompletedFolders.approved.txt and +// NullableEnable.IncompleteFolders.approved.txt). This test previews what would happen if nullable +// reference types were force-enabled for the whole project: files that already opt in via +// #nullable enable are unaffected, but any file without an explicit directive picks up the +// project-wide default instead of staying oblivious. This test captures the current set of +// resulting warnings so that any new regressions are immediately visible. The goal is to keep the +// list shrinking over time. Once all warnings are resolved +// and the approved file empty, this test can be deleted and enable can be set +// directly in the NServiceBus.Core.csproj. +// +// Only warnings matching the hardcoded set of nullable reference type diagnostic IDs below are captured +// (https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/nullable-warnings), +// +// See https://learn.microsoft.com/en-us/dotnet/csharp/nullable-references for more details. +[TestFixture] +public partial class NullabilityWarnings +{ + [Test] + [CancelAfter(30_000)] + public async Task ApproveNullabilityWarnings(CancellationToken cancellationToken = default) + { + var projectPath = Path.GetFullPath(Path.Combine( + TestContext.CurrentContext.TestDirectory, + "..", "..", "..", "..", + "NServiceBus.Core", + "NServiceBus.Core.csproj")); + + var binlogPath = Path.Combine(TestContext.CurrentContext.TestDirectory, "out.binlog"); + + try + { + var warnings = await BuildWithNullableEnabled(projectPath, binlogPath, cancellationToken); + + Approver.Verify(warnings); + } + finally + { + if (File.Exists(binlogPath)) + { + File.Delete(binlogPath); + } + } + } + + static async Task BuildWithNullableEnabled(string projectPath, string binlogPath, CancellationToken cancellationToken = default) + { + var startInfo = new ProcessStartInfo + { + FileName = "dotnet", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + }; + + startInfo.ArgumentList.Add("build"); + startInfo.ArgumentList.Add(projectPath); + startInfo.ArgumentList.Add("-p:Nullable=enable"); + startInfo.ArgumentList.Add("-p:TreatWarningsAsErrors=false"); + startInfo.ArgumentList.Add("-p:IsPackable=false"); + startInfo.ArgumentList.Add($"-bl:{binlogPath}"); + + using var process = Process.Start(startInfo)!; + + var outputTask = process.StandardOutput.ReadToEndAsync(cancellationToken); + var errorTask = process.StandardError.ReadToEndAsync(cancellationToken); + + await process.WaitForExitAsync(cancellationToken); + + var output = await outputTask; + var error = await errorTask; + + Assert.That(process.ExitCode, Is.Zero, $"Build failed:{Environment.NewLine}{error}{Environment.NewLine}{output}"); + + var warnings = NullableWarningRegex().Matches(output) + .Select(m => ScrubLine(m.Value.Trim())) + .Distinct() + .OrderBy(w => w, StringComparer.Ordinal) + .ToList(); + + var grouped = warnings + .GroupBy(w => FileRegex().Match(w).Groups["file"].Value) + .OrderBy(g => g.Key, StringComparer.Ordinal); + + var result = new StringBuilder() + .AppendLine("The following nullable warnings are present in NServiceBus.Core.") + .AppendLine("Changes that make this list longer should not be approved.") + .AppendLine("-----"); + + foreach (var group in grouped) + { + _ = result.AppendLine().AppendLine(group.Key); + foreach (var warning in group) + { + _ = result.AppendLine($" {MessageRegex().Match(warning).Groups["msg"].Value}"); + } + } + + return result.ToString(); + } + + static string ScrubLine(string line) + { + line = PathPrefixRegex().Replace(line, "", 1); + line = line.Replace('\\', '/'); + line = LineNumbersRegex().Replace(line, ""); + line = ProjectPathSuffixRegex().Replace(line, ""); + return line; + } + + [GeneratedRegex(@"^.+?(?=src[\\/])", RegexOptions.IgnoreCase)] + private static partial Regex PathPrefixRegex(); + + [GeneratedRegex(@"\(\d+,\d+\)")] + private static partial Regex LineNumbersRegex(); + + [GeneratedRegex(@"\s*\[[^\]]+[/\\][^\]]+\]$")] + private static partial Regex ProjectPathSuffixRegex(); + + [GeneratedRegex($@".+: warning CS({NullableWarningCodes}):.+")] + private static partial Regex NullableWarningRegex(); + + [GeneratedRegex(@"^(?src/[^\s:]+)")] + private static partial Regex FileRegex(); + + [GeneratedRegex($@": warning (?CS({NullableWarningCodes}):.+)$")] + private static partial Regex MessageRegex(); + + // Sourced from https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/nullable-warnings + const string NullableWarningCodes = + "8597|8598|8600|8601|8602|8603|8604|8605|8607|8608|8609|8610|8611|8612|8613|8614|" + + "8615|8616|8617|8618|8619|8620|8621|8622|8623|8624|8625|8628|8629|8631|8632|8633|" + + "8634|8636|8637|8639|8643|8644|8645|8650|8651|8655|8667|8668|8669|8670|8714|8762|" + + "8763|8764|8765|8766|8767|8768|8769|8770|8774|8775|8776|8777|8819|8824|8825|8847"; +} diff --git a/src/NServiceBus.Core.Tests/ApprovalFiles/NullabilityWarnings.ApproveNullabilityWarnings.approved.txt b/src/NServiceBus.Core.Tests/ApprovalFiles/NullabilityWarnings.ApproveNullabilityWarnings.approved.txt new file mode 100644 index 00000000000..2205efbcedb --- /dev/null +++ b/src/NServiceBus.Core.Tests/ApprovalFiles/NullabilityWarnings.ApproveNullabilityWarnings.approved.txt @@ -0,0 +1,362 @@ +The following nullable warnings are present in NServiceBus.Core. +Changes that make this list longer should not be approved. +----- + +src/NServiceBus.Core.Analyzer/FeatureDefaultsEnableFeatureAnalyzer.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core.Analyzer/ForwardCancellationTokenAnalyzer.cs + CS8600: Converting null literal or possible null value to non-nullable type. + CS8603: Possible null reference return. + CS8604: Possible null reference argument for parameter 'genericTaskType' in 'void ForwardCancellationTokenAnalyzer.Analyze(SyntaxNodeAnalysisContext context, INamedTypeSymbol cancellableContextInterface, INamedTypeSymbol cancellationTokenType, INamedTypeSymbol genericTaskType, INamedTypeSymbol genericValueTaskType)'. + CS8604: Possible null reference argument for parameter 'genericValueTaskType' in 'void ForwardCancellationTokenAnalyzer.Analyze(SyntaxNodeAnalysisContext context, INamedTypeSymbol cancellableContextInterface, INamedTypeSymbol cancellationTokenType, INamedTypeSymbol genericTaskType, INamedTypeSymbol genericValueTaskType)'. + CS8604: Possible null reference argument for parameter 'symbol' in 'SymbolExtensions.extension(ISymbol)'. + CS8620: Argument of type 'ImmutableDictionary' cannot be used for parameter 'properties' of type 'ImmutableDictionary' in 'Diagnostic Diagnostic.Create(DiagnosticDescriptor descriptor, Location? location, ImmutableDictionary? properties, params object?[]? messageArgs)' due to differences in the nullability of reference types. + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core.Analyzer/MethodSymbolExtensions.cs + CS8602: Dereference of a possibly null reference. + +src/NServiceBus.Core.Analyzer/Sagas/AddSagaInterceptor.cs + CS8604: Possible null reference argument for parameter 'knownTypes' in 'InterceptableSagaSpec? Parser.Parse(InvocationExpressionSyntax invocation, SemanticModel semanticModel, HandlerKnownTypes knownTypes, CancellationToken cancellationToken = default(CancellationToken))'. + +src/NServiceBus.Core.Analyzer/Sagas/FindSagaByDataSymbolVisitor.cs + CS8618: Non-nullable property 'FoundSaga' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core.Analyzer/Sagas/SagaAnalyzer.cs + CS8600: Converting null literal or possible null value to non-nullable type. + CS8601: Possible null reference assignment. + CS8602: Dereference of a possibly null reference. + CS8603: Possible null reference return. + CS8604: Possible null reference argument for parameter 'expression' in 'TypeInfo CSharpExtensions.GetTypeInfo(SemanticModel? semanticModel, ExpressionSyntax expression, CancellationToken cancellationToken = default(CancellationToken))'. + CS8604: Possible null reference argument for parameter 'interfaceType' in 'SagaHandlerDeclaration.SagaHandlerDeclaration(BaseTypeSyntax syntax, INamedTypeSymbol interfaceType)'. + CS8620: Argument of type 'ImmutableDictionary' cannot be used for parameter 'properties' of type 'ImmutableDictionary' in 'Diagnostic Diagnostic.Create(DiagnosticDescriptor descriptor, Location? location, IEnumerable? additionalLocations, ImmutableDictionary? properties, params object?[]? messageArgs)' due to differences in the nullability of reference types. + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core.Analyzer/Sagas/SagaDetails.cs + CS8618: Non-nullable property 'MapperParameterSyntax' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core.Analyzer/Sagas/SagaHandlerDeclaration.cs + CS8601: Possible null reference assignment. + CS8618: Non-nullable property 'MessageType' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'MessageTypeSyntax' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core.Analyzer/Sagas/SagaMessageMapping.cs + CS8601: Possible null reference assignment. + CS8618: Non-nullable property 'CorrelationId' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'MessageMappingExpression' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'MessageType' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'MessageTypeSyntax' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'ToSagaSyntax' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core.Analyzer/SymbolExtensions.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core.Analyzer/TypeSymbolExtensions.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core/EndpointConfiguration.cs + CS8600: Converting null literal or possible null value to non-nullable type. + CS8604: Possible null reference argument for parameter 'obj' in 'void Action.Invoke(TInitializationExtension obj)'. + +src/NServiceBus.Core/EndpointCreator.cs + CS8618: Non-nullable field 'envelopeComponent' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'featureComponent' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'hostingComponent' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'pipelineComponent' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'receiveComponent' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'recoverabilityComponent' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'sendComponent' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'transportSeam' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable property 'MessageSession' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core/Hosting/HostingComponent.Settings.cs + CS8604: Possible null reference argument for parameter 'value' in 'void SettingsHolder.Set(string key, object value)'. + +src/NServiceBus.Core/Licensing/LicenseReminder.cs + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Pipeline/Incoming/DeserializeMessageConnector.cs + CS8604: Possible null reference argument for parameter 'messageTypes' in 'object[] IMessageSerializer.Deserialize(ReadOnlyMemory body, IList messageTypes = null)'. + +src/NServiceBus.Core/Pipeline/Incoming/LogicalMessageFactory.cs + CS8604: Possible null reference argument for parameter 'messageType' in 'MessageMetadata MessageMetadataRegistry.GetMessageMetadata(Type messageType)'. + +src/NServiceBus.Core/Pipeline/Incoming/TransportReceiveToPhysicalMessageConnector.cs + CS8604: Possible null reference argument for parameter 'messageType' in 'MulticastAddressTag.MulticastAddressTag(Type messageType)'. + +src/NServiceBus.Core/Pipeline/Outgoing/SerializeMessageConnector.cs + CS8604: Possible null reference argument for parameter 'messageType' in 'MessageMetadata MessageMetadataRegistry.GetMessageMetadata(Type messageType)'. + +src/NServiceBus.Core/Reliability/Outbox/NoOpOutboxStorage.cs + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Reliability/SynchronizedStorage/SynchronizedStorage.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core/Routing/AutomaticSubscriptions/AutoSubscribe.cs + CS8602: Dereference of a possibly null reference. + +src/NServiceBus.Core/Routing/EndpointInstance.cs + CS8625: Cannot convert null literal to non-nullable reference type. + CS8765: Nullability of type of parameter 'obj' doesn't match overridden member (possibly because of nullability attributes). + +src/NServiceBus.Core/Routing/MessageDrivenSubscriptions/MessageDrivenSubscribeTerminator.cs + CS8597: Thrown value may be null. + CS8601: Possible null reference assignment. + CS8604: Possible null reference argument for parameter 'messageType' in 'Task MessageDrivenSubscribeTerminator.SendSubscribeMessageWithRetries(string destination, OutgoingMessage subscriptionMessage, string messageType, ContextBag context, int retriesCount, CancellationToken cancellationToken)'. + +src/NServiceBus.Core/Routing/MessageDrivenSubscriptions/MessageDrivenSubscriptionsConfigExtensions.cs + CS8600: Converting null literal or possible null value to non-nullable type. + CS8604: Possible null reference argument for parameter 'messageNamespace' in 'NamespacePublisherSource.NamespacePublisherSource(Assembly messageAssembly, string messageNamespace, PublisherAddress address)'. + +src/NServiceBus.Core/Routing/MessageDrivenSubscriptions/MessageDrivenUnsubscribeTerminator.cs + CS8601: Possible null reference assignment. + CS8604: Possible null reference argument for parameter 'messageType' in 'Task MessageDrivenUnsubscribeTerminator.SendUnsubscribeMessageWithRetries(string destination, OutgoingMessage unsubscribeMessage, string messageType, ContextBag context, int retriesCount, CancellationToken cancellationToken)'. + +src/NServiceBus.Core/Routing/MessageDrivenSubscriptions/MessageType.cs + CS8601: Possible null reference assignment. + CS8618: Non-nullable property 'TypeName' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'Version' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8765: Nullability of type of parameter 'obj' doesn't match overridden member (possibly because of nullability attributes). + +src/NServiceBus.Core/Routing/MessageDrivenSubscriptions/PublisherAddress.cs + CS8602: Dereference of a possibly null reference. + CS8618: Non-nullable field 'addresses' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'endpoint' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'instances' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8765: Nullability of type of parameter 'obj' doesn't match overridden member (possibly because of nullability attributes). + +src/NServiceBus.Core/Routing/MessageDrivenSubscriptions/SubscriptionReceiverBehavior.cs + CS8600: Converting null literal or possible null value to non-nullable type. + CS8603: Possible null reference return. + CS8604: Possible null reference argument for parameter 'endpoint' in 'Subscriber.Subscriber(string transportAddress, string endpoint)'. + +src/NServiceBus.Core/Routing/MessageDrivenSubscriptions/SubscriptionRouter.cs + CS8600: Converting null literal or possible null value to non-nullable type. + +src/NServiceBus.Core/Routing/RoutingComponent.cs + CS8604: Possible null reference argument for parameter 'instanceSpecificQueue' in 'UnicastSendRouter.UnicastSendRouter(bool isSendOnly, string receiveQueueName, QueueAddress instanceSpecificQueue, IDistributionPolicy defaultDistributionPolicy, UnicastRoutingTable unicastRoutingTable, EndpointInstances endpointInstances, ITransportAddressResolver transportAddressResolver)'. + +src/NServiceBus.Core/Routing/RoutingSettings.cs + CS8600: Converting null literal or possible null value to non-nullable type. + CS8604: Possible null reference argument for parameter 'messageNamespace' in 'NamespaceRouteSource.NamespaceRouteSource(Assembly messageAssembly, string messageNamespace, UnicastRoute route)'. + +src/NServiceBus.Core/Routing/SingleInstanceRoundRobinDistributionStrategy.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core/Routing/SubscriptionMigrationMode/MigrationSubscribeTerminator.cs + CS8597: Thrown value may be null. + CS8601: Possible null reference assignment. + CS8604: Possible null reference argument for parameter 'messageType' in 'Task MigrationSubscribeTerminator.SendSubscribeMessageWithRetries(string destination, OutgoingMessage subscriptionMessage, string messageType, ContextBag context, int retriesCount, CancellationToken cancellationToken)'. + +src/NServiceBus.Core/Routing/SubscriptionMigrationMode/MigrationUnsubscribeTerminator.cs + CS8601: Possible null reference assignment. + CS8604: Possible null reference argument for parameter 'messageType' in 'Task MigrationUnsubscribeTerminator.SendUnsubscribeMessageWithRetries(string destination, OutgoingMessage unsubscribeMessage, string messageType, ContextBag context, int retriesCount, CancellationToken cancellationToken)'. + +src/NServiceBus.Core/Routing/SubscriptionMigrationMode/SubscriptionMigrationModeSettings.cs + CS8600: Converting null literal or possible null value to non-nullable type. + CS8604: Possible null reference argument for parameter 'messageNamespace' in 'NamespacePublisherSource.NamespacePublisherSource(Assembly messageAssembly, string messageNamespace, PublisherAddress address)'. + +src/NServiceBus.Core/Routing/UnicastPublishRouter.cs + CS8600: Converting null literal or possible null value to non-nullable type. + +src/NServiceBus.Core/Routing/UnicastRoute.cs + CS8618: Non-nullable property 'Endpoint' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'Instance' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'PhysicalAddress' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Routing/UnicastRoutingTable.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core/Routing/UnicastSendRouter.cs + CS8618: Non-nullable field 'instanceSpecificQueue' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable property 'ExplicitDestination' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'SpecificInstance' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Sagas/ActiveSagaInstance.cs + CS8604: Possible null reference argument for parameter 'InitialValue' in 'CorrelationPropertyInfo.CorrelationPropertyInfo(string Name, Type Type, object InitialValue, bool HasInitialValue)'. + CS8604: Possible null reference argument for parameter 'currentCorrelationPropertyValue' in 'void ActiveSagaInstance.ValidateCorrelationPropertyHaveValue(object currentCorrelationPropertyValue)'. + CS8604: Possible null reference argument for parameter 'currentCorrelationPropertyValue' in 'void ActiveSagaInstance.ValidateCorrelationPropertyNotModified(object currentCorrelationPropertyValue)'. + CS8618: Non-nullable field 'correlationProperty' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable property 'SagaId' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core/Sagas/CustomFinderAdapter.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core/Sagas/Saga.cs + CS8604: Possible null reference argument for parameter 'message' in 'Task IPipelineContext.Send(object message, SendOptions options)'. + +src/NServiceBus.Core/Sagas/SagaCorrelationProperty.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core/Sagas/SagaFinderDefinition.cs + CS8618: Non-nullable property 'MessageTypeName' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'Properties' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core/Sagas/SagaLookupValues.cs + CS8601: Possible null reference assignment. + +src/NServiceBus.Core/Sagas/SagaPersistenceBehavior.cs + CS8603: Possible null reference return. + CS8604: Possible null reference argument for parameter 'messageType' in 'bool SagaMetadata.TryGetFinder(string messageType, out SagaFinderDefinition? finderDefinition)'. + CS8604: Possible null reference argument for parameter 'value' in 'SagaCorrelationProperty.SagaCorrelationProperty(string name, object value)'. + CS8619: Nullability of reference types in value of type 'Task' doesn't match target type 'Task'. + +src/NServiceBus.Core/Serialization/IMessageSerializer.cs + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Serializers/XML/XmlDeserialization.cs + CS8600: Converting null literal or possible null value to non-nullable type. + CS8603: Possible null reference return. + CS8604: Possible null reference argument for parameter 'fields' in 'FieldInfo XmlDeserialization.GetField(FieldInfo[] fields, string name)'. + CS8604: Possible null reference argument for parameter 'node' in 'object XmlDeserialization.Process(XmlNode node, object parent, Type nodeType = null)'. + CS8604: Possible null reference argument for parameter 'properties' in 'PropertyInfo XmlDeserialization.GetProperty(PropertyInfo[] properties, string name)'. + CS8618: Non-nullable field 'defaultNamespace' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Serializers/XML/XmlMessageSerializer.cs + CS8603: Possible null reference return. + CS8604: Possible null reference argument for parameter 'messageType' in 'XmlSerialization.XmlSerialization(Type messageType, Stream stream, object message, Conventions conventions, XmlSerializerCache cache, bool skipWrappingRawXml, string @namespace = "http://tempuri.net")'. + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Serializers/XML/XmlSanitizingStream.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core/Serializers/XML/XmlSerialization.cs + CS8604: Possible null reference argument for parameter 'elem' in 'void XmlSerialization.WriteObject(XElement elem, string name, Type type, object value, bool useNS = false)'. + CS8604: Possible null reference argument for parameter 'item' in 'bool List.Contains(string item)'. + CS8604: Possible null reference argument for parameter 'value' in 'void XmlSerialization.WriteObject(XElement elem, string name, Type type, object value, bool useNS = false)'. + +src/NServiceBus.Core/Serializers/XML/XmlSerializerCache.cs + CS8604: Possible null reference argument for parameter 'typeArguments' in 'Type Type.MakeGenericType(params Type[] typeArguments)'. + +src/NServiceBus.Core/ServicePlatform/Retries/RetryAcknowledgementBehavior.cs + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Settings/SettingsHolder.cs + CS8601: Possible null reference assignment. + CS8603: Possible null reference return. + CS8604: Possible null reference argument for parameter 'key' in 'T SettingsHolder.GetOrDefault(string key)'. + CS8604: Possible null reference argument for parameter 'key' in 'bool SettingsHolder.HasExplicitValue(string key)'. + CS8604: Possible null reference argument for parameter 'key' in 'bool SettingsHolder.HasSetting(string key)'. + CS8604: Possible null reference argument for parameter 'key' in 'bool SettingsHolder.TryGet(string key, out T val)'. + CS8604: Possible null reference argument for parameter 'key' in 'object SettingsHolder.Get(string key)'. + CS8604: Possible null reference argument for parameter 'key' in 'void SettingsHolder.Set(string key, object value)'. + CS8604: Possible null reference argument for parameter 'key' in 'void SettingsHolder.SetDefault(string key, object value)'. + CS8604: Possible null reference argument for parameter 'value' in 'void SettingsHolder.Set(string key, object value)'. + CS8604: Possible null reference argument for parameter 'value' in 'void SettingsHolder.SetDefault(string key, object value)'. + +src/NServiceBus.Core/StartableEndpoint.cs + CS8618: Non-nullable field 'stoppingTokenSource' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'transportInfrastructure' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + +src/NServiceBus.Core/Transports/DispatchProperties.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core/Transports/IncomingMessageExtensions.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core/Transports/Learning/DelayedMessagePoller.cs + CS8618: Non-nullable field 'polling' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + +src/NServiceBus.Core/Transports/Learning/DirectoryBasedTransaction.cs + CS8618: Non-nullable property 'FileToProcess' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core/Transports/Learning/HeaderSerializer.cs + CS8603: Possible null reference return. + +src/NServiceBus.Core/Transports/Learning/LearningTransport.cs + CS8618: Non-nullable property 'StorageDirectory' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core/Transports/Learning/LearningTransportDispatcher.cs + CS8604: Possible null reference argument for parameter 'path3' in 'string Path.Combine(string path1, string path2, string path3)'. + +src/NServiceBus.Core/Transports/Learning/LearningTransportInfrastructure.cs + CS8604: Possible null reference argument for parameter 'subscriptionManager' in 'LearningTransportMessagePump.LearningTransportMessagePump(string id, string receiveAddress, string basePath, Action criticalErrorAction, ISubscriptionManager subscriptionManager, ReceiveSettings receiveSettings, TransportTransactionMode transactionMode)'. + +src/NServiceBus.Core/Transports/Learning/LearningTransportMessagePump.cs + CS8618: Non-nullable field 'bodyDir' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'committedTransactionDir' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'concurrencyLimiter' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'delayedDir' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'delayedMessagePoller' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'messageProcessingCancellationTokenSource' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'messagePumpBasePath' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'messagePumpCancellationTokenSource' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'messagePumpTask' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'onError' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'onMessage' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'pendingTransactionDir' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Transports/Learning/LearningTransportSubscriptionManager.cs + CS8604: Possible null reference argument for parameter 'path2' in 'string Path.Combine(string path1, string path2)'. + +src/NServiceBus.Core/Transports/Learning/NoTransaction.cs + CS8618: Non-nullable property 'FileToProcess' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core/Transports/QueueAddress.cs + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Transports/TransportInfrastructure.cs + CS8618: Non-nullable property 'Dispatcher' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'Receivers' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core/Transports/TransportOperation.cs + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Transports/TransportSeam.cs + CS8618: Non-nullable field 'receiverSettings' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'transportInfrastructure' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + +src/NServiceBus.Core/Unicast/MessageOperations.cs + CS8604: Possible null reference argument for parameter 'message' in 'Task MessageOperations.Publish(IBehaviorContext context, Type messageType, object message, PublishOptions options)'. + CS8604: Possible null reference argument for parameter 'message' in 'Task MessageOperations.ReplyMessage(IBehaviorContext context, Type messageType, object message, ReplyOptions options)'. + CS8604: Possible null reference argument for parameter 'message' in 'Task MessageOperations.SendMessage(IBehaviorContext context, Type messageType, object message, SendOptions options)'. + CS8604: Possible null reference argument for parameter 'messageType' in 'Task MessageOperations.Publish(IBehaviorContext context, Type messageType, object message, PublishOptions options)'. + CS8604: Possible null reference argument for parameter 'messageType' in 'Task MessageOperations.ReplyMessage(IBehaviorContext context, Type messageType, object message, ReplyOptions options)'. + CS8604: Possible null reference argument for parameter 'messageType' in 'Task MessageOperations.SendMessage(IBehaviorContext context, Type messageType, object message, SendOptions options)'. + +src/NServiceBus.Core/Unicast/Messages/MessageMetadata.cs + CS8604: Possible null reference argument for parameter 'item' in 'bool ICollection.Contains(string item)'. + CS8625: Cannot convert null literal to non-nullable reference type. + +src/NServiceBus.Core/Unicast/Messages/MessageMetadataRegistry.cs + CS8601: Possible null reference assignment. + CS8603: Possible null reference return. + CS8604: Possible null reference argument for parameter 'key' in 'bool ConcurrentDictionary.TryAdd(string key, Type value)'. + CS8618: Non-nullable field 'isMessageType' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + +src/NServiceBus.Core/Unicast/Queuing/QueueNotFoundException.cs + CS8618: Non-nullable property 'Queue' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core/Utils/FileVersionRetriever.cs + CS8602: Dereference of a possibly null reference. + +src/NServiceBus.Core/Utils/Reflection/DelegateFactory.cs + CS8602: Dereference of a possibly null reference. + CS8604: Possible null reference argument for parameter 'meth' in 'void ILGenerator.Emit(OpCode opcode, MethodInfo meth)'. + CS8604: Possible null reference argument for parameter 'type' in 'UnaryExpression Expression.Convert(Expression expression, Type type)'. + +src/NServiceBus.Core/Utils/Reflection/TypeExtensionMethods.cs + CS8601: Possible null reference assignment. + CS8603: Possible null reference return. + +src/NServiceBus.Core/VersionInformation.cs + CS8601: Possible null reference assignment. + CS8618: Non-nullable property 'MajorMinorPatch' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + +src/NServiceBus.Core/obsoletes-v10.cs + CS8618: Non-nullable field 'isMessageType' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable field 'sagaFinders' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable. + CS8618: Non-nullable property 'AssociatedMessages' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'EntityName' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'Loader' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'NotFoundHandler' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'SagaDataFactory' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'SagaEntityType' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + CS8618: Non-nullable property 'SagaType' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. From 3fdc5da4b5345b7bf7b6b60f3c1b2b0306d31b26 Mon Sep 17 00:00:00 2001 From: Michelle Chamberlin Date: Wed, 22 Jul 2026 10:11:55 -0700 Subject: [PATCH 3/3] change the incompleteDirectories test to only generate the report when explicity run --- .../API/NullableEnabledDirectories.cs | 76 +------- ...lableEnable.IncompleteFolders.approved.txt | 171 ------------------ 2 files changed, 10 insertions(+), 237 deletions(-) delete mode 100644 src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.IncompleteFolders.approved.txt diff --git a/src/NServiceBus.Core.Tests/API/NullableEnabledDirectories.cs b/src/NServiceBus.Core.Tests/API/NullableEnabledDirectories.cs index 9d0e1b5b265..66384a8f0ba 100644 --- a/src/NServiceBus.Core.Tests/API/NullableEnabledDirectories.cs +++ b/src/NServiceBus.Core.Tests/API/NullableEnabledDirectories.cs @@ -1,7 +1,6 @@ namespace NServiceBus.Core.Tests.API; using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; @@ -47,82 +46,30 @@ public void EnsureFilesInCompletedDirectoriesAreAnnotated() } [Test] - public void EnsureIncompleteDirectoriesSnapshotIsUpToDate() + [Explicit("Run this test to generate a report of directories that are not fully annotated with '#nullable enable'.")] + public void GenerateIncompleteDirectoriesReport() { var sourceRoot = FindSourceRoot(); var approvalFilesDirectory = Path.Combine(sourceRoot, "NServiceBus.Core.Tests", "ApprovalFiles"); - var approvedFilePath = Path.Combine(approvalFilesDirectory, IncompleteApprovedFileName); - var receivedFilePath = Path.Combine(approvalFilesDirectory, IncompleteReceivedFileName); + var incompleteReportFilePath = Path.Combine(approvalFilesDirectory, IncompleteReceivedFileName); - var received = BuildIncompleteDirectoriesReport(sourceRoot); - var approved = File.Exists(approvedFilePath) ? File.ReadAllText(approvedFilePath) : ""; + var incompleteReport = BuildIncompleteDirectoriesReport(sourceRoot); - if (Normalize(received) == Normalize(approved)) + if (Path.Exists(incompleteReport)) { - File.Delete(receivedFilePath); - return; + File.Delete(incompleteReportFilePath); } - File.WriteAllText(receivedFilePath, received); - - var differences = DescribeDifferences(approved, received); - - Assert.Fail( - $"{IncompleteApprovedFileName} is out of date: the current annotated/total ratios no longer match. " + - $"This can happen when a file's annotation state changes, or when a directory reaches 100% and " + - $"should instead move to {ApprovedFileName}. Compare {receivedFilePath} against {approvedFilePath} " + - $"and update the approved file to match. Differing directories:{Environment.NewLine}{differences}"); - } - - static string DescribeDifferences(string approvedText, string receivedText) - { - var approvedEntries = ParseDirectoryRatios(approvedText); - var receivedEntries = ParseDirectoryRatios(receivedText); - - var allDirectories = approvedEntries.Keys - .Union(receivedEntries.Keys, StringComparer.Ordinal) - .OrderBy(directory => directory, StringComparer.Ordinal); - - var builder = new StringBuilder(); - - foreach (var directory in allDirectories) - { - var hasApproved = approvedEntries.TryGetValue(directory, out var approvedRatio); - var hasReceived = receivedEntries.TryGetValue(directory, out var receivedRatio); - - if (!hasApproved) - { - builder.AppendLine($" + {directory}\t{receivedRatio} (newly incomplete - not in {IncompleteApprovedFileName})"); - } - else if (!hasReceived) - { - builder.AppendLine($" - {directory}\t{approvedRatio} (no longer has any missing annotations - remove from {IncompleteApprovedFileName}, and add to {ApprovedFileName} if fully migrated)"); - } - else if (approvedRatio != receivedRatio) - { - builder.AppendLine($" ~ {directory}\t{approvedRatio} -> {receivedRatio}"); - } - } - - return builder.ToString(); + File.WriteAllText(incompleteReportFilePath, incompleteReport); } - static Dictionary ParseDirectoryRatios(string text) => - text - .Split('\n') - .Select(line => line.TrimEnd('\r')) - .SkipWhile(line => line != "-----") - .Skip(1) - .Where(line => !string.IsNullOrWhiteSpace(line)) - .Select(line => line.Split('\t')) - .ToDictionary(parts => parts[0], parts => parts[1]); - static string BuildIncompleteDirectoriesReport(string sourceRoot) { var builder = new StringBuilder() .AppendLine("The following directories have at least one .cs file that is NOT annotated with #nullable enable.") .AppendLine("Format: directoryannotated/total files.") - .AppendLine("-----"); + .AppendLine("-----") + .AppendLine("This file is for analysis purposes only and should not be committed."); var directories = Directory.EnumerateFiles(sourceRoot, "*.cs", SearchOption.AllDirectories) .Where(file => !IsBinOrObj(file)) @@ -159,8 +106,6 @@ static bool IsBinOrObj(string path) return normalized.Contains("/bin/") || normalized.Contains("/obj/"); } - static string Normalize(string text) => text.Replace("\r\n", "\n"); - static string[] ReadCompletedDirectories(string sourceRoot) { var approvedFilePath = Path.Combine(sourceRoot, "NServiceBus.Core.Tests", "ApprovalFiles", ApprovedFileName); @@ -190,6 +135,5 @@ static string FindSourceRoot() } const string ApprovedFileName = "NullableEnable.CompletedFolders.approved.txt"; - const string IncompleteApprovedFileName = "NullableEnable.IncompleteFolders.approved.txt"; - const string IncompleteReceivedFileName = "NullableEnable.IncompleteFolders.received.txt"; + const string IncompleteReceivedFileName = "NullableEnable.IncompleteFolders.txt"; } diff --git a/src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.IncompleteFolders.approved.txt b/src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.IncompleteFolders.approved.txt deleted file mode 100644 index f3734508590..00000000000 --- a/src/NServiceBus.Core.Tests/ApprovalFiles/NullableEnable.IncompleteFolders.approved.txt +++ /dev/null @@ -1,171 +0,0 @@ -The following directories have at least one .cs file that is NOT annotated with #nullable enable. -Format: directoryannotated/total files. ------ -NServiceBus.AcceptanceTesting 0/6 -NServiceBus.AcceptanceTesting/AcceptanceTestingPersistence 0/4 -NServiceBus.AcceptanceTesting/AcceptanceTestingPersistence/Outbox 0/3 -NServiceBus.AcceptanceTesting/AcceptanceTestingPersistence/SagaPersister 0/2 -NServiceBus.AcceptanceTesting/AcceptanceTestingPersistence/SubscriptionStorage 0/2 -NServiceBus.AcceptanceTesting/AcceptanceTestingTransport 0/2 -NServiceBus.AcceptanceTesting/Customization 0/4 -NServiceBus.AcceptanceTesting/Support 0/37 -NServiceBus.AcceptanceTests 0/8 -NServiceBus.AcceptanceTests/Audit 0/6 -NServiceBus.AcceptanceTests/Core 0/1 -NServiceBus.AcceptanceTests/Core/Audit 0/2 -NServiceBus.AcceptanceTests/Core/AutomaticSubscriptions 0/5 -NServiceBus.AcceptanceTests/Core/BestPractices 0/8 -NServiceBus.AcceptanceTests/Core/Causation 0/4 -NServiceBus.AcceptanceTests/Core/Conventions 0/6 -NServiceBus.AcceptanceTests/Core/CriticalError 0/2 -NServiceBus.AcceptanceTests/Core/DelayedDelivery 0/1 -NServiceBus.AcceptanceTests/Core/DependencyInjection 0/16 -NServiceBus.AcceptanceTests/Core/Diagnostics 0/8 -NServiceBus.AcceptanceTests/Core/FakeTransport 0/5 -NServiceBus.AcceptanceTests/Core/FakeTransport/CriticalError 0/1 -NServiceBus.AcceptanceTests/Core/FakeTransport/ProcessingOptimizations 0/1 -NServiceBus.AcceptanceTests/Core/Feature 0/6 -NServiceBus.AcceptanceTests/Core/Hosting 0/5 -NServiceBus.AcceptanceTests/Core/Installers 0/15 -NServiceBus.AcceptanceTests/Core/JsonSerializer 0/3 -NServiceBus.AcceptanceTests/Core/Mutators 0/5 -NServiceBus.AcceptanceTests/Core/OpenTelemetry 0/5 -NServiceBus.AcceptanceTests/Core/OpenTelemetry/Metrics 0/6 -NServiceBus.AcceptanceTests/Core/OpenTelemetry/Traces 0/22 -NServiceBus.AcceptanceTests/Core/Outbox 0/4 -NServiceBus.AcceptanceTests/Core/Persistence 0/8 -NServiceBus.AcceptanceTests/Core/Pipeline 0/21 -NServiceBus.AcceptanceTests/Core/PublishSubscribe 0/4 -NServiceBus.AcceptanceTests/Core/Recoverability 0/20 -NServiceBus.AcceptanceTests/Core/Reliability/SynchronizedStorage 0/1 -NServiceBus.AcceptanceTests/Core/Routing 0/9 -NServiceBus.AcceptanceTests/Core/Routing/AutomaticSubscriptions 0/1 -NServiceBus.AcceptanceTests/Core/Routing/MessageDrivenSubscriptions 0/3 -NServiceBus.AcceptanceTests/Core/Sagas 0/15 -NServiceBus.AcceptanceTests/Core/SelfVerification 0/4 -NServiceBus.AcceptanceTests/Core/Stopping 1/5 -NServiceBus.AcceptanceTests/Core/SubscriptionMigration 0/6 -NServiceBus.AcceptanceTests/Core/Transactions 0/1 -NServiceBus.AcceptanceTests/Core/TransportSeam 0/7 -NServiceBus.AcceptanceTests/Core/UnitOfWork/TransactionScope 0/4 -NServiceBus.AcceptanceTests/Correlation 0/2 -NServiceBus.AcceptanceTests/DelayedDelivery 0/4 -NServiceBus.AcceptanceTests/EndpointTemplates 0/8 -NServiceBus.AcceptanceTests/Feature 0/2 -NServiceBus.AcceptanceTests/Forwarding 0/1 -NServiceBus.AcceptanceTests/MessageId 0/2 -NServiceBus.AcceptanceTests/Outbox 0/8 -NServiceBus.AcceptanceTests/Pipeline 0/6 -NServiceBus.AcceptanceTests/Recoverability 0/19 -NServiceBus.AcceptanceTests/Registrations/Handlers 0/3 -NServiceBus.AcceptanceTests/Registrations/Sagas 0/5 -NServiceBus.AcceptanceTests/Routing 0/23 -NServiceBus.AcceptanceTests/Routing/MessageDrivenSubscriptions 0/8 -NServiceBus.AcceptanceTests/Routing/NativePublishSubscribe 0/6 -NServiceBus.AcceptanceTests/Sagas 0/33 -NServiceBus.AcceptanceTests/Satellites 0/1 -NServiceBus.AcceptanceTests/ScenarioDescriptors 0/1 -NServiceBus.AcceptanceTests/Serialization 0/16 -NServiceBus.AcceptanceTests/TimeToBeReceived 0/4 -NServiceBus.AcceptanceTests/Tx 0/5 -NServiceBus.AcceptanceTests/Tx/ImmediateDispatch 0/3 -NServiceBus.AcceptanceTests/Versioning 0/1 -NServiceBus.Core 16/48 -NServiceBus.Core.Analyzer 5/17 -NServiceBus.Core.Analyzer.Fixes 0/4 -NServiceBus.Core.Analyzer.Fixes/Handlers 0/5 -NServiceBus.Core.Analyzer.Fixes/Sagas 0/2 -NServiceBus.Core.Analyzer.Tests.Roslyn5 0/6 -NServiceBus.Core.Analyzer.Tests.Roslyn5/ForwardCancellationToken 0/3 -NServiceBus.Core.Analyzer.Tests.Roslyn5/Handlers 1/10 -NServiceBus.Core.Analyzer.Tests.Roslyn5/Helpers 0/1 -NServiceBus.Core.Analyzer.Tests.Roslyn5/Sagas 0/8 -NServiceBus.Core.Analyzer.Tests.Roslyn5/UniformSessionStubs 0/2 -NServiceBus.Core.Analyzer/Handlers 10/19 -NServiceBus.Core.Analyzer/Sagas 8/20 -NServiceBus.Core.Analyzer/Utility 3/9 -NServiceBus.Core.Tests 1/12 -NServiceBus.Core.Tests/API 1/7 -NServiceBus.Core.Tests/API/Infra 0/4 -NServiceBus.Core.Tests/AssemblyScanner 0/14 -NServiceBus.Core.Tests/Audit 0/1 -NServiceBus.Core.Tests/Causation 0/2 -NServiceBus.Core.Tests/Config 0/4 -NServiceBus.Core.Tests/DelayedDelivery 0/1 -NServiceBus.Core.Tests/Envelopes 0/1 -NServiceBus.Core.Tests/Fakes 0/6 -NServiceBus.Core.Tests/Features 0/12 -NServiceBus.Core.Tests/Handlers 0/1 -NServiceBus.Core.Tests/Helpers 2/3 -NServiceBus.Core.Tests/Hosting 6/10 -NServiceBus.Core.Tests/IdGeneration 0/1 -NServiceBus.Core.Tests/Licensing 0/1 -NServiceBus.Core.Tests/Logging 1/4 -NServiceBus.Core.Tests/MessageMapper 2/5 -NServiceBus.Core.Tests/MessageMutators 0/1 -NServiceBus.Core.Tests/MessageMutators/MutateInstanceMessage 0/2 -NServiceBus.Core.Tests/MessageMutators/MutateTransportMessage 0/2 -NServiceBus.Core.Tests/OpenTelemetry 2/12 -NServiceBus.Core.Tests/OpenTelemetry/Helpers 0/2 -NServiceBus.Core.Tests/Performance/TimeToBeReceived 0/1 -NServiceBus.Core.Tests/Persistence 0/2 -NServiceBus.Core.Tests/Pipeline 0/15 -NServiceBus.Core.Tests/Pipeline/Incoming 0/3 -NServiceBus.Core.Tests/Pipeline/Outgoing 0/7 -NServiceBus.Core.Tests/Recoverability 0/9 -NServiceBus.Core.Tests/Reliability/Outbox 0/2 -NServiceBus.Core.Tests/Routing 0/22 -NServiceBus.Core.Tests/Routing/MessageDrivenSubscriptions 0/5 -NServiceBus.Core.Tests/Routing/Routers 0/6 -NServiceBus.Core.Tests/Sagas 0/10 -NServiceBus.Core.Tests/Serializers 0/1 -NServiceBus.Core.Tests/Serializers/SystemTextJson 0/1 -NServiceBus.Core.Tests/Serializers/XML 0/24 -NServiceBus.Core.Tests/ServicePlatform/Retries 0/1 -NServiceBus.Core.Tests/Settings 0/1 -NServiceBus.Core.Tests/Timeout 0/1 -NServiceBus.Core.Tests/Transports 0/10 -NServiceBus.Core.Tests/Transports/Learning 0/3 -NServiceBus.Core.Tests/Unicast 0/6 -NServiceBus.Core.Tests/Unicast/Config 0/1 -NServiceBus.Core.Tests/Unicast/Contexts 0/3 -NServiceBus.Core.Tests/Unicast/Messages 0/4 -NServiceBus.Core.Tests/Unicast/Messages/ANamespace 0/1 -NServiceBus.Core.Tests/Unicast/Messages/ANamespace/ASubNamespace 0/1 -NServiceBus.Core.Tests/Utils/Reflection 0/3 -NServiceBus.Core/Properties 0/1 -NServiceBus.Core/Recoverability/Faults 7/8 -NServiceBus.Core/Reliability/Outbox 0/10 -NServiceBus.Core/Reliability/SynchronizedStorage 0/5 -NServiceBus.Core/Routing 2/46 -NServiceBus.Core/Routing/AutomaticSubscriptions 0/3 -NServiceBus.Core/Routing/MessageDrivenSubscriptions 0/19 -NServiceBus.Core/Routing/MessagingBestPractices 6/8 -NServiceBus.Core/Routing/Routers 1/4 -NServiceBus.Core/Routing/SubscriptionMigrationMode 0/5 -NServiceBus.Core/Sagas 22/47 -NServiceBus.Core/Serialization 0/8 -NServiceBus.Core/Serializers 1/3 -NServiceBus.Core/Serializers/XML 0/6 -NServiceBus.Core/Serializers/XML/Config 0/1 -NServiceBus.Core/ServicePlatform/Retries 1/3 -NServiceBus.Core/Settings 0/2 -NServiceBus.Core/StaticHeaders 0/4 -NServiceBus.Core/Transports 4/34 -NServiceBus.Core/Transports/Learning 1/15 -NServiceBus.Core/Unicast 1/6 -NServiceBus.Core/Unicast/Messages 0/3 -NServiceBus.Core/Unicast/Queuing 0/1 -NServiceBus.Core/Unicast/Transport 0/1 -NServiceBus.Core/UnitOfWork 0/2 -NServiceBus.Core/UnitOfWork/TransactionScopes 0/2 -NServiceBus.Core/Utils 5/8 -NServiceBus.Core/Utils/Reflection 3/5 -NServiceBus.Learning.AcceptanceTests 0/5 -NServiceBus.PersistenceTests 0/6 -NServiceBus.PersistenceTests/Outbox 0/1 -NServiceBus.PersistenceTests/Sagas 0/28 -NServiceBus.Testing.Fakes 0/35 -NServiceBus.TransportTests 0/42 -Shared 0/1 -msbuild 0/1