use super::*;
use crate::usage::test_support::{ FAR_FUTURE_MS, mk_aq_ok_both, mk_aq_sort, mk_aq_sort_weekly, mk_aq_err };
use crate::usage::types::PreferStrategy;
#[ doc = "bug_reproducer(BUG-271)" ]
#[ test ]
fn test_shorten_error_429_returns_rate_limited()
{
assert_eq!(
shorten_error( "HTTP transport error: HTTP 429" ),
"rate limited (429)",
);
}
#[ doc = "bug_reproducer(BUG-152)" ]
#[ test ]
fn test_shorten_error_mre_401_shortened()
{
assert_eq!(
shorten_error( "HTTP transport error: HTTP 401" ),
"auth expired (401)",
"HTTP 401 transport string must be shortened per AC-03 (BUG-152)",
);
}
#[ test ]
fn test_shorten_error_403_returns_auth_forbidden()
{
assert_eq!(
shorten_error( "HTTP transport error: HTTP 403" ),
"auth forbidden (403)",
"HTTP 403 transport string must be shortened per AC-03",
);
}
#[ test ]
fn test_shorten_error_no_raw_http_transport_passthrough()
{
let shortened_codes = &[
"HTTP transport error: HTTP 401", "HTTP transport error: HTTP 403", "HTTP transport error: HTTP 429", ];
for &e in shortened_codes
{
let shortened = shorten_error( e );
assert!(
!shortened.starts_with( "HTTP transport error:" ),
"shorten_error must shorten {e:?}; got verbatim passthrough {shortened:?}",
);
}
}
#[ test ]
fn test_shorten_error_no_header_preserved()
{
assert_eq!( shorten_error( "rate-limit header missing: X-RateLimit-Remaining" ), "no header" );
}
#[ test ]
fn test_shorten_error_empty_passthrough()
{
assert_eq!( shorten_error( "" ), "" );
}
#[ test ]
fn test_shorten_error_arbitrary_passthrough()
{
assert_eq!( shorten_error( "network timeout" ), "network timeout" );
}
#[ test ]
fn test_compute_expires_cell_both_zero()
{
assert_eq!( compute_expires_cell( 0, 0 ), "EXPIRED" );
}
#[ test ]
fn test_compute_expires_cell_subsecond_truncation()
{
assert_eq!( compute_expires_cell( 999, 0 ), "EXPIRED" );
}
#[ test ]
fn test_compute_expires_cell_one_second_remaining()
{
let result = compute_expires_cell( 1000, 0 );
assert!( result.starts_with( "in " ), "1 second remaining must start with 'in ', got: {result}" );
}
#[ test ]
fn test_compute_expires_cell_now_exceeds_expires()
{
assert_eq!( compute_expires_cell( 1000, 9999 ), "EXPIRED" );
}
#[ test ]
fn tel_epoch_zero_is_expired()
{
let label = token_exp_label( 0 );
assert!( label.starts_with( "expired(" ), "expected expired prefix; got: {label}" );
assert!( label.ends_with( " ago)" ), "expected ' ago)' suffix; got: {label}" );
}
#[ test ]
fn tel_far_future_is_valid()
{
let label = token_exp_label( u64::MAX );
assert!( label.starts_with( "valid(" ), "expected valid prefix; got: {label}" );
assert!( label.ends_with( " left)" ), "expected ' left)' suffix; got: {label}" );
}
#[ test ]
fn test_status_emoji_and_both_ample_green()
{
let aq = mk_aq_ok_both( 50.0, 50.0 );
assert_eq!( status_emoji( &aq.result ), "🟢", "5h > 15% and 7d > 5% → 🟢" );
}
#[ test ]
fn test_status_emoji_and_7d_low_yellow()
{
let aq = mk_aq_ok_both( 50.0, 97.0 );
assert_eq!( status_emoji( &aq.result ), "🟡", "7d ≤ 5% despite 5h ample → 🟡" );
}
#[ test ]
fn test_status_emoji_and_5h_low_yellow()
{
let aq = mk_aq_ok_both( 97.0, 50.0 );
assert_eq!( status_emoji( &aq.result ), "🟡", "5h ≤ 15% despite 7d ample → 🟡" );
}
#[ test ]
fn test_status_emoji_and_both_at_threshold_yellow()
{
let aq = mk_aq_ok_both( 85.0, 95.0 );
assert_eq!( status_emoji( &aq.result ), "🟡", "5h=15% and 7d=5% → 🟡 (neither > threshold)" );
}
#[ test ]
fn it151_status_emoji_boundary_precision()
{
let aq_a = mk_aq_ok_both( 85.0, 50.0 );
let aq_b = mk_aq_ok_both( 84.9, 50.0 );
let aq_c = mk_aq_ok_both( 50.0, 95.0 );
assert_eq!( status_emoji( &aq_a.result ), "🟡", "A: 5h=15.0% (at threshold) → 🟡" );
assert_eq!( status_emoji( &aq_b.result ), "🟢", "B: 5h=15.1% (just above) → 🟢" );
assert_eq!( status_emoji( &aq_c.result ), "🟡", "C: 7d=5.0% (at threshold) → 🟡" );
}
#[ test ]
fn test_status_emoji_five_hour_none_is_green()
{
let data = claude_quota::OauthUsageData
{
five_hour : None, seven_day : None, seven_day_sonnet : None,
};
let result : Result< claude_quota::OauthUsageData, String > = Ok( data );
assert_eq!(
status_emoji( &result ), "🟢",
"five_hour=None must yield 🟢 (conservative 100% left)",
);
}
#[ test ]
fn test_quota_text_cells_5h_emoji_green()
{
let data = claude_quota::OauthUsageData
{
five_hour : Some( claude_quota::PeriodUsage { utilization : 14.0, resets_at : None } ),
seven_day : None,
seven_day_sonnet : None,
};
let cells = quota_text_cells( &data, 0 );
assert_eq!( cells[ 0 ], "🟢 86%", "86% 5h left → 🟢 86%" );
}
#[ test ]
fn test_quota_text_cells_5h_emoji_yellow()
{
let data = claude_quota::OauthUsageData
{
five_hour : Some( claude_quota::PeriodUsage { utilization : 97.0, resets_at : None } ),
seven_day : None,
seven_day_sonnet : None,
};
let cells = quota_text_cells( &data, 0 );
assert_eq!( cells[ 0 ], "🟡 3%", "3% 5h left → 🟡 3%" );
}
#[ test ]
fn test_quota_text_cells_five_hour_none_shows_dash()
{
let data = claude_quota::OauthUsageData
{
five_hour : None, seven_day : None, seven_day_sonnet : None,
};
let cells = quota_text_cells( &data, 0 );
assert_eq!(
cells[ 0 ], "\u{2014}",
"five_hour=None must produce em-dash in cells[0], not a percentage",
);
}
#[ test ]
fn test_ft11_009_per_column_emoji_prefix_three_cases()
{
let mk_5h = |util : f64| -> claude_quota::OauthUsageData
{
claude_quota::OauthUsageData
{
five_hour : Some( claude_quota::PeriodUsage { utilization : util, resets_at : None } ),
seven_day : None,
seven_day_sonnet : None,
}
};
let cells_a = quota_text_cells( &mk_5h( 10.0 ), 0 );
assert_eq!( cells_a[ 0 ], "🟢 90%", "Pct A (90% left) must have 🟢 prefix (FT-11/009)" );
let cells_b = quota_text_cells( &mk_5h( 97.0 ), 0 );
assert_eq!( cells_b[ 0 ], "🟡 3%", "Pct B (3% left) must have 🟡 prefix (FT-11/009)" );
let cells_c = quota_text_cells( &mk_5h( 85.0 ), 0 );
assert_eq!( cells_c[ 0 ], "🟡 15%", "Pct C (exactly 15% left) must have 🟡 prefix — boundary inclusive (FT-11/009)" );
}
#[ test ]
fn rl_exact_from_renewal_at()
{
let now_secs = 1_893_456_000_u64;
let result = renews_label( Some( "2030-01-01T03:47:00Z" ), None, now_secs );
assert_eq!(
result, "in 3h 47m",
"exact _renewal_at must produce 'in 3h 47m' (no ~ prefix), got: {result}",
);
}
#[ test ]
fn rl_estimate_from_org_created_at()
{
let now_secs = 1_893_456_000_u64;
let result = renews_label( None, Some( "2025-01-15T00:00:00Z" ), now_secs );
assert!(
result.starts_with( "~in " ),
"estimate must start with '~in ', got: {result}",
);
assert!(
result.contains( 'd' ),
"estimate must include days unit, got: {result}",
);
}
#[ test ]
fn rl_auto_advance_past_renewal_at()
{
let now_secs = 1_893_456_000_u64;
let result = renews_label( Some( "2020-01-01T00:00:00Z" ), None, now_secs );
assert!(
result.starts_with( "in " ),
"auto-advanced _renewal_at must start with 'in ' (no ~ prefix), got: {result}",
);
assert!(
!result.contains( "31d" ) && !result.contains( "32d" ),
"auto-advance must land within 30d of now, got: {result}",
);
}
#[ test ]
fn rl_absent_returns_question()
{
let result = renews_label( None, None, 1_893_456_000 );
assert_eq!( result, "?", "both absent must return '?', got: {result}" );
}
#[ test ]
fn ne_tok_excluded_after_tsk228()
{
let result = next_event_label( Some( 7200 ), None, false );
assert_eq!( result, "in 2h +7d", "!tok must not be a candidate; got: {result}" );
}
#[ test ]
fn ne_7d_soonest()
{
let result = next_event_label( Some( 2 * 86400 ), None, false );
assert_eq!( result, "in 2d +7d", "7d reset soonest → 'in 2d +7d', got: {result}" );
}
#[ test ]
fn ne_renewal_soonest_exact()
{
let result = next_event_label( None, Some( 21600 ), false );
assert_eq!( result, "in 6h $ren", "exact renewal soonest → 'in 6h $ren', got: {result}" );
}
#[ test ]
fn ne_renewal_soonest_estimate()
{
let result = next_event_label( None, Some( 3 * 86400 ), true );
assert_eq!( result, "~in 3d $ren", "estimate renewal soonest → '~in 3d $ren', got: {result}" );
}
#[ test ]
fn ne_all_none_returns_dash()
{
let result = next_event_label( None, None, false );
assert_eq!( result, "\u{2014}", "all absent → em-dash, got: {result}" );
}
#[ test ]
fn test_relevant_quotas_any_no_sonnet()
{
let aq = mk_aq_ok_both( 20.0, 30.0 );
let quotas = relevant_quotas( &aq, PreferStrategy::Any );
assert!(
( quotas.1 - 70.0 ).abs() < 1e-9,
"prefer::any + absent Sonnet → relevant_7d_left must equal d7_left (70.0); got: {}",
quotas.1,
);
}
#[ test ]
fn test_relevant_quotas_son_no_sonnet()
{
let aq = mk_aq_ok_both( 20.0, 30.0 );
let quotas = relevant_quotas( &aq, PreferStrategy::Sonnet );
assert!(
quotas.1.abs() < 1e-9,
"prefer::son + absent Sonnet → relevant_7d_left must be 0.0 (absent = unknown); got: {}",
quotas.1,
);
}
#[ test ]
fn test_relevant_quotas_son_with_sonnet()
{
let aq = mk_aq_sort_weekly( "t@x.com", 20.0, 30.0, 70.0 );
let quotas = relevant_quotas( &aq, PreferStrategy::Sonnet );
assert!(
( quotas.1 - 30.0 ).abs() < 1e-9,
"prefer::son + son_util=70.0 → relevant_7d_left must be 30.0; got: {}",
quotas.1,
);
}
#[ test ]
fn test_relevant_quotas_opus()
{
let aq = mk_aq_sort_weekly( "t@x.com", 20.0, 40.0, 95.0 );
let quotas = relevant_quotas( &aq, PreferStrategy::Opus );
assert!(
( quotas.1 - 60.0 ).abs() < 1e-9,
"prefer::opus → relevant_7d_left must equal raw d7_left (60.0), ignoring Sonnet; got: {}",
quotas.1,
);
}
#[ test ]
fn test_relevant_quotas_err()
{
let aq = mk_aq_err();
let quotas = relevant_quotas( &aq, PreferStrategy::Any );
assert!(
( quotas.0 - ( -1.0 ) ).abs() < 1e-9 && quotas.1.abs() < 1e-9,
"Err result → relevant_quotas must return (-1.0, 0.0); got: {quotas:?}",
);
}
#[ test ]
fn ft01_recommended_model_sonnet_when_tier_absent()
{
let aq = mk_aq_sort( "a@test.com", 0.0, FAR_FUTURE_MS ); assert_eq!(
recommended_model( &aq ), "sonnet",
"absent Sonnet tier must return sonnet; got: {:?}", recommended_model( &aq ),
);
}
#[ test ]
fn ft02_recommended_model_sonnet_at_exactly_15_pct_left()
{
let aq = mk_aq_sort_weekly( "a@test.com", 0.0, 0.0, 85.0 ); assert_eq!(
recommended_model( &aq ), "sonnet",
"utilization=85.0 (15% left) must return sonnet (strict < boundary); got: {:?}", recommended_model( &aq ),
);
}
#[ test ]
fn ft03_recommended_model_opus_when_sonnet_below_threshold()
{
let aq = mk_aq_sort_weekly( "a@test.com", 0.0, 0.0, 86.0 ); assert_eq!(
recommended_model( &aq ), "opus",
"utilization=86.0 (14% left) must return opus; got: {:?}", recommended_model( &aq ),
);
}
#[ test ]
fn ft04_recommended_model_sonnet_on_err()
{
let aq = mk_aq_err();
assert_eq!(
recommended_model( &aq ), "sonnet",
"Err result must return sonnet; got: {:?}", recommended_model( &aq ),
);
}
#[ test ]
fn ec01_recommended_model_sonnet_at_15_001_pct_left()
{
let aq = mk_aq_sort_weekly( "a@test.com", 0.0, 0.0, 84.999 );
assert_eq!(
recommended_model( &aq ), "sonnet",
"utilization=84.999 (15.001% left) must return sonnet; got: {:?}", recommended_model( &aq ),
);
}