From 38562a340320f162b3d71f201fe47e04d8ac70aa Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 30 Jun 2026 11:10:42 +0200 Subject: [PATCH] style: apply repo-wide code formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply the configured ReSharper/formatter layout across the solution (attribute placement, member layout, whitespace). One semantic side-effect was corrected: the cleanup turned a test helper property get-only, breaking PropertyPathTests.Setter_Property_WritesValue (the property is written via an expression-tree setter the analyzer can't see) — restored its setter. No production property lost a setter (verified) and the full suite is green. --- SquidStd.slnx | 128 ++++++------ samples/SquidStd.Samples.Actors/Program.cs | 5 +- samples/SquidStd.Samples.Caching/Program.cs | 3 +- samples/SquidStd.Samples.Crypto/Program.cs | 17 +- samples/SquidStd.Samples.Database/Program.cs | 15 +- samples/SquidStd.Samples.Email/Program.cs | 23 +- .../Program.cs | 10 +- .../Program.cs | 3 +- samples/SquidStd.Samples.Messaging/Program.cs | 3 +- .../SquidStd.Samples.Networking/Program.cs | 8 +- .../SquidStd.Samples.Persistence/Program.cs | 12 +- samples/SquidStd.Samples.Plugins/Program.cs | 14 +- .../SquidStd.Samples.ScriptingLua/Program.cs | 13 +- samples/SquidStd.Samples.Search/Program.cs | 15 +- samples/SquidStd.Samples.Secrets/Program.cs | 57 ++--- samples/SquidStd.Samples.Storage/Program.cs | 3 +- .../SquidStd.Samples.Templating/Program.cs | 3 +- .../CounterComposedView.cs | 7 +- .../SquidStd.Samples.Tui/CounterViewModel.cs | 10 +- samples/SquidStd.Samples.Vfs/Program.cs | 3 +- .../SquidStd.Samples.WorkerSystem/Program.cs | 6 +- .../RegisterConfigSectionAttribute.cs | 8 +- .../RegisterEventListenerAttribute.cs | 6 +- .../Attributes/RegisterStdServiceAttribute.cs | 8 +- .../Commands/CommandHandlerRegistration.cs | 6 +- .../Events/EventListenerRegistration.cs | 6 +- .../RegisterCommandHandlerExtension.cs | 4 +- .../Config/RegisterConfigSectionExtension.cs | 5 +- .../Container/AddTypedListMethodExtension.cs | 6 +- .../Events/RegisterEventListenerExtension.cs | 4 +- .../Interfaces/Services/ISquidStdService.cs | 2 +- src/SquidStd.Abstractions/README.md | 23 +- src/SquidStd.Actors/Actor.cs | 36 ++-- src/SquidStd.Actors/ActorRequest.cs | 19 +- src/SquidStd.Actors/Data/ActorOptions.cs | 8 +- .../Extensions/ActorEventBusExtensions.cs | 13 +- .../Interfaces/IActorRequest.cs | 2 +- .../Interfaces/IActorRequestCore.cs | 4 +- src/SquidStd.Actors/README.md | 24 +-- src/SquidStd.Actors/Types/ActorErrorPolicy.cs | 2 +- .../Types/ActorOverflowPolicy.cs | 2 +- .../SquidStdAspNetCoreBuilderExtensions.cs | 10 +- .../SquidStdHealthChecksExtensions.cs | 10 +- .../Services/SquidStdHealthCheckAdapter.cs | 8 +- .../Services/SquidStdHostedService.cs | 12 +- .../Data/Config/AwsConfigEntry.cs | 4 +- src/SquidStd.Aws.Abstractions/README.md | 4 +- .../Data/Config/CacheConnectionString.cs | 24 +-- .../Data/Config/CacheOptions.cs | 2 +- .../Interfaces/ICacheMetrics.cs | 2 +- .../Interfaces/ICacheProvider.cs | 2 +- .../Interfaces/ICacheService.cs | 2 +- .../Services/CacheMetricsProvider.cs | 18 +- .../Services/CacheService.cs | 12 +- .../Services/NoOpCacheMetrics.cs | 18 +- .../Data/Config/RedisCacheOptions.cs | 2 +- .../RedisCacheRegistrationExtensions.cs | 2 +- .../Services/RedisCacheProvider.cs | 20 +- .../Extensions/CacheRegistrationExtensions.cs | 2 +- .../Services/InMemoryCacheProvider.cs | 14 +- .../Data/Bootstrap/SquidStdLoggerOptions.cs | 14 +- .../Data/Bootstrap/SquidStdOptions.cs | 6 +- .../Data/Commands/CommandDispatchResult.cs | 2 +- .../Data/Commands/CommandHandlerError.cs | 2 +- .../Data/Config/HealthCheckOptions.cs | 2 +- .../Data/Events/EventBusOptions.cs | 4 +- .../Data/Files/FileChangedEvent.cs | 2 +- .../Data/Health/HealthCheckResult.cs | 10 +- src/SquidStd.Core/Data/Health/HealthReport.cs | 2 +- src/SquidStd.Core/Data/Jobs/JobsConfig.cs | 6 +- .../Data/Metrics/MetricSample.cs | 2 +- .../Data/Metrics/MetricsCollectedEvent.cs | 2 +- .../Data/Metrics/MetricsConfig.cs | 14 +- .../Data/Metrics/MetricsSnapshot.cs | 8 +- .../Data/Scheduling/CronJobInfo.cs | 2 +- .../Data/Storage/SecretsConfig.cs | 10 +- .../Data/Timing/TimerWheelConfig.cs | 6 +- .../Data/Timing/TimerWheelPumpConfig.cs | 4 +- .../Directories/DirectoriesConfig.cs | 28 ++- .../Extensions/Crypto/EncryptExtensions.cs | 6 +- .../Directories/DirectoriesExtension.cs | 4 +- .../Extensions/Env/EnvExtensions.cs | 8 +- .../Extensions/Logger/LogLevelExtensions.cs | 8 +- .../Extensions/Random/RandomExtensions.cs | 18 +- .../Extensions/Strings/Base64Extensions.cs | 28 +-- .../Strings/StringMethodExtension.cs | 62 ++---- src/SquidStd.Core/Files/FileWatcherService.cs | 36 ++-- .../Bootstrap/ISquidStdBootstrap.cs | 18 +- .../Interfaces/Commands/ICommand.cs | 6 +- .../Commands/ICommandContextFactorySeeded.cs | 4 +- .../Interfaces/Commands/ICommandDispatcher.cs | 8 +- .../Interfaces/Commands/ICommandHandler.cs | 4 +- .../Commands/ISeededCommandDispatcher.cs | 14 +- .../Interfaces/Config/IConfigEntry.cs | 8 +- .../Config/IConfigManagerService.cs | 18 +- src/SquidStd.Core/Interfaces/Events/IEvent.cs | 6 +- .../Interfaces/Events/IEventBus.cs | 10 +- .../Interfaces/Events/IEventListener.cs | 4 +- .../Interfaces/Files/IFileWatcherService.cs | 16 +- .../Interfaces/Health/IHealthCheck.cs | 2 +- .../Interfaces/Health/IHealthCheckService.cs | 2 +- .../Interfaces/Jobs/IJobSystem.cs | 14 +- .../Interfaces/Metrics/IMetricProvider.cs | 6 +- .../Metrics/IMetricsCollectionService.cs | 8 +- .../Interfaces/Scheduling/ICronScheduler.cs | 4 +- .../Interfaces/Secrets/ISecretProtector.cs | 6 +- .../Interfaces/Secrets/ISecretStore.cs | 12 +- .../Serialization/IDataDeserializer.cs | 2 +- .../Serialization/IDataSerializer.cs | 2 +- .../Threading/IMainThreadDispatcher.cs | 8 +- .../Interfaces/Timing/ITimerService.cs | 12 +- .../Json/JsonContextTypeResolver.cs | 42 ++-- src/SquidStd.Core/Json/JsonDataSerializer.cs | 26 +-- src/SquidStd.Core/Json/JsonUtils.cs | 168 ++++++++------- src/SquidStd.Core/Logging/EventSink.cs | 16 +- .../Logging/EventSinkExtensions.cs | 10 +- src/SquidStd.Core/Logging/LogEventData.cs | 14 +- src/SquidStd.Core/Pool/ObjectPool.cs | 18 +- src/SquidStd.Core/README.md | 24 +-- src/SquidStd.Core/SquidStd.Core.csproj | 2 +- .../Types/Files/FileChangeKind.cs | 2 +- .../Types/Health/HealthStatus.cs | 2 +- src/SquidStd.Core/Types/LogLevelType.cs | 16 +- src/SquidStd.Core/Types/Metrics/MetricType.cs | 8 +- src/SquidStd.Core/Types/PlatformType.cs | 2 +- .../Types/SquidStdLogRollingIntervalType.cs | 14 +- src/SquidStd.Core/Utils/BuiltInRng.cs | 44 ++-- src/SquidStd.Core/Utils/CryptoUtils.cs | 10 +- src/SquidStd.Core/Utils/DirectoriesUtils.cs | 10 +- src/SquidStd.Core/Utils/HashUtils.cs | 6 +- src/SquidStd.Core/Utils/NetworkUtils.cs | 21 +- src/SquidStd.Core/Utils/PlatformUtils.cs | 22 +- src/SquidStd.Core/Utils/RandomUtils.cs | 38 ++-- src/SquidStd.Core/Utils/ResourceUtils.cs | 50 ++--- src/SquidStd.Core/Utils/SslUtils.cs | 6 +- src/SquidStd.Core/Utils/StringUtils.cs | 78 ++++--- src/SquidStd.Core/Utils/VersionUtils.cs | 12 +- src/SquidStd.Core/Yaml/YamlUtils.cs | 26 +-- .../Pgp/Data/PgpDecryptionResult.cs | 4 +- src/SquidStd.Crypto/Pgp/Data/PgpKey.cs | 4 +- src/SquidStd.Crypto/Pgp/Data/PgpKeyOptions.cs | 2 +- .../Pgp/Data/PgpVerificationResult.cs | 4 +- .../Pgp/Extensions/RegisterPgpExtensions.cs | 4 +- .../Pgp/Interfaces/IPgpKeyStore.cs | 2 +- .../Pgp/Interfaces/IPgpKeyring.cs | 4 +- .../Pgp/Interfaces/IPgpService.cs | 29 ++- .../Pgp/Internal/PgpKeyFactory.cs | 10 +- .../Pgp/Internal/PgpKeyStoreCodec.cs | 14 +- .../Pgp/Services/AesGcmPgpKeyStore.cs | 5 +- .../Pgp/Services/FilePgpKeyStore.cs | 31 +-- .../Pgp/Services/PgpKeyring.cs | 19 +- .../Pgp/Services/PgpService.cs | 63 ++++-- .../Pgp/Types/PgpKeyAlgorithm.cs | 2 +- src/SquidStd.Crypto/README.md | 16 +- .../RegisterCryptoVaultExtensions.cs | 4 +- .../Vfs/Internal/EntryCipher.cs | 7 +- .../Vfs/Internal/VaultHeader.cs | 10 +- .../Vfs/Internal/VaultIndex.cs | 8 +- .../Vfs/Internal/VaultKeyDerivation.cs | 12 +- .../Vfs/Services/CryptoFileSystem.cs | 40 ++-- .../Data/Database/DatabaseConfig.cs | 12 +- .../Data/Entities/BaseEntity.cs | 2 +- .../Data/PagedResultData.cs | 8 +- .../Interfaces/Data/IDataAccess.cs | 2 +- .../Types/Data/DatabaseProviderType.cs | 2 +- .../Connection/ConnectionStringParser.cs | 14 +- .../Connection/ParsedConnection.cs | 2 +- .../Data/FreeSqlDataAccess.cs | 58 +++--- .../Extensions/RegisterDatabaseExtension.cs | 4 +- .../Extensions/ZLinqResultExtensions.cs | 14 +- .../Interfaces/Services/IDatabaseService.cs | 2 +- .../Services/DatabaseService.cs | 16 +- .../AnalyzerReleases.Unshipped.md | 14 +- .../Common/GeneratorSymbolHelpers.cs | 37 ++-- .../ConfigSectionRegistrationGenerator.cs | 18 +- .../Config/ConfigSectionSourceBuilder.cs | 4 +- .../EventListenerRegistrationGenerator.cs | 17 +- src/SquidStd.Generators/README.md | 28 ++- .../Lua/ScriptModuleRegistrationGenerator.cs | 32 +-- .../StdServiceRegistrationGenerator.cs | 16 +- .../SquidStd.Generators.csproj | 4 +- .../JobHandlerRegistrationGenerator.cs | 11 +- .../Exceptions/MailSendException.cs | 4 +- .../Interfaces/IMailReader.cs | 4 +- .../Extensions/MailRegistrationExtensions.cs | 4 +- src/SquidStd.Mail.MailKit/README.md | 12 +- .../Services/MailPollingService.cs | 8 +- .../Services/MimeMessageMapper.cs | 14 +- .../Services/OutgoingMessageMapper.cs | 4 +- .../MailQueueRegistrationExtensions.cs | 4 +- src/SquidStd.Mail.Queue/README.md | 14 +- .../Services/MailSendConsumerService.cs | 8 +- .../Data/Config/MessagingConnectionString.cs | 30 ++- .../Data/Config/MessagingOptions.cs | 2 +- .../Data/Events/TopicMessageEvent.cs | 4 +- .../Interfaces/IMessageQueue.cs | 2 +- .../Interfaces/IMessageTopic.cs | 2 +- .../Interfaces/IMessagingMetrics.cs | 2 +- .../Interfaces/IQueueMessageListener.cs | 2 +- .../Interfaces/IQueueMessageListenerAsync.cs | 2 +- .../Interfaces/IQueueProvider.cs | 2 +- .../Interfaces/ITopicEventBridge.cs | 4 +- .../Interfaces/ITopicProvider.cs | 4 +- .../Services/MessageQueue.cs | 8 +- .../Services/MessageTopic.cs | 8 +- .../Services/MessagingMetricsProvider.cs | 56 ++--- .../Services/NoOpMessagingMetrics.cs | 30 +-- .../Services/TopicEventBridge.cs | 8 +- .../Data/Config/RabbitMqOptions.cs | 2 +- ...RabbitMqMessagingRegistrationExtensions.cs | 6 +- .../Services/RabbitMqQueueProvider.cs | 12 +- .../Services/RabbitMqTopicProvider.cs | 12 +- .../Data/Config/SqsOptions.cs | 4 +- .../SqsMessagingRegistrationExtensions.cs | 19 +- .../Internal/AwsClientFactory.cs | 6 +- .../Internal/SqsNames.cs | 4 +- src/SquidStd.Messaging.Sqs/README.md | 12 +- .../Services/SqsQueueProvider.cs | 62 +++--- .../Services/SqsTopicProvider.cs | 72 +++---- .../MessagingRegistrationExtensions.cs | 6 +- .../Internal/InMemoryQueue.cs | 12 +- .../Internal/QueuedMessage.cs | 2 +- .../Services/InMemoryQueueProvider.cs | 24 +-- .../Services/InMemoryTopicProvider.cs | 14 +- .../Buffers/CircularBuffer.cs | 164 +++++++-------- .../Client/SquidStdTcpClient.cs | 114 +++++----- .../Client/SquidStdUdpClient.cs | 56 +++-- .../Data/ConnectionPipeline.cs | 4 +- .../Events/SquidStdSessionDataEventArgs.cs | 2 +- .../Data/Events/SquidStdSessionEventArgs.cs | 2 +- .../Data/Events/SquidStdTcpClientEventArgs.cs | 4 +- .../SquidStdTcpDataReceivedEventArgs.cs | 6 +- .../Events/SquidStdTcpExceptionEventArgs.cs | 6 +- .../Data/Events/SquidStdUdpClientEventArgs.cs | 4 +- .../SquidStdUdpDataReceivedEventArgs.cs | 8 +- .../SquidStdUdpDatagramReceivedEventArgs.cs | 2 +- .../Events/SquidStdUdpExceptionEventArgs.cs | 6 +- .../Options/SquidStdTcpServerTlsOptions.cs | 8 +- .../Buffers/CircularBufferEmptyException.cs | 6 +- .../CircularBufferIndexOutOfRangeException.cs | 6 +- .../Extensions/PacketExtensions.cs | 4 +- .../Interfaces/Client/INetworkConnection.cs | 12 +- .../Interfaces/Codecs/ITransportCodec.cs | 10 +- .../Interfaces/Framing/INetFramer.cs | 24 +-- .../Interfaces/Middleware/INetMiddleware.cs | 20 +- .../Interfaces/Processing/IResultProcessor.cs | 4 +- .../Interfaces/Server/INetworkServer.cs | 12 +- .../Interfaces/Sessions/ISessionManager.cs | 2 +- .../Pipeline/NetMiddlewarePipeline.cs | 24 +-- .../Server/SquidStdUdpServer.cs | 66 +++--- src/SquidStd.Network/Server/SquidTcpServer.cs | 124 ++++++----- src/SquidStd.Network/Sessions/Session.cs | 10 +- .../Sessions/SessionManager.cs | 42 ++-- .../Sessions/UdpSessionConnection.cs | 8 +- .../Sessions/UdpSessionEntry.cs | 2 +- .../Sessions/UdpSessionManager.cs | 46 ++-- src/SquidStd.Network/Spans/SpanReader.cs | 76 ++----- src/SquidStd.Network/Spans/SpanWriter.cs | 48 ++--- .../Persistence/ISnapshotService.cs | 8 +- .../README.md | 22 +- .../README.md | 6 +- .../Data/PersistenceEntityDescriptor.cs | 2 +- .../Internal/JournalRecordCodec.cs | 2 +- .../Internal/SnapshotEnvelopeCodec.cs | 4 +- src/SquidStd.Persistence/README.md | 18 +- .../Services/BinaryJournalService.cs | 17 +- .../Services/EntityStore.cs | 4 +- .../Services/PersistenceService.cs | 4 +- .../Services/SnapshotService.cs | 24 +-- .../Data/PluginContext.cs | 4 +- .../Data/PluginMetadata.cs | 2 +- .../Interfaces/Plugins/ISquidStdPlugin.cs | 6 +- .../RegisterScriptModuleAttribute.cs | 6 +- .../Scripts/ScriptFunctionAttribute.cs | 8 +- .../Scripts/ScriptModuleAttribute.cs | 4 +- .../Context/SquidStdScriptJsonContext.cs | 14 +- .../Data/Internal/ScriptModuleData.cs | 6 +- .../Data/Internal/ScriptUserData.cs | 4 +- .../Data/Luarc/LuarcCompletionConfig.cs | 6 +- .../Data/Luarc/LuarcConfig.cs | 12 +- .../Data/Luarc/LuarcDiagnosticsConfig.cs | 5 +- .../Data/Luarc/LuarcFormatConfig.cs | 8 +- .../Data/Luarc/LuarcFormatDefaultConfig.cs | 8 +- .../Data/Luarc/LuarcRuntimeConfig.cs | 8 +- .../Data/Luarc/LuarcWorkspaceConfig.cs | 8 +- .../Data/Scripts/ScriptErrorInfo.cs | 24 +-- .../Data/Scripts/ScriptExecutionMetrics.cs | 14 +- .../Data/Scripts/ScriptResult.cs | 8 +- .../Data/Scripts/ScriptResultBuilder.cs | 30 ++- .../Descriptors/GenericUserDataDescriptor.cs | 28 +-- .../Scripts/AddScriptModuleExtension.cs | 14 +- .../Extensions/Scripts/TableExtensions.cs | 4 +- .../Interfaces/Events/ILuaEventBridge.cs | 10 +- .../Scripts/IScriptEngineService.cs | 64 +++--- .../Loaders/LuaScriptLoader.cs | 26 ++- .../Modules/EventsModule.cs | 4 +- .../Modules/LogModule.cs | 12 +- .../Modules/RandomModule.cs | 4 +- .../Proxies/LuaProxy.cs | 8 +- .../Services/LuaEventBridge.cs | 2 +- .../Services/LuaScriptEngineService.cs | 196 ++++++++---------- .../Utils/LuaDocumentationGenerator.cs | 113 +++++----- .../Attributes/SearchIndexAttribute.cs | 4 +- .../Exceptions/SearchException.cs | 8 +- .../Interfaces/IIndexableEntity.cs | 4 +- .../Interfaces/ISearchService.cs | 2 +- .../Search/SearchIndexNameResolver.cs | 14 +- .../SearchRegistrationExtensions.cs | 2 +- .../Linq/ElasticExpressionTranslator.cs | 69 +++--- .../Linq/ElasticQueryProvider.cs | 30 +-- .../Linq/ElasticQueryable.cs | 8 +- .../Linq/ElasticQueryableExtensions.cs | 32 +-- src/SquidStd.Search.Elasticsearch/README.md | 12 +- .../Services/ElasticSearchService.cs | 22 +- .../Services/ElasticTransport.cs | 36 ++-- .../Internal/AwsClientFactory.cs | 4 +- src/SquidStd.Secrets.Aws/README.md | 12 +- .../Services/AwsSecretsManagerStore.cs | 57 +++-- .../Services/KmsSecretProtector.cs | 23 +- .../SquidStdLogRollingIntervalExtensions.cs | 8 +- .../RegisterCommandDispatcherExtensions.cs | 10 +- .../RegisterDefaultServicesExtensions.cs | 48 ++--- .../RegisterHealthChecksServiceExtension.cs | 6 +- .../RegisterSchedulerServicesExtension.cs | 6 +- .../Services/Bootstrap/SquidStdBootstrap.cs | 54 ++--- .../Services/CommandDispatcher.cs | 21 +- .../Services/CommandDispatcherActivator.cs | 8 +- .../Services/ConfigManagerService.cs | 32 ++- .../Services/EventBusService.cs | 18 +- .../Services/EventListenerActivator.cs | 6 +- .../Services/HealthCheckService.cs | 10 +- .../Services/Internal/CommandSubscription.cs | 2 +- .../Services/Internal/CronJobEntry.cs | 2 +- .../Internal/DelegateCommandHandler.cs | 8 +- .../Internal/DelegateEventListener.cs | 6 +- .../Services/Internal/JobItem.cs | 10 +- .../MainThreadSynchronizationContext.cs | 2 +- .../Services/Internal/Subscription.cs | 2 +- .../Services/Internal/TimerEntry.cs | 2 +- .../Services/JobSystemService.cs | 16 +- .../Services/MainThreadDispatcherService.cs | 2 +- .../Services/MetricsCollectionService.cs | 26 +-- .../Scheduling/CronSchedulerService.cs | 35 ++-- .../Scheduling/TimerWheelPumpService.cs | 6 +- .../Services/SeededCommandDispatcher.cs | 14 +- .../Services/Storage/AesGcmSecretProtector.cs | 12 +- .../Services/Storage/FileSecretStore.cs | 18 +- .../Services/TimerWheelService.cs | 10 +- .../Types/BootstrapStateType.cs | 2 +- .../Data/Config/StorageConfig.cs | 8 +- .../Interfaces/IObjectStorageService.cs | 12 +- .../Interfaces/IStorageService.cs | 12 +- src/SquidStd.Storage.Abstractions/README.md | 10 +- .../Data/Config/S3StorageOptions.cs | 4 +- .../S3StorageRegistrationExtensions.cs | 2 +- src/SquidStd.Storage.S3/README.md | 10 +- .../Services/S3StorageService.cs | 10 +- .../StorageRegistrationExtensions.cs | 2 +- .../Internal/StoragePathResolver.cs | 6 +- src/SquidStd.Storage/README.md | 8 +- .../Services/FileStorageService.cs | 8 +- .../Services/YamlObjectStorageService.cs | 16 +- src/SquidStd.Telemetry.Abstractions/README.md | 8 +- .../SquidStdActivity.cs | 4 +- ...penTelemetryServiceCollectionExtensions.cs | 6 +- .../Internal/MetricsBridgeActivator.cs | 8 +- .../Internal/TelemetryPipeline.cs | 30 ++- .../README.md | 12 +- .../Services/MetricsSnapshotBridge.cs | 14 +- .../Services/TelemetryService.cs | 4 +- .../TemplatingRegistrationExtensions.cs | 6 +- .../Interfaces/ITemplateRenderer.cs | 2 +- .../Services/ScribanTemplateRenderer.cs | 8 +- src/SquidStd.Templating/TemplateException.cs | 10 +- .../Binding/ViewBinder.AutoBind.cs | 14 +- .../Binding/ViewBinder.Widgets.cs | 22 +- src/SquidStd.Tui/Binding/ViewBinder.cs | 48 +++-- src/SquidStd.Tui/Dsl/TuiNode.cs | 4 +- src/SquidStd.Tui/Dsl/TuiNodeMaterializer.cs | 12 +- src/SquidStd.Tui/Dsl/UiFactory.cs | 20 +- .../Hosting/TerminalGuiViewHost.cs | 4 +- src/SquidStd.Tui/Interfaces/ITuiNavigator.cs | 2 - src/SquidStd.Tui/Internal/ConventionNames.cs | 4 +- src/SquidStd.Tui/Internal/ReentryGuard.cs | 13 +- src/SquidStd.Tui/Internal/TuiViewRegistry.cs | 8 +- src/SquidStd.Tui/Navigation/TuiNavigator.cs | 7 +- src/SquidStd.Tui/README.md | 16 +- src/SquidStd.Tui/TuiComposedView.cs | 8 +- src/SquidStd.Tui/TuiView.cs | 10 +- src/SquidStd.Tui/TuiViewModel.cs | 8 +- src/SquidStd.Vfs.Abstractions/README.md | 15 +- src/SquidStd.Vfs.Abstractions/VfsPath.cs | 2 +- src/SquidStd.Vfs/README.md | 16 +- .../Services/InMemoryFileSystem.cs | 39 ++-- .../Services/PhysicalFileSystem.cs | 20 +- src/SquidStd.Vfs/Services/VfsDirectories.cs | 6 +- src/SquidStd.Vfs/Services/ZipFileSystem.cs | 29 ++- .../Data/JobRequest.cs | 2 +- .../Data/WorkerHeartbeat.cs | 6 +- .../Data/WorkerInfo.cs | 2 +- .../Types/WorkerStatusType.cs | 4 +- .../WorkerChannels.cs | 4 +- .../Data/Config/WorkerManagerConfig.cs | 2 +- .../Data/EnqueueJobRequest.cs | 2 +- .../Data/Events/WorkerStatusChangedEvent.cs | 4 +- .../Endpoints/WorkerManagerEndpoints.cs | 6 +- .../WorkerManagerEndpointsExtensions.cs | 4 +- .../WorkerManagerRegistrationExtensions.cs | 6 +- .../Interfaces/IJobScheduler.cs | 2 +- .../Interfaces/IWorkerRegistry.cs | 2 +- .../Services/HeartbeatCollectorService.cs | 8 +- .../Services/JobScheduler.cs | 10 +- .../Services/WorkerOfflineSweepService.cs | 8 +- .../Services/WorkerRegistry.cs | 22 +- .../Attributes/RegisterJobHandlerAttribute.cs | 6 +- .../Data/Config/WorkersConfig.cs | 6 +- .../Exceptions/JobHandlerNotFoundException.cs | 2 +- .../WorkersRegistrationExtensions.cs | 8 +- .../Interfaces/IJobDispatcher.cs | 4 +- .../Interfaces/IJobHandler.cs | 2 +- .../Interfaces/IWorkerState.cs | 2 +- .../Services/JobDispatcher.cs | 2 +- .../Services/WorkerConsumerService.cs | 6 +- .../Services/WorkerHeartbeatService.cs | 8 +- src/SquidStd.Workers/Services/WorkerState.cs | 12 +- .../ConfigRegistrationDataTests.cs | 11 +- tests/SquidStd.Tests/Actors/ActorAskTests.cs | 4 +- .../SquidStd.Tests/Actors/ActorErrorTests.cs | 17 +- .../Actors/ActorEventBusTests.cs | 4 +- .../Actors/ActorLifecycleTests.cs | 20 +- .../Actors/ActorOrderingTests.cs | 2 +- .../Actors/ActorOverflowTests.cs | 15 +- .../Actors/Support/ProbeActor.cs | 8 +- .../Actors/Support/ProbeMessages.cs | 4 +- .../AspNetCore/FakeSquidStdBootstrap.cs | 16 +- ...quidStdAspNetCoreBuilderExtensionsTests.cs | 3 +- .../SquidStdHealthCheckAdapterTests.cs | 4 +- .../Bootstrap/SquidStdBootstrapTests.cs | 31 ++- .../Caching/CacheMetricsProviderTests.cs | 8 +- .../Caching/CacheServiceTests.cs | 46 ++-- .../Caching/InMemoryCacheProviderTests.cs | 12 +- .../Caching/Redis/RedisCacheProviderTests.cs | 17 +- .../Caching/Redis/RedisContainerFixture.cs | 10 +- .../Random/RandomExtensionsTests.cs | 4 +- .../Strings/Base64ExtensionsTests.cs | 10 +- .../Core/Pool/ObjectPoolTests.cs | 17 +- .../Core/Utils/ChecksumUtilsTests.cs | 5 +- .../Core/Utils/CryptoUtilsTests.cs | 9 +- .../Core/Utils/RngCollection.cs | 8 +- .../Core/Utils/SslUtilsTests.cs | 4 +- .../Crypto/Pgp/AesGcmPgpKeyStoreTests.cs | 3 +- .../Crypto/Pgp/FilePgpKeyStoreTests.cs | 2 +- .../Crypto/Pgp/PgpServiceEncryptionTests.cs | 3 +- .../Crypto/Pgp/PgpServiceSigningTests.cs | 30 +-- .../Crypto/Pgp/Support/PgpKeysCollection.cs | 4 +- .../Crypto/Pgp/Support/PgpTestKeys.cs | 9 +- .../Crypto/Vfs/CryptoFileSystemDiskTests.cs | 4 +- .../Crypto/Vfs/CryptoFileSystemLockTests.cs | 7 +- .../Crypto/Vfs/CryptoFileSystemTests.cs | 5 +- .../Crypto/Vfs/EntryCipherTests.cs | 8 +- .../Crypto/Vfs/VaultHeaderTests.cs | 8 +- .../Crypto/Vfs/VaultIndexTests.cs | 2 +- .../Database/ConnectionStringParserTests.cs | 8 +- .../Database/FreeSqlDataAccessTests.cs | 19 +- tests/SquidStd.Tests/Env/ReplaceEnvTests.cs | 9 +- .../Directories/DirectoriesExtensionTests.cs | 9 +- .../Extensions/Env/EnvExtensionsTests.cs | 8 +- .../Logger/LogLevelExtensionsTests.cs | 19 +- .../Strings/StringMethodExtensionTests.cs | 40 +--- .../Support/GeneratorTestCompiler.cs | 11 +- .../Health/HealthCheckServiceTests.cs | 15 +- .../Mail/GreenMailContainerFixture.cs | 28 ++- .../Mail/MailPollingServiceTests.cs | 5 +- .../Mail/MailQueueIntegrationTests.cs | 23 +- .../Integration/Mail/MailReaderTests.cs | 6 +- .../Integration/Mail/MailSenderTests.cs | 49 +++-- .../Search/ElasticSearchServiceTests.cs | 19 +- .../Search/ElasticsearchContainerFixture.cs | 35 ++-- .../Templates/TemplatePackTests.cs | 18 +- .../Workers/WorkerSystemIntegrationTests.cs | 8 +- .../Json/JsonContextTypeResolverTests.cs | 8 +- tests/SquidStd.Tests/Json/JsonUtilsTests.cs | 55 ++--- .../Logging/EventSinkExtensionsTests.cs | 10 +- .../SquidStd.Tests/Logging/EventSinkTests.cs | 10 +- tests/SquidStd.Tests/Mail/MailQueueTests.cs | 4 +- .../Mail/MailRegistrationExtensionsTests.cs | 9 +- .../Mail/MailSendConsumerServiceTests.cs | 4 +- .../MailSenderRegistrationExtensionsTests.cs | 7 +- .../Mail/MimeMessageMapperTests.cs | 2 +- .../Mail/OutgoingMessageMapperTests.cs | 22 +- .../Mail/Support/FakeTimerService.cs | 16 +- .../Mail/Support/ThrowingMailSender.cs | 4 +- .../Manager/HeartbeatCollectorServiceTests.cs | 5 +- .../Manager/JobSchedulerTests.cs | 3 +- .../Manager/Support/FakeTimerService.cs | 12 +- .../Manager/WorkerManagerEndpointsTests.cs | 24 +-- .../Manager/WorkerOfflineSweepServiceTests.cs | 12 +- .../Manager/WorkerRegistryTests.cs | 9 +- .../Messaging/InMemoryQueueProviderTests.cs | 16 +- .../Messaging/InMemoryTopicProviderTests.cs | 4 +- .../Messaging/MessageQueueTests.cs | 3 +- .../MessagingConnectionStringTests.cs | 4 +- .../MessagingMetricsProviderTests.cs | 8 +- .../RabbitMq/RabbitMqContainerFixture.cs | 10 +- .../RabbitMq/RabbitMqQueueProviderTests.cs | 21 +- .../RabbitMq/RabbitMqTopicProviderTests.cs | 13 +- .../Sqs/LocalStackContainerFixture.cs | 27 ++- .../Messaging/Sqs/SqsConnectionStringTests.cs | 4 +- .../Messaging/Sqs/SqsNamesTests.cs | 12 +- .../Messaging/Sqs/SqsQueueProviderTests.cs | 23 +- .../Messaging/Sqs/SqsTopicProviderTests.cs | 19 +- .../Network/CircularBufferTests.cs | 8 +- .../Network/NetMiddlewarePipelineTests.cs | 5 +- .../Network/PacketExtensionsTests.cs | 10 +- .../Network/SessionManagerTests.cs | 12 +- .../Network/SquidStdUdpClientTests.cs | 31 +-- .../Network/SquidStdUdpServerTests.cs | 30 +-- .../Network/TcpMaxFrameLengthTests.cs | 65 +++--- .../Network/TransportCodecTests.cs | 85 ++++---- .../Network/UdpSessionManagerTests.cs | 18 +- .../Persistence/DurableWriteTests.cs | 20 +- .../Persistence/EntityStoreTests.cs | 20 +- .../EntityStoreWalOrderingTests.cs | 10 +- .../Integration/PersistenceEndToEndTests.cs | 12 +- .../Internal/SnapshotEnvelopeCodecTests.cs | 2 +- .../Persistence/PersistenceConfigTests.cs | 4 +- .../PersistenceEntityDescriptorTests.cs | 4 +- .../PersistenceEntityRegistryTests.cs | 2 +- .../Persistence/PersistenceServiceTests.cs | 45 ++-- .../PersistenceSnapshotConcurrencyTests.cs | 21 +- .../Persistence/SnapshotChecksumScopeTests.cs | 20 +- .../Persistence/SnapshotFilenameTests.cs | 8 +- .../PluginAbstractions/PluginContextTests.cs | 8 +- .../PluginAbstractions/PluginMetadataTests.cs | 10 +- .../PluginAbstractions/SquidStdPluginTests.cs | 4 +- .../Scripting/Lua/LuaEventBridgeTests.cs | 34 +-- .../Scripting/Lua/LuaModuleTests.cs | 30 ++- .../Lua/LuaScriptEngineServiceTests.cs | 26 +-- .../Scripting/Lua/LuaScriptLoaderTests.cs | 7 +- .../Scripting/Lua/ScriptResultBuilderTests.cs | 10 +- .../Scripting/Lua/TableExtensionsTests.cs | 20 +- .../ElasticExpressionTranslatorTests.cs | 28 +-- .../Search/SearchIndexNameResolverTests.cs | 8 +- .../Aws/AwsSecretsManagerStoreTests.cs | 4 +- .../Secrets/Aws/KmsSecretProtectorTests.cs | 9 +- .../Aws/Support/LocalStackSecretsFixture.cs | 23 +- .../FileSecretStoreEnumerationTests.cs | 2 + tests/SquidStd.Tests/Security/SecretsTests.cs | 8 +- .../Services/Core/CommandDispatcherTests.cs | 25 ++- .../Services/Core/EventBusServiceTests.cs | 30 ++- .../Services/Core/JobSystemServiceTests.cs | 24 +-- .../Core/MainThreadDispatcherServiceTests.cs | 6 +- .../Core/MetricsCollectionServiceTests.cs | 20 +- ...egisterCommandDispatcherExtensionsTests.cs | 4 +- .../Scheduling/CronSchedulerServiceTests.cs | 3 +- .../Scheduling/TimerWheelPumpServiceTests.cs | 10 +- .../Core/SeededCommandDispatcherTests.cs | 8 +- ...uidStdLogRollingIntervalExtensionsTests.cs | 21 +- .../Services/Core/TimerWheelServiceTests.cs | 17 +- tests/SquidStd.Tests/SquidStd.Tests.csproj | 110 +++++----- .../Storage/FileStorageServiceTests.cs | 20 +- .../Storage/S3/MinioContainerFixture.cs | 10 +- .../Storage/S3/S3StorageServiceTests.cs | 27 +-- .../Storage/StorageRegistrationTests.cs | 3 +- .../Support/AppendingMiddleware.cs | 12 +- .../Support/CapturingLogSink.cs | 2 +- .../Support/CountingXorCodec.cs | 6 +- .../Support/DroppingMiddleware.cs | 12 +- .../Support/DummyGuidConverter.cs | 10 +- .../Support/FakeCacheProvider.cs | 18 +- .../SquidStd.Tests/Support/FakeHealthCheck.cs | 4 +- .../Support/FakeNetworkConnection.cs | 4 +- tests/SquidStd.Tests/Support/FakePlugin.cs | 8 +- .../SquidStd.Tests/Support/FakeStdService.cs | 4 +- .../Support/FakeTimeProvider.cs | 28 +-- .../Support/FakeTimerService.cs | 14 +- .../Support/LengthPrefixFramer.cs | 4 +- .../SquidStd.Tests/Support/ManualJobSystem.cs | 10 +- tests/SquidStd.Tests/Support/OtherDto.cs | 4 +- tests/SquidStd.Tests/Support/SampleDto.cs | 6 +- .../Support/SerilogEventSinkCollection.cs | 4 +- tests/SquidStd.Tests/Support/TempDirectory.cs | 10 +- .../Support/TestDirectoryType.cs | 2 +- .../SquidStd.Tests/Support/TestJsonContext.cs | 9 +- .../Telemetry/MetricsSnapshotBridgeTests.cs | 10 +- .../Telemetry/OtlpProtocolTypeMappingTests.cs | 8 +- .../Support/FakeMetricsCollectionService.cs | 14 +- .../Telemetry/TelemetryRegistrationTests.cs | 5 +- .../SquidStd.Tests/Telemetry/TracingTests.cs | 8 +- .../ScribanTemplateRendererTests.cs | 5 +- .../Tui/Binding/ViewBinderAutoBindTests.cs | 49 +++-- .../Tui/Binding/ViewBinderCommandTests.cs | 7 +- .../Tui/Binding/ViewBinderOneWayTests.cs | 42 ++-- .../Tui/Binding/ViewBinderTwoWayTests.cs | 85 ++++---- .../Tui/Dsl/TuiNodeMaterializerTests.cs | 16 +- tests/SquidStd.Tests/Tui/Dsl/TuiNodeTests.cs | 12 +- .../SquidStd.Tests/Tui/Dsl/UiFactoryTests.cs | 14 +- .../Extensions/RegisterTuiExtensionsTests.cs | 50 ++--- .../Tui/Internal/ConventionNamesTests.cs | 15 +- .../Tui/Internal/PropertyPathTests.cs | 20 +- .../Tui/Navigation/TuiNavigatorTests.cs | 136 ++++++------ tests/SquidStd.Tests/Tui/TuiViewModelTests.cs | 29 ++- .../Utils/DirectoriesUtilsTests.cs | 4 +- tests/SquidStd.Tests/Utils/HashUtilsTests.cs | 31 +-- .../SquidStd.Tests/Utils/NetworkUtilsTests.cs | 61 ++---- .../Utils/PlatformUtilsTests.cs | 16 +- .../Utils/ResourceUtilsTests.cs | 37 +--- .../SquidStd.Tests/Utils/StringUtilsTests.cs | 117 +++-------- .../SquidStd.Tests/Utils/VersionUtilsTests.cs | 4 +- .../Vfs/InMemoryFileSystemTests.cs | 1 + .../Vfs/PhysicalFileSystemTests.cs | 3 +- tests/SquidStd.Tests/Vfs/VfsPathTests.cs | 18 +- .../Workers/JobDispatcherTests.cs | 14 +- .../Workers/Support/FakeMessageQueue.cs | 16 +- .../Workers/Support/RecordingJobHandler.cs | 4 +- .../Workers/WorkerConsumerServiceTests.cs | 26 +-- .../Workers/WorkerContractsTests.cs | 13 +- .../Workers/WorkerHeartbeatServiceTests.cs | 2 +- .../Workers/WorkerStateTests.cs | 9 +- .../WorkersRegistrationExtensionsTests.cs | 2 +- tests/SquidStd.Tests/Yaml/YamlUtilsTests.cs | 19 +- 621 files changed, 4060 insertions(+), 5283 deletions(-) diff --git a/SquidStd.slnx b/SquidStd.slnx index b6e06793..b6978e23 100644 --- a/SquidStd.slnx +++ b/SquidStd.slnx @@ -1,72 +1,72 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + diff --git a/samples/SquidStd.Samples.Actors/Program.cs b/samples/SquidStd.Samples.Actors/Program.cs index 01f2f0bc..73571e0c 100644 --- a/samples/SquidStd.Samples.Actors/Program.cs +++ b/samples/SquidStd.Samples.Actors/Program.cs @@ -1,5 +1,4 @@ using SquidStd.Actors; -using SquidStd.Actors.Interfaces; await using var counter = new CounterActor(); @@ -14,7 +13,7 @@ #region step-3 // Request/response: AskAsync enqueues a request and awaits its typed reply. -var total = await counter.AskAsync(new GetTotal()); +var total = await counter.AskAsync(new()); Console.WriteLine($"Total: {total}"); @@ -40,9 +39,11 @@ protected override ValueTask ReceiveAsync(ICounterMessage message, CancellationT { case Increment increment: _total += increment.By; + break; case GetTotal request: request.Reply(_total); + break; } diff --git a/samples/SquidStd.Samples.Caching/Program.cs b/samples/SquidStd.Samples.Caching/Program.cs index 2caf671f..59a0227e 100644 --- a/samples/SquidStd.Samples.Caching/Program.cs +++ b/samples/SquidStd.Samples.Caching/Program.cs @@ -1,10 +1,9 @@ using SquidStd.Caching.Abstractions.Interfaces; using SquidStd.Caching.Extensions; -using SquidStd.Core.Data.Bootstrap; using SquidStd.Services.Core.Services.Bootstrap; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory diff --git a/samples/SquidStd.Samples.Crypto/Program.cs b/samples/SquidStd.Samples.Crypto/Program.cs index 8fdd0532..5372fde4 100644 --- a/samples/SquidStd.Samples.Crypto/Program.cs +++ b/samples/SquidStd.Samples.Crypto/Program.cs @@ -1,12 +1,11 @@ using System.Text; -using SquidStd.Core.Data.Bootstrap; using SquidStd.Crypto.Pgp.Extensions; using SquidStd.Crypto.Pgp.Interfaces; using SquidStd.Crypto.Pgp.Services; using SquidStd.Services.Core.Services.Bootstrap; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory @@ -50,11 +49,11 @@ // Encrypt + sign for the recipient, then decrypt + verify the round-trip. var armored = await pgp.EncryptAndSignForAsync( - identity, - Encoding.UTF8.GetBytes("attack at dawn"), - identity, - passphrase -); + identity, + Encoding.UTF8.GetBytes("attack at dawn"), + identity, + passphrase + ); var result = await pgp.DecryptAndVerifyAsync(armored, passphrase); @@ -70,9 +69,7 @@ var reloaded = new PgpKeyring(); await reloaded.LoadAsync(keyStore); -Console.WriteLine( - $"Reloaded {reloaded.Keys.Count} key(s) from disk; contains '{identity}': {reloaded.Contains(identity)}" -); +Console.WriteLine($"Reloaded {reloaded.Keys.Count} key(s) from disk; contains '{identity}': {reloaded.Contains(identity)}"); #endregion diff --git a/samples/SquidStd.Samples.Database/Program.cs b/samples/SquidStd.Samples.Database/Program.cs index 08b45ace..97c8c65a 100644 --- a/samples/SquidStd.Samples.Database/Program.cs +++ b/samples/SquidStd.Samples.Database/Program.cs @@ -1,11 +1,10 @@ -using SquidStd.Core.Data.Bootstrap; using SquidStd.Database.Abstractions.Data.Entities; using SquidStd.Database.Abstractions.Interfaces.Data; using SquidStd.Database.Extensions; using SquidStd.Services.Core.Services.Bootstrap; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory @@ -24,14 +23,14 @@ var products = bootstrap.Resolve>(); -await products.InsertAsync(new Product { Name = "Squid Plushie", Price = 19.99m }); -await products.InsertAsync(new Product { Name = "Kraken Mug", Price = 12.50m }); +await products.InsertAsync(new() { Name = "Squid Plushie", Price = 19.99m }); +await products.InsertAsync(new() { Name = "Kraken Mug", Price = 12.50m }); var page = await products.GetPagedAsync( - 1, - 10, - orderBy: product => product.Price -); + 1, + 10, + orderBy: product => product.Price + ); Console.WriteLine($"Found {page.TotalCount} product(s) on page {page.Page}/{page.TotalPages}:"); diff --git a/samples/SquidStd.Samples.Email/Program.cs b/samples/SquidStd.Samples.Email/Program.cs index 0ca1f7ab..97bdbdaf 100644 --- a/samples/SquidStd.Samples.Email/Program.cs +++ b/samples/SquidStd.Samples.Email/Program.cs @@ -1,7 +1,5 @@ -using SquidStd.Core.Data.Bootstrap; using SquidStd.Core.Interfaces.Events; using SquidStd.Mail.Abstractions.Data; -using SquidStd.Mail.Abstractions.Data.Config; using SquidStd.Mail.Abstractions.Data.Events; using SquidStd.Mail.Abstractions.Interfaces; using SquidStd.Mail.Abstractions.Types.Mail; @@ -12,7 +10,7 @@ using SquidStd.Services.Core.Services.Bootstrap; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory @@ -21,8 +19,9 @@ #region step-1 -bootstrap.ConfigureServices(container => container.AddMail( - new MailOptions +bootstrap.ConfigureServices( + container => container.AddMail( + new() { Protocol = MailProtocolType.Imap, Host = "imap.example.com", @@ -37,8 +36,9 @@ #region step-2 -bootstrap.ConfigureServices(container => container.AddMailSender( - new SmtpOptions +bootstrap.ConfigureServices( + container => container.AddMailSender( + new() { Host = "smtp.example.com", Port = 587 @@ -50,9 +50,10 @@ #region step-3 -bootstrap.ConfigureServices(container => container - .AddInMemoryMessaging() - .AddMailQueue() +bootstrap.ConfigureServices( + container => container + .AddInMemoryMessaging() + .AddMailQueue() ); #endregion @@ -65,7 +66,7 @@ var outgoing = new OutgoingMailMessage { - To = [new MailAddress("Bob", "bob@example.com")], + To = [new("Bob", "bob@example.com")], Subject = "Hi", HtmlBody = "

Hi

" }; diff --git a/samples/SquidStd.Samples.EventsJobsScheduling/Program.cs b/samples/SquidStd.Samples.EventsJobsScheduling/Program.cs index 332014d0..dc3fbc6d 100644 --- a/samples/SquidStd.Samples.EventsJobsScheduling/Program.cs +++ b/samples/SquidStd.Samples.EventsJobsScheduling/Program.cs @@ -1,5 +1,4 @@ using SquidStd.Abstractions.Attributes; -using SquidStd.Core.Data.Bootstrap; using SquidStd.Core.Interfaces.Events; using SquidStd.Core.Interfaces.Jobs; using SquidStd.Core.Interfaces.Scheduling; @@ -8,7 +7,7 @@ using SquidStd.Services.Core.Services.Bootstrap; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory @@ -16,9 +15,10 @@ ); // The cron scheduler and timer wheel are opt-in. -bootstrap.ConfigureServices(container => container - .RegisterSchedulerServices() - .RegisterGeneratedEventListeners() +bootstrap.ConfigureServices( + container => container + .RegisterSchedulerServices() + .RegisterGeneratedEventListeners() ); await bootstrap.StartAsync(); diff --git a/samples/SquidStd.Samples.GettingStarted/Program.cs b/samples/SquidStd.Samples.GettingStarted/Program.cs index e9a6a176..c6dcb6cc 100644 --- a/samples/SquidStd.Samples.GettingStarted/Program.cs +++ b/samples/SquidStd.Samples.GettingStarted/Program.cs @@ -1,10 +1,9 @@ -using SquidStd.Core.Data.Bootstrap; using SquidStd.Services.Core.Services.Bootstrap; #region step-1 var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory diff --git a/samples/SquidStd.Samples.Messaging/Program.cs b/samples/SquidStd.Samples.Messaging/Program.cs index 75202d9e..32489792 100644 --- a/samples/SquidStd.Samples.Messaging/Program.cs +++ b/samples/SquidStd.Samples.Messaging/Program.cs @@ -1,10 +1,9 @@ -using SquidStd.Core.Data.Bootstrap; using SquidStd.Messaging.Abstractions.Interfaces; using SquidStd.Messaging.Extensions; using SquidStd.Services.Core.Services.Bootstrap; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory diff --git a/samples/SquidStd.Samples.Networking/Program.cs b/samples/SquidStd.Samples.Networking/Program.cs index 948269b4..8afd2de5 100644 --- a/samples/SquidStd.Samples.Networking/Program.cs +++ b/samples/SquidStd.Samples.Networking/Program.cs @@ -9,12 +9,12 @@ var server = new SquidTcpServer(endPoint); server.OnClientConnect += (_, args) => - Console.WriteLine($"Client connected: session {args.Client.SessionId}"); + Console.WriteLine($"Client connected: session {args.Client.SessionId}"); server.OnDataReceived += (_, args) => - Console.WriteLine( - $"Received {args.Data.Length} byte(s): {Encoding.UTF8.GetString(args.Data.Span)}" - ); + Console.WriteLine( + $"Received {args.Data.Length} byte(s): {Encoding.UTF8.GetString(args.Data.Span)}" + ); #endregion diff --git a/samples/SquidStd.Samples.Persistence/Program.cs b/samples/SquidStd.Samples.Persistence/Program.cs index a2bfdc1a..b075c313 100644 --- a/samples/SquidStd.Samples.Persistence/Program.cs +++ b/samples/SquidStd.Samples.Persistence/Program.cs @@ -18,10 +18,10 @@ IPersistenceService BuildPersistence() new PersistenceEntityDescriptor( serializer, serializer, - typeId: 1, - typeName: "Player", - schemaVersion: 1, - keySelector: player => player.Id + 1, + "Player", + 1, + player => player.Id ) ); @@ -50,8 +50,8 @@ IPersistenceService BuildPersistence() #region step-2: mutate — every upsert/remove is appended to the journal -var nextId = (await players.CountAsync()) + 1; -await players.UpsertAsync(new Player { Id = nextId, Name = $"Hero-{nextId}", Level = nextId * 10 }); +var nextId = await players.CountAsync() + 1; +await players.UpsertAsync(new() { Id = nextId, Name = $"Hero-{nextId}", Level = nextId * 10 }); Console.WriteLine($"Added player #{nextId}; store now holds {await players.CountAsync()} player(s)"); diff --git a/samples/SquidStd.Samples.Plugins/Program.cs b/samples/SquidStd.Samples.Plugins/Program.cs index 266558f6..5822c920 100644 --- a/samples/SquidStd.Samples.Plugins/Program.cs +++ b/samples/SquidStd.Samples.Plugins/Program.cs @@ -14,9 +14,7 @@ public interface IGreeter public sealed class WeatherGreeter : IGreeter { public string Greet(string name) - { - return $"Hello {name}, the weather plugin is online."; - } + => $"Hello {name}, the weather plugin is online."; } public sealed class WeatherPlugin : ISquidStdPlugin @@ -25,16 +23,14 @@ public sealed class WeatherPlugin : ISquidStdPlugin { Id = "squidstd.weather", Name = "Weather Plugin", - Version = new Version(1, 0, 0), + Version = new(1, 0, 0), Author = "SquidStd Samples", Description = "Registers a greeter service.", Dependencies = [] }; public void Configure(IContainer container, PluginContext context) - { - container.Register(Reuse.Singleton); - } + => container.Register(Reuse.Singleton); } #endregion @@ -43,7 +39,7 @@ internal static class Program { private static void Main() { - #region step-2 + #region step-2 var container = new Container(); var context = new PluginContext(); @@ -57,6 +53,6 @@ private static void Main() var greeter = container.Resolve(); Console.WriteLine(greeter.Greet("squid")); - #endregion + #endregion } } diff --git a/samples/SquidStd.Samples.ScriptingLua/Program.cs b/samples/SquidStd.Samples.ScriptingLua/Program.cs index 94115310..6d403e7a 100644 --- a/samples/SquidStd.Samples.ScriptingLua/Program.cs +++ b/samples/SquidStd.Samples.ScriptingLua/Program.cs @@ -1,6 +1,5 @@ using DryIoc; using SquidStd.Abstractions.Extensions.Services; -using SquidStd.Core.Data.Bootstrap; using SquidStd.Generators.Scripting.Lua; using SquidStd.Scripting.Lua.Attributes; using SquidStd.Scripting.Lua.Attributes.Scripts; @@ -10,7 +9,7 @@ using SquidStd.Services.Core.Services.Bootstrap; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory @@ -22,7 +21,8 @@ var scriptsDirectory = Path.Combine(AppContext.BaseDirectory, "scripts"); Directory.CreateDirectory(scriptsDirectory); -bootstrap.ConfigureServices(container => +bootstrap.ConfigureServices( + container => { var engineConfig = new LuaEngineConfig( AppContext.BaseDirectory, @@ -64,10 +64,7 @@ #region step-3 -[RegisterScriptModule] -[ScriptModule("sample")] -internal sealed class SampleLuaModule -{ -} +[RegisterScriptModule, ScriptModule("sample")] +internal sealed class SampleLuaModule { } #endregion diff --git a/samples/SquidStd.Samples.Search/Program.cs b/samples/SquidStd.Samples.Search/Program.cs index 905455ae..25b5594d 100644 --- a/samples/SquidStd.Samples.Search/Program.cs +++ b/samples/SquidStd.Samples.Search/Program.cs @@ -1,13 +1,11 @@ -using SquidStd.Core.Data.Bootstrap; using SquidStd.Search.Abstractions.Attributes; using SquidStd.Search.Abstractions.Interfaces; -using SquidStd.Search.Elasticsearch.Data.Config; using SquidStd.Search.Elasticsearch.Extensions; using SquidStd.Search.Elasticsearch.Linq; using SquidStd.Services.Core.Services.Bootstrap; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory @@ -16,10 +14,11 @@ #region step-1 -bootstrap.ConfigureServices(container => container.AddElasticsearch( - new ElasticsearchOptions +bootstrap.ConfigureServices( + container => container.AddElasticsearch( + new() { - Uri = new Uri("http://localhost:9200") + Uri = new("http://localhost:9200") } ) ); @@ -35,8 +34,8 @@ await search.IndexAsync(new Order("1", "open", 150), true); var open = await search.Query() - .Where(o => o.Status == "open") - .ToListAsync(); + .Where(o => o.Status == "open") + .ToListAsync(); Console.WriteLine($"found {open.Count} open order(s)"); diff --git a/samples/SquidStd.Samples.Secrets/Program.cs b/samples/SquidStd.Samples.Secrets/Program.cs index 7f98cb9e..148cd3ad 100644 --- a/samples/SquidStd.Samples.Secrets/Program.cs +++ b/samples/SquidStd.Samples.Secrets/Program.cs @@ -1,12 +1,10 @@ using System.Text; -using SquidStd.Aws.Abstractions.Data.Config; -using SquidStd.Core.Data.Bootstrap; using SquidStd.Core.Interfaces.Secrets; using SquidStd.Secrets.Aws.Extensions; using SquidStd.Services.Core.Services.Bootstrap; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory @@ -16,30 +14,36 @@ #region step-1 // Wire the KMS-backed protector and the Secrets Manager store against a LocalStack endpoint. -bootstrap.ConfigureServices(container => -{ - container.RegisterKmsSecretProtector(options => - { - options.KeyId = "alias/app"; - options.Aws = new AwsConfigEntry - { - Region = "us-east-1", - ServiceUrl = "http://localhost:4566" - }; - }); - - container.RegisterAwsSecretsManagerStore(options => +bootstrap.ConfigureServices( + container => { - options.NamePrefix = "myapp/"; - options.Aws = new AwsConfigEntry - { - Region = "us-east-1", - ServiceUrl = "http://localhost:4566" - }; - }); - - return container; -}); + container.RegisterKmsSecretProtector( + options => + { + options.KeyId = "alias/app"; + options.Aws = new() + { + Region = "us-east-1", + ServiceUrl = "http://localhost:4566" + }; + } + ); + + container.RegisterAwsSecretsManagerStore( + options => + { + options.NamePrefix = "myapp/"; + options.Aws = new() + { + Region = "us-east-1", + ServiceUrl = "http://localhost:4566" + }; + } + ); + + return container; + } +); #endregion @@ -54,6 +58,7 @@ { Console.WriteLine("Set SQUIDSTD_RUN_AWS=1 with LocalStack running to exercise the live calls."); await bootstrap.StopAsync(); + return; } diff --git a/samples/SquidStd.Samples.Storage/Program.cs b/samples/SquidStd.Samples.Storage/Program.cs index cde19fa4..ddaf9985 100644 --- a/samples/SquidStd.Samples.Storage/Program.cs +++ b/samples/SquidStd.Samples.Storage/Program.cs @@ -1,10 +1,9 @@ -using SquidStd.Core.Data.Bootstrap; using SquidStd.Services.Core.Services.Bootstrap; using SquidStd.Storage.Abstractions.Interfaces; using SquidStd.Storage.Extensions; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory diff --git a/samples/SquidStd.Samples.Templating/Program.cs b/samples/SquidStd.Samples.Templating/Program.cs index d46884f6..ad2b0e49 100644 --- a/samples/SquidStd.Samples.Templating/Program.cs +++ b/samples/SquidStd.Samples.Templating/Program.cs @@ -1,10 +1,9 @@ -using SquidStd.Core.Data.Bootstrap; using SquidStd.Services.Core.Services.Bootstrap; using SquidStd.Templating.Extensions; using SquidStd.Templating.Interfaces; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory diff --git a/samples/SquidStd.Samples.Tui/CounterComposedView.cs b/samples/SquidStd.Samples.Tui/CounterComposedView.cs index 90ff2679..b0cb9bac 100644 --- a/samples/SquidStd.Samples.Tui/CounterComposedView.cs +++ b/samples/SquidStd.Samples.Tui/CounterComposedView.cs @@ -6,10 +6,9 @@ namespace SquidStd.Samples.Tui; public sealed class CounterComposedView : TuiComposedView { protected override TuiNode Compose() - { - return Ui.VStack( + => Ui.VStack( Ui.Label(x => x.Title), Ui.Label(x => x.Value), - Ui.Button("+1", x => x.IncrementCommand)); - } + Ui.Button("+1", x => x.IncrementCommand) + ); } diff --git a/samples/SquidStd.Samples.Tui/CounterViewModel.cs b/samples/SquidStd.Samples.Tui/CounterViewModel.cs index 7f41c638..91ee3807 100644 --- a/samples/SquidStd.Samples.Tui/CounterViewModel.cs +++ b/samples/SquidStd.Samples.Tui/CounterViewModel.cs @@ -6,15 +6,11 @@ namespace SquidStd.Samples.Tui; public sealed partial class CounterViewModel : TuiViewModel { - [ObservableProperty] - private string _title = "SquidStd.Tui — Counter"; + [ObservableProperty] private string _title = "SquidStd.Tui — Counter"; - [ObservableProperty] - private string _value = "0"; + [ObservableProperty] private string _value = "0"; [RelayCommand] private void Increment() - { - Value = (int.Parse(Value) + 1).ToString(); - } + => Value = (int.Parse(Value) + 1).ToString(); } diff --git a/samples/SquidStd.Samples.Vfs/Program.cs b/samples/SquidStd.Samples.Vfs/Program.cs index 1a577c35..2c346213 100644 --- a/samples/SquidStd.Samples.Vfs/Program.cs +++ b/samples/SquidStd.Samples.Vfs/Program.cs @@ -1,5 +1,4 @@ using System.Text; -using SquidStd.Core.Data.Bootstrap; using SquidStd.Crypto.Vfs.Services; using SquidStd.Services.Core.Services.Bootstrap; using SquidStd.Vfs.Abstractions.Interfaces; @@ -7,7 +6,7 @@ using SquidStd.Vfs.Services; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory diff --git a/samples/SquidStd.Samples.WorkerSystem/Program.cs b/samples/SquidStd.Samples.WorkerSystem/Program.cs index 0f220543..6c4bb9ce 100644 --- a/samples/SquidStd.Samples.WorkerSystem/Program.cs +++ b/samples/SquidStd.Samples.WorkerSystem/Program.cs @@ -1,4 +1,3 @@ -using SquidStd.Core.Data.Bootstrap; using SquidStd.Generators.Workers; using SquidStd.Messaging.Extensions; using SquidStd.Services.Core.Services.Bootstrap; @@ -10,7 +9,7 @@ using SquidStd.Workers.Manager.Interfaces; var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "squidstd", RootDirectory = AppContext.BaseDirectory @@ -19,7 +18,8 @@ #region step-1 -bootstrap.ConfigureServices(c => +bootstrap.ConfigureServices( + c => { c.AddInMemoryMessaging(); c.AddWorkers(); diff --git a/src/SquidStd.Abstractions/Attributes/RegisterConfigSectionAttribute.cs b/src/SquidStd.Abstractions/Attributes/RegisterConfigSectionAttribute.cs index d5b94387..bf60a55e 100644 --- a/src/SquidStd.Abstractions/Attributes/RegisterConfigSectionAttribute.cs +++ b/src/SquidStd.Abstractions/Attributes/RegisterConfigSectionAttribute.cs @@ -1,23 +1,23 @@ namespace SquidStd.Abstractions.Attributes; /// -/// Marks a configuration type for generated config-section registration. +/// Marks a configuration type for generated config-section registration. /// [AttributeUsage(AttributeTargets.Class, Inherited = false)] public sealed class RegisterConfigSectionAttribute : Attribute { /// - /// Gets the configuration section name. + /// Gets the configuration section name. /// public string? SectionName { get; } /// - /// Gets or sets the config loading priority. + /// Gets or sets the config loading priority. /// public int Priority { get; set; } /// - /// Initializes a new instance of the attribute. + /// Initializes a new instance of the attribute. /// /// The configuration section name. public RegisterConfigSectionAttribute(string? sectionName = null) diff --git a/src/SquidStd.Abstractions/Attributes/RegisterEventListenerAttribute.cs b/src/SquidStd.Abstractions/Attributes/RegisterEventListenerAttribute.cs index a77c6dbe..17f02fa0 100644 --- a/src/SquidStd.Abstractions/Attributes/RegisterEventListenerAttribute.cs +++ b/src/SquidStd.Abstractions/Attributes/RegisterEventListenerAttribute.cs @@ -1,9 +1,7 @@ namespace SquidStd.Abstractions.Attributes; /// -/// Marks an event listener for generated registration. +/// Marks an event listener for generated registration. /// [AttributeUsage(AttributeTargets.Class, Inherited = false)] -public sealed class RegisterEventListenerAttribute : Attribute -{ -} +public sealed class RegisterEventListenerAttribute : Attribute { } diff --git a/src/SquidStd.Abstractions/Attributes/RegisterStdServiceAttribute.cs b/src/SquidStd.Abstractions/Attributes/RegisterStdServiceAttribute.cs index 53b3d5f9..e64fd1f9 100644 --- a/src/SquidStd.Abstractions/Attributes/RegisterStdServiceAttribute.cs +++ b/src/SquidStd.Abstractions/Attributes/RegisterStdServiceAttribute.cs @@ -1,23 +1,23 @@ namespace SquidStd.Abstractions.Attributes; /// -/// Marks a service implementation for generated SquidStd lifecycle registration. +/// Marks a service implementation for generated SquidStd lifecycle registration. /// [AttributeUsage(AttributeTargets.Class, Inherited = false)] public sealed class RegisterStdServiceAttribute : Attribute { /// - /// Gets the service contract registered for the annotated implementation. + /// Gets the service contract registered for the annotated implementation. /// public Type? ServiceType { get; } /// - /// Gets or sets the lifecycle start priority. + /// Gets or sets the lifecycle start priority. /// public int Priority { get; set; } /// - /// Initializes a new instance of the attribute. + /// Initializes a new instance of the attribute. /// /// The service contract registered for the annotated implementation. public RegisterStdServiceAttribute(Type? serviceType = null) diff --git a/src/SquidStd.Abstractions/Data/Internal/Commands/CommandHandlerRegistration.cs b/src/SquidStd.Abstractions/Data/Internal/Commands/CommandHandlerRegistration.cs index 21a569b5..6fb1f582 100644 --- a/src/SquidStd.Abstractions/Data/Internal/Commands/CommandHandlerRegistration.cs +++ b/src/SquidStd.Abstractions/Data/Internal/Commands/CommandHandlerRegistration.cs @@ -4,9 +4,9 @@ namespace SquidStd.Abstractions.Data.Internal.Commands; /// -/// A declarative command-handler registration consumed by the bootstrap activator. The -/// closure captures the concrete command and handler types at registration -/// time, so subscription needs no reflection. +/// A declarative command-handler registration consumed by the bootstrap activator. The +/// closure captures the concrete command and handler types at registration +/// time, so subscription needs no reflection. /// /// The dispatcher context type. /// The concrete handler implementation type. diff --git a/src/SquidStd.Abstractions/Data/Internal/Events/EventListenerRegistration.cs b/src/SquidStd.Abstractions/Data/Internal/Events/EventListenerRegistration.cs index 98b7ffbb..d108d476 100644 --- a/src/SquidStd.Abstractions/Data/Internal/Events/EventListenerRegistration.cs +++ b/src/SquidStd.Abstractions/Data/Internal/Events/EventListenerRegistration.cs @@ -4,9 +4,9 @@ namespace SquidStd.Abstractions.Data.Internal.Events; /// -/// A declarative event-listener registration consumed by the bootstrap activator. -/// The closure captures the concrete event and listener types at -/// registration time, so subscription needs no reflection. +/// A declarative event-listener registration consumed by the bootstrap activator. +/// The closure captures the concrete event and listener types at +/// registration time, so subscription needs no reflection. /// /// The concrete listener implementation type. /// Resolves the listener and subscribes it to the bus. diff --git a/src/SquidStd.Abstractions/Extensions/Commands/RegisterCommandHandlerExtension.cs b/src/SquidStd.Abstractions/Extensions/Commands/RegisterCommandHandlerExtension.cs index d7389d90..8c56e963 100644 --- a/src/SquidStd.Abstractions/Extensions/Commands/RegisterCommandHandlerExtension.cs +++ b/src/SquidStd.Abstractions/Extensions/Commands/RegisterCommandHandlerExtension.cs @@ -6,7 +6,7 @@ namespace SquidStd.Abstractions.Extensions.Commands; /// -/// Registers command handlers for DI-native auto-subscription at bootstrap. +/// Registers command handlers for DI-native auto-subscription at bootstrap. /// public static class RegisterCommandHandlerExtension { @@ -14,7 +14,7 @@ public static class RegisterCommandHandlerExtension extension(IContainer container) { /// - /// Registers a command handler as a singleton and records it for auto-subscription. + /// Registers a command handler as a singleton and records it for auto-subscription. /// /// The command type the handler handles. /// The dispatcher context type. diff --git a/src/SquidStd.Abstractions/Extensions/Config/RegisterConfigSectionExtension.cs b/src/SquidStd.Abstractions/Extensions/Config/RegisterConfigSectionExtension.cs index 79872dbd..822c32d0 100644 --- a/src/SquidStd.Abstractions/Extensions/Config/RegisterConfigSectionExtension.cs +++ b/src/SquidStd.Abstractions/Extensions/Config/RegisterConfigSectionExtension.cs @@ -22,7 +22,8 @@ public static IContainer RegisterConfigSection( if (container.IsRegistered>()) { var entries = container.Resolve>(); - var sameSection = entries.FirstOrDefault(entry => string.Equals( + var sameSection = entries.FirstOrDefault( + entry => string.Equals( entry.SectionName, sectionName, StringComparison.Ordinal @@ -45,7 +46,7 @@ public static IContainer RegisterConfigSection( } } - var factory = createDefault ?? (() => new TConfig()); + var factory = createDefault ?? (() => new()); container.AddToRegisterTypedList(new ConfigRegistrationData(sectionName, configType, () => factory(), priority)); return container; diff --git a/src/SquidStd.Abstractions/Extensions/Container/AddTypedListMethodExtension.cs b/src/SquidStd.Abstractions/Extensions/Container/AddTypedListMethodExtension.cs index 4eda3f26..570d0122 100644 --- a/src/SquidStd.Abstractions/Extensions/Container/AddTypedListMethodExtension.cs +++ b/src/SquidStd.Abstractions/Extensions/Container/AddTypedListMethodExtension.cs @@ -3,7 +3,7 @@ namespace SquidStd.Abstractions.Extensions.Container; /// -/// Extension methods for registering typed lists in the dependency injection container. +/// Extension methods for registering typed lists in the dependency injection container. /// public static class AddTypedListMethodExtension { @@ -11,8 +11,8 @@ public static class AddTypedListMethodExtension extension(IContainer container) { /// - /// Adds an entity to a typed list in the DryIoc container. - /// If the list doesn't exist, it creates and registers a new one. + /// Adds an entity to a typed list in the DryIoc container. + /// If the list doesn't exist, it creates and registers a new one. /// /// The type of entities in the list. /// The entity to add to the list. diff --git a/src/SquidStd.Abstractions/Extensions/Events/RegisterEventListenerExtension.cs b/src/SquidStd.Abstractions/Extensions/Events/RegisterEventListenerExtension.cs index 170988bd..b10b7230 100644 --- a/src/SquidStd.Abstractions/Extensions/Events/RegisterEventListenerExtension.cs +++ b/src/SquidStd.Abstractions/Extensions/Events/RegisterEventListenerExtension.cs @@ -6,7 +6,7 @@ namespace SquidStd.Abstractions.Extensions.Events; /// -/// Registers event listeners for DI-native auto-subscription at bootstrap. +/// Registers event listeners for DI-native auto-subscription at bootstrap. /// public static class RegisterEventListenerExtension { @@ -14,7 +14,7 @@ public static class RegisterEventListenerExtension extension(IContainer container) { /// - /// Registers a listener implementation as a singleton and records it for auto-subscription. + /// Registers a listener implementation as a singleton and records it for auto-subscription. /// /// The event type the listener handles. /// The listener implementation type. diff --git a/src/SquidStd.Abstractions/Interfaces/Services/ISquidStdService.cs b/src/SquidStd.Abstractions/Interfaces/Services/ISquidStdService.cs index dbc57ec2..4e9b5066 100644 --- a/src/SquidStd.Abstractions/Interfaces/Services/ISquidStdService.cs +++ b/src/SquidStd.Abstractions/Interfaces/Services/ISquidStdService.cs @@ -1,7 +1,7 @@ namespace SquidStd.Abstractions.Interfaces.Services; /// -/// Defines lifecycle operations for a SquidStd service. +/// Defines lifecycle operations for a SquidStd service. /// public interface ISquidStdService { diff --git a/src/SquidStd.Abstractions/README.md b/src/SquidStd.Abstractions/README.md index 00daacf7..9b2b921e 100644 --- a/src/SquidStd.Abstractions/README.md +++ b/src/SquidStd.Abstractions/README.md @@ -26,20 +26,21 @@ container.RegisterConfigSection("my"); ## Key types -| Type | Purpose | -|----------------------------------|--------------------------------------------------| -| `ISquidStdService` | Async start/stop lifecycle for managed services. | -| `RegisterEventListenerAttribute` | Marks event listeners for generated registration. | -| `RegisterStdServiceAttribute` | Marks services for generated registration. | -| `RegisterConfigSectionAttribute` | Marks config sections for generated registration. | -| `RegisterStdServiceExtension` | `RegisterStdService<,>` container extension. | -| `RegisterConfigSectionExtension` | `RegisterConfigSection<>` container extension. | -| `ServiceRegistrationData` | Ordered service registration record. | -| `ConfigRegistrationData` | Config section registration record. | +| Type | Purpose | +|----------------------------------|---------------------------------------------------| +| `ISquidStdService` | Async start/stop lifecycle for managed services. | +| `RegisterEventListenerAttribute` | Marks event listeners for generated registration. | +| `RegisterStdServiceAttribute` | Marks services for generated registration. | +| `RegisterConfigSectionAttribute` | Marks config sections for generated registration. | +| `RegisterStdServiceExtension` | `RegisterStdService<,>` container extension. | +| `RegisterConfigSectionExtension` | `RegisterConfigSection<>` container extension. | +| `ServiceRegistrationData` | Ordered service registration record. | +| `ConfigRegistrationData` | Config section registration record. | ## Related -- Tutorial: [Source generators: registration](https://tgiachi.github.io/squid-std/tutorials/source-generators-registration.html) +- +Tutorial: [Source generators: registration](https://tgiachi.github.io/squid-std/tutorials/source-generators-registration.html) ## License diff --git a/src/SquidStd.Actors/Actor.cs b/src/SquidStd.Actors/Actor.cs index 23cd542e..872dd9c4 100644 --- a/src/SquidStd.Actors/Actor.cs +++ b/src/SquidStd.Actors/Actor.cs @@ -9,9 +9,9 @@ namespace SquidStd.Actors; /// -/// Base class for an actor: a single-consumer mailbox that processes messages in FIFO order on one -/// logical thread, so handler state is mutated without locks. Send fire-and-forget messages with -/// and request/response messages with . +/// Base class for an actor: a single-consumer mailbox that processes messages in FIFO order on one +/// logical thread, so handler state is mutated without locks. Send fire-and-forget messages with +/// and request/response messages with . /// /// The base type of every message this actor accepts. public abstract class Actor : IAsyncDisposable @@ -24,18 +24,15 @@ public abstract class Actor : IAsyncDisposable private int _disposed; /// Number of messages waiting in the mailbox. - public int PendingCount - { - get { return _mailbox.InputCount; } - } + public int PendingCount => _mailbox.InputCount; /// Initializes the actor and starts its mailbox consumer. /// Mailbox options; defaults are used when null. protected Actor(ActorOptions? options = null) { _options = options ?? new ActorOptions(); - _shutdown = new CancellationTokenSource(); - _outstanding = new ConcurrentDictionary(); + _shutdown = new(); + _outstanding = new(); _logger = Log.ForContext(GetType()); // The mailbox is deliberately NOT bound to _shutdown.Token: cancelling that token would abort @@ -46,11 +43,11 @@ protected Actor(ActorOptions? options = null) MaxDegreeOfParallelism = 1, EnsureOrdered = true, BoundedCapacity = _options.OverflowPolicy == ActorOverflowPolicy.Unbounded - ? DataflowBlockOptions.Unbounded - : _options.Capacity + ? DataflowBlockOptions.Unbounded + : _options.Capacity }; - _mailbox = new ActionBlock(ProcessAsync, blockOptions); + _mailbox = new(ProcessAsync, blockOptions); } /// Enqueues a fire-and-forget message. Returns false only when dropped (DropNewest). @@ -76,9 +73,7 @@ public async ValueTask TellAsync(TMessage message, CancellationToken cance /// The request message type. /// The reply type. /// The reply. - public async Task AskAsync( - TRequest request, CancellationToken cancellationToken = default - ) + public async Task AskAsync(TRequest request, CancellationToken cancellationToken = default) where TRequest : TMessage, IActorRequest { ArgumentNullException.ThrowIfNull(request); @@ -87,8 +82,7 @@ public async Task AskAsync( _outstanding[request] = 0; using var registration = - cancellationToken.Register(() => request.Fail(new OperationCanceledException(cancellationToken)) - ); + cancellationToken.Register(() => request.Fail(new OperationCanceledException(cancellationToken))); try { @@ -116,9 +110,7 @@ public async Task AskAsync( /// The message whose handler threw. /// The thrown exception. protected virtual ValueTask OnErrorAsync(TMessage message, Exception error) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; private async Task ProcessAsync(TMessage message) { @@ -193,8 +185,8 @@ private async Task TryDrainAsync(TimeSpan timeout) } /// - /// Completes the mailbox and drains queued work within , - /// then cancels any handlers still running and faults requests that never completed. + /// Completes the mailbox and drains queued work within , + /// then cancels any handlers still running and faults requests that never completed. /// public async ValueTask DisposeAsync() { diff --git a/src/SquidStd.Actors/ActorRequest.cs b/src/SquidStd.Actors/ActorRequest.cs index e6eb1fb3..e099eb14 100644 --- a/src/SquidStd.Actors/ActorRequest.cs +++ b/src/SquidStd.Actors/ActorRequest.cs @@ -3,9 +3,9 @@ namespace SquidStd.Actors; /// -/// Base request record that removes the boilerplate. -/// Derive from it together with your actor's message interface, e.g. -/// record GetNick : ActorRequest<string?>, ISessionMessage;. +/// Base request record that removes the boilerplate. +/// Derive from it together with your actor's message interface, e.g. +/// record GetNick : ActorRequest<string?>, ISessionMessage;. /// /// The reply type. public abstract record ActorRequest : IActorRequest @@ -14,20 +14,13 @@ public abstract record ActorRequest : IActorRequest new(TaskCreationOptions.RunContinuationsAsynchronously); /// - public Task Completion - { - get { return _completion.Task; } - } + public Task Completion => _completion.Task; /// public void Reply(TReply value) - { - _completion.TrySetResult(value); - } + => _completion.TrySetResult(value); /// public void Fail(Exception error) - { - _completion.TrySetException(error); - } + => _completion.TrySetException(error); } diff --git a/src/SquidStd.Actors/Data/ActorOptions.cs b/src/SquidStd.Actors/Data/ActorOptions.cs index fefb36da..f4aa0603 100644 --- a/src/SquidStd.Actors/Data/ActorOptions.cs +++ b/src/SquidStd.Actors/Data/ActorOptions.cs @@ -3,7 +3,7 @@ namespace SquidStd.Actors.Data; /// -/// Configuration for an mailbox. +/// Configuration for an mailbox. /// public sealed class ActorOptions { @@ -17,9 +17,9 @@ public sealed class ActorOptions public ActorErrorPolicy ErrorPolicy { get; init; } = ActorErrorPolicy.Isolate; /// - /// How long drains queued messages - /// before cancelling in-flight handlers. Queued work runs to completion within this budget; - /// once it elapses, the actor cancels and faults any still-pending requests. + /// How long drains queued messages + /// before cancelling in-flight handlers. Queued work runs to completion within this budget; + /// once it elapses, the actor cancels and faults any still-pending requests. /// public TimeSpan ShutdownDrainTimeout { get; init; } = TimeSpan.FromSeconds(5); } diff --git a/src/SquidStd.Actors/Extensions/ActorEventBusExtensions.cs b/src/SquidStd.Actors/Extensions/ActorEventBusExtensions.cs index 03e87ef0..98acfa02 100644 --- a/src/SquidStd.Actors/Extensions/ActorEventBusExtensions.cs +++ b/src/SquidStd.Actors/Extensions/ActorEventBusExtensions.cs @@ -3,8 +3,8 @@ namespace SquidStd.Actors.Extensions; /// -/// Bridges the event bus to an actor mailbox: published events are mapped to messages and delivered -/// in order through the actor's single consumer. +/// Bridges the event bus to an actor mailbox: published events are mapped to messages and delivered +/// in order through the actor's single consumer. /// public static class ActorEventBusExtensions { @@ -12,8 +12,8 @@ public static class ActorEventBusExtensions extension(Actor actor) { /// - /// Subscribes the actor to on the bus, mapping each event to a - /// message and telling it to the mailbox. Dispose the returned token to stop delivery. + /// Subscribes the actor to on the bus, mapping each event to a + /// message and telling it to the mailbox. Dispose the returned token to stop delivery. /// /// The event bus to subscribe to. /// Maps an event to an actor message. @@ -21,12 +21,11 @@ public static class ActorEventBusExtensions /// A token that unsubscribes when disposed. public IDisposable SubscribeToEventBus(IEventBus eventBus, Func map) where TEvent : IEvent - { - return eventBus.Subscribe(async (eventData, cancellationToken) => + => eventBus.Subscribe( + async (eventData, cancellationToken) => { await actor.TellAsync(map(eventData), cancellationToken); } ); - } } } diff --git a/src/SquidStd.Actors/Interfaces/IActorRequest.cs b/src/SquidStd.Actors/Interfaces/IActorRequest.cs index abbe1e78..fb35c6ea 100644 --- a/src/SquidStd.Actors/Interfaces/IActorRequest.cs +++ b/src/SquidStd.Actors/Interfaces/IActorRequest.cs @@ -1,7 +1,7 @@ namespace SquidStd.Actors.Interfaces; /// -/// A request message that an actor answers with a single typed reply. +/// A request message that an actor answers with a single typed reply. /// /// The reply type. public interface IActorRequest : IActorRequestCore diff --git a/src/SquidStd.Actors/Interfaces/IActorRequestCore.cs b/src/SquidStd.Actors/Interfaces/IActorRequestCore.cs index 522a67ef..8e13e894 100644 --- a/src/SquidStd.Actors/Interfaces/IActorRequestCore.cs +++ b/src/SquidStd.Actors/Interfaces/IActorRequestCore.cs @@ -1,8 +1,8 @@ namespace SquidStd.Actors.Interfaces; /// -/// Non-generic request facet allowing the actor infrastructure to fault a pending request -/// without knowing its reply type. +/// Non-generic request facet allowing the actor infrastructure to fault a pending request +/// without knowing its reply type. /// public interface IActorRequestCore { diff --git a/src/SquidStd.Actors/README.md b/src/SquidStd.Actors/README.md index c88652e1..a34364b6 100644 --- a/src/SquidStd.Actors/README.md +++ b/src/SquidStd.Actors/README.md @@ -55,23 +55,23 @@ using var sub = session.SubscribeToEventBus(eventBus, (UserJoinedEvent e) => new ## Key types -| Type | Purpose | -|---------------------------|----------------------------------------------------| -| `Actor` | Mailbox base class (`TellAsync` / `AskAsync`). | -| `ActorRequest` | Base record for request/response messages. | -| `IActorRequest` | Request contract (implement directly if not using the base). | -| `ActorOptions` | Capacity / overflow / error configuration. | +| Type | Purpose | +|-------------------------|--------------------------------------------------------------| +| `Actor` | Mailbox base class (`TellAsync` / `AskAsync`). | +| `ActorRequest` | Base record for request/response messages. | +| `IActorRequest` | Request contract (implement directly if not using the base). | +| `ActorOptions` | Capacity / overflow / error configuration. | ## Options `ActorOptions` controls the mailbox: -| Property | Values | Default | -|------------------|-------------------------------------|----------| -| `Capacity` | bounded mailbox size | `1024` | -| `OverflowPolicy` | `Wait` / `DropNewest` / `Unbounded` | `Wait` | -| `ErrorPolicy` | `Isolate` / `StopOnError` | `Isolate`| -| `ShutdownDrainTimeout` | any `TimeSpan` | `5s` | +| Property | Values | Default | +|------------------------|-------------------------------------|-----------| +| `Capacity` | bounded mailbox size | `1024` | +| `OverflowPolicy` | `Wait` / `DropNewest` / `Unbounded` | `Wait` | +| `ErrorPolicy` | `Isolate` / `StopOnError` | `Isolate` | +| `ShutdownDrainTimeout` | any `TimeSpan` | `5s` | - **Wait**: `TellAsync` awaits until capacity frees (back-pressure). - **DropNewest**: `TellAsync` returns `false` when full. diff --git a/src/SquidStd.Actors/Types/ActorErrorPolicy.cs b/src/SquidStd.Actors/Types/ActorErrorPolicy.cs index ec42b9e9..056c66c7 100644 --- a/src/SquidStd.Actors/Types/ActorErrorPolicy.cs +++ b/src/SquidStd.Actors/Types/ActorErrorPolicy.cs @@ -1,7 +1,7 @@ namespace SquidStd.Actors.Types; /// -/// Behavior when a handler throws while processing a fire-and-forget message. +/// Behavior when a handler throws while processing a fire-and-forget message. /// public enum ActorErrorPolicy { diff --git a/src/SquidStd.Actors/Types/ActorOverflowPolicy.cs b/src/SquidStd.Actors/Types/ActorOverflowPolicy.cs index 9f1a1924..d54a777a 100644 --- a/src/SquidStd.Actors/Types/ActorOverflowPolicy.cs +++ b/src/SquidStd.Actors/Types/ActorOverflowPolicy.cs @@ -1,7 +1,7 @@ namespace SquidStd.Actors.Types; /// -/// Behavior when the actor mailbox reaches its bounded capacity. +/// Behavior when the actor mailbox reaches its bounded capacity. /// public enum ActorOverflowPolicy { diff --git a/src/SquidStd.AspNetCore/Extensions/SquidStdAspNetCoreBuilderExtensions.cs b/src/SquidStd.AspNetCore/Extensions/SquidStdAspNetCoreBuilderExtensions.cs index c44fd3c9..103c6d55 100644 --- a/src/SquidStd.AspNetCore/Extensions/SquidStdAspNetCoreBuilderExtensions.cs +++ b/src/SquidStd.AspNetCore/Extensions/SquidStdAspNetCoreBuilderExtensions.cs @@ -9,7 +9,7 @@ namespace SquidStd.AspNetCore.Extensions; /// -/// Extension methods for connecting SquidStd to ASP.NET Core Minimal API applications. +/// Extension methods for connecting SquidStd to ASP.NET Core Minimal API applications. /// public static class SquidStdAspNetCoreBuilderExtensions { @@ -26,17 +26,15 @@ private static void ValidateOptions(SquidStdOptions options) extension(WebApplicationBuilder builder) { /// - /// Registers SquidStd using DryIoc as the ASP.NET Core service provider. + /// Registers SquidStd using DryIoc as the ASP.NET Core service provider. /// /// Optional SquidStd bootstrap options callback. /// The same builder for chaining. public WebApplicationBuilder UseSquidStd(Action? configureOptions = null) - { - return builder.UseSquidStd(configureOptions, null); - } + => builder.UseSquidStd(configureOptions, null); /// - /// Registers SquidStd using DryIoc as the ASP.NET Core service provider. + /// Registers SquidStd using DryIoc as the ASP.NET Core service provider. /// /// Optional SquidStd bootstrap options callback. /// Optional DryIoc registration callback. diff --git a/src/SquidStd.AspNetCore/Extensions/SquidStdHealthChecksExtensions.cs b/src/SquidStd.AspNetCore/Extensions/SquidStdHealthChecksExtensions.cs index 6ff1155b..ab54d1ff 100644 --- a/src/SquidStd.AspNetCore/Extensions/SquidStdHealthChecksExtensions.cs +++ b/src/SquidStd.AspNetCore/Extensions/SquidStdHealthChecksExtensions.cs @@ -8,7 +8,7 @@ namespace SquidStd.AspNetCore.Extensions; /// -/// Extension methods that bridge SquidStd health checks into the standard ASP.NET Core health-check system. +/// Extension methods that bridge SquidStd health checks into the standard ASP.NET Core health-check system. /// public static class SquidStdHealthChecksExtensions { @@ -16,9 +16,9 @@ public static class SquidStdHealthChecksExtensions extension(WebApplicationBuilder builder) { /// - /// Registers each SquidStd IHealthCheck as a standard ASP.NET Core health check (one entry - /// per check, same name). Call after UseSquidStd; expose them with the standard - /// app.MapHealthChecks(...). Check names must be unique. + /// Registers each SquidStd IHealthCheck as a standard ASP.NET Core health check (one entry + /// per check, same name). Call after UseSquidStd; expose them with the standard + /// app.MapHealthChecks(...). Check names must be unique. /// /// The same builder for chaining. public WebApplicationBuilder AddSquidStdHealthChecks() @@ -40,7 +40,7 @@ out var value foreach (var check in checks) { healthChecks.Add( - new HealthCheckRegistration( + new( check.Name, _ => new SquidStdHealthCheckAdapter(check), HealthStatus.Unhealthy, diff --git a/src/SquidStd.AspNetCore/Services/SquidStdHealthCheckAdapter.cs b/src/SquidStd.AspNetCore/Services/SquidStdHealthCheckAdapter.cs index 037ed264..a9b64d07 100644 --- a/src/SquidStd.AspNetCore/Services/SquidStdHealthCheckAdapter.cs +++ b/src/SquidStd.AspNetCore/Services/SquidStdHealthCheckAdapter.cs @@ -5,8 +5,8 @@ namespace SquidStd.AspNetCore.Services; /// -/// Adapts a SquidStd to the standard ASP.NET Core -/// contract. +/// Adapts a SquidStd to the standard ASP.NET Core +/// contract. /// internal sealed class SquidStdHealthCheckAdapter : IHealthCheck { @@ -25,7 +25,7 @@ public async Task CheckHealthAsync( var result = await _check.CheckAsync(cancellationToken); return result.Status == SquidHealthStatus.Unhealthy - ? HealthCheckResult.Unhealthy(result.Description, result.Exception) - : HealthCheckResult.Healthy(result.Description); + ? HealthCheckResult.Unhealthy(result.Description, result.Exception) + : HealthCheckResult.Healthy(result.Description); } } diff --git a/src/SquidStd.AspNetCore/Services/SquidStdHostedService.cs b/src/SquidStd.AspNetCore/Services/SquidStdHostedService.cs index c2f65da8..b279eb7f 100644 --- a/src/SquidStd.AspNetCore/Services/SquidStdHostedService.cs +++ b/src/SquidStd.AspNetCore/Services/SquidStdHostedService.cs @@ -4,14 +4,14 @@ namespace SquidStd.AspNetCore.Services; /// -/// Bridges the ASP.NET Core host lifecycle to the SquidStd bootstrap lifecycle. +/// Bridges the ASP.NET Core host lifecycle to the SquidStd bootstrap lifecycle. /// internal sealed class SquidStdHostedService : IHostedService { private readonly ISquidStdBootstrap _bootstrap; /// - /// Initializes the hosted service. + /// Initializes the hosted service. /// /// SquidStd bootstrap instance started with the ASP.NET host. public SquidStdHostedService(ISquidStdBootstrap bootstrap) @@ -21,13 +21,9 @@ public SquidStdHostedService(ISquidStdBootstrap bootstrap) /// public async Task StartAsync(CancellationToken cancellationToken) - { - await _bootstrap.StartAsync(cancellationToken); - } + => await _bootstrap.StartAsync(cancellationToken); /// public async Task StopAsync(CancellationToken cancellationToken) - { - await _bootstrap.StopAsync(cancellationToken); - } + => await _bootstrap.StopAsync(cancellationToken); } diff --git a/src/SquidStd.Aws.Abstractions/Data/Config/AwsConfigEntry.cs b/src/SquidStd.Aws.Abstractions/Data/Config/AwsConfigEntry.cs index 80cc661e..fe5e1f43 100644 --- a/src/SquidStd.Aws.Abstractions/Data/Config/AwsConfigEntry.cs +++ b/src/SquidStd.Aws.Abstractions/Data/Config/AwsConfigEntry.cs @@ -1,8 +1,8 @@ namespace SquidStd.Aws.Abstractions.Data.Config; /// -/// Shared connection configuration for AWS-style services (region, credentials, endpoint override). -/// A dependency-free POCO: each provider maps it to its own SDK (AWS SDK, MinIO SDK, ...). +/// Shared connection configuration for AWS-style services (region, credentials, endpoint override). +/// A dependency-free POCO: each provider maps it to its own SDK (AWS SDK, MinIO SDK, ...). /// public sealed class AwsConfigEntry { diff --git a/src/SquidStd.Aws.Abstractions/README.md b/src/SquidStd.Aws.Abstractions/README.md index 20cc1518..d849eedf 100644 --- a/src/SquidStd.Aws.Abstractions/README.md +++ b/src/SquidStd.Aws.Abstractions/README.md @@ -29,8 +29,8 @@ client at that endpoint instead of the regional AWS endpoint. ## Key types -| Type | Purpose | -|------|---------| +| Type | Purpose | +|------------------|-----------------------------------------------------------------------------------| | `AwsConfigEntry` | Region, optional credentials and an optional endpoint override (e.g. LocalStack). | ## License diff --git a/src/SquidStd.Caching.Abstractions/Data/Config/CacheConnectionString.cs b/src/SquidStd.Caching.Abstractions/Data/Config/CacheConnectionString.cs index 0d1b9274..3463b840 100644 --- a/src/SquidStd.Caching.Abstractions/Data/Config/CacheConnectionString.cs +++ b/src/SquidStd.Caching.Abstractions/Data/Config/CacheConnectionString.cs @@ -4,7 +4,7 @@ namespace SquidStd.Caching.Abstractions.Data.Config; /// -/// Parsed cache connection string of the form scheme://[user:pass@]host[:port][?params]. +/// Parsed cache connection string of the form scheme://[user:pass@]host[:port][?params]. /// public sealed class CacheConnectionString { @@ -62,14 +62,14 @@ public static CacheConnectionString Parse(string connectionString) var query = HttpUtility.ParseQueryString(uri.Query); var parameters = query.AllKeys - .Where(static key => key is not null) - .ToFrozenDictionary( - key => key!, - key => query[key] ?? string.Empty, - StringComparer.OrdinalIgnoreCase - ); + .Where(static key => key is not null) + .ToFrozenDictionary( + key => key!, + key => query[key] ?? string.Empty, + StringComparer.OrdinalIgnoreCase + ); - return new CacheConnectionString( + return new( uri.Scheme, uri.Host, uri.Port > 0 ? uri.Port : null, @@ -81,13 +81,11 @@ public static CacheConnectionString Parse(string connectionString) /// Builds from the query parameters. public CacheOptions ToCacheOptions() - { - return new CacheOptions + => new() { DefaultTtl = Parameters.TryGetValue("defaultTtlSeconds", out var ttl) && int.TryParse(ttl, out var seconds) - ? TimeSpan.FromSeconds(seconds) - : null, + ? TimeSpan.FromSeconds(seconds) + : null, KeyPrefix = Parameters.TryGetValue("keyPrefix", out var prefix) ? prefix : string.Empty }; - } } diff --git a/src/SquidStd.Caching.Abstractions/Data/Config/CacheOptions.cs b/src/SquidStd.Caching.Abstractions/Data/Config/CacheOptions.cs index 0f633d4c..68fda982 100644 --- a/src/SquidStd.Caching.Abstractions/Data/Config/CacheOptions.cs +++ b/src/SquidStd.Caching.Abstractions/Data/Config/CacheOptions.cs @@ -1,7 +1,7 @@ namespace SquidStd.Caching.Abstractions.Data.Config; /// -/// Options shared by all cache providers. +/// Options shared by all cache providers. /// public sealed class CacheOptions { diff --git a/src/SquidStd.Caching.Abstractions/Interfaces/ICacheMetrics.cs b/src/SquidStd.Caching.Abstractions/Interfaces/ICacheMetrics.cs index c88d4bf2..bb966b18 100644 --- a/src/SquidStd.Caching.Abstractions/Interfaces/ICacheMetrics.cs +++ b/src/SquidStd.Caching.Abstractions/Interfaces/ICacheMetrics.cs @@ -1,7 +1,7 @@ namespace SquidStd.Caching.Abstractions.Interfaces; /// -/// Sink for cache instrumentation events. +/// Sink for cache instrumentation events. /// public interface ICacheMetrics { diff --git a/src/SquidStd.Caching.Abstractions/Interfaces/ICacheProvider.cs b/src/SquidStd.Caching.Abstractions/Interfaces/ICacheProvider.cs index dd061219..de8a47ae 100644 --- a/src/SquidStd.Caching.Abstractions/Interfaces/ICacheProvider.cs +++ b/src/SquidStd.Caching.Abstractions/Interfaces/ICacheProvider.cs @@ -3,7 +3,7 @@ namespace SquidStd.Caching.Abstractions.Interfaces; /// -/// Byte-level cache backend. Implemented by each provider (in-memory, Redis, ...). +/// Byte-level cache backend. Implemented by each provider (in-memory, Redis, ...). /// public interface ICacheProvider : ISquidStdService { diff --git a/src/SquidStd.Caching.Abstractions/Interfaces/ICacheService.cs b/src/SquidStd.Caching.Abstractions/Interfaces/ICacheService.cs index 46cf2db6..db57782e 100644 --- a/src/SquidStd.Caching.Abstractions/Interfaces/ICacheService.cs +++ b/src/SquidStd.Caching.Abstractions/Interfaces/ICacheService.cs @@ -1,7 +1,7 @@ namespace SquidStd.Caching.Abstractions.Interfaces; /// -/// Typed cache-aside facade over an . +/// Typed cache-aside facade over an . /// public interface ICacheService { diff --git a/src/SquidStd.Caching.Abstractions/Services/CacheMetricsProvider.cs b/src/SquidStd.Caching.Abstractions/Services/CacheMetricsProvider.cs index 04695d85..c35ee72f 100644 --- a/src/SquidStd.Caching.Abstractions/Services/CacheMetricsProvider.cs +++ b/src/SquidStd.Caching.Abstractions/Services/CacheMetricsProvider.cs @@ -6,7 +6,7 @@ namespace SquidStd.Caching.Abstractions.Services; /// -/// Accumulates aggregate cache metrics and exposes them to the metrics collection system. +/// Accumulates aggregate cache metrics and exposes them to the metrics collection system. /// public sealed class CacheMetricsProvider : ICacheMetrics, IMetricProvider { @@ -20,27 +20,19 @@ public sealed class CacheMetricsProvider : ICacheMetrics, IMetricProvider /// public void OnHit(string key) - { - Interlocked.Increment(ref _hits); - } + => Interlocked.Increment(ref _hits); /// public void OnMiss(string key) - { - Interlocked.Increment(ref _misses); - } + => Interlocked.Increment(ref _misses); /// public void OnRemove(string key) - { - Interlocked.Increment(ref _removes); - } + => Interlocked.Increment(ref _removes); /// public void OnSet(string key) - { - Interlocked.Increment(ref _sets); - } + => Interlocked.Increment(ref _sets); /// public ValueTask> CollectAsync(CancellationToken cancellationToken = default) diff --git a/src/SquidStd.Caching.Abstractions/Services/CacheService.cs b/src/SquidStd.Caching.Abstractions/Services/CacheService.cs index e21e6cbb..400c9d9e 100644 --- a/src/SquidStd.Caching.Abstractions/Services/CacheService.cs +++ b/src/SquidStd.Caching.Abstractions/Services/CacheService.cs @@ -5,8 +5,8 @@ namespace SquidStd.Caching.Abstractions.Services; /// -/// Typed cache-aside facade: serializes values, applies the key prefix and default TTL, and -/// implements once over any . +/// Typed cache-aside facade: serializes values, applies the key prefix and default TTL, and +/// implements once over any . /// public sealed class CacheService : ICacheService { @@ -35,9 +35,7 @@ public CacheService( /// public Task ExistsAsync(string key, CancellationToken cancellationToken = default) - { - return _provider.ExistsAsync(Prefixed(key), cancellationToken); - } + => _provider.ExistsAsync(Prefixed(key), cancellationToken); /// public async Task GetAsync(string key, CancellationToken cancellationToken = default) @@ -104,7 +102,5 @@ public async Task SetAsync(string key, T value, TimeSpan? ttl = null, Cancell } private string Prefixed(string key) - { - return _keyPrefix.Length == 0 ? key : _keyPrefix + key; - } + => _keyPrefix.Length == 0 ? key : _keyPrefix + key; } diff --git a/src/SquidStd.Caching.Abstractions/Services/NoOpCacheMetrics.cs b/src/SquidStd.Caching.Abstractions/Services/NoOpCacheMetrics.cs index 4d210305..285be016 100644 --- a/src/SquidStd.Caching.Abstractions/Services/NoOpCacheMetrics.cs +++ b/src/SquidStd.Caching.Abstractions/Services/NoOpCacheMetrics.cs @@ -3,26 +3,18 @@ namespace SquidStd.Caching.Abstractions.Services; /// -/// Metrics sink that ignores all events. Used when no metrics are configured. +/// Metrics sink that ignores all events. Used when no metrics are configured. /// public sealed class NoOpCacheMetrics : ICacheMetrics { /// Shared instance. public static NoOpCacheMetrics Instance { get; } = new(); - public void OnHit(string key) - { - } + public void OnHit(string key) { } - public void OnMiss(string key) - { - } + public void OnMiss(string key) { } - public void OnRemove(string key) - { - } + public void OnRemove(string key) { } - public void OnSet(string key) - { - } + public void OnSet(string key) { } } diff --git a/src/SquidStd.Caching.Redis/Data/Config/RedisCacheOptions.cs b/src/SquidStd.Caching.Redis/Data/Config/RedisCacheOptions.cs index 82bf02f9..30dd72d4 100644 --- a/src/SquidStd.Caching.Redis/Data/Config/RedisCacheOptions.cs +++ b/src/SquidStd.Caching.Redis/Data/Config/RedisCacheOptions.cs @@ -1,7 +1,7 @@ namespace SquidStd.Caching.Redis.Data.Config; /// -/// Connection options for the Redis cache provider. +/// Connection options for the Redis cache provider. /// public sealed class RedisCacheOptions { diff --git a/src/SquidStd.Caching.Redis/Extensions/RedisCacheRegistrationExtensions.cs b/src/SquidStd.Caching.Redis/Extensions/RedisCacheRegistrationExtensions.cs index 80798883..78e58210 100644 --- a/src/SquidStd.Caching.Redis/Extensions/RedisCacheRegistrationExtensions.cs +++ b/src/SquidStd.Caching.Redis/Extensions/RedisCacheRegistrationExtensions.cs @@ -11,7 +11,7 @@ namespace SquidStd.Caching.Redis.Extensions; /// -/// DryIoc registration helpers for the Redis cache provider. +/// DryIoc registration helpers for the Redis cache provider. /// public static class RedisCacheRegistrationExtensions { diff --git a/src/SquidStd.Caching.Redis/Services/RedisCacheProvider.cs b/src/SquidStd.Caching.Redis/Services/RedisCacheProvider.cs index 6163982c..97bcdb33 100644 --- a/src/SquidStd.Caching.Redis/Services/RedisCacheProvider.cs +++ b/src/SquidStd.Caching.Redis/Services/RedisCacheProvider.cs @@ -5,7 +5,7 @@ namespace SquidStd.Caching.Redis.Services; /// -/// Redis backed by a StackExchange.Redis connection multiplexer. +/// Redis backed by a StackExchange.Redis connection multiplexer. /// public sealed class RedisCacheProvider : ICacheProvider, IAsyncDisposable { @@ -38,9 +38,7 @@ public async ValueTask DisposeAsync() /// public Task ExistsAsync(string key, CancellationToken cancellationToken = default) - { - return Database.KeyExistsAsync(key); - } + => Database.KeyExistsAsync(key); /// public async Task?> GetAsync(string key, CancellationToken cancellationToken = default) @@ -57,9 +55,7 @@ public Task ExistsAsync(string key, CancellationToken cancellationToken = /// public Task RemoveAsync(string key, CancellationToken cancellationToken = default) - { - return Database.KeyDeleteAsync(key); - } + => Database.KeyDeleteAsync(key); /// public async Task SetAsync( @@ -69,19 +65,15 @@ public async Task SetAsync( CancellationToken cancellationToken = default ) { - var expiry = ttl is null ? Expiration.Default : new Expiration(ttl.Value); + var expiry = ttl is null ? Expiration.Default : new(ttl.Value); await Database.StringSetAsync(key, value.ToArray(), expiry); } /// public async ValueTask StartAsync(CancellationToken cancellationToken = default) - { - _connection = await ConnectionMultiplexer.ConnectAsync(_options.Configuration); - } + => _connection = await ConnectionMultiplexer.ConnectAsync(_options.Configuration); /// public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return DisposeAsync(); - } + => DisposeAsync(); } diff --git a/src/SquidStd.Caching/Extensions/CacheRegistrationExtensions.cs b/src/SquidStd.Caching/Extensions/CacheRegistrationExtensions.cs index e88685ce..2fb42565 100644 --- a/src/SquidStd.Caching/Extensions/CacheRegistrationExtensions.cs +++ b/src/SquidStd.Caching/Extensions/CacheRegistrationExtensions.cs @@ -11,7 +11,7 @@ namespace SquidStd.Caching.Extensions; /// -/// DryIoc registration helpers for the in-memory cache. +/// DryIoc registration helpers for the in-memory cache. /// public static class CacheRegistrationExtensions { diff --git a/src/SquidStd.Caching/Services/InMemoryCacheProvider.cs b/src/SquidStd.Caching/Services/InMemoryCacheProvider.cs index c7b93ccf..d63c2879 100644 --- a/src/SquidStd.Caching/Services/InMemoryCacheProvider.cs +++ b/src/SquidStd.Caching/Services/InMemoryCacheProvider.cs @@ -4,7 +4,7 @@ namespace SquidStd.Caching.Services; /// -/// In-memory backed by . +/// In-memory backed by . /// public sealed class InMemoryCacheProvider : ICacheProvider { @@ -17,9 +17,7 @@ public InMemoryCacheProvider(IMemoryCache cache) /// public Task ExistsAsync(string key, CancellationToken cancellationToken = default) - { - return Task.FromResult(_cache.TryGetValue(key, out _)); - } + => Task.FromResult(_cache.TryGetValue(key, out _)); /// public Task?> GetAsync(string key, CancellationToken cancellationToken = default) @@ -63,13 +61,9 @@ public Task SetAsync( /// public ValueTask StartAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; /// public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; } diff --git a/src/SquidStd.Core/Data/Bootstrap/SquidStdLoggerOptions.cs b/src/SquidStd.Core/Data/Bootstrap/SquidStdLoggerOptions.cs index bd0dd582..e361a730 100644 --- a/src/SquidStd.Core/Data/Bootstrap/SquidStdLoggerOptions.cs +++ b/src/SquidStd.Core/Data/Bootstrap/SquidStdLoggerOptions.cs @@ -3,37 +3,37 @@ namespace SquidStd.Core.Data.Bootstrap; /// -/// Defines YAML-backed logger options for SquidStd bootstrap. +/// Defines YAML-backed logger options for SquidStd bootstrap. /// public sealed class SquidStdLoggerOptions { /// - /// Gets or sets the minimum logger level. + /// Gets or sets the minimum logger level. /// public LogLevelType MinimumLevel { get; set; } = LogLevelType.Information; /// - /// Gets or sets whether console logging is enabled. + /// Gets or sets whether console logging is enabled. /// public bool EnableConsole { get; set; } = true; /// - /// Gets or sets whether file logging is enabled. + /// Gets or sets whether file logging is enabled. /// public bool EnableFile { get; set; } /// - /// Gets or sets the file log directory. Relative paths are resolved from the SquidStd root directory. + /// Gets or sets the file log directory. Relative paths are resolved from the SquidStd root directory. /// public string LogDirectory { get; set; } = "logs"; /// - /// Gets or sets the file log name or rolling file pattern. + /// Gets or sets the file log name or rolling file pattern. /// public string FileName { get; set; } = "squidstd-.log"; /// - /// Gets or sets the file log rolling interval. + /// Gets or sets the file log rolling interval. /// public SquidStdLogRollingIntervalType RollingInterval { get; set; } = SquidStdLogRollingIntervalType.Day; } diff --git a/src/SquidStd.Core/Data/Bootstrap/SquidStdOptions.cs b/src/SquidStd.Core/Data/Bootstrap/SquidStdOptions.cs index 24885cde..614508d6 100644 --- a/src/SquidStd.Core/Data/Bootstrap/SquidStdOptions.cs +++ b/src/SquidStd.Core/Data/Bootstrap/SquidStdOptions.cs @@ -1,17 +1,17 @@ namespace SquidStd.Core.Data.Bootstrap; /// -/// Defines bootstrap-only options used to locate SquidStd runtime resources. +/// Defines bootstrap-only options used to locate SquidStd runtime resources. /// public sealed class SquidStdOptions { /// - /// Gets or sets the root directory for configuration, logs, and runtime data. + /// Gets or sets the root directory for configuration, logs, and runtime data. /// public string RootDirectory { get; set; } = Directory.GetCurrentDirectory(); /// - /// Gets or sets the logical configuration name or YAML file name. + /// Gets or sets the logical configuration name or YAML file name. /// public string ConfigName { get; set; } = "squidstd"; } diff --git a/src/SquidStd.Core/Data/Commands/CommandDispatchResult.cs b/src/SquidStd.Core/Data/Commands/CommandDispatchResult.cs index 75f59ffb..1d5c44b5 100644 --- a/src/SquidStd.Core/Data/Commands/CommandDispatchResult.cs +++ b/src/SquidStd.Core/Data/Commands/CommandDispatchResult.cs @@ -1,7 +1,7 @@ namespace SquidStd.Core.Data.Commands; /// -/// The outcome of dispatching a command. +/// The outcome of dispatching a command. /// /// True when at least one handler was registered for the command type. /// The number of handlers invoked. diff --git a/src/SquidStd.Core/Data/Commands/CommandHandlerError.cs b/src/SquidStd.Core/Data/Commands/CommandHandlerError.cs index 2c946a2b..90a788eb 100644 --- a/src/SquidStd.Core/Data/Commands/CommandHandlerError.cs +++ b/src/SquidStd.Core/Data/Commands/CommandHandlerError.cs @@ -1,7 +1,7 @@ namespace SquidStd.Core.Data.Commands; /// -/// A handler that threw while processing a dispatched command. +/// A handler that threw while processing a dispatched command. /// /// The concrete handler type that failed. /// The exception thrown by the handler. diff --git a/src/SquidStd.Core/Data/Config/HealthCheckOptions.cs b/src/SquidStd.Core/Data/Config/HealthCheckOptions.cs index f578f535..b344fbe1 100644 --- a/src/SquidStd.Core/Data/Config/HealthCheckOptions.cs +++ b/src/SquidStd.Core/Data/Config/HealthCheckOptions.cs @@ -1,7 +1,7 @@ namespace SquidStd.Core.Data.Config; /// -/// Options for the health-check aggregator. +/// Options for the health-check aggregator. /// public sealed class HealthCheckOptions { diff --git a/src/SquidStd.Core/Data/Events/EventBusOptions.cs b/src/SquidStd.Core/Data/Events/EventBusOptions.cs index 7893a1dd..c3c2569c 100644 --- a/src/SquidStd.Core/Data/Events/EventBusOptions.cs +++ b/src/SquidStd.Core/Data/Events/EventBusOptions.cs @@ -1,12 +1,12 @@ namespace SquidStd.Core.Data.Events; /// -/// Options controlling event bus dispatch behavior. +/// Options controlling event bus dispatch behavior. /// public sealed record EventBusOptions { /// - /// Listeners whose handling exceeds this duration are logged as slow. Defaults to 100ms. + /// Listeners whose handling exceeds this duration are logged as slow. Defaults to 100ms. /// public TimeSpan SlowListenerThreshold { get; init; } = TimeSpan.FromMilliseconds(100); } diff --git a/src/SquidStd.Core/Data/Files/FileChangedEvent.cs b/src/SquidStd.Core/Data/Files/FileChangedEvent.cs index f5f7e728..ddb195f2 100644 --- a/src/SquidStd.Core/Data/Files/FileChangedEvent.cs +++ b/src/SquidStd.Core/Data/Files/FileChangedEvent.cs @@ -4,7 +4,7 @@ namespace SquidStd.Core.Data.Files; /// -/// Published on the event bus when a watched file changes, after debouncing. +/// Published on the event bus when a watched file changes, after debouncing. /// /// The kind of change observed. /// The absolute path of the affected file. diff --git a/src/SquidStd.Core/Data/Health/HealthCheckResult.cs b/src/SquidStd.Core/Data/Health/HealthCheckResult.cs index 76bba2b0..344b315c 100644 --- a/src/SquidStd.Core/Data/Health/HealthCheckResult.cs +++ b/src/SquidStd.Core/Data/Health/HealthCheckResult.cs @@ -3,7 +3,7 @@ namespace SquidStd.Core.Data.Health; /// -/// Result of a single health check. is stamped by the aggregator. +/// Result of a single health check. is stamped by the aggregator. /// public sealed record HealthCheckResult { @@ -21,13 +21,9 @@ public sealed record HealthCheckResult /// Creates a healthy result. public static HealthCheckResult Healthy(string? description = null) - { - return new HealthCheckResult { Status = HealthStatus.Healthy, Description = description }; - } + => new() { Status = HealthStatus.Healthy, Description = description }; /// Creates an unhealthy result. public static HealthCheckResult Unhealthy(string? description = null, Exception? exception = null) - { - return new HealthCheckResult { Status = HealthStatus.Unhealthy, Description = description, Exception = exception }; - } + => new() { Status = HealthStatus.Unhealthy, Description = description, Exception = exception }; } diff --git a/src/SquidStd.Core/Data/Health/HealthReport.cs b/src/SquidStd.Core/Data/Health/HealthReport.cs index e9a8a56f..93c05f8c 100644 --- a/src/SquidStd.Core/Data/Health/HealthReport.cs +++ b/src/SquidStd.Core/Data/Health/HealthReport.cs @@ -3,7 +3,7 @@ namespace SquidStd.Core.Data.Health; /// -/// Aggregated result of running every registered health check. +/// Aggregated result of running every registered health check. /// public sealed record HealthReport { diff --git a/src/SquidStd.Core/Data/Jobs/JobsConfig.cs b/src/SquidStd.Core/Data/Jobs/JobsConfig.cs index c83ae3a7..7f91275b 100644 --- a/src/SquidStd.Core/Data/Jobs/JobsConfig.cs +++ b/src/SquidStd.Core/Data/Jobs/JobsConfig.cs @@ -1,17 +1,17 @@ namespace SquidStd.Core.Data.Jobs; /// -/// Configuration for the background job system. +/// Configuration for the background job system. /// public sealed class JobsConfig { /// - /// Gets or sets the number of worker threads. + /// Gets or sets the number of worker threads. /// public int WorkerThreadCount { get; set; } /// - /// Gets or sets the seconds to wait for worker shutdown. + /// Gets or sets the seconds to wait for worker shutdown. /// public double ShutdownTimeoutSeconds { get; set; } = 1.0; } diff --git a/src/SquidStd.Core/Data/Metrics/MetricSample.cs b/src/SquidStd.Core/Data/Metrics/MetricSample.cs index 69ba580c..b4612060 100644 --- a/src/SquidStd.Core/Data/Metrics/MetricSample.cs +++ b/src/SquidStd.Core/Data/Metrics/MetricSample.cs @@ -3,7 +3,7 @@ namespace SquidStd.Core.Data.Metrics; /// -/// Represents one collected metric value. +/// Represents one collected metric value. /// /// Metric name emitted by the provider. /// Metric numeric value. diff --git a/src/SquidStd.Core/Data/Metrics/MetricsCollectedEvent.cs b/src/SquidStd.Core/Data/Metrics/MetricsCollectedEvent.cs index 38efc0ff..854a3f2b 100644 --- a/src/SquidStd.Core/Data/Metrics/MetricsCollectedEvent.cs +++ b/src/SquidStd.Core/Data/Metrics/MetricsCollectedEvent.cs @@ -3,7 +3,7 @@ namespace SquidStd.Core.Data.Metrics; /// -/// Event published after a metrics snapshot has been collected. +/// Event published after a metrics snapshot has been collected. /// /// The collected metrics snapshot. public sealed record MetricsCollectedEvent(MetricsSnapshot Snapshot) : IEvent; diff --git a/src/SquidStd.Core/Data/Metrics/MetricsConfig.cs b/src/SquidStd.Core/Data/Metrics/MetricsConfig.cs index 8c9424eb..531ce7f7 100644 --- a/src/SquidStd.Core/Data/Metrics/MetricsConfig.cs +++ b/src/SquidStd.Core/Data/Metrics/MetricsConfig.cs @@ -4,27 +4,27 @@ namespace SquidStd.Core.Data.Metrics; /// -/// Configuration for periodic metrics collection. +/// Configuration for periodic metrics collection. /// public sealed class MetricsConfig : IConfigEntry { /// - /// Gets or sets whether metrics collection is enabled. + /// Gets or sets whether metrics collection is enabled. /// public bool Enabled { get; set; } = true; /// - /// Gets or sets the collection interval in milliseconds. + /// Gets or sets the collection interval in milliseconds. /// public int IntervalMilliseconds { get; set; } = 1000; /// - /// Gets or sets whether each provider collection is logged. + /// Gets or sets whether each provider collection is logged. /// public bool LogEnabled { get; set; } = true; /// - /// Gets or sets the log level used for metrics collection logs. + /// Gets or sets the log level used for metrics collection logs. /// public LogLevelType LogLevel { get; set; } = LogLevelType.Trace; @@ -33,7 +33,5 @@ public sealed class MetricsConfig : IConfigEntry Type IConfigEntry.ConfigType => typeof(MetricsConfig); object IConfigEntry.CreateDefault() - { - return new MetricsConfig(); - } + => new MetricsConfig(); } diff --git a/src/SquidStd.Core/Data/Metrics/MetricsSnapshot.cs b/src/SquidStd.Core/Data/Metrics/MetricsSnapshot.cs index 58777768..a325930b 100644 --- a/src/SquidStd.Core/Data/Metrics/MetricsSnapshot.cs +++ b/src/SquidStd.Core/Data/Metrics/MetricsSnapshot.cs @@ -1,22 +1,22 @@ namespace SquidStd.Core.Data.Metrics; /// -/// Stores the last collected metrics batch. +/// Stores the last collected metrics batch. /// public sealed class MetricsSnapshot { /// - /// Gets the timestamp when the snapshot was collected. + /// Gets the timestamp when the snapshot was collected. /// public DateTimeOffset CollectedAt { get; } /// - /// Gets metrics keyed by their flattened metric name. + /// Gets metrics keyed by their flattened metric name. /// public IReadOnlyDictionary Metrics { get; } /// - /// Initializes a metrics snapshot. + /// Initializes a metrics snapshot. /// /// Timestamp when the snapshot was collected. /// Metrics keyed by their flattened metric name. diff --git a/src/SquidStd.Core/Data/Scheduling/CronJobInfo.cs b/src/SquidStd.Core/Data/Scheduling/CronJobInfo.cs index bf45a4b6..860db3fd 100644 --- a/src/SquidStd.Core/Data/Scheduling/CronJobInfo.cs +++ b/src/SquidStd.Core/Data/Scheduling/CronJobInfo.cs @@ -1,7 +1,7 @@ namespace SquidStd.Core.Data.Scheduling; /// -/// Immutable snapshot describing a registered cron job. +/// Immutable snapshot describing a registered cron job. /// public sealed class CronJobInfo { diff --git a/src/SquidStd.Core/Data/Storage/SecretsConfig.cs b/src/SquidStd.Core/Data/Storage/SecretsConfig.cs index 1708dc4e..ee471b1a 100644 --- a/src/SquidStd.Core/Data/Storage/SecretsConfig.cs +++ b/src/SquidStd.Core/Data/Storage/SecretsConfig.cs @@ -3,17 +3,17 @@ namespace SquidStd.Core.Data.Storage; /// -/// Configuration for encrypted local secret storage. +/// Configuration for encrypted local secret storage. /// public sealed class SecretsConfig : IConfigEntry { /// - /// Gets or sets the root directory used by local secret storage. + /// Gets or sets the root directory used by local secret storage. /// public string RootDirectory { get; set; } = "secrets"; /// - /// Gets or sets the environment variable that contains the base64 AES key. + /// Gets or sets the environment variable that contains the base64 AES key. /// public string KeyEnvironmentVariable { get; set; } = "SQUIDSTD_SECRETS_KEY"; @@ -22,7 +22,5 @@ public sealed class SecretsConfig : IConfigEntry Type IConfigEntry.ConfigType => typeof(SecretsConfig); object IConfigEntry.CreateDefault() - { - return new SecretsConfig(); - } + => new SecretsConfig(); } diff --git a/src/SquidStd.Core/Data/Timing/TimerWheelConfig.cs b/src/SquidStd.Core/Data/Timing/TimerWheelConfig.cs index 064129b1..a92aa79d 100644 --- a/src/SquidStd.Core/Data/Timing/TimerWheelConfig.cs +++ b/src/SquidStd.Core/Data/Timing/TimerWheelConfig.cs @@ -1,17 +1,17 @@ namespace SquidStd.Core.Data.Timing; /// -/// Configuration for the hashed timer wheel. +/// Configuration for the hashed timer wheel. /// public sealed class TimerWheelConfig { /// - /// Gets or sets the timer wheel granularity. + /// Gets or sets the timer wheel granularity. /// public TimeSpan TickDuration { get; set; } = TimeSpan.FromMilliseconds(8); /// - /// Gets or sets the number of slots in the wheel. + /// Gets or sets the number of slots in the wheel. /// public int WheelSize { get; set; } = 512; } diff --git a/src/SquidStd.Core/Data/Timing/TimerWheelPumpConfig.cs b/src/SquidStd.Core/Data/Timing/TimerWheelPumpConfig.cs index 6c12fadb..c106b8f8 100644 --- a/src/SquidStd.Core/Data/Timing/TimerWheelPumpConfig.cs +++ b/src/SquidStd.Core/Data/Timing/TimerWheelPumpConfig.cs @@ -1,12 +1,12 @@ namespace SquidStd.Core.Data.Timing; /// -/// Configuration for the timer wheel pump service. +/// Configuration for the timer wheel pump service. /// public sealed class TimerWheelPumpConfig { /// - /// Gets or sets how often the pump advances the timer wheel. + /// Gets or sets how often the pump advances the timer wheel. /// public TimeSpan PumpInterval { get; set; } = TimeSpan.FromMilliseconds(250); } diff --git a/src/SquidStd.Core/Directories/DirectoriesConfig.cs b/src/SquidStd.Core/Directories/DirectoriesConfig.cs index a9792945..9cfd74bd 100644 --- a/src/SquidStd.Core/Directories/DirectoriesConfig.cs +++ b/src/SquidStd.Core/Directories/DirectoriesConfig.cs @@ -3,33 +3,33 @@ namespace SquidStd.Core.Directories; /// -/// Configuration for managing directory structures with automatic creation and path resolution +/// Configuration for managing directory structures with automatic creation and path resolution /// public class DirectoriesConfig { private readonly string[] _directories; /// - /// Gets the root directory path. + /// Gets the root directory path. /// public string Root { get; } /// - /// Gets the path for the specified directory type. + /// Gets the path for the specified directory type. /// /// The directory type as string. /// The path for the directory type. public string this[string directoryType] => GetPath(directoryType); /// - /// Gets the path for the specified directory type enum. + /// Gets the path for the specified directory type enum. /// /// The directory type enum. /// The path for the directory type. public string this[Enum directoryType] => GetPath(directoryType.ToString()); /// - /// Initializes a new instance of the DirectoriesConfig class. + /// Initializes a new instance of the DirectoriesConfig class. /// /// The root directory path. /// The array of directory types. @@ -42,17 +42,15 @@ public DirectoriesConfig(string rootDirectory, string[] directories) } /// - /// Gets the path for the specified directory type enum. + /// Gets the path for the specified directory type enum. /// /// The directory type enum value. /// The path for the directory type. public string GetPath(TEnum value) where TEnum : struct, Enum - { - return GetPath(Enum.GetName(value)); - } + => GetPath(Enum.GetName(value)); /// - /// Gets the path for the specified directory type string. + /// Gets the path for the specified directory type string. /// /// The directory type as string. /// The path for the directory type. @@ -69,16 +67,14 @@ public string GetPath(string directoryType) } /// - /// Returns a string representation of the root directory. + /// Returns a string representation of the root directory. /// /// The root directory path. public override string ToString() - { - return Root; - } + => Root; /// - /// Initializes the directories configuration. + /// Initializes the directories configuration. /// private void Init() { @@ -90,7 +86,7 @@ private void Init() var directoryTypes = _directories.ToList(); foreach (var path in directoryTypes.Select(GetPath) - .Where(path => !Directory.Exists(path))) + .Where(path => !Directory.Exists(path))) { Directory.CreateDirectory(path); } diff --git a/src/SquidStd.Core/Extensions/Crypto/EncryptExtensions.cs b/src/SquidStd.Core/Extensions/Crypto/EncryptExtensions.cs index 4e05eab1..dbaf9b92 100644 --- a/src/SquidStd.Core/Extensions/Crypto/EncryptExtensions.cs +++ b/src/SquidStd.Core/Extensions/Crypto/EncryptExtensions.cs @@ -3,7 +3,7 @@ namespace SquidStd.Core.Extensions.Crypto; /// -/// String convenience helpers for AES-GCM encryption using a base64-encoded key. +/// String convenience helpers for AES-GCM encryption using a base64-encoded key. /// public static class EncryptExtensions { @@ -11,7 +11,7 @@ public static class EncryptExtensions extension(string text) { /// - /// Encrypts the string with AES-GCM and returns a base64 payload. + /// Encrypts the string with AES-GCM and returns a base64 payload. /// /// The base64-encoded key. /// The base64-encoded encrypted payload. @@ -23,7 +23,7 @@ public string EncryptString(string base64Key) } /// - /// Decrypts a base64 payload produced by . + /// Decrypts a base64 payload produced by . /// /// The base64-encoded key. /// The decrypted text. diff --git a/src/SquidStd.Core/Extensions/Directories/DirectoriesExtension.cs b/src/SquidStd.Core/Extensions/Directories/DirectoriesExtension.cs index cc1a1a03..0d263937 100644 --- a/src/SquidStd.Core/Extensions/Directories/DirectoriesExtension.cs +++ b/src/SquidStd.Core/Extensions/Directories/DirectoriesExtension.cs @@ -3,7 +3,7 @@ namespace SquidStd.Core.Extensions.Directories; /// -/// Provides extension methods for directory path resolution and environment variable expansion +/// Provides extension methods for directory path resolution and environment variable expansion /// public static class DirectoriesExtension { @@ -11,7 +11,7 @@ public static class DirectoriesExtension extension(string path) { /// - /// Resolves path by expanding tilde (~) to user home directory and expanding environment variables + /// Resolves path by expanding tilde (~) to user home directory and expanding environment variables /// /// The fully resolved path with expanded environment variables /// Thrown when path is null or empty diff --git a/src/SquidStd.Core/Extensions/Env/EnvExtensions.cs b/src/SquidStd.Core/Extensions/Env/EnvExtensions.cs index 141c896b..c70f81a0 100644 --- a/src/SquidStd.Core/Extensions/Env/EnvExtensions.cs +++ b/src/SquidStd.Core/Extensions/Env/EnvExtensions.cs @@ -4,7 +4,7 @@ namespace SquidStd.Core.Extensions.Env; /// -/// Provides extension methods for expanding environment variables in strings +/// Provides extension methods for expanding environment variables in strings /// public static class EnvExtensions { @@ -17,7 +17,7 @@ public static class EnvExtensions extension(string input) { /// - /// Expands environment variables in a string using custom $VARIABLE syntax + /// Expands environment variables in a string using custom $VARIABLE syntax /// /// The string with environment variables expanded to their values public string ExpandEnvironmentVariables() @@ -38,8 +38,8 @@ public string ExpandEnvironmentVariables() } /// - /// Replaces "$VAR" tokens with the matching environment variable value. Unknown variables are - /// left unchanged. + /// Replaces "$VAR" tokens with the matching environment variable value. Unknown variables are + /// left unchanged. /// /// The string with known $VAR tokens substituted. public string ReplaceEnv() diff --git a/src/SquidStd.Core/Extensions/Logger/LogLevelExtensions.cs b/src/SquidStd.Core/Extensions/Logger/LogLevelExtensions.cs index ff272cb5..9c676cfe 100644 --- a/src/SquidStd.Core/Extensions/Logger/LogLevelExtensions.cs +++ b/src/SquidStd.Core/Extensions/Logger/LogLevelExtensions.cs @@ -4,7 +4,7 @@ namespace SquidStd.Core.Extensions.Logger; /// -/// Extension methods for converting log levels between different logging frameworks. +/// Extension methods for converting log levels between different logging frameworks. /// public static class LogLevelExtensions { @@ -12,12 +12,11 @@ public static class LogLevelExtensions extension(LogLevelType logLevel) { /// - /// Converts a LogLevelType to a Serilog LogEventLevel. + /// Converts a LogLevelType to a Serilog LogEventLevel. /// /// The corresponding Serilog log event level. public LogEventLevel ToSerilogLogLevel() - { - return logLevel switch + => logLevel switch { LogLevelType.Trace => LogEventLevel.Verbose, LogLevelType.Debug => LogEventLevel.Debug, @@ -27,6 +26,5 @@ public LogEventLevel ToSerilogLogLevel() LogLevelType.Critical => LogEventLevel.Fatal, _ => LogEventLevel.Information }; - } } } diff --git a/src/SquidStd.Core/Extensions/Random/RandomExtensions.cs b/src/SquidStd.Core/Extensions/Random/RandomExtensions.cs index 1867a3d0..3ba2fc8e 100644 --- a/src/SquidStd.Core/Extensions/Random/RandomExtensions.cs +++ b/src/SquidStd.Core/Extensions/Random/RandomExtensions.cs @@ -5,7 +5,7 @@ namespace SquidStd.Core.Extensions.Random; /// -/// Shuffling and random-selection helpers over collections, built on . +/// Shuffling and random-selection helpers over collections, built on . /// public static class RandomExtensions { @@ -15,16 +15,12 @@ public static class RandomExtensions /// Shuffles the array in place. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Shuffle() - { - BuiltInRng.Generator.Shuffle(array.AsSpan()); - } + => BuiltInRng.Generator.Shuffle(array.AsSpan()); /// Returns a random element from the array. /// A random element, or default when the array is empty. public T? RandomElement() - { - return array.Length == 0 ? default : array[RandomUtils.Random(array.Length)]; - } + => array.Length == 0 ? default : array[RandomUtils.Random(array.Length)]; /// Returns a random sample of distinct elements without modifying the source. /// Number of elements to sample. @@ -63,9 +59,7 @@ public T[] RandomSample(int count) /// Shuffles the list in place. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Shuffle() - { - BuiltInRng.Generator.Shuffle(CollectionsMarshal.AsSpan(list)); - } + => BuiltInRng.Generator.Shuffle(CollectionsMarshal.AsSpan(list)); /// Returns a random sample of distinct elements without modifying the source. /// Number of elements to sample. @@ -105,8 +99,6 @@ public List RandomSample(int count) /// Returns a random element from the list. /// A random element, or default when the list is empty. public T? RandomElement() - { - return list.Count == 0 ? default : list[RandomUtils.Random(list.Count)]; - } + => list.Count == 0 ? default : list[RandomUtils.Random(list.Count)]; } } diff --git a/src/SquidStd.Core/Extensions/Strings/Base64Extensions.cs b/src/SquidStd.Core/Extensions/Strings/Base64Extensions.cs index 36063765..32ecaa4c 100644 --- a/src/SquidStd.Core/Extensions/Strings/Base64Extensions.cs +++ b/src/SquidStd.Core/Extensions/Strings/Base64Extensions.cs @@ -3,7 +3,7 @@ namespace SquidStd.Core.Extensions.Strings; /// -/// Provides base64 conversion helpers for strings and byte arrays. +/// Provides base64 conversion helpers for strings and byte arrays. /// public static class Base64Extensions { @@ -11,7 +11,7 @@ public static class Base64Extensions extension(string value) { /// - /// Determines whether the string is a well-formed base64 value. + /// Determines whether the string is a well-formed base64 value. /// /// true when the string decodes as base64; otherwise false. public bool IsBase64String() @@ -27,43 +27,35 @@ public bool IsBase64String() } /// - /// Encodes the UTF-8 bytes of the string as base64. + /// Encodes the UTF-8 bytes of the string as base64. /// /// The base64 representation. public string ToBase64() - { - return Convert.ToBase64String(Encoding.UTF8.GetBytes(value)); - } + => Convert.ToBase64String(Encoding.UTF8.GetBytes(value)); /// - /// Decodes a base64 string into its UTF-8 text. + /// Decodes a base64 string into its UTF-8 text. /// /// The decoded text. public string FromBase64() - { - return Encoding.UTF8.GetString(Convert.FromBase64String(value)); - } + => Encoding.UTF8.GetString(Convert.FromBase64String(value)); /// - /// Decodes a base64 string into its raw bytes. + /// Decodes a base64 string into its raw bytes. /// /// The decoded bytes. public byte[] FromBase64ToByteArray() - { - return Convert.FromBase64String(value); - } + => Convert.FromBase64String(value); } /// The bytes to encode. extension(byte[] value) { /// - /// Encodes the bytes as base64. + /// Encodes the bytes as base64. /// /// The base64 representation. public string ToBase64() - { - return Convert.ToBase64String(value); - } + => Convert.ToBase64String(value); } } diff --git a/src/SquidStd.Core/Extensions/Strings/StringMethodExtension.cs b/src/SquidStd.Core/Extensions/Strings/StringMethodExtension.cs index 41234bf9..2741372c 100644 --- a/src/SquidStd.Core/Extensions/Strings/StringMethodExtension.cs +++ b/src/SquidStd.Core/Extensions/Strings/StringMethodExtension.cs @@ -3,7 +3,7 @@ namespace SquidStd.Core.Extensions.Strings; /// -/// Provides extension methods for string operations, particularly for case conversions. +/// Provides extension methods for string operations, particularly for case conversions. /// public static class StringMethodExtension { @@ -11,93 +11,73 @@ public static class StringMethodExtension extension(string text) { /// - /// Converts a string to camelCase. + /// Converts a string to camelCase. /// /// A camelCase version of the input string. public string ToCamelCase() - { - return StringUtils.ToCamelCase(text); - } + => StringUtils.ToCamelCase(text); /// - /// Converts a string to Dot Case. + /// Converts a string to Dot Case. /// /// A Dot Case version of the input string. public string ToDotCase() - { - return StringUtils.ToDotCase(text); - } + => StringUtils.ToDotCase(text); /// - /// Converts a string to kebab-case. + /// Converts a string to kebab-case. /// /// A kebab-case version of the input string. public string ToKebabCase() - { - return StringUtils.ToKebabCase(text); - } + => StringUtils.ToKebabCase(text); /// - /// Converts a string to PascalCase. + /// Converts a string to PascalCase. /// /// A PascalCase version of the input string. public string ToPascalCase() - { - return StringUtils.ToPascalCase(text); - } + => StringUtils.ToPascalCase(text); /// - /// Converts a string to Path Case. + /// Converts a string to Path Case. /// /// A Path Case version of the input string. public string ToPathCase() - { - return StringUtils.ToPathCase(text); - } + => StringUtils.ToPathCase(text); /// - /// Converts a string to Sentence Case. + /// Converts a string to Sentence Case. /// /// A Sentence Case version of the input string. public string ToSentenceCase() - { - return StringUtils.ToSentenceCase(text); - } + => StringUtils.ToSentenceCase(text); /// - /// Converts a string to snake_case. + /// Converts a string to snake_case. /// /// A snake_case version of the input string. public string ToSnakeCase() - { - return StringUtils.ToSnakeCase(text); - } + => StringUtils.ToSnakeCase(text); /// - /// Converts a string to UPPER_SNAKE_CASE. + /// Converts a string to UPPER_SNAKE_CASE. /// /// An UPPER_SNAKE_CASE version of the input string. public string ToSnakeCaseUpper() - { - return StringUtils.ToUpperSnakeCase(text); - } + => StringUtils.ToUpperSnakeCase(text); /// - /// Converts a string to Title Case. + /// Converts a string to Title Case. /// /// A Title Case version of the input string. public string ToTitleCase() - { - return StringUtils.ToTitleCase(text); - } + => StringUtils.ToTitleCase(text); /// - /// Converts a string to Train Case. + /// Converts a string to Train Case. /// /// A Train Case version of the input string. public string ToTrainCase() - { - return StringUtils.ToTrainCase(text); - } + => StringUtils.ToTrainCase(text); } } diff --git a/src/SquidStd.Core/Files/FileWatcherService.cs b/src/SquidStd.Core/Files/FileWatcherService.cs index 837b274a..cbd150bb 100644 --- a/src/SquidStd.Core/Files/FileWatcherService.cs +++ b/src/SquidStd.Core/Files/FileWatcherService.cs @@ -9,11 +9,11 @@ namespace SquidStd.Core.Files; /// -/// Recursive directory watcher that coalesces rapid file-system notifications with a debounce window and -/// publishes a single per path on the event bus. Each -/// call adds one recursive watcher with its own glob filter, so several directories (each with a different -/// pattern, e.g. *.lua and *.json) can be watched at once. The watcher stays decoupled from -/// any reload logic. +/// Recursive directory watcher that coalesces rapid file-system notifications with a debounce window and +/// publishes a single per path on the event bus. Each +/// call adds one recursive watcher with its own glob filter, so several directories (each with a different +/// pattern, e.g. *.lua and *.json) can be watched at once. The watcher stays decoupled from +/// any reload logic. /// public sealed class FileWatcherService : IFileWatcherService { @@ -28,16 +28,14 @@ public sealed class FileWatcherService : IFileWatcherService private bool _disposed; /// - /// Initializes the watcher with the default 300ms debounce window. + /// Initializes the watcher with the default 300ms debounce window. /// /// The bus that receives notifications. public FileWatcherService(IEventBus eventBus) - : this(eventBus, TimeSpan.FromMilliseconds(300)) - { - } + : this(eventBus, TimeSpan.FromMilliseconds(300)) { } /// - /// Initializes the watcher with an explicit debounce window. + /// Initializes the watcher with an explicit debounce window. /// /// The bus that receives notifications. /// How long a path must be quiet before its change is published. @@ -54,9 +52,7 @@ public FileWatcherService(IEventBus eventBus, TimeSpan debounceDelay) /// public void Watch(string path) - { - Watch(path, "*"); - } + => Watch(path, "*"); /// public void Watch(string path, string filter) @@ -81,7 +77,7 @@ public void Watch(string path, string filter) return; } - watcher = new FileSystemWatcher(fullPath, filter) + watcher = new(fullPath, filter) { NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | @@ -173,7 +169,7 @@ private void OnFileChanged(object sender, FileSystemEventArgs e) _ => FileChangeKind.Changed }; - Schedule(new FileChangedEvent(kind, Path.GetFullPath(e.FullPath))); + Schedule(new(kind, Path.GetFullPath(e.FullPath))); } private void OnFileRenamed(object sender, RenamedEventArgs e) @@ -183,9 +179,7 @@ private void OnFileRenamed(object sender, RenamedEventArgs e) return; } - Schedule( - new FileChangedEvent(FileChangeKind.Renamed, Path.GetFullPath(e.FullPath), Path.GetFullPath(e.OldFullPath)) - ); + Schedule(new(FileChangeKind.Renamed, Path.GetFullPath(e.FullPath), Path.GetFullPath(e.OldFullPath))); } private void Schedule(FileChangedEvent change) @@ -200,7 +194,7 @@ private void Schedule(FileChangedEvent change) var timer = _debounceTimers.AddOrUpdate( key, - k => new Timer(OnDebounceElapsed, k, _debounce, Timeout.InfiniteTimeSpan), + k => new(OnDebounceElapsed, k, _debounce, Timeout.InfiniteTimeSpan), (_, existing) => { existing.Change(_debounce, Timeout.InfiniteTimeSpan); @@ -245,9 +239,7 @@ private async Task PublishAsync(FileChangedEvent change) } private static string KeyFor(string path, string filter) - { - return path + "|" + filter; - } + => path + "|" + filter; private static void DisposeWatcher(FileSystemWatcher watcher) { diff --git a/src/SquidStd.Core/Interfaces/Bootstrap/ISquidStdBootstrap.cs b/src/SquidStd.Core/Interfaces/Bootstrap/ISquidStdBootstrap.cs index b987f9f2..857851bf 100644 --- a/src/SquidStd.Core/Interfaces/Bootstrap/ISquidStdBootstrap.cs +++ b/src/SquidStd.Core/Interfaces/Bootstrap/ISquidStdBootstrap.cs @@ -4,57 +4,57 @@ namespace SquidStd.Core.Interfaces.Bootstrap; /// -/// Coordinates SquidStd dependency registration, configuration loading, and service lifecycle. +/// Coordinates SquidStd dependency registration, configuration loading, and service lifecycle. /// public interface ISquidStdBootstrap : IAsyncDisposable { /// - /// Gets the bootstrap options used to configure runtime resources. + /// Gets the bootstrap options used to configure runtime resources. /// SquidStdOptions Options { get; } /// - /// Gets the owned dependency injection container. + /// Gets the owned dependency injection container. /// IContainer Container { get; } /// - /// Applies custom service registrations before the bootstrap lifecycle starts. + /// Applies custom service registrations before the bootstrap lifecycle starts. /// /// Callback that receives and returns the container. /// The same bootstrap instance for chaining. ISquidStdBootstrap ConfigureService(Func configure); /// - /// Applies custom service registrations before the bootstrap lifecycle starts. + /// Applies custom service registrations before the bootstrap lifecycle starts. /// /// Callback that receives and returns the container. /// The same bootstrap instance for chaining. ISquidStdBootstrap ConfigureServices(Func configure); /// - /// Resolves a service from the owned dependency injection container. + /// Resolves a service from the owned dependency injection container. /// /// The service type to resolve. /// The resolved service instance. TService Resolve(); /// - /// Starts services, waits until cancellation, and then stops services. + /// Starts services, waits until cancellation, and then stops services. /// /// Token that controls the run lifetime. /// A task that completes after services have stopped. Task RunAsync(CancellationToken cancellationToken = default); /// - /// Starts registered lifecycle services in priority order. + /// Starts registered lifecycle services in priority order. /// /// Token used to cancel the start operation. /// A task that represents the asynchronous start operation. ValueTask StartAsync(CancellationToken cancellationToken = default); /// - /// Stops started lifecycle services in reverse priority order. + /// Stops started lifecycle services in reverse priority order. /// /// Token used to cancel the stop operation. /// A task that represents the asynchronous stop operation. diff --git a/src/SquidStd.Core/Interfaces/Commands/ICommand.cs b/src/SquidStd.Core/Interfaces/Commands/ICommand.cs index 71256c51..9d8dd4cc 100644 --- a/src/SquidStd.Core/Interfaces/Commands/ICommand.cs +++ b/src/SquidStd.Core/Interfaces/Commands/ICommand.cs @@ -1,8 +1,6 @@ namespace SquidStd.Core.Interfaces.Commands; /// -/// Marker contract for commands dispatched through an . +/// Marker contract for commands dispatched through an . /// -public interface ICommand -{ -} +public interface ICommand { } diff --git a/src/SquidStd.Core/Interfaces/Commands/ICommandContextFactorySeeded.cs b/src/SquidStd.Core/Interfaces/Commands/ICommandContextFactorySeeded.cs index f9631719..19f021b0 100644 --- a/src/SquidStd.Core/Interfaces/Commands/ICommandContextFactorySeeded.cs +++ b/src/SquidStd.Core/Interfaces/Commands/ICommandContextFactorySeeded.cs @@ -1,8 +1,8 @@ namespace SquidStd.Core.Interfaces.Commands; /// -/// Produces a from a seed (for example the connection a message -/// arrived on), so a dispatch can carry the context that belongs to that seed. +/// Produces a from a seed (for example the connection a message +/// arrived on), so a dispatch can carry the context that belongs to that seed. /// /// The context type produced. /// The seed the context is built from. diff --git a/src/SquidStd.Core/Interfaces/Commands/ICommandDispatcher.cs b/src/SquidStd.Core/Interfaces/Commands/ICommandDispatcher.cs index 768eb2f9..0214af29 100644 --- a/src/SquidStd.Core/Interfaces/Commands/ICommandDispatcher.cs +++ b/src/SquidStd.Core/Interfaces/Commands/ICommandDispatcher.cs @@ -3,8 +3,8 @@ namespace SquidStd.Core.Interfaces.Commands; /// -/// Dispatches typed commands to registered handlers within an ambient , -/// fanning a command out to every handler registered for its type. +/// Dispatches typed commands to registered handlers within an ambient , +/// fanning a command out to every handler registered for its type. /// /// The ambient context type. public interface ICommandDispatcher @@ -28,7 +28,9 @@ public interface ICommandDispatcher /// The cancellation token. /// The dispatch result. Task DispatchAsync( - TCommand command, TContext context, CancellationToken cancellationToken = default + TCommand command, + TContext context, + CancellationToken cancellationToken = default ) where TCommand : ICommand; } diff --git a/src/SquidStd.Core/Interfaces/Commands/ICommandHandler.cs b/src/SquidStd.Core/Interfaces/Commands/ICommandHandler.cs index 58d1940c..9a4676cd 100644 --- a/src/SquidStd.Core/Interfaces/Commands/ICommandHandler.cs +++ b/src/SquidStd.Core/Interfaces/Commands/ICommandHandler.cs @@ -1,8 +1,8 @@ namespace SquidStd.Core.Interfaces.Commands; /// -/// Handles a command of type within the ambient -/// (for example the current session or connection). +/// Handles a command of type within the ambient +/// (for example the current session or connection). /// /// The command type handled. /// The ambient context type passed to the handler. diff --git a/src/SquidStd.Core/Interfaces/Commands/ISeededCommandDispatcher.cs b/src/SquidStd.Core/Interfaces/Commands/ISeededCommandDispatcher.cs index a10511f1..8725f991 100644 --- a/src/SquidStd.Core/Interfaces/Commands/ISeededCommandDispatcher.cs +++ b/src/SquidStd.Core/Interfaces/Commands/ISeededCommandDispatcher.cs @@ -3,11 +3,11 @@ namespace SquidStd.Core.Interfaces.Commands; /// -/// Dispatches commands by first building the from a -/// (for example the originating connection) through an -/// , then delegating to the underlying -/// . Handlers are still registered on the -/// . +/// Dispatches commands by first building the from a +/// (for example the originating connection) through an +/// , then delegating to the underlying +/// . Handlers are still registered on the +/// . /// /// The ambient context type. /// The seed the context is built from. @@ -20,7 +20,9 @@ public interface ISeededCommandDispatcher /// The cancellation token. /// The dispatch result. Task DispatchAsync( - TCommand command, TSeed seed, CancellationToken cancellationToken = default + TCommand command, + TSeed seed, + CancellationToken cancellationToken = default ) where TCommand : ICommand; } diff --git a/src/SquidStd.Core/Interfaces/Config/IConfigEntry.cs b/src/SquidStd.Core/Interfaces/Config/IConfigEntry.cs index c5fcdbd8..0b7a7ca7 100644 --- a/src/SquidStd.Core/Interfaces/Config/IConfigEntry.cs +++ b/src/SquidStd.Core/Interfaces/Config/IConfigEntry.cs @@ -1,22 +1,22 @@ namespace SquidStd.Core.Interfaces.Config; /// -/// Describes a configuration section that can be composed into YAML and registered into DI. +/// Describes a configuration section that can be composed into YAML and registered into DI. /// public interface IConfigEntry { /// - /// Gets the top-level YAML section name. + /// Gets the top-level YAML section name. /// string SectionName { get; } /// - /// Gets the concrete configuration type for this section. + /// Gets the concrete configuration type for this section. /// Type ConfigType { get; } /// - /// Creates a default configuration value for this section. + /// Creates a default configuration value for this section. /// /// The default configuration object. object CreateDefault(); diff --git a/src/SquidStd.Core/Interfaces/Config/IConfigManagerService.cs b/src/SquidStd.Core/Interfaces/Config/IConfigManagerService.cs index 626620ee..0ae4a387 100644 --- a/src/SquidStd.Core/Interfaces/Config/IConfigManagerService.cs +++ b/src/SquidStd.Core/Interfaces/Config/IConfigManagerService.cs @@ -1,50 +1,50 @@ namespace SquidStd.Core.Interfaces.Config; /// -/// Manages the YAML configuration file and registers loaded sections into DI. +/// Manages the YAML configuration file and registers loaded sections into DI. /// public interface IConfigManagerService { /// - /// Gets the logical configuration name. + /// Gets the logical configuration name. /// string ConfigName { get; } /// - /// Gets the directory where the configuration file is searched. + /// Gets the directory where the configuration file is searched. /// string ConfigDirectory { get; } /// - /// Gets the resolved YAML configuration file path. + /// Gets the resolved YAML configuration file path. /// string ConfigPath { get; } /// - /// Gets the registered configuration entries. + /// Gets the registered configuration entries. /// IReadOnlyCollection Entries { get; } /// - /// Composes the currently loaded sections into YAML. + /// Composes the currently loaded sections into YAML. /// /// The composed YAML document. string Compose(); /// - /// Gets a loaded configuration section from DI. + /// Gets a loaded configuration section from DI. /// /// The configuration type. /// The loaded configuration section. TConfig GetConfig() where TConfig : class; /// - /// Loads or creates the configured YAML file and registers every section into DI. + /// Loads or creates the configured YAML file and registers every section into DI. /// void Load(); /// - /// Saves the currently loaded sections to the configured YAML file. + /// Saves the currently loaded sections to the configured YAML file. /// void Save(); } diff --git a/src/SquidStd.Core/Interfaces/Events/IEvent.cs b/src/SquidStd.Core/Interfaces/Events/IEvent.cs index 9dc7bc9e..3b4e0027 100644 --- a/src/SquidStd.Core/Interfaces/Events/IEvent.cs +++ b/src/SquidStd.Core/Interfaces/Events/IEvent.cs @@ -1,8 +1,6 @@ namespace SquidStd.Core.Interfaces.Events; /// -/// Marker contract for events dispatched through the SquidStd event bus. +/// Marker contract for events dispatched through the SquidStd event bus. /// -public interface IEvent -{ -} +public interface IEvent { } diff --git a/src/SquidStd.Core/Interfaces/Events/IEventBus.cs b/src/SquidStd.Core/Interfaces/Events/IEventBus.cs index 879e6344..2f3d8059 100644 --- a/src/SquidStd.Core/Interfaces/Events/IEventBus.cs +++ b/src/SquidStd.Core/Interfaces/Events/IEventBus.cs @@ -1,19 +1,19 @@ namespace SquidStd.Core.Interfaces.Events; /// -/// In-process event bus that dispatches events to registered listeners in parallel. +/// In-process event bus that dispatches events to registered listeners in parallel. /// public interface IEventBus { /// - /// Publishes an event and blocks until every listener has completed. + /// Publishes an event and blocks until every listener has completed. /// /// The event payload. /// The event type. void Publish(TEvent eventData) where TEvent : IEvent; /// - /// Publishes an event and completes when every listener has finished. + /// Publishes an event and completes when every listener has finished. /// /// The event payload. /// The cancellation token. @@ -22,7 +22,7 @@ public interface IEventBus Task PublishAsync(TEvent eventData, CancellationToken cancellationToken = default) where TEvent : IEvent; /// - /// Registers a listener for the specified event type. Dispose the returned token to unsubscribe. + /// Registers a listener for the specified event type. Dispose the returned token to unsubscribe. /// /// The listener to register. /// The event type. @@ -30,7 +30,7 @@ public interface IEventBus IDisposable RegisterListener(IEventListener listener) where TEvent : IEvent; /// - /// Subscribes a delegate handler for the specified event type. Dispose the returned token to unsubscribe. + /// Subscribes a delegate handler for the specified event type. Dispose the returned token to unsubscribe. /// /// The handler invoked for each published event. /// The event type. diff --git a/src/SquidStd.Core/Interfaces/Events/IEventListener.cs b/src/SquidStd.Core/Interfaces/Events/IEventListener.cs index f3a7a3b5..73820859 100644 --- a/src/SquidStd.Core/Interfaces/Events/IEventListener.cs +++ b/src/SquidStd.Core/Interfaces/Events/IEventListener.cs @@ -1,13 +1,13 @@ namespace SquidStd.Core.Interfaces.Events; /// -/// Handles an event published on the SquidStd event bus. +/// Handles an event published on the SquidStd event bus. /// /// The event type handled by the listener. public interface IEventListener where TEvent : IEvent { /// - /// Handles a published event. + /// Handles a published event. /// /// The event payload. /// The cancellation token. diff --git a/src/SquidStd.Core/Interfaces/Files/IFileWatcherService.cs b/src/SquidStd.Core/Interfaces/Files/IFileWatcherService.cs index 076d9565..19db2c43 100644 --- a/src/SquidStd.Core/Interfaces/Files/IFileWatcherService.cs +++ b/src/SquidStd.Core/Interfaces/Files/IFileWatcherService.cs @@ -1,34 +1,34 @@ namespace SquidStd.Core.Interfaces.Files; /// -/// Watches directories recursively and publishes debounced file-change events on the event bus. +/// Watches directories recursively and publishes debounced file-change events on the event bus. /// public interface IFileWatcherService : IDisposable { /// - /// Starts watching a directory and all of its current and future subdirectories, for every file. - /// The directory is created if it does not exist. + /// Starts watching a directory and all of its current and future subdirectories, for every file. + /// The directory is created if it does not exist. /// /// The directory to watch. void Watch(string path); /// - /// Starts watching a directory and all of its current and future subdirectories, limited to files - /// matching the glob filter. The directory is created if it does not exist. Call this once per - /// directory to watch several at the same time, each with its own filter. + /// Starts watching a directory and all of its current and future subdirectories, limited to files + /// matching the glob filter. The directory is created if it does not exist. Call this once per + /// directory to watch several at the same time, each with its own filter. /// /// The directory to watch. /// A glob pattern such as *.lua or * for all files. void Watch(string path, string filter); /// - /// Stops watching a directory and its subdirectories. + /// Stops watching a directory and its subdirectories. /// /// The directory to stop watching. void Unwatch(string path); /// - /// Stops every watcher and cancels pending debounced notifications. + /// Stops every watcher and cancels pending debounced notifications. /// void Stop(); } diff --git a/src/SquidStd.Core/Interfaces/Health/IHealthCheck.cs b/src/SquidStd.Core/Interfaces/Health/IHealthCheck.cs index 8acf796f..1555dad3 100644 --- a/src/SquidStd.Core/Interfaces/Health/IHealthCheck.cs +++ b/src/SquidStd.Core/Interfaces/Health/IHealthCheck.cs @@ -3,7 +3,7 @@ namespace SquidStd.Core.Interfaces.Health; /// -/// A single health check for one component. +/// A single health check for one component. /// public interface IHealthCheck { diff --git a/src/SquidStd.Core/Interfaces/Health/IHealthCheckService.cs b/src/SquidStd.Core/Interfaces/Health/IHealthCheckService.cs index 9da3dea7..c04b9042 100644 --- a/src/SquidStd.Core/Interfaces/Health/IHealthCheckService.cs +++ b/src/SquidStd.Core/Interfaces/Health/IHealthCheckService.cs @@ -3,7 +3,7 @@ namespace SquidStd.Core.Interfaces.Health; /// -/// Runs every registered and aggregates the results. +/// Runs every registered and aggregates the results. /// public interface IHealthCheckService { diff --git a/src/SquidStd.Core/Interfaces/Jobs/IJobSystem.cs b/src/SquidStd.Core/Interfaces/Jobs/IJobSystem.cs index 2bdd1104..79c5336e 100644 --- a/src/SquidStd.Core/Interfaces/Jobs/IJobSystem.cs +++ b/src/SquidStd.Core/Interfaces/Jobs/IJobSystem.cs @@ -1,32 +1,32 @@ namespace SquidStd.Core.Interfaces.Jobs; /// -/// Schedules work on a fixed-size pool of worker threads. +/// Schedules work on a fixed-size pool of worker threads. /// public interface IJobSystem : IDisposable { /// - /// Gets the number of worker threads. + /// Gets the number of worker threads. /// int WorkerCount { get; } /// - /// Gets the number of jobs waiting in the queue. + /// Gets the number of jobs waiting in the queue. /// int PendingCount { get; } /// - /// Gets the number of jobs currently executing. + /// Gets the number of jobs currently executing. /// int ActiveCount { get; } /// - /// Gets the number of jobs that completed since startup. + /// Gets the number of jobs that completed since startup. /// long CompletedCount { get; } /// - /// Schedules work on a worker thread. + /// Schedules work on a worker thread. /// /// Work invoked on a worker thread. /// Token used to cancel the job before it starts. @@ -34,7 +34,7 @@ public interface IJobSystem : IDisposable Task ScheduleAsync(Action work, CancellationToken cancellationToken = default); /// - /// Schedules work on a worker thread and returns the result. + /// Schedules work on a worker thread and returns the result. /// /// Work invoked on a worker thread. /// Token used to cancel the job before it starts. diff --git a/src/SquidStd.Core/Interfaces/Metrics/IMetricProvider.cs b/src/SquidStd.Core/Interfaces/Metrics/IMetricProvider.cs index a5d02ade..cd13980e 100644 --- a/src/SquidStd.Core/Interfaces/Metrics/IMetricProvider.cs +++ b/src/SquidStd.Core/Interfaces/Metrics/IMetricProvider.cs @@ -3,17 +3,17 @@ namespace SquidStd.Core.Interfaces.Metrics; /// -/// Provides metric samples for one subsystem domain. +/// Provides metric samples for one subsystem domain. /// public interface IMetricProvider { /// - /// Gets the unique provider name used as metric name prefix. + /// Gets the unique provider name used as metric name prefix. /// string ProviderName { get; } /// - /// Collects the current metric samples for this provider. + /// Collects the current metric samples for this provider. /// /// Token used to cancel collection. /// The collected metric samples. diff --git a/src/SquidStd.Core/Interfaces/Metrics/IMetricsCollectionService.cs b/src/SquidStd.Core/Interfaces/Metrics/IMetricsCollectionService.cs index c0e0989b..37aef401 100644 --- a/src/SquidStd.Core/Interfaces/Metrics/IMetricsCollectionService.cs +++ b/src/SquidStd.Core/Interfaces/Metrics/IMetricsCollectionService.cs @@ -3,24 +3,24 @@ namespace SquidStd.Core.Interfaces.Metrics; /// -/// Exposes the latest metrics snapshot collected from registered providers. +/// Exposes the latest metrics snapshot collected from registered providers. /// public interface IMetricsCollectionService { /// - /// Gets all metrics from the latest snapshot. + /// Gets all metrics from the latest snapshot. /// /// Metrics keyed by their flattened metric name. IReadOnlyDictionary GetAllMetrics(); /// - /// Gets the latest collected metrics snapshot. + /// Gets the latest collected metrics snapshot. /// /// The current metrics snapshot. MetricsSnapshot GetSnapshot(); /// - /// Gets the current metrics status. + /// Gets the current metrics status. /// /// The current metrics snapshot. MetricsSnapshot GetStatus(); diff --git a/src/SquidStd.Core/Interfaces/Scheduling/ICronScheduler.cs b/src/SquidStd.Core/Interfaces/Scheduling/ICronScheduler.cs index 255e6858..a3e6b1d5 100644 --- a/src/SquidStd.Core/Interfaces/Scheduling/ICronScheduler.cs +++ b/src/SquidStd.Core/Interfaces/Scheduling/ICronScheduler.cs @@ -3,7 +3,7 @@ namespace SquidStd.Core.Interfaces.Scheduling; /// -/// Schedules asynchronous jobs on standard 5-field cron expressions (UTC). +/// Schedules asynchronous jobs on standard 5-field cron expressions (UTC). /// public interface ICronScheduler { @@ -11,7 +11,7 @@ public interface ICronScheduler IReadOnlyCollection Jobs { get; } /// - /// Registers a cron job. + /// Registers a cron job. /// /// Logical job name. /// Standard 5-field cron expression, evaluated in UTC. diff --git a/src/SquidStd.Core/Interfaces/Secrets/ISecretProtector.cs b/src/SquidStd.Core/Interfaces/Secrets/ISecretProtector.cs index 382dea52..07fc86cb 100644 --- a/src/SquidStd.Core/Interfaces/Secrets/ISecretProtector.cs +++ b/src/SquidStd.Core/Interfaces/Secrets/ISecretProtector.cs @@ -1,19 +1,19 @@ namespace SquidStd.Core.Interfaces.Secrets; /// -/// Protects and unprotects secret payloads. +/// Protects and unprotects secret payloads. /// public interface ISecretProtector { /// - /// Protects a plaintext payload. + /// Protects a plaintext payload. /// /// Plaintext bytes to protect. /// Protected payload bytes. byte[] Protect(byte[] plaintext); /// - /// Unprotects a protected payload. + /// Unprotects a protected payload. /// /// Protected payload bytes. /// Plaintext bytes. diff --git a/src/SquidStd.Core/Interfaces/Secrets/ISecretStore.cs b/src/SquidStd.Core/Interfaces/Secrets/ISecretStore.cs index f499b937..6562762e 100644 --- a/src/SquidStd.Core/Interfaces/Secrets/ISecretStore.cs +++ b/src/SquidStd.Core/Interfaces/Secrets/ISecretStore.cs @@ -1,12 +1,12 @@ namespace SquidStd.Core.Interfaces.Secrets; /// -/// Stores encrypted secret values by logical name. +/// Stores encrypted secret values by logical name. /// public interface ISecretStore { /// - /// Deletes a secret. + /// Deletes a secret. /// /// The secret name. /// Token used to cancel the operation. @@ -14,7 +14,7 @@ public interface ISecretStore ValueTask DeleteAsync(string name, CancellationToken cancellationToken = default); /// - /// Checks whether a secret exists. + /// Checks whether a secret exists. /// /// The secret name. /// Token used to cancel the operation. @@ -22,7 +22,7 @@ public interface ISecretStore ValueTask ExistsAsync(string name, CancellationToken cancellationToken = default); /// - /// Gets a secret value. + /// Gets a secret value. /// /// The secret name. /// Token used to cancel the operation. @@ -30,7 +30,7 @@ public interface ISecretStore ValueTask GetAsync(string name, CancellationToken cancellationToken = default); /// - /// Sets a secret value. + /// Sets a secret value. /// /// The secret name. /// The secret value. @@ -38,7 +38,7 @@ public interface ISecretStore ValueTask SetAsync(string name, string value, CancellationToken cancellationToken = default); /// - /// Enumerates stored secret names, optionally filtered by prefix. + /// Enumerates stored secret names, optionally filtered by prefix. /// /// Optional name prefix; null or empty returns all names. /// Token used to cancel the enumeration. diff --git a/src/SquidStd.Core/Interfaces/Serialization/IDataDeserializer.cs b/src/SquidStd.Core/Interfaces/Serialization/IDataDeserializer.cs index c8fa8416..0c649821 100644 --- a/src/SquidStd.Core/Interfaces/Serialization/IDataDeserializer.cs +++ b/src/SquidStd.Core/Interfaces/Serialization/IDataDeserializer.cs @@ -1,7 +1,7 @@ namespace SquidStd.Core.Interfaces.Serialization; /// -/// Deserializes bytes to typed values. +/// Deserializes bytes to typed values. /// public interface IDataDeserializer { diff --git a/src/SquidStd.Core/Interfaces/Serialization/IDataSerializer.cs b/src/SquidStd.Core/Interfaces/Serialization/IDataSerializer.cs index a216e3be..6b4b140c 100644 --- a/src/SquidStd.Core/Interfaces/Serialization/IDataSerializer.cs +++ b/src/SquidStd.Core/Interfaces/Serialization/IDataSerializer.cs @@ -1,7 +1,7 @@ namespace SquidStd.Core.Interfaces.Serialization; /// -/// Serializes typed values to bytes. +/// Serializes typed values to bytes. /// public interface IDataSerializer { diff --git a/src/SquidStd.Core/Interfaces/Threading/IMainThreadDispatcher.cs b/src/SquidStd.Core/Interfaces/Threading/IMainThreadDispatcher.cs index aa9202a1..82fde106 100644 --- a/src/SquidStd.Core/Interfaces/Threading/IMainThreadDispatcher.cs +++ b/src/SquidStd.Core/Interfaces/Threading/IMainThreadDispatcher.cs @@ -1,24 +1,24 @@ namespace SquidStd.Core.Interfaces.Threading; /// -/// Queues callbacks for execution on the caller that drains the queue. +/// Queues callbacks for execution on the caller that drains the queue. /// public interface IMainThreadDispatcher { /// - /// Gets the number of callbacks waiting to be drained. + /// Gets the number of callbacks waiting to be drained. /// int PendingCount { get; } /// - /// Executes queued callbacks on the calling thread. + /// Executes queued callbacks on the calling thread. /// /// Optional wall-clock budget in milliseconds. /// The number of callbacks executed. int DrainPending(double? budgetMs = null); /// - /// Queues a callback for later execution. + /// Queues a callback for later execution. /// /// Callback to execute when the queue is drained. void Post(Action action); diff --git a/src/SquidStd.Core/Interfaces/Timing/ITimerService.cs b/src/SquidStd.Core/Interfaces/Timing/ITimerService.cs index 3e8d4a7e..41941238 100644 --- a/src/SquidStd.Core/Interfaces/Timing/ITimerService.cs +++ b/src/SquidStd.Core/Interfaces/Timing/ITimerService.cs @@ -1,12 +1,12 @@ namespace SquidStd.Core.Interfaces.Timing; /// -/// Schedules timer callbacks on a hashed timer wheel. +/// Schedules timer callbacks on a hashed timer wheel. /// public interface ITimerService { /// - /// Registers a timer. + /// Registers a timer. /// /// Logical timer name. /// Timer interval. @@ -23,26 +23,26 @@ string RegisterTimer( ); /// - /// Removes all registered timers. + /// Removes all registered timers. /// void UnregisterAllTimers(); /// - /// Removes a timer by id. + /// Removes a timer by id. /// /// Timer id to remove. /// true when a timer was removed; otherwise false. bool UnregisterTimer(string timerId); /// - /// Removes all timers with the specified name. + /// Removes all timers with the specified name. /// /// Timer name to remove. /// The number of removed timers. int UnregisterTimersByName(string name); /// - /// Advances the wheel using an absolute timestamp in milliseconds. + /// Advances the wheel using an absolute timestamp in milliseconds. /// /// Absolute monotonic timestamp in milliseconds. /// The number of processed wheel ticks. diff --git a/src/SquidStd.Core/Json/JsonContextTypeResolver.cs b/src/SquidStd.Core/Json/JsonContextTypeResolver.cs index ff0214f6..cf2cf232 100644 --- a/src/SquidStd.Core/Json/JsonContextTypeResolver.cs +++ b/src/SquidStd.Core/Json/JsonContextTypeResolver.cs @@ -5,12 +5,12 @@ namespace SquidStd.Core.Json; /// -/// Utility class to retrieve registered types from JsonSerializerContext at runtime. +/// Utility class to retrieve registered types from JsonSerializerContext at runtime. /// public static class JsonContextTypeResolver { /// - /// Gets all types registered in the specified JsonSerializerContext. + /// Gets all types registered in the specified JsonSerializerContext. /// /// The JsonSerializerContext to query. /// A collection of registered Type objects. @@ -18,10 +18,11 @@ public static IEnumerable GetRegisteredTypes(JsonSerializerContext context { // Get all JsonTypeInfo properties from the context var properties = GetContextType(context) - .GetProperties() - .Where(p => p.PropertyType.IsGenericType && - p.PropertyType.GetGenericTypeDefinition() == typeof(JsonTypeInfo<>) - ); + .GetProperties() + .Where( + p => p.PropertyType.IsGenericType && + p.PropertyType.GetGenericTypeDefinition() == typeof(JsonTypeInfo<>) + ); foreach (var property in properties) { @@ -33,19 +34,17 @@ public static IEnumerable GetRegisteredTypes(JsonSerializerContext context } /// - /// Gets all registered types that inherit from a specific base type. + /// Gets all registered types that inherit from a specific base type. /// /// The JsonSerializerContext to query. /// The base type to filter by. /// A collection of types that inherit from TBase. public static IEnumerable GetRegisteredTypes(JsonSerializerContext context) - { - return GetRegisteredTypes(context) + => GetRegisteredTypes(context) .Where(t => typeof(TBase).IsAssignableFrom(t)); - } /// - /// Gets all registered types with their corresponding JsonTypeInfo. + /// Gets all registered types with their corresponding JsonTypeInfo. /// /// The JsonSerializerContext to query. /// A dictionary mapping Type to JsonTypeInfo. @@ -54,10 +53,11 @@ public static Dictionary GetRegisteredTypesWithInfo(JsonSeri var result = new Dictionary(); var properties = GetContextType(context) - .GetProperties() - .Where(p => p.PropertyType.IsGenericType && - p.PropertyType.GetGenericTypeDefinition() == typeof(JsonTypeInfo<>) - ); + .GetProperties() + .Where( + p => p.PropertyType.IsGenericType && + p.PropertyType.GetGenericTypeDefinition() == typeof(JsonTypeInfo<>) + ); foreach (var property in properties) { @@ -74,7 +74,7 @@ public static Dictionary GetRegisteredTypesWithInfo(JsonSeri } /// - /// Gets the JsonTypeInfo for a specific type if registered. + /// Gets the JsonTypeInfo for a specific type if registered. /// /// The JsonSerializerContext to query. /// The type to get info for. @@ -90,15 +90,13 @@ public static Dictionary GetRegisteredTypesWithInfo(JsonSeri } /// - /// Checks if a specific type is registered in the context. + /// Checks if a specific type is registered in the context. /// /// The JsonSerializerContext to query. /// The type to check. /// True if the type is registered, false otherwise. public static bool IsTypeRegistered(JsonSerializerContext context, Type type) - { - return GetRegisteredTypes(context).Contains(type); - } + => GetRegisteredTypes(context).Contains(type); [UnconditionalSuppressMessage( "Trimming", @@ -107,7 +105,5 @@ public static bool IsTypeRegistered(JsonSerializerContext context, Type type) )] [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] private static Type GetContextType(JsonSerializerContext context) - { - return context.GetType(); - } + => context.GetType(); } diff --git a/src/SquidStd.Core/Json/JsonDataSerializer.cs b/src/SquidStd.Core/Json/JsonDataSerializer.cs index 3a2fd7a1..c20a7576 100644 --- a/src/SquidStd.Core/Json/JsonDataSerializer.cs +++ b/src/SquidStd.Core/Json/JsonDataSerializer.cs @@ -5,9 +5,9 @@ namespace SquidStd.Core.Json; /// -/// Default JSON data serializer based on Web defaults -/// (reflection-based, supports arbitrary types). Implements both -/// and . +/// Default JSON data serializer based on Web defaults +/// (reflection-based, supports arbitrary types). Implements both +/// and . /// public sealed class JsonDataSerializer : IDataSerializer, IDataDeserializer { @@ -15,21 +15,17 @@ public sealed class JsonDataSerializer : IDataSerializer, IDataDeserializer public JsonDataSerializer() { - _options = new JsonSerializerOptions(JsonSerializerDefaults.Web); + _options = new(JsonSerializerDefaults.Web); } - [RequiresUnreferencedCode("JSON deserialization may require types that cannot be statically analyzed.")] - [RequiresDynamicCode("JSON deserialization may require runtime code generation.")] + [RequiresUnreferencedCode("JSON deserialization may require types that cannot be statically analyzed."), + RequiresDynamicCode("JSON deserialization may require runtime code generation.")] public T Deserialize(ReadOnlyMemory data) - { - return JsonSerializer.Deserialize(data.Span, _options) ?? - throw new InvalidOperationException($"Deserialization returned null for type {typeof(T).Name}."); - } + => JsonSerializer.Deserialize(data.Span, _options) ?? + throw new InvalidOperationException($"Deserialization returned null for type {typeof(T).Name}."); - [RequiresUnreferencedCode("JSON serialization may require types that cannot be statically analyzed.")] - [RequiresDynamicCode("JSON serialization may require runtime code generation.")] + [RequiresUnreferencedCode("JSON serialization may require types that cannot be statically analyzed."), + RequiresDynamicCode("JSON serialization may require runtime code generation.")] public ReadOnlyMemory Serialize(T value) - { - return JsonSerializer.SerializeToUtf8Bytes(value, _options); - } + => JsonSerializer.SerializeToUtf8Bytes(value, _options); } diff --git a/src/SquidStd.Core/Json/JsonUtils.cs b/src/SquidStd.Core/Json/JsonUtils.cs index 93795587..847a038c 100644 --- a/src/SquidStd.Core/Json/JsonUtils.cs +++ b/src/SquidStd.Core/Json/JsonUtils.cs @@ -8,7 +8,7 @@ namespace SquidStd.Core.Json; /// -/// Provides utility methods for JSON serialization and deserialization. +/// Provides utility methods for JSON serialization and deserialization. /// public static class JsonUtils { @@ -27,7 +27,7 @@ static JsonUtils() } /// - /// Adds a JSON converter to the global converter list. Thread-safe. + /// Adds a JSON converter to the global converter list. Thread-safe. /// /// The converter to add. public static void AddJsonConverter(JsonConverter converter) @@ -47,17 +47,18 @@ public static void AddJsonConverter(JsonConverter converter) } /// - /// Deserializes a JSON string to an object using global options. + /// Deserializes a JSON string to an object using global options. /// /// The type to deserialize to. /// The JSON string to deserialize. /// Deserialized object. [RequiresUnreferencedCode( - "JSON deserialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." - )] - [RequiresDynamicCode( - "JSON deserialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." - )] + "JSON deserialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." + ), + RequiresDynamicCode( + "JSON deserialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." + )] + /// /// Deserializes a JSON string to an object using global options. /// @@ -80,7 +81,7 @@ public static void AddJsonConverter(JsonConverter converter) } /// - /// Deserializes a JSON string to an object using a JsonSerializerContext. + /// Deserializes a JSON string to an object using a JsonSerializerContext. /// /// The type to deserialize to. /// The JSON string to deserialize. @@ -105,17 +106,18 @@ public static T Deserialize(string json, JsonSerializerContext context) } /// - /// Deserializes an object from a JSON file. + /// Deserializes an object from a JSON file. /// /// The type to deserialize to. /// Path to the JSON file. /// Deserialized object. [RequiresUnreferencedCode( - "JSON deserialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." - )] - [RequiresDynamicCode( - "JSON deserialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." - )] + "JSON deserialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." + ), + RequiresDynamicCode( + "JSON deserialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." + )] + /// /// Deserializes an object from a JSON file. /// @@ -146,7 +148,7 @@ public static T DeserializeFromFile(string filePath) } /// - /// Deserializes an object from a JSON file using a JsonSerializerContext. + /// Deserializes an object from a JSON file using a JsonSerializerContext. /// /// The type to deserialize to. /// Path to the JSON file. @@ -169,8 +171,8 @@ public static T DeserializeFromFile(string filePath, JsonSerializerContext co var json = File.ReadAllText(normalizedPath); return JsonSerializer.Deserialize(json, context.GetTypeInfo(typeof(T))) is T typedResult - ? typedResult - : throw new JsonException($"Deserialization returned null for type {typeof(T).Name}"); + ? typedResult + : throw new JsonException($"Deserialization returned null for type {typeof(T).Name}"); } catch (JsonException ex) { @@ -186,18 +188,19 @@ public static T DeserializeFromFile(string filePath, JsonSerializerContext co } /// - /// Deserializes an object from a JSON file asynchronously. + /// Deserializes an object from a JSON file asynchronously. /// /// The type to deserialize to. /// Path to the JSON file. /// Cancellation token. /// Deserialized object. [RequiresUnreferencedCode( - "JSON deserialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." - )] - [RequiresDynamicCode( - "JSON deserialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." - )] + "JSON deserialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." + ), + RequiresDynamicCode( + "JSON deserialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." + )] + /// /// Deserializes an object from a JSON file asynchronously. /// @@ -229,18 +232,19 @@ public static async Task DeserializeFromFileAsync(string filePath, Cancell } /// - /// Deserializes an object from a stream asynchronously. + /// Deserializes an object from a stream asynchronously. /// /// The type to deserialize to. /// The stream containing JSON data. /// Cancellation token. /// Deserialized object. [RequiresUnreferencedCode( - "JSON deserialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." - )] - [RequiresDynamicCode( - "JSON deserialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." - )] + "JSON deserialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." + ), + RequiresDynamicCode( + "JSON deserialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." + )] + /// /// Deserializes an object from a stream asynchronously. /// @@ -255,7 +259,7 @@ public static async Task DeserializeFromStreamAsync(Stream stream, Cancell try { var result = await JsonSerializer.DeserializeAsync(stream, GetJsonSerializerOptions(), cancellationToken) - .ConfigureAwait(false); + .ConfigureAwait(false); return result ?? throw new JsonException($"Deserialization returned null for type {typeof(T).Name}"); } @@ -266,18 +270,19 @@ public static async Task DeserializeFromStreamAsync(Stream stream, Cancell } /// - /// Deserializes a JSON string to an object with fallback value. + /// Deserializes a JSON string to an object with fallback value. /// /// The type to deserialize to. /// The JSON string to deserialize. /// Default value if deserialization fails. /// Deserialized object or default value. [RequiresUnreferencedCode( - "JSON deserialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." - )] - [RequiresDynamicCode( - "JSON deserialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." - )] + "JSON deserialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." + ), + RequiresDynamicCode( + "JSON deserialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." + )] + /// /// Deserializes a JSON string to an object with fallback value. /// @@ -303,7 +308,7 @@ public static async Task DeserializeFromStreamAsync(Stream stream, Cancell } /// - /// Gets a read-only view of the current JSON converters. + /// Gets a read-only view of the current JSON converters. /// /// A read-only list of JSON converters. public static IReadOnlyList GetJsonConverters() @@ -316,15 +321,13 @@ public static IReadOnlyList GetJsonConverters() } /// - /// Gets the current JSON serializer options. Thread-safe. + /// Gets the current JSON serializer options. Thread-safe. /// public static JsonSerializerOptions GetJsonSerializerOptions() - { - return _jsonSerializerOptions ?? throw new InvalidOperationException("JsonSerializerOptions not initialized"); - } + => _jsonSerializerOptions ?? throw new InvalidOperationException("JsonSerializerOptions not initialized"); /// - /// Gets cached JSON serializer options combined with a context resolver. Thread-safe. + /// Gets cached JSON serializer options combined with a context resolver. Thread-safe. /// public static JsonSerializerOptions GetJsonSerializerOptions(JsonSerializerContext context) { @@ -336,7 +339,7 @@ public static JsonSerializerOptions GetJsonSerializerOptions(JsonSerializerConte { var baseOptions = GetJsonSerializerOptions(); - return new JsonSerializerOptions(baseOptions) + return new(baseOptions) { TypeInfoResolver = JsonTypeInfoResolver.Combine(context, baseOptions.TypeInfoResolver) }; @@ -345,7 +348,7 @@ public static JsonSerializerOptions GetJsonSerializerOptions(JsonSerializerConte } /// - /// Generates a schema file name for the given type using snake_case convention. + /// Generates a schema file name for the given type using snake_case convention. /// /// The type to generate a schema name for. /// A schema file name in the format "type_name.schema.json". @@ -368,7 +371,7 @@ public static string GetSchemaFileName(Type type) } /// - /// Determines if a JSON string represents an array. + /// Determines if a JSON string represents an array. /// /// The JSON string to analyze. /// True if the JSON represents an array, false otherwise. @@ -392,7 +395,7 @@ public static bool IsArray(string json) } /// - /// Determines if a JSON file contains an array. + /// Determines if a JSON file contains an array. /// /// Path to the JSON file to analyze. /// True if the JSON file contains an array, false otherwise. @@ -420,7 +423,7 @@ public static bool IsArrayFile(string filePath) } /// - /// Validates if a string is valid JSON without deserializing. + /// Validates if a string is valid JSON without deserializing. /// /// The JSON string to validate. /// True if valid JSON, false otherwise. @@ -444,7 +447,7 @@ public static bool IsValidJson(string json) } /// - /// Registers a JSON serializer context for source generation. Thread-safe. + /// Registers a JSON serializer context for source generation. Thread-safe. /// /// The context to register. public static void RegisterJsonContext(JsonSerializerContext context) @@ -456,7 +459,7 @@ public static void RegisterJsonContext(JsonSerializerContext context) } /// - /// Removes all converters of the specified type. Thread-safe. + /// Removes all converters of the specified type. Thread-safe. /// /// The converter type to remove. /// True if any converters were removed. @@ -494,17 +497,18 @@ public static bool RemoveJsonConverter() where T : JsonConverter } /// - /// Serializes an object to JSON string using global options. + /// Serializes an object to JSON string using global options. /// /// The type to serialize. /// The object to serialize. /// JSON string representation. [RequiresUnreferencedCode( - "JSON serialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." - )] - [RequiresDynamicCode( - "JSON serialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." - )] + "JSON serialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." + ), + RequiresDynamicCode( + "JSON serialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." + )] + /// /// Serializes an object to JSON string using global options. /// @@ -526,18 +530,19 @@ public static string Serialize(T obj) } /// - /// Serializes an object to JSON string using custom options. + /// Serializes an object to JSON string using custom options. /// /// The type to serialize. /// The object to serialize. /// Custom serialization options. /// JSON string representation. [RequiresUnreferencedCode( - "JSON serialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." - )] - [RequiresDynamicCode( - "JSON serialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." - )] + "JSON serialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." + ), + RequiresDynamicCode( + "JSON serialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." + )] + /// /// Serializes an object to JSON string using custom options. /// @@ -561,17 +566,18 @@ public static string Serialize(T obj, JsonSerializerOptions options) } /// - /// Serializes multiple objects to JSON files in a directory. + /// Serializes multiple objects to JSON files in a directory. /// /// The type to serialize. /// Dictionary of filename to object mappings. /// Target directory path. [RequiresUnreferencedCode( - "JSON serialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." - )] - [RequiresDynamicCode( - "JSON serialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." - )] + "JSON serialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." + ), + RequiresDynamicCode( + "JSON serialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." + )] + /// /// Serializes multiple objects to JSON files in a directory. /// @@ -604,17 +610,18 @@ public static void SerializeMultipleToDirectory(Dictionary objects } /// - /// Serializes an object to a JSON file with directory creation. + /// Serializes an object to a JSON file with directory creation. /// /// The type to serialize. /// The object to serialize. /// Path to the output JSON file. [RequiresUnreferencedCode( - "JSON serialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." - )] - [RequiresDynamicCode( - "JSON serialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." - )] + "JSON serialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." + ), + RequiresDynamicCode( + "JSON serialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." + )] + /// /// Serializes an object to a JSON file with directory creation. /// @@ -646,18 +653,19 @@ public static void SerializeToFile(T obj, string filePath) } /// - /// Serializes an object to a JSON file asynchronously with directory creation. + /// Serializes an object to a JSON file asynchronously with directory creation. /// /// The type to serialize. /// The object to serialize. /// Path to the output JSON file. /// Cancellation token. [RequiresUnreferencedCode( - "JSON serialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." - )] - [RequiresDynamicCode( - "JSON serialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." - )] + "JSON serialization may require types that cannot be statically analyzed. Use overload with JsonSerializerContext when possible." + ), + RequiresDynamicCode( + "JSON serialization may require dynamic code generation. Use overload with JsonSerializerContext when possible." + )] + /// /// Serializes an object to a JSON file asynchronously with directory creation. /// diff --git a/src/SquidStd.Core/Logging/EventSink.cs b/src/SquidStd.Core/Logging/EventSink.cs index ae2b57ec..0e328a1b 100644 --- a/src/SquidStd.Core/Logging/EventSink.cs +++ b/src/SquidStd.Core/Logging/EventSink.cs @@ -4,13 +4,13 @@ namespace SquidStd.Core.Logging; /// -/// A Serilog sink that raises events when logs are received. -/// Subscribe to to receive log events. +/// A Serilog sink that raises events when logs are received. +/// Subscribe to to receive log events. /// public class EventSink : ILogEventSink { /// - /// Emits a log event to all subscribers. + /// Emits a log event to all subscribers. /// /// The log event to emit. public void Emit(LogEvent logEvent) @@ -60,16 +60,14 @@ public void Emit(LogEvent logEvent) } /// - /// Clears all event subscribers. - /// Useful for cleanup or testing. + /// Clears all event subscribers. + /// Useful for cleanup or testing. /// public static void ClearSubscribers() - { - OnLogReceived = null; - } + => OnLogReceived = null; /// - /// Event raised when a log event is received. + /// Event raised when a log event is received. /// public static event EventHandler? OnLogReceived; } diff --git a/src/SquidStd.Core/Logging/EventSinkExtensions.cs b/src/SquidStd.Core/Logging/EventSinkExtensions.cs index fbdc1cf5..b89f8244 100644 --- a/src/SquidStd.Core/Logging/EventSinkExtensions.cs +++ b/src/SquidStd.Core/Logging/EventSinkExtensions.cs @@ -5,13 +5,13 @@ namespace SquidStd.Core.Logging; /// -/// Extension methods for configuring the EventSink. +/// Extension methods for configuring the EventSink. /// public static class EventSinkExtensions { /// - /// Adds the EventSink to the Serilog pipeline. - /// Subscribe to to receive log events. + /// Adds the EventSink to the Serilog pipeline. + /// Subscribe to to receive log events. /// /// The logger sink configuration. /// The minimum log level to capture. Defaults to Verbose (all logs). @@ -20,7 +20,5 @@ public static LoggerConfiguration EventSink( this LoggerSinkConfiguration sinkConfiguration, LogEventLevel restrictedToMinimumLevel = LogEventLevel.Verbose ) - { - return sinkConfiguration.Sink(new EventSink(), restrictedToMinimumLevel); - } + => sinkConfiguration.Sink(new EventSink(), restrictedToMinimumLevel); } diff --git a/src/SquidStd.Core/Logging/LogEventData.cs b/src/SquidStd.Core/Logging/LogEventData.cs index 57d92a5f..97c25271 100644 --- a/src/SquidStd.Core/Logging/LogEventData.cs +++ b/src/SquidStd.Core/Logging/LogEventData.cs @@ -3,37 +3,37 @@ namespace SquidStd.Core.Logging; /// -/// Contains data for a log event. +/// Contains data for a log event. /// public class LogEventData { /// - /// Gets the log level. + /// Gets the log level. /// public LogEventLevel Level { get; init; } /// - /// Gets the timestamp of the log event. + /// Gets the timestamp of the log event. /// public DateTimeOffset Timestamp { get; init; } /// - /// Gets the formatted log message. + /// Gets the formatted log message. /// public string Message { get; init; } = string.Empty; /// - /// Gets the exception associated with the log event, if any. + /// Gets the exception associated with the log event, if any. /// public Exception? Exception { get; init; } /// - /// Gets the properties associated with the log event. + /// Gets the properties associated with the log event. /// public IReadOnlyDictionary Properties { get; init; } = new Dictionary(); /// - /// Gets the source context (usually the logger name/class). + /// Gets the source context (usually the logger name/class). /// public string? SourceContext { get; init; } } diff --git a/src/SquidStd.Core/Pool/ObjectPool.cs b/src/SquidStd.Core/Pool/ObjectPool.cs index 8ad71859..9a4db3a6 100644 --- a/src/SquidStd.Core/Pool/ObjectPool.cs +++ b/src/SquidStd.Core/Pool/ObjectPool.cs @@ -3,10 +3,10 @@ namespace SquidStd.Core.Pool; /// -/// Thread-safe, non-blocking object pool. reuses a retained instance or creates a new -/// one through the factory; stocks the instance back (up to a bound), optionally -/// resetting it first. Instances dropped over the bound, and those still pooled on dispose, are disposed -/// when implements . +/// Thread-safe, non-blocking object pool. reuses a retained instance or creates a new +/// one through the factory; stocks the instance back (up to a bound), optionally +/// resetting it first. Instances dropped over the bound, and those still pooled on dispose, are disposed +/// when implements . /// /// The pooled reference type. public sealed class ObjectPool : IDisposable @@ -20,12 +20,12 @@ public sealed class ObjectPool : IDisposable private bool _disposed; /// - /// Gets the number of instances currently retained for reuse. + /// Gets the number of instances currently retained for reuse. /// public int Count => Volatile.Read(ref _retained); /// - /// Initializes the pool. + /// Initializes the pool. /// /// Creates a new instance when the pool is empty. /// Maximum number of instances kept for reuse. Defaults to 1024. @@ -45,7 +45,7 @@ public ObjectPool(Func factory, int maxRetained = 1024, Action? onReturn = } /// - /// Rents an instance from the pool, creating one through the factory when the pool is empty. + /// Rents an instance from the pool, creating one through the factory when the pool is empty. /// /// A pooled or freshly created instance. public T Get() @@ -61,7 +61,7 @@ public T Get() } /// - /// Returns an instance to the pool. Instances beyond the retained bound are disposed instead of kept. + /// Returns an instance to the pool. Instances beyond the retained bound are disposed instead of kept. /// /// The instance to return. public void Return(T item) @@ -82,7 +82,7 @@ public void Return(T item) } /// - /// Disposes every retained instance that implements . + /// Disposes every retained instance that implements . /// public void Dispose() { diff --git a/src/SquidStd.Core/README.md b/src/SquidStd.Core/README.md index 356350ad..0a16950c 100644 --- a/src/SquidStd.Core/README.md +++ b/src/SquidStd.Core/README.md @@ -49,18 +49,18 @@ pool.Return(builder); ## Key types -| Type | Purpose | -|-------------------------|-----------------------------------------------| -| `IConfigEntry` | A registrable YAML configuration section. | -| `IConfigManagerService` | Loads YAML config and exposes typed sections. | -| `IEventBus` | Publish/subscribe in-process event bus. | -| `IJobSystem` | Background job scheduling/execution. | -| `ITimerService` | Timer-wheel based scheduling. | -| `IMetricProvider` | Source of metric samples for collection. | -| `IStorageService` | File/object storage abstraction. | -| `IFileWatcherService` | Recursive, debounced file watcher publishing to the event bus. | -| `ObjectPool` | Thread-safe, non-blocking object pool. | -| `ICommandDispatcher` | Typed protocol command dispatch with context. | +| Type | Purpose | +|--------------------------------|----------------------------------------------------------------| +| `IConfigEntry` | A registrable YAML configuration section. | +| `IConfigManagerService` | Loads YAML config and exposes typed sections. | +| `IEventBus` | Publish/subscribe in-process event bus. | +| `IJobSystem` | Background job scheduling/execution. | +| `ITimerService` | Timer-wheel based scheduling. | +| `IMetricProvider` | Source of metric samples for collection. | +| `IStorageService` | File/object storage abstraction. | +| `IFileWatcherService` | Recursive, debounced file watcher publishing to the event bus. | +| `ObjectPool` | Thread-safe, non-blocking object pool. | +| `ICommandDispatcher` | Typed protocol command dispatch with context. | ## Related diff --git a/src/SquidStd.Core/SquidStd.Core.csproj b/src/SquidStd.Core/SquidStd.Core.csproj index ed893826..33720bd9 100644 --- a/src/SquidStd.Core/SquidStd.Core.csproj +++ b/src/SquidStd.Core/SquidStd.Core.csproj @@ -15,7 +15,7 @@ all runtime; build; native; contentfiles; analyzers - + diff --git a/src/SquidStd.Core/Types/Files/FileChangeKind.cs b/src/SquidStd.Core/Types/Files/FileChangeKind.cs index 256da868..fc24c5f8 100644 --- a/src/SquidStd.Core/Types/Files/FileChangeKind.cs +++ b/src/SquidStd.Core/Types/Files/FileChangeKind.cs @@ -1,7 +1,7 @@ namespace SquidStd.Core.Types.Files; /// -/// The kind of change observed on a watched file. +/// The kind of change observed on a watched file. /// public enum FileChangeKind { diff --git a/src/SquidStd.Core/Types/Health/HealthStatus.cs b/src/SquidStd.Core/Types/Health/HealthStatus.cs index 9dc66aed..d005a10e 100644 --- a/src/SquidStd.Core/Types/Health/HealthStatus.cs +++ b/src/SquidStd.Core/Types/Health/HealthStatus.cs @@ -1,7 +1,7 @@ namespace SquidStd.Core.Types.Health; /// -/// Overall health state of a check or report. +/// Overall health state of a check or report. /// public enum HealthStatus { diff --git a/src/SquidStd.Core/Types/LogLevelType.cs b/src/SquidStd.Core/Types/LogLevelType.cs index 6133c86c..43ef7f77 100644 --- a/src/SquidStd.Core/Types/LogLevelType.cs +++ b/src/SquidStd.Core/Types/LogLevelType.cs @@ -1,42 +1,42 @@ namespace SquidStd.Core.Types; /// -/// public enum LogLevelType : byte. +/// public enum LogLevelType : byte. /// public enum LogLevelType : byte { /// - /// No logging. + /// No logging. /// None = 0, /// - /// Trace level logging. + /// Trace level logging. /// Trace = 1, /// - /// Debug level logging. + /// Debug level logging. /// Debug = 2, /// - /// Information level logging. + /// Information level logging. /// Information = 3, /// - /// Warning level logging. + /// Warning level logging. /// Warning = 4, /// - /// Error level logging. + /// Error level logging. /// Error = 5, /// - /// Critical level logging. + /// Critical level logging. /// Critical = 6 } diff --git a/src/SquidStd.Core/Types/Metrics/MetricType.cs b/src/SquidStd.Core/Types/Metrics/MetricType.cs index 6202e72a..f59560ff 100644 --- a/src/SquidStd.Core/Types/Metrics/MetricType.cs +++ b/src/SquidStd.Core/Types/Metrics/MetricType.cs @@ -1,22 +1,22 @@ namespace SquidStd.Core.Types.Metrics; /// -/// Defines the semantic type of a metric sample. +/// Defines the semantic type of a metric sample. /// public enum MetricType { /// - /// A value that can go up or down. + /// A value that can go up or down. /// Gauge, /// - /// A cumulative value that only increases. + /// A cumulative value that only increases. /// Counter, /// - /// A value that represents a distribution bucket or aggregate. + /// A value that represents a distribution bucket or aggregate. /// Histogram } diff --git a/src/SquidStd.Core/Types/PlatformType.cs b/src/SquidStd.Core/Types/PlatformType.cs index 56571088..21f3f66c 100644 --- a/src/SquidStd.Core/Types/PlatformType.cs +++ b/src/SquidStd.Core/Types/PlatformType.cs @@ -1,7 +1,7 @@ namespace SquidStd.Core.Types; /// -/// Enumerates the supported platform types. +/// Enumerates the supported platform types. /// public enum PlatformType : byte { diff --git a/src/SquidStd.Core/Types/SquidStdLogRollingIntervalType.cs b/src/SquidStd.Core/Types/SquidStdLogRollingIntervalType.cs index 7584213a..9aa4830c 100644 --- a/src/SquidStd.Core/Types/SquidStdLogRollingIntervalType.cs +++ b/src/SquidStd.Core/Types/SquidStdLogRollingIntervalType.cs @@ -1,37 +1,37 @@ namespace SquidStd.Core.Types; /// -/// Defines file log rolling intervals. +/// Defines file log rolling intervals. /// public enum SquidStdLogRollingIntervalType { /// - /// Does not roll log files automatically. + /// Does not roll log files automatically. /// Infinite = 0, /// - /// Rolls log files every year. + /// Rolls log files every year. /// Year = 1, /// - /// Rolls log files every month. + /// Rolls log files every month. /// Month = 2, /// - /// Rolls log files every day. + /// Rolls log files every day. /// Day = 3, /// - /// Rolls log files every hour. + /// Rolls log files every hour. /// Hour = 4, /// - /// Rolls log files every minute. + /// Rolls log files every minute. /// Minute = 5 } diff --git a/src/SquidStd.Core/Utils/BuiltInRng.cs b/src/SquidStd.Core/Utils/BuiltInRng.cs index ad4d0580..7de1ccbf 100644 --- a/src/SquidStd.Core/Utils/BuiltInRng.cs +++ b/src/SquidStd.Core/Utils/BuiltInRng.cs @@ -3,8 +3,8 @@ namespace SquidStd.Core.Utils; /// -/// Ambient pseudo-random generator. Call with a fixed seed for reproducible -/// sequences (useful for deterministic simulations and game logic). +/// Ambient pseudo-random generator. Call with a fixed seed for reproducible +/// sequences (useful for deterministic simulations and game logic). /// public static class BuiltInRng { @@ -13,77 +13,57 @@ public static class BuiltInRng /// Replaces the generator with a new, non-deterministically seeded instance. public static void Reset() - { - Generator = new Random(); - } + => Generator = new(); /// Replaces the generator with one seeded for reproducible sequences. /// The seed value. public static void Reset(int seed) - { - Generator = new Random(seed); - } + => Generator = new(seed); /// Returns a non-negative random integer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Next() - { - return Generator.Next(); - } + => Generator.Next(); /// Returns a non-negative random integer below . /// Exclusive upper bound. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Next(int maxValue) - { - return Generator.Next(maxValue); - } + => Generator.Next(maxValue); /// Returns a random integer in [minValue, minValue + count). /// Inclusive lower bound. /// Number of distinct values. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Next(int minValue, int count) - { - return minValue + Generator.Next(count); - } + => minValue + Generator.Next(count); /// Returns a non-negative random long below . /// Exclusive upper bound. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Next(long maxValue) - { - return Generator.NextInt64(maxValue); - } + => Generator.NextInt64(maxValue); /// Returns a random long in [minValue, minValue + count). /// Inclusive lower bound. /// Number of distinct values. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Next(long minValue, long count) - { - return minValue + Generator.NextInt64(count); - } + => minValue + Generator.NextInt64(count); /// Returns a non-negative random long. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long NextLong() - { - return Generator.NextInt64(); - } + => Generator.NextInt64(); /// Returns a random double in [0, 1). [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double NextDouble() - { - return Generator.NextDouble(); - } + => Generator.NextDouble(); /// Fills the buffer with random bytes. /// The buffer to fill. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NextBytes(Span buffer) - { - Generator.NextBytes(buffer); - } + => Generator.NextBytes(buffer); } diff --git a/src/SquidStd.Core/Utils/CryptoUtils.cs b/src/SquidStd.Core/Utils/CryptoUtils.cs index 431faa5c..7c78ea7d 100644 --- a/src/SquidStd.Core/Utils/CryptoUtils.cs +++ b/src/SquidStd.Core/Utils/CryptoUtils.cs @@ -4,8 +4,8 @@ namespace SquidStd.Core.Utils; /// -/// Authenticated symmetric encryption helpers built on AES-GCM. Produced payloads are laid out as -/// nonce (12 bytes) | tag (16 bytes) | ciphertext. +/// Authenticated symmetric encryption helpers built on AES-GCM. Produced payloads are laid out as +/// nonce (12 bytes) | tag (16 bytes) | ciphertext. /// public static class CryptoUtils { @@ -13,7 +13,7 @@ public static class CryptoUtils private const int TagSize = 16; /// - /// Generates a random symmetric key and returns it as a base64 string. + /// Generates a random symmetric key and returns it as a base64 string. /// /// Key length in bytes; must be 16, 24, or 32. /// The base64-encoded key. @@ -28,7 +28,7 @@ public static string GenerateKey(int sizeInBytes = 32) } /// - /// Encrypts a UTF-8 string with AES-GCM under the supplied key. + /// Encrypts a UTF-8 string with AES-GCM under the supplied key. /// /// The text to encrypt. /// The 16, 24, or 32 byte key. @@ -55,7 +55,7 @@ public static byte[] Encrypt(string plaintext, byte[] key) } /// - /// Decrypts a payload produced by back into its UTF-8 string. + /// Decrypts a payload produced by back into its UTF-8 string. /// /// The nonce | tag | ciphertext payload. /// The key used to encrypt the payload. diff --git a/src/SquidStd.Core/Utils/DirectoriesUtils.cs b/src/SquidStd.Core/Utils/DirectoriesUtils.cs index ffd8612b..7fd8e34a 100644 --- a/src/SquidStd.Core/Utils/DirectoriesUtils.cs +++ b/src/SquidStd.Core/Utils/DirectoriesUtils.cs @@ -1,23 +1,21 @@ namespace SquidStd.Core.Utils; /// -/// Utility methods for working with directories and file system operations +/// Utility methods for working with directories and file system operations /// public class DirectoriesUtils { /// - /// Gets files from the specified path recursively with optional extension filtering + /// Gets files from the specified path recursively with optional extension filtering /// /// Directory path to search /// File extensions to filter by (e.g., "*.txt", "*.json") /// Array of file paths matching the criteria public static string[] GetFiles(string path, params string[] extensions) - { - return GetFiles(path, true, extensions); - } + => GetFiles(path, true, extensions); /// - /// Gets files from the specified path with configurable recursion and extension filtering + /// Gets files from the specified path with configurable recursion and extension filtering /// /// Directory path to search /// Whether to search subdirectories recursively diff --git a/src/SquidStd.Core/Utils/HashUtils.cs b/src/SquidStd.Core/Utils/HashUtils.cs index 786a1215..7c63ae4e 100644 --- a/src/SquidStd.Core/Utils/HashUtils.cs +++ b/src/SquidStd.Core/Utils/HashUtils.cs @@ -4,7 +4,7 @@ namespace SquidStd.Core.Utils; /// -/// Provides password hashing and verification helpers using PBKDF2-SHA256. +/// Provides password hashing and verification helpers using PBKDF2-SHA256. /// public static class HashUtils { @@ -14,7 +14,7 @@ public static class HashUtils private const int DefaultSaltSize = 16; /// - /// Hashes a password using PBKDF2-SHA256 and returns a serialized payload. + /// Hashes a password using PBKDF2-SHA256 and returns a serialized payload. /// /// Plain password. /// Serialized hash payload. @@ -41,7 +41,7 @@ public static string HashPassword(string password) } /// - /// Verifies a plain password against a serialized PBKDF2-SHA256 payload. + /// Verifies a plain password against a serialized PBKDF2-SHA256 payload. /// /// Plain password. /// Serialized hash payload. diff --git a/src/SquidStd.Core/Utils/NetworkUtils.cs b/src/SquidStd.Core/Utils/NetworkUtils.cs index 7d0258b5..e32c695e 100644 --- a/src/SquidStd.Core/Utils/NetworkUtils.cs +++ b/src/SquidStd.Core/Utils/NetworkUtils.cs @@ -4,12 +4,12 @@ namespace SquidStd.Core.Utils; /// -/// Utility methods for network configuration parsing. +/// Utility methods for network configuration parsing. /// public static class NetworkUtils { /// - /// Enumerates local unicast endpoints matching the supplied endpoint address family. + /// Enumerates local unicast endpoints matching the supplied endpoint address family. /// /// The template endpoint supplying address family and port. /// The matching local endpoints. @@ -18,16 +18,17 @@ public static IEnumerable GetListeningAddresses(IPEndPoint endPoint) ArgumentNullException.ThrowIfNull(endPoint); return NetworkInterface.GetAllNetworkInterfaces() - .SelectMany(adapter => - adapter.GetIPProperties() - .UnicastAddresses - .Where(unicast => endPoint.AddressFamily == unicast.Address.AddressFamily) - .Select(unicast => new IPEndPoint(unicast.Address, endPoint.Port)) - ); + .SelectMany( + adapter => + adapter.GetIPProperties() + .UnicastAddresses + .Where(unicast => endPoint.AddressFamily == unicast.Address.AddressFamily) + .Select(unicast => new IPEndPoint(unicast.Address, endPoint.Port)) + ); } /// - /// Parses an IP address, treating "*" as every IPv4 interface. + /// Parses an IP address, treating "*" as every IPv4 interface. /// /// The IP address or "*". /// The parsed IP address. @@ -39,7 +40,7 @@ public static IPAddress ParseIpAddress(string ipAddress) } /// - /// Parses a comma-separated port list with optional ranges. + /// Parses a comma-separated port list with optional ranges. /// /// The ports string, such as "6666-6668,6669,8000". /// The parsed ports. diff --git a/src/SquidStd.Core/Utils/PlatformUtils.cs b/src/SquidStd.Core/Utils/PlatformUtils.cs index 2debaa05..29c7583c 100644 --- a/src/SquidStd.Core/Utils/PlatformUtils.cs +++ b/src/SquidStd.Core/Utils/PlatformUtils.cs @@ -3,12 +3,12 @@ namespace SquidStd.Core.Utils; /// -/// Provides utilities for detecting the current platform. +/// Provides utilities for detecting the current platform. /// public static class PlatformUtils { /// - /// Gets the current platform type. + /// Gets the current platform type. /// /// The detected platform type. public static PlatformType GetCurrentPlatform() @@ -27,29 +27,23 @@ public static PlatformType GetCurrentPlatform() } /// - /// Checks if the application is running on Linux. + /// Checks if the application is running on Linux. /// /// True if running on Linux, otherwise false. public static bool IsRunningOnLinux() - { - return OperatingSystem.IsLinux(); - } + => OperatingSystem.IsLinux(); /// - /// Checks if the application is running on macOS. + /// Checks if the application is running on macOS. /// /// True if running on macOS, otherwise false. public static bool IsRunningOnMacOS() - { - return OperatingSystem.IsMacOS(); - } + => OperatingSystem.IsMacOS(); /// - /// Checks if the application is running on Windows. + /// Checks if the application is running on Windows. /// /// True if running on Windows, otherwise false. public static bool IsRunningOnWindows() - { - return OperatingSystem.IsWindows(); - } + => OperatingSystem.IsWindows(); } diff --git a/src/SquidStd.Core/Utils/RandomUtils.cs b/src/SquidStd.Core/Utils/RandomUtils.cs index db77417c..c2e63eff 100644 --- a/src/SquidStd.Core/Utils/RandomUtils.cs +++ b/src/SquidStd.Core/Utils/RandomUtils.cs @@ -4,7 +4,7 @@ namespace SquidStd.Core.Utils; /// -/// Random value helpers built on , including dice and coin-flip mechanics. +/// Random value helpers built on , including dice and coin-flip mechanics. /// public static class RandomUtils { @@ -13,53 +13,41 @@ public static class RandomUtils /// Number of distinct values. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Random(int from, int count) - { - return BuiltInRng.Next(from, count); - } + => BuiltInRng.Next(from, count); /// Returns a random integer below (sign-preserving). /// Exclusive bound; negative values mirror the range. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Random(int count) - { - return count < 0 ? -BuiltInRng.Next(-count) : BuiltInRng.Next(count); - } + => count < 0 ? -BuiltInRng.Next(-count) : BuiltInRng.Next(count); /// Returns a random long in [from, from + count). /// Inclusive lower bound. /// Number of distinct values. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Random(long from, long count) - { - return BuiltInRng.Next(from, count); - } + => BuiltInRng.Next(from, count); /// Returns a random long below (sign-preserving). /// Exclusive bound; negative values mirror the range. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Random(long count) - { - return count < 0 ? -BuiltInRng.Next(-count) : BuiltInRng.Next(count); - } + => count < 0 ? -BuiltInRng.Next(-count) : BuiltInRng.Next(count); /// Fills the buffer with random bytes. /// The buffer to fill. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void RandomBytes(Span buffer) - { - BuiltInRng.NextBytes(buffer); - } + => BuiltInRng.NextBytes(buffer); /// Returns a random double in [0, 1). [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double RandomDouble() - { - return BuiltInRng.NextDouble(); - } + => BuiltInRng.NextDouble(); /// - /// Counts heads across coin flips, stopping early once - /// heads are reached. + /// Counts heads across coin flips, stopping early once + /// heads are reached. /// /// Number of coins to flip. /// Cap on the number of heads to count. @@ -71,8 +59,8 @@ public static int CoinFlips(int amount, int maximum) while (amount > 0) { var num = amount >= 62 - ? (ulong)BuiltInRng.NextLong() - : (ulong)BuiltInRng.Next(1L << amount); + ? (ulong)BuiltInRng.NextLong() + : (ulong)BuiltInRng.Next(1L << amount); heads += BitOperations.PopCount(num); @@ -97,8 +85,8 @@ public static int CoinFlips(int amount) while (amount > 0) { var num = amount >= 62 - ? (ulong)BuiltInRng.NextLong() - : (ulong)BuiltInRng.Next(1L << amount); + ? (ulong)BuiltInRng.NextLong() + : (ulong)BuiltInRng.Next(1L << amount); heads += BitOperations.PopCount(num); diff --git a/src/SquidStd.Core/Utils/ResourceUtils.cs b/src/SquidStd.Core/Utils/ResourceUtils.cs index 55fb52f8..2559ba47 100644 --- a/src/SquidStd.Core/Utils/ResourceUtils.cs +++ b/src/SquidStd.Core/Utils/ResourceUtils.cs @@ -3,12 +3,12 @@ namespace SquidStd.Core.Utils; /// -/// Provides utilities for working with embedded resources. +/// Provides utilities for working with embedded resources. /// public static class ResourceUtils { /// - /// Converts a resource name to a file path format. + /// Converts a resource name to a file path format. /// /// The resource name to convert. /// The base namespace to remove. @@ -38,7 +38,7 @@ public static string ConvertResourceNameToPath(string resourceName, string baseN } /// - /// Copies all embedded resources from an assembly to a destination directory + /// Copies all embedded resources from an assembly to a destination directory /// /// The assembly containing the embedded resources /// The directory where resources will be copied @@ -72,7 +72,7 @@ public static void CopyEmbeddedToDirectory(Assembly assembly, string destination } /// - /// Converts an embedded resource name to a file path format + /// Converts an embedded resource name to a file path format /// /// The full embedded resource name /// The assembly prefix to remove from the resource name @@ -88,7 +88,7 @@ public static string EmbeddedNameToPath(string resourceName, string assemblyPref } /// - /// Converts an embedded resource name to a directory path structure + /// Converts an embedded resource name to a directory path structure /// /// The embedded resource name (e.g., "Assets.Fonts.DefaultUiFont.ttf") /// Optional base namespace to remove from the beginning @@ -128,7 +128,7 @@ public static string GetDirectoryPathFromResourceName(string resourceName, strin } /// - /// Gets an embedded resource as a byte array wrapped in Memory + /// Gets an embedded resource as a byte array wrapped in Memory /// /// The assembly containing the resource /// The full resource name @@ -145,7 +145,8 @@ public static Memory GetEmbeddedResourceByteArray(Assembly assembly, strin { // Try to find a partial match var resourceNames = assembly.GetManifestResourceNames(); - var matchingResource = resourceNames.FirstOrDefault(n => n.EndsWith( + var matchingResource = resourceNames.FirstOrDefault( + n => n.EndsWith( resourceName.Replace('/', '.').Replace('\\', '.'), StringComparison.Ordinal ) @@ -167,12 +168,12 @@ public static Memory GetEmbeddedResourceByteArray(Assembly assembly, strin using var memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); - return new Memory(memoryStream.ToArray()); + return new(memoryStream.ToArray()); } } /// - /// Reads the content of an embedded resource as a byte array + /// Reads the content of an embedded resource as a byte array /// /// Resource path (e.g. "Assets/Templates/welcome.scriban") /// The assembly to search in (if null, uses current assembly) @@ -220,7 +221,7 @@ public static byte[] GetEmbeddedResourceContent(string resourcePath, Assembly as } /// - /// Gets a list of all files in a specific embedded directory + /// Gets a list of all files in a specific embedded directory /// /// The assembly to search in (if null, uses current assembly) /// Directory path to search (e.g. "Assets/Templates") @@ -255,7 +256,7 @@ public static List GetEmbeddedResourceFileNames( } /// - /// Gets a list of all embedded resources that match a given pattern + /// Gets a list of all embedded resources that match a given pattern /// /// The assembly to search in (if null, uses current assembly) /// Directory path to search (e.g. "Assets.Templates") @@ -288,19 +289,17 @@ public static string[] GetEmbeddedResourceNames(Assembly assembly = null, string } /// - /// Gets a stream for an embedded resource, inferring the assembly from . + /// Gets a stream for an embedded resource, inferring the assembly from . /// /// Any type defined in the target assembly. /// The full resource name or a path-style suffix. /// A stream for the resource. /// Thrown when the resource cannot be found. public static Stream GetEmbeddedResourceStream(string resourceName) - { - return GetEmbeddedResourceStream(typeof(TClass).Assembly, resourceName); - } + => GetEmbeddedResourceStream(typeof(TClass).Assembly, resourceName); /// - /// Gets a stream for an embedded resource. + /// Gets a stream for an embedded resource. /// /// The assembly containing the resource. /// The full resource name. @@ -317,7 +316,8 @@ public static Stream GetEmbeddedResourceStream(Assembly assembly, string resourc { // Try to find a partial match var resourceNames = assembly.GetManifestResourceNames(); - var matchingResource = resourceNames.FirstOrDefault(n => n.EndsWith( + var matchingResource = resourceNames.FirstOrDefault( + n => n.EndsWith( resourceName.Replace('/', '.').Replace('\\', '.'), StringComparison.Ordinal ) @@ -350,8 +350,8 @@ public static string GetEmbeddedResourceString(Assembly assembly, string resourc } /// - /// Converts an embedded resource name to a proper file name by extracting the last part after the final dot - /// and treating everything before it as directory structure + /// Converts an embedded resource name to a proper file name by extracting the last part after the final dot + /// and treating everything before it as directory structure /// /// The embedded resource name (e.g., "Assets.Fonts.DefaultUiFont.ttf") /// The file name with extension (e.g., "DefaultUiFont.ttf") @@ -380,7 +380,7 @@ public static string GetFileNameFromResourceName(string resourceName) } /// - /// Extracts the file name from an embedded resource path + /// Extracts the file name from an embedded resource path /// /// Full resource name /// File name without path @@ -395,23 +395,23 @@ public static string GetFileNameFromResourcePath(string resourceName) } /// - /// Reads the content of an embedded resource as a string. + /// Reads the content of an embedded resource as a string. /// /// The name of the resource to read. /// The assembly containing the resource. /// The content of the resource as a string. /// Thrown when the resource cannot be found in the specified assembly. /// - /// This method handles resource names that may contain either forward slashes (/) or - /// backslashes (\) by converting them to dots, which is the standard separator for - /// resource names in .NET assemblies. + /// This method handles resource names that may contain either forward slashes (/) or + /// backslashes (\) by converting them to dots, which is the standard separator for + /// resource names in .NET assemblies. /// public static string? ReadEmbeddedResource(string resourceName, Assembly assembly) { var resourcePath = resourceName.Replace('/', '.').Replace('\\', '.'); var fullResourceName = assembly.GetManifestResourceNames() - .FirstOrDefault(name => name.EndsWith(resourcePath, StringComparison.Ordinal)); + .FirstOrDefault(name => name.EndsWith(resourcePath, StringComparison.Ordinal)); if (fullResourceName == null) { diff --git a/src/SquidStd.Core/Utils/SslUtils.cs b/src/SquidStd.Core/Utils/SslUtils.cs index 37d7dcaf..c22e1333 100644 --- a/src/SquidStd.Core/Utils/SslUtils.cs +++ b/src/SquidStd.Core/Utils/SslUtils.cs @@ -3,12 +3,12 @@ namespace SquidStd.Core.Utils; /// -/// Helpers for loading X.509 certificates used to secure TLS endpoints. +/// Helpers for loading X.509 certificates used to secure TLS endpoints. /// public static class SslUtils { /// - /// Loads a certificate from a PEM file, optionally combining it with a separate private-key PEM. + /// Loads a certificate from a PEM file, optionally combining it with a separate private-key PEM. /// /// Path to the certificate PEM file. /// Optional path to the private-key PEM file. @@ -21,7 +21,7 @@ public static X509Certificate2 LoadFromPem(string certificatePath, string? priva } /// - /// Loads a certificate (with its private key) from a PKCS#12 / PFX file. + /// Loads a certificate (with its private key) from a PKCS#12 / PFX file. /// /// Path to the PFX file. /// Optional password protecting the PFX file. diff --git a/src/SquidStd.Core/Utils/StringUtils.cs b/src/SquidStd.Core/Utils/StringUtils.cs index 591f1d27..33c29575 100644 --- a/src/SquidStd.Core/Utils/StringUtils.cs +++ b/src/SquidStd.Core/Utils/StringUtils.cs @@ -5,22 +5,22 @@ namespace SquidStd.Core.Utils; /// -/// Provides utility methods for string operations, including various case conversion methods. +/// Provides utility methods for string operations, including various case conversion methods. /// public static partial class StringUtils { private static readonly Regex WordSplitterRegex = WordSplitter(); /// - /// Converts a string to camelCase. + /// Converts a string to camelCase. /// /// The string to convert to camelCase. /// A camelCase version of the input string. /// Thrown when the input text is null or empty. /// - /// "HelloWorld" becomes "helloWorld" - /// "API_RESPONSE" becomes "apiResponse" - /// "user-id" becomes "userId" + /// "HelloWorld" becomes "helloWorld" + /// "API_RESPONSE" becomes "apiResponse" + /// "user-id" becomes "userId" /// public static string ToCamelCase(string text) { @@ -51,13 +51,13 @@ public static string ToCamelCase(string text) } /// - /// Converts a string to Dot Case. + /// Converts a string to Dot Case. /// /// The string to convert to Dot Case. /// A Dot Case version of the input string. /// - /// "HelloWorld" becomes "hello.world" - /// "API_RESPONSE" becomes "api.response" + /// "HelloWorld" becomes "hello.world" + /// "API_RESPONSE" becomes "api.response" /// public static string ToDotCase(string text) { @@ -96,15 +96,15 @@ public static string ToDotCase(string text) } /// - /// Converts a string to kebab-case. + /// Converts a string to kebab-case. /// /// The string to convert to kebab-case. /// A kebab-case version of the input string. /// Thrown when the input text is null or empty. /// - /// "HelloWorld" becomes "hello-world" - /// "API_RESPONSE" becomes "api-response" - /// "userId" becomes "user-id" + /// "HelloWorld" becomes "hello-world" + /// "API_RESPONSE" becomes "api-response" + /// "userId" becomes "user-id" /// public static string ToKebabCase(string text) { @@ -143,15 +143,15 @@ public static string ToKebabCase(string text) } /// - /// Converts a string to PascalCase. + /// Converts a string to PascalCase. /// /// The string to convert to PascalCase. /// A PascalCase version of the input string. /// Thrown when the input text is null or empty. /// - /// "hello_world" becomes "HelloWorld" - /// "api-response" becomes "ApiResponse" - /// "userId" becomes "UserId" + /// "hello_world" becomes "HelloWorld" + /// "api-response" becomes "ApiResponse" + /// "userId" becomes "UserId" /// public static string ToPascalCase(string text) { @@ -182,13 +182,13 @@ public static string ToPascalCase(string text) } /// - /// Converts a string to Path Case. + /// Converts a string to Path Case. /// /// The string to convert to Path Case. /// A Path Case version of the input string. /// - /// "HelloWorld" becomes "hello/world" - /// "API_RESPONSE" becomes "api/response" + /// "HelloWorld" becomes "hello/world" + /// "API_RESPONSE" becomes "api/response" /// public static string ToPathCase(string text) { @@ -227,13 +227,13 @@ public static string ToPathCase(string text) } /// - /// Converts a string to Sentence Case. + /// Converts a string to Sentence Case. /// /// The string to convert to Sentence Case. /// A Sentence Case version of the input string. /// - /// "hello world" becomes "Hello world" - /// "API_RESPONSE" becomes "Api response" + /// "hello world" becomes "Hello world" + /// "API_RESPONSE" becomes "Api response" /// public static string ToSentenceCase(string text) { @@ -284,15 +284,15 @@ public static string ToSentenceCase(string text) } /// - /// Converts a string from camelCase or PascalCase to snake_case. + /// Converts a string from camelCase or PascalCase to snake_case. /// /// The string to convert to snake_case. /// A snake_case version of the input string. /// Thrown when the input text is null or empty. /// - /// "HelloWorld" becomes "hello_world" - /// "APIResponse" becomes "api_response" - /// "userId" becomes "user_id" + /// "HelloWorld" becomes "hello_world" + /// "APIResponse" becomes "api_response" + /// "userId" becomes "user_id" /// public static string ToSnakeCase(string text) { @@ -331,15 +331,15 @@ public static string ToSnakeCase(string text) } /// - /// Converts a string to Title Case. + /// Converts a string to Title Case. /// /// The string to convert to Title Case. /// A Title Case version of the input string. /// Thrown when the input text is null or empty. /// - /// "hello_world" becomes "Hello World" - /// "API_RESPONSE" becomes "Api Response" - /// "user-id" becomes "User Id" + /// "hello_world" becomes "Hello World" + /// "API_RESPONSE" becomes "Api Response" + /// "user-id" becomes "User Id" /// public static string ToTitleCase(string text) { @@ -373,13 +373,13 @@ public static string ToTitleCase(string text) } /// - /// Converts a string to Train Case (Pascal Case with hyphens). + /// Converts a string to Train Case (Pascal Case with hyphens). /// /// The string to convert to Train Case. /// A Train Case version of the input string. /// - /// "hello_world" becomes "Hello-World" - /// "apiResponse" becomes "Api-Response" + /// "hello_world" becomes "Hello-World" + /// "apiResponse" becomes "Api-Response" /// public static string ToTrainCase(string text) { @@ -418,20 +418,18 @@ public static string ToTrainCase(string text) } /// - /// Converts a string to UPPER_SNAKE_CASE (screaming snake case). + /// Converts a string to UPPER_SNAKE_CASE (screaming snake case). /// /// The string to convert to UPPER_SNAKE_CASE. /// An UPPER_SNAKE_CASE version of the input string. /// Thrown when the input text is null or empty. /// - /// "HelloWorld" becomes "HELLO_WORLD" - /// "apiResponse" becomes "API_RESPONSE" - /// "user-id" becomes "USER_ID" + /// "HelloWorld" becomes "HELLO_WORLD" + /// "apiResponse" becomes "API_RESPONSE" + /// "user-id" becomes "USER_ID" /// public static string ToUpperSnakeCase(string text) - { - return ToSnakeCase(text).ToUpperInvariant(); - } + => ToSnakeCase(text).ToUpperInvariant(); [GeneratedRegex(@"[\s_-]|(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])", RegexOptions.Compiled)] private static partial Regex WordSplitter(); diff --git a/src/SquidStd.Core/Utils/VersionUtils.cs b/src/SquidStd.Core/Utils/VersionUtils.cs index 45938b01..60af9eb1 100644 --- a/src/SquidStd.Core/Utils/VersionUtils.cs +++ b/src/SquidStd.Core/Utils/VersionUtils.cs @@ -3,21 +3,19 @@ namespace SquidStd.Core.Utils; /// -/// Provides utility methods for reading assembly version metadata. +/// Provides utility methods for reading assembly version metadata. /// public static class VersionUtils { /// - /// Gets the informational version for the LyLy.Core assembly. + /// Gets the informational version for the LyLy.Core assembly. /// /// The package version declared for LyLy.Core. public static string GetVersion() - { - return GetVersion(typeof(VersionUtils).Assembly); - } + => GetVersion(typeof(VersionUtils).Assembly); /// - /// Gets the informational version for the specified assembly. + /// Gets the informational version for the specified assembly. /// /// The assembly to read version metadata from. /// The assembly informational version, or the assembly version when informational metadata is unavailable. @@ -26,7 +24,7 @@ public static string GetVersion(Assembly assembly) ArgumentNullException.ThrowIfNull(assembly); var informationalVersion = assembly.GetCustomAttribute() - ?.InformationalVersion; + ?.InformationalVersion; if (!string.IsNullOrWhiteSpace(informationalVersion)) { diff --git a/src/SquidStd.Core/Yaml/YamlUtils.cs b/src/SquidStd.Core/Yaml/YamlUtils.cs index 7fd5e36f..1e8dd7ca 100644 --- a/src/SquidStd.Core/Yaml/YamlUtils.cs +++ b/src/SquidStd.Core/Yaml/YamlUtils.cs @@ -3,21 +3,21 @@ namespace SquidStd.Core.Yaml; /// -/// Provides YAML serialization helpers. +/// Provides YAML serialization helpers. /// public static class YamlUtils { private static readonly ISerializer Serializer = new SerializerBuilder() - .DisableAliases() - .WithIndentedSequences() - .Build(); + .DisableAliases() + .WithIndentedSequences() + .Build(); private static readonly IDeserializer Deserializer = new DeserializerBuilder() - .IgnoreUnmatchedProperties() - .Build(); + .IgnoreUnmatchedProperties() + .Build(); /// - /// Deserializes YAML text using reflection-based metadata. + /// Deserializes YAML text using reflection-based metadata. /// /// The YAML text to deserialize. /// The target type. @@ -31,7 +31,7 @@ public static T Deserialize(string yaml) } /// - /// Deserializes YAML text to the specified runtime type. + /// Deserializes YAML text to the specified runtime type. /// /// The YAML text to deserialize. /// The target type. @@ -46,7 +46,7 @@ public static object Deserialize(string yaml, Type type) } /// - /// Deserializes YAML from a file using reflection-based metadata. + /// Deserializes YAML from a file using reflection-based metadata. /// /// The YAML file path. /// The target type. @@ -61,7 +61,7 @@ public static T DeserializeFromFile(string filePath) } /// - /// Deserializes a top-level YAML section to the specified runtime type. + /// Deserializes a top-level YAML section to the specified runtime type. /// /// The YAML document. /// The top-level section name. @@ -84,7 +84,7 @@ public static T DeserializeFromFile(string filePath) } /// - /// Serializes an object to YAML using reflection-based metadata. + /// Serializes an object to YAML using reflection-based metadata. /// /// The object to serialize. /// The source type. @@ -97,7 +97,7 @@ public static string Serialize(T obj) } /// - /// Serializes top-level YAML sections. + /// Serializes top-level YAML sections. /// /// The section map to serialize. /// The serialized YAML document. @@ -109,7 +109,7 @@ public static string SerializeSections(IReadOnlyDictionary secti } /// - /// Serializes an object to a YAML file using reflection-based metadata. + /// Serializes an object to a YAML file using reflection-based metadata. /// /// The object to serialize. /// The output YAML file path. diff --git a/src/SquidStd.Crypto/Pgp/Data/PgpDecryptionResult.cs b/src/SquidStd.Crypto/Pgp/Data/PgpDecryptionResult.cs index 417836b4..16d2eee8 100644 --- a/src/SquidStd.Crypto/Pgp/Data/PgpDecryptionResult.cs +++ b/src/SquidStd.Crypto/Pgp/Data/PgpDecryptionResult.cs @@ -1,7 +1,7 @@ namespace SquidStd.Crypto.Pgp.Data; /// -/// Outcome of decrypt-and-verify: the recovered plaintext, whether the message carried a signature, and -/// whether that signature validated against a keyring public key. +/// Outcome of decrypt-and-verify: the recovered plaintext, whether the message carried a signature, and +/// whether that signature validated against a keyring public key. /// public sealed record PgpDecryptionResult(byte[] Data, bool IsSigned, bool IsValid); diff --git a/src/SquidStd.Crypto/Pgp/Data/PgpKey.cs b/src/SquidStd.Crypto/Pgp/Data/PgpKey.cs index 2fd65dcd..114e6e00 100644 --- a/src/SquidStd.Crypto/Pgp/Data/PgpKey.cs +++ b/src/SquidStd.Crypto/Pgp/Data/PgpKey.cs @@ -3,8 +3,8 @@ namespace SquidStd.Crypto.Pgp.Data; /// -/// An OpenPGP key as held in the keyring: identity, key id, fingerprint, the armored public block, and -/// optionally the armored secret block. Metadata is derived from the public key material. +/// An OpenPGP key as held in the keyring: identity, key id, fingerprint, the armored public block, and +/// optionally the armored secret block. Metadata is derived from the public key material. /// public sealed record PgpKey( string Identity, diff --git a/src/SquidStd.Crypto/Pgp/Data/PgpKeyOptions.cs b/src/SquidStd.Crypto/Pgp/Data/PgpKeyOptions.cs index 69f62e86..8a1bd2bf 100644 --- a/src/SquidStd.Crypto/Pgp/Data/PgpKeyOptions.cs +++ b/src/SquidStd.Crypto/Pgp/Data/PgpKeyOptions.cs @@ -3,7 +3,7 @@ namespace SquidStd.Crypto.Pgp.Data; /// -/// Options controlling key generation: algorithm, key size, and an optional validity period. +/// Options controlling key generation: algorithm, key size, and an optional validity period. /// public sealed class PgpKeyOptions { diff --git a/src/SquidStd.Crypto/Pgp/Data/PgpVerificationResult.cs b/src/SquidStd.Crypto/Pgp/Data/PgpVerificationResult.cs index 7fe6fc3d..612b5dde 100644 --- a/src/SquidStd.Crypto/Pgp/Data/PgpVerificationResult.cs +++ b/src/SquidStd.Crypto/Pgp/Data/PgpVerificationResult.cs @@ -1,7 +1,7 @@ namespace SquidStd.Crypto.Pgp.Data; /// -/// Outcome of verifying a signed message: whether the signature validated against a keyring public key, -/// plus the recovered content. PgpCore reports pass/fail only — no signer attribution is exposed. +/// Outcome of verifying a signed message: whether the signature validated against a keyring public key, +/// plus the recovered content. PgpCore reports pass/fail only — no signer attribution is exposed. /// public sealed record PgpVerificationResult(bool IsValid, byte[] Data); diff --git a/src/SquidStd.Crypto/Pgp/Extensions/RegisterPgpExtensions.cs b/src/SquidStd.Crypto/Pgp/Extensions/RegisterPgpExtensions.cs index 56153d0b..cb57b89c 100644 --- a/src/SquidStd.Crypto/Pgp/Extensions/RegisterPgpExtensions.cs +++ b/src/SquidStd.Crypto/Pgp/Extensions/RegisterPgpExtensions.cs @@ -11,8 +11,8 @@ public static class RegisterPgpExtensions extension(IContainer container) { /// - /// Registers the PGP keyring, service, and the chosen key store (all singletons). The keyring is not - /// auto-loaded; call at startup if persistence is desired. + /// Registers the PGP keyring, service, and the chosen key store (all singletons). The keyring is not + /// auto-loaded; call at startup if persistence is desired. /// /// Builds the from the resolver. /// The same container for chaining. diff --git a/src/SquidStd.Crypto/Pgp/Interfaces/IPgpKeyStore.cs b/src/SquidStd.Crypto/Pgp/Interfaces/IPgpKeyStore.cs index b5f4ebbb..1fcecefc 100644 --- a/src/SquidStd.Crypto/Pgp/Interfaces/IPgpKeyStore.cs +++ b/src/SquidStd.Crypto/Pgp/Interfaces/IPgpKeyStore.cs @@ -3,7 +3,7 @@ namespace SquidStd.Crypto.Pgp.Interfaces; /// -/// Persistence backend for a set of PGP keys. Implementations decide the on-disk representation. +/// Persistence backend for a set of PGP keys. Implementations decide the on-disk representation. /// public interface IPgpKeyStore { diff --git a/src/SquidStd.Crypto/Pgp/Interfaces/IPgpKeyring.cs b/src/SquidStd.Crypto/Pgp/Interfaces/IPgpKeyring.cs index bd2917f6..bdcc4a9c 100644 --- a/src/SquidStd.Crypto/Pgp/Interfaces/IPgpKeyring.cs +++ b/src/SquidStd.Crypto/Pgp/Interfaces/IPgpKeyring.cs @@ -3,8 +3,8 @@ namespace SquidStd.Crypto.Pgp.Interfaces; /// -/// In-memory collection of PGP keys, indexed by identity, key id, and fingerprint. Crypto operations look -/// recipients and signers up here by identity. +/// In-memory collection of PGP keys, indexed by identity, key id, and fingerprint. Crypto operations look +/// recipients and signers up here by identity. /// public interface IPgpKeyring { diff --git a/src/SquidStd.Crypto/Pgp/Interfaces/IPgpService.cs b/src/SquidStd.Crypto/Pgp/Interfaces/IPgpService.cs index cdf07fcc..07b249c1 100644 --- a/src/SquidStd.Crypto/Pgp/Interfaces/IPgpService.cs +++ b/src/SquidStd.Crypto/Pgp/Interfaces/IPgpService.cs @@ -3,8 +3,8 @@ namespace SquidStd.Crypto.Pgp.Interfaces; /// -/// OpenPGP operations over the keyring: key generation, encrypt/decrypt, sign/verify, and the combined -/// encrypt+sign / decrypt+verify flows. Recipients and signers are resolved from the keyring by identity. +/// OpenPGP operations over the keyring: key generation, encrypt/decrypt, sign/verify, and the combined +/// encrypt+sign / decrypt+verify flows. Recipients and signers are resolved from the keyring by identity. /// public interface IPgpService { @@ -16,7 +16,10 @@ public interface IPgpService /// Encrypts a stream for the recipient, writing an armored message to . Task EncryptForAsync( - string recipientIdentity, Stream input, Stream output, CancellationToken cancellationToken = default + string recipientIdentity, + Stream input, + Stream output, + CancellationToken cancellationToken = default ); /// Decrypts an armored message using the matching keyring secret key and passphrase. @@ -27,24 +30,36 @@ Task EncryptForAsync( /// Encrypts for the recipient and signs it with the signer's secret key. Task EncryptAndSignForAsync( - string recipientIdentity, byte[] data, string signerIdentity, string signerPassphrase, + string recipientIdentity, + byte[] data, + string signerIdentity, + string signerPassphrase, CancellationToken cancellationToken = default ); /// Encrypts and signs a stream for the recipient. Task EncryptAndSignForAsync( - string recipientIdentity, Stream input, Stream output, string signerIdentity, string signerPassphrase, + string recipientIdentity, + Stream input, + Stream output, + string signerIdentity, + string signerPassphrase, CancellationToken cancellationToken = default ); /// Decrypts an armored message and reports whether it was signed and whether the signature validated. Task DecryptAndVerifyAsync( - string armored, string passphrase, CancellationToken cancellationToken = default + string armored, + string passphrase, + CancellationToken cancellationToken = default ); /// Produces an armored signed message that embeds . Task SignAsync( - byte[] data, string signerIdentity, string passphrase, CancellationToken cancellationToken = default + byte[] data, + string signerIdentity, + string passphrase, + CancellationToken cancellationToken = default ); /// Verifies an armored signed message against the keyring, recovering the embedded content. diff --git a/src/SquidStd.Crypto/Pgp/Internal/PgpKeyFactory.cs b/src/SquidStd.Crypto/Pgp/Internal/PgpKeyFactory.cs index 5838b962..082c3dd5 100644 --- a/src/SquidStd.Crypto/Pgp/Internal/PgpKeyFactory.cs +++ b/src/SquidStd.Crypto/Pgp/Internal/PgpKeyFactory.cs @@ -8,8 +8,8 @@ namespace SquidStd.Crypto.Pgp.Internal; /// -/// Builds a from armored key material by reading metadata off the public master key. -/// Shared by key generation, keyring import, and key-store loading. +/// Builds a from armored key material by reading metadata off the public master key. +/// Shared by key generation, keyring import, and key-store loading. /// internal static class PgpKeyFactory { @@ -25,7 +25,7 @@ public static PgpKey FromArmored(string publicArmored, string? privateArmored) var validSeconds = master.GetValidSeconds(); DateTimeOffset? expiresUtc = validSeconds > 0 ? createdUtc.AddSeconds(validSeconds) : null; - return new PgpKey( + return new( identity, keyId, fingerprint, @@ -51,12 +51,10 @@ private static string FirstUserId(PgpPublicKey master) } private static PgpKeyAlgorithm MapAlgorithm(PublicKeyAlgorithmTag tag) - { - return tag switch + => tag switch { PublicKeyAlgorithmTag.RsaGeneral or PublicKeyAlgorithmTag.RsaEncrypt or PublicKeyAlgorithmTag.RsaSign => PgpKeyAlgorithm.Rsa, _ => PgpKeyAlgorithm.Rsa }; - } } diff --git a/src/SquidStd.Crypto/Pgp/Internal/PgpKeyStoreCodec.cs b/src/SquidStd.Crypto/Pgp/Internal/PgpKeyStoreCodec.cs index 24d3fcad..83054767 100644 --- a/src/SquidStd.Crypto/Pgp/Internal/PgpKeyStoreCodec.cs +++ b/src/SquidStd.Crypto/Pgp/Internal/PgpKeyStoreCodec.cs @@ -4,8 +4,8 @@ namespace SquidStd.Crypto.Pgp.Internal; /// -/// Encodes a set of keys into a single byte blob (one base64 record per line) and back. Only armored -/// material is stored; metadata is re-derived on load. +/// Encodes a set of keys into a single byte blob (one base64 record per line) and back. Only armored +/// material is stored; metadata is re-derived on load. /// internal static class PgpKeyStoreCodec { @@ -17,8 +17,8 @@ public static byte[] Encode(IReadOnlyCollection keys) { var pub = Convert.ToBase64String(Encoding.UTF8.GetBytes(key.PublicArmored)); var sec = key.PrivateArmored is null - ? string.Empty - : Convert.ToBase64String(Encoding.UTF8.GetBytes(key.PrivateArmored)); + ? string.Empty + : Convert.ToBase64String(Encoding.UTF8.GetBytes(key.PrivateArmored)); builder.Append(pub).Append('\t').Append(sec).Append('\n'); } @@ -34,9 +34,9 @@ public static IReadOnlyList Decode(byte[] blob) { var parts = line.Split('\t'); var publicArmored = Encoding.UTF8.GetString(Convert.FromBase64String(parts[0])); - string? privateArmored = parts.Length > 1 && parts[1].Length > 0 - ? Encoding.UTF8.GetString(Convert.FromBase64String(parts[1])) - : null; + var privateArmored = parts.Length > 1 && parts[1].Length > 0 + ? Encoding.UTF8.GetString(Convert.FromBase64String(parts[1])) + : null; result.Add(PgpKeyFactory.FromArmored(publicArmored, privateArmored)); } diff --git a/src/SquidStd.Crypto/Pgp/Services/AesGcmPgpKeyStore.cs b/src/SquidStd.Crypto/Pgp/Services/AesGcmPgpKeyStore.cs index f595a789..7090f1cf 100644 --- a/src/SquidStd.Crypto/Pgp/Services/AesGcmPgpKeyStore.cs +++ b/src/SquidStd.Crypto/Pgp/Services/AesGcmPgpKeyStore.cs @@ -6,8 +6,8 @@ namespace SquidStd.Crypto.Pgp.Services; /// -/// Key store that serializes the keyring to a single file encrypted at rest with the application key via -/// . +/// Key store that serializes the keyring to a single file encrypted at rest with the application key via +/// . /// public sealed class AesGcmPgpKeyStore : IPgpKeyStore { @@ -30,6 +30,7 @@ public async Task SaveAsync(IReadOnlyCollection keys, CancellationToken var protectedBytes = _protector.Protect(plaintext); var directory = Path.GetDirectoryName(_path); + if (!string.IsNullOrEmpty(directory)) { Directory.CreateDirectory(directory); diff --git a/src/SquidStd.Crypto/Pgp/Services/FilePgpKeyStore.cs b/src/SquidStd.Crypto/Pgp/Services/FilePgpKeyStore.cs index e71d2c1c..55568d23 100644 --- a/src/SquidStd.Crypto/Pgp/Services/FilePgpKeyStore.cs +++ b/src/SquidStd.Crypto/Pgp/Services/FilePgpKeyStore.cs @@ -6,8 +6,8 @@ namespace SquidStd.Crypto.Pgp.Services; /// -/// Key store backed by a directory of armored .asc files (one public, optionally one secret, per -/// key). gpg-interoperable. +/// Key store backed by a directory of armored .asc files (one public, optionally one secret, per +/// key). gpg-interoperable. /// public sealed class FilePgpKeyStore : IPgpKeyStore { @@ -31,20 +31,20 @@ public async Task SaveAsync(IReadOnlyCollection keys, CancellationToken { var stem = Stem(key); await File.WriteAllTextAsync( - Path.Combine(_directory, stem + PublicSuffix), - key.PublicArmored, - cancellationToken - ) - .ConfigureAwait(false); + Path.Combine(_directory, stem + PublicSuffix), + key.PublicArmored, + cancellationToken + ) + .ConfigureAwait(false); if (key.PrivateArmored is not null) { await File.WriteAllTextAsync( - Path.Combine(_directory, stem + SecretSuffix), - key.PrivateArmored, - cancellationToken - ) - .ConfigureAwait(false); + Path.Combine(_directory, stem + SecretSuffix), + key.PrivateArmored, + cancellationToken + ) + .ConfigureAwait(false); } } } @@ -65,9 +65,9 @@ public async Task> LoadAsync(CancellationToken cancellatio var publicArmored = await File.ReadAllTextAsync(publicPath, cancellationToken).ConfigureAwait(false); var secretPath = Path.Combine(_directory, stem + SecretSuffix); - string? secretArmored = File.Exists(secretPath) - ? await File.ReadAllTextAsync(secretPath, cancellationToken).ConfigureAwait(false) - : null; + var secretArmored = File.Exists(secretPath) + ? await File.ReadAllTextAsync(secretPath, cancellationToken).ConfigureAwait(false) + : null; result.Add(PgpKeyFactory.FromArmored(publicArmored, secretArmored)); } @@ -78,6 +78,7 @@ public async Task> LoadAsync(CancellationToken cancellatio private static string Stem(PgpKey key) { var safeIdentity = new StringBuilder(key.Identity.Length); + foreach (var ch in key.Identity) { safeIdentity.Append(char.IsLetterOrDigit(ch) ? ch : '_'); diff --git a/src/SquidStd.Crypto/Pgp/Services/PgpKeyring.cs b/src/SquidStd.Crypto/Pgp/Services/PgpKeyring.cs index 8d258635..efc8ce14 100644 --- a/src/SquidStd.Crypto/Pgp/Services/PgpKeyring.cs +++ b/src/SquidStd.Crypto/Pgp/Services/PgpKeyring.cs @@ -9,7 +9,7 @@ namespace SquidStd.Crypto.Pgp.Services; /// -/// Thread-safe in-memory keyring indexed by identity, key id, and fingerprint. +/// Thread-safe in-memory keyring indexed by identity, key id, and fingerprint. /// public sealed class PgpKeyring : IPgpKeyring { @@ -25,8 +25,8 @@ public PgpKey Import(string armored) ArgumentException.ThrowIfNullOrWhiteSpace(armored); var key = armored.Contains(SecretHeader, StringComparison.Ordinal) - ? PgpKeyFactory.FromArmored(ExportPublic(armored), armored) - : PgpKeyFactory.FromArmored(armored, null); + ? PgpKeyFactory.FromArmored(ExportPublic(armored), armored) + : PgpKeyFactory.FromArmored(armored, null); _byKeyId[key.KeyId] = key; @@ -67,9 +67,7 @@ public bool Remove(string identityOrKeyIdOrFingerprint) /// public bool Contains(string identityOrKeyIdOrFingerprint) - { - return Find(identityOrKeyIdOrFingerprint) is not null; - } + => Find(identityOrKeyIdOrFingerprint) is not null; /// public async Task LoadAsync(IPgpKeyStore store, CancellationToken cancellationToken = default) @@ -95,15 +93,14 @@ public Task SaveAsync(IPgpKeyStore store, CancellationToken cancellationToken = private static string ExportPublic(string secretArmored) { - using var input = PgpUtilities.GetDecoderStream( - new MemoryStream(Encoding.UTF8.GetBytes(secretArmored)) - ); - var ring = new PgpSecretKeyRingBundle(input).GetKeyRings().Cast().First(); + using var input = PgpUtilities.GetDecoderStream(new MemoryStream(Encoding.UTF8.GetBytes(secretArmored))); + var ring = new PgpSecretKeyRingBundle(input).GetKeyRings().First(); using var output = new MemoryStream(); + using (var armor = new ArmoredOutputStream(output)) { - foreach (PgpSecretKey secretKey in ring.GetSecretKeys()) + foreach (var secretKey in ring.GetSecretKeys()) { secretKey.PublicKey.Encode(armor); } diff --git a/src/SquidStd.Crypto/Pgp/Services/PgpService.cs b/src/SquidStd.Crypto/Pgp/Services/PgpService.cs index 6838551f..5ff2d6ff 100644 --- a/src/SquidStd.Crypto/Pgp/Services/PgpService.cs +++ b/src/SquidStd.Crypto/Pgp/Services/PgpService.cs @@ -9,8 +9,8 @@ namespace SquidStd.Crypto.Pgp.Services; /// -/// OpenPGP operations over a keyring, implemented with PgpCore. Every byte/armored-string operation -/// round-trips through so binary payloads survive intact. +/// OpenPGP operations over a keyring, implemented with PgpCore. Every byte/armored-string operation +/// round-trips through so binary payloads survive intact. /// public sealed class PgpService : IPgpService { @@ -51,7 +51,9 @@ public PgpKey GenerateKey(string identity, string passphrase, PgpKeyOptions? opt /// public async Task EncryptForAsync( - string recipientIdentity, byte[] data, CancellationToken cancellationToken = default + string recipientIdentity, + byte[] data, + CancellationToken cancellationToken = default ) { ArgumentNullException.ThrowIfNull(data); @@ -68,7 +70,10 @@ public async Task EncryptForAsync( /// public async Task EncryptForAsync( - string recipientIdentity, Stream input, Stream output, CancellationToken cancellationToken = default + string recipientIdentity, + Stream input, + Stream output, + CancellationToken cancellationToken = default ) { ArgumentNullException.ThrowIfNull(input); @@ -96,7 +101,10 @@ public async Task DecryptAsync(string armored, string passphrase, Cancel /// public async Task DecryptAsync( - Stream input, Stream output, string passphrase, CancellationToken cancellationToken = default + Stream input, + Stream output, + string passphrase, + CancellationToken cancellationToken = default ) { ArgumentNullException.ThrowIfNull(input); @@ -116,7 +124,10 @@ public async Task DecryptAsync( /// public async Task EncryptAndSignForAsync( - string recipientIdentity, byte[] data, string signerIdentity, string signerPassphrase, + string recipientIdentity, + byte[] data, + string signerIdentity, + string signerPassphrase, CancellationToken cancellationToken = default ) { @@ -133,7 +144,11 @@ public async Task EncryptAndSignForAsync( /// public async Task EncryptAndSignForAsync( - string recipientIdentity, Stream input, Stream output, string signerIdentity, string signerPassphrase, + string recipientIdentity, + Stream input, + Stream output, + string signerIdentity, + string signerPassphrase, CancellationToken cancellationToken = default ) { @@ -146,7 +161,9 @@ public async Task EncryptAndSignForAsync( /// public async Task DecryptAndVerifyAsync( - string armored, string passphrase, CancellationToken cancellationToken = default + string armored, + string passphrase, + CancellationToken cancellationToken = default ) { ArgumentException.ThrowIfNullOrWhiteSpace(armored); @@ -161,7 +178,7 @@ public async Task DecryptAndVerifyAsync( { var plain = await DecryptWith(pgp, armored).ConfigureAwait(false); - return new PgpDecryptionResult(plain, false, false); + return new(plain, false, false); } try @@ -170,19 +187,22 @@ public async Task DecryptAndVerifyAsync( using var output = new MemoryStream(); await pgp.DecryptAndVerifyAsync(input, output).ConfigureAwait(false); - return new PgpDecryptionResult(output.ToArray(), true, true); + return new(output.ToArray(), true, true); } catch (Exception ex) when (ex is BcPgpException or InvalidOperationException or ArgumentException or IOException) { var plain = await DecryptWith(pgp, armored).ConfigureAwait(false); - return new PgpDecryptionResult(plain, true, false); + return new(plain, true, false); } } /// public async Task SignAsync( - byte[] data, string signerIdentity, string passphrase, CancellationToken cancellationToken = default + byte[] data, + string signerIdentity, + string passphrase, + CancellationToken cancellationToken = default ) { ArgumentNullException.ThrowIfNull(data); @@ -211,6 +231,7 @@ public async Task VerifyAsync(string signedMessage, Cance var pgp = new PGP(new EncryptionKeys(key.PublicArmored)); bool ok; + try { ok = await pgp.VerifyAsync(input, output).ConfigureAwait(false); @@ -227,11 +248,11 @@ public async Task VerifyAsync(string signedMessage, Cance if (ok) { - return new PgpVerificationResult(true, recovered); + return new(true, recovered); } } - return new PgpVerificationResult(false, recovered); + return new(false, recovered); } private PGP BuildEncryptAndSign(string recipientIdentity, string signerIdentity, string signerPassphrase) @@ -239,7 +260,7 @@ private PGP BuildEncryptAndSign(string recipientIdentity, string signerIdentity, var recipient = RequireKey(recipientIdentity); var signer = RequireKey(signerIdentity); - return new PGP(new EncryptionKeys(recipient.PublicArmored, signer.PrivateArmored!, signerPassphrase)); + return new(new EncryptionKeys(recipient.PublicArmored, signer.PrivateArmored!, signerPassphrase)); } private static async Task DecryptWith(PGP pgp, string armored) @@ -255,8 +276,8 @@ private PgpKey RequireKey(string identity) { ArgumentException.ThrowIfNullOrWhiteSpace(identity); - return _keyring.Find(identity) - ?? throw new KeyNotFoundException($"No key for identity '{identity}' in the keyring."); + return _keyring.Find(identity) ?? + throw new KeyNotFoundException($"No key for identity '{identity}' in the keyring."); } private PgpKey RequireSecretFor(string armored) @@ -275,12 +296,8 @@ private PgpKey RequireSecretFor(string armored) } private static long ParseKeyId(string keyId) - { - return long.Parse(keyId, NumberStyles.HexNumber, CultureInfo.InvariantCulture); - } + => long.Parse(keyId, NumberStyles.HexNumber, CultureInfo.InvariantCulture); private static string ReadAll(MemoryStream stream) - { - return Encoding.UTF8.GetString(stream.ToArray()); - } + => Encoding.UTF8.GetString(stream.ToArray()); } diff --git a/src/SquidStd.Crypto/Pgp/Types/PgpKeyAlgorithm.cs b/src/SquidStd.Crypto/Pgp/Types/PgpKeyAlgorithm.cs index f98a5288..ed52ffa2 100644 --- a/src/SquidStd.Crypto/Pgp/Types/PgpKeyAlgorithm.cs +++ b/src/SquidStd.Crypto/Pgp/Types/PgpKeyAlgorithm.cs @@ -1,7 +1,7 @@ namespace SquidStd.Crypto.Pgp.Types; /// -/// OpenPGP public-key algorithm family for a generated key. Extensible (ECC may be added later). +/// OpenPGP public-key algorithm family for a generated key. Extensible (ECC may be added later). /// public enum PgpKeyAlgorithm { diff --git a/src/SquidStd.Crypto/README.md b/src/SquidStd.Crypto/README.md index 27216f17..cd5d8436 100644 --- a/src/SquidStd.Crypto/README.md +++ b/src/SquidStd.Crypto/README.md @@ -52,14 +52,14 @@ await keyring.LoadAsync(container.Resolve()); ## Key types -| Type | Purpose | -|------|---------| -| `IPgpService` | Key generation, encrypt/decrypt, sign/verify, and combined encrypt+sign / decrypt+verify. | -| `IPgpKeyring` | Stateful, indexed keyring: import keys and save/load via an `IPgpKeyStore`. | -| `IPgpKeyStore` | Pluggable keyring persistence backend. | -| `FilePgpKeyStore` | One armored `.asc` per key (gpg-interoperable). | -| `AesGcmPgpKeyStore` | The whole keyring serialized to a single file, encrypted at rest via `ISecretProtector`. | -| `CryptoFileSystem` | `ILockableFileSystem` that encrypts content and names over any `IVirtualFileSystem`. | +| Type | Purpose | +|---------------------|-------------------------------------------------------------------------------------------| +| `IPgpService` | Key generation, encrypt/decrypt, sign/verify, and combined encrypt+sign / decrypt+verify. | +| `IPgpKeyring` | Stateful, indexed keyring: import keys and save/load via an `IPgpKeyStore`. | +| `IPgpKeyStore` | Pluggable keyring persistence backend. | +| `FilePgpKeyStore` | One armored `.asc` per key (gpg-interoperable). | +| `AesGcmPgpKeyStore` | The whole keyring serialized to a single file, encrypted at rest via `ISecretProtector`. | +| `CryptoFileSystem` | `ILockableFileSystem` that encrypts content and names over any `IVirtualFileSystem`. | ## Key stores diff --git a/src/SquidStd.Crypto/Vfs/Extensions/RegisterCryptoVaultExtensions.cs b/src/SquidStd.Crypto/Vfs/Extensions/RegisterCryptoVaultExtensions.cs index d87faadd..df8f116a 100644 --- a/src/SquidStd.Crypto/Vfs/Extensions/RegisterCryptoVaultExtensions.cs +++ b/src/SquidStd.Crypto/Vfs/Extensions/RegisterCryptoVaultExtensions.cs @@ -13,8 +13,8 @@ public static class RegisterCryptoVaultExtensions extension(IContainer container) { /// - /// Registers an singleton: a crypto vault over a single-file zip at - /// . The consumer calls at runtime. + /// Registers an singleton: a crypto vault over a single-file zip at + /// . The consumer calls at runtime. /// public IContainer RegisterCryptoVault(string path, CryptoVaultOptions? options = null) { diff --git a/src/SquidStd.Crypto/Vfs/Internal/EntryCipher.cs b/src/SquidStd.Crypto/Vfs/Internal/EntryCipher.cs index 03ce8db0..1cda677d 100644 --- a/src/SquidStd.Crypto/Vfs/Internal/EntryCipher.cs +++ b/src/SquidStd.Crypto/Vfs/Internal/EntryCipher.cs @@ -13,7 +13,7 @@ internal sealed class EntryCipher : IDisposable public EntryCipher(byte[] key, int chunkSize) { - _aes = new AesGcm(key, TagSize); + _aes = new(key, TagSize); _chunkSize = chunkSize; } @@ -58,6 +58,7 @@ public async Task DecryptAsync(Stream input, Stream output, CancellationToken ca if (length == 0) { _aes.Decrypt(nonce.Span, ReadOnlySpan.Empty, tag, Span.Empty); + break; } @@ -120,7 +121,5 @@ private static async Task ReadExactAsync(Stream stream, byte[] buffer, Cancellat } public void Dispose() - { - _aes.Dispose(); - } + => _aes.Dispose(); } diff --git a/src/SquidStd.Crypto/Vfs/Internal/VaultHeader.cs b/src/SquidStd.Crypto/Vfs/Internal/VaultHeader.cs index 289a9867..884939ce 100644 --- a/src/SquidStd.Crypto/Vfs/Internal/VaultHeader.cs +++ b/src/SquidStd.Crypto/Vfs/Internal/VaultHeader.cs @@ -14,13 +14,9 @@ int ChunkSize ) { public byte[] Serialize() - { - return JsonSerializer.SerializeToUtf8Bytes(this); - } + => JsonSerializer.SerializeToUtf8Bytes(this); public static VaultHeader Parse(byte[] data) - { - return JsonSerializer.Deserialize(data) - ?? throw new InvalidDataException("Vault header is empty or invalid."); - } + => JsonSerializer.Deserialize(data) ?? + throw new InvalidDataException("Vault header is empty or invalid."); } diff --git a/src/SquidStd.Crypto/Vfs/Internal/VaultIndex.cs b/src/SquidStd.Crypto/Vfs/Internal/VaultIndex.cs index fcd2c56e..cb6c6905 100644 --- a/src/SquidStd.Crypto/Vfs/Internal/VaultIndex.cs +++ b/src/SquidStd.Crypto/Vfs/Internal/VaultIndex.cs @@ -25,7 +25,7 @@ public IReadOnlyDictionary Entries public VaultIndex() { - _entries = new Dictionary(StringComparer.Ordinal); + _entries = new(StringComparer.Ordinal); } private VaultIndex(Dictionary entries) @@ -67,9 +67,9 @@ public byte[] Serialize() public static VaultIndex Parse(byte[] data) { - var map = JsonSerializer.Deserialize>(data) - ?? new Dictionary(StringComparer.Ordinal); + var map = JsonSerializer.Deserialize>(data) ?? + new Dictionary(StringComparer.Ordinal); - return new VaultIndex(new Dictionary(map, StringComparer.Ordinal)); + return new(new(map, StringComparer.Ordinal)); } } diff --git a/src/SquidStd.Crypto/Vfs/Internal/VaultKeyDerivation.cs b/src/SquidStd.Crypto/Vfs/Internal/VaultKeyDerivation.cs index abb5212a..9be8c299 100644 --- a/src/SquidStd.Crypto/Vfs/Internal/VaultKeyDerivation.cs +++ b/src/SquidStd.Crypto/Vfs/Internal/VaultKeyDerivation.cs @@ -12,12 +12,12 @@ internal static class VaultKeyDerivation public static byte[] DeriveMasterKey(string passphrase, byte[] salt, CryptoVaultOptions options) { var parameters = new Argon2Parameters.Builder(Argon2Parameters.Argon2id) - .WithVersion(Argon2Parameters.Version13) - .WithSalt(salt) - .WithIterations(options.Argon2Iterations) - .WithMemoryAsKB(options.Argon2MemoryKib) - .WithParallelism(options.Argon2Parallelism) - .Build(); + .WithVersion(Argon2Parameters.Version13) + .WithSalt(salt) + .WithIterations(options.Argon2Iterations) + .WithMemoryAsKB(options.Argon2MemoryKib) + .WithParallelism(options.Argon2Parallelism) + .Build(); var generator = new Argon2BytesGenerator(); generator.Init(parameters); diff --git a/src/SquidStd.Crypto/Vfs/Services/CryptoFileSystem.cs b/src/SquidStd.Crypto/Vfs/Services/CryptoFileSystem.cs index 078fca26..920ecfd1 100644 --- a/src/SquidStd.Crypto/Vfs/Services/CryptoFileSystem.cs +++ b/src/SquidStd.Crypto/Vfs/Services/CryptoFileSystem.cs @@ -2,9 +2,9 @@ using System.Security.Cryptography; using SquidStd.Crypto.Vfs.Data; using SquidStd.Crypto.Vfs.Internal; +using SquidStd.Vfs.Abstractions; using SquidStd.Vfs.Abstractions.Data; using SquidStd.Vfs.Abstractions.Interfaces; -using SquidStd.Vfs.Abstractions; namespace SquidStd.Crypto.Vfs.Services; @@ -35,7 +35,7 @@ public void Unlock(string passphrase) if (headerBytes is null) { - header = new VaultHeader( + header = new( "SQVFS1", 1, RandomNumberGenerator.GetBytes(16), @@ -62,8 +62,8 @@ public void Unlock(string passphrase) var indexBytes = _inner.ReadAllBytesAsync(IndexPath).AsTask().GetAwaiter().GetResult(); _index = indexBytes is null - ? new VaultIndex() - : VaultIndex.Parse(VaultBlob.Decrypt(VaultKeyDerivation.DeriveSubKey(master, "index"), indexBytes)); + ? new() + : VaultIndex.Parse(VaultBlob.Decrypt(VaultKeyDerivation.DeriveSubKey(master, "index"), indexBytes)); _masterKey = master; } @@ -98,8 +98,8 @@ public ValueTask ExistsAsync(string path, CancellationToken cancellationTo return null; } - var blob = await _inner.ReadAllBytesAsync(entry!.BlobId, cancellationToken).ConfigureAwait(false) - ?? throw new InvalidDataException($"Backing blob '{entry.BlobId}' is missing."); + var blob = await _inner.ReadAllBytesAsync(entry!.BlobId, cancellationToken).ConfigureAwait(false) ?? + throw new InvalidDataException($"Backing blob '{entry.BlobId}' is missing."); using var cipher = NewCipher(entry.BlobId); using var input = new MemoryStream(blob); @@ -110,7 +110,9 @@ public ValueTask ExistsAsync(string path, CancellationToken cancellationTo } public async ValueTask WriteAllBytesAsync( - string path, ReadOnlyMemory data, CancellationToken cancellationToken = default + string path, + ReadOnlyMemory data, + CancellationToken cancellationToken = default ) { EnsureUnlocked(); @@ -124,15 +126,15 @@ public async ValueTask WriteAllBytesAsync( await cipher.EncryptAsync(input, output, cancellationToken).ConfigureAwait(false); await _inner.WriteAllBytesAsync(blobId, output.ToArray(), cancellationToken).ConfigureAwait(false); - _index.Set(normalized, new VaultIndexEntry(blobId, data.Length, DateTimeOffset.UtcNow)); + _index.Set(normalized, new(blobId, data.Length, DateTimeOffset.UtcNow)); } public async Task OpenReadAsync(string path, CancellationToken cancellationToken = default) { - var data = await ReadAllBytesAsync(path, cancellationToken).ConfigureAwait(false) - ?? throw new FileNotFoundException($"No file at '{path}'.", path); + var data = await ReadAllBytesAsync(path, cancellationToken).ConfigureAwait(false) ?? + throw new FileNotFoundException($"No file at '{path}'.", path); - return new MemoryStream(data, writable: false); + return new MemoryStream(data, false); } public Task OpenWriteAsync(string path, CancellationToken cancellationToken = default) @@ -157,7 +159,8 @@ public async ValueTask DeleteAsync(string path, CancellationToken cancella } public async IAsyncEnumerable ListAsync( - string? prefix = null, [EnumeratorCancellation] CancellationToken cancellationToken = default + string? prefix = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default ) { EnsureUnlocked(); @@ -170,21 +173,17 @@ public async IAsyncEnumerable ListAsync( continue; } - yield return new VfsEntry(logicalPath, entry.Size, entry.ModifiedUtc); + yield return new(logicalPath, entry.Size, entry.ModifiedUtc); await Task.CompletedTask; } } private EntryCipher NewCipher(string blobId) - { - return new EntryCipher(VaultKeyDerivation.DeriveSubKey(_masterKey!, "entry:" + blobId), _options.ChunkSize); - } + => new(VaultKeyDerivation.DeriveSubKey(_masterKey!, "entry:" + blobId), _options.ChunkSize); private static string NewBlobId() - { - return Convert.ToHexStringLower(RandomNumberGenerator.GetBytes(16)); - } + => Convert.ToHexStringLower(RandomNumberGenerator.GetBytes(16)); private void FlushIndex() { @@ -203,6 +202,7 @@ private void PruneOrphans() var paths = new List(); var enumerator = _inner.ListAsync().GetAsyncEnumerator(); + try { while (enumerator.MoveNextAsync().AsTask().GetAwaiter().GetResult()) @@ -239,9 +239,11 @@ public void Dispose() { case IDisposable disposable: disposable.Dispose(); + break; case IAsyncDisposable asyncDisposable: asyncDisposable.DisposeAsync().AsTask().GetAwaiter().GetResult(); + break; } } diff --git a/src/SquidStd.Database.Abstractions/Data/Database/DatabaseConfig.cs b/src/SquidStd.Database.Abstractions/Data/Database/DatabaseConfig.cs index d386fd1b..39fdc203 100644 --- a/src/SquidStd.Database.Abstractions/Data/Database/DatabaseConfig.cs +++ b/src/SquidStd.Database.Abstractions/Data/Database/DatabaseConfig.cs @@ -3,18 +3,18 @@ namespace SquidStd.Database.Abstractions.Data.Database; /// -/// Database connection configuration. +/// Database connection configuration. /// public sealed class DatabaseConfig : IConfigEntry { /// - /// Gets or sets the URI-style connection string (e.g. "sqlite://squidstd.db", - /// "postgres://user:pass@host:5432/db"). The scheme selects the provider. + /// Gets or sets the URI-style connection string (e.g. "sqlite://squidstd.db", + /// "postgres://user:pass@host:5432/db"). The scheme selects the provider. /// public string ConnectionString { get; set; } = "sqlite://squidstd.db"; /// - /// Gets or sets a value indicating whether the schema is auto-synchronized on startup. + /// Gets or sets a value indicating whether the schema is auto-synchronized on startup. /// public bool AutoMigrate { get; set; } = true; @@ -23,7 +23,5 @@ public sealed class DatabaseConfig : IConfigEntry Type IConfigEntry.ConfigType => typeof(DatabaseConfig); object IConfigEntry.CreateDefault() - { - return new DatabaseConfig(); - } + => new DatabaseConfig(); } diff --git a/src/SquidStd.Database.Abstractions/Data/Entities/BaseEntity.cs b/src/SquidStd.Database.Abstractions/Data/Entities/BaseEntity.cs index 85dc2da7..aee115e9 100644 --- a/src/SquidStd.Database.Abstractions/Data/Entities/BaseEntity.cs +++ b/src/SquidStd.Database.Abstractions/Data/Entities/BaseEntity.cs @@ -1,7 +1,7 @@ namespace SquidStd.Database.Abstractions.Data.Entities; /// -/// Base class for all persisted entities: a Guid identity plus UTC create/update timestamps. +/// Base class for all persisted entities: a Guid identity plus UTC create/update timestamps. /// public abstract class BaseEntity { diff --git a/src/SquidStd.Database.Abstractions/Data/PagedResultData.cs b/src/SquidStd.Database.Abstractions/Data/PagedResultData.cs index cd16c889..a259ad19 100644 --- a/src/SquidStd.Database.Abstractions/Data/PagedResultData.cs +++ b/src/SquidStd.Database.Abstractions/Data/PagedResultData.cs @@ -1,7 +1,7 @@ namespace SquidStd.Database.Abstractions.Data; /// -/// A paginated result set with paging metadata. +/// A paginated result set with paging metadata. /// /// The item type. public sealed class PagedResultData @@ -28,7 +28,7 @@ public sealed class PagedResultData public bool HasPrevious => Page > 1 && TotalPages > 0; /// - /// Creates a paged result. + /// Creates a paged result. /// /// The current page items. /// The 1-based page number. @@ -36,13 +36,11 @@ public sealed class PagedResultData /// The total matching row count. /// The paged result. public static PagedResultData Create(IReadOnlyList items, int page, int pageSize, long totalCount) - { - return new PagedResultData + => new() { Items = items, Page = page, PageSize = pageSize, TotalCount = totalCount }; - } } diff --git a/src/SquidStd.Database.Abstractions/Interfaces/Data/IDataAccess.cs b/src/SquidStd.Database.Abstractions/Interfaces/Data/IDataAccess.cs index 8ba1f9ee..a5d8e020 100644 --- a/src/SquidStd.Database.Abstractions/Interfaces/Data/IDataAccess.cs +++ b/src/SquidStd.Database.Abstractions/Interfaces/Data/IDataAccess.cs @@ -6,7 +6,7 @@ namespace SquidStd.Database.Abstractions.Interfaces.Data; /// -/// Generic data access for a type: CRUD, bulk, and querying. +/// Generic data access for a type: CRUD, bulk, and querying. /// /// The entity type. public interface IDataAccess diff --git a/src/SquidStd.Database.Abstractions/Types/Data/DatabaseProviderType.cs b/src/SquidStd.Database.Abstractions/Types/Data/DatabaseProviderType.cs index 530fe8ed..81955055 100644 --- a/src/SquidStd.Database.Abstractions/Types/Data/DatabaseProviderType.cs +++ b/src/SquidStd.Database.Abstractions/Types/Data/DatabaseProviderType.cs @@ -1,7 +1,7 @@ namespace SquidStd.Database.Abstractions.Types.Data; /// -/// Supported database providers. +/// Supported database providers. /// public enum DatabaseProviderType { diff --git a/src/SquidStd.Database/Connection/ConnectionStringParser.cs b/src/SquidStd.Database/Connection/ConnectionStringParser.cs index 2eb883cc..1559f0c0 100644 --- a/src/SquidStd.Database/Connection/ConnectionStringParser.cs +++ b/src/SquidStd.Database/Connection/ConnectionStringParser.cs @@ -4,12 +4,12 @@ namespace SquidStd.Database.Connection; /// -/// Parses URI-style connection strings ("scheme://...") into a provider and native connection string. +/// Parses URI-style connection strings ("scheme://...") into a provider and native connection string. /// public static class ConnectionStringParser { /// - /// Parses the given URI connection string. + /// Parses the given URI connection string. /// /// The URI connection string. /// The parsed provider and native connection string. @@ -29,10 +29,10 @@ public static ParsedConnection Parse(string connectionString) var provider = ResolveProvider(scheme); var native = provider == DatabaseProviderType.Sqlite - ? BuildSqlite(remainder) - : BuildServer(provider, remainder); + ? BuildSqlite(remainder) + : BuildServer(provider, remainder); - return new ParsedConnection(provider, native); + return new(provider, native); } private static string BuildServer(DatabaseProviderType provider, string remainder) @@ -87,8 +87,7 @@ private static string BuildSqlite(string remainder) } private static DatabaseProviderType ResolveProvider(string scheme) - { - return scheme switch + => scheme switch { "sqlite" => DatabaseProviderType.Sqlite, "postgres" or "postgresql" => DatabaseProviderType.Postgres, @@ -96,7 +95,6 @@ private static DatabaseProviderType ResolveProvider(string scheme) "mysql" => DatabaseProviderType.MySql, _ => throw new NotSupportedException($"Unsupported database scheme '{scheme}'.") }; - } private static (string User, string Password, string HostPort) SplitAuthority(string authority) { diff --git a/src/SquidStd.Database/Connection/ParsedConnection.cs b/src/SquidStd.Database/Connection/ParsedConnection.cs index 6603c3fd..b03c0d84 100644 --- a/src/SquidStd.Database/Connection/ParsedConnection.cs +++ b/src/SquidStd.Database/Connection/ParsedConnection.cs @@ -3,7 +3,7 @@ namespace SquidStd.Database.Connection; /// -/// The result of parsing a URI connection string: the provider and the native connection string. +/// The result of parsing a URI connection string: the provider and the native connection string. /// /// The resolved database provider. /// The provider-native connection string for FreeSql. diff --git a/src/SquidStd.Database/Data/FreeSqlDataAccess.cs b/src/SquidStd.Database/Data/FreeSqlDataAccess.cs index 65a9dec0..b1fe240e 100644 --- a/src/SquidStd.Database/Data/FreeSqlDataAccess.cs +++ b/src/SquidStd.Database/Data/FreeSqlDataAccess.cs @@ -10,7 +10,7 @@ namespace SquidStd.Database.Data; /// -/// FreeSql-backed . Writes run inside a unit of work with rollback. +/// FreeSql-backed . Writes run inside a unit of work with rollback. /// /// The entity type. public sealed class FreeSqlDataAccess : IDataAccess @@ -21,7 +21,7 @@ public sealed class FreeSqlDataAccess : IDataAccess private readonly IFreeSql _orm; /// - /// Initializes the data access over the shared FreeSql instance. + /// Initializes the data access over the shared FreeSql instance. /// /// The database service that owns the FreeSql instance. public FreeSqlDataAccess(IDatabaseService databaseService) @@ -34,17 +34,15 @@ public Task BulkDeleteAsync( Expression> predicate, CancellationToken cancellationToken = default ) - { - return RunInTransactionAsync( + => RunInTransactionAsync( transaction => _orm.Delete() - .Where(predicate) - .WithTransaction(transaction) - .ExecuteAffrowsAsync(cancellationToken), + .Where(predicate) + .WithTransaction(transaction) + .ExecuteAffrowsAsync(cancellationToken), "BulkDelete", null, cancellationToken ); - } /// public Task BulkInsertAsync(IEnumerable entities, CancellationToken cancellationToken = default) @@ -72,9 +70,9 @@ public Task BulkUpdateAsync(IEnumerable entities, CancellationToke return RunInTransactionAsync( transaction => _orm.Update() - .SetSource(list) - .WithTransaction(transaction) - .ExecuteAffrowsAsync(cancellationToken), + .SetSource(list) + .WithTransaction(transaction) + .ExecuteAffrowsAsync(cancellationToken), "BulkUpdate", list.Count, cancellationToken @@ -101,35 +99,29 @@ public Task CountAsync( public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) { var affected = await RunInTransactionAsync( - transaction => _orm.Delete() - .Where(e => e.Id == id) - .WithTransaction(transaction) - .ExecuteAffrowsAsync(cancellationToken), - "Delete", - null, - cancellationToken - ); + transaction => _orm.Delete() + .Where(e => e.Id == id) + .WithTransaction(transaction) + .ExecuteAffrowsAsync(cancellationToken), + "Delete", + null, + cancellationToken + ); return affected > 0; } /// public Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) - { - return DeleteAsync(entity.Id, cancellationToken); - } + => DeleteAsync(entity.Id, cancellationToken); /// public Task ExistsAsync(Expression> predicate, CancellationToken cancellationToken = default) - { - return _orm.Select().Where(predicate).AnyAsync(cancellationToken); - } + => _orm.Select().Where(predicate).AnyAsync(cancellationToken); /// public Task GetByIdAsync(Guid id, CancellationToken cancellationToken = default) - { - return _orm.Select().Where(e => e.Id == id).FirstAsync(cancellationToken)!; - } + => _orm.Select().Where(e => e.Id == id).FirstAsync(cancellationToken)!; /// public async Task> GetPagedAsync( @@ -185,9 +177,7 @@ await RunInTransactionAsync( /// public ISelect Query() - { - return _orm.Select(); - } + => _orm.Select(); /// public async Task> QueryAsync( @@ -212,9 +202,9 @@ public async Task UpdateAsync(TEntity entity, CancellationToken cancell await RunInTransactionAsync( transaction => _orm.Update() - .SetSource(entity) - .WithTransaction(transaction) - .ExecuteAffrowsAsync(cancellationToken), + .SetSource(entity) + .WithTransaction(transaction) + .ExecuteAffrowsAsync(cancellationToken), "Update", 1, cancellationToken diff --git a/src/SquidStd.Database/Extensions/RegisterDatabaseExtension.cs b/src/SquidStd.Database/Extensions/RegisterDatabaseExtension.cs index abb91982..a357e873 100644 --- a/src/SquidStd.Database/Extensions/RegisterDatabaseExtension.cs +++ b/src/SquidStd.Database/Extensions/RegisterDatabaseExtension.cs @@ -10,7 +10,7 @@ namespace SquidStd.Database.Extensions; /// -/// DI registration for the database subsystem. +/// DI registration for the database subsystem. /// public static class RegisterDatabaseExtension { @@ -18,7 +18,7 @@ public static class RegisterDatabaseExtension extension(IContainer container) { /// - /// Registers the database config section, the database service, and the open-generic data access. + /// Registers the database config section, the database service, and the open-generic data access. /// /// The same container for chaining. public IContainer RegisterDatabase() diff --git a/src/SquidStd.Database/Extensions/ZLinqResultExtensions.cs b/src/SquidStd.Database/Extensions/ZLinqResultExtensions.cs index 16922587..5985a19a 100644 --- a/src/SquidStd.Database/Extensions/ZLinqResultExtensions.cs +++ b/src/SquidStd.Database/Extensions/ZLinqResultExtensions.cs @@ -3,7 +3,7 @@ namespace SquidStd.Database.Extensions; /// -/// Zero-allocation, in-memory helpers (ZLinq) over already-materialized result lists. +/// Zero-allocation, in-memory helpers (ZLinq) over already-materialized result lists. /// public static class ZLinqResultExtensions { @@ -11,25 +11,21 @@ public static class ZLinqResultExtensions extension(IReadOnlyList source) { /// - /// Projects each materialized item to a new form using ZLinq, returning a list. + /// Projects each materialized item to a new form using ZLinq, returning a list. /// /// The source item type. /// The projected item type. /// The projection. /// The projected list. - public List MapToList( - Func selector - ) - { - return source.AsValueEnumerable().Select(selector).ToList(); - } + public List MapToList(Func selector) + => source.AsValueEnumerable().Select(selector).ToList(); } /// The materialized source items. extension(IReadOnlyList source) { /// - /// Takes an in-memory page of a materialized list using ZLinq (no SQL involved). + /// Takes an in-memory page of a materialized list using ZLinq (no SQL involved). /// /// The item type. /// The 1-based page number. diff --git a/src/SquidStd.Database/Interfaces/Services/IDatabaseService.cs b/src/SquidStd.Database/Interfaces/Services/IDatabaseService.cs index 1662dde7..0ce04e6d 100644 --- a/src/SquidStd.Database/Interfaces/Services/IDatabaseService.cs +++ b/src/SquidStd.Database/Interfaces/Services/IDatabaseService.cs @@ -3,7 +3,7 @@ namespace SquidStd.Database.Interfaces.Services; /// -/// Owns the application's singleton FreeSql instance and its lifecycle. +/// Owns the application's singleton FreeSql instance and its lifecycle. /// public interface IDatabaseService : ISquidStdService { diff --git a/src/SquidStd.Database/Services/DatabaseService.cs b/src/SquidStd.Database/Services/DatabaseService.cs index e9a7512c..7b606ea2 100644 --- a/src/SquidStd.Database/Services/DatabaseService.cs +++ b/src/SquidStd.Database/Services/DatabaseService.cs @@ -8,7 +8,7 @@ namespace SquidStd.Database.Services; /// -/// Builds and owns the singleton FreeSql instance, logging SQL and migrations verbosely. +/// Builds and owns the singleton FreeSql instance, logging SQL and migrations verbosely. /// public sealed class DatabaseService : IDatabaseService { @@ -22,7 +22,7 @@ public sealed class DatabaseService : IDatabaseService public IFreeSql Orm => _orm ?? throw new InvalidOperationException("Database service is not started."); /// - /// Initializes the database service. + /// Initializes the database service. /// /// The database configuration section. public DatabaseService(DatabaseConfig config) @@ -44,13 +44,13 @@ public ValueTask StartAsync(CancellationToken cancellationToken = default) Logger.Verbose("Building FreeSql for provider {Provider}", parsed.Provider); var builder = new FreeSqlBuilder() - .UseConnectionString(MapDataType(parsed.Provider), parsed.NativeConnectionString) - .UseAutoSyncStructure(_config.AutoMigrate) - .UseMonitorCommand(cmd => Logger.Verbose("SQL {Sql}", cmd.CommandText)); + .UseConnectionString(MapDataType(parsed.Provider), parsed.NativeConnectionString) + .UseAutoSyncStructure(_config.AutoMigrate) + .UseMonitorCommand(cmd => Logger.Verbose("SQL {Sql}", cmd.CommandText)); _orm = builder.Build(); _orm.Aop.SyncStructureAfter += (_, e) => - Logger.Verbose("Migrated {Entities} -> {Sql}", e.EntityTypes, e.Sql); + Logger.Verbose("Migrated {Entities} -> {Sql}", e.EntityTypes, e.Sql); Logger.Information( "Database service started ({Provider}, autoMigrate={AutoMigrate})", @@ -73,8 +73,7 @@ public ValueTask StopAsync(CancellationToken cancellationToken = default) } private static DataType MapDataType(DatabaseProviderType provider) - { - return provider switch + => provider switch { DatabaseProviderType.Sqlite => DataType.Sqlite, DatabaseProviderType.Postgres => DataType.PostgreSQL, @@ -82,5 +81,4 @@ private static DataType MapDataType(DatabaseProviderType provider) DatabaseProviderType.MySql => DataType.MySql, _ => throw new NotSupportedException($"Unsupported provider {provider}.") }; - } } diff --git a/src/SquidStd.Generators/AnalyzerReleases.Unshipped.md b/src/SquidStd.Generators/AnalyzerReleases.Unshipped.md index 8dd9d9fb..822e1d6d 100644 --- a/src/SquidStd.Generators/AnalyzerReleases.Unshipped.md +++ b/src/SquidStd.Generators/AnalyzerReleases.Unshipped.md @@ -3,10 +3,10 @@ ### New Rules -Rule ID | Category | Severity | Notes ---------|----------|----------|------ -SQDGEN001 | SquidStd.Generators | Warning | Event listener cannot be generated -SQDGEN002 | SquidStd.Generators | Warning | Standard service cannot be generated -SQDGEN003 | SquidStd.Generators | Warning | Config section cannot be generated -SQDGEN004 | SquidStd.Generators | Warning | Job handler cannot be generated -SQDGEN005 | SquidStd.Generators | Warning | Script module cannot be generated + Rule ID | Category | Severity | Notes +-----------|---------------------|----------|-------------------------------------- + SQDGEN001 | SquidStd.Generators | Warning | Event listener cannot be generated + SQDGEN002 | SquidStd.Generators | Warning | Standard service cannot be generated + SQDGEN003 | SquidStd.Generators | Warning | Config section cannot be generated + SQDGEN004 | SquidStd.Generators | Warning | Job handler cannot be generated + SQDGEN005 | SquidStd.Generators | Warning | Script module cannot be generated diff --git a/src/SquidStd.Generators/Common/GeneratorSymbolHelpers.cs b/src/SquidStd.Generators/Common/GeneratorSymbolHelpers.cs index 6f10a228..10108900 100644 --- a/src/SquidStd.Generators/Common/GeneratorSymbolHelpers.cs +++ b/src/SquidStd.Generators/Common/GeneratorSymbolHelpers.cs @@ -5,24 +5,16 @@ namespace SquidStd.Generators.Common; internal static class GeneratorSymbolHelpers { public static string FullyQualified(ITypeSymbol symbol) - { - return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - } + => symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); public static string DisplayName(ISymbol symbol) - { - return symbol.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat); - } + => symbol.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat); public static Location? PrimaryLocation(ISymbol symbol) - { - return symbol.Locations.FirstOrDefault(); - } + => symbol.Locations.FirstOrDefault(); public static bool IsConcreteNonGenericClass(INamedTypeSymbol type) - { - return type.TypeKind == TypeKind.Class && !type.IsAbstract && !type.IsGenericType; - } + => type.TypeKind == TypeKind.Class && !type.IsAbstract && !type.IsGenericType; public static bool IsAccessibleFromGeneratedSource(INamedTypeSymbol type) { @@ -42,16 +34,15 @@ public static bool IsAccessibleFromGeneratedSource(INamedTypeSymbol type) } public static bool ImplementsInterface(INamedTypeSymbol type, string metadataName, string namespaceName) - { - return type.AllInterfaces.Any(interfaceType => + => type.AllInterfaces.Any( + interfaceType => { var originalDefinition = interfaceType.OriginalDefinition; - return originalDefinition.MetadataName == metadataName - && originalDefinition.ContainingNamespace.ToDisplayString() == namespaceName; + return originalDefinition.MetadataName == metadataName && + originalDefinition.ContainingNamespace.ToDisplayString() == namespaceName; } ); - } public static bool IsAssignableTo(INamedTypeSymbol implementationType, INamedTypeSymbol serviceType) { @@ -68,15 +59,15 @@ public static bool IsAssignableTo(INamedTypeSymbol implementationType, INamedTyp } } - return implementationType.AllInterfaces.Any(interfaceType => - SymbolEqualityComparer.Default.Equals(interfaceType, serviceType) + return implementationType.AllInterfaces.Any( + interfaceType => + SymbolEqualityComparer.Default.Equals(interfaceType, serviceType) ); } public static bool HasPublicParameterlessConstructor(INamedTypeSymbol type) - { - return type.InstanceConstructors.Any(constructor => - constructor.Parameters.Length == 0 && constructor.DeclaredAccessibility == Accessibility.Public + => type.InstanceConstructors.Any( + constructor => + constructor.Parameters.Length == 0 && constructor.DeclaredAccessibility == Accessibility.Public ); - } } diff --git a/src/SquidStd.Generators/Config/ConfigSectionRegistrationGenerator.cs b/src/SquidStd.Generators/Config/ConfigSectionRegistrationGenerator.cs index c45894b8..ec82ca29 100644 --- a/src/SquidStd.Generators/Config/ConfigSectionRegistrationGenerator.cs +++ b/src/SquidStd.Generators/Config/ConfigSectionRegistrationGenerator.cs @@ -35,12 +35,12 @@ CancellationToken cancellationToken var sectionName = GetSectionName(attribute); var priority = GetIntNamedArgument(attribute, "Priority"); - var isSupported = !string.IsNullOrWhiteSpace(sectionName) - && GeneratorSymbolHelpers.IsConcreteNonGenericClass(configType) - && GeneratorSymbolHelpers.IsAccessibleFromGeneratedSource(configType) - && GeneratorSymbolHelpers.HasPublicParameterlessConstructor(configType); + var isSupported = !string.IsNullOrWhiteSpace(sectionName) && + GeneratorSymbolHelpers.IsConcreteNonGenericClass(configType) && + GeneratorSymbolHelpers.IsAccessibleFromGeneratedSource(configType) && + GeneratorSymbolHelpers.HasPublicParameterlessConstructor(configType); - return new ConfigSectionRegistrationCandidate( + return new( GeneratorSymbolHelpers.FullyQualified(configType), sectionName ?? string.Empty, GeneratorSymbolHelpers.DisplayName(configType), @@ -97,19 +97,21 @@ ImmutableArray candidates } var key = candidate.SectionName + "|" + candidate.ConfigTypeName; + if (seenKeys.Add(key)) { supported.Add(candidate); } } - supported.Sort(static (left, right) => + supported.Sort( + static (left, right) => { var sectionComparison = string.Compare(left.SectionName, right.SectionName, StringComparison.Ordinal); return sectionComparison != 0 - ? sectionComparison - : string.Compare(left.ConfigTypeName, right.ConfigTypeName, StringComparison.Ordinal); + ? sectionComparison + : string.Compare(left.ConfigTypeName, right.ConfigTypeName, StringComparison.Ordinal); } ); diff --git a/src/SquidStd.Generators/Config/ConfigSectionSourceBuilder.cs b/src/SquidStd.Generators/Config/ConfigSectionSourceBuilder.cs index d145ddd8..75db280b 100644 --- a/src/SquidStd.Generators/Config/ConfigSectionSourceBuilder.cs +++ b/src/SquidStd.Generators/Config/ConfigSectionSourceBuilder.cs @@ -43,7 +43,5 @@ public static string Build(IReadOnlyList can } private static string FormatStringLiteral(string value) - { - return "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""; - } + => "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""; } diff --git a/src/SquidStd.Generators/Events/EventListenerRegistrationGenerator.cs b/src/SquidStd.Generators/Events/EventListenerRegistrationGenerator.cs index 3556912a..df4b7844 100644 --- a/src/SquidStd.Generators/Events/EventListenerRegistrationGenerator.cs +++ b/src/SquidStd.Generators/Events/EventListenerRegistrationGenerator.cs @@ -51,6 +51,7 @@ CancellationToken cancellationToken for (var i = 0; i < listenerType.AllInterfaces.Length; i++) { var interfaceType = listenerType.AllInterfaces[i]; + if (!IsEventListenerInterface(interfaceType)) { continue; @@ -61,12 +62,12 @@ CancellationToken cancellationToken continue; } - var isSupported = !listenerType.IsGenericType - && IsAccessibleFromGeneratedSource(listenerType) - && IsAccessibleFromGeneratedSource(eventType); + var isSupported = !listenerType.IsGenericType && + IsAccessibleFromGeneratedSource(listenerType) && + IsAccessibleFromGeneratedSource(eventType); candidates.Add( - new EventListenerCandidate( + new( eventType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), listenerType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), listenerType.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), @@ -83,8 +84,8 @@ private static bool IsEventListenerInterface(INamedTypeSymbol interfaceType) { var originalDefinition = interfaceType.OriginalDefinition; - return originalDefinition.MetadataName == EventListenerMetadataName - && originalDefinition.ContainingNamespace.ToDisplayString() == EventListenerNamespace; + return originalDefinition.MetadataName == EventListenerMetadataName && + originalDefinition.ContainingNamespace.ToDisplayString() == EventListenerNamespace; } private static bool IsAccessibleFromGeneratedSource(INamedTypeSymbol type) @@ -134,6 +135,7 @@ ImmutableArray> candidateGroups } var key = candidate.EventTypeName + "|" + candidate.ListenerTypeName; + if (seenKeys.Add(key)) { candidates.Add(candidate); @@ -141,7 +143,8 @@ ImmutableArray> candidateGroups } } - candidates.Sort(static (left, right) => string.Compare( + candidates.Sort( + static (left, right) => string.Compare( left.ListenerTypeName, right.ListenerTypeName, StringComparison.Ordinal diff --git a/src/SquidStd.Generators/README.md b/src/SquidStd.Generators/README.md index 405eb948..4cf86aa9 100644 --- a/src/SquidStd.Generators/README.md +++ b/src/SquidStd.Generators/README.md @@ -10,7 +10,8 @@ dotnet add package SquidStd.Generators ## Usage -The event listener generator discovers concrete `IEventListener` implementations marked with `[RegisterEventListener]` and generates a DryIoc registration extension: +The event listener generator discovers concrete `IEventListener` implementations marked with +`[RegisterEventListener]` and generates a DryIoc registration extension: ```csharp using SquidStd.Abstractions.Attributes; @@ -26,22 +27,27 @@ public sealed class PingListener : IEventListener container.RegisterGeneratedEventListeners(); ``` -The generated method reuses the normal `RegisterEventListener()` runtime path, so listener activation stays compatible with `SquidStd.Services.Core`. Each registration family has its own marker attribute and generated extension method, all calling the same runtime APIs as manual registration (`RegisterStdService`, `RegisterConfigSection`, `AddJobHandler`, `RegisterScriptModule`). +The generated method reuses the normal `RegisterEventListener()` runtime path, so listener activation stays +compatible with `SquidStd.Services.Core`. Each registration family has its own marker attribute and generated extension +method, all calling the same runtime APIs as manual registration (`RegisterStdService`, `RegisterConfigSection`, +`AddJobHandler`, `RegisterScriptModule`). ## Key types -| Marker attribute | Generated method | -|------------------|------------------| -| `[RegisterEventListener]` | `RegisterGeneratedEventListeners()` | -| `[RegisterStdService(typeof(IMyService), Priority = 10)]` | `RegisterGeneratedStdServices()` | -| `[RegisterConfigSection("workers", Priority = -50)]` | `RegisterGeneratedConfigSections()` | -| `[RegisterJobHandler]` | `RegisterGeneratedJobHandlers()` | -| `[RegisterScriptModule]` with `[ScriptModule("name")]` | `RegisterGeneratedScriptModules()` | +| Marker attribute | Generated method | +|-----------------------------------------------------------|-------------------------------------| +| `[RegisterEventListener]` | `RegisterGeneratedEventListeners()` | +| `[RegisterStdService(typeof(IMyService), Priority = 10)]` | `RegisterGeneratedStdServices()` | +| `[RegisterConfigSection("workers", Priority = -50)]` | `RegisterGeneratedConfigSections()` | +| `[RegisterJobHandler]` | `RegisterGeneratedJobHandlers()` | +| `[RegisterScriptModule]` with `[ScriptModule("name")]` | `RegisterGeneratedScriptModules()` | ## Related -- Tutorial: [Source generators: event listeners](https://tgiachi.github.io/squid-std/tutorials/source-generators-event-listeners.html) -- Tutorial: [Source generators: registration](https://tgiachi.github.io/squid-std/tutorials/source-generators-registration.html) +- +Tutorial: [Source generators: event listeners](https://tgiachi.github.io/squid-std/tutorials/source-generators-event-listeners.html) +- +Tutorial: [Source generators: registration](https://tgiachi.github.io/squid-std/tutorials/source-generators-registration.html) ## License diff --git a/src/SquidStd.Generators/Scripting/Lua/ScriptModuleRegistrationGenerator.cs b/src/SquidStd.Generators/Scripting/Lua/ScriptModuleRegistrationGenerator.cs index 5a4a0427..cafde2d0 100644 --- a/src/SquidStd.Generators/Scripting/Lua/ScriptModuleRegistrationGenerator.cs +++ b/src/SquidStd.Generators/Scripting/Lua/ScriptModuleRegistrationGenerator.cs @@ -33,11 +33,11 @@ CancellationToken cancellationToken cancellationToken.ThrowIfCancellationRequested(); var scriptModuleType = (INamedTypeSymbol)context.TargetSymbol; - var isSupported = GeneratorSymbolHelpers.IsConcreteNonGenericClass(scriptModuleType) - && GeneratorSymbolHelpers.IsAccessibleFromGeneratedSource(scriptModuleType) - && HasScriptModuleAttribute(scriptModuleType); + var isSupported = GeneratorSymbolHelpers.IsConcreteNonGenericClass(scriptModuleType) && + GeneratorSymbolHelpers.IsAccessibleFromGeneratedSource(scriptModuleType) && + HasScriptModuleAttribute(scriptModuleType); - return new ScriptModuleRegistrationCandidate( + return new( GeneratorSymbolHelpers.FullyQualified(scriptModuleType), GeneratorSymbolHelpers.DisplayName(scriptModuleType), GeneratorSymbolHelpers.PrimaryLocation(scriptModuleType), @@ -46,18 +46,17 @@ CancellationToken cancellationToken } private static bool HasScriptModuleAttribute(INamedTypeSymbol type) - { - return type.GetAttributes() - .Any(attribute => - { - var attributeClass = attribute.AttributeClass; + => type.GetAttributes() + .Any( + attribute => + { + var attributeClass = attribute.AttributeClass; - return attributeClass is not null - && attributeClass.MetadataName == ScriptModuleAttributeMetadataName - && attributeClass.ContainingNamespace.ToDisplayString() == ScriptModuleAttributeNamespace; - } - ); - } + return attributeClass is not null && + attributeClass.MetadataName == ScriptModuleAttributeMetadataName && + attributeClass.ContainingNamespace.ToDisplayString() == ScriptModuleAttributeNamespace; + } + ); private static void Execute( SourceProductionContext context, @@ -88,7 +87,8 @@ ImmutableArray candidates } } - supported.Sort(static (left, right) => string.Compare( + supported.Sort( + static (left, right) => string.Compare( left.ScriptModuleTypeName, right.ScriptModuleTypeName, StringComparison.Ordinal diff --git a/src/SquidStd.Generators/Services/StdServiceRegistrationGenerator.cs b/src/SquidStd.Generators/Services/StdServiceRegistrationGenerator.cs index 2fd7aae3..890ed61c 100644 --- a/src/SquidStd.Generators/Services/StdServiceRegistrationGenerator.cs +++ b/src/SquidStd.Generators/Services/StdServiceRegistrationGenerator.cs @@ -35,13 +35,13 @@ CancellationToken cancellationToken var serviceType = GetServiceType(attribute); var priority = GetIntNamedArgument(attribute, "Priority"); - var isSupported = serviceType is not null - && GeneratorSymbolHelpers.IsConcreteNonGenericClass(implementationType) - && GeneratorSymbolHelpers.IsAccessibleFromGeneratedSource(implementationType) - && GeneratorSymbolHelpers.IsAccessibleFromGeneratedSource(serviceType) - && GeneratorSymbolHelpers.IsAssignableTo(implementationType, serviceType); + var isSupported = serviceType is not null && + GeneratorSymbolHelpers.IsConcreteNonGenericClass(implementationType) && + GeneratorSymbolHelpers.IsAccessibleFromGeneratedSource(implementationType) && + GeneratorSymbolHelpers.IsAccessibleFromGeneratedSource(serviceType) && + GeneratorSymbolHelpers.IsAssignableTo(implementationType, serviceType); - return new StdServiceRegistrationCandidate( + return new( serviceType is null ? string.Empty : GeneratorSymbolHelpers.FullyQualified(serviceType), GeneratorSymbolHelpers.FullyQualified(implementationType), GeneratorSymbolHelpers.DisplayName(implementationType), @@ -95,13 +95,15 @@ private static void Execute(SourceProductionContext context, ImmutableArray string.Compare( + supported.Sort( + static (left, right) => string.Compare( left.ImplementationTypeName, right.ImplementationTypeName, StringComparison.Ordinal diff --git a/src/SquidStd.Generators/SquidStd.Generators.csproj b/src/SquidStd.Generators/SquidStd.Generators.csproj index e931f201..f9d941dc 100644 --- a/src/SquidStd.Generators/SquidStd.Generators.csproj +++ b/src/SquidStd.Generators/SquidStd.Generators.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/src/SquidStd.Generators/Workers/JobHandlerRegistrationGenerator.cs b/src/SquidStd.Generators/Workers/JobHandlerRegistrationGenerator.cs index 59ccd643..d3c01708 100644 --- a/src/SquidStd.Generators/Workers/JobHandlerRegistrationGenerator.cs +++ b/src/SquidStd.Generators/Workers/JobHandlerRegistrationGenerator.cs @@ -31,15 +31,15 @@ CancellationToken cancellationToken cancellationToken.ThrowIfCancellationRequested(); var handlerType = (INamedTypeSymbol)context.TargetSymbol; - var isSupported = GeneratorSymbolHelpers.IsConcreteNonGenericClass(handlerType) - && GeneratorSymbolHelpers.IsAccessibleFromGeneratedSource(handlerType) - && GeneratorSymbolHelpers.ImplementsInterface( + var isSupported = GeneratorSymbolHelpers.IsConcreteNonGenericClass(handlerType) && + GeneratorSymbolHelpers.IsAccessibleFromGeneratedSource(handlerType) && + GeneratorSymbolHelpers.ImplementsInterface( handlerType, "IJobHandler", "SquidStd.Workers.Interfaces" ); - return new JobHandlerRegistrationCandidate( + return new( GeneratorSymbolHelpers.FullyQualified(handlerType), GeneratorSymbolHelpers.DisplayName(handlerType), GeneratorSymbolHelpers.PrimaryLocation(handlerType), @@ -76,7 +76,8 @@ ImmutableArray candidates } } - supported.Sort(static (left, right) => string.Compare( + supported.Sort( + static (left, right) => string.Compare( left.HandlerTypeName, right.HandlerTypeName, StringComparison.Ordinal diff --git a/src/SquidStd.Mail.Abstractions/Exceptions/MailSendException.cs b/src/SquidStd.Mail.Abstractions/Exceptions/MailSendException.cs index b7b4c6e7..d640d699 100644 --- a/src/SquidStd.Mail.Abstractions/Exceptions/MailSendException.cs +++ b/src/SquidStd.Mail.Abstractions/Exceptions/MailSendException.cs @@ -5,7 +5,5 @@ public sealed class MailSendException : Exception { /// Initializes the exception with a message and the underlying cause. public MailSendException(string message, Exception innerException) - : base(message, innerException) - { - } + : base(message, innerException) { } } diff --git a/src/SquidStd.Mail.Abstractions/Interfaces/IMailReader.cs b/src/SquidStd.Mail.Abstractions/Interfaces/IMailReader.cs index 4ba210f8..3038bfb5 100644 --- a/src/SquidStd.Mail.Abstractions/Interfaces/IMailReader.cs +++ b/src/SquidStd.Mail.Abstractions/Interfaces/IMailReader.cs @@ -6,8 +6,8 @@ namespace SquidStd.Mail.Abstractions.Interfaces; public interface IMailReader { /// - /// Connects, fetches the new (unseen) messages, marks them seen / deletes them per options, disconnects, - /// and returns the parsed messages. + /// Connects, fetches the new (unseen) messages, marks them seen / deletes them per options, disconnects, + /// and returns the parsed messages. /// Task> FetchNewAsync(CancellationToken cancellationToken = default); } diff --git a/src/SquidStd.Mail.MailKit/Extensions/MailRegistrationExtensions.cs b/src/SquidStd.Mail.MailKit/Extensions/MailRegistrationExtensions.cs index 7faf1e79..9189363f 100644 --- a/src/SquidStd.Mail.MailKit/Extensions/MailRegistrationExtensions.cs +++ b/src/SquidStd.Mail.MailKit/Extensions/MailRegistrationExtensions.cs @@ -16,8 +16,8 @@ public static class MailRegistrationExtensions extension(IContainer container) { /// - /// Registers a single mailbox poller: the options, the protocol-specific , the - /// polling service, and the timer-wheel pump (only if not already registered). + /// Registers a single mailbox poller: the options, the protocol-specific , the + /// polling service, and the timer-wheel pump (only if not already registered). /// public IContainer AddMail(MailOptions options) { diff --git a/src/SquidStd.Mail.MailKit/README.md b/src/SquidStd.Mail.MailKit/README.md index 0465aa6c..0117e9bf 100644 --- a/src/SquidStd.Mail.MailKit/README.md +++ b/src/SquidStd.Mail.MailKit/README.md @@ -65,12 +65,12 @@ await sender.SendAsync(new OutgoingMailMessage ## Key types -| Type | Purpose | -|------|---------| -| `MailRegistrationExtensions` | `AddMail(...)` registration (IMAP/POP3 polling). | -| `MailSenderRegistrationExtensions` | `AddMailSender(...)` registration (SMTP). | -| `ImapMailReader` / `Pop3MailReader` | `IMailReader` implementations. | -| `MailKitMailSender` | `IMailSender` implementation over SMTP. | +| Type | Purpose | +|-------------------------------------|--------------------------------------------------| +| `MailRegistrationExtensions` | `AddMail(...)` registration (IMAP/POP3 polling). | +| `MailSenderRegistrationExtensions` | `AddMailSender(...)` registration (SMTP). | +| `ImapMailReader` / `Pop3MailReader` | `IMailReader` implementations. | +| `MailKitMailSender` | `IMailSender` implementation over SMTP. | ## Related diff --git a/src/SquidStd.Mail.MailKit/Services/MailPollingService.cs b/src/SquidStd.Mail.MailKit/Services/MailPollingService.cs index 7ae40175..0307a2aa 100644 --- a/src/SquidStd.Mail.MailKit/Services/MailPollingService.cs +++ b/src/SquidStd.Mail.MailKit/Services/MailPollingService.cs @@ -89,13 +89,9 @@ public async Task PollOnceAsync() } private void OnTick() - { - _ = PollOnceAsync(); - } + => _ = PollOnceAsync(); /// public void Dispose() - { - _gate.Dispose(); - } + => _gate.Dispose(); } diff --git a/src/SquidStd.Mail.MailKit/Services/MimeMessageMapper.cs b/src/SquidStd.Mail.MailKit/Services/MimeMessageMapper.cs index 8d959901..52335d34 100644 --- a/src/SquidStd.Mail.MailKit/Services/MimeMessageMapper.cs +++ b/src/SquidStd.Mail.MailKit/Services/MimeMessageMapper.cs @@ -15,9 +15,9 @@ public static MailMessage Map(MimeMessage message, bool includeAttachmentContent var to = message.To.Mailboxes.Select(ToAddress).ToArray(); var cc = message.Cc.Mailboxes.Select(ToAddress).ToArray(); var attachments = message.Attachments - .OfType() - .Select(part => ToAttachment(part, includeAttachmentContent)) - .ToArray(); + .OfType() + .Select(part => ToAttachment(part, includeAttachmentContent)) + .ToArray(); byte[]? rawEml = null; @@ -28,7 +28,7 @@ public static MailMessage Map(MimeMessage message, bool includeAttachmentContent rawEml = stream.ToArray(); } - return new MailMessage( + return new( from, to, cc, @@ -43,9 +43,7 @@ public static MailMessage Map(MimeMessage message, bool includeAttachmentContent } private static MailAddress ToAddress(MailboxAddress mailbox) - { - return new MailAddress(mailbox.Name ?? string.Empty, mailbox.Address); - } + => new(mailbox.Name ?? string.Empty, mailbox.Address); private static MailAttachment ToAttachment(MimePart part, bool includeContent) { @@ -65,6 +63,6 @@ private static MailAttachment ToAttachment(MimePart part, bool includeContent) var fileName = part.FileName ?? string.Empty; - return new MailAttachment(fileName, part.ContentType.MimeType, size, content); + return new(fileName, part.ContentType.MimeType, size, content); } } diff --git a/src/SquidStd.Mail.MailKit/Services/OutgoingMessageMapper.cs b/src/SquidStd.Mail.MailKit/Services/OutgoingMessageMapper.cs index c589197b..7ac2bd8b 100644 --- a/src/SquidStd.Mail.MailKit/Services/OutgoingMessageMapper.cs +++ b/src/SquidStd.Mail.MailKit/Services/OutgoingMessageMapper.cs @@ -44,7 +44,5 @@ public static MimeMessage ToMimeMessage(OutgoingMailMessage message, SmtpOptions } private static MailboxAddress ToMailbox(MailAddress address) - { - return new MailboxAddress(address.Name, address.Address); - } + => new(address.Name, address.Address); } diff --git a/src/SquidStd.Mail.Queue/Extensions/MailQueueRegistrationExtensions.cs b/src/SquidStd.Mail.Queue/Extensions/MailQueueRegistrationExtensions.cs index 75313393..5cdc396a 100644 --- a/src/SquidStd.Mail.Queue/Extensions/MailQueueRegistrationExtensions.cs +++ b/src/SquidStd.Mail.Queue/Extensions/MailQueueRegistrationExtensions.cs @@ -12,8 +12,8 @@ public static class MailQueueRegistrationExtensions extension(IContainer container) { /// - /// Registers the mail queue and its background consumer. Requires IMessageQueue (messaging) and - /// IMailSender (the SMTP sender) to be registered already. + /// Registers the mail queue and its background consumer. Requires IMessageQueue (messaging) and + /// IMailSender (the SMTP sender) to be registered already. /// public IContainer AddMailQueue(MailQueueOptions? options = null) { diff --git a/src/SquidStd.Mail.Queue/README.md b/src/SquidStd.Mail.Queue/README.md index 4d118cdd..889953dc 100644 --- a/src/SquidStd.Mail.Queue/README.md +++ b/src/SquidStd.Mail.Queue/README.md @@ -37,13 +37,13 @@ Retry/backoff/dead-letter are configured via `MessagingOptions` (`MaxDeliveryAtt ## Key types -| Type | Purpose | -|------|---------| -| `IMailQueue` | Enqueue an `OutgoingMailMessage` for background delivery. | -| `MailQueue` | `IMailQueue` implementation over the SquidStd messaging queue. | -| `MailSendConsumerService` | Background consumer that sends queued messages via `IMailSender`. | -| `MailQueueRegistrationExtensions` | `AddMailQueue(...)` registration. | -| `MailQueueOptions` | Queue name and send options. | +| Type | Purpose | +|-----------------------------------|-------------------------------------------------------------------| +| `IMailQueue` | Enqueue an `OutgoingMailMessage` for background delivery. | +| `MailQueue` | `IMailQueue` implementation over the SquidStd messaging queue. | +| `MailSendConsumerService` | Background consumer that sends queued messages via `IMailSender`. | +| `MailQueueRegistrationExtensions` | `AddMailQueue(...)` registration. | +| `MailQueueOptions` | Queue name and send options. | ## Related diff --git a/src/SquidStd.Mail.Queue/Services/MailSendConsumerService.cs b/src/SquidStd.Mail.Queue/Services/MailSendConsumerService.cs index a5bdf7bc..8a44a66d 100644 --- a/src/SquidStd.Mail.Queue/Services/MailSendConsumerService.cs +++ b/src/SquidStd.Mail.Queue/Services/MailSendConsumerService.cs @@ -8,8 +8,8 @@ namespace SquidStd.Mail.Queue.Services; /// -/// Consumes queued outbound messages and sends them via . Exceptions propagate so the -/// messaging layer retries / dead-letters. +/// Consumes queued outbound messages and sends them via . Exceptions propagate so the +/// messaging layer retries / dead-letters. /// public sealed class MailSendConsumerService : ISquidStdService, IQueueMessageListenerAsync { @@ -28,9 +28,7 @@ public MailSendConsumerService(IMessageQueue queue, IMailSender sender, MailQueu /// public Task HandleAsync(OutgoingMailMessage message, CancellationToken cancellationToken) - { - return _sender.SendAsync(message, cancellationToken); - } + => _sender.SendAsync(message, cancellationToken); /// public ValueTask StartAsync(CancellationToken cancellationToken = default) diff --git a/src/SquidStd.Messaging.Abstractions/Data/Config/MessagingConnectionString.cs b/src/SquidStd.Messaging.Abstractions/Data/Config/MessagingConnectionString.cs index c531dddc..9ca7ccd6 100644 --- a/src/SquidStd.Messaging.Abstractions/Data/Config/MessagingConnectionString.cs +++ b/src/SquidStd.Messaging.Abstractions/Data/Config/MessagingConnectionString.cs @@ -4,7 +4,7 @@ namespace SquidStd.Messaging.Abstractions.Data.Config; /// -/// Parsed messaging connection string of the form scheme://[user:pass@]host[:port][/vhost][?params]. +/// Parsed messaging connection string of the form scheme://[user:pass@]host[:port][/vhost][?params]. /// public sealed class MessagingConnectionString { @@ -68,14 +68,14 @@ public static MessagingConnectionString Parse(string connectionString) var virtualHost = uri.AbsolutePath.Trim('/'); var query = HttpUtility.ParseQueryString(uri.Query); var parameters = query.AllKeys - .Where(static key => key is not null) - .ToFrozenDictionary( - key => key!, - key => query[key] ?? string.Empty, - StringComparer.OrdinalIgnoreCase - ); - - return new MessagingConnectionString( + .Where(static key => key is not null) + .ToFrozenDictionary( + key => key!, + key => query[key] ?? string.Empty, + StringComparer.OrdinalIgnoreCase + ); + + return new( uri.Scheme, uri.Host, uri.Port > 0 ? uri.Port : null, @@ -88,17 +88,15 @@ public static MessagingConnectionString Parse(string connectionString) /// Builds from the query parameters. public MessagingOptions ToMessagingOptions() - { - return new MessagingOptions + => new() { MaxDeliveryAttempts = Parameters.TryGetValue("maxDeliveryAttempts", out var max) && int.TryParse(max, out var parsedMax) - ? parsedMax - : 3, + ? parsedMax + : 3, DeadLetterQueueSuffix = Parameters.TryGetValue("deadLetterSuffix", out var suffix) ? suffix : ".dlq", RetryDelay = Parameters.TryGetValue("retryDelayMs", out var delay) && int.TryParse(delay, out var parsedDelay) - ? TimeSpan.FromMilliseconds(parsedDelay) - : TimeSpan.Zero + ? TimeSpan.FromMilliseconds(parsedDelay) + : TimeSpan.Zero }; - } } diff --git a/src/SquidStd.Messaging.Abstractions/Data/Config/MessagingOptions.cs b/src/SquidStd.Messaging.Abstractions/Data/Config/MessagingOptions.cs index 482f174b..97afa226 100644 --- a/src/SquidStd.Messaging.Abstractions/Data/Config/MessagingOptions.cs +++ b/src/SquidStd.Messaging.Abstractions/Data/Config/MessagingOptions.cs @@ -1,7 +1,7 @@ namespace SquidStd.Messaging.Abstractions.Data.Config; /// -/// Configuration for the messaging system. +/// Configuration for the messaging system. /// public sealed class MessagingOptions { diff --git a/src/SquidStd.Messaging.Abstractions/Data/Events/TopicMessageEvent.cs b/src/SquidStd.Messaging.Abstractions/Data/Events/TopicMessageEvent.cs index b64fc0cd..b3a43554 100644 --- a/src/SquidStd.Messaging.Abstractions/Data/Events/TopicMessageEvent.cs +++ b/src/SquidStd.Messaging.Abstractions/Data/Events/TopicMessageEvent.cs @@ -3,7 +3,7 @@ namespace SquidStd.Messaging.Abstractions.Data.Events; /// -/// Event published on the in-process event bus when a topic message is bridged. is the -/// deserialized message. +/// Event published on the in-process event bus when a topic message is bridged. is the +/// deserialized message. /// public sealed record TopicMessageEvent(string Topic, object Data) : IEvent; diff --git a/src/SquidStd.Messaging.Abstractions/Interfaces/IMessageQueue.cs b/src/SquidStd.Messaging.Abstractions/Interfaces/IMessageQueue.cs index 0fd58df5..32f7011e 100644 --- a/src/SquidStd.Messaging.Abstractions/Interfaces/IMessageQueue.cs +++ b/src/SquidStd.Messaging.Abstractions/Interfaces/IMessageQueue.cs @@ -1,7 +1,7 @@ namespace SquidStd.Messaging.Abstractions.Interfaces; /// -/// Typed facade for publishing to and subscribing to named queues. +/// Typed facade for publishing to and subscribing to named queues. /// public interface IMessageQueue { diff --git a/src/SquidStd.Messaging.Abstractions/Interfaces/IMessageTopic.cs b/src/SquidStd.Messaging.Abstractions/Interfaces/IMessageTopic.cs index 09872ecc..e1b1c2be 100644 --- a/src/SquidStd.Messaging.Abstractions/Interfaces/IMessageTopic.cs +++ b/src/SquidStd.Messaging.Abstractions/Interfaces/IMessageTopic.cs @@ -1,7 +1,7 @@ namespace SquidStd.Messaging.Abstractions.Interfaces; /// -/// Typed facade for publishing to and subscribing to topics (fan-out). +/// Typed facade for publishing to and subscribing to topics (fan-out). /// public interface IMessageTopic { diff --git a/src/SquidStd.Messaging.Abstractions/Interfaces/IMessagingMetrics.cs b/src/SquidStd.Messaging.Abstractions/Interfaces/IMessagingMetrics.cs index 4b12e229..4ebcdb4e 100644 --- a/src/SquidStd.Messaging.Abstractions/Interfaces/IMessagingMetrics.cs +++ b/src/SquidStd.Messaging.Abstractions/Interfaces/IMessagingMetrics.cs @@ -1,7 +1,7 @@ namespace SquidStd.Messaging.Abstractions.Interfaces; /// -/// Sink for messaging metric events. Implementations must be thread-safe. +/// Sink for messaging metric events. Implementations must be thread-safe. /// public interface IMessagingMetrics { diff --git a/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueMessageListener.cs b/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueMessageListener.cs index a8d9d46a..b384b5f1 100644 --- a/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueMessageListener.cs +++ b/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueMessageListener.cs @@ -1,7 +1,7 @@ namespace SquidStd.Messaging.Abstractions.Interfaces; /// -/// Handles a queue message synchronously. +/// Handles a queue message synchronously. /// /// The message payload type. public interface IQueueMessageListener diff --git a/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueMessageListenerAsync.cs b/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueMessageListenerAsync.cs index 90f18c18..e7708457 100644 --- a/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueMessageListenerAsync.cs +++ b/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueMessageListenerAsync.cs @@ -1,7 +1,7 @@ namespace SquidStd.Messaging.Abstractions.Interfaces; /// -/// Handles a queue message asynchronously. +/// Handles a queue message asynchronously. /// /// The message payload type. public interface IQueueMessageListenerAsync diff --git a/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueProvider.cs b/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueProvider.cs index d7603f7e..18e26062 100644 --- a/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueProvider.cs +++ b/src/SquidStd.Messaging.Abstractions/Interfaces/IQueueProvider.cs @@ -3,7 +3,7 @@ namespace SquidStd.Messaging.Abstractions.Interfaces; /// -/// Byte-level queue transport owning buffering, round-robin delivery, retry and dead-lettering. +/// Byte-level queue transport owning buffering, round-robin delivery, retry and dead-lettering. /// public interface IQueueProvider : ISquidStdService, IAsyncDisposable { diff --git a/src/SquidStd.Messaging.Abstractions/Interfaces/ITopicEventBridge.cs b/src/SquidStd.Messaging.Abstractions/Interfaces/ITopicEventBridge.cs index 9cf69bac..2ba8483c 100644 --- a/src/SquidStd.Messaging.Abstractions/Interfaces/ITopicEventBridge.cs +++ b/src/SquidStd.Messaging.Abstractions/Interfaces/ITopicEventBridge.cs @@ -1,8 +1,8 @@ namespace SquidStd.Messaging.Abstractions.Interfaces; /// -/// Bridges a topic into the in-process event bus: each message of type T on the topic is republished -/// as a TopicMessageEvent. +/// Bridges a topic into the in-process event bus: each message of type T on the topic is republished +/// as a TopicMessageEvent. /// public interface ITopicEventBridge { diff --git a/src/SquidStd.Messaging.Abstractions/Interfaces/ITopicProvider.cs b/src/SquidStd.Messaging.Abstractions/Interfaces/ITopicProvider.cs index 3deffb58..c5882dc4 100644 --- a/src/SquidStd.Messaging.Abstractions/Interfaces/ITopicProvider.cs +++ b/src/SquidStd.Messaging.Abstractions/Interfaces/ITopicProvider.cs @@ -3,8 +3,8 @@ namespace SquidStd.Messaging.Abstractions.Interfaces; /// -/// Byte-level publish/subscribe transport: every current subscriber of a topic receives every message -/// (transient, at-most-once fan-out). +/// Byte-level publish/subscribe transport: every current subscriber of a topic receives every message +/// (transient, at-most-once fan-out). /// public interface ITopicProvider : ISquidStdService, IAsyncDisposable { diff --git a/src/SquidStd.Messaging.Abstractions/Services/MessageQueue.cs b/src/SquidStd.Messaging.Abstractions/Services/MessageQueue.cs index b1f2581b..8404b4a8 100644 --- a/src/SquidStd.Messaging.Abstractions/Services/MessageQueue.cs +++ b/src/SquidStd.Messaging.Abstractions/Services/MessageQueue.cs @@ -4,8 +4,8 @@ namespace SquidStd.Messaging.Abstractions.Services; /// -/// Typed facade over an : serializes outgoing messages and -/// deserializes incoming payloads before handing them to typed listeners. +/// Typed facade over an : serializes outgoing messages and +/// deserializes incoming payloads before handing them to typed listeners. /// public sealed class MessageQueue : IMessageQueue { @@ -22,9 +22,7 @@ public MessageQueue(IQueueProvider provider, IDataSerializer serializer, IDataDe /// public Task PublishAsync(string queueName, TMessage message, CancellationToken cancellationToken = default) - { - return _provider.PublishAsync(queueName, _serializer.Serialize(message), cancellationToken); - } + => _provider.PublishAsync(queueName, _serializer.Serialize(message), cancellationToken); /// public IDisposable Subscribe(string queueName, IQueueMessageListener listener) diff --git a/src/SquidStd.Messaging.Abstractions/Services/MessageTopic.cs b/src/SquidStd.Messaging.Abstractions/Services/MessageTopic.cs index 84085782..1b2de1dc 100644 --- a/src/SquidStd.Messaging.Abstractions/Services/MessageTopic.cs +++ b/src/SquidStd.Messaging.Abstractions/Services/MessageTopic.cs @@ -4,8 +4,8 @@ namespace SquidStd.Messaging.Abstractions.Services; /// -/// Typed facade over an : serializes outgoing messages and deserializes -/// incoming payloads. +/// Typed facade over an : serializes outgoing messages and deserializes +/// incoming payloads. /// public sealed class MessageTopic : IMessageTopic { @@ -22,9 +22,7 @@ public MessageTopic(ITopicProvider provider, IDataSerializer serializer, IDataDe /// public Task PublishAsync(string topic, TMessage message, CancellationToken cancellationToken = default) - { - return _provider.PublishAsync(topic, _serializer.Serialize(message), cancellationToken); - } + => _provider.PublishAsync(topic, _serializer.Serialize(message), cancellationToken); /// public IDisposable Subscribe(string topic, Func handler) diff --git a/src/SquidStd.Messaging.Abstractions/Services/MessagingMetricsProvider.cs b/src/SquidStd.Messaging.Abstractions/Services/MessagingMetricsProvider.cs index ef147307..626844b6 100644 --- a/src/SquidStd.Messaging.Abstractions/Services/MessagingMetricsProvider.cs +++ b/src/SquidStd.Messaging.Abstractions/Services/MessagingMetricsProvider.cs @@ -7,7 +7,7 @@ namespace SquidStd.Messaging.Abstractions.Services; /// -/// Accumulates messaging metrics and exposes them to the metrics collection system. +/// Accumulates messaging metrics and exposes them to the metrics collection system. /// public sealed class MessagingMetricsProvider : IMessagingMetrics, IMetricProvider { @@ -18,45 +18,31 @@ public sealed class MessagingMetricsProvider : IMessagingMetrics, IMetricProvide /// public void OnDeadLettered(string queueName) - { - Interlocked.Increment(ref Counters(queueName).DeadLettered); - } + => Interlocked.Increment(ref Counters(queueName).DeadLettered); /// public void OnDelivered(string queueName) - { - Interlocked.Increment(ref Counters(queueName).Delivered); - } + => Interlocked.Increment(ref Counters(queueName).Delivered); /// public void OnFailed(string queueName) - { - Interlocked.Increment(ref Counters(queueName).Failed); - } + => Interlocked.Increment(ref Counters(queueName).Failed); /// public void OnPublished(string queueName) - { - Interlocked.Increment(ref Counters(queueName).Published); - } + => Interlocked.Increment(ref Counters(queueName).Published); /// public void OnRetried(string queueName) - { - Interlocked.Increment(ref Counters(queueName).Retried); - } + => Interlocked.Increment(ref Counters(queueName).Retried); /// public void SetQueueDepth(string queueName, int depth) - { - Volatile.Write(ref Counters(queueName).Depth, depth); - } + => Volatile.Write(ref Counters(queueName).Depth, depth); /// public void SetSubscriberCount(string queueName, int count) - { - Volatile.Write(ref Counters(queueName).Subscribers, count); - } + => Volatile.Write(ref Counters(queueName).Subscribers, count); /// public ValueTask> CollectAsync(CancellationToken cancellationToken = default) @@ -67,37 +53,27 @@ public ValueTask> CollectAsync(CancellationToken can { var tags = new Dictionary(StringComparer.Ordinal) { ["queue"] = queueName }; + samples.Add(new("published", Interlocked.Read(ref counters.Published), Tags: tags, Type: MetricType.Counter)); + samples.Add(new("delivered", Interlocked.Read(ref counters.Delivered), Tags: tags, Type: MetricType.Counter)); + samples.Add(new("failed", Interlocked.Read(ref counters.Failed), Tags: tags, Type: MetricType.Counter)); + samples.Add(new("retried", Interlocked.Read(ref counters.Retried), Tags: tags, Type: MetricType.Counter)); samples.Add( - new MetricSample("published", Interlocked.Read(ref counters.Published), Tags: tags, Type: MetricType.Counter) - ); - samples.Add( - new MetricSample("delivered", Interlocked.Read(ref counters.Delivered), Tags: tags, Type: MetricType.Counter) - ); - samples.Add( - new MetricSample("failed", Interlocked.Read(ref counters.Failed), Tags: tags, Type: MetricType.Counter) - ); - samples.Add( - new MetricSample("retried", Interlocked.Read(ref counters.Retried), Tags: tags, Type: MetricType.Counter) - ); - samples.Add( - new MetricSample( + new( "dead_lettered", Interlocked.Read(ref counters.DeadLettered), Tags: tags, Type: MetricType.Counter ) ); - samples.Add(new MetricSample("queue_depth", Volatile.Read(ref counters.Depth), Tags: tags)); - samples.Add(new MetricSample("subscribers", Volatile.Read(ref counters.Subscribers), Tags: tags)); + samples.Add(new("queue_depth", Volatile.Read(ref counters.Depth), Tags: tags)); + samples.Add(new("subscribers", Volatile.Read(ref counters.Subscribers), Tags: tags)); } return ValueTask.FromResult>(samples); } private QueueCounters Counters(string queueName) - { - return _queues.GetOrAdd(queueName, static _ => new QueueCounters()); - } + => _queues.GetOrAdd(queueName, static _ => new()); private sealed class QueueCounters { diff --git a/src/SquidStd.Messaging.Abstractions/Services/NoOpMessagingMetrics.cs b/src/SquidStd.Messaging.Abstractions/Services/NoOpMessagingMetrics.cs index a51d632d..49fbfb26 100644 --- a/src/SquidStd.Messaging.Abstractions/Services/NoOpMessagingMetrics.cs +++ b/src/SquidStd.Messaging.Abstractions/Services/NoOpMessagingMetrics.cs @@ -3,38 +3,24 @@ namespace SquidStd.Messaging.Abstractions.Services; /// -/// Metrics sink that ignores all events. Used when no metrics are configured. +/// Metrics sink that ignores all events. Used when no metrics are configured. /// public sealed class NoOpMessagingMetrics : IMessagingMetrics { /// Shared instance. public static NoOpMessagingMetrics Instance { get; } = new(); - public void OnDeadLettered(string queueName) - { - } + public void OnDeadLettered(string queueName) { } - public void OnDelivered(string queueName) - { - } + public void OnDelivered(string queueName) { } - public void OnFailed(string queueName) - { - } + public void OnFailed(string queueName) { } - public void OnPublished(string queueName) - { - } + public void OnPublished(string queueName) { } - public void OnRetried(string queueName) - { - } + public void OnRetried(string queueName) { } - public void SetQueueDepth(string queueName, int depth) - { - } + public void SetQueueDepth(string queueName, int depth) { } - public void SetSubscriberCount(string queueName, int count) - { - } + public void SetSubscriberCount(string queueName, int count) { } } diff --git a/src/SquidStd.Messaging.Abstractions/Services/TopicEventBridge.cs b/src/SquidStd.Messaging.Abstractions/Services/TopicEventBridge.cs index 03e84c44..5e45bda4 100644 --- a/src/SquidStd.Messaging.Abstractions/Services/TopicEventBridge.cs +++ b/src/SquidStd.Messaging.Abstractions/Services/TopicEventBridge.cs @@ -5,8 +5,8 @@ namespace SquidStd.Messaging.Abstractions.Services; /// -/// One-way Topic → EventBus bridge. Subscribes a topic and republishes each message as a -/// on the . +/// One-way Topic → EventBus bridge. Subscribes a topic and republishes each message as a +/// on the . /// public sealed class TopicEventBridge : ITopicEventBridge { @@ -21,10 +21,8 @@ public TopicEventBridge(IMessageTopic topic, IEventBus eventBus) /// public IDisposable Bridge(string topic) - { - return _topic.Subscribe( + => _topic.Subscribe( topic, (data, cancellationToken) => _eventBus.PublishAsync(new TopicMessageEvent(topic, data!), cancellationToken) ); - } } diff --git a/src/SquidStd.Messaging.RabbitMq/Data/Config/RabbitMqOptions.cs b/src/SquidStd.Messaging.RabbitMq/Data/Config/RabbitMqOptions.cs index f4f90d1b..4e939ab7 100644 --- a/src/SquidStd.Messaging.RabbitMq/Data/Config/RabbitMqOptions.cs +++ b/src/SquidStd.Messaging.RabbitMq/Data/Config/RabbitMqOptions.cs @@ -1,7 +1,7 @@ namespace SquidStd.Messaging.RabbitMq.Data.Config; /// -/// Connection options for the RabbitMQ queue provider. +/// Connection options for the RabbitMQ queue provider. /// public sealed class RabbitMqOptions { diff --git a/src/SquidStd.Messaging.RabbitMq/Extensions/RabbitMqMessagingRegistrationExtensions.cs b/src/SquidStd.Messaging.RabbitMq/Extensions/RabbitMqMessagingRegistrationExtensions.cs index 5f3ad837..da9fe84f 100644 --- a/src/SquidStd.Messaging.RabbitMq/Extensions/RabbitMqMessagingRegistrationExtensions.cs +++ b/src/SquidStd.Messaging.RabbitMq/Extensions/RabbitMqMessagingRegistrationExtensions.cs @@ -11,7 +11,7 @@ namespace SquidStd.Messaging.RabbitMq.Extensions; /// -/// DryIoc registration helpers for the RabbitMQ messaging provider. +/// DryIoc registration helpers for the RabbitMQ messaging provider. /// public static class RabbitMqMessagingRegistrationExtensions { @@ -80,8 +80,8 @@ public IContainer AddRabbitMqMessaging(string connectionString) Password = cs.Password ?? "guest", PrefetchCount = cs.Parameters.TryGetValue("prefetch", out var prefetch) && ushort.TryParse(prefetch, out var parsed) - ? parsed - : (ushort)10 + ? parsed + : (ushort)10 }; return container.AddRabbitMqMessaging(options, cs.ToMessagingOptions()); diff --git a/src/SquidStd.Messaging.RabbitMq/Services/RabbitMqQueueProvider.cs b/src/SquidStd.Messaging.RabbitMq/Services/RabbitMqQueueProvider.cs index 1478923e..71cec08b 100644 --- a/src/SquidStd.Messaging.RabbitMq/Services/RabbitMqQueueProvider.cs +++ b/src/SquidStd.Messaging.RabbitMq/Services/RabbitMqQueueProvider.cs @@ -10,8 +10,8 @@ namespace SquidStd.Messaging.RabbitMq.Services; /// -/// RabbitMQ : named queues map to quorum queues with a delivery limit -/// and a dead-letter exchange; round-robin is the broker's native competing-consumers behaviour. +/// RabbitMQ : named queues map to quorum queues with a delivery limit +/// and a dead-letter exchange; round-robin is the broker's native competing-consumers behaviour. /// public sealed class RabbitMqQueueProvider : IQueueProvider { @@ -120,9 +120,7 @@ public async ValueTask StartAsync(CancellationToken cancellationToken = default) /// public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return DisposeAsync(); - } + => DisposeAsync(); /// public IDisposable Subscribe(string queueName, Func, CancellationToken, Task> handler) @@ -228,9 +226,7 @@ Func, CancellationToken, Task> handler } public void Start() - { - StartAsync().GetAwaiter().GetResult(); - } + => StartAsync().GetAwaiter().GetResult(); private async Task OnReceivedAsync(object sender, BasicDeliverEventArgs args) { diff --git a/src/SquidStd.Messaging.RabbitMq/Services/RabbitMqTopicProvider.cs b/src/SquidStd.Messaging.RabbitMq/Services/RabbitMqTopicProvider.cs index 58bb3361..2916fc38 100644 --- a/src/SquidStd.Messaging.RabbitMq/Services/RabbitMqTopicProvider.cs +++ b/src/SquidStd.Messaging.RabbitMq/Services/RabbitMqTopicProvider.cs @@ -7,8 +7,8 @@ namespace SquidStd.Messaging.RabbitMq.Services; /// -/// RabbitMQ : topics map to fanout exchanges; each subscriber binds an -/// exclusive auto-delete queue and consumes with auto-ack (transient, at-most-once fan-out). +/// RabbitMQ : topics map to fanout exchanges; each subscriber binds an +/// exclusive auto-delete queue and consumes with auto-ack (transient, at-most-once fan-out). /// public sealed class RabbitMqTopicProvider : ITopicProvider { @@ -102,9 +102,7 @@ public async ValueTask StartAsync(CancellationToken cancellationToken = default) /// public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return DisposeAsync(); - } + => DisposeAsync(); /// public IDisposable Subscribe(string topic, Func, CancellationToken, Task> handler) @@ -176,9 +174,7 @@ Func, CancellationToken, Task> handler } public void Start() - { - StartAsync().GetAwaiter().GetResult(); - } + => StartAsync().GetAwaiter().GetResult(); private async Task OnReceivedAsync(object sender, BasicDeliverEventArgs args) { diff --git a/src/SquidStd.Messaging.Sqs/Data/Config/SqsOptions.cs b/src/SquidStd.Messaging.Sqs/Data/Config/SqsOptions.cs index 7298d13a..2b2a14b1 100644 --- a/src/SquidStd.Messaging.Sqs/Data/Config/SqsOptions.cs +++ b/src/SquidStd.Messaging.Sqs/Data/Config/SqsOptions.cs @@ -3,8 +3,8 @@ namespace SquidStd.Messaging.Sqs.Data.Config; /// -/// Configuration for the SQS/SNS messaging provider. Connection details live in ; -/// the remaining knobs tune SQS receive behaviour. +/// Configuration for the SQS/SNS messaging provider. Connection details live in ; +/// the remaining knobs tune SQS receive behaviour. /// public sealed class SqsOptions { diff --git a/src/SquidStd.Messaging.Sqs/Extensions/SqsMessagingRegistrationExtensions.cs b/src/SquidStd.Messaging.Sqs/Extensions/SqsMessagingRegistrationExtensions.cs index 90a9419d..6b4959ed 100644 --- a/src/SquidStd.Messaging.Sqs/Extensions/SqsMessagingRegistrationExtensions.cs +++ b/src/SquidStd.Messaging.Sqs/Extensions/SqsMessagingRegistrationExtensions.cs @@ -1,6 +1,5 @@ using System.Globalization; using DryIoc; -using SquidStd.Aws.Abstractions.Data.Config; using SquidStd.Core.Interfaces.Metrics; using SquidStd.Core.Interfaces.Serialization; using SquidStd.Core.Json; @@ -13,7 +12,7 @@ namespace SquidStd.Messaging.Sqs.Extensions; /// -/// DryIoc registration helpers for the AWS SQS/SNS messaging provider. +/// DryIoc registration helpers for the AWS SQS/SNS messaging provider. /// public static class SqsMessagingRegistrationExtensions { @@ -30,9 +29,9 @@ public static SqsOptions ParseOptions(string connectionString) ); } - return new SqsOptions + return new() { - Aws = new AwsConfigEntry + Aws = new() { Region = string.IsNullOrEmpty(cs.Host) ? "us-east-1" : cs.Host, AccessKey = cs.UserName, @@ -42,16 +41,16 @@ public static SqsOptions ParseOptions(string connectionString) }, MaxNumberOfMessages = cs.Parameters.TryGetValue("maxMessages", out var max) && int.TryParse(max, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedMax) - ? parsedMax - : 10, + ? parsedMax + : 10, VisibilityTimeout = cs.Parameters.TryGetValue("visibilityTimeoutSec", out var vis) && int.TryParse(vis, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedVis) - ? TimeSpan.FromSeconds(parsedVis) - : TimeSpan.FromSeconds(30), + ? TimeSpan.FromSeconds(parsedVis) + : TimeSpan.FromSeconds(30), WaitTimeSeconds = cs.Parameters.TryGetValue("waitTimeSec", out var wait) && int.TryParse(wait, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedWait) - ? parsedWait - : 20 + ? parsedWait + : 20 }; } diff --git a/src/SquidStd.Messaging.Sqs/Internal/AwsClientFactory.cs b/src/SquidStd.Messaging.Sqs/Internal/AwsClientFactory.cs index f7466d6b..a055526c 100644 --- a/src/SquidStd.Messaging.Sqs/Internal/AwsClientFactory.cs +++ b/src/SquidStd.Messaging.Sqs/Internal/AwsClientFactory.cs @@ -7,7 +7,7 @@ namespace SquidStd.Messaging.Sqs.Internal; /// -/// Builds AWS SDK clients/credentials from a shared . +/// Builds AWS SDK clients/credentials from a shared . /// internal static class AwsClientFactory { @@ -16,8 +16,8 @@ public static AWSCredentials Credentials(AwsConfigEntry aws) if (!string.IsNullOrWhiteSpace(aws.AccessKey) && !string.IsNullOrWhiteSpace(aws.SecretKey)) { return string.IsNullOrWhiteSpace(aws.SessionToken) - ? new BasicAWSCredentials(aws.AccessKey, aws.SecretKey) - : new SessionAWSCredentials(aws.AccessKey, aws.SecretKey, aws.SessionToken); + ? new BasicAWSCredentials(aws.AccessKey, aws.SecretKey) + : new SessionAWSCredentials(aws.AccessKey, aws.SecretKey, aws.SessionToken); } return FallbackCredentialsFactory.GetCredentials(); diff --git a/src/SquidStd.Messaging.Sqs/Internal/SqsNames.cs b/src/SquidStd.Messaging.Sqs/Internal/SqsNames.cs index 15b6a275..8436dd48 100644 --- a/src/SquidStd.Messaging.Sqs/Internal/SqsNames.cs +++ b/src/SquidStd.Messaging.Sqs/Internal/SqsNames.cs @@ -1,7 +1,7 @@ namespace SquidStd.Messaging.Sqs.Internal; /// -/// Sanitizes queue/topic names to the SQS/SNS allowed alphabet (letters, digits, '-', '_'). +/// Sanitizes queue/topic names to the SQS/SNS allowed alphabet (letters, digits, '-', '_'). /// internal static class SqsNames { @@ -17,6 +17,6 @@ public static string Sanitize(string name) buffer[i] = char.IsAsciiLetterOrDigit(c) || c is '-' or '_' ? c : '-'; } - return new string(buffer); + return new(buffer); } } diff --git a/src/SquidStd.Messaging.Sqs/README.md b/src/SquidStd.Messaging.Sqs/README.md index 6aad0023..36db5ae0 100644 --- a/src/SquidStd.Messaging.Sqs/README.md +++ b/src/SquidStd.Messaging.Sqs/README.md @@ -32,12 +32,12 @@ container.AddSqsMessaging(new SqsOptions { Aws = new AwsConfigEntry { Region = " ## Key types -| Type | Purpose | -|-------------------------------------|------------------------------------------| -| `SqsMessagingRegistrationExtensions` | `AddSqsMessaging(...)` registration. | -| `SqsQueueProvider` | SQS-backed `IQueueProvider`. | -| `SqsTopicProvider` | SNS+SQS-backed `ITopicProvider`. | -| `SqsOptions` | AWS connection + queue/topic configuration. | +| Type | Purpose | +|--------------------------------------|---------------------------------------------| +| `SqsMessagingRegistrationExtensions` | `AddSqsMessaging(...)` registration. | +| `SqsQueueProvider` | SQS-backed `IQueueProvider`. | +| `SqsTopicProvider` | SNS+SQS-backed `ITopicProvider`. | +| `SqsOptions` | AWS connection + queue/topic configuration. | ## Related diff --git a/src/SquidStd.Messaging.Sqs/Services/SqsQueueProvider.cs b/src/SquidStd.Messaging.Sqs/Services/SqsQueueProvider.cs index 7910a2a9..a0df2c5f 100644 --- a/src/SquidStd.Messaging.Sqs/Services/SqsQueueProvider.cs +++ b/src/SquidStd.Messaging.Sqs/Services/SqsQueueProvider.cs @@ -13,10 +13,10 @@ namespace SquidStd.Messaging.Sqs.Services; /// -/// AWS SQS : named queues are created with a redrive policy to a -/// "<queue><suffix>" dead-letter queue (maxReceiveCount = MaxDeliveryAttempts). Subscribers -/// long-poll; a handler that throws leaves the message un-acked so SQS redelivers and eventually -/// dead-letters it. Payloads travel base64-encoded in the message body. +/// AWS SQS : named queues are created with a redrive policy to a +/// "<queue><suffix>" dead-letter queue (maxReceiveCount = MaxDeliveryAttempts). Subscribers +/// long-poll; a handler that throws leaves the message un-acked so SQS redelivers and eventually +/// dead-letters it. Payloads travel base64-encoded in the message body. /// public sealed class SqsQueueProvider : IQueueProvider { @@ -66,7 +66,7 @@ public async Task PublishAsync( var url = await EnsureQueueAsync(queueName, cancellationToken); await client.SendMessageAsync( - new SendMessageRequest { QueueUrl = url, MessageBody = Convert.ToBase64String(payload.Span) }, + new() { QueueUrl = url, MessageBody = Convert.ToBase64String(payload.Span) }, cancellationToken ); @@ -83,9 +83,7 @@ public ValueTask StartAsync(CancellationToken cancellationToken = default) /// public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return DisposeAsync(); - } + => DisposeAsync(); /// public IDisposable Subscribe(string queueName, Func, CancellationToken, Task> handler) @@ -132,9 +130,9 @@ private async Task EnsureQueueAsync(string queueName, CancellationToken { var dlqName = name + _deadLetterSuffix; var dlqUrl = (await client.CreateQueueAsync( - new CreateQueueRequest { QueueName = dlqName }, - cancellationToken - )).QueueUrl; + new CreateQueueRequest { QueueName = dlqName }, + cancellationToken + )).QueueUrl; var dlqArn = await GetQueueArnAsync(client, dlqUrl, cancellationToken); var redrivePolicy = JsonSerializer.Serialize( @@ -146,13 +144,13 @@ private async Task EnsureQueueAsync(string queueName, CancellationToken ); url = (await client.CreateQueueAsync( - new CreateQueueRequest - { - QueueName = name, - Attributes = new Dictionary { ["RedrivePolicy"] = redrivePolicy } - }, - cancellationToken - )).QueueUrl; + new CreateQueueRequest + { + QueueName = name, + Attributes = new() { ["RedrivePolicy"] = redrivePolicy } + }, + cancellationToken + )).QueueUrl; } _queueUrls[name] = url; @@ -172,9 +170,9 @@ CancellationToken cancellationToken ) { var response = await client.GetQueueAttributesAsync( - new GetQueueAttributesRequest { QueueUrl = queueUrl, AttributeNames = ["QueueArn"] }, - cancellationToken - ); + new() { QueueUrl = queueUrl, AttributeNames = ["QueueArn"] }, + cancellationToken + ); return response.Attributes["QueueArn"]; } @@ -203,9 +201,7 @@ Func, CancellationToken, Task> handler } public void Start() - { - _loop = Task.Run(() => RunAsync(_cts.Token)); - } + => _loop = Task.Run(() => RunAsync(_cts.Token)); private async Task RunAsync(CancellationToken cancellationToken) { @@ -233,15 +229,15 @@ private async Task RunAsync(CancellationToken cancellationToken) try { response = await _client.ReceiveMessageAsync( - new ReceiveMessageRequest - { - QueueUrl = url, - MaxNumberOfMessages = _provider._options.MaxNumberOfMessages, - WaitTimeSeconds = _provider._options.WaitTimeSeconds, - VisibilityTimeout = (int)_provider._options.VisibilityTimeout.TotalSeconds - }, - cancellationToken - ); + new ReceiveMessageRequest + { + QueueUrl = url, + MaxNumberOfMessages = _provider._options.MaxNumberOfMessages, + WaitTimeSeconds = _provider._options.WaitTimeSeconds, + VisibilityTimeout = (int)_provider._options.VisibilityTimeout.TotalSeconds + }, + cancellationToken + ); } catch (OperationCanceledException) { diff --git a/src/SquidStd.Messaging.Sqs/Services/SqsTopicProvider.cs b/src/SquidStd.Messaging.Sqs/Services/SqsTopicProvider.cs index 08d1c330..fbad2a80 100644 --- a/src/SquidStd.Messaging.Sqs/Services/SqsTopicProvider.cs +++ b/src/SquidStd.Messaging.Sqs/Services/SqsTopicProvider.cs @@ -12,9 +12,9 @@ namespace SquidStd.Messaging.Sqs.Services; /// -/// SNS+SQS : a topic is an SNS topic; each subscriber gets a dedicated -/// ephemeral SQS queue subscribed to the topic with raw message delivery, long-polled and torn down -/// on dispose (transient, at-most-once fan-out). Payloads travel base64-encoded. +/// SNS+SQS : a topic is an SNS topic; each subscriber gets a dedicated +/// ephemeral SQS queue subscribed to the topic with raw message delivery, long-polled and torn down +/// on dispose (transient, at-most-once fan-out). Payloads travel base64-encoded. /// public sealed class SqsTopicProvider : ITopicProvider { @@ -56,7 +56,7 @@ public async Task PublishAsync(string topic, ReadOnlyMemory payload, Cance var arn = await EnsureTopicAsync(topic, cancellationToken); await sns.PublishAsync( - new PublishRequest { TopicArn = arn, Message = Convert.ToBase64String(payload.Span) }, + new() { TopicArn = arn, Message = Convert.ToBase64String(payload.Span) }, cancellationToken ); } @@ -73,9 +73,7 @@ public ValueTask StartAsync(CancellationToken cancellationToken = default) /// public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return DisposeAsync(); - } + => DisposeAsync(); /// public IDisposable Subscribe(string topic, Func, CancellationToken, Task> handler) @@ -152,13 +150,10 @@ Func, CancellationToken, Task> handler } public void Start() - { - _loop = Task.Run(() => RunAsync(_cts.Token)); - } + => _loop = Task.Run(() => RunAsync(_cts.Token)); private static string BuildPolicy(string queueArn, string topicArn) - { - return JsonSerializer.Serialize( + => JsonSerializer.Serialize( new { Version = "2012-10-17", @@ -175,7 +170,6 @@ private static string BuildPolicy(string queueArn, string topicArn) } } ); - } private async Task RunAsync(CancellationToken cancellationToken) { @@ -186,37 +180,37 @@ private async Task RunAsync(CancellationToken cancellationToken) var topicArn = await _provider.EnsureTopicAsync(_topic, cancellationToken); var queueName = SqsNames.Sanitize(_topic) + "-sub-" + _index; queueUrl = (await _provider._sqs!.CreateQueueAsync( - new CreateQueueRequest { QueueName = queueName }, - cancellationToken - )).QueueUrl; + new CreateQueueRequest { QueueName = queueName }, + cancellationToken + )).QueueUrl; _queueUrl = queueUrl; var attributes = await _provider._sqs.GetQueueAttributesAsync( - new GetQueueAttributesRequest { QueueUrl = queueUrl, AttributeNames = ["QueueArn"] }, - cancellationToken - ); + new() { QueueUrl = queueUrl, AttributeNames = ["QueueArn"] }, + cancellationToken + ); var queueArn = attributes.Attributes["QueueArn"]; await _provider._sqs.SetQueueAttributesAsync( - new SetQueueAttributesRequest + new() { QueueUrl = queueUrl, - Attributes = new Dictionary { ["Policy"] = BuildPolicy(queueArn, topicArn) } + Attributes = new() { ["Policy"] = BuildPolicy(queueArn, topicArn) } }, cancellationToken ); _subscriptionArn = (await _provider._sns!.SubscribeAsync( - new SubscribeRequest - { - TopicArn = topicArn, - Protocol = "sqs", - Endpoint = queueArn, - ReturnSubscriptionArn = true, - Attributes = new Dictionary { ["RawMessageDelivery"] = "true" } - }, - cancellationToken - )).SubscriptionArn; + new() + { + TopicArn = topicArn, + Protocol = "sqs", + Endpoint = queueArn, + ReturnSubscriptionArn = true, + Attributes = new() { ["RawMessageDelivery"] = "true" } + }, + cancellationToken + )).SubscriptionArn; } catch (OperationCanceledException) { @@ -236,14 +230,14 @@ await _provider._sqs.SetQueueAttributesAsync( try { response = await _provider._sqs!.ReceiveMessageAsync( - new ReceiveMessageRequest - { - QueueUrl = queueUrl, - MaxNumberOfMessages = _provider._options.MaxNumberOfMessages, - WaitTimeSeconds = _provider._options.WaitTimeSeconds - }, - cancellationToken - ); + new ReceiveMessageRequest + { + QueueUrl = queueUrl, + MaxNumberOfMessages = _provider._options.MaxNumberOfMessages, + WaitTimeSeconds = _provider._options.WaitTimeSeconds + }, + cancellationToken + ); } catch (OperationCanceledException) { diff --git a/src/SquidStd.Messaging/Extensions/MessagingRegistrationExtensions.cs b/src/SquidStd.Messaging/Extensions/MessagingRegistrationExtensions.cs index 77c97ee1..bcb407c7 100644 --- a/src/SquidStd.Messaging/Extensions/MessagingRegistrationExtensions.cs +++ b/src/SquidStd.Messaging/Extensions/MessagingRegistrationExtensions.cs @@ -10,7 +10,7 @@ namespace SquidStd.Messaging.Extensions; /// -/// DryIoc registration helpers for the in-memory messaging system. +/// DryIoc registration helpers for the in-memory messaging system. /// public static class MessagingRegistrationExtensions { @@ -18,7 +18,7 @@ public static class MessagingRegistrationExtensions extension(IContainer container) { /// - /// Registers the in-memory messaging services (facade, provider, serializer, metrics). + /// Registers the in-memory messaging services (facade, provider, serializer, metrics). /// /// Optional messaging options; defaults are used when null. /// The container for chaining. @@ -47,7 +47,7 @@ public IContainer AddInMemoryMessaging(MessagingOptions? options = null) } /// - /// Registers the in-memory messaging services from a connection string (scheme must be "memory"). + /// Registers the in-memory messaging services from a connection string (scheme must be "memory"). /// public IContainer AddInMemoryMessaging(string connectionString) { diff --git a/src/SquidStd.Messaging/Internal/InMemoryQueue.cs b/src/SquidStd.Messaging/Internal/InMemoryQueue.cs index c4f1f555..1bbacaed 100644 --- a/src/SquidStd.Messaging/Internal/InMemoryQueue.cs +++ b/src/SquidStd.Messaging/Internal/InMemoryQueue.cs @@ -3,7 +3,7 @@ namespace SquidStd.Messaging.Internal; /// -/// Per-queue in-memory state: the buffer channel, the registered handlers, and the round-robin index. +/// Per-queue in-memory state: the buffer channel, the registered handlers, and the round-robin index. /// internal sealed class InMemoryQueue { @@ -13,7 +13,7 @@ internal sealed class InMemoryQueue private int _roundRobinIndex; public Channel Channel { get; } = System.Threading.Channels.Channel.CreateUnbounded( - new UnboundedChannelOptions { SingleReader = true, SingleWriter = false } + new() { SingleReader = true, SingleWriter = false } ); public Task? ConsumerLoop { get; set; } @@ -39,15 +39,11 @@ public void AddHandler(Func, CancellationToken, Task> handl /// Decrements the buffered depth and returns the new value. public int DecrementDepth() - { - return Interlocked.Decrement(ref _depth); - } + => Interlocked.Decrement(ref _depth); /// Increments the buffered depth and returns the new value. public int IncrementDepth() - { - return Interlocked.Increment(ref _depth); - } + => Interlocked.Increment(ref _depth); /// Returns the next handler in round-robin order, or null when none are registered. public Func, CancellationToken, Task>? NextHandler() diff --git a/src/SquidStd.Messaging/Internal/QueuedMessage.cs b/src/SquidStd.Messaging/Internal/QueuedMessage.cs index 6e46f970..0ff2c295 100644 --- a/src/SquidStd.Messaging/Internal/QueuedMessage.cs +++ b/src/SquidStd.Messaging/Internal/QueuedMessage.cs @@ -1,7 +1,7 @@ namespace SquidStd.Messaging.Internal; /// -/// A buffered queue message with its delivery attempt count. +/// A buffered queue message with its delivery attempt count. /// /// The raw message payload. /// Number of delivery attempts already made (0 on first enqueue). diff --git a/src/SquidStd.Messaging/Services/InMemoryQueueProvider.cs b/src/SquidStd.Messaging/Services/InMemoryQueueProvider.cs index 21d4f14c..81772162 100644 --- a/src/SquidStd.Messaging/Services/InMemoryQueueProvider.cs +++ b/src/SquidStd.Messaging/Services/InMemoryQueueProvider.cs @@ -8,8 +8,8 @@ namespace SquidStd.Messaging.Services; /// -/// In-memory : one buffered channel + consumer loop per named queue, -/// round-robin delivery, retry and dead-lettering. +/// In-memory : one buffered channel + consumer loop per named queue, +/// round-robin delivery, retry and dead-lettering. /// public sealed class InMemoryQueueProvider : IQueueProvider { @@ -73,7 +73,7 @@ public Task PublishAsync(string queueName, ReadOnlyMemory payload, Cancell ArgumentException.ThrowIfNullOrWhiteSpace(queueName); cancellationToken.ThrowIfCancellationRequested(); - Enqueue(queueName, new QueuedMessage(payload, 0)); + Enqueue(queueName, new(payload, 0)); _metrics.OnPublished(queueName); return Task.CompletedTask; @@ -81,15 +81,11 @@ public Task PublishAsync(string queueName, ReadOnlyMemory payload, Cancell /// public ValueTask StartAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; /// public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return DisposeAsync(); - } + => DisposeAsync(); /// public IDisposable Subscribe(string queueName, Func, CancellationToken, Task> handler) @@ -145,13 +141,10 @@ private async Task ConsumeLoopAsync(string queueName, InMemoryQueue queue, Cance } private void Enqueue(string queueName, QueuedMessage message) - { - Write(GetOrCreate(queueName), queueName, message); - } + => Write(GetOrCreate(queueName), queueName, message); private InMemoryQueue GetOrCreate(string queueName) - { - return _queues.GetOrAdd( + => _queues.GetOrAdd( queueName, name => { @@ -164,7 +157,6 @@ private InMemoryQueue GetOrCreate(string queueName) return queue; } ); - } private void HandleFailure(string queueName, InMemoryQueue queue, QueuedMessage message, Exception exception) { @@ -186,7 +178,7 @@ private void HandleFailure(string queueName, InMemoryQueue queue, QueuedMessage nextAttempt ); _metrics.OnDeadLettered(queueName); - Enqueue(queueName + _options.DeadLetterQueueSuffix, new QueuedMessage(message.Payload, 0)); + Enqueue(queueName + _options.DeadLetterQueueSuffix, new(message.Payload, 0)); } private async Task RequeueAsync(InMemoryQueue queue, string queueName, QueuedMessage message) diff --git a/src/SquidStd.Messaging/Services/InMemoryTopicProvider.cs b/src/SquidStd.Messaging/Services/InMemoryTopicProvider.cs index 0550ebbf..22518a7a 100644 --- a/src/SquidStd.Messaging/Services/InMemoryTopicProvider.cs +++ b/src/SquidStd.Messaging/Services/InMemoryTopicProvider.cs @@ -5,8 +5,8 @@ namespace SquidStd.Messaging.Services; /// -/// In-memory : fan-out delivery to all current subscribers of a topic. -/// Transient and at-most-once; exceptions in one subscriber are isolated. +/// In-memory : fan-out delivery to all current subscribers of a topic. +/// Transient and at-most-once; exceptions in one subscriber are isolated. /// public sealed class InMemoryTopicProvider : ITopicProvider { @@ -56,15 +56,11 @@ public async Task PublishAsync(string topic, ReadOnlyMemory payload, Cance /// public ValueTask StartAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; /// public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return DisposeAsync(); - } + => DisposeAsync(); /// public IDisposable Subscribe(string topic, Func, CancellationToken, Task> handler) @@ -74,7 +70,7 @@ public IDisposable Subscribe(string topic, Func, Cancellati var handlers = _topics.GetOrAdd( topic, - static _ => new ConcurrentDictionary, CancellationToken, Task>>() + static _ => new() ); var id = Guid.NewGuid(); handlers[id] = handler; diff --git a/src/SquidStd.Network/Buffers/CircularBuffer.cs b/src/SquidStd.Network/Buffers/CircularBuffer.cs index 61adcf2e..d1d597ff 100644 --- a/src/SquidStd.Network/Buffers/CircularBuffer.cs +++ b/src/SquidStd.Network/Buffers/CircularBuffer.cs @@ -5,56 +5,56 @@ namespace SquidStd.Network.Buffers; /// /// -/// Circular buffer. -/// When writing to a full buffer: -/// PushBack -> removes this[0] / Front() -/// PushFront -> removes this[Size-1] / Back() -/// this implementation is inspired by -/// http://www.boost.org/doc/libs/1_53_0/libs/circular_buffer/doc/circular_buffer.html -/// because I liked their interface. +/// Circular buffer. +/// When writing to a full buffer: +/// PushBack -> removes this[0] / Front() +/// PushFront -> removes this[Size-1] / Back() +/// this implementation is inspired by +/// http://www.boost.org/doc/libs/1_53_0/libs/circular_buffer/doc/circular_buffer.html +/// because I liked their interface. /// public class CircularBuffer : IEnumerable { private readonly T[] _buffer; /// - /// The _end. Index after the last element in the buffer. + /// The _end. Index after the last element in the buffer. /// private int _end; /// - /// The _start. Index of the first element in buffer. + /// The _start. Index of the first element in buffer. /// private int _start; /// - /// Maximum capacity of the buffer. Elements pushed into the buffer after - /// maximum capacity is reached (IsFull = true), will remove an element. + /// Maximum capacity of the buffer. Elements pushed into the buffer after + /// maximum capacity is reached (IsFull = true), will remove an element. /// public int Capacity => _buffer.Length; /// - /// Boolean indicating if Circular is at full capacity. - /// Adding more elements when the buffer is full will - /// cause elements to be removed from the other end - /// of the buffer. + /// Boolean indicating if Circular is at full capacity. + /// Adding more elements when the buffer is full will + /// cause elements to be removed from the other end + /// of the buffer. /// public bool IsFull => Size == Capacity; /// - /// True if has no elements. + /// True if has no elements. /// public bool IsEmpty => Size == 0; /// - /// Current buffer size (the number of elements that the buffer has). + /// Current buffer size (the number of elements that the buffer has). /// public int Size { get; private set; } /// - /// Index access to elements in buffer. - /// Index does not loop around like when adding elements, - /// valid interval is [0;Size[ + /// Index access to elements in buffer. + /// Index does not loop around like when adding elements, + /// valid interval is [0;Size[ /// /// Index of element to access. /// Thrown when index is outside of [; Size[ interval. @@ -94,26 +94,24 @@ public T this[int index] } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// - /// Buffer capacity. Must be positive. + /// Buffer capacity. Must be positive. /// public CircularBuffer(int capacity) - : this(capacity, []) - { - } + : this(capacity, []) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// - /// Buffer capacity. Must be positive. + /// Buffer capacity. Must be positive. /// /// - /// Items to fill buffer with. Items length must be less than capacity. - /// Suggestion: use Skip(x).Take(y).ToArray() to build this argument from - /// any enumerable. + /// Items to fill buffer with. Items length must be less than capacity. + /// Suggestion: use Skip(x).Take(y).ToArray() to build this argument from + /// any enumerable. /// public CircularBuffer(int capacity, T[] items) { @@ -144,10 +142,10 @@ public CircularBuffer(int capacity, T[] items) _end = Size == capacity ? 0 : Size; } - #region IEnumerable implementation +#region IEnumerable implementation /// - /// Returns an enumerator that iterates through this buffer. + /// Returns an enumerator that iterates through this buffer. /// /// An enumerator that can be used to iterate this collection. public IEnumerator GetEnumerator() @@ -163,19 +161,17 @@ public IEnumerator GetEnumerator() } } - #endregion +#endregion - #region IEnumerable implementation +#region IEnumerable implementation IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + => GetEnumerator(); - #endregion +#endregion /// - /// Element at the back of the buffer - this[Size - 1]. + /// Element at the back of the buffer - this[Size - 1]. /// /// The value of the element of type T at the back of the buffer. public T Back() @@ -186,7 +182,7 @@ public T Back() } /// - /// Clears the contents of the array. Size = 0, Capacity is unchanged. + /// Clears the contents of the array. Size = 0, Capacity is unchanged. /// /// public void Clear() @@ -199,7 +195,7 @@ public void Clear() } /// - /// Element at the front of the buffer - this[0]. + /// Element at the front of the buffer - this[0]. /// /// The value of the element of type T at the front of the buffer. public T Front() @@ -210,8 +206,8 @@ public T Front() } /// - /// Removes the element at the back of the buffer. Decreasing the - /// Buffer size by 1. + /// Removes the element at the back of the buffer. Decreasing the + /// Buffer size by 1. /// public void PopBack() { @@ -222,8 +218,8 @@ public void PopBack() } /// - /// Removes the element at the front of the buffer. Decreasing the - /// Buffer size by 1. + /// Removes the element at the front of the buffer. Decreasing the + /// Buffer size by 1. /// public void PopFront() { @@ -234,10 +230,10 @@ public void PopFront() } /// - /// Pushes a new element to the back of the buffer. Back()/this[Size-1] - /// will now return this element. - /// When the buffer is full, the element at Front()/this[0] will be - /// popped to allow for this new element to fit. + /// Pushes a new element to the back of the buffer. Back()/this[Size-1] + /// will now return this element. + /// When the buffer is full, the element at Front()/this[0] will be + /// popped to allow for this new element to fit. /// /// Item to push to the back of the buffer public void PushBack(T item) @@ -257,8 +253,8 @@ public void PushBack(T item) } /// - /// Pushes a contiguous range of elements to the back of the buffer in bulk. - /// When the buffer is full, the oldest elements are dropped to make room. + /// Pushes a contiguous range of elements to the back of the buffer in bulk. + /// When the buffer is full, the oldest elements are dropped to make room. /// /// Items to push. public void PushBackRange(ReadOnlySpan items) @@ -317,10 +313,10 @@ public void PushBackRange(ReadOnlySpan items) } /// - /// Pushes a new element to the front of the buffer. Front()/this[0] - /// will now return this element. - /// When the buffer is full, the element at Back()/this[Size-1] will be - /// popped to allow for this new element to fit. + /// Pushes a new element to the front of the buffer. Front()/this[0] + /// will now return this element. + /// When the buffer is full, the element at Back()/this[Size-1] will be + /// popped to allow for this new element to fit. /// /// Item to push to the front of the buffer public void PushFront(T item) @@ -340,9 +336,9 @@ public void PushFront(T item) } /// - /// Copies the buffer contents to an array, according to the logical - /// contents of the buffer (i.e. independent of the internal - /// order/contents) + /// Copies the buffer contents to an array, according to the logical + /// contents of the buffer (i.e. independent of the internal + /// order/contents) /// /// A new array with a copy of the buffer contents. public T[] ToArray() @@ -361,23 +357,21 @@ public T[] ToArray() } /// - /// Get the contents of the buffer as 2 ArraySegments. - /// Respects the logical contents of the buffer, where - /// each segment and items in each segment are ordered - /// according to insertion. - /// Fast: does not copy the array elements. - /// Useful for methods like Send(IList<ArraySegment<Byte>>). - /// Segments may be empty. + /// Get the contents of the buffer as 2 ArraySegments. + /// Respects the logical contents of the buffer, where + /// each segment and items in each segment are ordered + /// according to insertion. + /// Fast: does not copy the array elements. + /// Useful for methods like Send(IList<ArraySegment<Byte>>). + /// Segments may be empty. /// /// An IList with 2 segments corresponding to the buffer content. public IList> ToArraySegments() - { - return [ArrayOne(), ArrayTwo()]; - } + => [ArrayOne(), ArrayTwo()]; /// - /// Decrements the provided index variable by one, wrapping - /// around if necessary. + /// Decrements the provided index variable by one, wrapping + /// around if necessary. /// /// private void Decrement(ref int index) @@ -391,8 +385,8 @@ private void Decrement(ref int index) } /// - /// Increments the provided index variable by one, wrapping - /// around if necessary. + /// Increments the provided index variable by one, wrapping + /// around if necessary. /// /// private void Increment(ref int index) @@ -404,18 +398,16 @@ private void Increment(ref int index) } /// - /// Converts the index in the argument to an index in _buffer + /// Converts the index in the argument to an index in _buffer /// /// - /// The transformed index. + /// The transformed index. /// /// - /// External index. + /// External index. /// private int InternalIndex(int index) - { - return _start + (index < Capacity - _start ? index : index - Capacity); - } + => _start + (index < Capacity - _start ? index : index - Capacity); private void ThrowIfEmpty(string message = "Cannot access an empty buffer.") { @@ -430,7 +422,7 @@ private void ThrowIfEmpty(string message = "Cannot access an empty buffer.") // http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_1f5081a54afbc2dfc1a7fb20329df7d5b // should help a lot with the code. - #region Array items easy access. +#region Array items easy access. // The array is composed by at most two non-contiguous segments, // the next two methods allow easy access to those. @@ -439,31 +431,31 @@ private ArraySegment ArrayOne() { if (IsEmpty) { - return new ArraySegment([]); + return new([]); } if (_start < _end) { - return new ArraySegment(_buffer, _start, _end - _start); + return new(_buffer, _start, _end - _start); } - return new ArraySegment(_buffer, _start, _buffer.Length - _start); + return new(_buffer, _start, _buffer.Length - _start); } private ArraySegment ArrayTwo() { if (IsEmpty) { - return new ArraySegment([]); + return new([]); } if (_start < _end) { - return new ArraySegment(_buffer, _end, 0); + return new(_buffer, _end, 0); } - return new ArraySegment(_buffer, 0, _end); + return new(_buffer, 0, _end); } - #endregion +#endregion } diff --git a/src/SquidStd.Network/Client/SquidStdTcpClient.cs b/src/SquidStd.Network/Client/SquidStdTcpClient.cs index 5bf29931..7b7f9705 100644 --- a/src/SquidStd.Network/Client/SquidStdTcpClient.cs +++ b/src/SquidStd.Network/Client/SquidStdTcpClient.cs @@ -13,8 +13,8 @@ namespace SquidStd.Network.Client; /// -/// Represents a connected TCP client with async send/receive loops, -/// middleware processing, lifecycle events, and recent byte history. +/// Represents a connected TCP client with async send/receive loops, +/// middleware processing, lifecycle events, and recent byte history. /// public sealed class SquidStdTcpClient : INetworkConnection, IAsyncDisposable, IDisposable { @@ -44,12 +44,12 @@ public sealed class SquidStdTcpClient : INetworkConnection, IAsyncDisposable, ID private int _started; /// - /// Receives payload chunk size in bytes. + /// Receives payload chunk size in bytes. /// public int ReceiveBufferSize { get; } /// - /// Local endpoint used for this connection, when available. + /// Local endpoint used for this connection, when available. /// public EndPoint? LocalEndPoint { @@ -67,7 +67,7 @@ public EndPoint? LocalEndPoint } /// - /// Gets the number of bytes currently available in the receive circular buffer. + /// Gets the number of bytes currently available in the receive circular buffer. /// public int AvailableBytes { @@ -81,7 +81,7 @@ public int AvailableBytes } /// - /// Gets whether the receive circular buffer is full. + /// Gets whether the receive circular buffer is full. /// public bool IsReceiveBufferFull { @@ -95,12 +95,12 @@ public bool IsReceiveBufferFull } /// - /// Unique session identifier for this client connection. + /// Unique session identifier for this client connection. /// public long SessionId { get; } /// - /// Client remote endpoint, when connected. + /// Client remote endpoint, when connected. /// public EndPoint? RemoteEndPoint { @@ -118,18 +118,18 @@ public EndPoint? RemoteEndPoint } /// - /// True when the underlying socket is connected and client not closed. + /// True when the underlying socket is connected and client not closed. /// public bool IsConnected => _socket.Connected && Volatile.Read(ref _closed) == 0; /// - /// Creates a client wrapper for an accepted socket. + /// Creates a client wrapper for an accepted socket. /// /// Connected socket. /// Optional middleware list. /// - /// Optional framer. When supplied, the receive loop accumulates middleware output and - /// emits once per complete frame instead of once per socket read. + /// Optional framer. When supplied, the receive loop accumulates middleware output and + /// emits once per complete frame instead of once per socket read. /// /// Receive chunk size in bytes. /// Max number of received bytes to keep in history. @@ -150,12 +150,10 @@ public SquidStdTcpClient( receiveBufferSize, historyBufferCapacity, maxFrameLength - ) - { - } + ) { } /// - /// Creates a client wrapper for an accepted socket using the supplied transport stream. + /// Creates a client wrapper for an accepted socket using the supplied transport stream. /// public SquidStdTcpClient( Socket socket, @@ -173,10 +171,10 @@ public SquidStdTcpClient( _socket = socket; _stream = stream; - _middlewarePipeline = new NetMiddlewarePipeline(middlewares); + _middlewarePipeline = new(middlewares); _framer = framer; _codec = codec; - _receiveBuffer = new CircularBuffer(historyBufferCapacity); + _receiveBuffer = new(historyBufferCapacity); ReceiveBufferSize = receiveBufferSize; _maxFrameLength = maxFrameLength; SessionId = Interlocked.Increment(ref _sessionIdSequence); @@ -207,7 +205,7 @@ public async ValueTask DisposeAsync() } /// - /// Closes the client connection and raises disconnect event once. + /// Closes the client connection and raises disconnect event once. /// public async Task CloseAsync(CancellationToken cancellationToken = default) { @@ -248,7 +246,7 @@ public async Task CloseAsync(CancellationToken cancellationToken = default) } /// - /// Sends a payload to the connected socket. + /// Sends a payload to the connected socket. /// public async Task SendAsync(ReadOnlyMemory payload, CancellationToken cancellationToken) { @@ -304,7 +302,7 @@ public async Task SendAsync(ReadOnlyMemory payload, CancellationToken canc } /// - /// Adds a middleware component to this client pipeline. + /// Adds a middleware component to this client pipeline. /// public SquidStdTcpClient AddMiddleware(INetMiddleware middleware) { @@ -314,7 +312,7 @@ public SquidStdTcpClient AddMiddleware(INetMiddleware middleware) } /// - /// Creates an outbound client and connects to the specified endpoint. + /// Creates an outbound client and connects to the specified endpoint. /// public static async Task ConnectAsync( IPEndPoint endPoint, @@ -334,7 +332,7 @@ public static async Task ConnectAsync( } /// - /// Consumes bytes from the front of the receive circular buffer. + /// Consumes bytes from the front of the receive circular buffer. /// public int ConsumeBytes(int count) { @@ -357,24 +355,20 @@ public int ConsumeBytes(int count) } /// - /// Checks whether this client pipeline contains at least one middleware instance of the specified type. + /// Checks whether this client pipeline contains at least one middleware instance of the specified type. /// public bool ContainsMiddleware() where TMiddleware : INetMiddleware - { - return _middlewarePipeline.ContainsMiddleware(); - } + => _middlewarePipeline.ContainsMiddleware(); /// - /// Returns a snapshot of recent received bytes from the circular history buffer. + /// Returns a snapshot of recent received bytes from the circular history buffer. /// public byte[] GetRecentReceivedBytes() - { - return PeekData(); - } + => PeekData(); /// - /// Peeks at data in the receive circular buffer without consuming it. + /// Peeks at data in the receive circular buffer without consuming it. /// public byte[] PeekData(int count = 0) { @@ -398,26 +392,22 @@ public byte[] PeekData(int count = 0) } /// - /// Atomically swaps the transport codec for this connection. The new codec takes effect from the next - /// socket read; the caller must trigger the swap at a read boundary (no old-regime bytes still pending). + /// Atomically swaps the transport codec for this connection. The new codec takes effect from the next + /// socket read; the caller must trigger the swap at a read boundary (no old-regime bytes still pending). /// /// The new codec, or null to remove transport transformation. public void SwapCodec(ITransportCodec? codec) - { - Volatile.Write(ref _codec, codec); - } + => Volatile.Write(ref _codec, codec); /// - /// Removes all middleware components of the specified type from this client pipeline. + /// Removes all middleware components of the specified type from this client pipeline. /// public bool RemoveMiddleware() where TMiddleware : INetMiddleware - { - return _middlewarePipeline.RemoveMiddleware(); - } + => _middlewarePipeline.RemoveMiddleware(); /// - /// Starts the receive loop and raises connect event. + /// Starts the receive loop and raises connect event. /// public Task StartAsync(CancellationToken cancellationToken) { @@ -495,9 +485,7 @@ private void EmitFrames() // receive loop close the connection before the buffer grows further. if (_pendingLength > _maxFrameLength) { - throw new InvalidDataException( - $"Incoming frame exceeds the maximum of {_maxFrameLength} bytes." - ); + throw new InvalidDataException($"Incoming frame exceeds the maximum of {_maxFrameLength} bytes."); } break; @@ -524,7 +512,7 @@ private void EmitFrames() ConsumePending(frameLength); - OnDataReceived?.Invoke(this, new SquidStdTcpDataReceivedEventArgs(this, frame)); + OnDataReceived?.Invoke(this, new(this, frame)); } } @@ -535,7 +523,7 @@ private void RaiseConnected() SessionId, RemoteEndPoint ); - OnConnected?.Invoke(this, new SquidStdTcpClientEventArgs(this)); + OnConnected?.Invoke(this, new(this)); } private void RaiseDisconnected() @@ -545,7 +533,7 @@ private void RaiseDisconnected() SessionId, RemoteEndPoint ); - OnDisconnected?.Invoke(this, new SquidStdTcpClientEventArgs(this)); + OnDisconnected?.Invoke(this, new(this)); } private void RaiseException(Exception exception) @@ -556,7 +544,7 @@ private void RaiseException(Exception exception) SessionId, RemoteEndPoint ); - OnException?.Invoke(this, new SquidStdTcpExceptionEventArgs(exception, this)); + OnException?.Invoke(this, new(exception, this)); } private async Task ReceiveLoopAsync() @@ -568,9 +556,9 @@ private async Task ReceiveLoopAsync() while (!_internalCancellationTokenSource.IsCancellationRequested && IsConnected) { var received = await _stream.ReadAsync( - buffer.AsMemory(0, ReceiveBufferSize), - _internalCancellationTokenSource.Token - ); + buffer.AsMemory(0, ReceiveBufferSize), + _internalCancellationTokenSource.Token + ); if (received <= 0) { @@ -592,10 +580,10 @@ private async Task ReceiveLoopAsync() var chunkMemory = new ReadOnlyMemory(chunk, 0, received); var processed = await _middlewarePipeline.ExecuteAsync( - this, - chunkMemory, - _internalCancellationTokenSource.Token - ); + this, + chunkMemory, + _internalCancellationTokenSource.Token + ); if (processed.IsEmpty) { @@ -607,7 +595,7 @@ private async Task ReceiveLoopAsync() // Fresh copy so the event handler can outlive the pooled chunk. var payload = new byte[processed.Length]; processed.CopyTo(payload); - OnDataReceived?.Invoke(this, new SquidStdTcpDataReceivedEventArgs(this, payload)); + OnDataReceived?.Invoke(this, new(this, payload)); } else { @@ -652,27 +640,25 @@ private void ReleasePendingBuffer() /// public void Dispose() // Sync-over-async: best effort. Prefer DisposeAsync. - { - DisposeAsync().AsTask().GetAwaiter().GetResult(); - } + => DisposeAsync().AsTask().GetAwaiter().GetResult(); /// - /// Raised when the client is fully connected and receive loop starts. + /// Raised when the client is fully connected and receive loop starts. /// public event EventHandler? OnConnected; /// - /// Raised when the client is disconnected. + /// Raised when the client is disconnected. /// public event EventHandler? OnDisconnected; /// - /// Raised when data is received (after middleware pipeline). + /// Raised when data is received (after middleware pipeline). /// public event EventHandler? OnDataReceived; /// - /// Raised when receive/send loops throw an exception. + /// Raised when receive/send loops throw an exception. /// public event EventHandler? OnException; } diff --git a/src/SquidStd.Network/Client/SquidStdUdpClient.cs b/src/SquidStd.Network/Client/SquidStdUdpClient.cs index 2918aaa4..de8d31ee 100644 --- a/src/SquidStd.Network/Client/SquidStdUdpClient.cs +++ b/src/SquidStd.Network/Client/SquidStdUdpClient.cs @@ -7,11 +7,11 @@ namespace SquidStd.Network.Client; /// -/// Connectionless UDP client that binds a local socket and surfaces inbound datagrams through an -/// async receive loop. Datagrams can be sent to any endpoint with , or to -/// an optional default remote endpoint via . Mirrors the lifecycle surface of -/// (session id, connect/disconnect/data/exception events, and -/// ). Supports Start once; recreate the instance to listen again. +/// Connectionless UDP client that binds a local socket and surfaces inbound datagrams through an +/// async receive loop. Datagrams can be sent to any endpoint with , or to +/// an optional default remote endpoint via . Mirrors the lifecycle surface of +/// (session id, connect/disconnect/data/exception events, and +/// ). Supports Start once; recreate the instance to listen again. /// public sealed class SquidStdUdpClient : INetworkConnection, IAsyncDisposable, IDisposable { @@ -27,7 +27,7 @@ public sealed class SquidStdUdpClient : INetworkConnection, IAsyncDisposable, ID private int _started; /// - /// Local endpoint the client is bound to, when available. + /// Local endpoint the client is bound to, when available. /// public EndPoint? LocalEndPoint { @@ -45,33 +45,33 @@ public EndPoint? LocalEndPoint } /// - /// Unique session identifier for this client. + /// Unique session identifier for this client. /// public long SessionId { get; } /// - /// Default remote endpoint used by , when configured. + /// Default remote endpoint used by , when configured. /// public EndPoint? RemoteEndPoint => _defaultRemoteEndPoint; /// - /// True while the client is open (not closed). + /// True while the client is open (not closed). /// public bool IsConnected => Volatile.Read(ref _closed) == 0; /// - /// Creates a UDP client bound to a local endpoint. + /// Creates a UDP client bound to a local endpoint. /// /// - /// Local endpoint to bind. When null, binds an ephemeral port on . + /// Local endpoint to bind. When null, binds an ephemeral port on . /// /// - /// Optional default destination used by . When null, callers must use - /// with an explicit endpoint. + /// Optional default destination used by . When null, callers must use + /// with an explicit endpoint. /// public SquidStdUdpClient(IPEndPoint? localEndPoint = null, IPEndPoint? defaultRemoteEndPoint = null) { - _udpClient = new UdpClient(localEndPoint ?? new IPEndPoint(IPAddress.Any, 0)); + _udpClient = new(localEndPoint ?? new IPEndPoint(IPAddress.Any, 0)); _defaultRemoteEndPoint = defaultRemoteEndPoint; SessionId = Interlocked.Increment(ref _sessionIdSequence); } @@ -99,7 +99,7 @@ public async ValueTask DisposeAsync() } /// - /// Closes the client and raises once. + /// Closes the client and raises once. /// public async Task CloseAsync(CancellationToken cancellationToken = default) { @@ -123,7 +123,7 @@ public async Task CloseAsync(CancellationToken cancellationToken = default) } /// - /// Sends a datagram to the configured default remote endpoint. + /// Sends a datagram to the configured default remote endpoint. /// /// No default remote endpoint was configured. public Task SendAsync(ReadOnlyMemory payload, CancellationToken cancellationToken) @@ -139,7 +139,7 @@ public Task SendAsync(ReadOnlyMemory payload, CancellationToken cancellati } /// - /// Sends a datagram to an explicit endpoint. + /// Sends a datagram to an explicit endpoint. /// public async Task SendToAsync(ReadOnlyMemory payload, IPEndPoint endPoint, CancellationToken cancellationToken) { @@ -161,7 +161,7 @@ public async Task SendToAsync(ReadOnlyMemory payload, IPEndPoint endPoint, } /// - /// Starts the receive loop and raises . + /// Starts the receive loop and raises . /// public Task StartAsync(CancellationToken cancellationToken) { @@ -189,7 +189,7 @@ private void RaiseConnected() SessionId, LocalEndPoint ); - OnConnected?.Invoke(this, new SquidStdUdpClientEventArgs(this)); + OnConnected?.Invoke(this, new(this)); } private void RaiseDisconnected() @@ -199,13 +199,13 @@ private void RaiseDisconnected() SessionId, LocalEndPoint ); - OnDisconnected?.Invoke(this, new SquidStdUdpClientEventArgs(this)); + OnDisconnected?.Invoke(this, new(this)); } private void RaiseException(Exception exception) { _logger.Error(exception, "UDP client exception. SessionId={SessionId}", SessionId); - OnException?.Invoke(this, new SquidStdUdpExceptionEventArgs(exception, this)); + OnException?.Invoke(this, new(exception, this)); } private async Task ReceiveLoopAsync() @@ -219,7 +219,7 @@ private async Task ReceiveLoopAsync() // UdpReceiveResult.Buffer is a fresh array per receive, so it is safe to hand off. OnDataReceived?.Invoke( this, - new SquidStdUdpDataReceivedEventArgs(this, result.RemoteEndPoint, result.Buffer) + new(this, result.RemoteEndPoint, result.Buffer) ); } } @@ -248,27 +248,25 @@ private async Task ReceiveLoopAsync() /// public void Dispose() // Sync-over-async: best effort. Prefer DisposeAsync. - { - DisposeAsync().AsTask().GetAwaiter().GetResult(); - } + => DisposeAsync().AsTask().GetAwaiter().GetResult(); /// - /// Raised when the client starts and the receive loop begins. + /// Raised when the client starts and the receive loop begins. /// public event EventHandler? OnConnected; /// - /// Raised when the client is closed. + /// Raised when the client is closed. /// public event EventHandler? OnDisconnected; /// - /// Raised once per received datagram. + /// Raised once per received datagram. /// public event EventHandler? OnDataReceived; /// - /// Raised when the receive/send paths throw an unexpected exception. + /// Raised when the receive/send paths throw an unexpected exception. /// public event EventHandler? OnException; } diff --git a/src/SquidStd.Network/Data/ConnectionPipeline.cs b/src/SquidStd.Network/Data/ConnectionPipeline.cs index 15b13650..809a3932 100644 --- a/src/SquidStd.Network/Data/ConnectionPipeline.cs +++ b/src/SquidStd.Network/Data/ConnectionPipeline.cs @@ -5,8 +5,8 @@ namespace SquidStd.Network.Data; /// -/// Per-connection transport configuration produced by a server factory on each accepted connection. -/// Any member left null falls back to the server's shared configuration. +/// Per-connection transport configuration produced by a server factory on each accepted connection. +/// Any member left null falls back to the server's shared configuration. /// public sealed record ConnectionPipeline( ITransportCodec? Codec = null, diff --git a/src/SquidStd.Network/Data/Events/SquidStdSessionDataEventArgs.cs b/src/SquidStd.Network/Data/Events/SquidStdSessionDataEventArgs.cs index 2c39018d..4c8273ef 100644 --- a/src/SquidStd.Network/Data/Events/SquidStdSessionDataEventArgs.cs +++ b/src/SquidStd.Network/Data/Events/SquidStdSessionDataEventArgs.cs @@ -3,7 +3,7 @@ namespace SquidStd.Network.Data.Events; /// -/// Event payload carrying a session and the data it received. +/// Event payload carrying a session and the data it received. /// public sealed class SquidStdSessionDataEventArgs : EventArgs { diff --git a/src/SquidStd.Network/Data/Events/SquidStdSessionEventArgs.cs b/src/SquidStd.Network/Data/Events/SquidStdSessionEventArgs.cs index 4c8ef775..65fc0233 100644 --- a/src/SquidStd.Network/Data/Events/SquidStdSessionEventArgs.cs +++ b/src/SquidStd.Network/Data/Events/SquidStdSessionEventArgs.cs @@ -3,7 +3,7 @@ namespace SquidStd.Network.Data.Events; /// -/// Event payload carrying a session (created or removed). +/// Event payload carrying a session (created or removed). /// public sealed class SquidStdSessionEventArgs : EventArgs { diff --git a/src/SquidStd.Network/Data/Events/SquidStdTcpClientEventArgs.cs b/src/SquidStd.Network/Data/Events/SquidStdTcpClientEventArgs.cs index 56c64ae3..31e1920f 100644 --- a/src/SquidStd.Network/Data/Events/SquidStdTcpClientEventArgs.cs +++ b/src/SquidStd.Network/Data/Events/SquidStdTcpClientEventArgs.cs @@ -3,12 +3,12 @@ namespace SquidStd.Network.Data.Events; /// -/// Event payload containing a network client instance. +/// Event payload containing a network client instance. /// public sealed class SquidStdTcpClientEventArgs : EventArgs { /// - /// Connected or disconnected client. + /// Connected or disconnected client. /// public SquidStdTcpClient Client { get; } diff --git a/src/SquidStd.Network/Data/Events/SquidStdTcpDataReceivedEventArgs.cs b/src/SquidStd.Network/Data/Events/SquidStdTcpDataReceivedEventArgs.cs index 729e2aef..3fec6f48 100644 --- a/src/SquidStd.Network/Data/Events/SquidStdTcpDataReceivedEventArgs.cs +++ b/src/SquidStd.Network/Data/Events/SquidStdTcpDataReceivedEventArgs.cs @@ -3,17 +3,17 @@ namespace SquidStd.Network.Data.Events; /// -/// Event payload containing data received from a network client. +/// Event payload containing data received from a network client. /// public sealed class SquidStdTcpDataReceivedEventArgs : EventArgs { /// - /// Source client for the data payload. + /// Source client for the data payload. /// public SquidStdTcpClient Client { get; } /// - /// Received data payload. + /// Received data payload. /// public ReadOnlyMemory Data { get; } diff --git a/src/SquidStd.Network/Data/Events/SquidStdTcpExceptionEventArgs.cs b/src/SquidStd.Network/Data/Events/SquidStdTcpExceptionEventArgs.cs index 883f3a92..492be239 100644 --- a/src/SquidStd.Network/Data/Events/SquidStdTcpExceptionEventArgs.cs +++ b/src/SquidStd.Network/Data/Events/SquidStdTcpExceptionEventArgs.cs @@ -3,17 +3,17 @@ namespace SquidStd.Network.Data.Events; /// -/// Event payload containing an exception raised by server or client network loops. +/// Event payload containing an exception raised by server or client network loops. /// public sealed class SquidStdTcpExceptionEventArgs : EventArgs { /// - /// Exception raised by the networking component. + /// Exception raised by the networking component. /// public Exception Exception { get; } /// - /// Client related to the exception, when available. + /// Client related to the exception, when available. /// public SquidStdTcpClient? Client { get; } diff --git a/src/SquidStd.Network/Data/Events/SquidStdUdpClientEventArgs.cs b/src/SquidStd.Network/Data/Events/SquidStdUdpClientEventArgs.cs index 7f045360..71dbc282 100644 --- a/src/SquidStd.Network/Data/Events/SquidStdUdpClientEventArgs.cs +++ b/src/SquidStd.Network/Data/Events/SquidStdUdpClientEventArgs.cs @@ -3,12 +3,12 @@ namespace SquidStd.Network.Data.Events; /// -/// Event payload containing a UDP client instance. +/// Event payload containing a UDP client instance. /// public sealed class SquidStdUdpClientEventArgs : EventArgs { /// - /// Started or closed UDP client. + /// Started or closed UDP client. /// public SquidStdUdpClient Client { get; } diff --git a/src/SquidStd.Network/Data/Events/SquidStdUdpDataReceivedEventArgs.cs b/src/SquidStd.Network/Data/Events/SquidStdUdpDataReceivedEventArgs.cs index 4f8d526c..b931359e 100644 --- a/src/SquidStd.Network/Data/Events/SquidStdUdpDataReceivedEventArgs.cs +++ b/src/SquidStd.Network/Data/Events/SquidStdUdpDataReceivedEventArgs.cs @@ -4,22 +4,22 @@ namespace SquidStd.Network.Data.Events; /// -/// Event payload containing a datagram received from a UDP peer. +/// Event payload containing a datagram received from a UDP peer. /// public sealed class SquidStdUdpDataReceivedEventArgs : EventArgs { /// - /// UDP client that received the datagram. + /// UDP client that received the datagram. /// public SquidStdUdpClient Client { get; } /// - /// Endpoint that sent the datagram. + /// Endpoint that sent the datagram. /// public IPEndPoint RemoteEndPoint { get; } /// - /// Received datagram payload. + /// Received datagram payload. /// public ReadOnlyMemory Data { get; } diff --git a/src/SquidStd.Network/Data/Events/SquidStdUdpDatagramReceivedEventArgs.cs b/src/SquidStd.Network/Data/Events/SquidStdUdpDatagramReceivedEventArgs.cs index 56db7c5d..2cd200f2 100644 --- a/src/SquidStd.Network/Data/Events/SquidStdUdpDatagramReceivedEventArgs.cs +++ b/src/SquidStd.Network/Data/Events/SquidStdUdpDatagramReceivedEventArgs.cs @@ -3,7 +3,7 @@ namespace SquidStd.Network.Data.Events; /// -/// Event payload for a datagram received by the UDP server, carrying the sender endpoint. +/// Event payload for a datagram received by the UDP server, carrying the sender endpoint. /// public sealed class SquidStdUdpDatagramReceivedEventArgs : EventArgs { diff --git a/src/SquidStd.Network/Data/Events/SquidStdUdpExceptionEventArgs.cs b/src/SquidStd.Network/Data/Events/SquidStdUdpExceptionEventArgs.cs index 26c3f4d8..e22e173d 100644 --- a/src/SquidStd.Network/Data/Events/SquidStdUdpExceptionEventArgs.cs +++ b/src/SquidStd.Network/Data/Events/SquidStdUdpExceptionEventArgs.cs @@ -3,17 +3,17 @@ namespace SquidStd.Network.Data.Events; /// -/// Event payload containing an exception raised by the UDP client receive/send paths. +/// Event payload containing an exception raised by the UDP client receive/send paths. /// public sealed class SquidStdUdpExceptionEventArgs : EventArgs { /// - /// Exception raised by the networking component. + /// Exception raised by the networking component. /// public Exception Exception { get; } /// - /// UDP client related to the exception, when available. + /// UDP client related to the exception, when available. /// public SquidStdUdpClient? Client { get; } diff --git a/src/SquidStd.Network/Data/Options/SquidStdTcpServerTlsOptions.cs b/src/SquidStd.Network/Data/Options/SquidStdTcpServerTlsOptions.cs index 53e5a148..97d547e6 100644 --- a/src/SquidStd.Network/Data/Options/SquidStdTcpServerTlsOptions.cs +++ b/src/SquidStd.Network/Data/Options/SquidStdTcpServerTlsOptions.cs @@ -22,15 +22,13 @@ public SquidStdTcpServerTlsOptions(X509Certificate2 serverCertificate) } internal SslServerAuthenticationOptions ToAuthenticationOptions() - { - return new SslServerAuthenticationOptions + => new() { ServerCertificate = ServerCertificate, ClientCertificateRequired = ClientCertificateRequired, CertificateRevocationCheckMode = CheckCertificateRevocation - ? X509RevocationMode.Online - : X509RevocationMode.NoCheck, + ? X509RevocationMode.Online + : X509RevocationMode.NoCheck, EnabledSslProtocols = EnabledSslProtocols }; - } } diff --git a/src/SquidStd.Network/Exceptions/Buffers/CircularBufferEmptyException.cs b/src/SquidStd.Network/Exceptions/Buffers/CircularBufferEmptyException.cs index 1c50e2f3..22058ccd 100644 --- a/src/SquidStd.Network/Exceptions/Buffers/CircularBufferEmptyException.cs +++ b/src/SquidStd.Network/Exceptions/Buffers/CircularBufferEmptyException.cs @@ -1,12 +1,10 @@ namespace SquidStd.Network.Exceptions.Buffers; /// -/// Exception thrown when an operation requires at least one element in the circular buffer. +/// Exception thrown when an operation requires at least one element in the circular buffer. /// public sealed class CircularBufferEmptyException : InvalidOperationException { public CircularBufferEmptyException(string? message = null) - : base(message ?? "Circular buffer is empty.") - { - } + : base(message ?? "Circular buffer is empty.") { } } diff --git a/src/SquidStd.Network/Exceptions/Buffers/CircularBufferIndexOutOfRangeException.cs b/src/SquidStd.Network/Exceptions/Buffers/CircularBufferIndexOutOfRangeException.cs index 3df75eed..f9ce6d6e 100644 --- a/src/SquidStd.Network/Exceptions/Buffers/CircularBufferIndexOutOfRangeException.cs +++ b/src/SquidStd.Network/Exceptions/Buffers/CircularBufferIndexOutOfRangeException.cs @@ -1,12 +1,10 @@ namespace SquidStd.Network.Exceptions.Buffers; /// -/// Exception thrown when an index is outside the valid circular buffer bounds. +/// Exception thrown when an index is outside the valid circular buffer bounds. /// public sealed class CircularBufferIndexOutOfRangeException : ArgumentOutOfRangeException { public CircularBufferIndexOutOfRangeException(string paramName, int index, int size) - : base(paramName, index, $"Cannot access index {index}. Buffer size is {size}.") - { - } + : base(paramName, index, $"Cannot access index {index}. Buffer size is {size}.") { } } diff --git a/src/SquidStd.Network/Extensions/PacketExtensions.cs b/src/SquidStd.Network/Extensions/PacketExtensions.cs index 4359af89..79baf9ad 100644 --- a/src/SquidStd.Network/Extensions/PacketExtensions.cs +++ b/src/SquidStd.Network/Extensions/PacketExtensions.cs @@ -5,8 +5,6 @@ public static class PacketExtensions extension(byte opCode) { public string ToPacketString() - { - return "0x" + opCode.ToString("X2"); - } + => "0x" + opCode.ToString("X2"); } } diff --git a/src/SquidStd.Network/Interfaces/Client/INetworkConnection.cs b/src/SquidStd.Network/Interfaces/Client/INetworkConnection.cs index a0bb6858..2911ac6a 100644 --- a/src/SquidStd.Network/Interfaces/Client/INetworkConnection.cs +++ b/src/SquidStd.Network/Interfaces/Client/INetworkConnection.cs @@ -3,34 +3,34 @@ namespace SquidStd.Network.Interfaces.Client; /// -/// Represents a connected network client independently from the underlying transport. +/// Represents a connected network client independently from the underlying transport. /// public interface INetworkConnection { /// - /// Unique connection identifier assigned by the transport. + /// Unique connection identifier assigned by the transport. /// long SessionId { get; } /// - /// Remote endpoint when the transport exposes one. + /// Remote endpoint when the transport exposes one. /// EndPoint? RemoteEndPoint { get; } /// - /// Indicates whether the connection is still open. + /// Indicates whether the connection is still open. /// bool IsConnected { get; } /// - /// Closes the connection. + /// Closes the connection. /// /// The cancellation token. /// A task that completes when the connection has closed. Task CloseAsync(CancellationToken cancellationToken = default); /// - /// Sends raw bytes to the connected client. + /// Sends raw bytes to the connected client. /// /// The payload bytes. /// The cancellation token. diff --git a/src/SquidStd.Network/Interfaces/Codecs/ITransportCodec.cs b/src/SquidStd.Network/Interfaces/Codecs/ITransportCodec.cs index 11386dd7..4e6a60bb 100644 --- a/src/SquidStd.Network/Interfaces/Codecs/ITransportCodec.cs +++ b/src/SquidStd.Network/Interfaces/Codecs/ITransportCodec.cs @@ -1,13 +1,13 @@ namespace SquidStd.Network.Interfaces.Codecs; /// -/// An in-place, length-preserving transport transform applied at the wire — for example a stream cipher. +/// An in-place, length-preserving transport transform applied at the wire — for example a stream cipher. /// /// -/// Implementations MUST preserve the buffer length and transform in place. is invoked -/// only from a connection's receive loop (serial), and only from its send path (serial -/// under the send lock). The two directions may run concurrently (one each), so an implementation MUST NOT -/// share mutable state between decode and encode (real ciphers keep separate receive/send positions). +/// Implementations MUST preserve the buffer length and transform in place. is invoked +/// only from a connection's receive loop (serial), and only from its send path (serial +/// under the send lock). The two directions may run concurrently (one each), so an implementation MUST NOT +/// share mutable state between decode and encode (real ciphers keep separate receive/send positions). /// public interface ITransportCodec { diff --git a/src/SquidStd.Network/Interfaces/Framing/INetFramer.cs b/src/SquidStd.Network/Interfaces/Framing/INetFramer.cs index 977b4583..ff90d6db 100644 --- a/src/SquidStd.Network/Interfaces/Framing/INetFramer.cs +++ b/src/SquidStd.Network/Interfaces/Framing/INetFramer.cs @@ -1,29 +1,29 @@ namespace SquidStd.Network.Interfaces.Framing; /// -/// Extracts discrete frames from a continuous byte stream. +/// Extracts discrete frames from a continuous byte stream. /// /// -/// A framer is the optional bridge between the byte-oriented middleware pipeline -/// and a protocol-specific consumer. Implementations are typically stateless and -/// MUST be safe to call repeatedly: the same buffer may be inspected several times -/// as more bytes arrive across socket reads. Implementations holding per-connection -/// state must be supplied as a fresh instance per client. +/// A framer is the optional bridge between the byte-oriented middleware pipeline +/// and a protocol-specific consumer. Implementations are typically stateless and +/// MUST be safe to call repeatedly: the same buffer may be inspected several times +/// as more bytes arrive across socket reads. Implementations holding per-connection +/// state must be supplied as a fresh instance per client. /// public interface INetFramer { /// - /// Tries to read one complete frame from the start of . + /// Tries to read one complete frame from the start of . /// /// Accumulated bytes available for inspection. /// - /// The number of bytes to consume from the start of the buffer when a complete - /// frame is present. Undefined when the method returns false. + /// The number of bytes to consume from the start of the buffer when a complete + /// frame is present. Undefined when the method returns false. /// /// - /// true when starts with a complete frame and - /// has been written; false when more bytes - /// are required. + /// true when starts with a complete frame and + /// has been written; false when more bytes + /// are required. /// bool TryReadFrame(ReadOnlySpan buffer, out int frameLength); } diff --git a/src/SquidStd.Network/Interfaces/Middleware/INetMiddleware.cs b/src/SquidStd.Network/Interfaces/Middleware/INetMiddleware.cs index d5a3a047..ffc715c2 100644 --- a/src/SquidStd.Network/Interfaces/Middleware/INetMiddleware.cs +++ b/src/SquidStd.Network/Interfaces/Middleware/INetMiddleware.cs @@ -3,19 +3,19 @@ namespace SquidStd.Network.Interfaces.Middleware; /// -/// Transforms raw network bytes for a client connection. +/// Transforms raw network bytes for a client connection. /// /// -/// Middleware operates on raw bytes and MUST NOT assume any message, packet, or frame -/// semantics — framing and protocol parsing are the consumer's responsibility, applied -/// to the OnDataReceived output of the client. Returning -/// from either method drops the payload and -/// short-circuits the remaining pipeline. +/// Middleware operates on raw bytes and MUST NOT assume any message, packet, or frame +/// semantics — framing and protocol parsing are the consumer's responsibility, applied +/// to the OnDataReceived output of the client. Returning +/// from either method drops the payload and +/// short-circuits the remaining pipeline. /// public interface INetMiddleware { /// - /// Transforms an incoming payload before it is dispatched to consumers. + /// Transforms an incoming payload before it is dispatched to consumers. /// /// Client associated with the payload, if available. /// Incoming bytes. @@ -28,7 +28,7 @@ ValueTask> ProcessAsync( ); /// - /// Transforms an outgoing payload before it is written to the socket. + /// Transforms an outgoing payload before it is written to the socket. /// /// Client associated with the payload, if available. /// Outgoing bytes. @@ -39,7 +39,5 @@ ValueTask> ProcessSendAsync( ReadOnlyMemory data, CancellationToken cancellationToken = default ) - { - return ValueTask.FromResult(data); - } + => ValueTask.FromResult(data); } diff --git a/src/SquidStd.Network/Interfaces/Processing/IResultProcessor.cs b/src/SquidStd.Network/Interfaces/Processing/IResultProcessor.cs index 5d5e4562..529b9411 100644 --- a/src/SquidStd.Network/Interfaces/Processing/IResultProcessor.cs +++ b/src/SquidStd.Network/Interfaces/Processing/IResultProcessor.cs @@ -3,13 +3,13 @@ namespace SquidStd.Network.Interfaces.Processing; /// -/// Processes a framed network payload into a typed result. +/// Processes a framed network payload into a typed result. /// /// The processed result type. public interface IResultProcessor { /// - /// Processes one complete framed payload for a network connection. + /// Processes one complete framed payload for a network connection. /// /// The connection that produced the payload. /// The framed payload bytes. diff --git a/src/SquidStd.Network/Interfaces/Server/INetworkServer.cs b/src/SquidStd.Network/Interfaces/Server/INetworkServer.cs index 75506f01..36fcea8c 100644 --- a/src/SquidStd.Network/Interfaces/Server/INetworkServer.cs +++ b/src/SquidStd.Network/Interfaces/Server/INetworkServer.cs @@ -3,34 +3,34 @@ namespace SquidStd.Network.Interfaces.Server; /// -/// Represents a network listener with common lifecycle and metadata. +/// Represents a network listener with common lifecycle and metadata. /// public interface INetworkServer : IAsyncDisposable { /// - /// Transport type exposed by this server. + /// Transport type exposed by this server. /// ServerType ServerType { get; } /// - /// Current listening port. Returns 0 when no concrete port is bound. + /// Current listening port. Returns 0 when no concrete port is bound. /// int Port { get; } /// - /// Indicates whether the server is currently running. + /// Indicates whether the server is currently running. /// bool IsRunning { get; } /// - /// Starts the listener. + /// Starts the listener. /// /// The cancellation token. /// A task that completes when the listener has started. Task StartAsync(CancellationToken cancellationToken); /// - /// Stops the listener. + /// Stops the listener. /// /// The cancellation token. /// A task that completes when the listener has stopped. diff --git a/src/SquidStd.Network/Interfaces/Sessions/ISessionManager.cs b/src/SquidStd.Network/Interfaces/Sessions/ISessionManager.cs index 576e2e67..6f52a30c 100644 --- a/src/SquidStd.Network/Interfaces/Sessions/ISessionManager.cs +++ b/src/SquidStd.Network/Interfaces/Sessions/ISessionManager.cs @@ -4,7 +4,7 @@ namespace SquidStd.Network.Interfaces.Sessions; /// -/// Tracks active connections and their application state. +/// Tracks active connections and their application state. /// /// Application-defined per-connection state. public interface ISessionManager diff --git a/src/SquidStd.Network/Pipeline/NetMiddlewarePipeline.cs b/src/SquidStd.Network/Pipeline/NetMiddlewarePipeline.cs index 55afa18a..e47d9db6 100644 --- a/src/SquidStd.Network/Pipeline/NetMiddlewarePipeline.cs +++ b/src/SquidStd.Network/Pipeline/NetMiddlewarePipeline.cs @@ -4,14 +4,14 @@ namespace SquidStd.Network.Pipeline; /// -/// Executes components in registration order over a byte payload. +/// Executes components in registration order over a byte payload. /// /// -/// The pipeline is a byte transformer: each middleware sees a -/// of bytes and produces a of bytes. There is no concept of -/// message, packet, or frame at this layer — protocol-specific framing must happen on top of -/// the client's OnDataReceived output. Returning -/// from a middleware drops the payload and stops the chain. +/// The pipeline is a byte transformer: each middleware sees a +/// of bytes and produces a of bytes. There is no concept of +/// message, packet, or frame at this layer — protocol-specific framing must happen on top of +/// the client's OnDataReceived output. Returning +/// from a middleware drops the payload and stops the chain. /// public sealed class NetMiddlewarePipeline { @@ -19,7 +19,7 @@ public sealed class NetMiddlewarePipeline private INetMiddleware[] _middlewares; /// - /// Initializes the middleware pipeline. + /// Initializes the middleware pipeline. /// /// Optional initial middleware sequence. public NetMiddlewarePipeline(IEnumerable? middlewares = null) @@ -28,7 +28,7 @@ public NetMiddlewarePipeline(IEnumerable? middlewares = null) } /// - /// Adds a middleware component at the end of the execution chain. + /// Adds a middleware component at the end of the execution chain. /// /// Middleware to register. public void AddMiddleware(INetMiddleware middleware) @@ -40,7 +40,7 @@ public void AddMiddleware(INetMiddleware middleware) } /// - /// Checks whether at least one middleware component of the specified type is registered. + /// Checks whether at least one middleware component of the specified type is registered. /// /// Middleware type to check. /// true when a matching middleware is registered; otherwise false. @@ -54,7 +54,7 @@ public bool ContainsMiddleware() } /// - /// Processes the payload through all registered middleware components. + /// Processes the payload through all registered middleware components. /// /// Client associated with the payload, if available. /// Incoming payload. @@ -90,7 +90,7 @@ CancellationToken cancellationToken } /// - /// Processes the outgoing payload through all registered middleware components. + /// Processes the outgoing payload through all registered middleware components. /// /// Client associated with the payload, if available. /// Outgoing payload. @@ -126,7 +126,7 @@ CancellationToken cancellationToken } /// - /// Removes all middleware components of the specified type. + /// Removes all middleware components of the specified type. /// /// Middleware type to remove. /// true when at least one middleware was removed; otherwise false. diff --git a/src/SquidStd.Network/Server/SquidStdUdpServer.cs b/src/SquidStd.Network/Server/SquidStdUdpServer.cs index e62b9424..35da3fe7 100644 --- a/src/SquidStd.Network/Server/SquidStdUdpServer.cs +++ b/src/SquidStd.Network/Server/SquidStdUdpServer.cs @@ -10,10 +10,10 @@ namespace SquidStd.Network.Server; /// -/// Connectionless UDP server that binds one socket per local interface address and processes -/// each received datagram. By default it echoes the payload back to the sender (the behaviour the -/// UO launcher expects from a shard ping server); supply to customise the -/// response. Supports Start/Stop/Start cycles by recreating the sockets on each Start. +/// Connectionless UDP server that binds one socket per local interface address and processes +/// each received datagram. By default it echoes the payload back to the sender (the behaviour the +/// UO launcher expects from a shard ping server); supply to customise the +/// response. Supports Start/Stop/Start cycles by recreating the sockets on each Start. /// public sealed class SquidStdUdpServer : INetworkServer, IAsyncDisposable, IDisposable { @@ -29,14 +29,14 @@ public sealed class SquidStdUdpServer : INetworkServer, IAsyncDisposable, IDispo private int _started; /// - /// Optional response factory. Receives the datagram payload and the sender endpoint and returns - /// the bytes to send back; return to send no reply. - /// When null, the server echoes the payload unchanged. + /// Optional response factory. Receives the datagram payload and the sender endpoint and returns + /// the bytes to send back; return to send no reply. + /// When null, the server echoes the payload unchanged. /// public Func, IPEndPoint, ReadOnlyMemory>? OnDatagram { get; set; } /// - /// Number of bound listening sockets. + /// Number of bound listening sockets. /// public int ListenerCount { @@ -50,12 +50,12 @@ public int ListenerCount } /// - /// Transport type exposed by this server. + /// Transport type exposed by this server. /// public ServerType ServerType => ServerType.UDP; /// - /// Current listening port. Returns 0 when configured for an ephemeral port and stopped. + /// Current listening port. Returns 0 when configured for an ephemeral port and stopped. /// public int Port { @@ -76,17 +76,17 @@ public int Port } /// - /// True when the server is currently listening. + /// True when the server is currently listening. /// public bool IsRunning => Volatile.Read(ref _started) != 0; /// - /// Initializes a UDP server bound to the given endpoint on every StartAsync. + /// Initializes a UDP server bound to the given endpoint on every StartAsync. /// /// Endpoint supplying the port (and address when not binding all interfaces). /// - /// When true (default), binds one socket per local unicast address matching the endpoint's - /// address family. When false, binds only . + /// When true (default), binds one socket per local unicast address matching the endpoint's + /// address family. When false, binds only . /// public SquidStdUdpServer(IPEndPoint endPoint, bool bindAllInterfaces = true) { @@ -98,13 +98,11 @@ public SquidStdUdpServer(IPEndPoint endPoint, bool bindAllInterfaces = true) /// public async ValueTask DisposeAsync() - { - await StopAsync(CancellationToken.None); - } + => await StopAsync(CancellationToken.None); /// - /// Starts listening, binding sockets and launching a receive loop per socket. Recreates the - /// sockets on every call, so Stop/Start cycles are supported. + /// Starts listening, binding sockets and launching a receive loop per socket. Recreates the + /// sockets on every call, so Stop/Start cycles are supported. /// public Task StartAsync(CancellationToken cancellationToken) { @@ -138,7 +136,7 @@ public Task StartAsync(CancellationToken cancellationToken) } /// - /// Stops listening, closing every socket and awaiting the receive loops. + /// Stops listening, closing every socket and awaiting the receive loops. /// public async Task StopAsync(CancellationToken cancellationToken) { @@ -199,8 +197,8 @@ public async Task StopAsync(CancellationToken cancellationToken) } /// - /// Sends a datagram to a specific endpoint, using the listener that last received from it - /// (falling back to the first listener). No-op when no listener is available. + /// Sends a datagram to a specific endpoint, using the listener that last received from it + /// (falling back to the first listener). No-op when no listener is available. /// public async Task SendToAsync( IPEndPoint endPoint, @@ -230,7 +228,7 @@ public async Task SendToAsync( catch (Exception ex) { _logger.Warning(ex, "UDP SendToAsync failed for {EndPoint}", endPoint); - OnException?.Invoke(this, new SquidStdTcpExceptionEventArgs(ex)); + OnException?.Invoke(this, new(ex)); } } @@ -245,7 +243,7 @@ public async Task SendToAsync( { socket.Bind(endPoint); - return new UdpClient + return new() { Client = socket }; @@ -274,12 +272,12 @@ private async Task ReceiveLoopAsync(UdpClient listener, CancellationToken cancel _endpointListeners[result.RemoteEndPoint] = listener; OnDatagramReceived?.Invoke( this, - new SquidStdUdpDatagramReceivedEventArgs(result.RemoteEndPoint, result.Buffer) + new(result.RemoteEndPoint, result.Buffer) ); var response = OnDatagram is null - ? result.Buffer - : OnDatagram(result.Buffer, result.RemoteEndPoint); + ? result.Buffer + : OnDatagram(result.Buffer, result.RemoteEndPoint); if (!response.IsEmpty) { @@ -301,7 +299,7 @@ private async Task ReceiveLoopAsync(UdpClient listener, CancellationToken cancel catch (Exception ex) { _logger.Warning(ex, "UDP receive loop failed"); - OnException?.Invoke(this, new SquidStdTcpExceptionEventArgs(ex)); + OnException?.Invoke(this, new(ex)); } } } @@ -316,24 +314,22 @@ private IEnumerable ResolveBindEndPoints() return [ .. NetworkUtils.GetListeningAddresses(_endPoint) - .Select(address => new IPEndPoint(address.Address, _endPoint.Port)) + .Select(address => new IPEndPoint(address.Address, _endPoint.Port)) ]; } /// public void Dispose() - { - DisposeAsync().AsTask().GetAwaiter().GetResult(); - } + => DisposeAsync().AsTask().GetAwaiter().GetResult(); /// - /// Raised for every datagram received, carrying the sender endpoint. Always raised, regardless of - /// . + /// Raised for every datagram received, carrying the sender endpoint. Always raised, regardless of + /// . /// public event EventHandler? OnDatagramReceived; /// - /// Raised when receive loops throw an unexpected exception. + /// Raised when receive loops throw an unexpected exception. /// public event EventHandler? OnException; } diff --git a/src/SquidStd.Network/Server/SquidTcpServer.cs b/src/SquidStd.Network/Server/SquidTcpServer.cs index c02ab369..7411000b 100644 --- a/src/SquidStd.Network/Server/SquidTcpServer.cs +++ b/src/SquidStd.Network/Server/SquidTcpServer.cs @@ -15,8 +15,8 @@ namespace SquidStd.Network.Server; /// -/// High-throughput TCP server with client lifecycle events and middleware-enabled payload dispatch. -/// Supports Start/Stop/Start cycles by recreating the underlying socket on each Start. +/// High-throughput TCP server with client lifecycle events and middleware-enabled payload dispatch. +/// Supports Start/Stop/Start cycles by recreating the underlying socket on each Start. /// public sealed class SquidTcpServer : INetworkServer, IAsyncDisposable, IDisposable { @@ -40,34 +40,34 @@ public sealed class SquidTcpServer : INetworkServer, IAsyncDisposable, IDisposab private int _started; /// - /// Transport type exposed by this server. + /// Transport type exposed by this server. /// public ServerType ServerType => ServerType.TCP; /// - /// Current listening port. Returns 0 when the server is stopped. + /// Current listening port. Returns 0 when the server is stopped. /// public int Port => ((IPEndPoint?)_serverSocket?.LocalEndPoint)?.Port ?? 0; /// - /// True when the server is currently accepting connections. + /// True when the server is currently accepting connections. /// public bool IsRunning => Volatile.Read(ref _started) != 0; /// - /// Initializes a TCP server bound to the given endpoint. + /// Initializes a TCP server bound to the given endpoint. /// /// Endpoint to bind on every StartAsync. /// - /// Optional framer template. The same instance is shared by all accepted clients, - /// so implementations must be stateless or thread-safe. + /// Optional framer template. The same instance is shared by all accepted clients, + /// so implementations must be stateless or thread-safe. /// /// Per-client receive chunk size. /// Per-client history buffer capacity. /// - /// Optional factory invoked once per accepted connection to produce its transport configuration. - /// It MUST return fresh per-connection state — in particular a new ITransportCodec instance per - /// call — because codecs are stateful and must not be shared across connections. + /// Optional factory invoked once per accepted connection to produce its transport configuration. + /// It MUST return fresh per-connection state — in particular a new ITransportCodec instance per + /// call — because codecs are stateful and must not be shared across connections. /// public SquidTcpServer( IPEndPoint endPoint, @@ -90,13 +90,11 @@ public SquidTcpServer( /// public async ValueTask DisposeAsync() - { - await StopAsync(CancellationToken.None); - } + => await StopAsync(CancellationToken.None); /// - /// Starts accepting clients. Recreates the listening socket on every call, - /// so Stop/Start cycles are supported. + /// Starts accepting clients. Recreates the listening socket on every call, + /// so Stop/Start cycles are supported. /// public Task StartAsync(CancellationToken cancellationToken) { @@ -105,7 +103,7 @@ public Task StartAsync(CancellationToken cancellationToken) return Task.CompletedTask; } - _serverSocket = new Socket(_endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + _serverSocket = new(_endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _serverSocket.Bind(_endPoint); _serverSocket.Listen(DefaultBacklog); @@ -118,7 +116,7 @@ public Task StartAsync(CancellationToken cancellationToken) } /// - /// Stops accepting new clients and closes all active clients. + /// Stops accepting new clients and closes all active clients. /// public async Task StopAsync(CancellationToken cancellationToken) { @@ -173,7 +171,7 @@ public async Task StopAsync(CancellationToken cancellationToken) } /// - /// Registers middleware in execution order. + /// Registers middleware in execution order. /// public SquidTcpServer AddMiddleware(INetMiddleware middleware) { @@ -232,7 +230,7 @@ private async Task AcceptLoopAsync() catch (Exception ex) { _logger.Error(ex, "Accept loop failed"); - OnException?.Invoke(this, new SquidStdTcpExceptionEventArgs(ex)); + OnException?.Invoke(this, new(ex)); } } } @@ -251,10 +249,10 @@ private async Task CreateClientStreamAsync(Socket clientSocket, Cancella try { await sslStream.AuthenticateAsServerAsync( - _tlsOptions.ToAuthenticationOptions(), - cancellationToken - ) - .ConfigureAwait(false); + _tlsOptions.ToAuthenticationOptions(), + cancellationToken + ) + .ConfigureAwait(false); return sslStream; } @@ -270,67 +268,65 @@ await sslStream.AuthenticateAsServerAsync( private void WireClientEvents(SquidStdTcpClient client) { client.OnConnected += (_, args) => - { - _logger.Debug( - "OnClientConnect. SessionId={SessionId}, RemoteEndPoint={RemoteEndPoint}", - args.Client.SessionId, - args.Client.RemoteEndPoint - ); - OnClientConnect?.Invoke(this, args); - }; + { + _logger.Debug( + "OnClientConnect. SessionId={SessionId}, RemoteEndPoint={RemoteEndPoint}", + args.Client.SessionId, + args.Client.RemoteEndPoint + ); + OnClientConnect?.Invoke(this, args); + }; client.OnDataReceived += (_, args) => - { - _logger.Verbose( - "OnDataReceived. SessionId={SessionId}, Bytes={Bytes}", - args.Client.SessionId, - args.Data.Length - ); - OnDataReceived?.Invoke(this, args); - }; + { + _logger.Verbose( + "OnDataReceived. SessionId={SessionId}, Bytes={Bytes}", + args.Client.SessionId, + args.Data.Length + ); + OnDataReceived?.Invoke(this, args); + }; client.OnException += (_, args) => - { - _logger.Error( - args.Exception, - "OnException. SessionId={SessionId}", - args.Client?.SessionId - ); - OnException?.Invoke(this, args); - }; + { + _logger.Error( + args.Exception, + "OnException. SessionId={SessionId}", + args.Client?.SessionId + ); + OnException?.Invoke(this, args); + }; client.OnDisconnected += (_, args) => - { - _clients.TryRemove(args.Client.SessionId, out var _); - _logger.Debug( - "OnClientDisconnect. SessionId={SessionId}, RemoteEndPoint={RemoteEndPoint}", - args.Client.SessionId, - args.Client.RemoteEndPoint - ); - OnClientDisconnect?.Invoke(this, args); - }; + { + _clients.TryRemove(args.Client.SessionId, out var _); + _logger.Debug( + "OnClientDisconnect. SessionId={SessionId}, RemoteEndPoint={RemoteEndPoint}", + args.Client.SessionId, + args.Client.RemoteEndPoint + ); + OnClientDisconnect?.Invoke(this, args); + }; } /// public void Dispose() - { - DisposeAsync().AsTask().GetAwaiter().GetResult(); - } + => DisposeAsync().AsTask().GetAwaiter().GetResult(); /// - /// Raised when a client connects. + /// Raised when a client connects. /// public event EventHandler? OnClientConnect; /// - /// Raised when a client disconnects. + /// Raised when a client disconnects. /// public event EventHandler? OnClientDisconnect; /// - /// Raised when a client sends data after middleware processing. + /// Raised when a client sends data after middleware processing. /// public event EventHandler? OnDataReceived; /// - /// Raised when an exception happens in accept loop or client loops. + /// Raised when an exception happens in accept loop or client loops. /// public event EventHandler? OnException; } diff --git a/src/SquidStd.Network/Sessions/Session.cs b/src/SquidStd.Network/Sessions/Session.cs index 7f5584e2..6ff1a269 100644 --- a/src/SquidStd.Network/Sessions/Session.cs +++ b/src/SquidStd.Network/Sessions/Session.cs @@ -4,7 +4,7 @@ namespace SquidStd.Network.Sessions; /// -/// A tracked network connection with associated application state. +/// A tracked network connection with associated application state. /// /// Application-defined per-connection state. public sealed class Session @@ -39,13 +39,9 @@ public Session(long sessionId, INetworkConnection connection, TState state, Date /// Closes the underlying connection. public Task CloseAsync(CancellationToken cancellationToken = default) - { - return Connection.CloseAsync(cancellationToken); - } + => Connection.CloseAsync(cancellationToken); /// Sends a payload over the underlying connection. public Task SendAsync(ReadOnlyMemory payload, CancellationToken cancellationToken = default) - { - return Connection.SendAsync(payload, cancellationToken); - } + => Connection.SendAsync(payload, cancellationToken); } diff --git a/src/SquidStd.Network/Sessions/SessionManager.cs b/src/SquidStd.Network/Sessions/SessionManager.cs index 796a6244..ec66c803 100644 --- a/src/SquidStd.Network/Sessions/SessionManager.cs +++ b/src/SquidStd.Network/Sessions/SessionManager.cs @@ -8,8 +8,8 @@ namespace SquidStd.Network.Sessions; /// -/// Observes a and maintains a registry of . -/// The server is not modified; the manager subscribes to its lifecycle events. +/// Observes a and maintains a registry of . +/// The server is not modified; the manager subscribes to its lifecycle events. /// /// Application-defined per-connection state. public sealed class SessionManager : ISessionManager, IDisposable @@ -55,25 +55,19 @@ public async Task BroadcastAsync(ReadOnlyMemory payload, CancellationToken /// public Task DisconnectAsync(long sessionId, CancellationToken cancellationToken = default) - { - return _sessions.TryGetValue(sessionId, out var session) - ? session.CloseAsync(cancellationToken) - : Task.CompletedTask; - } + => _sessions.TryGetValue(sessionId, out var session) + ? session.CloseAsync(cancellationToken) + : Task.CompletedTask; /// public Task SendAsync(long sessionId, ReadOnlyMemory payload, CancellationToken cancellationToken = default) - { - return _sessions.TryGetValue(sessionId, out var session) - ? session.SendAsync(payload, cancellationToken) - : Task.CompletedTask; - } + => _sessions.TryGetValue(sessionId, out var session) + ? session.SendAsync(payload, cancellationToken) + : Task.CompletedTask; /// public bool TryGetSession(long sessionId, out Session? session) - { - return _sessions.TryGetValue(sessionId, out session); - } + => _sessions.TryGetValue(sessionId, out session); internal void HandleConnected(INetworkConnection connection) { @@ -111,25 +105,19 @@ internal void HandleDisconnected(INetworkConnection connection) } private void HandleServerClientConnect(object? sender, SquidStdTcpClientEventArgs e) - { - HandleConnected(e.Client); - } + => HandleConnected(e.Client); private void HandleServerClientDisconnect(object? sender, SquidStdTcpClientEventArgs e) - { - HandleDisconnected(e.Client); - } + => HandleDisconnected(e.Client); private void HandleServerDataReceived(object? sender, SquidStdTcpDataReceivedEventArgs e) - { - HandleData(e.Client, e.Data); - } + => HandleData(e.Client, e.Data); private void RaiseSessionCreated(Session session) { try { - OnSessionCreated?.Invoke(this, new SquidStdSessionEventArgs(session)); + OnSessionCreated?.Invoke(this, new(session)); } catch (Exception ex) { @@ -141,7 +129,7 @@ private void RaiseSessionData(Session session, ReadOnlyMemory data { try { - OnSessionData?.Invoke(this, new SquidStdSessionDataEventArgs(session, data)); + OnSessionData?.Invoke(this, new(session, data)); } catch (Exception ex) { @@ -153,7 +141,7 @@ private void RaiseSessionRemoved(Session session) { try { - OnSessionRemoved?.Invoke(this, new SquidStdSessionEventArgs(session)); + OnSessionRemoved?.Invoke(this, new(session)); } catch (Exception ex) { diff --git a/src/SquidStd.Network/Sessions/UdpSessionConnection.cs b/src/SquidStd.Network/Sessions/UdpSessionConnection.cs index b6fb7c8c..092d4b53 100644 --- a/src/SquidStd.Network/Sessions/UdpSessionConnection.cs +++ b/src/SquidStd.Network/Sessions/UdpSessionConnection.cs @@ -5,8 +5,8 @@ namespace SquidStd.Network.Sessions; /// -/// Virtual per-endpoint connection backing a UDP session. Sends route to the server's -/// ; closing removes the session via a callback. +/// Virtual per-endpoint connection backing a UDP session. Sends route to the server's +/// ; closing removes the session via a callback. /// internal sealed class UdpSessionConnection : INetworkConnection { @@ -38,7 +38,5 @@ public Task CloseAsync(CancellationToken cancellationToken = default) } public Task SendAsync(ReadOnlyMemory payload, CancellationToken cancellationToken) - { - return _server.SendToAsync(_remoteEndPoint, payload, cancellationToken); - } + => _server.SendToAsync(_remoteEndPoint, payload, cancellationToken); } diff --git a/src/SquidStd.Network/Sessions/UdpSessionEntry.cs b/src/SquidStd.Network/Sessions/UdpSessionEntry.cs index 5f5b38f0..3d4d3903 100644 --- a/src/SquidStd.Network/Sessions/UdpSessionEntry.cs +++ b/src/SquidStd.Network/Sessions/UdpSessionEntry.cs @@ -1,7 +1,7 @@ namespace SquidStd.Network.Sessions; /// -/// Internal registry entry pairing a UDP session with its last-activity timestamp. +/// Internal registry entry pairing a UDP session with its last-activity timestamp. /// /// Application-defined per-connection state. internal sealed class UdpSessionEntry diff --git a/src/SquidStd.Network/Sessions/UdpSessionManager.cs b/src/SquidStd.Network/Sessions/UdpSessionManager.cs index 4842a55e..20195e1a 100644 --- a/src/SquidStd.Network/Sessions/UdpSessionManager.cs +++ b/src/SquidStd.Network/Sessions/UdpSessionManager.cs @@ -9,8 +9,8 @@ namespace SquidStd.Network.Sessions; /// -/// Tracks per-endpoint UDP sessions over a . Sessions are created on -/// the first datagram from an endpoint and removed by idle-timeout sweep or explicit disconnect. +/// Tracks per-endpoint UDP sessions over a . Sessions are created on +/// the first datagram from an endpoint and removed by idle-timeout sweep or explicit disconnect. /// /// Application-defined per-connection state. public sealed class UdpSessionManager : ISessionManager, IDisposable @@ -75,19 +75,15 @@ public async Task BroadcastAsync(ReadOnlyMemory payload, CancellationToken /// public Task DisconnectAsync(long sessionId, CancellationToken cancellationToken = default) - { - return TryGetSession(sessionId, out var session) - ? session!.CloseAsync(cancellationToken) - : Task.CompletedTask; - } + => TryGetSession(sessionId, out var session) + ? session!.CloseAsync(cancellationToken) + : Task.CompletedTask; /// public Task SendAsync(long sessionId, ReadOnlyMemory payload, CancellationToken cancellationToken = default) - { - return TryGetSession(sessionId, out var session) - ? session!.SendAsync(payload, cancellationToken) - : Task.CompletedTask; - } + => TryGetSession(sessionId, out var session) + ? session!.SendAsync(payload, cancellationToken) + : Task.CompletedTask; /// public bool TryGetSession(long sessionId, out Session? session) @@ -106,19 +102,15 @@ public bool TryGetSession(long sessionId, out Session? session) /// Closes the session for the given endpoint. No-op when unknown. public Task DisconnectAsync(IPEndPoint endPoint, CancellationToken cancellationToken = default) - { - return TryGetSession(endPoint, out var session) - ? session!.CloseAsync(cancellationToken) - : Task.CompletedTask; - } + => TryGetSession(endPoint, out var session) + ? session!.CloseAsync(cancellationToken) + : Task.CompletedTask; /// Sends a payload to the session for the given endpoint. No-op when unknown. public Task SendToAsync(IPEndPoint endPoint, ReadOnlyMemory payload, CancellationToken cancellationToken = default) - { - return TryGetSession(endPoint, out var session) - ? session!.SendAsync(payload, cancellationToken) - : Task.CompletedTask; - } + => TryGetSession(endPoint, out var session) + ? session!.SendAsync(payload, cancellationToken) + : Task.CompletedTask; /// Looks up a session by remote endpoint. public bool TryGetSession(IPEndPoint endPoint, out Session? session) @@ -198,15 +190,13 @@ private UdpSessionEntry GetOrCreate(IPEndPoint remoteEndPoint, out bool } private void HandleServerDatagram(object? sender, SquidStdUdpDatagramReceivedEventArgs e) - { - HandleDatagram(e.RemoteEndPoint, e.Data); - } + => HandleDatagram(e.RemoteEndPoint, e.Data); private void RaiseSessionCreated(Session session) { try { - OnSessionCreated?.Invoke(this, new SquidStdSessionEventArgs(session)); + OnSessionCreated?.Invoke(this, new(session)); } catch (Exception ex) { @@ -218,7 +208,7 @@ private void RaiseSessionData(Session session, ReadOnlyMemory data { try { - OnSessionData?.Invoke(this, new SquidStdSessionDataEventArgs(session, data)); + OnSessionData?.Invoke(this, new(session, data)); } catch (Exception ex) { @@ -230,7 +220,7 @@ private void RaiseSessionRemoved(Session session) { try { - OnSessionRemoved?.Invoke(this, new SquidStdSessionEventArgs(session)); + OnSessionRemoved?.Invoke(this, new(session)); } catch (Exception ex) { diff --git a/src/SquidStd.Network/Spans/SpanReader.cs b/src/SquidStd.Network/Spans/SpanReader.cs index ea982d9b..3168a69e 100644 --- a/src/SquidStd.Network/Spans/SpanReader.cs +++ b/src/SquidStd.Network/Spans/SpanReader.cs @@ -38,57 +38,39 @@ public int Read(scoped Span bytes) [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadAscii(int fixedLength) - { - return ReadString(Encoding.ASCII, fixedLength: fixedLength); - } + => ReadString(Encoding.ASCII, fixedLength: fixedLength); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadAscii() - { - return ReadString(Encoding.ASCII); - } + => ReadString(Encoding.ASCII); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadAsciiSafe(int fixedLength) - { - return ReadString(Encoding.ASCII, true, fixedLength); - } + => ReadString(Encoding.ASCII, true, fixedLength); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadAsciiSafe() - { - return ReadString(Encoding.ASCII, true); - } + => ReadString(Encoding.ASCII, true); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadBigUni(int fixedLength) - { - return ReadString(Encoding.BigEndianUnicode, fixedLength: fixedLength); - } + => ReadString(Encoding.BigEndianUnicode, fixedLength: fixedLength); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadBigUni() - { - return ReadString(Encoding.BigEndianUnicode); - } + => ReadString(Encoding.BigEndianUnicode); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadBigUniSafe(int fixedLength) - { - return ReadString(Encoding.BigEndianUnicode, true, fixedLength); - } + => ReadString(Encoding.BigEndianUnicode, true, fixedLength); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadBigUniSafe() - { - return ReadString(Encoding.BigEndianUnicode, true); - } + => ReadString(Encoding.BigEndianUnicode, true); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool ReadBoolean() - { - return ReadByte() > 0; - } + => ReadByte() > 0; [MethodImpl(MethodImplOptions.AggressiveInlining)] public byte ReadByte() @@ -195,33 +177,23 @@ public long ReadInt64LE() [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadLittleUni(int fixedLength) - { - return ReadString(Encoding.Unicode, fixedLength: fixedLength); - } + => ReadString(Encoding.Unicode, fixedLength: fixedLength); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadLittleUni() - { - return ReadString(Encoding.Unicode); - } + => ReadString(Encoding.Unicode); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadLittleUniSafe(int fixedLength) - { - return ReadString(Encoding.Unicode, true, fixedLength); - } + => ReadString(Encoding.Unicode, true, fixedLength); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadLittleUniSafe() - { - return ReadString(Encoding.Unicode, true); - } + => ReadString(Encoding.Unicode, true); [MethodImpl(MethodImplOptions.AggressiveInlining)] public sbyte ReadSByte() - { - return (sbyte)ReadByte(); - } + => (sbyte)ReadByte(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadString(Encoding encoding, bool safeString = false, int fixedLength = -1) @@ -345,21 +317,15 @@ public ulong ReadUInt64LE() [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadUTF8() - { - return ReadString(Encoding.UTF8); - } + => ReadString(Encoding.UTF8); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadUTF8Safe(int fixedLength) - { - return ReadString(Encoding.UTF8, true, fixedLength); - } + => ReadString(Encoding.UTF8, true, fixedLength); [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadUTF8Safe() - { - return ReadString(Encoding.UTF8, true); - } + => ReadString(Encoding.UTF8, true); [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Seek(int offset, SeekOrigin origin) @@ -385,14 +351,12 @@ public int Seek(int offset, SeekOrigin origin) } private static int GetTerminatorWidth(Encoding encoding) - { - return encoding switch + => encoding switch { UnicodeEncoding => 2, UTF32Encoding => 4, _ => 1 }; - } private static int IndexOfTerminator(ReadOnlySpan span, int terminatorWidth) { @@ -426,9 +390,7 @@ private static int IndexOfTerminator(ReadOnlySpan span, int terminatorWidt [DoesNotReturn] private static void ThrowInsufficientData() - { - throw new InvalidOperationException("Insufficient data in buffer."); - } + => throw new InvalidOperationException("Insufficient data in buffer."); public void Dispose() { diff --git a/src/SquidStd.Network/Spans/SpanWriter.cs b/src/SquidStd.Network/Spans/SpanWriter.cs index f332a141..e7f2c053 100644 --- a/src/SquidStd.Network/Spans/SpanWriter.cs +++ b/src/SquidStd.Network/Spans/SpanWriter.cs @@ -75,9 +75,7 @@ public void EnsureCapacity(int capacity) } public ref byte GetPinnableReference() - { - return ref MemoryMarshal.GetReference(_buffer); - } + => ref MemoryMarshal.GetReference(_buffer); [MethodImpl(MethodImplOptions.NoInlining)] public void Grow(int additionalCapacity) @@ -151,7 +149,7 @@ public SpanOwner ToSpan() ArrayPool.Shared.Return(toReturn); } - return new SpanOwner(0, null, false); + return new(0, null, false); } // Capture the length BEFORE `this = default`, otherwise the reset zeroes @@ -163,14 +161,14 @@ public SpanOwner ToSpan() { this = default; - return new SpanOwner(length, currentPoolBuffer, true); + return new(length, currentPoolBuffer, true); } var ownedBuffer = ArrayPool.Shared.Rent(length); _buffer[..length].CopyTo(ownedBuffer); this = default; - return new SpanOwner(length, ownedBuffer, true); + return new(length, ownedBuffer, true); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -286,21 +284,15 @@ public void Write(ReadOnlySpan value, Encoding encoding, int fixedLength = [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteAscii(char chr) - { - Write((byte)chr); - } + => Write((byte)chr); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteAscii(string value) - { - Write(value.AsSpan(), Encoding.ASCII); - } + => Write(value.AsSpan(), Encoding.ASCII); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteAscii(string value, int fixedLength) - { - Write(value.AsSpan(), Encoding.ASCII, fixedLength); - } + => Write(value.AsSpan(), Encoding.ASCII, fixedLength); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteAsciiNull(string value) @@ -311,15 +303,11 @@ public void WriteAsciiNull(string value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteBigUni(string value) - { - Write(value.AsSpan(), Encoding.BigEndianUnicode); - } + => Write(value.AsSpan(), Encoding.BigEndianUnicode); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteBigUni(string value, int fixedLength) - { - Write(value.AsSpan(), Encoding.BigEndianUnicode, fixedLength); - } + => Write(value.AsSpan(), Encoding.BigEndianUnicode, fixedLength); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteBigUniNull(string value) @@ -362,15 +350,11 @@ public void WriteLE(uint value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteLittleUni(string value) - { - Write(value.AsSpan(), Encoding.Unicode); - } + => Write(value.AsSpan(), Encoding.Unicode); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteLittleUni(string value, int fixedLength) - { - Write(value.AsSpan(), Encoding.Unicode, fixedLength); - } + => Write(value.AsSpan(), Encoding.Unicode, fixedLength); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteLittleUniNull(string value) @@ -381,9 +365,7 @@ public void WriteLittleUniNull(string value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteUTF8(string value) - { - Write(value.AsSpan(), Encoding.UTF8); - } + => Write(value.AsSpan(), Encoding.UTF8); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteUTF8Null(string value) @@ -393,14 +375,12 @@ public void WriteUTF8Null(string value) } private static int GetTerminatorWidth(Encoding encoding) - { - return encoding switch + => encoding switch { UnicodeEncoding => 2, UTF32Encoding => 4, _ => 1 }; - } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void GrowIfNeeded(int count) @@ -431,7 +411,7 @@ public void Dispose() } /// - /// Represents SpanOwner. + /// Represents SpanOwner. /// public struct SpanOwner : IDisposable { diff --git a/src/SquidStd.Persistence.Abstractions/Interfaces/Persistence/ISnapshotService.cs b/src/SquidStd.Persistence.Abstractions/Interfaces/Persistence/ISnapshotService.cs index fc772362..987217c3 100644 --- a/src/SquidStd.Persistence.Abstractions/Interfaces/Persistence/ISnapshotService.cs +++ b/src/SquidStd.Persistence.Abstractions/Interfaces/Persistence/ISnapshotService.cs @@ -8,10 +8,14 @@ public interface ISnapshotService ValueTask DeleteBucketAsync(string typeName, ushort typeId, CancellationToken cancellationToken = default); ValueTask LoadBucketAsync( - string typeName, ushort typeId, CancellationToken cancellationToken = default + string typeName, + ushort typeId, + CancellationToken cancellationToken = default ); ValueTask SaveBucketAsync( - EntitySnapshotBucket bucket, long lastSequenceId, CancellationToken cancellationToken = default + EntitySnapshotBucket bucket, + long lastSequenceId, + CancellationToken cancellationToken = default ); } diff --git a/src/SquidStd.Persistence.Abstractions/README.md b/src/SquidStd.Persistence.Abstractions/README.md index 1276938d..9cef6e0f 100644 --- a/src/SquidStd.Persistence.Abstractions/README.md +++ b/src/SquidStd.Persistence.Abstractions/README.md @@ -11,17 +11,17 @@ dotnet add package SquidStd.Persistence.Abstractions ## Key types -| Type | Purpose | -|---------------------------------------|---------------------------------------------------------------| -| `IPersistenceService` | Lifecycle (`ISquidStdService`) + `GetStore()`. | -| `IEntityStore` | In-memory CRUD contract (clones on read, journals on write). | -| `IPersistenceEntityRegistry` | Registry of entity descriptors keyed by `typeId`/type pair. | -| `IPersistenceEntityDescriptor`| Serialize / deserialize / clone / key extraction contract. | -| `ISnapshotService` / `IJournalService`| Per-type snapshot and append-only journal contracts. | -| `PersistenceConfig` | Autosave cadence, file names, save directory, file lock. | -| `JournalEntry`, `EntitySnapshotBucket`, `PersistedBucket`, `SnapshotFileEnvelope` | Persisted DTOs. | -| `JournalEntityOperationType` | `Upsert` / `Remove` journal operation discriminator. | -| `SnapshotSaveStartedEvent` / `SnapshotSaveCompletedEvent` | Snapshot lifecycle events (`IEvent`). | +| Type | Purpose | +|-----------------------------------------------------------------------------------|--------------------------------------------------------------| +| `IPersistenceService` | Lifecycle (`ISquidStdService`) + `GetStore()`. | +| `IEntityStore` | In-memory CRUD contract (clones on read, journals on write). | +| `IPersistenceEntityRegistry` | Registry of entity descriptors keyed by `typeId`/type pair. | +| `IPersistenceEntityDescriptor` | Serialize / deserialize / clone / key extraction contract. | +| `ISnapshotService` / `IJournalService` | Per-type snapshot and append-only journal contracts. | +| `PersistenceConfig` | Autosave cadence, file names, save directory, file lock. | +| `JournalEntry`, `EntitySnapshotBucket`, `PersistedBucket`, `SnapshotFileEnvelope` | Persisted DTOs. | +| `JournalEntityOperationType` | `Upsert` / `Remove` journal operation discriminator. | +| `SnapshotSaveStartedEvent` / `SnapshotSaveCompletedEvent` | Snapshot lifecycle events (`IEvent`). | ## License diff --git a/src/SquidStd.Persistence.MessagePack/README.md b/src/SquidStd.Persistence.MessagePack/README.md index 643f25f6..16eff37d 100644 --- a/src/SquidStd.Persistence.MessagePack/README.md +++ b/src/SquidStd.Persistence.MessagePack/README.md @@ -29,9 +29,9 @@ container.RegisterInstance(new MessagePackDataSerializer()); ## Key types -| Type | Purpose | -|----------------------------|----------------------------------------------------------| -| `MessagePackDataSerializer`| Contractless MessagePack `IDataSerializer`/`IDataDeserializer`. | +| Type | Purpose | +|-----------------------------|-----------------------------------------------------------------| +| `MessagePackDataSerializer` | Contractless MessagePack `IDataSerializer`/`IDataDeserializer`. | ## License diff --git a/src/SquidStd.Persistence/Data/PersistenceEntityDescriptor.cs b/src/SquidStd.Persistence/Data/PersistenceEntityDescriptor.cs index 1170c6cf..9397b539 100644 --- a/src/SquidStd.Persistence/Data/PersistenceEntityDescriptor.cs +++ b/src/SquidStd.Persistence/Data/PersistenceEntityDescriptor.cs @@ -86,7 +86,7 @@ void IInternalEntityApplier.ApplyRemove(PersistenceStateStore stateStore, byte[] return null; } - return new EntitySnapshotBucket + return new() { TypeId = TypeId, TypeName = TypeName, diff --git a/src/SquidStd.Persistence/Internal/JournalRecordCodec.cs b/src/SquidStd.Persistence/Internal/JournalRecordCodec.cs index 43686e84..90cfc951 100644 --- a/src/SquidStd.Persistence/Internal/JournalRecordCodec.cs +++ b/src/SquidStd.Persistence/Internal/JournalRecordCodec.cs @@ -36,7 +36,7 @@ public static JournalEntry Decode(ReadOnlySpan bytes) var payloadLength = BinaryPrimitives.ReadInt32LittleEndian(bytes[19..]); var payload = bytes.Slice(FixedHeader, payloadLength).ToArray(); - return new JournalEntry + return new() { SequenceId = sequenceId, TimestampUnixMilliseconds = timestamp, diff --git a/src/SquidStd.Persistence/Internal/SnapshotEnvelopeCodec.cs b/src/SquidStd.Persistence/Internal/SnapshotEnvelopeCodec.cs index b0931f92..a2dd7dca 100644 --- a/src/SquidStd.Persistence/Internal/SnapshotEnvelopeCodec.cs +++ b/src/SquidStd.Persistence/Internal/SnapshotEnvelopeCodec.cs @@ -72,12 +72,12 @@ public static SnapshotFileEnvelope Decode(ReadOnlySpan bytes) offset += 4; var payload = bytes.Slice(offset, payloadLength).ToArray(); - return new SnapshotFileEnvelope + return new() { Version = version, LastSequenceId = lastSequenceId, Checksum = checksum, - Bucket = new EntitySnapshotBucket + Bucket = new() { TypeId = typeId, TypeName = typeName, diff --git a/src/SquidStd.Persistence/README.md b/src/SquidStd.Persistence/README.md index 39dde4a9..6700d011 100644 --- a/src/SquidStd.Persistence/README.md +++ b/src/SquidStd.Persistence/README.md @@ -56,15 +56,15 @@ container.ApplyPersistedEntityRegistrations(); // builds descriptors into IPer ## Key types -| Type | Purpose | -|---------------------------------------|---------------------------------------------------------------| -| `PersistenceService` | Lifecycle: load + replay, autosave, `GetStore()`. | -| `IEntityStore` | In-memory CRUD; reads clone, writes journal. | -| `PersistenceEntityDescriptor` | Serializer-injected descriptor (serialize/clone/key). | -| `PersistenceEntityRegistry` | Maps `typeId` ↔ descriptor; freezes after registration. | -| `BinaryJournalService` | Append-only framed binary WAL with tail-corruption recovery. | -| `SnapshotService` | Atomic per-type binary snapshot files with payload checksum. | -| `RegisterPersistedEntity()` | DI helper recording an entity for descriptor construction. | +| Type | Purpose | +|---------------------------------------|--------------------------------------------------------------| +| `PersistenceService` | Lifecycle: load + replay, autosave, `GetStore()`. | +| `IEntityStore` | In-memory CRUD; reads clone, writes journal. | +| `PersistenceEntityDescriptor` | Serializer-injected descriptor (serialize/clone/key). | +| `PersistenceEntityRegistry` | Maps `typeId` ↔ descriptor; freezes after registration. | +| `BinaryJournalService` | Append-only framed binary WAL with tail-corruption recovery. | +| `SnapshotService` | Atomic per-type binary snapshot files with payload checksum. | +| `RegisterPersistedEntity()` | DI helper recording an entity for descriptor construction. | ### Durability diff --git a/src/SquidStd.Persistence/Services/BinaryJournalService.cs b/src/SquidStd.Persistence/Services/BinaryJournalService.cs index 308dfbec..9a334b2c 100644 --- a/src/SquidStd.Persistence/Services/BinaryJournalService.cs +++ b/src/SquidStd.Persistence/Services/BinaryJournalService.cs @@ -55,7 +55,7 @@ public async ValueTask AppendAsync(JournalEntry entry, CancellationToken cancell if (_durability == DurabilityMode.Durable) { - stream.Flush(flushToDisk: true); + stream.Flush(true); } } finally @@ -65,7 +65,8 @@ public async ValueTask AppendAsync(JournalEntry entry, CancellationToken cancell } public async ValueTask AppendBatchAsync( - IReadOnlyList entries, CancellationToken cancellationToken = default + IReadOnlyList entries, + CancellationToken cancellationToken = default ) { ArgumentNullException.ThrowIfNull(entries); @@ -83,7 +84,7 @@ public async ValueTask AppendBatchAsync( if (_durability == DurabilityMode.Durable) { - stream.Flush(flushToDisk: true); + stream.Flush(true); } } finally @@ -137,8 +138,8 @@ public async ValueTask TrimThroughSequenceAsync(long inclusiveSequenceId, Cancel } var kept = ParseAll(await File.ReadAllBytesAsync(_path, cancellationToken)) - .Where(entry => entry.SequenceId > inclusiveSequenceId) - .ToArray(); + .Where(entry => entry.SequenceId > inclusiveSequenceId) + .ToArray(); await RewriteAsync(kept, cancellationToken); } @@ -152,7 +153,7 @@ private FileStream OpenAppendStream() { var options = _durability == DurabilityMode.Durable ? FileOptions.WriteThrough : FileOptions.None; - return new FileStream(_path, FileMode.Append, FileAccess.Write, FileShare.Read, bufferSize: 4096, options); + return new(_path, FileMode.Append, FileAccess.Write, FileShare.Read, 4096, options); } private List ParseAll(byte[] bytes) @@ -208,7 +209,9 @@ private async ValueTask RewriteAsync(IReadOnlyList entries, Cancel } private static async ValueTask WriteRecordAsync( - FileStream stream, JournalEntry entry, CancellationToken cancellationToken + FileStream stream, + JournalEntry entry, + CancellationToken cancellationToken ) { var record = JournalRecordCodec.Encode(entry); diff --git a/src/SquidStd.Persistence/Services/EntityStore.cs b/src/SquidStd.Persistence/Services/EntityStore.cs index e2f51e18..95de6fa8 100644 --- a/src/SquidStd.Persistence/Services/EntityStore.cs +++ b/src/SquidStd.Persistence/Services/EntityStore.cs @@ -78,7 +78,7 @@ public async ValueTask UpsertAsync(TEntity entity, CancellationToken cancellatio clone = _descriptor.Clone(entity); key = _descriptor.GetKey(clone); next = _stateStore.LastSequenceId + 1; // computed, not yet committed - entry = new JournalEntry + entry = new() { SequenceId = next, TimestampUnixMilliseconds = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), @@ -120,7 +120,7 @@ public async ValueTask RemoveAsync(TKey id, CancellationToken cancellation } next = _stateStore.LastSequenceId + 1; - entry = new JournalEntry + entry = new() { SequenceId = next, TimestampUnixMilliseconds = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), diff --git a/src/SquidStd.Persistence/Services/PersistenceService.cs b/src/SquidStd.Persistence/Services/PersistenceService.cs index 17d4e2c9..33d6dd2f 100644 --- a/src/SquidStd.Persistence/Services/PersistenceService.cs +++ b/src/SquidStd.Persistence/Services/PersistenceService.cs @@ -234,7 +234,5 @@ private async Task AutosaveLoopAsync(CancellationToken cancellationToken) } public async ValueTask DisposeAsync() - { - await StopAsync(CancellationToken.None); - } + => await StopAsync(CancellationToken.None); } diff --git a/src/SquidStd.Persistence/Services/SnapshotService.cs b/src/SquidStd.Persistence/Services/SnapshotService.cs index 2212bcb5..9edaeb41 100644 --- a/src/SquidStd.Persistence/Services/SnapshotService.cs +++ b/src/SquidStd.Persistence/Services/SnapshotService.cs @@ -60,7 +60,9 @@ public async ValueTask DeleteBucketAsync(string typeName, ushort typeId, Cancell } public async ValueTask LoadBucketAsync( - string typeName, ushort typeId, CancellationToken cancellationToken = default + string typeName, + ushort typeId, + CancellationToken cancellationToken = default ) { ArgumentException.ThrowIfNullOrWhiteSpace(typeName); @@ -91,8 +93,8 @@ public async ValueTask DeleteBucketAsync(string typeName, ushort typeId, Cancell var envelope = SnapshotEnvelopeCodec.Decode(bytes); var checksumValid = envelope.Version >= 2 - ? SnapshotEnvelopeCodec.ComputeFullChecksum(bytes) == envelope.Checksum - : ChecksumUtils.Compute(envelope.Bucket.Payload) == envelope.Checksum; + ? SnapshotEnvelopeCodec.ComputeFullChecksum(bytes) == envelope.Checksum + : ChecksumUtils.Compute(envelope.Bucket.Payload) == envelope.Checksum; if (!checksumValid || !string.Equals(envelope.Bucket.TypeName, typeName, StringComparison.Ordinal)) { @@ -101,7 +103,7 @@ public async ValueTask DeleteBucketAsync(string typeName, ushort typeId, Cancell return null; } - return new PersistedBucket(envelope.Bucket, envelope.LastSequenceId); + return new(envelope.Bucket, envelope.LastSequenceId); } catch (OperationCanceledException) { @@ -120,7 +122,9 @@ public async ValueTask DeleteBucketAsync(string typeName, ushort typeId, Cancell } public async ValueTask SaveBucketAsync( - EntitySnapshotBucket bucket, long lastSequenceId, CancellationToken cancellationToken = default + EntitySnapshotBucket bucket, + long lastSequenceId, + CancellationToken cancellationToken = default ) { ArgumentNullException.ThrowIfNull(bucket); @@ -153,7 +157,7 @@ public async ValueTask SaveBucketAsync( if (_durability == DurabilityMode.Durable) { - stream.Flush(flushToDisk: true); // fsync the temp file before the atomic rename + stream.Flush(true); // fsync the temp file before the atomic rename } else { @@ -170,14 +174,10 @@ public async ValueTask SaveBucketAsync( } private string PathFor(string typeName, ushort typeId) - { - return Path.Combine(_directory, SnakeName(typeName) + "_" + typeId + _suffix); - } + => Path.Combine(_directory, SnakeName(typeName) + "_" + typeId + _suffix); private string LegacyPathFor(string typeName) - { - return Path.Combine(_directory, SnakeName(typeName) + _suffix); - } + => Path.Combine(_directory, SnakeName(typeName) + _suffix); private string SnakeName(string typeName) { diff --git a/src/SquidStd.Plugin.Abstractions/Data/PluginContext.cs b/src/SquidStd.Plugin.Abstractions/Data/PluginContext.cs index 1d511a0a..93fed50e 100644 --- a/src/SquidStd.Plugin.Abstractions/Data/PluginContext.cs +++ b/src/SquidStd.Plugin.Abstractions/Data/PluginContext.cs @@ -5,7 +5,5 @@ public class PluginContext public Dictionary Data { get; } = new(); public TData GetData(string key) - { - return (TData)Data[key]; - } + => (TData)Data[key]; } diff --git a/src/SquidStd.Plugin.Abstractions/Data/PluginMetadata.cs b/src/SquidStd.Plugin.Abstractions/Data/PluginMetadata.cs index 65672cfa..eeffa2f3 100644 --- a/src/SquidStd.Plugin.Abstractions/Data/PluginMetadata.cs +++ b/src/SquidStd.Plugin.Abstractions/Data/PluginMetadata.cs @@ -1,7 +1,7 @@ namespace SquidStd.Plugin.Abstractions.Data; /// -/// Describes a Moongate plugin. This is the source of truth for plugin identity. +/// Describes a Moongate plugin. This is the source of truth for plugin identity. /// public sealed class PluginMetadata { diff --git a/src/SquidStd.Plugin.Abstractions/Interfaces/Plugins/ISquidStdPlugin.cs b/src/SquidStd.Plugin.Abstractions/Interfaces/Plugins/ISquidStdPlugin.cs index 7b575827..d761f5a0 100644 --- a/src/SquidStd.Plugin.Abstractions/Interfaces/Plugins/ISquidStdPlugin.cs +++ b/src/SquidStd.Plugin.Abstractions/Interfaces/Plugins/ISquidStdPlugin.cs @@ -4,7 +4,7 @@ namespace SquidStd.Plugin.Abstractions.Interfaces.Plugins; /// -/// Implemented by trusted .NET plugins loaded by Moongate during server startup. +/// Implemented by trusted .NET plugins loaded by Moongate during server startup. /// public interface ISquidStdPlugin { @@ -12,8 +12,8 @@ public interface ISquidStdPlugin PluginMetadata Metadata { get; } /// - /// Registers the plugin's services, handlers, config sections, Lua modules, and other integrations. - /// Called during container configuration before global server YAML config is loaded. + /// Registers the plugin's services, handlers, config sections, Lua modules, and other integrations. + /// Called during container configuration before global server YAML config is loaded. /// /// The DryIoc container being configured. /// The plugin-specific boot context. diff --git a/src/SquidStd.Scripting.Lua/Attributes/RegisterScriptModuleAttribute.cs b/src/SquidStd.Scripting.Lua/Attributes/RegisterScriptModuleAttribute.cs index c714e3b2..df3f076f 100644 --- a/src/SquidStd.Scripting.Lua/Attributes/RegisterScriptModuleAttribute.cs +++ b/src/SquidStd.Scripting.Lua/Attributes/RegisterScriptModuleAttribute.cs @@ -1,9 +1,7 @@ namespace SquidStd.Scripting.Lua.Attributes; /// -/// Marks a Lua script module for generated registration. +/// Marks a Lua script module for generated registration. /// [AttributeUsage(AttributeTargets.Class, Inherited = false)] -public sealed class RegisterScriptModuleAttribute : Attribute -{ -} +public sealed class RegisterScriptModuleAttribute : Attribute { } diff --git a/src/SquidStd.Scripting.Lua/Attributes/Scripts/ScriptFunctionAttribute.cs b/src/SquidStd.Scripting.Lua/Attributes/Scripts/ScriptFunctionAttribute.cs index a724f8ab..5f20e670 100644 --- a/src/SquidStd.Scripting.Lua/Attributes/Scripts/ScriptFunctionAttribute.cs +++ b/src/SquidStd.Scripting.Lua/Attributes/Scripts/ScriptFunctionAttribute.cs @@ -1,23 +1,23 @@ namespace SquidStd.Scripting.Lua.Attributes.Scripts; /// -/// Attribute that marks a method as a script function exposed to scripting languages. +/// Attribute that marks a method as a script function exposed to scripting languages. /// [AttributeUsage(AttributeTargets.Method)] public class ScriptFunctionAttribute : Attribute { /// - /// Gets the optional name override for the script function. + /// Gets the optional name override for the script function. /// public string? FunctionName { get; } /// - /// Gets the optional help text describing the function's purpose. + /// Gets the optional help text describing the function's purpose. /// public string? HelpText { get; } /// - /// Initializes a new instance of the ScriptFunctionAttribute class. + /// Initializes a new instance of the ScriptFunctionAttribute class. /// /// The optional name override for the script function. /// The optional help text describing the function's purpose. diff --git a/src/SquidStd.Scripting.Lua/Attributes/Scripts/ScriptModuleAttribute.cs b/src/SquidStd.Scripting.Lua/Attributes/Scripts/ScriptModuleAttribute.cs index b12b47c2..0e54b821 100644 --- a/src/SquidStd.Scripting.Lua/Attributes/Scripts/ScriptModuleAttribute.cs +++ b/src/SquidStd.Scripting.Lua/Attributes/Scripts/ScriptModuleAttribute.cs @@ -1,7 +1,7 @@ namespace SquidStd.Scripting.Lua.Attributes.Scripts; /// -/// Attribute that marks a class as a script module exposed to scripting languages. +/// Attribute that marks a class as a script module exposed to scripting languages. /// [AttributeUsage(AttributeTargets.Class)] public class ScriptModuleAttribute : Attribute @@ -13,7 +13,7 @@ public class ScriptModuleAttribute : Attribute public string? HelpText { get; } /// - /// Initializes a new instance of the ScriptModuleAttribute class. + /// Initializes a new instance of the ScriptModuleAttribute class. /// /// The name under which the module will be accessible in Lua. /// The optional help text describing the module's purpose. diff --git a/src/SquidStd.Scripting.Lua/Context/SquidStdScriptJsonContext.cs b/src/SquidStd.Scripting.Lua/Context/SquidStdScriptJsonContext.cs index 485076cb..d55ec080 100644 --- a/src/SquidStd.Scripting.Lua/Context/SquidStdScriptJsonContext.cs +++ b/src/SquidStd.Scripting.Lua/Context/SquidStdScriptJsonContext.cs @@ -3,15 +3,11 @@ namespace SquidStd.Scripting.Lua.Context; -[JsonSerializable(typeof(LuarcConfig))] -[JsonSerializable(typeof(LuarcRuntimeConfig))] -[JsonSerializable(typeof(LuarcWorkspaceConfig))] -[JsonSerializable(typeof(LuarcDiagnosticsConfig))] -[JsonSerializable(typeof(LuarcCompletionConfig))] -[JsonSerializable(typeof(LuarcFormatConfig))] +[JsonSerializable(typeof(LuarcConfig)), JsonSerializable(typeof(LuarcRuntimeConfig)), + JsonSerializable(typeof(LuarcWorkspaceConfig)), JsonSerializable(typeof(LuarcDiagnosticsConfig)), + JsonSerializable(typeof(LuarcCompletionConfig)), JsonSerializable(typeof(LuarcFormatConfig))] + /// /// JSON serialization context for Lua scripting configuration types. /// -public partial class SquidStdScriptJsonContext : JsonSerializerContext -{ -} +public partial class SquidStdScriptJsonContext : JsonSerializerContext { } diff --git a/src/SquidStd.Scripting.Lua/Data/Internal/ScriptModuleData.cs b/src/SquidStd.Scripting.Lua/Data/Internal/ScriptModuleData.cs index bde2dd25..531d682d 100644 --- a/src/SquidStd.Scripting.Lua/Data/Internal/ScriptModuleData.cs +++ b/src/SquidStd.Scripting.Lua/Data/Internal/ScriptModuleData.cs @@ -1,17 +1,17 @@ namespace SquidStd.Scripting.Lua.Data.Internal; /// -/// Record containing data about a script module for internal processing. +/// Record containing data about a script module for internal processing. /// public sealed record ScriptModuleData { /// - /// The .NET type of the script module. + /// The .NET type of the script module. /// public Type ModuleType { get; } /// - /// Initializes a new instance of the ScriptModuleData record. + /// Initializes a new instance of the ScriptModuleData record. /// /// The .NET type of the script module. public ScriptModuleData(Type moduleType) diff --git a/src/SquidStd.Scripting.Lua/Data/Internal/ScriptUserData.cs b/src/SquidStd.Scripting.Lua/Data/Internal/ScriptUserData.cs index a002f05f..6f518bbb 100644 --- a/src/SquidStd.Scripting.Lua/Data/Internal/ScriptUserData.cs +++ b/src/SquidStd.Scripting.Lua/Data/Internal/ScriptUserData.cs @@ -1,12 +1,12 @@ namespace SquidStd.Scripting.Lua.Data.Internal; /// -/// Represents user data for scripts. +/// Represents user data for scripts. /// public class ScriptUserData { /// - /// Gets or sets the user type. + /// Gets or sets the user type. /// public Type UserType { get; set; } } diff --git a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcCompletionConfig.cs b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcCompletionConfig.cs index 112af62e..b7086634 100644 --- a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcCompletionConfig.cs +++ b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcCompletionConfig.cs @@ -3,18 +3,18 @@ namespace SquidStd.Scripting.Lua.Data.Luarc; /// -/// Completion configuration for Lua Language Server +/// Completion configuration for Lua Language Server /// public class LuarcCompletionConfig { /// - /// Gets or sets whether completion is enabled. + /// Gets or sets whether completion is enabled. /// [JsonPropertyName("enable")] public bool Enable { get; set; } = true; /// - /// Gets or sets the call snippet setting. + /// Gets or sets the call snippet setting. /// [JsonPropertyName("callSnippet")] public string CallSnippet { get; set; } = "Replace"; diff --git a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcConfig.cs b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcConfig.cs index bf5b2e58..8726bd11 100644 --- a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcConfig.cs +++ b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcConfig.cs @@ -3,7 +3,7 @@ namespace SquidStd.Scripting.Lua.Data.Luarc; /// -/// Configuration class for Lua Language Server (.luarc.json file) +/// Configuration class for Lua Language Server (.luarc.json file) /// public class LuarcConfig { @@ -15,31 +15,31 @@ public class LuarcConfig public string Schema { get; set; } = "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json"; /// - /// Gets or sets the runtime configuration. + /// Gets or sets the runtime configuration. /// [JsonPropertyName("runtime")] public LuarcRuntimeConfig Runtime { get; set; } = new(); /// - /// Gets or sets the workspace configuration. + /// Gets or sets the workspace configuration. /// [JsonPropertyName("workspace")] public LuarcWorkspaceConfig Workspace { get; set; } = new(); /// - /// Gets or sets the diagnostics configuration. + /// Gets or sets the diagnostics configuration. /// [JsonPropertyName("diagnostics")] public LuarcDiagnosticsConfig Diagnostics { get; set; } = new(); /// - /// Gets or sets the completion configuration. + /// Gets or sets the completion configuration. /// [JsonPropertyName("completion")] public LuarcCompletionConfig Completion { get; set; } = new(); /// - /// Gets or sets the format configuration. + /// Gets or sets the format configuration. /// [JsonPropertyName("format")] public LuarcFormatConfig Format { get; set; } = new(); diff --git a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcDiagnosticsConfig.cs b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcDiagnosticsConfig.cs index 777a2b3d..bb22e469 100644 --- a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcDiagnosticsConfig.cs +++ b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcDiagnosticsConfig.cs @@ -3,9 +3,10 @@ namespace SquidStd.Scripting.Lua.Data.Luarc; /// -/// Diagnostics configuration for Lua Language Server +/// Diagnostics configuration for Lua Language Server /// public class LuarcDiagnosticsConfig { - [JsonPropertyName("globals")] public string[] Globals { get; set; } = []; + [JsonPropertyName("globals")] + public string[] Globals { get; set; } = []; } diff --git a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcFormatConfig.cs b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcFormatConfig.cs index 5b823013..0828099e 100644 --- a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcFormatConfig.cs +++ b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcFormatConfig.cs @@ -3,11 +3,13 @@ namespace SquidStd.Scripting.Lua.Data.Luarc; /// -/// Format configuration for Lua Language Server +/// Format configuration for Lua Language Server /// public class LuarcFormatConfig { - [JsonPropertyName("enable")] public bool Enable { get; set; } = true; + [JsonPropertyName("enable")] + public bool Enable { get; set; } = true; - [JsonPropertyName("defaultConfig")] public LuarcFormatDefaultConfig DefaultConfig { get; set; } = new(); + [JsonPropertyName("defaultConfig")] + public LuarcFormatDefaultConfig DefaultConfig { get; set; } = new(); } diff --git a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcFormatDefaultConfig.cs b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcFormatDefaultConfig.cs index 0456d94e..e34ca695 100644 --- a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcFormatDefaultConfig.cs +++ b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcFormatDefaultConfig.cs @@ -3,11 +3,13 @@ namespace SquidStd.Scripting.Lua.Data.Luarc; /// -/// Default format configuration for Lua Language Server +/// Default format configuration for Lua Language Server /// public class LuarcFormatDefaultConfig { - [JsonPropertyName("indent_style")] public string IndentStyle { get; set; } = "space"; + [JsonPropertyName("indent_style")] + public string IndentStyle { get; set; } = "space"; - [JsonPropertyName("indent_size")] public string IndentSize { get; set; } = "4"; + [JsonPropertyName("indent_size")] + public string IndentSize { get; set; } = "4"; } diff --git a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcRuntimeConfig.cs b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcRuntimeConfig.cs index 0ac03aa8..b6ecbe4c 100644 --- a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcRuntimeConfig.cs +++ b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcRuntimeConfig.cs @@ -3,11 +3,13 @@ namespace SquidStd.Scripting.Lua.Data.Luarc; /// -/// Runtime configuration for Lua Language Server +/// Runtime configuration for Lua Language Server /// public class LuarcRuntimeConfig { - [JsonPropertyName("version")] public string Version { get; set; } = "Lua 5.4"; + [JsonPropertyName("version")] + public string Version { get; set; } = "Lua 5.4"; - [JsonPropertyName("path")] public string[] Path { get; set; } = []; + [JsonPropertyName("path")] + public string[] Path { get; set; } = []; } diff --git a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcWorkspaceConfig.cs b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcWorkspaceConfig.cs index fa114261..72ba1948 100644 --- a/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcWorkspaceConfig.cs +++ b/src/SquidStd.Scripting.Lua/Data/Luarc/LuarcWorkspaceConfig.cs @@ -3,11 +3,13 @@ namespace SquidStd.Scripting.Lua.Data.Luarc; /// -/// Workspace configuration for Lua Language Server +/// Workspace configuration for Lua Language Server /// public class LuarcWorkspaceConfig { - [JsonPropertyName("library")] public string[] Library { get; set; } = []; + [JsonPropertyName("library")] + public string[] Library { get; set; } = []; - [JsonPropertyName("checkThirdParty")] public bool CheckThirdParty { get; set; } = false; + [JsonPropertyName("checkThirdParty")] + public bool CheckThirdParty { get; set; } = false; } diff --git a/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptErrorInfo.cs b/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptErrorInfo.cs index 41d257af..5b88190f 100644 --- a/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptErrorInfo.cs +++ b/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptErrorInfo.cs @@ -1,62 +1,62 @@ namespace SquidStd.Scripting.Lua.Data.Scripts; /// -/// Detailed information about a Lua execution error. +/// Detailed information about a Lua execution error. /// public class ScriptErrorInfo { /// - /// Gets or sets the error message. + /// Gets or sets the error message. /// public string Message { get; set; } = ""; /// - /// Gets or sets the stack trace. + /// Gets or sets the stack trace. /// public string? StackTrace { get; set; } /// - /// Gets or sets the line number. + /// Gets or sets the line number. /// public int? LineNumber { get; set; } /// - /// Gets or sets the column number. + /// Gets or sets the column number. /// public int? ColumnNumber { get; set; } /// - /// Gets or sets the file name. + /// Gets or sets the file name. /// public string? FileName { get; set; } /// - /// Gets or sets the error type. + /// Gets or sets the error type. /// public string? ErrorType { get; set; } /// - /// Gets or sets the source code. + /// Gets or sets the source code. /// public string? SourceCode { get; set; } /// - /// Original source file name when a mapped source is available. + /// Original source file name when a mapped source is available. /// public string? OriginalFileName { get; set; } /// - /// Original line number when a mapped source is available. + /// Original line number when a mapped source is available. /// public int? OriginalLineNumber { get; set; } /// - /// Original column number when a mapped source is available. + /// Original column number when a mapped source is available. /// public int? OriginalColumnNumber { get; set; } /// - /// Optional origin label — e.g. the Lua component name when the error came from a lifecycle hook. + /// Optional origin label — e.g. the Lua component name when the error came from a lifecycle hook. /// public string? Source { get; set; } } diff --git a/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptExecutionMetrics.cs b/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptExecutionMetrics.cs index aa2dd0f2..a14d7fd1 100644 --- a/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptExecutionMetrics.cs +++ b/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptExecutionMetrics.cs @@ -1,37 +1,37 @@ namespace SquidStd.Scripting.Lua.Data.Scripts; /// -/// Metrics about script execution performance. +/// Metrics about script execution performance. /// public class ScriptExecutionMetrics { /// - /// Gets or sets the execution time in milliseconds. + /// Gets or sets the execution time in milliseconds. /// public long ExecutionTimeMs { get; set; } /// - /// Gets or sets the memory used in bytes. + /// Gets or sets the memory used in bytes. /// public long MemoryUsedBytes { get; set; } /// - /// Gets or sets the number of statements executed. + /// Gets or sets the number of statements executed. /// public int StatementsExecuted { get; set; } /// - /// Gets or sets the number of cache hits. + /// Gets or sets the number of cache hits. /// public int CacheHits { get; set; } /// - /// Gets or sets the number of cache misses. + /// Gets or sets the number of cache misses. /// public int CacheMisses { get; set; } /// - /// Gets or sets the total number of scripts cached. + /// Gets or sets the total number of scripts cached. /// public int TotalScriptsCached { get; set; } } diff --git a/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptResult.cs b/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptResult.cs index 79f37619..a6e991f1 100644 --- a/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptResult.cs +++ b/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptResult.cs @@ -1,22 +1,22 @@ namespace SquidStd.Scripting.Lua.Data.Scripts; /// -/// Represents the result of a script execution. +/// Represents the result of a script execution. /// public class ScriptResult { /// - /// Gets or sets a value indicating whether the script execution was successful. + /// Gets or sets a value indicating whether the script execution was successful. /// public bool Success { get; set; } /// - /// Gets or sets the message associated with the script result. + /// Gets or sets the message associated with the script result. /// public string Message { get; set; } /// - /// Gets or sets the data returned by the script execution. + /// Gets or sets the data returned by the script execution. /// public object? Data { get; set; } } diff --git a/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptResultBuilder.cs b/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptResultBuilder.cs index 0c13c2d5..147af4e1 100644 --- a/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptResultBuilder.cs +++ b/src/SquidStd.Scripting.Lua/Data/Scripts/ScriptResultBuilder.cs @@ -1,7 +1,7 @@ namespace SquidStd.Scripting.Lua.Data.Scripts; /// -/// Builder class for creating ScriptResult instances. +/// Builder class for creating ScriptResult instances. /// public class ScriptResultBuilder { @@ -10,36 +10,30 @@ public class ScriptResultBuilder private bool _success; /// - /// Builds the ScriptResult instance. + /// Builds the ScriptResult instance. /// public ScriptResult Build() - { - return new ScriptResult + => new() { Success = _success, Message = _message, Data = _data }; - } /// - /// Creates a ScriptResultBuilder initialized for an error result. + /// Creates a ScriptResultBuilder initialized for an error result. /// public static ScriptResultBuilder CreateError() - { - return new ScriptResultBuilder().WithSuccess(false); - } + => new ScriptResultBuilder().WithSuccess(false); /// - /// Creates a ScriptResultBuilder initialized for a successful result. + /// Creates a ScriptResultBuilder initialized for a successful result. /// public static ScriptResultBuilder CreateSuccess() - { - return new ScriptResultBuilder().WithSuccess(true); - } + => new ScriptResultBuilder().WithSuccess(true); /// - /// Sets the result as failed. + /// Sets the result as failed. /// public ScriptResultBuilder Failure() { @@ -49,7 +43,7 @@ public ScriptResultBuilder Failure() } /// - /// Sets the result as successful. + /// Sets the result as successful. /// public ScriptResultBuilder Success() { @@ -59,7 +53,7 @@ public ScriptResultBuilder Success() } /// - /// Sets the data of the result. + /// Sets the data of the result. /// public ScriptResultBuilder WithData(object? data) { @@ -69,7 +63,7 @@ public ScriptResultBuilder WithData(object? data) } /// - /// Sets the message of the result. + /// Sets the message of the result. /// public ScriptResultBuilder WithMessage(string message) { @@ -79,7 +73,7 @@ public ScriptResultBuilder WithMessage(string message) } /// - /// Sets the success status of the result. + /// Sets the success status of the result. /// public ScriptResultBuilder WithSuccess(bool success) { diff --git a/src/SquidStd.Scripting.Lua/Descriptors/GenericUserDataDescriptor.cs b/src/SquidStd.Scripting.Lua/Descriptors/GenericUserDataDescriptor.cs index 458658b6..245c9db8 100644 --- a/src/SquidStd.Scripting.Lua/Descriptors/GenericUserDataDescriptor.cs +++ b/src/SquidStd.Scripting.Lua/Descriptors/GenericUserDataDescriptor.cs @@ -4,16 +4,16 @@ namespace SquidStd.Scripting.Lua.Descriptors; /// -/// Generic UserData descriptor that adds support for string concatenation and conversion. -/// Implements the __tostring metamethod to allow Lua to convert any userdata type to strings. +/// Generic UserData descriptor that adds support for string concatenation and conversion. +/// Implements the __tostring metamethod to allow Lua to convert any userdata type to strings. /// public class GenericUserDataDescriptor : StandardUserDataDescriptor { private readonly bool _isXnaType; /// - /// Creates a new descriptor for a type with reflection access mode. - /// Automatically detects if the type is an XNA Framework type. + /// Creates a new descriptor for a type with reflection access mode. + /// Automatically detects if the type is an XNA Framework type. /// /// The type to describe (can be XNA or any other .NET type). public GenericUserDataDescriptor(Type type) @@ -24,17 +24,17 @@ public GenericUserDataDescriptor(Type type) } /// - /// Converts the object to its string representation. - /// This is used by MoonSharp when the object is converted to a string in Lua (concatenation, tostring(), etc.). + /// Converts the object to its string representation. + /// This is used by MoonSharp when the object is converted to a string in Lua (concatenation, tostring(), etc.). /// /// The object to convert to string. /// - /// For XNA types: Uses ToString() for a readable representation. - /// For other types: Uses ToString() or the type name if ToString() returns null. + /// For XNA types: Uses ToString() for a readable representation. + /// For other types: Uses ToString() or the type name if ToString() returns null. /// /// - /// In Lua, this allows: - /// + /// In Lua, this allows: + /// /// local vec = Vector2(10, 20) /// print("Position: " .. vec) -- ✅ Calls AsString(vec) instead of erroring /// local str = tostring(vec) -- ✅ Works with tostring() @@ -51,10 +51,10 @@ public override string AsString(object obj) var str = obj.ToString(); return string.IsNullOrWhiteSpace(str) - ? + ? - // Fallback: use the type name if ToString() returns empty/null - $"{Type.Name}({{}})" - : str; + // Fallback: use the type name if ToString() returns empty/null + $"{Type.Name}({{}})" + : str; } } diff --git a/src/SquidStd.Scripting.Lua/Extensions/Scripts/AddScriptModuleExtension.cs b/src/SquidStd.Scripting.Lua/Extensions/Scripts/AddScriptModuleExtension.cs index df5c2fb8..4cf0e5f0 100644 --- a/src/SquidStd.Scripting.Lua/Extensions/Scripts/AddScriptModuleExtension.cs +++ b/src/SquidStd.Scripting.Lua/Extensions/Scripts/AddScriptModuleExtension.cs @@ -6,7 +6,7 @@ namespace SquidStd.Scripting.Lua.Extensions.Scripts; /// -/// Extension methods for registering Lua script modules in the dependency injection container. +/// Extension methods for registering Lua script modules in the dependency injection container. /// public static class AddScriptModuleExtension { @@ -14,7 +14,7 @@ public static class AddScriptModuleExtension extension(IContainer container) { /// - /// Registers a user data type with the container for Lua scripting. + /// Registers a user data type with the container for Lua scripting. /// public IContainer RegisterLuaUserData(Type userDataType) { @@ -29,7 +29,7 @@ public IContainer RegisterLuaUserData(Type userDataType) } /// - /// Registers a user data type with the container for Lua scripting using generics. + /// Registers a user data type with the container for Lua scripting using generics. /// public IContainer RegisterLuaUserData() { @@ -39,7 +39,7 @@ public IContainer RegisterLuaUserData() } /// - /// Registers a Lua script module type with the container. + /// Registers a Lua script module type with the container. /// /// The type of the script module to register. /// The container for method chaining. @@ -59,13 +59,11 @@ public IContainer RegisterScriptModule(Type scriptModule) } /// - /// Registers a Lua script module type with the container using a generic type parameter. + /// Registers a Lua script module type with the container using a generic type parameter. /// /// The type of the script module to register. /// The container for method chaining. public IContainer RegisterScriptModule() where TScriptModule : class - { - return container.RegisterScriptModule(typeof(TScriptModule)); - } + => container.RegisterScriptModule(typeof(TScriptModule)); } } diff --git a/src/SquidStd.Scripting.Lua/Extensions/Scripts/TableExtensions.cs b/src/SquidStd.Scripting.Lua/Extensions/Scripts/TableExtensions.cs index 945ea825..76fe5311 100644 --- a/src/SquidStd.Scripting.Lua/Extensions/Scripts/TableExtensions.cs +++ b/src/SquidStd.Scripting.Lua/Extensions/Scripts/TableExtensions.cs @@ -5,14 +5,14 @@ namespace SquidStd.Scripting.Lua.Extensions.Scripts; /// -/// Provides extension methods for MoonSharp Table objects to enable proxying to interfaces. +/// Provides extension methods for MoonSharp Table objects to enable proxying to interfaces. /// public static class TableExtensions { extension(Table table) { /// - /// Converts a MoonSharp Table to a proxy implementing the specified interface. + /// Converts a MoonSharp Table to a proxy implementing the specified interface. /// public TInterface ToProxy() where TInterface : class diff --git a/src/SquidStd.Scripting.Lua/Interfaces/Events/ILuaEventBridge.cs b/src/SquidStd.Scripting.Lua/Interfaces/Events/ILuaEventBridge.cs index fd74fdca..d7e37dbb 100644 --- a/src/SquidStd.Scripting.Lua/Interfaces/Events/ILuaEventBridge.cs +++ b/src/SquidStd.Scripting.Lua/Interfaces/Events/ILuaEventBridge.cs @@ -3,18 +3,18 @@ namespace SquidStd.Scripting.Lua.Interfaces.Events; /// -/// Bridges named server events and internal callbacks into Lua closures. +/// Bridges named server events and internal callbacks into Lua closures. /// public interface ILuaEventBridge { /// - /// Attaches the active MoonSharp script runtime used to invoke registered closures. + /// Attaches the active MoonSharp script runtime used to invoke registered closures. /// /// Active Lua script runtime. void Attach(Script script); /// - /// Invokes a single closure with the supplied payload. + /// Invokes a single closure with the supplied payload. /// /// Lua closure to invoke. /// Payload exposed to Lua as a table. @@ -22,14 +22,14 @@ public interface ILuaEventBridge DynValue Invoke(Closure callback, IReadOnlyDictionary payload); /// - /// Publishes a named event to every Lua callback registered for it. + /// Publishes a named event to every Lua callback registered for it. /// /// Stable event name, such as player.connected. /// Payload exposed to Lua as a table. void Publish(string eventName, IReadOnlyDictionary payload); /// - /// Registers a Lua callback for a named event. + /// Registers a Lua callback for a named event. /// /// Stable event name, such as player.connected. /// Lua closure to invoke when the event is published. diff --git a/src/SquidStd.Scripting.Lua/Interfaces/Scripts/IScriptEngineService.cs b/src/SquidStd.Scripting.Lua/Interfaces/Scripts/IScriptEngineService.cs index 5d4783b6..7cc7403a 100644 --- a/src/SquidStd.Scripting.Lua/Interfaces/Scripts/IScriptEngineService.cs +++ b/src/SquidStd.Scripting.Lua/Interfaces/Scripts/IScriptEngineService.cs @@ -4,32 +4,32 @@ namespace SquidStd.Scripting.Lua.Interfaces.Scripts; /// -/// Interface for the script engine service that manages Lua execution. +/// Interface for the script engine service that manages Lua execution. /// public interface IScriptEngineService : ISquidStdService { /// - /// Adds a callback function that can be called from Lua. + /// Adds a callback function that can be called from Lua. /// /// The name of the callback function in Lua. /// The C# action to execute when the callback is invoked. void AddCallback(string name, Action callback); /// - /// Adds a constant value accessible from Lua. + /// Adds a constant value accessible from Lua. /// /// The name of the constant in Lua. /// The value of the constant. void AddConstant(string name, object value); /// - /// Adds a script to be executed during engine initialization. + /// Adds a script to be executed during engine initialization. /// /// The Lua code to execute on startup. void AddInitScript(string script); /// - /// Adds a manual module function that can be called from scripts. + /// Adds a manual module function that can be called from scripts. /// /// The name of the module. /// The name of the function. @@ -37,7 +37,7 @@ public interface IScriptEngineService : ISquidStdService void AddManualModuleFunction(string moduleName, string functionName, Action callback); /// - /// Adds a typed manual module function that can be called from scripts. + /// Adds a typed manual module function that can be called from scripts. /// /// The input parameter type. /// The output return type. @@ -51,43 +51,43 @@ void AddManualModuleFunction( ); /// - /// Adds a .NET type as a module accessible from Lua. + /// Adds a .NET type as a module accessible from Lua. /// /// The type to register as a script module. void AddScriptModule(Type type); /// - /// Adds a directory to the Lua script search paths. + /// Adds a directory to the Lua script search paths. /// /// Directory path to search for scripts. void AddSearchDirectory(string path); /// - /// Clears the script cache + /// Clears the script cache /// void ClearScriptCache(); /// - /// Executes a previously registered callback function. + /// Executes a previously registered callback function. /// /// The name of the callback to execute. /// Arguments to pass to the callback. void ExecuteCallback(string name, params object[] args); /// - /// Notifies the script engine that the engine initialization is complete and ready. + /// Notifies the script engine that the engine initialization is complete and ready. /// void ExecuteEngineReady(); /// - /// Executes a Lua function or expression and returns the result. + /// Executes a Lua function or expression and returns the result. /// /// The Lua function call or expression to execute. /// A ScriptResult containing the execution outcome. ScriptResult ExecuteFunction(string command); /// - /// Asynchronously executes a Lua function or expression and returns the result. + /// Asynchronously executes a Lua function or expression and returns the result. /// /// The Lua function call or expression to execute. /// Token used to cancel the operation. @@ -95,87 +95,87 @@ void AddManualModuleFunction( Task ExecuteFunctionAsync(string command, CancellationToken cancellationToken = default); /// - /// Executes a function defined in the bootstrap script. + /// Executes a function defined in the bootstrap script. /// /// void ExecuteFunctionFromBootstrap(string name); /// - /// Executes a Lua script string. + /// Executes a Lua script string. /// /// The Lua code to execute. void ExecuteScript(string script); /// - /// Executes a Lua file. + /// Executes a Lua file. /// /// The path to the Lua file to execute. void ExecuteScriptFile(string scriptFile); /// - /// Gets execution metrics for performance monitoring + /// Gets execution metrics for performance monitoring /// /// Metrics about script execution ScriptExecutionMetrics GetExecutionMetrics(); /// - /// Registers a global object/value accessible from scripts. + /// Registers a global object/value accessible from scripts. /// /// The name of the global in scripts. /// The object/value to register. void RegisterGlobal(string name, object value); /// - /// Registers a global function that can be called from scripts. + /// Registers a global function that can be called from scripts. /// /// The name of the global function in scripts. /// The delegate to register as a global function. void RegisterGlobalFunction(string name, Delegate func); /// - /// Converts a .NET method name to a Lua-compatible function name. + /// Converts a .NET method name to a Lua-compatible function name. /// /// The .NET method name to convert. /// The Lua-compatible function name. string ToScriptEngineFunctionName(string name); /// - /// Unregisters a global function or value. + /// Unregisters a global function or value. /// /// The name of the global to unregister. /// True if the global was found and removed, false otherwise. bool UnregisterGlobal(string name); /// - /// Delegate for handling script file change events. + /// Delegate for handling script file change events. /// /// The path to the changed file. /// True if the file change was handled successfully, false otherwise. delegate bool LuaFileChangedHandler(string filePath); /// - /// Event raised when a script file is modified. + /// Event raised when a script file is modified. /// event LuaFileChangedHandler? FileChanged; /// - /// Event raised when a script error occurs + /// Event raised when a script error occurs /// event EventHandler? OnScriptError; /// - /// Fires once during StartAsync, after script modules have been registered - /// but before bootstrap scripts run. Handlers can install additional UserData types, globals, - /// or scanners that depend on the script runtime being ready. The argument is the underlying - /// MoonSharp Script, typed as so the interface stays - /// implementation-agnostic; callers cast as needed. + /// Fires once during StartAsync, after script modules have been registered + /// but before bootstrap scripts run. Handlers can install additional UserData types, globals, + /// or scanners that depend on the script runtime being ready. The argument is the underlying + /// MoonSharp Script, typed as so the interface stays + /// implementation-agnostic; callers cast as needed. /// event Action? AfterModulesRegistered; /// - /// Fires when a .lua file under a components/ subdirectory of the scripts - /// directory changes on disk. Carries the full file path. Used by the engine-side - /// component loader to hot-reload Lua-defined components. + /// Fires when a .lua file under a components/ subdirectory of the scripts + /// directory changes on disk. Carries the full file path. Used by the engine-side + /// component loader to hot-reload Lua-defined components. /// event Action? OnComponentFileChanged; } diff --git a/src/SquidStd.Scripting.Lua/Loaders/LuaScriptLoader.cs b/src/SquidStd.Scripting.Lua/Loaders/LuaScriptLoader.cs index 0ee14b7b..f4571e88 100644 --- a/src/SquidStd.Scripting.Lua/Loaders/LuaScriptLoader.cs +++ b/src/SquidStd.Scripting.Lua/Loaders/LuaScriptLoader.cs @@ -6,8 +6,8 @@ namespace SquidStd.Scripting.Lua.Loaders; /// -/// Custom script loader for MoonSharp that loads Lua modules from the configured Scripts directory. -/// Implements the MoonSharp script loader interface to provide require() functionality. +/// Custom script loader for MoonSharp that loads Lua modules from the configured Scripts directory. +/// Implements the MoonSharp script loader interface to provide require() functionality. /// public class LuaScriptLoader : ScriptLoaderBase { @@ -15,14 +15,14 @@ public class LuaScriptLoader : ScriptLoaderBase private readonly List _scriptsDirectories; /// - /// Initializes a new instance of the LuaScriptLoader class. + /// Initializes a new instance of the LuaScriptLoader class. /// /// The directories configuration to resolve the scripts directory. public LuaScriptLoader(string rootDirectory) { ArgumentNullException.ThrowIfNull(rootDirectory); - _scriptsDirectories = new List { Path.GetFullPath(rootDirectory) }; + _scriptsDirectories = new() { Path.GetFullPath(rootDirectory) }; // Configure default module search paths ModulePaths = @@ -37,13 +37,11 @@ public LuaScriptLoader(string rootDirectory) } /// - /// Initializes a new instance of the LuaScriptLoader class with multiple search directories. + /// Initializes a new instance of the LuaScriptLoader class with multiple search directories. /// /// Ordered list of directories to search. public LuaScriptLoader(IReadOnlyList searchDirectories) - : this(searchDirectories, true) - { - } + : this(searchDirectories, true) { } private LuaScriptLoader(IReadOnlyList searchDirectories, bool _) { @@ -55,9 +53,9 @@ private LuaScriptLoader(IReadOnlyList searchDirectories, bool _) } _scriptsDirectories = searchDirectories.Where(d => !string.IsNullOrWhiteSpace(d)) - .Select(d => Path.GetFullPath(d.ResolvePathAndEnvs()).ResolvePathAndEnvs()) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); + .Select(d => Path.GetFullPath(d.ResolvePathAndEnvs()).ResolvePathAndEnvs()) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); if (_scriptsDirectories.Count == 0) { @@ -94,7 +92,7 @@ public void AddSearchDirectory(string directory) } /// - /// Loads a Lua script file from the configured scripts directory. + /// Loads a Lua script file from the configured scripts directory. /// /// The filename or module name to load. /// The global context table. @@ -132,7 +130,7 @@ public override object LoadFile(string file, Table globalContext) } /// - /// Checks if a script file exists in the configured scripts directory. + /// Checks if a script file exists in the configured scripts directory. /// /// The filename or module name to check. /// True if the file exists, false otherwise. @@ -147,7 +145,7 @@ public override bool ScriptFileExists(string name) } /// - /// Resolves a module name to a full file path by searching through configured module paths. + /// Resolves a module name to a full file path by searching through configured module paths. /// /// The module name to resolve. /// The full path to the module file, or null if not found. diff --git a/src/SquidStd.Scripting.Lua/Modules/EventsModule.cs b/src/SquidStd.Scripting.Lua/Modules/EventsModule.cs index 366f1cc6..9137a3e8 100644 --- a/src/SquidStd.Scripting.Lua/Modules/EventsModule.cs +++ b/src/SquidStd.Scripting.Lua/Modules/EventsModule.cs @@ -16,7 +16,5 @@ public EventsModule(ILuaEventBridge events) [ScriptFunction("on", "Registers a callback for a named server event.")] public void On(string eventName, Closure callback) - { - _events.Register(eventName, callback); - } + => _events.Register(eventName, callback); } diff --git a/src/SquidStd.Scripting.Lua/Modules/LogModule.cs b/src/SquidStd.Scripting.Lua/Modules/LogModule.cs index c28979d7..dd462dbc 100644 --- a/src/SquidStd.Scripting.Lua/Modules/LogModule.cs +++ b/src/SquidStd.Scripting.Lua/Modules/LogModule.cs @@ -10,19 +10,13 @@ public class LogModule [ScriptFunction(helpText: "Logs a message at the ERROR level.")] public void Error(string message, params object[]? args) - { - _logger.Error(message, args); - } + => _logger.Error(message, args); [ScriptFunction(helpText: "Logs a message at the INFO level.")] public void Info(string message, params object[]? args) - { - _logger.Information(message, args); - } + => _logger.Information(message, args); [ScriptFunction(helpText: "Logs a message at the WARNING level.")] public void Warning(string message, params object[]? args) - { - _logger.Warning(message, args); - } + => _logger.Warning(message, args); } diff --git a/src/SquidStd.Scripting.Lua/Modules/RandomModule.cs b/src/SquidStd.Scripting.Lua/Modules/RandomModule.cs index a60d7e67..4547ab25 100644 --- a/src/SquidStd.Scripting.Lua/Modules/RandomModule.cs +++ b/src/SquidStd.Scripting.Lua/Modules/RandomModule.cs @@ -24,9 +24,7 @@ public bool Chance(double percent) [ScriptFunction("float", "Returns a random floating-point number between 0 and 1.")] public double Float() - { - return Random.Shared.NextDouble(); - } + => Random.Shared.NextDouble(); [ScriptFunction("int", "Returns a random integer in the inclusive range.")] public int Int(int min, int max) diff --git a/src/SquidStd.Scripting.Lua/Proxies/LuaProxy.cs b/src/SquidStd.Scripting.Lua/Proxies/LuaProxy.cs index 36d8cae5..bf5c8bd1 100644 --- a/src/SquidStd.Scripting.Lua/Proxies/LuaProxy.cs +++ b/src/SquidStd.Scripting.Lua/Proxies/LuaProxy.cs @@ -4,7 +4,7 @@ namespace SquidStd.Scripting.Lua.Proxies; /// -/// A proxy class that implements an interface by delegating method calls to a MoonSharp Table. +/// A proxy class that implements an interface by delegating method calls to a MoonSharp Table. /// /// The interface type to implement. public class LuaProxy : DispatchProxy @@ -12,7 +12,7 @@ public class LuaProxy : DispatchProxy public Table Table { get; set; } /// - /// Invokes the Lua function corresponding to the method name on the associated table. + /// Invokes the Lua function corresponding to the method name on the associated table. /// /// The method information for the invoked method. /// The arguments passed to the method. @@ -27,8 +27,8 @@ protected override object Invoke(MethodInfo targetMethod, object[] args) } var dynArgs = args - .Select(a => DynValue.FromObject(null, a)) - .ToArray(); + .Select(a => DynValue.FromObject(null, a)) + .ToArray(); var result = fn.Function.Call(dynArgs); return result.ToObject(targetMethod.ReturnType); diff --git a/src/SquidStd.Scripting.Lua/Services/LuaEventBridge.cs b/src/SquidStd.Scripting.Lua/Services/LuaEventBridge.cs index 8201739e..fe473fb3 100644 --- a/src/SquidStd.Scripting.Lua/Services/LuaEventBridge.cs +++ b/src/SquidStd.Scripting.Lua/Services/LuaEventBridge.cs @@ -6,7 +6,7 @@ namespace SquidStd.Scripting.Lua.Services; /// -/// Default Lua event bridge backed by named MoonSharp closures. +/// Default Lua event bridge backed by named MoonSharp closures. /// public sealed class LuaEventBridge : ILuaEventBridge { diff --git a/src/SquidStd.Scripting.Lua/Services/LuaScriptEngineService.cs b/src/SquidStd.Scripting.Lua/Services/LuaScriptEngineService.cs index cbd3c2db..b075355b 100644 --- a/src/SquidStd.Scripting.Lua/Services/LuaScriptEngineService.cs +++ b/src/SquidStd.Scripting.Lua/Services/LuaScriptEngineService.cs @@ -30,8 +30,8 @@ namespace SquidStd.Scripting.Lua.Services; /// -/// Lua engine service that integrates MoonSharp with the SquidCraft game engine -/// Provides script execution, module loading, and Lua meta file generation +/// Lua engine service that integrates MoonSharp with the SquidCraft game engine +/// Provides script execution, module loading, and Lua meta file generation /// public class LuaScriptEngineService : IScriptEngineService, IDisposable { @@ -62,17 +62,17 @@ public class LuaScriptEngineService : IScriptEngineService, IDisposable private FileSystemWatcher? _watcher; /// - /// Gets the MoonSharp script instance. + /// Gets the MoonSharp script instance. /// public Script LuaScript { get; } /// - /// Gets the script engine instance. + /// Gets the script engine instance. /// public object Engine => LuaScript; /// - /// Initializes a new instance of the LuaScriptEngineService class. + /// Initializes a new instance of the LuaScriptEngineService class. /// /// The directories configuration. /// The list of script modules. @@ -89,8 +89,8 @@ public LuaScriptEngineService( { JsonUtils.RegisterJsonContext(SquidStdScriptJsonContext.Default); - scriptModules ??= new List(); - loadedUserData ??= new List(); + scriptModules ??= new(); + loadedUserData ??= new(); _scriptModules = scriptModules; _directoriesConfig = directoriesConfig; @@ -107,7 +107,7 @@ public LuaScriptEngineService( } /// - /// Adds a callback function that can be called from Lua scripts. + /// Adds a callback function that can be called from Lua scripts. /// /// The name of the callback. /// The callback action. @@ -123,7 +123,7 @@ public void AddCallback(string name, Action callback) } /// - /// Adds a constant value that can be accessed from Lua scripts. + /// Adds a constant value that can be accessed from Lua scripts. /// /// The name of the constant. /// The value of the constant. @@ -153,7 +153,7 @@ public void AddConstant(string name, object? value) } /// - /// Adds an initialization script. + /// Adds an initialization script. /// /// The script to add. public void AddInitScript(string script) @@ -167,7 +167,7 @@ public void AddInitScript(string script) } /// - /// Adds a manual module function that can be called from Lua scripts with a callback. + /// Adds a manual module function that can be called from Lua scripts with a callback. /// public void AddManualModuleFunction(string moduleName, string functionName, Action callback) { @@ -177,7 +177,8 @@ public void AddManualModuleFunction(string moduleName, string functionName, Acti var (normalizedModule, normalizedFunction, moduleTable) = PrepareManualModule(moduleName, functionName); - moduleTable[normalizedFunction] = DynValue.NewCallback((_, args) => + moduleTable[normalizedFunction] = DynValue.NewCallback( + (_, args) => { try { @@ -204,7 +205,7 @@ public void AddManualModuleFunction(string moduleName, string functionName, Acti } /// - /// Adds a manual module function with typed input and output that can be called from Lua scripts. + /// Adds a manual module function with typed input and output that can be called from Lua scripts. /// public void AddManualModuleFunction( string moduleName, @@ -218,7 +219,8 @@ public void AddManualModuleFunction( var (normalizedModule, normalizedFunction, moduleTable) = PrepareManualModule(moduleName, functionName); - moduleTable[normalizedFunction] = DynValue.NewCallback((_, args) => + moduleTable[normalizedFunction] = DynValue.NewCallback( + (_, args) => { try { @@ -245,22 +247,20 @@ public void AddManualModuleFunction( } /// - /// Adds a script module to the engine. + /// Adds a script module to the engine. /// /// The type of the script module. public void AddScriptModule(Type type) { ArgumentNullException.ThrowIfNull(type); - _scriptModules.Add(new ScriptModuleData(type)); + _scriptModules.Add(new(type)); } public void AddSearchDirectory(string path) - { - _scriptLoader.AddSearchDirectory(path); - } + => _scriptLoader.AddSearchDirectory(path); /// - /// Clears the script cache + /// Clears the script cache /// public void ClearScriptCache() { @@ -271,7 +271,7 @@ public void ClearScriptCache() } /// - /// Executes a registered callback with the specified arguments. + /// Executes a registered callback with the specified arguments. /// /// The name of the callback. /// The arguments to pass to the callback. @@ -302,15 +302,13 @@ public void ExecuteCallback(string name, params object[] args) } /// - /// Executes the engine ready function from bootstrap scripts. + /// Executes the engine ready function from bootstrap scripts. /// public void ExecuteEngineReady() - { - ExecuteFunctionFromBootstrap(OnEngineRunFunctionName); - } + => ExecuteFunctionFromBootstrap(OnEngineRunFunctionName); /// - /// Executes a Lua function and returns the result. + /// Executes a Lua function and returns the result. /// /// The function command to execute. /// The result of the function execution. @@ -336,10 +334,10 @@ public ScriptResult ExecuteFunction(string command) ); return ScriptResultBuilder.CreateError() - .WithMessage( - $"{errorInfo.ErrorType}: {errorInfo.Message} at line {errorInfo.LineNumber}" - ) - .Build(); + .WithMessage( + $"{errorInfo.ErrorType}: {errorInfo.Message} at line {errorInfo.LineNumber}" + ) + .Build(); } catch (InterpreterException luaEx) { @@ -356,10 +354,10 @@ public ScriptResult ExecuteFunction(string command) ); return ScriptResultBuilder.CreateError() - .WithMessage( - $"{errorInfo.ErrorType}: {errorInfo.Message} at line {errorInfo.LineNumber}" - ) - .Build(); + .WithMessage( + $"{errorInfo.ErrorType}: {errorInfo.Message} at line {errorInfo.LineNumber}" + ) + .Build(); } catch (Exception ex) { @@ -370,7 +368,7 @@ public ScriptResult ExecuteFunction(string command) } /// - /// Executes a Lua function asynchronously and returns the result. + /// Executes a Lua function asynchronously and returns the result. /// /// The function command to execute. /// Token used to cancel the operation. @@ -419,16 +417,14 @@ public void ExecuteFunctionFromBootstrap(string name) } /// - /// Executes a script string. + /// Executes a script string. /// /// The script to execute. public void ExecuteScript(string script) - { - ExecuteScript(script, null); - } + => ExecuteScript(script, null); /// - /// Executes a script from a file. + /// Executes a script from a file. /// /// The path to the script file. public void ExecuteScriptFile(string scriptFile) @@ -453,20 +449,18 @@ public void ExecuteScriptFile(string scriptFile) } /// - /// Gets execution metrics for performance monitoring + /// Gets execution metrics for performance monitoring /// public ScriptExecutionMetrics GetExecutionMetrics() - { - return new ScriptExecutionMetrics + => new() { CacheHits = _cacheHits, CacheMisses = _cacheMisses, TotalScriptsCached = _scriptCache.Count }; - } /// - /// Registers a global variable in the Lua environment. + /// Registers a global variable in the Lua environment. /// /// The name of the variable. /// The value of the variable. @@ -480,7 +474,7 @@ public void RegisterGlobal(string name, object value) } /// - /// Registers a global function in the Lua environment. + /// Registers a global function in the Lua environment. /// /// The name of the function. /// The delegate representing the function. @@ -494,7 +488,7 @@ public void RegisterGlobalFunction(string name, Delegate func) } /// - /// Starts the script engine asynchronously. + /// Starts the script engine asynchronously. /// /// A task representing the asynchronous operation. public async ValueTask StartAsync(CancellationToken cancellationToken = default) @@ -531,7 +525,7 @@ public async ValueTask StartAsync(CancellationToken cancellationToken = default) if (_watcher == null) { - _watcher = new FileSystemWatcher(_engineConfig.ScriptsDirectory, "*.lua") + _watcher = new(_engineConfig.ScriptsDirectory, "*.lua") { NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.Size, IncludeSubdirectories = true, @@ -550,16 +544,14 @@ public async ValueTask StartAsync(CancellationToken cancellationToken = default) } /// - /// Stops the script engine asynchronously. + /// Stops the script engine asynchronously. /// /// A task representing the asynchronous operation. public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; /// - /// Converts a name to the script engine function name format. + /// Converts a name to the script engine function name format. /// /// The name to convert. /// The converted function name. @@ -571,7 +563,7 @@ public string ToScriptEngineFunctionName(string name) } /// - /// Unregisters a global variable from the Lua environment. + /// Unregisters a global variable from the Lua environment. /// /// The name of the variable to unregister. /// True if the variable was unregistered, false otherwise. @@ -595,7 +587,7 @@ public bool UnregisterGlobal(string name) } /// - /// Executes a script file asynchronously. + /// Executes a script file asynchronously. /// /// The path to the script file. /// Token used to cancel the operation. @@ -624,16 +616,14 @@ public async Task ExecuteScriptFileAsync(string scriptFile, CancellationToken ca } /// - /// Gets the statistics of the script engine. + /// Gets the statistics of the script engine. /// /// A tuple containing the module count, callback count, constant count, and initialization status. public (int ModuleCount, int CallbackCount, int ConstantCount, bool IsInitialized) GetStats() - { - return (_loadedModules.Count, _callbacks.Count, _constants.Count, _isInitialized); - } + => (_loadedModules.Count, _callbacks.Count, _constants.Count, _isInitialized); /// - /// Registers a global type user data. + /// Registers a global type user data. /// /// The type to register. public void RegisterGlobalTypeUserData(Type type) @@ -646,7 +636,7 @@ public void RegisterGlobalTypeUserData(Type type) } /// - /// Registers a global type user data for the specified type. + /// Registers a global type user data for the specified type. /// /// The type to register. public void RegisterGlobalTypeUserData() @@ -658,7 +648,7 @@ public void RegisterGlobalTypeUserData() } /// - /// Resets the script engine to its initial state. + /// Resets the script engine to its initial state. /// public void Reset() { @@ -696,8 +686,7 @@ private void AttachLuaEventBridge() } private static object? ConvertFromLua(DynValue dynValue, Type targetType) - { - return dynValue.Type switch + => dynValue.Type switch { DataType.Nil => null, DataType.Boolean => dynValue.Boolean, @@ -706,19 +695,15 @@ private void AttachLuaEventBridge() DataType.Table => dynValue.ToObject(), _ => dynValue.ToObject() }; - } private DynValue ConvertToLua(object? value) - { - return value == null ? DynValue.Nil : DynValue.FromObject(LuaScript, value); - } + => value == null ? DynValue.Nil : DynValue.FromObject(LuaScript, value); /// - /// Creates a Lua callback that invokes the constructor matching the number of arguments passed from Lua. + /// Creates a Lua callback that invokes the constructor matching the number of arguments passed from Lua. /// private DynValue CreateConstructorCallback( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - Type type + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type ) { var constructorsByParamCount = new Dictionary(); @@ -730,7 +715,8 @@ Type type constructorsByParamCount.TryAdd(paramCount, ctor); } - return DynValue.NewCallback((_, args) => + return DynValue.NewCallback( + (_, args) => { var argCount = args.Count; @@ -767,7 +753,7 @@ Type type } /// - /// Creates detailed error information from a Lua exception + /// Creates detailed error information from a Lua exception /// private static ScriptErrorInfo CreateErrorInfo(ScriptRuntimeException luaEx, string sourceCode, string? fileName = null) { @@ -786,7 +772,7 @@ private static ScriptErrorInfo CreateErrorInfo(ScriptRuntimeException luaEx, str } /// - /// Creates detailed error information from a Lua interpreter exception (syntax errors, etc.) + /// Creates detailed error information from a Lua interpreter exception (syntax errors, etc.) /// private static ScriptErrorInfo CreateErrorInfo(InterpreterException luaEx, string sourceCode, string? fileName = null) { @@ -830,8 +816,8 @@ private static ScriptErrorInfo CreateErrorInfo(InterpreterException luaEx, strin } private DynValue CreateMethodClosure(object instance, MethodInfo method) - { - return DynValue.NewCallback((context, args) => + => DynValue.NewCallback( + (context, args) => { try { @@ -890,7 +876,6 @@ private DynValue CreateMethodClosure(object instance, MethodInfo method) } } ); - } private Table CreateModuleTable( object instance, @@ -901,7 +886,7 @@ Type moduleType var moduleTable = new Table(LuaScript); var methods = moduleType.GetMethods(BindingFlags.Public | BindingFlags.Instance) - .Where(m => m.GetCustomAttribute() is not null); + .Where(m => m.GetCustomAttribute() is not null); foreach (var method in methods) { @@ -913,8 +898,8 @@ Type moduleType } var functionName = string.IsNullOrWhiteSpace(scriptFunctionAttr.FunctionName) - ? _nameResolver(method.Name) - : scriptFunctionAttr.FunctionName; + ? _nameResolver(method.Name) + : scriptFunctionAttr.FunctionName; // Create a closure that captures the instance and method var closure = CreateMethodClosure(instance, method); @@ -925,9 +910,7 @@ Type moduleType } private void CreateNameResolver() - { - _nameResolver = name => name.ToSnakeCase(); - } + => _nameResolver = name => name.ToSnakeCase(); // _nameResolver = _scriptEngineConfig.ScriptNameConversion switch // { @@ -938,7 +921,7 @@ private void CreateNameResolver() // }; private Script CreateOptimizedEngine() { - _scriptLoader = new LuaScriptLoader(new[] { _engineConfig.ScriptsDirectory }); + _scriptLoader = new(new[] { _engineConfig.ScriptsDirectory }); var script = new Script { Options = @@ -955,9 +938,7 @@ private Script CreateOptimizedEngine() } private void ExecuteBootFunction() - { - ExecuteFunctionFromBootstrap(OnReadyFunctionName); - } + => ExecuteFunctionFromBootstrap(OnReadyFunctionName); private void ExecuteBootstrap() { @@ -973,7 +954,7 @@ private void ExecuteBootstrap() } /// - /// Executes a script string with an optional file name for error reporting. + /// Executes a script string with an optional file name for error reporting. /// /// The script to execute. /// Optional file name for error reporting. @@ -1088,7 +1069,7 @@ private async Task GenerateLuaMetaFileAsync(CancellationToken cancellationToken) "Moongate", _engineConfig.EngineVersion, _scriptModules, - new Dictionary(_constants), + new(_constants), manualModulesSnapshot, _nameResolver ); @@ -1122,7 +1103,7 @@ private string GenerateLuarcJson() var luarcConfig = new LuarcConfig { - Runtime = new LuarcRuntimeConfig + Runtime = new() { Path = [ @@ -1132,11 +1113,11 @@ private string GenerateLuarcJson() "modules/?/init.lua" ] }, - Workspace = new LuarcWorkspaceConfig + Workspace = new() { Library = [_engineConfig.ScriptsDirectory] }, - Diagnostics = new LuarcDiagnosticsConfig + Diagnostics = new() { Globals = [..globalsList] } @@ -1146,7 +1127,7 @@ private string GenerateLuarcJson() } /// - /// Generates a hash for script caching + /// Generates a hash for script caching /// private static string GetScriptHash(string script) { @@ -1156,9 +1137,7 @@ private static string GetScriptHash(string script) } private static bool IsSimpleType(Type type) - { - return type.IsPrimitive || type == typeof(string) || type.IsEnum; - } + => type.IsPrimitive || type == typeof(string) || type.IsEnum; private void LoadToUserData() { @@ -1274,7 +1253,7 @@ string functionName } else { - moduleTable = new Table(LuaScript); + moduleTable = new(LuaScript); LuaScript.Globals[normalizedModuleName] = moduleTable; } @@ -1322,7 +1301,8 @@ private void RegisterEnum(Type enumType) var metatable = new Table(LuaScript); // __index: allows case-insensitive access - metatable["__index"] = DynValue.NewCallback((ctx, args) => + metatable["__index"] = DynValue.NewCallback( + (ctx, args) => { var key = args[1].String; @@ -1356,7 +1336,8 @@ private void RegisterEnum(Type enumType) ); // __newindex: prevents modifications (read-only) - metatable["__newindex"] = DynValue.NewCallback((ctx, args) => + metatable["__newindex"] = DynValue.NewCallback( + (ctx, args) => { var key = args[1].String; @@ -1365,8 +1346,7 @@ private void RegisterEnum(Type enumType) ); // __tostring: pretty print - metatable["__tostring"] = DynValue.NewCallback((ctx, args) => { return DynValue.NewString($"enum<{enumName}>"); } - ); + metatable["__tostring"] = DynValue.NewCallback((ctx, args) => { return DynValue.NewString($"enum<{enumName}>"); }); // Set the enum table first var enumTableDynValue = DynValue.NewTable(enumTable); @@ -1407,9 +1387,9 @@ private void RegisterEnums() private void RegisterGlobalFunctions() { LuaScript.Globals["delay"] = (Func)(async milliseconds => - { - await Task.Delay(Math.Min(milliseconds, 5000)); - }); + { + await Task.Delay(Math.Min(milliseconds, 5000)); + }); // NOTE: do NOT define a bare 'log' global here — the LogModule registered above already // exposes 'log.info / log.warning / log.error' as a table; overwriting it with a function @@ -1420,7 +1400,7 @@ private void RegisterGlobalFunctions() private void RegisterManualModuleFunction(string moduleName, string functionName) { - var functions = _manualModuleFunctions.GetOrAdd(moduleName, _ => new ConcurrentDictionary()); + var functions = _manualModuleFunctions.GetOrAdd(moduleName, _ => new()); functions.TryAdd(functionName, 0); } @@ -1466,7 +1446,7 @@ private async Task RegisterScriptModulesAsync(CancellationToken cancellationToke } /// - /// Disposes of the resources used by the LuaScriptEngineService. + /// Disposes of the resources used by the LuaScriptEngineService. /// public void Dispose() { @@ -1496,12 +1476,12 @@ public void Dispose() } /// - /// Raised when a watched Lua file changes. + /// Raised when a watched Lua file changes. /// public event IScriptEngineService.LuaFileChangedHandler? FileChanged; /// - /// Event raised when a script error occurs + /// Event raised when a script error occurs /// public event EventHandler? OnScriptError; diff --git a/src/SquidStd.Scripting.Lua/Utils/LuaDocumentationGenerator.cs b/src/SquidStd.Scripting.Lua/Utils/LuaDocumentationGenerator.cs index 92e25e5b..bc69e34c 100644 --- a/src/SquidStd.Scripting.Lua/Utils/LuaDocumentationGenerator.cs +++ b/src/SquidStd.Scripting.Lua/Utils/LuaDocumentationGenerator.cs @@ -11,8 +11,8 @@ namespace SquidStd.Scripting.Lua.Utils; /// -/// Utility class for generating Lua meta files with EmmyLua/LuaLS annotations -/// Automatically creates meta.lua files with function signatures, types, and documentation +/// Utility class for generating Lua meta files with EmmyLua/LuaLS annotations +/// Automatically creates meta.lua files with function signatures, types, and documentation /// [RequiresUnreferencedCode( "This class uses reflection to analyze types for Lua meta generation and requires full type metadata." @@ -30,12 +30,12 @@ public static class LuaDocumentationGenerator private static Func _nameResolver = name => name.ToSnakeCase(); /// - /// List of enums found during documentation generation + /// List of enums found during documentation generation /// public static List FoundEnums { get; } = new(16); /// - /// Adds a class type to be generated in the documentation + /// Adds a class type to be generated in the documentation /// public static void AddClassToGenerate(Type type) { @@ -44,7 +44,7 @@ public static void AddClassToGenerate(Type type) } /// - /// Clears all internal caches and state + /// Clears all internal caches and state /// public static void ClearCaches() { @@ -60,12 +60,13 @@ public static void ClearCaches() } } - [SuppressMessage("Trimming", "IL2075:Reflection", Justification = "Reflection is required for script module analysis")] - [SuppressMessage( - "Trimming", - "IL2072:Reflection", - Justification = "Reflection is required for parameter and return type analysis" - )] + [SuppressMessage("Trimming", "IL2075:Reflection", Justification = "Reflection is required for script module analysis"), + SuppressMessage( + "Trimming", + "IL2072:Reflection", + Justification = "Reflection is required for parameter and return type analysis" + )] + /// /// Generates Lua documentation meta file with all module functions, classes, and constants /// @@ -124,8 +125,8 @@ public static string GenerateDocumentation( } var distinctConstants = constants - .GroupBy(kvp => kvp.Key) - .ToDictionary(g => g.Key, g => g.First().Value); + .GroupBy(kvp => kvp.Key) + .ToDictionary(g => g.Key, g => g.First().Value); ProcessConstants(distinctConstants); sb.Append(_constantsBuilder); @@ -156,9 +157,9 @@ public static string GenerateDocumentation( // Get all methods with ScriptFunction attribute var methods = module.ModuleType - .GetMethods(BindingFlags.Public | BindingFlags.Instance) - .Where(m => m.GetCustomAttribute() is not null) - .ToList(); + .GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Where(m => m.GetCustomAttribute() is not null) + .ToList(); foreach (var method in methods) { @@ -170,8 +171,8 @@ public static string GenerateDocumentation( } var functionName = string.IsNullOrWhiteSpace(scriptFunctionAttr.FunctionName) - ? _nameResolver(method.Name) - : scriptFunctionAttr.FunctionName; + ? _nameResolver(method.Name) + : scriptFunctionAttr.FunctionName; sb.AppendLine(CultureInfo.InvariantCulture, $"{moduleName}.{functionName} = function() end"); } @@ -190,8 +191,8 @@ public static string GenerateDocumentation( } var functionName = string.IsNullOrWhiteSpace(scriptFunctionAttr.FunctionName) - ? _nameResolver(method.Name) - : scriptFunctionAttr.FunctionName; + ? _nameResolver(method.Name) + : scriptFunctionAttr.FunctionName; var description = scriptFunctionAttr.HelpText ?? "No description available"; sb.AppendLine("---"); @@ -205,8 +206,8 @@ public static string GenerateDocumentation( { var isParams = param.IsDefined(typeof(ParamArrayAttribute), false); var paramType = isParams - ? ConvertToLuaType(param.ParameterType.GetElementType()!) - : ConvertToLuaType(param.ParameterType); + ? ConvertToLuaType(param.ParameterType.GetElementType()!) + : ConvertToLuaType(param.ParameterType); var paramName = isParams ? "..." : param.Name ?? $"param{Array.IndexOf(parameters, param)}"; var paramDescription = GetParameterDescription(param, paramType); sb.AppendLine( @@ -294,13 +295,11 @@ public static string GenerateDocumentation( } private static bool CanProcessType(Type type) - { - return true; - } + => true; - [SuppressMessage("Trimming", "IL2070:Reflection", Justification = "Reflection is required for Lua type conversion")] - [SuppressMessage("Trimming", "IL2072:Reflection", Justification = "Reflection is required for Lua type conversion")] - [SuppressMessage("Trimming", "IL2062:Reflection", Justification = "Reflection is required for Lua type conversion")] + [SuppressMessage("Trimming", "IL2070:Reflection", Justification = "Reflection is required for Lua type conversion"), + SuppressMessage("Trimming", "IL2072:Reflection", Justification = "Reflection is required for Lua type conversion"), + SuppressMessage("Trimming", "IL2062:Reflection", Justification = "Reflection is required for Lua type conversion")] private static string ConvertToLuaType( [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicMethods | @@ -585,7 +584,7 @@ private static string FormatConstantValue(object? value, Type type) } /// - /// Generate all classes after collecting them, with robust circular dependency handling + /// Generate all classes after collecting them, with robust circular dependency handling /// private static void GenerateAllClasses() { @@ -635,10 +634,10 @@ private static void GenerateAllClasses() } /// - /// Generate a single class with properties, constructors, and methods + /// Generate a single class with properties, constructors, and methods /// - [SuppressMessage("Trimming", "IL2070:Reflection", Justification = "Reflection is required for class generation")] - [SuppressMessage("Trimming", "IL2072:Reflection", Justification = "Reflection is required for class generation")] + [SuppressMessage("Trimming", "IL2070:Reflection", Justification = "Reflection is required for class generation"), + SuppressMessage("Trimming", "IL2072:Reflection", Justification = "Reflection is required for class generation")] private static void GenerateClass( [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicProperties | @@ -674,8 +673,8 @@ Type type // Generate properties with documentation (exclude indexers which have parameters) var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) - .Where(p => p.CanRead && p.GetIndexParameters().Length == 0) - .ToList(); + .Where(p => p.CanRead && p.GetIndexParameters().Length == 0) + .ToList(); foreach (var property in properties) { @@ -694,8 +693,8 @@ Type type // Use original property name for built-in types (XNA), apply resolver for custom types var displayName = luaFieldAttr?.Name ?? (type.Namespace?.StartsWith("Microsoft.Xna.Framework", StringComparison.Ordinal) == true - ? propertyName - : _nameResolver(propertyName)); + ? propertyName + : _nameResolver(propertyName)); _classesBuilder.AppendLine( CultureInfo.InvariantCulture, @@ -705,8 +704,8 @@ Type type // Generate public constructors var constructors = type.GetConstructors(BindingFlags.Public) - .Where(c => c.GetParameters().Length > 0) - .ToList(); + .Where(c => c.GetParameters().Length > 0) + .ToList(); if (constructors.Count > 0) { @@ -729,8 +728,8 @@ Type type // Use original parameter names for XNA types, apply resolver for custom types var paramName = isXnaType - ? param.Name ?? $"param{i}" - : _nameResolver(param.Name ?? $"param{i}"); + ? param.Name ?? $"param{i}" + : _nameResolver(param.Name ?? $"param{i}"); _classesBuilder.Append(CultureInfo.InvariantCulture, $"{paramName}: {paramType}"); if (i < parameters.Length - 1) @@ -770,11 +769,12 @@ Type type }; var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) - .Where(m => !propertyMethods.Contains(m.Name) && - !m.IsSpecialName && - !excludedMethods.Contains(m.Name) - ) - .ToList(); + .Where( + m => !propertyMethods.Contains(m.Name) && + !m.IsSpecialName && + !excludedMethods.Contains(m.Name) + ) + .ToList(); if (methods.Count > 0) { @@ -794,8 +794,8 @@ Type type foreach (var method in methodGroup) { var returnType = method.ReturnType == typeof(void) - ? "nil" - : ConvertToLuaType(method.ReturnType); + ? "nil" + : ConvertToLuaType(method.ReturnType); var parameters = method.GetParameters(); @@ -808,8 +808,8 @@ Type type // Use original parameter names for XNA types, apply resolver for custom types var paramName = isXnaType - ? param.Name ?? $"param{i}" - : _nameResolver(param.Name ?? $"param{i}"); + ? param.Name ?? $"param{i}" + : _nameResolver(param.Name ?? $"param{i}"); _classesBuilder.Append(CultureInfo.InvariantCulture, $"{paramName}: {paramType}"); if (i < parameters.Length - 1) @@ -885,7 +885,7 @@ private static void GenerateEnumClass(Type enumType) } /// - /// Gets enhanced parameter description with type information + /// Gets enhanced parameter description with type information /// private static string GetParameterDescription(ParameterInfo param, string luaType) { @@ -933,7 +933,7 @@ private static string GetParameterDescription(ParameterInfo param, string luaTyp } /// - /// Gets enhanced return description with type information + /// Gets enhanced return description with type information /// private static string GetReturnDescription(Type returnType, string luaType) { @@ -968,7 +968,7 @@ private static string GetReturnDescription(Type returnType, string luaType) } /// - /// Check if a type is a C# record type + /// Check if a type is a C# record type /// [SuppressMessage("Trimming", "IL2070:Reflection", Justification = "Reflection is required for record type detection")] private static bool IsRecordType( @@ -1005,10 +1005,11 @@ Type type } var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); - var hasCompilerGeneratedToString = methods.Any(m => - m.Name == "ToString" && - m.GetParameters().Length == 0 && - m.GetCustomAttributes().Any(attr => attr.GetType().Name.Contains("CompilerGenerated")) + var hasCompilerGeneratedToString = methods.Any( + m => + m.Name == "ToString" && + m.GetParameters().Length == 0 && + m.GetCustomAttributes().Any(attr => attr.GetType().Name.Contains("CompilerGenerated")) ); var result = hasCompilerGeneratedToString; diff --git a/src/SquidStd.Search.Abstractions/Attributes/SearchIndexAttribute.cs b/src/SquidStd.Search.Abstractions/Attributes/SearchIndexAttribute.cs index 1ea23c62..f1c689ec 100644 --- a/src/SquidStd.Search.Abstractions/Attributes/SearchIndexAttribute.cs +++ b/src/SquidStd.Search.Abstractions/Attributes/SearchIndexAttribute.cs @@ -1,8 +1,8 @@ namespace SquidStd.Search.Abstractions.Attributes; /// -/// Declares the Elasticsearch index for a type. The name supports environment-variable expansion: -/// ${VAR} and ${VAR:-default} (e.g. "orders_${ENV:-dev}"). +/// Declares the Elasticsearch index for a type. The name supports environment-variable expansion: +/// ${VAR} and ${VAR:-default} (e.g. "orders_${ENV:-dev}"). /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)] public sealed class SearchIndexAttribute : Attribute diff --git a/src/SquidStd.Search.Abstractions/Exceptions/SearchException.cs b/src/SquidStd.Search.Abstractions/Exceptions/SearchException.cs index d82f80a0..69b187f7 100644 --- a/src/SquidStd.Search.Abstractions/Exceptions/SearchException.cs +++ b/src/SquidStd.Search.Abstractions/Exceptions/SearchException.cs @@ -5,13 +5,9 @@ public sealed class SearchException : Exception { /// Initializes the exception with a message. public SearchException(string message) - : base(message) - { - } + : base(message) { } /// Initializes the exception with a message and inner exception. public SearchException(string message, Exception innerException) - : base(message, innerException) - { - } + : base(message, innerException) { } } diff --git a/src/SquidStd.Search.Abstractions/Interfaces/IIndexableEntity.cs b/src/SquidStd.Search.Abstractions/Interfaces/IIndexableEntity.cs index 80be32f4..4624c8a2 100644 --- a/src/SquidStd.Search.Abstractions/Interfaces/IIndexableEntity.cs +++ b/src/SquidStd.Search.Abstractions/Interfaces/IIndexableEntity.cs @@ -1,8 +1,8 @@ namespace SquidStd.Search.Abstractions.Interfaces; /// -/// Marks an entity as indexable and supplies its document id. The target index comes from a -/// on the type (or the lowercased type name). +/// Marks an entity as indexable and supplies its document id. The target index comes from a +/// on the type (or the lowercased type name). /// public interface IIndexableEntity { diff --git a/src/SquidStd.Search.Abstractions/Interfaces/ISearchService.cs b/src/SquidStd.Search.Abstractions/Interfaces/ISearchService.cs index b7f9c6b4..be94562d 100644 --- a/src/SquidStd.Search.Abstractions/Interfaces/ISearchService.cs +++ b/src/SquidStd.Search.Abstractions/Interfaces/ISearchService.cs @@ -1,7 +1,7 @@ namespace SquidStd.Search.Abstractions.Interfaces; /// -/// Indexes, deletes, and queries documents. +/// Indexes, deletes, and queries documents. /// public interface ISearchService { diff --git a/src/SquidStd.Search.Abstractions/Search/SearchIndexNameResolver.cs b/src/SquidStd.Search.Abstractions/Search/SearchIndexNameResolver.cs index febd3317..1a8b04f6 100644 --- a/src/SquidStd.Search.Abstractions/Search/SearchIndexNameResolver.cs +++ b/src/SquidStd.Search.Abstractions/Search/SearchIndexNameResolver.cs @@ -4,9 +4,9 @@ namespace SquidStd.Search.Abstractions.Search; /// -/// Resolves the Elasticsearch index name for a type from its (or the -/// lowercased type name), expanding ${VAR} / ${VAR:-default} from environment variables. The -/// result is always lowercased (an Elasticsearch requirement). +/// Resolves the Elasticsearch index name for a type from its (or the +/// lowercased type name), expanding ${VAR} / ${VAR:-default} from environment variables. The +/// result is always lowercased (an Elasticsearch requirement). /// public static partial class SearchIndexNameResolver { @@ -17,15 +17,14 @@ public static string Resolve(Type type) var template = type.GetCustomAttributes(typeof(SearchIndexAttribute), false) is { Length: > 0 } attributes && attributes[0] is SearchIndexAttribute attribute - ? attribute.Name - : type.Name; + ? attribute.Name + : type.Name; return ExpandEnvironment(template).ToLowerInvariant(); } private static string ExpandEnvironment(string template) - { - return PlaceholderRegex() + => PlaceholderRegex() .Replace( template, match => @@ -49,7 +48,6 @@ private static string ExpandEnvironment(string template) ); } ); - } [GeneratedRegex(@"\$\{(?[A-Za-z_][A-Za-z0-9_]*)(:-(?[^}]*))?\}")] private static partial Regex PlaceholderRegex(); diff --git a/src/SquidStd.Search.Elasticsearch/Extensions/SearchRegistrationExtensions.cs b/src/SquidStd.Search.Elasticsearch/Extensions/SearchRegistrationExtensions.cs index b5b5934a..94ef2f2a 100644 --- a/src/SquidStd.Search.Elasticsearch/Extensions/SearchRegistrationExtensions.cs +++ b/src/SquidStd.Search.Elasticsearch/Extensions/SearchRegistrationExtensions.cs @@ -28,7 +28,7 @@ private static ElasticsearchClient CreateClient(ElasticsearchOptions options) settings = settings.ServerCertificateValidationCallback((_, _, _, _) => true); } - return new ElasticsearchClient(settings); + return new(settings); } extension(IContainer container) diff --git a/src/SquidStd.Search.Elasticsearch/Linq/ElasticExpressionTranslator.cs b/src/SquidStd.Search.Elasticsearch/Linq/ElasticExpressionTranslator.cs index 60aa43d9..0eff7e6f 100644 --- a/src/SquidStd.Search.Elasticsearch/Linq/ElasticExpressionTranslator.cs +++ b/src/SquidStd.Search.Elasticsearch/Linq/ElasticExpressionTranslator.cs @@ -5,10 +5,10 @@ namespace SquidStd.Search.Elasticsearch.Linq; /// -/// Translates a constrained LINQ expression chain into an . Supported: Where -/// (==, !=, <, >, <=, >=, &&, ||, !, bool members, string.Contains/StartsWith), -/// OrderBy/ThenBy(Descending), Skip, Take, and the Match/FullText markers. Anything else throws -/// . +/// Translates a constrained LINQ expression chain into an . Supported: Where +/// (==, !=, <, >, <=, >=, &&, ||, !, bool members, string.Contains/StartsWith), +/// OrderBy/ThenBy(Descending), Skip, Take, and the Match/FullText markers. Anything else throws +/// . /// public static class ElasticExpressionTranslator { @@ -25,7 +25,7 @@ public static ElasticQuery Translate(Expression expression, Type elementType) if (must.Count > 0) { - result.Query = new JsonObject { ["bool"] = new JsonObject { ["must"] = must } }; + result.Query = new() { ["bool"] = new JsonObject { ["must"] = must } }; } if (sort.Count > 0) @@ -37,11 +37,9 @@ public static ElasticQuery Translate(Expression expression, Type elementType) } private static object? EvaluateValue(Expression expression) - { - return expression is ConstantExpression constant - ? constant.Value - : Expression.Lambda(expression).Compile().DynamicInvoke(); - } + => expression is ConstantExpression constant + ? constant.Value + : Expression.Lambda(expression).Compile().DynamicInvoke(); private static string FieldName(MemberExpression member) { @@ -58,19 +56,15 @@ private static string FieldName(MemberExpression member) } private static object? GetConstant(Expression expression) - { - return EvaluateValue(expression); - } + => EvaluateValue(expression); private static bool IsParameterBound(Expression expression) - { - return expression switch + => expression switch { ParameterExpression => true, MemberExpression m => m.Expression is not null && IsParameterBound(m.Expression), _ => false }; - } private static (MemberExpression Member, Expression Value) OrientMemberValue(BinaryExpression binary) { @@ -88,33 +82,27 @@ private static (MemberExpression Member, Expression Value) OrientMemberValue(Bin } private static JsonObject Range(string field, string op, JsonNode? value) - { - return new JsonObject { ["range"] = new JsonObject { [field] = new JsonObject { [op] = value } } }; - } + => new() { ["range"] = new JsonObject { [field] = new JsonObject { [op] = value } } }; private static JsonObject SortClause(Expression keySelector, string order) { var member = (MemberExpression)UnquoteLambda(keySelector).Body; - return new JsonObject { [FieldName(member)] = new JsonObject { ["order"] = order } }; + return new() { [FieldName(member)] = new JsonObject { ["order"] = order } }; } private static Expression StripConvert(Expression expression) - { - return expression is UnaryExpression { NodeType: ExpressionType.Convert } convert ? convert.Operand : expression; - } + => expression is UnaryExpression { NodeType: ExpressionType.Convert } convert ? convert.Operand : expression; private static JsonObject TermOrKeyword(string field, Type memberType, JsonNode? value) { var termField = memberType == typeof(string) ? $"{field}.keyword" : field; - return new JsonObject { ["term"] = new JsonObject { [termField] = value } }; + return new() { ["term"] = new JsonObject { [termField] = value } }; } private static JsonNode? ToJsonValue(object? value) - { - return value is null ? null : JsonSerializer.SerializeToNode(value, WebOptions); - } + => value is null ? null : JsonSerializer.SerializeToNode(value, WebOptions); private static JsonObject TranslateComparison(BinaryExpression binary) { @@ -125,7 +113,7 @@ private static JsonObject TranslateComparison(BinaryExpression binary) return binary.NodeType switch { ExpressionType.Equal => TermOrKeyword(field, member.Type, value), - ExpressionType.NotEqual => new JsonObject + ExpressionType.NotEqual => new() { ["bool"] = new JsonObject { ["must_not"] = new JsonArray(TermOrKeyword(field, member.Type, value)) } }, ExpressionType.GreaterThan => Range(field, "gt", value), ExpressionType.GreaterThanOrEqual => Range(field, "gte", value), @@ -140,13 +128,13 @@ private static JsonObject TranslatePredicate(Expression expression) switch (expression) { case BinaryExpression { NodeType: ExpressionType.AndAlso } and1: - return new JsonObject + return new() { ["bool"] = new JsonObject { ["must"] = new JsonArray(TranslatePredicate(and1.Left), TranslatePredicate(and1.Right)) } }; case BinaryExpression { NodeType: ExpressionType.OrElse } or1: - return new JsonObject + return new() { ["bool"] = new JsonObject { @@ -155,12 +143,11 @@ private static JsonObject TranslatePredicate(Expression expression) } }; case UnaryExpression { NodeType: ExpressionType.Not } not: - return new JsonObject - { ["bool"] = new JsonObject { ["must_not"] = new JsonArray(TranslatePredicate(not.Operand)) } }; + return new() { ["bool"] = new JsonObject { ["must_not"] = new JsonArray(TranslatePredicate(not.Operand)) } }; case BinaryExpression binary: return TranslateComparison(binary); case MemberExpression member when member.Type == typeof(bool): - return new JsonObject { ["term"] = new JsonObject { [FieldName(member)] = true } }; + return new() { ["term"] = new JsonObject { [FieldName(member)] = true } }; case MethodCallExpression methodCall: return TranslateStringMethod(methodCall); default: @@ -180,25 +167,21 @@ private static JsonObject TranslateStringMethod(MethodCallExpression call) return call.Method.Name switch { - "Contains" => new JsonObject { ["wildcard"] = new JsonObject { [$"{field}.keyword"] = $"*{arg}*" } }, - "StartsWith" => new JsonObject { ["prefix"] = new JsonObject { [$"{field}.keyword"] = arg } }, + "Contains" => new() { ["wildcard"] = new JsonObject { [$"{field}.keyword"] = $"*{arg}*" } }, + "StartsWith" => new() { ["prefix"] = new JsonObject { [$"{field}.keyword"] = arg } }, _ => throw Unsupported(call) }; } private static LambdaExpression UnquoteLambda(Expression expression) - { - return expression is UnaryExpression { NodeType: ExpressionType.Quote } quote - ? (LambdaExpression)quote.Operand - : (LambdaExpression)expression; - } + => expression is UnaryExpression { NodeType: ExpressionType.Quote } quote + ? (LambdaExpression)quote.Operand + : (LambdaExpression)expression; private static NotSupportedException Unsupported(Expression expression) - { - return new NotSupportedException( + => new( $"Expression '{expression}' is not supported by the Elasticsearch provider. Use the native ElasticsearchClient for advanced queries." ); - } private static void Walk(Expression expression, JsonArray must, JsonArray sort, ElasticQuery result) { diff --git a/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryProvider.cs b/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryProvider.cs index 65f5c23e..c9eb475d 100644 --- a/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryProvider.cs +++ b/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryProvider.cs @@ -6,8 +6,8 @@ namespace SquidStd.Search.Elasticsearch.Linq; /// -/// Executes a translated against Elasticsearch. Synchronous LINQ execution is not -/// supported — use the async terminals in . +/// Executes a translated against Elasticsearch. Synchronous LINQ execution is not +/// supported — use the async terminals in . /// public sealed class ElasticQueryProvider : IQueryProvider { @@ -23,28 +23,20 @@ public ElasticQueryProvider(ElasticTransport transport, string index, Type eleme } public IQueryable CreateQuery(Expression expression) - { - return (IQueryable)Activator.CreateInstance( + => (IQueryable)Activator.CreateInstance( typeof(ElasticQueryable<>).MakeGenericType(_elementType), this, expression )!; - } public IQueryable CreateQuery(Expression expression) - { - return new ElasticQueryable(this, expression); - } + => new ElasticQueryable(this, expression); public object? Execute(Expression expression) - { - throw new NotSupportedException("Use the async terminals (ToListAsync/CountAsync/FirstOrDefaultAsync)."); - } + => throw new NotSupportedException("Use the async terminals (ToListAsync/CountAsync/FirstOrDefaultAsync)."); public TResult Execute(Expression expression) - { - throw new NotSupportedException("Use the async terminals (ToListAsync/CountAsync/FirstOrDefaultAsync)."); - } + => throw new NotSupportedException("Use the async terminals (ToListAsync/CountAsync/FirstOrDefaultAsync)."); /// Runs a count and returns the total. public async Task CountAsync(Expression expression, CancellationToken cancellationToken) @@ -61,11 +53,11 @@ public async Task> ToListAsync(Expression expression, CancellationTok { var query = ElasticExpressionTranslator.Translate(expression, _elementType); var (status, body) = await _transport.SendAsync( - HttpMethod.POST, - $"/{_index}/_search", - query.ToRequestBody(), - cancellationToken - ); + HttpMethod.POST, + $"/{_index}/_search", + query.ToRequestBody(), + cancellationToken + ); if (status == 404) { diff --git a/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryable.cs b/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryable.cs index 5ce839f5..4ab05700 100644 --- a/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryable.cs +++ b/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryable.cs @@ -25,12 +25,8 @@ public ElasticQueryable(ElasticQueryProvider provider) } public IEnumerator GetEnumerator() - { - throw new NotSupportedException("Use the async terminals (ToListAsync/CountAsync/FirstOrDefaultAsync)."); - } + => throw new NotSupportedException("Use the async terminals (ToListAsync/CountAsync/FirstOrDefaultAsync)."); IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + => GetEnumerator(); } diff --git a/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryableExtensions.cs b/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryableExtensions.cs index f2081720..9373c06a 100644 --- a/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryableExtensions.cs +++ b/src/SquidStd.Search.Elasticsearch/Linq/ElasticQueryableExtensions.cs @@ -4,31 +4,23 @@ namespace SquidStd.Search.Elasticsearch.Linq; /// -/// LINQ surface for the Elasticsearch provider. and are -/// markers recognized by the translator (no standalone runtime behavior); the async terminals execute the query. +/// LINQ surface for the Elasticsearch provider. and are +/// markers recognized by the translator (no standalone runtime behavior); the async terminals execute the query. /// public static class ElasticQueryableExtensions { private static ElasticQueryProvider Provider(IQueryable source) - { - return source.Provider as ElasticQueryProvider ?? - throw new NotSupportedException( - "These async terminals require a query created by ISearchService.Query()." - ); - } + => source.Provider as ElasticQueryProvider ?? + throw new NotSupportedException("These async terminals require a query created by ISearchService.Query()."); extension(IQueryable source) { /// Executes a count of matching documents. public Task CountAsync(CancellationToken cancellationToken = default) - { - return Provider(source).CountAsync(source.Expression, cancellationToken); - } + => Provider(source).CountAsync(source.Expression, cancellationToken); /// Executes the query and returns the first matching document, or null. - public async Task FirstOrDefaultAsync( - CancellationToken cancellationToken = default - ) + public async Task FirstOrDefaultAsync(CancellationToken cancellationToken = default) { var limited = source.Take(1); var results = await Provider(limited).ToListAsync(limited.Expression, cancellationToken); @@ -38,20 +30,17 @@ public Task CountAsync(CancellationToken cancellationToken = default) /// Full-text match of across all fields. public IQueryable FullText(string text) - { - return source.Provider.CreateQuery( + => source.Provider.CreateQuery( Expression.Call( ((MethodInfo)MethodBase.GetCurrentMethod()!).MakeGenericMethod(typeof(T)), source.Expression, Expression.Constant(text) ) ); - } /// Full-text match of against a single field. public IQueryable Match(string field, string text) - { - return source.Provider.CreateQuery( + => source.Provider.CreateQuery( Expression.Call( ((MethodInfo)MethodBase.GetCurrentMethod()!).MakeGenericMethod(typeof(T)), source.Expression, @@ -59,12 +48,9 @@ public IQueryable Match(string field, string text) Expression.Constant(text) ) ); - } /// Executes the query and returns all matching documents. public Task> ToListAsync(CancellationToken cancellationToken = default) - { - return Provider(source).ToListAsync(source.Expression, cancellationToken); - } + => Provider(source).ToListAsync(source.Expression, cancellationToken); } } diff --git a/src/SquidStd.Search.Elasticsearch/README.md b/src/SquidStd.Search.Elasticsearch/README.md index 2b80206a..e1c668f1 100644 --- a/src/SquidStd.Search.Elasticsearch/README.md +++ b/src/SquidStd.Search.Elasticsearch/README.md @@ -37,12 +37,12 @@ Anything else throws `NotSupportedException` — drop down to the native `Elasti ## Key types -| Type | Purpose | -|------|---------| -| `SearchRegistrationExtensions` | `AddElasticsearch(...)` registration. | -| `ElasticSearchService` | `ISearchService` backed by the Elasticsearch client. | -| `ElasticsearchOptions` | Connection options (URI, credentials). | -| `ElasticQueryable` | Constrained `IQueryable` translated to the Elasticsearch query DSL. | +| Type | Purpose | +|--------------------------------|------------------------------------------------------------------------| +| `SearchRegistrationExtensions` | `AddElasticsearch(...)` registration. | +| `ElasticSearchService` | `ISearchService` backed by the Elasticsearch client. | +| `ElasticsearchOptions` | Connection options (URI, credentials). | +| `ElasticQueryable` | Constrained `IQueryable` translated to the Elasticsearch query DSL. | ## Related diff --git a/src/SquidStd.Search.Elasticsearch/Services/ElasticSearchService.cs b/src/SquidStd.Search.Elasticsearch/Services/ElasticSearchService.cs index d74c3d4f..afff670f 100644 --- a/src/SquidStd.Search.Elasticsearch/Services/ElasticSearchService.cs +++ b/src/SquidStd.Search.Elasticsearch/Services/ElasticSearchService.cs @@ -11,8 +11,8 @@ namespace SquidStd.Search.Elasticsearch.Services; /// -/// Default : indexes, deletes, and queries documents over the Elasticsearch -/// low-level transport, with index names resolved from [SearchIndex] + the configured prefix. +/// Default : indexes, deletes, and queries documents over the Elasticsearch +/// low-level transport, with index names resolved from [SearchIndex] + the configured prefix. /// public sealed class ElasticSearchService : ISearchService { @@ -82,11 +82,11 @@ public async Task IndexAsync(T entity, bool refresh = false, CancellationToke var index = ResolveIndex(); var path = $"/{index}/_doc/{Uri.EscapeDataString(entity.IndexId)}{RefreshQuery(refresh)}"; var (status, body) = await _transport.SendAsync( - HttpMethod.PUT, - path, - ElasticTransport.SerializeDocument(entity), - cancellationToken - ); + HttpMethod.PUT, + path, + ElasticTransport.SerializeDocument(entity), + cancellationToken + ); EnsureSuccess(status, body, $"index document '{entity.IndexId}' into '{index}'"); } @@ -130,9 +130,7 @@ public async Task IndexManyAsync( /// public IQueryable Query() where T : IIndexableEntity - { - return new ElasticQueryable(new ElasticQueryProvider(_transport, ResolveIndex(), typeof(T))); - } + => new ElasticQueryable(new(_transport, ResolveIndex(), typeof(T))); /// Resolves the (prefixed, lowercased) index name for a type. public string ResolveIndex() @@ -156,7 +154,5 @@ private void EnsureSuccess(int status, JsonNode? body, string operation) } private static string RefreshQuery(bool refresh) - { - return refresh ? "?refresh=wait_for" : string.Empty; - } + => refresh ? "?refresh=wait_for" : string.Empty; } diff --git a/src/SquidStd.Search.Elasticsearch/Services/ElasticTransport.cs b/src/SquidStd.Search.Elasticsearch/Services/ElasticTransport.cs index 70e81ecf..3ab5c941 100644 --- a/src/SquidStd.Search.Elasticsearch/Services/ElasticTransport.cs +++ b/src/SquidStd.Search.Elasticsearch/Services/ElasticTransport.cs @@ -7,8 +7,8 @@ namespace SquidStd.Search.Elasticsearch.Services; /// -/// Thin JSON request helper over the Elasticsearch client's low-level transport. Sends raw DSL/document JSON -/// and returns the parsed response, decoupling the provider from the strongly-typed query DSL. +/// Thin JSON request helper over the Elasticsearch client's low-level transport. Sends raw DSL/document JSON +/// and returns the parsed response, decoupling the provider from the strongly-typed query DSL. /// public sealed class ElasticTransport { @@ -37,9 +37,7 @@ public ElasticTransport(ElasticsearchClient client) /// Deserializes a document body (an Elasticsearch _source) to . public static T DeserializeDocument(JsonNode source) - { - return source.Deserialize(WebOptions)!; - } + => source.Deserialize(WebOptions)!; /// Sends a request with an optional JSON body and returns (statusCode, bodyJson). public Task<(int Status, JsonNode? Body)> SendAsync( @@ -48,9 +46,7 @@ public static T DeserializeDocument(JsonNode source) JsonNode? body, CancellationToken cancellationToken ) - { - return SendCoreAsync(method, path, body?.ToJsonString(), JsonRequest, cancellationToken); - } + => SendCoreAsync(method, path, body?.ToJsonString(), JsonRequest, cancellationToken); /// Sends a raw (already-serialized) NDJSON body for the bulk API. public Task<(int Status, JsonNode? Body)> SendRawAsync( @@ -59,15 +55,11 @@ CancellationToken cancellationToken string? body, CancellationToken cancellationToken ) - { - return SendCoreAsync(method, path, body, NdjsonRequest, cancellationToken); - } + => SendCoreAsync(method, path, body, NdjsonRequest, cancellationToken); /// Serializes a value to a using Web (camelCase) defaults. public static JsonNode SerializeDocument(T value) - { - return JsonSerializer.SerializeToNode(value, WebOptions)!; - } + => JsonSerializer.SerializeToNode(value, WebOptions)!; private async Task<(int Status, JsonNode? Body)> SendCoreAsync( HttpMethod method, @@ -80,14 +72,14 @@ CancellationToken cancellationToken var postData = body is null ? null : PostData.String(body); var response = await _client.Transport - .RequestAsync( - method, - path, - postData, - requestConfiguration, - cancellationToken - ) - .ConfigureAwait(false); + .RequestAsync( + method, + path, + postData, + requestConfiguration, + cancellationToken + ) + .ConfigureAwait(false); var status = response.ApiCallDetails.HttpStatusCode ?? 0; var text = response.Body; diff --git a/src/SquidStd.Secrets.Aws/Internal/AwsClientFactory.cs b/src/SquidStd.Secrets.Aws/Internal/AwsClientFactory.cs index eaaf6c8c..954460e2 100644 --- a/src/SquidStd.Secrets.Aws/Internal/AwsClientFactory.cs +++ b/src/SquidStd.Secrets.Aws/Internal/AwsClientFactory.cs @@ -14,8 +14,8 @@ public static AWSCredentials Credentials(AwsConfigEntry aws) if (!string.IsNullOrWhiteSpace(aws.AccessKey) && !string.IsNullOrWhiteSpace(aws.SecretKey)) { return string.IsNullOrWhiteSpace(aws.SessionToken) - ? new BasicAWSCredentials(aws.AccessKey, aws.SecretKey) - : new SessionAWSCredentials(aws.AccessKey, aws.SecretKey, aws.SessionToken); + ? new BasicAWSCredentials(aws.AccessKey, aws.SecretKey) + : new SessionAWSCredentials(aws.AccessKey, aws.SecretKey, aws.SessionToken); } return FallbackCredentialsFactory.GetCredentials(); diff --git a/src/SquidStd.Secrets.Aws/README.md b/src/SquidStd.Secrets.Aws/README.md index bbc215d0..81544369 100644 --- a/src/SquidStd.Secrets.Aws/README.md +++ b/src/SquidStd.Secrets.Aws/README.md @@ -46,12 +46,12 @@ await foreach (var name in store.ListNamesAsync("db/")) { /* ... */ } ## Key types -| Type | Purpose | -|------|---------| -| `KmsSecretProtector` | `ISecretProtector` using AWS KMS data keys (envelope encryption). | -| `AwsSecretsManagerStore` | `ISecretStore` backed by AWS Secrets Manager. | -| `KmsSecretProtectorOptions` | KMS key id/ARN/alias, region and credentials. | -| `AwsSecretsManagerOptions` | Optional name prefix, region and credentials. | +| Type | Purpose | +|-----------------------------|-------------------------------------------------------------------| +| `KmsSecretProtector` | `ISecretProtector` using AWS KMS data keys (envelope encryption). | +| `AwsSecretsManagerStore` | `ISecretStore` backed by AWS Secrets Manager. | +| `KmsSecretProtectorOptions` | KMS key id/ARN/alias, region and credentials. | +| `AwsSecretsManagerOptions` | Optional name prefix, region and credentials. | ## Notes diff --git a/src/SquidStd.Secrets.Aws/Services/AwsSecretsManagerStore.cs b/src/SquidStd.Secrets.Aws/Services/AwsSecretsManagerStore.cs index f1f48c04..b3eedb91 100644 --- a/src/SquidStd.Secrets.Aws/Services/AwsSecretsManagerStore.cs +++ b/src/SquidStd.Secrets.Aws/Services/AwsSecretsManagerStore.cs @@ -18,7 +18,7 @@ public AwsSecretsManagerStore(AwsSecretsManagerOptions options) ArgumentNullException.ThrowIfNull(options); _prefix = options.NamePrefix ?? string.Empty; - _client = new AmazonSecretsManagerClient( + _client = new( AwsClientFactory.Credentials(options.Aws), AwsClientFactory.SecretsManagerConfig(options.Aws) ); @@ -37,10 +37,10 @@ public async ValueTask DeleteAsync(string name, CancellationToken cancella try { await _client.DeleteSecretAsync( - new DeleteSecretRequest { SecretId = _prefix + name, ForceDeleteWithoutRecovery = true }, - cancellationToken - ) - .ConfigureAwait(false); + new() { SecretId = _prefix + name, ForceDeleteWithoutRecovery = true }, + cancellationToken + ) + .ConfigureAwait(false); return true; } @@ -58,10 +58,10 @@ public async ValueTask ExistsAsync(string name, CancellationToken cancella try { await _client.DescribeSecretAsync( - new DescribeSecretRequest { SecretId = _prefix + name }, - cancellationToken - ) - .ConfigureAwait(false); + new() { SecretId = _prefix + name }, + cancellationToken + ) + .ConfigureAwait(false); return true; } @@ -79,10 +79,10 @@ await _client.DescribeSecretAsync( try { var response = await _client.GetSecretValueAsync( - new GetSecretValueRequest { SecretId = _prefix + name }, - cancellationToken - ) - .ConfigureAwait(false); + new() { SecretId = _prefix + name }, + cancellationToken + ) + .ConfigureAwait(false); return response.SecretString; } @@ -103,24 +103,25 @@ public async ValueTask SetAsync(string name, string value, CancellationToken can try { await _client.PutSecretValueAsync( - new PutSecretValueRequest { SecretId = secretId, SecretString = value }, - cancellationToken - ) - .ConfigureAwait(false); + new() { SecretId = secretId, SecretString = value }, + cancellationToken + ) + .ConfigureAwait(false); } catch (ResourceNotFoundException) { await _client.CreateSecretAsync( - new CreateSecretRequest { Name = secretId, SecretString = value }, - cancellationToken - ) - .ConfigureAwait(false); + new() { Name = secretId, SecretString = value }, + cancellationToken + ) + .ConfigureAwait(false); } } /// public async IAsyncEnumerable ListNamesAsync( - string? prefix = null, [EnumeratorCancellation] CancellationToken cancellationToken = default + string? prefix = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default ) { var fullPrefix = _prefix + (prefix ?? string.Empty); @@ -129,10 +130,10 @@ public async IAsyncEnumerable ListNamesAsync( do { var response = await _client.ListSecretsAsync( - new ListSecretsRequest { NextToken = token, MaxResults = 100 }, - cancellationToken - ) - .ConfigureAwait(false); + new() { NextToken = token, MaxResults = 100 }, + cancellationToken + ) + .ConfigureAwait(false); foreach (var secret in response.SecretList) { @@ -148,7 +149,5 @@ public async IAsyncEnumerable ListNamesAsync( /// public void Dispose() - { - _client.Dispose(); - } + => _client.Dispose(); } diff --git a/src/SquidStd.Secrets.Aws/Services/KmsSecretProtector.cs b/src/SquidStd.Secrets.Aws/Services/KmsSecretProtector.cs index 32388dac..63be54ca 100644 --- a/src/SquidStd.Secrets.Aws/Services/KmsSecretProtector.cs +++ b/src/SquidStd.Secrets.Aws/Services/KmsSecretProtector.cs @@ -1,6 +1,5 @@ using System.Security.Cryptography; using Amazon.KeyManagementService; -using Amazon.KeyManagementService.Model; using SquidStd.Core.Interfaces.Secrets; using SquidStd.Secrets.Aws.Data; using SquidStd.Secrets.Aws.Internal; @@ -19,7 +18,7 @@ public KmsSecretProtector(KmsSecretProtectorOptions options) ArgumentException.ThrowIfNullOrWhiteSpace(options.KeyId); _keyId = options.KeyId; - _kms = new AmazonKeyManagementServiceClient( + _kms = new( AwsClientFactory.Credentials(options.Aws), AwsClientFactory.KmsConfig(options.Aws) ); @@ -30,11 +29,9 @@ public byte[] Protect(byte[] plaintext) { ArgumentNullException.ThrowIfNull(plaintext); - var generated = _kms.GenerateDataKeyAsync( - new GenerateDataKeyRequest { KeyId = _keyId, KeySpec = DataKeySpec.AES_256 } - ) - .GetAwaiter() - .GetResult(); + var generated = _kms.GenerateDataKeyAsync(new() { KeyId = _keyId, KeySpec = DataKeySpec.AES_256 }) + .GetAwaiter() + .GetResult(); var dataKey = generated.Plaintext.ToArray(); @@ -54,11 +51,9 @@ public byte[] Unprotect(byte[] protectedData) ArgumentNullException.ThrowIfNull(protectedData); var wrappedKey = KmsEnvelope.ReadWrappedKey(protectedData); - var decrypted = _kms.DecryptAsync( - new DecryptRequest { CiphertextBlob = new MemoryStream(wrappedKey) } - ) - .GetAwaiter() - .GetResult(); + var decrypted = _kms.DecryptAsync(new() { CiphertextBlob = new(wrappedKey) }) + .GetAwaiter() + .GetResult(); var dataKey = decrypted.Plaintext.ToArray(); @@ -74,7 +69,5 @@ public byte[] Unprotect(byte[] protectedData) /// public void Dispose() - { - _kms.Dispose(); - } + => _kms.Dispose(); } diff --git a/src/SquidStd.Services.Core/Extensions/Logger/SquidStdLogRollingIntervalExtensions.cs b/src/SquidStd.Services.Core/Extensions/Logger/SquidStdLogRollingIntervalExtensions.cs index bb9df9b9..79712f86 100644 --- a/src/SquidStd.Services.Core/Extensions/Logger/SquidStdLogRollingIntervalExtensions.cs +++ b/src/SquidStd.Services.Core/Extensions/Logger/SquidStdLogRollingIntervalExtensions.cs @@ -4,7 +4,7 @@ namespace SquidStd.Services.Core.Extensions.Logger; /// -/// Extension methods for converting SquidStd logger options to Serilog values. +/// Extension methods for converting SquidStd logger options to Serilog values. /// public static class SquidStdLogRollingIntervalExtensions { @@ -12,12 +12,11 @@ public static class SquidStdLogRollingIntervalExtensions extension(SquidStdLogRollingIntervalType interval) { /// - /// Converts a SquidStd rolling interval to a Serilog rolling interval. + /// Converts a SquidStd rolling interval to a Serilog rolling interval. /// /// The corresponding Serilog rolling interval. public RollingInterval ToSerilogRollingInterval() - { - return interval switch + => interval switch { SquidStdLogRollingIntervalType.Infinite => RollingInterval.Infinite, SquidStdLogRollingIntervalType.Year => RollingInterval.Year, @@ -27,6 +26,5 @@ public RollingInterval ToSerilogRollingInterval() SquidStdLogRollingIntervalType.Minute => RollingInterval.Minute, _ => RollingInterval.Day }; - } } } diff --git a/src/SquidStd.Services.Core/Extensions/RegisterCommandDispatcherExtensions.cs b/src/SquidStd.Services.Core/Extensions/RegisterCommandDispatcherExtensions.cs index 82fb76f4..de9e1436 100644 --- a/src/SquidStd.Services.Core/Extensions/RegisterCommandDispatcherExtensions.cs +++ b/src/SquidStd.Services.Core/Extensions/RegisterCommandDispatcherExtensions.cs @@ -6,7 +6,7 @@ namespace SquidStd.Services.Core.Extensions; /// -/// Extension methods for registering a command dispatcher and its context factory. +/// Extension methods for registering a command dispatcher and its context factory. /// public static class RegisterCommandDispatcherExtensions { @@ -14,7 +14,7 @@ public static class RegisterCommandDispatcherExtensions extension(IContainer container) { /// - /// Registers an singleton and its bootstrap activator. + /// Registers an singleton and its bootstrap activator. /// /// The dispatcher context type. /// The same container for chaining. @@ -27,9 +27,9 @@ public IContainer RegisterCommandDispatcher() } /// - /// Registers a seeded context factory and an - /// singleton over the existing (which must already be - /// registered via ). + /// Registers a seeded context factory and an + /// singleton over the existing (which must already be + /// registered via ). /// /// The dispatcher context type. /// The seed the context is built from. diff --git a/src/SquidStd.Services.Core/Extensions/RegisterDefaultServicesExtensions.cs b/src/SquidStd.Services.Core/Extensions/RegisterDefaultServicesExtensions.cs index 00ca09c7..c6c4bffc 100644 --- a/src/SquidStd.Services.Core/Extensions/RegisterDefaultServicesExtensions.cs +++ b/src/SquidStd.Services.Core/Extensions/RegisterDefaultServicesExtensions.cs @@ -28,7 +28,7 @@ namespace SquidStd.Services.Core.Extensions; /// -/// Extension methods for registering the default SquidStd core services. +/// Extension methods for registering the default SquidStd core services. /// public static class RegisterDefaultServicesExtensions { @@ -48,16 +48,14 @@ public IContainer RegisterConfigManagerService(string configName, string configD } /// - /// Registers the default SquidStd core services using the default config file location. + /// Registers the default SquidStd core services using the default config file location. /// /// The same container for chaining. public IContainer RegisterCoreServices() - { - return container.RegisterCoreServices("squidstd", Directory.GetCurrentDirectory()); - } + => container.RegisterCoreServices("squidstd", Directory.GetCurrentDirectory()); /// - /// Registers the default SquidStd core services and config manager. + /// Registers the default SquidStd core services and config manager. /// /// The logical config name or YAML file name. /// The directory where the config file is searched. @@ -79,14 +77,14 @@ public IContainer RegisterCoreServices(string configName, string configDirectory } /// - /// Registers the default config manager service as a singleton instance. + /// Registers the default config manager service as a singleton instance. /// /// The logical config name or YAML file name. /// The directory where the config file is searched. /// The same container for chaining. /// - /// Registers the default JSON data serializer for and - /// (same singleton instance). + /// Registers the default JSON data serializer for and + /// (same singleton instance). /// /// The same container for chaining. public IContainer RegisterDataSerializer() @@ -99,7 +97,7 @@ public IContainer RegisterDataSerializer() } /// - /// Registers the default SquidStd core configuration sections. + /// Registers the default SquidStd core configuration sections. /// /// The same container for chaining. public IContainer RegisterDefaultCoreConfigSections() @@ -115,7 +113,7 @@ public IContainer RegisterDefaultCoreConfigSections() } /// - /// Registers the default event bus service in the container. + /// Registers the default event bus service in the container. /// /// The same container for chaining. public IContainer RegisterEventBusService() @@ -125,18 +123,16 @@ public IContainer RegisterEventBusService() resolver => new EventBusService(resolver.Resolve()), Reuse.Singleton ); - container.AddToRegisterTypedList( - new ServiceRegistrationData(typeof(IEventBus), typeof(EventBusService), -1) - ); + container.AddToRegisterTypedList(new ServiceRegistrationData(typeof(IEventBus), typeof(EventBusService), -1)); container.RegisterStdService(-900); return container; } /// - /// Registers the recursive file watcher service as a singleton resolving the event bus. - /// Not part of : opt in, then call - /// for the directories to watch. + /// Registers the recursive file watcher service as a singleton resolving the event bus. + /// Not part of : opt in, then call + /// for the directories to watch. /// /// Optional debounce window; defaults to 300ms when null. /// The same container for chaining. @@ -144,8 +140,8 @@ public IContainer RegisterFileWatcherService(TimeSpan? debounceDelay = null) { container.RegisterDelegate( resolver => debounceDelay is { } delay - ? new FileWatcherService(resolver.Resolve(), delay) - : new FileWatcherService(resolver.Resolve()), + ? new FileWatcherService(resolver.Resolve(), delay) + : new FileWatcherService(resolver.Resolve()), Reuse.Singleton ); @@ -153,7 +149,7 @@ public IContainer RegisterFileWatcherService(TimeSpan? debounceDelay = null) } /// - /// Registers the default job system service in the container. + /// Registers the default job system service in the container. /// /// The same container for chaining. public IContainer RegisterJobSystemService() @@ -164,16 +160,14 @@ public IContainer RegisterJobSystemService() } /// - /// Registers the default main-thread dispatcher service in the container. + /// Registers the default main-thread dispatcher service in the container. /// /// The same container for chaining. public IContainer RegisterMainThreadDispatcherService() - { - return container.RegisterStdService(-1); - } + => container.RegisterStdService(-1); /// - /// Registers the default metrics collection service in the container. + /// Registers the default metrics collection service in the container. /// /// The same container for chaining. public IContainer RegisterMetricsCollectionService() @@ -184,7 +178,7 @@ public IContainer RegisterMetricsCollectionService() } /// - /// Registers default encrypted local secret services in the container. + /// Registers default encrypted local secret services in the container. /// /// The same container for chaining. public IContainer RegisterSecretServices() @@ -197,7 +191,7 @@ public IContainer RegisterSecretServices() } /// - /// Registers the default timer wheel service in the container. + /// Registers the default timer wheel service in the container. /// /// The same container for chaining. public IContainer RegisterTimerWheelService() diff --git a/src/SquidStd.Services.Core/Extensions/RegisterHealthChecksServiceExtension.cs b/src/SquidStd.Services.Core/Extensions/RegisterHealthChecksServiceExtension.cs index a15c540e..b04fd4f9 100644 --- a/src/SquidStd.Services.Core/Extensions/RegisterHealthChecksServiceExtension.cs +++ b/src/SquidStd.Services.Core/Extensions/RegisterHealthChecksServiceExtension.cs @@ -7,7 +7,7 @@ namespace SquidStd.Services.Core.Extensions; /// -/// Extension methods for registering the health-check aggregator. +/// Extension methods for registering the health-check aggregator. /// public static class RegisterHealthChecksServiceExtension { @@ -15,8 +15,8 @@ public static class RegisterHealthChecksServiceExtension extension(IContainer container) { /// - /// Registers the health-check aggregator () as a singleton. - /// Concrete checks register themselves as IHealthCheck and are collected automatically. + /// Registers the health-check aggregator () as a singleton. + /// Concrete checks register themselves as IHealthCheck and are collected automatically. /// /// The same container for chaining. public IContainer RegisterHealthChecksService() diff --git a/src/SquidStd.Services.Core/Extensions/RegisterSchedulerServicesExtension.cs b/src/SquidStd.Services.Core/Extensions/RegisterSchedulerServicesExtension.cs index 98473b2d..dbed6903 100644 --- a/src/SquidStd.Services.Core/Extensions/RegisterSchedulerServicesExtension.cs +++ b/src/SquidStd.Services.Core/Extensions/RegisterSchedulerServicesExtension.cs @@ -8,7 +8,7 @@ namespace SquidStd.Services.Core.Extensions; /// -/// Extension methods for registering the SquidStd cron scheduler. +/// Extension methods for registering the SquidStd cron scheduler. /// public static class RegisterSchedulerServicesExtension { @@ -16,8 +16,8 @@ public static class RegisterSchedulerServicesExtension extension(IContainer container) { /// - /// Registers the timer wheel pump and the cron scheduler. Must be called after - /// RegisterCoreServices so that ITimerService and IJobSystem exist. + /// Registers the timer wheel pump and the cron scheduler. Must be called after + /// RegisterCoreServices so that ITimerService and IJobSystem exist. /// /// The same container for chaining. public IContainer RegisterSchedulerServices() diff --git a/src/SquidStd.Services.Core/Services/Bootstrap/SquidStdBootstrap.cs b/src/SquidStd.Services.Core/Services/Bootstrap/SquidStdBootstrap.cs index 1d10c44d..d8ab9057 100644 --- a/src/SquidStd.Services.Core/Services/Bootstrap/SquidStdBootstrap.cs +++ b/src/SquidStd.Services.Core/Services/Bootstrap/SquidStdBootstrap.cs @@ -14,7 +14,7 @@ namespace SquidStd.Services.Core.Services.Bootstrap; /// -/// Default SquidStd bootstrapper and service lifecycle orchestrator. +/// Default SquidStd bootstrapper and service lifecycle orchestrator. /// public sealed class SquidStdBootstrap : ISquidStdBootstrap { @@ -32,21 +32,17 @@ public sealed class SquidStdBootstrap : ISquidStdBootstrap public IContainer Container { get; } /// - /// Initializes a bootstrapper with default options. + /// Initializes a bootstrapper with default options. /// public SquidStdBootstrap() - : this(new SquidStdOptions()) - { - } + : this(new()) { } /// - /// Initializes a bootstrapper with the specified options. + /// Initializes a bootstrapper with the specified options. /// /// Bootstrap options used to register core services. public SquidStdBootstrap(SquidStdOptions options) - : this(options, new Container(), true) - { - } + : this(options, new Container(), true) { } private SquidStdBootstrap(SquidStdOptions options, IContainer container, bool ownsContainer) { @@ -67,9 +63,7 @@ private SquidStdBootstrap(SquidStdOptions options, IContainer container, bool ow /// public ISquidStdBootstrap ConfigureService(Func configure) - { - return ConfigureServices(configure); - } + => ConfigureServices(configure); /// public ISquidStdBootstrap ConfigureServices(Func configure) @@ -88,8 +82,8 @@ public ISquidStdBootstrap ConfigureServices(Func configu var configuredContainer = configure(Container); return !ReferenceEquals(configuredContainer, Container) - ? throw new InvalidOperationException("ConfigureServices must return the bootstrap container instance.") - : this; + ? throw new InvalidOperationException("ConfigureServices must return the bootstrap container instance.") + : this; } /// @@ -135,9 +129,7 @@ public async Task RunAsync(CancellationToken cancellationToken = default) { await Task.Delay(Timeout.InfiniteTimeSpan, cancellationToken); } - catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) - { - } + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { } finally { await StopAsync(CancellationToken.None); @@ -207,34 +199,28 @@ public async ValueTask StopAsync(CancellationToken cancellationToken = default) } /// - /// Creates a bootstrapper with default options. + /// Creates a bootstrapper with default options. /// /// The created bootstrapper. public static SquidStdBootstrap Create() - { - return new SquidStdBootstrap(); - } + => new(); /// - /// Creates a bootstrapper with the specified options. + /// Creates a bootstrapper with the specified options. /// /// Bootstrap options used to register core services. /// The created bootstrapper. public static SquidStdBootstrap Create(SquidStdOptions options) - { - return new SquidStdBootstrap(options); - } + => new(options); /// - /// Creates a bootstrapper using an externally owned DryIoc container. + /// Creates a bootstrapper using an externally owned DryIoc container. /// /// Bootstrap options used to register core services. /// Externally owned container that receives SquidStd services. /// The created bootstrapper. public static SquidStdBootstrap Create(SquidStdOptions options, IContainer container) - { - return new SquidStdBootstrap(options, container, false); - } + => new(options, container, false); private void ConfigureLogger() { @@ -282,9 +268,9 @@ private ServiceRegistrationData[] GetServiceRegistrations() return [ .. Container.Resolve>() - .OrderBy(registration => registration.Priority) - .ThenBy(registration => registration.ServiceType.FullName, StringComparer.Ordinal) - .ThenBy(registration => registration.ImplementationType.FullName, StringComparer.Ordinal) + .OrderBy(registration => registration.Priority) + .ThenBy(registration => registration.ServiceType.FullName, StringComparer.Ordinal) + .ThenBy(registration => registration.ImplementationType.FullName, StringComparer.Ordinal) ]; } @@ -341,8 +327,8 @@ private string ResolveLogPath(SquidStdLoggerOptions options) var logDirectory = string.IsNullOrWhiteSpace(options.LogDirectory) ? "logs" : options.LogDirectory; var fileName = string.IsNullOrWhiteSpace(options.FileName) ? "squidstd-.log" : options.FileName; var directory = Path.IsPathRooted(logDirectory) - ? logDirectory - : Path.Combine(Options.RootDirectory, logDirectory); + ? logDirectory + : Path.Combine(Options.RootDirectory, logDirectory); return Path.Combine(directory, fileName); } diff --git a/src/SquidStd.Services.Core/Services/CommandDispatcher.cs b/src/SquidStd.Services.Core/Services/CommandDispatcher.cs index 5db4f86d..c888f198 100644 --- a/src/SquidStd.Services.Core/Services/CommandDispatcher.cs +++ b/src/SquidStd.Services.Core/Services/CommandDispatcher.cs @@ -8,8 +8,8 @@ namespace SquidStd.Services.Core.Services; /// -/// In-process command dispatcher with parallel per-handler fan-out, fault isolation, and a dispatch -/// result. Commands route by their CLR type within the ambient . +/// In-process command dispatcher with parallel per-handler fan-out, fault isolation, and a dispatch +/// result. Commands route by their CLR type within the ambient . /// /// The ambient context type. public sealed class CommandDispatcher : ICommandDispatcher, IDisposable @@ -38,7 +38,9 @@ public IDisposable Subscribe(Func public async Task DispatchAsync( - TCommand command, TContext context, CancellationToken cancellationToken = default + TCommand command, + TContext context, + CancellationToken cancellationToken = default ) where TCommand : ICommand { @@ -48,7 +50,7 @@ public async Task DispatchAsync( if (handlers is null) { - return new CommandDispatchResult(false, 0, []); + return new(false, 0, []); } var tasks = new Task[handlers.Length]; @@ -61,7 +63,7 @@ public async Task DispatchAsync( var outcomes = await Task.WhenAll(tasks); var errors = outcomes.Where(static error => error is not null).Select(static error => error!).ToArray(); - return new CommandDispatchResult(true, handlers.Length, errors); + return new(true, handlers.Length, errors); } private CommandSubscription Add(Type commandType, object handler) @@ -75,7 +77,7 @@ private CommandSubscription Add(Type commandType, object handler) bucket.Add(handler); } - return new CommandSubscription(bucket, handler); + return new(bucket, handler); } private object[]? Snapshot(Type commandType) @@ -92,7 +94,10 @@ private CommandSubscription Add(Type commandType, object handler) } private async Task DispatchSafeAsync( - object handler, TCommand command, TContext context, CancellationToken cancellationToken + object handler, + TCommand command, + TContext context, + CancellationToken cancellationToken ) where TCommand : ICommand { @@ -118,7 +123,7 @@ private CommandSubscription Add(Type commandType, object handler) typeof(TCommand).Name ); - return new CommandHandlerError(handler.GetType(), ex); + return new(handler.GetType(), ex); } } diff --git a/src/SquidStd.Services.Core/Services/CommandDispatcherActivator.cs b/src/SquidStd.Services.Core/Services/CommandDispatcherActivator.cs index 832fdcea..8e177eaa 100644 --- a/src/SquidStd.Services.Core/Services/CommandDispatcherActivator.cs +++ b/src/SquidStd.Services.Core/Services/CommandDispatcherActivator.cs @@ -6,8 +6,8 @@ namespace SquidStd.Services.Core.Services; /// -/// Subscribes every DI-registered command handler to the dispatcher at startup, before publishing -/// services run. +/// Subscribes every DI-registered command handler to the dispatcher at startup, before publishing +/// services run. /// /// The dispatcher context type. internal sealed class CommandDispatcherActivator : ISquidStdService @@ -37,7 +37,5 @@ public ValueTask StartAsync(CancellationToken cancellationToken = default) } public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; } diff --git a/src/SquidStd.Services.Core/Services/ConfigManagerService.cs b/src/SquidStd.Services.Core/Services/ConfigManagerService.cs index e590af58..09ac24d7 100644 --- a/src/SquidStd.Services.Core/Services/ConfigManagerService.cs +++ b/src/SquidStd.Services.Core/Services/ConfigManagerService.cs @@ -9,7 +9,7 @@ namespace SquidStd.Services.Core.Services; /// -/// Loads YAML configuration sections and registers them into DryIoc. +/// Loads YAML configuration sections and registers them into DryIoc. /// public sealed class ConfigManagerService : IConfigManagerService, ISquidStdService { @@ -30,7 +30,7 @@ public sealed class ConfigManagerService : IConfigManagerService, ISquidStdServi public IReadOnlyCollection Entries => GetEntries(); /// - /// Initializes the config manager service. + /// Initializes the config manager service. /// /// Container that receives loaded configuration sections. /// Logical configuration name or YAML file name. @@ -48,15 +48,11 @@ public ConfigManagerService(IContainer container, string configName, string conf /// public string Compose() - { - return YamlUtils.SerializeSections(BuildSectionMap()); - } + => YamlUtils.SerializeSections(BuildSectionMap()); /// public TConfig GetConfig() where TConfig : class - { - return _container.Resolve(); - } + => _container.Resolve(); /// public void Load() @@ -70,11 +66,11 @@ public void Load() { var entry = entries[i]; var value = string.IsNullOrWhiteSpace(yaml) - ? entry.CreateDefault() - : YamlUtils.DeserializeSection(yaml, entry.SectionName, entry.ConfigType) ?? - entry.CreateDefault(); + ? entry.CreateDefault() + : YamlUtils.DeserializeSection(yaml, entry.SectionName, entry.ConfigType) ?? + entry.CreateDefault(); - ApplyEnvSubstitution(value, new HashSet(ReferenceEqualityComparer.Instance)); + ApplyEnvSubstitution(value, new(ReferenceEqualityComparer.Instance)); _values[entry.ConfigType] = value; _container.RegisterInstance(entry.ConfigType, value, IfAlreadyRegistered.Replace); @@ -88,9 +84,7 @@ public void Load() /// public void Save() - { - YamlUtils.SerializeToFile(BuildSectionMap(), ConfigPath); - } + => YamlUtils.SerializeToFile(BuildSectionMap(), ConfigPath); /// public ValueTask StartAsync(CancellationToken cancellationToken = default) @@ -176,9 +170,7 @@ private Dictionary BuildSectionMap() } private IReadOnlyCollection GetEntries() - { - return GetRegistrations().Cast().ToArray(); - } + => GetRegistrations().Cast().ToArray(); private List GetRegistrations() { @@ -190,8 +182,8 @@ private List GetRegistrations() return [ .. _container.Resolve>() - .OrderBy(entry => entry.Priority) - .ThenBy(entry => entry.SectionName, StringComparer.Ordinal) + .OrderBy(entry => entry.Priority) + .ThenBy(entry => entry.SectionName, StringComparer.Ordinal) ]; } diff --git a/src/SquidStd.Services.Core/Services/EventBusService.cs b/src/SquidStd.Services.Core/Services/EventBusService.cs index e570a3b5..2b1ea54b 100644 --- a/src/SquidStd.Services.Core/Services/EventBusService.cs +++ b/src/SquidStd.Services.Core/Services/EventBusService.cs @@ -8,8 +8,8 @@ namespace SquidStd.Services.Core.Services; /// -/// In-process event bus with parallel per-listener dispatch, catch-all listeners, -/// fault isolation, and slow-listener telemetry. +/// In-process event bus with parallel per-listener dispatch, catch-all listeners, +/// fault isolation, and slow-listener telemetry. /// public sealed class EventBusService : IEventBus, IDisposable { @@ -19,15 +19,13 @@ public sealed class EventBusService : IEventBus, IDisposable private bool _disposed; /// - /// Initializes the event bus with default options. + /// Initializes the event bus with default options. /// public EventBusService() - : this(new EventBusOptions()) - { - } + : this(new()) { } /// - /// Initializes the event bus with the supplied options. + /// Initializes the event bus with the supplied options. /// public EventBusService(EventBusOptions options) { @@ -37,9 +35,7 @@ public EventBusService(EventBusOptions options) /// public void Publish(TEvent eventData) where TEvent : IEvent - { - PublishAsync(eventData, CancellationToken.None).GetAwaiter().GetResult(); - } + => PublishAsync(eventData, CancellationToken.None).GetAwaiter().GetResult(); /// public async Task PublishAsync(TEvent eventData, CancellationToken cancellationToken = default) @@ -116,7 +112,7 @@ private Subscription Add(Type eventType, object listener) bucket.Add(listener); } - return new Subscription(bucket, listener); + return new(bucket, listener); } private object[]? Snapshot(Type eventType) diff --git a/src/SquidStd.Services.Core/Services/EventListenerActivator.cs b/src/SquidStd.Services.Core/Services/EventListenerActivator.cs index 35517a35..ce487ec5 100644 --- a/src/SquidStd.Services.Core/Services/EventListenerActivator.cs +++ b/src/SquidStd.Services.Core/Services/EventListenerActivator.cs @@ -6,7 +6,7 @@ namespace SquidStd.Services.Core.Services; /// -/// Subscribes every DI-registered event listener to the bus at startup, before publishing services run. +/// Subscribes every DI-registered event listener to the bus at startup, before publishing services run. /// internal sealed class EventListenerActivator : ISquidStdService { @@ -35,7 +35,5 @@ public ValueTask StartAsync(CancellationToken cancellationToken = default) } public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; } diff --git a/src/SquidStd.Services.Core/Services/HealthCheckService.cs b/src/SquidStd.Services.Core/Services/HealthCheckService.cs index 76377539..634a119b 100644 --- a/src/SquidStd.Services.Core/Services/HealthCheckService.cs +++ b/src/SquidStd.Services.Core/Services/HealthCheckService.cs @@ -8,8 +8,8 @@ namespace SquidStd.Services.Core.Services; /// -/// Runs every registered in parallel with a per-check timeout and -/// exception isolation, then aggregates the results into a single . +/// Runs every registered in parallel with a per-check timeout and +/// exception isolation, then aggregates the results into a single . /// public sealed class HealthCheckService : IHealthCheckService { @@ -36,7 +36,7 @@ public async ValueTask CheckHealthAsync(CancellationToken cancella if (_checks.Length == 0) { - return new HealthReport + return new() { Status = HealthStatus.Healthy, Entries = new Dictionary(StringComparer.Ordinal), @@ -77,7 +77,7 @@ public async ValueTask CheckHealthAsync(CancellationToken cancella } } - return new HealthReport + return new() { Status = overall, Entries = entries, @@ -105,7 +105,7 @@ CancellationToken cancellationToken catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) { return (check.Name, - HealthCheckResult.Unhealthy($"Timed out after {_checkTimeout}.") with { Duration = stopwatch.Elapsed }); + HealthCheckResult.Unhealthy($"Timed out after {_checkTimeout}.") with { Duration = stopwatch.Elapsed }); } catch (OperationCanceledException) { diff --git a/src/SquidStd.Services.Core/Services/Internal/CommandSubscription.cs b/src/SquidStd.Services.Core/Services/Internal/CommandSubscription.cs index 97bb29c5..39f441c8 100644 --- a/src/SquidStd.Services.Core/Services/Internal/CommandSubscription.cs +++ b/src/SquidStd.Services.Core/Services/Internal/CommandSubscription.cs @@ -1,7 +1,7 @@ namespace SquidStd.Services.Core.Services.Internal; /// -/// Unsubscribe token that removes a command handler from its bucket when disposed. +/// Unsubscribe token that removes a command handler from its bucket when disposed. /// internal sealed class CommandSubscription : IDisposable { diff --git a/src/SquidStd.Services.Core/Services/Internal/CronJobEntry.cs b/src/SquidStd.Services.Core/Services/Internal/CronJobEntry.cs index 705f2f77..617ea42e 100644 --- a/src/SquidStd.Services.Core/Services/Internal/CronJobEntry.cs +++ b/src/SquidStd.Services.Core/Services/Internal/CronJobEntry.cs @@ -3,7 +3,7 @@ namespace SquidStd.Services.Core.Services.Internal; /// -/// Internal mutable state for a registered cron job. +/// Internal mutable state for a registered cron job. /// internal sealed class CronJobEntry { diff --git a/src/SquidStd.Services.Core/Services/Internal/DelegateCommandHandler.cs b/src/SquidStd.Services.Core/Services/Internal/DelegateCommandHandler.cs index 957f0db7..fe4674d9 100644 --- a/src/SquidStd.Services.Core/Services/Internal/DelegateCommandHandler.cs +++ b/src/SquidStd.Services.Core/Services/Internal/DelegateCommandHandler.cs @@ -3,8 +3,8 @@ namespace SquidStd.Services.Core.Services.Internal; /// -/// Adapts a delegate to so the dispatcher has a -/// single dispatch path. +/// Adapts a delegate to so the dispatcher has a +/// single dispatch path. /// /// The command type. /// The context type. @@ -19,7 +19,5 @@ public DelegateCommandHandler(Func } public Task HandleAsync(TCommand command, TContext context, CancellationToken cancellationToken = default) - { - return _handler(command, context, cancellationToken); - } + => _handler(command, context, cancellationToken); } diff --git a/src/SquidStd.Services.Core/Services/Internal/DelegateEventListener.cs b/src/SquidStd.Services.Core/Services/Internal/DelegateEventListener.cs index 3e64fa7b..7f966981 100644 --- a/src/SquidStd.Services.Core/Services/Internal/DelegateEventListener.cs +++ b/src/SquidStd.Services.Core/Services/Internal/DelegateEventListener.cs @@ -3,7 +3,7 @@ namespace SquidStd.Services.Core.Services.Internal; /// -/// Adapts a delegate handler to so the bus has a single dispatch path. +/// Adapts a delegate handler to so the bus has a single dispatch path. /// /// The event type. internal sealed class DelegateEventListener : IEventListener @@ -17,7 +17,5 @@ public DelegateEventListener(Func handler) } public Task HandleAsync(TEvent eventData, CancellationToken cancellationToken = default) - { - return _handler(eventData, cancellationToken); - } + => _handler(eventData, cancellationToken); } diff --git a/src/SquidStd.Services.Core/Services/Internal/JobItem.cs b/src/SquidStd.Services.Core/Services/Internal/JobItem.cs index 3e9f3014..71fd52ae 100644 --- a/src/SquidStd.Services.Core/Services/Internal/JobItem.cs +++ b/src/SquidStd.Services.Core/Services/Internal/JobItem.cs @@ -1,7 +1,7 @@ namespace SquidStd.Services.Core.Services.Internal; /// -/// Internal envelope for a scheduled job. +/// Internal envelope for a scheduled job. /// internal sealed class JobItem { @@ -17,12 +17,8 @@ public JobItem(Action run, Action cancel) } public void Cancel() - { - _cancel(); - } + => _cancel(); public void Run() - { - _run(); - } + => _run(); } diff --git a/src/SquidStd.Services.Core/Services/Internal/MainThreadSynchronizationContext.cs b/src/SquidStd.Services.Core/Services/Internal/MainThreadSynchronizationContext.cs index 01630bf6..65255cbf 100644 --- a/src/SquidStd.Services.Core/Services/Internal/MainThreadSynchronizationContext.cs +++ b/src/SquidStd.Services.Core/Services/Internal/MainThreadSynchronizationContext.cs @@ -3,7 +3,7 @@ namespace SquidStd.Services.Core.Services.Internal; /// -/// Synchronization context that forwards asynchronous posts to a main-thread dispatcher. +/// Synchronization context that forwards asynchronous posts to a main-thread dispatcher. /// internal sealed class MainThreadSynchronizationContext : SynchronizationContext { diff --git a/src/SquidStd.Services.Core/Services/Internal/Subscription.cs b/src/SquidStd.Services.Core/Services/Internal/Subscription.cs index 6264dcfd..a0753960 100644 --- a/src/SquidStd.Services.Core/Services/Internal/Subscription.cs +++ b/src/SquidStd.Services.Core/Services/Internal/Subscription.cs @@ -1,7 +1,7 @@ namespace SquidStd.Services.Core.Services.Internal; /// -/// Unsubscribe token that removes a listener from its bucket when disposed. +/// Unsubscribe token that removes a listener from its bucket when disposed. /// internal sealed class Subscription : IDisposable { diff --git a/src/SquidStd.Services.Core/Services/Internal/TimerEntry.cs b/src/SquidStd.Services.Core/Services/Internal/TimerEntry.cs index 88a5415a..d13435d3 100644 --- a/src/SquidStd.Services.Core/Services/Internal/TimerEntry.cs +++ b/src/SquidStd.Services.Core/Services/Internal/TimerEntry.cs @@ -1,7 +1,7 @@ namespace SquidStd.Services.Core.Services.Internal; /// -/// Internal mutable timer wheel entry. +/// Internal mutable timer wheel entry. /// internal sealed class TimerEntry { diff --git a/src/SquidStd.Services.Core/Services/JobSystemService.cs b/src/SquidStd.Services.Core/Services/JobSystemService.cs index b36ed572..07ae39d1 100644 --- a/src/SquidStd.Services.Core/Services/JobSystemService.cs +++ b/src/SquidStd.Services.Core/Services/JobSystemService.cs @@ -8,7 +8,7 @@ namespace SquidStd.Services.Core.Services; /// -/// Schedules jobs on a fixed set of worker threads. +/// Schedules jobs on a fixed set of worker threads. /// public sealed class JobSystemService : IJobSystem, ISquidStdService { @@ -36,7 +36,7 @@ public sealed class JobSystemService : IJobSystem, ISquidStdService public int WorkerCount { get; } /// - /// Initializes the job system service. + /// Initializes the job system service. /// /// Job system configuration. public JobSystemService(JobsConfig config) @@ -45,7 +45,7 @@ public JobSystemService(JobsConfig config) _config = config; WorkerCount = ResolveWorkerCount(config.WorkerThreadCount); _channel = Channel.CreateUnbounded( - new UnboundedChannelOptions + new() { SingleReader = false, SingleWriter = false @@ -200,9 +200,7 @@ private void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEv } private static int ResolveWorkerCount(int configured) - { - return configured > 0 ? configured : Math.Max(1, Environment.ProcessorCount - 1); - } + => configured > 0 ? configured : Math.Max(1, Environment.ProcessorCount - 1); private void Stop(CancellationToken cancellationToken) { @@ -315,10 +313,8 @@ private void WorkerLoop() } /// - /// Releases worker resources. + /// Releases worker resources. /// public void Dispose() - { - Stop(CancellationToken.None); - } + => Stop(CancellationToken.None); } diff --git a/src/SquidStd.Services.Core/Services/MainThreadDispatcherService.cs b/src/SquidStd.Services.Core/Services/MainThreadDispatcherService.cs index a6c84e6a..bbabe5e4 100644 --- a/src/SquidStd.Services.Core/Services/MainThreadDispatcherService.cs +++ b/src/SquidStd.Services.Core/Services/MainThreadDispatcherService.cs @@ -6,7 +6,7 @@ namespace SquidStd.Services.Core.Services; /// -/// Queues callbacks and drains them on the calling thread. +/// Queues callbacks and drains them on the calling thread. /// public sealed class MainThreadDispatcherService : IMainThreadDispatcher { diff --git a/src/SquidStd.Services.Core/Services/MetricsCollectionService.cs b/src/SquidStd.Services.Core/Services/MetricsCollectionService.cs index c34322fb..3d346482 100644 --- a/src/SquidStd.Services.Core/Services/MetricsCollectionService.cs +++ b/src/SquidStd.Services.Core/Services/MetricsCollectionService.cs @@ -9,7 +9,7 @@ namespace SquidStd.Services.Core.Services; /// -/// Periodically collects metrics from registered providers and stores the latest snapshot. +/// Periodically collects metrics from registered providers and stores the latest snapshot. /// public sealed class MetricsCollectionService : IMetricsCollectionService, ISquidStdService, IDisposable { @@ -31,7 +31,7 @@ public sealed class MetricsCollectionService : IMetricsCollectionService, ISquid private int _started; /// - /// Initializes the metrics collection service. + /// Initializes the metrics collection service. /// /// Metric providers to collect from. /// Metrics collection configuration. @@ -66,9 +66,7 @@ public MetricsSnapshot GetSnapshot() /// public MetricsSnapshot GetStatus() - { - return GetSnapshot(); - } + => GetSnapshot(); /// public ValueTask StartAsync(CancellationToken cancellationToken = default) @@ -89,7 +87,7 @@ public ValueTask StartAsync(CancellationToken cancellationToken = default) if (_lifetimeCts.IsCancellationRequested) { _lifetimeCts.Dispose(); - _lifetimeCts = new CancellationTokenSource(); + _lifetimeCts = new(); } _collectionTask = Task.Run(() => RunCollectionLoopAsync(_lifetimeCts.Token), _lifetimeCts.Token); @@ -113,9 +111,7 @@ public async ValueTask StopAsync(CancellationToken cancellationToken = default) { await _collectionTask; } - catch (OperationCanceledException) - { - } + catch (OperationCanceledException) { } } private async Task CollectOnceAsync(CancellationToken cancellationToken) @@ -161,10 +157,8 @@ private async Task CollectOnceAsync(CancellationToken cancellationToken) } private static string CreateMetricKey(string providerName, string metricName) - { - return string.IsNullOrWhiteSpace(providerName) ? metricName : - string.IsNullOrWhiteSpace(metricName) ? providerName : providerName + "." + metricName; - } + => string.IsNullOrWhiteSpace(providerName) ? metricName : + string.IsNullOrWhiteSpace(metricName) ? providerName : providerName + "." + metricName; private void LogProviderCollection(IMetricProvider provider, int metricCount) { @@ -225,7 +219,7 @@ private void ThrowIfDisposed() } /// - /// Releases metrics collection resources. + /// Releases metrics collection resources. /// public void Dispose() { @@ -242,9 +236,7 @@ public void Dispose() { _collectionTask.GetAwaiter().GetResult(); } - catch (OperationCanceledException) - { - } + catch (OperationCanceledException) { } } _lifetimeCts.Dispose(); diff --git a/src/SquidStd.Services.Core/Services/Scheduling/CronSchedulerService.cs b/src/SquidStd.Services.Core/Services/Scheduling/CronSchedulerService.cs index a4fe9da9..8045b477 100644 --- a/src/SquidStd.Services.Core/Services/Scheduling/CronSchedulerService.cs +++ b/src/SquidStd.Services.Core/Services/Scheduling/CronSchedulerService.cs @@ -11,9 +11,9 @@ namespace SquidStd.Services.Core.Services.Scheduling; /// -/// Cron scheduler built on the timer wheel: each job is a one-shot, self-rescheduling -/// timer. On fire, the handler is dispatched through ; an occurrence -/// is skipped when the previous run of the same job is still in flight. +/// Cron scheduler built on the timer wheel: each job is a one-shot, self-rescheduling +/// timer. On fire, the handler is dispatched through ; an occurrence +/// is skipped when the previous run of the same job is still in flight. /// public sealed class CronSchedulerService : ICronScheduler, ISquidStdService, IDisposable { @@ -27,18 +27,19 @@ public sealed class CronSchedulerService : ICronScheduler, ISquidStdService, IDi /// public IReadOnlyCollection Jobs => _entries.Values - .Select(entry => new CronJobInfo - { - JobId = entry.JobId, - Name = entry.Name, - CronExpression = entry.CronText, - NextOccurrenceUtc = entry.NextOccurrenceUtc, - IsRunning = Volatile.Read(ref entry.Running) == 1, - LastRunUtc = entry.LastRunUtc, - RunCount = Interlocked.Read(ref entry.RunCount) - } - ) - .ToArray(); + .Select( + entry => new CronJobInfo + { + JobId = entry.JobId, + Name = entry.Name, + CronExpression = entry.CronText, + NextOccurrenceUtc = entry.NextOccurrenceUtc, + IsRunning = Volatile.Read(ref entry.Running) == 1, + LastRunUtc = entry.LastRunUtc, + RunCount = Interlocked.Read(ref entry.RunCount) + } + ) + .ToArray(); public CronSchedulerService(ITimerService timer, IJobSystem jobs) { @@ -105,9 +106,7 @@ public int UnscheduleByName(string name) /// public ValueTask StartAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; /// public ValueTask StopAsync(CancellationToken cancellationToken = default) diff --git a/src/SquidStd.Services.Core/Services/Scheduling/TimerWheelPumpService.cs b/src/SquidStd.Services.Core/Services/Scheduling/TimerWheelPumpService.cs index ed849d08..c0f07ff1 100644 --- a/src/SquidStd.Services.Core/Services/Scheduling/TimerWheelPumpService.cs +++ b/src/SquidStd.Services.Core/Services/Scheduling/TimerWheelPumpService.cs @@ -7,9 +7,9 @@ namespace SquidStd.Services.Core.Services.Scheduling; /// -/// Periodically advances the timer wheel so that wheel-backed timers fire in a normal -/// (non-game-loop) application. Drives on a -/// background loop. +/// Periodically advances the timer wheel so that wheel-backed timers fire in a normal +/// (non-game-loop) application. Drives on a +/// background loop. /// public sealed class TimerWheelPumpService : ISquidStdService, IDisposable { diff --git a/src/SquidStd.Services.Core/Services/SeededCommandDispatcher.cs b/src/SquidStd.Services.Core/Services/SeededCommandDispatcher.cs index a9c4fd13..bc2a0161 100644 --- a/src/SquidStd.Services.Core/Services/SeededCommandDispatcher.cs +++ b/src/SquidStd.Services.Core/Services/SeededCommandDispatcher.cs @@ -4,9 +4,9 @@ namespace SquidStd.Services.Core.Services; /// -/// Seeded dispatcher that builds the context from a seed via an -/// and forwards to the underlying -/// . +/// Seeded dispatcher that builds the context from a seed via an +/// and forwards to the underlying +/// . /// /// The ambient context type. /// The seed the context is built from. @@ -26,10 +26,10 @@ ICommandContextFactory contextFactory /// public Task DispatchAsync( - TCommand command, TSeed seed, CancellationToken cancellationToken = default + TCommand command, + TSeed seed, + CancellationToken cancellationToken = default ) where TCommand : ICommand - { - return _dispatcher.DispatchAsync(command, _contextFactory.Create(seed), cancellationToken); - } + => _dispatcher.DispatchAsync(command, _contextFactory.Create(seed), cancellationToken); } diff --git a/src/SquidStd.Services.Core/Services/Storage/AesGcmSecretProtector.cs b/src/SquidStd.Services.Core/Services/Storage/AesGcmSecretProtector.cs index 0e740776..d1230cbf 100644 --- a/src/SquidStd.Services.Core/Services/Storage/AesGcmSecretProtector.cs +++ b/src/SquidStd.Services.Core/Services/Storage/AesGcmSecretProtector.cs @@ -7,7 +7,7 @@ namespace SquidStd.Services.Core.Services.Storage; /// -/// Protects secrets using AES-GCM and a key supplied by environment variable. +/// Protects secrets using AES-GCM and a key supplied by environment variable. /// public sealed class AesGcmSecretProtector : ISecretProtector { @@ -18,7 +18,7 @@ public sealed class AesGcmSecretProtector : ISecretProtector private readonly byte[] _key; /// - /// Initializes the AES-GCM secret protector. + /// Initializes the AES-GCM secret protector. /// /// Secret storage configuration. public AesGcmSecretProtector(SecretsConfig config) @@ -75,9 +75,7 @@ public byte[] Unprotect(byte[] protectedData) } private static byte[] CreateDefaultKey() - { - return SHA256.HashData(Encoding.UTF8.GetBytes(DefaultKeyMaterial)); - } + => SHA256.HashData(Encoding.UTF8.GetBytes(DefaultKeyMaterial)); private static byte[] ResolveKey(string environmentVariable) { @@ -107,7 +105,7 @@ private static byte[] ResolveKey(string environmentVariable) } return key.Length is 16 or 24 or 32 - ? key - : throw new InvalidOperationException("Secret key must be 16, 24, or 32 bytes after base64 decoding."); + ? key + : throw new InvalidOperationException("Secret key must be 16, 24, or 32 bytes after base64 decoding."); } } diff --git a/src/SquidStd.Services.Core/Services/Storage/FileSecretStore.cs b/src/SquidStd.Services.Core/Services/Storage/FileSecretStore.cs index e497ea51..c8b763d1 100644 --- a/src/SquidStd.Services.Core/Services/Storage/FileSecretStore.cs +++ b/src/SquidStd.Services.Core/Services/Storage/FileSecretStore.cs @@ -2,14 +2,13 @@ using System.Text; using SquidStd.Core.Data.Storage; using SquidStd.Core.Interfaces.Secrets; -using SquidStd.Storage.Abstractions.Data.Config; using SquidStd.Storage.Abstractions.Interfaces; using SquidStd.Storage.Services; namespace SquidStd.Services.Core.Services.Storage; /// -/// File-backed encrypted secret store. +/// File-backed encrypted secret store. /// public sealed class FileSecretStore : ISecretStore { @@ -17,7 +16,7 @@ public sealed class FileSecretStore : ISecretStore private readonly IStorageService _storageService; /// - /// Initializes the encrypted file secret store. + /// Initializes the encrypted file secret store. /// /// Secret storage configuration. /// Secret protector used for encryption. @@ -27,20 +26,16 @@ public FileSecretStore(SecretsConfig config, ISecretProtector secretProtector) ArgumentNullException.ThrowIfNull(secretProtector); _secretProtector = secretProtector; - _storageService = new FileStorageService(new StorageConfig { RootDirectory = config.RootDirectory }); + _storageService = new FileStorageService(new() { RootDirectory = config.RootDirectory }); } /// public ValueTask DeleteAsync(string name, CancellationToken cancellationToken = default) - { - return _storageService.DeleteAsync(ToStorageKey(name), cancellationToken); - } + => _storageService.DeleteAsync(ToStorageKey(name), cancellationToken); /// public ValueTask ExistsAsync(string name, CancellationToken cancellationToken = default) - { - return _storageService.ExistsAsync(ToStorageKey(name), cancellationToken); - } + => _storageService.ExistsAsync(ToStorageKey(name), cancellationToken); /// public async ValueTask GetAsync(string name, CancellationToken cancellationToken = default) @@ -70,7 +65,8 @@ public async ValueTask SetAsync(string name, string value, CancellationToken can /// public async IAsyncEnumerable ListNamesAsync( - string? prefix = null, [EnumeratorCancellation] CancellationToken cancellationToken = default + string? prefix = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default ) { const string suffix = ".secret"; diff --git a/src/SquidStd.Services.Core/Services/TimerWheelService.cs b/src/SquidStd.Services.Core/Services/TimerWheelService.cs index c26f2bcf..76703d65 100644 --- a/src/SquidStd.Services.Core/Services/TimerWheelService.cs +++ b/src/SquidStd.Services.Core/Services/TimerWheelService.cs @@ -8,7 +8,7 @@ namespace SquidStd.Services.Core.Services; /// -/// Hashed timer wheel driven by absolute timestamp updates. +/// Hashed timer wheel driven by absolute timestamp updates. /// public sealed class TimerWheelService : ITimerService, ISquidStdService { @@ -24,7 +24,7 @@ public sealed class TimerWheelService : ITimerService, ISquidStdService private long _lastTimestampMilliseconds = -1; /// - /// Initializes the timer wheel service. + /// Initializes the timer wheel service. /// /// Timer wheel configuration. public TimerWheelService(TimerWheelConfig config) @@ -53,15 +53,13 @@ public TimerWheelService(TimerWheelConfig config) for (var i = 0; i < _wheel.Length; i++) { - _wheel[i] = new LinkedList(); + _wheel[i] = new(); } } /// public ValueTask StartAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; /// public ValueTask StopAsync(CancellationToken cancellationToken = default) diff --git a/src/SquidStd.Services.Core/Types/BootstrapStateType.cs b/src/SquidStd.Services.Core/Types/BootstrapStateType.cs index a6a59707..2b1d72ff 100644 --- a/src/SquidStd.Services.Core/Types/BootstrapStateType.cs +++ b/src/SquidStd.Services.Core/Types/BootstrapStateType.cs @@ -1,7 +1,7 @@ namespace SquidStd.Services.Core.Types; /// -/// Lifecycle state of the SquidStd bootstrapper. +/// Lifecycle state of the SquidStd bootstrapper. /// internal enum BootstrapStateType { diff --git a/src/SquidStd.Storage.Abstractions/Data/Config/StorageConfig.cs b/src/SquidStd.Storage.Abstractions/Data/Config/StorageConfig.cs index 2fda7e43..d75be728 100644 --- a/src/SquidStd.Storage.Abstractions/Data/Config/StorageConfig.cs +++ b/src/SquidStd.Storage.Abstractions/Data/Config/StorageConfig.cs @@ -3,12 +3,12 @@ namespace SquidStd.Storage.Abstractions.Data.Config; /// -/// Configuration for local file storage. +/// Configuration for local file storage. /// public sealed class StorageConfig : IConfigEntry { /// - /// Gets or sets the root directory used by local storage. + /// Gets or sets the root directory used by local storage. /// public string RootDirectory { get; set; } = "storage"; @@ -17,7 +17,5 @@ public sealed class StorageConfig : IConfigEntry Type IConfigEntry.ConfigType => typeof(StorageConfig); object IConfigEntry.CreateDefault() - { - return new StorageConfig(); - } + => new StorageConfig(); } diff --git a/src/SquidStd.Storage.Abstractions/Interfaces/IObjectStorageService.cs b/src/SquidStd.Storage.Abstractions/Interfaces/IObjectStorageService.cs index b2e4a504..580e98d0 100644 --- a/src/SquidStd.Storage.Abstractions/Interfaces/IObjectStorageService.cs +++ b/src/SquidStd.Storage.Abstractions/Interfaces/IObjectStorageService.cs @@ -1,12 +1,12 @@ namespace SquidStd.Storage.Abstractions.Interfaces; /// -/// Stores typed objects by logical key. +/// Stores typed objects by logical key. /// public interface IObjectStorageService { /// - /// Deletes a stored object. + /// Deletes a stored object. /// /// The logical storage key. /// Token used to cancel the operation. @@ -14,7 +14,7 @@ public interface IObjectStorageService ValueTask DeleteAsync(string key, CancellationToken cancellationToken = default); /// - /// Checks whether an object exists. + /// Checks whether an object exists. /// /// The logical storage key. /// Token used to cancel the operation. @@ -22,7 +22,7 @@ public interface IObjectStorageService ValueTask ExistsAsync(string key, CancellationToken cancellationToken = default); /// - /// Enumerates stored keys, optionally filtered by prefix. + /// Enumerates stored keys, optionally filtered by prefix. /// /// Optional key prefix; null or empty returns all keys. /// Token used to cancel the enumeration. @@ -30,7 +30,7 @@ public interface IObjectStorageService IAsyncEnumerable ListKeysAsync(string? prefix = null, CancellationToken cancellationToken = default); /// - /// Loads a stored object. + /// Loads a stored object. /// /// The logical storage key. /// Token used to cancel the operation. @@ -39,7 +39,7 @@ public interface IObjectStorageService ValueTask LoadAsync(string key, CancellationToken cancellationToken = default); /// - /// Saves an object. + /// Saves an object. /// /// The logical storage key. /// The object value. diff --git a/src/SquidStd.Storage.Abstractions/Interfaces/IStorageService.cs b/src/SquidStd.Storage.Abstractions/Interfaces/IStorageService.cs index 6b469e5d..b307f2aa 100644 --- a/src/SquidStd.Storage.Abstractions/Interfaces/IStorageService.cs +++ b/src/SquidStd.Storage.Abstractions/Interfaces/IStorageService.cs @@ -1,12 +1,12 @@ namespace SquidStd.Storage.Abstractions.Interfaces; /// -/// Stores binary payloads by logical key. +/// Stores binary payloads by logical key. /// public interface IStorageService { /// - /// Deletes a stored payload. + /// Deletes a stored payload. /// /// The logical storage key. /// Token used to cancel the operation. @@ -14,7 +14,7 @@ public interface IStorageService ValueTask DeleteAsync(string key, CancellationToken cancellationToken = default); /// - /// Checks whether a payload exists. + /// Checks whether a payload exists. /// /// The logical storage key. /// Token used to cancel the operation. @@ -22,7 +22,7 @@ public interface IStorageService ValueTask ExistsAsync(string key, CancellationToken cancellationToken = default); /// - /// Enumerates stored keys, optionally filtered by prefix. + /// Enumerates stored keys, optionally filtered by prefix. /// /// Optional key prefix; null or empty returns all keys. /// Token used to cancel the enumeration. @@ -30,7 +30,7 @@ public interface IStorageService IAsyncEnumerable ListKeysAsync(string? prefix = null, CancellationToken cancellationToken = default); /// - /// Loads a binary payload. + /// Loads a binary payload. /// /// The logical storage key. /// Token used to cancel the operation. @@ -38,7 +38,7 @@ public interface IStorageService ValueTask LoadAsync(string key, CancellationToken cancellationToken = default); /// - /// Saves a binary payload atomically. + /// Saves a binary payload atomically. /// /// The logical storage key. /// The payload to store. diff --git a/src/SquidStd.Storage.Abstractions/README.md b/src/SquidStd.Storage.Abstractions/README.md index 24268d7f..fbd6e858 100644 --- a/src/SquidStd.Storage.Abstractions/README.md +++ b/src/SquidStd.Storage.Abstractions/README.md @@ -27,11 +27,11 @@ public async Task DumpKeysAsync(IStorageService storage) ## Key types -| Type | Purpose | -|------|---------| -| `IStorageService` | Binary blob store: `SaveAsync` / `LoadAsync` / `DeleteAsync` / `ExistsAsync` / `ListKeysAsync`. | -| `IObjectStorageService` | Typed object store over a blob backend (serialized by the provider). | -| `StorageConfig` | Root directory for file storage. | +| Type | Purpose | +|-------------------------|-------------------------------------------------------------------------------------------------| +| `IStorageService` | Binary blob store: `SaveAsync` / `LoadAsync` / `DeleteAsync` / `ExistsAsync` / `ListKeysAsync`. | +| `IObjectStorageService` | Typed object store over a blob backend (serialized by the provider). | +| `StorageConfig` | Root directory for file storage. | ## Related diff --git a/src/SquidStd.Storage.S3/Data/Config/S3StorageOptions.cs b/src/SquidStd.Storage.S3/Data/Config/S3StorageOptions.cs index c26069bc..071ae4d3 100644 --- a/src/SquidStd.Storage.S3/Data/Config/S3StorageOptions.cs +++ b/src/SquidStd.Storage.S3/Data/Config/S3StorageOptions.cs @@ -3,8 +3,8 @@ namespace SquidStd.Storage.S3.Data.Config; /// -/// Connection options for the S3-compatible (MinIO) storage provider. Connection details live in -/// (shared with other AWS-SDK providers); is storage-specific. +/// Connection options for the S3-compatible (MinIO) storage provider. Connection details live in +/// (shared with other AWS-SDK providers); is storage-specific. /// public sealed class S3StorageOptions { diff --git a/src/SquidStd.Storage.S3/Extensions/S3StorageRegistrationExtensions.cs b/src/SquidStd.Storage.S3/Extensions/S3StorageRegistrationExtensions.cs index 0fe1eff8..14fc320a 100644 --- a/src/SquidStd.Storage.S3/Extensions/S3StorageRegistrationExtensions.cs +++ b/src/SquidStd.Storage.S3/Extensions/S3StorageRegistrationExtensions.cs @@ -6,7 +6,7 @@ namespace SquidStd.Storage.S3.Extensions; /// -/// DryIoc registration helpers for the S3-compatible (MinIO) storage provider. +/// DryIoc registration helpers for the S3-compatible (MinIO) storage provider. /// public static class S3StorageRegistrationExtensions { diff --git a/src/SquidStd.Storage.S3/README.md b/src/SquidStd.Storage.S3/README.md index f3d74062..ab43cd5b 100644 --- a/src/SquidStd.Storage.S3/README.md +++ b/src/SquidStd.Storage.S3/README.md @@ -35,11 +35,11 @@ await storage.SaveAsync("reports/2026.json", "{}"u8.ToArray()); ## Key types -| Type | Purpose | -|------|---------| -| `S3StorageRegistrationExtensions` | `AddS3Storage(...)` registration. | -| `S3StorageService` | MinIO-backed `IStorageService` with lazy bucket creation. | -| `S3StorageOptions` | Endpoint, credentials, bucket, TLS, region. | +| Type | Purpose | +|-----------------------------------|-----------------------------------------------------------| +| `S3StorageRegistrationExtensions` | `AddS3Storage(...)` registration. | +| `S3StorageService` | MinIO-backed `IStorageService` with lazy bucket creation. | +| `S3StorageOptions` | Endpoint, credentials, bucket, TLS, region. | ## Related diff --git a/src/SquidStd.Storage.S3/Services/S3StorageService.cs b/src/SquidStd.Storage.S3/Services/S3StorageService.cs index 2743d637..59e005af 100644 --- a/src/SquidStd.Storage.S3/Services/S3StorageService.cs +++ b/src/SquidStd.Storage.S3/Services/S3StorageService.cs @@ -8,8 +8,8 @@ namespace SquidStd.Storage.S3.Services; /// -/// S3-compatible backed by the MinIO client. The bucket is created -/// lazily on first use. +/// S3-compatible backed by the MinIO client. The bucket is created +/// lazily on first use. /// public sealed class S3StorageService : IStorageService, IDisposable { @@ -139,9 +139,9 @@ private static IMinioClient CreateClient(S3StorageOptions options) var endpoint = uri.IsDefaultPort ? uri.Host : $"{uri.Host}:{uri.Port}"; var minio = new MinioClient() - .WithEndpoint(endpoint) - .WithCredentials(options.Aws.AccessKey, options.Aws.SecretKey) - .WithSSL(string.Equals(uri.Scheme, "https", StringComparison.OrdinalIgnoreCase)); + .WithEndpoint(endpoint) + .WithCredentials(options.Aws.AccessKey, options.Aws.SecretKey) + .WithSSL(string.Equals(uri.Scheme, "https", StringComparison.OrdinalIgnoreCase)); if (!string.IsNullOrWhiteSpace(options.Aws.Region)) { diff --git a/src/SquidStd.Storage/Extensions/StorageRegistrationExtensions.cs b/src/SquidStd.Storage/Extensions/StorageRegistrationExtensions.cs index 078d0711..8560d300 100644 --- a/src/SquidStd.Storage/Extensions/StorageRegistrationExtensions.cs +++ b/src/SquidStd.Storage/Extensions/StorageRegistrationExtensions.cs @@ -6,7 +6,7 @@ namespace SquidStd.Storage.Extensions; /// -/// DryIoc registration helpers for the local file storage provider. +/// DryIoc registration helpers for the local file storage provider. /// public static class StorageRegistrationExtensions { diff --git a/src/SquidStd.Storage/Internal/StoragePathResolver.cs b/src/SquidStd.Storage/Internal/StoragePathResolver.cs index 2ee06091..8e357434 100644 --- a/src/SquidStd.Storage/Internal/StoragePathResolver.cs +++ b/src/SquidStd.Storage/Internal/StoragePathResolver.cs @@ -1,7 +1,7 @@ namespace SquidStd.Storage.Internal; /// -/// Resolves logical storage keys into paths constrained to one root directory. +/// Resolves logical storage keys into paths constrained to one root directory. /// internal static class StoragePathResolver { @@ -40,8 +40,8 @@ public static string ResolveFilePath(string rootDirectory, string key, string? e var fullPath = Path.GetFullPath(Path.Combine(normalizedRoot, relativePath)); var rootPrefix = normalizedRoot.EndsWith(Path.DirectorySeparatorChar) - ? normalizedRoot - : normalizedRoot + Path.DirectorySeparatorChar; + ? normalizedRoot + : normalizedRoot + Path.DirectorySeparatorChar; if (!fullPath.StartsWith(rootPrefix, StringComparison.Ordinal)) { diff --git a/src/SquidStd.Storage/README.md b/src/SquidStd.Storage/README.md index c3fdf955..a16f0537 100644 --- a/src/SquidStd.Storage/README.md +++ b/src/SquidStd.Storage/README.md @@ -30,11 +30,11 @@ enumerates stored keys (`/`-separated), excluding in-flight temp files. ## Key types -| Type | Purpose | -|------|---------| +| Type | Purpose | +|---------------------------------|---------------------------------------------------------------------------------------------| | `StorageRegistrationExtensions` | `AddFileStorage(...)` registration (file `IStorageService` + YAML `IObjectStorageService`). | -| `FileStorageService` | Filesystem-backed `IStorageService`. | -| `YamlObjectStorageService` | YAML-backed `IObjectStorageService` over a blob store. | +| `FileStorageService` | Filesystem-backed `IStorageService`. | +| `YamlObjectStorageService` | YAML-backed `IObjectStorageService` over a blob store. | ## Related diff --git a/src/SquidStd.Storage/Services/FileStorageService.cs b/src/SquidStd.Storage/Services/FileStorageService.cs index 74118821..94c75417 100644 --- a/src/SquidStd.Storage/Services/FileStorageService.cs +++ b/src/SquidStd.Storage/Services/FileStorageService.cs @@ -6,14 +6,14 @@ namespace SquidStd.Storage.Services; /// -/// Local file-backed binary storage. +/// Local file-backed binary storage. /// public sealed class FileStorageService : IStorageService { private readonly string _rootDirectory; /// - /// Initializes local file storage. + /// Initializes local file storage. /// /// Storage configuration. public FileStorageService(StorageConfig config) @@ -126,7 +126,5 @@ public async ValueTask SaveAsync( } private string ResolvePath(string key) - { - return StoragePathResolver.ResolveFilePath(_rootDirectory, key); - } + => StoragePathResolver.ResolveFilePath(_rootDirectory, key); } diff --git a/src/SquidStd.Storage/Services/YamlObjectStorageService.cs b/src/SquidStd.Storage/Services/YamlObjectStorageService.cs index 619ab586..6bc30acb 100644 --- a/src/SquidStd.Storage/Services/YamlObjectStorageService.cs +++ b/src/SquidStd.Storage/Services/YamlObjectStorageService.cs @@ -5,14 +5,14 @@ namespace SquidStd.Storage.Services; /// -/// YAML object storage built on top of binary storage. +/// YAML object storage built on top of binary storage. /// public sealed class YamlObjectStorageService : IObjectStorageService { private readonly IStorageService _storageService; /// - /// Initializes YAML object storage. + /// Initializes YAML object storage. /// /// Underlying binary storage service. public YamlObjectStorageService(IStorageService storageService) @@ -22,21 +22,15 @@ public YamlObjectStorageService(IStorageService storageService) /// public ValueTask DeleteAsync(string key, CancellationToken cancellationToken = default) - { - return _storageService.DeleteAsync(key, cancellationToken); - } + => _storageService.DeleteAsync(key, cancellationToken); /// public ValueTask ExistsAsync(string key, CancellationToken cancellationToken = default) - { - return _storageService.ExistsAsync(key, cancellationToken); - } + => _storageService.ExistsAsync(key, cancellationToken); /// public IAsyncEnumerable ListKeysAsync(string? prefix = null, CancellationToken cancellationToken = default) - { - return _storageService.ListKeysAsync(prefix, cancellationToken); - } + => _storageService.ListKeysAsync(prefix, cancellationToken); /// public async ValueTask LoadAsync(string key, CancellationToken cancellationToken = default) diff --git a/src/SquidStd.Telemetry.Abstractions/README.md b/src/SquidStd.Telemetry.Abstractions/README.md index 5f1405dd..b475f626 100644 --- a/src/SquidStd.Telemetry.Abstractions/README.md +++ b/src/SquidStd.Telemetry.Abstractions/README.md @@ -25,11 +25,11 @@ captures every `SquidStd.*` source automatically. ## Key types -| Type | Purpose | -|------|---------| +| Type | Purpose | +|--------------------|----------------------------------------------------------------------------| | `TelemetryOptions` | Service name, OTLP endpoint/protocol, sampling and exporter configuration. | -| `OtlpProtocolType` | OTLP transport: gRPC or HTTP. | -| `SquidStdActivity` | Shared `ActivitySource` and the `SquidStd.*` source naming convention. | +| `OtlpProtocolType` | OTLP transport: gRPC or HTTP. | +| `SquidStdActivity` | Shared `ActivitySource` and the `SquidStd.*` source naming convention. | ## License diff --git a/src/SquidStd.Telemetry.Abstractions/SquidStdActivity.cs b/src/SquidStd.Telemetry.Abstractions/SquidStdActivity.cs index aa60d76c..bba30264 100644 --- a/src/SquidStd.Telemetry.Abstractions/SquidStdActivity.cs +++ b/src/SquidStd.Telemetry.Abstractions/SquidStdActivity.cs @@ -3,8 +3,8 @@ namespace SquidStd.Telemetry.Abstractions; /// -/// Well-known SquidStd ActivitySource for app-level custom spans. SquidStd subsystems name their own -/// sources with the "SquidStd." prefix; the OpenTelemetry provider captures them via "SquidStd.*". +/// Well-known SquidStd ActivitySource for app-level custom spans. SquidStd subsystems name their own +/// sources with the "SquidStd." prefix; the OpenTelemetry provider captures them via "SquidStd.*". /// public static class SquidStdActivity { diff --git a/src/SquidStd.Telemetry.OpenTelemetry/Extensions/OpenTelemetryServiceCollectionExtensions.cs b/src/SquidStd.Telemetry.OpenTelemetry/Extensions/OpenTelemetryServiceCollectionExtensions.cs index 6cb28a17..a4203d5d 100644 --- a/src/SquidStd.Telemetry.OpenTelemetry/Extensions/OpenTelemetryServiceCollectionExtensions.cs +++ b/src/SquidStd.Telemetry.OpenTelemetry/Extensions/OpenTelemetryServiceCollectionExtensions.cs @@ -24,7 +24,8 @@ public IServiceCollection AddSquidStdTelemetry(TelemetryOptions options) if (options.EnableTracing) { - builder.WithTracing(tracing => + builder.WithTracing( + tracing => { TelemetryPipeline.ConfigureTracing(tracing, options, true); TelemetryPipeline.AddTraceExporters(tracing, options); @@ -35,7 +36,8 @@ public IServiceCollection AddSquidStdTelemetry(TelemetryOptions options) if (options.EnableMetrics) { services.AddHostedService(); - builder.WithMetrics(metrics => + builder.WithMetrics( + metrics => { TelemetryPipeline.ConfigureMetrics(metrics, options); TelemetryPipeline.AddMetricExporters(metrics, options); diff --git a/src/SquidStd.Telemetry.OpenTelemetry/Internal/MetricsBridgeActivator.cs b/src/SquidStd.Telemetry.OpenTelemetry/Internal/MetricsBridgeActivator.cs index a215f6c7..fd8e8c76 100644 --- a/src/SquidStd.Telemetry.OpenTelemetry/Internal/MetricsBridgeActivator.cs +++ b/src/SquidStd.Telemetry.OpenTelemetry/Internal/MetricsBridgeActivator.cs @@ -4,8 +4,8 @@ namespace SquidStd.Telemetry.OpenTelemetry.Internal; /// -/// Warms the at host start so its observable instruments exist -/// for the MeterProvider's first collection (ASP.NET Core host path). +/// Warms the at host start so its observable instruments exist +/// for the MeterProvider's first collection (ASP.NET Core host path). /// internal sealed class MetricsBridgeActivator : IHostedService { @@ -24,7 +24,5 @@ public Task StartAsync(CancellationToken cancellationToken) } public Task StopAsync(CancellationToken cancellationToken) - { - return Task.CompletedTask; - } + => Task.CompletedTask; } diff --git a/src/SquidStd.Telemetry.OpenTelemetry/Internal/TelemetryPipeline.cs b/src/SquidStd.Telemetry.OpenTelemetry/Internal/TelemetryPipeline.cs index 07623277..4649d044 100644 --- a/src/SquidStd.Telemetry.OpenTelemetry/Internal/TelemetryPipeline.cs +++ b/src/SquidStd.Telemetry.OpenTelemetry/Internal/TelemetryPipeline.cs @@ -11,17 +11,18 @@ namespace SquidStd.Telemetry.OpenTelemetry.Internal; /// -/// Shared OpenTelemetry pipeline configuration, used by both the IContainer and IServiceCollection -/// registration surfaces. Instrumentation/source configuration is split from exporter configuration so -/// tests can reuse the production pipeline and append an in-memory exporter. +/// Shared OpenTelemetry pipeline configuration, used by both the IContainer and IServiceCollection +/// registration surfaces. Instrumentation/source configuration is split from exporter configuration so +/// tests can reuse the production pipeline and append an in-memory exporter. /// internal static class TelemetryPipeline { public static void AddMetricExporters(MeterProviderBuilder builder, TelemetryOptions options) { - builder.AddOtlpExporter(o => + builder.AddOtlpExporter( + o => { - o.Endpoint = new Uri(options.OtlpEndpoint); + o.Endpoint = new(options.OtlpEndpoint); o.Protocol = Map(options.OtlpProtocol); } ); @@ -34,9 +35,10 @@ public static void AddMetricExporters(MeterProviderBuilder builder, TelemetryOpt public static void AddTraceExporters(TracerProviderBuilder builder, TelemetryOptions options) { - builder.AddOtlpExporter(o => + builder.AddOtlpExporter( + o => { - o.Endpoint = new Uri(options.OtlpEndpoint); + o.Endpoint = new(options.OtlpEndpoint); o.Protocol = Map(options.OtlpProtocol); } ); @@ -64,12 +66,10 @@ public static ResourceBuilder BuildResource(TelemetryOptions options) } public static void ConfigureMetrics(MeterProviderBuilder builder, TelemetryOptions options) - { - builder - .SetResourceBuilder(BuildResource(options)) - .AddRuntimeInstrumentation() - .AddMeter(MetricsSnapshotBridge.MeterName); - } + => builder + .SetResourceBuilder(BuildResource(options)) + .AddRuntimeInstrumentation() + .AddMeter(MetricsSnapshotBridge.MeterName); public static void ConfigureTracing(TracerProviderBuilder builder, TelemetryOptions options, bool includeAspNetCore) { @@ -87,7 +87,5 @@ public static void ConfigureTracing(TracerProviderBuilder builder, TelemetryOpti } public static OtlpExportProtocol Map(OtlpProtocolType protocol) - { - return protocol == OtlpProtocolType.HttpProtobuf ? OtlpExportProtocol.HttpProtobuf : OtlpExportProtocol.Grpc; - } + => protocol == OtlpProtocolType.HttpProtobuf ? OtlpExportProtocol.HttpProtobuf : OtlpExportProtocol.Grpc; } diff --git a/src/SquidStd.Telemetry.OpenTelemetry/README.md b/src/SquidStd.Telemetry.OpenTelemetry/README.md index 82c9c48d..1927c527 100644 --- a/src/SquidStd.Telemetry.OpenTelemetry/README.md +++ b/src/SquidStd.Telemetry.OpenTelemetry/README.md @@ -38,12 +38,12 @@ builder.Services.AddSquidStdTelemetry(new TelemetryOptions { ServiceName = "orde ## Key types -| Type | Purpose | -|------|---------| -| `OpenTelemetryContainerExtensions` | `AddSquidStdTelemetry(...)` for the DryIoc/worker host. | -| `OpenTelemetryServiceCollectionExtensions` | `AddSquidStdTelemetry(...)` for the ASP.NET Core host. | -| `TelemetryService` | Configures tracing/metrics providers and exporters from `TelemetryOptions`. | -| `MetricsSnapshotBridge` | Exports the existing SquidStd metrics snapshot to OTel instruments. | +| Type | Purpose | +|--------------------------------------------|-----------------------------------------------------------------------------| +| `OpenTelemetryContainerExtensions` | `AddSquidStdTelemetry(...)` for the DryIoc/worker host. | +| `OpenTelemetryServiceCollectionExtensions` | `AddSquidStdTelemetry(...)` for the ASP.NET Core host. | +| `TelemetryService` | Configures tracing/metrics providers and exporters from `TelemetryOptions`. | +| `MetricsSnapshotBridge` | Exports the existing SquidStd metrics snapshot to OTel instruments. | ## License diff --git a/src/SquidStd.Telemetry.OpenTelemetry/Services/MetricsSnapshotBridge.cs b/src/SquidStd.Telemetry.OpenTelemetry/Services/MetricsSnapshotBridge.cs index a803dbb3..d6e8ec7f 100644 --- a/src/SquidStd.Telemetry.OpenTelemetry/Services/MetricsSnapshotBridge.cs +++ b/src/SquidStd.Telemetry.OpenTelemetry/Services/MetricsSnapshotBridge.cs @@ -6,9 +6,9 @@ namespace SquidStd.Telemetry.OpenTelemetry.Services; /// -/// Bridges the SquidStd metrics snapshot () to OpenTelemetry -/// observable instruments: counters become observable counters, everything else an observable gauge, -/// each callback reading the latest snapshot value for its metric name. +/// Bridges the SquidStd metrics snapshot () to OpenTelemetry +/// observable instruments: counters become observable counters, everything else an observable gauge, +/// each callback reading the latest snapshot value for its metric name. /// public sealed class MetricsSnapshotBridge : IDisposable { @@ -24,7 +24,7 @@ public sealed class MetricsSnapshotBridge : IDisposable public MetricsSnapshotBridge(IMetricsCollectionService metrics) { _metrics = metrics; - _meter = new Meter(MeterName); + _meter = new(MeterName); EnsureInstruments(); } @@ -57,10 +57,10 @@ private IEnumerable> Observe(string name) } var tags = sample.Tags is { Count: > 0 } - ? sample.Tags.Select(kv => new KeyValuePair(kv.Key, kv.Value)).ToArray() - : []; + ? sample.Tags.Select(kv => new KeyValuePair(kv.Key, kv.Value)).ToArray() + : []; - return [new Measurement(sample.Value, tags)]; + return [new(sample.Value, tags)]; } public void Dispose() diff --git a/src/SquidStd.Telemetry.OpenTelemetry/Services/TelemetryService.cs b/src/SquidStd.Telemetry.OpenTelemetry/Services/TelemetryService.cs index 98b73969..d2595a1d 100644 --- a/src/SquidStd.Telemetry.OpenTelemetry/Services/TelemetryService.cs +++ b/src/SquidStd.Telemetry.OpenTelemetry/Services/TelemetryService.cs @@ -9,8 +9,8 @@ namespace SquidStd.Telemetry.OpenTelemetry.Services; /// -/// Owns the OpenTelemetry TracerProvider/MeterProvider for non-web (DryIoc/worker) hosts, building -/// them on start and disposing (flushing) them on stop. Telemetry failures never crash the host. +/// Owns the OpenTelemetry TracerProvider/MeterProvider for non-web (DryIoc/worker) hosts, building +/// them on start and disposing (flushing) them on stop. Telemetry failures never crash the host. /// public sealed class TelemetryService : ISquidStdService, IDisposable { diff --git a/src/SquidStd.Templating/Extensions/TemplatingRegistrationExtensions.cs b/src/SquidStd.Templating/Extensions/TemplatingRegistrationExtensions.cs index 730ed9ee..6c7260fe 100644 --- a/src/SquidStd.Templating/Extensions/TemplatingRegistrationExtensions.cs +++ b/src/SquidStd.Templating/Extensions/TemplatingRegistrationExtensions.cs @@ -6,15 +6,15 @@ namespace SquidStd.Templating.Extensions; /// -/// DryIoc registration helpers for the templating module. +/// DryIoc registration helpers for the templating module. /// public static class TemplatingRegistrationExtensions { extension(IContainer container) { /// - /// Registers the Scriban template renderer as a singleton SquidStd service (so its startup - /// auto-load of templates/*.tmpl runs with the host). Requires a registered DirectoriesConfig. + /// Registers the Scriban template renderer as a singleton SquidStd service (so its startup + /// auto-load of templates/*.tmpl runs with the host). Requires a registered DirectoriesConfig. /// public IContainer AddTemplating() { diff --git a/src/SquidStd.Templating/Interfaces/ITemplateRenderer.cs b/src/SquidStd.Templating/Interfaces/ITemplateRenderer.cs index 48457e9d..f947933f 100644 --- a/src/SquidStd.Templating/Interfaces/ITemplateRenderer.cs +++ b/src/SquidStd.Templating/Interfaces/ITemplateRenderer.cs @@ -1,7 +1,7 @@ namespace SquidStd.Templating.Interfaces; /// -/// Renders Scriban templates from strings or registered named templates. +/// Renders Scriban templates from strings or registered named templates. /// public interface ITemplateRenderer { diff --git a/src/SquidStd.Templating/Services/ScribanTemplateRenderer.cs b/src/SquidStd.Templating/Services/ScribanTemplateRenderer.cs index e066c41e..532cb1d4 100644 --- a/src/SquidStd.Templating/Services/ScribanTemplateRenderer.cs +++ b/src/SquidStd.Templating/Services/ScribanTemplateRenderer.cs @@ -8,8 +8,8 @@ namespace SquidStd.Templating.Services; /// -/// Scriban-backed . Named templates are compiled and cached; ad-hoc -/// strings are parsed per call. On start it auto-loads templates/**/*.tmpl. +/// Scriban-backed . Named templates are compiled and cached; ad-hoc +/// strings are parsed per call. On start it auto-loads templates/**/*.tmpl. /// public sealed class ScribanTemplateRenderer : ITemplateRenderer, ISquidStdService { @@ -45,9 +45,7 @@ public async ValueTask StartAsync(CancellationToken cancellationToken = default) /// public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; /// public void Register(string name, string template) diff --git a/src/SquidStd.Templating/TemplateException.cs b/src/SquidStd.Templating/TemplateException.cs index 383b31e4..6ceb4f3e 100644 --- a/src/SquidStd.Templating/TemplateException.cs +++ b/src/SquidStd.Templating/TemplateException.cs @@ -1,17 +1,13 @@ namespace SquidStd.Templating; /// -/// Raised when a template fails to parse or render. +/// Raised when a template fails to parse or render. /// public sealed class TemplateException : Exception { public TemplateException(string message) - : base(message) - { - } + : base(message) { } public TemplateException(string message, Exception innerException) - : base(message, innerException) - { - } + : base(message, innerException) { } } diff --git a/src/SquidStd.Tui/Binding/ViewBinder.AutoBind.cs b/src/SquidStd.Tui/Binding/ViewBinder.AutoBind.cs index 55c69aaa..056642ed 100644 --- a/src/SquidStd.Tui/Binding/ViewBinder.AutoBind.cs +++ b/src/SquidStd.Tui/Binding/ViewBinder.AutoBind.cs @@ -31,12 +31,15 @@ public void AutoBind(View view, INotifyPropertyChanged viewModel) { case Button button: BindCommandByName(vmType, viewModel, ConventionNames.CommandName(id), button); + break; case TextField field: - BindStringByName(vmType, viewModel, ConventionNames.MemberName(id), field, twoWay: true, null); + BindStringByName(vmType, viewModel, ConventionNames.MemberName(id), field, true, null); + break; case Label label: - BindStringByName(vmType, viewModel, ConventionNames.MemberName(id), null, twoWay: false, label); + BindStringByName(vmType, viewModel, ConventionNames.MemberName(id), null, false, label); + break; } } @@ -53,7 +56,12 @@ private void BindCommandByName(Type vmType, INotifyPropertyChanged vm, string me } private void BindStringByName( - Type vmType, INotifyPropertyChanged vm, string memberName, TextField? field, bool twoWay, Label? label + Type vmType, + INotifyPropertyChanged vm, + string memberName, + TextField? field, + bool twoWay, + Label? label ) { var property = vmType.GetProperty(memberName, BindingFlags.Public | BindingFlags.Instance); diff --git a/src/SquidStd.Tui/Binding/ViewBinder.Widgets.cs b/src/SquidStd.Tui/Binding/ViewBinder.Widgets.cs index 7755e43e..433555a0 100644 --- a/src/SquidStd.Tui/Binding/ViewBinder.Widgets.cs +++ b/src/SquidStd.Tui/Binding/ViewBinder.Widgets.cs @@ -11,32 +11,26 @@ public sealed partial class ViewBinder /// One-way bind a source string property to a 's text. public void OneWayText(TSource source, Expression> property, Label label) where TSource : INotifyPropertyChanged - { - OneWay(source, property, label, l => l.Text); - } + => OneWay(source, property, label, l => l.Text); /// One-way bind a source string property to a 's title. public void OneWayTitle(TSource source, Expression> property, Window window) where TSource : INotifyPropertyChanged - { - OneWay(source, property, window, w => w.Title); - } + => OneWay(source, property, window, w => w.Title); /// Two-way bind a source string property to a . public void TwoWay(TSource source, Expression> property, TextField field) where TSource : INotifyPropertyChanged - { - // Terminal.Gui 2.4.16 exposes ValueChanged (EventHandler>) - // rather than a TextChanged event. - TwoWay(source, property, field, f => f.Text, callback => field.ValueChanged += (_, _) => callback()); - } + + // Terminal.Gui 2.4.16 exposes ValueChanged (EventHandler>) + // rather than a TextChanged event. + => TwoWay(source, property, field, f => f.Text, callback => field.ValueChanged += (_, _) => callback()); /// Bind a command to a : Accepted triggers it, CanExecute drives Enabled. public void Command(Button button, ICommand command) - { + // Use Accepted (post-accept, non-cancellable) rather than Accepting for this side-effect-only // handler; Terminal.Gui 2.4.16 docs mark subscribing side effects to the cancellable Accepting // phase as incorrect. - Command(command, enabled => button.Enabled = enabled, callback => button.Accepted += (_, _) => callback()); - } + => Command(command, enabled => button.Enabled = enabled, callback => button.Accepted += (_, _) => callback()); } diff --git a/src/SquidStd.Tui/Binding/ViewBinder.cs b/src/SquidStd.Tui/Binding/ViewBinder.cs index 82a9385a..96e051a3 100644 --- a/src/SquidStd.Tui/Binding/ViewBinder.cs +++ b/src/SquidStd.Tui/Binding/ViewBinder.cs @@ -69,30 +69,34 @@ void SourceHandler(object? sender, PropertyChangedEventArgs e) return; } - _marshal(() => - { - using (guard.Enter()) + _marshal( + () => { - applyToTarget(); + using (guard.Enter()) + { + applyToTarget(); + } } - }); + ); } source.PropertyChanged += SourceHandler; _subscriptions.Add(new Unsubscriber(() => source.PropertyChanged -= SourceHandler)); - subscribeTargetChanged(() => - { - if (guard.IsBusy) + subscribeTargetChanged( + () => { - return; - } + if (guard.IsBusy) + { + return; + } - using (guard.Enter()) - { - writeToSource(); + using (guard.Enter()) + { + writeToSource(); + } } - }); + ); } /// @@ -104,20 +108,20 @@ public void Command(ICommand command, Action setEnabled, Action su setEnabled(command.CanExecute(null)); void CanHandler(object? sender, EventArgs e) - { - _marshal(() => setEnabled(command.CanExecute(null))); - } + => _marshal(() => setEnabled(command.CanExecute(null))); command.CanExecuteChanged += CanHandler; _subscriptions.Add(new Unsubscriber(() => command.CanExecuteChanged -= CanHandler)); - subscribeTrigger(() => - { - if (command.CanExecute(null)) + subscribeTrigger( + () => { - command.Execute(null); + if (command.CanExecute(null)) + { + command.Execute(null); + } } - }); + ); } /// Disposes all active subscriptions created by this binder. diff --git a/src/SquidStd.Tui/Dsl/TuiNode.cs b/src/SquidStd.Tui/Dsl/TuiNode.cs index 30a46f5c..3d6d3110 100644 --- a/src/SquidStd.Tui/Dsl/TuiNode.cs +++ b/src/SquidStd.Tui/Dsl/TuiNode.cs @@ -2,6 +2,4 @@ namespace SquidStd.Tui.Dsl; /// Immutable description of a UI element bound to . /// The ViewModel the node's bindings target. -public abstract class TuiNode -{ -} +public abstract class TuiNode { } diff --git a/src/SquidStd.Tui/Dsl/TuiNodeMaterializer.cs b/src/SquidStd.Tui/Dsl/TuiNodeMaterializer.cs index b9abeba6..445dfce8 100644 --- a/src/SquidStd.Tui/Dsl/TuiNodeMaterializer.cs +++ b/src/SquidStd.Tui/Dsl/TuiNodeMaterializer.cs @@ -6,12 +6,16 @@ namespace SquidStd.Tui.Dsl; -/// Turns a tree into a Terminal.Gui view graph, wiring each -/// node's binding through the supplied . +/// +/// Turns a tree into a Terminal.Gui view graph, wiring each +/// node's binding through the supplied . +/// public sealed class TuiNodeMaterializer { - /// Materialises against , registering - /// bindings on , and returns the produced view. + /// + /// Materialises against , registering + /// bindings on , and returns the produced view. + /// public View Materialize(TuiNode node, TViewModel viewModel, ViewBinder binder) where TViewModel : INotifyPropertyChanged { diff --git a/src/SquidStd.Tui/Dsl/UiFactory.cs b/src/SquidStd.Tui/Dsl/UiFactory.cs index e6ad22ea..4d245cfb 100644 --- a/src/SquidStd.Tui/Dsl/UiFactory.cs +++ b/src/SquidStd.Tui/Dsl/UiFactory.cs @@ -13,31 +13,21 @@ public sealed class UiFactory { /// A label one-way bound to a string property. public LabelNode Label(Expression> text) - { - return new LabelNode(text); - } + => new(text); /// A text field bound to a string property (two-way by default). public TextFieldNode TextField(Expression> text, BindMode mode = BindMode.TwoWay) - { - return new TextFieldNode(text, mode); - } + => new(text, mode); /// A button that runs the command resolved from the ViewModel. public ButtonNode Button(string caption, Expression> command) - { - return new ButtonNode(caption, command); - } + => new(caption, command); /// A vertical stack of child nodes. public StackNode VStack(params TuiNode[] children) - { - return new StackNode(StackOrientation.Vertical, children); - } + => new(StackOrientation.Vertical, children); /// A horizontal stack of child nodes. public StackNode HStack(params TuiNode[] children) - { - return new StackNode(StackOrientation.Horizontal, children); - } + => new(StackOrientation.Horizontal, children); } diff --git a/src/SquidStd.Tui/Hosting/TerminalGuiViewHost.cs b/src/SquidStd.Tui/Hosting/TerminalGuiViewHost.cs index 86dcd060..2fd35982 100644 --- a/src/SquidStd.Tui/Hosting/TerminalGuiViewHost.cs +++ b/src/SquidStd.Tui/Hosting/TerminalGuiViewHost.cs @@ -13,7 +13,7 @@ public sealed class TerminalGuiViewHost : ITuiViewHost /// The shell the navigator's screens are added to. Set by the application host before running. public View? Container { get; set; } - /// Adds as a full-size child of and gives it focus. + /// Adds as a full-size child of and gives it focus. public void Show(object view) { if (Container is not null && view is View concrete) @@ -25,7 +25,7 @@ public void Show(object view) } } - /// Removes from and disposes it. + /// Removes from and disposes it. public void Remove(object view) { if (Container is not null && view is View concrete) diff --git a/src/SquidStd.Tui/Interfaces/ITuiNavigator.cs b/src/SquidStd.Tui/Interfaces/ITuiNavigator.cs index 1452ed8f..c1e22713 100644 --- a/src/SquidStd.Tui/Interfaces/ITuiNavigator.cs +++ b/src/SquidStd.Tui/Interfaces/ITuiNavigator.cs @@ -1,5 +1,3 @@ -using SquidStd.Tui; - namespace SquidStd.Tui.Interfaces; /// ViewModel-first navigation over a stack of screens. diff --git a/src/SquidStd.Tui/Internal/ConventionNames.cs b/src/SquidStd.Tui/Internal/ConventionNames.cs index 828200f2..d470ed93 100644 --- a/src/SquidStd.Tui/Internal/ConventionNames.cs +++ b/src/SquidStd.Tui/Internal/ConventionNames.cs @@ -19,7 +19,5 @@ public static string MemberName(string widgetId) } public static string CommandName(string widgetId) - { - return MemberName(widgetId) + "Command"; - } + => MemberName(widgetId) + "Command"; } diff --git a/src/SquidStd.Tui/Internal/ReentryGuard.cs b/src/SquidStd.Tui/Internal/ReentryGuard.cs index 1bf5f195..afb6bc01 100644 --- a/src/SquidStd.Tui/Internal/ReentryGuard.cs +++ b/src/SquidStd.Tui/Internal/ReentryGuard.cs @@ -3,16 +3,11 @@ namespace SquidStd.Tui.Internal; /// Single-threaded reentrancy flag used to stop two-way binding write-back loops. internal sealed class ReentryGuard { - private bool _busy; - - public bool IsBusy - { - get { return _busy; } - } + public bool IsBusy { get; private set; } public IDisposable Enter() { - _busy = true; + IsBusy = true; return new Scope(this); } @@ -27,8 +22,6 @@ public Scope(ReentryGuard owner) } public void Dispose() - { - _owner._busy = false; - } + => _owner.IsBusy = false; } } diff --git a/src/SquidStd.Tui/Internal/TuiViewRegistry.cs b/src/SquidStd.Tui/Internal/TuiViewRegistry.cs index e1e0b5c6..30d0da7b 100644 --- a/src/SquidStd.Tui/Internal/TuiViewRegistry.cs +++ b/src/SquidStd.Tui/Internal/TuiViewRegistry.cs @@ -5,13 +5,11 @@ public sealed class TuiViewRegistry { private readonly Dictionary _map = new(); - /// Registers a mapping from to the that renders it. + /// Registers a mapping from to the that renders it. public void Map(Type viewModelType, Type viewType) - { - _map[viewModelType] = viewType; - } + => _map[viewModelType] = viewType; - /// Returns the view type registered for , or throws if none is registered. + /// Returns the view type registered for , or throws if none is registered. public Type ViewTypeFor(Type viewModelType) { if (_map.TryGetValue(viewModelType, out var viewType)) diff --git a/src/SquidStd.Tui/Navigation/TuiNavigator.cs b/src/SquidStd.Tui/Navigation/TuiNavigator.cs index 3c7a3d93..dec1d83c 100644 --- a/src/SquidStd.Tui/Navigation/TuiNavigator.cs +++ b/src/SquidStd.Tui/Navigation/TuiNavigator.cs @@ -12,10 +12,7 @@ public sealed class TuiNavigator : ITuiNavigator private readonly ITuiViewHost _viewHost; private readonly Stack _stack = new(); - public int Depth - { - get { return _stack.Count; } - } + public int Depth => _stack.Count; public TuiNavigator(IResolver resolver, TuiViewRegistry registry, ITuiViewHost viewHost) { @@ -40,7 +37,7 @@ public async Task NavigateToAsync(CancellationToken cancellationToke await _stack.Peek().ViewModel.OnDeactivatedAsync(); } - _stack.Push(new Screen(viewModel, view)); + _stack.Push(new(viewModel, view)); _viewHost.Show(view); await viewModel.OnActivatedAsync(); diff --git a/src/SquidStd.Tui/README.md b/src/SquidStd.Tui/README.md index 3452b06e..e3cdb69e 100644 --- a/src/SquidStd.Tui/README.md +++ b/src/SquidStd.Tui/README.md @@ -70,14 +70,14 @@ public sealed class CounterView : TuiComposedView ## Key types -| Type | Purpose | -|------|---------| -| `TuiViewModel` | ViewModel base (ObservableObject + activation hooks + `Navigator`). | -| `TuiView` | View base: a Terminal.Gui `Window` with a typed ViewModel and a binder. | -| `ViewBinder` | One-way / two-way / command binding; fluent typed + `AutoBind` by convention. | -| `ITuiNavigator` | ViewModel-first stack navigation (`NavigateToAsync`, `BackAsync`). | -| `TuiApplicationHost` | Boots the Terminal.Gui loop with a root ViewModel. | -| `RegisterTui()` / `RegisterView<,>()` | DryIoc registration. | +| Type | Purpose | +|---------------------------------------|-------------------------------------------------------------------------------| +| `TuiViewModel` | ViewModel base (ObservableObject + activation hooks + `Navigator`). | +| `TuiView` | View base: a Terminal.Gui `Window` with a typed ViewModel and a binder. | +| `ViewBinder` | One-way / two-way / command binding; fluent typed + `AutoBind` by convention. | +| `ITuiNavigator` | ViewModel-first stack navigation (`NavigateToAsync`, `BackAsync`). | +| `TuiApplicationHost` | Boots the Terminal.Gui loop with a root ViewModel. | +| `RegisterTui()` / `RegisterView<,>()` | DryIoc registration. | ## License diff --git a/src/SquidStd.Tui/TuiComposedView.cs b/src/SquidStd.Tui/TuiComposedView.cs index 85c26c7d..0f85d711 100644 --- a/src/SquidStd.Tui/TuiComposedView.cs +++ b/src/SquidStd.Tui/TuiComposedView.cs @@ -20,13 +20,9 @@ public abstract class TuiComposedView : TuiView /// Returns the declarative node tree for this view. protected abstract TuiNode Compose(); - protected sealed override void BuildLayout() - { - } + protected sealed override void BuildLayout() { } - protected sealed override void Bind(ViewBinder binder) - { - } + protected sealed override void Bind(ViewBinder binder) { } protected override void OnInitialize(ViewBinder binder) { diff --git a/src/SquidStd.Tui/TuiView.cs b/src/SquidStd.Tui/TuiView.cs index e7b1a306..c39e6908 100644 --- a/src/SquidStd.Tui/TuiView.cs +++ b/src/SquidStd.Tui/TuiView.cs @@ -21,18 +21,14 @@ public abstract class TuiView : Window, ITuiView protected TuiView() { - _binder = new ViewBinder(Application.Invoke); + _binder = new(Application.Invoke); } void ITuiView.Bind(object viewModel) - { - ViewModel = (TViewModel)viewModel; - } + => ViewModel = (TViewModel)viewModel; void ITuiView.Initialize() - { - OnInitialize(_binder); - } + => OnInitialize(_binder); /// /// Builds the view. The default runs then ; the diff --git a/src/SquidStd.Tui/TuiViewModel.cs b/src/SquidStd.Tui/TuiViewModel.cs index 6566658b..84414e89 100644 --- a/src/SquidStd.Tui/TuiViewModel.cs +++ b/src/SquidStd.Tui/TuiViewModel.cs @@ -15,13 +15,9 @@ public abstract class TuiViewModel : ObservableObject /// Invoked after the screen becomes active. Default is a no-op. public virtual ValueTask OnActivatedAsync() - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; /// Invoked after the screen is removed or hidden. Default is a no-op. public virtual ValueTask OnDeactivatedAsync() - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; } diff --git a/src/SquidStd.Vfs.Abstractions/README.md b/src/SquidStd.Vfs.Abstractions/README.md index a68e0c3b..fa75b934 100644 --- a/src/SquidStd.Vfs.Abstractions/README.md +++ b/src/SquidStd.Vfs.Abstractions/README.md @@ -1,6 +1,7 @@

SquidStd.Vfs.Abstractions

-Virtual filesystem contracts for SquidStd: a path-based file/directory abstraction implemented by physical, in-memory and zip backends. +Virtual filesystem contracts for SquidStd: a path-based file/directory abstraction implemented by physical, in-memory and zip +backends. ## Install @@ -10,12 +11,12 @@ dotnet add package SquidStd.Vfs.Abstractions ## Key types -| Type | Purpose | -|------|---------| -| `IVirtualFileSystem` | Path-based filesystem over a pluggable backend (directory, zip, encrypted container): exists, read/write bytes, open read/write streams, delete and list entries. | -| `ILockableFileSystem` | An `IVirtualFileSystem` that stays locked until unlocked with a passphrase (e.g. an encrypted vault), exposing `IsUnlocked`, `Unlock` and `Lock`. | -| `VfsPath` | Static helper that normalizes logical paths to forward-slash, root-relative form and rejects `.`/`..` traversal segments. | -| `VfsEntry` | Record describing a listed entry: its logical path, byte size and last-modified UTC timestamp. | +| Type | Purpose | +|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `IVirtualFileSystem` | Path-based filesystem over a pluggable backend (directory, zip, encrypted container): exists, read/write bytes, open read/write streams, delete and list entries. | +| `ILockableFileSystem` | An `IVirtualFileSystem` that stays locked until unlocked with a passphrase (e.g. an encrypted vault), exposing `IsUnlocked`, `Unlock` and `Lock`. | +| `VfsPath` | Static helper that normalizes logical paths to forward-slash, root-relative form and rejects `.`/`..` traversal segments. | +| `VfsEntry` | Record describing a listed entry: its logical path, byte size and last-modified UTC timestamp. | ## Related diff --git a/src/SquidStd.Vfs.Abstractions/VfsPath.cs b/src/SquidStd.Vfs.Abstractions/VfsPath.cs index 4c3db181..07e92cc8 100644 --- a/src/SquidStd.Vfs.Abstractions/VfsPath.cs +++ b/src/SquidStd.Vfs.Abstractions/VfsPath.cs @@ -9,7 +9,7 @@ public static string Normalize(string path) ArgumentException.ThrowIfNullOrWhiteSpace(path); var segments = path.Replace('\\', '/') - .Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + .Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); foreach (var segment in segments) { diff --git a/src/SquidStd.Vfs/README.md b/src/SquidStd.Vfs/README.md index 01137a3e..82c5e888 100644 --- a/src/SquidStd.Vfs/README.md +++ b/src/SquidStd.Vfs/README.md @@ -51,14 +51,14 @@ Logical paths are normalized (forward slashes, root-relative) and reject `..` tr ## Key types -| Type | Purpose | -|------|---------| -| `IVirtualFileSystem` | Path-based filesystem over a pluggable backend. | -| `PhysicalFileSystem` | Maps logical paths onto a real directory tree. | -| `ZipFileSystem` | A single `.zip` archive opened in update mode; `IAsyncDisposable`. | -| `InMemoryFileSystem` | Ephemeral, in-process; handy for tests and as a decorator target. | -| `VfsDirectories` | Named directory layout (`DirectoriesConfig` analogue) over any backend. | -| `RegisterVfsExtensions` | `RegisterVfs(...)` registration. | +| Type | Purpose | +|-------------------------|-------------------------------------------------------------------------| +| `IVirtualFileSystem` | Path-based filesystem over a pluggable backend. | +| `PhysicalFileSystem` | Maps logical paths onto a real directory tree. | +| `ZipFileSystem` | A single `.zip` archive opened in update mode; `IAsyncDisposable`. | +| `InMemoryFileSystem` | Ephemeral, in-process; handy for tests and as a decorator target. | +| `VfsDirectories` | Named directory layout (`DirectoriesConfig` analogue) over any backend. | +| `RegisterVfsExtensions` | `RegisterVfs(...)` registration. | ## Related diff --git a/src/SquidStd.Vfs/Services/InMemoryFileSystem.cs b/src/SquidStd.Vfs/Services/InMemoryFileSystem.cs index 964002f3..a6782a7b 100644 --- a/src/SquidStd.Vfs/Services/InMemoryFileSystem.cs +++ b/src/SquidStd.Vfs/Services/InMemoryFileSystem.cs @@ -1,33 +1,31 @@ using System.Collections.Concurrent; using System.Runtime.CompilerServices; +using SquidStd.Vfs.Abstractions; using SquidStd.Vfs.Abstractions.Data; using SquidStd.Vfs.Abstractions.Interfaces; -using SquidStd.Vfs.Abstractions; namespace SquidStd.Vfs.Services; /// An in-memory virtual filesystem. Ephemeral; useful for tests and as a backend decorator target. public sealed class InMemoryFileSystem : IVirtualFileSystem { - private readonly ConcurrentDictionary _files = new( - StringComparer.Ordinal - ); + private readonly ConcurrentDictionary _files = + new(StringComparer.Ordinal); public ValueTask ExistsAsync(string path, CancellationToken cancellationToken = default) - { - return ValueTask.FromResult(_files.ContainsKey(VfsPath.Normalize(path))); - } + => ValueTask.FromResult(_files.ContainsKey(VfsPath.Normalize(path))); public ValueTask ReadAllBytesAsync(string path, CancellationToken cancellationToken = default) - { + // Return a copy: the stored array must not be aliased to callers, who may mutate what they read. - return ValueTask.FromResult( + => ValueTask.FromResult( _files.TryGetValue(VfsPath.Normalize(path), out var entry) ? (byte[])entry.Data.Clone() : null ); - } public ValueTask WriteAllBytesAsync( - string path, ReadOnlyMemory data, CancellationToken cancellationToken = default + string path, + ReadOnlyMemory data, + CancellationToken cancellationToken = default ) { _files[VfsPath.Normalize(path)] = (data.ToArray(), DateTimeOffset.UtcNow); @@ -37,24 +35,21 @@ public ValueTask WriteAllBytesAsync( public async Task OpenReadAsync(string path, CancellationToken cancellationToken = default) { - var data = await ReadAllBytesAsync(path, cancellationToken).ConfigureAwait(false) - ?? throw new FileNotFoundException($"No file at '{path}'.", path); + var data = await ReadAllBytesAsync(path, cancellationToken).ConfigureAwait(false) ?? + throw new FileNotFoundException($"No file at '{path}'.", path); - return new MemoryStream(data, writable: false); + return new MemoryStream(data, false); } public Task OpenWriteAsync(string path, CancellationToken cancellationToken = default) - { - return Task.FromResult(new WriteBackStream(this, path)); - } + => Task.FromResult(new WriteBackStream(this, path)); public ValueTask DeleteAsync(string path, CancellationToken cancellationToken = default) - { - return ValueTask.FromResult(_files.TryRemove(VfsPath.Normalize(path), out _)); - } + => ValueTask.FromResult(_files.TryRemove(VfsPath.Normalize(path), out _)); public async IAsyncEnumerable ListAsync( - string? prefix = null, [EnumeratorCancellation] CancellationToken cancellationToken = default + string? prefix = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default ) { var normalizedPrefix = string.IsNullOrEmpty(prefix) ? null : VfsPath.Normalize(prefix); @@ -66,7 +61,7 @@ public async IAsyncEnumerable ListAsync( continue; } - yield return new VfsEntry(path, entry.Data.Length, entry.Modified); + yield return new(path, entry.Data.Length, entry.Modified); await Task.CompletedTask; } diff --git a/src/SquidStd.Vfs/Services/PhysicalFileSystem.cs b/src/SquidStd.Vfs/Services/PhysicalFileSystem.cs index 4de9584c..55b74f50 100644 --- a/src/SquidStd.Vfs/Services/PhysicalFileSystem.cs +++ b/src/SquidStd.Vfs/Services/PhysicalFileSystem.cs @@ -1,7 +1,7 @@ using System.Runtime.CompilerServices; +using SquidStd.Vfs.Abstractions; using SquidStd.Vfs.Abstractions.Data; using SquidStd.Vfs.Abstractions.Interfaces; -using SquidStd.Vfs.Abstractions; namespace SquidStd.Vfs.Services; @@ -18,21 +18,21 @@ public PhysicalFileSystem(string root) } public ValueTask ExistsAsync(string path, CancellationToken cancellationToken = default) - { - return ValueTask.FromResult(File.Exists(Resolve(path))); - } + => ValueTask.FromResult(File.Exists(Resolve(path))); public async ValueTask ReadAllBytesAsync(string path, CancellationToken cancellationToken = default) { var full = Resolve(path); return File.Exists(full) - ? await File.ReadAllBytesAsync(full, cancellationToken).ConfigureAwait(false) - : null; + ? await File.ReadAllBytesAsync(full, cancellationToken).ConfigureAwait(false) + : null; } public async ValueTask WriteAllBytesAsync( - string path, ReadOnlyMemory data, CancellationToken cancellationToken = default + string path, + ReadOnlyMemory data, + CancellationToken cancellationToken = default ) { var full = Resolve(path); @@ -75,7 +75,8 @@ public ValueTask DeleteAsync(string path, CancellationToken cancellationTo } public async IAsyncEnumerable ListAsync( - string? prefix = null, [EnumeratorCancellation] CancellationToken cancellationToken = default + string? prefix = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default ) { if (!Directory.Exists(_root)) @@ -97,7 +98,8 @@ public async IAsyncEnumerable ListAsync( } var info = new FileInfo(file); - yield return new VfsEntry(logical, info.Length, info.LastWriteTimeUtc); + + yield return new(logical, info.Length, info.LastWriteTimeUtc); await Task.CompletedTask; } diff --git a/src/SquidStd.Vfs/Services/VfsDirectories.cs b/src/SquidStd.Vfs/Services/VfsDirectories.cs index 531a3a57..2078bd53 100644 --- a/src/SquidStd.Vfs/Services/VfsDirectories.cs +++ b/src/SquidStd.Vfs/Services/VfsDirectories.cs @@ -1,5 +1,5 @@ -using SquidStd.Vfs.Abstractions.Interfaces; using SquidStd.Vfs.Abstractions; +using SquidStd.Vfs.Abstractions.Interfaces; namespace SquidStd.Vfs.Services; @@ -37,7 +37,5 @@ public string GetPath(string directoryName) /// Combines a named directory with a relative sub-path into a normalized logical path. public string Combine(string directoryName, string relativePath) - { - return VfsPath.Normalize(GetPath(directoryName) + "/" + relativePath); - } + => VfsPath.Normalize(GetPath(directoryName) + "/" + relativePath); } diff --git a/src/SquidStd.Vfs/Services/ZipFileSystem.cs b/src/SquidStd.Vfs/Services/ZipFileSystem.cs index a080fa81..63207e34 100644 --- a/src/SquidStd.Vfs/Services/ZipFileSystem.cs +++ b/src/SquidStd.Vfs/Services/ZipFileSystem.cs @@ -1,8 +1,8 @@ using System.IO.Compression; using System.Runtime.CompilerServices; +using SquidStd.Vfs.Abstractions; using SquidStd.Vfs.Abstractions.Data; using SquidStd.Vfs.Abstractions.Interfaces; -using SquidStd.Vfs.Abstractions; namespace SquidStd.Vfs.Services; @@ -16,14 +16,12 @@ public sealed class ZipFileSystem : IVirtualFileSystem, IAsyncDisposable, IDispo public ZipFileSystem(string path) { ArgumentException.ThrowIfNullOrWhiteSpace(path); - _file = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); - _archive = new ZipArchive(_file, ZipArchiveMode.Update, leaveOpen: true); + _file = new(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); + _archive = new(_file, ZipArchiveMode.Update, true); } public ValueTask ExistsAsync(string path, CancellationToken cancellationToken = default) - { - return ValueTask.FromResult(_archive.GetEntry(VfsPath.Normalize(path)) is not null); - } + => ValueTask.FromResult(_archive.GetEntry(VfsPath.Normalize(path)) is not null); public async ValueTask ReadAllBytesAsync(string path, CancellationToken cancellationToken = default) { @@ -42,7 +40,9 @@ public ValueTask ExistsAsync(string path, CancellationToken cancellationTo } public async ValueTask WriteAllBytesAsync( - string path, ReadOnlyMemory data, CancellationToken cancellationToken = default + string path, + ReadOnlyMemory data, + CancellationToken cancellationToken = default ) { var name = VfsPath.Normalize(path); @@ -59,16 +59,14 @@ public async ValueTask WriteAllBytesAsync( public async Task OpenReadAsync(string path, CancellationToken cancellationToken = default) { - var data = await ReadAllBytesAsync(path, cancellationToken).ConfigureAwait(false) - ?? throw new FileNotFoundException($"No file at '{path}'.", path); + var data = await ReadAllBytesAsync(path, cancellationToken).ConfigureAwait(false) ?? + throw new FileNotFoundException($"No file at '{path}'.", path); - return new MemoryStream(data, writable: false); + return new MemoryStream(data, false); } public Task OpenWriteAsync(string path, CancellationToken cancellationToken = default) - { - return Task.FromResult(new WriteBackStream(this, path)); - } + => Task.FromResult(new WriteBackStream(this, path)); public ValueTask DeleteAsync(string path, CancellationToken cancellationToken = default) { @@ -87,7 +85,8 @@ public ValueTask DeleteAsync(string path, CancellationToken cancellationTo } public async IAsyncEnumerable ListAsync( - string? prefix = null, [EnumeratorCancellation] CancellationToken cancellationToken = default + string? prefix = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default ) { var normalizedPrefix = string.IsNullOrEmpty(prefix) ? null : VfsPath.Normalize(prefix); @@ -99,7 +98,7 @@ public async IAsyncEnumerable ListAsync( continue; } - yield return new VfsEntry(entry.FullName, EntrySize(entry), entry.LastWriteTime); + yield return new(entry.FullName, EntrySize(entry), entry.LastWriteTime); await Task.CompletedTask; } diff --git a/src/SquidStd.Workers.Abstractions/Data/JobRequest.cs b/src/SquidStd.Workers.Abstractions/Data/JobRequest.cs index cc9477e4..0effc8c4 100644 --- a/src/SquidStd.Workers.Abstractions/Data/JobRequest.cs +++ b/src/SquidStd.Workers.Abstractions/Data/JobRequest.cs @@ -1,7 +1,7 @@ namespace SquidStd.Workers.Abstractions.Data; /// -/// A unit of work the manager enqueues on the jobs queue for a worker to execute. +/// A unit of work the manager enqueues on the jobs queue for a worker to execute. /// /// Logical name of the job, used by the worker to pick a handler. /// Opaque string key/value arguments for the job. diff --git a/src/SquidStd.Workers.Abstractions/Data/WorkerHeartbeat.cs b/src/SquidStd.Workers.Abstractions/Data/WorkerHeartbeat.cs index 622fc150..a9c75ba7 100644 --- a/src/SquidStd.Workers.Abstractions/Data/WorkerHeartbeat.cs +++ b/src/SquidStd.Workers.Abstractions/Data/WorkerHeartbeat.cs @@ -3,13 +3,13 @@ namespace SquidStd.Workers.Abstractions.Data; /// -/// A liveness signal a worker publishes on the heartbeat topic at a fixed interval. +/// A liveness signal a worker publishes on the heartbeat topic at a fixed interval. /// /// Stable identity of the reporting worker. /// UTC time the heartbeat was produced. /// -/// Self-reported status ( when no job is running, else -/// ). +/// Self-reported status ( when no job is running, else +/// ). /// /// Number of jobs currently in progress on this worker. /// Maximum number of jobs the worker runs at once. diff --git a/src/SquidStd.Workers.Abstractions/Data/WorkerInfo.cs b/src/SquidStd.Workers.Abstractions/Data/WorkerInfo.cs index 036d7090..86d5f548 100644 --- a/src/SquidStd.Workers.Abstractions/Data/WorkerInfo.cs +++ b/src/SquidStd.Workers.Abstractions/Data/WorkerInfo.cs @@ -3,7 +3,7 @@ namespace SquidStd.Workers.Abstractions.Data; /// -/// The manager-side view of a worker, folded from incoming heartbeats. +/// The manager-side view of a worker, folded from incoming heartbeats. /// /// Stable identity of the worker. /// Last known status; the manager sets on missed heartbeats. diff --git a/src/SquidStd.Workers.Abstractions/Types/WorkerStatusType.cs b/src/SquidStd.Workers.Abstractions/Types/WorkerStatusType.cs index 449b32dd..d3aa947c 100644 --- a/src/SquidStd.Workers.Abstractions/Types/WorkerStatusType.cs +++ b/src/SquidStd.Workers.Abstractions/Types/WorkerStatusType.cs @@ -1,8 +1,8 @@ namespace SquidStd.Workers.Abstractions.Types; /// -/// Lifecycle status of a worker. Workers report or ; -/// the manager assigns when a worker's heartbeats stop arriving. +/// Lifecycle status of a worker. Workers report or ; +/// the manager assigns when a worker's heartbeats stop arriving. /// public enum WorkerStatusType { diff --git a/src/SquidStd.Workers.Abstractions/WorkerChannels.cs b/src/SquidStd.Workers.Abstractions/WorkerChannels.cs index 899972c2..6514a147 100644 --- a/src/SquidStd.Workers.Abstractions/WorkerChannels.cs +++ b/src/SquidStd.Workers.Abstractions/WorkerChannels.cs @@ -1,8 +1,8 @@ namespace SquidStd.Workers.Abstractions; /// -/// Default names of the messaging channels the workers system uses. Shared so the manager -/// and workers agree out of the box; either side may override them via its own configuration. +/// Default names of the messaging channels the workers system uses. Shared so the manager +/// and workers agree out of the box; either side may override them via its own configuration. /// public static class WorkerChannels { diff --git a/src/SquidStd.Workers.Manager/Data/Config/WorkerManagerConfig.cs b/src/SquidStd.Workers.Manager/Data/Config/WorkerManagerConfig.cs index 96e577db..beef18cd 100644 --- a/src/SquidStd.Workers.Manager/Data/Config/WorkerManagerConfig.cs +++ b/src/SquidStd.Workers.Manager/Data/Config/WorkerManagerConfig.cs @@ -3,7 +3,7 @@ namespace SquidStd.Workers.Manager.Data.Config; /// -/// Configuration for the worker manager (config section "workerManager"). +/// Configuration for the worker manager (config section "workerManager"). /// public sealed class WorkerManagerConfig { diff --git a/src/SquidStd.Workers.Manager/Data/EnqueueJobRequest.cs b/src/SquidStd.Workers.Manager/Data/EnqueueJobRequest.cs index d78e30bf..8869f5f7 100644 --- a/src/SquidStd.Workers.Manager/Data/EnqueueJobRequest.cs +++ b/src/SquidStd.Workers.Manager/Data/EnqueueJobRequest.cs @@ -1,7 +1,7 @@ namespace SquidStd.Workers.Manager.Data; /// -/// Request body for enqueuing a job via the manager's HTTP surface. +/// Request body for enqueuing a job via the manager's HTTP surface. /// /// Logical name of the job. /// Optional string key/value arguments; treated as empty when null. diff --git a/src/SquidStd.Workers.Manager/Data/Events/WorkerStatusChangedEvent.cs b/src/SquidStd.Workers.Manager/Data/Events/WorkerStatusChangedEvent.cs index c9e43cae..e2922b8c 100644 --- a/src/SquidStd.Workers.Manager/Data/Events/WorkerStatusChangedEvent.cs +++ b/src/SquidStd.Workers.Manager/Data/Events/WorkerStatusChangedEvent.cs @@ -4,8 +4,8 @@ namespace SquidStd.Workers.Manager.Data.Events; /// -/// Published on the event bus when a worker's status changes: discovered ( null), -/// gone Offline (via the sweep), or returned (Offline → Idle/Busy). +/// Published on the event bus when a worker's status changes: discovered ( null), +/// gone Offline (via the sweep), or returned (Offline → Idle/Busy). /// /// The worker whose status changed. /// Previous status, or null when the worker was just discovered. diff --git a/src/SquidStd.Workers.Manager/Endpoints/WorkerManagerEndpoints.cs b/src/SquidStd.Workers.Manager/Endpoints/WorkerManagerEndpoints.cs index 0fcd2174..d3928537 100644 --- a/src/SquidStd.Workers.Manager/Endpoints/WorkerManagerEndpoints.cs +++ b/src/SquidStd.Workers.Manager/Endpoints/WorkerManagerEndpoints.cs @@ -7,7 +7,7 @@ namespace SquidStd.Workers.Manager.Endpoints; /// -/// Typed minimal-API handlers for the worker manager surface. Static so they can be unit-tested directly. +/// Typed minimal-API handlers for the worker manager surface. Static so they can be unit-tested directly. /// public static class WorkerManagerEndpoints { @@ -52,7 +52,5 @@ public static Results, NotFound> GetWorker(string id, IWorkerRegi /// Lists all known workers. public static Ok> GetWorkers(IWorkerRegistry registry) - { - return TypedResults.Ok(registry.GetAll()); - } + => TypedResults.Ok(registry.GetAll()); } diff --git a/src/SquidStd.Workers.Manager/Extensions/WorkerManagerEndpointsExtensions.cs b/src/SquidStd.Workers.Manager/Extensions/WorkerManagerEndpointsExtensions.cs index 3a9a88ad..56733c6c 100644 --- a/src/SquidStd.Workers.Manager/Extensions/WorkerManagerEndpointsExtensions.cs +++ b/src/SquidStd.Workers.Manager/Extensions/WorkerManagerEndpointsExtensions.cs @@ -5,14 +5,14 @@ namespace SquidStd.Workers.Manager.Extensions; /// -/// Maps the opt-in worker manager HTTP endpoints. +/// Maps the opt-in worker manager HTTP endpoints. /// public static class WorkerManagerEndpointsExtensions { extension(IEndpointRouteBuilder endpoints) { /// - /// Maps GET /workers, GET /workers/{id}, and POST /jobs. + /// Maps GET /workers, GET /workers/{id}, and POST /jobs. /// public IEndpointRouteBuilder MapWorkerManagerEndpoints() { diff --git a/src/SquidStd.Workers.Manager/Extensions/WorkerManagerRegistrationExtensions.cs b/src/SquidStd.Workers.Manager/Extensions/WorkerManagerRegistrationExtensions.cs index 12500e49..a75b9aae 100644 --- a/src/SquidStd.Workers.Manager/Extensions/WorkerManagerRegistrationExtensions.cs +++ b/src/SquidStd.Workers.Manager/Extensions/WorkerManagerRegistrationExtensions.cs @@ -10,15 +10,15 @@ namespace SquidStd.Workers.Manager.Extensions; /// -/// DryIoc registration helpers for the worker manager. +/// DryIoc registration helpers for the worker manager. /// public static class WorkerManagerRegistrationExtensions { extension(IContainer container) { /// - /// Registers the worker manager: config section, registry, job scheduler, the collector and sweep - /// lifecycle services, and the timer-wheel pump (only if it is not already registered). + /// Registers the worker manager: config section, registry, job scheduler, the collector and sweep + /// lifecycle services, and the timer-wheel pump (only if it is not already registered). /// public IContainer AddWorkerManager() { diff --git a/src/SquidStd.Workers.Manager/Interfaces/IJobScheduler.cs b/src/SquidStd.Workers.Manager/Interfaces/IJobScheduler.cs index e5d68888..337d0f5f 100644 --- a/src/SquidStd.Workers.Manager/Interfaces/IJobScheduler.cs +++ b/src/SquidStd.Workers.Manager/Interfaces/IJobScheduler.cs @@ -1,7 +1,7 @@ namespace SquidStd.Workers.Manager.Interfaces; /// -/// Enqueues jobs for workers to consume. +/// Enqueues jobs for workers to consume. /// public interface IJobScheduler { diff --git a/src/SquidStd.Workers.Manager/Interfaces/IWorkerRegistry.cs b/src/SquidStd.Workers.Manager/Interfaces/IWorkerRegistry.cs index 39eff65f..8c46d819 100644 --- a/src/SquidStd.Workers.Manager/Interfaces/IWorkerRegistry.cs +++ b/src/SquidStd.Workers.Manager/Interfaces/IWorkerRegistry.cs @@ -3,7 +3,7 @@ namespace SquidStd.Workers.Manager.Interfaces; /// -/// Read access to the manager's in-memory view of known workers. +/// Read access to the manager's in-memory view of known workers. /// public interface IWorkerRegistry { diff --git a/src/SquidStd.Workers.Manager/Services/HeartbeatCollectorService.cs b/src/SquidStd.Workers.Manager/Services/HeartbeatCollectorService.cs index 86023ff2..e58c69dd 100644 --- a/src/SquidStd.Workers.Manager/Services/HeartbeatCollectorService.cs +++ b/src/SquidStd.Workers.Manager/Services/HeartbeatCollectorService.cs @@ -9,8 +9,8 @@ namespace SquidStd.Workers.Manager.Services; /// -/// Subscribes to the heartbeat topic and folds each into the registry, -/// publishing any resulting status transition on the event bus. +/// Subscribes to the heartbeat topic and folds each into the registry, +/// publishing any resulting status transition on the event bus. /// public sealed class HeartbeatCollectorService : ISquidStdService { @@ -32,8 +32,8 @@ WorkerManagerConfig config _registry = registry; _eventBus = eventBus; _topicName = string.IsNullOrWhiteSpace(config.HeartbeatTopic) - ? WorkerChannels.HeartbeatTopic - : config.HeartbeatTopic; + ? WorkerChannels.HeartbeatTopic + : config.HeartbeatTopic; } /// diff --git a/src/SquidStd.Workers.Manager/Services/JobScheduler.cs b/src/SquidStd.Workers.Manager/Services/JobScheduler.cs index c45dac81..646c7b5f 100644 --- a/src/SquidStd.Workers.Manager/Services/JobScheduler.cs +++ b/src/SquidStd.Workers.Manager/Services/JobScheduler.cs @@ -7,7 +7,7 @@ namespace SquidStd.Workers.Manager.Services; /// -/// Default : publishes s onto the configured jobs queue. +/// Default : publishes s onto the configured jobs queue. /// public sealed class JobScheduler : IJobScheduler { @@ -26,13 +26,9 @@ public Task EnqueueAsync( IReadOnlyDictionary parameters, CancellationToken cancellationToken = default ) - { - return _queue.PublishAsync(_queueName, new JobRequest(jobName, parameters), cancellationToken); - } + => _queue.PublishAsync(_queueName, new JobRequest(jobName, parameters), cancellationToken); /// public Task EnqueueAsync(string jobName, CancellationToken cancellationToken = default) - { - return EnqueueAsync(jobName, new Dictionary(), cancellationToken); - } + => EnqueueAsync(jobName, new Dictionary(), cancellationToken); } diff --git a/src/SquidStd.Workers.Manager/Services/WorkerOfflineSweepService.cs b/src/SquidStd.Workers.Manager/Services/WorkerOfflineSweepService.cs index 0937723a..c2abe81c 100644 --- a/src/SquidStd.Workers.Manager/Services/WorkerOfflineSweepService.cs +++ b/src/SquidStd.Workers.Manager/Services/WorkerOfflineSweepService.cs @@ -7,8 +7,8 @@ namespace SquidStd.Workers.Manager.Services; /// -/// Periodically marks workers Offline whose heartbeats have stopped, using the timer wheel -/// (), and publishes the resulting transitions. +/// Periodically marks workers Offline whose heartbeats have stopped, using the timer wheel +/// (), and publishes the resulting transitions. /// public sealed class WorkerOfflineSweepService : ISquidStdService { @@ -83,7 +83,5 @@ public async Task RunSweepAsync() } private void OnTick() - { - _ = RunSweepAsync(); - } + => _ = RunSweepAsync(); } diff --git a/src/SquidStd.Workers.Manager/Services/WorkerRegistry.cs b/src/SquidStd.Workers.Manager/Services/WorkerRegistry.cs index 64cf72c6..509e2bb1 100644 --- a/src/SquidStd.Workers.Manager/Services/WorkerRegistry.cs +++ b/src/SquidStd.Workers.Manager/Services/WorkerRegistry.cs @@ -7,8 +7,8 @@ namespace SquidStd.Workers.Manager.Services; /// -/// In-memory registry of workers, folded from heartbeats. Pure: it returns status transitions for the -/// caller to publish, and never touches the event bus or a real clock (the sweep takes the time as a parameter). +/// In-memory registry of workers, folded from heartbeats. Pure: it returns status transitions for the +/// caller to publish, and never touches the event bus or a real clock (the sweep takes the time as a parameter). /// public sealed class WorkerRegistry : IWorkerRegistry { @@ -41,8 +41,8 @@ public IReadOnlyCollection GetAll() } /// - /// Folds a heartbeat into the registry. Returns a transition only when the worker is newly discovered - /// or has returned from ; otherwise null. + /// Folds a heartbeat into the registry. Returns a transition only when the worker is newly discovered + /// or has returned from ; otherwise null. /// public WorkerStatusChangedEvent? Record(WorkerHeartbeat heartbeat) { @@ -52,7 +52,7 @@ public IReadOnlyCollection GetAll() { if (!_workers.TryGetValue(heartbeat.WorkerId, out var existing)) { - _workers[heartbeat.WorkerId] = new WorkerInfo( + _workers[heartbeat.WorkerId] = new( heartbeat.WorkerId, heartbeat.Status, heartbeat.ActiveJobs, @@ -61,7 +61,7 @@ public IReadOnlyCollection GetAll() now ); - return new WorkerStatusChangedEvent(heartbeat.WorkerId, null, heartbeat.Status); + return new(heartbeat.WorkerId, null, heartbeat.Status); } var old = existing.Status; @@ -74,14 +74,14 @@ public IReadOnlyCollection GetAll() }; return old == WorkerStatusType.Offline && heartbeat.Status != WorkerStatusType.Offline - ? new WorkerStatusChangedEvent(heartbeat.WorkerId, old, heartbeat.Status) - : null; + ? new WorkerStatusChangedEvent(heartbeat.WorkerId, old, heartbeat.Status) + : null; } } /// - /// Marks workers Offline whose last heartbeat is older than the configured timeout relative to - /// . Returns the resulting transitions. + /// Marks workers Offline whose last heartbeat is older than the configured timeout relative to + /// . Returns the resulting transitions. /// public IReadOnlyList Sweep(DateTime nowUtc) { @@ -97,7 +97,7 @@ public IReadOnlyList Sweep(DateTime nowUtc) } _workers[id] = info with { Status = WorkerStatusType.Offline }; - changes.Add(new WorkerStatusChangedEvent(id, info.Status, WorkerStatusType.Offline)); + changes.Add(new(id, info.Status, WorkerStatusType.Offline)); } } diff --git a/src/SquidStd.Workers/Attributes/RegisterJobHandlerAttribute.cs b/src/SquidStd.Workers/Attributes/RegisterJobHandlerAttribute.cs index 71b75a66..0babcfb7 100644 --- a/src/SquidStd.Workers/Attributes/RegisterJobHandlerAttribute.cs +++ b/src/SquidStd.Workers/Attributes/RegisterJobHandlerAttribute.cs @@ -1,9 +1,7 @@ namespace SquidStd.Workers.Attributes; /// -/// Marks a worker job handler for generated registration. +/// Marks a worker job handler for generated registration. /// [AttributeUsage(AttributeTargets.Class, Inherited = false)] -public sealed class RegisterJobHandlerAttribute : Attribute -{ -} +public sealed class RegisterJobHandlerAttribute : Attribute { } diff --git a/src/SquidStd.Workers/Data/Config/WorkersConfig.cs b/src/SquidStd.Workers/Data/Config/WorkersConfig.cs index 3340c181..d9bf2b4f 100644 --- a/src/SquidStd.Workers/Data/Config/WorkersConfig.cs +++ b/src/SquidStd.Workers/Data/Config/WorkersConfig.cs @@ -3,13 +3,13 @@ namespace SquidStd.Workers.Data.Config; /// -/// Configuration for the worker runtime (config section "workers"). +/// Configuration for the worker runtime (config section "workers"). /// public sealed class WorkersConfig { /// - /// Stable worker identity. When blank, the runtime falls back to the machine name - /// (in Docker, the container hostname). + /// Stable worker identity. When blank, the runtime falls back to the machine name + /// (in Docker, the container hostname). /// public string WorkerId { get; set; } = string.Empty; diff --git a/src/SquidStd.Workers/Exceptions/JobHandlerNotFoundException.cs b/src/SquidStd.Workers/Exceptions/JobHandlerNotFoundException.cs index 429efa2c..61a4d92d 100644 --- a/src/SquidStd.Workers/Exceptions/JobHandlerNotFoundException.cs +++ b/src/SquidStd.Workers/Exceptions/JobHandlerNotFoundException.cs @@ -1,7 +1,7 @@ namespace SquidStd.Workers.Exceptions; /// -/// Thrown when a job arrives whose name has no registered . +/// Thrown when a job arrives whose name has no registered . /// public sealed class JobHandlerNotFoundException : Exception { diff --git a/src/SquidStd.Workers/Extensions/WorkersRegistrationExtensions.cs b/src/SquidStd.Workers/Extensions/WorkersRegistrationExtensions.cs index 25dbae16..263b0723 100644 --- a/src/SquidStd.Workers/Extensions/WorkersRegistrationExtensions.cs +++ b/src/SquidStd.Workers/Extensions/WorkersRegistrationExtensions.cs @@ -8,14 +8,14 @@ namespace SquidStd.Workers.Extensions; /// -/// DryIoc registration helpers for the worker runtime. +/// DryIoc registration helpers for the worker runtime. /// public static class WorkersRegistrationExtensions { extension(IContainer container) { /// - /// Registers a job handler so the dispatcher can route jobs to it by name. + /// Registers a job handler so the dispatcher can route jobs to it by name. /// public IContainer AddJobHandler() where THandler : class, IJobHandler @@ -28,8 +28,8 @@ public IContainer AddJobHandler() } /// - /// Registers the worker runtime: the "workers" config section, shared state, job dispatcher, and the - /// consumer + heartbeat lifecycle services. + /// Registers the worker runtime: the "workers" config section, shared state, job dispatcher, and the + /// consumer + heartbeat lifecycle services. /// public IContainer AddWorkers() { diff --git a/src/SquidStd.Workers/Interfaces/IJobDispatcher.cs b/src/SquidStd.Workers/Interfaces/IJobDispatcher.cs index 9c9a18f3..fdae86b5 100644 --- a/src/SquidStd.Workers/Interfaces/IJobDispatcher.cs +++ b/src/SquidStd.Workers/Interfaces/IJobDispatcher.cs @@ -3,12 +3,12 @@ namespace SquidStd.Workers.Interfaces; /// -/// Routes a to the registered for its job name. +/// Routes a to the registered for its job name. /// public interface IJobDispatcher { /// - /// Dispatches the job to its handler. + /// Dispatches the job to its handler. /// /// No handler matches the job name. Task DispatchAsync(JobRequest job, CancellationToken cancellationToken); diff --git a/src/SquidStd.Workers/Interfaces/IJobHandler.cs b/src/SquidStd.Workers/Interfaces/IJobHandler.cs index efd2a910..d64a706e 100644 --- a/src/SquidStd.Workers/Interfaces/IJobHandler.cs +++ b/src/SquidStd.Workers/Interfaces/IJobHandler.cs @@ -3,7 +3,7 @@ namespace SquidStd.Workers.Interfaces; /// -/// Handles jobs of a single named kind. Implemented by consumers of the worker library. +/// Handles jobs of a single named kind. Implemented by consumers of the worker library. /// public interface IJobHandler { diff --git a/src/SquidStd.Workers/Interfaces/IWorkerState.cs b/src/SquidStd.Workers/Interfaces/IWorkerState.cs index c27933a9..98e90069 100644 --- a/src/SquidStd.Workers/Interfaces/IWorkerState.cs +++ b/src/SquidStd.Workers/Interfaces/IWorkerState.cs @@ -3,7 +3,7 @@ namespace SquidStd.Workers.Interfaces; /// -/// Shared runtime state of a worker, read by the heartbeat service and mutated by the consumer. +/// Shared runtime state of a worker, read by the heartbeat service and mutated by the consumer. /// public interface IWorkerState { diff --git a/src/SquidStd.Workers/Services/JobDispatcher.cs b/src/SquidStd.Workers/Services/JobDispatcher.cs index f097823d..e0c739cd 100644 --- a/src/SquidStd.Workers/Services/JobDispatcher.cs +++ b/src/SquidStd.Workers/Services/JobDispatcher.cs @@ -6,7 +6,7 @@ namespace SquidStd.Workers.Services; /// -/// Default : indexes the registered handlers by job name. +/// Default : indexes the registered handlers by job name. /// public sealed class JobDispatcher : IJobDispatcher { diff --git a/src/SquidStd.Workers/Services/WorkerConsumerService.cs b/src/SquidStd.Workers/Services/WorkerConsumerService.cs index 1c9e0903..94a10254 100644 --- a/src/SquidStd.Workers/Services/WorkerConsumerService.cs +++ b/src/SquidStd.Workers/Services/WorkerConsumerService.cs @@ -10,8 +10,8 @@ namespace SquidStd.Workers.Services; /// -/// Subscribes to the jobs queue and dispatches each to its handler, -/// bounded by . +/// Subscribes to the jobs queue and dispatches each to its handler, +/// bounded by . /// public sealed class WorkerConsumerService : ISquidStdService, IQueueMessageListenerAsync { @@ -29,7 +29,7 @@ public WorkerConsumerService(IMessageQueue queue, IJobDispatcher dispatcher, IWo _queue = queue; _dispatcher = dispatcher; _state = state; - _semaphore = new SemaphoreSlim(state.MaxConcurrency); + _semaphore = new(state.MaxConcurrency); _queueName = string.IsNullOrWhiteSpace(config.JobQueue) ? WorkerChannels.JobQueue : config.JobQueue; } diff --git a/src/SquidStd.Workers/Services/WorkerHeartbeatService.cs b/src/SquidStd.Workers/Services/WorkerHeartbeatService.cs index c76ad93a..8cc3a933 100644 --- a/src/SquidStd.Workers/Services/WorkerHeartbeatService.cs +++ b/src/SquidStd.Workers/Services/WorkerHeartbeatService.cs @@ -9,8 +9,8 @@ namespace SquidStd.Workers.Services; /// -/// Publishes a on the heartbeat topic immediately on start and then once -/// per configured interval. +/// Publishes a on the heartbeat topic immediately on start and then once +/// per configured interval. /// public sealed class WorkerHeartbeatService : ISquidStdService { @@ -42,8 +42,8 @@ public WorkerHeartbeatService(IMessageTopic topic, IWorkerState state, WorkersCo _interval = TimeSpan.FromSeconds(seconds); _topicName = string.IsNullOrWhiteSpace(config.HeartbeatTopic) - ? WorkerChannels.HeartbeatTopic - : config.HeartbeatTopic; + ? WorkerChannels.HeartbeatTopic + : config.HeartbeatTopic; } /// diff --git a/src/SquidStd.Workers/Services/WorkerState.cs b/src/SquidStd.Workers/Services/WorkerState.cs index 07849b18..e42747db 100644 --- a/src/SquidStd.Workers/Services/WorkerState.cs +++ b/src/SquidStd.Workers/Services/WorkerState.cs @@ -5,8 +5,8 @@ namespace SquidStd.Workers.Services; /// -/// Default backed by an interlocked counter; resolves identity and -/// concurrency from at construction. +/// Default backed by an interlocked counter; resolves identity and +/// concurrency from at construction. /// public sealed class WorkerState : IWorkerState { @@ -32,13 +32,9 @@ public WorkerState(WorkersConfig config) /// public void JobFinished() - { - Interlocked.Decrement(ref _activeJobs); - } + => Interlocked.Decrement(ref _activeJobs); /// public void JobStarted() - { - Interlocked.Increment(ref _activeJobs); - } + => Interlocked.Increment(ref _activeJobs); } diff --git a/tests/SquidStd.Tests/Abstractions/ConfigRegistrationDataTests.cs b/tests/SquidStd.Tests/Abstractions/ConfigRegistrationDataTests.cs index df9a2af0..d55e3d23 100644 --- a/tests/SquidStd.Tests/Abstractions/ConfigRegistrationDataTests.cs +++ b/tests/SquidStd.Tests/Abstractions/ConfigRegistrationDataTests.cs @@ -8,7 +8,7 @@ public class ConfigRegistrationDataTests [Fact] public void CreateDefault_IncompatibleFactory_Throws() { - var entry = new ConfigRegistrationData("test", typeof(TestConfig), () => new object()); + var entry = new ConfigRegistrationData("test", typeof(TestConfig), () => new()); Assert.Throws(() => entry.CreateDefault()); } @@ -34,18 +34,15 @@ public void CreateDefault_UsesFactory() [Fact] public void Ctor_InvalidSectionName_Throws() - { - Assert.Throws(() => new ConfigRegistrationData( + => Assert.Throws( + () => new ConfigRegistrationData( string.Empty, typeof(TestConfig), () => new TestConfig() ) ); - } [Fact] public void Ctor_NullType_Throws() - { - Assert.Throws(() => new ConfigRegistrationData("test", null!, () => new TestConfig())); - } + => Assert.Throws(() => new ConfigRegistrationData("test", null!, () => new TestConfig())); } diff --git a/tests/SquidStd.Tests/Actors/ActorAskTests.cs b/tests/SquidStd.Tests/Actors/ActorAskTests.cs index 29a4db32..5fbbbbb4 100644 --- a/tests/SquidStd.Tests/Actors/ActorAskTests.cs +++ b/tests/SquidStd.Tests/Actors/ActorAskTests.cs @@ -34,7 +34,7 @@ public async Task AskAsync_ReturnsReplyFromHandler() await actor.TellAsync(new Append("x")); await actor.TellAsync(new Append("y")); - var log = await actor.AskAsync(new GetLog()); + var log = await actor.AskAsync(new()); Assert.Equal("x,y", log); } @@ -47,7 +47,7 @@ public async Task AskAsync_WhenTokenCancelled_Faults() await actor.TellAsync(new Hold(gate)); // occupy the consumer so the request waits using var cts = new CancellationTokenSource(); - var ask = actor.AskAsync(new GetLog(), cts.Token); + var ask = actor.AskAsync(new(), cts.Token); cts.Cancel(); await Assert.ThrowsAsync(() => ask); diff --git a/tests/SquidStd.Tests/Actors/ActorErrorTests.cs b/tests/SquidStd.Tests/Actors/ActorErrorTests.cs index d09edca5..3900af98 100644 --- a/tests/SquidStd.Tests/Actors/ActorErrorTests.cs +++ b/tests/SquidStd.Tests/Actors/ActorErrorTests.cs @@ -1,4 +1,3 @@ -using SquidStd.Actors.Data; using SquidStd.Actors.Types; using SquidStd.Tests.Actors.Support; @@ -15,7 +14,7 @@ public async Task Isolate_KeepsProcessingAfterHandlerThrows() await actor.TellAsync(new Boom()); await actor.TellAsync(new Append("b")); - var log = await actor.AskAsync(new GetLog()); + var log = await actor.AskAsync(new()); Assert.Equal("a,b", log); Assert.Contains("boom", actor.Errors); @@ -26,9 +25,10 @@ public async Task AskAsync_PropagatesHandlerException() { await using var actor = new ProbeActor(); - var ex = await Assert.ThrowsAsync(() => - actor.AskAsync(new FailingRequest()) - ); + var ex = await Assert.ThrowsAsync( + () => + actor.AskAsync(new()) + ); Assert.Equal("ask-boom", ex.Message); } @@ -36,14 +36,11 @@ public async Task AskAsync_PropagatesHandlerException() [Fact] public async Task StopOnError_StopsProcessingAfterThrow() { - await using var actor = new ProbeActor( - new ActorOptions { ErrorPolicy = ActorErrorPolicy.StopOnError } - ); + await using var actor = new ProbeActor(new() { ErrorPolicy = ActorErrorPolicy.StopOnError }); await actor.TellAsync(new Boom()); // faults the mailbox await Task.Delay(50); - await Assert.ThrowsAsync(() => actor.AskAsync(new GetLog()) - ); + await Assert.ThrowsAsync(() => actor.AskAsync(new())); } } diff --git a/tests/SquidStd.Tests/Actors/ActorEventBusTests.cs b/tests/SquidStd.Tests/Actors/ActorEventBusTests.cs index f94daab5..ad6a96e9 100644 --- a/tests/SquidStd.Tests/Actors/ActorEventBusTests.cs +++ b/tests/SquidStd.Tests/Actors/ActorEventBusTests.cs @@ -16,7 +16,7 @@ public async Task SubscribeToEventBus_MapsEventsIntoMailboxInOrder() await bus.PublishAsync(new PingEvent("x")); await bus.PublishAsync(new PingEvent("y")); - var log = await actor.AskAsync(new GetLog()); + var log = await actor.AskAsync(new()); Assert.Equal("x,y", log); } @@ -31,7 +31,7 @@ public async Task SubscribeToEventBus_DisposingSubscription_StopsDelivery() subscription.Dispose(); await bus.PublishAsync(new PingEvent("second")); - var log = await actor.AskAsync(new GetLog()); + var log = await actor.AskAsync(new()); Assert.Equal("first", log); } } diff --git a/tests/SquidStd.Tests/Actors/ActorLifecycleTests.cs b/tests/SquidStd.Tests/Actors/ActorLifecycleTests.cs index 677c72f4..f71b3fd3 100644 --- a/tests/SquidStd.Tests/Actors/ActorLifecycleTests.cs +++ b/tests/SquidStd.Tests/Actors/ActorLifecycleTests.cs @@ -1,4 +1,3 @@ -using SquidStd.Actors.Data; using SquidStd.Tests.Actors.Support; namespace SquidStd.Tests.Actors; @@ -10,11 +9,11 @@ public async Task DisposeAsync_DrainsQueuedMessages() { var gate = new TaskCompletionSource(); var actor = new ProbeActor(); - await actor.TellAsync(new Hold(gate)); // in-flight, blocks until released (ignores cancellation) - await actor.TellAsync(new Append("a")); // queued behind the hold - await actor.TellAsync(new Append("b")); // queued behind the hold - var logTask = actor.AskAsync(new GetLog()); // queued last - await Task.Delay(50); // let the request enqueue before dispose completes the mailbox + await actor.TellAsync(new Hold(gate)); // in-flight, blocks until released (ignores cancellation) + await actor.TellAsync(new Append("a")); // queued behind the hold + await actor.TellAsync(new Append("b")); // queued behind the hold + var logTask = actor.AskAsync(new()); // queued last + await Task.Delay(50); // let the request enqueue before dispose completes the mailbox var disposeTask = actor.DisposeAsync(); gate.SetResult(); // release the hold so the queue can drain @@ -29,9 +28,9 @@ public async Task DisposeAsync_DrainsQueuedMessages() public async Task DisposeAsync_DrainTimeout_FaultsOutstandingAsk() { var gate = new TaskCompletionSource(); - var actor = new ProbeActor(new ActorOptions { ShutdownDrainTimeout = TimeSpan.FromMilliseconds(50) }); - await actor.TellAsync(new Hold(gate)); // in-flight, never released and ignores cancellation - var ask = actor.AskAsync(new GetLog()); // queued behind, never reached + var actor = new ProbeActor(new() { ShutdownDrainTimeout = TimeSpan.FromMilliseconds(50) }); + await actor.TellAsync(new Hold(gate)); // in-flight, never released and ignores cancellation + var ask = actor.AskAsync(new()); // queued behind, never reached await Task.Delay(50); await actor.DisposeAsync(); // drain exceeds the budget; the still-pending request is faulted @@ -47,8 +46,7 @@ public async Task TellAsync_AfterDispose_Throws() var actor = new ProbeActor(); await actor.DisposeAsync(); - await Assert.ThrowsAsync(async () => await actor.TellAsync(new Append("x")) - ); + await Assert.ThrowsAsync(async () => await actor.TellAsync(new Append("x"))); } [Fact] diff --git a/tests/SquidStd.Tests/Actors/ActorOrderingTests.cs b/tests/SquidStd.Tests/Actors/ActorOrderingTests.cs index fdc4b5be..0ad9ec37 100644 --- a/tests/SquidStd.Tests/Actors/ActorOrderingTests.cs +++ b/tests/SquidStd.Tests/Actors/ActorOrderingTests.cs @@ -14,7 +14,7 @@ public async Task Messages_AreProcessedInFifoOrder() await actor.TellAsync(new Append(i.ToString())); } - var log = await actor.AskAsync(new GetLog()); + var log = await actor.AskAsync(new()); Assert.Equal(string.Join(",", Enumerable.Range(0, 100)), log); } diff --git a/tests/SquidStd.Tests/Actors/ActorOverflowTests.cs b/tests/SquidStd.Tests/Actors/ActorOverflowTests.cs index 9da1daa4..8baba268 100644 --- a/tests/SquidStd.Tests/Actors/ActorOverflowTests.cs +++ b/tests/SquidStd.Tests/Actors/ActorOverflowTests.cs @@ -1,4 +1,3 @@ -using SquidStd.Actors.Data; using SquidStd.Actors.Types; using SquidStd.Tests.Actors.Support; @@ -10,9 +9,7 @@ public class ActorOverflowTests public async Task Wait_BlocksUntilCapacityFrees() { var gate = new TaskCompletionSource(); - await using var actor = new ProbeActor( - new ActorOptions { Capacity = 2, OverflowPolicy = ActorOverflowPolicy.Wait } - ); + await using var actor = new ProbeActor(new() { Capacity = 2, OverflowPolicy = ActorOverflowPolicy.Wait }); await actor.TellAsync(new Hold(gate)); // occupies the consumer (slot 1) await actor.TellAsync(new Append("a")); // buffered (slot 2) -> full @@ -29,9 +26,7 @@ public async Task Wait_BlocksUntilCapacityFrees() public async Task DropNewest_ReturnsFalseWhenFull() { var gate = new TaskCompletionSource(); - await using var actor = new ProbeActor( - new ActorOptions { Capacity = 1, OverflowPolicy = ActorOverflowPolicy.DropNewest } - ); + await using var actor = new ProbeActor(new() { Capacity = 1, OverflowPolicy = ActorOverflowPolicy.DropNewest }); await actor.TellAsync(new Hold(gate)); // occupies the only slot @@ -44,16 +39,14 @@ public async Task DropNewest_ReturnsFalseWhenFull() [Fact] public async Task Unbounded_AcceptsEveryMessage() { - await using var actor = new ProbeActor( - new ActorOptions { OverflowPolicy = ActorOverflowPolicy.Unbounded } - ); + await using var actor = new ProbeActor(new() { OverflowPolicy = ActorOverflowPolicy.Unbounded }); for (var i = 0; i < 500; i++) { Assert.True(await actor.TellAsync(new Append(i.ToString()))); } - var log = await actor.AskAsync(new GetLog()); + var log = await actor.AskAsync(new()); Assert.Equal(500, log.Split(",").Length); } } diff --git a/tests/SquidStd.Tests/Actors/Support/ProbeActor.cs b/tests/SquidStd.Tests/Actors/Support/ProbeActor.cs index 07474013..434b72fd 100644 --- a/tests/SquidStd.Tests/Actors/Support/ProbeActor.cs +++ b/tests/SquidStd.Tests/Actors/Support/ProbeActor.cs @@ -12,9 +12,7 @@ public sealed class ProbeActor : Actor public List Errors { get; } = new(); public ProbeActor(ActorOptions? options = null) - : base(options) - { - } + : base(options) { } protected override async ValueTask ReceiveAsync(IProbeMessage message, CancellationToken cancellationToken) { @@ -22,17 +20,21 @@ protected override async ValueTask ReceiveAsync(IProbeMessage message, Cancellat { case Append append: _log.Add(append.Value); + break; case Boom: throw new InvalidOperationException("boom"); case Hold hold: await hold.Gate.Task; + break; case HoldUntilCancelled: await Task.Delay(Timeout.Infinite, cancellationToken); + break; case GetLog getLog: getLog.Reply(string.Join(",", _log)); + break; case FailingRequest: throw new InvalidOperationException("ask-boom"); diff --git a/tests/SquidStd.Tests/Actors/Support/ProbeMessages.cs b/tests/SquidStd.Tests/Actors/Support/ProbeMessages.cs index b421e2a2..9eab0e24 100644 --- a/tests/SquidStd.Tests/Actors/Support/ProbeMessages.cs +++ b/tests/SquidStd.Tests/Actors/Support/ProbeMessages.cs @@ -3,9 +3,7 @@ namespace SquidStd.Tests.Actors.Support; /// Marker interface for every message the accepts. -public interface IProbeMessage -{ -} +public interface IProbeMessage { } /// Appends a value to the actor's log. public sealed record Append(string Value) : IProbeMessage; diff --git a/tests/SquidStd.Tests/AspNetCore/FakeSquidStdBootstrap.cs b/tests/SquidStd.Tests/AspNetCore/FakeSquidStdBootstrap.cs index a2d78432..17489326 100644 --- a/tests/SquidStd.Tests/AspNetCore/FakeSquidStdBootstrap.cs +++ b/tests/SquidStd.Tests/AspNetCore/FakeSquidStdBootstrap.cs @@ -15,9 +15,7 @@ internal sealed class FakeSquidStdBootstrap : ISquidStdBootstrap public IContainer Container { get; } = new Container(); public ISquidStdBootstrap ConfigureService(Func configure) - { - return ConfigureServices(configure); - } + => ConfigureServices(configure); public ISquidStdBootstrap ConfigureServices(Func configure) { @@ -25,8 +23,8 @@ public ISquidStdBootstrap ConfigureServices(Func configu var configuredContainer = configure(Container); return ReferenceEquals(configuredContainer, Container) - ? this - : throw new InvalidOperationException("ConfigureServices must return the bootstrap container instance."); + ? this + : throw new InvalidOperationException("ConfigureServices must return the bootstrap container instance."); } public ValueTask DisposeAsync() @@ -37,14 +35,10 @@ public ValueTask DisposeAsync() } public TService Resolve() - { - return Container.Resolve(); - } + => Container.Resolve(); public async Task RunAsync(CancellationToken cancellationToken = default) - { - await StartAsync(cancellationToken); - } + => await StartAsync(cancellationToken); public ValueTask StartAsync(CancellationToken cancellationToken = default) { diff --git a/tests/SquidStd.Tests/AspNetCore/SquidStdAspNetCoreBuilderExtensionsTests.cs b/tests/SquidStd.Tests/AspNetCore/SquidStdAspNetCoreBuilderExtensionsTests.cs index 994698a1..c29c0a56 100644 --- a/tests/SquidStd.Tests/AspNetCore/SquidStdAspNetCoreBuilderExtensionsTests.cs +++ b/tests/SquidStd.Tests/AspNetCore/SquidStdAspNetCoreBuilderExtensionsTests.cs @@ -108,7 +108,8 @@ public void UseSquidStd_WhenContainerCallbackReturnsDifferentContainer_Throws() using var temp = new TempDirectory(); var builder = CreateBuilder(temp.Path); - var ex = Assert.Throws(() => builder.UseSquidStd( + var ex = Assert.Throws( + () => builder.UseSquidStd( options => options.ConfigName = "app", _ => new Container() ) diff --git a/tests/SquidStd.Tests/AspNetCore/SquidStdHealthCheckAdapterTests.cs b/tests/SquidStd.Tests/AspNetCore/SquidStdHealthCheckAdapterTests.cs index 53ee2055..069efe15 100644 --- a/tests/SquidStd.Tests/AspNetCore/SquidStdHealthCheckAdapterTests.cs +++ b/tests/SquidStd.Tests/AspNetCore/SquidStdHealthCheckAdapterTests.cs @@ -12,7 +12,7 @@ public async Task CheckHealthAsync_MapsHealthy() { var adapter = new SquidStdHealthCheckAdapter(new FakeHealthCheck("ok", SquidHealthResult.Healthy("all good"))); - var result = await adapter.CheckHealthAsync(new HealthCheckContext()); + var result = await adapter.CheckHealthAsync(new()); Assert.Equal(HealthStatus.Healthy, result.Status); Assert.Equal("all good", result.Description); @@ -24,7 +24,7 @@ public async Task CheckHealthAsync_MapsUnhealthy_WithDescriptionAndException() var ex = new InvalidOperationException("boom"); var adapter = new SquidStdHealthCheckAdapter(new FakeHealthCheck("bad", SquidHealthResult.Unhealthy("down", ex))); - var result = await adapter.CheckHealthAsync(new HealthCheckContext()); + var result = await adapter.CheckHealthAsync(new()); Assert.Equal(HealthStatus.Unhealthy, result.Status); Assert.Equal("down", result.Description); diff --git a/tests/SquidStd.Tests/Bootstrap/SquidStdBootstrapTests.cs b/tests/SquidStd.Tests/Bootstrap/SquidStdBootstrapTests.cs index caa9a1bb..f01952fb 100644 --- a/tests/SquidStd.Tests/Bootstrap/SquidStdBootstrapTests.cs +++ b/tests/SquidStd.Tests/Bootstrap/SquidStdBootstrapTests.cs @@ -19,7 +19,7 @@ public async Task Create_RegistersBootstrapAndDefaultServices() { using var temp = new TempDirectory(); await using var bootstrap = - SquidStdBootstrap.Create(new SquidStdOptions { ConfigName = "app", RootDirectory = temp.Path }); + SquidStdBootstrap.Create(new() { ConfigName = "app", RootDirectory = temp.Path }); var resolved = bootstrap.Resolve(); var configManager = bootstrap.Resolve(); @@ -36,7 +36,7 @@ public async Task Create_WithContainer_UsesProvidedContainer() var container = new Container(); await using var bootstrap = SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "app", RootDirectory = temp.Path @@ -58,15 +58,13 @@ public async Task DisposeAsync_WithProvidedContainer_DoesNotDisposeContainer() var container = new Container(); await using (SquidStdBootstrap.Create( - new SquidStdOptions + new() { ConfigName = "app", RootDirectory = temp.Path }, container - )) - { - } + )) { } container.RegisterInstance("still-open"); @@ -82,9 +80,10 @@ public async Task RunAsync_StartsUntilCancellationThenStops() using var cancellation = new CancellationTokenSource(); var state = new RunTrackedState(); await using var bootstrap = - SquidStdBootstrap.Create(new SquidStdOptions { ConfigName = "app", RootDirectory = temp.Path }); + SquidStdBootstrap.Create(new() { ConfigName = "app", RootDirectory = temp.Path }); - bootstrap.ConfigureService(container => + bootstrap.ConfigureService( + container => { container.RegisterInstance(state); container.Register(Reuse.Singleton); @@ -127,7 +126,7 @@ public async Task StartAsync_ConfiguresFileSinkFromLoggerOptions() """ ); await using var bootstrap = - SquidStdBootstrap.Create(new SquidStdOptions { ConfigName = "app", RootDirectory = temp.Path }); + SquidStdBootstrap.Create(new() { ConfigName = "app", RootDirectory = temp.Path }); await bootstrap.StartAsync(CancellationToken.None); await bootstrap.StopAsync(CancellationToken.None); @@ -153,9 +152,10 @@ public async Task StartAsync_LoadsConfigBeforeResolvingRegisteredServices() ); var events = new List(); await using var bootstrap = - SquidStdBootstrap.Create(new SquidStdOptions { ConfigName = "app", RootDirectory = temp.Path }); + SquidStdBootstrap.Create(new() { ConfigName = "app", RootDirectory = temp.Path }); - bootstrap.ConfigureServices(container => + bootstrap.ConfigureServices( + container => { container.RegisterInstance(events); container.Register(Reuse.Singleton); @@ -183,9 +183,10 @@ public async Task StartAsync_OrdersServicesByPriorityAndStopAsync_ReversesOrder( using var temp = new TempDirectory(); var events = new List(); await using var bootstrap = - SquidStdBootstrap.Create(new SquidStdOptions { ConfigName = "app", RootDirectory = temp.Path }); + SquidStdBootstrap.Create(new() { ConfigName = "app", RootDirectory = temp.Path }); - bootstrap.ConfigureServices(container => + bootstrap.ConfigureServices( + container => { container.RegisterInstance(events); container.Register(Reuse.Singleton); @@ -222,9 +223,7 @@ public ValueTask StartAsync(CancellationToken cancellationToken = default) } public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; } private sealed class EarlyTrackedService(List events) : ISquidStdService diff --git a/tests/SquidStd.Tests/Caching/CacheMetricsProviderTests.cs b/tests/SquidStd.Tests/Caching/CacheMetricsProviderTests.cs index 2448e664..fa35387f 100644 --- a/tests/SquidStd.Tests/Caching/CacheMetricsProviderTests.cs +++ b/tests/SquidStd.Tests/Caching/CacheMetricsProviderTests.cs @@ -17,9 +17,7 @@ public async Task CollectAsync_ReportsCountersAndHitRatio() var samples = await metrics.CollectAsync(); double Value(string name) - { - return samples.Single(s => s.Name == name).Value; - } + => samples.Single(s => s.Name == name).Value; Assert.Equal(2, Value("hits")); Assert.Equal(1, Value("misses")); @@ -30,7 +28,5 @@ double Value(string name) [Fact] public void ProviderName_IsCache() - { - Assert.Equal("cache", new CacheMetricsProvider().ProviderName); - } + => Assert.Equal("cache", new CacheMetricsProvider().ProviderName); } diff --git a/tests/SquidStd.Tests/Caching/CacheServiceTests.cs b/tests/SquidStd.Tests/Caching/CacheServiceTests.cs index 66fc9f05..aa490ce6 100644 --- a/tests/SquidStd.Tests/Caching/CacheServiceTests.cs +++ b/tests/SquidStd.Tests/Caching/CacheServiceTests.cs @@ -9,26 +9,24 @@ public class CacheServiceTests { [Fact] public async Task Get_Missing_ReturnsDefault() - { - Assert.Null(await NewService(new FakeCacheProvider()).GetAsync("absent")); - } + => Assert.Null(await NewService(new()).GetAsync("absent")); [Fact] public async Task GetOrSet_Hit_DoesNotInvokeFactory() { - var service = NewService(new FakeCacheProvider()); + var service = NewService(new()); await service.SetAsync("k", 7); var calls = 0; var value = await service.GetOrSetAsync( - "k", - _ => - { - calls++; + "k", + _ => + { + calls++; - return Task.FromResult(0); - } - ); + return Task.FromResult(0); + } + ); Assert.Equal(7, value); Assert.Equal(0, calls); @@ -42,14 +40,14 @@ public async Task GetOrSet_Miss_InvokesFactoryAndStores() var calls = 0; var value = await service.GetOrSetAsync( - "k", - _ => - { - calls++; + "k", + _ => + { + calls++; - return Task.FromResult(99); - } - ); + return Task.FromResult(99); + } + ); Assert.Equal(99, value); Assert.Equal(1, calls); @@ -60,7 +58,7 @@ public async Task GetOrSet_Miss_InvokesFactoryAndStores() public async Task KeyPrefix_IsAppliedToProvider() { var provider = new FakeCacheProvider(); - var service = NewService(provider, new CacheOptions { KeyPrefix = "app:" }); + var service = NewService(provider, new() { KeyPrefix = "app:" }); await service.SetAsync("k", "v"); @@ -72,7 +70,7 @@ public async Task KeyPrefix_IsAppliedToProvider() public async Task Metrics_RecordHitAndMiss() { var metrics = new CacheMetricsProvider(); - var service = NewService(new FakeCacheProvider(), metrics: metrics); + var service = NewService(new(), metrics: metrics); await service.GetAsync("absent"); // miss await service.SetAsync("k", 1); @@ -87,7 +85,7 @@ public async Task Metrics_RecordHitAndMiss() public async Task Set_PerEntryTtl_OverridesDefault() { var provider = new FakeCacheProvider(); - var service = NewService(provider, new CacheOptions { DefaultTtl = TimeSpan.FromSeconds(30) }); + var service = NewService(provider, new() { DefaultTtl = TimeSpan.FromSeconds(30) }); await service.SetAsync("k", "v", TimeSpan.FromSeconds(5)); @@ -98,7 +96,7 @@ public async Task Set_PerEntryTtl_OverridesDefault() public async Task Set_UsesDefaultTtl_WhenNoneGiven() { var provider = new FakeCacheProvider(); - var service = NewService(provider, new CacheOptions { DefaultTtl = TimeSpan.FromSeconds(30) }); + var service = NewService(provider, new() { DefaultTtl = TimeSpan.FromSeconds(30) }); await service.SetAsync("k", "v"); @@ -108,7 +106,7 @@ public async Task Set_UsesDefaultTtl_WhenNoneGiven() [Fact] public async Task SetThenGet_RoundTrips() { - var service = NewService(new FakeCacheProvider()); + var service = NewService(new()); await service.SetAsync("k", 42); @@ -123,6 +121,6 @@ private static CacheService NewService( { var serializer = new JsonDataSerializer(); - return new CacheService(provider, serializer, serializer, options ?? new CacheOptions(), metrics); + return new(provider, serializer, serializer, options ?? new CacheOptions(), metrics); } } diff --git a/tests/SquidStd.Tests/Caching/InMemoryCacheProviderTests.cs b/tests/SquidStd.Tests/Caching/InMemoryCacheProviderTests.cs index 5fc13cfc..c803d1b3 100644 --- a/tests/SquidStd.Tests/Caching/InMemoryCacheProviderTests.cs +++ b/tests/SquidStd.Tests/Caching/InMemoryCacheProviderTests.cs @@ -20,9 +20,7 @@ public async Task Exists_And_Remove() [Fact] public async Task Get_Missing_ReturnsNull() - { - Assert.Null(await NewProvider().GetAsync("absent")); - } + => Assert.Null(await NewProvider().GetAsync("absent")); [Fact] public async Task SetThenGet_ReturnsValue() @@ -48,12 +46,8 @@ public async Task Ttl_Expires() } private static ReadOnlyMemory Bytes(string s) - { - return Encoding.UTF8.GetBytes(s); - } + => Encoding.UTF8.GetBytes(s); private static InMemoryCacheProvider NewProvider() - { - return new InMemoryCacheProvider(new MemoryCache(new MemoryCacheOptions())); - } + => new(new MemoryCache(new MemoryCacheOptions())); } diff --git a/tests/SquidStd.Tests/Caching/Redis/RedisCacheProviderTests.cs b/tests/SquidStd.Tests/Caching/Redis/RedisCacheProviderTests.cs index 42906a5c..e3e0b318 100644 --- a/tests/SquidStd.Tests/Caching/Redis/RedisCacheProviderTests.cs +++ b/tests/SquidStd.Tests/Caching/Redis/RedisCacheProviderTests.cs @@ -1,5 +1,4 @@ using System.Text; -using SquidStd.Caching.Redis.Data.Config; using SquidStd.Caching.Redis.Services; namespace SquidStd.Tests.Caching.Redis; @@ -57,22 +56,14 @@ public async Task Ttl_Expires() } private static ReadOnlyMemory Bytes(string s) - { - return Encoding.UTF8.GetBytes(s); - } + => Encoding.UTF8.GetBytes(s); private static string Key() - { - return "k-" + Guid.NewGuid().ToString("N"); - } + => "k-" + Guid.NewGuid().ToString("N"); private RedisCacheProvider NewProvider() - { - return new RedisCacheProvider(new RedisCacheOptions { Configuration = _fixture.ConnectionString }); - } + => new(new() { Configuration = _fixture.ConnectionString }); private static string Text(ReadOnlyMemory b) - { - return Encoding.UTF8.GetString(b.Span); - } + => Encoding.UTF8.GetString(b.Span); } diff --git a/tests/SquidStd.Tests/Caching/Redis/RedisContainerFixture.cs b/tests/SquidStd.Tests/Caching/Redis/RedisContainerFixture.cs index 8d7df788..bd17f84e 100644 --- a/tests/SquidStd.Tests/Caching/Redis/RedisContainerFixture.cs +++ b/tests/SquidStd.Tests/Caching/Redis/RedisContainerFixture.cs @@ -3,7 +3,7 @@ namespace SquidStd.Tests.Caching.Redis; /// -/// Starts a Redis container once for the whole collection and exposes its connection string. +/// Starts a Redis container once for the whole collection and exposes its connection string. /// public sealed class RedisContainerFixture : IAsyncLifetime { @@ -12,14 +12,10 @@ public sealed class RedisContainerFixture : IAsyncLifetime public string ConnectionString => _container.GetConnectionString(); public Task DisposeAsync() - { - return _container.DisposeAsync().AsTask(); - } + => _container.DisposeAsync().AsTask(); public Task InitializeAsync() - { - return _container.StartAsync(); - } + => _container.StartAsync(); } [CollectionDefinition(Name)] diff --git a/tests/SquidStd.Tests/Core/Extensions/Random/RandomExtensionsTests.cs b/tests/SquidStd.Tests/Core/Extensions/Random/RandomExtensionsTests.cs index a37472ed..cea8f810 100644 --- a/tests/SquidStd.Tests/Core/Extensions/Random/RandomExtensionsTests.cs +++ b/tests/SquidStd.Tests/Core/Extensions/Random/RandomExtensionsTests.cs @@ -42,9 +42,7 @@ public void RandomElement_ReturnsElementFromSource() [Fact] public void RandomElement_OnEmpty_ReturnsDefault() - { - Assert.Equal(0, Array.Empty().RandomElement()); - } + => Assert.Equal(0, Array.Empty().RandomElement()); [Fact] public void RandomElement_OnList_ReturnsElementFromSource() diff --git a/tests/SquidStd.Tests/Core/Extensions/Strings/Base64ExtensionsTests.cs b/tests/SquidStd.Tests/Core/Extensions/Strings/Base64ExtensionsTests.cs index f704254b..df6a32f2 100644 --- a/tests/SquidStd.Tests/Core/Extensions/Strings/Base64ExtensionsTests.cs +++ b/tests/SquidStd.Tests/Core/Extensions/Strings/Base64ExtensionsTests.cs @@ -31,13 +31,7 @@ public void FromBase64ToByteArray_DecodesBytes() Assert.Equal(bytes, encoded.FromBase64ToByteArray()); } - [Theory] - [InlineData("c3F1aWQ=", true)] - [InlineData("not base64!", false)] - [InlineData("abc", false)] - [InlineData("", false)] + [Theory, InlineData("c3F1aWQ=", true), InlineData("not base64!", false), InlineData("abc", false), InlineData("", false)] public void IsBase64String_DetectsValidPayloads(string value, bool expected) - { - Assert.Equal(expected, value.IsBase64String()); - } + => Assert.Equal(expected, value.IsBase64String()); } diff --git a/tests/SquidStd.Tests/Core/Pool/ObjectPoolTests.cs b/tests/SquidStd.Tests/Core/Pool/ObjectPoolTests.cs index 4305724b..6749d691 100644 --- a/tests/SquidStd.Tests/Core/Pool/ObjectPoolTests.cs +++ b/tests/SquidStd.Tests/Core/Pool/ObjectPoolTests.cs @@ -8,11 +8,12 @@ public class ObjectPoolTests public void Get_WhenEmpty_CreatesThroughFactory() { var created = 0; - using var pool = new ObjectPool(() => + using var pool = new ObjectPool( + () => { created++; - return new Boxed(); + return new(); } ); @@ -25,7 +26,7 @@ public void Get_WhenEmpty_CreatesThroughFactory() [Fact] public void Return_ThenGet_ReusesSameInstance() { - using var pool = new ObjectPool(() => new Boxed()); + using var pool = new ObjectPool(() => new()); var first = pool.Get(); pool.Return(first); @@ -38,7 +39,7 @@ public void Return_ThenGet_ReusesSameInstance() [Fact] public void Return_InvokesResetCallback() { - using var pool = new ObjectPool(() => new Boxed(), onReturn: boxed => boxed.Value = 0); + using var pool = new ObjectPool(() => new(), onReturn: boxed => boxed.Value = 0); var item = pool.Get(); item.Value = 42; @@ -50,7 +51,7 @@ public void Return_InvokesResetCallback() [Fact] public void Return_BeyondMaxRetained_DisposesInsteadOfPooling() { - using var pool = new ObjectPool(() => new Boxed(), 1); + using var pool = new ObjectPool(() => new(), 1); var kept = new Boxed(); var overflow = new Boxed(); @@ -65,7 +66,7 @@ public void Return_BeyondMaxRetained_DisposesInsteadOfPooling() [Fact] public void Dispose_DisposesRetainedInstances() { - var pool = new ObjectPool(() => new Boxed()); + var pool = new ObjectPool(() => new()); var item = pool.Get(); pool.Return(item); @@ -81,8 +82,6 @@ private sealed class Boxed : IDisposable public bool Disposed { get; private set; } public void Dispose() - { - Disposed = true; - } + => Disposed = true; } } diff --git a/tests/SquidStd.Tests/Core/Utils/ChecksumUtilsTests.cs b/tests/SquidStd.Tests/Core/Utils/ChecksumUtilsTests.cs index 047b3fe9..cf90385b 100644 --- a/tests/SquidStd.Tests/Core/Utils/ChecksumUtilsTests.cs +++ b/tests/SquidStd.Tests/Core/Utils/ChecksumUtilsTests.cs @@ -11,10 +11,9 @@ public void Compute_EmptyInput_ReturnsOffsetBasis() [Fact] public void Compute_KnownVector_MatchesFnv1a() - { + // FNV-1a 32-bit of ASCII "a" = 0xE40C292C. - Assert.Equal(0xE40C292Cu, ChecksumUtils.Compute("a"u8)); - } + => Assert.Equal(0xE40C292Cu, ChecksumUtils.Compute("a"u8)); [Fact] public void Compute_IsStableAcrossCalls() diff --git a/tests/SquidStd.Tests/Core/Utils/CryptoUtilsTests.cs b/tests/SquidStd.Tests/Core/Utils/CryptoUtilsTests.cs index beaeeab0..b879477d 100644 --- a/tests/SquidStd.Tests/Core/Utils/CryptoUtilsTests.cs +++ b/tests/SquidStd.Tests/Core/Utils/CryptoUtilsTests.cs @@ -27,10 +27,7 @@ public void Encrypt_ProducesDifferentPayloadsPerCall() Assert.NotEqual(first, second); } - [Theory] - [InlineData(16)] - [InlineData(24)] - [InlineData(32)] + [Theory, InlineData(16), InlineData(24), InlineData(32)] public void GenerateKey_ReturnsKeyOfRequestedSize(int size) { var key = Convert.FromBase64String(CryptoUtils.GenerateKey(size)); @@ -40,9 +37,7 @@ public void GenerateKey_ReturnsKeyOfRequestedSize(int size) [Fact] public void GenerateKey_WhenSizeInvalid_Throws() - { - Assert.Throws(() => CryptoUtils.GenerateKey(20)); - } + => Assert.Throws(() => CryptoUtils.GenerateKey(20)); [Fact] public void Decrypt_WithWrongKey_Throws() diff --git a/tests/SquidStd.Tests/Core/Utils/RngCollection.cs b/tests/SquidStd.Tests/Core/Utils/RngCollection.cs index c6fd733e..414525ba 100644 --- a/tests/SquidStd.Tests/Core/Utils/RngCollection.cs +++ b/tests/SquidStd.Tests/Core/Utils/RngCollection.cs @@ -1,10 +1,8 @@ namespace SquidStd.Tests.Core.Utils; /// -/// Serializes tests that exercise the global state so a -/// seeded sequence is not perturbed by concurrent consumers. +/// Serializes tests that exercise the global state so a +/// seeded sequence is not perturbed by concurrent consumers. /// [CollectionDefinition("BuiltInRng")] -public sealed class RngCollection -{ -} +public sealed class RngCollection { } diff --git a/tests/SquidStd.Tests/Core/Utils/SslUtilsTests.cs b/tests/SquidStd.Tests/Core/Utils/SslUtilsTests.cs index 0a1bd0ad..6c5d20cc 100644 --- a/tests/SquidStd.Tests/Core/Utils/SslUtilsTests.cs +++ b/tests/SquidStd.Tests/Core/Utils/SslUtilsTests.cs @@ -75,7 +75,5 @@ public void LoadFromPfx_LoadsCertificateWithPrivateKey() [Fact] public void LoadFromPem_WhenPathBlank_Throws() - { - Assert.Throws(() => SslUtils.LoadFromPem(" ")); - } + => Assert.Throws(() => SslUtils.LoadFromPem(" ")); } diff --git a/tests/SquidStd.Tests/Crypto/Pgp/AesGcmPgpKeyStoreTests.cs b/tests/SquidStd.Tests/Crypto/Pgp/AesGcmPgpKeyStoreTests.cs index d4e820db..6b8bb4c3 100644 --- a/tests/SquidStd.Tests/Crypto/Pgp/AesGcmPgpKeyStoreTests.cs +++ b/tests/SquidStd.Tests/Crypto/Pgp/AesGcmPgpKeyStoreTests.cs @@ -1,5 +1,4 @@ using System.Text; -using SquidStd.Core.Data.Storage; using SquidStd.Crypto.Pgp.Services; using SquidStd.Services.Core.Services.Storage; using SquidStd.Tests.Crypto.Pgp.Support; @@ -20,7 +19,7 @@ public AesGcmPgpKeyStoreTests(PgpTestKeys keys) public async Task SaveThenLoad_RoundTripsAndBlobIsNotPlaintext() { var path = Path.Combine(Path.GetTempPath(), "squidstd-pgp-" + Guid.NewGuid().ToString("N") + ".bin"); - var protector = new AesGcmSecretProtector(new SecretsConfig()); + var protector = new AesGcmSecretProtector(new()); try { diff --git a/tests/SquidStd.Tests/Crypto/Pgp/FilePgpKeyStoreTests.cs b/tests/SquidStd.Tests/Crypto/Pgp/FilePgpKeyStoreTests.cs index f905de9a..de8af47a 100644 --- a/tests/SquidStd.Tests/Crypto/Pgp/FilePgpKeyStoreTests.cs +++ b/tests/SquidStd.Tests/Crypto/Pgp/FilePgpKeyStoreTests.cs @@ -38,7 +38,7 @@ public async Task SaveThenLoad_RestoresPublicAndSecretKeys() { if (Directory.Exists(dir)) { - Directory.Delete(dir, recursive: true); + Directory.Delete(dir, true); } } } diff --git a/tests/SquidStd.Tests/Crypto/Pgp/PgpServiceEncryptionTests.cs b/tests/SquidStd.Tests/Crypto/Pgp/PgpServiceEncryptionTests.cs index 0a1904c8..d48d5304 100644 --- a/tests/SquidStd.Tests/Crypto/Pgp/PgpServiceEncryptionTests.cs +++ b/tests/SquidStd.Tests/Crypto/Pgp/PgpServiceEncryptionTests.cs @@ -35,7 +35,8 @@ public async Task EncryptFor_UnknownRecipient_ThrowsKeyNotFound() { var service = new PgpService(new PgpKeyring()); - await Assert.ThrowsAsync(() => service.EncryptForAsync( + await Assert.ThrowsAsync( + () => service.EncryptForAsync( "nobody@squidstd.test", Encoding.UTF8.GetBytes("x") ) diff --git a/tests/SquidStd.Tests/Crypto/Pgp/PgpServiceSigningTests.cs b/tests/SquidStd.Tests/Crypto/Pgp/PgpServiceSigningTests.cs index cad70f8d..f3554f36 100644 --- a/tests/SquidStd.Tests/Crypto/Pgp/PgpServiceSigningTests.cs +++ b/tests/SquidStd.Tests/Crypto/Pgp/PgpServiceSigningTests.cs @@ -37,10 +37,10 @@ public async Task Verify_TamperedMessage_IsInvalid() var service = new PgpService(keyring); var signed = await service.SignAsync( - Encoding.UTF8.GetBytes("original"), - PgpTestKeys.AliceIdentity, - PgpTestKeys.AlicePassphrase - ); + Encoding.UTF8.GetBytes("original"), + PgpTestKeys.AliceIdentity, + PgpTestKeys.AlicePassphrase + ); var tampered = MutateBody(signed); var result = await service.VerifyAsync(tampered); @@ -58,11 +58,11 @@ public async Task EncryptAndSign_ThenDecryptAndVerify_RoundTripsAndValidates() var payload = Encoding.UTF8.GetBytes("confidential and signed"); var armored = await service.EncryptAndSignForAsync( - PgpTestKeys.AliceIdentity, - payload, - PgpTestKeys.BobIdentity, - PgpTestKeys.BobPassphrase - ); + PgpTestKeys.AliceIdentity, + payload, + PgpTestKeys.BobIdentity, + PgpTestKeys.BobPassphrase + ); var result = await service.DecryptAndVerifyAsync(armored, PgpTestKeys.AlicePassphrase); Assert.Equal(payload, result.Data); @@ -80,11 +80,11 @@ public async Task DecryptAndVerify_SignerNotInKeyring_RecoversDataButInvalid() var signingService = new PgpService(signingKeyring); var payload = Encoding.UTF8.GetBytes("signed by an unknown party"); var armored = await signingService.EncryptAndSignForAsync( - PgpTestKeys.AliceIdentity, - payload, - PgpTestKeys.BobIdentity, - PgpTestKeys.BobPassphrase - ); + PgpTestKeys.AliceIdentity, + payload, + PgpTestKeys.BobIdentity, + PgpTestKeys.BobPassphrase + ); var recipientOnly = new PgpKeyring(); recipientOnly.Import(_keys.AlicePrivate); // no Bob public key @@ -107,7 +107,7 @@ private static string MutateBody(string signed) { var chars = lines[mid].ToCharArray(); chars[2] = chars[2] == 'A' ? 'B' : 'A'; - lines[mid] = new string(chars); + lines[mid] = new(chars); } return string.Join('\n', lines); diff --git a/tests/SquidStd.Tests/Crypto/Pgp/Support/PgpKeysCollection.cs b/tests/SquidStd.Tests/Crypto/Pgp/Support/PgpKeysCollection.cs index 93185bd8..1529fdde 100644 --- a/tests/SquidStd.Tests/Crypto/Pgp/Support/PgpKeysCollection.cs +++ b/tests/SquidStd.Tests/Crypto/Pgp/Support/PgpKeysCollection.cs @@ -2,6 +2,4 @@ namespace SquidStd.Tests.Crypto.Pgp.Support; /// Shares one instance across the PGP test classes. [CollectionDefinition("PgpKeys")] -public sealed class PgpKeysCollection : ICollectionFixture -{ -} +public sealed class PgpKeysCollection : ICollectionFixture { } diff --git a/tests/SquidStd.Tests/Crypto/Pgp/Support/PgpTestKeys.cs b/tests/SquidStd.Tests/Crypto/Pgp/Support/PgpTestKeys.cs index 16b6e9ce..e87d29bf 100644 --- a/tests/SquidStd.Tests/Crypto/Pgp/Support/PgpTestKeys.cs +++ b/tests/SquidStd.Tests/Crypto/Pgp/Support/PgpTestKeys.cs @@ -1,10 +1,11 @@ +using System.Text; using PgpCore; namespace SquidStd.Tests.Crypto.Pgp.Support; /// -/// Generates two throwaway armored RSA-2048 key pairs once for the whole assembly. Key generation is -/// expensive, so tests share this fixture via . +/// Generates two throwaway armored RSA-2048 key pairs once for the whole assembly. Key generation is +/// expensive, so tests share this fixture via . /// public sealed class PgpTestKeys { @@ -38,7 +39,5 @@ private static (string Public, string Private) Generate(string identity, string } private static string ReadAll(MemoryStream stream) - { - return System.Text.Encoding.UTF8.GetString(stream.ToArray()); - } + => Encoding.UTF8.GetString(stream.ToArray()); } diff --git a/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemDiskTests.cs b/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemDiskTests.cs index b92cc5b5..e7f832d2 100644 --- a/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemDiskTests.cs +++ b/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemDiskTests.cs @@ -8,9 +8,7 @@ namespace SquidStd.Tests.Crypto.Vfs; public class CryptoFileSystemDiskTests { private static CryptoVaultOptions FastOptions() - { - return new CryptoVaultOptions { Argon2MemoryKib = 8192, Argon2Iterations = 1 }; - } + => new() { Argon2MemoryKib = 8192, Argon2Iterations = 1 }; [Fact] public async Task Lock_AfterWrites_OverZipBackend_DoesNotThrow() diff --git a/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemLockTests.cs b/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemLockTests.cs index 94353dfb..87db65ef 100644 --- a/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemLockTests.cs +++ b/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemLockTests.cs @@ -8,9 +8,7 @@ namespace SquidStd.Tests.Crypto.Vfs; public class CryptoFileSystemLockTests { private static CryptoVaultOptions FastOptions() - { - return new CryptoVaultOptions { Argon2MemoryKib = 8192, Argon2Iterations = 1 }; - } + => new() { Argon2MemoryKib = 8192, Argon2Iterations = 1 }; [Fact] public async Task LockedOperations_Throw_UntilUnlocked() @@ -18,8 +16,7 @@ public async Task LockedOperations_Throw_UntilUnlocked() var vault = new CryptoFileSystem(new InMemoryFileSystem(), FastOptions()); Assert.False(vault.IsUnlocked); - await Assert.ThrowsAsync(() => vault.WriteAllBytesAsync("a", new byte[] { 1 }).AsTask() - ); + await Assert.ThrowsAsync(() => vault.WriteAllBytesAsync("a", new byte[] { 1 }).AsTask()); vault.Unlock("pw"); Assert.True(vault.IsUnlocked); diff --git a/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemTests.cs b/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemTests.cs index 394594c6..83f1f436 100644 --- a/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemTests.cs +++ b/tests/SquidStd.Tests/Crypto/Vfs/CryptoFileSystemTests.cs @@ -9,9 +9,7 @@ namespace SquidStd.Tests.Crypto.Vfs; public class CryptoFileSystemTests { private static CryptoVaultOptions FastOptions() - { - return new CryptoVaultOptions { Argon2MemoryKib = 8192, Argon2Iterations = 1 }; - } + => new() { Argon2MemoryKib = 8192, Argon2Iterations = 1 }; [Fact] public async Task Write_Read_List_Delete_RoundTrips() @@ -23,6 +21,7 @@ public async Task Write_Read_List_Delete_RoundTrips() Assert.Equal("hello", Encoding.UTF8.GetString((await vault.ReadAllBytesAsync("docs/cv.pdf"))!)); var paths = new List(); + await foreach (var e in vault.ListAsync()) { paths.Add(e.Path); diff --git a/tests/SquidStd.Tests/Crypto/Vfs/EntryCipherTests.cs b/tests/SquidStd.Tests/Crypto/Vfs/EntryCipherTests.cs index 4a10faa1..418e31b6 100644 --- a/tests/SquidStd.Tests/Crypto/Vfs/EntryCipherTests.cs +++ b/tests/SquidStd.Tests/Crypto/Vfs/EntryCipherTests.cs @@ -13,7 +13,7 @@ public async Task EncryptThenDecrypt_RoundTripsAcrossChunkBoundaries() var key = RandomNumberGenerator.GetBytes(32); var payload = RandomNumberGenerator.GetBytes(200_000); // > 3 chunks at 64 KiB - using var cipher = new EntryCipher(key, chunkSize: 65536); + using var cipher = new EntryCipher(key, 65536); using var encrypted = new MemoryStream(); await cipher.EncryptAsync(new MemoryStream(payload), encrypted); @@ -34,7 +34,8 @@ public async Task Decrypt_WrongKey_Throws() using var wrong = new EntryCipher(RandomNumberGenerator.GetBytes(32), 65536); encrypted.Position = 0; - await Assert.ThrowsAsync(() => wrong.DecryptAsync(encrypted, new MemoryStream()) + await Assert.ThrowsAsync( + () => wrong.DecryptAsync(encrypted, new MemoryStream()) ); } @@ -49,7 +50,8 @@ public async Task Decrypt_RecordLengthExceedingChunkSize_Throws_WithoutAllocatin BinaryPrimitives.WriteInt32BigEndian(header, chunkSize + 1); using var cipher = new EntryCipher(RandomNumberGenerator.GetBytes(32), chunkSize); - await Assert.ThrowsAsync(() => cipher.DecryptAsync(new MemoryStream(header), new MemoryStream()) + await Assert.ThrowsAsync( + () => cipher.DecryptAsync(new MemoryStream(header), new MemoryStream()) ); } } diff --git a/tests/SquidStd.Tests/Crypto/Vfs/VaultHeaderTests.cs b/tests/SquidStd.Tests/Crypto/Vfs/VaultHeaderTests.cs index 93ad01c0..fdf0b083 100644 --- a/tests/SquidStd.Tests/Crypto/Vfs/VaultHeaderTests.cs +++ b/tests/SquidStd.Tests/Crypto/Vfs/VaultHeaderTests.cs @@ -11,10 +11,10 @@ public void Serialize_Parse_RoundTrips() "SQVFS1", 1, [1, 2, 3, 4], - MemoryKib: 8192, - Iterations: 2, - Parallelism: 1, - ChunkSize: 65536 + 8192, + 2, + 1, + 65536 ); var parsed = VaultHeader.Parse(header.Serialize()); diff --git a/tests/SquidStd.Tests/Crypto/Vfs/VaultIndexTests.cs b/tests/SquidStd.Tests/Crypto/Vfs/VaultIndexTests.cs index a7f0efd9..4ca031ee 100644 --- a/tests/SquidStd.Tests/Crypto/Vfs/VaultIndexTests.cs +++ b/tests/SquidStd.Tests/Crypto/Vfs/VaultIndexTests.cs @@ -8,7 +8,7 @@ public class VaultIndexTests public void Serialize_Parse_RoundTripsEntries() { var index = new VaultIndex(); - index.Set("docs/cv.pdf", new VaultIndexEntry("a1b2", 100, DateTimeOffset.UnixEpoch)); + index.Set("docs/cv.pdf", new("a1b2", 100, DateTimeOffset.UnixEpoch)); var parsed = VaultIndex.Parse(index.Serialize()); diff --git a/tests/SquidStd.Tests/Database/ConnectionStringParserTests.cs b/tests/SquidStd.Tests/Database/ConnectionStringParserTests.cs index f5d25619..73ee8d68 100644 --- a/tests/SquidStd.Tests/Database/ConnectionStringParserTests.cs +++ b/tests/SquidStd.Tests/Database/ConnectionStringParserTests.cs @@ -7,9 +7,7 @@ public class ConnectionStringParserTests { [Fact] public void Parse_MissingHostForServerProvider_Throws() - { - Assert.Throws(() => ConnectionStringParser.Parse("postgres:///db")); - } + => Assert.Throws(() => ConnectionStringParser.Parse("postgres:///db")); [Fact] public void Parse_MySql_BuildsNativeString() @@ -78,7 +76,5 @@ public void Parse_SqlServer_BuildsNativeString() [Fact] public void Parse_UnknownScheme_Throws() - { - Assert.Throws(() => ConnectionStringParser.Parse("oracle://h/db")); - } + => Assert.Throws(() => ConnectionStringParser.Parse("oracle://h/db")); } diff --git a/tests/SquidStd.Tests/Database/FreeSqlDataAccessTests.cs b/tests/SquidStd.Tests/Database/FreeSqlDataAccessTests.cs index 42846655..4ecec4bd 100644 --- a/tests/SquidStd.Tests/Database/FreeSqlDataAccessTests.cs +++ b/tests/SquidStd.Tests/Database/FreeSqlDataAccessTests.cs @@ -1,4 +1,3 @@ -using SquidStd.Database.Abstractions.Data.Database; using SquidStd.Database.Abstractions.Data.Entities; using SquidStd.Database.Data; using SquidStd.Database.Services; @@ -29,8 +28,8 @@ public async Task DisposeAsync() public async Task InitializeAsync() { _dbPath = Path.Combine(Path.GetTempPath(), "squidstd-db-" + Guid.NewGuid().ToString("N") + ".db"); - _service = new DatabaseService( - new DatabaseConfig + _service = new( + new() { ConnectionString = $"sqlite://{_dbPath}", AutoMigrate = true @@ -84,7 +83,7 @@ await access.BulkInsertAsync( public async Task DeleteAsync_RemovesRow() { var access = NewAccess(); - var user = await access.InsertAsync(new SampleUser { Name = "Cara", Age = 40 }); + var user = await access.InsertAsync(new() { Name = "Cara", Age = 40 }); Assert.True(await access.DeleteAsync(user.Id)); Assert.Null(await access.GetByIdAsync(user.Id)); @@ -98,7 +97,7 @@ public async Task GetPagedAsync_ReturnsMetadata() for (var i = 0; i < 25; i++) { - await access.InsertAsync(new SampleUser { Name = $"u{i}", Age = i }); + await access.InsertAsync(new() { Name = $"u{i}", Age = i }); } var page = await access.GetPagedAsync(2, 10, orderBy: u => u.Age); @@ -115,7 +114,7 @@ public async Task GetPagedAsync_ReturnsMetadata() public async Task InsertAsync_RollsBackOnFailure() { var access = NewAccess(); - var first = await access.InsertAsync(new SampleUser { Name = "first", Age = 1 }); + var first = await access.InsertAsync(new() { Name = "first", Age = 1 }); // Re-using an existing primary key forces a unique-constraint violation. var duplicate = new SampleUser { Id = first.Id, Name = "dup", Age = 2 }; @@ -128,7 +127,7 @@ public async Task InsertAsync_RollsBackOnFailure() public async Task InsertAsync_SetsIdAndTimestamps() { var access = NewAccess(); - var inserted = await access.InsertAsync(new SampleUser { Name = "Ann", Age = 30 }); + var inserted = await access.InsertAsync(new() { Name = "Ann", Age = 30 }); Assert.NotEqual(Guid.Empty, inserted.Id); Assert.NotEqual(default, inserted.Created); @@ -143,7 +142,7 @@ public async Task InsertAsync_SetsIdAndTimestamps() public async Task UpdateAsync_BumpsUpdated() { var access = NewAccess(); - var user = await access.InsertAsync(new SampleUser { Name = "Bob", Age = 20 }); + var user = await access.InsertAsync(new() { Name = "Bob", Age = 20 }); user.Age = 21; var updated = await access.UpdateAsync(user); @@ -153,7 +152,5 @@ public async Task UpdateAsync_BumpsUpdated() } private FreeSqlDataAccess NewAccess() - { - return new FreeSqlDataAccess(_service); - } + => new(_service); } diff --git a/tests/SquidStd.Tests/Env/ReplaceEnvTests.cs b/tests/SquidStd.Tests/Env/ReplaceEnvTests.cs index 59f97402..84180983 100644 --- a/tests/SquidStd.Tests/Env/ReplaceEnvTests.cs +++ b/tests/SquidStd.Tests/Env/ReplaceEnvTests.cs @@ -11,14 +11,9 @@ public void ReplaceEnv_LeavesUnknownVariableUntouched() Assert.Equal("x=$SQUID_MISSING_VAR", "x=$SQUID_MISSING_VAR".ReplaceEnv()); } - [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData("no tokens here")] + [Theory, InlineData(null), InlineData(""), InlineData("no tokens here")] public void ReplaceEnv_PassesThroughWhenNothingToReplace(string? input) - { - Assert.Equal(input, input!.ReplaceEnv()); - } + => Assert.Equal(input, input!.ReplaceEnv()); [Fact] public void ReplaceEnv_SubstitutesKnownVariable() diff --git a/tests/SquidStd.Tests/Extensions/Directories/DirectoriesExtensionTests.cs b/tests/SquidStd.Tests/Extensions/Directories/DirectoriesExtensionTests.cs index b9cd69dd..7cd656a5 100644 --- a/tests/SquidStd.Tests/Extensions/Directories/DirectoriesExtensionTests.cs +++ b/tests/SquidStd.Tests/Extensions/Directories/DirectoriesExtensionTests.cs @@ -4,14 +4,9 @@ namespace SquidStd.Tests.Extensions.Directories; public class DirectoriesExtensionTests { - [Theory] - [InlineData("")] - [InlineData(" ")] - [InlineData(null)] + [Theory, InlineData(""), InlineData(" "), InlineData(null)] public void ResolvePathAndEnvs_NullOrWhitespace_ReturnsNull(string? path) - { - Assert.Null(path!.ResolvePathAndEnvs()); - } + => Assert.Null(path!.ResolvePathAndEnvs()); [Fact] public void ResolvePathAndEnvs_TildePrefix_ExpandsToUserProfile() diff --git a/tests/SquidStd.Tests/Extensions/Env/EnvExtensionsTests.cs b/tests/SquidStd.Tests/Extensions/Env/EnvExtensionsTests.cs index 9a6e1e07..1a408dfc 100644 --- a/tests/SquidStd.Tests/Extensions/Env/EnvExtensionsTests.cs +++ b/tests/SquidStd.Tests/Extensions/Env/EnvExtensionsTests.cs @@ -6,13 +6,9 @@ public class EnvExtensionsTests { private const string TestVariable = "SQUIDSTD_UNIT_TEST_VAR"; - [Theory] - [InlineData("")] - [InlineData("no variables here")] + [Theory, InlineData(""), InlineData("no variables here")] public void ExpandEnvironmentVariables_NoMatch_ReturnsInput(string input) - { - Assert.Equal(input, input.ExpandEnvironmentVariables()); - } + => Assert.Equal(input, input.ExpandEnvironmentVariables()); [Fact] public void ExpandEnvironmentVariables_ReplacesDollarPrefixedVariable() diff --git a/tests/SquidStd.Tests/Extensions/Logger/LogLevelExtensionsTests.cs b/tests/SquidStd.Tests/Extensions/Logger/LogLevelExtensionsTests.cs index d229a467..bb72c066 100644 --- a/tests/SquidStd.Tests/Extensions/Logger/LogLevelExtensionsTests.cs +++ b/tests/SquidStd.Tests/Extensions/Logger/LogLevelExtensionsTests.cs @@ -6,21 +6,14 @@ namespace SquidStd.Tests.Extensions.Logger; public class LogLevelExtensionsTests { - [Theory] - [InlineData(LogLevelType.Trace, LogEventLevel.Verbose)] - [InlineData(LogLevelType.Debug, LogEventLevel.Debug)] - [InlineData(LogLevelType.Information, LogEventLevel.Information)] - [InlineData(LogLevelType.Warning, LogEventLevel.Warning)] - [InlineData(LogLevelType.Error, LogEventLevel.Error)] - [InlineData(LogLevelType.Critical, LogEventLevel.Fatal)] + [Theory, InlineData(LogLevelType.Trace, LogEventLevel.Verbose), InlineData(LogLevelType.Debug, LogEventLevel.Debug), + InlineData(LogLevelType.Information, LogEventLevel.Information), + InlineData(LogLevelType.Warning, LogEventLevel.Warning), InlineData(LogLevelType.Error, LogEventLevel.Error), + InlineData(LogLevelType.Critical, LogEventLevel.Fatal)] public void ToSerilogLogLevel_KnownLevels_MapsExpected(LogLevelType input, LogEventLevel expected) - { - Assert.Equal(expected, input.ToSerilogLogLevel()); - } + => Assert.Equal(expected, input.ToSerilogLogLevel()); [Fact] public void ToSerilogLogLevel_UnmappedLevels_FallsBackToInformation() - { - Assert.Equal(LogEventLevel.Information, ((LogLevelType)255).ToSerilogLogLevel()); - } + => Assert.Equal(LogEventLevel.Information, ((LogLevelType)255).ToSerilogLogLevel()); } diff --git a/tests/SquidStd.Tests/Extensions/Strings/StringMethodExtensionTests.cs b/tests/SquidStd.Tests/Extensions/Strings/StringMethodExtensionTests.cs index 53ea0b58..9aee1867 100644 --- a/tests/SquidStd.Tests/Extensions/Strings/StringMethodExtensionTests.cs +++ b/tests/SquidStd.Tests/Extensions/Strings/StringMethodExtensionTests.cs @@ -6,61 +6,41 @@ public class StringMethodExtensionTests { [Fact] public void ToCamelCase_DelegatesToStringUtils() - { - Assert.Equal("helloWorld", "HelloWorld".ToCamelCase()); - } + => Assert.Equal("helloWorld", "HelloWorld".ToCamelCase()); [Fact] public void ToDotCase_DelegatesToStringUtils() - { - Assert.Equal("hello.world", "HelloWorld".ToDotCase()); - } + => Assert.Equal("hello.world", "HelloWorld".ToDotCase()); [Fact] public void ToKebabCase_DelegatesToStringUtils() - { - Assert.Equal("hello-world", "HelloWorld".ToKebabCase()); - } + => Assert.Equal("hello-world", "HelloWorld".ToKebabCase()); [Fact] public void ToPascalCase_DelegatesToStringUtils() - { - Assert.Equal("HelloWorld", "hello_world".ToPascalCase()); - } + => Assert.Equal("HelloWorld", "hello_world".ToPascalCase()); [Fact] public void ToPathCase_DelegatesToStringUtils() - { - Assert.Equal("hello/world", "HelloWorld".ToPathCase()); - } + => Assert.Equal("hello/world", "HelloWorld".ToPathCase()); [Fact] public void ToSentenceCase_DelegatesToStringUtils() - { - Assert.Equal("Hello world", "hello world".ToSentenceCase()); - } + => Assert.Equal("Hello world", "hello world".ToSentenceCase()); [Fact] public void ToSnakeCase_DelegatesToStringUtils() - { - Assert.Equal("hello_world", "HelloWorld".ToSnakeCase()); - } + => Assert.Equal("hello_world", "HelloWorld".ToSnakeCase()); [Fact] public void ToSnakeCaseUpper_DelegatesToStringUtils() - { - Assert.Equal("HELLO_WORLD", "HelloWorld".ToSnakeCaseUpper()); - } + => Assert.Equal("HELLO_WORLD", "HelloWorld".ToSnakeCaseUpper()); [Fact] public void ToTitleCase_DelegatesToStringUtils() - { - Assert.Equal("Hello World", "hello_world".ToTitleCase()); - } + => Assert.Equal("Hello World", "hello_world".ToTitleCase()); [Fact] public void ToTrainCase_DelegatesToStringUtils() - { - Assert.Equal("Hello-World", "hello_world".ToTrainCase()); - } + => Assert.Equal("Hello-World", "hello_world".ToTrainCase()); } diff --git a/tests/SquidStd.Tests/Generators/Support/GeneratorTestCompiler.cs b/tests/SquidStd.Tests/Generators/Support/GeneratorTestCompiler.cs index 8fbabee1..f5580150 100644 --- a/tests/SquidStd.Tests/Generators/Support/GeneratorTestCompiler.cs +++ b/tests/SquidStd.Tests/Generators/Support/GeneratorTestCompiler.cs @@ -33,10 +33,11 @@ params IIncrementalGenerator[] generators "SquidStdGeneratorTests", new[] { syntaxTree }, references, - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + new(OutputKind.DynamicallyLinkedLibrary) ); ISourceGenerator[] selectedGenerators; + if (generators.Length == 0) { selectedGenerators = new[] { new EventListenerRegistrationGenerator().AsSourceGenerator() }; @@ -60,10 +61,10 @@ private static IReadOnlyList CreateReferences() { var trustedPlatformAssemblies = (string?)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") ?? string.Empty; var references = trustedPlatformAssemblies - .Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries) - .Select(path => MetadataReference.CreateFromFile(path)) - .Cast() - .ToList(); + .Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries) + .Select(path => MetadataReference.CreateFromFile(path)) + .Cast() + .ToList(); AddReference(references, typeof(IEvent).Assembly.Location); AddReference(references, typeof(RegisterEventListenerAttribute).Assembly.Location); diff --git a/tests/SquidStd.Tests/Health/HealthCheckServiceTests.cs b/tests/SquidStd.Tests/Health/HealthCheckServiceTests.cs index cd462d69..304c469c 100644 --- a/tests/SquidStd.Tests/Health/HealthCheckServiceTests.cs +++ b/tests/SquidStd.Tests/Health/HealthCheckServiceTests.cs @@ -57,13 +57,12 @@ public async Task CheckThatThrows_IsCapturedAsUnhealthy_AndDoesNotBreakOthers() [Fact] public void Ctor_NonPositiveTimeout_Throws() - { - Assert.Throws(() => new HealthCheckService( + => Assert.Throws( + () => new HealthCheckService( [], - new HealthCheckOptions { CheckTimeout = TimeSpan.Zero } + new() { CheckTimeout = TimeSpan.Zero } ) ); - } [Fact] public async Task DuplicateNames_AreMadeUnique() @@ -113,12 +112,8 @@ public async Task OneUnhealthy_MakesOverallUnhealthy() } private static HealthCheckService NewService(HealthCheckOptions options, params IHealthCheck[] checks) - { - return new HealthCheckService(checks, options); - } + => new(checks, options); private static HealthCheckOptions Options(double timeoutSeconds = 5) - { - return new HealthCheckOptions { CheckTimeout = TimeSpan.FromSeconds(timeoutSeconds) }; - } + => new() { CheckTimeout = TimeSpan.FromSeconds(timeoutSeconds) }; } diff --git a/tests/SquidStd.Tests/Integration/Mail/GreenMailContainerFixture.cs b/tests/SquidStd.Tests/Integration/Mail/GreenMailContainerFixture.cs index 60152131..c6d4d846 100644 --- a/tests/SquidStd.Tests/Integration/Mail/GreenMailContainerFixture.cs +++ b/tests/SquidStd.Tests/Integration/Mail/GreenMailContainerFixture.cs @@ -7,16 +7,16 @@ namespace SquidStd.Tests.Integration.Mail; public sealed class GreenMailContainerFixture : IAsyncLifetime { private readonly IContainer _container = new ContainerBuilder() - .WithImage("greenmail/standalone:2.1.0") - .WithEnvironment( - "GREENMAIL_OPTS", - "-Dgreenmail.setup.test.all -Dgreenmail.hostname=0.0.0.0 -Dgreenmail.auth.disabled -Dgreenmail.verbose" - ) - .WithPortBinding(3025, true) - .WithPortBinding(3143, true) - .WithPortBinding(3110, true) - .WithWaitStrategy(Wait.ForUnixContainer().UntilInternalTcpPortIsAvailable(3143)) - .Build(); + .WithImage("greenmail/standalone:2.1.0") + .WithEnvironment( + "GREENMAIL_OPTS", + "-Dgreenmail.setup.test.all -Dgreenmail.hostname=0.0.0.0 -Dgreenmail.auth.disabled -Dgreenmail.verbose" + ) + .WithPortBinding(3025, true) + .WithPortBinding(3143, true) + .WithPortBinding(3110, true) + .WithWaitStrategy(Wait.ForUnixContainer().UntilInternalTcpPortIsAvailable(3143)) + .Build(); public string Host => _container.Hostname; @@ -27,14 +27,10 @@ public sealed class GreenMailContainerFixture : IAsyncLifetime public int Pop3Port => _container.GetMappedPublicPort(3110); public Task DisposeAsync() - { - return _container.DisposeAsync().AsTask(); - } + => _container.DisposeAsync().AsTask(); public Task InitializeAsync() - { - return _container.StartAsync(); - } + => _container.StartAsync(); } [CollectionDefinition(Name)] diff --git a/tests/SquidStd.Tests/Integration/Mail/MailPollingServiceTests.cs b/tests/SquidStd.Tests/Integration/Mail/MailPollingServiceTests.cs index 52646060..c3c1d00b 100644 --- a/tests/SquidStd.Tests/Integration/Mail/MailPollingServiceTests.cs +++ b/tests/SquidStd.Tests/Integration/Mail/MailPollingServiceTests.cs @@ -2,7 +2,6 @@ using MailKit.Security; using MimeKit; using SquidStd.Core.Interfaces.Events; -using SquidStd.Mail.Abstractions.Data.Config; using SquidStd.Mail.Abstractions.Data.Events; using SquidStd.Mail.Abstractions.Types.Mail; using SquidStd.Mail.MailKit.Services; @@ -45,7 +44,7 @@ public async Task PollOnce_PublishesMailReceivedEvent() eventBus.RegisterListener(new DelegateListener(e => received.TrySetResult(e))); var reader = new ImapMailReader( - new MailOptions + new() { Protocol = MailProtocolType.Imap, Host = _fixture.Host, @@ -60,7 +59,7 @@ public async Task PollOnce_PublishesMailReceivedEvent() reader, eventBus, new FakeTimerService(), - new MailOptions { PollIntervalSeconds = 60 } + new() { PollIntervalSeconds = 60 } ); await service.PollOnceAsync(); diff --git a/tests/SquidStd.Tests/Integration/Mail/MailQueueIntegrationTests.cs b/tests/SquidStd.Tests/Integration/Mail/MailQueueIntegrationTests.cs index be7b422f..83fa0fc4 100644 --- a/tests/SquidStd.Tests/Integration/Mail/MailQueueIntegrationTests.cs +++ b/tests/SquidStd.Tests/Integration/Mail/MailQueueIntegrationTests.cs @@ -1,7 +1,6 @@ using DryIoc; using SquidStd.Core.Interfaces.Events; using SquidStd.Mail.Abstractions.Data; -using SquidStd.Mail.Abstractions.Data.Config; using SquidStd.Mail.Abstractions.Types.Mail; using SquidStd.Mail.MailKit.Extensions; using SquidStd.Mail.MailKit.Services; @@ -33,25 +32,25 @@ public async Task Enqueue_IsSentByConsumer_AndDelivered() var container = new Container(); container.RegisterInstance(new EventBusService()); container.AddInMemoryMessaging(); - container.AddMailSender(new SmtpOptions { Host = _fixture.Host, Port = _fixture.SmtpPort, UseSsl = false }); + container.AddMailSender(new() { Host = _fixture.Host, Port = _fixture.SmtpPort, UseSsl = false }); container.AddMailQueue(); var consumer = container.Resolve(); await consumer.StartAsync(); await container.Resolve() - .EnqueueAsync( - new OutgoingMailMessage - { - From = new MailAddress("Sender", "sender@example.com"), - To = [new MailAddress("Target", recipient)], - Subject = "queued-subject", - TextBody = "hi" - } - ); + .EnqueueAsync( + new() + { + From = new("Sender", "sender@example.com"), + To = [new("Target", recipient)], + Subject = "queued-subject", + TextBody = "hi" + } + ); var reader = new ImapMailReader( - new MailOptions + new() { Protocol = MailProtocolType.Imap, Host = _fixture.Host, diff --git a/tests/SquidStd.Tests/Integration/Mail/MailReaderTests.cs b/tests/SquidStd.Tests/Integration/Mail/MailReaderTests.cs index 392156f3..e465f03b 100644 --- a/tests/SquidStd.Tests/Integration/Mail/MailReaderTests.cs +++ b/tests/SquidStd.Tests/Integration/Mail/MailReaderTests.cs @@ -43,7 +43,7 @@ public async Task Pop3_FetchesNewMessage_WithDelete() var user = "pop-user@example.com"; await SendAsync(user, "pop-subject", false); var reader = new Pop3MailReader( - new MailOptions + new() { Protocol = MailProtocolType.Pop3, Host = _fixture.Host, @@ -63,8 +63,7 @@ public async Task Pop3_FetchesNewMessage_WithDelete() } private MailOptions ImapOptions(string user) - { - return new MailOptions + => new() { Protocol = MailProtocolType.Imap, Host = _fixture.Host, @@ -75,7 +74,6 @@ private MailOptions ImapOptions(string user) MarkAsSeen = true, IncludeRawEml = true }; - } private async Task SendAsync(string to, string subject, bool withAttachment) { diff --git a/tests/SquidStd.Tests/Integration/Mail/MailSenderTests.cs b/tests/SquidStd.Tests/Integration/Mail/MailSenderTests.cs index ad1d5e7c..8c92e31c 100644 --- a/tests/SquidStd.Tests/Integration/Mail/MailSenderTests.cs +++ b/tests/SquidStd.Tests/Integration/Mail/MailSenderTests.cs @@ -1,7 +1,5 @@ using System.Text; using SquidStd.Core.Interfaces.Events; -using SquidStd.Mail.Abstractions.Data; -using SquidStd.Mail.Abstractions.Data.Config; using SquidStd.Mail.Abstractions.Data.Events; using SquidStd.Mail.Abstractions.Exceptions; using SquidStd.Mail.Abstractions.Types.Mail; @@ -31,27 +29,27 @@ public async Task SendAsync_DeliversMessage_AndPublishesMailSent() eventBus.RegisterListener(new DelegateListener(e => sent.TrySetResult(e))); var sender = new MailKitMailSender( - new SmtpOptions { Host = _fixture.Host, Port = _fixture.SmtpPort, UseSsl = false }, + new() { Host = _fixture.Host, Port = _fixture.SmtpPort, UseSsl = false }, eventBus ); await sender.SendAsync( - new OutgoingMailMessage - { - From = new MailAddress("Sender", "sender@example.com"), - To = [new MailAddress("Target", recipient)], - Subject = "sent-subject", - TextBody = "hello", - Attachments = [new OutgoingAttachment("a.txt", "text/plain", Encoding.UTF8.GetBytes("xyz"))] - } - ) - .WaitAsync(Timeout); + new() + { + From = new("Sender", "sender@example.com"), + To = [new("Target", recipient)], + Subject = "sent-subject", + TextBody = "hello", + Attachments = [new("a.txt", "text/plain", Encoding.UTF8.GetBytes("xyz"))] + } + ) + .WaitAsync(Timeout); var sentEvent = await sent.Task.WaitAsync(Timeout); Assert.Equal("sent-subject", sentEvent.Subject); var reader = new ImapMailReader( - new MailOptions + new() { Protocol = MailProtocolType.Imap, Host = _fixture.Host, @@ -73,17 +71,18 @@ public async Task SendAsync_Throws_AndPublishesFailed_OnClosedPort() var failed = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); eventBus.RegisterListener(new DelegateListener(e => failed.TrySetResult(e))); - var sender = new MailKitMailSender(new SmtpOptions { Host = _fixture.Host, Port = 1, UseSsl = false }, eventBus); - - await Assert.ThrowsAsync(() => sender.SendAsync( - new OutgoingMailMessage - { - From = new MailAddress("Sender", "sender@example.com"), - To = [new MailAddress("Target", "x@example.com")], - Subject = "fail-subject" - } - ) - .WaitAsync(Timeout) + var sender = new MailKitMailSender(new() { Host = _fixture.Host, Port = 1, UseSsl = false }, eventBus); + + await Assert.ThrowsAsync( + () => sender.SendAsync( + new() + { + From = new("Sender", "sender@example.com"), + To = [new("Target", "x@example.com")], + Subject = "fail-subject" + } + ) + .WaitAsync(Timeout) ); var failedEvent = await failed.Task.WaitAsync(Timeout); diff --git a/tests/SquidStd.Tests/Integration/Search/ElasticSearchServiceTests.cs b/tests/SquidStd.Tests/Integration/Search/ElasticSearchServiceTests.cs index 3739755f..1cf2c7d7 100644 --- a/tests/SquidStd.Tests/Integration/Search/ElasticSearchServiceTests.cs +++ b/tests/SquidStd.Tests/Integration/Search/ElasticSearchServiceTests.cs @@ -1,7 +1,6 @@ using DryIoc; using SquidStd.Search.Abstractions.Attributes; using SquidStd.Search.Abstractions.Interfaces; -using SquidStd.Search.Elasticsearch.Data.Config; using SquidStd.Search.Elasticsearch.Extensions; using SquidStd.Search.Elasticsearch.Linq; @@ -86,16 +85,16 @@ public async Task Query_Range_Order_Take() { var search = NewService(); await search.IndexManyAsync( - [new Order("a", "open", 50, "A"), new Order("b", "open", 200, "B"), new Order("c", "open", 300, "C")], - true - ) - .WaitAsync(Timeout); + [new("a", "open", 50, "A"), new("b", "open", 200, "B"), new Order("c", "open", 300, "C")], + true + ) + .WaitAsync(Timeout); var results = await search.Query() - .Where(o => o.Total > 100) - .OrderByDescending(o => o.Total) - .Take(1) - .ToListAsync(); + .Where(o => o.Total > 100) + .OrderByDescending(o => o.Total) + .Take(1) + .ToListAsync(); Assert.Single(results); Assert.Equal("c", results[0].Id); @@ -104,7 +103,7 @@ await search.IndexManyAsync( private ISearchService NewService() { var container = new Container(); - container.AddElasticsearch(new ElasticsearchOptions { Uri = new Uri(_fixture.ConnectionString) }); + container.AddElasticsearch(new() { Uri = new(_fixture.ConnectionString) }); return container.Resolve(); } diff --git a/tests/SquidStd.Tests/Integration/Search/ElasticsearchContainerFixture.cs b/tests/SquidStd.Tests/Integration/Search/ElasticsearchContainerFixture.cs index 4a4af548..0db6a967 100644 --- a/tests/SquidStd.Tests/Integration/Search/ElasticsearchContainerFixture.cs +++ b/tests/SquidStd.Tests/Integration/Search/ElasticsearchContainerFixture.cs @@ -5,37 +5,34 @@ namespace SquidStd.Tests.Integration.Search; /// -/// Starts a single-node Elasticsearch container once for the collection (security disabled → plain HTTP) and -/// exposes its URI. The default Elasticsearch wait strategy probes over https; we override it to poll http so -/// startup completes against the security-disabled node. +/// Starts a single-node Elasticsearch container once for the collection (security disabled → plain HTTP) and +/// exposes its URI. The default Elasticsearch wait strategy probes over https; we override it to poll http so +/// startup completes against the security-disabled node. /// public sealed class ElasticsearchContainerFixture : IAsyncLifetime { private readonly ElasticsearchContainer _container = new ElasticsearchBuilder() - .WithEnvironment("xpack.security.enabled", "false") - .WithWaitStrategy( - Wait.ForUnixContainer() - .UntilHttpRequestIsSucceeded(request => - request.ForPort(9200) - .ForPath("/_cluster/health") - .ForStatusCode(HttpStatusCode.OK) - ) - ) - .Build(); + .WithEnvironment("xpack.security.enabled", "false") + .WithWaitStrategy( + Wait.ForUnixContainer() + .UntilHttpRequestIsSucceeded( + request => + request.ForPort(9200) + .ForPath("/_cluster/health") + .ForStatusCode(HttpStatusCode.OK) + ) + ) + .Build(); // Security is disabled, so the node serves plain HTTP with no auth. GetConnectionString() still returns // an https:// URL with credentials for 8.x images, so build the endpoint explicitly instead. public string ConnectionString => $"http://{_container.Hostname}:{_container.GetMappedPublicPort(9200)}"; public Task DisposeAsync() - { - return _container.DisposeAsync().AsTask(); - } + => _container.DisposeAsync().AsTask(); public Task InitializeAsync() - { - return _container.StartAsync(); - } + => _container.StartAsync(); } [CollectionDefinition(Name)] diff --git a/tests/SquidStd.Tests/Integration/Templates/TemplatePackTests.cs b/tests/SquidStd.Tests/Integration/Templates/TemplatePackTests.cs index f0c7e7a0..e2a063b7 100644 --- a/tests/SquidStd.Tests/Integration/Templates/TemplatePackTests.cs +++ b/tests/SquidStd.Tests/Integration/Templates/TemplatePackTests.cs @@ -3,9 +3,9 @@ namespace SquidStd.Tests.Integration.Templates; /// -/// Packs SquidStd.Templates, installs it into an isolated dotnet-new hive, instantiates each template, and -/// asserts the generated output (name substitution, version-sentinel replacement, messaging branch). No build -/// of the generated projects: the referenced SquidStd.* packages may not be published yet. +/// Packs SquidStd.Templates, installs it into an isolated dotnet-new hive, instantiates each template, and +/// asserts the generated output (name substitution, version-sentinel replacement, messaging branch). No build +/// of the generated projects: the referenced SquidStd.* packages may not be published yet. /// public sealed class TemplatePackTests : IDisposable { @@ -37,12 +37,12 @@ public TemplatePackTests() Assert.True(TryRun("dotnet", $"pack \"{project}\" -c Release", _repoRoot, out _), "pack failed"); var nupkg = Directory - .GetFiles( - Path.Combine(_repoRoot, "src", "SquidStd.Templates", "bin", "Release"), - "SquidStd.Templates.*.nupkg" - ) - .OrderByDescending(File.GetLastWriteTimeUtc) - .First(); + .GetFiles( + Path.Combine(_repoRoot, "src", "SquidStd.Templates", "bin", "Release"), + "SquidStd.Templates.*.nupkg" + ) + .OrderByDescending(File.GetLastWriteTimeUtc) + .First(); _installed = TryRun("dotnet", $"new install \"{nupkg}\" --debug:custom-hive \"{_hive}\"", _repoRoot, out _); } diff --git a/tests/SquidStd.Tests/Integration/Workers/WorkerSystemIntegrationTests.cs b/tests/SquidStd.Tests/Integration/Workers/WorkerSystemIntegrationTests.cs index 05881c5d..cc5002f7 100644 --- a/tests/SquidStd.Tests/Integration/Workers/WorkerSystemIntegrationTests.cs +++ b/tests/SquidStd.Tests/Integration/Workers/WorkerSystemIntegrationTests.cs @@ -15,9 +15,9 @@ namespace SquidStd.Tests.Integration.Workers; /// -/// End-to-end test of the workers system over a real RabbitMQ broker (Testcontainers): the manager -/// enqueues a job that the worker consumes and runs (real queue), and the worker's heartbeat reaches the -/// manager's registry (real fan-out topic). +/// End-to-end test of the workers system over a real RabbitMQ broker (Testcontainers): the manager +/// enqueues a job that the worker consumes and runs (real queue), and the worker's heartbeat reaches the +/// manager's registry (real fan-out topic). /// [Collection(RabbitMqCollection.Name)] public class WorkerSystemIntegrationTests @@ -36,7 +36,7 @@ public async Task Manager_EnqueuesJob_WorkerRunsIt_AndHeartbeatReachesRegistry() { using var container = new Container(); container.RegisterInstance(new EventBusService()); - container.AddRabbitMqMessaging(new RabbitMqOptions { Uri = new Uri(_fixture.AmqpUri) }); + container.AddRabbitMqMessaging(new RabbitMqOptions { Uri = new(_fixture.AmqpUri) }); // Unique channel names per run so parallel/other tests on the shared broker do not interfere. var suffix = Guid.NewGuid().ToString("N"); diff --git a/tests/SquidStd.Tests/Json/JsonContextTypeResolverTests.cs b/tests/SquidStd.Tests/Json/JsonContextTypeResolverTests.cs index ef40a5b4..bb476cef 100644 --- a/tests/SquidStd.Tests/Json/JsonContextTypeResolverTests.cs +++ b/tests/SquidStd.Tests/Json/JsonContextTypeResolverTests.cs @@ -43,15 +43,11 @@ public void GetTypeInfo_RegisteredType_ReturnsTypeInfo() [Fact] public void IsTypeRegistered_RegisteredType_ReturnsTrue() - { - Assert.True(JsonContextTypeResolver.IsTypeRegistered(TestJsonContext.Default, typeof(SampleDto))); - } + => Assert.True(JsonContextTypeResolver.IsTypeRegistered(TestJsonContext.Default, typeof(SampleDto))); [Fact] public void IsTypeRegistered_UnregisteredType_ReturnsFalse() - { - Assert.False( + => Assert.False( JsonContextTypeResolver.IsTypeRegistered(TestJsonContext.Default, typeof(JsonContextTypeResolverTests)) ); - } } diff --git a/tests/SquidStd.Tests/Json/JsonUtilsTests.cs b/tests/SquidStd.Tests/Json/JsonUtilsTests.cs index 4420d268..b26f3add 100644 --- a/tests/SquidStd.Tests/Json/JsonUtilsTests.cs +++ b/tests/SquidStd.Tests/Json/JsonUtilsTests.cs @@ -35,17 +35,11 @@ public void AddAndRemoveJsonConverter_MutatesConverterList() [Fact] public void Deserialize_InvalidJson_ThrowsJsonException() - { - Assert.Throws(() => JsonUtils.Deserialize("{ not valid")); - } + => Assert.Throws(() => JsonUtils.Deserialize("{ not valid")); - [Theory] - [InlineData("")] - [InlineData(" ")] + [Theory, InlineData(""), InlineData(" ")] public void Deserialize_NullOrWhitespace_Throws(string json) - { - Assert.Throws(() => JsonUtils.Deserialize(json)); - } + => Assert.Throws(() => JsonUtils.Deserialize(json)); [Fact] public void Deserialize_WithExplicitContext_ReturnsObject() @@ -60,11 +54,10 @@ public void Deserialize_WithExplicitContext_ReturnsObject() [Fact] public void DeserializeFromFile_MissingFile_Throws() - { - Assert.Throws(() => - JsonUtils.DeserializeFromFile(Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".json")) + => Assert.Throws( + () => + JsonUtils.DeserializeFromFile(Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".json")) ); - } [Fact] public void DeserializeOrDefault_EmptyJson_ReturnsDefault() @@ -87,13 +80,9 @@ public void DeserializeOrDefault_ValidJson_ReturnsObject() [Fact] public void GetJsonConverters_ContainsDefaultEnumConverter() - { - Assert.Contains(JsonUtils.GetJsonConverters(), converter => converter is JsonStringEnumConverter); - } + => Assert.Contains(JsonUtils.GetJsonConverters(), converter => converter is JsonStringEnumConverter); - [Theory] - [InlineData("UserEntity", "user.schema.json")] - [InlineData("SampleDto", "sample_dto.schema.json")] + [Theory, InlineData("UserEntity", "user.schema.json"), InlineData("SampleDto", "sample_dto.schema.json")] public void GetSchemaFileName_GeneratesSnakeCaseSchemaName(string typeName, string expected) { // Map the parameterized type name to a real type with the same Name. @@ -102,30 +91,18 @@ public void GetSchemaFileName_GeneratesSnakeCaseSchemaName(string typeName, stri Assert.Equal(expected, JsonUtils.GetSchemaFileName(type)); } - [Theory] - [InlineData("[1,2,3]", true)] - [InlineData("{\"a\":1}", false)] - [InlineData("invalid", false)] + [Theory, InlineData("[1,2,3]", true), InlineData("{\"a\":1}", false), InlineData("invalid", false)] public void IsArray_VariousInputs_ReturnsExpected(string json, bool expected) - { - Assert.Equal(expected, JsonUtils.IsArray(json)); - } + => Assert.Equal(expected, JsonUtils.IsArray(json)); - [Theory] - [InlineData("{\"a\":1}", true)] - [InlineData("[1,2,3]", true)] - [InlineData("not json", false)] - [InlineData("", false)] + [Theory, InlineData("{\"a\":1}", true), InlineData("[1,2,3]", true), InlineData("not json", false), + InlineData("", false)] public void IsValidJson_VariousInputs_ReturnsExpected(string json, bool expected) - { - Assert.Equal(expected, JsonUtils.IsValidJson(json)); - } + => Assert.Equal(expected, JsonUtils.IsValidJson(json)); [Fact] public void Serialize_NullObject_Throws() - { - Assert.Throws(() => JsonUtils.Serialize(null!)); - } + => Assert.Throws(() => JsonUtils.Serialize(null!)); [Fact] public void SerializeDeserialize_RoundTrip_PreservesValues() @@ -155,7 +132,5 @@ public void SerializeToFile_DeserializeFromFile_RoundTrips() } // Local type whose name ends with "Entity" to verify suffix stripping. - private sealed class UserEntity - { - } + private sealed class UserEntity { } } diff --git a/tests/SquidStd.Tests/Logging/EventSinkExtensionsTests.cs b/tests/SquidStd.Tests/Logging/EventSinkExtensionsTests.cs index c3dd804f..8e2aa0a5 100644 --- a/tests/SquidStd.Tests/Logging/EventSinkExtensionsTests.cs +++ b/tests/SquidStd.Tests/Logging/EventSinkExtensionsTests.cs @@ -13,16 +13,14 @@ public void EventSink_WiredIntoSerilog_RaisesEventsForLogs() LogEventData? captured = null; void Handler(object? sender, LogEventData data) - { - captured = data; - } + => captured = data; EventSink.OnLogReceived += Handler; var logger = new LoggerConfiguration() - .WriteTo - .EventSink() - .CreateLogger(); + .WriteTo + .EventSink() + .CreateLogger(); try { diff --git a/tests/SquidStd.Tests/Logging/EventSinkTests.cs b/tests/SquidStd.Tests/Logging/EventSinkTests.cs index 6955c382..1a0b90a8 100644 --- a/tests/SquidStd.Tests/Logging/EventSinkTests.cs +++ b/tests/SquidStd.Tests/Logging/EventSinkTests.cs @@ -14,9 +14,7 @@ public void Emit_AfterClearSubscribers_DoesNotInvokeHandler() var invoked = false; void Handler(object? sender, LogEventData data) - { - invoked = true; - } + => invoked = true; EventSink.OnLogReceived += Handler; EventSink.ClearSubscribers(); @@ -50,9 +48,7 @@ public void Emit_WithSubscriber_RaisesEventWithMappedData() LogEventData? captured = null; void Handler(object? sender, LogEventData data) - { - captured = data; - } + => captured = data; EventSink.OnLogReceived += Handler; @@ -84,6 +80,6 @@ private static LogEvent CreateLogEvent(LogEventLevel level, string template, par { var parsedTemplate = new MessageTemplateParser().Parse(template); - return new LogEvent(DateTimeOffset.UtcNow, level, null, parsedTemplate, properties); + return new(DateTimeOffset.UtcNow, level, null, parsedTemplate, properties); } } diff --git a/tests/SquidStd.Tests/Mail/MailQueueTests.cs b/tests/SquidStd.Tests/Mail/MailQueueTests.cs index a1fa7dfd..e962f63e 100644 --- a/tests/SquidStd.Tests/Mail/MailQueueTests.cs +++ b/tests/SquidStd.Tests/Mail/MailQueueTests.cs @@ -25,9 +25,9 @@ public async Task EnqueueAsync_PublishesMessageToConfiguredQueue() var queue = new MailQueue(messageQueue, options); await queue.EnqueueAsync( - new OutgoingMailMessage + new() { - To = [new MailAddress("Bob", "bob@example.com")], + To = [new("Bob", "bob@example.com")], Subject = "queued" } ); diff --git a/tests/SquidStd.Tests/Mail/MailRegistrationExtensionsTests.cs b/tests/SquidStd.Tests/Mail/MailRegistrationExtensionsTests.cs index 725d8860..4c477239 100644 --- a/tests/SquidStd.Tests/Mail/MailRegistrationExtensionsTests.cs +++ b/tests/SquidStd.Tests/Mail/MailRegistrationExtensionsTests.cs @@ -41,8 +41,8 @@ public void AddMail_Throws_OnInvalidHostOrPort() { using var container = NewContainer(); - Assert.Throws(() => container.AddMail(new MailOptions { Host = string.Empty, Port = 993 })); - Assert.Throws(() => container.AddMail(new MailOptions { Host = "h", Port = 0 })); + Assert.Throws(() => container.AddMail(new() { Host = string.Empty, Port = 993 })); + Assert.Throws(() => container.AddMail(new() { Host = "h", Port = 0 })); } private static Container NewContainer() @@ -55,8 +55,5 @@ private static Container NewContainer() } private static MailOptions ValidOptions(MailProtocolType protocol) - { - return new MailOptions - { Protocol = protocol, Host = "mail.example.com", Port = 993, Username = "u", Password = "p" }; - } + => new() { Protocol = protocol, Host = "mail.example.com", Port = 993, Username = "u", Password = "p" }; } diff --git a/tests/SquidStd.Tests/Mail/MailSendConsumerServiceTests.cs b/tests/SquidStd.Tests/Mail/MailSendConsumerServiceTests.cs index 1cf74691..3d04adcf 100644 --- a/tests/SquidStd.Tests/Mail/MailSendConsumerServiceTests.cs +++ b/tests/SquidStd.Tests/Mail/MailSendConsumerServiceTests.cs @@ -66,9 +66,7 @@ public async Task Consumer_SendsEnqueuedMessage() } private static OutgoingMailMessage NewMessage() - { - return new OutgoingMailMessage { To = [new MailAddress("Bob", "bob@example.com")], Subject = "queued" }; - } + => new() { To = [new("Bob", "bob@example.com")], Subject = "queued" }; private static async Task WaitUntilAsync(Func condition, TimeSpan timeout) { diff --git a/tests/SquidStd.Tests/Mail/MailSenderRegistrationExtensionsTests.cs b/tests/SquidStd.Tests/Mail/MailSenderRegistrationExtensionsTests.cs index 5b7d57ab..94308654 100644 --- a/tests/SquidStd.Tests/Mail/MailSenderRegistrationExtensionsTests.cs +++ b/tests/SquidStd.Tests/Mail/MailSenderRegistrationExtensionsTests.cs @@ -1,6 +1,5 @@ using DryIoc; using SquidStd.Core.Interfaces.Events; -using SquidStd.Mail.Abstractions.Data.Config; using SquidStd.Mail.Abstractions.Interfaces; using SquidStd.Mail.MailKit.Extensions; using SquidStd.Mail.MailKit.Services; @@ -15,7 +14,7 @@ public void AddMailSender_RegistersSender() { using var container = NewContainer(); - container.AddMailSender(new SmtpOptions { Host = "smtp.example.com", Port = 587 }); + container.AddMailSender(new() { Host = "smtp.example.com", Port = 587 }); Assert.IsType(container.Resolve()); } @@ -25,8 +24,8 @@ public void AddMailSender_Throws_OnInvalidHostOrPort() { using var container = NewContainer(); - Assert.Throws(() => container.AddMailSender(new SmtpOptions { Host = string.Empty, Port = 587 })); - Assert.Throws(() => container.AddMailSender(new SmtpOptions { Host = "h", Port = 0 })); + Assert.Throws(() => container.AddMailSender(new() { Host = string.Empty, Port = 587 })); + Assert.Throws(() => container.AddMailSender(new() { Host = "h", Port = 0 })); } private static Container NewContainer() diff --git a/tests/SquidStd.Tests/Mail/MimeMessageMapperTests.cs b/tests/SquidStd.Tests/Mail/MimeMessageMapperTests.cs index c72d7c0d..3c59034d 100644 --- a/tests/SquidStd.Tests/Mail/MimeMessageMapperTests.cs +++ b/tests/SquidStd.Tests/Mail/MimeMessageMapperTests.cs @@ -55,7 +55,7 @@ private static MimeMessage BuildMessage() message.To.Add(new MailboxAddress("Bob", "bob@example.com")); message.Cc.Add(new MailboxAddress("Carol", "carol@example.com")); message.Subject = "Hello"; - message.Date = new DateTimeOffset(2026, 6, 24, 10, 0, 0, TimeSpan.Zero); + message.Date = new(2026, 6, 24, 10, 0, 0, TimeSpan.Zero); message.MessageId = "msg-1@example.com"; var builder = new BodyBuilder diff --git a/tests/SquidStd.Tests/Mail/OutgoingMessageMapperTests.cs b/tests/SquidStd.Tests/Mail/OutgoingMessageMapperTests.cs index a8ff5f22..29bb27c0 100644 --- a/tests/SquidStd.Tests/Mail/OutgoingMessageMapperTests.cs +++ b/tests/SquidStd.Tests/Mail/OutgoingMessageMapperTests.cs @@ -11,7 +11,7 @@ public class OutgoingMessageMapperTests [Fact] public void ToMimeMessage_FallsBackToDefaultFrom() { - var options = new SmtpOptions { DefaultFrom = new MailAddress("Sys", "sys@example.com") }; + var options = new SmtpOptions { DefaultFrom = new("Sys", "sys@example.com") }; var mime = OutgoingMessageMapper.ToMimeMessage(Message(), options); @@ -21,9 +21,9 @@ public void ToMimeMessage_FallsBackToDefaultFrom() [Fact] public void ToMimeMessage_MapsRecipientsSubjectBodiesAndAttachment() { - var options = new SmtpOptions { DefaultFrom = new MailAddress("Sys", "sys@example.com") }; + var options = new SmtpOptions { DefaultFrom = new("Sys", "sys@example.com") }; - var mime = OutgoingMessageMapper.ToMimeMessage(Message(new MailAddress("Alice", "alice@example.com")), options); + var mime = OutgoingMessageMapper.ToMimeMessage(Message(new("Alice", "alice@example.com")), options); Assert.Equal("alice@example.com", mime.From.Mailboxes.Single().Address); Assert.Contains(mime.To.Mailboxes, m => m.Address == "bob@example.com"); @@ -37,22 +37,18 @@ public void ToMimeMessage_MapsRecipientsSubjectBodiesAndAttachment() [Fact] public void ToMimeMessage_Throws_WhenNoFromAndNoDefault() - { - Assert.Throws(() => OutgoingMessageMapper.ToMimeMessage(Message(), new SmtpOptions())); - } + => Assert.Throws(() => OutgoingMessageMapper.ToMimeMessage(Message(), new())); private static OutgoingMailMessage Message(MailAddress? from = null) - { - return new OutgoingMailMessage + => new() { From = from, - To = [new MailAddress("Bob", "bob@example.com")], - Cc = [new MailAddress("Carol", "carol@example.com")], - Bcc = [new MailAddress("Dave", "dave@example.com")], + To = [new("Bob", "bob@example.com")], + Cc = [new("Carol", "carol@example.com")], + Bcc = [new("Dave", "dave@example.com")], Subject = "Hello", TextBody = "plain", HtmlBody = "

html

", - Attachments = [new OutgoingAttachment("a.txt", "text/plain", Encoding.UTF8.GetBytes("xyz"))] + Attachments = [new("a.txt", "text/plain", Encoding.UTF8.GetBytes("xyz"))] }; - } } diff --git a/tests/SquidStd.Tests/Mail/Support/FakeTimerService.cs b/tests/SquidStd.Tests/Mail/Support/FakeTimerService.cs index deb15def..b27bef21 100644 --- a/tests/SquidStd.Tests/Mail/Support/FakeTimerService.cs +++ b/tests/SquidStd.Tests/Mail/Support/FakeTimerService.cs @@ -14,22 +14,14 @@ public string RegisterTimer(string name, TimeSpan interval, Action callback, Tim return "timer-1"; } - public void UnregisterAllTimers() - { - } + public void UnregisterAllTimers() { } public bool UnregisterTimer(string timerId) - { - return true; - } + => true; public int UnregisterTimersByName(string name) - { - return 0; - } + => 0; public int UpdateTicksDelta(long timestampMilliseconds) - { - return 0; - } + => 0; } diff --git a/tests/SquidStd.Tests/Mail/Support/ThrowingMailSender.cs b/tests/SquidStd.Tests/Mail/Support/ThrowingMailSender.cs index 48ee9089..1f94054c 100644 --- a/tests/SquidStd.Tests/Mail/Support/ThrowingMailSender.cs +++ b/tests/SquidStd.Tests/Mail/Support/ThrowingMailSender.cs @@ -7,7 +7,5 @@ namespace SquidStd.Tests.Mail.Support; public sealed class ThrowingMailSender : IMailSender { public Task SendAsync(OutgoingMailMessage message, CancellationToken cancellationToken = default) - { - throw new InvalidOperationException("send failed"); - } + => throw new InvalidOperationException("send failed"); } diff --git a/tests/SquidStd.Tests/Manager/HeartbeatCollectorServiceTests.cs b/tests/SquidStd.Tests/Manager/HeartbeatCollectorServiceTests.cs index decf3670..62c4d761 100644 --- a/tests/SquidStd.Tests/Manager/HeartbeatCollectorServiceTests.cs +++ b/tests/SquidStd.Tests/Manager/HeartbeatCollectorServiceTests.cs @@ -6,7 +6,6 @@ using SquidStd.Workers.Abstractions; using SquidStd.Workers.Abstractions.Data; using SquidStd.Workers.Abstractions.Types; -using SquidStd.Workers.Manager.Data.Config; using SquidStd.Workers.Manager.Data.Events; using SquidStd.Workers.Manager.Services; @@ -23,12 +22,12 @@ public async Task Collector_RecordsHeartbeat_AndPublishesDiscoveredEvent() container.AddInMemoryMessaging(); var topic = container.Resolve(); - var registry = new WorkerRegistry(new WorkerManagerConfig()); + var registry = new WorkerRegistry(new()); var discovered = new TaskCompletionSource(); eventBus.RegisterListener(new DelegateListener(e => discovered.TrySetResult(e))); - var service = new HeartbeatCollectorService(topic, registry, eventBus, new WorkerManagerConfig()); + var service = new HeartbeatCollectorService(topic, registry, eventBus, new()); await service.StartAsync(); await topic.PublishAsync( diff --git a/tests/SquidStd.Tests/Manager/JobSchedulerTests.cs b/tests/SquidStd.Tests/Manager/JobSchedulerTests.cs index 57c03f32..2f38d528 100644 --- a/tests/SquidStd.Tests/Manager/JobSchedulerTests.cs +++ b/tests/SquidStd.Tests/Manager/JobSchedulerTests.cs @@ -5,7 +5,6 @@ using SquidStd.Services.Core.Services; using SquidStd.Workers.Abstractions; using SquidStd.Workers.Abstractions.Data; -using SquidStd.Workers.Manager.Data.Config; using SquidStd.Workers.Manager.Services; namespace SquidStd.Tests.Manager; @@ -26,7 +25,7 @@ public async Task EnqueueAsync_PublishesJobRequestToConfiguredQueue() new DelegateListener(job => received.TrySetResult(job)) ); - var scheduler = new JobScheduler(queue, new WorkerManagerConfig()); + var scheduler = new JobScheduler(queue, new()); await scheduler.EnqueueAsync("resize", new Dictionary { ["w"] = "100" }); var job = await received.Task.WaitAsync(TimeSpan.FromSeconds(5)); diff --git a/tests/SquidStd.Tests/Manager/Support/FakeTimerService.cs b/tests/SquidStd.Tests/Manager/Support/FakeTimerService.cs index 3867541a..edd54854 100644 --- a/tests/SquidStd.Tests/Manager/Support/FakeTimerService.cs +++ b/tests/SquidStd.Tests/Manager/Support/FakeTimerService.cs @@ -22,9 +22,7 @@ public string RegisterTimer(string name, TimeSpan interval, Action callback, Tim return "timer-1"; } - public void UnregisterAllTimers() - { - } + public void UnregisterAllTimers() { } public bool UnregisterTimer(string timerId) { @@ -34,12 +32,8 @@ public bool UnregisterTimer(string timerId) } public int UnregisterTimersByName(string name) - { - return 0; - } + => 0; public int UpdateTicksDelta(long timestampMilliseconds) - { - return 0; - } + => 0; } diff --git a/tests/SquidStd.Tests/Manager/WorkerManagerEndpointsTests.cs b/tests/SquidStd.Tests/Manager/WorkerManagerEndpointsTests.cs index d4bf2dcd..a6cd82d1 100644 --- a/tests/SquidStd.Tests/Manager/WorkerManagerEndpointsTests.cs +++ b/tests/SquidStd.Tests/Manager/WorkerManagerEndpointsTests.cs @@ -6,8 +6,6 @@ using SquidStd.Services.Core.Services; using SquidStd.Workers.Abstractions.Data; using SquidStd.Workers.Abstractions.Types; -using SquidStd.Workers.Manager.Data; -using SquidStd.Workers.Manager.Data.Config; using SquidStd.Workers.Manager.Endpoints; using SquidStd.Workers.Manager.Services; @@ -19,10 +17,10 @@ public class WorkerManagerEndpointsTests public async Task EnqueueJob_ReturnsAccepted_AndSchedulesJob() { var result = await WorkerManagerEndpoints.EnqueueJob( - new EnqueueJobRequest("resize", new Dictionary()), - NewScheduler(), - CancellationToken.None - ); + new("resize", new Dictionary()), + NewScheduler(), + CancellationToken.None + ); Assert.IsType(result.Result); } @@ -31,10 +29,10 @@ public async Task EnqueueJob_ReturnsAccepted_AndSchedulesJob() public async Task EnqueueJob_ReturnsBadRequest_WhenJobNameBlank() { var result = await WorkerManagerEndpoints.EnqueueJob( - new EnqueueJobRequest(" ", null), - NewScheduler(), - CancellationToken.None - ); + new(" ", null), + NewScheduler(), + CancellationToken.None + ); Assert.IsType>(result.Result); } @@ -69,16 +67,16 @@ private static JobScheduler NewScheduler() container.RegisterInstance(new EventBusService()); container.AddInMemoryMessaging(); - return new JobScheduler(container.Resolve(), new WorkerManagerConfig()); + return new(container.Resolve(), new()); } private static WorkerRegistry RegistryWith(params string[] workerIds) { - var registry = new WorkerRegistry(new WorkerManagerConfig()); + var registry = new WorkerRegistry(new()); foreach (var id in workerIds) { - registry.Record(new WorkerHeartbeat(id, DateTime.UtcNow, WorkerStatusType.Idle, 0, 8)); + registry.Record(new(id, DateTime.UtcNow, WorkerStatusType.Idle, 0, 8)); } return registry; diff --git a/tests/SquidStd.Tests/Manager/WorkerOfflineSweepServiceTests.cs b/tests/SquidStd.Tests/Manager/WorkerOfflineSweepServiceTests.cs index fd0933b1..9b689499 100644 --- a/tests/SquidStd.Tests/Manager/WorkerOfflineSweepServiceTests.cs +++ b/tests/SquidStd.Tests/Manager/WorkerOfflineSweepServiceTests.cs @@ -1,9 +1,7 @@ using SquidStd.Core.Interfaces.Events; using SquidStd.Services.Core.Services; using SquidStd.Tests.Manager.Support; -using SquidStd.Workers.Abstractions.Data; using SquidStd.Workers.Abstractions.Types; -using SquidStd.Workers.Manager.Data.Config; using SquidStd.Workers.Manager.Data.Events; using SquidStd.Workers.Manager.Services; @@ -14,15 +12,15 @@ public class WorkerOfflineSweepServiceTests [Fact] public async Task RunSweepAsync_MarksOverdueWorkerOffline_AndPublishesTransition() { - var registry = new WorkerRegistry(new WorkerManagerConfig { OfflineTimeoutSeconds = 1 }); - registry.Record(new WorkerHeartbeat("w1", DateTime.UtcNow, WorkerStatusType.Idle, 0, 8)); + var registry = new WorkerRegistry(new() { OfflineTimeoutSeconds = 1 }); + registry.Record(new("w1", DateTime.UtcNow, WorkerStatusType.Idle, 0, 8)); await Task.Delay(1100); var eventBus = new EventBusService(); var offline = new TaskCompletionSource(); eventBus.RegisterListener(new DelegateListener(e => offline.TrySetResult(e))); - var service = new WorkerOfflineSweepService(new FakeTimerService(), registry, eventBus, new WorkerManagerConfig()); + var service = new WorkerOfflineSweepService(new FakeTimerService(), registry, eventBus, new()); await service.RunSweepAsync(); var change = await offline.Task.WaitAsync(TimeSpan.FromSeconds(5)); @@ -35,12 +33,12 @@ public async Task RunSweepAsync_MarksOverdueWorkerOffline_AndPublishesTransition public async Task StartAsync_RegistersRepeatingTimer_StopAsyncUnregisters() { var timer = new FakeTimerService(); - var registry = new WorkerRegistry(new WorkerManagerConfig()); + var registry = new WorkerRegistry(new()); var service = new WorkerOfflineSweepService( timer, registry, new EventBusService(), - new WorkerManagerConfig { SweepIntervalSeconds = 5 } + new() { SweepIntervalSeconds = 5 } ); await service.StartAsync(); diff --git a/tests/SquidStd.Tests/Manager/WorkerRegistryTests.cs b/tests/SquidStd.Tests/Manager/WorkerRegistryTests.cs index f5a219fd..e2b45c92 100644 --- a/tests/SquidStd.Tests/Manager/WorkerRegistryTests.cs +++ b/tests/SquidStd.Tests/Manager/WorkerRegistryTests.cs @@ -1,6 +1,5 @@ using SquidStd.Workers.Abstractions.Data; using SquidStd.Workers.Abstractions.Types; -using SquidStd.Workers.Manager.Data.Config; using SquidStd.Workers.Manager.Services; namespace SquidStd.Tests.Manager; @@ -90,12 +89,8 @@ public void Sweep_MarksOverdueWorkerOffline_AndReturnsTransition() } private static WorkerHeartbeat Heartbeat(string id, WorkerStatusType status, int activeJobs = 0) - { - return new WorkerHeartbeat(id, DateTime.UtcNow, status, activeJobs, 8); - } + => new(id, DateTime.UtcNow, status, activeJobs, 8); private static WorkerRegistry NewRegistry(int offlineTimeoutSeconds = 30) - { - return new WorkerRegistry(new WorkerManagerConfig { OfflineTimeoutSeconds = offlineTimeoutSeconds }); - } + => new(new() { OfflineTimeoutSeconds = offlineTimeoutSeconds }); } diff --git a/tests/SquidStd.Tests/Messaging/InMemoryQueueProviderTests.cs b/tests/SquidStd.Tests/Messaging/InMemoryQueueProviderTests.cs index 4bd45577..d1f9e2f8 100644 --- a/tests/SquidStd.Tests/Messaging/InMemoryQueueProviderTests.cs +++ b/tests/SquidStd.Tests/Messaging/InMemoryQueueProviderTests.cs @@ -12,7 +12,7 @@ public class InMemoryQueueProviderTests [Fact] public async Task AlwaysFailing_IsDeadLetteredAfterMaxAttempts() { - await using var provider = NewProvider(options: new MessagingOptions { MaxDeliveryAttempts = 2 }); + await using var provider = NewProvider(options: new() { MaxDeliveryAttempts = 2 }); var attempts = 0; provider.Subscribe( "q", @@ -66,7 +66,7 @@ public async Task DisposedSubscription_StopsReceiving() [Fact] public async Task FailingThenSucceeding_IsRetriedAndDelivered() { - await using var provider = NewProvider(options: new MessagingOptions { MaxDeliveryAttempts = 3 }); + await using var provider = NewProvider(options: new() { MaxDeliveryAttempts = 3 }); var attempts = 0; var delivered = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); provider.Subscribe( @@ -169,20 +169,14 @@ public async Task TwoSubscribers_ReceiveRoundRobin() } private static ReadOnlyMemory Bytes(string s) - { - return Encoding.UTF8.GetBytes(s); - } + => Encoding.UTF8.GetBytes(s); private static InMemoryQueueProvider NewProvider( MessagingMetricsProvider? metrics = null, MessagingOptions? options = null ) - { - return new InMemoryQueueProvider(options ?? new MessagingOptions(), metrics ?? new MessagingMetricsProvider()); - } + => new(options ?? new MessagingOptions(), metrics ?? new MessagingMetricsProvider()); private static string Text(ReadOnlyMemory b) - { - return Encoding.UTF8.GetString(b.Span); - } + => Encoding.UTF8.GetString(b.Span); } diff --git a/tests/SquidStd.Tests/Messaging/InMemoryTopicProviderTests.cs b/tests/SquidStd.Tests/Messaging/InMemoryTopicProviderTests.cs index 97b02930..888e1224 100644 --- a/tests/SquidStd.Tests/Messaging/InMemoryTopicProviderTests.cs +++ b/tests/SquidStd.Tests/Messaging/InMemoryTopicProviderTests.cs @@ -87,7 +87,5 @@ public async Task Publish_NoSubscribers_IsNoOp() } private static ReadOnlyMemory Bytes(string s) - { - return Encoding.UTF8.GetBytes(s); - } + => Encoding.UTF8.GetBytes(s); } diff --git a/tests/SquidStd.Tests/Messaging/MessageQueueTests.cs b/tests/SquidStd.Tests/Messaging/MessageQueueTests.cs index 78148e57..c0f71e00 100644 --- a/tests/SquidStd.Tests/Messaging/MessageQueueTests.cs +++ b/tests/SquidStd.Tests/Messaging/MessageQueueTests.cs @@ -1,5 +1,4 @@ using SquidStd.Core.Json; -using SquidStd.Messaging.Abstractions.Data.Config; using SquidStd.Messaging.Abstractions.Interfaces; using SquidStd.Messaging.Abstractions.Services; using SquidStd.Messaging.Services; @@ -13,7 +12,7 @@ public class MessageQueueTests [Fact] public async Task PublishAsync_DeliversTypedMessageToListener() { - await using var provider = new InMemoryQueueProvider(new MessagingOptions(), new MessagingMetricsProvider()); + await using var provider = new InMemoryQueueProvider(new(), new MessagingMetricsProvider()); var serializer = new JsonDataSerializer(); IMessageQueue queue = new MessageQueue(provider, serializer, serializer); var listener = new CapturingListener(); diff --git a/tests/SquidStd.Tests/Messaging/MessagingConnectionStringTests.cs b/tests/SquidStd.Tests/Messaging/MessagingConnectionStringTests.cs index f82c8b0a..57be3c85 100644 --- a/tests/SquidStd.Tests/Messaging/MessagingConnectionStringTests.cs +++ b/tests/SquidStd.Tests/Messaging/MessagingConnectionStringTests.cs @@ -16,9 +16,7 @@ public void Parse_Memory_ReadsScheme() [Fact] public void Parse_NullOrWhitespace_Throws() - { - Assert.Throws(() => MessagingConnectionString.Parse(" ")); - } + => Assert.Throws(() => MessagingConnectionString.Parse(" ")); [Fact] public void Parse_RabbitMq_ReadsCredentialsHostPortVhost() diff --git a/tests/SquidStd.Tests/Messaging/MessagingMetricsProviderTests.cs b/tests/SquidStd.Tests/Messaging/MessagingMetricsProviderTests.cs index ea163748..4cf10819 100644 --- a/tests/SquidStd.Tests/Messaging/MessagingMetricsProviderTests.cs +++ b/tests/SquidStd.Tests/Messaging/MessagingMetricsProviderTests.cs @@ -21,9 +21,7 @@ public async Task CollectAsync_ReportsCountersAndGaugesPerQueue() var samples = await metrics.CollectAsync(); double Value(string name) - { - return samples.Single(s => s.Name == name && s.Tags != null && s.Tags["queue"] == "orders").Value; - } + => samples.Single(s => s.Name == name && s.Tags != null && s.Tags["queue"] == "orders").Value; Assert.Equal(2, Value("published")); Assert.Equal(1, Value("delivered")); @@ -36,7 +34,5 @@ double Value(string name) [Fact] public void ProviderName_IsMessaging() - { - Assert.Equal("messaging", new MessagingMetricsProvider().ProviderName); - } + => Assert.Equal("messaging", new MessagingMetricsProvider().ProviderName); } diff --git a/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqContainerFixture.cs b/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqContainerFixture.cs index f30af310..3a1291f0 100644 --- a/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqContainerFixture.cs +++ b/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqContainerFixture.cs @@ -3,7 +3,7 @@ namespace SquidStd.Tests.Messaging.RabbitMq; /// -/// Starts a RabbitMQ container once for the whole collection and exposes its AMQP URI. +/// Starts a RabbitMQ container once for the whole collection and exposes its AMQP URI. /// public sealed class RabbitMqContainerFixture : IAsyncLifetime { @@ -12,14 +12,10 @@ public sealed class RabbitMqContainerFixture : IAsyncLifetime public string AmqpUri => _container.GetConnectionString(); public Task DisposeAsync() - { - return _container.DisposeAsync().AsTask(); - } + => _container.DisposeAsync().AsTask(); public Task InitializeAsync() - { - return _container.StartAsync(); - } + => _container.StartAsync(); } [CollectionDefinition(Name)] diff --git a/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqQueueProviderTests.cs b/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqQueueProviderTests.cs index ae74710c..b55e5de2 100644 --- a/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqQueueProviderTests.cs +++ b/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqQueueProviderTests.cs @@ -1,6 +1,5 @@ using System.Text; using SquidStd.Messaging.Abstractions.Data.Config; -using SquidStd.Messaging.RabbitMq.Data.Config; using SquidStd.Messaging.RabbitMq.Services; namespace SquidStd.Tests.Messaging.RabbitMq; @@ -20,7 +19,7 @@ public RabbitMqQueueProviderTests(RabbitMqContainerFixture fixture) [Fact] public async Task AlwaysFailing_IsDeadLettered() { - await using var provider = NewProvider(new MessagingOptions { MaxDeliveryAttempts = 2 }); + await using var provider = NewProvider(new() { MaxDeliveryAttempts = 2 }); await provider.StartAsync(); var queue = Queue(); provider.Subscribe(queue, (_, _) => throw new InvalidOperationException("always")); @@ -106,25 +105,17 @@ public async Task TwoSubscribers_ShareTheLoad() } private static ReadOnlyMemory Bytes(string s) - { - return Encoding.UTF8.GetBytes(s); - } + => Encoding.UTF8.GetBytes(s); private RabbitMqQueueProvider NewProvider(MessagingOptions? options = null) - { - return new RabbitMqQueueProvider( - new RabbitMqOptions { Uri = new Uri(_fixture.AmqpUri) }, + => new( + new() { Uri = new(_fixture.AmqpUri) }, options ?? new MessagingOptions() ); - } private static string Queue() - { - return "q-" + Guid.NewGuid().ToString("N"); - } + => "q-" + Guid.NewGuid().ToString("N"); private static string Text(ReadOnlyMemory b) - { - return Encoding.UTF8.GetString(b.Span); - } + => Encoding.UTF8.GetString(b.Span); } diff --git a/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqTopicProviderTests.cs b/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqTopicProviderTests.cs index 23691198..7cfbdffe 100644 --- a/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqTopicProviderTests.cs +++ b/tests/SquidStd.Tests/Messaging/RabbitMq/RabbitMqTopicProviderTests.cs @@ -1,5 +1,4 @@ using System.Text; -using SquidStd.Messaging.RabbitMq.Data.Config; using SquidStd.Messaging.RabbitMq.Services; namespace SquidStd.Tests.Messaging.RabbitMq; @@ -76,17 +75,11 @@ public async Task Publish_FansOutToAllSubscribers() } private static ReadOnlyMemory Bytes(string s) - { - return Encoding.UTF8.GetBytes(s); - } + => Encoding.UTF8.GetBytes(s); private RabbitMqTopicProvider NewProvider() - { - return new RabbitMqTopicProvider(new RabbitMqOptions { Uri = new Uri(_fixture.AmqpUri) }); - } + => new(new() { Uri = new(_fixture.AmqpUri) }); private static string Topic() - { - return "topic-" + Guid.NewGuid().ToString("N"); - } + => "topic-" + Guid.NewGuid().ToString("N"); } diff --git a/tests/SquidStd.Tests/Messaging/Sqs/LocalStackContainerFixture.cs b/tests/SquidStd.Tests/Messaging/Sqs/LocalStackContainerFixture.cs index 98b86d4e..c67be6c3 100644 --- a/tests/SquidStd.Tests/Messaging/Sqs/LocalStackContainerFixture.cs +++ b/tests/SquidStd.Tests/Messaging/Sqs/LocalStackContainerFixture.cs @@ -4,31 +4,28 @@ namespace SquidStd.Tests.Messaging.Sqs; /// -/// Starts a LocalStack container (SQS + SNS) once for the whole collection and exposes an -/// pointing at its edge endpoint with dummy credentials. +/// Starts a LocalStack container (SQS + SNS) once for the whole collection and exposes an +/// pointing at its edge endpoint with dummy credentials. /// public sealed class LocalStackContainerFixture : IAsyncLifetime { private readonly LocalStackContainer _container = new LocalStackBuilder().WithImage("localstack/localstack:3").Build(); - public AwsConfigEntry Aws => new() - { - Region = "us-east-1", - AccessKey = "test", - SecretKey = "test", - ServiceUrl = _container.GetConnectionString() - }; + public AwsConfigEntry Aws + => new() + { + Region = "us-east-1", + AccessKey = "test", + SecretKey = "test", + ServiceUrl = _container.GetConnectionString() + }; public Task DisposeAsync() - { - return _container.DisposeAsync().AsTask(); - } + => _container.DisposeAsync().AsTask(); public Task InitializeAsync() - { - return _container.StartAsync(); - } + => _container.StartAsync(); } [CollectionDefinition(Name)] diff --git a/tests/SquidStd.Tests/Messaging/Sqs/SqsConnectionStringTests.cs b/tests/SquidStd.Tests/Messaging/Sqs/SqsConnectionStringTests.cs index 00b83af0..032978c8 100644 --- a/tests/SquidStd.Tests/Messaging/Sqs/SqsConnectionStringTests.cs +++ b/tests/SquidStd.Tests/Messaging/Sqs/SqsConnectionStringTests.cs @@ -36,9 +36,7 @@ public void Parse_WithoutCredentials_LeavesThemNull() [Fact] public void WrongScheme_Throws() - { - Assert.Throws(() => SqsMessagingRegistrationExtensions.ParseOptions("rabbitmq://x")); - } + => Assert.Throws(() => SqsMessagingRegistrationExtensions.ParseOptions("rabbitmq://x")); [Fact] public void AddSqsMessaging_RegistersBothProviders() diff --git a/tests/SquidStd.Tests/Messaging/Sqs/SqsNamesTests.cs b/tests/SquidStd.Tests/Messaging/Sqs/SqsNamesTests.cs index 47779db9..31b555ab 100644 --- a/tests/SquidStd.Tests/Messaging/Sqs/SqsNamesTests.cs +++ b/tests/SquidStd.Tests/Messaging/Sqs/SqsNamesTests.cs @@ -6,19 +6,13 @@ public class SqsNamesTests { [Fact] public void Sanitize_ReplacesDotsWithDashes() - { - Assert.Equal("orders-dlq", SqsNames.Sanitize("orders.dlq")); - } + => Assert.Equal("orders-dlq", SqsNames.Sanitize("orders.dlq")); [Fact] public void Sanitize_KeepsLettersDigitsDashUnderscore() - { - Assert.Equal("a_b-9", SqsNames.Sanitize("a_b-9")); - } + => Assert.Equal("a_b-9", SqsNames.Sanitize("a_b-9")); [Fact] public void Sanitize_ReplacesSlashesAndColons() - { - Assert.Equal("a-b-c", SqsNames.Sanitize("a/b:c")); - } + => Assert.Equal("a-b-c", SqsNames.Sanitize("a/b:c")); } diff --git a/tests/SquidStd.Tests/Messaging/Sqs/SqsQueueProviderTests.cs b/tests/SquidStd.Tests/Messaging/Sqs/SqsQueueProviderTests.cs index 073a175f..6eab7439 100644 --- a/tests/SquidStd.Tests/Messaging/Sqs/SqsQueueProviderTests.cs +++ b/tests/SquidStd.Tests/Messaging/Sqs/SqsQueueProviderTests.cs @@ -55,6 +55,7 @@ public async Task TwoSubscribers_ShareTheLoad() { Interlocked.Increment(ref a); done.Signal(); + return Task.CompletedTask; } ); @@ -64,6 +65,7 @@ public async Task TwoSubscribers_ShareTheLoad() { Interlocked.Increment(ref b); done.Signal(); + return Task.CompletedTask; } ); @@ -81,8 +83,8 @@ public async Task TwoSubscribers_ShareTheLoad() public async Task AlwaysFailing_IsDeadLettered() { await using var provider = NewProvider( - new MessagingOptions { MaxDeliveryAttempts = 1 }, - new SqsOptions { Aws = _fixture.Aws, VisibilityTimeout = TimeSpan.FromSeconds(1), WaitTimeSeconds = 1 } + new() { MaxDeliveryAttempts = 1 }, + new() { Aws = _fixture.Aws, VisibilityTimeout = TimeSpan.FromSeconds(1), WaitTimeSeconds = 1 } ); await provider.StartAsync(); var queue = Queue(); @@ -94,6 +96,7 @@ public async Task AlwaysFailing_IsDeadLettered() (payload, _) => { deadLettered.TrySetResult(Text(payload)); + return Task.CompletedTask; } ); @@ -104,25 +107,17 @@ public async Task AlwaysFailing_IsDeadLettered() } private SqsQueueProvider NewProvider(MessagingOptions? messaging = null, SqsOptions? sqs = null) - { - return new SqsQueueProvider( + => new( sqs ?? new SqsOptions { Aws = _fixture.Aws, WaitTimeSeconds = 1 }, messaging ?? new MessagingOptions() ); - } private static ReadOnlyMemory Bytes(string s) - { - return Encoding.UTF8.GetBytes(s); - } + => Encoding.UTF8.GetBytes(s); private static string Text(ReadOnlyMemory b) - { - return Encoding.UTF8.GetString(b.Span); - } + => Encoding.UTF8.GetString(b.Span); private static string Queue() - { - return "q-" + Guid.NewGuid().ToString("N"); - } + => "q-" + Guid.NewGuid().ToString("N"); } diff --git a/tests/SquidStd.Tests/Messaging/Sqs/SqsTopicProviderTests.cs b/tests/SquidStd.Tests/Messaging/Sqs/SqsTopicProviderTests.cs index 818df2ea..5a591d99 100644 --- a/tests/SquidStd.Tests/Messaging/Sqs/SqsTopicProviderTests.cs +++ b/tests/SquidStd.Tests/Messaging/Sqs/SqsTopicProviderTests.cs @@ -1,5 +1,4 @@ using System.Text; -using SquidStd.Messaging.Sqs.Data.Config; using SquidStd.Messaging.Sqs.Services; namespace SquidStd.Tests.Messaging.Sqs; @@ -29,6 +28,7 @@ public async Task Publish_FansOutToAllSubscribers() (payload, _) => { a.TrySetResult(Text(payload)); + return Task.CompletedTask; } ); @@ -37,6 +37,7 @@ public async Task Publish_FansOutToAllSubscribers() (payload, _) => { b.TrySetResult(Text(payload)); + return Task.CompletedTask; } ); @@ -50,22 +51,14 @@ public async Task Publish_FansOutToAllSubscribers() } private SqsTopicProvider NewProvider() - { - return new SqsTopicProvider(new SqsOptions { Aws = _fixture.Aws, WaitTimeSeconds = 1 }); - } + => new(new() { Aws = _fixture.Aws, WaitTimeSeconds = 1 }); private static ReadOnlyMemory Bytes(string s) - { - return Encoding.UTF8.GetBytes(s); - } + => Encoding.UTF8.GetBytes(s); private static string Text(ReadOnlyMemory b) - { - return Encoding.UTF8.GetString(b.Span); - } + => Encoding.UTF8.GetString(b.Span); private static string Topic() - { - return "topic-" + Guid.NewGuid().ToString("N"); - } + => "topic-" + Guid.NewGuid().ToString("N"); } diff --git a/tests/SquidStd.Tests/Network/CircularBufferTests.cs b/tests/SquidStd.Tests/Network/CircularBufferTests.cs index 70306fe9..8b1215db 100644 --- a/tests/SquidStd.Tests/Network/CircularBufferTests.cs +++ b/tests/SquidStd.Tests/Network/CircularBufferTests.cs @@ -18,15 +18,11 @@ public void Clear_ResetsSizeButKeepsCapacity() [Fact] public void Constructor_NonPositiveCapacity_Throws() - { - Assert.Throws(() => new CircularBuffer(0)); - } + => Assert.Throws(() => new CircularBuffer(0)); [Fact] public void Constructor_TooManyItems_Throws() - { - Assert.Throws(() => new CircularBuffer(2, [1, 2, 3])); - } + => Assert.Throws(() => new CircularBuffer(2, [1, 2, 3])); [Fact] public void Constructor_WithItems_PopulatesBuffer() diff --git a/tests/SquidStd.Tests/Network/NetMiddlewarePipelineTests.cs b/tests/SquidStd.Tests/Network/NetMiddlewarePipelineTests.cs index 2598633e..01657a69 100644 --- a/tests/SquidStd.Tests/Network/NetMiddlewarePipelineTests.cs +++ b/tests/SquidStd.Tests/Network/NetMiddlewarePipelineTests.cs @@ -30,8 +30,9 @@ public async Task ExecuteAsync_CancelledToken_Throws() using var cts = new CancellationTokenSource(); await cts.CancelAsync(); - await Assert.ThrowsAsync(async () => - await pipeline.ExecuteAsync(null, new byte[] { 1 }, cts.Token) + await Assert.ThrowsAsync( + async () => + await pipeline.ExecuteAsync(null, new byte[] { 1 }, cts.Token) ); } diff --git a/tests/SquidStd.Tests/Network/PacketExtensionsTests.cs b/tests/SquidStd.Tests/Network/PacketExtensionsTests.cs index 96099258..5f680b54 100644 --- a/tests/SquidStd.Tests/Network/PacketExtensionsTests.cs +++ b/tests/SquidStd.Tests/Network/PacketExtensionsTests.cs @@ -4,13 +4,7 @@ namespace SquidStd.Tests.Network; public class PacketExtensionsTests { - [Theory] - [InlineData(0x00, "0x00")] - [InlineData(0x0F, "0x0F")] - [InlineData(0xAB, "0xAB")] - [InlineData(0xFF, "0xFF")] + [Theory, InlineData(0x00, "0x00"), InlineData(0x0F, "0x0F"), InlineData(0xAB, "0xAB"), InlineData(0xFF, "0xFF")] public void ToPacketString_FormatsAsTwoDigitHex(byte opCode, string expected) - { - Assert.Equal(expected, opCode.ToPacketString()); - } + => Assert.Equal(expected, opCode.ToPacketString()); } diff --git a/tests/SquidStd.Tests/Network/SessionManagerTests.cs b/tests/SquidStd.Tests/Network/SessionManagerTests.cs index 54084230..7032ef30 100644 --- a/tests/SquidStd.Tests/Network/SessionManagerTests.cs +++ b/tests/SquidStd.Tests/Network/SessionManagerTests.cs @@ -139,7 +139,7 @@ public async Task Integration_LifecycleOverLoopback() { var timeout = TimeSpan.FromSeconds(5); - await using var server = new SquidTcpServer(new IPEndPoint(IPAddress.Loopback, 0)); + await using var server = new SquidTcpServer(new(IPAddress.Loopback, 0)); using var manager = NewManager(server); var created = new TaskCompletionSource>(TaskCreationOptions.RunContinuationsAsynchronously); @@ -152,7 +152,7 @@ public async Task Integration_LifecycleOverLoopback() await server.StartAsync(CancellationToken.None); var port = server.Port; - var client = await SquidStdTcpClient.ConnectAsync(new IPEndPoint(IPAddress.Loopback, port)); + var client = await SquidStdTcpClient.ConnectAsync(new(IPAddress.Loopback, port)); var session = await created.Task.WaitAsync(timeout); Assert.Equal(1, manager.Count); @@ -216,12 +216,8 @@ public void TryGetSession_HitAndMiss() } private static SessionManager NewManager(SquidTcpServer server) - { - return new SessionManager(server, connection => $"state-{connection.SessionId}"); - } + => new(server, connection => $"state-{connection.SessionId}"); private static SquidTcpServer NewServer() - { - return new SquidTcpServer(new IPEndPoint(IPAddress.Loopback, 0)); - } + => new(new(IPAddress.Loopback, 0)); } diff --git a/tests/SquidStd.Tests/Network/SquidStdUdpClientTests.cs b/tests/SquidStd.Tests/Network/SquidStdUdpClientTests.cs index f80106d8..334d8ffb 100644 --- a/tests/SquidStd.Tests/Network/SquidStdUdpClientTests.cs +++ b/tests/SquidStd.Tests/Network/SquidStdUdpClientTests.cs @@ -10,7 +10,7 @@ public class SquidStdUdpClientTests [Fact] public async Task CloseAsync_RaisesDisconnectedOnceAndMarksDisconnected() { - var client = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + var client = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); var disconnects = 0; client.OnDisconnected += (_, _) => Interlocked.Increment(ref disconnects); await client.StartAsync(CancellationToken.None); @@ -25,8 +25,8 @@ public async Task CloseAsync_RaisesDisconnectedOnceAndMarksDisconnected() [Fact] public void Constructor_AssignsUniqueSessionIds() { - using var first = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); - using var second = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + using var first = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); + using var second = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); Assert.NotEqual(first.SessionId, second.SessionId); } @@ -34,7 +34,7 @@ public void Constructor_AssignsUniqueSessionIds() [Fact] public void Constructor_BindsLocalEndPoint() { - using var client = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + using var client = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); var local = Assert.IsType(client.LocalEndPoint); Assert.NotEqual(0, local.Port); @@ -46,7 +46,7 @@ public void RemoteEndPoint_ReflectsConfiguredDefault() { var remote = new IPEndPoint(IPAddress.Loopback, 9999); - using var client = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0), remote); + using var client = new SquidStdUdpClient(new(IPAddress.Loopback, 0), remote); Assert.Equal(remote, client.RemoteEndPoint); } @@ -54,7 +54,7 @@ public void RemoteEndPoint_ReflectsConfiguredDefault() [Fact] public async Task SendAsync_UsesConfiguredDefaultRemote() { - await using var receiver = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + await using var receiver = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); receiver.OnDataReceived += (_, e) => received.TrySetResult(e.Data.ToArray()); await receiver.StartAsync(CancellationToken.None); @@ -62,8 +62,8 @@ public async Task SendAsync_UsesConfiguredDefaultRemote() var receiverPort = ((IPEndPoint)receiver.LocalEndPoint!).Port; await using var sender = new SquidStdUdpClient( - new IPEndPoint(IPAddress.Loopback, 0), - new IPEndPoint(IPAddress.Loopback, receiverPort) + new(IPAddress.Loopback, 0), + new(IPAddress.Loopback, receiverPort) ); await sender.StartAsync(CancellationToken.None); await sender.SendAsync(new byte[] { 9, 8, 7 }, CancellationToken.None); @@ -75,28 +75,29 @@ public async Task SendAsync_UsesConfiguredDefaultRemote() [Fact] public async Task SendAsync_WithoutDefaultRemote_Throws() { - await using var client = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + await using var client = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); - await Assert.ThrowsAsync(async () => - await client.SendAsync(new byte[] { 1 }, CancellationToken.None) + await Assert.ThrowsAsync( + async () => + await client.SendAsync(new byte[] { 1 }, CancellationToken.None) ); } [Fact] public async Task SendToAsync_DeliversDatagramToPeer() { - await using var receiver = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + await using var receiver = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); receiver.OnDataReceived += (_, e) => received.TrySetResult(e.Data.ToArray()); await receiver.StartAsync(CancellationToken.None); var receiverPort = ((IPEndPoint)receiver.LocalEndPoint!).Port; - await using var sender = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + await using var sender = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); await sender.StartAsync(CancellationToken.None); await sender.SendToAsync( new byte[] { 1, 2, 3, 4 }, - new IPEndPoint(IPAddress.Loopback, receiverPort), + new(IPAddress.Loopback, receiverPort), CancellationToken.None ); @@ -107,7 +108,7 @@ await sender.SendToAsync( [Fact] public async Task StartAsync_RaisesConnected() { - await using var client = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + await using var client = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); var connected = false; client.OnConnected += (_, _) => connected = true; diff --git a/tests/SquidStd.Tests/Network/SquidStdUdpServerTests.cs b/tests/SquidStd.Tests/Network/SquidStdUdpServerTests.cs index 2f9d4d5d..de740c6f 100644 --- a/tests/SquidStd.Tests/Network/SquidStdUdpServerTests.cs +++ b/tests/SquidStd.Tests/Network/SquidStdUdpServerTests.cs @@ -12,7 +12,7 @@ public class SquidStdUdpServerTests [Fact] public async Task BindSingleInterface_HasOneListener() { - await using var server = new SquidStdUdpServer(new IPEndPoint(IPAddress.Loopback, 0), false); + await using var server = new SquidStdUdpServer(new(IPAddress.Loopback, 0), false); await server.StartAsync(CancellationToken.None); Assert.Equal(1, server.ListenerCount); @@ -21,17 +21,17 @@ public async Task BindSingleInterface_HasOneListener() [Fact] public async Task DefaultBehaviour_EchoesDatagramBackToSender() { - await using var server = new SquidStdUdpServer(new IPEndPoint(IPAddress.Loopback, 0), false); + await using var server = new SquidStdUdpServer(new(IPAddress.Loopback, 0), false); await server.StartAsync(CancellationToken.None); var serverPort = server.Port; - await using var client = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + await using var client = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); client.OnDataReceived += (_, e) => received.TrySetResult(e.Data.ToArray()); await client.StartAsync(CancellationToken.None); var payload = new byte[] { 1, 2, 3, 4, 5 }; - await client.SendToAsync(payload, new IPEndPoint(IPAddress.Loopback, serverPort), CancellationToken.None); + await client.SendToAsync(payload, new(IPAddress.Loopback, serverPort), CancellationToken.None); Assert.Equal(payload, await received.Task.WaitAsync(Timeout)); } @@ -39,19 +39,19 @@ public async Task DefaultBehaviour_EchoesDatagramBackToSender() [Fact] public async Task OnDatagram_CustomResponse_IsReturnedToSender() { - await using var server = new SquidStdUdpServer(new IPEndPoint(IPAddress.Loopback, 0), false) + await using var server = new SquidStdUdpServer(new(IPAddress.Loopback, 0), false) { OnDatagram = (_, _) => new byte[] { 0xFF, 0xFE } }; await server.StartAsync(CancellationToken.None); var serverPort = server.Port; - await using var client = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + await using var client = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); client.OnDataReceived += (_, e) => received.TrySetResult(e.Data.ToArray()); await client.StartAsync(CancellationToken.None); - await client.SendToAsync(new byte[] { 1 }, new IPEndPoint(IPAddress.Loopback, serverPort), CancellationToken.None); + await client.SendToAsync(new byte[] { 1 }, new(IPAddress.Loopback, serverPort), CancellationToken.None); Assert.Equal([0xFF, 0xFE], await received.Task.WaitAsync(Timeout)); } @@ -59,17 +59,17 @@ public async Task OnDatagram_CustomResponse_IsReturnedToSender() [Fact] public async Task OnDatagramReceived_RaisedForIncomingDatagram() { - await using var server = new SquidStdUdpServer(new IPEndPoint(IPAddress.Loopback, 0), false); + await using var server = new SquidStdUdpServer(new(IPAddress.Loopback, 0), false); var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); server.OnDatagramReceived += (_, e) => received.TrySetResult(e.Data.ToArray()); await server.StartAsync(CancellationToken.None); var serverPort = server.Port; - await using var client = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + await using var client = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); await client.StartAsync(CancellationToken.None); await client.SendToAsync( new byte[] { 1, 2, 3 }, - new IPEndPoint(IPAddress.Loopback, serverPort), + new(IPAddress.Loopback, serverPort), CancellationToken.None ); @@ -79,7 +79,7 @@ await client.SendToAsync( [Fact] public async Task SendToAsync_DeliversToEndpointThatWasSeen() { - await using var server = new SquidStdUdpServer(new IPEndPoint(IPAddress.Loopback, 0), false) + await using var server = new SquidStdUdpServer(new(IPAddress.Loopback, 0), false) { OnDatagram = static (_, _) => ReadOnlyMemory.Empty // suppress default echo for this test }; @@ -88,13 +88,13 @@ public async Task SendToAsync_DeliversToEndpointThatWasSeen() await server.StartAsync(CancellationToken.None); var serverPort = server.Port; - await using var client = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + await using var client = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); var clientReceived = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); client.OnDataReceived += (_, e) => clientReceived.TrySetResult(e.Data.ToArray()); await client.StartAsync(CancellationToken.None); // Make the server "see" the client endpoint first. - await client.SendToAsync(new byte[] { 0 }, new IPEndPoint(IPAddress.Loopback, serverPort), CancellationToken.None); + await client.SendToAsync(new byte[] { 0 }, new(IPAddress.Loopback, serverPort), CancellationToken.None); var clientEndpoint = await senderEndpoint.Task.WaitAsync(Timeout); await server.SendToAsync(clientEndpoint, new byte[] { 9, 9 }, CancellationToken.None); @@ -105,7 +105,7 @@ public async Task SendToAsync_DeliversToEndpointThatWasSeen() [Fact] public void ServerType_IsUdp() { - using var server = new SquidStdUdpServer(new IPEndPoint(IPAddress.Loopback, 0), false); + using var server = new SquidStdUdpServer(new(IPAddress.Loopback, 0), false); Assert.Equal(ServerType.UDP, server.ServerType); } @@ -113,7 +113,7 @@ public void ServerType_IsUdp() [Fact] public async Task StartStop_TogglesIsRunning() { - await using var server = new SquidStdUdpServer(new IPEndPoint(IPAddress.Loopback, 0), false); + await using var server = new SquidStdUdpServer(new(IPAddress.Loopback, 0), false); Assert.False(server.IsRunning); await server.StartAsync(CancellationToken.None); diff --git a/tests/SquidStd.Tests/Network/TcpMaxFrameLengthTests.cs b/tests/SquidStd.Tests/Network/TcpMaxFrameLengthTests.cs index 7ad61377..91203987 100644 --- a/tests/SquidStd.Tests/Network/TcpMaxFrameLengthTests.cs +++ b/tests/SquidStd.Tests/Network/TcpMaxFrameLengthTests.cs @@ -8,36 +8,10 @@ namespace SquidStd.Tests.Network; public sealed class TcpMaxFrameLengthTests { - // 4-byte big-endian length prefix framer. - private sealed class LengthPrefixFramer : INetFramer - { - public bool TryReadFrame(ReadOnlySpan buffer, out int frameLength) - { - frameLength = 0; - - if (buffer.Length < 4) - { - return false; - } - - var payloadLength = BinaryPrimitives.ReadInt32BigEndian(buffer); - var total = 4 + payloadLength; - - if (buffer.Length < total) - { - return false; - } - - frameLength = total; - - return true; - } - } - [Fact] public async Task OversizedDeclaredFrame_ClosesConnection() { - var (server, client) = await ConnectedPairAsync(maxFrameLength: 1024); + var (server, client) = await ConnectedPairAsync(1024); try { @@ -61,7 +35,7 @@ public async Task OversizedDeclaredFrame_ClosesConnection() [Fact] public async Task FrameAtTheLimit_IsDelivered() { - var (server, client) = await ConnectedPairAsync(maxFrameLength: 1024); + var (server, client) = await ConnectedPairAsync(1024); var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); client.OnDataReceived += (_, e) => received.TrySetResult(e.Data.ToArray()); @@ -99,8 +73,13 @@ public async Task FrameAtTheLimit_IsDelivered() // "server" side here is just the sending end; the receiving end (client) enforces the cap. var server = new SquidStdTcpClient(serverSocket); - var client = new SquidStdTcpClient(clientSocket, middlewares: null, framer: new LengthPrefixFramer(), - codec: null, maxFrameLength: maxFrameLength); + var client = new SquidStdTcpClient( + clientSocket, + middlewares: null, + new LengthPrefixFramer(), + null, + maxFrameLength: maxFrameLength + ); await server.StartAsync(CancellationToken.None); await client.StartAsync(CancellationToken.None); @@ -124,4 +103,30 @@ private static async Task WaitUntilAsync(Func condition, TimeSpan ti return condition(); } + + // 4-byte big-endian length prefix framer. + private sealed class LengthPrefixFramer : INetFramer + { + public bool TryReadFrame(ReadOnlySpan buffer, out int frameLength) + { + frameLength = 0; + + if (buffer.Length < 4) + { + return false; + } + + var payloadLength = BinaryPrimitives.ReadInt32BigEndian(buffer); + var total = 4 + payloadLength; + + if (buffer.Length < total) + { + return false; + } + + frameLength = total; + + return true; + } + } } diff --git a/tests/SquidStd.Tests/Network/TransportCodecTests.cs b/tests/SquidStd.Tests/Network/TransportCodecTests.cs index fe812271..c02f6cf5 100644 --- a/tests/SquidStd.Tests/Network/TransportCodecTests.cs +++ b/tests/SquidStd.Tests/Network/TransportCodecTests.cs @@ -1,7 +1,6 @@ using System.Collections.Concurrent; using System.Net; using SquidStd.Network.Client; -using SquidStd.Network.Data; using SquidStd.Network.Server; using SquidStd.Tests.Support; @@ -17,16 +16,16 @@ public async Task Codec_RoundTripsClientToServer() var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); await using var server = new SquidTcpServer( - new IPEndPoint(IPAddress.Loopback, 0), - connectionPipelineFactory: () => new ConnectionPipeline(new CountingXorCodec(7)) + new(IPAddress.Loopback, 0), + connectionPipelineFactory: () => new(new CountingXorCodec(7)) ); server.OnDataReceived += (_, e) => received.TrySetResult(e.Data.ToArray()); await server.StartAsync(CancellationToken.None); await using var client = await SquidStdTcpClient.ConnectAsync( - new IPEndPoint(IPAddress.Loopback, server.Port), - codec: new CountingXorCodec(7) - ); + new(IPAddress.Loopback, server.Port), + codec: new CountingXorCodec(7) + ); var payload = new byte[] { 1, 2, 3, 4, 5 }; await client.SendAsync(payload, CancellationToken.None); @@ -39,11 +38,11 @@ public async Task NoCodecNoFactory_PassesBytesUnchanged() { var received = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - await using var server = new SquidTcpServer(new IPEndPoint(IPAddress.Loopback, 0)); + await using var server = new SquidTcpServer(new(IPAddress.Loopback, 0)); server.OnDataReceived += (_, e) => received.TrySetResult(e.Data.ToArray()); await server.StartAsync(CancellationToken.None); - await using var client = await SquidStdTcpClient.ConnectAsync(new IPEndPoint(IPAddress.Loopback, server.Port)); + await using var client = await SquidStdTcpClient.ConnectAsync(new(IPAddress.Loopback, server.Port)); var payload = new byte[] { 42, 43, 44 }; await client.SendAsync(payload, CancellationToken.None); @@ -62,20 +61,20 @@ public async Task Codec_ConcurrentSends_PreserveKeystreamIntegrity() using var done = new CountdownEvent(messageCount); await using var server = new SquidTcpServer( - new IPEndPoint(IPAddress.Loopback, 0), - connectionPipelineFactory: () => new ConnectionPipeline(new CountingXorCodec(5), null, new LengthPrefixFramer()) + new(IPAddress.Loopback, 0), + connectionPipelineFactory: () => new(new CountingXorCodec(5), null, new LengthPrefixFramer()) ); server.OnDataReceived += (_, e) => - { - frames.Add(e.Data.ToArray()); - done.Signal(); - }; + { + frames.Add(e.Data.ToArray()); + done.Signal(); + }; await server.StartAsync(CancellationToken.None); await using var client = await SquidStdTcpClient.ConnectAsync( - new IPEndPoint(IPAddress.Loopback, server.Port), - codec: new CountingXorCodec(5) - ); + new(IPAddress.Loopback, server.Port), + codec: new CountingXorCodec(5) + ); await Parallel.ForEachAsync( Enumerable.Range(0, messageCount), @@ -121,16 +120,16 @@ public async Task Codec_WithFramer_EmitsDecodedFrames() var frames = new BlockingCollection(); await using var server = new SquidTcpServer( - new IPEndPoint(IPAddress.Loopback, 0), - connectionPipelineFactory: () => new ConnectionPipeline(new CountingXorCodec(2), null, new LengthPrefixFramer()) + new(IPAddress.Loopback, 0), + connectionPipelineFactory: () => new(new CountingXorCodec(2), null, new LengthPrefixFramer()) ); server.OnDataReceived += (_, e) => frames.Add(e.Data.ToArray()); await server.StartAsync(CancellationToken.None); await using var client = await SquidStdTcpClient.ConnectAsync( - new IPEndPoint(IPAddress.Loopback, server.Port), - codec: new CountingXorCodec(2) - ); + new(IPAddress.Loopback, server.Port), + codec: new CountingXorCodec(2) + ); // Three length-prefixed messages in a single send: [len=2][AA BB] [len=1][CC] [len=3][01 02 03]. var buffer = new byte[] { 2, 0xAA, 0xBB, 1, 0xCC, 3, 0x01, 0x02, 0x03 }; @@ -151,8 +150,8 @@ public async Task Codec_IsolatesStatePerConnection() var inbox = new BlockingCollection(); await using var server = new SquidTcpServer( - new IPEndPoint(IPAddress.Loopback, 0), - connectionPipelineFactory: () => new ConnectionPipeline(new CountingXorCodec(3)) + new(IPAddress.Loopback, 0), + connectionPipelineFactory: () => new(new CountingXorCodec(3)) ); server.OnDataReceived += (_, e) => inbox.Add(e.Data.ToArray()); await server.StartAsync(CancellationToken.None); @@ -162,9 +161,9 @@ public async Task Codec_IsolatesStatePerConnection() for (var i = 0; i < 2; i++) { await using var client = await SquidStdTcpClient.ConnectAsync( - new IPEndPoint(IPAddress.Loopback, server.Port), - codec: new CountingXorCodec(3) - ); + new(IPAddress.Loopback, server.Port), + codec: new CountingXorCodec(3) + ); await client.SendAsync(payload, CancellationToken.None); Assert.True(inbox.TryTake(out var got, Timeout)); @@ -181,27 +180,27 @@ public async Task Codec_SwapsAtomicallyMidConnection() var second = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); await using var server = new SquidTcpServer( - new IPEndPoint(IPAddress.Loopback, 0), - connectionPipelineFactory: () => new ConnectionPipeline(new CountingXorCodec(10)) + new(IPAddress.Loopback, 0), + connectionPipelineFactory: () => new(new CountingXorCodec(10)) ); server.OnDataReceived += (_, e) => - { - if (first.Task.IsCompleted) - { - second.TrySetResult(e.Data.ToArray()); - } - else - { - e.Client.SwapCodec(new CountingXorCodec(20)); - first.TrySetResult(e.Data.ToArray()); - } - }; + { + if (first.Task.IsCompleted) + { + second.TrySetResult(e.Data.ToArray()); + } + else + { + e.Client.SwapCodec(new CountingXorCodec(20)); + first.TrySetResult(e.Data.ToArray()); + } + }; await server.StartAsync(CancellationToken.None); await using var client = await SquidStdTcpClient.ConnectAsync( - new IPEndPoint(IPAddress.Loopback, server.Port), - codec: new CountingXorCodec(10) - ); + new(IPAddress.Loopback, server.Port), + codec: new CountingXorCodec(10) + ); await client.SendAsync(msg1, CancellationToken.None); Assert.Equal(msg1, await first.Task.WaitAsync(Timeout)); diff --git a/tests/SquidStd.Tests/Network/UdpSessionManagerTests.cs b/tests/SquidStd.Tests/Network/UdpSessionManagerTests.cs index 5980026e..2dfaf20f 100644 --- a/tests/SquidStd.Tests/Network/UdpSessionManagerTests.cs +++ b/tests/SquidStd.Tests/Network/UdpSessionManagerTests.cs @@ -82,7 +82,7 @@ public async Task Integration_DatagramCreatesSessionAndManagerCanReply() { var timeout = TimeSpan.FromSeconds(5); - await using var server = new SquidStdUdpServer(new IPEndPoint(IPAddress.Loopback, 0), false); + await using var server = new SquidStdUdpServer(new(IPAddress.Loopback, 0), false); using var manager = new UdpSessionManager(server, c => $"state-{c.SessionId}"); var created = new TaskCompletionSource>(TaskCreationOptions.RunContinuationsAsynchronously); @@ -93,14 +93,14 @@ public async Task Integration_DatagramCreatesSessionAndManagerCanReply() await server.StartAsync(CancellationToken.None); var serverPort = server.Port; - await using var client = new SquidStdUdpClient(new IPEndPoint(IPAddress.Loopback, 0)); + await using var client = new SquidStdUdpClient(new(IPAddress.Loopback, 0)); var clientReceived = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); client.OnDataReceived += (_, e) => clientReceived.TrySetResult(e.Data.ToArray()); await client.StartAsync(CancellationToken.None); await client.SendToAsync( new byte[] { 1, 2, 3 }, - new IPEndPoint(IPAddress.Loopback, serverPort), + new(IPAddress.Loopback, serverPort), CancellationToken.None ); @@ -168,23 +168,17 @@ public void SweepExpiredSessions_RemovesIdleSessions() } private static UdpSessionManager NewManager(SquidStdUdpServer server, FakeTimeProvider time) - { - return new UdpSessionManager( + => new( server, connection => $"state-{connection.SessionId}", TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(10), time ); - } private static SquidStdUdpServer NewServer() - { - return new SquidStdUdpServer(new IPEndPoint(IPAddress.Loopback, 0), false); - } + => new(new(IPAddress.Loopback, 0), false); private static IPEndPoint Peer(int port) - { - return new IPEndPoint(IPAddress.Loopback, port); - } + => new(IPAddress.Loopback, port); } diff --git a/tests/SquidStd.Tests/Persistence/DurableWriteTests.cs b/tests/SquidStd.Tests/Persistence/DurableWriteTests.cs index 4a554745..92ac939b 100644 --- a/tests/SquidStd.Tests/Persistence/DurableWriteTests.cs +++ b/tests/SquidStd.Tests/Persistence/DurableWriteTests.cs @@ -15,14 +15,16 @@ public async Task DurableJournal_AppendThenReadAll_RoundTrips() var path = Path.Combine(_dir, "world.journal.bin"); await using var journal = new BinaryJournalService(path, DurabilityMode.Durable); - await journal.AppendAsync(new JournalEntry - { - SequenceId = 1, - TimestampUnixMilliseconds = 1000, - TypeId = 1, - Operation = JournalEntityOperationType.Upsert, - Payload = [1, 2, 3] - }); + await journal.AppendAsync( + new() + { + SequenceId = 1, + TimestampUnixMilliseconds = 1000, + TypeId = 1, + Operation = JournalEntityOperationType.Upsert, + Payload = [1, 2, 3] + } + ); var entries = (await journal.ReadAllAsync()).ToArray(); Assert.Single(entries); @@ -35,7 +37,7 @@ public async Task DurableSnapshot_SaveThenLoad_RoundTrips() var service = new SnapshotService(_dir, ".snapshot.bin", DurabilityMode.Durable); var bucket = new EntitySnapshotBucket { TypeId = 1, TypeName = "Player", SchemaVersion = 1, Payload = [9, 9] }; - await service.SaveBucketAsync(bucket, lastSequenceId: 5); + await service.SaveBucketAsync(bucket, 5); var loaded = await service.LoadBucketAsync("Player", 1); Assert.NotNull(loaded); diff --git a/tests/SquidStd.Tests/Persistence/EntityStoreTests.cs b/tests/SquidStd.Tests/Persistence/EntityStoreTests.cs index 39f60a39..73fb5264 100644 --- a/tests/SquidStd.Tests/Persistence/EntityStoreTests.cs +++ b/tests/SquidStd.Tests/Persistence/EntityStoreTests.cs @@ -18,14 +18,14 @@ public EntityStoreTests() var serializer = new JsonDataSerializer(); IPersistenceEntityDescriptor descriptor = new PersistenceEntityDescriptor(serializer, serializer, 1, "Player", 1, p => p.Id); - _journal = new BinaryJournalService(Path.Combine(_dir, "world.journal.bin")); - _store = new EntityStore(_stateStore, _journal, descriptor); + _journal = new(Path.Combine(_dir, "world.journal.bin")); + _store = new(_stateStore, _journal, descriptor); } [Fact] public async Task Upsert_ThenGetById_ReturnsClone() { - await _store.UpsertAsync(new Player { Id = 1, Name = "Bob" }); + await _store.UpsertAsync(new() { Id = 1, Name = "Bob" }); var fetched = await _store.GetByIdAsync(1); @@ -36,7 +36,7 @@ public async Task Upsert_ThenGetById_ReturnsClone() [Fact] public async Task GetById_ReturnsDetachedClone() { - await _store.UpsertAsync(new Player { Id = 1, Tags = ["a"] }); + await _store.UpsertAsync(new() { Id = 1, Tags = ["a"] }); var first = await _store.GetByIdAsync(1); first!.Tags.Add("mutated"); @@ -48,7 +48,7 @@ public async Task GetById_ReturnsDetachedClone() [Fact] public async Task Upsert_AppendsToJournal() { - await _store.UpsertAsync(new Player { Id = 1 }); + await _store.UpsertAsync(new() { Id = 1 }); Assert.Single(await _journal.ReadAllAsync()); } @@ -56,7 +56,7 @@ public async Task Upsert_AppendsToJournal() [Fact] public async Task Remove_ExistingKey_ReturnsTrueAndJournals() { - await _store.UpsertAsync(new Player { Id = 1 }); + await _store.UpsertAsync(new() { Id = 1 }); Assert.True(await _store.RemoveAsync(1)); Assert.Null(await _store.GetByIdAsync(1)); @@ -73,8 +73,8 @@ public async Task Remove_MissingKey_ReturnsFalseAndDoesNotJournal() [Fact] public async Task CountAndGetAll_ReflectState() { - await _store.UpsertAsync(new Player { Id = 1 }); - await _store.UpsertAsync(new Player { Id = 2 }); + await _store.UpsertAsync(new() { Id = 1 }); + await _store.UpsertAsync(new() { Id = 2 }); Assert.Equal(2, await _store.CountAsync()); Assert.Equal(2, (await _store.GetAllAsync()).Count); @@ -83,8 +83,8 @@ public async Task CountAndGetAll_ReflectState() [Fact] public async Task Query_ReturnsQueryableClones() { - await _store.UpsertAsync(new Player { Id = 1, Name = "Alice" }); - await _store.UpsertAsync(new Player { Id = 2, Name = "Bob" }); + await _store.UpsertAsync(new() { Id = 1, Name = "Alice" }); + await _store.UpsertAsync(new() { Id = 2, Name = "Bob" }); var names = _store.Query().Where(p => p.Name.StartsWith('A')).Select(p => p.Name).ToArray(); diff --git a/tests/SquidStd.Tests/Persistence/EntityStoreWalOrderingTests.cs b/tests/SquidStd.Tests/Persistence/EntityStoreWalOrderingTests.cs index 4a600045..702c5ec1 100644 --- a/tests/SquidStd.Tests/Persistence/EntityStoreWalOrderingTests.cs +++ b/tests/SquidStd.Tests/Persistence/EntityStoreWalOrderingTests.cs @@ -18,7 +18,7 @@ public async Task Upsert_WhenJournalAppendThrows_LeavesInMemoryStateUnchanged() var stateStore = new PersistenceStateStore(); var store = new EntityStore(stateStore, new ThrowingJournalService(), descriptor); - await Assert.ThrowsAsync(async () => await store.UpsertAsync(new Player { Id = 1, Name = "Bob" })); + await Assert.ThrowsAsync(async () => await store.UpsertAsync(new() { Id = 1, Name = "Bob" })); // The failed durable append must NOT have applied the mutation in memory. Assert.Null(await store.GetByIdAsync(1)); @@ -34,7 +34,7 @@ public async Task Remove_WhenJournalAppendThrows_KeepsEntity() var stateStore = new PersistenceStateStore(); var ok = new CountingJournalService(); var store = new EntityStore(stateStore, ok, descriptor); - await store.UpsertAsync(new Player { Id = 1, Name = "Bob" }); + await store.UpsertAsync(new() { Id = 1, Name = "Bob" }); ok.FailNextAppend = true; await Assert.ThrowsAsync(async () => await store.RemoveAsync(1)); @@ -59,7 +59,8 @@ public ValueTask AppendBatchAsync(IReadOnlyList entries, Cancellat public ValueTask> ReadAllAsync(CancellationToken cancellationToken = default) => ValueTask.FromResult>([]); - public ValueTask ResetAsync(CancellationToken cancellationToken = default) => ValueTask.CompletedTask; + public ValueTask ResetAsync(CancellationToken cancellationToken = default) + => ValueTask.CompletedTask; public ValueTask TrimThroughSequenceAsync(long inclusiveSequenceId, CancellationToken cancellationToken = default) => ValueTask.CompletedTask; @@ -85,7 +86,8 @@ public ValueTask AppendBatchAsync(IReadOnlyList entries, Cancellat public ValueTask> ReadAllAsync(CancellationToken cancellationToken = default) => ValueTask.FromResult>([]); - public ValueTask ResetAsync(CancellationToken cancellationToken = default) => ValueTask.CompletedTask; + public ValueTask ResetAsync(CancellationToken cancellationToken = default) + => ValueTask.CompletedTask; public ValueTask TrimThroughSequenceAsync(long inclusiveSequenceId, CancellationToken cancellationToken = default) => ValueTask.CompletedTask; diff --git a/tests/SquidStd.Tests/Persistence/Integration/PersistenceEndToEndTests.cs b/tests/SquidStd.Tests/Persistence/Integration/PersistenceEndToEndTests.cs index 8f074528..b5fe218c 100644 --- a/tests/SquidStd.Tests/Persistence/Integration/PersistenceEndToEndTests.cs +++ b/tests/SquidStd.Tests/Persistence/Integration/PersistenceEndToEndTests.cs @@ -18,7 +18,7 @@ private PersistenceService Create() var journal = new BinaryJournalService(Path.Combine(_dir, config.JournalFileName)); var snapshot = new SnapshotService(_dir, config.SnapshotFileSuffix); - return new PersistenceService(registry, journal, snapshot, config, eventBus: null); + return new(registry, journal, snapshot, config); } [Fact] @@ -29,11 +29,11 @@ public async Task FullCycle_SnapshotRemoveTailCrashRestart_RestoresExactState() var service = Create(); await service.InitializeAsync(); var store = service.GetStore(); - await store.UpsertAsync(new Item { Id = 1, Label = "Sword", Quantity = 1 }); - await store.UpsertAsync(new Item { Id = 2, Label = "Potion", Quantity = 5 }); - await service.SaveSnapshotAsync(); // snapshot at seq 2 - await store.UpsertAsync(new Item { Id = 2, Label = "Potion", Quantity = 9 }); // tail update (seq 3) - await store.RemoveAsync(1); // tail remove (seq 4) + await store.UpsertAsync(new() { Id = 1, Label = "Sword", Quantity = 1 }); + await store.UpsertAsync(new() { Id = 2, Label = "Potion", Quantity = 5 }); + await service.SaveSnapshotAsync(); // snapshot at seq 2 + await store.UpsertAsync(new() { Id = 2, Label = "Potion", Quantity = 9 }); // tail update (seq 3) + await store.RemoveAsync(1); // tail remove (seq 4) var reloaded = Create(); await reloaded.InitializeAsync(); diff --git a/tests/SquidStd.Tests/Persistence/Internal/SnapshotEnvelopeCodecTests.cs b/tests/SquidStd.Tests/Persistence/Internal/SnapshotEnvelopeCodecTests.cs index 0b31d104..85ef2721 100644 --- a/tests/SquidStd.Tests/Persistence/Internal/SnapshotEnvelopeCodecTests.cs +++ b/tests/SquidStd.Tests/Persistence/Internal/SnapshotEnvelopeCodecTests.cs @@ -13,7 +13,7 @@ public void EncodeDecode_RoundTrips() Version = 1, LastSequenceId = 99, Checksum = 123456u, - Bucket = new EntitySnapshotBucket + Bucket = new() { TypeId = 3, TypeName = "PlayerData", diff --git a/tests/SquidStd.Tests/Persistence/PersistenceConfigTests.cs b/tests/SquidStd.Tests/Persistence/PersistenceConfigTests.cs index eef85fa2..e80df2f6 100644 --- a/tests/SquidStd.Tests/Persistence/PersistenceConfigTests.cs +++ b/tests/SquidStd.Tests/Persistence/PersistenceConfigTests.cs @@ -7,9 +7,7 @@ public class PersistenceConfigTests { [Fact] public void DurabilityMode_DefaultsToBuffered() - { - Assert.Equal(DurabilityMode.Buffered, new PersistenceConfig().DurabilityMode); - } + => Assert.Equal(DurabilityMode.Buffered, new PersistenceConfig().DurabilityMode); [Fact] public void DurabilityMode_CanBeSetToDurable() diff --git a/tests/SquidStd.Tests/Persistence/PersistenceEntityDescriptorTests.cs b/tests/SquidStd.Tests/Persistence/PersistenceEntityDescriptorTests.cs index 3fd58a16..cc16a102 100644 --- a/tests/SquidStd.Tests/Persistence/PersistenceEntityDescriptorTests.cs +++ b/tests/SquidStd.Tests/Persistence/PersistenceEntityDescriptorTests.cs @@ -9,12 +9,12 @@ private static PersistenceEntityDescriptor CreateDescriptor() { var serializer = new JsonDataSerializer(); - return new PersistenceEntityDescriptor(serializer, serializer, 1, "Player", 1, p => p.Id); + return new(serializer, serializer, 1, "Player", 1, p => p.Id); } [Fact] public void GetKey_UsesSelector() - => Assert.Equal(5, CreateDescriptor().GetKey(new Player { Id = 5 })); + => Assert.Equal(5, CreateDescriptor().GetKey(new() { Id = 5 })); [Fact] public void SerializeDeserializeEntity_RoundTrips() diff --git a/tests/SquidStd.Tests/Persistence/PersistenceEntityRegistryTests.cs b/tests/SquidStd.Tests/Persistence/PersistenceEntityRegistryTests.cs index 548011c7..84921539 100644 --- a/tests/SquidStd.Tests/Persistence/PersistenceEntityRegistryTests.cs +++ b/tests/SquidStd.Tests/Persistence/PersistenceEntityRegistryTests.cs @@ -10,7 +10,7 @@ private static PersistenceEntityDescriptor Descriptor(ushort typeId { var serializer = new JsonDataSerializer(); - return new PersistenceEntityDescriptor(serializer, serializer, typeId, "Player", 1, p => p.Id); + return new(serializer, serializer, typeId, "Player", 1, p => p.Id); } [Fact] diff --git a/tests/SquidStd.Tests/Persistence/PersistenceServiceTests.cs b/tests/SquidStd.Tests/Persistence/PersistenceServiceTests.cs index 63843288..39fce6fa 100644 --- a/tests/SquidStd.Tests/Persistence/PersistenceServiceTests.cs +++ b/tests/SquidStd.Tests/Persistence/PersistenceServiceTests.cs @@ -18,7 +18,7 @@ public sealed class PersistenceServiceTests : IDisposable var config = new PersistenceConfig { SaveDirectory = _dir, AutosaveInterval = TimeSpan.FromHours(1) }; var journal = new BinaryJournalService(Path.Combine(_dir, config.JournalFileName)); var snapshot = new SnapshotService(_dir, config.SnapshotFileSuffix); - var service = new PersistenceService(registry, journal, snapshot, config, eventBus: null); + var service = new PersistenceService(registry, journal, snapshot, config, null); return (service, registry); } @@ -29,7 +29,7 @@ public async Task SnapshotThenReload_RestoresState() var (service, _) = Create(); await service.InitializeAsync(); var store = service.GetStore(); - await store.UpsertAsync(new Player { Id = 1, Name = "Bob" }); + await store.UpsertAsync(new() { Id = 1, Name = "Bob" }); await service.SaveSnapshotAsync(); var (reloaded, _) = Create(); @@ -45,7 +45,7 @@ public async Task NoSnapshot_ReplaysJournal() { var (service, _) = Create(); await service.InitializeAsync(); - await service.GetStore().UpsertAsync(new Player { Id = 7, Name = "Eve" }); + await service.GetStore().UpsertAsync(new() { Id = 7, Name = "Eve" }); var (reloaded, _) = Create(); await reloaded.InitializeAsync(); // only journal exists, no snapshot @@ -60,9 +60,9 @@ public async Task SnapshotPlusJournalTail_ReplaysTail() var (service, _) = Create(); await service.InitializeAsync(); var store = service.GetStore(); - await store.UpsertAsync(new Player { Id = 1, Name = "First" }); + await store.UpsertAsync(new() { Id = 1, Name = "First" }); await service.SaveSnapshotAsync(); - await store.UpsertAsync(new Player { Id = 2, Name = "Second" }); + await store.UpsertAsync(new() { Id = 2, Name = "Second" }); var (reloaded, _) = Create(); await reloaded.InitializeAsync(); @@ -76,7 +76,7 @@ public async Task SaveSnapshot_TrimsJournal() { var (service, _) = Create(); await service.InitializeAsync(); - await service.GetStore().UpsertAsync(new Player { Id = 1 }); + await service.GetStore().UpsertAsync(new() { Id = 1 }); await service.SaveSnapshotAsync(); var journal = new BinaryJournalService(Path.Combine(_dir, "world.journal.bin")); @@ -95,11 +95,11 @@ public async Task PartialSnapshotSave_ReplaysLaggingTypeFromJournal() // (untrimmed) journal — the exact state a partial snapshot save leaves behind. var journal = new BinaryJournalService(Path.Combine(_dir, config.JournalFileName)); var faulty = new FailOnSecondSaveSnapshotService(new SnapshotService(_dir, config.SnapshotFileSuffix)); - var service = new PersistenceService(BuildRegistry(serializer), journal, faulty, config, eventBus: null); + var service = new PersistenceService(BuildRegistry(serializer), journal, faulty, config); await service.InitializeAsync(); - await service.GetStore().UpsertAsync(new Player { Id = 1, Name = "First" }); - await service.GetStore().UpsertAsync(new Item { Id = 1, Name = "Sword" }); + await service.GetStore().UpsertAsync(new() { Id = 1, Name = "First" }); + await service.GetStore().UpsertAsync(new() { Id = 1, Name = "Sword" }); await Assert.ThrowsAnyAsync(async () => await service.SaveSnapshotAsync()); await journal.DisposeAsync(); @@ -108,7 +108,10 @@ public async Task PartialSnapshotSave_ReplaysLaggingTypeFromJournal() // watermark would skip the journal entry for whichever type's snapshot did persist, losing it. var reloadJournal = new BinaryJournalService(Path.Combine(_dir, config.JournalFileName)); var reloaded = new PersistenceService( - BuildRegistry(serializer), reloadJournal, new SnapshotService(_dir, config.SnapshotFileSuffix), config, eventBus: null + BuildRegistry(serializer), + reloadJournal, + new SnapshotService(_dir, config.SnapshotFileSuffix), + config ); await reloaded.InitializeAsync(); @@ -150,8 +153,10 @@ private sealed class Item public string Name { get; set; } = string.Empty; } - /// Delegates to a real snapshot service but throws on the second bucket save, simulating a - /// snapshot run that persists one type's bucket and then fails before the next. + /// + /// Delegates to a real snapshot service but throws on the second bucket save, simulating a + /// snapshot run that persists one type's bucket and then fails before the next. + /// private sealed class FailOnSecondSaveSnapshotService : ISnapshotService { private readonly ISnapshotService _inner; @@ -163,7 +168,9 @@ public FailOnSecondSaveSnapshotService(ISnapshotService inner) } public ValueTask SaveBucketAsync( - EntitySnapshotBucket bucket, long lastSequenceId, CancellationToken cancellationToken = default + EntitySnapshotBucket bucket, + long lastSequenceId, + CancellationToken cancellationToken = default ) { if (++_saveCount >= 2) @@ -175,15 +182,13 @@ public ValueTask SaveBucketAsync( } public ValueTask LoadBucketAsync( - string typeName, ushort typeId, CancellationToken cancellationToken = default + string typeName, + ushort typeId, + CancellationToken cancellationToken = default ) - { - return _inner.LoadBucketAsync(typeName, typeId, cancellationToken); - } + => _inner.LoadBucketAsync(typeName, typeId, cancellationToken); public ValueTask DeleteBucketAsync(string typeName, ushort typeId, CancellationToken cancellationToken = default) - { - return _inner.DeleteBucketAsync(typeName, typeId, cancellationToken); - } + => _inner.DeleteBucketAsync(typeName, typeId, cancellationToken); } } diff --git a/tests/SquidStd.Tests/Persistence/PersistenceSnapshotConcurrencyTests.cs b/tests/SquidStd.Tests/Persistence/PersistenceSnapshotConcurrencyTests.cs index aba0e03b..b9b0734d 100644 --- a/tests/SquidStd.Tests/Persistence/PersistenceSnapshotConcurrencyTests.cs +++ b/tests/SquidStd.Tests/Persistence/PersistenceSnapshotConcurrencyTests.cs @@ -8,7 +8,8 @@ namespace SquidStd.Tests.Persistence; public sealed class PersistenceSnapshotConcurrencyTests : IDisposable { - private readonly string _dir = Path.Combine(Path.GetTempPath(), "squidstd-snapshot-conc-" + Guid.NewGuid().ToString("N")); + private readonly string _dir = + Path.Combine(Path.GetTempPath(), "squidstd-snapshot-conc-" + Guid.NewGuid().ToString("N")); [Fact] public async Task SaveSnapshotAsync_ConcurrentCalls_DoNotInterleave() @@ -19,14 +20,12 @@ public async Task SaveSnapshotAsync_ConcurrentCalls_DoNotInterleave() var config = new PersistenceConfig { SaveDirectory = _dir, AutosaveInterval = TimeSpan.FromHours(1) }; var journal = new BinaryJournalService(Path.Combine(_dir, config.JournalFileName)); var snapshot = new ConcurrencyProbeSnapshotService(); - var service = new PersistenceService(registry, journal, snapshot, config, eventBus: null); + var service = new PersistenceService(registry, journal, snapshot, config, null); await service.InitializeAsync(); - await service.GetStore().UpsertAsync(new Player { Id = 1, Name = "Bob" }); + await service.GetStore().UpsertAsync(new() { Id = 1, Name = "Bob" }); - await Task.WhenAll( - Enumerable.Range(0, 8).Select(async _ => await service.SaveSnapshotAsync()) - ); + await Task.WhenAll(Enumerable.Range(0, 8).Select(async _ => await service.SaveSnapshotAsync())); await journal.DisposeAsync(); Assert.Equal(1, snapshot.MaxObservedConcurrency); // never two snapshot operations at once @@ -53,7 +52,9 @@ private sealed class ConcurrencyProbeSnapshotService : ISnapshotService public int MaxObservedConcurrency { get; private set; } public async ValueTask SaveBucketAsync( - EntitySnapshotBucket bucket, long lastSequenceId, CancellationToken cancellationToken = default + EntitySnapshotBucket bucket, + long lastSequenceId, + CancellationToken cancellationToken = default ) { var now = Interlocked.Increment(ref _active); @@ -62,7 +63,11 @@ public async ValueTask SaveBucketAsync( Interlocked.Decrement(ref _active); } - public ValueTask LoadBucketAsync(string typeName, ushort typeId, CancellationToken cancellationToken = default) + public ValueTask LoadBucketAsync( + string typeName, + ushort typeId, + CancellationToken cancellationToken = default + ) => ValueTask.FromResult(null); public ValueTask DeleteBucketAsync(string typeName, ushort typeId, CancellationToken cancellationToken = default) diff --git a/tests/SquidStd.Tests/Persistence/SnapshotChecksumScopeTests.cs b/tests/SquidStd.Tests/Persistence/SnapshotChecksumScopeTests.cs index 6116259f..b996f958 100644 --- a/tests/SquidStd.Tests/Persistence/SnapshotChecksumScopeTests.cs +++ b/tests/SquidStd.Tests/Persistence/SnapshotChecksumScopeTests.cs @@ -16,7 +16,7 @@ private static EntitySnapshotBucket Bucket() public async Task LoadBucketAsync_WhenLastSequenceIdCorrupted_RejectsSnapshot() { var service = new SnapshotService(_dir, ".snapshot.bin"); - await service.SaveBucketAsync(Bucket(), lastSequenceId: 42); + await service.SaveBucketAsync(Bucket(), 42); var file = Directory.GetFiles(_dir, "*.snapshot.bin").Single(); var bytes = await File.ReadAllBytesAsync(file); @@ -30,17 +30,19 @@ public async Task LoadBucketAsync_WhenLastSequenceIdCorrupted_RejectsSnapshot() public async Task LoadBucketAsync_LegacyVersion1File_StillLoads() { var service = new SnapshotService(_dir, ".snapshot.bin"); - await service.SaveBucketAsync(Bucket(), lastSequenceId: 7); // creates the file at the correct path + await service.SaveBucketAsync(Bucket(), 7); // creates the file at the correct path // Overwrite it with a legacy Version-1 envelope (payload-only checksum), as written before this change. var file = Directory.GetFiles(_dir, "*.snapshot.bin").Single(); - var legacy = SnapshotEnvelopeCodec.Encode(new SnapshotFileEnvelope - { - Version = 1, - LastSequenceId = 7, - Checksum = ChecksumUtils.Compute(Bucket().Payload), - Bucket = Bucket() - }); + var legacy = SnapshotEnvelopeCodec.Encode( + new() + { + Version = 1, + LastSequenceId = 7, + Checksum = ChecksumUtils.Compute(Bucket().Payload), + Bucket = Bucket() + } + ); await File.WriteAllBytesAsync(file, legacy); var loaded = await service.LoadBucketAsync("Player", 1); diff --git a/tests/SquidStd.Tests/Persistence/SnapshotFilenameTests.cs b/tests/SquidStd.Tests/Persistence/SnapshotFilenameTests.cs index 065db64e..95dfaa39 100644 --- a/tests/SquidStd.Tests/Persistence/SnapshotFilenameTests.cs +++ b/tests/SquidStd.Tests/Persistence/SnapshotFilenameTests.cs @@ -16,8 +16,8 @@ public async Task SameTypeName_DifferentTypeId_ProduceDistinctFiles() { var service = new SnapshotService(_dir, ".snapshot.bin"); - await service.SaveBucketAsync(Bucket(1, 0xAA), lastSequenceId: 1); - await service.SaveBucketAsync(Bucket(2, 0xBB), lastSequenceId: 2); + await service.SaveBucketAsync(Bucket(1, 0xAA), 1); + await service.SaveBucketAsync(Bucket(2, 0xBB), 2); Assert.Equal(2, Directory.GetFiles(_dir, "*.snapshot.bin").Length); @@ -34,7 +34,7 @@ public async Task LoadBucketAsync_MigratesLegacyNamedFile() var service = new SnapshotService(_dir, ".snapshot.bin"); // Write a file at the OLD path (no TypeId) by saving then renaming to the legacy name. - await service.SaveBucketAsync(Bucket(1, 0x7), lastSequenceId: 9); + await service.SaveBucketAsync(Bucket(1, 0x7), 9); var newPath = Directory.GetFiles(_dir, "*.snapshot.bin").Single(); var legacyPath = Path.Combine(_dir, StringUtils.ToSnakeCase("Player") + ".snapshot.bin"); File.Move(newPath, legacyPath); @@ -43,7 +43,7 @@ public async Task LoadBucketAsync_MigratesLegacyNamedFile() Assert.NotNull(loaded); Assert.Equal(9, loaded.LastSequenceId); - Assert.False(File.Exists(legacyPath)); // legacy file was migrated away + Assert.False(File.Exists(legacyPath)); // legacy file was migrated away Assert.True(File.Exists(Path.Combine(_dir, "player_1.snapshot.bin"))); // to the new TypeId path } diff --git a/tests/SquidStd.Tests/PluginAbstractions/PluginContextTests.cs b/tests/SquidStd.Tests/PluginAbstractions/PluginContextTests.cs index c44c0461..6b49f609 100644 --- a/tests/SquidStd.Tests/PluginAbstractions/PluginContextTests.cs +++ b/tests/SquidStd.Tests/PluginAbstractions/PluginContextTests.cs @@ -6,15 +6,11 @@ public class PluginContextTests { [Fact] public void Data_IsEmptyByDefault() - { - Assert.Empty(new PluginContext().Data); - } + => Assert.Empty(new PluginContext().Data); [Fact] public void GetData_MissingKey_Throws() - { - Assert.Throws(() => { _ = new PluginContext().GetData("missing"); }); - } + => Assert.Throws(() => { _ = new PluginContext().GetData("missing"); }); [Fact] public void GetData_ReferenceType_ReturnsStoredValue() diff --git a/tests/SquidStd.Tests/PluginAbstractions/PluginMetadataTests.cs b/tests/SquidStd.Tests/PluginAbstractions/PluginMetadataTests.cs index 5d27d2af..bbaa345e 100644 --- a/tests/SquidStd.Tests/PluginAbstractions/PluginMetadataTests.cs +++ b/tests/SquidStd.Tests/PluginAbstractions/PluginMetadataTests.cs @@ -11,13 +11,13 @@ public void Constructor_SetsRequiredProperties() { Id = "squidstd.weather", Name = "Weather", - Version = new Version(2, 1, 0), + Version = new(2, 1, 0), Author = "squid" }; Assert.Equal("squidstd.weather", metadata.Id); Assert.Equal("Weather", metadata.Name); - Assert.Equal(new Version(2, 1, 0), metadata.Version); + Assert.Equal(new(2, 1, 0), metadata.Version); Assert.Equal("squid", metadata.Author); } @@ -28,7 +28,7 @@ public void Dependencies_CanBeProvided() { Id = "id", Name = "name", - Version = new Version(1, 0), + Version = new(1, 0), Author = "author", Dependencies = ["squidstd.core", "squidstd.net"] }; @@ -43,7 +43,7 @@ public void Dependencies_DefaultsToEmpty() { Id = "id", Name = "name", - Version = new Version(1, 0), + Version = new(1, 0), Author = "author" }; @@ -57,7 +57,7 @@ public void Description_DefaultsToNull() { Id = "id", Name = "name", - Version = new Version(1, 0), + Version = new(1, 0), Author = "author" }; diff --git a/tests/SquidStd.Tests/PluginAbstractions/SquidStdPluginTests.cs b/tests/SquidStd.Tests/PluginAbstractions/SquidStdPluginTests.cs index ea081e1d..2fc16ed9 100644 --- a/tests/SquidStd.Tests/PluginAbstractions/SquidStdPluginTests.cs +++ b/tests/SquidStd.Tests/PluginAbstractions/SquidStdPluginTests.cs @@ -25,7 +25,7 @@ public void Configure_RegistersServicesIntoContainer() using var container = new Container(); var plugin = new FakePlugin(); - ((ISquidStdPlugin)plugin).Configure(container, new PluginContext()); + ((ISquidStdPlugin)plugin).Configure(container, new()); Assert.Same(plugin, container.Resolve()); } @@ -36,6 +36,6 @@ public void Metadata_ExposesPluginIdentity() ISquidStdPlugin plugin = new FakePlugin(); Assert.Equal("squidstd.fake", plugin.Metadata.Id); - Assert.Equal(new Version(1, 2, 3), plugin.Metadata.Version); + Assert.Equal(new(1, 2, 3), plugin.Metadata.Version); } } diff --git a/tests/SquidStd.Tests/Scripting/Lua/LuaEventBridgeTests.cs b/tests/SquidStd.Tests/Scripting/Lua/LuaEventBridgeTests.cs index 212b0e28..000afc41 100644 --- a/tests/SquidStd.Tests/Scripting/Lua/LuaEventBridgeTests.cs +++ b/tests/SquidStd.Tests/Scripting/Lua/LuaEventBridgeTests.cs @@ -12,13 +12,13 @@ public void Invoke_ConvertsNestedPayloadToLuaTable() var bridge = new LuaEventBridge(); bridge.Attach(script); var callback = script.DoString( - """ - return function(payload) - return payload.actor.name .. ':' .. payload.values[2] - end - """ - ) - .Function; + """ + return function(payload) + return payload.actor.name .. ':' .. payload.values[2] + end + """ + ) + .Function; var result = bridge.Invoke( callback, @@ -49,16 +49,16 @@ public void Publish_InvokesRegisteredCallbacksCaseInsensitively() var bridge = new LuaEventBridge(); bridge.Attach(script); var callback = script.DoString( - """ - calls = 0 - captured = nil - return function(payload) - calls = calls + 1 - captured = payload.name - end - """ - ) - .Function; + """ + calls = 0 + captured = nil + return function(payload) + calls = calls + 1 + captured = payload.name + end + """ + ) + .Function; bridge.Register("Spawned", callback); bridge.Publish("spawned", new Dictionary { ["name"] = "slime" }); diff --git a/tests/SquidStd.Tests/Scripting/Lua/LuaModuleTests.cs b/tests/SquidStd.Tests/Scripting/Lua/LuaModuleTests.cs index 450ea071..f22dfd03 100644 --- a/tests/SquidStd.Tests/Scripting/Lua/LuaModuleTests.cs +++ b/tests/SquidStd.Tests/Scripting/Lua/LuaModuleTests.cs @@ -44,7 +44,7 @@ public void RandomModule_PickRejectsEmptyTable() { var module = new RandomModule(); - Assert.Throws(() => module.Pick(new Table(new Script()))); + Assert.Throws(() => module.Pick(new(new()))); } [Fact] @@ -52,14 +52,14 @@ public void RandomModule_WeightedRejectsEntriesWithoutPositiveWeight() { var script = new Script(); var entries = script.DoString( - """ - return { - { value = 'a', weight = 0 }, - { value = 'b', weight = -3 } - } - """ - ) - .Table; + """ + return { + { value = 'a', weight = 0 }, + { value = 'b', weight = -3 } + } + """ + ) + .Table; var module = new RandomModule(); Assert.Throws(() => module.Weighted(entries)); @@ -71,18 +71,12 @@ private sealed class CapturingLuaEventBridge : ILuaEventBridge public string? EventName { get; private set; } - public void Attach(Script script) - { - } + public void Attach(Script script) { } public DynValue Invoke(Closure callback, IReadOnlyDictionary payload) - { - return DynValue.Nil; - } + => DynValue.Nil; - public void Publish(string eventName, IReadOnlyDictionary payload) - { - } + public void Publish(string eventName, IReadOnlyDictionary payload) { } public void Register(string eventName, Closure callback) { diff --git a/tests/SquidStd.Tests/Scripting/Lua/LuaScriptEngineServiceTests.cs b/tests/SquidStd.Tests/Scripting/Lua/LuaScriptEngineServiceTests.cs index 057b592c..3cb6f157 100644 --- a/tests/SquidStd.Tests/Scripting/Lua/LuaScriptEngineServiceTests.cs +++ b/tests/SquidStd.Tests/Scripting/Lua/LuaScriptEngineServiceTests.cs @@ -1,7 +1,5 @@ using DryIoc; using MoonSharp.Interpreter; -using SquidStd.Core.Directories; -using SquidStd.Scripting.Lua.Data.Config; using SquidStd.Scripting.Lua.Data.Internal; using SquidStd.Scripting.Lua.Data.Scripts; using SquidStd.Scripting.Lua.Interfaces.Events; @@ -130,7 +128,7 @@ public void RegisteredUserData_CanBeConstructedFromLuaWithMoreThanFourArguments( container, loadedUserData: [ - new ScriptUserData { UserType = typeof(FiveArgumentUserData) } + new() { UserType = typeof(FiveArgumentUserData) } ] ); @@ -191,10 +189,10 @@ private static LuaScriptEngineService CreateEngine( var luarcDirectory = temp.Combine("luarc"); Directory.CreateDirectory(scriptsDirectory); - return new LuaScriptEngineService( - new DirectoriesConfig(temp.Path, []), + return new( + new(temp.Path, []), container, - new LuaEngineConfig(luarcDirectory, scriptsDirectory, "SquidStd", "1.0.0"), + new(luarcDirectory, scriptsDirectory, "SquidStd", "1.0.0"), scriptModules, loadedUserData ); @@ -210,25 +208,17 @@ private sealed class CapturingLuaEventBridge : ILuaEventBridge public Script? AttachedScript { get; private set; } public void Attach(Script script) - { - AttachedScript = script; - } + => AttachedScript = script; public DynValue Invoke( Closure callback, IReadOnlyDictionary payload ) - { - return DynValue.Nil; - } + => DynValue.Nil; - public void Publish(string eventName, IReadOnlyDictionary payload) - { - } + public void Publish(string eventName, IReadOnlyDictionary payload) { } - public void Register(string eventName, Closure callback) - { - } + public void Register(string eventName, Closure callback) { } } private sealed record LimitConfig(string Name, int Count); diff --git a/tests/SquidStd.Tests/Scripting/Lua/LuaScriptLoaderTests.cs b/tests/SquidStd.Tests/Scripting/Lua/LuaScriptLoaderTests.cs index 4ed4ae4f..df24478d 100644 --- a/tests/SquidStd.Tests/Scripting/Lua/LuaScriptLoaderTests.cs +++ b/tests/SquidStd.Tests/Scripting/Lua/LuaScriptLoaderTests.cs @@ -1,4 +1,3 @@ -using MoonSharp.Interpreter; using SquidStd.Scripting.Lua.Loaders; using SquidStd.Tests.Support; @@ -21,9 +20,7 @@ public void AddSearchDirectory_AddsAdditionalLookupRoot() [Fact] public void Constructor_EmptySearchDirectoriesThrows() - { - Assert.Throws(() => new LuaScriptLoader(Array.Empty())); - } + => Assert.Throws(() => new LuaScriptLoader(Array.Empty())); [Fact] public void LoadFile_LoadsContentFromFirstMatchingSearchDirectory() @@ -33,7 +30,7 @@ public void LoadFile_LoadsContentFromFirstMatchingSearchDirectory() File.WriteAllText(second.Combine("feature.lua"), "return 'loaded'"); var loader = new LuaScriptLoader([first.Path, second.Path]); - var content = loader.LoadFile("feature.lua", new Table(new Script())); + var content = loader.LoadFile("feature.lua", new(new())); Assert.Equal("return 'loaded'", content); } diff --git a/tests/SquidStd.Tests/Scripting/Lua/ScriptResultBuilderTests.cs b/tests/SquidStd.Tests/Scripting/Lua/ScriptResultBuilderTests.cs index be23b5ba..2aeb3623 100644 --- a/tests/SquidStd.Tests/Scripting/Lua/ScriptResultBuilderTests.cs +++ b/tests/SquidStd.Tests/Scripting/Lua/ScriptResultBuilderTests.cs @@ -8,8 +8,8 @@ public class ScriptResultBuilderTests public void CreateError_BuildsFailedResult() { var result = ScriptResultBuilder.CreateError() - .WithMessage("failed") - .Build(); + .WithMessage("failed") + .Build(); Assert.False(result.Success); Assert.Equal("failed", result.Message); @@ -20,9 +20,9 @@ public void CreateError_BuildsFailedResult() public void CreateSuccess_BuildsSuccessfulResult() { var result = ScriptResultBuilder.CreateSuccess() - .WithMessage("ok") - .WithData(42) - .Build(); + .WithMessage("ok") + .WithData(42) + .Build(); Assert.True(result.Success); Assert.Equal("ok", result.Message); diff --git a/tests/SquidStd.Tests/Scripting/Lua/TableExtensionsTests.cs b/tests/SquidStd.Tests/Scripting/Lua/TableExtensionsTests.cs index 0ffdd12b..f0516e64 100644 --- a/tests/SquidStd.Tests/Scripting/Lua/TableExtensionsTests.cs +++ b/tests/SquidStd.Tests/Scripting/Lua/TableExtensionsTests.cs @@ -10,15 +10,15 @@ public void ToProxy_DelegatesInterfaceCallsToLuaFunctions() { var script = new Script(); var table = script.DoString( - """ - return { - Sum = function(left, right) - return left + right - end - } - """ - ) - .Table; + """ + return { + Sum = function(left, right) + return left + right + end + } + """ + ) + .Table; var proxy = table.ToProxy(); @@ -28,7 +28,7 @@ public void ToProxy_DelegatesInterfaceCallsToLuaFunctions() [Fact] public void ToProxy_MissingFunctionThrowsMissingMethodException() { - var proxy = new Table(new Script()).ToProxy(); + var proxy = new Table(new()).ToProxy(); Assert.Throws(() => proxy.Sum(1, 2)); } diff --git a/tests/SquidStd.Tests/Search/ElasticExpressionTranslatorTests.cs b/tests/SquidStd.Tests/Search/ElasticExpressionTranslatorTests.cs index e77e8f41..848f3497 100644 --- a/tests/SquidStd.Tests/Search/ElasticExpressionTranslatorTests.cs +++ b/tests/SquidStd.Tests/Search/ElasticExpressionTranslatorTests.cs @@ -18,9 +18,7 @@ public void Match_ProducesMatchClause() [Fact] public void UnsupportedExpression_Throws() - { - Assert.Throws(() => Translate(s => s.Where(d => d.Name.ToUpperInvariant() == "X"))); - } + => Assert.Throws(() => Translate(s => s.Where(d => d.Name.ToUpperInvariant() == "X"))); [Fact] public void Where_Equality_ProducesTermOnKeyword() @@ -68,34 +66,22 @@ private TranslateOnlyQueryable(Expression expression) } public IEnumerator GetEnumerator() - { - throw new NotSupportedException(); - } + => throw new NotSupportedException(); IEnumerator IEnumerable.GetEnumerator() - { - throw new NotSupportedException(); - } + => throw new NotSupportedException(); public IQueryable CreateQuery(Expression expression) - { - return new TranslateOnlyQueryable(expression); - } + => new TranslateOnlyQueryable(expression); public IQueryable CreateQuery(Expression expression) - { - return new TranslateOnlyQueryable(expression); - } + => new TranslateOnlyQueryable(expression); public object? Execute(Expression expression) - { - throw new NotSupportedException(); - } + => throw new NotSupportedException(); public TResult Execute(Expression expression) - { - throw new NotSupportedException(); - } + => throw new NotSupportedException(); } private sealed record Doc(string Status, int Total, string Name) : IIndexableEntity diff --git a/tests/SquidStd.Tests/Search/SearchIndexNameResolverTests.cs b/tests/SquidStd.Tests/Search/SearchIndexNameResolverTests.cs index 26072076..c265afea 100644 --- a/tests/SquidStd.Tests/Search/SearchIndexNameResolverTests.cs +++ b/tests/SquidStd.Tests/Search/SearchIndexNameResolverTests.cs @@ -23,9 +23,7 @@ public void Resolve_ExpandsEnvVariable() [Fact] public void Resolve_FallsBackToLowercasedTypeName() - { - Assert.Equal("plaindoc", SearchIndexNameResolver.Resolve(typeof(PlainDoc))); - } + => Assert.Equal("plaindoc", SearchIndexNameResolver.Resolve(typeof(PlainDoc))); [Fact] public void Resolve_Throws_WhenRequiredVariableMissing() @@ -36,9 +34,7 @@ public void Resolve_Throws_WhenRequiredVariableMissing() [Fact] public void Resolve_UsesAttribute_Lowercased() - { - Assert.Equal("orders", SearchIndexNameResolver.Resolve(typeof(AttributedDoc))); - } + => Assert.Equal("orders", SearchIndexNameResolver.Resolve(typeof(AttributedDoc))); [Fact] public void Resolve_UsesDefault_WhenVariableMissing() diff --git a/tests/SquidStd.Tests/Secrets/Aws/AwsSecretsManagerStoreTests.cs b/tests/SquidStd.Tests/Secrets/Aws/AwsSecretsManagerStoreTests.cs index e3a148cd..b42a6b02 100644 --- a/tests/SquidStd.Tests/Secrets/Aws/AwsSecretsManagerStoreTests.cs +++ b/tests/SquidStd.Tests/Secrets/Aws/AwsSecretsManagerStoreTests.cs @@ -1,4 +1,3 @@ -using SquidStd.Secrets.Aws.Data; using SquidStd.Secrets.Aws.Services; using SquidStd.Tests.Secrets.Aws.Support; @@ -18,7 +17,7 @@ public AwsSecretsManagerStoreTests(LocalStackSecretsFixture localStack) public async Task Set_Get_Exists_List_Delete_RoundTrips() { var prefix = "test-" + Guid.NewGuid().ToString("N") + "/"; - var store = new AwsSecretsManagerStore(new AwsSecretsManagerOptions { Aws = _localStack.Aws, NamePrefix = prefix }); + var store = new AwsSecretsManagerStore(new() { Aws = _localStack.Aws, NamePrefix = prefix }); Assert.Null(await store.GetAsync("db/main")); Assert.False(await store.ExistsAsync("db/main")); @@ -30,6 +29,7 @@ public async Task Set_Get_Exists_List_Delete_RoundTrips() Assert.True(await store.ExistsAsync("db/main")); var names = new List(); + await foreach (var name in store.ListNamesAsync()) { names.Add(name); diff --git a/tests/SquidStd.Tests/Secrets/Aws/KmsSecretProtectorTests.cs b/tests/SquidStd.Tests/Secrets/Aws/KmsSecretProtectorTests.cs index 86319911..f0ac1ab1 100644 --- a/tests/SquidStd.Tests/Secrets/Aws/KmsSecretProtectorTests.cs +++ b/tests/SquidStd.Tests/Secrets/Aws/KmsSecretProtectorTests.cs @@ -1,7 +1,6 @@ using System.Text; using Amazon.KeyManagementService; -using Amazon.KeyManagementService.Model; -using SquidStd.Secrets.Aws.Data; +using Amazon.Runtime; using SquidStd.Secrets.Aws.Services; using SquidStd.Tests.Secrets.Aws.Support; @@ -21,7 +20,7 @@ public KmsSecretProtectorTests(LocalStackSecretsFixture localStack) public async Task Protect_Unprotect_RoundTripsLargePayload_WithoutPlaintext() { var keyId = await CreateKeyAsync(); - var protector = new KmsSecretProtector(new KmsSecretProtectorOptions { Aws = _localStack.Aws, KeyId = keyId }); + var protector = new KmsSecretProtector(new() { Aws = _localStack.Aws, KeyId = keyId }); var plaintext = Encoding.UTF8.GetBytes(new string('s', 10_000)); // > 4 KB → exercises envelope var blob = protector.Protect(plaintext); @@ -34,11 +33,11 @@ public async Task Protect_Unprotect_RoundTripsLargePayload_WithoutPlaintext() private async Task CreateKeyAsync() { using var kms = new AmazonKeyManagementServiceClient( - new Amazon.Runtime.BasicAWSCredentials("test", "test"), + new BasicAWSCredentials("test", "test"), new AmazonKeyManagementServiceConfig { ServiceURL = _localStack.Aws.ServiceUrl, AuthenticationRegion = "us-east-1" } ); - var created = await kms.CreateKeyAsync(new CreateKeyRequest()); + var created = await kms.CreateKeyAsync(new()); return created.KeyMetadata.KeyId; } diff --git a/tests/SquidStd.Tests/Secrets/Aws/Support/LocalStackSecretsFixture.cs b/tests/SquidStd.Tests/Secrets/Aws/Support/LocalStackSecretsFixture.cs index ed07dbe2..6720d79f 100644 --- a/tests/SquidStd.Tests/Secrets/Aws/Support/LocalStackSecretsFixture.cs +++ b/tests/SquidStd.Tests/Secrets/Aws/Support/LocalStackSecretsFixture.cs @@ -9,23 +9,20 @@ public sealed class LocalStackSecretsFixture : IAsyncLifetime private readonly LocalStackContainer _container = new LocalStackBuilder().WithImage("localstack/localstack:3").Build(); - public AwsConfigEntry Aws => new() - { - Region = "us-east-1", - AccessKey = "test", - SecretKey = "test", - ServiceUrl = _container.GetConnectionString() - }; + public AwsConfigEntry Aws + => new() + { + Region = "us-east-1", + AccessKey = "test", + SecretKey = "test", + ServiceUrl = _container.GetConnectionString() + }; public Task DisposeAsync() - { - return _container.DisposeAsync().AsTask(); - } + => _container.DisposeAsync().AsTask(); public Task InitializeAsync() - { - return _container.StartAsync(); - } + => _container.StartAsync(); } [CollectionDefinition(Name)] diff --git a/tests/SquidStd.Tests/Security/FileSecretStoreEnumerationTests.cs b/tests/SquidStd.Tests/Security/FileSecretStoreEnumerationTests.cs index d4887644..04d5fbeb 100644 --- a/tests/SquidStd.Tests/Security/FileSecretStoreEnumerationTests.cs +++ b/tests/SquidStd.Tests/Security/FileSecretStoreEnumerationTests.cs @@ -25,12 +25,14 @@ public async Task ListNamesAsync_ReturnsSetNames_AndHonoursPrefix() await store.SetAsync("api/key", "c"); var all = new List(); + await foreach (var name in store.ListNamesAsync()) { all.Add(name); } var db = new List(); + await foreach (var name in store.ListNamesAsync("db/")) { db.Add(name); diff --git a/tests/SquidStd.Tests/Security/SecretsTests.cs b/tests/SquidStd.Tests/Security/SecretsTests.cs index ba6ed233..1c62ecda 100644 --- a/tests/SquidStd.Tests/Security/SecretsTests.cs +++ b/tests/SquidStd.Tests/Security/SecretsTests.cs @@ -22,7 +22,7 @@ public void AesGcmSecretProtector_Protect_Unprotect_RoundTripsWithoutPlaintext() try { Environment.SetEnvironmentVariable(variableName, Convert.ToBase64String(key)); - var protector = new AesGcmSecretProtector(new SecretsConfig { KeyEnvironmentVariable = variableName }); + var protector = new AesGcmSecretProtector(new() { KeyEnvironmentVariable = variableName }); var plaintext = Encoding.UTF8.GetBytes("super-secret-value"); var protectedData = protector.Protect(plaintext); @@ -49,7 +49,7 @@ public void AesGcmSecretProtector_WhenKeyEnvironmentVariableIsMissing_UsesDefaul { Environment.SetEnvironmentVariable(variableName, null); Log.Logger = new LoggerConfiguration().MinimumLevel.Verbose().WriteTo.Sink(sink).CreateLogger(); - var protector = new AesGcmSecretProtector(new SecretsConfig { KeyEnvironmentVariable = variableName }); + var protector = new AesGcmSecretProtector(new() { KeyEnvironmentVariable = variableName }); var plaintext = Encoding.UTF8.GetBytes("default-key-secret"); var protectedData = protector.Protect(plaintext); @@ -110,8 +110,6 @@ private sealed class CapturingSink : ILogEventSink public IReadOnlyList Events => _events; public void Emit(LogEvent logEvent) - { - _events.Add(logEvent); - } + => _events.Add(logEvent); } } diff --git a/tests/SquidStd.Tests/Services/Core/CommandDispatcherTests.cs b/tests/SquidStd.Tests/Services/Core/CommandDispatcherTests.cs index f1d02ec7..9208cba0 100644 --- a/tests/SquidStd.Tests/Services/Core/CommandDispatcherTests.cs +++ b/tests/SquidStd.Tests/Services/Core/CommandDispatcherTests.cs @@ -30,7 +30,7 @@ public async Task DispatchAsync_WhenNoHandler_ReturnsUnmatched() { using var dispatcher = new CommandDispatcher(); - var result = await dispatcher.DispatchAsync(new PingCommand("x"), new Session()); + var result = await dispatcher.DispatchAsync(new PingCommand("x"), new()); Assert.False(result.Matched); Assert.Equal(0, result.HandlerCount); @@ -45,7 +45,7 @@ public async Task DispatchAsync_IsolatesFaults() dispatcher.RegisterHandler(new ThrowingHandler()); dispatcher.RegisterHandler(healthy); - var result = await dispatcher.DispatchAsync(new PingCommand("go"), new Session()); + var result = await dispatcher.DispatchAsync(new PingCommand("go"), new()); Assert.True(result.Matched); Assert.Equal(2, result.HandlerCount); @@ -61,7 +61,8 @@ public async Task DispatchAsync_WhenCancelled_Propagates() using var dispatcher = new CommandDispatcher(); using var cts = new CancellationTokenSource(); await cts.CancelAsync(); - dispatcher.Subscribe((_, _, token) => + dispatcher.Subscribe( + (_, _, token) => { token.ThrowIfCancellationRequested(); @@ -69,9 +70,10 @@ public async Task DispatchAsync_WhenCancelled_Propagates() } ); - await Assert.ThrowsAsync(() => dispatcher.DispatchAsync( + await Assert.ThrowsAsync( + () => dispatcher.DispatchAsync( new PingCommand("x"), - new Session(), + new(), cts.Token ) ); @@ -85,7 +87,7 @@ public async Task RegisterHandler_DisposeToken_StopsDelivery() var token = dispatcher.RegisterHandler(handler); token.Dispose(); - var result = await dispatcher.DispatchAsync(new PingCommand("x"), new Session()); + var result = await dispatcher.DispatchAsync(new PingCommand("x"), new()); Assert.False(result.Matched); Assert.Null(handler.LastText); @@ -97,7 +99,8 @@ public async Task Subscribe_DeliversToDelegate() using var dispatcher = new CommandDispatcher(); string? seen = null; Session? seenContext = null; - dispatcher.Subscribe((command, context, _) => + dispatcher.Subscribe( + (command, context, _) => { seen = command.Text; seenContext = context; @@ -114,9 +117,7 @@ public async Task Subscribe_DeliversToDelegate() Assert.Same(session, seenContext); } - private sealed class Session - { - } + private sealed class Session { } private sealed class RecordingHandler : ICommandHandler { @@ -136,9 +137,7 @@ public Task HandleAsync(PingCommand command, Session context, CancellationToken private sealed class ThrowingHandler : ICommandHandler { public Task HandleAsync(PingCommand command, Session context, CancellationToken cancellationToken = default) - { - throw new InvalidOperationException("Synthetic failure."); - } + => throw new InvalidOperationException("Synthetic failure."); } private sealed record PingCommand(string Text) : ICommand; diff --git a/tests/SquidStd.Tests/Services/Core/EventBusServiceTests.cs b/tests/SquidStd.Tests/Services/Core/EventBusServiceTests.cs index 88ba7b0c..4d74712e 100644 --- a/tests/SquidStd.Tests/Services/Core/EventBusServiceTests.cs +++ b/tests/SquidStd.Tests/Services/Core/EventBusServiceTests.cs @@ -1,6 +1,5 @@ using Serilog; using Serilog.Events; -using SquidStd.Core.Data.Events; using SquidStd.Core.Interfaces.Events; using SquidStd.Services.Core.Services; using SquidStd.Tests.Support; @@ -112,8 +111,7 @@ public async Task PublishAsync_PreCancelledToken_Throws() using var cts = new CancellationTokenSource(); await cts.CancelAsync(); - await Assert.ThrowsAnyAsync(() => bus.PublishAsync(new TestEvent("payload"), cts.Token) - ); + await Assert.ThrowsAnyAsync(() => bus.PublishAsync(new TestEvent("payload"), cts.Token)); } [Fact] @@ -124,8 +122,7 @@ public async Task PublishAsync_ListenerCancellation_IsNotSwallowed() using var cts = new CancellationTokenSource(); bus.RegisterListener(new SelfCancellingListener(cts)); - await Assert.ThrowsAnyAsync(() => bus.PublishAsync(new TestEvent("payload"), cts.Token) - ); + await Assert.ThrowsAnyAsync(() => bus.PublishAsync(new TestEvent("payload"), cts.Token)); } [Fact] @@ -149,7 +146,8 @@ public async Task Subscribe_DelegateHandler_ReceivesAndUnsubscribes() using var eventBus = new EventBusService(); IEventBus bus = eventBus; var received = new List(); - var token = bus.Subscribe((e, _) => + var token = bus.Subscribe( + (e, _) => { received.Add(e.Payload); @@ -228,9 +226,7 @@ public Task HandleAsync(IEvent eventData, CancellationToken cancellationToken = private sealed class ThrowingListener : IEventListener { public Task HandleAsync(TestEvent eventData, CancellationToken cancellationToken = default) - { - throw new InvalidOperationException("listener failure"); - } + => throw new InvalidOperationException("listener failure"); } private sealed class SelfCancellingListener : IEventListener @@ -254,9 +250,7 @@ public Task HandleAsync(TestEvent eventData, CancellationToken cancellationToken private sealed class SlowListener : IEventListener { public async Task HandleAsync(TestEvent eventData, CancellationToken cancellationToken = default) - { - await Task.Delay(TimeSpan.FromMilliseconds(40), cancellationToken); - } + => await Task.Delay(TimeSpan.FromMilliseconds(40), cancellationToken); } [Collection(SerilogEventSinkCollection.Name)] @@ -268,15 +262,15 @@ public async Task PublishAsync_SlowListener_LogsWarning() var sink = new CapturingLogSink(); var original = Log.Logger; Log.Logger = new LoggerConfiguration() - .MinimumLevel.Verbose() - .WriteTo.Sink(sink) - .CreateLogger(); + .MinimumLevel + .Verbose() + .WriteTo + .Sink(sink) + .CreateLogger(); try { - using var eventBus = new EventBusService( - new EventBusOptions { SlowListenerThreshold = TimeSpan.FromMilliseconds(5) } - ); + using var eventBus = new EventBusService(new() { SlowListenerThreshold = TimeSpan.FromMilliseconds(5) }); IEventBus bus = eventBus; bus.RegisterListener(new SlowListener()); diff --git a/tests/SquidStd.Tests/Services/Core/JobSystemServiceTests.cs b/tests/SquidStd.Tests/Services/Core/JobSystemServiceTests.cs index 2b0477b2..18c306c5 100644 --- a/tests/SquidStd.Tests/Services/Core/JobSystemServiceTests.cs +++ b/tests/SquidStd.Tests/Services/Core/JobSystemServiceTests.cs @@ -1,4 +1,3 @@ -using SquidStd.Core.Data.Jobs; using SquidStd.Core.Interfaces.Jobs; using SquidStd.Services.Core.Services; @@ -47,7 +46,8 @@ public async Task ScheduleAsync_ManyJobs_AllComplete() { var value = i; tasks.Add( - system.ScheduleAsync(() => + system.ScheduleAsync( + () => { lock (sync) { @@ -72,8 +72,9 @@ public async Task ScheduleAsync_ThrowingAction_PropagatesExceptionToAwaiter() IJobSystem system = jobs; await jobs.StartAsync(CancellationToken.None); - await Assert.ThrowsAsync(() => - system.ScheduleAsync(() => throw new InvalidOperationException("boom")) + await Assert.ThrowsAsync( + () => + system.ScheduleAsync(() => throw new InvalidOperationException("boom")) ); } @@ -102,7 +103,8 @@ public async Task ScheduleAsync_TokenCancelledBeforePickup_TransitionsToCanceled using var cancellationTokenSource = new CancellationTokenSource(); await jobs.StartAsync(CancellationToken.None); - _ = system.ScheduleAsync(() => + _ = system.ScheduleAsync( + () => { firstStarted.Set(); gate.Wait(TimeSpan.FromSeconds(2)); @@ -127,7 +129,8 @@ public async Task StopAsync_CancelsQueuedJobsAndPreventsNewSchedules() using var firstStarted = new ManualResetEventSlim(false); await jobs.StartAsync(CancellationToken.None); - _ = system.ScheduleAsync(() => + _ = system.ScheduleAsync( + () => { firstStarted.Set(); gate.Wait(TimeSpan.FromSeconds(2)); @@ -140,8 +143,7 @@ public async Task StopAsync_CancelsQueuedJobsAndPreventsNewSchedules() gate.Set(); await Assert.ThrowsAsync(() => queued); - Assert.Throws(() => { _ = system.ScheduleAsync(() => { }); } - ); + Assert.Throws(() => { _ = system.ScheduleAsync(() => { }); }); jobs.Dispose(); } @@ -162,15 +164,13 @@ public void WorkerCount_UsesExplicitValue() } private static JobSystemService NewService(int workerCount) - { - return new JobSystemService( - new JobsConfig + => new( + new() { WorkerThreadCount = workerCount, ShutdownTimeoutSeconds = 1.0 } ); - } // CompletedCount is incremented by the worker after the scheduled task's completion fires, so // awaiting ScheduleAsync does not guarantee the counter is updated yet. Wait for it (bounded). diff --git a/tests/SquidStd.Tests/Services/Core/MainThreadDispatcherServiceTests.cs b/tests/SquidStd.Tests/Services/Core/MainThreadDispatcherServiceTests.cs index 52cd0af7..fb13ca65 100644 --- a/tests/SquidStd.Tests/Services/Core/MainThreadDispatcherServiceTests.cs +++ b/tests/SquidStd.Tests/Services/Core/MainThreadDispatcherServiceTests.cs @@ -13,7 +13,8 @@ public void DrainPending_BudgetExceededAfterFirstCallback_DefersRest() { IMainThreadDispatcher dispatcher = new MainThreadDispatcherService(); var calls = new List(); - dispatcher.Post(() => + dispatcher.Post( + () => { calls.Add(1); Thread.Sleep(5); @@ -34,7 +35,8 @@ public void DrainPending_CallbackPostsAnother_DefersToNextDrain() { IMainThreadDispatcher dispatcher = new MainThreadDispatcherService(); var calls = new List(); - dispatcher.Post(() => + dispatcher.Post( + () => { calls.Add(1); dispatcher.Post(() => calls.Add(2)); diff --git a/tests/SquidStd.Tests/Services/Core/MetricsCollectionServiceTests.cs b/tests/SquidStd.Tests/Services/Core/MetricsCollectionServiceTests.cs index 59346887..30767f10 100644 --- a/tests/SquidStd.Tests/Services/Core/MetricsCollectionServiceTests.cs +++ b/tests/SquidStd.Tests/Services/Core/MetricsCollectionServiceTests.cs @@ -10,7 +10,7 @@ public class MetricsCollectionServiceTests [Fact] public void GetSnapshot_WhenNotStarted_ReturnsEmptySnapshot() { - using var service = new MetricsCollectionService([], new MetricsConfig()); + using var service = new MetricsCollectionService([], new()); var snapshot = service.GetSnapshot(); @@ -23,7 +23,7 @@ public async Task GetStatus_ReturnsLatestMetricsSnapshot() { using var service = new MetricsCollectionService( [new CountingMetricProvider("jobs", "completed.total", 11)], - new MetricsConfig + new() { IntervalMilliseconds = 10, LogEnabled = false @@ -45,7 +45,7 @@ public async Task StartAsync_CollectsMetricsFromRegisteredProviders() { using var service = new MetricsCollectionService( [new CountingMetricProvider("jobs", "pending.total", 7)], - new MetricsConfig + new() { IntervalMilliseconds = 10, LogEnabled = false @@ -74,7 +74,7 @@ public async Task StartAsync_PublishesMetricsCollectedEventThroughEventBus() bus.RegisterListener(secondListener); using var service = new MetricsCollectionService( [new CountingMetricProvider("events", "published.total", 5)], - new MetricsConfig + new() { IntervalMilliseconds = 1000, LogEnabled = false @@ -99,7 +99,7 @@ public async Task StartAsync_WhenDisabled_DoesNotCollectMetrics() var provider = new CountingMetricProvider("jobs", "pending.total", 7); using var service = new MetricsCollectionService( [provider], - new MetricsConfig + new() { Enabled = false, IntervalMilliseconds = 10, @@ -122,7 +122,7 @@ public async Task StartAsync_WhenProviderThrows_ContinuesCollectingOtherProvider new ThrowingMetricProvider("broken"), new CountingMetricProvider("timer", "callbacks.total", 3) ], - new MetricsConfig + new() { IntervalMilliseconds = 10, LogEnabled = false @@ -144,7 +144,7 @@ public async Task StopAsync_StopsCollectionLoop() var provider = new CountingMetricProvider("bus", "dispatch.total", 1); using var service = new MetricsCollectionService( [provider], - new MetricsConfig + new() { IntervalMilliseconds = 10, LogEnabled = false @@ -199,7 +199,7 @@ public ValueTask> CollectAsync(CancellationToken can { Interlocked.Increment(ref _collectionCount); - return ValueTask.FromResult>([new MetricSample(_metricName, _value)]); + return ValueTask.FromResult>([new(_metricName, _value)]); } } @@ -213,9 +213,7 @@ public ThrowingMetricProvider(string providerName) } public ValueTask> CollectAsync(CancellationToken cancellationToken = default) - { - throw new InvalidOperationException("Synthetic test failure."); - } + => throw new InvalidOperationException("Synthetic test failure."); } private sealed class MetricsCollectedListener : IEventListener diff --git a/tests/SquidStd.Tests/Services/Core/RegisterCommandDispatcherExtensionsTests.cs b/tests/SquidStd.Tests/Services/Core/RegisterCommandDispatcherExtensionsTests.cs index e7dbb2ac..2ca8b713 100644 --- a/tests/SquidStd.Tests/Services/Core/RegisterCommandDispatcherExtensionsTests.cs +++ b/tests/SquidStd.Tests/Services/Core/RegisterCommandDispatcherExtensionsTests.cs @@ -40,9 +40,7 @@ public async Task Activator_SubscribesRegisteredHandlers() Assert.Equal("hi", container.Resolve().LastText); } - private sealed class Session - { - } + private sealed class Session { } private sealed class PingHandler : ICommandHandler { diff --git a/tests/SquidStd.Tests/Services/Core/Scheduling/CronSchedulerServiceTests.cs b/tests/SquidStd.Tests/Services/Core/Scheduling/CronSchedulerServiceTests.cs index ff7ea983..02ee3891 100644 --- a/tests/SquidStd.Tests/Services/Core/Scheduling/CronSchedulerServiceTests.cs +++ b/tests/SquidStd.Tests/Services/Core/Scheduling/CronSchedulerServiceTests.cs @@ -1,5 +1,4 @@ using Cronos; -using SquidStd.Core.Data.Timing; using SquidStd.Services.Core.Services; using SquidStd.Services.Core.Services.Scheduling; using SquidStd.Tests.Support; @@ -104,7 +103,7 @@ public void Jobs_ExposesRegisteredJob() public void RealTimerWheel_FiresJob_WhenAdvancedPastAMinute() { var timer = new TimerWheelService( - new TimerWheelConfig + new() { TickDuration = TimeSpan.FromMilliseconds(8), WheelSize = 512 diff --git a/tests/SquidStd.Tests/Services/Core/Scheduling/TimerWheelPumpServiceTests.cs b/tests/SquidStd.Tests/Services/Core/Scheduling/TimerWheelPumpServiceTests.cs index e2dc7208..ae020365 100644 --- a/tests/SquidStd.Tests/Services/Core/Scheduling/TimerWheelPumpServiceTests.cs +++ b/tests/SquidStd.Tests/Services/Core/Scheduling/TimerWheelPumpServiceTests.cs @@ -1,4 +1,3 @@ -using SquidStd.Core.Data.Timing; using SquidStd.Services.Core.Services.Scheduling; using SquidStd.Tests.Support; @@ -8,13 +7,12 @@ public class TimerWheelPumpServiceTests { [Fact] public void Ctor_NonPositiveInterval_Throws() - { - Assert.Throws(() => new TimerWheelPumpService( + => Assert.Throws( + () => new TimerWheelPumpService( new FakeTimerService(), - new TimerWheelPumpConfig { PumpInterval = TimeSpan.Zero } + new() { PumpInterval = TimeSpan.Zero } ) ); - } [Fact] public async Task Pump_AdvancesTheWheel() @@ -22,7 +20,7 @@ public async Task Pump_AdvancesTheWheel() var timer = new FakeTimerService(); var pump = new TimerWheelPumpService( timer, - new TimerWheelPumpConfig { PumpInterval = TimeSpan.FromMilliseconds(20) } + new() { PumpInterval = TimeSpan.FromMilliseconds(20) } ); await pump.StartAsync(); diff --git a/tests/SquidStd.Tests/Services/Core/SeededCommandDispatcherTests.cs b/tests/SquidStd.Tests/Services/Core/SeededCommandDispatcherTests.cs index 8ec0a1b2..9cb55b3a 100644 --- a/tests/SquidStd.Tests/Services/Core/SeededCommandDispatcherTests.cs +++ b/tests/SquidStd.Tests/Services/Core/SeededCommandDispatcherTests.cs @@ -16,7 +16,7 @@ public async Task DispatchAsync_BuildsContextFromSeed() inner.RegisterHandler(handler); var seeded = new SeededCommandDispatcher(inner, new ConnectionSessionFactory()); - var result = await seeded.DispatchAsync(new PingCommand("hi"), new Connection("conn-1")); + var result = await seeded.DispatchAsync(new PingCommand("hi"), new("conn-1")); Assert.True(result.Matched); Assert.Equal(1, result.HandlerCount); @@ -35,7 +35,7 @@ public async Task RegisterSeededCommandDispatcher_ResolvesAndDispatches() await container.Resolve>().StartAsync(CancellationToken.None); var seeded = container.Resolve>(); - var result = await seeded.DispatchAsync(new PingCommand("yo"), new Connection("conn-2")); + var result = await seeded.DispatchAsync(new PingCommand("yo"), new("conn-2")); Assert.True(result.Matched); var handler = container.Resolve(); @@ -66,9 +66,7 @@ public Session(string id) private sealed class ConnectionSessionFactory : ICommandContextFactory { public Session Create(Connection seed) - { - return new Session(seed.Id); - } + => new(seed.Id); } private sealed class RecordingHandler : ICommandHandler diff --git a/tests/SquidStd.Tests/Services/Core/SquidStdLogRollingIntervalExtensionsTests.cs b/tests/SquidStd.Tests/Services/Core/SquidStdLogRollingIntervalExtensionsTests.cs index 28edec22..900c5a58 100644 --- a/tests/SquidStd.Tests/Services/Core/SquidStdLogRollingIntervalExtensionsTests.cs +++ b/tests/SquidStd.Tests/Services/Core/SquidStdLogRollingIntervalExtensionsTests.cs @@ -6,24 +6,19 @@ namespace SquidStd.Tests.Services.Core; public class SquidStdLogRollingIntervalExtensionsTests { - [Theory] - [InlineData(SquidStdLogRollingIntervalType.Infinite, RollingInterval.Infinite)] - [InlineData(SquidStdLogRollingIntervalType.Year, RollingInterval.Year)] - [InlineData(SquidStdLogRollingIntervalType.Month, RollingInterval.Month)] - [InlineData(SquidStdLogRollingIntervalType.Day, RollingInterval.Day)] - [InlineData(SquidStdLogRollingIntervalType.Hour, RollingInterval.Hour)] - [InlineData(SquidStdLogRollingIntervalType.Minute, RollingInterval.Minute)] + [Theory, InlineData(SquidStdLogRollingIntervalType.Infinite, RollingInterval.Infinite), + InlineData(SquidStdLogRollingIntervalType.Year, RollingInterval.Year), + InlineData(SquidStdLogRollingIntervalType.Month, RollingInterval.Month), + InlineData(SquidStdLogRollingIntervalType.Day, RollingInterval.Day), + InlineData(SquidStdLogRollingIntervalType.Hour, RollingInterval.Hour), + InlineData(SquidStdLogRollingIntervalType.Minute, RollingInterval.Minute)] public void ToSerilogRollingInterval_KnownIntervals_MapExpected( SquidStdLogRollingIntervalType input, RollingInterval expected ) - { - Assert.Equal(expected, input.ToSerilogRollingInterval()); - } + => Assert.Equal(expected, input.ToSerilogRollingInterval()); [Fact] public void ToSerilogRollingInterval_UnmappedInterval_FallsBackToDay() - { - Assert.Equal(RollingInterval.Day, ((SquidStdLogRollingIntervalType)255).ToSerilogRollingInterval()); - } + => Assert.Equal(RollingInterval.Day, ((SquidStdLogRollingIntervalType)255).ToSerilogRollingInterval()); } diff --git a/tests/SquidStd.Tests/Services/Core/TimerWheelServiceTests.cs b/tests/SquidStd.Tests/Services/Core/TimerWheelServiceTests.cs index d8e3947f..ca10cc8b 100644 --- a/tests/SquidStd.Tests/Services/Core/TimerWheelServiceTests.cs +++ b/tests/SquidStd.Tests/Services/Core/TimerWheelServiceTests.cs @@ -1,4 +1,3 @@ -using SquidStd.Core.Data.Timing; using SquidStd.Core.Interfaces.Timing; using SquidStd.Services.Core.Services; @@ -23,11 +22,13 @@ public void CallbackException_DoesNotStopOtherTimers() [Fact] public void Ctor_InvalidConfig_Throws() { - Assert.Throws(() => - new TimerWheelService(new TimerWheelConfig { TickDuration = TimeSpan.Zero }) + Assert.Throws( + () => + new TimerWheelService(new() { TickDuration = TimeSpan.Zero }) ); - Assert.Throws(() => - new TimerWheelService(new TimerWheelConfig { TickDuration = TimeSpan.FromMilliseconds(8), WheelSize = 0 }) + Assert.Throws( + () => + new TimerWheelService(new() { TickDuration = TimeSpan.FromMilliseconds(8), WheelSize = 0 }) ); } @@ -152,13 +153,11 @@ public void UpdateTicksDelta_AdvancesByWholeTicks() } private static TimerWheelService NewService(int tickDurationMs = 8, int wheelSize = 16) - { - return new TimerWheelService( - new TimerWheelConfig + => new( + new() { TickDuration = TimeSpan.FromMilliseconds(tickDurationMs), WheelSize = wheelSize } ); - } } diff --git a/tests/SquidStd.Tests/SquidStd.Tests.csproj b/tests/SquidStd.Tests/SquidStd.Tests.csproj index 70fb3401..69fab085 100644 --- a/tests/SquidStd.Tests/SquidStd.Tests.csproj +++ b/tests/SquidStd.Tests/SquidStd.Tests.csproj @@ -8,73 +8,73 @@ - - - - - - - - - - - - + + + + + + + + + + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SquidStd.Tests/Storage/FileStorageServiceTests.cs b/tests/SquidStd.Tests/Storage/FileStorageServiceTests.cs index 2254f41f..5a12f47d 100644 --- a/tests/SquidStd.Tests/Storage/FileStorageServiceTests.cs +++ b/tests/SquidStd.Tests/Storage/FileStorageServiceTests.cs @@ -1,5 +1,4 @@ using System.Text; -using SquidStd.Storage.Abstractions.Data.Config; using SquidStd.Storage.Services; using SquidStd.Tests.Support; @@ -11,7 +10,7 @@ public class FileStorageServiceTests public async Task DeleteAsync_RemovesStoredValue() { using var temp = new TempDirectory(); - var service = new FileStorageService(new StorageConfig { RootDirectory = temp.Path }); + var service = new FileStorageService(new() { RootDirectory = temp.Path }); await service.SaveAsync("cache/value.bin", new byte[] { 1, 2, 3 }); var deleted = await service.DeleteAsync("cache/value.bin"); @@ -25,7 +24,7 @@ public async Task DeleteAsync_RemovesStoredValue() public async Task ListKeysAsync_EmptyStore_ReturnsEmpty() { using var temp = new TempDirectory(); - var service = new FileStorageService(new StorageConfig { RootDirectory = temp.Path }); + var service = new FileStorageService(new() { RootDirectory = temp.Path }); Assert.Empty(await ToListAsync(service.ListKeysAsync())); } @@ -34,7 +33,7 @@ public async Task ListKeysAsync_EmptyStore_ReturnsEmpty() public async Task ListKeysAsync_ReturnsSavedKeys_AndFiltersByPrefix() { using var temp = new TempDirectory(); - var service = new FileStorageService(new StorageConfig { RootDirectory = temp.Path }); + var service = new FileStorageService(new() { RootDirectory = temp.Path }); await service.SaveAsync("a/one.bin", new byte[] { 1 }); await service.SaveAsync("a/two.bin", new byte[] { 2 }); await service.SaveAsync("b/three.bin", new byte[] { 3 }); @@ -50,7 +49,7 @@ public async Task ListKeysAsync_ReturnsSavedKeys_AndFiltersByPrefix() public async Task ObjectStorage_ListKeysAsync_ReturnsSavedKeys() { using var temp = new TempDirectory(); - var storage = new FileStorageService(new StorageConfig { RootDirectory = temp.Path }); + var storage = new FileStorageService(new() { RootDirectory = temp.Path }); var objects = new YamlObjectStorageService(storage); await objects.SaveAsync("objects/x.yaml", new SampleObject { Name = "x", Value = 1 }); @@ -63,7 +62,7 @@ public async Task ObjectStorage_ListKeysAsync_ReturnsSavedKeys() public async Task ObjectStorage_SaveAsync_LoadAsync_RoundTripsYamlObject() { using var temp = new TempDirectory(); - var storage = new FileStorageService(new StorageConfig { RootDirectory = temp.Path }); + var storage = new FileStorageService(new() { RootDirectory = temp.Path }); var objects = new YamlObjectStorageService(storage); var expected = new SampleObject { @@ -84,7 +83,7 @@ public async Task ObjectStorage_SaveAsync_LoadAsync_RoundTripsYamlObject() public async Task SaveAsync_LoadAsync_RoundTripsBytes() { using var temp = new TempDirectory(); - var service = new FileStorageService(new StorageConfig { RootDirectory = temp.Path }); + var service = new FileStorageService(new() { RootDirectory = temp.Path }); var data = Encoding.UTF8.GetBytes("hello storage"); await service.SaveAsync("profiles/main.bin", data); @@ -95,14 +94,11 @@ public async Task SaveAsync_LoadAsync_RoundTripsBytes() Assert.True(await service.ExistsAsync("profiles/main.bin")); } - [Theory] - [InlineData("../escape.bin")] - [InlineData("/absolute.bin")] - [InlineData("nested/../../escape.bin")] + [Theory, InlineData("../escape.bin"), InlineData("/absolute.bin"), InlineData("nested/../../escape.bin")] public async Task SaveAsync_RejectsUnsafeKeys(string key) { using var temp = new TempDirectory(); - var service = new FileStorageService(new StorageConfig { RootDirectory = temp.Path }); + var service = new FileStorageService(new() { RootDirectory = temp.Path }); await Assert.ThrowsAsync(() => service.SaveAsync(key, new byte[] { 1 }).AsTask()); } diff --git a/tests/SquidStd.Tests/Storage/S3/MinioContainerFixture.cs b/tests/SquidStd.Tests/Storage/S3/MinioContainerFixture.cs index 368a5826..f7dda433 100644 --- a/tests/SquidStd.Tests/Storage/S3/MinioContainerFixture.cs +++ b/tests/SquidStd.Tests/Storage/S3/MinioContainerFixture.cs @@ -3,7 +3,7 @@ namespace SquidStd.Tests.Storage.S3; /// -/// Starts a MinIO container once for the whole collection and exposes its endpoint and credentials. +/// Starts a MinIO container once for the whole collection and exposes its endpoint and credentials. /// public sealed class MinioContainerFixture : IAsyncLifetime { @@ -18,14 +18,10 @@ public sealed class MinioContainerFixture : IAsyncLifetime public string SecretKey => _container.GetSecretKey(); public Task DisposeAsync() - { - return _container.DisposeAsync().AsTask(); - } + => _container.DisposeAsync().AsTask(); public Task InitializeAsync() - { - return _container.StartAsync(); - } + => _container.StartAsync(); } [CollectionDefinition(Name)] diff --git a/tests/SquidStd.Tests/Storage/S3/S3StorageServiceTests.cs b/tests/SquidStd.Tests/Storage/S3/S3StorageServiceTests.cs index cf36ea79..7c1443b0 100644 --- a/tests/SquidStd.Tests/Storage/S3/S3StorageServiceTests.cs +++ b/tests/SquidStd.Tests/Storage/S3/S3StorageServiceTests.cs @@ -1,6 +1,4 @@ using System.Text; -using SquidStd.Aws.Abstractions.Data.Config; -using SquidStd.Storage.S3.Data.Config; using SquidStd.Storage.S3.Services; namespace SquidStd.Tests.Storage.S3; @@ -17,13 +15,10 @@ public S3StorageServiceTests(MinioContainerFixture fixture) [Fact] public void Ctor_MissingServiceUrl_Throws() - { - Assert.ThrowsAny(() => - new S3StorageService( - new S3StorageOptions { Aws = new AwsConfigEntry { AccessKey = "a", SecretKey = "b" }, Bucket = "c" } - ) + => Assert.ThrowsAny( + () => + new S3StorageService(new() { Aws = new() { AccessKey = "a", SecretKey = "b" }, Bucket = "c" }) ); - } [Fact] public async Task Exists_And_Delete() @@ -60,9 +55,7 @@ public async Task ListKeysAsync_ReturnsObjectsUnderPrefix() [Fact] public async Task Load_MissingKey_ReturnsNull() - { - Assert.Null(await NewService().LoadAsync(Key())); - } + => Assert.Null(await NewService().LoadAsync(Key())); [Fact] public async Task SaveThenLoad_RoundTrips_AndCreatesBucket() @@ -78,16 +71,13 @@ public async Task SaveThenLoad_RoundTrips_AndCreatesBucket() } private static string Key() - { - return "k-" + Guid.NewGuid().ToString("N"); - } + => "k-" + Guid.NewGuid().ToString("N"); private S3StorageService NewService() - { - return new S3StorageService( - new S3StorageOptions + => new( + new() { - Aws = new AwsConfigEntry + Aws = new() { ServiceUrl = _fixture.ServiceUrl, AccessKey = _fixture.AccessKey, @@ -96,5 +86,4 @@ private S3StorageService NewService() Bucket = "squidstd-tests" } ); - } } diff --git a/tests/SquidStd.Tests/Storage/StorageRegistrationTests.cs b/tests/SquidStd.Tests/Storage/StorageRegistrationTests.cs index 6d35c2fd..a7d7f88c 100644 --- a/tests/SquidStd.Tests/Storage/StorageRegistrationTests.cs +++ b/tests/SquidStd.Tests/Storage/StorageRegistrationTests.cs @@ -1,5 +1,4 @@ using DryIoc; -using SquidStd.Storage.Abstractions.Data.Config; using SquidStd.Storage.Abstractions.Interfaces; using SquidStd.Storage.Extensions; @@ -13,7 +12,7 @@ public async Task AddFileStorage_ResolvesAndRoundTrips() var root = Path.Combine(Path.GetTempPath(), "squidstd-storage-" + Guid.NewGuid().ToString("N")); using var container = new Container(); - container.AddFileStorage(new StorageConfig { RootDirectory = root }); + container.AddFileStorage(new() { RootDirectory = root }); var storage = container.Resolve(); Assert.NotNull(container.Resolve()); diff --git a/tests/SquidStd.Tests/Support/AppendingMiddleware.cs b/tests/SquidStd.Tests/Support/AppendingMiddleware.cs index a3578f8f..fc63af15 100644 --- a/tests/SquidStd.Tests/Support/AppendingMiddleware.cs +++ b/tests/SquidStd.Tests/Support/AppendingMiddleware.cs @@ -4,8 +4,8 @@ namespace SquidStd.Tests.Support; /// -/// Test middleware that appends a marker byte to every payload, on both receive and send paths. -/// Used to verify pipeline ordering and transformation. +/// Test middleware that appends a marker byte to every payload, on both receive and send paths. +/// Used to verify pipeline ordering and transformation. /// public sealed class AppendingMiddleware : INetMiddleware { @@ -21,18 +21,14 @@ public ValueTask> ProcessAsync( ReadOnlyMemory data, CancellationToken cancellationToken = default ) - { - return ValueTask.FromResult>(Append(data)); - } + => ValueTask.FromResult>(Append(data)); public ValueTask> ProcessSendAsync( SquidStdTcpClient? client, ReadOnlyMemory data, CancellationToken cancellationToken = default ) - { - return ValueTask.FromResult>(Append(data)); - } + => ValueTask.FromResult>(Append(data)); private byte[] Append(ReadOnlyMemory data) { diff --git a/tests/SquidStd.Tests/Support/CapturingLogSink.cs b/tests/SquidStd.Tests/Support/CapturingLogSink.cs index d0beaf98..f2232b82 100644 --- a/tests/SquidStd.Tests/Support/CapturingLogSink.cs +++ b/tests/SquidStd.Tests/Support/CapturingLogSink.cs @@ -4,7 +4,7 @@ namespace SquidStd.Tests.Support; /// -/// In-memory Serilog sink that records emitted log events for assertions. +/// In-memory Serilog sink that records emitted log events for assertions. /// public sealed class CapturingLogSink : ILogEventSink { diff --git a/tests/SquidStd.Tests/Support/CountingXorCodec.cs b/tests/SquidStd.Tests/Support/CountingXorCodec.cs index 150defb6..3d1939f0 100644 --- a/tests/SquidStd.Tests/Support/CountingXorCodec.cs +++ b/tests/SquidStd.Tests/Support/CountingXorCodec.cs @@ -3,9 +3,9 @@ namespace SquidStd.Tests.Support; /// -/// Deterministic stateful test codec: XORs each byte with a counter-based keystream (seed + position). -/// Decode and Encode keep independent positions, mirroring the separate receive/send state of real -/// stream ciphers. Two codecs created with the same seed cancel out (one encodes, the other decodes). +/// Deterministic stateful test codec: XORs each byte with a counter-based keystream (seed + position). +/// Decode and Encode keep independent positions, mirroring the separate receive/send state of real +/// stream ciphers. Two codecs created with the same seed cancel out (one encodes, the other decodes). /// public sealed class CountingXorCodec : ITransportCodec { diff --git a/tests/SquidStd.Tests/Support/DroppingMiddleware.cs b/tests/SquidStd.Tests/Support/DroppingMiddleware.cs index 833f7002..448a5063 100644 --- a/tests/SquidStd.Tests/Support/DroppingMiddleware.cs +++ b/tests/SquidStd.Tests/Support/DroppingMiddleware.cs @@ -4,8 +4,8 @@ namespace SquidStd.Tests.Support; /// -/// Test middleware that drops every payload by returning , -/// short-circuiting the pipeline. +/// Test middleware that drops every payload by returning , +/// short-circuiting the pipeline. /// public sealed class DroppingMiddleware : INetMiddleware { @@ -14,16 +14,12 @@ public ValueTask> ProcessAsync( ReadOnlyMemory data, CancellationToken cancellationToken = default ) - { - return ValueTask.FromResult(ReadOnlyMemory.Empty); - } + => ValueTask.FromResult(ReadOnlyMemory.Empty); public ValueTask> ProcessSendAsync( SquidStdTcpClient? client, ReadOnlyMemory data, CancellationToken cancellationToken = default ) - { - return ValueTask.FromResult(ReadOnlyMemory.Empty); - } + => ValueTask.FromResult(ReadOnlyMemory.Empty); } diff --git a/tests/SquidStd.Tests/Support/DummyGuidConverter.cs b/tests/SquidStd.Tests/Support/DummyGuidConverter.cs index 219e12d5..e989ec5f 100644 --- a/tests/SquidStd.Tests/Support/DummyGuidConverter.cs +++ b/tests/SquidStd.Tests/Support/DummyGuidConverter.cs @@ -4,17 +4,13 @@ namespace SquidStd.Tests.Support; /// -/// No-op JSON converter used to exercise converter registration helpers. +/// No-op JSON converter used to exercise converter registration helpers. /// public class DummyGuidConverter : JsonConverter { public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return Guid.Empty; - } + => Guid.Empty; public override void Write(Utf8JsonWriter writer, Guid value, JsonSerializerOptions options) - { - writer.WriteStringValue(value.ToString()); - } + => writer.WriteStringValue(value.ToString()); } diff --git a/tests/SquidStd.Tests/Support/FakeCacheProvider.cs b/tests/SquidStd.Tests/Support/FakeCacheProvider.cs index 2fc4bd35..d2f71128 100644 --- a/tests/SquidStd.Tests/Support/FakeCacheProvider.cs +++ b/tests/SquidStd.Tests/Support/FakeCacheProvider.cs @@ -4,7 +4,7 @@ namespace SquidStd.Tests.Support; /// -/// In-memory for tests. Ignores TTL expiry (records the last TTL seen). +/// In-memory for tests. Ignores TTL expiry (records the last TTL seen). /// public sealed class FakeCacheProvider : ICacheProvider { @@ -13,9 +13,7 @@ public sealed class FakeCacheProvider : ICacheProvider public TimeSpan? LastTtl { get; private set; } public Task ExistsAsync(string key, CancellationToken cancellationToken = default) - { - return Task.FromResult(_store.ContainsKey(key)); - } + => Task.FromResult(_store.ContainsKey(key)); public Task?> GetAsync(string key, CancellationToken cancellationToken = default) { @@ -28,9 +26,7 @@ public Task ExistsAsync(string key, CancellationToken cancellationToken = } public Task RemoveAsync(string key, CancellationToken cancellationToken = default) - { - return Task.FromResult(_store.TryRemove(key, out _)); - } + => Task.FromResult(_store.TryRemove(key, out _)); public Task SetAsync( string key, @@ -46,12 +42,8 @@ public Task SetAsync( } public ValueTask StartAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; public ValueTask StopAsync(CancellationToken cancellationToken = default) - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; } diff --git a/tests/SquidStd.Tests/Support/FakeHealthCheck.cs b/tests/SquidStd.Tests/Support/FakeHealthCheck.cs index 108c1d8d..7def6254 100644 --- a/tests/SquidStd.Tests/Support/FakeHealthCheck.cs +++ b/tests/SquidStd.Tests/Support/FakeHealthCheck.cs @@ -4,8 +4,8 @@ namespace SquidStd.Tests.Support; /// -/// Configurable for tests: returns a fixed result, optionally after a -/// delay, or throws a configured exception. +/// Configurable for tests: returns a fixed result, optionally after a +/// delay, or throws a configured exception. /// public sealed class FakeHealthCheck : IHealthCheck { diff --git a/tests/SquidStd.Tests/Support/FakeNetworkConnection.cs b/tests/SquidStd.Tests/Support/FakeNetworkConnection.cs index 77e24963..fe634f36 100644 --- a/tests/SquidStd.Tests/Support/FakeNetworkConnection.cs +++ b/tests/SquidStd.Tests/Support/FakeNetworkConnection.cs @@ -4,8 +4,8 @@ namespace SquidStd.Tests.Support; /// -/// In-memory for testing sessions without sockets. -/// Records sent payloads and close calls; SendCallback can inject failures. +/// In-memory for testing sessions without sockets. +/// Records sent payloads and close calls; SendCallback can inject failures. /// public sealed class FakeNetworkConnection : INetworkConnection { diff --git a/tests/SquidStd.Tests/Support/FakePlugin.cs b/tests/SquidStd.Tests/Support/FakePlugin.cs index 5f9934d5..a5571283 100644 --- a/tests/SquidStd.Tests/Support/FakePlugin.cs +++ b/tests/SquidStd.Tests/Support/FakePlugin.cs @@ -5,23 +5,23 @@ namespace SquidStd.Tests.Support; /// -/// Minimal implementation used to exercise the plugin contract. +/// Minimal implementation used to exercise the plugin contract. /// public class FakePlugin : ISquidStdPlugin { /// - /// Gets the context received during the last call. + /// Gets the context received during the last call. /// public PluginContext? ReceivedContext { get; private set; } /// - /// Gets the plugin metadata. + /// Gets the plugin metadata. /// public PluginMetadata Metadata { get; } = new() { Id = "squidstd.fake", Name = "Fake Plugin", - Version = new Version(1, 2, 3), + Version = new(1, 2, 3), Author = "tests" }; diff --git a/tests/SquidStd.Tests/Support/FakeStdService.cs b/tests/SquidStd.Tests/Support/FakeStdService.cs index f6cb6261..24e464d0 100644 --- a/tests/SquidStd.Tests/Support/FakeStdService.cs +++ b/tests/SquidStd.Tests/Support/FakeStdService.cs @@ -3,12 +3,12 @@ namespace SquidStd.Tests.Support; /// -/// Minimal implementation tracking start/stop calls. +/// Minimal implementation tracking start/stop calls. /// public class FakeStdService : ISquidStdService { /// - /// Gets a value indicating whether the service is currently started. + /// Gets a value indicating whether the service is currently started. /// public bool Started { get; private set; } diff --git a/tests/SquidStd.Tests/Support/FakeTimeProvider.cs b/tests/SquidStd.Tests/Support/FakeTimeProvider.cs index b9df069d..be2815a6 100644 --- a/tests/SquidStd.Tests/Support/FakeTimeProvider.cs +++ b/tests/SquidStd.Tests/Support/FakeTimeProvider.cs @@ -1,8 +1,8 @@ namespace SquidStd.Tests.Support; /// -/// Test TimeProvider with a manually advanced clock and an inert timer (so periodic sweeps -/// never fire on their own; tests invoke the sweep explicitly). +/// Test TimeProvider with a manually advanced clock and an inert timer (so periodic sweeps +/// never fire on their own; tests invoke the sweep explicitly). /// public sealed class FakeTimeProvider : TimeProvider { @@ -14,34 +14,22 @@ public FakeTimeProvider(DateTimeOffset start) } public void Advance(TimeSpan delta) - { - _utcNow = _utcNow.Add(delta); - } + => _utcNow = _utcNow.Add(delta); public override ITimer CreateTimer(TimerCallback callback, object? state, TimeSpan dueTime, TimeSpan period) - { - return new InertTimer(); - } + => new InertTimer(); public override DateTimeOffset GetUtcNow() - { - return _utcNow; - } + => _utcNow; private sealed class InertTimer : ITimer { public bool Change(TimeSpan dueTime, TimeSpan period) - { - return true; - } + => true; public ValueTask DisposeAsync() - { - return ValueTask.CompletedTask; - } + => ValueTask.CompletedTask; - public void Dispose() - { - } + public void Dispose() { } } } diff --git a/tests/SquidStd.Tests/Support/FakeTimerService.cs b/tests/SquidStd.Tests/Support/FakeTimerService.cs index fea9a939..be9668a5 100644 --- a/tests/SquidStd.Tests/Support/FakeTimerService.cs +++ b/tests/SquidStd.Tests/Support/FakeTimerService.cs @@ -3,9 +3,9 @@ namespace SquidStd.Tests.Support; /// -/// In-memory for tests. Timers do not fire on their own: -/// call to invoke and clear the currently-registered timers -/// (one-shot semantics). only records that a pump ran. +/// In-memory for tests. Timers do not fire on their own: +/// call to invoke and clear the currently-registered timers +/// (one-shot semantics). only records that a pump ran. /// public sealed class FakeTimerService : ITimerService { @@ -26,14 +26,10 @@ public string RegisterTimer(string name, TimeSpan interval, Action callback, Tim } public void UnregisterAllTimers() - { - _timers.Clear(); - } + => _timers.Clear(); public bool UnregisterTimer(string timerId) - { - return _timers.Remove(timerId); - } + => _timers.Remove(timerId); public int UnregisterTimersByName(string name) { diff --git a/tests/SquidStd.Tests/Support/LengthPrefixFramer.cs b/tests/SquidStd.Tests/Support/LengthPrefixFramer.cs index 90d40464..a58fe544 100644 --- a/tests/SquidStd.Tests/Support/LengthPrefixFramer.cs +++ b/tests/SquidStd.Tests/Support/LengthPrefixFramer.cs @@ -3,8 +3,8 @@ namespace SquidStd.Tests.Support; /// -/// Test framer: a single length-prefix byte followed by that many payload bytes. The emitted frame -/// length includes the prefix byte. +/// Test framer: a single length-prefix byte followed by that many payload bytes. The emitted frame +/// length includes the prefix byte. /// public sealed class LengthPrefixFramer : INetFramer { diff --git a/tests/SquidStd.Tests/Support/ManualJobSystem.cs b/tests/SquidStd.Tests/Support/ManualJobSystem.cs index 54387c49..01c988e6 100644 --- a/tests/SquidStd.Tests/Support/ManualJobSystem.cs +++ b/tests/SquidStd.Tests/Support/ManualJobSystem.cs @@ -3,9 +3,9 @@ namespace SquidStd.Tests.Support; /// -/// Single-threaded for tests: -/// queues the work; call to execute it. This keeps overlap and -/// rescheduling tests fully deterministic. +/// Single-threaded for tests: +/// queues the work; call to execute it. This keeps overlap and +/// rescheduling tests fully deterministic. /// public sealed class ManualJobSystem : IJobSystem { @@ -49,7 +49,5 @@ public int RunAll() return snapshot.Length; } - public void Dispose() - { - } + public void Dispose() { } } diff --git a/tests/SquidStd.Tests/Support/OtherDto.cs b/tests/SquidStd.Tests/Support/OtherDto.cs index 4aa40f90..d3acf7c3 100644 --- a/tests/SquidStd.Tests/Support/OtherDto.cs +++ b/tests/SquidStd.Tests/Support/OtherDto.cs @@ -1,12 +1,12 @@ namespace SquidStd.Tests.Support; /// -/// Secondary data carrier used to verify multi-type JSON serializer contexts. +/// Secondary data carrier used to verify multi-type JSON serializer contexts. /// public class OtherDto { /// - /// Gets or sets the value. + /// Gets or sets the value. /// public string Value { get; set; } = ""; } diff --git a/tests/SquidStd.Tests/Support/SampleDto.cs b/tests/SquidStd.Tests/Support/SampleDto.cs index f3442f31..e20b9f7c 100644 --- a/tests/SquidStd.Tests/Support/SampleDto.cs +++ b/tests/SquidStd.Tests/Support/SampleDto.cs @@ -1,17 +1,17 @@ namespace SquidStd.Tests.Support; /// -/// Simple data carrier used for JSON and YAML serialization round-trip tests. +/// Simple data carrier used for JSON and YAML serialization round-trip tests. /// public class SampleDto { /// - /// Gets or sets the display name. + /// Gets or sets the display name. /// public string Name { get; set; } = ""; /// - /// Gets or sets the numeric count. + /// Gets or sets the numeric count. /// public int Count { get; set; } } diff --git a/tests/SquidStd.Tests/Support/SerilogEventSinkCollection.cs b/tests/SquidStd.Tests/Support/SerilogEventSinkCollection.cs index 808d4c74..a37b1d3b 100644 --- a/tests/SquidStd.Tests/Support/SerilogEventSinkCollection.cs +++ b/tests/SquidStd.Tests/Support/SerilogEventSinkCollection.cs @@ -1,8 +1,8 @@ namespace SquidStd.Tests.Support; /// -/// Serializes the tests that mutate the static EventSink.OnLogReceived handler, -/// preventing cross-talk between parallel test classes. +/// Serializes the tests that mutate the static EventSink.OnLogReceived handler, +/// preventing cross-talk between parallel test classes. /// [CollectionDefinition(Name, DisableParallelization = true)] public class SerilogEventSinkCollection diff --git a/tests/SquidStd.Tests/Support/TempDirectory.cs b/tests/SquidStd.Tests/Support/TempDirectory.cs index 65f1d40d..931f7259 100644 --- a/tests/SquidStd.Tests/Support/TempDirectory.cs +++ b/tests/SquidStd.Tests/Support/TempDirectory.cs @@ -3,12 +3,12 @@ namespace SquidStd.Tests.Support; /// -/// Creates a unique temporary directory for a test and removes it on dispose. +/// Creates a unique temporary directory for a test and removes it on dispose. /// public sealed class TempDirectory : IDisposable { /// - /// Gets the absolute path of the temporary directory. + /// Gets the absolute path of the temporary directory. /// public string Path { get; } @@ -19,14 +19,12 @@ public TempDirectory() } /// - /// Combines a relative path with the temporary directory root. + /// Combines a relative path with the temporary directory root. /// /// The relative path. /// The combined absolute path. public string Combine(string relative) - { - return SysPath.Combine(Path, relative); - } + => SysPath.Combine(Path, relative); public void Dispose() { diff --git a/tests/SquidStd.Tests/Support/TestDirectoryType.cs b/tests/SquidStd.Tests/Support/TestDirectoryType.cs index 588a42ea..12b64303 100644 --- a/tests/SquidStd.Tests/Support/TestDirectoryType.cs +++ b/tests/SquidStd.Tests/Support/TestDirectoryType.cs @@ -1,7 +1,7 @@ namespace SquidStd.Tests.Support; /// -/// Directory type values used to exercise DirectoriesConfig enum overloads. +/// Directory type values used to exercise DirectoriesConfig enum overloads. /// public enum TestDirectoryType { diff --git a/tests/SquidStd.Tests/Support/TestJsonContext.cs b/tests/SquidStd.Tests/Support/TestJsonContext.cs index 7f738a2a..f6c211e3 100644 --- a/tests/SquidStd.Tests/Support/TestJsonContext.cs +++ b/tests/SquidStd.Tests/Support/TestJsonContext.cs @@ -3,10 +3,7 @@ namespace SquidStd.Tests.Support; /// -/// Source-generated JSON serializer context exposing the test DTO types. +/// Source-generated JSON serializer context exposing the test DTO types. /// -[JsonSerializable(typeof(SampleDto))] -[JsonSerializable(typeof(OtherDto))] -public partial class TestJsonContext : JsonSerializerContext -{ -} +[JsonSerializable(typeof(SampleDto)), JsonSerializable(typeof(OtherDto))] +public partial class TestJsonContext : JsonSerializerContext { } diff --git a/tests/SquidStd.Tests/Telemetry/MetricsSnapshotBridgeTests.cs b/tests/SquidStd.Tests/Telemetry/MetricsSnapshotBridgeTests.cs index 7482efe7..4e4cca5d 100644 --- a/tests/SquidStd.Tests/Telemetry/MetricsSnapshotBridgeTests.cs +++ b/tests/SquidStd.Tests/Telemetry/MetricsSnapshotBridgeTests.cs @@ -25,9 +25,9 @@ public void Bridge_ExportsSnapshotSamplesAsInstruments() using var bridge = new MetricsSnapshotBridge(metrics); using (var provider = Sdk.CreateMeterProviderBuilder() - .AddMeter(MetricsSnapshotBridge.MeterName) - .AddInMemoryExporter(exported) - .Build()) + .AddMeter(MetricsSnapshotBridge.MeterName) + .AddInMemoryExporter(exported) + .Build()) { provider.ForceFlush(); } @@ -43,8 +43,8 @@ private static double ReadValue(List metrics, string name) foreach (ref readonly var point in metric.GetMetricPoints()) { return metric.MetricType == OtelMetricType.DoubleGauge - ? point.GetGaugeLastValueDouble() - : point.GetSumDouble(); + ? point.GetGaugeLastValueDouble() + : point.GetSumDouble(); } return double.NaN; diff --git a/tests/SquidStd.Tests/Telemetry/OtlpProtocolTypeMappingTests.cs b/tests/SquidStd.Tests/Telemetry/OtlpProtocolTypeMappingTests.cs index 46293f45..fd757d99 100644 --- a/tests/SquidStd.Tests/Telemetry/OtlpProtocolTypeMappingTests.cs +++ b/tests/SquidStd.Tests/Telemetry/OtlpProtocolTypeMappingTests.cs @@ -8,13 +8,9 @@ public class OtlpProtocolTypeMappingTests { [Fact] public void Grpc_MapsToGrpc() - { - Assert.Equal(OtlpExportProtocol.Grpc, TelemetryPipeline.Map(OtlpProtocolType.Grpc)); - } + => Assert.Equal(OtlpExportProtocol.Grpc, TelemetryPipeline.Map(OtlpProtocolType.Grpc)); [Fact] public void HttpProtobuf_MapsToHttpProtobuf() - { - Assert.Equal(OtlpExportProtocol.HttpProtobuf, TelemetryPipeline.Map(OtlpProtocolType.HttpProtobuf)); - } + => Assert.Equal(OtlpExportProtocol.HttpProtobuf, TelemetryPipeline.Map(OtlpProtocolType.HttpProtobuf)); } diff --git a/tests/SquidStd.Tests/Telemetry/Support/FakeMetricsCollectionService.cs b/tests/SquidStd.Tests/Telemetry/Support/FakeMetricsCollectionService.cs index 837837a6..8c3d769a 100644 --- a/tests/SquidStd.Tests/Telemetry/Support/FakeMetricsCollectionService.cs +++ b/tests/SquidStd.Tests/Telemetry/Support/FakeMetricsCollectionService.cs @@ -10,21 +10,15 @@ public sealed class FakeMetricsCollectionService : IMetricsCollectionService public FakeMetricsCollectionService(IReadOnlyDictionary metrics) { - _snapshot = new MetricsSnapshot(DateTimeOffset.UnixEpoch, metrics); + _snapshot = new(DateTimeOffset.UnixEpoch, metrics); } public IReadOnlyDictionary GetAllMetrics() - { - return _snapshot.Metrics; - } + => _snapshot.Metrics; public MetricsSnapshot GetSnapshot() - { - return _snapshot; - } + => _snapshot; public MetricsSnapshot GetStatus() - { - return _snapshot; - } + => _snapshot; } diff --git a/tests/SquidStd.Tests/Telemetry/TelemetryRegistrationTests.cs b/tests/SquidStd.Tests/Telemetry/TelemetryRegistrationTests.cs index e91befc5..f0219a1c 100644 --- a/tests/SquidStd.Tests/Telemetry/TelemetryRegistrationTests.cs +++ b/tests/SquidStd.Tests/Telemetry/TelemetryRegistrationTests.cs @@ -5,7 +5,6 @@ using SquidStd.Abstractions.Interfaces.Services; using SquidStd.Core.Data.Metrics; using SquidStd.Core.Interfaces.Metrics; -using SquidStd.Telemetry.Abstractions.Data.Config; using SquidStd.Telemetry.OpenTelemetry.Extensions; using SquidStd.Telemetry.OpenTelemetry.Services; using SquidStd.Tests.Telemetry.Support; @@ -22,7 +21,7 @@ public async Task Container_RegistersTelemetryServiceAndStartsCleanly() new FakeMetricsCollectionService(new Dictionary()) ); - container.AddSquidStdTelemetry(new TelemetryOptions { EnableConsoleExporter = false }); + container.AddSquidStdTelemetry(new() { EnableConsoleExporter = false }); var service = container.Resolve(); Assert.IsAssignableFrom(service); @@ -39,7 +38,7 @@ public void ServiceCollection_RegistersTracerAndMeterProviders() new FakeMetricsCollectionService(new Dictionary()) ); - services.AddSquidStdTelemetry(new TelemetryOptions()); + services.AddSquidStdTelemetry(new()); using var provider = services.BuildServiceProvider(); diff --git a/tests/SquidStd.Tests/Telemetry/TracingTests.cs b/tests/SquidStd.Tests/Telemetry/TracingTests.cs index f95d2e7f..1bbfcab0 100644 --- a/tests/SquidStd.Tests/Telemetry/TracingTests.cs +++ b/tests/SquidStd.Tests/Telemetry/TracingTests.cs @@ -17,7 +17,7 @@ public void Pipeline_ExportsSpans() var exported = new List(); using var source = new ActivitySource(sourceName); - using (var provider = BuildProvider(new TelemetryOptions { ServiceName = "test-svc" }, sourceName, exported)) + using (var provider = BuildProvider(new() { ServiceName = "test-svc" }, sourceName, exported)) { using (var activity = source.StartActivity("do-work")) { @@ -38,11 +38,9 @@ public void Pipeline_WithZeroSampling_RecordsNothing() var exported = new List(); using var source = new ActivitySource(sourceName); - using (var provider = BuildProvider(new TelemetryOptions { TracingSampleRatio = 0.0 }, sourceName, exported)) + using (var provider = BuildProvider(new() { TracingSampleRatio = 0.0 }, sourceName, exported)) { - using (source.StartActivity("dropped")) - { - } + using (source.StartActivity("dropped")) { } provider.ForceFlush(); } diff --git a/tests/SquidStd.Tests/Templating/ScribanTemplateRendererTests.cs b/tests/SquidStd.Tests/Templating/ScribanTemplateRendererTests.cs index edf0eb31..be52fb88 100644 --- a/tests/SquidStd.Tests/Templating/ScribanTemplateRendererTests.cs +++ b/tests/SquidStd.Tests/Templating/ScribanTemplateRendererTests.cs @@ -1,4 +1,3 @@ -using SquidStd.Core.Directories; using SquidStd.Templating; using SquidStd.Templating.Services; using SquidStd.Tests.Support; @@ -83,7 +82,5 @@ public async Task StartAsync_AutoLoadsTemplatesFromDirectory() } private static ScribanTemplateRenderer NewRenderer(string root) - { - return new ScribanTemplateRenderer(new DirectoriesConfig(root, [])); - } + => new(new(root, [])); } diff --git a/tests/SquidStd.Tests/Tui/Binding/ViewBinderAutoBindTests.cs b/tests/SquidStd.Tests/Tui/Binding/ViewBinderAutoBindTests.cs index 220936cf..3e612338 100644 --- a/tests/SquidStd.Tests/Tui/Binding/ViewBinderAutoBindTests.cs +++ b/tests/SquidStd.Tests/Tui/Binding/ViewBinderAutoBindTests.cs @@ -8,31 +8,6 @@ namespace SquidStd.Tests.Tui.Binding; public partial class ViewBinderAutoBindTests { - private sealed partial class AutoBindViewModel : ObservableObject - { - [ObservableProperty] - private string _title = string.Empty; - - [ObservableProperty] - private string _name = string.Empty; - - // Wrong type on purpose — used by the "wrong type" skip-path test. - public int Count { get; } = 42; - - private bool _canSave; - - [RelayCommand(CanExecute = nameof(CanSave))] - private void Save() { } - - private bool CanSave() => _canSave; - - public void SetCanSave(bool value) - { - _canSave = value; - SaveCommand.NotifyCanExecuteChanged(); - } - } - // ------------------------------------------------------------------- // Label one-way // ------------------------------------------------------------------- @@ -161,4 +136,28 @@ public void AutoBind_WrongPropertyType_DoesNotThrow() Assert.Null(ex); Assert.Equal(string.Empty, label.Text); // left untouched } + + private sealed partial class AutoBindViewModel : ObservableObject + { + [ObservableProperty] private string _title = string.Empty; + + [ObservableProperty] private string _name = string.Empty; + + private bool _canSave; + + // Wrong type on purpose — used by the "wrong type" skip-path test. + public int Count { get; } = 42; + + [RelayCommand(CanExecute = nameof(CanSave))] + private void Save() { } + + private bool CanSave() + => _canSave; + + public void SetCanSave(bool value) + { + _canSave = value; + SaveCommand.NotifyCanExecuteChanged(); + } + } } diff --git a/tests/SquidStd.Tests/Tui/Binding/ViewBinderCommandTests.cs b/tests/SquidStd.Tests/Tui/Binding/ViewBinderCommandTests.cs index 14101e56..b3567f5c 100644 --- a/tests/SquidStd.Tests/Tui/Binding/ViewBinderCommandTests.cs +++ b/tests/SquidStd.Tests/Tui/Binding/ViewBinderCommandTests.cs @@ -10,6 +10,7 @@ public void Command_ExecutesTrigger_AndReflectsCanExecute() { var executed = 0; var canRun = false; + // ReSharper disable once AccessToModifiedClosure var command = new RelayCommand(() => executed++, () => canRun); var enabled = true; @@ -18,13 +19,13 @@ public void Command_ExecutesTrigger_AndReflectsCanExecute() binder.Command(command, isEnabled => enabled = isEnabled, cb => trigger = cb); - Assert.False(enabled); // initial CanExecute == false -> disabled + Assert.False(enabled); // initial CanExecute == false -> disabled canRun = true; command.NotifyCanExecuteChanged(); - Assert.True(enabled); // CanExecuteChanged -> enabled + Assert.True(enabled); // CanExecuteChanged -> enabled - trigger!(); // user activates the control + trigger!(); // user activates the control Assert.Equal(1, executed); } diff --git a/tests/SquidStd.Tests/Tui/Binding/ViewBinderOneWayTests.cs b/tests/SquidStd.Tests/Tui/Binding/ViewBinderOneWayTests.cs index 9a831f62..826b6df5 100644 --- a/tests/SquidStd.Tests/Tui/Binding/ViewBinderOneWayTests.cs +++ b/tests/SquidStd.Tests/Tui/Binding/ViewBinderOneWayTests.cs @@ -5,23 +5,6 @@ namespace SquidStd.Tests.Tui.Binding; public class ViewBinderOneWayTests { - private sealed class FakeViewModel : INotifyPropertyChanged - { - private string _title = string.Empty; - - public string Title - { - get { return _title; } - set - { - _title = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title))); - } - } - - public event PropertyChangedEventHandler? PropertyChanged; - } - [Fact] public void OneWay_AppliesInitialValueAndUpdates() { @@ -56,11 +39,34 @@ public void OneWay_UsesMarshal() { var vm = new FakeViewModel(); var marshalled = 0; - var binder = new ViewBinder(action => { marshalled++; action(); }); + var binder = new ViewBinder( + action => + { + marshalled++; + action(); + } + ); binder.OneWay(vm, nameof(FakeViewModel.Title), () => { }); vm.Title = "x"; Assert.Equal(1, marshalled); // change marshalled once; the initial apply is NOT marshalled } + + private sealed class FakeViewModel : INotifyPropertyChanged + { + private string _title = string.Empty; + + public string Title + { + get => _title; + set + { + _title = value; + PropertyChanged?.Invoke(this, new(nameof(Title))); + } + } + + public event PropertyChangedEventHandler? PropertyChanged; + } } diff --git a/tests/SquidStd.Tests/Tui/Binding/ViewBinderTwoWayTests.cs b/tests/SquidStd.Tests/Tui/Binding/ViewBinderTwoWayTests.cs index 586cff1d..fe354b62 100644 --- a/tests/SquidStd.Tests/Tui/Binding/ViewBinderTwoWayTests.cs +++ b/tests/SquidStd.Tests/Tui/Binding/ViewBinderTwoWayTests.cs @@ -5,47 +5,6 @@ namespace SquidStd.Tests.Tui.Binding; public class ViewBinderTwoWayTests { - private sealed class FakeViewModel : INotifyPropertyChanged - { - private string _name = string.Empty; - - public string Name - { - get { return _name; } - set - { - if (string.Equals(_name, value, StringComparison.Ordinal)) - { - return; - } - - _name = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name))); - } - } - - public event PropertyChangedEventHandler? PropertyChanged; - } - - private sealed class FakeField - { - private string _text = string.Empty; - - public string Text - { - get { return _text; } - set { _text = value; } - } - - public event Action? Changed; - - public void UserTypes(string value) - { - _text = value; - Changed?.Invoke(); - } - } - [Fact] public void TwoWay_PropagatesBothDirections_WithoutLooping() { @@ -54,10 +13,11 @@ public void TwoWay_PropagatesBothDirections_WithoutLooping() var binder = new ViewBinder(); binder.TwoWay( - vm, nameof(FakeViewModel.Name), - applyToTarget: () => field.Text = vm.Name, - subscribeTargetChanged: cb => field.Changed += () => cb(), - writeToSource: () => vm.Name = field.Text + vm, + nameof(FakeViewModel.Name), + () => field.Text = vm.Name, + cb => field.Changed += () => cb(), + () => vm.Name = field.Text ); Assert.Equal("init", field.Text); @@ -84,4 +44,39 @@ public void TwoWay_Typed_BindsViaExpressions() field.UserTypes("c"); Assert.Equal("c", vm.Name); } + + private sealed class FakeViewModel : INotifyPropertyChanged + { + private string _name = string.Empty; + + public string Name + { + get => _name; + set + { + if (string.Equals(_name, value, StringComparison.Ordinal)) + { + return; + } + + _name = value; + PropertyChanged?.Invoke(this, new(nameof(Name))); + } + } + + public event PropertyChangedEventHandler? PropertyChanged; + } + + private sealed class FakeField + { + public string Text { get; set; } = string.Empty; + + public void UserTypes(string value) + { + Text = value; + Changed?.Invoke(); + } + + public event Action? Changed; + } } diff --git a/tests/SquidStd.Tests/Tui/Dsl/TuiNodeMaterializerTests.cs b/tests/SquidStd.Tests/Tui/Dsl/TuiNodeMaterializerTests.cs index 72f367cc..bfa9fb41 100644 --- a/tests/SquidStd.Tests/Tui/Dsl/TuiNodeMaterializerTests.cs +++ b/tests/SquidStd.Tests/Tui/Dsl/TuiNodeMaterializerTests.cs @@ -7,15 +7,6 @@ namespace SquidStd.Tests.Tui.Dsl; public partial class TuiNodeMaterializerTests { - private sealed partial class SampleViewModel : ObservableObject - { - [ObservableProperty] - private string _title = "start"; - - [ObservableProperty] - private string _name = string.Empty; - } - [Fact] public void Materialize_VStack_ProducesChildrenAndAppliesOneWay() { @@ -46,4 +37,11 @@ public void Materialize_TextField_TwoWay_WritesBackToViewModel() vm.Name = "from-vm"; Assert.Equal("from-vm", field.Text); } + + private sealed partial class SampleViewModel : ObservableObject + { + [ObservableProperty] private string _title = "start"; + + [ObservableProperty] private string _name = string.Empty; + } } diff --git a/tests/SquidStd.Tests/Tui/Dsl/TuiNodeTests.cs b/tests/SquidStd.Tests/Tui/Dsl/TuiNodeTests.cs index 72ea2eba..135b3747 100644 --- a/tests/SquidStd.Tests/Tui/Dsl/TuiNodeTests.cs +++ b/tests/SquidStd.Tests/Tui/Dsl/TuiNodeTests.cs @@ -8,12 +8,6 @@ namespace SquidStd.Tests.Tui.Dsl; public class TuiNodeTests { - private sealed class SampleViewModel - { - public string Title { get; set; } = string.Empty; - public ICommand Save { get; } = new RelayCommand(() => { }); - } - [Fact] public void LabelNode_CapturesTextExpression() { @@ -50,4 +44,10 @@ public void StackNode_HoldsOrientationAndChildren() Assert.Single(node.Children); Assert.Same(child, node.Children[0]); } + + private sealed class SampleViewModel + { + public string Title { get; } = string.Empty; + public ICommand Save { get; } = new RelayCommand(() => { }); + } } diff --git a/tests/SquidStd.Tests/Tui/Dsl/UiFactoryTests.cs b/tests/SquidStd.Tests/Tui/Dsl/UiFactoryTests.cs index 7d897068..d4d11bb9 100644 --- a/tests/SquidStd.Tests/Tui/Dsl/UiFactoryTests.cs +++ b/tests/SquidStd.Tests/Tui/Dsl/UiFactoryTests.cs @@ -8,13 +8,6 @@ namespace SquidStd.Tests.Tui.Dsl; public class UiFactoryTests { - private sealed class SampleViewModel - { - public string Title { get; set; } = string.Empty; - public string Name { get; set; } = string.Empty; - public ICommand Save { get; } = new RelayCommand(() => { }); - } - private readonly UiFactory _ui = new(); [Fact] @@ -51,4 +44,11 @@ public void VStack_And_HStack_SetOrientationAndChildren() Assert.Equal(StackOrientation.Horizontal, h.Orientation); Assert.Single(h.Children); } + + private sealed class SampleViewModel + { + public string Title { get; } = string.Empty; + public string Name { get; } = string.Empty; + public ICommand Save { get; } = new RelayCommand(() => { }); + } } diff --git a/tests/SquidStd.Tests/Tui/Extensions/RegisterTuiExtensionsTests.cs b/tests/SquidStd.Tests/Tui/Extensions/RegisterTuiExtensionsTests.cs index 8aefa735..94cf84b6 100644 --- a/tests/SquidStd.Tests/Tui/Extensions/RegisterTuiExtensionsTests.cs +++ b/tests/SquidStd.Tests/Tui/Extensions/RegisterTuiExtensionsTests.cs @@ -9,37 +9,6 @@ namespace SquidStd.Tests.Tui.Extensions; public class RegisterTuiExtensionsTests { - private sealed class HomeViewModel : TuiViewModel - { - } - - private sealed class HomeView : ITuiView - { - public void Bind(object viewModel) - { - } - - public void Initialize() - { - } - } - - // Real views derive from Window (IDisposable); this fake reproduces that shape. - private sealed class DisposableView : ITuiView, IDisposable - { - public void Bind(object viewModel) - { - } - - public void Initialize() - { - } - - public void Dispose() - { - } - } - [Fact] public void RegisterTui_RegistersNavigatorAndRegistry() { @@ -78,4 +47,23 @@ public void RegisterView_AllowsDisposableTransientView() Assert.NotNull(container.Resolve()); } + + private sealed class HomeViewModel : TuiViewModel { } + + private sealed class HomeView : ITuiView + { + public void Bind(object viewModel) { } + + public void Initialize() { } + } + + // Real views derive from Window (IDisposable); this fake reproduces that shape. + private sealed class DisposableView : ITuiView, IDisposable + { + public void Bind(object viewModel) { } + + public void Initialize() { } + + public void Dispose() { } + } } diff --git a/tests/SquidStd.Tests/Tui/Internal/ConventionNamesTests.cs b/tests/SquidStd.Tests/Tui/Internal/ConventionNamesTests.cs index 3d23f76d..f92b031a 100644 --- a/tests/SquidStd.Tests/Tui/Internal/ConventionNamesTests.cs +++ b/tests/SquidStd.Tests/Tui/Internal/ConventionNamesTests.cs @@ -4,19 +4,12 @@ namespace SquidStd.Tests.Tui.Internal; public class ConventionNamesTests { - [Theory] - [InlineData("NameField", "Name")] - [InlineData("TitleLabel", "Title")] - [InlineData("SaveButton", "Save")] - [InlineData("Name", "Name")] + [Theory, InlineData("NameField", "Name"), InlineData("TitleLabel", "Title"), InlineData("SaveButton", "Save"), + InlineData("Name", "Name")] public void MemberName_StripsKnownWidgetSuffixes(string widgetId, string expected) - { - Assert.Equal(expected, ConventionNames.MemberName(widgetId)); - } + => Assert.Equal(expected, ConventionNames.MemberName(widgetId)); [Fact] public void CommandName_AppendsCommandSuffix() - { - Assert.Equal("SaveCommand", ConventionNames.CommandName("SaveButton")); - } + => Assert.Equal("SaveCommand", ConventionNames.CommandName("SaveButton")); } diff --git a/tests/SquidStd.Tests/Tui/Internal/PropertyPathTests.cs b/tests/SquidStd.Tests/Tui/Internal/PropertyPathTests.cs index d1411c99..452caf45 100644 --- a/tests/SquidStd.Tests/Tui/Internal/PropertyPathTests.cs +++ b/tests/SquidStd.Tests/Tui/Internal/PropertyPathTests.cs @@ -4,23 +4,13 @@ namespace SquidStd.Tests.Tui.Internal; public class PropertyPathTests { - private sealed class Sample - { - public string Name { get; set; } = string.Empty; - public int Count; - } - [Fact] public void NameOf_Property_ReturnsName() - { - Assert.Equal("Name", PropertyPath.NameOf(s => s.Name)); - } + => Assert.Equal("Name", PropertyPath.NameOf(s => s.Name)); [Fact] public void NameOf_Field_ReturnsName() - { - Assert.Equal("Count", PropertyPath.NameOf(s => s.Count)); - } + => Assert.Equal("Count", PropertyPath.NameOf(s => s.Count)); [Fact] public void Setter_Property_WritesValue() @@ -35,7 +25,11 @@ public void Setter_Property_WritesValue() [Fact] public void NameOf_NonMemberExpression_Throws() + => Assert.Throws(() => PropertyPath.NameOf(s => s.Count + 1)); + + private sealed class Sample { - Assert.Throws(() => PropertyPath.NameOf(s => s.Count + 1)); + public int Count; + public string Name { get; set; } = string.Empty; } } diff --git a/tests/SquidStd.Tests/Tui/Navigation/TuiNavigatorTests.cs b/tests/SquidStd.Tests/Tui/Navigation/TuiNavigatorTests.cs index aeb072f9..6f117c5d 100644 --- a/tests/SquidStd.Tests/Tui/Navigation/TuiNavigatorTests.cs +++ b/tests/SquidStd.Tests/Tui/Navigation/TuiNavigatorTests.cs @@ -8,47 +8,6 @@ namespace SquidStd.Tests.Tui.Navigation; public class TuiNavigatorTests { - private sealed class HomeViewModel : TuiViewModel - { - } - - private sealed class DetailViewModel : TuiViewModel - { - } - - // Non-generic fake view that records the ViewModel it was given and that it was initialised. - private sealed class FakeView : ITuiView - { - public object? BoundViewModel { get; private set; } - public bool Initialized { get; private set; } - - public void Bind(object viewModel) - { - BoundViewModel = viewModel; - } - - public void Initialize() - { - Initialized = true; - } - } - - private sealed class FakeViewHost : ITuiViewHost - { - public List Shown { get; } = new(); - public List Removed { get; } = new(); - - public void Show(object view) - { - Shown.Add(view); - } - - public void Remove(object view) - { - Removed.Add(view); - } - } - private static (TuiNavigator Navigator, FakeViewHost Host) Build() { var container = new Container(); @@ -107,6 +66,66 @@ public async Task Back_OnLastScreen_DoesNothing() Assert.Equal(1, navigator.Depth); // refuses to pop the root } + [Fact] + public async Task ForwardThenBack_PairsActivationHooks_NoDoubleActivateWithoutDeactivate() + { + var container = new Container(); + container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); + container.Register(Reuse.Transient); + + var registry = new TuiViewRegistry(); + registry.Map(typeof(TrackingHomeViewModel), typeof(FakeView)); + registry.Map(typeof(TrackingDetailViewModel), typeof(FakeView)); + + var navigator = new TuiNavigator(container, registry, new FakeViewHost()); + var home = container.Resolve(); + var detail = container.Resolve(); + + await navigator.NavigateToAsync(); // home: A1 D0 + Assert.Equal(1, home.Activated); + Assert.Equal(0, home.Deactivated); + + await navigator.NavigateToAsync(); // home deactivated; detail A1 + Assert.Equal(1, home.Activated); + Assert.Equal(1, home.Deactivated); + Assert.Equal(1, detail.Activated); + + await navigator.BackAsync(); // detail D1; home reactivated + Assert.Equal(1, detail.Deactivated); + Assert.Equal(2, home.Activated); + Assert.Equal(1, home.Deactivated); // still 1 — every activate is now paired with a prior deactivate + } + + private sealed class HomeViewModel : TuiViewModel { } + + private sealed class DetailViewModel : TuiViewModel { } + + // Non-generic fake view that records the ViewModel it was given and that it was initialised. + private sealed class FakeView : ITuiView + { + public object? BoundViewModel { get; private set; } + public bool Initialized { get; private set; } + + public void Bind(object viewModel) + => BoundViewModel = viewModel; + + public void Initialize() + => Initialized = true; + } + + private sealed class FakeViewHost : ITuiViewHost + { + public List Shown { get; } = new(); + public List Removed { get; } = new(); + + public void Show(object view) + => Shown.Add(view); + + public void Remove(object view) + => Removed.Add(view); + } + private sealed class TrackingHomeViewModel : TuiViewModel { public int Activated { get; private set; } @@ -115,12 +134,14 @@ private sealed class TrackingHomeViewModel : TuiViewModel public override ValueTask OnActivatedAsync() { Activated++; + return ValueTask.CompletedTask; } public override ValueTask OnDeactivatedAsync() { Deactivated++; + return ValueTask.CompletedTask; } } @@ -133,44 +154,15 @@ private sealed class TrackingDetailViewModel : TuiViewModel public override ValueTask OnActivatedAsync() { Activated++; + return ValueTask.CompletedTask; } public override ValueTask OnDeactivatedAsync() { Deactivated++; + return ValueTask.CompletedTask; } } - - [Fact] - public async Task ForwardThenBack_PairsActivationHooks_NoDoubleActivateWithoutDeactivate() - { - var container = new Container(); - container.Register(Reuse.Singleton); - container.Register(Reuse.Singleton); - container.Register(Reuse.Transient); - - var registry = new TuiViewRegistry(); - registry.Map(typeof(TrackingHomeViewModel), typeof(FakeView)); - registry.Map(typeof(TrackingDetailViewModel), typeof(FakeView)); - - var navigator = new TuiNavigator(container, registry, new FakeViewHost()); - var home = container.Resolve(); - var detail = container.Resolve(); - - await navigator.NavigateToAsync(); // home: A1 D0 - Assert.Equal(1, home.Activated); - Assert.Equal(0, home.Deactivated); - - await navigator.NavigateToAsync(); // home deactivated; detail A1 - Assert.Equal(1, home.Activated); - Assert.Equal(1, home.Deactivated); - Assert.Equal(1, detail.Activated); - - await navigator.BackAsync(); // detail D1; home reactivated - Assert.Equal(1, detail.Deactivated); - Assert.Equal(2, home.Activated); - Assert.Equal(1, home.Deactivated); // still 1 — every activate is now paired with a prior deactivate - } } diff --git a/tests/SquidStd.Tests/Tui/TuiViewModelTests.cs b/tests/SquidStd.Tests/Tui/TuiViewModelTests.cs index 6cd048e3..28427ec9 100644 --- a/tests/SquidStd.Tests/Tui/TuiViewModelTests.cs +++ b/tests/SquidStd.Tests/Tui/TuiViewModelTests.cs @@ -5,21 +5,6 @@ namespace SquidStd.Tests.Tui; public partial class TuiViewModelTests { - private sealed partial class SampleViewModel : TuiViewModel - { - [ObservableProperty] - private string _title = string.Empty; - - public int Activated { get; private set; } - - public override ValueTask OnActivatedAsync() - { - Activated++; - - return ValueTask.CompletedTask; - } - } - [Fact] public void ObservableProperty_RaisesPropertyChanged() { @@ -49,4 +34,18 @@ public async Task OnDeactivatedAsync_DefaultsToNoOp() await vm.OnDeactivatedAsync(); // does not throw } + + private sealed partial class SampleViewModel : TuiViewModel + { + [ObservableProperty] private string _title = string.Empty; + + public int Activated { get; private set; } + + public override ValueTask OnActivatedAsync() + { + Activated++; + + return ValueTask.CompletedTask; + } + } } diff --git a/tests/SquidStd.Tests/Utils/DirectoriesUtilsTests.cs b/tests/SquidStd.Tests/Utils/DirectoriesUtilsTests.cs index 9f30bddd..2a7c61a9 100644 --- a/tests/SquidStd.Tests/Utils/DirectoriesUtilsTests.cs +++ b/tests/SquidStd.Tests/Utils/DirectoriesUtilsTests.cs @@ -33,9 +33,7 @@ public void GetFiles_NoExtensionFilter_ReturnsAllFiles() [Fact] public void GetFiles_NonExistentDirectory_ReturnsEmpty() - { - Assert.Empty(DirectoriesUtils.GetFiles(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")))); - } + => Assert.Empty(DirectoriesUtils.GetFiles(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")))); [Fact] public void GetFiles_NonRecursive_ExcludesNestedFiles() diff --git a/tests/SquidStd.Tests/Utils/HashUtilsTests.cs b/tests/SquidStd.Tests/Utils/HashUtilsTests.cs index d97a393a..be8ca6dc 100644 --- a/tests/SquidStd.Tests/Utils/HashUtilsTests.cs +++ b/tests/SquidStd.Tests/Utils/HashUtilsTests.cs @@ -4,14 +4,9 @@ namespace SquidStd.Tests.Utils; public class HashUtilsTests { - [Theory] - [InlineData("")] - [InlineData(" ")] - [InlineData(null)] + [Theory, InlineData(""), InlineData(" "), InlineData(null)] public void HashPassword_NullOrWhitespace_Throws(string? password) - { - Assert.Throws(() => HashUtils.HashPassword(password!)); - } + => Assert.Throws(() => HashUtils.HashPassword(password!)); [Fact] public void HashPassword_SamePasswordTwice_ProducesDifferentHashes() @@ -44,25 +39,15 @@ public void VerifyPassword_CorrectPassword_ReturnsTrue() Assert.True(HashUtils.VerifyPassword("s3cret", hash)); } - [Theory] - [InlineData("not-a-hash")] - [InlineData("md5$100000$c2FsdA==$aGFzaA==")] - [InlineData("pbkdf2-sha256$abc$c2FsdA==$aGFzaA==")] - [InlineData("pbkdf2-sha256$0$c2FsdA==$aGFzaA==")] - [InlineData("pbkdf2-sha256$100000$not-base64$aGFzaA==")] + [Theory, InlineData("not-a-hash"), InlineData("md5$100000$c2FsdA==$aGFzaA=="), + InlineData("pbkdf2-sha256$abc$c2FsdA==$aGFzaA=="), InlineData("pbkdf2-sha256$0$c2FsdA==$aGFzaA=="), + InlineData("pbkdf2-sha256$100000$not-base64$aGFzaA==")] public void VerifyPassword_MalformedStoredHash_ReturnsFalse(string storedHash) - { - Assert.False(HashUtils.VerifyPassword("s3cret", storedHash)); - } + => Assert.False(HashUtils.VerifyPassword("s3cret", storedHash)); - [Theory] - [InlineData("")] - [InlineData(" ")] - [InlineData(null)] + [Theory, InlineData(""), InlineData(" "), InlineData(null)] public void VerifyPassword_NullOrWhitespacePassword_ReturnsFalse(string? password) - { - Assert.False(HashUtils.VerifyPassword(password!, "pbkdf2-sha256$100000$c2FsdA==$aGFzaA==")); - } + => Assert.False(HashUtils.VerifyPassword(password!, "pbkdf2-sha256$100000$c2FsdA==$aGFzaA==")); [Fact] public void VerifyPassword_WrongPassword_ReturnsFalse() diff --git a/tests/SquidStd.Tests/Utils/NetworkUtilsTests.cs b/tests/SquidStd.Tests/Utils/NetworkUtilsTests.cs index 1c1a2a87..6d634a6c 100644 --- a/tests/SquidStd.Tests/Utils/NetworkUtilsTests.cs +++ b/tests/SquidStd.Tests/Utils/NetworkUtilsTests.cs @@ -7,9 +7,7 @@ public class NetworkUtilsTests { [Fact] public void GetListeningAddresses_NullEndpoint_Throws() - { - Assert.Throws(() => NetworkUtils.GetListeningAddresses(null!).ToList()); - } + => Assert.Throws(() => NetworkUtils.GetListeningAddresses(null!).ToList()); [Fact] public void GetListeningAddresses_ReturnsEndpointsMatchingFamilyAndPort() @@ -28,72 +26,43 @@ public void GetListeningAddresses_ReturnsEndpointsMatchingFamilyAndPort() ); } - [Theory] - [InlineData("")] - [InlineData(" ")] + [Theory, InlineData(""), InlineData(" ")] public void ParseIpAddress_NullOrWhitespace_Throws(string ipAddress) - { - Assert.Throws(() => NetworkUtils.ParseIpAddress(ipAddress)); - } + => Assert.Throws(() => NetworkUtils.ParseIpAddress(ipAddress)); [Fact] public void ParseIpAddress_ValidAddress_ReturnsParsedAddress() - { - Assert.Equal(IPAddress.Parse("127.0.0.1"), NetworkUtils.ParseIpAddress("127.0.0.1")); - } + => Assert.Equal(IPAddress.Parse("127.0.0.1"), NetworkUtils.ParseIpAddress("127.0.0.1")); [Fact] public void ParseIpAddress_Wildcard_ReturnsAny() - { - Assert.Equal(IPAddress.Any, NetworkUtils.ParseIpAddress("*")); - } + => Assert.Equal(IPAddress.Any, NetworkUtils.ParseIpAddress("*")); - [Theory] - [InlineData("99999")] - [InlineData("-1")] - [InlineData("abc")] + [Theory, InlineData("99999"), InlineData("-1"), InlineData("abc")] public void ParsePorts_InvalidPort_ThrowsFormatException(string ports) - { - Assert.Throws(() => NetworkUtils.ParsePorts(ports)); - } + => Assert.Throws(() => NetworkUtils.ParsePorts(ports)); - [Theory] - [InlineData("8000-7000")] - [InlineData("1-2-3")] + [Theory, InlineData("8000-7000"), InlineData("1-2-3")] public void ParsePorts_InvalidRange_ThrowsFormatException(string ports) - { - Assert.Throws(() => NetworkUtils.ParsePorts(ports)); - } + => Assert.Throws(() => NetworkUtils.ParsePorts(ports)); [Fact] public void ParsePorts_MixedRangeAndList_ReturnsAllPorts() - { - Assert.Equal([6666, 6667, 6668, 6669, 8000], NetworkUtils.ParsePorts("6666-6668,6669,8000")); - } + => Assert.Equal([6666, 6667, 6668, 6669, 8000], NetworkUtils.ParsePorts("6666-6668,6669,8000")); - [Theory] - [InlineData("")] - [InlineData(" ")] + [Theory, InlineData(""), InlineData(" ")] public void ParsePorts_NullOrWhitespace_ThrowsArgumentException(string ports) - { - Assert.Throws(() => NetworkUtils.ParsePorts(ports)); - } + => Assert.Throws(() => NetworkUtils.ParsePorts(ports)); [Fact] public void ParsePorts_Range_ReturnsExpandedRange() - { - Assert.Equal([6666, 6667, 6668], NetworkUtils.ParsePorts("6666-6668")); - } + => Assert.Equal([6666, 6667, 6668], NetworkUtils.ParsePorts("6666-6668")); [Fact] public void ParsePorts_SinglePort_ReturnsSingleEntry() - { - Assert.Equal([8000], NetworkUtils.ParsePorts("8000")); - } + => Assert.Equal([8000], NetworkUtils.ParsePorts("8000")); [Fact] public void ParsePorts_TrimsWhitespaceEntries() - { - Assert.Equal([80, 443], NetworkUtils.ParsePorts(" 80 , 443 ")); - } + => Assert.Equal([80, 443], NetworkUtils.ParsePorts(" 80 , 443 ")); } diff --git a/tests/SquidStd.Tests/Utils/PlatformUtilsTests.cs b/tests/SquidStd.Tests/Utils/PlatformUtilsTests.cs index 874e6bab..01e1512e 100644 --- a/tests/SquidStd.Tests/Utils/PlatformUtilsTests.cs +++ b/tests/SquidStd.Tests/Utils/PlatformUtilsTests.cs @@ -9,27 +9,21 @@ public class PlatformUtilsTests public void GetCurrentPlatform_MatchesOperatingSystemDetection() { var expected = OperatingSystem.IsWindows() ? PlatformType.Windows : - OperatingSystem.IsMacOS() ? PlatformType.MacOS : - OperatingSystem.IsLinux() ? PlatformType.Linux : PlatformType.Unknown; + OperatingSystem.IsMacOS() ? PlatformType.MacOS : + OperatingSystem.IsLinux() ? PlatformType.Linux : PlatformType.Unknown; Assert.Equal(expected, PlatformUtils.GetCurrentPlatform()); } [Fact] public void IsRunningOnLinux_MatchesOperatingSystem() - { - Assert.Equal(OperatingSystem.IsLinux(), PlatformUtils.IsRunningOnLinux()); - } + => Assert.Equal(OperatingSystem.IsLinux(), PlatformUtils.IsRunningOnLinux()); [Fact] public void IsRunningOnMacOS_MatchesOperatingSystem() - { - Assert.Equal(OperatingSystem.IsMacOS(), PlatformUtils.IsRunningOnMacOS()); - } + => Assert.Equal(OperatingSystem.IsMacOS(), PlatformUtils.IsRunningOnMacOS()); [Fact] public void IsRunningOnWindows_MatchesOperatingSystem() - { - Assert.Equal(OperatingSystem.IsWindows(), PlatformUtils.IsRunningOnWindows()); - } + => Assert.Equal(OperatingSystem.IsWindows(), PlatformUtils.IsRunningOnWindows()); } diff --git a/tests/SquidStd.Tests/Utils/ResourceUtilsTests.cs b/tests/SquidStd.Tests/Utils/ResourceUtilsTests.cs index 9b23e390..641f8c32 100644 --- a/tests/SquidStd.Tests/Utils/ResourceUtilsTests.cs +++ b/tests/SquidStd.Tests/Utils/ResourceUtilsTests.cs @@ -18,9 +18,7 @@ public void ConvertResourceNameToPath_NestedName_ConvertsDotsToSeparators() [Fact] public void ConvertResourceNameToPath_NoExtension_Throws() - { - Assert.Throws(() => ResourceUtils.ConvertResourceNameToPath("Asm.file", "Asm")); - } + => Assert.Throws(() => ResourceUtils.ConvertResourceNameToPath("Asm.file", "Asm")); [Fact] public void ConvertResourceNameToPath_ValidName_ReturnsFilePath() @@ -32,15 +30,11 @@ public void ConvertResourceNameToPath_ValidName_ReturnsFilePath() [Fact] public void ConvertResourceNameToPath_WrongNamespace_Throws() - { - Assert.Throws(() => ResourceUtils.ConvertResourceNameToPath("Other.cfg.json", "Asm")); - } + => Assert.Throws(() => ResourceUtils.ConvertResourceNameToPath("Other.cfg.json", "Asm")); [Fact] public void EmbeddedNameToPath_StripsPrefixAndConvertsDots() - { - Assert.Equal("Folder/file/txt", ResourceUtils.EmbeddedNameToPath("Asm.Folder.file.txt", "Asm")); - } + => Assert.Equal("Folder/file/txt", ResourceUtils.EmbeddedNameToPath("Asm.Folder.file.txt", "Asm")); [Fact] public void GetDirectoryPathFromResourceName_RemovesBaseNamespace() @@ -68,11 +62,10 @@ public void GetEmbeddedResourceNames_NoFilter_IncludesSampleResource() [Fact] public void GetEmbeddedResourceStream_MissingResource_Throws() - { - Assert.Throws(() => - ResourceUtils.GetEmbeddedResourceStream(TestAssembly, "does-not-exist.bin") + => Assert.Throws( + () => + ResourceUtils.GetEmbeddedResourceStream(TestAssembly, "does-not-exist.bin") ); - } [Fact] public void GetEmbeddedResourceString_ExistingResource_ReturnsContent() @@ -84,18 +77,11 @@ public void GetEmbeddedResourceString_ExistingResource_ReturnsContent() [Fact] public void GetFileNameFromResourceName_ReturnsFileNameWithExtension() - { - Assert.Equal("DefaultUiFont.ttf", ResourceUtils.GetFileNameFromResourceName("Assets.Fonts.DefaultUiFont.ttf")); - } + => Assert.Equal("DefaultUiFont.ttf", ResourceUtils.GetFileNameFromResourceName("Assets.Fonts.DefaultUiFont.ttf")); - [Theory] - [InlineData("a/b/c.txt", "c.txt")] - [InlineData("a\\b\\c.txt", "c.txt")] - [InlineData("c.txt", "c.txt")] + [Theory, InlineData("a/b/c.txt", "c.txt"), InlineData("a\\b\\c.txt", "c.txt"), InlineData("c.txt", "c.txt")] public void GetFileNameFromResourcePath_ReturnsFinalSegment(string input, string expected) - { - Assert.Equal(expected, ResourceUtils.GetFileNameFromResourcePath(input)); - } + => Assert.Equal(expected, ResourceUtils.GetFileNameFromResourcePath(input)); [Fact] public void ReadEmbeddedResource_ExistingResource_ReturnsContent() @@ -108,8 +94,7 @@ public void ReadEmbeddedResource_ExistingResource_ReturnsContent() [Fact] public void ReadEmbeddedResource_MissingResource_Throws() - { - Assert.Throws(() => ResourceUtils.ReadEmbeddedResource("does-not-exist.bin", TestAssembly) + => Assert.Throws( + () => ResourceUtils.ReadEmbeddedResource("does-not-exist.bin", TestAssembly) ); - } } diff --git a/tests/SquidStd.Tests/Utils/StringUtilsTests.cs b/tests/SquidStd.Tests/Utils/StringUtilsTests.cs index 950798f8..c2850852 100644 --- a/tests/SquidStd.Tests/Utils/StringUtilsTests.cs +++ b/tests/SquidStd.Tests/Utils/StringUtilsTests.cs @@ -4,118 +4,65 @@ namespace SquidStd.Tests.Utils; public class StringUtilsTests { - [Theory] - [InlineData("")] - [InlineData(null)] + [Theory, InlineData(""), InlineData(null)] public void ToCamelCase_NullOrEmpty_ReturnsEmpty(string? input) - { - Assert.Equal("", StringUtils.ToCamelCase(input!)); - } + => Assert.Equal("", StringUtils.ToCamelCase(input!)); [Fact] public void ToCamelCase_SingleCharacter_ReturnsLowerCase() - { - Assert.Equal("a", StringUtils.ToCamelCase("A")); - } + => Assert.Equal("a", StringUtils.ToCamelCase("A")); - [Theory] - [InlineData("HelloWorld", "helloWorld")] - [InlineData("API_RESPONSE", "apiResponse")] - [InlineData("user-id", "userId")] - [InlineData("hello world", "helloWorld")] + [Theory, InlineData("HelloWorld", "helloWorld"), InlineData("API_RESPONSE", "apiResponse"), + InlineData("user-id", "userId"), InlineData("hello world", "helloWorld")] public void ToCamelCase_VariousInputs_ReturnsCamelCase(string input, string expected) - { - Assert.Equal(expected, StringUtils.ToCamelCase(input)); - } + => Assert.Equal(expected, StringUtils.ToCamelCase(input)); - [Theory] - [InlineData("HelloWorld", "hello.world")] - [InlineData("API_RESPONSE", "api.response")] + [Theory, InlineData("HelloWorld", "hello.world"), InlineData("API_RESPONSE", "api.response")] public void ToDotCase_VariousInputs_ReturnsDotCase(string input, string expected) - { - Assert.Equal(expected, StringUtils.ToDotCase(input)); - } + => Assert.Equal(expected, StringUtils.ToDotCase(input)); - [Theory] - [InlineData("HelloWorld", "hello-world")] - [InlineData("API_RESPONSE", "api-response")] - [InlineData("userId", "user-id")] + [Theory, InlineData("HelloWorld", "hello-world"), InlineData("API_RESPONSE", "api-response"), + InlineData("userId", "user-id")] public void ToKebabCase_VariousInputs_ReturnsKebabCase(string input, string expected) - { - Assert.Equal(expected, StringUtils.ToKebabCase(input)); - } + => Assert.Equal(expected, StringUtils.ToKebabCase(input)); [Fact] public void ToPascalCase_SingleCharacter_ReturnsUpperCase() - { - Assert.Equal("A", StringUtils.ToPascalCase("a")); - } + => Assert.Equal("A", StringUtils.ToPascalCase("a")); - [Theory] - [InlineData("hello_world", "HelloWorld")] - [InlineData("api-response", "ApiResponse")] - [InlineData("userId", "UserId")] + [Theory, InlineData("hello_world", "HelloWorld"), InlineData("api-response", "ApiResponse"), + InlineData("userId", "UserId")] public void ToPascalCase_VariousInputs_ReturnsPascalCase(string input, string expected) - { - Assert.Equal(expected, StringUtils.ToPascalCase(input)); - } + => Assert.Equal(expected, StringUtils.ToPascalCase(input)); - [Theory] - [InlineData("HelloWorld", "hello/world")] - [InlineData("API_RESPONSE", "api/response")] + [Theory, InlineData("HelloWorld", "hello/world"), InlineData("API_RESPONSE", "api/response")] public void ToPathCase_VariousInputs_ReturnsPathCase(string input, string expected) - { - Assert.Equal(expected, StringUtils.ToPathCase(input)); - } + => Assert.Equal(expected, StringUtils.ToPathCase(input)); - [Theory] - [InlineData("hello world", "Hello world")] - [InlineData("API_RESPONSE", "Api response")] + [Theory, InlineData("hello world", "Hello world"), InlineData("API_RESPONSE", "Api response")] public void ToSentenceCase_VariousInputs_ReturnsSentenceCase(string input, string expected) - { - Assert.Equal(expected, StringUtils.ToSentenceCase(input)); - } + => Assert.Equal(expected, StringUtils.ToSentenceCase(input)); - [Theory] - [InlineData("")] - [InlineData(null)] + [Theory, InlineData(""), InlineData(null)] public void ToSnakeCase_NullOrEmpty_ReturnsEmpty(string? input) - { - Assert.Equal("", StringUtils.ToSnakeCase(input!)); - } + => Assert.Equal("", StringUtils.ToSnakeCase(input!)); - [Theory] - [InlineData("HelloWorld", "hello_world")] - [InlineData("APIResponse", "api_response")] - [InlineData("userId", "user_id")] + [Theory, InlineData("HelloWorld", "hello_world"), InlineData("APIResponse", "api_response"), + InlineData("userId", "user_id")] public void ToSnakeCase_VariousInputs_ReturnsSnakeCase(string input, string expected) - { - Assert.Equal(expected, StringUtils.ToSnakeCase(input)); - } + => Assert.Equal(expected, StringUtils.ToSnakeCase(input)); - [Theory] - [InlineData("hello_world", "Hello World")] - [InlineData("API_RESPONSE", "Api Response")] - [InlineData("user-id", "User Id")] + [Theory, InlineData("hello_world", "Hello World"), InlineData("API_RESPONSE", "Api Response"), + InlineData("user-id", "User Id")] public void ToTitleCase_VariousInputs_ReturnsTitleCase(string input, string expected) - { - Assert.Equal(expected, StringUtils.ToTitleCase(input)); - } + => Assert.Equal(expected, StringUtils.ToTitleCase(input)); - [Theory] - [InlineData("hello_world", "Hello-World")] - [InlineData("apiResponse", "Api-Response")] + [Theory, InlineData("hello_world", "Hello-World"), InlineData("apiResponse", "Api-Response")] public void ToTrainCase_VariousInputs_ReturnsTrainCase(string input, string expected) - { - Assert.Equal(expected, StringUtils.ToTrainCase(input)); - } + => Assert.Equal(expected, StringUtils.ToTrainCase(input)); - [Theory] - [InlineData("HelloWorld", "HELLO_WORLD")] - [InlineData("apiResponse", "API_RESPONSE")] - [InlineData("user-id", "USER_ID")] + [Theory, InlineData("HelloWorld", "HELLO_WORLD"), InlineData("apiResponse", "API_RESPONSE"), + InlineData("user-id", "USER_ID")] public void ToUpperSnakeCase_VariousInputs_ReturnsScreamingSnakeCase(string input, string expected) - { - Assert.Equal(expected, StringUtils.ToUpperSnakeCase(input)); - } + => Assert.Equal(expected, StringUtils.ToUpperSnakeCase(input)); } diff --git a/tests/SquidStd.Tests/Utils/VersionUtilsTests.cs b/tests/SquidStd.Tests/Utils/VersionUtilsTests.cs index aff8ef90..5347ceb4 100644 --- a/tests/SquidStd.Tests/Utils/VersionUtilsTests.cs +++ b/tests/SquidStd.Tests/Utils/VersionUtilsTests.cs @@ -24,7 +24,5 @@ public void GetVersion_ExplicitAssembly_ReturnsNonEmptyVersion() [Fact] public void GetVersion_NullAssembly_Throws() - { - Assert.Throws(() => VersionUtils.GetVersion(null!)); - } + => Assert.Throws(() => VersionUtils.GetVersion(null!)); } diff --git a/tests/SquidStd.Tests/Vfs/InMemoryFileSystemTests.cs b/tests/SquidStd.Tests/Vfs/InMemoryFileSystemTests.cs index 8a2847b0..08fa9e4a 100644 --- a/tests/SquidStd.Tests/Vfs/InMemoryFileSystemTests.cs +++ b/tests/SquidStd.Tests/Vfs/InMemoryFileSystemTests.cs @@ -15,6 +15,7 @@ public async Task Write_Read_List_Delete_RoundTrips() Assert.Equal("x", Encoding.UTF8.GetString((await fs.ReadAllBytesAsync("a/b.txt"))!)); var paths = new List(); + await foreach (var e in fs.ListAsync("a")) { paths.Add(e.Path); diff --git a/tests/SquidStd.Tests/Vfs/PhysicalFileSystemTests.cs b/tests/SquidStd.Tests/Vfs/PhysicalFileSystemTests.cs index f3efa01e..cee9224a 100644 --- a/tests/SquidStd.Tests/Vfs/PhysicalFileSystemTests.cs +++ b/tests/SquidStd.Tests/Vfs/PhysicalFileSystemTests.cs @@ -19,6 +19,7 @@ public async Task Write_Read_List_Delete_RoundTrips() Assert.Equal("hello", Encoding.UTF8.GetString((await fs.ReadAllBytesAsync("docs/cv.pdf"))!)); var entries = new List(); + await foreach (var e in fs.ListAsync()) { entries.Add(e.Path); @@ -35,7 +36,7 @@ public async Task Write_Read_List_Delete_RoundTrips() { if (Directory.Exists(root)) { - Directory.Delete(root, recursive: true); + Directory.Delete(root, true); } } } diff --git a/tests/SquidStd.Tests/Vfs/VfsPathTests.cs b/tests/SquidStd.Tests/Vfs/VfsPathTests.cs index 903666fd..35fb995e 100644 --- a/tests/SquidStd.Tests/Vfs/VfsPathTests.cs +++ b/tests/SquidStd.Tests/Vfs/VfsPathTests.cs @@ -4,20 +4,12 @@ namespace SquidStd.Tests.Vfs; public class VfsPathTests { - [Theory] - [InlineData("docs/cv.pdf", "docs/cv.pdf")] - [InlineData("/docs//cv.pdf", "docs/cv.pdf")] - [InlineData("docs\\cv.pdf", "docs/cv.pdf")] + [Theory, InlineData("docs/cv.pdf", "docs/cv.pdf"), InlineData("/docs//cv.pdf", "docs/cv.pdf"), + InlineData("docs\\cv.pdf", "docs/cv.pdf")] public void Normalize_ProducesForwardSlashRelativePath(string input, string expected) - { - Assert.Equal(expected, VfsPath.Normalize(input)); - } + => Assert.Equal(expected, VfsPath.Normalize(input)); - [Theory] - [InlineData("../escape")] - [InlineData("a/../../b")] + [Theory, InlineData("../escape"), InlineData("a/../../b")] public void Normalize_RejectsTraversal(string input) - { - Assert.Throws(() => VfsPath.Normalize(input)); - } + => Assert.Throws(() => VfsPath.Normalize(input)); } diff --git a/tests/SquidStd.Tests/Workers/JobDispatcherTests.cs b/tests/SquidStd.Tests/Workers/JobDispatcherTests.cs index 108dd995..d5b7b6c1 100644 --- a/tests/SquidStd.Tests/Workers/JobDispatcherTests.cs +++ b/tests/SquidStd.Tests/Workers/JobDispatcherTests.cs @@ -26,7 +26,8 @@ public async Task DispatchAsync_PropagatesHandlerException() var boom = new RecordingJobHandler("resize") { ThrowOnHandle = new InvalidOperationException("boom") }; var dispatcher = new JobDispatcher([boom]); - await Assert.ThrowsAsync(() => dispatcher.DispatchAsync( + await Assert.ThrowsAsync( + () => dispatcher.DispatchAsync( Job("resize"), CancellationToken.None ) @@ -38,15 +39,14 @@ public async Task DispatchAsync_ThrowsWhenNoHandlerMatches() { var dispatcher = new JobDispatcher([new RecordingJobHandler("resize")]); - var ex = await Assert.ThrowsAsync(() => - dispatcher.DispatchAsync(Job("unknown"), CancellationToken.None) - ); + var ex = await Assert.ThrowsAsync( + () => + dispatcher.DispatchAsync(Job("unknown"), CancellationToken.None) + ); Assert.Equal("unknown", ex.JobName); } private static JobRequest Job(string name) - { - return new JobRequest(name, new Dictionary()); - } + => new(name, new Dictionary()); } diff --git a/tests/SquidStd.Tests/Workers/Support/FakeMessageQueue.cs b/tests/SquidStd.Tests/Workers/Support/FakeMessageQueue.cs index 35d72091..3e961992 100644 --- a/tests/SquidStd.Tests/Workers/Support/FakeMessageQueue.cs +++ b/tests/SquidStd.Tests/Workers/Support/FakeMessageQueue.cs @@ -6,24 +6,16 @@ namespace SquidStd.Tests.Workers.Support; public sealed class FakeMessageQueue : IMessageQueue { public Task PublishAsync(string queueName, TMessage message, CancellationToken cancellationToken = default) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public IDisposable Subscribe(string queueName, IQueueMessageListener listener) - { - return new Subscription(); - } + => new Subscription(); public IDisposable Subscribe(string queueName, IQueueMessageListenerAsync listener) - { - return new Subscription(); - } + => new Subscription(); private sealed class Subscription : IDisposable { - public void Dispose() - { - } + public void Dispose() { } } } diff --git a/tests/SquidStd.Tests/Workers/Support/RecordingJobHandler.cs b/tests/SquidStd.Tests/Workers/Support/RecordingJobHandler.cs index d94aae33..e16a7fd1 100644 --- a/tests/SquidStd.Tests/Workers/Support/RecordingJobHandler.cs +++ b/tests/SquidStd.Tests/Workers/Support/RecordingJobHandler.cs @@ -4,8 +4,8 @@ namespace SquidStd.Tests.Workers.Support; /// -/// Configurable for tests: records the jobs it received and can be told -/// to throw, or to block until released, so concurrency and error paths can be exercised. +/// Configurable for tests: records the jobs it received and can be told +/// to throw, or to block until released, so concurrency and error paths can be exercised. /// public sealed class RecordingJobHandler : IJobHandler { diff --git a/tests/SquidStd.Tests/Workers/WorkerConsumerServiceTests.cs b/tests/SquidStd.Tests/Workers/WorkerConsumerServiceTests.cs index 13217db3..ef8383fb 100644 --- a/tests/SquidStd.Tests/Workers/WorkerConsumerServiceTests.cs +++ b/tests/SquidStd.Tests/Workers/WorkerConsumerServiceTests.cs @@ -1,6 +1,5 @@ using SquidStd.Tests.Workers.Support; using SquidStd.Workers.Abstractions.Data; -using SquidStd.Workers.Data.Config; using SquidStd.Workers.Services; namespace SquidStd.Tests.Workers; @@ -10,7 +9,7 @@ public class WorkerConsumerServiceTests [Fact] public async Task HandleAsync_DropsUnknownJobWithoutThrowing() { - var state = new WorkerState(new WorkersConfig { WorkerId = "w1", MaxConcurrency = 2 }); + var state = new WorkerState(new() { WorkerId = "w1", MaxConcurrency = 2 }); var consumer = Build(state, new RecordingJobHandler("resize")); var ex = await Record.ExceptionAsync(() => consumer.HandleAsync(Job("unknown"), CancellationToken.None)); @@ -22,14 +21,14 @@ public async Task HandleAsync_DropsUnknownJobWithoutThrowing() [Fact] public async Task HandleAsync_NeverExceedsMaxConcurrency() { - var handler = new RecordingJobHandler("resize") { Gate = new TaskCompletionSource() }; - var state = new WorkerState(new WorkersConfig { WorkerId = "w1", MaxConcurrency = 2 }); + var handler = new RecordingJobHandler("resize") { Gate = new() }; + var state = new WorkerState(new() { WorkerId = "w1", MaxConcurrency = 2 }); var consumer = Build(state, handler); // Launch 5 concurrent dispatches against a handler that blocks on its gate. var inFlight = Enumerable.Range(0, 5) - .Select(_ => consumer.HandleAsync(Job("resize"), CancellationToken.None)) - .ToArray(); + .Select(_ => consumer.HandleAsync(Job("resize"), CancellationToken.None)) + .ToArray(); // Give the semaphore time to admit as many as it will, then assert the cap held. await Task.Delay(200); @@ -46,10 +45,11 @@ public async Task HandleAsync_NeverExceedsMaxConcurrency() public async Task HandleAsync_RethrowsHandlerExceptionForRequeue() { var handler = new RecordingJobHandler("resize") { ThrowOnHandle = new InvalidOperationException("boom") }; - var state = new WorkerState(new WorkersConfig { WorkerId = "w1", MaxConcurrency = 2 }); + var state = new WorkerState(new() { WorkerId = "w1", MaxConcurrency = 2 }); var consumer = Build(state, handler); - await Assert.ThrowsAsync(() => consumer.HandleAsync(Job("resize"), CancellationToken.None) + await Assert.ThrowsAsync( + () => consumer.HandleAsync(Job("resize"), CancellationToken.None) ); Assert.Equal(0, state.ActiveJobs); @@ -59,7 +59,7 @@ await Assert.ThrowsAsync(() => consumer.HandleAsync(J public async Task HandleAsync_RunsMatchingHandler() { var handler = new RecordingJobHandler("resize"); - var state = new WorkerState(new WorkersConfig { WorkerId = "w1", MaxConcurrency = 2 }); + var state = new WorkerState(new() { WorkerId = "w1", MaxConcurrency = 2 }); var consumer = Build(state, handler); await consumer.HandleAsync(Job("resize"), CancellationToken.None); @@ -69,12 +69,8 @@ public async Task HandleAsync_RunsMatchingHandler() } private static WorkerConsumerService Build(WorkerState state, params RecordingJobHandler[] handlers) - { - return new WorkerConsumerService(new FakeMessageQueue(), new JobDispatcher(handlers), state, new WorkersConfig()); - } + => new(new FakeMessageQueue(), new JobDispatcher(handlers), state, new()); private static JobRequest Job(string name) - { - return new JobRequest(name, new Dictionary()); - } + => new(name, new Dictionary()); } diff --git a/tests/SquidStd.Tests/Workers/WorkerContractsTests.cs b/tests/SquidStd.Tests/Workers/WorkerContractsTests.cs index 36c3e033..d801fb9d 100644 --- a/tests/SquidStd.Tests/Workers/WorkerContractsTests.cs +++ b/tests/SquidStd.Tests/Workers/WorkerContractsTests.cs @@ -33,15 +33,12 @@ public void WorkerChannels_NamesAreNonEmptyAndDistinct() Assert.NotEqual(WorkerChannels.JobQueue, WorkerChannels.HeartbeatTopic); } - [Theory] - [InlineData(WorkerStatusType.Idle)] - [InlineData(WorkerStatusType.Busy)] - [InlineData(WorkerStatusType.Offline)] + [Theory, InlineData(WorkerStatusType.Idle), InlineData(WorkerStatusType.Busy), InlineData(WorkerStatusType.Offline)] public void WorkerHeartbeat_RoundTrips_EveryStatus(WorkerStatusType status) { var original = new WorkerHeartbeat( "worker-3", - new DateTime(2026, 6, 23, 11, 0, 0, DateTimeKind.Utc), + new(2026, 6, 23, 11, 0, 0, DateTimeKind.Utc), status, 0, 4 @@ -57,7 +54,7 @@ public void WorkerHeartbeat_RoundTrips_PreservingAllFields() { var original = new WorkerHeartbeat( "worker-1", - new DateTime(2026, 6, 23, 10, 0, 0, DateTimeKind.Utc), + new(2026, 6, 23, 10, 0, 0, DateTimeKind.Utc), WorkerStatusType.Busy, 3, 8 @@ -76,8 +73,8 @@ public void WorkerInfo_RoundTrips_PreservingAllFields() WorkerStatusType.Offline, 2, 8, - new DateTime(2026, 6, 23, 9, 0, 0, DateTimeKind.Utc), - new DateTime(2026, 6, 23, 9, 30, 0, DateTimeKind.Utc) + new(2026, 6, 23, 9, 0, 0, DateTimeKind.Utc), + new(2026, 6, 23, 9, 30, 0, DateTimeKind.Utc) ); var restored = Serializer.Deserialize(Serializer.Serialize(original)); diff --git a/tests/SquidStd.Tests/Workers/WorkerHeartbeatServiceTests.cs b/tests/SquidStd.Tests/Workers/WorkerHeartbeatServiceTests.cs index 5c268bde..c52d488e 100644 --- a/tests/SquidStd.Tests/Workers/WorkerHeartbeatServiceTests.cs +++ b/tests/SquidStd.Tests/Workers/WorkerHeartbeatServiceTests.cs @@ -76,6 +76,6 @@ private static (IMessageTopic topic, WorkerState state) NewMessaging(WorkersConf container.RegisterInstance(new EventBusService()); container.AddInMemoryMessaging(); - return (container.Resolve(), new WorkerState(config)); + return (container.Resolve(), new(config)); } } diff --git a/tests/SquidStd.Tests/Workers/WorkerStateTests.cs b/tests/SquidStd.Tests/Workers/WorkerStateTests.cs index ab0b6a86..281e2e5b 100644 --- a/tests/SquidStd.Tests/Workers/WorkerStateTests.cs +++ b/tests/SquidStd.Tests/Workers/WorkerStateTests.cs @@ -1,5 +1,4 @@ using SquidStd.Workers.Abstractions.Types; -using SquidStd.Workers.Data.Config; using SquidStd.Workers.Services; namespace SquidStd.Tests.Workers; @@ -9,7 +8,7 @@ public class WorkerStateTests [Fact] public void MaxConcurrency_FallsBackToProcessorCountWhenNotPositive() { - var state = new WorkerState(new WorkersConfig { WorkerId = "w1", MaxConcurrency = 0 }); + var state = new WorkerState(new() { WorkerId = "w1", MaxConcurrency = 0 }); Assert.Equal(Environment.ProcessorCount, state.MaxConcurrency); } @@ -17,7 +16,7 @@ public void MaxConcurrency_FallsBackToProcessorCountWhenNotPositive() [Fact] public void Status_IsBusyWhileJobsActive() { - var state = new WorkerState(new WorkersConfig { WorkerId = "w1", MaxConcurrency = 4 }); + var state = new WorkerState(new() { WorkerId = "w1", MaxConcurrency = 4 }); state.JobStarted(); state.JobStarted(); @@ -35,7 +34,7 @@ public void Status_IsBusyWhileJobsActive() [Fact] public void Status_IsIdleWhenNoActiveJobs() { - var state = new WorkerState(new WorkersConfig { WorkerId = "w1", MaxConcurrency = 4 }); + var state = new WorkerState(new() { WorkerId = "w1", MaxConcurrency = 4 }); Assert.Equal(WorkerStatusType.Idle, state.Status); Assert.Equal(0, state.ActiveJobs); @@ -44,7 +43,7 @@ public void Status_IsIdleWhenNoActiveJobs() [Fact] public void WorkerId_FallsBackToMachineNameWhenBlank() { - var state = new WorkerState(new WorkersConfig { WorkerId = " ", MaxConcurrency = 4 }); + var state = new WorkerState(new() { WorkerId = " ", MaxConcurrency = 4 }); Assert.Equal(Environment.MachineName, state.WorkerId); } diff --git a/tests/SquidStd.Tests/Workers/WorkersRegistrationExtensionsTests.cs b/tests/SquidStd.Tests/Workers/WorkersRegistrationExtensionsTests.cs index 777f595b..3cb6bb63 100644 --- a/tests/SquidStd.Tests/Workers/WorkersRegistrationExtensionsTests.cs +++ b/tests/SquidStd.Tests/Workers/WorkersRegistrationExtensionsTests.cs @@ -21,7 +21,7 @@ public async Task AddJobHandler_MakesHandlerReachableFromDispatcher() container.AddJobHandler(); var dispatcher = container.Resolve(); - await dispatcher.DispatchAsync(new JobRequest("echo", new Dictionary()), CancellationToken.None); + await dispatcher.DispatchAsync(new("echo", new Dictionary()), CancellationToken.None); Assert.Equal(1, EchoJobHandler.Calls); } diff --git a/tests/SquidStd.Tests/Yaml/YamlUtilsTests.cs b/tests/SquidStd.Tests/Yaml/YamlUtilsTests.cs index dc82d2bb..9dc7a333 100644 --- a/tests/SquidStd.Tests/Yaml/YamlUtilsTests.cs +++ b/tests/SquidStd.Tests/Yaml/YamlUtilsTests.cs @@ -5,13 +5,9 @@ namespace SquidStd.Tests.Yaml; public class YamlUtilsTests { - [Theory] - [InlineData("")] - [InlineData(" ")] + [Theory, InlineData(""), InlineData(" ")] public void Deserialize_NullOrWhitespace_Throws(string yaml) - { - Assert.Throws(() => YamlUtils.Deserialize(yaml)); - } + => Assert.Throws(() => YamlUtils.Deserialize(yaml)); [Fact] public void Deserialize_RuntimeType_ReturnsTypedObject() @@ -31,11 +27,10 @@ public void Deserialize_RuntimeType_ReturnsTypedObject() [Fact] public void DeserializeFromFile_MissingFile_Throws() - { - Assert.Throws(() => - YamlUtils.DeserializeFromFile(Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".yaml")) + => Assert.Throws( + () => + YamlUtils.DeserializeFromFile(Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".yaml")) ); - } [Fact] public void DeserializeSection_ExistingSection_ReturnsTypedObject() @@ -69,9 +64,7 @@ public void DeserializeSection_MissingSection_ReturnsNull() [Fact] public void Serialize_NullObject_Throws() - { - Assert.Throws(() => YamlUtils.Serialize(null!)); - } + => Assert.Throws(() => YamlUtils.Serialize(null!)); [Fact] public void SerializeDeserialize_RoundTrip_PreservesValues()