Skip to content
Open
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
17 changes: 13 additions & 4 deletions Projects/Domain/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

## 현재 상태
- Auth 포트 추가 (`AuthSession`, `AuthError`, `AuthProvider`, `AuthClient`)
- User 포트 추가 (`UserProfile`, `OnboardingDraft`, `Gender`, `Interest`, `UserError`, `UserClient`)

## 이후 패턴
- `Domain/<Name>/{Model,Client,Error}`
Expand All @@ -20,14 +21,22 @@
- UseCase 층 없음

## 주요 진입점
- `Sources/Auth/AuthClient.swift`
- `Sources/Auth/AuthSession.swift`
- `Sources/Auth/AuthError.swift`
- `Sources/Auth/AuthProvider.swift`
- `Sources/Auth/Client/AuthClient.swift`
- `Sources/Auth/Model/AuthSession.swift`
- `Sources/Auth/Model/AuthProvider.swift`
- `Sources/Auth/Error/AuthError.swift`
- `Sources/User/Client/UserClient.swift`
- `Sources/User/Model/UserProfile.swift`
- `Sources/User/Model/OnboardingDraft.swift`
- `Sources/User/Model/Gender.swift`
- `Sources/User/Model/Interest.swift`
- `Sources/User/Error/UserError.swift`

## 테스트 포인트
- 세션 동등성/Codable 왕복
- `AuthClient.testValue` 기본 unimplemented 동작 (`@DependencyClient`)
- User model 동등성/Codable 왕복
- `UserClient.testValue` 기본 unimplemented 동작 (`@DependencyClient`)

## 관련 문서
- [ARCHITECTURE.md](../../docs/ARCHITECTURE.md)
Expand Down
18 changes: 18 additions & 0 deletions Projects/Domain/Sources/User/Client/UserClient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation
import ThirdParty

@DependencyClient
public struct UserClient: Sendable {
public var completeOnboarding: @Sendable (OnboardingDraft) async throws -> AuthSession
}

extension UserClient: TestDependencyKey {
public static let testValue = UserClient()
}

public extension DependencyValues {
var userClient: UserClient {
get { self[UserClient.self] }
set { self[UserClient.self] = newValue }
}
}
10 changes: 10 additions & 0 deletions Projects/Domain/Sources/User/Error/UserError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Foundation

public enum UserError: Error, Equatable, Sendable {
case network
case unauthorized
case validation(message: String)
case updateFailed
case storage(message: String)
case unknown(message: String)
}
7 changes: 7 additions & 0 deletions Projects/Domain/Sources/User/Model/Gender.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Foundation

public enum Gender: String, Equatable, Hashable, Sendable, Codable {
case male
case female
case other
}
11 changes: 11 additions & 0 deletions Projects/Domain/Sources/User/Model/Interest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Foundation

public struct Interest: Equatable, Hashable, Sendable, Codable {
public var id: String
public var name: String

public init(id: String, name: String) {
self.id = id
self.name = name
}
}
20 changes: 20 additions & 0 deletions Projects/Domain/Sources/User/Model/OnboardingDraft.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Foundation

public struct OnboardingDraft: Equatable, Sendable {
public var nickname: String
public var gender: Gender
public var birthDate: Date
public var interestIDs: [String]

public init(
nickname: String,
gender: Gender,
birthDate: Date,
interestIDs: [String]
) {
self.nickname = nickname
self.gender = gender
self.birthDate = birthDate
self.interestIDs = interestIDs
}
}
20 changes: 20 additions & 0 deletions Projects/Domain/Sources/User/Model/UserProfile.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Foundation

public struct UserProfile: Equatable, Sendable, Codable {
public var nickname: String
public var gender: Gender
public var birthDate: Date
public var interestIDs: [String]

public init(
nickname: String,
gender: Gender,
birthDate: Date,
interestIDs: [String]
) {
self.nickname = nickname
self.gender = gender
self.birthDate = birthDate
self.interestIDs = interestIDs
}
}
11 changes: 11 additions & 0 deletions Projects/Domain/Tests/User/UserClientTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Domain
import XCTest

