PresentersTests/AppPresenterTests.swift:59 |
presenter.layout.windowFrame != expected.windowFrame |
PresentersTests/AppPresenterTests.swift:93 |
presenter.layout.windowFrame != initial.windowFrame |
PresentersTests/AppPresenterTests.swift:102 |
presenter.layout.windowFrame != updated.windowFrame |
PresentersTests/AppPresenterTests.swift:154 |
presenter.layout.windowFrame != updated.windowFrame |
PresentersTests/AppPresenterTests.swift:201 |
ripple.screenOrigin != CGPoint(x: 100, y: 40) |
PresentersTests/AppPresenterTests.swift:231 |
ripple.screenOrigin != CGPoint(x: 0, y: 40) |
PresentersTests/AppPresenterTests.swift:240 |
ripple.screenOrigin != CGPoint(x: 1920, y: 40) |
PresentersTests/AppPresenterTests.swift:271 |
presenter.layout.windowFrame != first.windowFrame |
PresentersTests/AppPresenterTests.swift:291 |
counter.count < 3 |
PresentersTests/AppPresenterTests.swift:312 |
presenter.layout.windowFrame != initial.windowFrame |
PresentersTests/AppPresenterTests.swift:358 |
presenter.layout.windowFrame == initial.windowFrame |
PresentersTests/AppPresenterTests.swift:365 |
presenter.layout.windowFrame == updated.windowFrame |
PresentersTests/AppPresenterTests.swift:391 |
presenter.layout.windowFrame == initial.windowFrame |
PresentersTests/AppPresenterTests.swift:405 |
presenter.layout.windowFrame == polled.windowFrame |
PresentersTests/HeaderPresenterDuplicateTests.swift:69 |
presenter.titlePhase != .revealed || presenter.artistPhase … |
PresentersTests/HeaderPresenterDuplicateTests.swift:107 |
presenter.titlePhase != .revealed || presenter.artistPhase … |
PresentersTests/HeaderPresenterDuplicateTests.swift:115 |
presenter.artworkImage == nil |
PresentersTests/HeaderPresenterDuplicateTests.swift:151 |
presenter.titlePhase != .revealed || presenter.artistPhase … |
PresentersTests/HeaderPresenterDuplicateTests.swift:162 |
presenter.artworkImage === cachedImage |
PresentersTests/HeaderPresenterTests.swift:162 |
presenter.titlePhase != .revealed || presenter.artistPhase … |
PresentersTests/HeaderPresenterTests.swift:187 |
presenter.titlePhase != .revealed || presenter.artistPhase … |
PresentersTests/HeaderPresenterTests.swift:193 |
presenter.titlePhase != .idle |
PresentersTests/HeaderPresenterTests.swift:241 |
presenter.titleColor == Self.processing |
PresentersTests/HeaderPresenterTests.swift:274 |
presenter.titleColor == Self.processing |
PresentersTests/HeaderPresenterTests.swift:277 |
presenter.titlePhase != .revealed || presenter.artistPhase … |
PresentersTests/HeaderPresenterTests.swift:300 |
presenter.titlePhase != .revealed || presenter.artistPhase … |
PresentersTests/HeaderPresenterTests.swift:326 |
presenter.titlePhase != .revealed || presenter.artistPhase … |
PresentersTests/HeaderPresenterTests.swift:377 |
presenter.titleStyle.fontSize == 32 |
PresentersTests/HeaderPresenterTests.swift:410 |
presenter.titleColor == initialProcessing |
PresentersTests/HeaderPresenterTests.swift:420 |
presenter.titleColor == updatedProcessing |
PresentersTests/HeaderPresenterTests.swift:462 |
presenter.displayTitle == "††" |
PresentersTests/HeaderPresenterTests.swift:476 |
presenter.displayTitle == "ΑΑ" |
PresentersTests/LyricsPresenterColumnsTests.swift:65 |
presenter.lyricsState が .success ケースになるまで(switch文でそれ以外は10ms… |
PresentersTests/LyricsPresenterColumnsTests.swift:92 |
presenter.lyricsState が .success ケースになるまで |
PresentersTests/LyricsPresenterColumnsTests.swift:119 |
presenter.lyricsState が .success ケースになるまで |
PresentersTests/LyricsPresenterColumnsTests.swift:143 |
presenter.lyricsState が .success ケースになるまで |
PresentersTests/LyricsPresenterDuplicateTests.swift:66 |
presenter.lyricsState.isSuccess が true になるまで(!isSuccess && … |
PresentersTests/LyricsPresenterDuplicateTests.swift:106 |
presenter.lyricsState.isSuccess が true になるまで |
PresentersTests/LyricsPresenterDuplicateTests.swift:157 |
presenter.lyricsState.isSuccess が true になるまで |
PresentersTests/LyricsPresenterTests.swift:154 |
presenter.lyricStyle.fontSize == 20 |
PresentersTests/LyricsPresenterTests.swift:180 |
presenter.lyricsState.isLoading |
PresentersTests/LyricsPresenterTests.swift:203 |
presenter.lyricsState != .failure(ループはこれを満たさなくなるまで継続) |
PresentersTests/LyricsPresenterTests.swift:228 |
presenter.lyricsState.isLoading |
PresentersTests/LyricsPresenterTests.swift:235 |
presenter.lyricsState.isIdle |
PresentersTests/LyricsPresenterTests.swift:261 |
presenter.lyricsStateが.success(_)になるまで |
PresentersTests/LyricsPresenterTests.swift:293 |
presenter.lyricsStateが.success(_)になるまで |
PresentersTests/LyricsPresenterTests.swift:336 |
presenter.lyricsStateが.success(_)になるまで |
PresentersTests/LyricsPresenterTests.swift:376 |
presenter.lyricsStateが.success(_)になるまで |
PresentersTests/LyricsPresenterTests.swift:428 |
presenter.lyricsStateが.success(_)になるまで |
PresentersTests/LyricsPresenterTests.swift:469 |
presenter.lyricsStateが.success(_)になるまで |
PresentersTests/LyricsPresenterTests.swift:517 |
presenter.lyricsStateが.success(_)になるまで |
PresentersTests/LyricsPresenterTests.swift:554 |
presenter.lyricsStateが.success(_)になるまで |
PresentersTests/LyricsPresenterTests.swift:612 |
presenter.lyricsStateが.success(_)になるまで |
PresentersTests/LyricsPresenterTests.swift:649 |
presenter.lyricsStateが.success(_)になるまで |
PresentersTests/SpectrumPresenterTests.swift:148 |
状態条件なし。直前の config.fire()(147行)で enqueue された appStyleChanges… |
PresentersTests/SpectrumPresenterTests.swift:154 |
状態条件なし。直前の2回目の config.fire()(153行、enabled:falseへの変更後)のmain-… |
PresentersTests/SpectrumPresenterTests.swift:184 |
状態条件なし。直前の config.fire()(183行、スタイルのみ変更後)のmain-queue配信完了を保証する |
PresentersTests/SpectrumPresenterTests.swift:190 |
状態条件なし。2回目の config.fire()(189行、スタイル変更なしの同一pingを再送)のmain-que… |
PresentersTests/SpectrumPresenterTests.swift:204 |
!presenter.binHeights().isEmpty(capturingTickPublishesBars:… |
PresentersTests/SpectrumPresenterTests.swift:222 |
!presenter.binHeights().isEmpty(barCountFollowsWidth: バー本数が… |
PresentersTests/SpectrumPresenterTests.swift:238 |
!presenter.binHeights().isEmpty(stereoCountIsEven: ステレオでのバー… |
PresentersTests/SpectrumPresenterTests.swift:253 |
presenter.isAnimating(zeroWidthNoBars: trackLength未設定でもcapt… |
PresentersTests/SpectrumPresenterTests.swift:270 |
!presenter.binHeights().isEmpty(barsFallAfterCapture 1回目: c… |
PresentersTests/SpectrumPresenterTests.swift:274 |
(presenter.binHeights().first ?? 1) < 1(barsFallAfterCaptur… |
PresentersTests/SpectrumPresenterTests.swift:280 |
presenter.binHeights().isEmpty(barsFallAfterCapture 3回目: 完全… |
PresentersTests/SpectrumPresenterTests.swift:298 |
!presenter.binHeights().isEmpty(attackIsInstant: capturing=… |
PresentersTests/SpectrumPresenterTests.swift:370 |
!presenter.binHeights().isEmpty(framesToClear 1回目: capturin… |
PresentersTests/SpectrumPresenterTests.swift:375 |
(presenter.binHeights().first ?? 1) < 0.5(framesToClear 2回目… |
PresentersTests/SpectrumPresenterTests.swift:408 |
!presenter.binHeights().isEmpty(fallenHeight 1回目: capturing… |
PresentersTests/SpectrumPresenterTests.swift:410 |
(presenter.binHeights().first ?? 1) < 1(fallenHeight 2回目: c… |
PresentersTests/WallpaperPresenterTests.swift:184 |
presenter.wallpaperURL == url |
PresentersTests/WallpaperPresenterTests.swift:203 |
!presenter.isLoading |
PresentersTests/WallpaperPresenterTests.swift:226 |
presenter.wallpaperURL == url |
PresentersTests/WallpaperPresenterTests.swift:246 |
presenter.wallpaperURL == url |
PresentersTests/WallpaperPresenterTests.swift:281 |
counter.count >= 1 |
PresentersTests/WallpaperPresenterTests.swift:301 |
!presenter.isLoading |
PresentersTests/WallpaperPresenterTests.swift:330 |
presenter.items.count == 2 |
PresentersTests/WallpaperPresenterTests.swift:332 |
recorder.players.count >= 1 |
PresentersTests/WallpaperPresenterTests.swift:337 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:357 |
presenter.wallpaperURL == url |
PresentersTests/WallpaperPresenterTests.swift:388 |
recorder.scales.contains(1.2) |
PresentersTests/WallpaperPresenterTests.swift:392 |
recorder.scales.contains(1.6) |
PresentersTests/WallpaperPresenterTests.swift:413 |
presenter.items.count == 3 |
PresentersTests/WallpaperPresenterTests.swift:418 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:422 |
presenter.wallpaperURL == c.url |
PresentersTests/WallpaperPresenterTests.swift:426 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:450 |
presenter.items.count == 3 |
PresentersTests/WallpaperPresenterTests.swift:454 |
presenter.wallpaperURL == c.url |
PresentersTests/WallpaperPresenterTests.swift:457 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:477 |
presenter.wallpaperURL == item.url |
PresentersTests/WallpaperPresenterTests.swift:503 |
presenter.items.count == 2 |
PresentersTests/WallpaperPresenterTests.swift:508 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:527 |
presenter.items.count == 2 |
PresentersTests/WallpaperPresenterTests.swift:532 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:552 |
presenter.items.count == 3 |
PresentersTests/WallpaperPresenterTests.swift:561 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:585 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:591 |
presenter.items.count == 2 |
PresentersTests/WallpaperPresenterTests.swift:594 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:615 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:627 |
presenter.items.count == 2 |
PresentersTests/WallpaperPresenterTests.swift:632 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:656 |
presenter.items.count == items.count (=5) |
PresentersTests/WallpaperPresenterTests.swift:662 |
presenter.wallpaperURL != prev |
PresentersTests/WallpaperPresenterTests.swift:688 |
presenter.items.count == 3 |
PresentersTests/WallpaperPresenterTests.swift:695 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:723 |
!presenter.isLoading |
PresentersTests/WallpaperPresenterTests.swift:755 |
presenter.showLoadingIndicator |
PresentersTests/WallpaperPresenterTests.swift:762 |
!presenter.showLoadingIndicator |
PresentersTests/WallpaperPresenterTests.swift:805 |
!presenter.isLoading |
PresentersTests/WallpaperPresenterTests.swift:831 |
presenter.player != nil |
PresentersTests/WallpaperPresenterTests.swift:857 |
presenter.player != nil |
PresentersTests/WallpaperPresenterTests.swift:884 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:891 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:914 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:940 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:946 |
presenter.wallpaperURL == nil |
PresentersTests/WallpaperPresenterTests.swift:951 |
presenter.player == nil |
PresentersTests/WallpaperPresenterTests.swift:975 |
presenter.player != nil |
PresentersTests/WallpaperPresenterTests.swift:981 |
counter.count == 1 |
PresentersTests/WallpaperPresenterTests.swift:1007 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:1008 |
attachCount.count == 1 |
PresentersTests/WallpaperPresenterTests.swift:1014 |
presenter.player == nil |
PresentersTests/WallpaperPresenterTests.swift:1020 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:1043 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:1081 |
presenter.items.count == 2 |
PresentersTests/WallpaperPresenterTests.swift:1097 |
presenter.wallpaperURL == a2.url |
PresentersTests/WallpaperPresenterTests.swift:1119 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:1125 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:1132 |
interactor.resolveCount == 3 |
PresentersTests/WallpaperPresenterTests.swift:1133 |
!presenter.isLoading |
PresentersTests/WallpaperPresenterTests.swift:1140 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:1169 |
presenter.items.count == 3 |
PresentersTests/WallpaperPresenterTests.swift:1176 |
interactor.resolveCount == 2 |
PresentersTests/WallpaperPresenterTests.swift:1177 |
!presenter.isLoading |
PresentersTests/WallpaperPresenterTests.swift:1180 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:1201 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:1207 |
!presenter.isLoading |
PresentersTests/WallpaperPresenterTests.swift:1219 |
presenter.wallpaperURL == b.url |
PresentersTests/WallpaperPresenterTests.swift:1240 |
presenter.wallpaperURL == a.url |
PresentersTests/WallpaperPresenterTests.swift:1255 |
!presenter.isLoading |
ViewsTests/SpectrumViewRenderingTests.swift:87 |
!presenter.binHeights().isEmpty (tickUntilBars 内部、35行目で毎tic… |
ViewsTests/ViewRenderingTests.swift:127 |
presenter.displayTitle == "Song" |
ViewsTests/ViewRenderingTests.swift:142 |
presenter.displayTitle == "Song" |
ViewsTests/ViewRenderingTests.swift:166 |
presenter.artworkImage != nil && presenter.displayTitle == … |
ViewsTests/ViewRenderingTests.swift:373 |
presenter.displayLyricLines == ["Line 1", "Line 2", "Line 3… |
ViewsTests/ViewRenderingTests.swift:466 |
wallpaperPresenter.showLoadingIndicator |
ViewsTests/ViewRenderingTests.swift:512 |
configStatusPresenter.invalidConfig != nil |
ViewsTests/ViewRenderingTests.swift:586 |
presenter.invalidConfig != nil |
ViewsTests/ViewRenderingTests.swift:613 |
presenter.invalidConfig != nil |
Issue #347(
#348)のフォローアップ。
背景
Issue #347 で、
が main queue を詰まらせると 期限切れの継続が presenter の
賭けの掛け金が上がるだけ。
#348 は待つ対象を「subject が書く
AppRouterTestsの期限ポーリングが flaky の原因そのものだと分かった:ContinuousClock期限付きのTask.sleepループは、.receive(on: DispatchQueue.main)ブロックより先に走り、値が届く直前の状態を assert する。期限を伸ばしても@Publishedの値そのもの」に変え、settle(_:until:)($property.valuesをfor await)で決定化した。Tests/PresentersTests/TestSupport/WaitUntil.swiftは棚卸し
Tests/配下の待機箇所を 1 ファイル 1 agent で全件列挙し、各箇所について 条件が読む状態の宣言(@Publishedか / どの isolation が書くか)をSources/まで追って 分類。別 agent が反証レビュー(11 件のAppRouterTestsは移行済みで除外)PresentersTests/ConfigStatusPresenterTests.swift(waitUntil3 箇所、未分類 —ConfigStatusPresenterの@Publishedを待つ形なのでpublished見込み)をCompletionCommandTests/YouTubeToolDetectionTestsのProcess.waitUntilExit()と、TrackInteractorRaceTestsの continuation ベースwaitForはpublished@Publishedを await)spy-readableexternalnegativeclockfixed-delayAsyncRunnableCommandTests/AsyncRunnableCommandTests.swiftConfigDataSourceTests/ConfigWatchTests.swiftConfigHotReloadTests/ConfigHotReloadPipelineTests.swiftConfigInteractorTests/ConfigInteractorImplTests.swiftDarwinGatewayTests/DarwinGatewayProcessTests.swiftDarwinGatewayTests/DarwinGatewayRunProcessTests.swiftDarwinGatewayTests/ProcessLockTests.swiftFileWatchGatewayTests/FileWatchGatewayTests.swiftLyricsRepositoryTests/LyricsCandidateWaveTests.swiftMediaRemoteDataSourceTests/MediaRemoteDataSourceImplTests.swiftNowPlayingRepositoryTests/NowPlayingRepositoryTests.swiftPresentersTests/AppPresenterTests.swiftPresentersTests/HeaderPresenterDuplicateTests.swiftPresentersTests/HeaderPresenterTests.swiftPresentersTests/LyricsPresenterColumnsTests.swiftPresentersTests/LyricsPresenterDuplicateTests.swiftPresentersTests/LyricsPresenterTests.swiftPresentersTests/SpectrumPresenterTests.swiftPresentersTests/WallpaperPresenterTests.swiftScreenInteractorTests/ScreenInteractorImplTests.swiftSpectrumInteractorTests/SpectrumInteractorImplTests.swiftTrackInteractorTests/TrackInteractorAIProcessingTests.swiftTrackInteractorTests/TrackInteractorArtworkTests.swiftTrackInteractorTests/TrackInteractorFallbackDisplayTests.swiftTrackInteractorTests/TrackInteractorPlaybackPositionTests.swiftViewsTests/SpectrumViewRenderingTests.swiftViewsTests/ViewRenderingTests.swiftWallpaperInteractorTests/WallpaperInteractorImplTests.swiftpublished— 150 箇所: settle にそのまま置換可(`@Published` を await)PresentersTests/AppPresenterTests.swift:59PresentersTests/AppPresenterTests.swift:93PresentersTests/AppPresenterTests.swift:102PresentersTests/AppPresenterTests.swift:154PresentersTests/AppPresenterTests.swift:201PresentersTests/AppPresenterTests.swift:231PresentersTests/AppPresenterTests.swift:240PresentersTests/AppPresenterTests.swift:271PresentersTests/AppPresenterTests.swift:291PresentersTests/AppPresenterTests.swift:312PresentersTests/AppPresenterTests.swift:358PresentersTests/AppPresenterTests.swift:365PresentersTests/AppPresenterTests.swift:391PresentersTests/AppPresenterTests.swift:405PresentersTests/HeaderPresenterDuplicateTests.swift:69PresentersTests/HeaderPresenterDuplicateTests.swift:107PresentersTests/HeaderPresenterDuplicateTests.swift:115PresentersTests/HeaderPresenterDuplicateTests.swift:151PresentersTests/HeaderPresenterDuplicateTests.swift:162PresentersTests/HeaderPresenterTests.swift:162PresentersTests/HeaderPresenterTests.swift:187PresentersTests/HeaderPresenterTests.swift:193PresentersTests/HeaderPresenterTests.swift:241PresentersTests/HeaderPresenterTests.swift:274PresentersTests/HeaderPresenterTests.swift:277PresentersTests/HeaderPresenterTests.swift:300PresentersTests/HeaderPresenterTests.swift:326PresentersTests/HeaderPresenterTests.swift:377PresentersTests/HeaderPresenterTests.swift:410PresentersTests/HeaderPresenterTests.swift:420PresentersTests/HeaderPresenterTests.swift:462PresentersTests/HeaderPresenterTests.swift:476PresentersTests/LyricsPresenterColumnsTests.swift:65PresentersTests/LyricsPresenterColumnsTests.swift:92PresentersTests/LyricsPresenterColumnsTests.swift:119PresentersTests/LyricsPresenterColumnsTests.swift:143PresentersTests/LyricsPresenterDuplicateTests.swift:66PresentersTests/LyricsPresenterDuplicateTests.swift:106PresentersTests/LyricsPresenterDuplicateTests.swift:157PresentersTests/LyricsPresenterTests.swift:154PresentersTests/LyricsPresenterTests.swift:180PresentersTests/LyricsPresenterTests.swift:203PresentersTests/LyricsPresenterTests.swift:228PresentersTests/LyricsPresenterTests.swift:235PresentersTests/LyricsPresenterTests.swift:261PresentersTests/LyricsPresenterTests.swift:293PresentersTests/LyricsPresenterTests.swift:336PresentersTests/LyricsPresenterTests.swift:376PresentersTests/LyricsPresenterTests.swift:428PresentersTests/LyricsPresenterTests.swift:469PresentersTests/LyricsPresenterTests.swift:517PresentersTests/LyricsPresenterTests.swift:554PresentersTests/LyricsPresenterTests.swift:612PresentersTests/LyricsPresenterTests.swift:649PresentersTests/SpectrumPresenterTests.swift:148PresentersTests/SpectrumPresenterTests.swift:154PresentersTests/SpectrumPresenterTests.swift:184PresentersTests/SpectrumPresenterTests.swift:190PresentersTests/SpectrumPresenterTests.swift:204PresentersTests/SpectrumPresenterTests.swift:222PresentersTests/SpectrumPresenterTests.swift:238PresentersTests/SpectrumPresenterTests.swift:253PresentersTests/SpectrumPresenterTests.swift:270PresentersTests/SpectrumPresenterTests.swift:274PresentersTests/SpectrumPresenterTests.swift:280PresentersTests/SpectrumPresenterTests.swift:298PresentersTests/SpectrumPresenterTests.swift:370PresentersTests/SpectrumPresenterTests.swift:375PresentersTests/SpectrumPresenterTests.swift:408PresentersTests/SpectrumPresenterTests.swift:410PresentersTests/WallpaperPresenterTests.swift:184PresentersTests/WallpaperPresenterTests.swift:203PresentersTests/WallpaperPresenterTests.swift:226PresentersTests/WallpaperPresenterTests.swift:246PresentersTests/WallpaperPresenterTests.swift:281PresentersTests/WallpaperPresenterTests.swift:301PresentersTests/WallpaperPresenterTests.swift:330PresentersTests/WallpaperPresenterTests.swift:332PresentersTests/WallpaperPresenterTests.swift:337PresentersTests/WallpaperPresenterTests.swift:357PresentersTests/WallpaperPresenterTests.swift:388PresentersTests/WallpaperPresenterTests.swift:392PresentersTests/WallpaperPresenterTests.swift:413PresentersTests/WallpaperPresenterTests.swift:418PresentersTests/WallpaperPresenterTests.swift:422PresentersTests/WallpaperPresenterTests.swift:426PresentersTests/WallpaperPresenterTests.swift:450PresentersTests/WallpaperPresenterTests.swift:454PresentersTests/WallpaperPresenterTests.swift:457PresentersTests/WallpaperPresenterTests.swift:477PresentersTests/WallpaperPresenterTests.swift:503PresentersTests/WallpaperPresenterTests.swift:508PresentersTests/WallpaperPresenterTests.swift:527PresentersTests/WallpaperPresenterTests.swift:532PresentersTests/WallpaperPresenterTests.swift:552PresentersTests/WallpaperPresenterTests.swift:561PresentersTests/WallpaperPresenterTests.swift:585PresentersTests/WallpaperPresenterTests.swift:591PresentersTests/WallpaperPresenterTests.swift:594PresentersTests/WallpaperPresenterTests.swift:615PresentersTests/WallpaperPresenterTests.swift:627PresentersTests/WallpaperPresenterTests.swift:632PresentersTests/WallpaperPresenterTests.swift:656PresentersTests/WallpaperPresenterTests.swift:662PresentersTests/WallpaperPresenterTests.swift:688PresentersTests/WallpaperPresenterTests.swift:695PresentersTests/WallpaperPresenterTests.swift:723PresentersTests/WallpaperPresenterTests.swift:755PresentersTests/WallpaperPresenterTests.swift:762PresentersTests/WallpaperPresenterTests.swift:805PresentersTests/WallpaperPresenterTests.swift:831PresentersTests/WallpaperPresenterTests.swift:857PresentersTests/WallpaperPresenterTests.swift:884PresentersTests/WallpaperPresenterTests.swift:891PresentersTests/WallpaperPresenterTests.swift:914PresentersTests/WallpaperPresenterTests.swift:940PresentersTests/WallpaperPresenterTests.swift:946PresentersTests/WallpaperPresenterTests.swift:951PresentersTests/WallpaperPresenterTests.swift:975PresentersTests/WallpaperPresenterTests.swift:981PresentersTests/WallpaperPresenterTests.swift:1007PresentersTests/WallpaperPresenterTests.swift:1008PresentersTests/WallpaperPresenterTests.swift:1014PresentersTests/WallpaperPresenterTests.swift:1020PresentersTests/WallpaperPresenterTests.swift:1043PresentersTests/WallpaperPresenterTests.swift:1081PresentersTests/WallpaperPresenterTests.swift:1097PresentersTests/WallpaperPresenterTests.swift:1119PresentersTests/WallpaperPresenterTests.swift:1125PresentersTests/WallpaperPresenterTests.swift:1132PresentersTests/WallpaperPresenterTests.swift:1133PresentersTests/WallpaperPresenterTests.swift:1140PresentersTests/WallpaperPresenterTests.swift:1169PresentersTests/WallpaperPresenterTests.swift:1176PresentersTests/WallpaperPresenterTests.swift:1177PresentersTests/WallpaperPresenterTests.swift:1180PresentersTests/WallpaperPresenterTests.swift:1201PresentersTests/WallpaperPresenterTests.swift:1207PresentersTests/WallpaperPresenterTests.swift:1219PresentersTests/WallpaperPresenterTests.swift:1240PresentersTests/WallpaperPresenterTests.swift:1255ViewsTests/SpectrumViewRenderingTests.swift:87ViewsTests/ViewRenderingTests.swift:127ViewsTests/ViewRenderingTests.swift:142ViewsTests/ViewRenderingTests.swift:166ViewsTests/ViewRenderingTests.swift:373ViewsTests/ViewRenderingTests.swift:466ViewsTests/ViewRenderingTests.swift:512ViewsTests/ViewRenderingTests.swift:586ViewsTests/ViewRenderingTests.swift:613spy-readable— 54 箇所: spy / fake が publish すれば置換可ConfigHotReloadTests/ConfigHotReloadPipelineTests.swift:88ConfigHotReloadTests/ConfigHotReloadPipelineTests.swift:102ConfigHotReloadTests/ConfigHotReloadPipelineTests.swift:185ConfigInteractorTests/ConfigInteractorImplTests.swift:43observed.pingedはローカルObservedクラス(23-35行目)の NSLock 保護された素の `Bool…ConfigInteractorTests/ConfigInteractorImplTests.swift:85observed.invalidはローカルObservedクラス(65-77行目)の NSLock 保護された `Confi…LyricsRepositoryTests/LyricsCandidateWaveTests.swift:163private var waveArrived = false(154行目)とprivate var inFlight = 0(…LyricsRepositoryTests/LyricsCandidateWaveTests.swift:227private var fastAnswered = false(205行目)は `private actor SlowHitData…NowPlayingRepositoryTests/NowPlayingRepositoryTests.swift:283ScreenInteractorTests/ScreenInteractorImplTests.swift:313ScreenInteractorTests/ScreenInteractorImplTests.swift:340SpectrumInteractorTests/SpectrumInteractorImplTests.swift:18SpectrumInteractorTests/SpectrumInteractorImplTests.swift:20SpectrumInteractorTests/SpectrumInteractorImplTests.swift:29SpectrumInteractorTests/SpectrumInteractorImplTests.swift:32SpectrumInteractorTests/SpectrumInteractorImplTests.swift:34SpectrumInteractorTests/SpectrumInteractorImplTests.swift:45SpectrumInteractorTests/SpectrumInteractorImplTests.swift:61SpectrumInteractorTests/SpectrumInteractorImplTests.swift:70SpectrumInteractorTests/SpectrumInteractorImplTests.swift:73SpectrumInteractorTests/SpectrumInteractorImplTests.swift:94SpectrumInteractorTests/SpectrumInteractorImplTests.swift:97SpectrumInteractorTests/SpectrumInteractorImplTests.swift:106SpectrumInteractorTests/SpectrumInteractorImplTests.swift:116SpectrumInteractorTests/SpectrumInteractorImplTests.swift:135SpectrumInteractorTests/SpectrumInteractorImplTests.swift:137SpectrumInteractorTests/SpectrumInteractorImplTests.swift:155SpectrumInteractorTests/SpectrumInteractorImplTests.swift:171SpectrumInteractorTests/SpectrumInteractorImplTests.swift:180SpectrumInteractorTests/SpectrumInteractorImplTests.swift:186SpectrumInteractorTests/SpectrumInteractorImplTests.swift:188TrackInteractorTests/TrackInteractorAIProcessingTests.swift:125TrackInteractorTests/TrackInteractorAIProcessingTests.swift:142TrackInteractorTests/TrackInteractorAIProcessingTests.swift:157TrackInteractorTests/TrackInteractorArtworkTests.swift:104private var emissions: [Data?] = [](N…TrackInteractorTests/TrackInteractorArtworkTests.swift:108TrackInteractorTests/TrackInteractorArtworkTests.swift:124private var emissions: [Data?] = [])。in…TrackInteractorTests/TrackInteractorArtworkTests.swift:127TrackInteractorTests/TrackInteractorArtworkTests.swift:144TrackInteractorTests/TrackInteractorArtworkTests.swift:147TrackInteractorTests/TrackInteractorArtworkTests.swift:164TrackInteractorTests/TrackInteractorArtworkTests.swift:174TrackInteractorTests/TrackInteractorArtworkTests.swift:189TrackInteractorTests/TrackInteractorArtworkTests.swift:195TrackInteractorTests/TrackInteractorArtworkTests.swift:210TrackInteractorTests/TrackInteractorArtworkTests.swift:213TrackInteractorTests/TrackInteractorFallbackDisplayTests.swift:99TrackInteractorTests/TrackInteractorPlaybackPositionTests.swift:100TrackInteractorTests/TrackInteractorPlaybackPositionTests.swift:120TrackInteractorTests/TrackInteractorPlaybackPositionTests.swift:142TrackInteractorTests/TrackInteractorPlaybackPositionTests.swift:148TrackInteractorTests/TrackInteractorPlaybackPositionTests.swift:171TrackInteractorTests/TrackInteractorPlaybackPositionTests.swift:186WallpaperInteractorTests/WallpaperInteractorImplTests.swift:231Collector.events(本ファイル223行目): `final class Collector: @unchecked Se…WallpaperInteractorTests/WallpaperInteractorImplTests.swift:256Collector.events(本ファイル248行目、emitsWillSleep とは別インスタンスの同一定義): `final …external— 43 箇所: 外部要因(subprocess / FS / DispatchSource / tick 駆動)— 期限ポーリングのままConfigDataSourceTests/ConfigWatchTests.swift:416ConfigDataSourceTests/ConfigWatchTests.swift:430ConfigDataSourceTests/ConfigWatchTests.swift:461ConfigDataSourceTests/ConfigWatchTests.swift:473ConfigDataSourceTests/ConfigWatchTests.swift:484DarwinGatewayTests/DarwinGatewayProcessTests.swift:23DarwinGatewayTests/DarwinGatewayProcessTests.swift:25gateway.isRunning(pid)がtrueを返すことDarwinGatewayTests/DarwinGatewayProcessTests.swift:48DarwinGatewayTests/DarwinGatewayProcessTests.swift:50gateway.isRunning(process.processIdentifier)がtrueを返すことDarwinGatewayTests/DarwinGatewayProcessTests.swift:54DarwinGatewayTests/DarwinGatewayRunProcessTests.swift:72DarwinGatewayTests/DarwinGatewayRunProcessTests.swift:88DarwinGatewayTests/DarwinGatewayRunProcessTests.swift:115DarwinGatewayTests/DarwinGatewayRunProcessTests.swift:129DarwinGatewayTests/ProcessLockTests.swift:53DarwinGatewayTests/ProcessLockTests.swift:54DarwinGatewayTests/ProcessLockTests.swift:66DarwinGatewayTests/ProcessLockTests.swift:67DarwinGatewayTests/ProcessLockTests.swift:104DarwinGatewayTests/ProcessLockTests.swift:107DarwinGatewayTests/ProcessLockTests.swift:119DarwinGatewayTests/ProcessLockTests.swift:122DarwinGatewayTests/ProcessLockTests.swift:146DarwinGatewayTests/ProcessLockTests.swift:147DarwinGatewayTests/ProcessLockTests.swift:151DarwinGatewayTests/ProcessLockTests.swift:205DarwinGatewayTests/ProcessLockTests.swift:206FileWatchGatewayTests/FileWatchGatewayTests.swift:26FileWatchGatewayTests/FileWatchGatewayTests.swift:52FileWatchGatewayTests/FileWatchGatewayTests.swift:77PresentersTests/AppPresenterTests.swift:364PresentersTests/AppPresenterTests.swift:397PresentersTests/LyricsPresenterDuplicateTests.swift:111PresentersTests/LyricsPresenterDuplicateTests.swift:124PresentersTests/LyricsPresenterDuplicateTests.swift:161PresentersTests/LyricsPresenterTests.swift:342PresentersTests/LyricsPresenterTests.swift:387PresentersTests/LyricsPresenterTests.swift:438PresentersTests/LyricsPresenterTests.swift:474PresentersTests/LyricsPresenterTests.swift:484PresentersTests/LyricsPresenterTests.swift:522PresentersTests/LyricsPresenterTests.swift:560PresentersTests/WallpaperPresenterTests.swift:836negative— 13 箇所: 否定アサーション(起きないことの確認)— 別の表現が要るConfigInteractorTests/ConfigInteractorImplTests.swift:181PresentersTests/AppPresenterTests.swift:321PresentersTests/HeaderPresenterDuplicateTests.swift:75PresentersTests/HeaderPresenterDuplicateTests.swift:125PresentersTests/HeaderPresenterTests.swift:333PresentersTests/LyricsPresenterDuplicateTests.swift:71PresentersTests/LyricsPresenterDuplicateTests.swift:171PresentersTests/LyricsPresenterTests.swift:304PresentersTests/LyricsPresenterTests.swift:588presenter.lyricsState.isIdleを確認する…PresentersTests/LyricsPresenterTests.swift:623!enteredRevealingを確認する否定的アサーション(『…PresentersTests/LyricsPresenterTests.swift:657presenter.stop()呼び出し後に新規emissionを送り、200ms待った後に一…PresentersTests/WallpaperPresenterTests.swift:483PresentersTests/WallpaperPresenterTests.swift:620clock— 1 箇所: 本来は clock 注入で解くべきPresentersTests/SpectrumPresenterTests.swift:380fixed-delay— 3 箇所: 条件なしの固定 sleepAsyncRunnableCommandTests/AsyncRunnableCommandTests.swift:151LyricsRepositoryTests/LyricsCandidateWaveTests.swift:189MediaRemoteDataSourceTests/MediaRemoteDataSourceImplTests.swift:480スイープで拾った scout リスト外のファイル
PresentersTests/TestSupport/WaitUntil.swiftPresentersTests/ConfigStatusPresenterTests.swiftCLITests/CompletionCommandTests.swiftWallpaperDataSourceTests/YouTubeToolDetectionTests.swiftPresentersTests/FakeConfigInteractor.swiftTrackInteractorTests/TrackInteractorRaceTests.swift分類ごとに手段が違う。数の多い順ではなく 依存順 に並べる。
0.
ターゲットへ(前提)
settleをsettleはTests/AppRouterTests/TestSupport/Settle.swiftにあり、SwiftPM のPresentersTestsからは呼べない(Package.swiftのPresentersTestsはPresenters/Domain/Dependenciesにしか依存していない)。Tests/TestSupport/に通常の.target(依存は Combine のみ)を作ってsettleを移し、使うsettleを使う suite にはAppRouterTestsと.timeLimit(.minutes(1))を付ける(値が来ない回帰はハングになるため)。1.
published— 150 箇所: 機械的にawait waitUntil { p.x == v }→await settle(p.$x) { $0 == v }。複合条件は 1 値 1settleにWallpaperPresenterTests71、SpectrumPresenterTests16、LyricsPresenterTests15、AppPresenterTests14、HeaderPresenterTests13、ViewRenderingTests8、HeaderPresenterDuplicateTests5、LyricsPresenterColumnsTests4、LyricsPresenterDuplicateTests3、SpectrumViewRenderingTests1。WallpaperPresenterTests:330が読むWallpaperPresenter.itemsは@Publishedではない本番プロパティ。@Publishedの隣接状態を待つか、itemsを@Publishedにする(小さな本番変更)かを PR で判断。呼び出し元がなくなった時点で
。
Tests/PresentersTests/TestSupport/WaitUntil.swiftと各ファイルの privatewaitUntil/waitForReveal/waitForLyricsSuccess/waitForItemsLoadedを2.
spy-readable— 54 箇所: spy を publish させる条件が読むのは
側の collector / stub の plain プロパティで、書き手は nonisolated
の
Taskや thread pool。NSLockemissions配列 +waitForCountが典型:TrackInteractorTestsのArtworkCollector/PositionCollector/TrackUpdateCollector(19)、SpectrumInteractorImplTestsの stub(20)、ConfigHotReloadPipelineTests3、TrackInteractorAIProcessingTests3、ScreenInteractorImplTests2、WallpaperInteractorImplTests2、ConfigInteractorImplTests2、LyricsCandidateWaveTests2、NowPlayingRepositoryTests1。手本はリポジトリ内にある:
く suite に
TrackInteractorRaceTests.TrackUpdateCollector.waitFor(predicate:)はCheckedContinuationで 要素の到着時に再開 する。これをTestSupportの汎用Collector<Element>(waitFor(predicate:)/waitForCount(_:)、期限なし)に一般化し、3 つの同型 collector と stub 群を置き換える。settleと.timeLimit。3.
を名前に
external— 43 箇所: 期限ポーリングのまま、ただしDarwinGatewayTests22)、DispatchSource/ FSEvents(ConfigWatchTests5、FileWatchGatewayTests3): プロセス外の状態に await できる signal はないので poll が正しい。subprocess 側の timeout oracle は test: executeProcess の Oracle 要素を抽象化してフレークを構造的に断つ #340 のProcessExecutorへの clock 注入)に従い、ここでは触らないLyricsPresenterTests7、LyricsPresenterDuplicateTests3、AppPresenterTests2、WallpaperPresenterTests1): ループ内でupdateActiveLineTick()を呼んで@Published activeLineIndexを再計算させている。書き手はsettleは永久にハングする。SpectrumPresenterTestsのtickUntilと残す poll は
であること が名前から分かる形にし、
waitUntilではなくpollUntil(deadline:)のように 期限がCLAUDE.mdの「読むしかない状態」に該当する旨をコメントに書く。4.
negative— 13 箇所: 「起きないこと」の固定 sleep や短い期限で「状態が変わらない」ことを見ている(
なので表現できない。方針: 番兵イベント —
できる後続イベントを送って
LyricsPresenterTests4、LyricsPresenterDuplicateTests2、HeaderPresenterDuplicateTests2、WallpaperPresenterTests2、AppPresenterTests1、HeaderPresenterTests1、ConfigInteractorImplTests1)。settleは「特定の値への emit」を待つsettleで待ち、その時点で「途中の遷移がなかった」ことを assert する(LyricsPresenterTests.resolvedDuplicateLyricsが$lyricsState.dropFirst().sinkで既にやっている形)。番兵を作れない箇所は短い有界 wait を残し、否定アサーションである旨をコメントに書く。5.
外(記録のみ)
PresentersTests/SpectrumPresenterTests.swift:380tick()を何回呼べば収束するかを数えるLyricsRepositoryTests/LyricsCandidateWaveTests.swift:189AsyncRunnableCommandTests/AsyncRunnableCommandTests.swift:151DispatchSemaphore+ 非Task)を通すための mock 側 sleepMediaRemoteDataSourceTests/MediaRemoteDataSourceImplTests.swift:480poll()を確実に並行させるためのタイミング調整。本物の smell だがsettleの話ではない — 別 issue 候補進め方
1 と 2 は独立なので並行可。各
で mutation 検証(
settle/Collector.waitForを no-op 化して移行対象が CI と同じシグネチャで落ちること)と、8 コア飽和の負荷下ストレス(PR #348 と同じ手順)を通す。Tests/TestSupport/にsettleとCollectorがあり、AppRouterTestsを含む複数ターゲットから使われている(test(#349): PresentersTests / ViewsTests の published 待ちを settle(_:until:) に移行する #350、test(#349): spy-readable 54 箇所の期限ポーリングを Collector 待ちに移行する #351)published150 箇所とspy-readable54 箇所にContinuousClock期限が残っていない(test(#349): PresentersTests / ViewsTests の published 待ちを settle(_:until:) に移行する #350、test(#349): spy-readable 54 箇所の期限ポーリングを Collector 待ちに移行する #351)Tests/PresentersTests/TestSupport/WaitUntil.swiftと各ファイルの期限付き private ヘルパーがsettle/Collectorを使う全 suite に.timeLimit(test(#349): PresentersTests / ViewsTests の published 待ちを settle(_:until:) に移行する #350、test(#349): spy-readable 54 箇所の期限ポーリングを Collector 待ちに移行する #351、test(#349): external / tick / negative の待ちを pollUntil / tickUntil / Collector / 番兵に移行する #352)external/negativeの待機は名前かコメントでConfigStatusPresenterTestsの 3 箇所も分類・swift test全ターゲット並列で green、PresentersTestsの負荷下 20/20(test(#349): external / tick / negative の待ちを pollUntil / tickUntil / Collector / 番兵に移行する #352 — 全体 1448 tests green、移行 6 ターゲット負荷下 20/20)CLAUDE.md/AGENTS.mdの Testing Guidelines が「settleはTestSupport」を指している(8d4248e、test(#349): PresentersTests / ViewsTests の published 待ちを settle(_:until:) に移行する #350)settleのwithMainSerialExecutor却下の経緯externalの subprocess 系はこちらの