use sqlmodel_console::{OutputMode, SqlModelConsole};
use std::env;
const MODE_VARS: &[&str] = &[
"SQLMODEL_PLAIN",
"SQLMODEL_JSON",
"SQLMODEL_RICH",
"NO_COLOR",
"CI",
"TERM",
"CLAUDE_CODE",
"CODEX_CLI",
"CODEX_SESSION",
"CURSOR_SESSION",
"CURSOR_EDITOR",
"AIDER_MODEL",
"AIDER_REPO",
"AGENT_MODE",
"AI_AGENT",
"GITHUB_COPILOT",
"COPILOT_SESSION",
"CONTINUE_SESSION",
"CODY_AGENT",
"CODY_SESSION",
"WINDSURF_SESSION",
"CODEIUM_AGENT",
"GEMINI_CLI",
"GEMINI_SESSION",
"CODEWHISPERER_SESSION",
"AMAZON_Q_SESSION",
];
#[allow(unsafe_code)]
fn set_var(key: &str, value: &str) {
unsafe { env::set_var(key, value) };
}
#[allow(unsafe_code)]
fn remove_var(key: &str) {
unsafe { env::remove_var(key) };
}
struct EnvGuard {
saved: Vec<(&'static str, Option<String>)>,
}
impl EnvGuard {
fn new() -> Self {
let saved = MODE_VARS
.iter()
.map(|&var| (var, env::var(var).ok()))
.collect();
for &var in MODE_VARS {
remove_var(var);
}
Self { saved }
}
}
impl Drop for EnvGuard {
fn drop(&mut self) {
for &(var, ref val) in &self.saved {
match val {
Some(v) => set_var(var, v),
None => remove_var(var),
}
}
}
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_claude_code() {
let _guard = EnvGuard::new();
set_var("CLAUDE_CODE", "1");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_codex_cli() {
let _guard = EnvGuard::new();
set_var("CODEX_CLI", "1");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_codex_session() {
let _guard = EnvGuard::new();
set_var("CODEX_SESSION", "session-123");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_cursor_session() {
let _guard = EnvGuard::new();
set_var("CURSOR_SESSION", "abc123");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_cursor_editor() {
let _guard = EnvGuard::new();
set_var("CURSOR_EDITOR", "1");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "requires --test-threads=1 due to env var race conditions"]
fn test_detects_aider_model() {
let _guard = EnvGuard::new();
set_var("AIDER_MODEL", "gpt-4");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_aider_repo() {
let _guard = EnvGuard::new();
set_var("AIDER_REPO", "/path/to/repo");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_agent_mode() {
let _guard = EnvGuard::new();
set_var("AGENT_MODE", "1");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_ai_agent() {
let _guard = EnvGuard::new();
set_var("AI_AGENT", "1");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_github_copilot() {
let _guard = EnvGuard::new();
set_var("GITHUB_COPILOT", "1");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_copilot_session() {
let _guard = EnvGuard::new();
set_var("COPILOT_SESSION", "sess-456");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_continue_session() {
let _guard = EnvGuard::new();
set_var("CONTINUE_SESSION", "cont-789");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_cody_agent() {
let _guard = EnvGuard::new();
set_var("CODY_AGENT", "1");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_cody_session() {
let _guard = EnvGuard::new();
set_var("CODY_SESSION", "cody-abc");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_windsurf_session() {
let _guard = EnvGuard::new();
set_var("WINDSURF_SESSION", "ws-123");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_codeium_agent() {
let _guard = EnvGuard::new();
set_var("CODEIUM_AGENT", "1");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_gemini_cli() {
let _guard = EnvGuard::new();
set_var("GEMINI_CLI", "1");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_gemini_session() {
let _guard = EnvGuard::new();
set_var("GEMINI_SESSION", "gem-xyz");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_codewhisperer() {
let _guard = EnvGuard::new();
set_var("CODEWHISPERER_SESSION", "cw-123");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_detects_amazon_q() {
let _guard = EnvGuard::new();
set_var("AMAZON_Q_SESSION", "q-456");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
fn test_no_agent_when_clean() {
let _guard = EnvGuard::new();
assert!(!OutputMode::is_agent_environment());
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_force_rich_in_agent_environment() {
let _guard = EnvGuard::new();
set_var("CLAUDE_CODE", "1");
set_var("SQLMODEL_RICH", "1");
assert_eq!(OutputMode::detect(), OutputMode::Rich);
}
#[test]
fn test_plain_override_with_agent() {
let _guard = EnvGuard::new();
set_var("CLAUDE_CODE", "1");
set_var("SQLMODEL_PLAIN", "1");
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
fn test_plain_beats_rich_override() {
let _guard = EnvGuard::new();
set_var("SQLMODEL_PLAIN", "1");
set_var("SQLMODEL_RICH", "1");
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
fn test_plain_beats_json_override() {
let _guard = EnvGuard::new();
set_var("SQLMODEL_PLAIN", "1");
set_var("SQLMODEL_JSON", "1");
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
fn test_json_beats_rich_override() {
let _guard = EnvGuard::new();
set_var("SQLMODEL_JSON", "1");
set_var("SQLMODEL_RICH", "1");
assert_eq!(OutputMode::detect(), OutputMode::Json);
}
#[test]
fn test_no_color_causes_plain() {
let _guard = EnvGuard::new();
set_var("NO_COLOR", ""); assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
fn test_ci_causes_plain() {
let _guard = EnvGuard::new();
set_var("CI", "true");
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_dumb_terminal_causes_plain() {
let _guard = EnvGuard::new();
set_var("TERM", "dumb");
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_multiple_agents_detected() {
let _guard = EnvGuard::new();
set_var("CLAUDE_CODE", "1");
set_var("CODEX_CLI", "1");
set_var("CURSOR_SESSION", "test");
assert!(OutputMode::is_agent_environment());
assert_eq!(OutputMode::detect(), OutputMode::Plain);
}
#[test]
fn test_plain_mode_console_no_ansi() {
let console = SqlModelConsole::with_mode(OutputMode::Plain);
assert!(console.is_plain());
assert!(!console.mode().supports_ansi());
}
#[test]
fn test_json_mode_no_ansi() {
let console = SqlModelConsole::with_mode(OutputMode::Json);
assert!(console.is_json());
assert!(!console.mode().supports_ansi());
}
#[test]
fn test_only_rich_supports_ansi() {
assert!(!OutputMode::Plain.supports_ansi());
assert!(OutputMode::Rich.supports_ansi());
assert!(!OutputMode::Json.supports_ansi());
}
#[test]
fn test_strip_markup_removes_style_tags() {
use sqlmodel_console::console::strip_markup;
assert_eq!(strip_markup("[bold]text[/]"), "text");
assert_eq!(strip_markup("[red]error[/]"), "error");
assert_eq!(strip_markup("[green]success[/]"), "success");
assert_eq!(strip_markup("[bold red]warning[/]"), "warning");
assert_eq!(strip_markup("[red on white]highlighted[/]"), "highlighted");
assert_eq!(strip_markup("[bold][italic]nested[/][/]"), "nested");
assert_eq!(strip_markup("[red]a[/] [blue]b[/]"), "a b");
}
#[test]
fn test_strip_markup_preserves_array_indices() {
use sqlmodel_console::console::strip_markup;
assert_eq!(strip_markup("array[0]"), "array[0]");
assert_eq!(strip_markup("array[123]"), "array[123]");
assert_eq!(strip_markup("items[i]"), "items[i]");
assert_eq!(strip_markup("matrix[n]"), "matrix[n]");
assert_eq!(strip_markup("data[x1]"), "data[x1]");
assert_eq!(strip_markup("arr[i2]"), "arr[i2]");
assert_eq!(strip_markup("get_item(arr[0])"), "get_item(arr[0])");
}
#[test]
fn test_plain_output_no_escape_sequences() {
let ansi_patterns = [
"\x1b[", "\x1b]", "\x1bP", "\x1b\\", "\u{009b}", ];
let console = SqlModelConsole::with_mode(OutputMode::Plain);
assert!(console.is_plain());
assert!(!console.mode().supports_ansi());
for pattern in ansi_patterns {
let mode_str = OutputMode::Plain.as_str();
assert!(
!mode_str.contains(pattern),
"Mode string should not contain ANSI: {mode_str}"
);
}
}
#[test]
fn test_plain_mode_strings_parseable() {
let console = SqlModelConsole::with_mode(OutputMode::Plain);
assert_eq!(console.mode().as_str(), "plain");
assert!(console.mode().as_str().is_ascii());
}
#[test]
fn test_json_mode_produces_valid_json() {
#[derive(serde::Serialize)]
struct TestData {
name: String,
count: i32,
active: bool,
}
let data = TestData {
name: "test".to_string(),
count: 42,
active: true,
};
let json = serde_json::to_string(&data).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(parsed["name"], "test");
assert_eq!(parsed["count"], 42);
assert_eq!(parsed["active"], true);
}
#[test]
fn test_json_mode_string() {
assert_eq!(OutputMode::Json.as_str(), "json");
assert!(OutputMode::Json.is_structured());
}
#[test]
fn test_mode_display() {
assert_eq!(format!("{}", OutputMode::Plain), "plain");
assert_eq!(format!("{}", OutputMode::Rich), "rich");
assert_eq!(format!("{}", OutputMode::Json), "json");
}
#[test]
fn test_console_auto_detection() {
let _guard = EnvGuard::new();
set_var("CLAUDE_CODE", "1");
let console = SqlModelConsole::new();
assert!(console.is_plain());
}
#[test]
fn test_console_explicit_mode() {
let console = SqlModelConsole::with_mode(OutputMode::Rich);
assert!(console.is_rich());
let console = SqlModelConsole::with_mode(OutputMode::Plain);
assert!(console.is_plain());
let console = SqlModelConsole::with_mode(OutputMode::Json);
assert!(console.is_json());
}
#[test]
fn test_console_set_mode() {
let mut console = SqlModelConsole::with_mode(OutputMode::Rich);
assert!(console.is_rich());
console.set_mode(OutputMode::Plain);
assert!(console.is_plain());
console.set_mode(OutputMode::Json);
assert!(console.is_json());
}
#[test]
fn test_truthy_values() {
let _guard = EnvGuard::new();
for truthy in ["1", "true", "TRUE", "True", "yes", "YES", "on", "ON"] {
remove_var("SQLMODEL_PLAIN");
set_var("SQLMODEL_PLAIN", truthy);
assert_eq!(
OutputMode::detect(),
OutputMode::Plain,
"Failed for truthy value: {truthy}"
);
}
}
#[test]
#[ignore = "flaky: env var race conditions in parallel tests"]
fn test_falsy_values() {
for falsy in ["0", "false", "FALSE", "no", "NO", "off", "OFF", ""] {
let _guard = EnvGuard::new();
set_var("SQLMODEL_PLAIN", falsy);
set_var("SQLMODEL_RICH", "1");
let mode = OutputMode::detect();
assert_eq!(
mode,
OutputMode::Rich,
"SQLMODEL_PLAIN={falsy} should not trigger plain mode"
);
}
}
#[test]
#[ignore = "flaky: depends on environment variables not being set by CI/agent context"]
fn test_agent_marker_presence_not_value() {
let _guard = EnvGuard::new();
set_var("CLAUDE_CODE", "");
assert!(OutputMode::is_agent_environment());
}
#[test]
fn test_output_mode_default() {
assert_eq!(OutputMode::default(), OutputMode::Rich);
}
#[test]
fn test_mode_predicates() {
assert!(OutputMode::Plain.is_plain());
assert!(!OutputMode::Rich.is_plain());
assert!(!OutputMode::Json.is_plain());
assert!(!OutputMode::Plain.is_rich());
assert!(OutputMode::Rich.is_rich());
assert!(!OutputMode::Json.is_rich());
assert!(!OutputMode::Plain.is_structured());
assert!(!OutputMode::Rich.is_structured());
assert!(OutputMode::Json.is_structured());
}
#[test]
fn test_console_default_equals_new() {
let _guard = EnvGuard::new();
let c1 = SqlModelConsole::default();
let c2 = SqlModelConsole::new();
assert_eq!(c1.mode(), c2.mode());
assert_eq!(c1.get_plain_width(), c2.get_plain_width());
}
#[test]
#[ignore = "requires --test-threads=1 due to env var race conditions"]
fn test_documented_agent_support() {
struct AgentInfo {
name: &'static str,
env_var: &'static str,
example_value: &'static str,
}
let agents = [
AgentInfo {
name: "Claude Code",
env_var: "CLAUDE_CODE",
example_value: "1",
},
AgentInfo {
name: "OpenAI Codex CLI",
env_var: "CODEX_CLI",
example_value: "1",
},
AgentInfo {
name: "Cursor IDE",
env_var: "CURSOR_SESSION",
example_value: "session-id",
},
AgentInfo {
name: "Aider",
env_var: "AIDER_MODEL",
example_value: "gpt-4",
},
AgentInfo {
name: "GitHub Copilot",
env_var: "GITHUB_COPILOT",
example_value: "1",
},
AgentInfo {
name: "Continue.dev",
env_var: "CONTINUE_SESSION",
example_value: "sess-123",
},
AgentInfo {
name: "Sourcegraph Cody",
env_var: "CODY_AGENT",
example_value: "1",
},
AgentInfo {
name: "Windsurf/Codeium",
env_var: "WINDSURF_SESSION",
example_value: "ws-123",
},
AgentInfo {
name: "Google Gemini CLI",
env_var: "GEMINI_CLI",
example_value: "1",
},
AgentInfo {
name: "Amazon CodeWhisperer",
env_var: "CODEWHISPERER_SESSION",
example_value: "cw-123",
},
AgentInfo {
name: "Amazon Q",
env_var: "AMAZON_Q_SESSION",
example_value: "q-456",
},
];
for agent in agents {
let _guard = EnvGuard::new();
set_var(agent.env_var, agent.example_value);
assert!(
OutputMode::is_agent_environment(),
"{} should be detected via {} env var",
agent.name,
agent.env_var
);
assert_eq!(
OutputMode::detect(),
OutputMode::Plain,
"{} should trigger plain mode",
agent.name
);
}
}