From 6e51ab5b89309349542de0e25c3e21fbab613eb7 Mon Sep 17 00:00:00 2001 From: Prachi Gauriar Date: Fri, 4 Jul 2025 15:58:18 -0400 Subject: [PATCH] Add .swift-format and fix lint warnings --- .github/workflows/VerifyChanges.yaml | 14 + .swift-format | 75 +++++ CLAUDE.md | 186 ++++++++++++ Documentation/MarkdownStyleGuide.md | 190 ++++++++++++ Documentation/TestMocks.md | 275 ++++++++++++++++++ Package.swift | 3 +- Scripts/install-git-hooks | 50 ++++ Scripts/lint | 10 + .../DispatchQueue+NonOvercommitting.swift | 1 - .../Concurrency/DispatchQueue+Standard.swift | 1 - .../Concurrency/ExecutionGroup.swift | 3 +- .../Date Providers/DateProvider.swift | 1 - .../Date Providers/DateProviders.swift | 3 +- .../Date Providers/OffsetDateProvider.swift | 5 +- .../Date Providers/ScaledDateProvider.swift | 3 +- .../Date Providers/SystemDateProvider.swift | 1 - Sources/DevFoundation/DevFoundation.swift | 1 - .../DevFoundation/Event Bus/BusEvent.swift | 3 +- .../Event Bus/BusEventObserver.swift | 1 - .../ContextualBusEventObserver.swift | 15 +- .../DevFoundation/Event Bus/EventBus.swift | 7 +- .../Extensions/Data+Obfuscation.swift | 25 +- .../FixedWidthInteger+BigEndianData.swift | 5 +- ...ngeReplaceableCollection+RemoveFirst.swift | 1 - .../AuthenticatorCancellationError.swift | 1 - .../Errors/InvalidHTTPStatusCodeError.swift | 1 - .../InvalidWebServiceRequestError.swift | 3 +- .../Errors/NonHTTPURLResponseError.swift | 3 +- .../Errors/UnauthorizedHTTPRequestError.swift | 1 - .../AuthenticatingHTTPClient.swift | 13 +- .../Low-Level Clients/HTTPClient.swift | 19 +- .../HTTPClientRequestInterceptor.swift | 1 - .../HTTPClientResponseInterceptor.swift | 1 - .../HTTPRequestAuthenticationFailure.swift | 5 +- .../HTTPRequestAuthenticator.swift | 1 - .../Low-Level Clients/URLRequestLoader.swift | 1 - .../Requests and Responses/HTTPBody.swift | 1 - .../HTTPHeaderField.swift | 5 +- .../HTTPHeaderItem.swift | 5 +- .../Requests and Responses/HTTPMethod.swift | 3 +- .../Requests and Responses/HTTPResponse.swift | 13 +- .../HTTPStatusCode.swift | 1 - .../Requests and Responses/MediaType.swift | 11 +- .../URLPathComponent.swift | 5 +- .../BaseURLConfiguring.swift | 1 - .../JSONBodyWebServiceRequest.swift | 3 +- .../SingleBaseURLConfiguration.swift | 3 +- .../Web Service Client/WebServiceClient.swift | 12 +- .../WebServiceRequest.swift | 20 +- .../Utility Types/AnySendableHashable.swift | 4 +- .../Utility Types/DottedHierarchicalID.swift | 6 +- .../Utility Types/ExpiringValue.swift | 25 +- .../Utility Types/GibberishGenerator.swift | 8 +- .../Utility Types/HashableByID.swift | 3 +- .../Utility Types/JSONValue.swift | 13 +- .../Utility Types/SoftwareComponentID.swift | 1 - .../Utility Types/TopLevelCoding.swift | 19 +- .../Utility Types/TypedExtensibleEnum.swift | 1 - Sources/dfob/ObfuscateCommand.swift | 10 +- ...DispatchQueue+NonOvercommittingTests.swift | 1 - .../DispatchQueue+StandardTests.swift | 1 - .../Concurrency/ExecutionGroupTests.swift | 1 - .../Date Providers/DateProvidersTests.swift | 2 +- .../OffsetDateProviderTests.swift | 1 - .../ScaledDateProviderTests.swift | 1 - .../SystemDateProviderTests.swift | 1 - .../ContextualBusEventObserverTests.swift | 3 +- .../Event Bus/EventBusTests.swift | 1 - .../Extensions/Data+ObfuscationTests.swift | 4 +- ...FixedWidthInteger+BigEndianDataTests.swift | 2 +- ...placeableCollection+RemoveFirstTests.swift | 2 +- .../AuthenticatorCancellationErrorTests.swift | 1 - .../InvalidHTTPStatusCodeErrorTests.swift | 1 - .../InvalidWebServiceRequestError.swift | 1 - .../Errors/NonHTTPURLResponseErrorTests.swift | 3 +- .../UnauthorizedHTTPRequestErrorTests.swift | 1 - .../AuthenticatingHTTPClientTests.swift | 1 - .../Low-Level Clients/HTTPClientTests.swift | 3 +- ...TTPRequestAuthenticationFailureTests.swift | 1 - .../HTTPRequestAuthenticatorTests.swift | 1 - .../HTTPBodyTests.swift | 1 - .../HTTPHeaderFieldTests.swift | 3 +- .../HTTPHeaderItemTests.swift | 3 +- .../HTTPMethodTests.swift | 1 - .../HTTPResponseTests.swift | 1 - .../HTTPStatusCodeTests.swift | 4 +- .../MediaTypeTests.swift | 1 - .../URLPathComponentTests.swift | 1 - .../JSONBodyWebServiceRequestTests.swift | 7 +- .../SingleBaseURLConfigurationTests.swift | 1 - .../WebServiceClientTests.swift | 1 - .../WebServiceRequestTests.swift | 9 +- .../Date+IsApproximatelyEqual.swift | 2 - .../MockBaseURLConfiguration.swift | 4 +- .../MockBusEventObserver.swift | 11 +- .../Testing Helpers/MockBusEvents.swift | 1 - .../Testing Helpers/MockCodables.swift | 1 - .../Testing Helpers/MockDateProvider.swift | 4 +- .../Testing Helpers/MockError.swift | 1 - .../MockHTTPClientRequestInterceptor.swift | 8 +- .../MockHTTPClientResponseInterceptor.swift | 8 +- .../MockHTTPRequestAuthenticator.swift | 16 +- .../MockURLRequestLoader.swift | 8 +- .../MockWebServiceRequest.swift | 40 +-- .../RandomValueGenerating+DevFoundation.swift | 1 - .../AnySendableHashableTests.swift | 1 - .../DottedHierarchicalIDTests.swift | 1 - .../Utility Types/ExpiringValueTests.swift | 1 - .../GibberishGeneratorTests.swift | 3 +- .../Utility Types/HashableByIDTests.swift | 1 - .../Utility Types/JSONValueTests.swift | 14 +- .../SoftwareComponentIDTests.swift | 1 - .../Utility Types/TopLevelCodingTests.swift | 1 - .../TypedExtensibleEnumTests.swift | 1 - Tests/dfobTests/ObfuscateCommandTests.swift | 4 +- 115 files changed, 978 insertions(+), 323 deletions(-) create mode 100644 .swift-format create mode 100644 CLAUDE.md create mode 100644 Documentation/MarkdownStyleGuide.md create mode 100644 Documentation/TestMocks.md create mode 100755 Scripts/install-git-hooks create mode 100755 Scripts/lint diff --git a/.github/workflows/VerifyChanges.yaml b/.github/workflows/VerifyChanges.yaml index 1336372..631022b 100644 --- a/.github/workflows/VerifyChanges.yaml +++ b/.github/workflows/VerifyChanges.yaml @@ -8,8 +8,22 @@ on: branches: [ $default-branch ] jobs: + lint: + name: Lint + runs-on: macos-15 + if: ${{ github.event_name == 'pull_request' }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Select Xcode 16.4 + run: | + sudo xcode-select -s /Applications/Xcode_16.4.0.app + - name: Lint + run: | + Scripts/lint build-and-test: name: Build and Test (${{ matrix.platform }}) + needs: lint runs-on: macos-15 strategy: fail-fast: false diff --git a/.swift-format b/.swift-format new file mode 100644 index 0000000..6cd31d6 --- /dev/null +++ b/.swift-format @@ -0,0 +1,75 @@ +{ + "fileScopedDeclarationPrivacy": { + "accessLevel": "private" + }, + "indentConditionalCompilationBlocks": false, + "indentSwitchCaseLabels": false, + "indentation": { + "spaces": 4 + }, + "lineBreakAroundMultilineExpressionChainComponents": false, + "lineBreakBeforeControlFlowKeywords": false, + "lineBreakBeforeEachArgument": false, + "lineBreakBeforeEachGenericRequirement": false, + "lineBreakBetweenDeclarationAttributes": false, + "lineLength": 120, + "maximumBlankLines": 2, + "multiElementCollectionTrailingCommas": true, + "noAssignmentInExpressions": { + "allowedFunctions": [] + }, + "prioritizeKeepingFunctionOutputTogether": true, + "reflowMultilineStringLiterals": { + "never": {} + }, + "respectsExistingLineBreaks": true, + "rules": { + "AllPublicDeclarationsHaveDocumentation": false, + "AlwaysUseLiteralForEmptyCollectionInit": true, + "AlwaysUseLowerCamelCase": true, + "AmbiguousTrailingClosureOverload": true, + "AvoidRetroactiveConformances": false, + "BeginDocumentationCommentWithOneLineSummary": true, + "DoNotUseSemicolons": true, + "DontRepeatTypeInStaticProperties": true, + "FileScopedDeclarationPrivacy": true, + "FullyIndirectEnum": true, + "GroupNumericLiterals": true, + "IdentifiersMustBeASCII": true, + "NeverForceUnwrap": false, + "NeverUseForceTry": false, + "NeverUseImplicitlyUnwrappedOptionals": false, + "NoAccessLevelOnExtensionDeclaration": true, + "NoAssignmentInExpressions": true, + "NoBlockComments": true, + "NoCasesWithOnlyFallthrough": true, + "NoEmptyLinesOpeningClosingBraces": false, + "NoEmptyTrailingClosureParentheses": true, + "NoLabelsInCasePatterns": true, + "NoLeadingUnderscores": false, + "NoParensAroundConditions": true, + "NoPlaygroundLiterals": true, + "NoVoidReturnOnFunctionSignature": true, + "OmitExplicitReturns": false, + "OneCasePerLine": true, + "OneVariableDeclarationPerLine": true, + "OnlyOneTrailingClosureArgument": true, + "OrderedImports": true, + "ReplaceForEachWithForLoop": true, + "ReturnVoidInsteadOfEmptyTuple": true, + "TypeNamesShouldBeCapitalized": true, + "UseEarlyExits": true, + "UseExplicitNilCheckInConditions": true, + "UseLetInEveryBoundCaseVariable": true, + "UseShorthandTypeNames": true, + "UseSingleLinePropertyGetter": true, + "UseSynthesizedInitializer": true, + "UseTripleSlashForDocumentationComments": true, + "UseWhereClausesInForLoops": true, + "ValidateDocumentationComments": false + }, + "spacesAroundRangeFormationOperators": true, + "spacesBeforeEndOfLineComments": 4, + "tabWidth": 4, + "version": 1 +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..cb9f6f1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,186 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this +repository. + + +## Development Commands + +### Building and Testing + + - **Build**: `swift build` + - **Test all**: `swift test` + - **Test specific target**: `swift test --filter DevFoundationTests` or + `swift test --filter dfobTests` + - **Test with coverage**: Use Xcode test plans in `Build Support/Test Plans/` + (AllTests.xctestplan for all tests) + +### Code Quality + + - **Lint**: `Scripts/lint` (uses `swift format lint --recursive --strict`) + - **Format**: `swift format --recursive Sources/ Tests/` + +### GitHub Actions + +The repository uses GitHub Actions for CI/CD with the workflow in +`.github/workflows/VerifyChanges.yaml`. The workflow: + + - Lints code on PRs using `swift format` + - Builds and tests on multiple Apple platforms (iOS, macOS, tvOS, watchOS) + - Generates code coverage reports using xccovPretty + - Requires Xcode 16.4 and macOS 15 runners + + +## Architecture Overview + +DevFoundation is a Swift package providing foundational utilities for iOS, macOS, tvOS, visionOS, +and watchOS development. It consists of two main products: + +### 1. DevFoundation Library + +A comprehensive utility library with the following major components: + +#### Networking Layer + + - **WebServiceClient**: Generic web service client with declarative request/response handling + - **AuthenticatingHTTPClient**: HTTP client with built-in authentication support + - **HTTPClient**: Lower-level HTTP client with request/response interceptors + - **WebServiceRequest**: Protocol for defining web service requests + - **BaseURLConfiguring**: Protocol for managing different base URLs (staging, production, etc.) + +#### Event System + + - **EventBus**: Type-safe event bus for decoupled component communication + - **BusEventObserver**: Protocol for observing bus events + - **ContextualBusEventObserver**: Observer with contextual event handling + +#### Date Management + + - **DateProvider**: Protocol for abstracting date/time sources + - **DateProviders**: Namespace providing system, scaled, and offset date providers + - **SystemDateProvider**: Default system date provider + - **OffsetDateProvider**: Date provider with fixed offset + - **ScaledDateProvider**: Date provider with time scaling + +#### Concurrency Utilities + + - **ExecutionGroup**: Utility for managing concurrent operations + - **DispatchQueue extensions**: Non-overcommitting and standard queue utilities + +#### Utility Types + + - **AnySendableHashable**: Type-erased sendable hashable wrapper + - **DottedHierarchicalID**: Hierarchical identifier with dot notation + - **ExpiringValue**: Value wrapper with expiration logic + - **GibberishGenerator**: Random string generation + - **HashableByID**: Protocol for hashable-by-identity types + - **JSONValue**: Unified JSON value representation + - **SoftwareComponentID**: Identifier for software components + - **TopLevelCoding**: Protocol for top-level encoding/decoding + - **TypedExtensibleEnum**: Type-safe extensible enumerations + +### 2. dfob Command Line Tool + +A command-line utility for data obfuscation/deobfuscation: + + - Uses Swift ArgumentParser for command-line interface + - Supports obfuscation (`-O`) and deobfuscation (`-D`) operations + - Handles file input/output or stdin/stdout + - Implements custom obfuscation algorithm with configurable key and message sizes + + +## Key Design Patterns + +### Generic Web Service Architecture + +The networking layer uses heavy generics to provide type-safe, declarative web service access: + + - `WebServiceClient` for type-safe clients + - Protocol-based request/response mapping + - Interceptor pattern for request/response modification + +### Protocol-Oriented Date Handling + +Date providers use protocols to enable dependency injection and testing: + + - `DateProvider` protocol abstracts time sources + - `DateProviders.current` provides global date provider configuration + - Warning: Setting `DateProviders.current` to auto-updating providers causes infinite loops + +### Thread-Safe Event Bus + +The event bus uses Swift's new Synchronization framework: + + - `Mutex<[any BusEventObserver]>` for thread-safe observer management + - Type-safe event posting with generic constraints + - Support for both regular and identifiable events + + +## Dependencies + +External dependencies managed via Swift Package Manager: + + - **swift-argument-parser**: Command-line argument parsing (dfob tool) + - **swift-numerics**: Numeric utilities (testing) + - **DevTesting**: Custom testing framework + - **URLMock**: URL mocking for tests + + +## Testing + +The codebase maintains >99% test coverage with comprehensive test suites: + + - All major components have corresponding test files + - Mock implementations in `Tests/DevFoundationTests/Testing Helpers/` + - Test utilities for date approximation, random value generation + - Separate test plans for different components + + +## Testing and Mocking Standards + +### Test Mock Architecture + +The codebase uses a consistent stub-based mocking pattern built on the DevTesting framework: + +#### Core Mock Patterns + + - **Stub-based mocks**: All mocks use `Stub` or + `ThrowingStub` + - **Force-unwrapped stubs**: Stub properties are declared with `!` - tests must configure them + - **Swift 6 concurrency**: All stub properties marked `nonisolated(unsafe)` + - **Argument structures**: Complex parameters use dedicated structures (e.g., + `LogErrorArguments`) + +#### Mock Organization + + - **File naming**: `Mock[ProtocolName].swift` + - **Type naming**: `Mock[ProtocolName]` + - **Stub properties**: `[functionName]Stub` + - **Location**: `Tests/[ModuleName]/Testing Helpers/` + +#### Test Patterns + + - Use `@Test` with Swift Testing framework + - Use `#expect()` and `#require()` for assertions + - Always configure stubs before use to avoid crashes + - Leverage DevTesting's call tracking for verification + +### Documentation Standards + +Follow the project's Markdown Style Guide: + + - **Line length**: 100 characters max + - **Code blocks**: Use 4-space indentation, not fenced blocks + - **Lists**: Use `-` for bullets, align continuation lines with text + - **Spacing**: 2 blank lines between major sections, 1 after headers + - **Terminology**: Use "function" over "method", "type" over "class" + + +## Development Notes + + - Follows Swift API Design Guidelines + - Uses Swift 6.1 with `ExistentialAny` feature enabled + - Minimum deployment targets: iOS 18+, macOS 15+, tvOS 18+, visionOS 2+, watchOS 11+ + - Reverse DNS prefix: `com.gauriar.devfoundation` + - All public APIs are documented and tested + - Test coverage target: >99% \ No newline at end of file diff --git a/Documentation/MarkdownStyleGuide.md b/Documentation/MarkdownStyleGuide.md new file mode 100644 index 0000000..d94f75c --- /dev/null +++ b/Documentation/MarkdownStyleGuide.md @@ -0,0 +1,190 @@ +# Markdown Style Guide + +This document defines the Markdown formatting standards for documentation in the Shopper iOS +codebase. + + +## General Formatting + +### Line Length + +Keep all lines under **100 characters**. Break long sentences and paragraphs at natural points +to stay within this limit. + + ✅ Good: + Faucibus consectetur lacinia nostra eros conubia nibh inceptos hendrerit, ante blandit + vulputate imperdiet amet porttitor torquent mattis. + + ❌ Bad: + Faucibus consectetur lacinia nostra eros conubia nibh inceptos hendrerit, ante blandit vulputate imperdiet amet porttitor torquent mattis. + + +### Spacing + +Use consistent spacing for visual hierarchy: + +- **Between major sections**: 2 blank lines +- **After code blocks**: 1 blank line +- **Before subsections**: 1 blank line +- **After section headers**: 1 blank line + +Example: + + ## Major Section + + Content here. + + + ## Another Major Section + + ### Subsection + + Content after subsection header. + + code block here + + Content after code block. + + +## Headers + +### Structure + +Use consistent header hierarchy: + + - `#` for document title + - `##` for major sections + - `###` for subsections + - `####` for sub-subsections (use sparingly) + +### Numbering + +Number subsections when they represent sequential steps or ordered items: + + ## Usage Patterns + + ### 1. Basic Setup + ### 2. Advanced Configuration + ### 3. Verification + + +## Code Blocks + +### Indented Code Blocks + +Use **4-space indentation** for all code blocks instead of fenced blocks: + + ✅ Good: + import DevTesting + + final class MockService: ServiceProtocol { + nonisolated(unsafe) var performActionStub: Stub! + } + + ❌ Bad: + ```swift + import DevTesting + + final class MockService: ServiceProtocol { + nonisolated(unsafe) var performActionStub: Stub! + } + ``` + + +## Lists + +### Unordered Lists + +Use `-` as the bullet character for unordered lists. Place the hyphen 2 spaces from current +indentation level, followed by a space, then your text. When a bullet point spans multiple lines, +align continuation lines with the start of the text (not the hyphen). This ensures all text within a +bullet aligns vertically and makes proper indentation on continuation lines a matter of pressing tab +one or more times. + + - Turpis cubilia sit urna dis ultricies consequat massa hendrerit enim natoque. + - Consectetur sapien posuere sit arcu finibus mattis dictumst dis, lectus ipsum in dictum + lobortis bibendum enim, suscipit aliquet nulla porta erat id class purus. + - Scelerisque massa rutrum dapibus placerat aenean tellus arcu cursus. + - Iaculis, cubilia tristique efficitur bibendum urna imperdiet facilisis turpis hac, + platea est habitant auctor quisque nec pulvinar fermentum sociosqu. + - Parturient justo, venenatis nunc lobortis senectus tortor orci elementum consequat. + - In nibh nisl venenatis bibendum neque mattis habitant tempor proin, tincidunt lobortis + vulputate commodo. + +Blank lines can be placed between bullets if it aids in readability. + +### Ordered Lists + +Use standard numbered lists for sequential items. Follow similar indentation rules as for unordered +lists. Note that the `.` characters in the bullets leads to some strange indentation, but this is +unavoidable. + + 1. Turpis cubilia sit urna dis ultricies consequat massa hendrerit enim natoque. + + 2. Consectetur sapien posuere sit arcu finibus mattis dictumst dis, lectus ipsum in dictum + lobortis bibendum enim, suscipit aliquet nulla porta erat id class purus. + + 1. Scelerisque massa rutrum dapibus placerat aenean tellus arcu cursus. + 2. Iaculis, cubilia tristique efficitur bibendum urna imperdiet facilisis turpis hac, + platea est habitant auctor quisque nec pulvinar fermentum sociosqu. + 3. Parturient justo, venenatis nunc lobortis senectus tortor orci elementum consequat. + + 4. In nibh nisl venenatis bibendum neque mattis habitant tempor proin, tincidunt lobortis + vulputate commodo. + + +## Text Formatting + +### Bold Text + +Use bold for emphasis on key terms: + + - **File names**: `Mock[ProtocolName].swift` + - **Type names**: `Mock[ProtocolName]` + +### Code Spans + +Use backticks for: + + - Type names: `Stub` + - Function names: `performAction(_:)` + - File names: `MockAppServices.swift` + - Keywords: `nonisolated(unsafe)` + +### Terminology Consistency + +Use consistent terminology throughout documents: + +- Prefer "function" over "method" when referring to Swift functions +- Use "type" instead of "class" when referring generically to classes/structs/enums +- Use "property" for stored and computed properties + + +## File Structure Examples + +Use indented text blocks for file structure diagrams: + + Tests/ + ├── Folder 1/ + │ └── Folder 2/ + │ ├── File1.swift + │ └── File2.swift + └── Folder 3/ + └── Folder 4/ + ├── File3.swift + └── File4.swift + + +## Links and References + +### Internal References + +Use relative paths for internal documentation: + + See [Test Mock Documentation](TestMocks.md) for details. + +### Code References + +Reference specific locations using this pattern: + + The main implementation is in `Stub.swift:42-68`. diff --git a/Documentation/TestMocks.md b/Documentation/TestMocks.md new file mode 100644 index 0000000..3e9ab80 --- /dev/null +++ b/Documentation/TestMocks.md @@ -0,0 +1,275 @@ +# Test Mock Documentation + +This document outlines the patterns and conventions for writing test mocks in the Shopper iOS +codebase. + + +## Overview + +The codebase uses a consistent approach to mocking based on the DevTesting framework's `Stub` type. +All mocks follow standardized patterns that make them predictable, testable, and maintainable. + + +## Core Mock Patterns + +### 1. Stub-Based Architecture + +All mocks use `DevTesting`’s `Stub` or `ThrowingStub` types +for function and property implementations: + + import DevTesting + + + final class MockService: ServiceProtocol { + nonisolated(unsafe) + var performActionStub: Stub! + + + func performAction(_ input: String) -> Bool { + performActionStub(input) + } + } + +**Key characteristics:** + + - Properties are marked `nonisolated(unsafe)` for Swift 6 concurrency + - Stub properties are force-unwrapped (`!`). Tests must configure them. + - Function implementations simply call the corresponding stub + + +### 2. Argument Structures for Complex Parameters + +When functions have multiple parameters, create dedicated argument structures: + + final class MockTelemetryDestination: TelemetryDestination { + struct LogErrorArguments { + let error: any Error + let attributes: [String : any Encodable] + } + + + nonisolated(unsafe) + var logErrorStub: Stub! + + + func logError(_ error: some Error, attributes: [String : any Encodable]) { + logErrorStub(.init(error: error, attributes: attributes)) + } + } + +**Benefits:** + + - Simplifies stub configuration in tests + - Provides clear parameter documentation + - Enables easy verification of function calls + + +### 3. Property-Only Services + +For services that only expose properties (like `MockAppServices`), each property delegates to a +stub: + + final class MockAppServices: PlatformAppServices { + nonisolated(unsafe) + var stylesheetStub: Stub! + + nonisolated(unsafe) + var telemetryEventLoggerStub: Stub! + + + var stylesheet: Stylesheet { + stylesheetStub() + } + + + var telemetryEventLogger: any TelemetryEventLogging { + telemetryEventLoggerStub() + } + } + + +### 4. Generic Mock Types + +For protocols with associated types, create generic mocks: + + struct MockTelemetryEvent: TelemetryEvent + where EventData: Encodable & Sendable { + let name: TelemetryEventName + var eventData: EventData + } + + extension MockTelemetryEvent: Equatable where EventData: Equatable { } + extension MockTelemetryEvent: Hashable where EventData: Hashable { } + + +**Pattern:** + + - Use generic parameters for flexible data types + - Add conditional conformances for `Equatable` and `Hashable` when possible + - Maintain protocol requirements while allowing test customization + + +### 5. Simple Error Mocks + +For testing error scenarios, use simple enum-based errors: + + enum MockError: Error, CaseIterable, Hashable, Sendable { + case error1 + case error2 + case error3 + } + +**Characteristics:** + + - Implement `CaseIterable` for easy test iteration + - Include `Hashable` and `Sendable` for Swift 6 compatibility + - Use descriptive but simple case names + + +## Mock Organization + +### File Structure + + Tests/ + ├── AppPlatformTests/ + │ └── Testing Support/ + │ ├── MockAppServices.swift + │ ├── MockBootstrapper.swift + │ └── MockSubapp.swift + └── TelemetryTests/ + └── Testing Support/ + ├── MockTelemetryDestination.swift + ├── MockTelemetryEvent.swift + └── MockError.swift + + +### Naming Conventions + + - **File names**: `Mock[ProtocolName].swift` + - **Type names**: `Mock[ProtocolName]` + - **Argument structures**: `[FunctionName]Arguments` + - **Stub properties**: `[functionName]Stub` + + +## Special Patterns + +### 1. Static Stubs for Initializers + +When mocking types with custom initializers, use static stubs: + + final class MockSubapp: Subapp { + struct InitArguments { + let appConfiguration: AppConfiguration + let subappServices: any SubappServices + } + + + nonisolated(unsafe) + static var initStub: Stub! + + + init(appConfiguration: AppConfiguration, subappServices: any SubappServices) async { + Self.initStub(.init(appConfiguration: appConfiguration, subappServices: subappServices)) + } + } + + +### 2. Default Stub Values + +For functions that might not be called in every test, provide default stub values: + + final class MockSubapp: Subapp { + // Initialize to non-nil to avoid crashes in tests that don't configure this stub + nonisolated(unsafe) + var installTelemetryBusEventHandlersStub: Stub = .init() + } + + +### 3. Protocol Imports with @testable + +Import protocols under test with `@testable` when accessing internal details: + + import AppPlatform + @testable import protocol AppPlatform.PlatformAppServices + @testable import protocol Telemetry.TelemetryDestination + + +## Usage in Tests + +### 1. Typical Test Setup + + @Test + mutating func testEventLogging() throws { + let mockDestination = MockTelemetryDestination() + mockDestination.logEventStub = .init() // Initialize stub + + let logger = TelemetryEventLogger(telemetryDestination: mockDestination) + logger.logEvent(someEvent) + + // Verify the call was made + #expect(mockDestination.logEventStub.calls.count == 1) + + // Extract and verify arguments + let arguments = try #require(mockDestination.logEventStub.callArguments.first) + #expect(arguments.name == expectedEventName) + #expect(arguments.attributes["key"] as? String == "expectedValue") + } + + +### 2. Return Value Configuration + + @Test + func testServiceCall() { + let mockServices = MockAppServices() + mockServices.stylesheetStub = Stub(defaultReturnValue: .standard) + + let result = systemUnderTest.processWithServices(mockServices) + + // Verify the service was called + #expect(mockServices.stylesheetStub.calls.count == 1) + } + + +### 3. Argument Verification Patterns + + @Test + mutating func testComplexMethodCall() throws { + let mockDestination = MockTelemetryDestination() + mockDestination.logErrorStub = .init() + + let error = MockError.error1 + let attributes = ["key": "value"] + + logger.logError(error, attributes: attributes) + + // Verify call count + #expect(mockDestination.logErrorStub.calls.count == 1) + + // Extract and verify arguments + let arguments = try #require(mockDestination.logErrorStub.callArguments.first) + #expect(arguments.error as? MockError == error) + #expect(arguments.attributes["key"] as? String == "value") + } + + +## Best Practices + + 1. **Always configure stubs**: Force-unwrapped stubs will crash if not configured + 2. **Use argument structures**: Simplifies complex parameter verification + 3. **Maintain protocol fidelity**: Mocks should behave like real implementations + 4. **Leverage DevTesting**: Use the framework's call tracking and verification capabilities + 5. **Keep mocks simple**: Avoid complex logic in mock implementations + 6. **Group related mocks**: Place mocks in appropriate Testing Support directories + 7. **Follow naming conventions**: Consistent naming improves maintainability + 8. **Use Swift Testing**: Leverage `@Test`, `#expect()`, and `#require()` for assertions + + +## Thread Safety + +All mocks use `nonisolated(unsafe)` markings for Swift 6 compatibility. This assumes: + + - Tests run on a single thread or properly synchronize access + - Stub configuration happens during test setup before concurrent access + - Mock usage patterns don't require additional synchronization + +When mocking concurrent code, consider additional synchronization mechanisms if needed. diff --git a/Package.swift b/Package.swift index ea73f09..b870716 100644 --- a/Package.swift +++ b/Package.swift @@ -2,7 +2,6 @@ import PackageDescription - let swiftSettings: [SwiftSetting] = [ .enableUpcomingFeature("ExistentialAny") ] @@ -27,7 +26,7 @@ let package = Package( "DevFoundation", "dfob", ] - ) + ), ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.5.0"), diff --git a/Scripts/install-git-hooks b/Scripts/install-git-hooks new file mode 100755 index 0000000..670ea93 --- /dev/null +++ b/Scripts/install-git-hooks @@ -0,0 +1,50 @@ +#!/bin/bash + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Go to the repository root (one level up from Scripts) +REPO_ROOT="$(dirname "$SCRIPT_DIR")" + +# Check if we're in a git repository +if [ ! -d "$REPO_ROOT/.git" ]; then + echo "Error: Not in a git repository" + exit 1 +fi + +mkdir -p "$REPO_ROOT/.git/hooks" + +# Function to install the pre-commit hook +install_pre_commit_hook() { + local pre_commit_hook="$REPO_ROOT/.git/hooks/pre-commit" + + echo "Installing pre-commit hook..." + + cat > "$pre_commit_hook" << 'EOF' +#!/bin/bash + +# Get the directory where this hook is located +HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Go to the repository root (two levels up from .git/hooks) +REPO_ROOT="$(dirname "$(dirname "$HOOK_DIR")")" + +# Run the lint script +echo "Running lint check..." +if ! "$REPO_ROOT/Scripts/lint"; then + echo "Lint check failed. Please fix formatting issues before committing." + exit 1 +fi + +echo "Lint check passed." +EOF + + chmod +x "$pre_commit_hook" + echo "Pre-commit hook installed successfully!" +} + +# Install the pre-commit hook +install_pre_commit_hook + +echo "All git hooks installed successfully!" +echo "The pre-commit hook will run 'Scripts/lint' before each commit." diff --git a/Scripts/lint b/Scripts/lint new file mode 100755 index 0000000..8e11414 --- /dev/null +++ b/Scripts/lint @@ -0,0 +1,10 @@ +#!/bin/bash + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Go to the repository root (one level up from Scripts) +REPO_ROOT="$(dirname "$SCRIPT_DIR")" + +# Run swift format lint with full paths to preserve user's PWD +swift format lint --recursive --strict "$REPO_ROOT/Sources/" "$REPO_ROOT/Tests/" diff --git a/Sources/DevFoundation/Concurrency/DispatchQueue+NonOvercommitting.swift b/Sources/DevFoundation/Concurrency/DispatchQueue+NonOvercommitting.swift index a0a794c..d9f60b4 100644 --- a/Sources/DevFoundation/Concurrency/DispatchQueue+NonOvercommitting.swift +++ b/Sources/DevFoundation/Concurrency/DispatchQueue+NonOvercommitting.swift @@ -7,7 +7,6 @@ import Foundation - extension DispatchQueue { /// Creates a new non-overcommitting dispatch queue to which work items can be submitted. /// diff --git a/Sources/DevFoundation/Concurrency/DispatchQueue+Standard.swift b/Sources/DevFoundation/Concurrency/DispatchQueue+Standard.swift index a63d023..5d68444 100644 --- a/Sources/DevFoundation/Concurrency/DispatchQueue+Standard.swift +++ b/Sources/DevFoundation/Concurrency/DispatchQueue+Standard.swift @@ -7,7 +7,6 @@ import Foundation - extension DispatchQueue { /// A non-overcommitting, serial dispatch queue that can be used to execute utility tasks. /// diff --git a/Sources/DevFoundation/Concurrency/ExecutionGroup.swift b/Sources/DevFoundation/Concurrency/ExecutionGroup.swift index 7797845..9bded37 100644 --- a/Sources/DevFoundation/Concurrency/ExecutionGroup.swift +++ b/Sources/DevFoundation/Concurrency/ExecutionGroup.swift @@ -8,7 +8,6 @@ import Foundation import Synchronization - /// A dynamic group of tasks that tracks its execution status. /// /// Execution groups can be used to determine whether a group of related tasks is currently executing. It is ideal for @@ -67,7 +66,7 @@ public final class ExecutionGroup: Sendable { // Intentionally empty } - + /// Whether the group has any currently executing tasks. public var isExecuting: Bool { access(keyPath: \.isExecuting) diff --git a/Sources/DevFoundation/Date Providers/DateProvider.swift b/Sources/DevFoundation/Date Providers/DateProvider.swift index 819ba34..13258c7 100644 --- a/Sources/DevFoundation/Date Providers/DateProvider.swift +++ b/Sources/DevFoundation/Date Providers/DateProvider.swift @@ -7,7 +7,6 @@ import Foundation - /// A type that provides the current date. /// /// Date providers make it easier to test code that relies on dates. Tests can mock date providers to always return diff --git a/Sources/DevFoundation/Date Providers/DateProviders.swift b/Sources/DevFoundation/Date Providers/DateProviders.swift index dd5f4e6..5eef797 100644 --- a/Sources/DevFoundation/Date Providers/DateProviders.swift +++ b/Sources/DevFoundation/Date Providers/DateProviders.swift @@ -9,7 +9,6 @@ import Foundation import Synchronization import os - /// DevFoundation’s logger for outputting information about date providers. let dateProvidersLogger = Logger(subsystem: "DevFoundation", category: "dateProviders") @@ -19,7 +18,7 @@ public enum DateProviders { /// A mutex that synchronizes access to the current date provider. private static let currentDateProvider: Mutex = .init(SystemDateProvider()) - + /// The current date provider. /// /// - Warning: Setting this value to a date provider that references the auto-updating current date provider, e.g., diff --git a/Sources/DevFoundation/Date Providers/OffsetDateProvider.swift b/Sources/DevFoundation/Date Providers/OffsetDateProvider.swift index 08d417d..9188f58 100644 --- a/Sources/DevFoundation/Date Providers/OffsetDateProvider.swift +++ b/Sources/DevFoundation/Date Providers/OffsetDateProvider.swift @@ -7,12 +7,11 @@ import Foundation - /// A date provider that returns a date that is offset from a base provider’s by some fixed time interval. struct OffsetDateProvider: DateProvider where Base: DateProvider { /// The base date provider whose dates this provider’s dates are relative to. private let base: Base - + /// The time interval that this provider adds to the base provider’s dates. private let offset: TimeInterval @@ -26,7 +25,7 @@ struct OffsetDateProvider: DateProvider where Base: DateProvider { self.base = base self.offset = offset } - + var now: Date { return base.now + offset diff --git a/Sources/DevFoundation/Date Providers/ScaledDateProvider.swift b/Sources/DevFoundation/Date Providers/ScaledDateProvider.swift index 9050755..b05eff2 100644 --- a/Sources/DevFoundation/Date Providers/ScaledDateProvider.swift +++ b/Sources/DevFoundation/Date Providers/ScaledDateProvider.swift @@ -7,7 +7,6 @@ import Foundation - /// A date provider that runs at a different rate relative to a base date provider. struct ScaledDateProvider: DateProvider where Base: DateProvider { /// The base date provider whose dates this provider’s dates are relative to. @@ -19,7 +18,7 @@ struct ScaledDateProvider: DateProvider where Base: DateProvider { /// /// This value must be postive. private let scale: Double - + /// The base provider’s date when this provider was initialized. private let startDate: Date diff --git a/Sources/DevFoundation/Date Providers/SystemDateProvider.swift b/Sources/DevFoundation/Date Providers/SystemDateProvider.swift index 656905d..5eae0bb 100644 --- a/Sources/DevFoundation/Date Providers/SystemDateProvider.swift +++ b/Sources/DevFoundation/Date Providers/SystemDateProvider.swift @@ -7,7 +7,6 @@ import Foundation - /// A date provider whose dates match the current system date. struct SystemDateProvider: DateProvider { var now: Date { diff --git a/Sources/DevFoundation/DevFoundation.swift b/Sources/DevFoundation/DevFoundation.swift index ee7d505..837ffdd 100644 --- a/Sources/DevFoundation/DevFoundation.swift +++ b/Sources/DevFoundation/DevFoundation.swift @@ -7,7 +7,6 @@ import Foundation - /// Prepends the specified string with `"com.gauriar.devfoundation."`. /// /// - Parameter suffix: The string that will have DevFoundation’s reverse DNS prefix prepended to it. diff --git a/Sources/DevFoundation/Event Bus/BusEvent.swift b/Sources/DevFoundation/Event Bus/BusEvent.swift index 6d970e7..b25297c 100644 --- a/Sources/DevFoundation/Event Bus/BusEvent.swift +++ b/Sources/DevFoundation/Event Bus/BusEvent.swift @@ -7,7 +7,6 @@ import Foundation - /// An event that can be posted to an event bus. /// /// Types that conform to `BusEvent` have no requirements other than being `Sendable`. They are nearly always structs @@ -15,4 +14,4 @@ import Foundation /// /// `BusEvent`s that are also `Identifiable` enable special handling by ``BusEventObserver``s and /// ``ContextualBusEventObserver``, in particular. -public protocol BusEvent: Sendable { } +public protocol BusEvent: Sendable {} diff --git a/Sources/DevFoundation/Event Bus/BusEventObserver.swift b/Sources/DevFoundation/Event Bus/BusEventObserver.swift index 36cdb12..04a03a0 100644 --- a/Sources/DevFoundation/Event Bus/BusEventObserver.swift +++ b/Sources/DevFoundation/Event Bus/BusEventObserver.swift @@ -7,7 +7,6 @@ import Foundation - /// A type that can observe events posted to an event bus. /// /// In general, you will rarely need to conform to this type; ``ContextualBusEventObserver`` provides an implementation diff --git a/Sources/DevFoundation/Event Bus/ContextualBusEventObserver.swift b/Sources/DevFoundation/Event Bus/ContextualBusEventObserver.swift index ee9974f..c505f1e 100644 --- a/Sources/DevFoundation/Event Bus/ContextualBusEventObserver.swift +++ b/Sources/DevFoundation/Event Bus/ContextualBusEventObserver.swift @@ -8,7 +8,6 @@ import Foundation import Synchronization - /// A bus event observer that enables handling events with closures that share some common context. public final class ContextualBusEventObserver: BusEventObserver where Context: Sendable { /// A struct representing the type’s internal mutable state. @@ -35,7 +34,7 @@ public final class ContextualBusEventObserver: BusEventObserver where C /// The instance’s internal mutable state, protected by a mutex. private let state: Mutex = Mutex(.init()) - + /// Creates a new contextual bus event observer with the specified context. /// /// - Parameter context: The context that stores state and behavior common to the observer’s handlers. @@ -43,7 +42,7 @@ public final class ContextualBusEventObserver: BusEventObserver where C self.dispatcher = Dispatcher(context: context) } - + /// Adds a new handler for the specified event type. /// /// - Parameters: @@ -89,7 +88,7 @@ public final class ContextualBusEventObserver: BusEventObserver where C return handler } - + /// Removes the specified handler. /// /// Does nothing if the handler was not previously added. @@ -230,7 +229,7 @@ extension ContextualBusEventObserver { } } - + /// A wrapper for a registered handler. /// /// Instances of this type are used as values in `ContextualBusEventObserver.State`’s dictionaries. @@ -265,7 +264,7 @@ extension ContextualBusEventObserver { body(event, &context) } - + var eventTypeID: ObjectIdentifier { return ObjectIdentifier(Event.self) } @@ -276,7 +275,7 @@ extension ContextualBusEventObserver { private final class Dispatcher: Sendable { /// The shared context that can be mutated by handlers. nonisolated(unsafe) - private var context: Context + private var context: Context /// The dispatch queue that handlers are executed on. private let queue = DispatchQueue( @@ -292,7 +291,7 @@ extension ContextualBusEventObserver { self.context = context } - + /// Sends an event to an array of handlers, passing them the instance’s shared context. /// /// - Parameters: diff --git a/Sources/DevFoundation/Event Bus/EventBus.swift b/Sources/DevFoundation/Event Bus/EventBus.swift index 8313001..896e12b 100644 --- a/Sources/DevFoundation/Event Bus/EventBus.swift +++ b/Sources/DevFoundation/Event Bus/EventBus.swift @@ -8,19 +8,18 @@ import Foundation import Synchronization - /// An object that sends type-safe events to registered observers. public final class EventBus: HashableByID, Sendable { /// The bus’s observers. private let observers: Mutex<[any BusEventObserver]> = .init([]) - + /// Creates a new event bus with no registered observers. public init() { // Intentionally empty } - + /// Adds an observer to the event bus. /// /// - Parameter observer: The observer to add. @@ -40,7 +39,7 @@ public final class EventBus: HashableByID, Sendable { } } - + /// Posts an event to the event bus. /// /// Bus event observers are sent the event via ``BusEventObserver/observe(_:)-7p3d5``. Observers are called in the diff --git a/Sources/DevFoundation/Extensions/Data+Obfuscation.swift b/Sources/DevFoundation/Extensions/Data+Obfuscation.swift index d976f80..23f45bf 100644 --- a/Sources/DevFoundation/Extensions/Data+Obfuscation.swift +++ b/Sources/DevFoundation/Extensions/Data+Obfuscation.swift @@ -7,7 +7,6 @@ import Foundation - extension Data { /// Returns an obfuscated form of the data instance. /// @@ -25,8 +24,9 @@ extension Data { keySizeType: KeySize.Type, messageSizeType: MessageSize.Type ) throws -> Data - where KeySize : FixedWidthInteger, - MessageSize : FixedWidthInteger + where + KeySize: FixedWidthInteger, + MessageSize: FixedWidthInteger { guard count <= MessageSize.max else { throw DataObfuscationError.messageSizeExceedsMaximum @@ -57,8 +57,9 @@ extension Data { keySizeType: KeySize.Type, messageSizeType: MessageSize.Type ) throws -> Data - where KeySize : FixedWidthInteger, - MessageSize : FixedWidthInteger + where + KeySize: FixedWidthInteger & Sendable, + MessageSize: FixedWidthInteger & Sendable { guard let (message, keyStartIndex) = extractFieldData(at: 0, sizeType: messageSizeType) else { throw DataDeobfuscationError.invalidMessage @@ -89,16 +90,16 @@ extension Data { at index: Int, sizeType: FieldSize.Type ) -> (Data, Int)? - where FieldSize : FixedWidthInteger - { + where FieldSize: FixedWidthInteger & Sendable { let fieldSizeEndIndex = index + FieldSize.byteWidth guard endIndex >= fieldSizeEndIndex else { return nil } let fieldSizeData = self[index ..< fieldSizeEndIndex] - guard let fieldSize = FieldSize(bigEndianData: fieldSizeData).flatMap(Int.init(exactly:)), - fieldSize > 0 + guard + let fieldSize = FieldSize(bigEndianData: fieldSizeData).flatMap(Int.init(exactly:)), + fieldSize > 0 else { return nil } @@ -124,7 +125,7 @@ extension Data { /// - Parameters: /// - lhs: A data instance. /// - rhs: Another data instance. Must not be empty. - fileprivate static func ^(lhs: Data, rhs: Data) -> Data { + fileprivate static func ^ (lhs: Data, rhs: Data) -> Data { precondition(!rhs.isEmpty, "rhs must be non-empty") return Data( lhs.enumerated().map { (i, byte) in @@ -136,7 +137,7 @@ extension Data { /// Errors that can be thrown during data obfuscation. -enum DataObfuscationError : Error { +enum DataObfuscationError: Error { /// Indicates that the key is too large to be stored using the given key size type. case keySizeExceedsMaximum @@ -146,7 +147,7 @@ enum DataObfuscationError : Error { /// Errors that can be thrown during data deobfuscation. -enum DataDeobfuscationError : Error { +enum DataDeobfuscationError: Error { /// Indicates that a key could not be extracted from the obfuscated data. case invalidKey diff --git a/Sources/DevFoundation/Extensions/FixedWidthInteger+BigEndianData.swift b/Sources/DevFoundation/Extensions/FixedWidthInteger+BigEndianData.swift index 6ba9108..55ed862 100644 --- a/Sources/DevFoundation/Extensions/FixedWidthInteger+BigEndianData.swift +++ b/Sources/DevFoundation/Extensions/FixedWidthInteger+BigEndianData.swift @@ -7,14 +7,13 @@ import Foundation - extension FixedWidthInteger { /// The number of bytes used for the underlying binary representation of values of this type. static var byteWidth: Int { return bitWidth / 8 } - + /// Creates a new integer using the big-endian bytes in a `Data` instance. /// /// Returns `nil` if the data does not contain exactly `byteWidth` bytes. @@ -34,7 +33,7 @@ extension FixedWidthInteger { } ) } - + /// The integer’s big-endian representation as a `Data` instance. var bigEndianData: Data { diff --git a/Sources/DevFoundation/Extensions/RangeReplaceableCollection+RemoveFirst.swift b/Sources/DevFoundation/Extensions/RangeReplaceableCollection+RemoveFirst.swift index 8ba7e66..b4fa18c 100644 --- a/Sources/DevFoundation/Extensions/RangeReplaceableCollection+RemoveFirst.swift +++ b/Sources/DevFoundation/Extensions/RangeReplaceableCollection+RemoveFirst.swift @@ -7,7 +7,6 @@ import Foundation - extension RangeReplaceableCollection { /// Removes the first element in the collection that satisfies the given predicate. /// diff --git a/Sources/DevFoundation/Networking/Errors/AuthenticatorCancellationError.swift b/Sources/DevFoundation/Networking/Errors/AuthenticatorCancellationError.swift index 92ee0fc..7544008 100644 --- a/Sources/DevFoundation/Networking/Errors/AuthenticatorCancellationError.swift +++ b/Sources/DevFoundation/Networking/Errors/AuthenticatorCancellationError.swift @@ -7,7 +7,6 @@ import Foundation - /// An error indicating that an authenticated HTTP request was canceled by an authenticator. public struct AuthenticatorCancellationError: Error, Hashable { /// Creates a new authenticator cancellation error. diff --git a/Sources/DevFoundation/Networking/Errors/InvalidHTTPStatusCodeError.swift b/Sources/DevFoundation/Networking/Errors/InvalidHTTPStatusCodeError.swift index b447419..e3d3076 100644 --- a/Sources/DevFoundation/Networking/Errors/InvalidHTTPStatusCodeError.swift +++ b/Sources/DevFoundation/Networking/Errors/InvalidHTTPStatusCodeError.swift @@ -7,7 +7,6 @@ import Foundation - /// An error indicating that an HTTP response was received that had an invalid status code. public struct InvalidHTTPStatusCodeError: Error, Hashable { /// The HTTP URL response that was received. diff --git a/Sources/DevFoundation/Networking/Errors/InvalidWebServiceRequestError.swift b/Sources/DevFoundation/Networking/Errors/InvalidWebServiceRequestError.swift index 3122f50..6d054bc 100644 --- a/Sources/DevFoundation/Networking/Errors/InvalidWebServiceRequestError.swift +++ b/Sources/DevFoundation/Networking/Errors/InvalidWebServiceRequestError.swift @@ -7,7 +7,6 @@ import Foundation - /// An error indicating that a web service request was invalid. /// /// A web service request might be invalid because it couldn’t be used to construct a valid URL request or its HTTP body @@ -19,7 +18,7 @@ public struct InvalidWebServiceRequestError: Error { /// The underlying error which caused this error, if any. public let underlyingError: (any Error)? - + /// Creates a new invalid web service request error with the specified debug description and underyling error. /// /// - Parameters: diff --git a/Sources/DevFoundation/Networking/Errors/NonHTTPURLResponseError.swift b/Sources/DevFoundation/Networking/Errors/NonHTTPURLResponseError.swift index 16ad486..ece3087 100644 --- a/Sources/DevFoundation/Networking/Errors/NonHTTPURLResponseError.swift +++ b/Sources/DevFoundation/Networking/Errors/NonHTTPURLResponseError.swift @@ -7,13 +7,12 @@ import Foundation - /// An error indicating that an HTTP client received a non-HTTP URL response. public struct NonHTTPURLResponseError: Error, Hashable { /// The non-HTTP URL response that was received. public let urlResponse: URLResponse - + /// Creates a new non-HTTP URL response error. /// - Parameter urlResponse: The non-HTTP URL response that was received. public init(urlResponse: URLResponse) { diff --git a/Sources/DevFoundation/Networking/Errors/UnauthorizedHTTPRequestError.swift b/Sources/DevFoundation/Networking/Errors/UnauthorizedHTTPRequestError.swift index 5df1ed3..8ce5df0 100644 --- a/Sources/DevFoundation/Networking/Errors/UnauthorizedHTTPRequestError.swift +++ b/Sources/DevFoundation/Networking/Errors/UnauthorizedHTTPRequestError.swift @@ -7,7 +7,6 @@ import Foundation - /// An error indicating that an HTTP request failed because it was unauthorized. /// /// An error of this type is thrown by diff --git a/Sources/DevFoundation/Networking/Low-Level Clients/AuthenticatingHTTPClient.swift b/Sources/DevFoundation/Networking/Low-Level Clients/AuthenticatingHTTPClient.swift index e20dbeb..dbf9173 100644 --- a/Sources/DevFoundation/Networking/Low-Level Clients/AuthenticatingHTTPClient.swift +++ b/Sources/DevFoundation/Networking/Low-Level Clients/AuthenticatingHTTPClient.swift @@ -7,7 +7,6 @@ import Foundation - /// An HTTP client that uses an authenticator to authenticate requests. /// /// Authenticating HTTP clients use ``HTTPRequestAuthenticator``s to prepare their outgoing requests with authentication @@ -110,11 +109,13 @@ public final class AuthenticatingHTTPClient: Sendable where Authe previousFailures: [HTTPRequestAuthenticationFailure] ) async throws -> HTTPResponse { // Prepare the request, throwing a cancellation error if the authenticator returns nil - guard let preparedRequest = try await authenticator.prepare( - urlRequest, - context: authenticatorContext, - previousFailures: previousFailures - ) else { + guard + let preparedRequest = try await authenticator.prepare( + urlRequest, + context: authenticatorContext, + previousFailures: previousFailures + ) + else { throw AuthenticatorCancellationError() } diff --git a/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClient.swift b/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClient.swift index e35d3fe..2aa0692 100644 --- a/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClient.swift +++ b/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClient.swift @@ -7,19 +7,18 @@ import Foundation - /// A simple client for loading URL requests and returning an HTTP response. public final class HTTPClient: Sendable { /// The client’s underlying URL request loader. public let urlRequestLoader: any URLRequestLoader - + /// The client’s request interceptors. public let requestInterceptors: [any HTTPClientRequestInterceptor] /// The client’s response interceptors. public let responseInterceptors: [any HTTPClientResponseInterceptor] - + /// Creates a new HTTP client. /// - Parameters: /// - urlRequestLoader: The client’s underlying URL request loader. @@ -35,7 +34,7 @@ public final class HTTPClient: Sendable { self.responseInterceptors = responseInterceptors } - + /// Loads the specified URL request and asynchronously returns its HTTP response. /// /// Before loading the request, the client first allows its request interceptors the option to return it unchanged, @@ -72,11 +71,13 @@ public final class HTTPClient: Sendable { var interceptedResponse = HTTPResponse(httpURLResponse: httpURLResponse, body: data) for responseInterceptor in responseInterceptors { // If the interceptor returns nil, load the original request - guard let nextResponse = try await responseInterceptor.intercept( - interceptedResponse, - from: self, - for: interceptedRequest - ) else { + guard + let nextResponse = try await responseInterceptor.intercept( + interceptedResponse, + from: self, + for: interceptedRequest + ) + else { try Task.checkCancellation() return try await load(urlRequest) } diff --git a/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClientRequestInterceptor.swift b/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClientRequestInterceptor.swift index a346494..8e681df 100644 --- a/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClientRequestInterceptor.swift +++ b/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClientRequestInterceptor.swift @@ -7,7 +7,6 @@ import Foundation - /// A type that can intercept and potentially modify a request before an HTTP client loads it. public protocol HTTPClientRequestInterceptor: Sendable { /// Intercepts a request from an HTTP client. diff --git a/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClientResponseInterceptor.swift b/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClientResponseInterceptor.swift index 7f714a8..f6807db 100644 --- a/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClientResponseInterceptor.swift +++ b/Sources/DevFoundation/Networking/Low-Level Clients/HTTPClientResponseInterceptor.swift @@ -7,7 +7,6 @@ import Foundation - /// A type that can intercept and potentially modify an HTTP response before an HTTP client returns it to a caller. public protocol HTTPClientResponseInterceptor: Sendable { /// Intercepts a response from an HTTP client. diff --git a/Sources/DevFoundation/Networking/Low-Level Clients/HTTPRequestAuthenticationFailure.swift b/Sources/DevFoundation/Networking/Low-Level Clients/HTTPRequestAuthenticationFailure.swift index f6285fd..5ee1e56 100644 --- a/Sources/DevFoundation/Networking/Low-Level Clients/HTTPRequestAuthenticationFailure.swift +++ b/Sources/DevFoundation/Networking/Low-Level Clients/HTTPRequestAuthenticationFailure.swift @@ -7,7 +7,6 @@ import Foundation - /// Information about an HTTP request authentication failure. /// /// Authentication failures are relevant if you are creating an ``HTTPRequestAuthenticator``, but are otherwise of @@ -15,14 +14,14 @@ import Foundation public struct HTTPRequestAuthenticationFailure: Sendable { /// The prepared request whose response contained an authentication error. public let preparedRequest: URLRequest - + /// The response to the prepared request. public let response: HTTPResponse /// The authentication error that occurred. public let error: any Error - + /// Creates a new HTTP request authentication failure with the specified prepared request, response, and error. /// - Parameters: /// - preparedRequest: The prepared request whose response contained an authentication error. diff --git a/Sources/DevFoundation/Networking/Low-Level Clients/HTTPRequestAuthenticator.swift b/Sources/DevFoundation/Networking/Low-Level Clients/HTTPRequestAuthenticator.swift index abc6a36..2046087 100644 --- a/Sources/DevFoundation/Networking/Low-Level Clients/HTTPRequestAuthenticator.swift +++ b/Sources/DevFoundation/Networking/Low-Level Clients/HTTPRequestAuthenticator.swift @@ -7,7 +7,6 @@ import Foundation - /// A type that authenticates requests on behalf of an authenticating HTTP client. public protocol HTTPRequestAuthenticator: Sendable { /// A type that contains contextual information for the authenticator. diff --git a/Sources/DevFoundation/Networking/Low-Level Clients/URLRequestLoader.swift b/Sources/DevFoundation/Networking/Low-Level Clients/URLRequestLoader.swift index a04c032..99bfa90 100644 --- a/Sources/DevFoundation/Networking/Low-Level Clients/URLRequestLoader.swift +++ b/Sources/DevFoundation/Networking/Low-Level Clients/URLRequestLoader.swift @@ -7,7 +7,6 @@ import Foundation - public protocol URLRequestLoader: Sendable { /// Loads a URL request and delivers its data asynchronously. /// diff --git a/Sources/DevFoundation/Networking/Requests and Responses/HTTPBody.swift b/Sources/DevFoundation/Networking/Requests and Responses/HTTPBody.swift index 5f2b3e6..d025a40 100644 --- a/Sources/DevFoundation/Networking/Requests and Responses/HTTPBody.swift +++ b/Sources/DevFoundation/Networking/Requests and Responses/HTTPBody.swift @@ -7,7 +7,6 @@ import Foundation - /// The body of an HTTP request, which pairs the body’s data with its content type. public struct HTTPBody: Hashable, Sendable { /// The body’s content type. diff --git a/Sources/DevFoundation/Networking/Requests and Responses/HTTPHeaderField.swift b/Sources/DevFoundation/Networking/Requests and Responses/HTTPHeaderField.swift index c1a165b..214213c 100644 --- a/Sources/DevFoundation/Networking/Requests and Responses/HTTPHeaderField.swift +++ b/Sources/DevFoundation/Networking/Requests and Responses/HTTPHeaderField.swift @@ -7,7 +7,6 @@ import Foundation - /// An HTTP header field. /// /// DevFoundation provides a few common header fields out of the box, but as with all typed extensible enums, you can @@ -15,7 +14,7 @@ import Foundation public struct HTTPHeaderField: TypedExtensibleEnum { public let rawValue: String - + /// Creates a new HTTP header field. /// /// The raw value is lowercased before being stored. @@ -28,7 +27,7 @@ public struct HTTPHeaderField: TypedExtensibleEnum { extension HTTPHeaderField { - /// The Accept HTTP header field, `accept`. + /// The Accept HTTP header field, `accept`. public static let accept = HTTPHeaderField("accept") /// The Accept Language HTTP header field, `accept-language`. diff --git a/Sources/DevFoundation/Networking/Requests and Responses/HTTPHeaderItem.swift b/Sources/DevFoundation/Networking/Requests and Responses/HTTPHeaderItem.swift index d66886f..79f6695 100644 --- a/Sources/DevFoundation/Networking/Requests and Responses/HTTPHeaderItem.swift +++ b/Sources/DevFoundation/Networking/Requests and Responses/HTTPHeaderItem.swift @@ -7,7 +7,6 @@ import Foundation - /// An HTTP header item, including its field and value. public struct HTTPHeaderItem: Hashable, Sendable { /// The HTTP header item’s field. @@ -16,7 +15,7 @@ public struct HTTPHeaderItem: Hashable, Sendable { /// The HTTP header item’s value. public var value: String - + /// Creates a new HTTP header item with the specified field and value. /// - Parameters: /// - field: The HTTP header item’s field. @@ -69,7 +68,7 @@ extension URLRequest { addHTTPHeaderValue(item.value, for: item.field) } - + /// Sets the specified HTTP header item on the request. /// /// - Parameter item: The HTTP header item to set. diff --git a/Sources/DevFoundation/Networking/Requests and Responses/HTTPMethod.swift b/Sources/DevFoundation/Networking/Requests and Responses/HTTPMethod.swift index 2af74a2..05d3b3a 100644 --- a/Sources/DevFoundation/Networking/Requests and Responses/HTTPMethod.swift +++ b/Sources/DevFoundation/Networking/Requests and Responses/HTTPMethod.swift @@ -7,7 +7,6 @@ import Foundation - /// An HTTP method. /// /// DevFoundation provides constants for ``get``, ``post``, ``put``, ``patch``, and ``delete``. Other HTTP methods can @@ -15,7 +14,7 @@ import Foundation public struct HTTPMethod: TypedExtensibleEnum { public let rawValue: String - + /// Creates a new HTTP method with the specified raw value. /// /// The raw value is uppercased before being stored. diff --git a/Sources/DevFoundation/Networking/Requests and Responses/HTTPResponse.swift b/Sources/DevFoundation/Networking/Requests and Responses/HTTPResponse.swift index 29114ce..6b01dce 100644 --- a/Sources/DevFoundation/Networking/Requests and Responses/HTTPResponse.swift +++ b/Sources/DevFoundation/Networking/Requests and Responses/HTTPResponse.swift @@ -7,7 +7,6 @@ import Foundation - /// An HTTP response, which pairs an `HTTPURLResponse` with a type-safe representation of the response’s body. public struct HTTPResponse { /// The response’s HTTP URL response. @@ -16,7 +15,7 @@ public struct HTTPResponse { /// The response’s body. public var body: Body - + /// Creates a new HTTP response with the specified HTTP URL response and body. /// - Parameters: /// - httpURLResponse: The response’s HTTP URL response. @@ -32,7 +31,7 @@ public struct HTTPResponse { return httpURLResponse.httpStatusCode } - + /// Returns a copy of the response whose body is the result of calling a closure. /// /// - Parameter transform: A closure to transform the response’s body. @@ -47,9 +46,9 @@ public struct HTTPResponse { } -extension HTTPResponse: Equatable where Body: Equatable { } -extension HTTPResponse: Hashable where Body: Hashable { } -extension HTTPResponse: Sendable where Body: Sendable { } +extension HTTPResponse: Equatable where Body: Equatable {} +extension HTTPResponse: Hashable where Body: Hashable {} +extension HTTPResponse: Sendable where Body: Sendable {} // MARK: - Status Codes @@ -61,7 +60,7 @@ extension HTTPResponse { /// For example, to throw if a status code indicates an error, you can write: /// /// try httpResponse.throwIfStatusCode(\.isError) - /// + /// /// The function returns `self` if it doesn’t throw, which allows you to chain it with calls to ``mapBody(_:)``. /// /// - Parameter shouldThrow: A predicate that returns whether the function should throw. diff --git a/Sources/DevFoundation/Networking/Requests and Responses/HTTPStatusCode.swift b/Sources/DevFoundation/Networking/Requests and Responses/HTTPStatusCode.swift index f4375a5..ae04d87 100644 --- a/Sources/DevFoundation/Networking/Requests and Responses/HTTPStatusCode.swift +++ b/Sources/DevFoundation/Networking/Requests and Responses/HTTPStatusCode.swift @@ -7,7 +7,6 @@ import Foundation - /// A type-safe representation of an HTTP status code. public struct HTTPStatusCode: TypedExtensibleEnum { public let rawValue: Int diff --git a/Sources/DevFoundation/Networking/Requests and Responses/MediaType.swift b/Sources/DevFoundation/Networking/Requests and Responses/MediaType.swift index 16a102b..52b1826 100644 --- a/Sources/DevFoundation/Networking/Requests and Responses/MediaType.swift +++ b/Sources/DevFoundation/Networking/Requests and Responses/MediaType.swift @@ -8,7 +8,6 @@ import Foundation import UniformTypeIdentifiers - /// A typed extensible enum for representing IANA media types. /// /// Media types are often referred to as MIME types. DevFoundation includes a few common media types like ``json`` and @@ -16,7 +15,7 @@ import UniformTypeIdentifiers public struct MediaType: TypedExtensibleEnum { public let rawValue: String - + /// Creates a new media type with the specified raw value. /// /// The raw value is lowercased before being stored. @@ -37,15 +36,15 @@ public struct MediaType: TypedExtensibleEnum { extension MediaType { - /// The media type for JSON data, `"application/json"`. + /// The media type for JSON data, "application/json". public static let json = MediaType("application/json") - /// The media type for arbitrary binary data, `"application/octet-stream"`. + /// The media type for arbitrary binary data, "application/octet-stream". public static let octetStream = MediaType("application/octet-stream") - /// The media type for plain text, `"text/plain"`. + /// The media type for plain text, "text/plain". public static let plainText = MediaType("text/plain") - /// The media type for URL-encoded HTML form data, `"application/x-www-form-urlencoded"`. + /// The media type for URL-encoded HTML form data, "application/x-www-form-urlencoded". public static let wwwFormURLEncoded = MediaType("application/x-www-form-urlencoded") } diff --git a/Sources/DevFoundation/Networking/Requests and Responses/URLPathComponent.swift b/Sources/DevFoundation/Networking/Requests and Responses/URLPathComponent.swift index b5cf224..347984d 100644 --- a/Sources/DevFoundation/Networking/Requests and Responses/URLPathComponent.swift +++ b/Sources/DevFoundation/Networking/Requests and Responses/URLPathComponent.swift @@ -7,7 +7,6 @@ import Foundation - /// A component in a URL path. /// /// URL path components are used by ``WebServiceRequest``s to perform some basic sanitization of URLs. Instead of @@ -21,7 +20,7 @@ public struct URLPathComponent: ExpressibleByStringLiteral, Hashable, RawReprese /// The URL path component’s raw value. public let rawValue: String - + /// Creates a new URL path component with the specified raw value. /// /// Any `"/"` characters are removed from `rawValue` before storing it. @@ -35,7 +34,7 @@ public struct URLPathComponent: ExpressibleByStringLiteral, Hashable, RawReprese public init(rawValue: String) { self.init(rawValue) } - + public init(stringLiteral: StringLiteralType) { self.init(stringLiteral) diff --git a/Sources/DevFoundation/Networking/Web Service Client/BaseURLConfiguring.swift b/Sources/DevFoundation/Networking/Web Service Client/BaseURLConfiguring.swift index feecb00..f849003 100644 --- a/Sources/DevFoundation/Networking/Web Service Client/BaseURLConfiguring.swift +++ b/Sources/DevFoundation/Networking/Web Service Client/BaseURLConfiguring.swift @@ -7,7 +7,6 @@ import Foundation - /// A type that provides a way to refer to a web service’s base URLs symbolically and to get the real URLs for those /// symbols. /// diff --git a/Sources/DevFoundation/Networking/Web Service Client/JSONBodyWebServiceRequest.swift b/Sources/DevFoundation/Networking/Web Service Client/JSONBodyWebServiceRequest.swift index 3436715..1ea2c5d 100644 --- a/Sources/DevFoundation/Networking/Web Service Client/JSONBodyWebServiceRequest.swift +++ b/Sources/DevFoundation/Networking/Web Service Client/JSONBodyWebServiceRequest.swift @@ -7,14 +7,13 @@ import Foundation - /// A web service request with a JSON body. /// /// Types that conform to `JSONBodyWebServiceRequest`s provide a JSON body as an encodable type. public protocol JSONBodyWebServiceRequest: WebServiceRequest { /// The type of the request’s body expressed as an encodable type. associatedtype JSONBody: Encodable - + /// The JSON encoder to use when creating the body’s data. /// /// This defaults to `JSONEncoder()`, but requests with specific needs can customize it. diff --git a/Sources/DevFoundation/Networking/Web Service Client/SingleBaseURLConfiguration.swift b/Sources/DevFoundation/Networking/Web Service Client/SingleBaseURLConfiguration.swift index 4cf5326..ca53ecf 100644 --- a/Sources/DevFoundation/Networking/Web Service Client/SingleBaseURLConfiguration.swift +++ b/Sources/DevFoundation/Networking/Web Service Client/SingleBaseURLConfiguration.swift @@ -7,7 +7,6 @@ import Foundation - /// A base URL configuration that has a single URL. public struct SingleBaseURLConfiguration: BaseURLConfiguring { public typealias BaseURL = Void @@ -15,7 +14,7 @@ public struct SingleBaseURLConfiguration: BaseURLConfiguring { /// The configuration’s single base URL. public let baseURL: URL - + /// Creates a new single base URL configuration with the specified URL. /// /// - Parameter baseURL: The single base URL that the configuration has. diff --git a/Sources/DevFoundation/Networking/Web Service Client/WebServiceClient.swift b/Sources/DevFoundation/Networking/Web Service Client/WebServiceClient.swift index fb90fa8..1267fd7 100644 --- a/Sources/DevFoundation/Networking/Web Service Client/WebServiceClient.swift +++ b/Sources/DevFoundation/Networking/Web Service Client/WebServiceClient.swift @@ -7,7 +7,6 @@ import Foundation - /// A client for a web service. /// /// Web service clients provides a declarative approach for accessing a web service. The client itself is simple: @@ -28,7 +27,7 @@ where BaseURLConfiguration: BaseURLConfiguring, Authenticator: HTTPRequestAuthen /// The base URL configuration that the web service client uses to create its requests. public let baseURLConfiguration: BaseURLConfiguration - + /// Creates a new web service client with the specified properties. /// /// - Parameters: @@ -79,7 +78,7 @@ where BaseURLConfiguration: BaseURLConfiguring, Authenticator: HTTPRequestAuthen return authenticatingHTTPClient.responseInterceptors } - + /// Loads a request and returns its mapped response. /// /// This function works by creating a URL request for the web service request by calling @@ -95,9 +94,10 @@ where BaseURLConfiguration: BaseURLConfiguring, Authenticator: HTTPRequestAuthen public func load( _ request: Request ) async throws -> Request.MappedResponse - where Request: WebServiceRequest, - Request.BaseURLConfiguration == BaseURLConfiguration, - Request.Authenticator == Authenticator + where + Request: WebServiceRequest, + Request.BaseURLConfiguration == BaseURLConfiguration, + Request.Authenticator == Authenticator { let urlRequest = try request.urlRequest(with: baseURLConfiguration) let response = try await authenticatingHTTPClient.load( diff --git a/Sources/DevFoundation/Networking/Web Service Client/WebServiceRequest.swift b/Sources/DevFoundation/Networking/Web Service Client/WebServiceRequest.swift index 76d168a..7877906 100644 --- a/Sources/DevFoundation/Networking/Web Service Client/WebServiceRequest.swift +++ b/Sources/DevFoundation/Networking/Web Service Client/WebServiceRequest.swift @@ -7,7 +7,6 @@ import Foundation - /// A type that describes the parts of a web service request and how to handle the response. /// /// `WebServiceRequest` provides a declarative interface for creating URL requests and handling their responses. This @@ -40,7 +39,7 @@ public protocol WebServiceRequest: Sendable { /// /// This is most often an ``HTTPResponse`` with a specific body type. associatedtype MappedResponse - + /// The HTTP method for the web service request. var httpMethod: HTTPMethod { get } @@ -58,23 +57,23 @@ public protocol WebServiceRequest: Sendable { /// /// A default implementation of this function is provided if `BaseURLConfiguration.BaseURL` is `Void`. var baseURL: BaseURLConfiguration.BaseURL { get } - + /// The path components of the web service request’s URL relative to its base URL. /// /// Path components are automatically percent-encoded when a URL request is created, and thus should not be /// percent-encoded in advance. var pathComponents: [URLPathComponent] { get } - + /// The URL fragment for the web service request. /// /// Defaults to `nil`. var fragment: String? { get } - + /// The web service request’s URL query items. /// /// Defaults to `[]`. var queryItems: [URLQueryItem] { get } - + /// Whether the web service request automatically percent-encodes query items. /// /// Defaults to `true`. @@ -167,7 +166,7 @@ extension WebServiceRequest { return request } - + /// Returns the request’s URL using the specified base URL configuration. /// /// - Parameter baseURLConfiguration: The configuration from which to get a base URL for the request. @@ -176,9 +175,10 @@ extension WebServiceRequest { let baseURL = baseURLConfiguration.url(for: baseURL) let path = pathComponents.map(\.rawValue).joined(separator: "/") - guard let percentEncodedPath = path.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed), - let url = percentEncodedPath.isEmpty ? baseURL : URL(string: percentEncodedPath, relativeTo: baseURL), - var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) + guard + let percentEncodedPath = path.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed), + let url = percentEncodedPath.isEmpty ? baseURL : URL(string: percentEncodedPath, relativeTo: baseURL), + var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) else { // This line is likely impossible to hit given how we’ve written this code return nil diff --git a/Sources/DevFoundation/Utility Types/AnySendableHashable.swift b/Sources/DevFoundation/Utility Types/AnySendableHashable.swift index e4f99a3..5c367d3 100644 --- a/Sources/DevFoundation/Utility Types/AnySendableHashable.swift +++ b/Sources/DevFoundation/Utility Types/AnySendableHashable.swift @@ -7,12 +7,10 @@ import Foundation - /// A type-erased sendable, hashable value. public struct AnySendableHashable: Hashable, Sendable { /// The ``AnyHashable`` that this instance wraps. - nonisolated(unsafe) - let _base: AnyHashable + nonisolated(unsafe) let _base: AnyHashable /// Creates a type-erased sendable, hashable value that wraps the given instance. diff --git a/Sources/DevFoundation/Utility Types/DottedHierarchicalID.swift b/Sources/DevFoundation/Utility Types/DottedHierarchicalID.swift index d13d176..d69847e 100644 --- a/Sources/DevFoundation/Utility Types/DottedHierarchicalID.swift +++ b/Sources/DevFoundation/Utility Types/DottedHierarchicalID.swift @@ -7,7 +7,6 @@ import Foundation - /// A type representing a string identifier that uses period characters to indicate hierarchy. /// /// `DottedHierarchicalIDs`s provide a type-safe way to store IDs in what is commonly referred to as reverse-DNS @@ -79,8 +78,9 @@ extension DottedHierarchicalID { public func lowestCommonAncestor(with other: Self) -> Self? { var ancestor: Self? = nil for component in components.map(String.init(_:)) { - guard let candidate = ancestor.flatMap({ $0.appending(component) }) ?? Self(rawValue: component), - candidate.isAncestor(of: other) + guard + let candidate = ancestor.flatMap({ $0.appending(component) }) ?? Self(rawValue: component), + candidate.isAncestor(of: other) else { return ancestor } diff --git a/Sources/DevFoundation/Utility Types/ExpiringValue.swift b/Sources/DevFoundation/Utility Types/ExpiringValue.swift index f1501f5..1bf065d 100644 --- a/Sources/DevFoundation/Utility Types/ExpiringValue.swift +++ b/Sources/DevFoundation/Utility Types/ExpiringValue.swift @@ -7,23 +7,22 @@ import Foundation - /// A value that can expire after its lifetime is complete. /// -/// This type is useful for implementing time-based caches. +/// This type is useful for implementing time-based caches. public struct ExpiringValue { /// The value. public let value: Value - + /// The range of dates encompassing the value’s lifetime. /// /// The value is expired for any dates outside of this range. public let lifetimeRange: ClosedRange - + /// Whether the value has been manually expired by calling ``expire()``. private var isManuallyExpired: Bool = false - + /// Creates a new expiring value with the specified value and lifetime range. /// /// - Parameters: @@ -48,7 +47,7 @@ public struct ExpiringValue { self.lifetimeRange = now ... (now + lifetimeDuration) } - + /// Manually expires the value. /// /// Use this function mark a value as expired, regardless of its lifetime range. @@ -56,7 +55,7 @@ public struct ExpiringValue { isManuallyExpired = true } - + /// Whether the value is expired now. /// /// See ``isExpired(at:)`` for details about how expiration is computed. @@ -64,7 +63,7 @@ public struct ExpiringValue { return isExpired(at: DateProviders.current.now) } - + /// Whether the value is expired at a specified date. /// /// This function returns true if the value was manually expired or `date` is outside the lifetime range of the @@ -77,8 +76,8 @@ public struct ExpiringValue { } -extension ExpiringValue: Decodable where Value: Decodable { } -extension ExpiringValue: Encodable where Value: Encodable { } -extension ExpiringValue: Equatable where Value: Equatable { } -extension ExpiringValue: Hashable where Value: Hashable { } -extension ExpiringValue: Sendable where Value: Sendable { } +extension ExpiringValue: Decodable where Value: Decodable {} +extension ExpiringValue: Encodable where Value: Encodable {} +extension ExpiringValue: Equatable where Value: Equatable {} +extension ExpiringValue: Hashable where Value: Hashable {} +extension ExpiringValue: Sendable where Value: Sendable {} diff --git a/Sources/DevFoundation/Utility Types/GibberishGenerator.swift b/Sources/DevFoundation/Utility Types/GibberishGenerator.swift index bc6ca74..a633a79 100644 --- a/Sources/DevFoundation/Utility Types/GibberishGenerator.swift +++ b/Sources/DevFoundation/Utility Types/GibberishGenerator.swift @@ -7,7 +7,6 @@ import Foundation - /// An object that generates gibberish. /// /// Each gibberish generator can generate words, sentences or paragraphs. A generator’s words and sentences are stored @@ -174,6 +173,7 @@ public struct GibberishGenerator: Sendable { using randomNumberGenerator: inout some RandomNumberGenerator, sentenceCount: Int? = nil ) -> String { + // swift-format-ignore let sentenceCount = sentenceCount ?? Int.random( in: lexicon.preferredSentencesPerParagraphRange, using: &randomNumberGenerator @@ -214,7 +214,7 @@ extension GibberishGenerator { "@ @ @ @ @, @ @ @.", "@ @ @ @ @; @ @ @ @ @.", "@ @ @ @ @.", - "@ @ @ @ @ @." , + "@ @ @ @ @ @.", "@ @ @ @ @ @ @, @ @ @ @ @ @.", "@ @ @ @ @ @ @.", "@ @ @ @ @ @ @ @ @; @ @ @ @ @ @.", @@ -224,7 +224,7 @@ extension GibberishGenerator { "@ @ @ @ @ @ @ @; @ @ @ @.", "@ @ @ @ @, @ @ @ @ @ @ @ @ @.", "@ @ @, @ @ @ @ @ @, @ @ @.", - "@ @ @ @ @ @ @, @ @ @, @ @ @ @." + "@ @ @ @ @ @ @, @ @ @, @ @ @ @.", ], templateWordToken: "@", words: [ @@ -314,7 +314,7 @@ extension GibberishGenerator { "viverra", "volenisis", "volesed", "volobore", "volor", "volore", "volorerci", "voloreros", "volumsan", "volut", "volutpat", "vulla", "vullam", "vullan", "vullandigna", "vullandio", "vulluptat", "vulluptatet", "vulluptatum", "vulput", "vulputat", "vulputate", "vulpute", "wis", "wiscinim", "wisi", - "wisis", "wisl", "wismod", "wismodi", "wismoloreet", "wisse", "xer" + "wisis", "wisl", "wismod", "wismodi", "wismoloreet", "wisse", "xer", ] ) diff --git a/Sources/DevFoundation/Utility Types/HashableByID.swift b/Sources/DevFoundation/Utility Types/HashableByID.swift index 4e1a44f..9e1ff78 100644 --- a/Sources/DevFoundation/Utility Types/HashableByID.swift +++ b/Sources/DevFoundation/Utility Types/HashableByID.swift @@ -7,14 +7,13 @@ import Foundation - /// A type that conforms to `Hashable` using only its ID. /// /// `HashableByID` provides default conformance to `Hashable` as follows: /// /// - Two instances are equal if their IDs are the same. /// - An instance’s hash is computed using only its ID. -public protocol HashableByID: Hashable, Identifiable { } +public protocol HashableByID: Hashable, Identifiable {} extension HashableByID { diff --git a/Sources/DevFoundation/Utility Types/JSONValue.swift b/Sources/DevFoundation/Utility Types/JSONValue.swift index 9f00d7b..5c5d136 100644 --- a/Sources/DevFoundation/Utility Types/JSONValue.swift +++ b/Sources/DevFoundation/Utility Types/JSONValue.swift @@ -7,7 +7,6 @@ import Foundation - /// A type-safe representation of a JSON payload. /// /// JSON values can only represent valid JSON payloads. A JSON value can be an array, boolean, number, object, string, @@ -216,7 +215,7 @@ struct JSONCodingKey: CodingKey { // MARK: - Hashable extension JSONValue: Hashable { - public static func ==(lhs: Self, rhs: Self) -> Bool { + public static func == (lhs: Self, rhs: Self) -> Bool { switch (lhs, rhs) { case (.array(let left), .array(let right)): return left.compactMap(\.unwrapped) == right.compactMap(\.unwrapped) @@ -322,7 +321,7 @@ extension JSONValue { /// This is equivalent to `.ifPresent(value.map(JSONValue.number(_:)))`. /// /// - Parameter value: The optional binary floating point to wrap. - public static func ifPresent(_ value: (some BinaryFloatingPoint)?) -> JSONValue { + public static func ifPresent(_ value: (some BinaryFloatingPoint & Sendable)?) -> JSONValue { return .ifPresent(value.map(JSONValue.number(_:))) } @@ -332,7 +331,7 @@ extension JSONValue { /// This is equivalent to `.ifPresent(value.map(JSONValue.number(_:)))`. /// /// - Parameter value: The optional binary floating point to wrap. - public static func ifPresent(_ integer: (some SignedInteger)?) -> JSONValue { + public static func ifPresent(_ integer: (some SignedInteger & Sendable)?) -> JSONValue { return .ifPresent(integer.map(JSONValue.number(_:))) } @@ -352,7 +351,7 @@ extension JSONValue { /// This is equivalent to `.ifPresent(value.map(JSONValue.number(_:)))`. /// /// - Parameter value: The optional unsigned integer to wrap. - public static func ifPresent(_ value: (some UnsignedInteger)?) -> JSONValue { + public static func ifPresent(_ value: (some UnsignedInteger & Sendable)?) -> JSONValue { return .ifPresent(value.map(JSONValue.number(_:))) } @@ -468,8 +467,8 @@ extension JSONValue { self = .array(elements) case let bool as Bool: self = .boolean(bool) - case let dictionary as [String : Any?]: - var elements: [String : JSONValue] = [:] + case let dictionary as [String: Any?]: + var elements: [String: JSONValue] = [:] for (key, anyValue) in dictionary { guard let value = JSONValue(value: anyValue) else { diff --git a/Sources/DevFoundation/Utility Types/SoftwareComponentID.swift b/Sources/DevFoundation/Utility Types/SoftwareComponentID.swift index efc73a1..2ac5c96 100644 --- a/Sources/DevFoundation/Utility Types/SoftwareComponentID.swift +++ b/Sources/DevFoundation/Utility Types/SoftwareComponentID.swift @@ -7,7 +7,6 @@ import Foundation - /// A reverse-DNS identifier for a software component. /// /// The term _software component_ is intentionally vaguely defined. It could be a function, type, subsystem, module or diff --git a/Sources/DevFoundation/Utility Types/TopLevelCoding.swift b/Sources/DevFoundation/Utility Types/TopLevelCoding.swift index 29fb5dc..4fdfab8 100644 --- a/Sources/DevFoundation/Utility Types/TopLevelCoding.swift +++ b/Sources/DevFoundation/Utility Types/TopLevelCoding.swift @@ -7,7 +7,6 @@ import Foundation - /// A type that can decode `Decodable` values. /// /// This type differs from Combine’s `TopLevelDecoder` in that it also requires a mutable ``userInfo`` dictionary. @@ -15,13 +14,8 @@ public protocol TopLevelDecoder: AnyObject { /// The type this decoder accepts. associatedtype Input -#if compiler(>=6.1) /// A dictionary you use to customize the decoding process by providing contextual information. var userInfo: [CodingUserInfoKey: any Sendable] { get set } -#else - /// A dictionary you use to customize the decoding process by providing contextual information. - var userInfo: [CodingUserInfoKey: Any] { get set } -#endif /// Decodes a value of the specified type from an input. /// @@ -39,13 +33,8 @@ public protocol TopLevelEncoder: AnyObject { /// The type this encoder produces. associatedtype Output -#if compiler(>=6.1) /// A dictionary you use to customize the encoding process by providing contextual information. var userInfo: [CodingUserInfoKey: any Sendable] { get set } -#else - /// A dictionary you use to customize the encoding process by providing contextual information. - var userInfo: [CodingUserInfoKey: Any] { get set } -#endif /// Encodes a value of the specified type. /// @@ -54,11 +43,11 @@ public protocol TopLevelEncoder: AnyObject { } -extension JSONDecoder: TopLevelDecoder { } -extension JSONEncoder: TopLevelEncoder { } +extension JSONDecoder: TopLevelDecoder {} +extension JSONEncoder: TopLevelEncoder {} -extension PropertyListDecoder: TopLevelDecoder { } -extension PropertyListEncoder: TopLevelEncoder { } +extension PropertyListDecoder: TopLevelDecoder {} +extension PropertyListEncoder: TopLevelEncoder {} // MARK: - Decoding Top-Level Keys diff --git a/Sources/DevFoundation/Utility Types/TypedExtensibleEnum.swift b/Sources/DevFoundation/Utility Types/TypedExtensibleEnum.swift index 302a629..52a30c7 100644 --- a/Sources/DevFoundation/Utility Types/TypedExtensibleEnum.swift +++ b/Sources/DevFoundation/Utility Types/TypedExtensibleEnum.swift @@ -7,7 +7,6 @@ import Foundation - /// A type whose instances represent an extensible set of known values. /// /// Typed extensible enums provide an extensible way to represent strongly-typed constants. Its interface is modeled diff --git a/Sources/dfob/ObfuscateCommand.swift b/Sources/dfob/ObfuscateCommand.swift index 98945e0..d4c3968 100644 --- a/Sources/dfob/ObfuscateCommand.swift +++ b/Sources/dfob/ObfuscateCommand.swift @@ -9,12 +9,11 @@ import ArgumentParser import DevFoundation import Foundation - /// A command for obfuscating and deobfuscating data. @main -struct ObfuscateCommand : AsyncParsableCommand { +struct ObfuscateCommand: AsyncParsableCommand { /// The action that the command should take. - enum Action : EnumerableFlag { + enum Action: EnumerableFlag { /// Indicates that the command should obfuscate. case obfuscate @@ -77,8 +76,9 @@ struct ObfuscateCommand : AsyncParsableCommand { return FileHandle.standardOutput } - guard FileManager.default.createFile(atPath: outputPath, contents: nil), - let fileHandle = FileHandle(forWritingAtPath: outputPath) + guard + FileManager.default.createFile(atPath: outputPath, contents: nil), + let fileHandle = FileHandle(forWritingAtPath: outputPath) else { fatalError("Could not open output file at \(outputPath).") } diff --git a/Tests/DevFoundationTests/Concurrency/DispatchQueue+NonOvercommittingTests.swift b/Tests/DevFoundationTests/Concurrency/DispatchQueue+NonOvercommittingTests.swift index ea903e5..98461f2 100644 --- a/Tests/DevFoundationTests/Concurrency/DispatchQueue+NonOvercommittingTests.swift +++ b/Tests/DevFoundationTests/Concurrency/DispatchQueue+NonOvercommittingTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct DispatchQueue_NonOvercommittingTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Concurrency/DispatchQueue+StandardTests.swift b/Tests/DevFoundationTests/Concurrency/DispatchQueue+StandardTests.swift index 1b3eaf2..37f6fd1 100644 --- a/Tests/DevFoundationTests/Concurrency/DispatchQueue+StandardTests.swift +++ b/Tests/DevFoundationTests/Concurrency/DispatchQueue+StandardTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct DispatchQueue_StandardTests { @Test func utilityQueueHasCorrectProperties() { diff --git a/Tests/DevFoundationTests/Concurrency/ExecutionGroupTests.swift b/Tests/DevFoundationTests/Concurrency/ExecutionGroupTests.swift index bc5b539..427822d 100644 --- a/Tests/DevFoundationTests/Concurrency/ExecutionGroupTests.swift +++ b/Tests/DevFoundationTests/Concurrency/ExecutionGroupTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct ExecutionGroupTests { @Test func tasksUpdateIsExecuting() async throws { diff --git a/Tests/DevFoundationTests/Date Providers/DateProvidersTests.swift b/Tests/DevFoundationTests/Date Providers/DateProvidersTests.swift index 89d4f26..f5c8641 100644 --- a/Tests/DevFoundationTests/Date Providers/DateProvidersTests.swift +++ b/Tests/DevFoundationTests/Date Providers/DateProvidersTests.swift @@ -5,11 +5,11 @@ // Created by Prachi Gauriar on 6/16/25. // -@testable import DevFoundation import DevTesting import Foundation import Testing +@testable import DevFoundation @Suite(.serialized) struct DateProvidersTests: RandomValueGenerating { diff --git a/Tests/DevFoundationTests/Date Providers/OffsetDateProviderTests.swift b/Tests/DevFoundationTests/Date Providers/OffsetDateProviderTests.swift index 48fc396..2f1c87f 100644 --- a/Tests/DevFoundationTests/Date Providers/OffsetDateProviderTests.swift +++ b/Tests/DevFoundationTests/Date Providers/OffsetDateProviderTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct OffsetDateProviderTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Date Providers/ScaledDateProviderTests.swift b/Tests/DevFoundationTests/Date Providers/ScaledDateProviderTests.swift index a8afb9e..6671a63 100644 --- a/Tests/DevFoundationTests/Date Providers/ScaledDateProviderTests.swift +++ b/Tests/DevFoundationTests/Date Providers/ScaledDateProviderTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct ScaledDateProviderTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Date Providers/SystemDateProviderTests.swift b/Tests/DevFoundationTests/Date Providers/SystemDateProviderTests.swift index 030b455..410bc8e 100644 --- a/Tests/DevFoundationTests/Date Providers/SystemDateProviderTests.swift +++ b/Tests/DevFoundationTests/Date Providers/SystemDateProviderTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct SystemDateProviderTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Event Bus/ContextualBusEventObserverTests.swift b/Tests/DevFoundationTests/Event Bus/ContextualBusEventObserverTests.swift index 1d56735..c58f950 100644 --- a/Tests/DevFoundationTests/Event Bus/ContextualBusEventObserverTests.swift +++ b/Tests/DevFoundationTests/Event Bus/ContextualBusEventObserverTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct ContextualBusEventObserverTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() @@ -48,7 +47,7 @@ struct ContextualBusEventObserverTests: RandomValueGenerating { observer.addHandler(for: MockBusEvent.self) { (_, _) in didCallHandler() } observer.addHandler( for: MockIdentifiableBusEvent.self, - id: random(Int.self, in: .min ..< 0) + id: random(Int.self, in: .min ..< 0) ) { (_, _) in didCallHandler() } diff --git a/Tests/DevFoundationTests/Event Bus/EventBusTests.swift b/Tests/DevFoundationTests/Event Bus/EventBusTests.swift index ada985f..28e53b1 100644 --- a/Tests/DevFoundationTests/Event Bus/EventBusTests.swift +++ b/Tests/DevFoundationTests/Event Bus/EventBusTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct EventBusTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Extensions/Data+ObfuscationTests.swift b/Tests/DevFoundationTests/Extensions/Data+ObfuscationTests.swift index 3468452..9a77c47 100644 --- a/Tests/DevFoundationTests/Extensions/Data+ObfuscationTests.swift +++ b/Tests/DevFoundationTests/Extensions/Data+ObfuscationTests.swift @@ -6,12 +6,12 @@ // import DevFoundation -@testable import enum DevFoundation.DataDeobfuscationError -@testable import enum DevFoundation.DataObfuscationError import DevTesting import Foundation import Testing +@testable import enum DevFoundation.DataDeobfuscationError +@testable import enum DevFoundation.DataObfuscationError struct Data_ObfuscationTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Extensions/FixedWidthInteger+BigEndianDataTests.swift b/Tests/DevFoundationTests/Extensions/FixedWidthInteger+BigEndianDataTests.swift index 7c853bf..05f139f 100644 --- a/Tests/DevFoundationTests/Extensions/FixedWidthInteger+BigEndianDataTests.swift +++ b/Tests/DevFoundationTests/Extensions/FixedWidthInteger+BigEndianDataTests.swift @@ -5,11 +5,11 @@ // Created by Prachi Gauriar on 4/28/25. // -@testable import DevFoundation import DevTesting import Foundation import Testing +@testable import DevFoundation struct FixedWidthInteger_BigEndianDataTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Extensions/RangeReplaceableCollection+RemoveFirstTests.swift b/Tests/DevFoundationTests/Extensions/RangeReplaceableCollection+RemoveFirstTests.swift index cb4d87a..06cc53d 100644 --- a/Tests/DevFoundationTests/Extensions/RangeReplaceableCollection+RemoveFirstTests.swift +++ b/Tests/DevFoundationTests/Extensions/RangeReplaceableCollection+RemoveFirstTests.swift @@ -5,11 +5,11 @@ // Created by Prachi Gauriar on 4/5/25. // -@testable import DevFoundation import DevTesting import Foundation import Testing +@testable import DevFoundation struct RangeReplaceableCollection_RemoveFirstTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Errors/AuthenticatorCancellationErrorTests.swift b/Tests/DevFoundationTests/Networking/Errors/AuthenticatorCancellationErrorTests.swift index 6982679..ec00e2b 100644 --- a/Tests/DevFoundationTests/Networking/Errors/AuthenticatorCancellationErrorTests.swift +++ b/Tests/DevFoundationTests/Networking/Errors/AuthenticatorCancellationErrorTests.swift @@ -9,7 +9,6 @@ import DevFoundation import Foundation import Testing - struct AuthenticatorCancellationErrorTests { @Test func initDoesNothing() { diff --git a/Tests/DevFoundationTests/Networking/Errors/InvalidHTTPStatusCodeErrorTests.swift b/Tests/DevFoundationTests/Networking/Errors/InvalidHTTPStatusCodeErrorTests.swift index bd503c7..9d7f5aa 100644 --- a/Tests/DevFoundationTests/Networking/Errors/InvalidHTTPStatusCodeErrorTests.swift +++ b/Tests/DevFoundationTests/Networking/Errors/InvalidHTTPStatusCodeErrorTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct InvalidHTTPStatusCodeErrorTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Errors/InvalidWebServiceRequestError.swift b/Tests/DevFoundationTests/Networking/Errors/InvalidWebServiceRequestError.swift index 6265542..41abd6c 100644 --- a/Tests/DevFoundationTests/Networking/Errors/InvalidWebServiceRequestError.swift +++ b/Tests/DevFoundationTests/Networking/Errors/InvalidWebServiceRequestError.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct InvalidWebServiceRequestErrorTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Errors/NonHTTPURLResponseErrorTests.swift b/Tests/DevFoundationTests/Networking/Errors/NonHTTPURLResponseErrorTests.swift index f5ccc49..26190f9 100644 --- a/Tests/DevFoundationTests/Networking/Errors/NonHTTPURLResponseErrorTests.swift +++ b/Tests/DevFoundationTests/Networking/Errors/NonHTTPURLResponseErrorTests.swift @@ -5,12 +5,11 @@ // Created by Prachi Gauriar on 3/16/25. // -import DevTesting import DevFoundation +import DevTesting import Foundation import Testing - struct NonHTTPURLResponseErrorTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Errors/UnauthorizedHTTPRequestErrorTests.swift b/Tests/DevFoundationTests/Networking/Errors/UnauthorizedHTTPRequestErrorTests.swift index b4ec21e..9abbfd2 100644 --- a/Tests/DevFoundationTests/Networking/Errors/UnauthorizedHTTPRequestErrorTests.swift +++ b/Tests/DevFoundationTests/Networking/Errors/UnauthorizedHTTPRequestErrorTests.swift @@ -9,7 +9,6 @@ import DevFoundation import Foundation import Testing - struct UnauthorizedHTTPRequestErrorTests { @Test func initDoesNothing() { diff --git a/Tests/DevFoundationTests/Networking/Low-Level Clients/AuthenticatingHTTPClientTests.swift b/Tests/DevFoundationTests/Networking/Low-Level Clients/AuthenticatingHTTPClientTests.swift index 42a4202..a9d4bc5 100644 --- a/Tests/DevFoundationTests/Networking/Low-Level Clients/AuthenticatingHTTPClientTests.swift +++ b/Tests/DevFoundationTests/Networking/Low-Level Clients/AuthenticatingHTTPClientTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct AuthenticatingHTTPClientTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPClientTests.swift b/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPClientTests.swift index 6281616..50e5a5d 100644 --- a/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPClientTests.swift +++ b/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPClientTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct HTTPClientTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() @@ -313,7 +312,7 @@ struct HTTPClientTests: RandomValueGenerating { let urlRequestLoader = MockURLRequestLoader() let expectedError = randomError() urlRequestLoader.dataStub = .init( - defaultResult: .failure(expectedError) , + defaultResult: .failure(expectedError), resultQueue: [.success((randomData(), randomHTTPURLResponse()))] ) diff --git a/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPRequestAuthenticationFailureTests.swift b/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPRequestAuthenticationFailureTests.swift index 55c6237..579fa1f 100644 --- a/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPRequestAuthenticationFailureTests.swift +++ b/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPRequestAuthenticationFailureTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct HTTPRequestAuthenticationFailureTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPRequestAuthenticatorTests.swift b/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPRequestAuthenticatorTests.swift index d3d2782..02ef9fe 100644 --- a/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPRequestAuthenticatorTests.swift +++ b/Tests/DevFoundationTests/Networking/Low-Level Clients/HTTPRequestAuthenticatorTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct HTTPRequestAuthenticatorTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPBodyTests.swift b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPBodyTests.swift index 7f683e3..f350afd 100644 --- a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPBodyTests.swift +++ b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPBodyTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct HTTPBodyTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPHeaderFieldTests.swift b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPHeaderFieldTests.swift index e53af91..fb86c48 100644 --- a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPHeaderFieldTests.swift +++ b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPHeaderFieldTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct HTTPHeaderFieldTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() @@ -57,7 +56,7 @@ struct HTTPHeaderFieldTests: RandomValueGenerating { mutating func httpURLResponseAccessor() throws { let response = randomHTTPURLResponse() - let headers = try #require(response.allHeaderFields as? [String : String]) + let headers = try #require(response.allHeaderFields as? [String: String]) for (field, value) in headers { #expect(response.httpHeaderValue(for: HTTPHeaderField(field)) == value) } diff --git a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPHeaderItemTests.swift b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPHeaderItemTests.swift index 677753a..3f73ca1 100644 --- a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPHeaderItemTests.swift +++ b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPHeaderItemTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct HTTPHeaderItemTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() @@ -64,7 +63,7 @@ struct HTTPHeaderItemTests: RandomValueGenerating { mutating func httpURLResponseAccessor() throws { let response = randomHTTPURLResponse() - let headers = try #require(response.allHeaderFields as? [String : String]) + let headers = try #require(response.allHeaderFields as? [String: String]) let headerItems = response.httpHeaderItems #expect(headerItems.count == headers.count) diff --git a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPMethodTests.swift b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPMethodTests.swift index 45ba0f6..417d57a 100644 --- a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPMethodTests.swift +++ b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPMethodTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct HTTPMethodTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPResponseTests.swift b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPResponseTests.swift index ce120c0..b04c11d 100644 --- a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPResponseTests.swift +++ b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPResponseTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct HTTPResponseTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPStatusCodeTests.swift b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPStatusCodeTests.swift index aaf388a..8552518 100644 --- a/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPStatusCodeTests.swift +++ b/Tests/DevFoundationTests/Networking/Requests and Responses/HTTPStatusCodeTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct HTTPStatusCodeTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() @@ -112,9 +111,8 @@ struct HTTPStatusCodeTests: RandomValueGenerating { @Test mutating func httpURLResponseStatusCode() { - let statusCode = random(Int.self , in: 100 ..< 600) + let statusCode = random(Int.self, in: 100 ..< 600) let response = randomHTTPURLResponse(statusCode: statusCode) #expect(response.httpStatusCode == HTTPStatusCode(statusCode)) } } - diff --git a/Tests/DevFoundationTests/Networking/Requests and Responses/MediaTypeTests.swift b/Tests/DevFoundationTests/Networking/Requests and Responses/MediaTypeTests.swift index caa6c8e..afe6a43 100644 --- a/Tests/DevFoundationTests/Networking/Requests and Responses/MediaTypeTests.swift +++ b/Tests/DevFoundationTests/Networking/Requests and Responses/MediaTypeTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct MediaTypeTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Requests and Responses/URLPathComponentTests.swift b/Tests/DevFoundationTests/Networking/Requests and Responses/URLPathComponentTests.swift index 9501ee0..82141a7 100644 --- a/Tests/DevFoundationTests/Networking/Requests and Responses/URLPathComponentTests.swift +++ b/Tests/DevFoundationTests/Networking/Requests and Responses/URLPathComponentTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct URLPathComponentTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Web Service Client/JSONBodyWebServiceRequestTests.swift b/Tests/DevFoundationTests/Networking/Web Service Client/JSONBodyWebServiceRequestTests.swift index 57c4efa..f675797 100644 --- a/Tests/DevFoundationTests/Networking/Web Service Client/JSONBodyWebServiceRequestTests.swift +++ b/Tests/DevFoundationTests/Networking/Web Service Client/JSONBodyWebServiceRequestTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct JSONBodyWebServiceRequestTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() @@ -80,7 +79,7 @@ private struct MockJSONBody: Codable, Hashable { private struct DefaultJSONBodyWebServiceRequest: JSONBodyWebServiceRequest { -typealias Authenticator = MockHTTPRequestAuthenticator + typealias Authenticator = MockHTTPRequestAuthenticator typealias BaseURLConfiguration = SingleBaseURLConfiguration var jsonBody: MockJSONBody @@ -101,7 +100,7 @@ typealias Authenticator = MockHTTPRequestAuthenticator } - func mapResponse(_ response: HTTPResponse) throws -> Void { + func mapResponse(_ response: HTTPResponse) throws { fatalError("not implemented") } } @@ -131,7 +130,7 @@ where JSONBody: Encodable & Sendable { } - func mapResponse(_ response: HTTPResponse) throws -> Void { + func mapResponse(_ response: HTTPResponse) throws { fatalError("not implemented") } } diff --git a/Tests/DevFoundationTests/Networking/Web Service Client/SingleBaseURLConfigurationTests.swift b/Tests/DevFoundationTests/Networking/Web Service Client/SingleBaseURLConfigurationTests.swift index 69f8994..ecd16bd 100644 --- a/Tests/DevFoundationTests/Networking/Web Service Client/SingleBaseURLConfigurationTests.swift +++ b/Tests/DevFoundationTests/Networking/Web Service Client/SingleBaseURLConfigurationTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct SingleBaseURLConfigurationTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Web Service Client/WebServiceClientTests.swift b/Tests/DevFoundationTests/Networking/Web Service Client/WebServiceClientTests.swift index 0bde2bc..3d7bc2b 100644 --- a/Tests/DevFoundationTests/Networking/Web Service Client/WebServiceClientTests.swift +++ b/Tests/DevFoundationTests/Networking/Web Service Client/WebServiceClientTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct WebServiceClientTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Networking/Web Service Client/WebServiceRequestTests.swift b/Tests/DevFoundationTests/Networking/Web Service Client/WebServiceRequestTests.swift index 6a41bc9..ece8938 100644 --- a/Tests/DevFoundationTests/Networking/Web Service Client/WebServiceRequestTests.swift +++ b/Tests/DevFoundationTests/Networking/Web Service Client/WebServiceRequestTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct WebServiceRequestTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() @@ -160,7 +159,7 @@ struct WebServiceRequestTests: RandomValueGenerating { @Test mutating func urlRequestCreationFailsWhenHTTPBodyThrows() throws { let expectedError = randomError() - + let request = MockWebServiceRequest( httpMethod: randomHTTPMethod(), headerItems: [], @@ -171,11 +170,11 @@ struct WebServiceRequestTests: RandomValueGenerating { queryItems: [], httpBodyResult: .failure(expectedError) ) - + let baseURLConfiguration = MockBaseURLConfiguration() let url = randomURL(includeFragment: false, includeQueryItems: false) baseURLConfiguration.urlStub = Stub(defaultReturnValue: url) - + do { _ = try request.urlRequest(with: baseURLConfiguration) Issue.record("does not throw error") @@ -213,7 +212,7 @@ private struct DefaultWebServiceRequest: WebServiceRequest { } - func mapResponse(_ response: HTTPResponse) throws -> Void { + func mapResponse(_ response: HTTPResponse) throws { // Intentionally empty } } diff --git a/Tests/DevFoundationTests/Testing Helpers/Date+IsApproximatelyEqual.swift b/Tests/DevFoundationTests/Testing Helpers/Date+IsApproximatelyEqual.swift index a558115..34d3b40 100644 --- a/Tests/DevFoundationTests/Testing Helpers/Date+IsApproximatelyEqual.swift +++ b/Tests/DevFoundationTests/Testing Helpers/Date+IsApproximatelyEqual.swift @@ -8,8 +8,6 @@ import Foundation import RealModule - - extension Date { func isApproximatelyEqual(to date: Date, absoluteTolerance: TimeInterval) -> Bool { return timeIntervalSinceReferenceDate.isApproximatelyEqual( diff --git a/Tests/DevFoundationTests/Testing Helpers/MockBaseURLConfiguration.swift b/Tests/DevFoundationTests/Testing Helpers/MockBaseURLConfiguration.swift index 3f9838a..59010d4 100644 --- a/Tests/DevFoundationTests/Testing Helpers/MockBaseURLConfiguration.swift +++ b/Tests/DevFoundationTests/Testing Helpers/MockBaseURLConfiguration.swift @@ -9,10 +9,8 @@ import DevFoundation import DevTesting import Foundation - final class MockBaseURLConfiguration: BaseURLConfiguring { - nonisolated(unsafe) - var urlStub: Stub! + nonisolated(unsafe) var urlStub: Stub! func url(for baseURL: Int) -> URL { diff --git a/Tests/DevFoundationTests/Testing Helpers/MockBusEventObserver.swift b/Tests/DevFoundationTests/Testing Helpers/MockBusEventObserver.swift index cb1b958..a104ddd 100644 --- a/Tests/DevFoundationTests/Testing Helpers/MockBusEventObserver.swift +++ b/Tests/DevFoundationTests/Testing Helpers/MockBusEventObserver.swift @@ -9,20 +9,15 @@ import DevFoundation import DevTesting import Foundation - final class MockBusEventObserver: BusEventObserver { - nonisolated(unsafe) - var observeStub: Stub! - - - nonisolated(unsafe) - var observeIdentifiableStub: Stub! + nonisolated(unsafe) var observeStub: Stub! + nonisolated(unsafe) var observeIdentifiableStub: Stub! func observe(_ event: some BusEvent) { observeStub(event) } - + func observe(_ event: Event) where Event: BusEvent & Identifiable, Event.ID: Sendable { observeIdentifiableStub(event) diff --git a/Tests/DevFoundationTests/Testing Helpers/MockBusEvents.swift b/Tests/DevFoundationTests/Testing Helpers/MockBusEvents.swift index 001bf98..99fce62 100644 --- a/Tests/DevFoundationTests/Testing Helpers/MockBusEvents.swift +++ b/Tests/DevFoundationTests/Testing Helpers/MockBusEvents.swift @@ -8,7 +8,6 @@ import DevFoundation import Foundation - struct MockBusEvent: BusEvent, Hashable { let string: String } diff --git a/Tests/DevFoundationTests/Testing Helpers/MockCodables.swift b/Tests/DevFoundationTests/Testing Helpers/MockCodables.swift index 4636370..1c04875 100644 --- a/Tests/DevFoundationTests/Testing Helpers/MockCodables.swift +++ b/Tests/DevFoundationTests/Testing Helpers/MockCodables.swift @@ -7,7 +7,6 @@ import Foundation - struct MockCodable: Codable, Hashable, Sendable { enum CodingKeys: String, CodingKey { case array diff --git a/Tests/DevFoundationTests/Testing Helpers/MockDateProvider.swift b/Tests/DevFoundationTests/Testing Helpers/MockDateProvider.swift index 02ef69e..8aa30ca 100644 --- a/Tests/DevFoundationTests/Testing Helpers/MockDateProvider.swift +++ b/Tests/DevFoundationTests/Testing Helpers/MockDateProvider.swift @@ -9,10 +9,8 @@ import DevFoundation import DevTesting import Foundation - final class MockDateProvider: DateProvider { - nonisolated(unsafe) - var nowStub: Stub! + nonisolated(unsafe) var nowStub: Stub! convenience init(now: Date) { diff --git a/Tests/DevFoundationTests/Testing Helpers/MockError.swift b/Tests/DevFoundationTests/Testing Helpers/MockError.swift index 410de3a..d3e297e 100644 --- a/Tests/DevFoundationTests/Testing Helpers/MockError.swift +++ b/Tests/DevFoundationTests/Testing Helpers/MockError.swift @@ -7,7 +7,6 @@ import Foundation - struct MockError: Error, Hashable, Sendable { let id: Int } diff --git a/Tests/DevFoundationTests/Testing Helpers/MockHTTPClientRequestInterceptor.swift b/Tests/DevFoundationTests/Testing Helpers/MockHTTPClientRequestInterceptor.swift index ff58156..e1cb82e 100644 --- a/Tests/DevFoundationTests/Testing Helpers/MockHTTPClientRequestInterceptor.swift +++ b/Tests/DevFoundationTests/Testing Helpers/MockHTTPClientRequestInterceptor.swift @@ -9,7 +9,6 @@ import DevFoundation import DevTesting import Foundation - final class MockHTTPClientRequestInterceptor: HashableByID, HTTPClientRequestInterceptor { struct InterceptArguments { let request: URLRequest @@ -17,11 +16,8 @@ final class MockHTTPClientRequestInterceptor: HashableByID, HTTPClientRequestInt } - nonisolated(unsafe) - var interceptPrologue: (() async throws -> Void)? - - nonisolated(unsafe) - var interceptStub: ThrowingStub! + nonisolated(unsafe) var interceptPrologue: (() async throws -> Void)? + nonisolated(unsafe) var interceptStub: ThrowingStub! func intercept(_ request: URLRequest, from client: HTTPClient) async throws -> URLRequest { diff --git a/Tests/DevFoundationTests/Testing Helpers/MockHTTPClientResponseInterceptor.swift b/Tests/DevFoundationTests/Testing Helpers/MockHTTPClientResponseInterceptor.swift index 98feeb6..ba8e7ce 100644 --- a/Tests/DevFoundationTests/Testing Helpers/MockHTTPClientResponseInterceptor.swift +++ b/Tests/DevFoundationTests/Testing Helpers/MockHTTPClientResponseInterceptor.swift @@ -9,7 +9,6 @@ import DevFoundation import DevTesting import Foundation - final class MockHTTPClientResponseInterceptor: HashableByID, HTTPClientResponseInterceptor { struct InterceptArguments { let response: HTTPResponse @@ -18,11 +17,8 @@ final class MockHTTPClientResponseInterceptor: HashableByID, HTTPClientResponseI } - nonisolated(unsafe) - var interceptPrologue: (() async throws -> Void)? - - nonisolated(unsafe) - var interceptStub: ThrowingStub?, any Error>! + nonisolated(unsafe) var interceptPrologue: (() async throws -> Void)? + nonisolated(unsafe) var interceptStub: ThrowingStub?, any Error>! func intercept( diff --git a/Tests/DevFoundationTests/Testing Helpers/MockHTTPRequestAuthenticator.swift b/Tests/DevFoundationTests/Testing Helpers/MockHTTPRequestAuthenticator.swift index d3ec46e..4034268 100644 --- a/Tests/DevFoundationTests/Testing Helpers/MockHTTPRequestAuthenticator.swift +++ b/Tests/DevFoundationTests/Testing Helpers/MockHTTPRequestAuthenticator.swift @@ -9,7 +9,6 @@ import DevFoundation import DevTesting import Foundation - final class MockHTTPRequestAuthenticator: HTTPRequestAuthenticator { enum Context: CaseIterable, Hashable, Sendable { case case1, case2, case3 @@ -30,17 +29,10 @@ final class MockHTTPRequestAuthenticator: HTTPRequestAuthenticator { } - nonisolated(unsafe) - var preparePrologue: (() async throws -> Void)? - - nonisolated(unsafe) - var prepareStub: ThrowingStub! - - nonisolated(unsafe) - var throwPrologue: (() throws -> Void)? - - nonisolated(unsafe) - var throwStub: ThrowingStub! + nonisolated(unsafe) var preparePrologue: (() async throws -> Void)? + nonisolated(unsafe) var prepareStub: ThrowingStub! + nonisolated(unsafe) var throwPrologue: (() throws -> Void)? + nonisolated(unsafe) var throwStub: ThrowingStub! func prepare( diff --git a/Tests/DevFoundationTests/Testing Helpers/MockURLRequestLoader.swift b/Tests/DevFoundationTests/Testing Helpers/MockURLRequestLoader.swift index 25225c1..ecbdb25 100644 --- a/Tests/DevFoundationTests/Testing Helpers/MockURLRequestLoader.swift +++ b/Tests/DevFoundationTests/Testing Helpers/MockURLRequestLoader.swift @@ -9,13 +9,9 @@ import DevFoundation import DevTesting import Foundation - final class MockURLRequestLoader: URLRequestLoader { - nonisolated(unsafe) - var dataPrologue: (() async throws -> Void)? - - nonisolated(unsafe) - var dataStub: ThrowingStub! + nonisolated(unsafe) var dataPrologue: (() async throws -> Void)? + nonisolated(unsafe) var dataStub: ThrowingStub! func data(for urlRequest: URLRequest) async throws -> (Data, URLResponse) { diff --git a/Tests/DevFoundationTests/Testing Helpers/MockWebServiceRequest.swift b/Tests/DevFoundationTests/Testing Helpers/MockWebServiceRequest.swift index f531275..738b0af 100644 --- a/Tests/DevFoundationTests/Testing Helpers/MockWebServiceRequest.swift +++ b/Tests/DevFoundationTests/Testing Helpers/MockWebServiceRequest.swift @@ -9,40 +9,20 @@ import DevFoundation import DevTesting import Foundation - final class MockWebServiceRequest: WebServiceRequest { typealias Authenticator = MockHTTPRequestAuthenticator typealias BaseURLConfiguration = MockBaseURLConfiguration - nonisolated(unsafe) - var httpMethod: HTTPMethod - - nonisolated(unsafe) - var headerItems: [HTTPHeaderItem] - - nonisolated(unsafe) - var authenticatorContext: MockHTTPRequestAuthenticator.Context - - nonisolated(unsafe) - var baseURL: Int - - nonisolated(unsafe) - var pathComponents: [URLPathComponent] - - nonisolated(unsafe) - var fragment: String? - - nonisolated(unsafe) - var queryItems: [URLQueryItem] - - nonisolated(unsafe) - var automaticallyPercentEncodesQueryItems: Bool - - nonisolated(unsafe) - var httpBodyResult: Result - - nonisolated(unsafe) - var mapResponseStub: ThrowingStub, String, any Error>! + nonisolated(unsafe) var httpMethod: HTTPMethod + nonisolated(unsafe) var headerItems: [HTTPHeaderItem] + nonisolated(unsafe) var authenticatorContext: MockHTTPRequestAuthenticator.Context + nonisolated(unsafe) var baseURL: Int + nonisolated(unsafe) var pathComponents: [URLPathComponent] + nonisolated(unsafe) var fragment: String? + nonisolated(unsafe) var queryItems: [URLQueryItem] + nonisolated(unsafe) var automaticallyPercentEncodesQueryItems: Bool + nonisolated(unsafe) var httpBodyResult: Result + nonisolated(unsafe) var mapResponseStub: ThrowingStub, String, any Error>! init( diff --git a/Tests/DevFoundationTests/Testing Helpers/RandomValueGenerating+DevFoundation.swift b/Tests/DevFoundationTests/Testing Helpers/RandomValueGenerating+DevFoundation.swift index 4266700..4857e9f 100644 --- a/Tests/DevFoundationTests/Testing Helpers/RandomValueGenerating+DevFoundation.swift +++ b/Tests/DevFoundationTests/Testing Helpers/RandomValueGenerating+DevFoundation.swift @@ -9,7 +9,6 @@ import DevFoundation import DevTesting import Foundation - extension RandomValueGenerating { mutating func randomAuthenticatorContext() -> MockHTTPRequestAuthenticator.Context { return randomCase(of: MockHTTPRequestAuthenticator.Context.self)! diff --git a/Tests/DevFoundationTests/Utility Types/AnySendableHashableTests.swift b/Tests/DevFoundationTests/Utility Types/AnySendableHashableTests.swift index ad7320c..facfcf8 100644 --- a/Tests/DevFoundationTests/Utility Types/AnySendableHashableTests.swift +++ b/Tests/DevFoundationTests/Utility Types/AnySendableHashableTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct AnySendableHashableTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Utility Types/DottedHierarchicalIDTests.swift b/Tests/DevFoundationTests/Utility Types/DottedHierarchicalIDTests.swift index 5094773..efa7758 100644 --- a/Tests/DevFoundationTests/Utility Types/DottedHierarchicalIDTests.swift +++ b/Tests/DevFoundationTests/Utility Types/DottedHierarchicalIDTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct DottedHierarchicalIDTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Utility Types/ExpiringValueTests.swift b/Tests/DevFoundationTests/Utility Types/ExpiringValueTests.swift index 46ab809..bdf9a55 100644 --- a/Tests/DevFoundationTests/Utility Types/ExpiringValueTests.swift +++ b/Tests/DevFoundationTests/Utility Types/ExpiringValueTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct ExpiringValueTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Utility Types/GibberishGeneratorTests.swift b/Tests/DevFoundationTests/Utility Types/GibberishGeneratorTests.swift index 940e20a..6764265 100644 --- a/Tests/DevFoundationTests/Utility Types/GibberishGeneratorTests.swift +++ b/Tests/DevFoundationTests/Utility Types/GibberishGeneratorTests.swift @@ -6,12 +6,11 @@ // import DevFoundation -import Foundation import DevTesting +import Foundation import Synchronization import Testing - struct GibberishGeneratorTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Utility Types/HashableByIDTests.swift b/Tests/DevFoundationTests/Utility Types/HashableByIDTests.swift index 3b9f2db..af2f09b 100644 --- a/Tests/DevFoundationTests/Utility Types/HashableByIDTests.swift +++ b/Tests/DevFoundationTests/Utility Types/HashableByIDTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct HashableByIDTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Utility Types/JSONValueTests.swift b/Tests/DevFoundationTests/Utility Types/JSONValueTests.swift index b502564..cb2034d 100644 --- a/Tests/DevFoundationTests/Utility Types/JSONValueTests.swift +++ b/Tests/DevFoundationTests/Utility Types/JSONValueTests.swift @@ -6,11 +6,11 @@ // import DevFoundation -@testable import struct DevFoundation.JSONCodingKey import DevTesting import Foundation import Testing +@testable import struct DevFoundation.JSONCodingKey struct JSONValueTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() @@ -33,7 +33,7 @@ struct JSONValueTests: RandomValueGenerating { [ "key1": .null, "key2": .ifPresent(.ifPresent(.number(0))), - "key3": .ifPresent(nil as Bool?) + "key3": .ifPresent(nil as Bool?), ] ), .null, @@ -72,7 +72,7 @@ struct JSONValueTests: RandomValueGenerating { .number(100 as UInt), .number(-100), .ifPresent(.ifPresent(.number(Float64.pi))), - .ifPresent(nil as Int?) + .ifPresent(nil as Int?), ] ), "bool": .boolean(true), @@ -85,7 +85,7 @@ struct JSONValueTests: RandomValueGenerating { [ "key1": .null, "key2": .ifPresent(.number(0)), - "key3": .ifPresent(nil as Bool?) + "key3": .ifPresent(nil as Bool?), ] ), "null": .null, @@ -231,7 +231,7 @@ struct JSONValueTests: RandomValueGenerating { "key2": false, "key3": 1, "key4": "two", - "key5": .ifPresent(.ifPresent(.number(Float64.pi))) + "key5": .ifPresent(.ifPresent(.number(Float64.pi))), ] let equal = object let unequal: JSONValue = [ @@ -240,7 +240,7 @@ struct JSONValueTests: RandomValueGenerating { "key3": 1, "key4": false, "key5": nil, - "key6": 0 + "key6": 0, ] #expect(object == equal) @@ -534,7 +534,7 @@ struct JSONValueTests: RandomValueGenerating { "6": ["key": .string("value")], ], ), - .string("string") + .string("string"), ] #expect(jsonValue == expectedJSONValue) diff --git a/Tests/DevFoundationTests/Utility Types/SoftwareComponentIDTests.swift b/Tests/DevFoundationTests/Utility Types/SoftwareComponentIDTests.swift index 75511a7..79a1ec5 100644 --- a/Tests/DevFoundationTests/Utility Types/SoftwareComponentIDTests.swift +++ b/Tests/DevFoundationTests/Utility Types/SoftwareComponentIDTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct SoftwareComponentIDTests { @Test func initOmitsEmptyComponents() { diff --git a/Tests/DevFoundationTests/Utility Types/TopLevelCodingTests.swift b/Tests/DevFoundationTests/Utility Types/TopLevelCodingTests.swift index cba42a2..5ada1d6 100644 --- a/Tests/DevFoundationTests/Utility Types/TopLevelCodingTests.swift +++ b/Tests/DevFoundationTests/Utility Types/TopLevelCodingTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct TopLevelCodingTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator() diff --git a/Tests/DevFoundationTests/Utility Types/TypedExtensibleEnumTests.swift b/Tests/DevFoundationTests/Utility Types/TypedExtensibleEnumTests.swift index cf1a249..05b2ebf 100644 --- a/Tests/DevFoundationTests/Utility Types/TypedExtensibleEnumTests.swift +++ b/Tests/DevFoundationTests/Utility Types/TypedExtensibleEnumTests.swift @@ -10,7 +10,6 @@ import DevTesting import Foundation import Testing - struct TypedExtensibleEnumTests: RandomValueGenerating { var randomNumberGenerator = Self.makeRandomNumberGenerator() diff --git a/Tests/dfobTests/ObfuscateCommandTests.swift b/Tests/dfobTests/ObfuscateCommandTests.swift index ed96546..acde930 100644 --- a/Tests/dfobTests/ObfuscateCommandTests.swift +++ b/Tests/dfobTests/ObfuscateCommandTests.swift @@ -5,13 +5,13 @@ // Created by Prachi Gauriar on 4/30/25. // -@testable import ArgumentParser -@testable import dfob import DevFoundation import DevTesting import Foundation import Testing +@testable import ArgumentParser +@testable import dfob struct ObfuscateCommandTests: RandomValueGenerating { var randomNumberGenerator = makeRandomNumberGenerator()