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
16 changes: 12 additions & 4 deletions Projects/App/Sources/DI/Assembly/DomainAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,20 @@ class DomainAssembly: Assembly {
DefaultRootPageUseCase()
}

container.register(AllMarketTickersUseCase.self) { _ in
DefaultAllMarketTickersUseCase()
container.register(AllMarketTickersUseCase.self) { resolver in
DefaultAllMarketTickersUseCase(
allMarketTickersRepository: resolver.resolve(AllMarketTickersRepository.self)!,
exchangeRateRepository: resolver.resolve(ExchangeRateRepository.self)!,
userConfigurationRepository: resolver.resolve(UserConfigurationRepository.self)!
)
}

container.register(CoinDetailPageUseCase.self) { _ in
DefaultCoinDetailPageUseCase()
container.register(CoinDetailPageUseCase.self) { resolver in
DefaultCoinDetailPageUseCase(
orderbookRepository: resolver.resolve(OrderbookRepository.self)!,
singleTickerRepository: resolver.resolve(SingleMarketTickerRepository.self)!,
coinTradeRepository: resolver.resolve(CoinTradeRepository.self)!
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,21 @@ import CoreUtil

public final class DefaultAllMarketTickersUseCase: AllMarketTickersUseCase {
// Dependency
@Injected private var allMarketTickersRepository: AllMarketTickersRepository
@Injected private var exchangeRateRepository: ExchangeRateRepository
@Injected private var userConfigurationRepository: UserConfigurationRepository
private var allMarketTickersRepository: AllMarketTickersRepository
private var exchangeRateRepository: ExchangeRateRepository
private var userConfigurationRepository: UserConfigurationRepository

private let standardSymbol = "USDT"

public init() { }
public init(
allMarketTickersRepository: AllMarketTickersRepository,
exchangeRateRepository: ExchangeRateRepository,
userConfigurationRepository: UserConfigurationRepository
) {
self.allMarketTickersRepository = allMarketTickersRepository
self.exchangeRateRepository = exchangeRateRepository
self.userConfigurationRepository = userConfigurationRepository
}

// 도메인 로직
private func fetchGreatestQuantity(entity: AVLTree<Twenty4HourTickerForSymbolVO>, maxCount: UInt) -> [Twenty4HourTickerForSymbolVO] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,18 @@ import CoreUtil

final public class DefaultCoinDetailPageUseCase: CoinDetailPageUseCase {
// Dependency
@Injected private var orderbookRepository: OrderbookRepository
@Injected private var singleTickerRepository: SingleMarketTickerRepository
@Injected private var coinTradeRepository: CoinTradeRepository
private var orderbookRepository: OrderbookRepository
private var singleTickerRepository: SingleMarketTickerRepository
private var coinTradeRepository: CoinTradeRepository

public init() { }
public init(
orderbookRepository: OrderbookRepository,
singleTickerRepository: SingleMarketTickerRepository,
coinTradeRepository: CoinTradeRepository) {
self.orderbookRepository = orderbookRepository
self.singleTickerRepository = singleTickerRepository
self.coinTradeRepository = coinTradeRepository
}
}


Expand Down
2 changes: 1 addition & 1 deletion Projects/Domain/Interface/Entity/Orderbook/Orderbook.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import CoreUtil

public struct Orderbook: Sendable {
public struct Orderbook: Sendable, Equatable {
public let price: CVNumber
public let quantity: CVNumber
public init(price: CVNumber, quantity: CVNumber) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
import CoreUtil

public struct OrderbookTable {
public let bidOrderbooks: HashMap<CVNumber, CVNumber>
public let askOrderbooks: HashMap<CVNumber, CVNumber>
public typealias Price = CVNumber
public typealias Quantity = CVNumber

public init(bidOrderbooks: HashMap<CVNumber, CVNumber>, askOrderbooks: HashMap<CVNumber, CVNumber>) {
public let bidOrderbooks: HashMap<Price, Quantity>
public let askOrderbooks: HashMap<Price, Quantity>

public init(bidOrderbooks: HashMap<Price, Quantity>, askOrderbooks: HashMap<Price, Quantity>) {
self.bidOrderbooks = bidOrderbooks
self.askOrderbooks = askOrderbooks
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// StubAllMaketTickerRepository.swift
// Domain
//
// Created by choijunios on 4/24/25.
//

import Combine

import DomainInterface
import CoreUtil

public struct StubAllMarketTickerRepository: AllMarketTickersRepository {

public let maxTickerCount: Int
public let usdtSuffixCount: Int

public init(maxTickerCount: Int, usdtSuffixCount: Int) {
self.maxTickerCount = maxTickerCount
self.usdtSuffixCount = usdtSuffixCount
}

private func createFakeData() -> AVLTree<Twenty4HourTickerForSymbolVO> {
let tree = AVLTree<Twenty4HourTickerForSymbolVO>()
for index in 0..<maxTickerCount {
let vo = Twenty4HourTickerForSymbolVO(
pairSymbol: index < usdtSuffixCount ? "BTCUSDT" : "BTCADA",
price: CVNumber(Double(100 * index)),
totalTradedQuoteAssetVolume: CVNumber(Double(100 * index)),
changedPercent: CVNumber(Double(100 * index)),
bestBidPrice: CVNumber(Double(100 * index)),
bestAskPrice: CVNumber(Double(100 * index))
)
tree.insert(vo)
}
return tree
}

public func getAllMarketTicker() -> AnyPublisher<AVLTree<Twenty4HourTickerForSymbolVO>, Never> {
return Just(createFakeData()).eraseToAnyPublisher()
}

public func getAllMarketTicker() async -> AVLTree<Twenty4HourTickerForSymbolVO> {
return createFakeData()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// StubExchangeRateRepository.swift
// Domain
//
// Created by choijunios on 4/24/25.
//

import DomainInterface

public struct StubExchangeRateRepository: ExchangeRateRepository {

public let fixedRate: Double

public init(fixedRate: Double) {
self.fixedRate = fixedRate
}

public func prepareRates(base: DomainInterface.CurrencyType, to: [DomainInterface.CurrencyType]) async throws { }
public func getRate(base: DomainInterface.CurrencyType, to: DomainInterface.CurrencyType) async -> Double? { return fixedRate }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// StubUserConfigurationRepository.swift
// Domain
//
// Created by choijunios on 4/24/25.
//

import DomainInterface

public struct StubUserConfigurationRepository: UserConfigurationRepository {

public init() { }

public func getCurrencyType() -> DomainInterface.CurrencyType {
return .dollar
}

public func setCurrencyType(type: DomainInterface.CurrencyType) {

}

public func getLanguageType() -> DomainInterface.LanguageType {
return .english
}

public func setLanguageType(type: DomainInterface.LanguageType) {

}

public func getGridType() -> DomainInterface.GridType {
return .list
}

public func setGridType(type: DomainInterface.GridType) {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// StubCoinTradeRepository.swift
// Domain
//
// Created by choijunios on 4/24/25.
//

import Foundation
import Combine

import DomainInterface
import CoreUtil

public struct StubCoinTradeRepository: CoinTradeRepository {

public init() { }

public func getCoinTradeList(symbolPair: String, tableUpdateInterval: Double?) -> AnyPublisher<HashMap<Date, CoinTradeVO>, Never> {
let hashMap = HashMap<Date, CoinTradeVO>()
return Just(hashMap).eraseToAnyPublisher()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// StubOrderbookRepository.swift
// Domain
//
// Created by choijunios on 4/24/25.
//

import Combine

import DomainInterface
import CoreUtil

public struct StubOrderbookRepository: OrderbookRepository {

private let bidOrderbookCount: Int
public var bidOrderbookSource: [(CVNumber, CVNumber)] {
(0..<bidOrderbookCount).map { index in
(CVNumber(index)!, CVNumber((0..<1000).randomElement()!)!)
}
}

private let askOrderbookCount: Int
public var askOrderbookSource: [(CVNumber, CVNumber)] {
(0..<askOrderbookCount).map { index in
(CVNumber(index)!, CVNumber((0..<1000).randomElement()!)!)
}
}

public init(bidOrderbookCount: Int, askOrderbookCount: Int) {
self.bidOrderbookCount = bidOrderbookCount
self.askOrderbookCount = askOrderbookCount
}


public func getOrderbookTable(symbolPair: String) -> AnyPublisher<OrderbookTable, any Error> {
let bidOrderbooks: HashMap<CVNumber, CVNumber> = .init()
bidOrderbookSource.forEach { price, qty in
bidOrderbooks[price] = qty
}

let askOrderbooks: HashMap<CVNumber, CVNumber> = .init()
askOrderbookSource.forEach { price, qty in
askOrderbooks[price] = qty
}

let table = OrderbookTable(
bidOrderbooks: bidOrderbooks,
askOrderbooks: askOrderbooks
)
let publisher = CurrentValueSubject<OrderbookTable, Error>(table)
return publisher.eraseToAnyPublisher()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// SingleMarketTickerRepository.swift
// Domain
//
// Created by choijunios on 4/24/25.
//

import DomainInterface
import CoreUtil

public struct StubSingleMarketTickerRepository: SingleMarketTickerRepository {

public init() { }

public func request24hTickerChange(pairSymbol: String) -> AsyncStream<Twenty4HourTickerForSymbolVO> {
AsyncStream { continuation in
let vo = Twenty4HourTickerForSymbolVO(
pairSymbol: "BTCUSDT",
price: 0.0,
totalTradedQuoteAssetVolume: 0.0,
changedPercent: 0.0,
bestBidPrice: 0.0,
bestAskPrice: 0.0
)
continuation.yield(vo)
}
}
}
12 changes: 0 additions & 12 deletions Projects/Domain/Testing/StubAllMarketTickersRepository.swift

This file was deleted.

63 changes: 57 additions & 6 deletions Projects/Domain/Tests/AllMarketTickerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,67 @@
//

import Testing
import Foundation
import Combine

@testable import DomainInterface
@testable import Domain
@testable import DomainTesting
import DomainInterface
import DomainTesting

import CoreUtil
@testable import Domain

// MARK: AllMarketTickerUseCaseTests
struct AllMarketTickerUseCaseTests {


@Test("Suffix심볼이 USDT인지 확인")
func checkSuffixSymbolIsUSDT() async {
// Given
let useCase = DefaultAllMarketTickersUseCase(
allMarketTickersRepository: StubAllMarketTickerRepository(maxTickerCount: 10000, usdtSuffixCount: 2500),
exchangeRateRepository: StubExchangeRateRepository(fixedRate: 1.0),
userConfigurationRepository: StubUserConfigurationRepository()
)


// When
let published_tickers: AnyPublisher<[Twenty4HourTickerForSymbolVO], Never> = useCase.getTickerList(rowCount: 2500)
let async_tickers = await useCase.getTickerList(rowCount: 2500)


// Then
for await tickers in published_tickers.values {
for ticker in tickers {
#expect(ticker.secondSymbol.uppercased() == "USDT")
}
break
}
for ticker in async_tickers {
#expect(ticker.secondSymbol.uppercased() == "USDT")
}
}

@Test("totalTradedQuoteAssetVolume이 큰 기준으로 정해진 개수를 추출하는지 확인")
func checkFetchingCollectList() async {
// Given
let useCase = DefaultAllMarketTickersUseCase(
allMarketTickersRepository: StubAllMarketTickerRepository(maxTickerCount: 10000, usdtSuffixCount: 2500),
exchangeRateRepository: StubExchangeRateRepository(fixedRate: 1.0),
userConfigurationRepository: StubUserConfigurationRepository()
)


// When
let published_tickers: AnyPublisher<[Twenty4HourTickerForSymbolVO], Never> = useCase.getTickerList(rowCount: 2500)
let async_tickers = await useCase.getTickerList(rowCount: 2500)


// Then
for await tickers in published_tickers.values {
#expect(tickers.count == 2500)
let sorted = tickers.sorted(by: { $0.totalTradedQuoteAssetVolume > $1.totalTradedQuoteAssetVolume })
#expect(sorted == tickers)
break
}
#expect(async_tickers.count == 2500)
let sorted = async_tickers.sorted(by: { $0.totalTradedQuoteAssetVolume > $1.totalTradedQuoteAssetVolume })
#expect(sorted == async_tickers)
}
}
Loading