Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ struct RootFeature {
if result {
state.selectedMainTab = .home
} else {
return trackLoginScreenEffect()
return .merge(
trackLoginScreenEffect(),
clearApplicationBadgeCountEffect()
)
}
Comment thread
opficdev marked this conversation as resolved.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Combine
import ComposableArchitecture
import DevLogCore
import DevLogDomain
import Foundation
import Testing
@testable import DevLogPresentation

Expand Down Expand Up @@ -299,9 +300,18 @@ final class RootTrackAnalyticsEventUseCaseSpy: TrackAnalyticsEventUseCase {
}

final class RootApplicationBadgeCountSpy: @unchecked Sendable {
private(set) var counts = [Int]()
private let lock = NSLock()
private var protectedCounts = [Int]()

var counts: [Int] {
lock.withLock {
protectedCounts
}
}

func setBadgeCount(_ count: Int) async throws {
counts.append(count)
lock.withLock {
protectedCounts.append(count)
}
}
}
13 changes: 13 additions & 0 deletions Application/DevLogPresentation/Tests/Root/RootFeatureTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ struct RootFeatureTests {
await verifyDidLoginedFalse(adapter: adapter, trackAnalyticsEventUseCaseSpy: trackSpy)
}

@Test("RootFeature didLogined(false)는 앱 badge 초기화를 요청한다")
func RootFeature_didLogined_false는_앱_badge_초기화를_요청한다() async {
let badgeSpy = RootApplicationBadgeCountSpy()
let adapter = RootStoreTestAdapter(badgeCountSpy: badgeSpy)

await adapter.didLogined(false)
await waitUntil {
badgeSpy.counts == [0]
}

#expect(badgeSpy.counts == [0])
Comment on lines +48 to +52

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

현재 RootApplicationBadgeCountSpy@unchecked Sendable로 선언되어 있으나, 내부 counts 배열에 대한 동기화 처리가 없어 Data Race가 발생할 수 있습니다.

clearApplicationBadgeCountEffect().run 블록은 협력 스레드 풀(Cooperative Thread Pool)에서 비동기적으로 실행되어 setBadgeCount를 호출하는 반면, 테스트 코드는 @MainActor에서 badgeSpy.counts를 읽기 때문에 동시 접근이 발생합니다.

이 문제를 해결하려면 RootFeatureTestSupport.swift 파일에 정의된 RootApplicationBadgeCountSpy@MainActor로 격리하거나, 내부적으로 NSLock 또는 OSAllocatedUnfairLock 등을 사용하여 스레드 안전성을 확보해야 합니다.

}

@Test("RootFeature didLogined(true)는 기존 Root 상태관리처럼 signIn 상태를 true로 갱신하고 selectedMainTab을 home으로 되돌린다")
func RootFeature_didLogined_true는_기존_Root_상태관리처럼_signIn_상태를_true로_갱신하고_selectedMainTab을_home으로_되돌린다() async {
let trackSpy = RootTrackAnalyticsEventUseCaseSpy()
Expand Down
Loading