final class UserClientTests: XCTestCase {
func test_UserClient_testValue는_빈_클라이언트로_생성() {
// @DependencyClient 는 testValue = UserClient() 를 기본 제공한다.
// 미구현 endpoint 호출 시 issue를 내므로, 생성 가능성만 검증한다.
_ = UserClient.testValue
XCTAssertTrue(true)
Comment on lines +5 to +9

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

UserClient.testValue의 검증 계약을 실제 테스트와 일치시키세요.

현재 테스트는 UserClient.testValue 생성만 확인합니다. README는 unimplemented endpoint 동작까지 검증한다고 설명합니다. Line 6의 주석도 testValue의 선언 주체를 잘못 설명합니다.

  • Projects/Domain/Tests/User/UserClientTests.swift#L5-L9: 테스트 주석과 이름을 생성 가능성 검증으로 명확히 하고, 불필요한 XCTAssertTrue(true)를 제거하거나 실제 검증으로 교체하세요.
  • Projects/Domain/README.md#L35-L39: 테스트 포인트를 “UserClient.testValue 생성 가능성 검증”으로 수정하거나 실제 unimplemented 동작 검증을 추가하세요.

As per coding guidelines: “테스트는 한국어 이름의 test_상황_기대결과 형식으로 작성하고, 모델 계약의 Equatable/Codable 및 Client testValue 동작을 검증한다.”

📍 Affects 2 files
  • Projects/Domain/Tests/User/UserClientTests.swift#L5-L9 (this comment)
  • Projects/Domain/README.md#L35-L39
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Projects/Domain/Tests/User/UserClientTests.swift` around lines 5 - 9, The
test contract is inconsistent with the documented behavior: update
Projects/Domain/Tests/User/UserClientTests.swift lines 5-9 by renaming the
Korean test to clearly describe UserClient.testValue creation, correcting the
comment to identify its actual declaration source, and removing the meaningless
XCTAssertTrue(true) or replacing it with a meaningful assertion; update
Projects/Domain/README.md lines 35-39 to document only UserClient.testValue
creation verification unless the test is expanded to exercise unimplemented
endpoint behavior.

Source: Coding guidelines

}
}
70 changes: 70 additions & 0 deletions Projects/Domain/Tests/User/UserModelTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import Domain
import XCTest

final class UserModelTests: XCTestCase {
func test_성별_rawValue와_동등성() {
XCTAssertEqual(Gender.male.rawValue, "male")
XCTAssertEqual(Gender.female.rawValue, "female")
XCTAssertEqual(Gender.other.rawValue, "other")
XCTAssertEqual(Gender.male, Gender.male)
}
Comment on lines +5 to +10

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

GenderCodable 계약을 검증하세요.

GenderCodable을 공개하지만 현재 테스트는 rawValueEquatable만 검증합니다. InterestUserProfile과 같이 JSON 인코드·디코드 왕복 테스트를 추가하세요.

수정 예시
+    func test_성별_codable_왕복() throws {
+        let data = try JSONEncoder().encode(Gender.other)
+        let decoded = try JSONDecoder().decode(Gender.self, from: data)
+        XCTAssertEqual(decoded, .other)
+    }

As per coding guidelines, "모델 계약의 Equatable/Codable 및 Client testValue 동작을 검증한다."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func test_성별_rawValue와_동등성() {
XCTAssertEqual(Gender.male.rawValue, "male")
XCTAssertEqual(Gender.female.rawValue, "female")
XCTAssertEqual(Gender.other.rawValue, "other")
XCTAssertEqual(Gender.male, Gender.male)
}
func test_성별_rawValue와_동등성() {
XCTAssertEqual(Gender.male.rawValue, "male")
XCTAssertEqual(Gender.female.rawValue, "female")
XCTAssertEqual(Gender.other.rawValue, "other")
XCTAssertEqual(Gender.male, Gender.male)
}
func test_성별_codable_왕복() throws {
let data = try JSONEncoder().encode(Gender.other)
let decoded = try JSONDecoder().decode(Gender.self, from: data)
XCTAssertEqual(decoded, .other)
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Projects/Domain/Tests/User/UserModelTests.swift` around lines 5 - 10, Update
the Gender tests around test_성별_rawValue와_동등성 to verify its Codable contract
with JSON encode/decode round-trip coverage, matching the existing Interest and
UserProfile test patterns. Preserve the current rawValue and equality assertions
while confirming each Gender case survives encoding and decoding.

Source: Coding guidelines


func test_관심사_동등성_비교() {
let a = Interest(id: "sports", name: "운동")
let b = Interest(id: "sports", name: "운동")
XCTAssertEqual(a, b)
}

func test_관심사_codable_왕복() throws {
let original = Interest(id: "music", name: "음악")
let data = try JSONEncoder().encode(original)
let decoded = try JSONDecoder().decode(Interest.self, from: data)
XCTAssertEqual(decoded, original)
}

func test_프로필_동등성_비교() {
let birthDate = Date(timeIntervalSince1970: 0)
let a = UserProfile(
nickname: "모지",
gender: .female,
birthDate: birthDate,
interestIDs: ["sports", "music"]
)
let b = UserProfile(
nickname: "모지",
gender: .female,
birthDate: birthDate,
interestIDs: ["sports", "music"]
)
XCTAssertEqual(a, b)
}

func test_프로필_codable_왕복() throws {
let original = UserProfile(
nickname: "모지",
gender: .other,
birthDate: Date(timeIntervalSince1970: 1_000),
interestIDs: ["travel"]
)
let data = try JSONEncoder().encode(original)
let decoded = try JSONDecoder().decode(UserProfile.self, from: data)
XCTAssertEqual(decoded, original)
}

func test_온보딩초안_동등성_비교() {
let birthDate = Date(timeIntervalSince1970: 2_000)
let a = OnboardingDraft(
nickname: "모지",
gender: .male,
birthDate: birthDate,
interestIDs: ["food"]
)
let b = OnboardingDraft(
nickname: "모지",
gender: .male,
birthDate: birthDate,
interestIDs: ["food"]
)
XCTAssertEqual(a, b)
}
}