use browsing::error::BrowsingError;
#[test]
fn test_navigation_handler_search_action_type() {
let action_type = "search";
assert_eq!(action_type, "search");
}
#[test]
fn test_navigation_handler_navigate_action_type() {
let action_type = "navigate";
assert_eq!(action_type, "navigate");
}
#[test]
fn test_search_engine_duckduckgo() {
let engine = "duckduckgo";
let query = "test query";
let encoded_query = urlencoding::encode(query);
let search_url = format!("https://duckduckgo.com/?q={encoded_query}");
assert_eq!(search_url, "https://duckduckgo.com/?q=test%20query");
assert!(search_url.contains("duckduckgo.com"));
}
#[test]
fn test_search_engine_google() {
let engine = "google";
let query = "rust programming";
let encoded_query = urlencoding::encode(query);
let search_url = format!("https://www.google.com/search?q={encoded_query}&udm=14");
assert!(search_url.contains("google.com/search"));
assert!(search_url.contains("q=rust%20programming"));
}
#[test]
fn test_search_engine_bing() {
let engine = "bing";
let query = "browser automation";
let encoded_query = urlencoding::encode(query);
let search_url = format!("https://www.bing.com/search?q={encoded_query}");
assert!(search_url.contains("bing.com/search"));
assert!(search_url.contains("q=browser%20automation"));
}
#[test]
fn test_url_encoding() {
let query = "hello world & test";
let encoded = urlencoding::encode(query);
let encoded_str = encoded.to_string();
assert_eq!(encoded_str, "hello%20world%20%26%20test");
assert!(!encoded_str.contains(" "));
assert!(!encoded_str.contains("&"));
}
#[test]
fn test_navigate_url_validation() {
let valid_urls = vec![
"https://example.com",
"http://localhost:8080",
"https://www.google.com/search?q=test",
];
for url in valid_urls {
assert!(url.starts_with("http://") || url.starts_with("https://"));
assert!(url.len() > 10);
}
}
#[test]
fn test_navigate_new_tab_flag() {
let new_tab = true;
assert!(new_tab, "Should create new tab");
let new_tab = false;
assert!(!new_tab, "Should navigate in current tab");
}
#[test]
fn test_interaction_handler_click_action_type() {
let action_type = "click";
assert_eq!(action_type, "click");
}
#[test]
fn test_interaction_handler_input_action_type() {
let action_type = "input";
assert_eq!(action_type, "input");
}
#[test]
fn test_interaction_handler_send_keys_action_type() {
let action_type = "send_keys";
assert_eq!(action_type, "send_keys");
}
#[test]
fn test_element_index_validation() {
let valid_indices = vec![0u32, 1, 10, 100, 999999];
for index in valid_indices {
assert!(index < u32::MAX, "Index should be valid");
}
}
#[test]
fn test_input_text_validation() {
let valid_texts = vec![
"Hello, World!",
"test@example.com",
"12345",
"Special chars: !@#$%^&*()",
"Unicode: 你好世界 🌍",
];
for text in valid_texts {
assert!(!text.is_empty(), "Input text should not be empty");
}
}
#[test]
fn test_key_sequence_parsing() {
let key_sequences = vec![
"Enter",
"Escape",
"Control+A",
"Shift+End",
"Control+C Control+V",
];
for sequence in key_sequences {
let keys: Vec<&str> = sequence.split_whitespace().collect();
assert!(!keys.is_empty(), "Key sequence should not be empty");
}
}
#[test]
fn test_backend_node_id_validation() {
let valid_ids = vec![1u32, 100, 1000, 999999];
for id in valid_ids {
assert!(id > 0, "Backend node ID should be positive");
}
}
#[test]
fn test_content_handler_scroll_action_type() {
let action_type = "scroll";
assert_eq!(action_type, "scroll");
}
#[test]
fn test_content_handler_find_text_action_type() {
let action_type = "find_text";
assert_eq!(action_type, "find_text");
}
#[test]
fn test_content_handler_dropdown_options_action_type() {
let action_type = "dropdown_options";
assert_eq!(action_type, "dropdown_options");
}
#[test]
fn test_content_handler_select_dropdown_action_type() {
let action_type = "select_dropdown";
assert_eq!(action_type, "select_dropdown");
}
#[test]
fn test_scroll_direction_validation() {
let down = true;
assert!(down, "Should scroll down");
let down = false;
assert!(!down, "Should scroll up");
}
#[test]
fn test_scroll_pages_validation() {
let valid_pages = vec![0.5f64, 1.0, 2.0, 3.5, 10.0];
for pages in valid_pages {
assert!(pages > 0.0, "Scroll pages should be positive");
assert!(pages <= 100.0, "Scroll pages should be reasonable");
}
}
#[test]
fn test_scroll_delta_calculation() {
let viewport_height = 1000.0f64;
let pages = 2.0f64;
let delta_down = pages * viewport_height; let delta_up = -pages * viewport_height;
assert_eq!(delta_down, 2000.0);
assert_eq!(delta_up, -2000.0);
}
#[test]
fn test_find_text_validation() {
let valid_texts = vec![
"Search term",
"123",
"Special & chars",
"Unicode text",
"Single word",
];
for text in valid_texts {
assert!(!text.is_empty(), "Search text should not be empty");
}
}
#[test]
fn test_dropdown_option_format() {
let option_value = "option1";
let option_text = "Option 1";
let option_selected = true;
assert_eq!(option_value, "option1");
assert_eq!(option_text, "Option 1");
assert!(option_selected);
}
#[test]
fn test_select_dropdown_validation() {
let valid_selections = vec!["Option 1", "option1", "First option", "value", "Any text"];
for selection in valid_selections {
assert!(
!selection.is_empty(),
"Dropdown selection should not be empty"
);
}
}
#[test]
fn test_tabs_handler_create_tab_action_type() {
let action_type = "create_tab";
assert_eq!(action_type, "create_tab");
}
#[test]
fn test_tabs_handler_switch_tab_action_type() {
let action_type = "switch_tab";
assert_eq!(action_type, "switch_tab");
}
#[test]
fn test_tabs_handler_close_tab_action_type() {
let action_type = "close_tab";
assert_eq!(action_type, "close_tab");
}
#[test]
fn test_tab_creation_with_url() {
let url = "https://example.com";
assert!(url.starts_with("https://"));
}
#[test]
fn test_tab_creation_blank_url() {
let url = "about:blank";
assert_eq!(url, "about:blank");
}
#[test]
fn test_target_id_format() {
let target_id = "E12BA567-8A90-1234-5678-9ABCDEF01234";
assert_eq!(target_id.len(), 36);
assert!(target_id.contains('-'));
}
#[test]
fn test_extract_content_action_type() {
let action_type = "extract_content";
assert_eq!(action_type, "extract_content");
}
#[test]
fn test_extract_links_action_type() {
let action_type = "extract_links";
assert_eq!(action_type, "extract_links");
}
#[test]
fn test_extract_images_action_type() {
let action_type = "extract_images";
assert_eq!(action_type, "extract_images");
}
#[test]
fn test_wait_action_type() {
let action_type = "wait";
assert_eq!(action_type, "wait");
}
#[test]
fn test_wait_duration_validation() {
let valid_durations = vec![100u64, 500, 1000, 5000, 10000];
for duration in valid_durations {
assert!(duration >= 100, "Wait duration should be at least 100ms");
assert!(
duration <= 60000,
"Wait duration should not exceed 60 seconds"
);
}
}
#[test]
fn test_action_result_default() {
use browsing::agent::views::ActionResult;
let result = ActionResult::default();
assert!(result.extracted_content.is_none_or(|s| s.is_empty()));
assert!(result.long_term_memory.is_none_or(|s| s.is_empty()));
}
#[test]
fn test_action_result_with_content() {
use browsing::agent::views::ActionResult;
let result = ActionResult {
extracted_content: Some("Test content".to_string()),
long_term_memory: Some("Test memory".to_string()),
..Default::default()
};
assert_eq!(result.extracted_content, Some("Test content".to_string()));
assert_eq!(result.long_term_memory, Some("Test memory".to_string()));
}
#[test]
fn test_action_result_memory_format() {
let memories = vec![
"Navigated to https://example.com",
"Clicked element 1 (backend_node_id: 123)",
"Input text into element 5 (backend_node_id: 456)",
"Scrolled down 1 pages",
"Searched duckduckgo for 'test query'",
];
for memory in memories {
assert!(!memory.is_empty(), "Memory should not be empty");
assert!(memory.len() <= 512, "Memory should be reasonable length");
}
}
#[test]
fn test_action_params_get_required_str() {
let test_data = vec![
("url", "https://example.com"),
("query", "test query"),
("text", "input text"),
("engine", "google"),
];
for (key, value) in test_data {
assert!(!key.is_empty(), "Parameter key should not be empty");
assert!(!value.is_empty(), "Parameter value should not be empty");
}
}
#[test]
fn test_action_params_get_required_u32() {
let test_data = vec![("index", 1u32), ("count", 5u32), ("timeout", 10000u32)];
for (key, value) in test_data {
assert!(!key.is_empty(), "Parameter key should not be empty");
assert!(value > 0, "Parameter value should be positive");
}
}
#[test]
fn test_action_params_get_optional_bool() {
let test_cases = vec![
("new_tab", Some(true)),
("down", Some(false)),
("full_page", Some(true)),
("optional", None),
];
for (key, value) in test_cases {
assert!(!key.is_empty(), "Parameter key should not be empty");
assert!(
value.is_some() || value.is_none(),
"Parameter should be optional"
);
}
}
#[test]
fn test_action_params_get_optional_f64() {
let test_cases = vec![
("pages", Some(1.0f64)),
("quality", Some(85.0)),
("delay", Some(500.0)),
("optional", None),
];
for (key, value) in test_cases {
assert!(!key.is_empty(), "Parameter key should not be empty");
if let Some(v) = value {
assert!(v >= 0.0, "Optional f64 should be non-negative");
}
}
}
#[test]
fn test_selector_map_structure() {
use browsing::dom::views::DOMInteractedElement;
use std::collections::HashMap;
let entry = DOMInteractedElement {
index: 1,
backend_node_id: Some(123),
tag: "button".to_string(),
text: Some("Click me".to_string()),
attributes: HashMap::new(),
selector: None,
};
assert_eq!(entry.index, 1);
assert_eq!(entry.backend_node_id, Some(123));
assert_eq!(entry.tag, "button");
assert_eq!(entry.text, Some("Click me".to_string()));
}
#[test]
fn test_selector_map_validation() {
use browsing::dom::views::DOMInteractedElement;
use std::collections::HashMap;
let entries = vec![
DOMInteractedElement {
index: 0,
backend_node_id: Some(100),
tag: "input".to_string(),
text: Some("text".to_string()),
attributes: HashMap::new(),
selector: None,
},
DOMInteractedElement {
index: 1,
backend_node_id: Some(101),
tag: "button".to_string(),
text: Some("Submit".to_string()),
attributes: HashMap::new(),
selector: None,
},
];
assert_eq!(entries.len(), 2);
assert_eq!(entries[0].index, 0);
assert_eq!(entries[1].index, 1);
}
#[test]
fn test_tool_error_creation() {
let error = BrowsingError::Tool("Test tool error".to_string());
assert!(matches!(error, BrowsingError::Tool(_)));
}
#[test]
fn test_element_not_found_error() {
let index = 999u32;
let error = BrowsingError::Tool(format!("Element index {} not found", index));
assert!(matches!(error, BrowsingError::Tool(_)));
if let BrowsingError::Tool(msg) = error {
assert!(msg.contains("not found"));
assert!(msg.contains("999"));
}
}
#[test]
fn test_unsupported_search_engine_error() {
let engine = "unknown_engine";
let error = BrowsingError::Tool(format!(
"Unsupported search engine: {}. Options: duckduckgo, google, bing",
engine
));
assert!(matches!(error, BrowsingError::Tool(_)));
if let BrowsingError::Tool(msg) = error {
assert!(msg.contains("Unsupported"));
assert!(msg.contains("unknown_engine"));
}
}
#[test]
fn test_navigation_handler_search() {
let engines = vec!["duckduckgo", "google", "bing"];
let query = "test query";
for engine in engines {
assert!(!engine.is_empty());
assert!(!query.is_empty());
let encoded_query = urlencoding::encode(query);
let search_url = match engine {
"duckduckgo" => format!("https://duckduckgo.com/?q={encoded_query}"),
"google" => format!("https://www.google.com/search?q={encoded_query}&udm=14"),
"bing" => format!("https://www.bing.com/search?q={encoded_query}"),
_ => panic!("Unknown engine"),
};
assert!(search_url.contains(engine));
assert!(search_url.contains("q="));
}
}
#[test]
fn test_navigation_handler_navigate() {
let test_urls = vec![
("https://example.com", true),
("http://localhost:8080", true),
("ftp://example.com", false),
("not-a-url", false),
("", false),
];
for (url, should_be_valid) in test_urls {
let is_valid = url.starts_with("http://") || url.starts_with("https://");
assert_eq!(
is_valid, should_be_valid,
"URL {} validity check failed",
url
);
}
}
#[test]
fn test_interaction_handler_click() {
let element_indices = vec![0u32, 1, 5, 10, 100];
for index in element_indices {
assert!(index >= 0, "Element index must be non-negative");
}
let click_params = vec![(0, Some("left")), (5, Some("right")), (10, Some("middle"))];
for (index, button) in click_params {
assert!(index >= 0);
assert!(button.is_some());
}
}
#[test]
fn test_interaction_handler_input() {
let test_inputs = vec![
("test text", true),
("", false),
("Hello, world!", true),
("special chars: @#$%", true),
];
for (input, should_be_valid) in test_inputs {
let is_valid = !input.is_empty();
assert_eq!(
is_valid, should_be_valid,
"Input '{}' validation failed",
input
);
}
let element_index = 5u32;
let text = "sample text";
assert!(element_index >= 0);
assert!(!text.is_empty());
}
#[test]
fn test_content_handler_scroll() {
let scroll_directions = vec!["up", "down", "left", "right"];
for direction in scroll_directions {
assert!(!direction.is_empty());
assert!(direction.len() <= 10);
}
let scroll_amounts = vec![0, 100, 500, 1000];
for amount in scroll_amounts {
assert!(amount >= 0);
assert!(amount <= 10000);
}
}
#[test]
fn test_content_handler_find_text() {
let search_queries = vec!["example text", "search term", "multiple words"];
for query in search_queries {
assert!(!query.is_empty());
assert!(query.len() > 3);
}
let text = "This is a sample text for testing find functionality";
assert!(text.contains("sample"));
assert!(text.contains("text"));
}
#[test]
fn test_content_handler_dropdown() {
let dropdown_indices = vec![0u32, 1, 2, 5, 10];
for index in dropdown_indices {
assert!(index >= 0);
}
let dropdown_options = vec!["Option 1", "Option 2", "Option 3"];
for option in dropdown_options {
assert!(!option.is_empty());
}
}
#[test]
fn test_tabs_handler_lifecycle() {
let tab_operations = vec!["create", "switch", "close"];
for operation in tab_operations {
assert!(!operation.is_empty());
}
let tab_ids = vec!["CDEB6E0D5C0F4D1A8B9E5C0F4D1A8B9E", "1234567890abcdef"];
for tab_id in tab_ids {
assert!(!tab_id.is_empty());
assert!(tab_id.len() >= 16);
}
}
#[test]
fn test_file_handler_write_file_action_type() {
let action_type = "write_file";
assert_eq!(action_type, "write_file");
}
#[test]
fn test_file_handler_read_file_action_type() {
let action_type = "read_file";
assert_eq!(action_type, "read_file");
}
#[test]
fn test_file_path_validation() {
let valid_paths = vec![
"/tmp/test.txt",
"./output.json",
"data/results.csv",
"report.md",
];
for path in valid_paths {
assert!(!path.is_empty());
assert!(!path.contains(".."));
assert!(!path.contains('~'));
}
}
#[test]
fn test_file_path_traversal_rejection() {
let invalid_paths = vec![
"../etc/passwd",
"../../secret.txt",
"~/config.yml",
"./../escape.txt",
];
for path in invalid_paths {
assert!(path.contains("..") || path.contains('~'));
}
}
#[test]
fn test_navigation_handler_go_back_action_type() {
let action_type = "go_back";
assert_eq!(action_type, "go_back");
}
#[test]
fn test_go_back_action_exists_in_registry() {
let tools = browsing::tools::service::Tools::new(vec![]);
assert!(
tools.registry.registry.actions.contains_key("go_back"),
"go_back action should be registered"
);
}
#[test]
fn test_file_actions_exist_in_registry() {
let tools = browsing::tools::service::Tools::new(vec![]);
assert!(
tools.registry.registry.actions.contains_key("write_file"),
"write_file action should be registered"
);
assert!(
tools.registry.registry.actions.contains_key("read_file"),
"read_file action should be registered"
);
assert!(
tools.registry.registry.actions.contains_key("replace_file"),
"replace_file action should be registered"
);
}
#[test]
fn test_navigation_handler_go_forward_action_type() {
let action_type = "go_forward";
assert_eq!(action_type, "go_forward");
}
#[test]
fn test_navigation_handler_reload_action_type() {
let action_type = "reload";
assert_eq!(action_type, "reload");
}
#[test]
fn test_go_forward_and_reload_actions_exist_in_registry() {
let tools = browsing::tools::service::Tools::new(vec![]);
assert!(
tools.registry.registry.actions.contains_key("go_forward"),
"go_forward action should be registered"
);
assert!(
tools.registry.registry.actions.contains_key("reload"),
"reload action should be registered"
);
}
#[test]
fn test_replace_file_action_type() {
let action_type = "replace_file";
assert_eq!(action_type, "replace_file");
}