use std::path::Path;
use std::process::Command;
use tempfile::TempDir;
fn tokf_with_db(db_path: &Path) -> Command {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_tokf"));
cmd.env("TOKF_DB_PATH", db_path);
cmd
}
fn temp_db_dir() -> TempDir {
TempDir::new().expect("tempdir")
}
#[test]
fn gain_empty_db_exits_zero() {
let dir = temp_db_dir();
let db = dir.path().join("tracking.db");
let status = tokf_with_db(&db)
.args(["gain"])
.status()
.expect("run tokf gain");
assert!(status.success(), "exit code: {:?}", status.code());
}
#[test]
fn gain_summary_shows_zeros_on_fresh_db() {
let dir = temp_db_dir();
let db = dir.path().join("tracking.db");
let out = tokf_with_db(&db)
.args(["gain"])
.output()
.expect("run tokf gain");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(out.status.success());
assert!(stdout.contains("total runs:"), "stdout: {stdout}");
assert!(stdout.contains('0'), "stdout: {stdout}");
}
#[test]
fn gain_records_run_after_tokf_run() {
let dir = temp_db_dir();
let db = dir.path().join("tracking.db");
tokf_with_db(&db)
.args(["run", "echo", "hello"])
.output()
.expect("run tokf run echo hello");
let out = tokf_with_db(&db)
.args(["gain"])
.output()
.expect("run tokf gain");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(out.status.success());
assert!(stdout.contains("total runs: 1"), "stdout: {stdout}");
}
#[test]
fn gain_records_passthrough_when_no_filter_match() {
let dir = temp_db_dir();
let db = dir.path().join("tracking.db");
tokf_with_db(&db)
.args(["run", "echo", "passthrough_test"])
.output()
.expect("run");
let out = tokf_with_db(&db)
.args(["gain", "--by-filter", "--json"])
.output()
.expect("gain by-filter json");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(out.status.success());
assert!(
stdout.contains("passthrough"),
"expected 'passthrough' in: {stdout}"
);
}
#[test]
fn gain_json_output_is_valid_json() {
let dir = temp_db_dir();
let db = dir.path().join("tracking.db");
let out = tokf_with_db(&db)
.args(["gain", "--json"])
.output()
.expect("gain json");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(out.status.success());
let parsed: serde_json::Value = serde_json::from_str(&stdout).expect("must be valid JSON");
assert!(parsed.get("total_commands").is_some(), "json: {parsed}");
assert!(parsed.get("tokens_saved").is_some(), "json: {parsed}");
}
#[test]
fn gain_daily_json_is_array() {
let dir = temp_db_dir();
let db = dir.path().join("tracking.db");
tokf_with_db(&db)
.args(["run", "echo", "hello"])
.output()
.expect("run");
let out = tokf_with_db(&db)
.args(["gain", "--daily", "--json"])
.output()
.expect("gain daily json");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(out.status.success());
let parsed: serde_json::Value = serde_json::from_str(&stdout).expect("valid JSON");
assert!(parsed.is_array(), "expected array, got: {parsed}");
}
#[test]
fn gain_by_filter_shows_filter_name() {
let dir = temp_db_dir();
let db = dir.path().join("tracking.db");
tokf_with_db(&db)
.args(["run", "echo", "hello"])
.output()
.expect("run");
let out = tokf_with_db(&db)
.args(["gain", "--by-filter"])
.output()
.expect("gain by-filter");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(out.status.success());
assert!(
stdout.contains("passthrough"),
"expected filter row in: {stdout}"
);
}
#[test]
fn gain_tokens_saved_positive_after_filtered_run() {
let dir = temp_db_dir();
let db = dir.path().join("tracking.db");
use tokf::tracking;
let path = db.clone();
let conn = tracking::open_db(&path).expect("open");
let ev = tracking::build_event("git status", Some("git status"), 4000, 400, 5, 0);
tracking::record_event(&conn, &ev).expect("record");
drop(conn);
let out = tokf_with_db(&db)
.args(["gain", "--json"])
.output()
.expect("gain json");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(out.status.success());
let parsed: serde_json::Value = serde_json::from_str(&stdout).expect("json");
let saved = parsed["tokens_saved"].as_i64().expect("tokens_saved");
assert!(saved > 0, "expected positive savings, got: {saved}");
}
#[test]
fn run_db_write_failure_does_not_block_output() {
let out = Command::new(env!("CARGO_BIN_EXE_tokf"))
.env("TOKF_DB_PATH", "/dev/null/x/tracking.db")
.args(["run", "echo", "hello"])
.output()
.expect("run");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(out.status.success(), "exit code: {:?}", out.status.code());
assert!(stdout.trim() == "hello", "stdout: {stdout}");
}
#[test]
fn gain_by_filter_json_output_is_array() {
let dir = temp_db_dir();
let db = dir.path().join("tracking.db");
tokf_with_db(&db)
.args(["run", "echo", "hi"])
.output()
.expect("run");
let out = tokf_with_db(&db)
.args(["gain", "--by-filter", "--json"])
.output()
.expect("gain by-filter json");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(out.status.success());
let parsed: serde_json::Value = serde_json::from_str(&stdout).expect("valid JSON");
assert!(parsed.is_array(), "expected array, got: {parsed}");
}