Files
steipete--codexbar/Tests/CodexBarTests/CopilotUsageFetcherTests.swift
2026-07-13 12:22:33 +08:00

201 lines
7.9 KiB
Swift

import Foundation
import Testing
@testable import CodexBarCore
struct CopilotUsageFetcherTests {
@Test
func `fetchGitHubIdentity uses shared client`() async throws {
let transport = ProviderHTTPTransportStub { request in
guard request.value(forHTTPHeaderField: "Authorization") == "token abc123" else {
throw URLError(.userAuthenticationRequired)
}
let response = try HTTPURLResponse(
url: #require(request.url),
statusCode: 200,
httpVersion: "HTTP/1.1",
headerFields: ["Content-Type": "application/json"])!
return (Data(#"{"login":"testuser","id":123}"#.utf8), response)
}
let identity = try await CopilotUsageFetcher.fetchGitHubIdentity(token: "abc123", transport: transport)
#expect(identity.login == "testuser")
#expect(identity.id == 123)
let requests = await transport.requests()
#expect(requests.count == 1)
#expect(requests.first?.url?.host == "api.github.com")
}
@Test
func `fetch returns unavailable snapshot for business token billing placeholders`() async throws {
let transport = ProviderHTTPTransportStub { request in
#expect(request.value(forHTTPHeaderField: "Authorization") == "token gh-token")
let response = try HTTPURLResponse(
url: #require(request.url),
statusCode: 200,
httpVersion: "HTTP/1.1",
headerFields: ["Content-Type": "application/json"])!
let data = Data(
"""
{
"copilot_plan": "business",
"token_based_billing": true,
"quota_snapshots": {
"premium_interactions": {
"entitlement": 0,
"remaining": 0,
"percent_remaining": 100,
"quota_id": "premium_interactions"
},
"chat": {
"entitlement": 0,
"remaining": 0,
"percent_remaining": 100,
"quota_id": "chat"
}
}
}
""".utf8)
return (data, response)
}
let fetcher = CopilotUsageFetcher(token: "gh-token", transport: transport)
let snapshot = try await fetcher.fetch()
#expect(snapshot.primary == nil)
#expect(snapshot.secondary == nil)
#expect(snapshot.identity?.loginMethod == "Business")
}
@Test
func `fetch keeps explicitly unlimited chat quota`() async throws {
let transport = ProviderHTTPTransportStub { request in
#expect(request.value(forHTTPHeaderField: "Authorization") == "token gh-token")
let response = try HTTPURLResponse(
url: #require(request.url),
statusCode: 200,
httpVersion: "HTTP/1.1",
headerFields: ["Content-Type": "application/json"])!
let data = Data(
"""
{
"copilot_plan": "individual",
"quota_reset_date": "2026-07-01",
"quota_snapshots": {
"chat_messages": {
"entitlement": 0,
"remaining": 0,
"quota_id": "chat_messages",
"unlimited": true
}
}
}
""".utf8)
return (data, response)
}
let fetcher = CopilotUsageFetcher(token: "gh-token", transport: transport)
let snapshot = try await fetcher.fetch()
#expect(snapshot.primary == nil)
#expect(snapshot.secondary?.usedPercent == 0)
#expect(snapshot.secondary?.resetsAt == nil)
#expect(snapshot.identity?.loginMethod == "Individual")
}
@Test
func `fetch attaches quota reset date to copilot windows`() async throws {
let transport = ProviderHTTPTransportStub { request in
#expect(request.value(forHTTPHeaderField: "Authorization") == "token gh-token")
let response = try HTTPURLResponse(
url: #require(request.url),
statusCode: 200,
httpVersion: "HTTP/1.1",
headerFields: ["Content-Type": "application/json"])!
let data = Data(
"""
{
"copilot_plan": "individual",
"quota_reset_date": "2026-07-01",
"quota_snapshots": {
"premium_interactions": {
"entitlement": 500,
"remaining": 125,
"percent_remaining": 25,
"quota_id": "premium_interactions"
},
"chat": {
"entitlement": 300,
"remaining": 240,
"percent_remaining": 80,
"quota_id": "chat"
}
}
}
""".utf8)
return (data, response)
}
let fetcher = CopilotUsageFetcher(token: "gh-token", transport: transport)
let expectedReset = try #require(CopilotUsageFetcher.parseQuotaResetDate("2026-07-01"))
let snapshot = try await fetcher.fetch()
#expect(snapshot.primary?.usedPercent == 75)
#expect(snapshot.primary?.resetsAt == expectedReset)
#expect(snapshot.secondary?.usedPercent == 20)
#expect(snapshot.secondary?.resetsAt == expectedReset)
}
@Test
func `makeRateWindow drops business token billing placeholder quota`() {
// entitlement=0/remaining=0/percent_remaining=100 must not become a "0% used"
// rate window for Copilot Business token-based billing accounts. (#1258)
let placeholder = CopilotUsageResponse.QuotaSnapshot(
entitlement: 0,
remaining: 0,
percentRemaining: 100,
quotaId: "premium_interactions")
#expect(CopilotUsageFetcher.makeRateWindow(from: placeholder) == nil)
}
@Test
func `makeRateWindow keeps real quota window`() {
let real = CopilotUsageResponse.QuotaSnapshot(
entitlement: 500,
remaining: 125,
percentRemaining: 25,
quotaId: "premium_interactions")
let window = CopilotUsageFetcher.makeRateWindow(from: real)
#expect(window?.usedPercent == 75)
}
@Test
func `makeRateWindow carries reset date`() {
let resetDate = Date(timeIntervalSince1970: 1_783_468_800)
let real = CopilotUsageResponse.QuotaSnapshot(
entitlement: 500,
remaining: 125,
percentRemaining: 25,
quotaId: "premium_interactions")
let window = CopilotUsageFetcher.makeRateWindow(from: real, resetsAt: resetDate)
#expect(window?.usedPercent == 75)
#expect(window?.resetsAt == resetDate)
}
@Test
func `parseQuotaResetDate supports date only and ISO timestamps`() throws {
let dateOnly = try #require(ISO8601DateFormatter().date(from: "2026-07-01T00:00:00Z"))
let iso = try #require(ISO8601DateFormatter().date(from: "2026-07-01T08:30:45Z"))
let fractionalFormatter = ISO8601DateFormatter()
fractionalFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let fractionalISO = try #require(fractionalFormatter.date(from: "2026-07-01T08:30:45.123Z"))
#expect(CopilotUsageFetcher.parseQuotaResetDate("2026-07-01") == dateOnly)
#expect(CopilotUsageFetcher.parseQuotaResetDate("2026-07-01T08:30:45Z") == iso)
#expect(CopilotUsageFetcher.parseQuotaResetDate("2026-07-01T08:30:45.123Z") == fractionalISO)
#expect(CopilotUsageFetcher.parseQuotaResetDate(" ") == nil)
}
}