Skip to content

Download refactor#133

Merged
Aldo10012 merged 8 commits into
mainfrom
download_refactor
Apr 19, 2026
Merged

Download refactor#133
Aldo10012 merged 8 commits into
mainfrom
download_refactor

Conversation

@Aldo10012

@Aldo10012 Aldo10012 commented Apr 19, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Refactor

    • Improved internal architecture and state management of the download service for better maintainability.
  • Tests

    • Updated download service tests to enhance coverage and focus on observable behavior without directly verifying internal state.

@coderabbitai

coderabbitai Bot commented Apr 19, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@Aldo10012 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 46 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 21 minutes and 46 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a52debbc-55b0-4bf7-ae3f-c1adaabc7824

📥 Commits

Reviewing files that changed from the base of the PR and between c775d4f and b8d183b.

📒 Files selected for processing (3)
  • Sources/EZNetworking/Services/Downloader/FileDownloader.swift
  • Sources/EZNetworking/Services/Downloader/Helpers/DownloadState.swift
  • Tests/EZNetworkingTests/Services/Downloader/Helpers/DownloadStateTests.swift
📝 Walkthrough

Walkthrough

This PR refactors FileDownloader's internal state management by introducing a new DownloadState enum to replace the old State implementation. It updates state validation, request error handling, and consolidates termination logic. Tests now verify behavior through event streams rather than direct state inspection.

Changes

Cohort / File(s) Summary
Core State Refactoring
Sources/EZNetworking/Services/Downloader/FileDownloader.swift
Replaced internal State enum with DownloadState type; delegated startup validation to validateCanStartDownload(); wrapped URLRequest construction in do/catch for error handling; consolidated terminate(with:state:) to conditionally yield events, removing terminateSilently().
State Type Definition
Sources/EZNetworking/Services/Downloader/Helpers/DownloadState.swift
Added new DownloadState enum with cases: idle, downloading, pausing, paused(resumeData:), completed, failed, failedButCanResume(resumeData:), cancelled.
Test Assertion Cleanup
Tests/EZNetworkingTests/Services/Downloader/FileDownloader{CoreFunctionality,InvalidState,PauseResume,TaskCancellation}Tests.swift, Tests/EZNetworkingTests/Services/Downloader/Helpers/DownloadStateTests.swift
Removed direct sut.state assertions from core downloader tests; added new DownloadStateTests suite verifying enum equivalence across all state cases.

Possibly related PRs

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 The FileDownloader hops with pride,
Its state machine now unified,
Old States retired, DownloadState reigns,
Tests trust events through and through—
No assertions peek inside! 🎉

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Download refactor' is vague and generic, using non-descriptive language that doesn't convey what specific aspect of the download functionality was refactored or improved. Provide a more specific title that describes the main refactoring objective, such as 'Refactor FileDownloader state management with new DownloadState enum' or 'Simplify FileDownloader state transitions'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch download_refactor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/EZNetworking/Services/Downloader/FileDownloader.swift (1)

58-77: ⚠️ Potential issue | 🟠 Major

Continuation leak when getURLRequest() throws.

self.continuation is assigned at line 59 before the do block. If request.getURLRequest() throws, the catch returns a separate stream via earlyExitStream, but the continuation stored on self is never finish()-ed and onTermination is never invoked. Because state also remains .idle, a subsequent downloadFileStream() call will pass validateCanStartDownload() and overwrite self.continuation without terminating the previous one — leaking the prior stream's consumers.

Construct the URLRequest before wiring up self.continuation, or clean up on failure:

Proposed fix
-        let (stream, continuation) = AsyncStream<DownloadEvent>.makeStream()
-        self.continuation = continuation
-
-        continuation.onTermination = { `@Sendable` [weak self] termination in
-            guard case .cancelled = termination else { return }
-            Task { [weak self] in
-                try? await self?.cancel()
-            }
-        }
-
-        do {
-            let urlRequest = try request.getURLRequest()
-            state = .downloading
-            let task = session.urlSession.downloadTaskInspectable(with: urlRequest)
-            downloadTask = task
-            task.resume()
-            return stream
-        } catch {
-            return earlyExitStream(yielding: .failed(mapNetworkingError(from: error)))
-        }
+        let urlRequest: URLRequest
+        do {
+            urlRequest = try request.getURLRequest()
+        } catch {
+            return earlyExitStream(yielding: .failed(mapNetworkingError(from: error)))
+        }
+
+        let (stream, continuation) = AsyncStream<DownloadEvent>.makeStream()
+        self.continuation = continuation
+        continuation.onTermination = { `@Sendable` [weak self] termination in
+            guard case .cancelled = termination else { return }
+            Task { [weak self] in try? await self?.cancel() }
+        }
+
+        state = .downloading
+        let task = session.urlSession.downloadTaskInspectable(with: urlRequest)
+        downloadTask = task
+        task.resume()
+        return stream
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/EZNetworking/Services/Downloader/FileDownloader.swift` around lines
58 - 77, The continuation is created and stored on self before calling
request.getURLRequest(), so if getURLRequest() throws the stored
self.continuation is never finished and leaks; fix by creating the URLRequest
first (call request.getURLRequest() before creating AsyncStream/assigning
self.continuation) or, if you prefer minimal change, ensure you clean up in the
catch by calling self.continuation?.finish(), setting self.continuation = nil,
and returning the earlyExitStream; update FileDownloader's downloadFileStream
(the AsyncStream/continuation creation and the catch block) to perform one of
these fixes so no continuation remains un-finished when getURLRequest() fails.
🧹 Nitpick comments (1)
Tests/EZNetworkingTests/Services/Downloader/Helpers/DownloadStateTests.swift (1)

8-18: Consider adding negative-equality cases.

The test only asserts each case equals itself, which Equatable synthesis makes trivially true. A few inequality checks — especially for associated-value cases with differing Data — would give the test real signal:

Proposed additions
         `#expect`(DownloadState.cancelled == DownloadState.cancelled)
