#[cfg(feature = "firecracker")]
use terraphim_agent::repl::commands::VmSubcommand;
use terraphim_agent::repl::commands::{
ConfigSubcommand, ReplCommand, RobotSubcommand, RoleSubcommand, UpdateSubcommand,
};
#[test]
fn test_repl_command_parsing() {
let cmd: Result<ReplCommand, _> = "/help".parse();
assert!(matches!(cmd, Ok(ReplCommand::Help { .. })));
let cmd: Result<ReplCommand, _> = "/quit".parse();
assert!(matches!(cmd, Ok(ReplCommand::Quit)));
let cmd: Result<ReplCommand, _> = "/exit".parse();
assert!(matches!(cmd, Ok(ReplCommand::Exit)));
let cmd: Result<ReplCommand, _> = "/search rust programming".parse();
assert!(matches!(cmd, Ok(ReplCommand::Search { .. })));
let cmd: Result<ReplCommand, _> = "".parse();
assert!(cmd.is_err());
}
#[test]
fn test_repl_available_commands() {
let commands = ReplCommand::available_commands();
assert!(!commands.is_empty());
let has_search = commands.contains(&"search");
let has_config = commands.contains(&"config");
let has_role = commands.contains(&"role");
let has_help = commands.contains(&"help");
let has_quit = commands.contains(&"quit");
assert!(has_search, "should have search command");
assert!(has_config, "should have config command");
assert!(has_role, "should have role command");
assert!(has_help, "should have help command");
assert!(has_quit, "should have quit command");
}
#[test]
fn test_repl_search_command_parsing() {
let cmd: Result<ReplCommand, _> = "/search test query".parse();
match cmd {
Ok(ReplCommand::Search { query, .. }) => {
assert_eq!(query, "test query");
}
_ => panic!("Expected Search command"),
}
}
#[test]
fn test_repl_search_with_options() {
let cmd: Result<ReplCommand, _> = "/search rust --role engineer --limit 10".parse();
match cmd {
Ok(ReplCommand::Search {
query, role, limit, ..
}) => {
assert_eq!(query, "rust");
assert_eq!(role, Some("engineer".to_string()));
assert_eq!(limit, Some(10));
}
_ => panic!("Expected Search command with options"),
}
}
#[test]
fn test_repl_role_command_parsing() {
let cmd: Result<ReplCommand, _> = "/role list".parse();
match cmd {
Ok(ReplCommand::Role { subcommand }) => {
assert!(matches!(subcommand, RoleSubcommand::List));
}
_ => panic!("Expected Role command with List subcommand"),
}
let cmd: Result<ReplCommand, _> = "/role select terraphim-engineer".parse();
match cmd {
Ok(ReplCommand::Role { subcommand }) => match subcommand {
RoleSubcommand::Select { name } => {
assert_eq!(name, "terraphim-engineer");
}
_ => panic!("Expected Select subcommand"),
},
_ => panic!("Expected Role command with Select subcommand"),
}
}
#[test]
fn test_repl_config_command_parsing() {
let cmd: Result<ReplCommand, _> = "/config show".parse();
match cmd {
Ok(ReplCommand::Config { subcommand }) => {
assert!(matches!(subcommand, ConfigSubcommand::Show));
}
_ => panic!("Expected Config command with Show subcommand"),
}
let cmd: Result<ReplCommand, _> = "/config set selected_role terraphim-engineer".parse();
match cmd {
Ok(ReplCommand::Config { subcommand }) => match subcommand {
ConfigSubcommand::Set { key, value } => {
assert_eq!(key, "selected_role");
assert_eq!(value, "terraphim-engineer");
}
_ => panic!("Expected Set subcommand"),
},
_ => panic!("Expected Config command with Set subcommand"),
}
}
#[test]
fn test_repl_graph_command_parsing() {
let cmd: Result<ReplCommand, _> = "/graph --top-k 20".parse();
match cmd {
Ok(ReplCommand::Graph { top_k }) => {
assert_eq!(top_k, Some(20));
}
_ => panic!("Expected Graph command"),
}
}
#[test]
fn test_repl_help_command() {
let cmd: Result<ReplCommand, _> = "/help".parse();
match cmd {
Ok(ReplCommand::Help { command }) => {
assert!(command.is_none());
}
_ => panic!("Expected Help command"),
}
let cmd: Result<ReplCommand, _> = "/help search".parse();
match cmd {
Ok(ReplCommand::Help { command }) => {
assert_eq!(command, Some("search".to_string()));
}
_ => panic!("Expected Help command with search argument"),
}
}
#[tokio::test]
async fn test_repl_handler_offline_mode() {
use terraphim_agent::repl::handler::ReplHandler;
use terraphim_agent::service::TuiService;
match TuiService::new(None).await {
Ok(service) => {
let _handler = ReplHandler::new_offline(service);
}
Err(_) => {
}
}
}
#[tokio::test]
async fn test_repl_handler_server_mode() {
use terraphim_agent::client::ApiClient;
use terraphim_agent::repl::handler::ReplHandler;
let api_client = ApiClient::new("http://localhost:8000".to_string());
let _handler = ReplHandler::new_server(api_client);
}
#[test]
fn test_repl_command_edge_cases() {
let cmd: Result<ReplCommand, _> = "/search multiple spaces ".parse();
assert!(cmd.is_ok());
let cmd: Result<ReplCommand, _> = "/search rust&cargo".parse();
assert!(cmd.is_ok());
let cmd: Result<ReplCommand, _> = "/unknowncommand".parse();
assert!(cmd.is_err());
let cmd: Result<ReplCommand, _> = "search test".parse();
assert!(matches!(cmd, Ok(ReplCommand::Search { .. })));
}
#[test]
fn test_tui_render_search_view() {
use ratatui::Terminal;
use ratatui::backend::TestBackend;
let backend = TestBackend::new(80, 24);
let mut terminal = Terminal::new(backend).unwrap();
terminal
.draw(|f| {
use ratatui::layout::{Constraint, Direction, Layout};
use ratatui::text::Line;
use ratatui::widgets::{Block, Borders, List, ListItem, Paragraph};
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(3),
Constraint::Length(5),
Constraint::Min(3),
Constraint::Length(3),
])
.split(f.area());
let input = Paragraph::new(Line::from("test query"))
.block(Block::default().title("Search").borders(Borders::ALL));
f.render_widget(input, chunks[0]);
let items: Vec<ListItem> = vec![ListItem::new("Result 1"), ListItem::new("Result 2")];
let list =
List::new(items).block(Block::default().title("Results").borders(Borders::ALL));
f.render_widget(list, chunks[2]);
})
.unwrap();
let buffer = terminal.backend().buffer();
assert!(!buffer.content.is_empty());
let buffer_text: String = buffer.content.iter().map(|c| c.symbol()).collect();
assert!(buffer_text.contains("Search"));
assert!(buffer_text.contains("Results"));
}
#[test]
fn test_tui_render_detail_view() {
use ratatui::Terminal;
use ratatui::backend::TestBackend;
use terraphim_types::Document;
let backend = TestBackend::new(80, 24);
let mut terminal = Terminal::new(backend).unwrap();
let doc = Document {
id: "test-doc-1".to_string(),
title: "Test Document Title".to_string(),
url: "https://example.com/test".to_string(),
body: "This is the body of the test document. It contains content.".to_string(),
description: None,
summarization: None,
stub: None,
rank: Some(1),
tags: None,
source_haystack: None,
doc_type: terraphim_types::DocumentType::Document,
synonyms: None,
route: None,
priority: None,
};
terminal
.draw(|f| {
use ratatui::layout::{Constraint, Direction, Layout};
use ratatui::text::Line;
use ratatui::widgets::{Block, Borders, Paragraph};
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(3),
Constraint::Min(5),
Constraint::Length(3),
])
.split(f.area());
let title = Paragraph::new(Line::from(doc.title.as_str()))
.block(Block::default().title("Document").borders(Borders::ALL));
f.render_widget(title, chunks[0]);
let body = Paragraph::new(doc.body.as_str())
.block(Block::default().title("Content").borders(Borders::ALL));
f.render_widget(body, chunks[1]);
})
.unwrap();
let buffer = terminal.backend().buffer();
let buffer_text: String = buffer.content.iter().map(|c| c.symbol()).collect();
assert!(buffer_text.contains("Test Document Title"));
assert!(buffer_text.contains("This is the body"));
}
#[test]
fn test_tui_render_with_suggestions() {
use ratatui::Terminal;
use ratatui::backend::TestBackend;
let backend = TestBackend::new(80, 24);
let mut terminal = Terminal::new(backend).unwrap();
let suggestions = ["rust".to_string(), "react".to_string(), "ruby".to_string()];
terminal
.draw(|f| {
use ratatui::layout::{Constraint, Direction, Layout};
use ratatui::widgets::{Block, Borders, List, ListItem};
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Length(5), Constraint::Min(3)])
.split(f.area());
let items: Vec<ListItem> = suggestions
.iter()
.map(|s| ListItem::new(s.as_str()))
.collect();
let list =
List::new(items).block(Block::default().title("Suggestions").borders(Borders::ALL));
f.render_widget(list, chunks[0]);
})
.unwrap();
let buffer = terminal.backend().buffer();
let buffer_text: String = buffer.content.iter().map(|c| c.symbol()).collect();
assert!(buffer_text.contains("Suggestions"));
assert!(buffer_text.contains("rust"));
assert!(buffer_text.contains("react"));
assert!(buffer_text.contains("ruby"));
}
#[test]
fn test_tui_render_small_terminal() {
use ratatui::Terminal;
use ratatui::backend::TestBackend;
let backend = TestBackend::new(20, 10);
let mut terminal = Terminal::new(backend).unwrap();
terminal
.draw(|f| {
use ratatui::layout::{Constraint, Direction, Layout};
use ratatui::text::Line;
use ratatui::widgets::{Block, Borders, Paragraph};
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(1)])
.split(f.area());
let widget =
Paragraph::new(Line::from("Test")).block(Block::default().borders(Borders::ALL));
f.render_widget(widget, chunks[0]);
})
.unwrap();
let buffer = terminal.backend().buffer();
assert!(!buffer.content.is_empty());
}
#[test]
fn test_repl_command_error_handling() {
let invalid_inputs = vec![
"/", "/ ", "/search", "/role", "/config", ];
for input in invalid_inputs {
let result: Result<ReplCommand, _> = input.parse();
assert!(result.is_err(), "'{}' should fail to parse", input);
}
}
#[tokio::test]
async fn test_repl_integration_components() {
let commands = ReplCommand::available_commands();
assert!(!commands.is_empty(), "REPL should have available commands");
let test_inputs = vec![
"/help",
"/quit",
"/search test",
"/config show",
"/role list",
"/graph",
];
for input in test_inputs {
let _result: Result<ReplCommand, _> = input.parse();
}
}
#[test]
fn test_render_empty_results() {
use ratatui::Terminal;
use ratatui::backend::TestBackend;
let backend = TestBackend::new(80, 24);
let mut terminal = Terminal::new(backend).unwrap();
terminal
.draw(|f| {
use ratatui::layout::{Constraint, Direction, Layout};
use ratatui::widgets::{Block, Borders, List};
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(3)])
.split(f.area());
let empty_items: Vec<ratatui::widgets::ListItem> = vec![];
let list = List::new(empty_items)
.block(Block::default().title("No Results").borders(Borders::ALL));
f.render_widget(list, chunks[0]);
})
.unwrap();
let buffer = terminal.backend().buffer();
assert!(!buffer.content.is_empty());
}
#[test]
fn test_render_long_content() {
use ratatui::Terminal;
use ratatui::backend::TestBackend;
let backend = TestBackend::new(80, 24);
let mut terminal = Terminal::new(backend).unwrap();
let long_content = "a".repeat(1000);
terminal
.draw(|f| {
use ratatui::layout::{Constraint, Direction, Layout};
use ratatui::widgets::{Block, Borders, Paragraph, Wrap};
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(5)])
.split(f.area());
let paragraph = Paragraph::new(long_content.as_str())
.block(Block::default().borders(Borders::ALL))
.wrap(Wrap { trim: true });
f.render_widget(paragraph, chunks[0]);
})
.unwrap();
let buffer = terminal.backend().buffer();
assert!(!buffer.content.is_empty());
}
#[test]
fn test_render_with_selection() {
use ratatui::Terminal;
use ratatui::backend::TestBackend;
use ratatui::style::{Modifier, Style};
let backend = TestBackend::new(80, 24);
let mut terminal = Terminal::new(backend).unwrap();
let results = ["Item 1", "Item 2", "Item 3"];
let selected_index = 1;
terminal
.draw(|f| {
use ratatui::layout::{Constraint, Direction, Layout};
use ratatui::widgets::{Block, Borders, List, ListItem};
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(3)])
.split(f.area());
let items: Vec<ListItem> = results
.iter()
.enumerate()
.map(|(i, r)| {
let item = ListItem::new(*r);
if i == selected_index {
item.style(Style::default().add_modifier(Modifier::REVERSED))
} else {
item
}
})
.collect();
let list =
List::new(items).block(Block::default().title("Results").borders(Borders::ALL));
f.render_widget(list, chunks[0]);
})
.unwrap();
let buffer = terminal.backend().buffer();
assert!(!buffer.content.is_empty());
}
#[test]
fn test_render_transparent_background() {
use ratatui::Terminal;
use ratatui::backend::TestBackend;
use ratatui::style::{Color, Style};
let backend = TestBackend::new(80, 24);
let mut terminal = Terminal::new(backend).unwrap();
terminal
.draw(|f| {
use ratatui::layout::{Constraint, Direction, Layout};
use ratatui::text::Line;
use ratatui::widgets::{Block, Borders, Paragraph};
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(3)])
.split(f.area());
let transparent_style = Style::default().bg(Color::Reset);
let widget = Paragraph::new(Line::from("Transparent Test")).block(
Block::default()
.borders(Borders::ALL)
.style(transparent_style),
);
f.render_widget(widget, chunks[0]);
})
.unwrap();
let buffer = terminal.backend().buffer();
assert!(!buffer.content.is_empty());
}
#[test]
fn test_repl_search_with_flags() {
let cmd: Result<ReplCommand, _> = "/search rust programming --semantic --concepts".parse();
match cmd {
Ok(ReplCommand::Search {
query,
semantic,
concepts,
..
}) => {
assert_eq!(query, "rust programming");
assert!(semantic);
assert!(concepts);
}
_ => panic!("Expected Search command with semantic and concepts flags"),
}
}
#[test]
fn test_available_commands_by_feature() {
let commands = ReplCommand::available_commands();
let has_search = commands.contains(&"search");
let has_config = commands.contains(&"config");
let has_role = commands.contains(&"role");
let has_graph = commands.contains(&"graph");
let has_vm = commands.contains(&"vm");
let has_robot = commands.contains(&"robot");
let has_update = commands.contains(&"update");
let has_help = commands.contains(&"help");
let has_quit = commands.contains(&"quit");
let has_exit = commands.contains(&"exit");
let has_clear = commands.contains(&"clear");
assert!(has_search);
assert!(has_config);
assert!(has_role);
assert!(has_graph);
assert!(has_vm);
assert!(has_robot);
assert!(has_update);
assert!(has_help);
assert!(has_quit);
assert!(has_exit);
assert!(has_clear);
}
#[test]
fn test_command_help_retrieval() {
let help = ReplCommand::get_command_help("search");
assert!(help.is_some());
assert!(help.unwrap().contains("Search"));
let help = ReplCommand::get_command_help("quit");
assert!(help.is_some());
let help = ReplCommand::get_command_help("nonexistent");
assert!(help.is_none());
}
#[cfg(feature = "firecracker")]
#[test]
fn test_repl_vm_command_parsing() {
let cmd: Result<ReplCommand, _> = "/vm list".parse();
match cmd {
Ok(ReplCommand::Vm { subcommand }) => {
assert!(matches!(subcommand, VmSubcommand::List));
}
_ => panic!("Expected Vm command with List subcommand"),
}
}
#[test]
fn test_repl_update_command_parsing() {
let cmd: Result<ReplCommand, _> = "/update check".parse();
match cmd {
Ok(ReplCommand::Update { subcommand }) => {
assert!(matches!(subcommand, UpdateSubcommand::Check));
}
_ => panic!("Expected Update command with Check subcommand"),
}
let cmd: Result<ReplCommand, _> = "/update install".parse();
match cmd {
Ok(ReplCommand::Update { subcommand }) => {
assert!(matches!(subcommand, UpdateSubcommand::Install));
}
_ => panic!("Expected Update command with Install subcommand"),
}
}
#[test]
fn test_repl_robot_command_parsing() {
let cmd: Result<ReplCommand, _> = "/robot capabilities".parse();
match cmd {
Ok(ReplCommand::Robot { subcommand }) => {
assert!(matches!(subcommand, RobotSubcommand::Capabilities));
}
_ => panic!("Expected Robot command with Capabilities subcommand"),
}
let cmd: Result<ReplCommand, _> = "/robot schemas search".parse();
match cmd {
Ok(ReplCommand::Robot { subcommand }) => match subcommand {
RobotSubcommand::Schemas { command } => {
assert_eq!(command, Some("search".to_string()));
}
_ => panic!("Expected Schemas subcommand"),
},
_ => panic!("Expected Robot command with Schemas subcommand"),
}
}
#[test]
fn test_repl_complex_search_query() {
let cmd: Result<ReplCommand, _> =
"/search rust async programming --role engineer --limit 50 --semantic".parse();
match cmd {
Ok(ReplCommand::Search {
query,
role,
limit,
semantic,
concepts,
}) => {
assert_eq!(query, "rust async programming");
assert_eq!(role, Some("engineer".to_string()));
assert_eq!(limit, Some(50));
assert!(semantic);
assert!(!concepts);
}
_ => panic!("Expected complex Search command"),
}
}
#[test]
fn test_repl_search_query_order() {
let cmd: Result<ReplCommand, _> = "/search first second third".parse();
match cmd {
Ok(ReplCommand::Search { query, .. }) => {
assert_eq!(query, "first second third");
}
_ => panic!("Expected Search command with ordered query"),
}
}
#[test]
fn test_repl_command_case_sensitivity() {
let cmd: Result<ReplCommand, _> = "/SEARCH test".parse();
assert!(cmd.is_err());
let cmd: Result<ReplCommand, _> = "/Search test".parse();
assert!(cmd.is_err());
let cmd: Result<ReplCommand, _> = "/search TestQuery".parse();
match cmd {
Ok(ReplCommand::Search { query, .. }) => {
assert_eq!(query, "TestQuery");
}
_ => panic!("Expected Search command with case-preserved query"),
}
}