import Foundation
import Testing
@testable import CodexBarCore
@Suite
struct MiniMaxCookieHeaderTests {
@Test
func normalizesRawCookieHeader() {
let raw = "foo=bar; session=abc123"
let normalized = MiniMaxCookieHeader.normalized(from: raw)
#expect(normalized == "foo=bar; session=abc123")
}
@Test
func extractsFromCookieHeaderLine() {
let raw = "Cookie: foo=bar; session=abc123"
let normalized = MiniMaxCookieHeader.normalized(from: raw)
#expect(normalized == "foo=bar; session=abc123")
}
@Test
func extractsFromCurlHeader() {
let raw = "curl https://platform.minimax.io -H 'Cookie: foo=bar; session=abc123' -H 'accept: */*'"
let normalized = MiniMaxCookieHeader.normalized(from: raw)
#expect(normalized == "foo=bar; session=abc123")
}
@Test
func extractsFromCurlCookieFlag() {
let raw = "curl https://platform.minimax.io --cookie 'foo=bar; session=abc123'"
let normalized = MiniMaxCookieHeader.normalized(from: raw)
#expect(normalized == "foo=bar; session=abc123")
}
@Test
func extractsAuthAndGroupIDFromCurl() {
let raw = """
curl 'https://platform.minimax.io/v1/api/openplatform/coding_plan/remains?GroupId=123456' \
-H 'authorization: Bearer token123' \
-H 'Cookie: foo=bar; session=abc123'
"""
let override = MiniMaxCookieHeader.override(from: raw)
#expect(override?.cookieHeader == "foo=bar; session=abc123")
#expect(override?.authorizationToken == "token123")
#expect(override?.groupID == "123456")
}
@Test
func extractsAuthFromUppercaseHeader() {
let raw = """
curl 'https://platform.minimax.io/v1/api/openplatform/coding_plan/remains?GROUP_ID=98765' \
-H 'Authorization: Bearer token-abc' \
-H 'Cookie: foo=bar; session=abc123'
"""
let override = MiniMaxCookieHeader.override(from: raw)
#expect(override?.authorizationToken == "token-abc")
#expect(override?.groupID == "98765")
}
}
@Suite
struct MiniMaxUsageParserTests {
@Test
func parsesCodingPlanSnapshot() throws {
let now = Date(timeIntervalSince1970: 1_700_000_000)
let html = """
Coding Plan
Max
Available usage: 1,000 prompts / 5 hours
Current Usage
0% Used
Resets in 4 min
"""
let snapshot = try MiniMaxUsageParser.parse(html: html, now: now)
#expect(snapshot.planName == "Max")
#expect(snapshot.availablePrompts == 1000)
#expect(snapshot.windowMinutes == 300)
#expect(snapshot.usedPercent == 0)
#expect(snapshot.resetsAt == now.addingTimeInterval(240))
let usage = snapshot.toUsageSnapshot()
#expect(usage.primary?.resetDescription == "1000 prompts / 5 hours")
}
@Test
func parsesCodingPlanRemainsResponse() throws {
let now = Date(timeIntervalSince1970: 1_700_000_000)
let start = 1_700_000_000_000
let end = start + 5 * 60 * 60 * 1000
let json = """
{
"base_resp": { "status_code": 0 },
"current_subscribe_title": "Max",
"model_remains": [
{
"current_interval_total_count": 1000,
"current_interval_usage_count": 250,
"start_time": \(start),
"end_time": \(end),
"remains_time": 240000
}
]
}
"""
let snapshot = try MiniMaxUsageParser.parseCodingPlanRemains(data: Data(json.utf8), now: now)
let expectedReset = Date(timeIntervalSince1970: TimeInterval(end) / 1000)
#expect(snapshot.planName == "Max")
#expect(snapshot.availablePrompts == 1000)
#expect(snapshot.windowMinutes == 300)
#expect(snapshot.usedPercent == 75)
#expect(snapshot.resetsAt == expectedReset)
}
@Test
func parsesCodingPlanRemainsFromDataWrapper() throws {
let now = Date(timeIntervalSince1970: 1_700_000_100)
let start = 1_700_000_000_000
let end = start + 5 * 60 * 60 * 1000
let json = """
{
"base_resp": { "status_code": "0" },
"data": {
"current_subscribe_title": "Max",
"model_remains": [
{
"current_interval_total_count": "15000",
"current_interval_usage_count": "14989",
"start_time": \(start),
"end_time": \(end),
"remains_time": 8941292
}
]
}
}
"""
let snapshot = try MiniMaxUsageParser.parseCodingPlanRemains(data: Data(json.utf8), now: now)
let expectedUsed = Double(11) / Double(15000) * 100
let expectedReset = Date(timeIntervalSince1970: TimeInterval(end) / 1000)
#expect(snapshot.planName == "Max")
#expect(snapshot.availablePrompts == 15000)
#expect(snapshot.windowMinutes == 300)
#expect(abs((snapshot.usedPercent ?? 0) - expectedUsed) < 0.01)
#expect(snapshot.resetsAt == expectedReset)
}
@Test
func parsesCodingPlanFromNextData() throws {
let now = Date(timeIntervalSince1970: 1_700_000_000)
let start = 1_700_000_000_000
let end = start + 5 * 60 * 60 * 1000
let json = """
{
"props": {
"pageProps": {
"data": {
"base_resp": { "status_code": 0 },
"current_subscribe_title": "Max",
"model_remains": [
{
"current_interval_total_count": 1000,
"current_interval_usage_count": 250,
"start_time": \(start),
"end_time": \(end),
"remains_time": 240000
}
]
}
}
}
}
"""
let html = """
"""
let snapshot = try MiniMaxUsageParser.parse(html: html, now: now)
let expectedReset = Date(timeIntervalSince1970: TimeInterval(end) / 1000)
#expect(snapshot.planName == "Max")
#expect(snapshot.availablePrompts == 1000)
#expect(snapshot.windowMinutes == 300)
#expect(snapshot.usedPercent == 75)
#expect(snapshot.resetsAt == expectedReset)
}
@Test
func parsesHTMLWithUsedPrefixAndResetTime() throws {
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "UTC") ?? .current
let now = calendar.date(from: DateComponents(year: 2025, month: 1, day: 1, hour: 10, minute: 0))!
let expectedReset = calendar.date(from: DateComponents(year: 2025, month: 1, day: 1, hour: 23, minute: 30))!
let html = """
Coding Plan Pro
Available usage: 1,500 prompts / 1.5 hours
Used 75%
Resets at 23:30 (UTC)
"""
let snapshot = try MiniMaxUsageParser.parse(html: html, now: now)
#expect(snapshot.planName == "Pro")
#expect(snapshot.availablePrompts == 1500)
#expect(snapshot.windowMinutes == 90)
#expect(snapshot.usedPercent == 75)
#expect(snapshot.resetsAt == expectedReset)
}
@Test
func throwsOnMissingCookieResponse() {
let json = """
{
"base_resp": { "status_code": 1004, "status_msg": "cookie is missing, log in again" }
}
"""
#expect(throws: MiniMaxUsageError.invalidCredentials) {
try MiniMaxUsageParser.parseCodingPlanRemains(data: Data(json.utf8))
}
}
@Test
func throwsOnStringStatusCodeWhenLoggedOut() {
let json = """
{
"base_resp": { "status_code": "1004", "status_msg": "login required" }
}
"""
#expect(throws: MiniMaxUsageError.invalidCredentials) {
try MiniMaxUsageParser.parseCodingPlanRemains(data: Data(json.utf8))
}
}
}