+
+        // Different cases should not be equal
+        `#expect`(DownloadState.idle != DownloadState.downloading)
+        `#expect`(DownloadState.completed != DownloadState.failed)
+
+        // Associated values must participate in equality
+        let other = Data([0x01])
+        `#expect`(DownloadState.paused(resumeData: data) != .paused(resumeData: other))
+        `#expect`(DownloadState.failedButCanResume(resumeData: data)
+                != .failedButCanResume(resumeData: other))
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Tests/EZNetworkingTests/Services/Downloader/Helpers/DownloadStateTests.swift`
around lines 8 - 18, The test testDownloadStateEquivalence currently only checks
each DownloadState case equals itself; add negative-equality assertions to
verify non-equivalence between different enum cases and between associated-value
variants with different Data to ensure Equatable behaves correctly: assert that
distinct cases like DownloadState.idle != DownloadState.downloading (and other
pairings) are not equal, and assert that DownloadState.paused(resumeData: dataA)
!= DownloadState.paused(resumeData: dataB) and
DownloadState.failedButCanResume(resumeData: dataA) !=
DownloadState.failedButCanResume(resumeData: dataB) where dataA and dataB are
different Data instances.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Sources/EZNetworking/Services/Downloader/FileDownloader.swift`:
- Around line 166-169: The doc comment for private func terminate(with event:
DownloadEvent?, state newState: DownloadState) describes behavior inverted
relative to implementation; update the comment to state that when event is
non-nil the stream yields that final event and then closes, and when event is
nil the stream closes without yielding, and ensure the summary line and the two
bullet lines reflect this exact behavior for DownloadEvent and DownloadState.

---

Outside diff comments:
In `@Sources/EZNetworking/Services/Downloader/FileDownloader.swift`:
- Around line 58-77: The continuation is created and stored on self before
calling request.getURLRequest(), so if getURLRequest() throws the stored
self.continuation is never finished and leaks; fix by creating the URLRequest
first (call request.getURLRequest() before creating AsyncStream/assigning
self.continuation) or, if you prefer minimal change, ensure you clean up in the
catch by calling self.continuation?.finish(), setting self.continuation = nil,
and returning the earlyExitStream; update FileDownloader's downloadFileStream
(the AsyncStream/continuation creation and the catch block) to perform one of
these fixes so no continuation remains un-finished when getURLRequest() fails.

---

Nitpick comments:
In
`@Tests/EZNetworkingTests/Services/Downloader/Helpers/DownloadStateTests.swift`:
- Around line 8-18: The test testDownloadStateEquivalence currently only checks
each DownloadState case equals itself; add negative-equality assertions to
verify non-equivalence between different enum cases and between associated-value
variants with different Data to ensure Equatable behaves correctly: assert that
distinct cases like DownloadState.idle != DownloadState.downloading (and other
pairings) are not equal, and assert that DownloadState.paused(resumeData: dataA)
!= DownloadState.paused(resumeData: dataB) and
DownloadState.failedButCanResume(resumeData: dataA) !=
DownloadState.failedButCanResume(resumeData: dataB) where dataA and dataB are
different Data instances.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e6dd6db4-2b6a-4473-98bc-c533d74c2fa0

📥 Commits

Reviewing files that changed from the base of the PR and between bc908e0 and c775d4f.

📒 Files selected for processing (7)
  • Sources/EZNetworking/Services/Downloader/FileDownloader.swift
  • Sources/EZNetworking/Services/Downloader/Helpers/DownloadState.swift
  • Tests/EZNetworkingTests/Services/Downloader/FileDownloaderCoreFunctionalityTests.swift
  • Tests/EZNetworkingTests/Services/Downloader/FileDownloaderInvalidStateTests.swift
  • Tests/EZNetworkingTests/Services/Downloader/FileDownloaderPauseResumeTests.swift
  • Tests/EZNetworkingTests/Services/Downloader/FileDownloaderTaskCancellationTests.swift
  • Tests/EZNetworkingTests/Services/Downloader/Helpers/DownloadStateTests.swift
💤 Files with no reviewable changes (4)
  • Tests/EZNetworkingTests/Services/Downloader/FileDownloaderTaskCancellationTests.swift
  • Tests/EZNetworkingTests/Services/Downloader/FileDownloaderInvalidStateTests.swift
  • Tests/EZNetworkingTests/Services/Downloader/FileDownloaderPauseResumeTests.swift
  • Tests/EZNetworkingTests/Services/Downloader/FileDownloaderCoreFunctionalityTests.swift

Comment thread Sources/EZNetworking/Services/Downloader/FileDownloader.swift Outdated
@codecov

codecov Bot commented Apr 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.66667% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...etworking/Services/Downloader/FileDownloader.swift 96.77% 1 Missing ⚠️
...rvices/Downloader/Helpers/DownloadStateTests.swift 95.23% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@Aldo10012
Aldo10012 merged commit e4617a0 into main Apr 19, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant