More tests#7
Merged
Merged
Conversation
Adds test files for DateProvider, HapticFeedback, MainScheduler, and the Pasteboard protocol-extension overload so the only previously-tested primitive (Clock) is no longer alone. The DefaultPasteboard production writes and DefaultUrlOpener.open are intentionally left uncovered — exercising them requires touching UIPasteboard.general / UIApplication.shared, which is flaky and slow on the simulator and defeats the abstraction. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7 +/- ##
==========================================
+ Coverage 87.77% 96.08% +8.31%
==========================================
Files 30 18 -12
Lines 1562 511 -1051
==========================================
- Hits 1371 491 -880
+ Misses 191 20 -171 🚀 New features to boost your workflow:
|
Replaces the wide xccov text dump with a SwiftIntro-style coverage table: one Unicode box per non-test target, colour-coded green/yellow/red, plus a grand total across all libraries. The result-bundle → JSON conversion moves into _run-cov so cov-cobertura also benefits from a single source of truth. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Lifts package coverage from 70% to 91% by:
* Core: deeper ActivityIndicator lifecycle tests (subscribe/output/
completion/cancellation flips) and a stub-subclass exercise of
AbstractViewModel.
* Combine: binders for UIControl.isEnabled, UIControl.becomeFirstResponder,
UILabel.text, UIButton.titleBinder(for:), UIActivityIndicatorView
isAnimatingBinder; UITextField + UITextView text/placeholder binders
and notification-driven textPublisher / isEditingPublisher /
didBeginEditingPublisher; UITextView.isNearBottomPublisher.
The remaining gaps are unreachable without a host app:
.editingDidBegin/.editingDidEnd on UIControl don't fire reliably under
sendActions(for:) in an SPM test target without a window, and
Never+Helpers.swift's three fatalError traps are uncoverable by design.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
New tests close the reachable gaps in already-tested files:
* ErrorTracker.compactMap typed-error projection
* WithLatestFromPublisher upstream-completion forwarding
* UIControlPublisher dead-control branch (control deallocated
before subscribe)
* UITextView.isNearBottomPublisher overflow path (contentSize >
frame, threshold comparison)
Add codecov.yml + teach scripts/cov_table.py to honour its ignore
list. Three files are excluded so the metric reflects what's
actually testable from this SPM-only test setup:
* Pasteboard.swift / UrlOpener.swift — production wrappers around
UIPasteboard.general / UIApplication.shared. Covered via mock
conformers; testing live singletons was flaky and slow.
* Never+Helpers.swift — three fatalError traps that deliberately
crash on invariant violations.
Result: total coverage 97.4% (631/648), Combine 97.4%, Core 95.7%,
DIPrimitives 100%. Controller / Navigation / SceneViews still have
no test target wired up at all.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds broader unit test coverage across the package’s “primitives” and Combine/Core helpers, and introduces local/CI coverage reporting configuration aligned with Codecov.
Changes:
- Adds new XCTest files covering DI primitives (DateProvider, HapticFeedback, MainScheduler, Pasteboard convenience overload) plus additional Core/Combine branches.
- Introduces a
scripts/cov_table.pyhelper to render per-target/per-file coverage tables, and wires it intojust cov. - Adds a
codecov.ymlconfiguration (project coverage status; patch coverage disabled; ignore list for excluded files).
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Tests/NanoViewControllerDIPrimitivesTests/PasteboardTests.swift | Tests Pasteboard.copy(_:) extension overload forwarding behavior. |
| Tests/NanoViewControllerDIPrimitivesTests/MainSchedulerTests.swift | Tests ImmediateMainScheduler sync behavior and DispatchMainScheduler async behavior. |
| Tests/NanoViewControllerDIPrimitivesTests/HapticFeedbackTests.swift | Smoke-coverage for DefaultHapticFeedback.notify(_:) across feedback types. |
| Tests/NanoViewControllerDIPrimitivesTests/DateProviderTests.swift | Tests DefaultDateProvider.now() against wall-clock bounds / progression. |
| Tests/NanoViewControllerCoreTests/ErrorTrackerCompactMapTests.swift | Covers typed projections via ErrorTracker.compactMap(_:). |
| Tests/NanoViewControllerCoreTests/ActivityIndicatorTests.swift | Verifies activity lifecycle pulses flip the indicator as documented. |
| Tests/NanoViewControllerCoreTests/AbstractViewModelTests.swift | Exercises AbstractViewModel input stitching and override behavior. |
| Tests/NanoViewControllerCombineTests/WithLatestFromCompletionTests.swift | Covers upstream completion forwarding in withLatestFrom. |
| Tests/NanoViewControllerCombineTests/UIViewBindersTests.swift | Covers UIActivityIndicatorView.isAnimatingBinder start/stop branches. |
| Tests/NanoViewControllerCombineTests/UITextFieldPublishersTests.swift | Covers text binders/publishers and UITextView “near bottom” helpers. |
| Tests/NanoViewControllerCombineTests/UIControlPublisherDeadControlTests.swift | Covers “control already deallocated” completion path. |
| Tests/NanoViewControllerCombineTests/UIControlBindersTests.swift | Covers UIControl/UILabel/UIButton binder helpers. |
| scripts/cov_table.py | New script to print per-target/per-file coverage tables honoring Codecov ignore patterns. |
| justfile | Updates cov to use cov_table.py; moves JSON generation into _run-cov. |
| codecov.yml | Adds Codecov configuration and coverage ignore list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+20
to
+27
| func test_now_advancesMonotonically() async throws { | ||
| let provider = DefaultDateProvider() | ||
| let first = provider.now() | ||
| try await Task.sleep(for: .milliseconds(20)) | ||
| let second = provider.now() | ||
|
|
||
| XCTAssertGreaterThan(second, first) | ||
| } |
Comment on lines
+51
to
+56
| # - SceneViews / Navigation / Controller — large UIKit-bound modules | ||
| # with no test target wired up yet. They contribute 0 lines to xccov | ||
| # because they're never exercised; listing them here makes that | ||
| # intent explicit (and prevents future contributors from being | ||
| # confused by a sudden coverage drop when one of them gets its first | ||
| # test). |
Comment on lines
+19
to
+20
| COV_JSON = sys.argv[1] | ||
|
|
* DateProviderTests: drop the `>` monotonicity assertion — `Date()` is
a wall-clock read, not strictly monotonic, so an NTP adjustment or
fast successive calls could fail the assertion. Replace with a
bounded-window check that still re-exercises `now()` without baking
in an ordering invariant the API doesn't promise.
* codecov.yml: rewrite the misleading SceneViews/Navigation/Controller
note. Those modules are intentionally NOT in the ignore list — they
have no test target yet, so xccov reports 0 lines (not 0%), and once
a test target is added they should count toward the total.
* scripts/cov_table.py: validate sys.argv length and print a usage
line + exit 2 instead of letting an IndexError propagate.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
| // MIT License — Copyright (c) 2018-2026 Alexander Cyon (github.com/sajjon) | ||
|
|
||
| @testable import NanoViewControllerDIPrimitives | ||
| import UIKit |
Comment on lines
+7
to
+8
| /// returns `Date()`. Verifies that successive `now()` calls advance | ||
| /// monotonically and stay within a tight window of the real wall clock. |
Comment on lines
+21
to
+31
| // `Date()` reads the wall clock, which is not strictly monotonic | ||
| // (an NTP adjustment can move it backward, and successive reads on | ||
| // fast hardware can return equal timestamps). We only assert that | ||
| // the second read stays within a generous window of the first — | ||
| // enough to cover the `now()` line a second time without baking in | ||
| // a brittle ordering invariant the underlying API doesn't promise. | ||
| let provider = DefaultDateProvider() | ||
| let first = provider.now() | ||
| let second = provider.now() | ||
|
|
||
| XCTAssertLessThan(abs(second.timeIntervalSince(first)), 1.0) |
* DateProviderTests: reword the file's doc-comment so it no longer
claims a monotonicity invariant the tests deliberately don't assert.
Widen the bounded-window check from 1s to 30s so contended CI runners
(which can stall arbitrary user code for seconds) don't flake; the
looser envelope still catches a wholly-broken impl.
* PasteboardTests: drop the unused `import UIKit` (the file references
no UIKit symbols directly — the `Pasteboard` protocol's UIKit import
propagates transitively but doesn't belong in the test file).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds `// ARRANGE`, `// ACT`, `// ASSERT` markers inside each test function across all 22 test files in the package. The mechanical restructure preserves every assertion and ordering; behaviour is unchanged. All 89 tests still pass after the refactor. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds test files for DateProvider, HapticFeedback, MainScheduler, and the Pasteboard protocol-extension overload so the only previously-tested primitive (Clock) is no longer alone. The DefaultPasteboard production writes and DefaultUrlOpener.open are intentionally left uncovered — exercising them requires touching UIPasteboard.general / UIApplication.shared, which is flaky and slow on the simulator and defeats the abstraction.