import Foundationimport Testing@testable import CodexBarCore struct CostUsageFetcherCacheSnapshotTests { @Test func `cached codex token snapshot loads from existing cache without rescanning`() async throws { let env = try CostUsageTestEnvironment() defer { env.cleanup() } let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8) try Self.writeCodexSessionFile( homeRoot: env.codexHomeRoot, env: env, day: day, filename: "cached.jsonl", tokens: 42) let options = CostUsageScanner.Options( codexSessionsRoot: env.codexSessionsRoot, cacheRoot: env.cacheRoot) _ = try await CostUsageFetcher.loadTokenSnapshot( provider: .codex, now: day, historyDays: 1, scannerOptions: options) let cached = await CostUsageFetcher.loadCachedCodexTokenSnapshot( now: day, historyDays: 1, scannerOptions: options) #expect(cached?.sessionTokens == 42) #expect(cached?.last30DaysTokens == 42) #expect(cached?.daily.map(\.date) == ["2026-04-08"]) } @Test func `cached codex token snapshot refuses expanded or managed scopes`() async throws { let env = try CostUsageTestEnvironment() defer { env.cleanup() } let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8) try Self.writeCodexSessionFile( homeRoot: env.codexHomeRoot, env: env, day: day, filename: "cached.jsonl", tokens: 42) let options = CostUsageScanner.Options( codexSessionsRoot: env.codexSessionsRoot, cacheRoot: env.cacheRoot) _ = try await CostUsageFetcher.loadTokenSnapshot( provider: .codex, now: day, historyDays: 1, scannerOptions: options) let expanded = await CostUsageFetcher.loadCachedCodexTokenSnapshot( now: day, historyDays: 7, scannerOptions: options) let managed = await CostUsageFetcher.loadCachedCodexTokenSnapshot( now: day, codexHomePath: env.codexHomeRoot.path, historyDays: 1, scannerOptions: options) #expect(expanded == nil) #expect(managed == nil) } @Test func `cached codex token snapshot refuses mismatched roots fingerprint`() async throws { let env = try CostUsageTestEnvironment() defer { env.cleanup() } let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8) try Self.writeCodexSessionFile( homeRoot: env.codexHomeRoot, env: env, day: day, filename: "cached.jsonl", tokens: 42) let options = CostUsageScanner.Options( codexSessionsRoot: env.codexSessionsRoot, cacheRoot: env.cacheRoot) _ = try await CostUsageFetcher.loadTokenSnapshot( provider: .codex, now: day, historyDays: 1, scannerOptions: options) var cache = CostUsageCacheIO.load(provider: .codex, cacheRoot: env.cacheRoot) cache.roots = [env.root.appendingPathComponent("other/sessions", isDirectory: true).path: 0] CostUsageCacheIO.save(provider: .codex, cache: cache, cacheRoot: env.cacheRoot) let cached = await CostUsageFetcher.loadCachedCodexTokenSnapshot( now: day, historyDays: 1, scannerOptions: options) #expect(cached == nil) } @Test func `cached codex token snapshot merges cached pi sessions`() async throws { let env = try CostUsageTestEnvironment() defer { env.cleanup() } let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8) try Self.writeCodexSessionFile( homeRoot: env.codexHomeRoot, env: env, day: day, filename: "cached.jsonl", tokens: 42) try Self.writePiCodexSessionFile(env: env, day: day, tokens: 165) let options = CostUsageScanner.Options( codexSessionsRoot: env.codexSessionsRoot, cacheRoot: env.cacheRoot) let piOptions = PiSessionCostScanner.Options( piSessionsRoot: env.piSessionsRoot, cacheRoot: env.cacheRoot, refreshMinIntervalSeconds: 0) _ = try await CostUsageFetcher.loadTokenSnapshot( provider: .codex, now: day, historyDays: 1, refreshPricingInBackground: false, scannerOptions: options, piScannerOptions: piOptions) let cached = await CostUsageFetcher.loadCachedCodexTokenSnapshot( now: day, historyDays: 1, scannerOptions: options) #expect(cached?.sessionTokens == 207) #expect(cached?.last30DaysTokens == 207) } @Test func `cached codex token snapshot loads cached pi sessions without native codex cache`() async throws { let env = try CostUsageTestEnvironment() defer { env.cleanup() } let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8) try Self.writePiCodexSessionFile(env: env, day: day, tokens: 165) let piOptions = PiSessionCostScanner.Options( piSessionsRoot: env.piSessionsRoot, cacheRoot: env.cacheRoot, refreshMinIntervalSeconds: 0) _ = PiSessionCostScanner.loadDailyReport( provider: .codex, since: day, until: day, now: day, options: piOptions) let cached = await CostUsageFetcher.loadCachedCodexTokenSnapshot( now: day, historyDays: 1, scannerOptions: CostUsageScanner.Options( codexSessionsRoot: env.codexSessionsRoot, cacheRoot: env.cacheRoot)) #expect(cached?.sessionTokens == 165) #expect(cached?.last30DaysTokens == 165) } @Test func `cached codex token snapshot still loads pi sessions when native cache roots mismatch`() async throws { let env = try CostUsageTestEnvironment() defer { env.cleanup() } let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8) try Self.writeCodexSessionFile( homeRoot: env.codexHomeRoot, env: env, day: day, filename: "cached.jsonl", tokens: 42) try Self.writePiCodexSessionFile(env: env, day: day, tokens: 165) let options = CostUsageScanner.Options( codexSessionsRoot: env.codexSessionsRoot, cacheRoot: env.cacheRoot) let piOptions = PiSessionCostScanner.Options( piSessionsRoot: env.piSessionsRoot, cacheRoot: env.cacheRoot, refreshMinIntervalSeconds: 0) _ = try await CostUsageFetcher.loadTokenSnapshot( provider: .codex, now: day, historyDays: 1, refreshPricingInBackground: false, scannerOptions: options, piScannerOptions: piOptions) var cache = CostUsageCacheIO.load(provider: .codex, cacheRoot: env.cacheRoot) cache.roots = [env.root.appendingPathComponent("other/sessions", isDirectory: true).path: 0] CostUsageCacheIO.save(provider: .codex, cache: cache, cacheRoot: env.cacheRoot) let cached = await CostUsageFetcher.loadCachedCodexTokenSnapshot( now: day, historyDays: 1, scannerOptions: options) #expect(cached?.sessionTokens == 165) #expect(cached?.last30DaysTokens == 165) } private static func writeCodexSessionFile( homeRoot: URL, env: CostUsageTestEnvironment, day: Date, filename: String, tokens: Int) throws { let comps = Calendar.current.dateComponents([.year, .month, .day], from: day) let dir = homeRoot .appendingPathComponent("sessions", isDirectory: true) .appendingPathComponent(String(format: "%04d", comps.year ?? 1970), isDirectory: true) .appendingPathComponent(String(format: "%02d", comps.month ?? 1), isDirectory: true) .appendingPathComponent(String(format: "%02d", comps.day ?? 1), isDirectory: true) try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true) let model = "openai/gpt-5.4" let url = dir.appendingPathComponent(filename, isDirectory: false) try env.jsonl([ [ "type": "turn_context", "timestamp": env.isoString(for: day), "payload": ["model": model], ], [ "type": "event_msg", "timestamp": env.isoString(for: day.addingTimeInterval(1)), "payload": [ "type": "token_count", "info": [ "last_token_usage": [ "input_tokens": tokens, "cached_input_tokens": 0, "output_tokens": 0, ], "model": model, ], ], ], ]).write(to: url, atomically: true, encoding: .utf8) } private static func writePiCodexSessionFile( env: CostUsageTestEnvironment, day: Date, tokens: Int) throws { _ = try env.writePiSessionFile( relativePath: "nested/run-0/2026-04-08T10-00-00-000Z_test.jsonl", contents: env.jsonl([ [ "type": "message", "timestamp": env.isoString(for: day), "message": [ "role": "assistant", "provider": "openai-codex", "model": "openai/gpt-5.4", "timestamp": Int(day.timeIntervalSince1970 * 1000), "usage": [ "input": tokens, "output": 0, "cacheRead": 0, "cacheWrite": 0, "totalTokens": tokens, ], ], ], ])) }}
import Foundation
import Testing
@testable import CodexBarCore
struct CostUsageFetcherCacheSnapshotTests {
@Test
func `cached codex token snapshot loads from existing cache without rescanning`() async throws {
let env = try CostUsageTestEnvironment()
defer { env.cleanup() }
let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8)
try Self.writeCodexSessionFile(
homeRoot: env.codexHomeRoot,
env: env,
day: day,
filename: "cached.jsonl",
tokens: 42)
let options = CostUsageScanner.Options(
codexSessionsRoot: env.codexSessionsRoot,
cacheRoot: env.cacheRoot)
_ = try await CostUsageFetcher.loadTokenSnapshot(
provider: .codex,
now: day,
historyDays: 1,
scannerOptions: options)
let cached = await CostUsageFetcher.loadCachedCodexTokenSnapshot(
now: day,
historyDays: 1,
scannerOptions: options)
#expect(cached?.sessionTokens == 42)
#expect(cached?.last30DaysTokens == 42)
#expect(cached?.daily.map(\.date) == ["2026-04-08"])
}
@Test
func `cached codex token snapshot refuses expanded or managed scopes`() async throws {
let env = try CostUsageTestEnvironment()
defer { env.cleanup() }
let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8)
try Self.writeCodexSessionFile(
homeRoot: env.codexHomeRoot,
env: env,
day: day,
filename: "cached.jsonl",
tokens: 42)
let options = CostUsageScanner.Options(
codexSessionsRoot: env.codexSessionsRoot,
cacheRoot: env.cacheRoot)
_ = try await CostUsageFetcher.loadTokenSnapshot(
provider: .codex,
now: day,
historyDays: 1,
scannerOptions: options)
let expanded = await CostUsageFetcher.loadCachedCodexTokenSnapshot(
now: day,
historyDays: 7,
scannerOptions: options)
let managed = await CostUsageFetcher.loadCachedCodexTokenSnapshot(
now: day,
codexHomePath: env.codexHomeRoot.path,
historyDays: 1,
scannerOptions: options)
#expect(expanded == nil)
#expect(managed == nil)
}
@Test
func `cached codex token snapshot refuses mismatched roots fingerprint`() async throws {
let env = try CostUsageTestEnvironment()
defer { env.cleanup() }
let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8)
try Self.writeCodexSessionFile(
homeRoot: env.codexHomeRoot,
env: env,
day: day,
filename: "cached.jsonl",
tokens: 42)
let options = CostUsageScanner.Options(
codexSessionsRoot: env.codexSessionsRoot,
cacheRoot: env.cacheRoot)
_ = try await CostUsageFetcher.loadTokenSnapshot(
provider: .codex,
now: day,
historyDays: 1,
scannerOptions: options)
var cache = CostUsageCacheIO.load(provider: .codex, cacheRoot: env.cacheRoot)
cache.roots = [env.root.appendingPathComponent("other/sessions", isDirectory: true).path: 0]
CostUsageCacheIO.save(provider: .codex, cache: cache, cacheRoot: env.cacheRoot)
let cached = await CostUsageFetcher.loadCachedCodexTokenSnapshot(
now: day,
historyDays: 1,
scannerOptions: options)
#expect(cached == nil)
}
@Test
func `cached codex token snapshot merges cached pi sessions`() async throws {
let env = try CostUsageTestEnvironment()
defer { env.cleanup() }
let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8)
try Self.writeCodexSessionFile(
homeRoot: env.codexHomeRoot,
env: env,
day: day,
filename: "cached.jsonl",
tokens: 42)
try Self.writePiCodexSessionFile(env: env, day: day, tokens: 165)
let options = CostUsageScanner.Options(
codexSessionsRoot: env.codexSessionsRoot,
cacheRoot: env.cacheRoot)
let piOptions = PiSessionCostScanner.Options(
piSessionsRoot: env.piSessionsRoot,
cacheRoot: env.cacheRoot,
refreshMinIntervalSeconds: 0)
_ = try await CostUsageFetcher.loadTokenSnapshot(
provider: .codex,
now: day,
historyDays: 1,
refreshPricingInBackground: false,
scannerOptions: options,
piScannerOptions: piOptions)
let cached = await CostUsageFetcher.loadCachedCodexTokenSnapshot(
now: day,
historyDays: 1,
scannerOptions: options)
#expect(cached?.sessionTokens == 207)
#expect(cached?.last30DaysTokens == 207)
}
@Test
func `cached codex token snapshot loads cached pi sessions without native codex cache`() async throws {
let env = try CostUsageTestEnvironment()
defer { env.cleanup() }
let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8)
try Self.writePiCodexSessionFile(env: env, day: day, tokens: 165)
let piOptions = PiSessionCostScanner.Options(
piSessionsRoot: env.piSessionsRoot,
cacheRoot: env.cacheRoot,
refreshMinIntervalSeconds: 0)
_ = PiSessionCostScanner.loadDailyReport(
provider: .codex,
since: day,
until: day,
now: day,
options: piOptions)
let cached = await CostUsageFetcher.loadCachedCodexTokenSnapshot(
now: day,
historyDays: 1,
scannerOptions: CostUsageScanner.Options(
codexSessionsRoot: env.codexSessionsRoot,
cacheRoot: env.cacheRoot))
#expect(cached?.sessionTokens == 165)
#expect(cached?.last30DaysTokens == 165)
}
@Test
func `cached codex token snapshot still loads pi sessions when native cache roots mismatch`() async throws {
let env = try CostUsageTestEnvironment()
defer { env.cleanup() }
let day = try env.makeLocalNoon(year: 2026, month: 4, day: 8)
try Self.writeCodexSessionFile(
homeRoot: env.codexHomeRoot,
env: env,
day: day,
filename: "cached.jsonl",
tokens: 42)
try Self.writePiCodexSessionFile(env: env, day: day, tokens: 165)
let options = CostUsageScanner.Options(
codexSessionsRoot: env.codexSessionsRoot,
cacheRoot: env.cacheRoot)
let piOptions = PiSessionCostScanner.Options(
piSessionsRoot: env.piSessionsRoot,
cacheRoot: env.cacheRoot,
refreshMinIntervalSeconds: 0)
_ = try await CostUsageFetcher.loadTokenSnapshot(
provider: .codex,
now: day,
historyDays: 1,
refreshPricingInBackground: false,
scannerOptions: options,
piScannerOptions: piOptions)
var cache = CostUsageCacheIO.load(provider: .codex, cacheRoot: env.cacheRoot)
cache.roots = [env.root.appendingPathComponent("other/sessions", isDirectory: true).path: 0]
CostUsageCacheIO.save(provider: .codex, cache: cache, cacheRoot: env.cacheRoot)
let cached = await CostUsageFetcher.loadCachedCodexTokenSnapshot(
now: day,
historyDays: 1,
scannerOptions: options)
#expect(cached?.sessionTokens == 165)
#expect(cached?.last30DaysTokens == 165)
}
private static func writeCodexSessionFile(
homeRoot: URL,
env: CostUsageTestEnvironment,
day: Date,
filename: String,
tokens: Int) throws
{
let comps = Calendar.current.dateComponents([.year, .month, .day], from: day)
let dir = homeRoot
.appendingPathComponent("sessions", isDirectory: true)
.appendingPathComponent(String(format: "%04d", comps.year ?? 1970), isDirectory: true)
.appendingPathComponent(String(format: "%02d", comps.month ?? 1), isDirectory: true)
.appendingPathComponent(String(format: "%02d", comps.day ?? 1), isDirectory: true)
try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
let model = "openai/gpt-5.4"
let url = dir.appendingPathComponent(filename, isDirectory: false)
try env.jsonl([
[
"type": "turn_context",
"timestamp": env.isoString(for: day),
"payload": ["model": model],
],
[
"type": "event_msg",
"timestamp": env.isoString(for: day.addingTimeInterval(1)),
"payload": [
"type": "token_count",
"info": [
"last_token_usage": [
"input_tokens": tokens,
"cached_input_tokens": 0,
"output_tokens": 0,
],
"model": model,
],
],
],
]).write(to: url, atomically: true, encoding: .utf8)
}
private static func writePiCodexSessionFile(
env: CostUsageTestEnvironment,
day: Date,
tokens: Int) throws
{
_ = try env.writePiSessionFile(
relativePath: "nested/run-0/2026-04-08T10-00-00-000Z_test.jsonl",
contents: env.jsonl([
[
"type": "message",
"timestamp": env.isoString(for: day),
"message": [
"role": "assistant",
"provider": "openai-codex",
"model": "openai/gpt-5.4",
"timestamp": Int(day.timeIntervalSince1970 * 1000),
"usage": [
"input": tokens,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0,
"totalTokens": tokens,
],
],
],
]))
}
}