298 lines
9.0 KiB
Swift
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)
|
|
}
|
|
}
|