616 lines
22 KiB
Swift
616 lines
22 KiB
Swift
import CodexBarCore
|
|
import Foundation
|
|
import Testing
|
|
@testable import CodexBarCLI
|
|
|
|
struct CLICardsRendererTests {
|
|
@Test
|
|
func `computes column count from terminal width`() {
|
|
#expect(CLICardsRenderer.columnCount(terminalWidth: 80) == 2)
|
|
#expect(CLICardsRenderer.columnCount(terminalWidth: 120) == 3)
|
|
#expect(CLICardsRenderer.columnCount(terminalWidth: 160) == 4)
|
|
#expect(CLICardsRenderer.columnCount(terminalWidth: 30) == 1)
|
|
}
|
|
|
|
@Test
|
|
func `renders single codex card without color`() {
|
|
let identity = ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "user@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "pro")
|
|
let snapshot = UsageSnapshot(
|
|
primary: .init(usedPercent: 12, windowMinutes: 300, resetsAt: nil, resetDescription: "today at 3:00 PM"),
|
|
secondary: .init(usedPercent: 25, windowMinutes: 10080, resetsAt: nil, resetDescription: "Fri at 9:00 AM"),
|
|
tertiary: nil,
|
|
updatedAt: Date(timeIntervalSince1970: 0),
|
|
identity: identity)
|
|
let card = CLICardsRenderer.makeCard(CLICardBuildInput(
|
|
provider: .codex,
|
|
snapshot: snapshot,
|
|
credits: CreditsSnapshot(remaining: 42, events: [], updatedAt: Date()),
|
|
source: "oauth",
|
|
status: nil,
|
|
notes: [],
|
|
useColor: false,
|
|
resetStyle: .absolute,
|
|
weeklyWorkDays: nil,
|
|
now: Date()))
|
|
|
|
let output = CLICardsRenderer.render(cards: [card], failures: [], terminalWidth: 80, useColor: false)
|
|
|
|
#expect(output.contains("Codex"))
|
|
#expect(output.contains("[oauth]"))
|
|
#expect(output.contains("PLAN Pro 20x"))
|
|
#expect(output.contains("Session"))
|
|
#expect(output.contains("88% left"))
|
|
#expect(output.contains("[ "))
|
|
#expect(output.contains("━"))
|
|
#expect(output.contains("Credits:"))
|
|
#expect(output.contains("42 left"))
|
|
#expect(output.contains("@ user@example.com"))
|
|
#expect(output.contains("╰"))
|
|
}
|
|
|
|
@Test
|
|
func `card includes account line`() {
|
|
let identity = ProviderIdentitySnapshot(
|
|
providerID: .codex,
|
|
accountEmail: "user@example.com",
|
|
accountOrganization: nil,
|
|
loginMethod: "pro")
|
|
let snapshot = UsageSnapshot(
|
|
primary: .init(usedPercent: 12, windowMinutes: 300, resetsAt: nil, resetDescription: nil),
|
|
secondary: nil,
|
|
tertiary: nil,
|
|
updatedAt: Date(timeIntervalSince1970: 0),
|
|
identity: identity)
|
|
let card = CLICardsRenderer.makeCard(CLICardBuildInput(
|
|
provider: .codex,
|
|
snapshot: snapshot,
|
|
credits: nil,
|
|
source: "cli",
|
|
status: nil,
|
|
notes: [],
|
|
useColor: false,
|
|
resetStyle: .absolute,
|
|
weeklyWorkDays: nil,
|
|
now: Date()))
|
|
|
|
let lines = CLICardsRenderer.renderCard(card, width: 48, useColor: false)
|
|
let joined = lines.joined(separator: "\n")
|
|
|
|
#expect(joined.contains("@ user@example.com"))
|
|
#expect(joined.contains("Session"))
|
|
#expect(!joined.contains("Plan: Pro 20x"))
|
|
}
|
|
|
|
@Test
|
|
func `renders two card grid at fixed width`() {
|
|
let codex = CLICardModel(
|
|
provider: .codex,
|
|
title: "Codex",
|
|
sourceLabel: "oauth",
|
|
planBadge: "Pro",
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 88, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil)
|
|
let claude = CLICardModel(
|
|
provider: .claude,
|
|
title: "Claude",
|
|
sourceLabel: "web",
|
|
planBadge: "Max",
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 50, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil)
|
|
|
|
let output = CLICardsRenderer.render(cards: [codex, claude], failures: [], terminalWidth: 120, useColor: false)
|
|
|
|
#expect(output.contains("Codex"))
|
|
#expect(output.contains("Claude"))
|
|
#expect(output.contains("88% left"))
|
|
#expect(output.contains("50% left"))
|
|
#expect(output.components(separatedBy: "╰").count >= 3)
|
|
}
|
|
|
|
@Test
|
|
func `renders failure footer without cards`() {
|
|
let failures = [
|
|
CLICardFailure(provider: .cursor, accountLabel: nil, message: "not configured"),
|
|
]
|
|
let output = CLICardsRenderer.render(cards: [], failures: failures, terminalWidth: 80, useColor: false)
|
|
|
|
#expect(output.contains("Failed providers:"))
|
|
#expect(output.contains("Cursor: not configured"))
|
|
}
|
|
|
|
@Test
|
|
func `appends failure footer after successful cards`() {
|
|
let card = CLICardModel(
|
|
provider: .codex,
|
|
title: "Codex",
|
|
sourceLabel: "oauth",
|
|
planBadge: nil,
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 88, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil)
|
|
let failures = [
|
|
CLICardFailure(provider: .grok, accountLabel: nil, message: "timeout"),
|
|
]
|
|
|
|
let output = CLICardsRenderer.render(cards: [card], failures: failures, terminalWidth: 80, useColor: false)
|
|
|
|
#expect(output.contains("88% left"))
|
|
#expect(output.contains("Failed providers:"))
|
|
#expect(output.contains("Grok: timeout"))
|
|
}
|
|
|
|
@Test
|
|
func `brief mode renders usage table`() {
|
|
let card = CLICardModel(
|
|
provider: .claude,
|
|
title: "Claude",
|
|
sourceLabel: "web",
|
|
planBadge: "Max",
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 2, resetText: "⏳ Resets in 1h 49m")],
|
|
extraLines: [],
|
|
statusLine: nil)
|
|
let rows = CLICardsBriefRenderer.makeRows(cards: [card])
|
|
let output = CLICardsBriefRenderer.render(
|
|
rows: rows,
|
|
failures: [],
|
|
terminalWidth: 80,
|
|
useColor: false,
|
|
now: Date(timeIntervalSince1970: 0))
|
|
|
|
#expect(output.contains("codexbar • AI Usage & Limits"))
|
|
#expect(output.contains("Provider"))
|
|
#expect(output.contains("Claude"))
|
|
#expect(output.contains("web"))
|
|
#expect(output.contains("Max"))
|
|
#expect(output.contains("98%"))
|
|
#expect(output.contains("█"))
|
|
#expect(output.contains("1h 49m"))
|
|
#expect(output.contains("⚠ Warnings:"))
|
|
let tableLine = output.split(separator: "\n").first { $0.hasPrefix("┌") } ?? ""
|
|
#expect(tableLine.count >= 50)
|
|
#expect(tableLine.count <= 72)
|
|
}
|
|
|
|
@Test
|
|
func `synthetic quota lanes do not replace real brief usage`() {
|
|
let snapshot = UsageSnapshot(
|
|
primary: .init(
|
|
usedPercent: 0,
|
|
windowMinutes: 300,
|
|
resetsAt: nil,
|
|
resetDescription: nil,
|
|
isSyntheticPlaceholder: true),
|
|
secondary: .init(
|
|
usedPercent: 20,
|
|
windowMinutes: 10080,
|
|
resetsAt: nil,
|
|
resetDescription: nil),
|
|
tertiary: nil,
|
|
updatedAt: Date(timeIntervalSince1970: 0))
|
|
let card = CLICardsRenderer.makeCard(CLICardBuildInput(
|
|
provider: .claude,
|
|
snapshot: snapshot,
|
|
credits: nil,
|
|
source: "oauth",
|
|
status: nil,
|
|
notes: [],
|
|
useColor: false,
|
|
resetStyle: .countdown,
|
|
weeklyWorkDays: nil,
|
|
now: Date(timeIntervalSince1970: 0)))
|
|
let rows = CLICardsBriefRenderer.makeRows(cards: [card])
|
|
|
|
#expect(card.metrics.map(\.label) == ["Weekly"])
|
|
#expect(rows.first?.usedPercent == 20)
|
|
}
|
|
|
|
@Test
|
|
func `brief reset summary wraps to terminal width`() {
|
|
let now = Date(timeIntervalSince1970: 1_700_000_000)
|
|
let card = CLICardModel(
|
|
provider: .alibabatokenplan,
|
|
title: "Alibaba Token Plan",
|
|
sourceLabel: "web",
|
|
planBadge: "International",
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(
|
|
label: "Monthly budget",
|
|
remainingPercent: 50,
|
|
resetText: "⏳ Resets July 30 at 11:59 PM",
|
|
resetAt: now.addingTimeInterval(3600))],
|
|
extraLines: [],
|
|
statusLine: nil)
|
|
|
|
let output = CLICardsBriefRenderer.render(
|
|
rows: CLICardsBriefRenderer.makeRows(cards: [card]),
|
|
failures: [],
|
|
terminalWidth: 40,
|
|
useColor: false,
|
|
now: now)
|
|
let lines = output.split(separator: "\n", omittingEmptySubsequences: false)
|
|
|
|
#expect(output.contains("Next reset: Alibaba Token Plan"))
|
|
#expect(lines.allSatisfy { $0.count <= 40 })
|
|
}
|
|
|
|
@Test
|
|
func `detail backed quota descriptions are not rendered as resets`() {
|
|
let snapshot = UsageSnapshot(
|
|
primary: .init(
|
|
usedPercent: 25,
|
|
windowMinutes: nil,
|
|
resetsAt: nil,
|
|
resetDescription: "25/100 credits"),
|
|
secondary: nil,
|
|
tertiary: nil,
|
|
updatedAt: Date(timeIntervalSince1970: 0))
|
|
let card = CLICardsRenderer.makeCard(CLICardBuildInput(
|
|
provider: .kilo,
|
|
snapshot: snapshot,
|
|
credits: nil,
|
|
source: "api",
|
|
status: nil,
|
|
notes: [],
|
|
useColor: false,
|
|
resetStyle: .countdown,
|
|
weeklyWorkDays: nil,
|
|
now: Date(timeIntervalSince1970: 0)))
|
|
|
|
#expect(card.metrics.first?.resetText == nil)
|
|
#expect(card.metrics.first?.detailText == "25/100 credits")
|
|
|
|
let output = CLICardsBriefRenderer.render(
|
|
rows: CLICardsBriefRenderer.makeRows(cards: [card]),
|
|
failures: [],
|
|
terminalWidth: 80,
|
|
useColor: false,
|
|
now: Date(timeIntervalSince1970: 0))
|
|
#expect(!output.contains("Next reset"))
|
|
#expect(!output.contains("Reset 25/100 credits"))
|
|
}
|
|
|
|
@Test
|
|
func `card metrics honor reset display style`() {
|
|
let now = Date(timeIntervalSince1970: 1_700_000_000)
|
|
let snapshot = UsageSnapshot(
|
|
primary: .init(
|
|
usedPercent: 25,
|
|
windowMinutes: 300,
|
|
resetsAt: now.addingTimeInterval(3600),
|
|
resetDescription: nil),
|
|
secondary: nil,
|
|
tertiary: nil,
|
|
updatedAt: now)
|
|
let countdown = CLICardsRenderer.makeCard(CLICardBuildInput(
|
|
provider: .codex,
|
|
snapshot: snapshot,
|
|
credits: nil,
|
|
source: "oauth",
|
|
status: nil,
|
|
notes: [],
|
|
useColor: false,
|
|
resetStyle: .countdown,
|
|
weeklyWorkDays: nil,
|
|
now: now))
|
|
let absolute = CLICardsRenderer.makeCard(CLICardBuildInput(
|
|
provider: .codex,
|
|
snapshot: snapshot,
|
|
credits: nil,
|
|
source: "oauth",
|
|
status: nil,
|
|
notes: [],
|
|
useColor: false,
|
|
resetStyle: .absolute,
|
|
weeklyWorkDays: nil,
|
|
now: now))
|
|
|
|
#expect(countdown.metrics.first?.resetText != absolute.metrics.first?.resetText)
|
|
#expect(countdown.metrics.first?.resetText?.contains("in 1h") == true)
|
|
#expect(absolute.metrics.first?.resetAt == now.addingTimeInterval(3600))
|
|
}
|
|
|
|
@Test
|
|
func `long detail rows stay within card width`() {
|
|
let card = CLICardModel(
|
|
provider: .clawrouter,
|
|
title: "ClawRouter",
|
|
sourceLabel: "api",
|
|
planBadge: nil,
|
|
accountLine: nil,
|
|
infoLines: ["Workspace: " + String(repeating: "long-name-", count: 12)],
|
|
metrics: [],
|
|
extraLines: [],
|
|
statusLine: nil)
|
|
|
|
let lines = CLICardsRenderer.renderCard(card, width: 38, useColor: true, enhanced: true)
|
|
#expect(lines.allSatisfy { TextParsing.stripANSICodes($0).count == 38 })
|
|
}
|
|
|
|
@Test
|
|
func `brief warnings name the actual quota metric`() {
|
|
let card = CLICardModel(
|
|
provider: .openrouter,
|
|
title: "OpenRouter",
|
|
sourceLabel: "api",
|
|
planBadge: nil,
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Spend", remainingPercent: 10, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil)
|
|
|
|
let output = CLICardsBriefRenderer.render(
|
|
rows: CLICardsBriefRenderer.makeRows(cards: [card]),
|
|
failures: [],
|
|
terminalWidth: 80,
|
|
useColor: false,
|
|
now: Date(timeIntervalSince1970: 0))
|
|
|
|
#expect(output.contains("OpenRouter Spend: 90% used"))
|
|
#expect(!output.contains("session limit"))
|
|
}
|
|
|
|
@Test
|
|
func `brief rows preserve account identity`() {
|
|
let cards = [
|
|
CLICardModel(
|
|
provider: .codex,
|
|
title: "Codex",
|
|
sourceLabel: "oauth",
|
|
planBadge: "Pro",
|
|
accountLine: "one@x.dev",
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 80, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil),
|
|
CLICardModel(
|
|
provider: .codex,
|
|
title: "Codex",
|
|
sourceLabel: "oauth",
|
|
planBadge: "Pro",
|
|
accountLine: "two@x.dev",
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 60, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil),
|
|
]
|
|
|
|
let output = CLICardsBriefRenderer.render(
|
|
rows: CLICardsBriefRenderer.makeRows(cards: cards),
|
|
failures: [],
|
|
terminalWidth: 80,
|
|
useColor: false,
|
|
now: Date(timeIntervalSince1970: 0))
|
|
|
|
#expect(output.contains("one@x.dev"))
|
|
#expect(output.contains("two@x.dev"))
|
|
}
|
|
|
|
@Test
|
|
func `brief warnings wrap to terminal width`() {
|
|
let cards = ["OpenRouter", "Antigravity", "CommandCode"].map { title in
|
|
CLICardModel(
|
|
provider: .openrouter,
|
|
title: title,
|
|
sourceLabel: "api",
|
|
planBadge: nil,
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Monthly budget", remainingPercent: 5, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil)
|
|
}
|
|
|
|
let output = CLICardsBriefRenderer.render(
|
|
rows: CLICardsBriefRenderer.makeRows(cards: cards),
|
|
failures: [],
|
|
terminalWidth: 40,
|
|
useColor: false,
|
|
now: Date(timeIntervalSince1970: 0))
|
|
let warningLines = output.split(separator: "\n").filter {
|
|
$0.contains("Warnings:") || $0.contains("% used")
|
|
}
|
|
|
|
#expect(warningLines.count > 1)
|
|
#expect(warningLines.allSatisfy { $0.count <= 40 })
|
|
}
|
|
|
|
@Test
|
|
func `brief summary ignores unparseable reset labels and fits narrow terminals`() {
|
|
let now = Date(timeIntervalSince1970: 1_700_000_000)
|
|
let rows = CLICardsBriefRenderer.makeRows(cards: [
|
|
CLICardModel(
|
|
provider: .kilo,
|
|
title: "Kilo",
|
|
sourceLabel: "api",
|
|
planBadge: nil,
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Credits", remainingPercent: 75, resetText: "Reset Unlimited")],
|
|
extraLines: [],
|
|
statusLine: nil),
|
|
CLICardModel(
|
|
provider: .codex,
|
|
title: "Codex",
|
|
sourceLabel: "oauth",
|
|
planBadge: "Pro",
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(
|
|
label: "Session",
|
|
remainingPercent: 50,
|
|
resetText: "⏳ Resets in 5h",
|
|
resetAt: now.addingTimeInterval(5 * 3600))],
|
|
extraLines: [],
|
|
statusLine: nil),
|
|
])
|
|
|
|
let output = CLICardsBriefRenderer.render(
|
|
rows: rows,
|
|
failures: [],
|
|
terminalWidth: 40,
|
|
useColor: false,
|
|
now: now)
|
|
let lines = output.split(separator: "\n", omittingEmptySubsequences: false)
|
|
|
|
#expect(output.contains("Next reset: Codex in 5h"))
|
|
#expect(!output.contains("Next reset: Kilo"))
|
|
#expect(lines.allSatisfy { $0.count <= 40 })
|
|
}
|
|
|
|
@Test
|
|
func `enhanced brief mode fills bars from used percentage`() {
|
|
let rows = CLICardsBriefRenderer.makeRows(cards: [
|
|
CLICardModel(
|
|
provider: .codex,
|
|
title: "Unused",
|
|
sourceLabel: "oauth",
|
|
planBadge: nil,
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 100, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil),
|
|
CLICardModel(
|
|
provider: .openrouter,
|
|
title: "Exhausted",
|
|
sourceLabel: "api",
|
|
planBadge: nil,
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 0, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil),
|
|
])
|
|
let output = CLICardsBriefRenderer.render(
|
|
rows: rows,
|
|
failures: [],
|
|
terminalWidth: 80,
|
|
useColor: true,
|
|
enhanced: true,
|
|
now: Date(timeIntervalSince1970: 0))
|
|
let plainLines = TextParsing.stripANSICodes(output).split(separator: "\n")
|
|
let unusedLine = String(plainLines.first { $0.contains("Unused") } ?? "")
|
|
let exhaustedLine = String(plainLines.first { $0.contains("Exhausted") } ?? "")
|
|
|
|
#expect(unusedLine.contains("0%"))
|
|
#expect(unusedLine.filter { $0 == "█" }.isEmpty)
|
|
#expect(exhaustedLine.contains("100%"))
|
|
#expect(exhaustedLine.filter { $0 == "░" }.isEmpty)
|
|
}
|
|
|
|
@Test
|
|
func `standard brief mode fills bars from used percentage`() {
|
|
let rows = CLICardsBriefRenderer.makeRows(cards: [
|
|
CLICardModel(
|
|
provider: .codex,
|
|
title: "Unused",
|
|
sourceLabel: "oauth",
|
|
planBadge: nil,
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 100, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil),
|
|
CLICardModel(
|
|
provider: .openrouter,
|
|
title: "Exhausted",
|
|
sourceLabel: "api",
|
|
planBadge: nil,
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 0, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil),
|
|
])
|
|
let output = CLICardsBriefRenderer.render(
|
|
rows: rows,
|
|
failures: [],
|
|
terminalWidth: 80,
|
|
useColor: false,
|
|
enhanced: false,
|
|
now: Date(timeIntervalSince1970: 0))
|
|
let plainLines = output.split(separator: "\n")
|
|
let unusedLine = String(plainLines.first { $0.contains("Unused") } ?? "")
|
|
let exhaustedLine = String(plainLines.first { $0.contains("Exhausted") } ?? "")
|
|
|
|
#expect(unusedLine.contains("0%"))
|
|
#expect(unusedLine.filter { $0 == "█" }.isEmpty)
|
|
#expect(exhaustedLine.contains("100%"))
|
|
#expect(exhaustedLine.filter { $0 == "░" }.isEmpty)
|
|
}
|
|
|
|
@Test
|
|
func `standard card grid shows empty remaining bar at exhaustion`() {
|
|
let card = CLICardModel(
|
|
provider: .openrouter,
|
|
title: "Exhausted",
|
|
sourceLabel: "api",
|
|
planBadge: nil,
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 0, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil)
|
|
let lines = CLICardsRenderer.renderCard(card, width: 48, useColor: false, enhanced: false)
|
|
let barLine = String(lines.first { $0.contains("[ ") && $0.contains("]") } ?? "")
|
|
#expect(barLine.filter { $0 == "━" }.isEmpty)
|
|
}
|
|
|
|
@Test
|
|
func `enhanced card grid shows empty remaining bar at exhaustion`() {
|
|
let card = CLICardModel(
|
|
provider: .openrouter,
|
|
title: "Exhausted",
|
|
sourceLabel: "api",
|
|
planBadge: nil,
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 0, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil)
|
|
let lines = CLICardsRenderer.renderCard(card, width: 48, useColor: true, enhanced: true)
|
|
let plainBarLine = TextParsing.stripANSICodes(
|
|
String(lines.first { $0.contains("[ ") && $0.contains("]") } ?? ""))
|
|
#expect(plainBarLine.filter { !$0.isWhitespace && $0 != "│" && $0 != "[" && $0 != "]" }.isEmpty)
|
|
}
|
|
|
|
@Test
|
|
func `enhanced mode uses truecolor gradient bars`() {
|
|
let card = CLICardModel(
|
|
provider: .codex,
|
|
title: "Codex",
|
|
sourceLabel: "oauth",
|
|
planBadge: "Pro",
|
|
accountLine: nil,
|
|
infoLines: [],
|
|
metrics: [CLICardMetric(label: "Session", remainingPercent: 50, resetText: nil)],
|
|
extraLines: [],
|
|
statusLine: nil)
|
|
let output = CLICardsRenderer.render(
|
|
cards: [card],
|
|
failures: [],
|
|
terminalWidth: 80,
|
|
useColor: true,
|
|
enhanced: true)
|
|
#expect(output.contains("38;2;"))
|
|
#expect(output.contains("48;2;"))
|
|
#expect(output.contains("[ "))
|
|
}
|
|
}
|