167 lines
6.6 KiB
Swift
167 lines
6.6 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import CodexBarCore
|
|
|
|
struct CostUsageDailyReportMergeTests {
|
|
@Test
|
|
func `merged report sums overlapping day totals and model breakdowns`() {
|
|
let native = CostUsageDailyReport(
|
|
data: [
|
|
CostUsageDailyReport.Entry(
|
|
date: "2026-04-04",
|
|
inputTokens: 100,
|
|
outputTokens: 20,
|
|
cacheReadTokens: 10,
|
|
cacheCreationTokens: nil,
|
|
totalTokens: 130,
|
|
costUSD: 1.25,
|
|
modelsUsed: ["gpt-5.4"],
|
|
modelBreakdowns: [
|
|
CostUsageDailyReport.ModelBreakdown(
|
|
modelName: "gpt-5.4",
|
|
costUSD: 1.25,
|
|
totalTokens: 130,
|
|
standardCostUSD: 0.75,
|
|
priorityCostUSD: 0.50,
|
|
standardTokens: 80,
|
|
priorityTokens: 50),
|
|
]),
|
|
],
|
|
summary: CostUsageDailyReport.Summary(
|
|
totalInputTokens: 100,
|
|
totalOutputTokens: 20,
|
|
cacheReadTokens: 10,
|
|
cacheCreationTokens: nil,
|
|
totalTokens: 130,
|
|
totalCostUSD: 1.25))
|
|
let pi = CostUsageDailyReport(
|
|
data: [
|
|
CostUsageDailyReport.Entry(
|
|
date: "2026-04-04",
|
|
inputTokens: 50,
|
|
outputTokens: 10,
|
|
cacheReadTokens: 5,
|
|
cacheCreationTokens: 2,
|
|
totalTokens: 67,
|
|
costUSD: 0.75,
|
|
modelsUsed: ["gpt-5.4"],
|
|
modelBreakdowns: [
|
|
CostUsageDailyReport.ModelBreakdown(
|
|
modelName: "gpt-5.4",
|
|
costUSD: 0.75,
|
|
totalTokens: 67,
|
|
standardCostUSD: 0.25,
|
|
priorityCostUSD: 0.50,
|
|
standardTokens: 20,
|
|
priorityTokens: 47),
|
|
]),
|
|
],
|
|
summary: CostUsageDailyReport.Summary(
|
|
totalInputTokens: 50,
|
|
totalOutputTokens: 10,
|
|
cacheReadTokens: 5,
|
|
cacheCreationTokens: 2,
|
|
totalTokens: 67,
|
|
totalCostUSD: 0.75))
|
|
|
|
let merged = native.merged(with: pi)
|
|
#expect(merged.data.count == 1)
|
|
#expect(merged.data.first?.inputTokens == 150)
|
|
#expect(merged.data.first?.outputTokens == 30)
|
|
#expect(merged.data.first?.cacheReadTokens == 15)
|
|
#expect(merged.data.first?.cacheCreationTokens == 2)
|
|
#expect(merged.data.first?.totalTokens == 197)
|
|
#expect(abs((merged.data.first?.costUSD ?? 0) - 2.0) < 0.000001)
|
|
#expect(merged.data.first?.modelBreakdowns == [
|
|
CostUsageDailyReport.ModelBreakdown(
|
|
modelName: "gpt-5.4",
|
|
costUSD: 2.0,
|
|
totalTokens: 197,
|
|
standardCostUSD: 1.0,
|
|
priorityCostUSD: 1.0,
|
|
standardTokens: 100,
|
|
priorityTokens: 97),
|
|
])
|
|
#expect(merged.summary?.totalTokens == 197)
|
|
#expect(abs((merged.summary?.totalCostUSD ?? 0) - 2.0) < 0.000001)
|
|
}
|
|
|
|
@Test
|
|
func `merged report unions days and orders model breakdowns deterministically`() {
|
|
let first = CostUsageDailyReport(
|
|
data: [
|
|
CostUsageDailyReport.Entry(
|
|
date: "2026-04-04",
|
|
inputTokens: nil,
|
|
outputTokens: nil,
|
|
cacheReadTokens: nil,
|
|
cacheCreationTokens: nil,
|
|
totalTokens: 30,
|
|
costUSD: 0.30,
|
|
modelsUsed: ["gpt-5.3-codex"],
|
|
modelBreakdowns: [
|
|
CostUsageDailyReport.ModelBreakdown(modelName: "gpt-5.3-codex", costUSD: 0.30, totalTokens: 30),
|
|
]),
|
|
],
|
|
summary: nil)
|
|
let second = CostUsageDailyReport(
|
|
data: [
|
|
CostUsageDailyReport.Entry(
|
|
date: "2026-04-05",
|
|
inputTokens: nil,
|
|
outputTokens: nil,
|
|
cacheReadTokens: nil,
|
|
cacheCreationTokens: nil,
|
|
totalTokens: 40,
|
|
costUSD: 0.40,
|
|
modelsUsed: ["gpt-5.4", "gpt-5.3-codex"],
|
|
modelBreakdowns: [
|
|
CostUsageDailyReport.ModelBreakdown(modelName: "gpt-5.4", costUSD: 0.40, totalTokens: 40),
|
|
CostUsageDailyReport.ModelBreakdown(modelName: "gpt-5.3-codex", costUSD: 0.00, totalTokens: 0),
|
|
]),
|
|
],
|
|
summary: nil)
|
|
|
|
let merged = CostUsageDailyReport.merged([first, second])
|
|
#expect(merged.data.map(\.date) == ["2026-04-04", "2026-04-05"])
|
|
#expect(merged.data.last?.modelBreakdowns?.map(\.modelName) == ["gpt-5.4", "gpt-5.3-codex"])
|
|
#expect(merged.summary?.totalTokens == 70)
|
|
#expect(abs((merged.summary?.totalCostUSD ?? 0) - 0.70) < 0.000001)
|
|
}
|
|
|
|
@Test
|
|
func `merged report includes derived totals when another same day entry has explicit total`() {
|
|
let explicit = CostUsageDailyReport(
|
|
data: [
|
|
CostUsageDailyReport.Entry(
|
|
date: "2026-04-04",
|
|
inputTokens: 70,
|
|
outputTokens: 30,
|
|
totalTokens: 100,
|
|
costUSD: 1.0,
|
|
modelsUsed: ["gpt-5.4"],
|
|
modelBreakdowns: nil),
|
|
],
|
|
summary: nil)
|
|
let derived = CostUsageDailyReport(
|
|
data: [
|
|
CostUsageDailyReport.Entry(
|
|
date: "2026-04-04",
|
|
inputTokens: 10,
|
|
outputTokens: 5,
|
|
cacheReadTokens: 3,
|
|
cacheCreationTokens: 2,
|
|
totalTokens: nil,
|
|
costUSD: 0.25,
|
|
modelsUsed: ["gpt-5.3-codex"],
|
|
modelBreakdowns: nil),
|
|
],
|
|
summary: nil)
|
|
|
|
let merged = CostUsageDailyReport.merged([explicit, derived])
|
|
#expect(merged.data.first?.totalTokens == 120)
|
|
#expect(merged.summary?.totalTokens == 120)
|
|
#expect(abs((merged.data.first?.costUSD ?? 0) - 1.25) < 0.000001)
|
|
}
|
|
}
|