Files
2026-07-13 12:22:33 +08:00

298 lines
9.0 KiB
Swift

import Foundation
import Testing
@testable import CodexBarCore
struct VeniceUsageFetcherTests {
@Test
func `parses DIEM balance response`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": "DIEM",
"balances": {
"diem": 90.50,
"usd": null
},
"diemEpochAllocation": 100.0
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
#expect(snapshot.canConsume == true)
#expect(snapshot.consumptionCurrency == "DIEM")
#expect(snapshot.diemBalance == 90.50)
#expect(snapshot.usdBalance == nil)
#expect(snapshot.diemEpochAllocation == 100.0)
}
@Test
func `parses USD balance response`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": "USD",
"balances": {
"diem": null,
"usd": 25.75
},
"diemEpochAllocation": null
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
#expect(snapshot.canConsume == true)
#expect(snapshot.consumptionCurrency == "USD")
#expect(snapshot.diemBalance == nil)
#expect(snapshot.usdBalance == 25.75)
#expect(snapshot.diemEpochAllocation == nil)
}
@Test
func `parses string-encoded balances and allocation`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": "DIEM",
"balances": {
"diem": "90.50",
"usd": "25.75"
},
"diemEpochAllocation": "100.0"
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
#expect(snapshot.diemBalance == 90.50)
#expect(snapshot.usdBalance == 25.75)
#expect(snapshot.diemEpochAllocation == 100.0)
}
@Test
func `parses both DIEM and USD present`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": "BUNDLED_CREDITS",
"balances": {
"diem": 50.0,
"usd": 10.0
},
"diemEpochAllocation": 100.0
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
#expect(snapshot.diemBalance == 50.0)
#expect(snapshot.usdBalance == 10.0)
}
@Test
func `uses DIEM allocation progress for bundled credits currency`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": "BUNDLED_CREDITS",
"balances": {
"diem": 50.0,
"usd": 10.0
},
"diemEpochAllocation": 100.0
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
let usage = snapshot.toUsageSnapshot()
#expect(usage.primary?.resetDescription?.contains("DIEM 50.00 / 100.00") == true)
#expect(usage.primary?.usedPercent == 50.0)
}
@Test
func `uses USD display when consumptionCurrency is USD and both balances exist`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": "USD",
"balances": {
"diem": 50.0,
"usd": 12.34
},
"diemEpochAllocation": 100.0
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
let usage = snapshot.toUsageSnapshot()
#expect(usage.primary?.resetDescription == "$12.34 USD remaining")
#expect(usage.primary?.usedPercent == 0)
}
@Test
func `handles canConsume=false`() throws {
let json = """
{
"canConsume": false,
"consumptionCurrency": "USD",
"balances": {
"diem": null,
"usd": 100.0
},
"diemEpochAllocation": null
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
let usage = snapshot.toUsageSnapshot()
#expect(usage.primary?.usedPercent == 100)
#expect(usage.primary?.resetDescription == "Balance unavailable for API calls")
}
@Test
func `displays DIEM with epoch allocation`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": "DIEM",
"balances": {
"diem": 75.0,
"usd": null
},
"diemEpochAllocation": 100.0
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
let usage = snapshot.toUsageSnapshot()
#expect(usage.primary?.resetDescription?.contains("DIEM 75.00 / 100.00") == true)
#expect(usage.primary?.usedPercent == 25.0)
}
@Test
func `displays DIEM without allocation`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": "DIEM",
"balances": {
"diem": 50.0,
"usd": null
},
"diemEpochAllocation": null
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
let usage = snapshot.toUsageSnapshot()
#expect(usage.primary?.resetDescription?.contains("DIEM 50.00 remaining") == true)
#expect(usage.primary?.usedPercent == 0)
}
@Test
func `displays USD balance`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": "USD",
"balances": {
"diem": null,
"usd": 15.50
},
"diemEpochAllocation": null
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
let usage = snapshot.toUsageSnapshot()
#expect(usage.primary?.resetDescription?.contains("$15.50") == true)
#expect(usage.primary?.usedPercent == 0)
}
@Test
func `handles zero balances`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": "USD",
"balances": {
"diem": 0.0,
"usd": 0.0
},
"diemEpochAllocation": null
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
let usage = snapshot.toUsageSnapshot()
#expect(usage.primary?.resetDescription == "No Venice API balance available")
#expect(usage.primary?.usedPercent == 100)
}
@Test
func `handles null balances with canConsume=true`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": null,
"balances": {
"diem": null,
"usd": null
},
"diemEpochAllocation": null
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
let usage = snapshot.toUsageSnapshot()
#expect(usage.primary?.resetDescription == "No Venice API balance available")
#expect(usage.primary?.usedPercent == 100)
}
@Test
func `identity uses venice provider ID`() throws {
let json = """
{
"canConsume": true,
"consumptionCurrency": "DIEM",
"balances": {
"diem": 90.0,
"usd": null
},
"diemEpochAllocation": 100.0
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
let usage = snapshot.toUsageSnapshot()
#expect(usage.identity?.providerID == .venice)
#expect(usage.identity?.accountEmail == nil)
#expect(usage.identity?.accountOrganization == nil)
}
@Test
func `throws on malformed JSON`() {
let json = "[{ \"canConsume\": true }]"
#expect {
_ = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
} throws: { error in
guard case VeniceUsageError.parseFailed = error else { return false }
return true
}
}
@Test
func `throws on invalid JSON`() {
let json = "{ invalid json }"
#expect {
_ = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
} throws: { error in
guard case VeniceUsageError.parseFailed = error else { return false }
return true
}
}
@Test
func `clamps used percent to 0-100 range`() throws {
// Negative used percent should be clamped to 0
let json = """
{
"canConsume": true,
"consumptionCurrency": "DIEM",
"balances": {
"diem": 150.0,
"usd": null
},
"diemEpochAllocation": 100.0
}
"""
let snapshot = try VeniceUsageFetcher._parseSnapshotForTesting(Data(json.utf8))
let usage = snapshot.toUsageSnapshot()
#expect(usage.primary?.usedPercent == 0)
}
}