From b38574c5885d356b026f5060af51ad02d2fcef21 Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Fri, 26 Dec 2025 08:59:54 -0300 Subject: [PATCH] Update test structure and cleanup deprecated tests --- src/bot/runner.rs | 148 +++--- src/desktop/mod.rs | 44 +- src/harness.rs | 11 +- src/main.rs | 26 +- src/services/postgres.rs | 47 +- src/web/browser.rs | 347 +++++++------ tests/e2e/mod.rs | 5 +- tests/unit/attendance/attendance.rs | 34 -- .../unit/attendance/attendance_llm_assist.rs | 93 ---- tests/unit/attendance/mod.rs | 3 - .../basic/basic_compiler_goto_transform.rs | 147 ------ .../unit/basic/basic_keywords_a2a_protocol.rs | 125 ----- tests/unit/basic/basic_keywords_add_bot.rs | 77 --- tests/unit/basic/basic_keywords_add_member.rs | 37 -- .../basic/basic_keywords_add_suggestion.rs | 67 --- .../basic/basic_keywords_agent_reflection.rs | 114 ---- tests/unit/basic/basic_keywords_arrays.rs | 56 -- .../basic/basic_keywords_arrays_contains.rs | 92 ---- .../basic/basic_keywords_arrays_push_pop.rs | 62 --- .../unit/basic/basic_keywords_arrays_slice.rs | 81 --- .../unit/basic/basic_keywords_arrays_sort.rs | 73 --- .../basic/basic_keywords_arrays_unique.rs | 108 ---- tests/unit/basic/basic_keywords_book.rs | 46 -- tests/unit/basic/basic_keywords_card.rs | 41 -- tests/unit/basic/basic_keywords_clear_kb.rs | 28 - .../unit/basic/basic_keywords_code_sandbox.rs | 81 --- .../basic/basic_keywords_core_functions.rs | 17 - .../unit/basic/basic_keywords_create_task.rs | 31 -- .../basic/basic_keywords_crm_attendance.rs | 120 ----- .../basic/basic_keywords_crm_score_lead.rs | 69 --- .../basic/basic_keywords_data_operations.rs | 52 -- .../basic/basic_keywords_datetime_dateadd.rs | 61 --- .../basic/basic_keywords_datetime_extract.rs | 39 -- .../unit/basic/basic_keywords_datetime_now.rs | 71 --- .../basic/basic_keywords_episodic_memory.rs | 114 ---- tests/unit/basic/basic_keywords_errors.rs | 25 - .../basic/basic_keywords_errors_on_error.rs | 74 --- .../unit/basic/basic_keywords_errors_throw.rs | 16 - .../basic/basic_keywords_file_operations.rs | 29 -- tests/unit/basic/basic_keywords_hear_talk.rs | 88 ---- .../basic/basic_keywords_http_operations.rs | 48 -- .../basic/basic_keywords_human_approval.rs | 148 ------ .../basic/basic_keywords_import_export.rs | 53 -- .../basic/basic_keywords_kb_statistics.rs | 50 -- .../basic/basic_keywords_knowledge_graph.rs | 110 ---- .../unit/basic/basic_keywords_lead_scoring.rs | 17 - tests/unit/basic/basic_keywords_llm_macros.rs | 40 -- tests/unit/basic/basic_keywords_math_abs.rs | 32 -- .../basic/basic_keywords_math_aggregate.rs | 47 -- .../basic/basic_keywords_math_basic_math.rs | 62 --- .../unit/basic/basic_keywords_math_minmax.rs | 24 - .../unit/basic/basic_keywords_math_random.rs | 17 - tests/unit/basic/basic_keywords_math_round.rs | 28 - tests/unit/basic/basic_keywords_math_trig.rs | 44 -- .../basic/basic_keywords_mcp_directory.rs | 56 -- .../basic_keywords_messaging_send_template.rs | 89 ---- .../basic/basic_keywords_model_routing.rs | 92 ---- tests/unit/basic/basic_keywords_on_change.rs | 208 -------- tests/unit/basic/basic_keywords_on_email.rs | 198 ------- tests/unit/basic/basic_keywords_play.rs | 94 ---- tests/unit/basic/basic_keywords_procedures.rs | 181 ------- tests/unit/basic/basic_keywords_qrcode.rs | 52 -- tests/unit/basic/basic_keywords_remember.rs | 19 - .../basic_keywords_save_from_unstructured.rs | 28 - tests/unit/basic/basic_keywords_send_mail.rs | 31 -- .../basic/basic_keywords_send_template.rs | 17 - .../unit/basic/basic_keywords_set_schedule.rs | 164 ------ tests/unit/basic/basic_keywords_sms.rs | 57 -- .../basic_keywords_social_get_metrics.rs | 24 - .../unit/basic/basic_keywords_social_media.rs | 17 - ...basic_keywords_social_post_to_scheduled.rs | 21 - .../basic/basic_keywords_string_functions.rs | 71 --- .../unit/basic/basic_keywords_switch_case.rs | 92 ---- .../basic/basic_keywords_table_definition.rs | 147 ------ .../basic/basic_keywords_transfer_to_human.rs | 99 ---- .../unit/basic/basic_keywords_use_account.rs | 35 -- tests/unit/basic/basic_keywords_use_kb.rs | 23 - .../unit/basic/basic_keywords_use_website.rs | 42 -- .../unit/basic/basic_keywords_user_memory.rs | 16 - .../basic_keywords_validation_isempty.rs | 77 --- .../basic/basic_keywords_validation_isnull.rs | 38 -- .../basic_keywords_validation_nvl_iif.rs | 56 -- .../basic_keywords_validation_str_val.rs | 27 - .../basic_keywords_validation_typeof_check.rs | 33 -- tests/unit/basic/basic_keywords_weather.rs | 44 -- tests/unit/basic/basic_keywords_webhook.rs | 85 --- tests/unit/basic/mod.rs | 77 --- tests/unit/calendar/calendar.rs | 53 -- tests/unit/calendar/mod.rs | 2 - tests/unit/compliance/compliance.rs | 45 -- .../compliance/compliance_code_scanner.rs | 92 ---- tests/unit/compliance/mod.rs | 3 - tests/unit/console/console_wizard.rs | 34 -- tests/unit/console/mod.rs | 2 - tests/unit/core/core_bot_manager.rs | 65 --- .../core/core_config_model_routing_config.rs | 105 ---- tests/unit/core/core_config_sse_config.rs | 53 -- .../core/core_config_user_memory_config.rs | 79 --- tests/unit/core/core_kb.rs | 28 - tests/unit/core/core_kb_document_processor.rs | 70 --- .../unit/core/core_kb_embedding_generator.rs | 30 -- tests/unit/core/core_kb_kb_indexer.rs | 52 -- tests/unit/core/core_oauth.rs | 57 -- tests/unit/core/core_oauth_providers.rs | 69 --- tests/unit/core/core_package_manager_cache.rs | 199 ------- ...e_package_manager_setup_directory_setup.rs | 18 - .../core_package_manager_setup_email_setup.rs | 33 -- tests/unit/core/core_rate_limit.rs | 49 -- tests/unit/core/core_secrets.rs | 75 --- tests/unit/core/core_shared_models.rs | 35 -- tests/unit/core/core_shared_state.rs | 63 --- tests/unit/core/core_shared_test_utils.rs | 70 --- tests/unit/core/core_urls.rs | 34 -- tests/unit/core/mod.rs | 20 - tests/unit/drive/drive_vectordb.rs | 52 -- tests/unit/drive/mod.rs | 2 - tests/unit/email/email_stalwart_client.rs | 141 ----- tests/unit/email/email_stalwart_sync.rs | 99 ---- tests/unit/email/email_vectordb.rs | 37 -- tests/unit/email/mod.rs | 4 - tests/unit/llm/llm_cache_test.rs | 342 ------------ tests/unit/llm/llm_observability.rs | 130 ----- tests/unit/llm/mod.rs | 3 - tests/unit/math_functions.rs | 490 ------------------ tests/unit/mod.rs | 22 +- tests/unit/security/mod.rs | 8 - tests/unit/security/security.rs | 43 -- tests/unit/security/security_antivirus.rs | 58 --- tests/unit/security/security_ca.rs | 31 -- tests/unit/security/security_cert_pinning.rs | 128 ----- tests/unit/security/security_integration.rs | 75 --- tests/unit/security/security_mutual_tls.rs | 78 --- tests/unit/security/security_tls.rs | 49 -- tests/unit/sources/mod.rs | 2 - tests/unit/sources/sources_mcp.rs | 36 -- tests/unit/string_functions.rs | 374 ------------- tests/unit/timeseries/mod.rs | 2 - tests/unit/timeseries/timeseries.rs | 53 -- tests/unit/vector_db/mod.rs | 4 - tests/unit/vector_db/vector_db_bm25_config.rs | 129 ----- .../unit/vector_db/vector_db_hybrid_search.rs | 152 ------ .../vector_db/vector_db_vectordb_indexer.rs | 24 - tests/unit/weba/mod.rs | 2 - tests/unit/weba/weba.rs | 39 -- tests/unit/whatsapp/mod.rs | 2 - tests/unit/whatsapp/whatsapp.rs | 62 --- 146 files changed, 332 insertions(+), 9605 deletions(-) delete mode 100644 tests/unit/attendance/attendance.rs delete mode 100644 tests/unit/attendance/attendance_llm_assist.rs delete mode 100644 tests/unit/attendance/mod.rs delete mode 100644 tests/unit/basic/basic_compiler_goto_transform.rs delete mode 100644 tests/unit/basic/basic_keywords_a2a_protocol.rs delete mode 100644 tests/unit/basic/basic_keywords_add_bot.rs delete mode 100644 tests/unit/basic/basic_keywords_add_member.rs delete mode 100644 tests/unit/basic/basic_keywords_add_suggestion.rs delete mode 100644 tests/unit/basic/basic_keywords_agent_reflection.rs delete mode 100644 tests/unit/basic/basic_keywords_arrays.rs delete mode 100644 tests/unit/basic/basic_keywords_arrays_contains.rs delete mode 100644 tests/unit/basic/basic_keywords_arrays_push_pop.rs delete mode 100644 tests/unit/basic/basic_keywords_arrays_slice.rs delete mode 100644 tests/unit/basic/basic_keywords_arrays_sort.rs delete mode 100644 tests/unit/basic/basic_keywords_arrays_unique.rs delete mode 100644 tests/unit/basic/basic_keywords_book.rs delete mode 100644 tests/unit/basic/basic_keywords_card.rs delete mode 100644 tests/unit/basic/basic_keywords_clear_kb.rs delete mode 100644 tests/unit/basic/basic_keywords_code_sandbox.rs delete mode 100644 tests/unit/basic/basic_keywords_core_functions.rs delete mode 100644 tests/unit/basic/basic_keywords_create_task.rs delete mode 100644 tests/unit/basic/basic_keywords_crm_attendance.rs delete mode 100644 tests/unit/basic/basic_keywords_crm_score_lead.rs delete mode 100644 tests/unit/basic/basic_keywords_data_operations.rs delete mode 100644 tests/unit/basic/basic_keywords_datetime_dateadd.rs delete mode 100644 tests/unit/basic/basic_keywords_datetime_extract.rs delete mode 100644 tests/unit/basic/basic_keywords_datetime_now.rs delete mode 100644 tests/unit/basic/basic_keywords_episodic_memory.rs delete mode 100644 tests/unit/basic/basic_keywords_errors.rs delete mode 100644 tests/unit/basic/basic_keywords_errors_on_error.rs delete mode 100644 tests/unit/basic/basic_keywords_errors_throw.rs delete mode 100644 tests/unit/basic/basic_keywords_file_operations.rs delete mode 100644 tests/unit/basic/basic_keywords_hear_talk.rs delete mode 100644 tests/unit/basic/basic_keywords_http_operations.rs delete mode 100644 tests/unit/basic/basic_keywords_human_approval.rs delete mode 100644 tests/unit/basic/basic_keywords_import_export.rs delete mode 100644 tests/unit/basic/basic_keywords_kb_statistics.rs delete mode 100644 tests/unit/basic/basic_keywords_knowledge_graph.rs delete mode 100644 tests/unit/basic/basic_keywords_lead_scoring.rs delete mode 100644 tests/unit/basic/basic_keywords_llm_macros.rs delete mode 100644 tests/unit/basic/basic_keywords_math_abs.rs delete mode 100644 tests/unit/basic/basic_keywords_math_aggregate.rs delete mode 100644 tests/unit/basic/basic_keywords_math_basic_math.rs delete mode 100644 tests/unit/basic/basic_keywords_math_minmax.rs delete mode 100644 tests/unit/basic/basic_keywords_math_random.rs delete mode 100644 tests/unit/basic/basic_keywords_math_round.rs delete mode 100644 tests/unit/basic/basic_keywords_math_trig.rs delete mode 100644 tests/unit/basic/basic_keywords_mcp_directory.rs delete mode 100644 tests/unit/basic/basic_keywords_messaging_send_template.rs delete mode 100644 tests/unit/basic/basic_keywords_model_routing.rs delete mode 100644 tests/unit/basic/basic_keywords_on_change.rs delete mode 100644 tests/unit/basic/basic_keywords_on_email.rs delete mode 100644 tests/unit/basic/basic_keywords_play.rs delete mode 100644 tests/unit/basic/basic_keywords_procedures.rs delete mode 100644 tests/unit/basic/basic_keywords_qrcode.rs delete mode 100644 tests/unit/basic/basic_keywords_remember.rs delete mode 100644 tests/unit/basic/basic_keywords_save_from_unstructured.rs delete mode 100644 tests/unit/basic/basic_keywords_send_mail.rs delete mode 100644 tests/unit/basic/basic_keywords_send_template.rs delete mode 100644 tests/unit/basic/basic_keywords_set_schedule.rs delete mode 100644 tests/unit/basic/basic_keywords_sms.rs delete mode 100644 tests/unit/basic/basic_keywords_social_get_metrics.rs delete mode 100644 tests/unit/basic/basic_keywords_social_media.rs delete mode 100644 tests/unit/basic/basic_keywords_social_post_to_scheduled.rs delete mode 100644 tests/unit/basic/basic_keywords_string_functions.rs delete mode 100644 tests/unit/basic/basic_keywords_switch_case.rs delete mode 100644 tests/unit/basic/basic_keywords_table_definition.rs delete mode 100644 tests/unit/basic/basic_keywords_transfer_to_human.rs delete mode 100644 tests/unit/basic/basic_keywords_use_account.rs delete mode 100644 tests/unit/basic/basic_keywords_use_kb.rs delete mode 100644 tests/unit/basic/basic_keywords_use_website.rs delete mode 100644 tests/unit/basic/basic_keywords_user_memory.rs delete mode 100644 tests/unit/basic/basic_keywords_validation_isempty.rs delete mode 100644 tests/unit/basic/basic_keywords_validation_isnull.rs delete mode 100644 tests/unit/basic/basic_keywords_validation_nvl_iif.rs delete mode 100644 tests/unit/basic/basic_keywords_validation_str_val.rs delete mode 100644 tests/unit/basic/basic_keywords_validation_typeof_check.rs delete mode 100644 tests/unit/basic/basic_keywords_weather.rs delete mode 100644 tests/unit/basic/basic_keywords_webhook.rs delete mode 100644 tests/unit/basic/mod.rs delete mode 100644 tests/unit/calendar/calendar.rs delete mode 100644 tests/unit/calendar/mod.rs delete mode 100644 tests/unit/compliance/compliance.rs delete mode 100644 tests/unit/compliance/compliance_code_scanner.rs delete mode 100644 tests/unit/compliance/mod.rs delete mode 100644 tests/unit/console/console_wizard.rs delete mode 100644 tests/unit/console/mod.rs delete mode 100644 tests/unit/core/core_bot_manager.rs delete mode 100644 tests/unit/core/core_config_model_routing_config.rs delete mode 100644 tests/unit/core/core_config_sse_config.rs delete mode 100644 tests/unit/core/core_config_user_memory_config.rs delete mode 100644 tests/unit/core/core_kb.rs delete mode 100644 tests/unit/core/core_kb_document_processor.rs delete mode 100644 tests/unit/core/core_kb_embedding_generator.rs delete mode 100644 tests/unit/core/core_kb_kb_indexer.rs delete mode 100644 tests/unit/core/core_oauth.rs delete mode 100644 tests/unit/core/core_oauth_providers.rs delete mode 100644 tests/unit/core/core_package_manager_cache.rs delete mode 100644 tests/unit/core/core_package_manager_setup_directory_setup.rs delete mode 100644 tests/unit/core/core_package_manager_setup_email_setup.rs delete mode 100644 tests/unit/core/core_rate_limit.rs delete mode 100644 tests/unit/core/core_secrets.rs delete mode 100644 tests/unit/core/core_shared_models.rs delete mode 100644 tests/unit/core/core_shared_state.rs delete mode 100644 tests/unit/core/core_shared_test_utils.rs delete mode 100644 tests/unit/core/core_urls.rs delete mode 100644 tests/unit/core/mod.rs delete mode 100644 tests/unit/drive/drive_vectordb.rs delete mode 100644 tests/unit/drive/mod.rs delete mode 100644 tests/unit/email/email_stalwart_client.rs delete mode 100644 tests/unit/email/email_stalwart_sync.rs delete mode 100644 tests/unit/email/email_vectordb.rs delete mode 100644 tests/unit/email/mod.rs delete mode 100644 tests/unit/llm/llm_cache_test.rs delete mode 100644 tests/unit/llm/llm_observability.rs delete mode 100644 tests/unit/llm/mod.rs delete mode 100644 tests/unit/math_functions.rs delete mode 100644 tests/unit/security/mod.rs delete mode 100644 tests/unit/security/security.rs delete mode 100644 tests/unit/security/security_antivirus.rs delete mode 100644 tests/unit/security/security_ca.rs delete mode 100644 tests/unit/security/security_cert_pinning.rs delete mode 100644 tests/unit/security/security_integration.rs delete mode 100644 tests/unit/security/security_mutual_tls.rs delete mode 100644 tests/unit/security/security_tls.rs delete mode 100644 tests/unit/sources/mod.rs delete mode 100644 tests/unit/sources/sources_mcp.rs delete mode 100644 tests/unit/string_functions.rs delete mode 100644 tests/unit/timeseries/mod.rs delete mode 100644 tests/unit/timeseries/timeseries.rs delete mode 100644 tests/unit/vector_db/mod.rs delete mode 100644 tests/unit/vector_db/vector_db_bm25_config.rs delete mode 100644 tests/unit/vector_db/vector_db_hybrid_search.rs delete mode 100644 tests/unit/vector_db/vector_db_vectordb_indexer.rs delete mode 100644 tests/unit/weba/mod.rs delete mode 100644 tests/unit/weba/weba.rs delete mode 100644 tests/unit/whatsapp/mod.rs delete mode 100644 tests/unit/whatsapp/whatsapp.rs diff --git a/src/bot/runner.rs b/src/bot/runner.rs index 6ddd833..edc239d 100644 --- a/src/bot/runner.rs +++ b/src/bot/runner.rs @@ -1,4 +1,3 @@ - use super::{BotResponse, ConversationState, ResponseContentType}; use crate::fixtures::{Bot, Channel, Customer, Session}; use crate::harness::TestContext; @@ -137,7 +136,7 @@ impl BotRunner { self } - pub fn load_script(&mut self, name: &str, content: &str) -> &mut Self { + pub fn load_script(&self, name: &str, content: &str) -> &Self { self.script_cache .lock() .unwrap() @@ -145,9 +144,9 @@ impl BotRunner { self } - pub fn load_script_file(&mut self, name: &str, path: &PathBuf) -> Result<&mut Self> { + pub fn load_script_file(&self, name: &str, path: &PathBuf) -> Result<&Self> { let content = std::fs::read_to_string(path) - .with_context(|| format!("Failed to read script file: {path:?}"))?; + .with_context(|| format!("Failed to read script file: {}", path.display()))?; self.script_cache .lock() .unwrap() @@ -155,7 +154,7 @@ impl BotRunner { Ok(self) } - pub fn start_session(&mut self, customer: Customer) -> Result { + pub fn start_session(&self, customer: Customer) -> Result { let session_id = Uuid::new_v4(); let bot_id = self.bot.as_ref().map_or_else(Uuid::new_v4, |b| b.id); @@ -182,13 +181,13 @@ impl BotRunner { Ok(session_id) } - pub fn end_session(&mut self, session_id: Uuid) -> Result<()> { + pub fn end_session(&self, session_id: Uuid) -> Result<()> { self.sessions.lock().unwrap().remove(&session_id); Ok(()) } pub async fn process_message( - &mut self, + &self, session_id: Uuid, message: &str, ) -> Result { @@ -205,18 +204,15 @@ impl BotRunner { sessions.get(&session_id).cloned() }; - let state = match state { - Some(s) => s, - None => { - return Ok(ExecutionResult { - session_id, - response: None, - state: ConversationState::Error, - execution_time: start.elapsed(), - logs, - error: Some("Session not found".to_string()), - }); - } + let Some(state) = state else { + return Ok(ExecutionResult { + session_id, + response: None, + state: ConversationState::Error, + execution_time: start.elapsed(), + logs, + error: Some("Session not found".to_string()), + }); }; if self.config.capture_logs { @@ -308,17 +304,18 @@ impl BotRunner { let response_content = if script_content.is_empty() { format!("Received: {message}") } else { - self.evaluate_basic_script(&script_content, message, &state.context) - .await + Self::evaluate_basic_script(&script_content, message, &state.context) .unwrap_or_else(|e| format!("Error: {e}")) }; let latency = start.elapsed().as_millis() as u64; - let mut metrics = self.metrics.lock().unwrap(); - metrics.total_requests += 1; - metrics.successful_requests += 1; - metrics.total_latency_ms += latency; + { + let mut metrics = self.metrics.lock().unwrap(); + metrics.total_requests += 1; + metrics.successful_requests += 1; + metrics.total_latency_ms += latency; + } Ok(BotResponse { id: Uuid::new_v4(), @@ -338,8 +335,7 @@ impl BotRunner { }) } - async fn evaluate_basic_script( - &self, + fn evaluate_basic_script( script: &str, input: &str, context: &HashMap, @@ -360,7 +356,7 @@ impl BotRunner { if line.to_uppercase().starts_with("TALK") { let content = line[4..].trim().trim_matches('"'); - let expanded = self.expand_variables(content, &variables); + let expanded = Self::expand_variables(content, &variables); if !output.is_empty() { output.push('\n'); } @@ -372,7 +368,7 @@ impl BotRunner { if parts.len() == 2 { let var_name = parts[0].trim().to_uppercase(); let var_value = parts[1].trim().trim_matches('"').to_string(); - let expanded = self.expand_variables(&var_value, &variables); + let expanded = Self::expand_variables(&var_value, &variables); variables.insert(var_name, expanded); } } @@ -385,7 +381,7 @@ impl BotRunner { Ok(output) } - fn expand_variables(&self, text: &str, variables: &HashMap) -> String { + fn expand_variables(text: &str, variables: &HashMap) -> String { let mut result = text.to_string(); for (key, value) in variables { result = result.replace(&format!("{{{key}}}"), value); @@ -395,11 +391,7 @@ impl BotRunner { result } - pub async fn execute_script( - &mut self, - script_name: &str, - input: &str, - ) -> Result { + pub fn execute_script(&self, script_name: &str, input: &str) -> Result { let session_id = Uuid::new_v4(); let start = Instant::now(); let mut logs = Vec::new(); @@ -409,18 +401,15 @@ impl BotRunner { cache.get(script_name).cloned() }; - let script = match script { - Some(s) => s, - None => { - return Ok(ExecutionResult { - session_id, - response: None, - state: ConversationState::Error, - execution_time: start.elapsed(), - logs, - error: Some(format!("Script '{script_name}' not found")), - }); - } + let Some(script) = script else { + return Ok(ExecutionResult { + session_id, + response: None, + state: ConversationState::Error, + execution_time: start.elapsed(), + logs, + error: Some(format!("Script '{script_name}' not found")), + }); }; if self.config.capture_logs { @@ -437,7 +426,7 @@ impl BotRunner { metrics.script_executions += 1; } - let result = self.execute_script_internal(&script, input).await; + let result = Self::execute_script_internal(&script, input); let execution_time = start.elapsed(); @@ -467,16 +456,16 @@ impl BotRunner { } } - async fn execute_script_internal(&self, script: &str, input: &str) -> Result { + fn execute_script_internal(script: &str, input: &str) -> Result { let context = HashMap::new(); - self.evaluate_basic_script(script, input, &context).await + Self::evaluate_basic_script(script, input, &context) } pub fn metrics(&self) -> RunnerMetrics { self.metrics.lock().unwrap().clone() } - pub fn reset_metrics(&mut self) { + pub fn reset_metrics(&self) { *self.metrics.lock().unwrap() = RunnerMetrics::default(); } @@ -486,14 +475,16 @@ impl BotRunner { pub fn get_session_info(&self, session_id: Uuid) -> Option { let sessions = self.sessions.lock().unwrap(); - sessions.get(&session_id).map(|s| SessionInfo { + let info = sessions.get(&session_id).map(|s| SessionInfo { session_id: s.session.id, customer_id: s.customer.id, channel: s.channel, message_count: s.message_count, state: s.conversation_state, duration: s.started_at.elapsed(), - }) + }); + drop(sessions); + info } pub fn set_env(&mut self, key: &str, value: &str) -> &mut Self { @@ -553,27 +544,31 @@ mod tests { #[test] fn test_runner_metrics_avg_latency() { - let mut metrics = RunnerMetrics::default(); - metrics.total_requests = 10; - metrics.total_latency_ms = 1000; + let metrics = RunnerMetrics { + total_requests: 10, + total_latency_ms: 1000, + ..Default::default() + }; assert_eq!(metrics.avg_latency_ms(), 100); } #[test] fn test_runner_metrics_success_rate() { - let mut metrics = RunnerMetrics::default(); - metrics.total_requests = 100; - metrics.successful_requests = 95; + let metrics = RunnerMetrics { + total_requests: 100, + successful_requests: 95, + ..Default::default() + }; - assert_eq!(metrics.success_rate(), 95.0); + assert!((metrics.success_rate() - 95.0).abs() < f64::EPSILON); } #[test] fn test_runner_metrics_zero_requests() { let metrics = RunnerMetrics::default(); assert_eq!(metrics.avg_latency_ms(), 0); - assert_eq!(metrics.success_rate(), 0.0); + assert!(metrics.success_rate().abs() < f64::EPSILON); } #[test] @@ -584,16 +579,17 @@ mod tests { #[test] fn test_load_script() { - let mut runner = BotRunner::new(); + let runner = BotRunner::new(); runner.load_script("test", "TALK \"Hello\""); let cache = runner.script_cache.lock().unwrap(); assert!(cache.contains_key("test")); + drop(cache); } #[test] fn test_start_session() { - let mut runner = BotRunner::new(); + let runner = BotRunner::new(); let customer = Customer::default(); let session_id = runner.start_session(customer).unwrap(); @@ -604,7 +600,7 @@ mod tests { #[test] fn test_end_session() { - let mut runner = BotRunner::new(); + let runner = BotRunner::new(); let customer = Customer::default(); let session_id = runner.start_session(customer).unwrap(); @@ -616,7 +612,7 @@ mod tests { #[tokio::test] async fn test_process_message() { - let mut runner = BotRunner::new(); + let runner = BotRunner::new(); let customer = Customer::default(); let session_id = runner.start_session(customer).unwrap(); @@ -629,7 +625,7 @@ mod tests { #[tokio::test] async fn test_process_message_invalid_session() { - let mut runner = BotRunner::new(); + let runner = BotRunner::new(); let invalid_session_id = Uuid::new_v4(); let result = runner @@ -642,22 +638,22 @@ mod tests { assert_eq!(result.state, ConversationState::Error); } - #[tokio::test] - async fn test_execute_script() { - let mut runner = BotRunner::new(); + #[test] + fn test_execute_script() { + let runner = BotRunner::new(); runner.load_script("greeting", "TALK \"Hello\""); - let result = runner.execute_script("greeting", "Hi").await.unwrap(); + let result = runner.execute_script("greeting", "Hi").unwrap(); assert!(result.response.is_some()); assert!(result.error.is_none()); } - #[tokio::test] - async fn test_execute_script_not_found() { - let mut runner = BotRunner::new(); + #[test] + fn test_execute_script_not_found() { + let runner = BotRunner::new(); - let result = runner.execute_script("nonexistent", "Hi").await.unwrap(); + let result = runner.execute_script("nonexistent", "Hi").unwrap(); assert!(result.response.is_none()); assert!(result.error.is_some()); @@ -675,7 +671,7 @@ mod tests { #[test] fn test_reset_metrics() { - let mut runner = BotRunner::new(); + let runner = BotRunner::new(); { let mut metrics = runner.metrics.lock().unwrap(); @@ -709,7 +705,7 @@ mod tests { #[test] fn test_session_info() { - let mut runner = BotRunner::new(); + let runner = BotRunner::new(); let customer = Customer::default(); let customer_id = customer.id; diff --git a/src/desktop/mod.rs b/src/desktop/mod.rs index c2ffe07..82e4d22 100644 --- a/src/desktop/mod.rs +++ b/src/desktop/mod.rs @@ -1,4 +1,3 @@ - use anyhow::Result; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -171,45 +170,46 @@ impl DesktopApp { self.platform } - pub async fn find_window(&self, title: &str) -> Result> { + pub fn find_window(&self, title: &str) -> Result> { match self.platform { - Platform::Windows => self.find_window_windows(title).await, - Platform::MacOS => self.find_window_macos(title).await, - Platform::Linux => self.find_window_linux(title).await, + Platform::Windows => Self::find_window_windows(title), + Platform::MacOS => Self::find_window_macos(title), + Platform::Linux => Self::find_window_linux(title), } } #[cfg(target_os = "windows")] - async fn find_window_windows(&self, _title: &str) -> Result> { + fn find_window_windows(_title: &str) -> Result> { anyhow::bail!("Windows desktop testing not yet implemented") } #[cfg(not(target_os = "windows"))] - async fn find_window_windows(&self, _title: &str) -> Result> { + fn find_window_windows(_title: &str) -> Result> { anyhow::bail!("Windows desktop testing not available on this platform") } #[cfg(target_os = "macos")] - async fn find_window_macos(&self, _title: &str) -> Result> { + fn find_window_macos(_title: &str) -> Result> { anyhow::bail!("macOS desktop testing not yet implemented") } #[cfg(not(target_os = "macos"))] - async fn find_window_macos(&self, _title: &str) -> Result> { + fn find_window_macos(_title: &str) -> Result> { anyhow::bail!("macOS desktop testing not available on this platform") } #[cfg(target_os = "linux")] - async fn find_window_linux(&self, _title: &str) -> Result> { + fn find_window_linux(_title: &str) -> Result> { anyhow::bail!("Linux desktop testing not yet implemented") } #[cfg(not(target_os = "linux"))] - async fn find_window_linux(&self, _title: &str) -> Result> { + fn find_window_linux(_title: &str) -> Result> { anyhow::bail!("Linux desktop testing not available on this platform") } - pub async fn screenshot(&self) -> Result { + pub fn screenshot(&self) -> Result { + let _ = &self.platform; anyhow::bail!("Screenshot functionality not yet implemented") } } @@ -255,7 +255,7 @@ pub struct Screenshot { impl Screenshot { pub fn save(&self, path: impl Into) -> Result<()> { let path = path.into(); - anyhow::bail!("Screenshot save not yet implemented: {path:?}") + anyhow::bail!("Screenshot save not yet implemented: {}", path.display()) } } @@ -302,23 +302,28 @@ pub struct Element { } impl Element { - pub async fn click(&self) -> Result<()> { + pub fn click(&self) -> Result<()> { + let _ = &self.locator; anyhow::bail!("Element click not yet implemented") } - pub async fn double_click(&self) -> Result<()> { + pub fn double_click(&self) -> Result<()> { + let _ = &self.locator; anyhow::bail!("Element double-click not yet implemented") } - pub async fn right_click(&self) -> Result<()> { + pub fn right_click(&self) -> Result<()> { + let _ = &self.locator; anyhow::bail!("Element right-click not yet implemented") } - pub async fn type_text(&self, _text: &str) -> Result<()> { + pub fn type_text(&self, _text: &str) -> Result<()> { + let _ = &self.locator; anyhow::bail!("Element type_text not yet implemented") } - pub async fn clear(&self) -> Result<()> { + pub fn clear(&self) -> Result<()> { + let _ = &self.locator; anyhow::bail!("Element clear not yet implemented") } @@ -332,7 +337,8 @@ impl Element { self.bounds.width > 0 && self.bounds.height > 0 } - pub async fn focus(&self) -> Result<()> { + pub fn focus(&self) -> Result<()> { + let _ = &self.locator; anyhow::bail!("Element focus not yet implemented") } } diff --git a/src/harness.rs b/src/harness.rs index 2568a15..9c5464f 100644 --- a/src/harness.rs +++ b/src/harness.rs @@ -133,9 +133,7 @@ impl TestContext { let user = std::env::var("DB_USER").unwrap_or_else(|_| "gbuser".to_string()); let password = std::env::var("DB_PASSWORD").unwrap_or_else(|_| "gbuser".to_string()); let database = std::env::var("DB_NAME").unwrap_or_else(|_| "botserver".to_string()); - format!( - "postgres://{user}:{password}@{host}:{port}/{database}" - ) + format!("postgres://{user}:{password}@{host}:{port}/{database}") } else { format!( "postgres://bottest:bottest@127.0.0.1:{}/bottest", @@ -706,7 +704,6 @@ impl BotServerInstance { log::info!("Botserver working directory: {botserver_dir:?}"); log::info!("Stack path (absolute): {stack_path:?}"); - let installers_path = botserver_dir.join("botserver-installers"); let installers_path = installers_path.canonicalize().unwrap_or(installers_path); log::info!("Using installers from: {installers_path:?}"); @@ -733,9 +730,7 @@ impl BotServerInstance { if process.is_some() { let max_wait = 600; - log::info!( - "Waiting for botserver to bootstrap and become ready... (max {max_wait}s)" - ); + log::info!("Waiting for botserver to bootstrap and become ready... (max {max_wait}s)"); for i in 0..max_wait { if let Ok(resp) = reqwest::get(&format!("{url}/health")).await { if resp.status().is_success() { @@ -951,7 +946,7 @@ impl TestHarness { log::info!("Starting PostgreSQL on port {}...", ctx.ports.postgres); let pg = PostgresService::start(ctx.ports.postgres, &data_dir_str).await?; if config.run_migrations { - pg.run_migrations().await?; + pg.run_migrations()?; } ctx.postgres = Some(pg); } diff --git a/src/main.rs b/src/main.rs index d33db43..20c6025 100644 --- a/src/main.rs +++ b/src/main.rs @@ -262,12 +262,7 @@ fn detect_browser_version(browser_path: &str) -> Option { let parts: Vec<&str> = version_str.split_whitespace().collect(); for part in parts { - if part.contains('.') - && part - .chars() - .next() - .is_some_and(|c| c.is_ascii_digit()) - { + if part.contains('.') && part.chars().next().is_some_and(|c| c.is_ascii_digit()) { let major = part.split('.').next()?; return Some(major.to_string()); } @@ -389,9 +384,8 @@ async fn setup_chromedriver(browser_path: &str) -> Result { let chrome_version = get_chromedriver_version_for_browser(&major_version).await?; - let chromedriver_url = format!( - "{CHROMEDRIVER_URL}/{chrome_version}/linux64/chromedriver-linux64.zip" - ); + let chromedriver_url = + format!("{CHROMEDRIVER_URL}/{chrome_version}/linux64/chromedriver-linux64.zip"); let zip_path = cache_dir.join("chromedriver.zip"); download_file(&chromedriver_url, &zip_path).await?; @@ -440,9 +434,7 @@ async fn setup_chrome_for_testing() -> Result { .await .unwrap_or_else(|_| "131.0.6778.204".to_string()); - let chrome_url = format!( - "{CHROMEDRIVER_URL}/{chrome_version}/linux64/chrome-linux64.zip" - ); + let chrome_url = format!("{CHROMEDRIVER_URL}/{chrome_version}/linux64/chrome-linux64.zip"); let zip_path = cache_dir.join("chrome.zip"); download_file(&chrome_url, &zip_path).await?; @@ -555,7 +547,7 @@ async fn run_browser_demo() -> Result<()> { tokio::time::sleep(std::time::Duration::from_secs(5)).await; info!("Closing browser..."); - let _ = browser.close().await; + let _ = browser.close(); let _ = browser_service.stop().await; info!("Demo complete!"); @@ -864,9 +856,7 @@ async fn run_e2e_tests(config: &RunnerConfig) -> Result { let _ = child.kill(); } results.failed = 1; - results - .errors - .push(format!("Botserver start failed: {e}")); + results.errors.push(format!("Botserver start failed: {e}")); return Ok(results); } }; @@ -917,9 +907,7 @@ async fn run_e2e_tests(config: &RunnerConfig) -> Result { results.skipped = skipped; } Err(e) => { - results - .errors - .push(format!("Failed to run E2E tests: {e}")); + results.errors.push(format!("Failed to run E2E tests: {e}")); results.failed = 1; } } diff --git a/src/services/postgres.rs b/src/services/postgres.rs index 6b8bdee..38ad5f1 100644 --- a/src/services/postgres.rs +++ b/src/services/postgres.rs @@ -1,4 +1,3 @@ - use super::{check_tcp_port, ensure_dir, wait_for, HEALTH_CHECK_INTERVAL, HEALTH_CHECK_TIMEOUT}; use anyhow::{Context, Result}; use nix::sys::signal::{kill, Signal}; @@ -32,7 +31,10 @@ impl PostgresService { let bin_dir = PathBuf::from(&stack_path).join("bin/tables/bin"); let lib_dir = PathBuf::from(&stack_path).join("bin/tables/lib"); if bin_dir.join("postgres").exists() || bin_dir.join("initdb").exists() { - log::info!("Using PostgreSQL from BOTSERVER_STACK_PATH: {bin_dir:?}"); + log::info!( + "Using PostgreSQL from BOTSERVER_STACK_PATH: {}", + bin_dir.display() + ); return Ok((bin_dir, Some(lib_dir))); } } @@ -48,7 +50,10 @@ impl PostgresService { let bin_dir = cwd.join(rel_path); if bin_dir.join("postgres").exists() || bin_dir.join("initdb").exists() { let lib_dir = bin_dir.parent().unwrap().join("lib"); - log::info!("Using PostgreSQL from botserver-stack: {bin_dir:?}"); + log::info!( + "Using PostgreSQL from botserver-stack: {}", + bin_dir.display() + ); return Ok(( bin_dir, if lib_dir.exists() { @@ -76,14 +81,14 @@ impl PostgresService { for path in &system_paths { let bin_dir = PathBuf::from(path); if bin_dir.join("postgres").exists() || bin_dir.join("initdb").exists() { - log::info!("Using system PostgreSQL from: {bin_dir:?}"); + log::info!("Using system PostgreSQL from: {}", bin_dir.display()); return Ok((bin_dir, None)); } } if let Ok(initdb_path) = which::which("initdb") { if let Some(bin_dir) = initdb_path.parent() { - log::info!("Using PostgreSQL from PATH: {bin_dir:?}"); + log::info!("Using PostgreSQL from PATH: {}", bin_dir.display()); return Ok((bin_dir.to_path_buf(), None)); } } @@ -114,14 +119,14 @@ impl PostgresService { service.connection_string = service.build_connection_string(); if !data_path.join("PG_VERSION").exists() { - service.init_db().await?; + service.init_db()?; } - service.start_server().await?; + service.start_server()?; service.wait_ready().await?; - service.setup_test_database().await?; + service.setup_test_database()?; Ok(service) } @@ -139,10 +144,10 @@ impl PostgresService { cmd } - async fn init_db(&self) -> Result<()> { + fn init_db(&self) -> Result<()> { log::info!( - "Initializing PostgreSQL data directory at {:?}", - self.data_dir + "Initializing PostgreSQL data directory at {}", + self.data_dir.display() ); let output = self @@ -207,15 +212,15 @@ unix_socket_directories = '{}' Ok(()) } - async fn start_server(&mut self) -> Result<()> { + fn start_server(&mut self) -> Result<()> { log::info!("Starting PostgreSQL on port {}", self.port); let log_path = self.data_dir.join("postgres.log"); let log_file = std::fs::File::create(&log_path) - .context(format!("Failed to create log file {log_path:?}"))?; + .context(format!("Failed to create log file {}", log_path.display()))?; let stderr_file = log_file.try_clone()?; - log::debug!("PostgreSQL log file: {log_path:?}"); + log::debug!("PostgreSQL log file: {}", log_path.display()); let mut cmd = self.build_command("postgres"); let child = cmd @@ -237,14 +242,14 @@ unix_socket_directories = '{}' }) .await; - if result.is_err() { + if let Err(e) = result { let log_path = self.data_dir.join("postgres.log"); if log_path.exists() { if let Ok(log_content) = std::fs::read_to_string(&log_path) { log::error!("PostgreSQL log:\n{log_content}"); } } - return Err(result.unwrap_err()).context("PostgreSQL failed to start in time"); + return Err(e).context("PostgreSQL failed to start in time"); } for _ in 0..30 { @@ -262,7 +267,7 @@ unix_socket_directories = '{}' Ok(()) } - async fn setup_test_database(&self) -> Result<()> { + fn setup_test_database(&self) -> Result<()> { log::info!("Setting up test database '{}'", self.database_name); let _ = self @@ -302,7 +307,7 @@ unix_socket_directories = '{}' Ok(()) } - pub async fn run_migrations(&self) -> Result<()> { + pub fn run_migrations(&self) -> Result<()> { log::info!("Running database migrations..."); if let Ok(diesel) = which::which("diesel") { @@ -324,7 +329,7 @@ unix_socket_directories = '{}' Ok(()) } - pub async fn create_database(&self, name: &str) -> Result<()> { + pub fn create_database(&self, name: &str) -> Result<()> { let output = self .build_command("psql") .args([ @@ -349,7 +354,7 @@ unix_socket_directories = '{}' Ok(()) } - pub async fn execute(&self, sql: &str) -> Result<()> { + pub fn execute(&self, sql: &str) -> Result<()> { let output = self .build_command("psql") .args([ @@ -374,7 +379,7 @@ unix_socket_directories = '{}' Ok(()) } - pub async fn query(&self, sql: &str) -> Result { + pub fn query(&self, sql: &str) -> Result { let output = self .build_command("psql") .args([ diff --git a/src/web/browser.rs b/src/web/browser.rs index 906eab4..0d34aea 100644 --- a/src/web/browser.rs +++ b/src/web/browser.rs @@ -1,4 +1,3 @@ - use anyhow::{Context, Result}; use chromiumoxide::browser::{Browser as CdpBrowser, BrowserConfig as CdpBrowserConfig}; use chromiumoxide::cdp::browser_protocol::page::CaptureScreenshotFormat; @@ -31,7 +30,7 @@ impl Default for BrowserType { impl BrowserType { #[must_use] - pub const fn browser_name(&self) -> &'static str { + pub const fn browser_name(self) -> &'static str { match self { Self::Chrome => "chrome", Self::Firefox => "firefox", @@ -41,7 +40,7 @@ impl BrowserType { } #[must_use] - pub const fn capability_name(&self) -> &'static str { + pub const fn capability_name(self) -> &'static str { match self { Self::Chrome => "goog:chromeOptions", Self::Firefox => "moz:firefoxOptions", @@ -223,7 +222,7 @@ impl BrowserConfig { } pub struct Browser { - browser: Arc, + cdp: Arc, page: Arc>, config: BrowserConfig, _handle: tokio::task::JoinHandle<()>, @@ -241,7 +240,11 @@ impl Browser { .await .context("Failed to parse CDP JSON response")?; json.get("webSocketDebuggerUrl") - .and_then(|v| v.as_str()).map_or_else(|| format!("ws://127.0.0.1:{}", config.debug_port), std::string::ToString::to_string) + .and_then(|v| v.as_str()) + .map_or_else( + || format!("ws://127.0.0.1:{}", config.debug_port), + std::string::ToString::to_string, + ) } _ => format!("ws://127.0.0.1:{}", config.debug_port), }; @@ -255,8 +258,7 @@ impl Browser { let handle = tokio::spawn(async move { loop { match handler.next().await { - Some(Ok(())) => { - } + Some(Ok(())) => {} Some(Err(e)) => { let err_str = format!("{e:?}"); if err_str.contains("did not match any variant") { @@ -315,7 +317,7 @@ impl Browser { log::info!("Successfully connected to browser via CDP"); Ok(Self { - browser: Arc::new(browser), + cdp: Arc::new(browser), page: Arc::new(Mutex::new(page)), config, _handle: handle, @@ -334,8 +336,7 @@ impl Browser { let handle = tokio::spawn(async move { loop { match handler.next().await { - Some(Ok(())) => { - } + Some(Ok(())) => {} Some(Err(e)) => { let err_str = format!("{e:?}"); if err_str.contains("did not match any variant") { @@ -375,7 +376,7 @@ impl Browser { log::info!("Browser launched successfully"); Ok(Self { - browser: Arc::new(browser), + cdp: Arc::new(browser), page: Arc::new(Mutex::new(page)), config, _handle: handle, @@ -391,77 +392,93 @@ impl Browser { } pub async fn goto(&self, url: &str) -> Result<()> { - let page = self.page.lock().await; - - let _ = page.bring_to_front().await; - if url.starts_with("https://") { log::info!("Using JavaScript navigation for HTTPS URL: {url}"); - let _ = page.goto("about:blank").await; + { + let page = self.page.lock().await; + let _ = page.bring_to_front().await; + let _ = page.goto("about:blank").await; + } sleep(Duration::from_millis(100)).await; - let nav_script = format!("window.location.href = '{url}';"); - let _ = page.evaluate(nav_script.as_str()).await; + { + let page = self.page.lock().await; + let nav_script = format!("window.location.href = '{url}';"); + let _ = page.evaluate(nav_script.as_str()).await; + } sleep(Duration::from_millis(1500)).await; - if let Ok(Some(current)) = page.url().await { - if current.as_str() != "about:blank" { - log::info!("Navigation successful: {current}"); + { + let page = self.page.lock().await; + if let Ok(Some(current)) = page.url().await { + if current.as_str() != "about:blank" { + log::info!("Navigation successful: {current}"); + } } } } else { - page.goto(url) - .await - .context(format!("Failed to navigate to {url}"))?; + { + let page = self.page.lock().await; + let _ = page.bring_to_front().await; + page.goto(url) + .await + .context(format!("Failed to navigate to {url}"))?; + } sleep(Duration::from_millis(300)).await; } - let _ = page.bring_to_front().await; - - let _ = page - .evaluate("window.focus(); document.body.style.visibility = 'visible';") - .await; + { + let page = self.page.lock().await; + let _ = page.bring_to_front().await; + let _ = page + .evaluate("window.focus(); document.body.style.visibility = 'visible';") + .await; + } Ok(()) } pub async fn current_url(&self) -> Result { - let page = self.page.lock().await; - let url = page - .url() - .await - .context("Failed to get current URL")? - .unwrap_or_default(); + let url = { + let page = self.page.lock().await; + page.url() + .await + .context("Failed to get current URL")? + .unwrap_or_default() + }; Ok(url) } pub async fn title(&self) -> Result { - let page = self.page.lock().await; - let title = page - .get_title() - .await - .context("Failed to get page title")? - .unwrap_or_default(); + let title = { + let page = self.page.lock().await; + page.get_title() + .await + .context("Failed to get page title")? + .unwrap_or_default() + }; Ok(title) } pub async fn page_source(&self) -> Result { - let page = self.page.lock().await; - let content = page.content().await.context("Failed to get page source")?; + let content = { + let page = self.page.lock().await; + page.content().await.context("Failed to get page source")? + }; Ok(content) } pub async fn find(&self, locator: Locator) -> Result { - let page = self.page.lock().await; - let selector = locator.to_css_selector(); - - let element = page - .find_element(&selector) - .await - .context(format!("Failed to find element: {locator:?}"))?; + let element = { + let page = self.page.lock().await; + let selector = locator.to_css_selector(); + page.find_element(&selector) + .await + .context(format!("Failed to find element: {locator:?}"))? + }; Ok(Element { inner: element, @@ -470,13 +487,13 @@ impl Browser { } pub async fn find_all(&self, locator: Locator) -> Result> { - let page = self.page.lock().await; - let selector = locator.to_css_selector(); - - let elements = page - .find_elements(&selector) - .await - .context(format!("Failed to find elements: {locator:?}"))?; + let elements = { + let page = self.page.lock().await; + let selector = locator.to_css_selector(); + page.find_elements(&selector) + .await + .context(format!("Failed to find elements: {locator:?}"))? + }; Ok(elements .into_iter() @@ -504,16 +521,7 @@ impl Browser { match &condition { WaitCondition::Present | WaitCondition::Visible | WaitCondition::Clickable => { if let Ok(elem) = self.find(locator.clone()).await { - match &condition { - WaitCondition::Present => return Ok(elem), - WaitCondition::Visible => { - return Ok(elem); - } - WaitCondition::Clickable => { - return Ok(elem); - } - _ => {} - } + return Ok(elem); } } WaitCondition::NotPresent => { @@ -556,9 +564,7 @@ impl Browser { sleep(Duration::from_millis(100)).await; } - anyhow::bail!( - "Timeout waiting for element {locator:?} with condition {condition:?}" - ) + anyhow::bail!("Timeout waiting for element {locator:?} with condition {condition:?}") } pub async fn click(&self, locator: Locator) -> Result<()> { @@ -586,11 +592,12 @@ impl Browser { } pub async fn execute_script(&self, script: &str) -> Result { - let page = self.page.lock().await; - let result = page - .evaluate(script) - .await - .context("Failed to execute script")?; + let result = { + let page = self.page.lock().await; + page.evaluate(script) + .await + .context("Failed to execute script")? + }; Ok(result.value().cloned().unwrap_or(serde_json::Value::Null)) } @@ -603,27 +610,31 @@ impl Browser { } pub async fn screenshot(&self) -> Result> { - let page = self.page.lock().await; - let screenshot = page - .screenshot( + let screenshot = { + let page = self.page.lock().await; + page.screenshot( chromiumoxide::page::ScreenshotParams::builder() .format(CaptureScreenshotFormat::Png) .build(), ) .await - .context("Failed to take screenshot")?; + .context("Failed to take screenshot")? + }; Ok(screenshot) } pub async fn screenshot_to_file(&self, path: impl Into) -> Result<()> { let data = self.screenshot().await?; let path = path.into(); - std::fs::write(&path, data).context(format!("Failed to write screenshot to {path:?}")) + std::fs::write(&path, &data) + .context(format!("Failed to write screenshot to {}", path.display())) } pub async fn refresh(&self) -> Result<()> { - let page = self.page.lock().await; - page.reload().await.context("Failed to refresh page")?; + { + let page = self.page.lock().await; + page.reload().await.context("Failed to refresh page")?; + } Ok(()) } @@ -638,17 +649,19 @@ impl Browser { } pub async fn set_window_size(&self, width: u32, height: u32) -> Result<()> { - let page = self.page.lock().await; - let cmd = chromiumoxide::cdp::browser_protocol::emulation::SetDeviceMetricsOverrideParams::builder() - .width(width) - .height(height) - .device_scale_factor(1.0) - .mobile(false) - .build() - .map_err(|e| anyhow::anyhow!("Failed to build set window size params: {e}"))?; - page.execute(cmd) - .await - .context("Failed to set window size")?; + { + let page = self.page.lock().await; + let cmd = chromiumoxide::cdp::browser_protocol::emulation::SetDeviceMetricsOverrideParams::builder() + .width(width) + .height(height) + .device_scale_factor(1.0) + .mobile(false) + .build() + .map_err(|e| anyhow::anyhow!("Failed to build set window size params: {e}"))?; + page.execute(cmd) + .await + .context("Failed to set window size")?; + } Ok(()) } @@ -657,8 +670,10 @@ impl Browser { } pub async fn get_cookies(&self) -> Result> { - let page = self.page.lock().await; - let cookies = page.get_cookies().await.context("Failed to get cookies")?; + let cookies = { + let page = self.page.lock().await; + page.get_cookies().await.context("Failed to get cookies")? + }; Ok(cookies .into_iter() @@ -676,44 +691,45 @@ impl Browser { } pub async fn set_cookie(&self, cookie: Cookie) -> Result<()> { - let page = self.page.lock().await; - page.set_cookie( - chromiumoxide::cdp::browser_protocol::network::CookieParam::builder() - .name(cookie.name) - .value(cookie.value) - .build() - .map_err(|e| anyhow::anyhow!("Failed to build cookie: {e}"))?, - ) - .await - .context("Failed to set cookie")?; + { + let page = self.page.lock().await; + page.set_cookie( + chromiumoxide::cdp::browser_protocol::network::CookieParam::builder() + .name(cookie.name) + .value(cookie.value) + .build() + .map_err(|e| anyhow::anyhow!("Failed to build cookie: {e}"))?, + ) + .await + .context("Failed to set cookie")?; + } Ok(()) } pub async fn delete_cookie(&self, name: &str) -> Result<()> { - let page = self.page.lock().await; - page.delete_cookie( - chromiumoxide::cdp::browser_protocol::network::DeleteCookiesParams::builder() + { + let page = self.page.lock().await; + let cmd = chromiumoxide::cdp::browser_protocol::network::DeleteCookiesParams::builder() .name(name) .build() - .map_err(|e| anyhow::anyhow!("Failed to build delete cookie params: {e}"))?, - ) - .await - .context("Failed to delete cookie")?; + .map_err(|e| anyhow::anyhow!("Failed to build delete cookie params: {e}"))?; + page.execute(cmd).await.context("Failed to delete cookie")?; + } Ok(()) } pub async fn delete_all_cookies(&self) -> Result<()> { - let page = self.page.lock().await; - let cookies = page.get_cookies().await?; + let cookies = { + let page = self.page.lock().await; + page.get_cookies().await? + }; for c in cookies { - page.delete_cookie( - chromiumoxide::cdp::browser_protocol::network::DeleteCookiesParams::builder() - .name(&c.name) - .build() - .map_err(|e| anyhow::anyhow!("Failed to build delete cookie params: {e}"))?, - ) - .await - .ok(); + let page = self.page.lock().await; + let cmd = chromiumoxide::cdp::browser_protocol::network::DeleteCookiesParams::builder() + .name(&c.name) + .build() + .map_err(|e| anyhow::anyhow!("Failed to build delete cookie params: {e}"))?; + page.execute(cmd).await.ok(); } Ok(()) } @@ -745,20 +761,25 @@ impl Browser { elem.is_displayed().await } - pub async fn close(self) -> Result<()> { + pub fn close(self) -> Result<()> { + let _ = self.cdp; Ok(()) } pub async fn send_key(&self, key: Key) -> Result<()> { - let page = self.page.lock().await; let key_str = Self::key_to_cdp_key(key); - if let Ok(cmd) = - chromiumoxide::cdp::browser_protocol::input::DispatchKeyEventParams::builder() - .r#type(chromiumoxide::cdp::browser_protocol::input::DispatchKeyEventType::KeyDown) - .text(key_str) - .build() { - let _ = page.execute(cmd).await; + let page = self.page.lock().await; + if let Ok(cmd) = + chromiumoxide::cdp::browser_protocol::input::DispatchKeyEventParams::builder() + .r#type( + chromiumoxide::cdp::browser_protocol::input::DispatchKeyEventType::KeyDown, + ) + .text(key_str) + .build() + { + let _ = page.execute(cmd).await; + } } Ok(()) } @@ -767,42 +788,63 @@ impl Browser { match key { Key::Enter => "\r", Key::Tab => "\t", - Key::Escape => "", - Key::Backspace => "", - Key::Delete => "", - Key::ArrowUp => "", - Key::ArrowDown => "", - Key::ArrowLeft => "", - Key::ArrowRight => "", - Key::Home => "", - Key::End => "", - Key::PageUp => "", - Key::PageDown => "", - _ => "", + Key::Escape + | Key::Backspace + | Key::Delete + | Key::ArrowUp + | Key::ArrowDown + | Key::ArrowLeft + | Key::ArrowRight + | Key::Home + | Key::End + | Key::PageUp + | Key::PageDown + | Key::F1 + | Key::F2 + | Key::F3 + | Key::F4 + | Key::F5 + | Key::F6 + | Key::F7 + | Key::F8 + | Key::F9 + | Key::F10 + | Key::F11 + | Key::F12 + | Key::Shift + | Key::Control + | Key::Alt + | Key::Meta => "", } } - pub async fn switch_to_frame(&self, _locator: Locator) -> Result<()> { + pub fn switch_to_frame(&self, _locator: Locator) -> Result<()> { + let _ = &self.page; Ok(()) } - pub async fn switch_to_frame_by_index(&self, _index: u16) -> Result<()> { + pub fn switch_to_frame_by_index(&self, _index: u16) -> Result<()> { + let _ = &self.page; Ok(()) } - pub async fn switch_to_parent_frame(&self) -> Result<()> { + pub fn switch_to_parent_frame(&self) -> Result<()> { + let _ = &self.page; Ok(()) } - pub async fn switch_to_default_content(&self) -> Result<()> { + pub fn switch_to_default_content(&self) -> Result<()> { + let _ = &self.page; Ok(()) } - pub async fn current_window_handle(&self) -> Result { + pub fn current_window_handle(&self) -> Result { + let _ = &self.page; Ok("main".to_string()) } - pub async fn window_handles(&self) -> Result> { + pub fn window_handles(&self) -> Result> { + let _ = &self.page; Ok(vec!["main".to_string()]) } } @@ -869,7 +911,8 @@ impl Element { .context(format!("Failed to get attribute {name}")) } - pub async fn css_value(&self, _name: &str) -> Result { + pub fn css_value(&self, _name: &str) -> Result { + let _ = &self.inner; Ok(String::new()) } @@ -887,7 +930,8 @@ impl Element { Ok(checked.is_some()) } - pub async fn tag_name(&self) -> Result { + pub fn tag_name(&self) -> Result { + let _ = &self.inner; Ok("element".to_string()) } @@ -896,7 +940,8 @@ impl Element { Ok((point.x as i64, point.y as i64)) } - pub async fn size(&self) -> Result<(u64, u64)> { + pub fn size(&self) -> Result<(u64, u64)> { + let _ = &self.inner; Ok((100, 20)) } diff --git a/tests/e2e/mod.rs b/tests/e2e/mod.rs index 9b2ae38..8698ddc 100644 --- a/tests/e2e/mod.rs +++ b/tests/e2e/mod.rs @@ -36,7 +36,6 @@ async fn is_service_running(url: &str) -> bool { impl E2ETestContext { pub async fn setup() -> anyhow::Result { - let botserver_url = std::env::var("BOTSERVER_URL").unwrap_or_else(|_| "https://localhost:8080".to_string()); let botui_url = @@ -86,7 +85,6 @@ impl E2ETestContext { } pub async fn setup_with_browser() -> anyhow::Result { - let botserver_url = std::env::var("BOTSERVER_URL").unwrap_or_else(|_| "https://localhost:8080".to_string()); let botui_url = @@ -183,7 +181,7 @@ impl E2ETestContext { pub async fn close(mut self) { if let Some(browser) = self.browser { - let _ = browser.close().await; + let _ = browser.close(); } if let Some(mut bs) = self.browser_service.take() { let _ = bs.stop().await; @@ -322,7 +320,6 @@ async fn test_full_harness_has_all_services() { "MockZitadel should be available" ); - assert!(ctx.data_dir.exists()); assert!(ctx.data_dir.to_str().unwrap().contains("bottest-")); } diff --git a/tests/unit/attendance/attendance.rs b/tests/unit/attendance/attendance.rs deleted file mode 100644 index 93443bf..0000000 --- a/tests/unit/attendance/attendance.rs +++ /dev/null @@ -1,34 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use serde_json; - - - - #[test] - - - fn test_module_exports() { - - let _config = KeywordConfig::default(); - let _parser = KeywordParser::new(); - } - - #[test] - - - fn test_respond_request_parse() { - let json = r#"{ - "session_id": "123e4567-e89b-12d3-a456-426614174000", - "message": "Hello, how can I help?", - "attendant_id": "att-001" - }"#; - - let request: AttendantRespondRequest = serde_json::from_str(json).unwrap(); - assert_eq!(request.attendant_id, "att-001"); - assert_eq!(request.message, "Hello, how can I help?"); - } \ No newline at end of file diff --git a/tests/unit/attendance/attendance_llm_assist.rs b/tests/unit/attendance/attendance_llm_assist.rs deleted file mode 100644 index 5bf07e6..0000000 --- a/tests/unit/attendance/attendance_llm_assist.rs +++ /dev/null @@ -1,93 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_config_defaults() { - let config = LlmAssistConfig::default(); - assert!(!config.tips_enabled); - assert!(!config.polish_enabled); - assert!(!config.any_enabled()); - } - - #[test] - - - fn test_fallback_tips_urgent() { - let tips = generate_fallback_tips("This is URGENT! I need help immediately!"); - assert!(!tips.is_empty()); - assert!(tips.iter().any(|t| matches!(t.tip_type, TipType::Warning))); - } - - #[test] - - - fn test_fallback_tips_question() { - let tips = generate_fallback_tips("How do I reset my password?"); - assert!(!tips.is_empty()); - assert!(tips.iter().any(|t| matches!(t.tip_type, TipType::Intent))); - } - - #[test] - - - fn test_sentiment_positive() { - let sentiment = analyze_sentiment_keywords("Thank you so much! This is great!"); - assert_eq!(sentiment.overall, "positive"); - assert!(sentiment.score > 0.0); - assert_eq!(sentiment.escalation_risk, "low"); - } - - #[test] - - - fn test_sentiment_negative() { - let sentiment = - analyze_sentiment_keywords("This is terrible! I'm very frustrated with this problem."); - assert_eq!(sentiment.overall, "negative"); - assert!(sentiment.score < 0.0); - assert!(sentiment.escalation_risk == "medium" || sentiment.escalation_risk == "high"); - } - - #[test] - - - fn test_sentiment_urgent() { - let sentiment = analyze_sentiment_keywords("I need help ASAP! This is urgent!"); - assert!(sentiment.urgency == "high" || sentiment.urgency == "urgent"); - } - - #[test] - - - fn test_extract_json() { - let response = "Here is the result: {\"key\": \"value\"} and some more text."; - let json = extract_json(response); - assert_eq!(json, "{\"key\": \"value\"}"); - } - - #[test] - - - fn test_fallback_replies() { - let replies = generate_fallback_replies(); - assert_eq!(replies.len(), 3); - assert!(replies.iter().any(|r| r.category == "greeting")); - assert!(replies.iter().any(|r| r.category == "follow_up")); - } - - #[test] - - - fn test_help_text() { - let help = get_help_text(); - assert!(help.contains("/queue")); - assert!(help.contains("/tips")); - assert!(help.contains("/polish")); - } \ No newline at end of file diff --git a/tests/unit/attendance/mod.rs b/tests/unit/attendance/mod.rs deleted file mode 100644 index c9c537d..0000000 --- a/tests/unit/attendance/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ - -mod attendance_llm_assist; -mod attendance; diff --git a/tests/unit/basic/basic_compiler_goto_transform.rs b/tests/unit/basic/basic_compiler_goto_transform.rs deleted file mode 100644 index f2aa034..0000000 --- a/tests/unit/basic/basic_compiler_goto_transform.rs +++ /dev/null @@ -1,147 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_is_label_line() { - assert!(is_label_line("start:")); - assert!(is_label_line(" mainLoop:")); - assert!(is_label_line("my_label:")); - assert!(is_label_line("label123:")); - - assert!(!is_label_line("TALK \"hello:\"")); - assert!(!is_label_line("' comment:")); - assert!(!is_label_line("CASE:")); - assert!(!is_label_line("123label:")); - assert!(!is_label_line("has space:")); - } - - #[test] - - - fn test_extract_goto_target() { - assert_eq!(extract_goto_target("GOTO start"), Some("start".to_string())); - assert_eq!( - extract_goto_target(" GOTO myLabel"), - Some("myLabel".to_string()) - ); - assert_eq!( - extract_goto_target("IF x > 5 THEN GOTO done"), - Some("done".to_string()) - ); - assert_eq!(extract_goto_target("TALK \"hello\""), None); - } - - #[test] - - - fn test_transform_line_simple_goto() { - assert_eq!( - transform_line("GOTO start"), - "__goto_label = \"start\"; continue;" - ); - assert_eq!( - transform_line(" GOTO myLoop "), - "__goto_label = \"myLoop\"; continue;" - ); - } - - #[test] - - - fn test_transform_line_if_then_goto() { - let result = transform_line("IF x < 10 THEN GOTO start"); - assert!(result.contains("if x < 10")); - assert!(result.contains("__goto_label = \"start\"")); - assert!(result.contains("continue")); - } - - #[test] - - - fn test_transform_line_if_goto_no_then() { - let result = transform_line("IF x < 10 GOTO start"); - assert!(result.contains("if x < 10")); - assert!(result.contains("__goto_label = \"start\"")); - } - - #[test] - - - fn test_transform_line_not_goto() { - assert_eq!(transform_line("TALK \"Hello\""), "TALK \"Hello\""); - assert_eq!(transform_line("x = x + 1"), "x = x + 1"); - assert_eq!(transform_line("ON ERROR GOTO 0"), "ON ERROR GOTO 0"); - } - - #[test] - - - fn test_has_goto_constructs() { - assert!(has_goto_constructs("start:\nTALK \"hi\"\nGOTO start")); - assert!(has_goto_constructs("IF x > 0 THEN GOTO done")); - assert!(!has_goto_constructs("TALK \"hello\"\nWAIT 1")); - assert!(!has_goto_constructs("ON ERROR GOTO 0")); - } - - #[test] - - - fn test_transform_goto_simple() { - let input = r#"start: - TALK "Hello" - x = x + 1 - IF x < 3 THEN GOTO start - TALK "Done""#; - - let output = transform_goto(input); - - assert!(output.contains("__goto_label")); - assert!(output.contains("while")); - assert!(output.contains("\"start\"")); - assert!(output.contains("WARNING")); - } - - #[test] - - - fn test_transform_goto_no_goto() { - let input = "TALK \"Hello\"\nTALK \"World\""; - let output = transform_goto(input); - assert_eq!(output, input); - } - - #[test] - - - fn test_transform_goto_multiple_labels() { - let input = r#"start: - TALK "Start" - GOTO middle -middle: - TALK "Middle" - GOTO done -done: - TALK "Done""#; - - let output = transform_goto(input); - - assert!(output.contains("\"start\"")); - assert!(output.contains("\"middle\"")); - assert!(output.contains("\"done\"")); - } - - #[test] - - - fn test_infinite_loop_protection() { - let output = transform_goto("loop:\nGOTO loop"); - assert!(output.contains("__goto_max_iterations")); - assert!(output.contains("throw")); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_a2a_protocol.rs b/tests/unit/basic/basic_keywords_a2a_protocol.rs deleted file mode 100644 index 1af95a2..0000000 --- a/tests/unit/basic/basic_keywords_a2a_protocol.rs +++ /dev/null @@ -1,125 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use serde_json; - - - - #[test] - - - fn test_a2a_message_creation() { - let msg = A2AMessage::new( - "bot_a", - Some("bot_b"), - A2AMessageType::Request, - serde_json::json!({"test": "data"}), - Uuid::new_v4(), - ); - - assert_eq!(msg.from_agent, "bot_a"); - assert_eq!(msg.to_agent, Some("bot_b".to_string())); - assert_eq!(msg.message_type, A2AMessageType::Request); - assert_eq!(msg.hop_count, 0); - } - - #[test] - - - fn test_a2a_message_response() { - let original = A2AMessage::new( - "bot_a", - Some("bot_b"), - A2AMessageType::Request, - serde_json::json!({"question": "test"}), - Uuid::new_v4(), - ); - - let response = original.create_response("bot_b", serde_json::json!({"answer": "result"})); - - assert_eq!(response.from_agent, "bot_b"); - assert_eq!(response.to_agent, Some("bot_a".to_string())); - assert_eq!(response.message_type, A2AMessageType::Response); - assert_eq!(response.correlation_id, original.correlation_id); - assert_eq!(response.hop_count, 1); - } - - #[test] - - - fn test_message_type_display() { - assert_eq!(A2AMessageType::Request.to_string(), "request"); - assert_eq!(A2AMessageType::Response.to_string(), "response"); - assert_eq!(A2AMessageType::Broadcast.to_string(), "broadcast"); - assert_eq!(A2AMessageType::Delegate.to_string(), "delegate"); - } - - #[test] - - - fn test_message_type_from_str() { - assert_eq!(A2AMessageType::from("request"), A2AMessageType::Request); - assert_eq!(A2AMessageType::from("RESPONSE"), A2AMessageType::Response); - assert_eq!(A2AMessageType::from("unknown"), A2AMessageType::Request); - } - - #[test] - - - fn test_a2a_config_default() { - let config = A2AConfig::default(); - assert!(config.enabled); - assert_eq!(config.timeout_seconds, 30); - assert_eq!(config.max_hops, 5); - assert_eq!(config.protocol_version, "1.0"); - } - - #[test] - - - fn test_message_not_expired() { - let msg = A2AMessage::new( - "bot_a", - Some("bot_b"), - A2AMessageType::Request, - serde_json::json!({}), - Uuid::new_v4(), - ); - - assert!(!msg.is_expired()); - } - - #[test] - - - fn test_max_hops_not_exceeded() { - let msg = A2AMessage::new( - "bot_a", - Some("bot_b"), - A2AMessageType::Request, - serde_json::json!({}), - Uuid::new_v4(), - ); - - assert!(!msg.max_hops_exceeded(5)); - } - - #[test] - - - fn test_max_hops_exceeded() { - let mut msg = A2AMessage::new( - "bot_a", - Some("bot_b"), - A2AMessageType::Request, - serde_json::json!({}), - Uuid::new_v4(), - ); - msg.hop_count = 5; - - assert!(msg.max_hops_exceeded(5)); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_add_bot.rs b/tests/unit/basic/basic_keywords_add_bot.rs deleted file mode 100644 index 6198650..0000000 --- a/tests/unit/basic/basic_keywords_add_bot.rs +++ /dev/null @@ -1,77 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_trigger_from_keywords() { - let trigger = BotTrigger::from_keywords(vec!["finance".to_string(), "money".to_string()]); - assert_eq!(trigger.trigger_type, TriggerType::Keyword); - assert_eq!(trigger.keywords.unwrap().len(), 2); - } - - #[test] - - - fn test_match_bot_triggers() { - let bots = vec![ - SessionBot { - id: Uuid::new_v4(), - session_id: Uuid::new_v4(), - bot_id: Uuid::new_v4(), - bot_name: "finance-bot".to_string(), - trigger: BotTrigger::from_keywords(vec!["money".to_string(), "budget".to_string()]), - priority: 1, - is_active: true, - }, - SessionBot { - id: Uuid::new_v4(), - session_id: Uuid::new_v4(), - bot_id: Uuid::new_v4(), - bot_name: "hr-bot".to_string(), - trigger: BotTrigger::from_keywords(vec![ - "vacation".to_string(), - "employee".to_string(), - ]), - priority: 0, - is_active: true, - }, - ]; - - let matches = match_bot_triggers("How much money do I have?", &bots); - assert_eq!(matches.len(), 1); - assert_eq!(matches[0].bot_name, "finance-bot"); - - let matches = match_bot_triggers("I need to request vacation", &bots); - assert_eq!(matches.len(), 1); - assert_eq!(matches[0].bot_name, "hr-bot"); - - let matches = match_bot_triggers("Hello world", &bots); - assert!(matches.is_empty()); - } - - #[test] - - - fn test_match_tool_triggers() { - let bots = vec![SessionBot { - id: Uuid::new_v4(), - session_id: Uuid::new_v4(), - bot_id: Uuid::new_v4(), - bot_name: "data-bot".to_string(), - trigger: BotTrigger::from_tools(vec!["AGGREGATE".to_string(), "CHART".to_string()]), - priority: 1, - is_active: true, - }]; - - let matches = match_tool_triggers("aggregate", &bots); - assert_eq!(matches.len(), 1); - - let matches = match_tool_triggers("SEND", &bots); - assert!(matches.is_empty()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_add_member.rs b/tests/unit/basic/basic_keywords_add_member.rs deleted file mode 100644 index ff5a2aa..0000000 --- a/tests/unit/basic/basic_keywords_add_member.rs +++ /dev/null @@ -1,37 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_validate_role() { - assert_eq!(validate_role("admin"), "admin"); - assert_eq!(validate_role("ADMIN"), "admin"); - assert_eq!(validate_role("contributor"), "contributor"); - assert_eq!(validate_role("viewer"), "viewer"); - assert_eq!(validate_role("unknown"), "member"); - } - - #[test] - - - fn test_get_permissions_for_role() { - let admin_perms = get_permissions_for_role("admin"); - assert!(admin_perms.get("read").unwrap().as_bool().unwrap()); - assert!(admin_perms.get("write").unwrap().as_bool().unwrap()); - assert!(admin_perms - .get("manage_members") - .unwrap() - .as_bool() - .unwrap()); - - let viewer_perms = get_permissions_for_role("viewer"); - assert!(viewer_perms.get("read").unwrap().as_bool().unwrap()); - assert!(!viewer_perms.get("write").unwrap().as_bool().unwrap()); - assert!(!viewer_perms.get("delete").unwrap().as_bool().unwrap()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_add_suggestion.rs b/tests/unit/basic/basic_keywords_add_suggestion.rs deleted file mode 100644 index 1c768ea..0000000 --- a/tests/unit/basic/basic_keywords_add_suggestion.rs +++ /dev/null @@ -1,67 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_suggestion_json_context() { - let suggestion = json!({ - "type": "context", - "context": "products", - "text": "View Products", - "action": { - "type": "select_context", - "context": "products" - } - }); - - assert_eq!(suggestion["type"], "context"); - assert_eq!(suggestion["action"]["type"], "select_context"); - } - - #[test] - - - fn test_suggestion_json_tool_no_params() { - let suggestion = json!({ - "type": "tool", - "tool": "search_kb", - "text": "Search Knowledge Base", - "action": { - "type": "invoke_tool", - "tool": "search_kb", - "params": Option::>::None, - "prompt_for_params": true - } - }); - - assert_eq!(suggestion["type"], "tool"); - assert_eq!(suggestion["action"]["prompt_for_params"], true); - } - - #[test] - - - fn test_suggestion_json_tool_with_params() { - let params = vec!["query".to_string(), "products".to_string()]; - let suggestion = json!({ - "type": "tool", - "tool": "search_kb", - "text": "Search Products", - "action": { - "type": "invoke_tool", - "tool": "search_kb", - "params": params, - "prompt_for_params": false - } - }); - - assert_eq!(suggestion["type"], "tool"); - assert_eq!(suggestion["action"]["prompt_for_params"], false); - assert!(suggestion["action"]["params"].is_array()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_agent_reflection.rs b/tests/unit/basic/basic_keywords_agent_reflection.rs deleted file mode 100644 index 4ede355..0000000 --- a/tests/unit/basic/basic_keywords_agent_reflection.rs +++ /dev/null @@ -1,114 +0,0 @@ -use botserver::basic::keywords::agent_reflection::{ - extract_insights_from_text, ReflectionConfig, ReflectionResult, ReflectionType, -}; -use uuid::Uuid; - -#[test] -fn test_reflection_type_from_str() { - assert_eq!( - ReflectionType::from("conversation_quality"), - ReflectionType::ConversationQuality - ); - assert_eq!( - ReflectionType::from("quality"), - ReflectionType::ConversationQuality - ); - assert_eq!( - ReflectionType::from("tool_usage"), - ReflectionType::ToolUsage - ); - assert_eq!( - ReflectionType::from("performance"), - ReflectionType::Performance - ); -} - -#[test] -fn test_reflection_config_default() { - let config = ReflectionConfig::default(); - assert!(!config.enabled); - assert_eq!(config.interval, 10); - assert!(!config.auto_apply); -} - -#[test] -fn test_reflection_result_new() { - let bot_id = Uuid::new_v4(); - let session_id = Uuid::new_v4(); - let result = ReflectionResult::new(bot_id, session_id, ReflectionType::ConversationQuality); - - assert_eq!(result.bot_id, bot_id); - assert_eq!(result.session_id, session_id); - assert_eq!(result.score, 0.0); - assert!(result.insights.is_empty()); -} - -#[test] -fn test_reflection_result_from_json() { - let json_response = r#"{ - "score": 7.5, - "key_insights": ["Users prefer concise responses", "Technical questions need more detail"], - "improvements": ["Add more examples", "Improve response time"], - "positive_patterns": ["Good greeting", "Clear explanations"] - }"#; - - let result = ReflectionResult::from_llm_response( - Uuid::new_v4(), - Uuid::new_v4(), - ReflectionType::ConversationQuality, - json_response, - 10, - ); - - assert_eq!(result.score, 7.5); - assert_eq!(result.insights.len(), 2); - assert_eq!(result.improvements.len(), 2); - assert_eq!(result.positive_patterns.len(), 2); -} - -#[test] -fn test_reflection_result_needs_improvement() { - let mut result = - ReflectionResult::new(Uuid::new_v4(), Uuid::new_v4(), ReflectionType::Performance); - - result.score = 5.0; - assert!(result.needs_improvement(6.0)); - - result.score = 8.0; - assert!(!result.needs_improvement(6.0)); -} - -#[test] -fn test_extract_insights_from_text() { - let text = "Here are some insights:\n\ - 1. Users prefer short responses\n\ - 2. Technical questions need examples\n\ - - Consider adding more context\n\ - • Improve response time"; - - let insights = extract_insights_from_text(text); - assert!(!insights.is_empty()); -} - -#[test] -fn test_reflection_type_prompt_template() { - let template = ReflectionType::ConversationQuality.prompt_template(); - assert!(template.contains("{conversation}")); - assert!(template.contains("JSON format")); -} - -#[test] -fn test_reflection_result_summary() { - let mut result = - ReflectionResult::new(Uuid::new_v4(), Uuid::new_v4(), ReflectionType::Performance); - result.score = 7.5; - result.messages_analyzed = 15; - result.insights = vec!["Insight 1".to_string(), "Insight 2".to_string()]; - result.improvements = vec!["Improvement 1".to_string()]; - - let summary = result.summary(); - assert!(summary.contains("7.5")); - assert!(summary.contains("15")); - assert!(summary.contains("2")); - assert!(summary.contains("1")); -} diff --git a/tests/unit/basic/basic_keywords_arrays.rs b/tests/unit/basic/basic_keywords_arrays.rs deleted file mode 100644 index 7d811c4..0000000 --- a/tests/unit/basic/basic_keywords_arrays.rs +++ /dev/null @@ -1,56 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - use rhai::Dynamic; - - #[test] - - - fn test_ubound() { - let arr: Vec = vec![Dynamic::from(1), Dynamic::from(2), Dynamic::from(3)]; - assert_eq!(arr.len() - 1, 2); - } - - #[test] - - - fn test_join() { - let arr = vec!["a", "b", "c"]; - let result = arr.join("-"); - assert_eq!(result, "a-b-c"); - } - - #[test] - - - fn test_split() { - let s = "a,b,c"; - let parts: Vec<&str> = s.split(',').collect(); - assert_eq!(parts.len(), 3); - } - - #[test] - - - fn test_range() { - let range: Vec = (1..=5).collect(); - assert_eq!(range, vec![1, 2, 3, 4, 5]); - } - - #[test] - - - fn test_flatten() { - - let nested = vec![vec![1, 2], vec![3, 4]]; - let flat: Vec = nested.into_iter().flatten().collect(); - assert_eq!(flat, vec![1, 2, 3, 4]); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_arrays_contains.rs b/tests/unit/basic/basic_keywords_arrays_contains.rs deleted file mode 100644 index ba12afc..0000000 --- a/tests/unit/basic/basic_keywords_arrays_contains.rs +++ /dev/null @@ -1,92 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - #[test] - - - fn test_contains_string() { - let arr: Array = vec![ - Dynamic::from("Alice"), - Dynamic::from("Bob"), - Dynamic::from("Charlie"), - ]; - - assert!(array_contains(&arr, &Dynamic::from("Bob"))); - assert!(!array_contains(&arr, &Dynamic::from("David"))); - } - - #[test] - - - fn test_contains_integer() { - let arr: Array = vec![ - Dynamic::from(1_i64), - Dynamic::from(2_i64), - Dynamic::from(3_i64), - ]; - - assert!(array_contains(&arr, &Dynamic::from(2_i64))); - assert!(!array_contains(&arr, &Dynamic::from(5_i64))); - } - - #[test] - - - fn test_contains_float() { - let arr: Array = vec![ - Dynamic::from(1.5_f64), - Dynamic::from(2.5_f64), - Dynamic::from(3.5_f64), - ]; - - assert!(array_contains(&arr, &Dynamic::from(2.5_f64))); - assert!(!array_contains(&arr, &Dynamic::from(4.5_f64))); - } - - #[test] - - - fn test_contains_bool() { - let arr: Array = vec![Dynamic::from(true), Dynamic::from(false)]; - - assert!(array_contains(&arr, &Dynamic::from(true))); - assert!(array_contains(&arr, &Dynamic::from(false))); - } - - #[test] - - - fn test_contains_empty_array() { - let arr = Array::new(); - assert!(!array_contains(&arr, &Dynamic::from("anything"))); - } - - #[test] - - - fn test_items_equal_integers() { - assert!(items_equal(&Dynamic::from(5_i64), &Dynamic::from(5_i64))); - assert!(!items_equal(&Dynamic::from(5_i64), &Dynamic::from(6_i64))); - } - - #[test] - - - fn test_items_equal_strings() { - assert!(items_equal( - &Dynamic::from("hello"), - &Dynamic::from("hello") - )); - assert!(!items_equal( - &Dynamic::from("hello"), - &Dynamic::from("world") - )); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_arrays_push_pop.rs b/tests/unit/basic/basic_keywords_arrays_push_pop.rs deleted file mode 100644 index 1c790a2..0000000 --- a/tests/unit/basic/basic_keywords_arrays_push_pop.rs +++ /dev/null @@ -1,62 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - use rhai::{Array, Dynamic}; - - #[test] - - - fn test_push() { - let mut arr: Array = vec![Dynamic::from(1), Dynamic::from(2)]; - arr.push(Dynamic::from(3)); - assert_eq!(arr.len(), 3); - assert_eq!(arr[2].as_int().unwrap_or(0), 3); - } - - #[test] - - - fn test_pop() { - let mut arr: Array = vec![Dynamic::from(1), Dynamic::from(2), Dynamic::from(3)]; - let popped = arr.pop(); - assert_eq!(arr.len(), 2); - assert_eq!(popped.and_then(|v| v.as_int().ok()).unwrap_or(0), 3); - } - - #[test] - - - fn test_pop_empty() { - let mut arr: Array = vec![]; - let popped = arr.pop(); - assert!(popped.is_none()); - } - - #[test] - - - fn test_shift() { - let mut arr: Array = vec![Dynamic::from(1), Dynamic::from(2), Dynamic::from(3)]; - let shifted = arr.remove(0); - assert_eq!(arr.len(), 2); - assert_eq!(shifted.as_int().unwrap_or(0), 1); - assert_eq!(arr[0].as_int().unwrap_or(0), 2); - } - - #[test] - - - fn test_unshift() { - let mut arr: Array = vec![Dynamic::from(2), Dynamic::from(3)]; - arr.insert(0, Dynamic::from(1)); - assert_eq!(arr.len(), 3); - assert_eq!(arr[0].as_int().unwrap_or(0), 1); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_arrays_slice.rs b/tests/unit/basic/basic_keywords_arrays_slice.rs deleted file mode 100644 index e24a214..0000000 --- a/tests/unit/basic/basic_keywords_arrays_slice.rs +++ /dev/null @@ -1,81 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - fn make_test_array() -> Array { - vec![ - Dynamic::from(1), - Dynamic::from(2), - Dynamic::from(3), - Dynamic::from(4), - Dynamic::from(5), - ] - } - - #[test] - - - fn test_slice_from_start() { - let arr = make_test_array(); - let result = slice_array(&arr, 2, None); - assert_eq!(result.len(), 3); - assert_eq!(result[0].as_int().unwrap(), 3); - } - - #[test] - - - fn test_slice_with_end() { - let arr = make_test_array(); - let result = slice_array(&arr, 1, Some(3)); - assert_eq!(result.len(), 2); - assert_eq!(result[0].as_int().unwrap(), 2); - assert_eq!(result[1].as_int().unwrap(), 3); - } - - #[test] - - - fn test_slice_negative_start() { - let arr = make_test_array(); - let result = slice_array(&arr, -2, None); - assert_eq!(result.len(), 2); - assert_eq!(result[0].as_int().unwrap(), 4); - assert_eq!(result[1].as_int().unwrap(), 5); - } - - #[test] - - - fn test_slice_negative_end() { - let arr = make_test_array(); - let result = slice_array(&arr, 0, Some(-2)); - assert_eq!(result.len(), 3); - assert_eq!(result[0].as_int().unwrap(), 1); - assert_eq!(result[2].as_int().unwrap(), 3); - } - - #[test] - - - fn test_slice_out_of_bounds() { - let arr = make_test_array(); - let result = slice_array(&arr, 10, None); - assert!(result.is_empty()); - } - - #[test] - - - fn test_slice_empty_range() { - let arr = make_test_array(); - let result = slice_array(&arr, 3, Some(2)); - assert!(result.is_empty()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_arrays_sort.rs b/tests/unit/basic/basic_keywords_arrays_sort.rs deleted file mode 100644 index 44aad38..0000000 --- a/tests/unit/basic/basic_keywords_arrays_sort.rs +++ /dev/null @@ -1,73 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - #[test] - - - fn test_sort_integers() { - let arr: Array = vec![ - Dynamic::from(3), - Dynamic::from(1), - Dynamic::from(4), - Dynamic::from(1), - Dynamic::from(5), - ]; - let sorted = sort_array(arr, false); - assert_eq!(sorted[0].as_int().unwrap(), 1); - assert_eq!(sorted[1].as_int().unwrap(), 1); - assert_eq!(sorted[2].as_int().unwrap(), 3); - assert_eq!(sorted[3].as_int().unwrap(), 4); - assert_eq!(sorted[4].as_int().unwrap(), 5); - } - - #[test] - - - fn test_sort_strings() { - let arr: Array = vec![ - Dynamic::from("banana"), - Dynamic::from("apple"), - Dynamic::from("cherry"), - ]; - let sorted = sort_array(arr, false); - assert_eq!(sorted[0].clone().into_string().unwrap(), "apple"); - assert_eq!(sorted[1].clone().into_string().unwrap(), "banana"); - assert_eq!(sorted[2].clone().into_string().unwrap(), "cherry"); - } - - #[test] - - - fn test_sort_descending() { - let arr: Array = vec![Dynamic::from(1), Dynamic::from(3), Dynamic::from(2)]; - let sorted = sort_array(arr, true); - assert_eq!(sorted[0].as_int().unwrap(), 3); - assert_eq!(sorted[1].as_int().unwrap(), 2); - assert_eq!(sorted[2].as_int().unwrap(), 1); - } - - #[test] - - - fn test_compare_dynamic_numbers() { - let a = Dynamic::from(5); - let b = Dynamic::from(3); - assert_eq!(compare_dynamic(&a, &b), std::cmp::Ordering::Greater); - } - - #[test] - - - fn test_compare_dynamic_strings() { - let a = Dynamic::from("apple"); - let b = Dynamic::from("banana"); - assert_eq!(compare_dynamic(&a, &b), std::cmp::Ordering::Less); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_arrays_unique.rs b/tests/unit/basic/basic_keywords_arrays_unique.rs deleted file mode 100644 index 2b594b5..0000000 --- a/tests/unit/basic/basic_keywords_arrays_unique.rs +++ /dev/null @@ -1,108 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - use rhai::Dynamic; - - #[test] - - - fn test_unique_integers() { - let mut arr = Array::new(); - arr.push(Dynamic::from(1_i64)); - arr.push(Dynamic::from(2_i64)); - arr.push(Dynamic::from(2_i64)); - arr.push(Dynamic::from(3_i64)); - arr.push(Dynamic::from(3_i64)); - arr.push(Dynamic::from(3_i64)); - arr.push(Dynamic::from(4_i64)); - - let result = unique_array(arr); - assert_eq!(result.len(), 4); - } - - #[test] - - - fn test_unique_strings() { - let mut arr = Array::new(); - arr.push(Dynamic::from("Alice")); - arr.push(Dynamic::from("Bob")); - arr.push(Dynamic::from("Alice")); - arr.push(Dynamic::from("Charlie")); - - let result = unique_array(arr); - assert_eq!(result.len(), 3); - } - - #[test] - - - fn test_unique_preserves_order() { - let mut arr = Array::new(); - arr.push(Dynamic::from("C")); - arr.push(Dynamic::from("A")); - arr.push(Dynamic::from("B")); - arr.push(Dynamic::from("A")); - arr.push(Dynamic::from("C")); - - let result = unique_array(arr); - assert_eq!(result.len(), 3); - assert_eq!(result[0].to_string(), "C"); - assert_eq!(result[1].to_string(), "A"); - assert_eq!(result[2].to_string(), "B"); - } - - #[test] - - - fn test_unique_empty_array() { - let arr = Array::new(); - let result = unique_array(arr); - assert!(result.is_empty()); - } - - #[test] - - - fn test_unique_single_element() { - let mut arr = Array::new(); - arr.push(Dynamic::from(42_i64)); - - let result = unique_array(arr); - assert_eq!(result.len(), 1); - } - - #[test] - - - fn test_unique_all_same() { - let mut arr = Array::new(); - arr.push(Dynamic::from(1_i64)); - arr.push(Dynamic::from(1_i64)); - arr.push(Dynamic::from(1_i64)); - - let result = unique_array(arr); - assert_eq!(result.len(), 1); - } - - #[test] - - - fn test_unique_mixed_types() { - let mut arr = Array::new(); - arr.push(Dynamic::from(1_i64)); - arr.push(Dynamic::from("1")); - arr.push(Dynamic::from(1_i64)); - - let result = unique_array(arr); - - - assert!(result.len() >= 1 && result.len() <= 2); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_book.rs b/tests/unit/basic/basic_keywords_book.rs deleted file mode 100644 index d0862b2..0000000 --- a/tests/unit/basic/basic_keywords_book.rs +++ /dev/null @@ -1,46 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_parse_time_string() { - let result = parse_time_string("2024-01-15 14:30"); - assert!(result.is_ok()); - - let result = parse_time_string("tomorrow at 3pm"); - assert!(result.is_ok()); - - let result = parse_time_string("in 2 hours"); - assert!(result.is_ok()); - } - - #[test] - - - fn test_parse_date_string() { - let result = parse_date_string("today"); - assert!(result.is_ok()); - - let result = parse_date_string("2024-01-15"); - assert!(result.is_ok()); - - let result = parse_date_string("tomorrow"); - assert!(result.is_ok()); - } - - #[test] - - - fn test_extract_hour() { - assert_eq!(extract_hour_from_string("3pm"), Some(15)); - assert_eq!(extract_hour_from_string("3 PM"), Some(15)); - assert_eq!(extract_hour_from_string("10am"), Some(10)); - assert_eq!(extract_hour_from_string("12am"), Some(0)); - assert_eq!(extract_hour_from_string("12pm"), Some(12)); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_card.rs b/tests/unit/basic/basic_keywords_card.rs deleted file mode 100644 index 7a42ebc..0000000 --- a/tests/unit/basic/basic_keywords_card.rs +++ /dev/null @@ -1,41 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_card_style_from_string() { - assert!(matches!(CardStyle::from("minimal"), CardStyle::Minimal)); - assert!(matches!(CardStyle::from("VIBRANT"), CardStyle::Vibrant)); - assert!(matches!(CardStyle::from("dark"), CardStyle::Dark)); - assert!(matches!(CardStyle::from("unknown"), CardStyle::Modern)); - } - - #[test] - - - fn test_card_dimensions_for_style() { - let story_dims = CardDimensions::for_style(&CardStyle::Story); - assert_eq!(story_dims.width, 1080); - assert_eq!(story_dims.height, 1920); - - let square_dims = CardDimensions::for_style(&CardStyle::Modern); - assert_eq!(square_dims.width, 1080); - assert_eq!(square_dims.height, 1080); - } - - #[test] - - - fn test_card_config_default() { - let config = CardConfig::default(); - assert!(matches!(config.style, CardStyle::Modern)); - assert!(config.include_hashtags); - assert!(config.include_caption); - assert!(config.brand_watermark.is_none()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_clear_kb.rs b/tests/unit/basic/basic_keywords_clear_kb.rs deleted file mode 100644 index facd48d..0000000 --- a/tests/unit/basic/basic_keywords_clear_kb.rs +++ /dev/null @@ -1,28 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; -use rhai::Engine; - - - - #[test] - - - fn test_clear_kb_syntax() { - let mut engine = Engine::new(); - - - assert!(engine - .register_custom_syntax(&["CLEAR_KB", "$expr$"], true, |_, _| Ok(Dynamic::UNIT)) - .is_ok()); - - - assert!(engine - .register_custom_syntax(&["CLEAR_KB"], true, |_, _| Ok(Dynamic::UNIT)) - .is_ok()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_code_sandbox.rs b/tests/unit/basic/basic_keywords_code_sandbox.rs deleted file mode 100644 index b21cacc..0000000 --- a/tests/unit/basic/basic_keywords_code_sandbox.rs +++ /dev/null @@ -1,81 +0,0 @@ -use botserver::basic::keywords::code_sandbox::{ - generate_node_lxc_config, generate_python_lxc_config, CodeLanguage, ExecutionResult, - SandboxConfig, SandboxRuntime, -}; - -#[test] -fn test_sandbox_config_default() { - let config = SandboxConfig::default(); - assert!(config.enabled); - assert_eq!(config.timeout_seconds, 30); - assert_eq!(config.memory_limit_mb, 256); - assert!(!config.network_enabled); -} - -#[test] -fn test_execution_result_success() { - let result = ExecutionResult::success("Hello, World!".to_string(), String::new(), 100); - assert!(result.is_success()); - assert_eq!(result.output(), "Hello, World!"); -} - -#[test] -fn test_execution_result_error() { - let result = ExecutionResult::error("Something went wrong"); - assert!(!result.is_success()); - assert!(result.output().contains("Error")); -} - -#[test] -fn test_execution_result_timeout() { - let result = ExecutionResult::timeout(); - assert!(!result.is_success()); - assert!(result.timed_out); -} - -#[test] -fn test_code_language_from_str() { - assert_eq!(CodeLanguage::from("python"), CodeLanguage::Python); - assert_eq!(CodeLanguage::from("PYTHON"), CodeLanguage::Python); - assert_eq!(CodeLanguage::from("py"), CodeLanguage::Python); - assert_eq!(CodeLanguage::from("javascript"), CodeLanguage::JavaScript); - assert_eq!(CodeLanguage::from("js"), CodeLanguage::JavaScript); - assert_eq!(CodeLanguage::from("node"), CodeLanguage::JavaScript); - assert_eq!(CodeLanguage::from("bash"), CodeLanguage::Bash); -} - -#[test] -fn test_code_language_file_extension() { - assert_eq!(CodeLanguage::Python.file_extension(), "py"); - assert_eq!(CodeLanguage::JavaScript.file_extension(), "js"); - assert_eq!(CodeLanguage::Bash.file_extension(), "sh"); -} - -#[test] -fn test_code_language_interpreter() { - assert_eq!(CodeLanguage::Python.interpreter(), "python3"); - assert_eq!(CodeLanguage::JavaScript.interpreter(), "node"); - assert_eq!(CodeLanguage::Bash.interpreter(), "bash"); -} - -#[test] -fn test_sandbox_runtime_from_str() { - assert_eq!(SandboxRuntime::from("lxc"), SandboxRuntime::LXC); - assert_eq!(SandboxRuntime::from("docker"), SandboxRuntime::Docker); - assert_eq!( - SandboxRuntime::from("firecracker"), - SandboxRuntime::Firecracker - ); - assert_eq!(SandboxRuntime::from("unknown"), SandboxRuntime::Process); -} - -#[test] -fn test_lxc_config_generation() { - let python_config = generate_python_lxc_config(); - assert!(python_config.contains("gb-sandbox-python")); - assert!(python_config.contains("memory.max")); - - let node_config = generate_node_lxc_config(); - assert!(node_config.contains("gb-sandbox-node")); - assert!(node_config.contains("/usr/bin/node")); -} diff --git a/tests/unit/basic/basic_keywords_core_functions.rs b/tests/unit/basic/basic_keywords_core_functions.rs deleted file mode 100644 index c243b29..0000000 --- a/tests/unit/basic/basic_keywords_core_functions.rs +++ /dev/null @@ -1,17 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_module_structure() { - - - assert!(true); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_create_task.rs b/tests/unit/basic/basic_keywords_create_task.rs deleted file mode 100644 index b054f07..0000000 --- a/tests/unit/basic/basic_keywords_create_task.rs +++ /dev/null @@ -1,31 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_parse_due_date() { - assert!(parse_due_date("tomorrow").is_ok()); - assert!(parse_due_date("+3 days").is_ok()); - assert!(parse_due_date("2024-12-31").is_ok()); - assert!(parse_due_date("null").unwrap().is_none()); - } - - #[test] - - - fn test_determine_priority() { - let tomorrow = Some(Utc::now() + Duration::days(1)); - assert_eq!(determine_priority(tomorrow), "high"); - - let next_week = Some(Utc::now() + Duration::days(7)); - assert_eq!(determine_priority(next_week), "medium"); - - let next_month = Some(Utc::now() + Duration::days(30)); - assert_eq!(determine_priority(next_month), "low"); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_crm_attendance.rs b/tests/unit/basic/basic_keywords_crm_attendance.rs deleted file mode 100644 index b549019..0000000 --- a/tests/unit/basic/basic_keywords_crm_attendance.rs +++ /dev/null @@ -1,120 +0,0 @@ - - - -use botserver::basic::keywords::crm::attendance::create_fallback_tips; -use rhai::Map; - -#[test] -fn test_fallback_tips_urgent() { - let tips = create_fallback_tips("This is URGENT! Help now!"); - let result = tips.try_cast::().unwrap(); - assert!(result.get("success").unwrap().as_bool().unwrap()); -} - -#[test] -fn test_fallback_tips_question() { - let tips = create_fallback_tips("Can you help me with this?"); - let result = tips.try_cast::().unwrap(); - assert!(result.get("success").unwrap().as_bool().unwrap()); -} - -#[test] -fn test_polish_message() { - let polished = polish_text("thx 4 ur msg", "professional"); - assert!(!polished.contains("thx")); - assert!(polished.contains("your")); -} - -#[test] -fn test_polish_message_capitalization() { - let polished = polish_text("hello there", "professional"); - assert!(polished.starts_with('H')); - assert!(polished.ends_with('.')); -} - -fn polish_text(message: &str, _tone: &str) -> String { - let mut polished = message.to_string(); - polished = polished - .replace("thx", "Thank you") - .replace("u ", "you ") - .replace(" u", " you") - .replace("ur ", "your ") - .replace("ill ", "I'll ") - .replace("dont ", "don't ") - .replace("cant ", "can't ") - .replace("wont ", "won't ") - .replace("im ", "I'm ") - .replace("ive ", "I've "); - if let Some(first_char) = polished.chars().next() { - polished = first_char.to_uppercase().to_string() + &polished[1..]; - } - if !polished.ends_with('.') && !polished.ends_with('!') && !polished.ends_with('?') { - polished.push('.'); - } - polished -} - -#[test] -fn test_sentiment_positive() { - let result = analyze_text_sentiment("Thank you so much! This is great!"); - assert_eq!(result, "positive"); -} - -#[test] -fn test_sentiment_negative() { - let result = analyze_text_sentiment("This is terrible! I'm so frustrated!"); - assert_eq!(result, "negative"); -} - -#[test] -fn test_sentiment_neutral() { - let result = analyze_text_sentiment("The meeting is at 3pm."); - assert_eq!(result, "neutral"); -} - -fn analyze_text_sentiment(message: &str) -> &'static str { - let msg_lower = message.to_lowercase(); - let positive_words = [ - "thank", "great", "perfect", "awesome", "excellent", "good", "happy", "love", - ]; - let negative_words = [ - "angry", "frustrated", "terrible", "awful", "horrible", "hate", "disappointed", "problem", - "issue", - ]; - let positive_count = positive_words - .iter() - .filter(|w| msg_lower.contains(*w)) - .count(); - let negative_count = negative_words - .iter() - .filter(|w| msg_lower.contains(*w)) - .count(); - if positive_count > negative_count { - "positive" - } else if negative_count > positive_count { - "negative" - } else { - "neutral" - } -} - -#[test] -fn test_smart_replies_count() { - let replies = generate_smart_replies(); - assert_eq!(replies.len(), 3); -} - -#[test] -fn test_smart_replies_content() { - let replies = generate_smart_replies(); - assert!(replies.iter().any(|r| r.contains("Thank you"))); - assert!(replies.iter().any(|r| r.contains("understand"))); -} - -fn generate_smart_replies() -> Vec { - vec![ - "Thank you for reaching out! I'd be happy to help you with that.".to_string(), - "I understand your concern. Let me look into this for you right away.".to_string(), - "Is there anything else I can help you with today?".to_string(), - ] -} diff --git a/tests/unit/basic/basic_keywords_crm_score_lead.rs b/tests/unit/basic/basic_keywords_crm_score_lead.rs deleted file mode 100644 index ebbd965..0000000 --- a/tests/unit/basic/basic_keywords_crm_score_lead.rs +++ /dev/null @@ -1,69 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - #[test] - - - fn test_calculate_lead_score_empty() { - let lead_data = Map::new(); - let score = calculate_lead_score(&lead_data, None); - assert_eq!(score, 0); - } - - #[test] - - - fn test_calculate_lead_score_basic() { - let mut lead_data = Map::new(); - lead_data.insert("job_title".into(), Dynamic::from("CEO")); - lead_data.insert("company_size".into(), Dynamic::from(500_i64)); - lead_data.insert("email".into(), Dynamic::from("ceo@company.com")); - - let score = calculate_lead_score(&lead_data, None); - assert!(score > 30); - } - - #[test] - - - fn test_calculate_lead_score_with_title() { - let mut lead_data = Map::new(); - lead_data.insert("job_title".into(), Dynamic::from("CTO")); - - let score = calculate_lead_score(&lead_data, None); - assert!(score >= 30); - } - - #[test] - - - fn test_determine_priority() { - assert_eq!(determine_priority(95), "CRITICAL"); - assert_eq!(determine_priority(75), "HIGH"); - assert_eq!(determine_priority(55), "MEDIUM"); - assert_eq!(determine_priority(35), "LOW"); - assert_eq!(determine_priority(10), "MINIMAL"); - } - - #[test] - - - fn test_score_clamping() { - let mut lead_data = Map::new(); - lead_data.insert("budget".into(), Dynamic::from(1000000_i64)); - - let score = calculate_lead_score(&lead_data, None); - assert!( - score <= 100, - "Score should be clamped to 100, got {}", - score - ); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_data_operations.rs b/tests/unit/basic/basic_keywords_data_operations.rs deleted file mode 100644 index 94fcd6f..0000000 --- a/tests/unit/basic/basic_keywords_data_operations.rs +++ /dev/null @@ -1,52 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_sanitize_identifier() { - assert_eq!(sanitize_identifier("users"), "users"); - assert_eq!(sanitize_identifier("user_name"), "user_name"); - assert_eq!( - sanitize_identifier("users; DROP TABLE users;"), - "usersDROPTABLEusers" - ); - } - - #[test] - - - fn test_sanitize_sql() { - assert_eq!(sanitize_sql("hello"), "hello"); - assert_eq!(sanitize_sql("it's"), "it''s"); - assert_eq!(sanitize_sql("O'Brien"), "O''Brien"); - } - - #[test] - - - fn test_parse_condition() { - let (field, op, value) = parse_condition_internal("status=active").unwrap(); - assert_eq!(field, "status"); - assert_eq!(op, "="); - assert_eq!(value, "active"); - - let (field, op, value) = parse_condition_internal("age>=18").unwrap(); - assert_eq!(field, "age"); - assert_eq!(op, ">="); - assert_eq!(value, "18"); - } - - #[test] - - - fn test_parse_filter_clause() { - let clause = parse_filter_clause("name=John").unwrap(); - assert!(clause.contains("name")); - assert!(clause.contains("John")); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_datetime_dateadd.rs b/tests/unit/basic/basic_keywords_datetime_dateadd.rs deleted file mode 100644 index 84cca3b..0000000 --- a/tests/unit/basic/basic_keywords_datetime_dateadd.rs +++ /dev/null @@ -1,61 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_dateadd_days() { - assert_eq!(dateadd_impl("2025-01-15", 5, "day"), "2025-01-20"); - assert_eq!(dateadd_impl("2025-01-15", -10, "day"), "2025-01-05"); - } - - #[test] - - - fn test_dateadd_months() { - assert_eq!(dateadd_impl("2025-01-15", 1, "month"), "2025-02-15"); - assert_eq!(dateadd_impl("2025-01-15", -1, "month"), "2024-12-15"); - } - - #[test] - - - fn test_dateadd_years() { - assert_eq!(dateadd_impl("2025-01-15", 1, "year"), "2026-01-15"); - } - - #[test] - - - fn test_datediff_days() { - assert_eq!(datediff_impl("2025-01-01", "2025-01-15", "day"), 14); - assert_eq!(datediff_impl("2025-01-15", "2025-01-01", "day"), -14); - } - - #[test] - - - fn test_datediff_months() { - assert_eq!(datediff_impl("2025-01-01", "2025-03-01", "month"), 2); - } - - #[test] - - - fn test_datediff_years() { - assert_eq!(datediff_impl("2024-01-01", "2025-01-01", "year"), 1); - } - - #[test] - - - fn test_parse_date() { - assert!(parse_date("2025-01-15").is_some()); - assert!(parse_date("15/01/2025").is_some()); - assert!(parse_date("invalid").is_none()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_datetime_extract.rs b/tests/unit/basic/basic_keywords_datetime_extract.rs deleted file mode 100644 index 1a807cf..0000000 --- a/tests/unit/basic/basic_keywords_datetime_extract.rs +++ /dev/null @@ -1,39 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_parse_date() { - let date = parse_date("2025-01-22"); - assert!(date.is_some()); - let d = date.unwrap(); - assert_eq!(d.year(), 2025); - assert_eq!(d.month(), 1); - assert_eq!(d.day(), 22); - } - - #[test] - - - fn test_parse_datetime() { - let dt = parse_datetime("2025-01-22 14:30:45"); - assert!(dt.is_some()); - let d = dt.unwrap(); - assert_eq!(d.hour(), 14); - assert_eq!(d.minute(), 30); - assert_eq!(d.second(), 45); - } - - #[test] - - - fn test_invalid_date() { - let date = parse_date("invalid"); - assert!(date.is_none()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_datetime_now.rs b/tests/unit/basic/basic_keywords_datetime_now.rs deleted file mode 100644 index 9d11937..0000000 --- a/tests/unit/basic/basic_keywords_datetime_now.rs +++ /dev/null @@ -1,71 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_create_datetime_map() { - let now = Local::now(); - let map = create_datetime_map(now); - - assert!(map.contains_key("year")); - assert!(map.contains_key("month")); - assert!(map.contains_key("day")); - assert!(map.contains_key("hour")); - assert!(map.contains_key("minute")); - assert!(map.contains_key("second")); - assert!(map.contains_key("weekday")); - assert!(map.contains_key("timestamp")); - assert!(map.contains_key("formatted")); - assert!(map.contains_key("is_weekend")); - assert!(map.contains_key("quarter")); - } - - #[test] - - - fn test_year_extraction() { - let now = Local::now(); - let map = create_datetime_map(now); - - let year = map.get("year").unwrap().as_int().unwrap(); - assert!(year >= 2024); - } - - #[test] - - - fn test_month_range() { - let now = Local::now(); - let map = create_datetime_map(now); - - let month = map.get("month").unwrap().as_int().unwrap(); - assert!(month >= 1 && month <= 12); - } - - #[test] - - - fn test_hour12_range() { - let now = Local::now(); - let map = create_datetime_map(now); - - let hour12 = map.get("hour12").unwrap().as_int().unwrap(); - assert!(hour12 >= 1 && hour12 <= 12); - } - - #[test] - - - fn test_quarter_calculation() { - let now = Local::now(); - let map = create_datetime_map(now); - - let quarter = map.get("quarter").unwrap().as_int().unwrap(); - assert!(quarter >= 1 && quarter <= 4); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_episodic_memory.rs b/tests/unit/basic/basic_keywords_episodic_memory.rs deleted file mode 100644 index fd77a3c..0000000 --- a/tests/unit/basic/basic_keywords_episodic_memory.rs +++ /dev/null @@ -1,114 +0,0 @@ -use botserver::basic::keywords::episodic_memory::{ - extract_json, ConversationMessage, Episode, EpisodicMemoryConfig, EpisodicMemoryManager, - ResolutionStatus, Sentiment, -}; -use chrono::Utc; -use rhai::Map; -use uuid::Uuid; - -#[test] -fn test_default_config() { - let config = EpisodicMemoryConfig::default(); - assert!(config.enabled); - assert_eq!(config.threshold, 4); - assert_eq!(config.history, 2); - assert_eq!(config.max_episodes, 100); -} - -#[test] -fn test_should_summarize() { - let manager = EpisodicMemoryManager::new(EpisodicMemoryConfig { - enabled: true, - threshold: 4, - history: 2, - auto_summarize: true, - ..Default::default() - }); - - assert!(!manager.should_summarize(2)); - assert!(manager.should_summarize(4)); - assert!(manager.should_summarize(10)); -} - -#[test] -fn test_extract_json() { - let response = "Here's the summary:\n```json\n{\"summary\": \"test\"}\n```\n"; - assert!(extract_json(response).is_ok()); - - let response = "The result is {\"summary\": \"test\"}"; - assert!(extract_json(response).is_ok()); -} - -#[test] -fn test_generate_summary_prompt() { - let manager = EpisodicMemoryManager::new(EpisodicMemoryConfig::default()); - let messages = vec![ConversationMessage { - id: Uuid::new_v4(), - role: "user".to_string(), - content: "Hello".to_string(), - timestamp: Utc::now(), - }]; - - let prompt = manager.generate_summary_prompt(&messages); - assert!(prompt.contains("CONVERSATION:")); - assert!(prompt.contains("Hello")); -} - -#[test] -fn test_parse_summary_response() { - let manager = EpisodicMemoryManager::new(EpisodicMemoryConfig::default()); - let response = r#"{ - "summary": "User asked about billing", - "key_topics": ["billing", "payment"], - "decisions": [], - "action_items": [], - "sentiment": {"score": 0.5, "label": "positive", "confidence": 0.8}, - "resolution": "resolved" - }"#; - - let messages = vec![ConversationMessage { - id: Uuid::new_v4(), - role: "user".to_string(), - content: "What's my balance?".to_string(), - timestamp: Utc::now(), - }]; - - let episode = manager.parse_summary_response( - response, - &messages, - Uuid::new_v4(), - Uuid::new_v4(), - Uuid::new_v4(), - ); - - assert!(episode.is_ok()); - let ep = episode.unwrap(); - assert_eq!(ep.summary, "User asked about billing"); - assert_eq!(ep.key_topics, vec!["billing", "payment"]); - assert_eq!(ep.resolution, ResolutionStatus::Resolved); -} - -#[test] -fn test_episode_to_dynamic() { - let episode = Episode { - id: Uuid::new_v4(), - user_id: Uuid::new_v4(), - bot_id: Uuid::new_v4(), - session_id: Uuid::new_v4(), - summary: "Test summary".to_string(), - key_topics: vec!["topic1".to_string()], - decisions: vec![], - action_items: vec![], - sentiment: Sentiment::default(), - resolution: ResolutionStatus::Resolved, - message_count: 5, - message_ids: vec![], - created_at: Utc::now(), - conversation_start: Utc::now(), - conversation_end: Utc::now(), - metadata: serde_json::json!({}), - }; - - let dynamic = episode.to_dynamic(); - assert!(dynamic.is::()); -} diff --git a/tests/unit/basic/basic_keywords_errors.rs b/tests/unit/basic/basic_keywords_errors.rs deleted file mode 100644 index a9042c2..0000000 --- a/tests/unit/basic/basic_keywords_errors.rs +++ /dev/null @@ -1,25 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - #[test] - - - - fn test_error_map() { - use rhai::{Dynamic, Map}; - - let mut map = Map::new(); - map.insert("error".into(), Dynamic::from(true)); - map.insert("message".into(), Dynamic::from("test error")); - - assert!(map.contains_key("error")); - assert_eq!(map.get("error").unwrap().as_bool().unwrap_or(false), true); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_errors_on_error.rs b/tests/unit/basic/basic_keywords_errors_on_error.rs deleted file mode 100644 index 2d33fff..0000000 --- a/tests/unit/basic/basic_keywords_errors_on_error.rs +++ /dev/null @@ -1,74 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_error_resume_next_flag() { - - assert!(!is_error_resume_next_active()); - - - set_error_resume_next(true); - assert!(is_error_resume_next_active()); - - - set_error_resume_next(false); - assert!(!is_error_resume_next_active()); - } - - #[test] - - - fn test_error_storage() { - clear_last_error(); - assert!(get_last_error().is_none()); - assert_eq!(get_error_number(), 0); - - set_last_error("Test error", 42); - assert_eq!(get_last_error(), Some("Test error".to_string())); - assert_eq!(get_error_number(), 42); - - clear_last_error(); - assert!(get_last_error().is_none()); - assert_eq!(get_error_number(), 0); - } - - #[test] - - - fn test_handle_error_without_resume_next() { - set_error_resume_next(false); - clear_last_error(); - - let result: Result> = - Err("Test error".into()); - let handled = handle_error(result); - - - assert!(handled.is_err()); - } - - #[test] - - - fn test_handle_error_with_resume_next() { - set_error_resume_next(true); - clear_last_error(); - - let result: Result> = - Err("Test error".into()); - let handled = handle_error(result); - - - assert!(handled.is_ok()); - assert_eq!(get_last_error(), Some("Test error".to_string())); - - - set_error_resume_next(false); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_errors_throw.rs b/tests/unit/basic/basic_keywords_errors_throw.rs deleted file mode 100644 index e410e83..0000000 --- a/tests/unit/basic/basic_keywords_errors_throw.rs +++ /dev/null @@ -1,16 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_placeholder() { - - assert!(true); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_file_operations.rs b/tests/unit/basic/basic_keywords_file_operations.rs deleted file mode 100644 index 74dcdb0..0000000 --- a/tests/unit/basic/basic_keywords_file_operations.rs +++ /dev/null @@ -1,29 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - #[test] - - - fn test_dynamic_to_json() { - let dynamic = Dynamic::from("hello"); - let json = dynamic_to_json(&dynamic); - assert_eq!(json, Value::String("hello".to_string())); - } - - #[test] - - - fn test_dynamic_to_file_data() { - let dynamic = Dynamic::from("test content"); - let file_data = dynamic_to_file_data(&dynamic); - assert_eq!(file_data.filename, "file"); - assert!(!file_data.content.is_empty()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_hear_talk.rs b/tests/unit/basic/basic_keywords_hear_talk.rs deleted file mode 100644 index f95711b..0000000 --- a/tests/unit/basic/basic_keywords_hear_talk.rs +++ /dev/null @@ -1,88 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_validate_email() { - assert!(validate_email("test@example.com").is_valid); - assert!(validate_email("user.name+tag@domain.co.uk").is_valid); - assert!(!validate_email("invalid").is_valid); - assert!(!validate_email("@nodomain.com").is_valid); - } - - #[test] - - - fn test_validate_date() { - assert!(validate_date("25/12/2024").is_valid); - assert!(validate_date("2024-12-25").is_valid); - assert!(validate_date("today").is_valid); - assert!(validate_date("tomorrow").is_valid); - assert!(!validate_date("invalid").is_valid); - } - - #[test] - - - fn test_validate_cpf() { - assert!(validate_cpf("529.982.247-25").is_valid); - assert!(validate_cpf("52998224725").is_valid); - assert!(!validate_cpf("111.111.111-11").is_valid); - assert!(!validate_cpf("123").is_valid); - } - - #[test] - - - fn test_validate_money() { - let result = validate_money("R$ 1.234,56"); - assert!(result.is_valid); - assert_eq!(result.normalized_value, "1234.56"); - - let result = validate_money("$1,234.56"); - assert!(result.is_valid); - assert_eq!(result.normalized_value, "1234.56"); - } - - #[test] - - - fn test_validate_boolean() { - assert!(validate_boolean("yes").is_valid); - assert!(validate_boolean("sim").is_valid); - assert!(validate_boolean("no").is_valid); - assert!(validate_boolean("não").is_valid); - assert!(!validate_boolean("maybe").is_valid); - } - - #[test] - - - fn test_validate_menu() { - let options = vec![ - "Apple".to_string(), - "Banana".to_string(), - "Cherry".to_string(), - ]; - - assert!(validate_menu("Apple", &options).is_valid); - assert!(validate_menu("1", &options).is_valid); - assert!(validate_menu("ban", &options).is_valid); - assert!(!validate_menu("Orange", &options).is_valid); - } - - #[test] - - - fn test_validate_credit_card() { - - assert!(validate_credit_card("4111 1111 1111 1111").is_valid); - - assert!(!validate_credit_card("1234567890123456").is_valid); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_http_operations.rs b/tests/unit/basic/basic_keywords_http_operations.rs deleted file mode 100644 index c27b706..0000000 --- a/tests/unit/basic/basic_keywords_http_operations.rs +++ /dev/null @@ -1,48 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - #[test] - - - fn test_dynamic_to_json_string() { - let dynamic = Dynamic::from("hello"); - let json = dynamic_to_json(&dynamic); - assert_eq!(json, Value::String("hello".to_string())); - } - - #[test] - - - fn test_dynamic_to_json_number() { - let dynamic = Dynamic::from(42_i64); - let json = dynamic_to_json(&dynamic); - assert_eq!(json, Value::Number(42.into())); - } - - #[test] - - - fn test_build_soap_envelope() { - let params = json!({"name": "John", "age": 30}); - let envelope = build_soap_envelope("GetUser", ¶ms); - assert!(envelope.contains("John")); - assert!(envelope.contains("30")); - } - - #[test] - - - fn test_parse_soap_response() { - let xml = r#"Success"#; - let result = parse_soap_response(xml); - assert!(result.get("raw").is_some()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_human_approval.rs b/tests/unit/basic/basic_keywords_human_approval.rs deleted file mode 100644 index d74c935..0000000 --- a/tests/unit/basic/basic_keywords_human_approval.rs +++ /dev/null @@ -1,148 +0,0 @@ -use botserver::basic::keywords::human_approval::{ - ApprovalChannel, ApprovalConfig, ApprovalDecision, ApprovalManager, ApprovalStatus, -}; -use chrono::{Duration, Utc}; -use rhai::Map; -use uuid::Uuid; - -#[test] -fn test_default_config() { - let config = ApprovalConfig::default(); - assert!(config.enabled); - assert_eq!(config.default_timeout, 3600); - assert_eq!(config.max_reminders, 3); -} - -#[test] -fn test_create_request() { - let manager = ApprovalManager::new(ApprovalConfig::default()); - let request = manager.create_request( - Uuid::new_v4(), - Uuid::new_v4(), - Uuid::new_v4(), - "expense_approval", - ApprovalChannel::Email, - "manager@example.com", - serde_json::json!({"amount": 1000}), - "Please approve expense", - None, - None, - ); - - assert_eq!(request.status, ApprovalStatus::Pending); - assert_eq!(request.approval_type, "expense_approval"); - assert!(request.expires_at > Utc::now()); -} - -#[test] -fn test_is_expired() { - let manager = ApprovalManager::new(ApprovalConfig::default()); - let mut request = manager.create_request( - Uuid::new_v4(), - Uuid::new_v4(), - Uuid::new_v4(), - "test", - ApprovalChannel::Email, - "test@example.com", - serde_json::json!({}), - "Test", - Some(1), - None, - ); - - assert!(!manager.is_expired(&request)); - - request.expires_at = Utc::now() - Duration::seconds(10); - assert!(manager.is_expired(&request)); -} - -#[test] -fn test_process_decision() { - let manager = ApprovalManager::new(ApprovalConfig::default()); - let mut request = manager.create_request( - Uuid::new_v4(), - Uuid::new_v4(), - Uuid::new_v4(), - "test", - ApprovalChannel::Email, - "test@example.com", - serde_json::json!({}), - "Test", - None, - None, - ); - - manager.process_decision( - &mut request, - ApprovalDecision::Approve, - "manager@example.com", - Some("Looks good!".to_string()), - ); - - assert_eq!(request.status, ApprovalStatus::Approved); - assert_eq!(request.decision, Some(ApprovalDecision::Approve)); - assert_eq!(request.decided_by, Some("manager@example.com".to_string())); - assert_eq!(request.comments, Some("Looks good!".to_string())); -} - -#[test] -fn test_evaluate_condition() { - let manager = ApprovalManager::new(ApprovalConfig::default()); - let context = serde_json::json!({ - "amount": 15000, - "priority": 2 - }); - - assert!(manager - .evaluate_condition("amount > 10000", &context) - .unwrap()); - assert!(!manager - .evaluate_condition("amount > 20000", &context) - .unwrap()); - assert!(manager - .evaluate_condition("priority == 2", &context) - .unwrap()); -} - -#[test] -fn test_handle_timeout_with_default() { - let manager = ApprovalManager::new(ApprovalConfig::default()); - let mut request = manager.create_request( - Uuid::new_v4(), - Uuid::new_v4(), - Uuid::new_v4(), - "test", - ApprovalChannel::Email, - "test@example.com", - serde_json::json!({}), - "Test", - None, - Some(ApprovalDecision::Approve), - ); - - manager.handle_timeout(&mut request); - - assert_eq!(request.status, ApprovalStatus::Approved); - assert_eq!(request.decision, Some(ApprovalDecision::Approve)); - assert_eq!(request.decided_by, Some("system:timeout".to_string())); -} - -#[test] -fn test_request_to_dynamic() { - let manager = ApprovalManager::new(ApprovalConfig::default()); - let request = manager.create_request( - Uuid::new_v4(), - Uuid::new_v4(), - Uuid::new_v4(), - "test", - ApprovalChannel::Email, - "test@example.com", - serde_json::json!({"key": "value"}), - "Test message", - None, - None, - ); - - let dynamic = request.to_dynamic(); - assert!(dynamic.is::()); -} diff --git a/tests/unit/basic/basic_keywords_import_export.rs b/tests/unit/basic/basic_keywords_import_export.rs deleted file mode 100644 index 2f533f3..0000000 --- a/tests/unit/basic/basic_keywords_import_export.rs +++ /dev/null @@ -1,53 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use serde_json; - - - - #[test] - - - fn test_parse_csv_line_simple() { - let line = "a,b,c"; - let result = parse_csv_line(line); - assert_eq!(result, vec!["a", "b", "c"]); - } - - #[test] - - - fn test_parse_csv_line_quoted() { - let line = r#""hello, world",test,"another, value""#; - let result = parse_csv_line(line); - assert_eq!(result, vec!["hello, world", "test", "another, value"]); - } - - #[test] - - - fn test_escape_csv_value() { - assert_eq!(escape_csv_value("simple"), "simple"); - assert_eq!(escape_csv_value("with,comma"), "\"with,comma\""); - assert_eq!(escape_csv_value("with\"quote"), "\"with\"\"quote\""); - } - - #[test] - - - fn test_json_to_dynamic_and_back() { - let json = serde_json::json!({ - "name": "test", - "value": 42, - "active": true - }); - - let dynamic = json_to_dynamic(&json); - let back = dynamic_to_json(&dynamic); - - assert_eq!(json, back); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_kb_statistics.rs b/tests/unit/basic/basic_keywords_kb_statistics.rs deleted file mode 100644 index 4fee012..0000000 --- a/tests/unit/basic/basic_keywords_kb_statistics.rs +++ /dev/null @@ -1,50 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use serde_json; - - - - #[test] - - - fn test_collection_stats_serialization() { - let stats = CollectionStats { - name: "test_collection".to_string(), - vectors_count: 1000, - points_count: 1000, - segments_count: 2, - disk_data_size: 1024 * 1024, - ram_data_size: 512 * 1024, - indexed_vectors_count: 1000, - status: "green".to_string(), - }; - - let json = serde_json::to_string(&stats).unwrap(); - assert!(json.contains("test_collection")); - assert!(json.contains("1000")); - } - - #[test] - - - fn test_kb_statistics_serialization() { - let stats = KBStatistics { - total_collections: 3, - total_documents: 5000, - total_vectors: 5000, - total_disk_size_mb: 10.5, - total_ram_size_mb: 5.2, - documents_added_last_week: 100, - documents_added_last_month: 500, - collections: vec![], - }; - - let json = serde_json::to_string(&stats).unwrap(); - assert!(json.contains("5000")); - assert!(json.contains("10.5")); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_knowledge_graph.rs b/tests/unit/basic/basic_keywords_knowledge_graph.rs deleted file mode 100644 index ace5a32..0000000 --- a/tests/unit/basic/basic_keywords_knowledge_graph.rs +++ /dev/null @@ -1,110 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use serde_json; - - - - #[test] - - - fn test_default_config() { - let config = KnowledgeGraphConfig::default(); - assert!(config.enabled); - assert_eq!(config.backend, "postgresql"); - assert!(config.entity_types.contains(&"person".to_string())); - } - - #[test] - - - fn test_extraction_prompt() { - let manager = KnowledgeGraphManager::new(KnowledgeGraphConfig::default()); - let prompt = manager.generate_extraction_prompt("John works at Acme Corp."); - assert!(prompt.contains("John works at Acme Corp.")); - assert!(prompt.contains("ENTITY TYPES TO EXTRACT")); - } - - #[test] - - - fn test_parse_extraction_response() { - let manager = KnowledgeGraphManager::new(KnowledgeGraphConfig::default()); - let response = r#"{ - "entities": [ - { - "name": "John", - "canonical_name": "John Smith", - "entity_type": "person", - "confidence": 0.9, - "properties": {} - } - ], - "relationships": [ - { - "from_entity": "John", - "to_entity": "Acme Corp", - "relationship_type": "works_on", - "confidence": 0.85, - "evidence": "John works at Acme Corp" - } - ] - }"#; - - let result = manager.parse_extraction_response(response, 100, 50); - assert!(result.is_ok()); - let extraction = result.unwrap(); - assert_eq!(extraction.entities.len(), 1); - assert_eq!(extraction.relationships.len(), 1); - } - - #[test] - - - fn test_entity_to_dynamic() { - let entity = KgEntity { - id: Uuid::new_v4(), - bot_id: Uuid::new_v4(), - entity_type: "person".to_string(), - entity_name: "John Smith".to_string(), - aliases: vec!["John".to_string()], - properties: serde_json::json!({"department": "Sales"}), - confidence: 0.95, - source: EntitySource::Manual, - created_at: Utc::now(), - updated_at: Utc::now(), - }; - - let dynamic = entity.to_dynamic(); - assert!(dynamic.is::()); - } - - #[test] - - - fn test_is_valid_entity_type() { - let manager = KnowledgeGraphManager::new(KnowledgeGraphConfig::default()); - assert!(manager.is_valid_entity_type("person")); - assert!(manager.is_valid_entity_type("PERSON")); - assert!(manager.is_valid_entity_type("organization")); - assert!(!manager.is_valid_entity_type("unknown_type")); - } - - #[test] - - - fn test_json_to_dynamic() { - let json = serde_json::json!({ - "name": "test", - "count": 42, - "active": true, - "tags": ["a", "b"] - }); - - let dynamic = json_to_dynamic(&json); - assert!(dynamic.is::()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_lead_scoring.rs b/tests/unit/basic/basic_keywords_lead_scoring.rs deleted file mode 100644 index c243b29..0000000 --- a/tests/unit/basic/basic_keywords_lead_scoring.rs +++ /dev/null @@ -1,17 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_module_structure() { - - - assert!(true); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_llm_macros.rs b/tests/unit/basic/basic_keywords_llm_macros.rs deleted file mode 100644 index 48f11df..0000000 --- a/tests/unit/basic/basic_keywords_llm_macros.rs +++ /dev/null @@ -1,40 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_parse_calculate_result_integer() { - let result = parse_calculate_result("42").unwrap(); - assert_eq!(result.as_int().unwrap(), 42); - } - - #[test] - - - fn test_parse_calculate_result_float() { - let result = parse_calculate_result("3.14").unwrap(); - assert!((result.as_float().unwrap() - 3.14).abs() < 0.001); - } - - #[test] - - - fn test_parse_calculate_result_boolean() { - let result = parse_calculate_result("true").unwrap(); - assert!(result.as_bool().unwrap()); - } - - #[test] - - - fn test_build_translate_prompt() { - let prompt = build_translate_prompt("Hello", "Spanish"); - assert!(prompt.contains("Hello")); - assert!(prompt.contains("Spanish")); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_math_abs.rs b/tests/unit/basic/basic_keywords_math_abs.rs deleted file mode 100644 index b577ea6..0000000 --- a/tests/unit/basic/basic_keywords_math_abs.rs +++ /dev/null @@ -1,32 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_abs_positive() { - assert_eq!(42_i64.abs(), 42); - assert_eq!(3.14_f64.abs(), 3.14); - } - - #[test] - - - fn test_abs_negative() { - assert_eq!((-42_i64).abs(), 42); - assert_eq!((-3.14_f64).abs(), 3.14); - } - - #[test] - - - fn test_abs_zero() { - assert_eq!(0_i64.abs(), 0); - assert_eq!(0.0_f64.abs(), 0.0); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_math_aggregate.rs b/tests/unit/basic/basic_keywords_math_aggregate.rs deleted file mode 100644 index 686c018..0000000 --- a/tests/unit/basic/basic_keywords_math_aggregate.rs +++ /dev/null @@ -1,47 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - use rhai::Dynamic; - - #[test] - - - fn test_sum() { - let arr: Vec = vec![ - Dynamic::from(10_i64), - Dynamic::from(20_i64), - Dynamic::from(30_i64), - ]; - let sum: f64 = arr - .iter() - .filter_map(|v| v.as_int().ok().map(|i| i as f64)) - .sum(); - assert_eq!(sum, 60.0); - } - - #[test] - - - fn test_avg() { - let arr: Vec = vec![10.0, 20.0, 30.0]; - let sum: f64 = arr.iter().sum(); - let avg = sum / arr.len() as f64; - assert_eq!(avg, 20.0); - } - - #[test] - - - fn test_empty_array() { - let arr: Vec = vec![]; - let result = if arr.is_empty() { 0.0 } else { arr.iter().sum::() / arr.len() as f64 }; - assert_eq!(result, 0.0); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_math_basic_math.rs b/tests/unit/basic/basic_keywords_math_basic_math.rs deleted file mode 100644 index 4df62ee..0000000 --- a/tests/unit/basic/basic_keywords_math_basic_math.rs +++ /dev/null @@ -1,62 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_int() { - assert_eq!(3.9_f64.trunc() as i64, 3); - assert_eq!((-3.9_f64).trunc() as i64, -3); - } - - #[test] - - - fn test_floor_ceil() { - assert_eq!(3.7_f64.floor() as i64, 3); - assert_eq!(3.2_f64.ceil() as i64, 4); - } - - #[test] - - - fn test_minmax() { - assert_eq!(10_i64.max(5), 10); - assert_eq!(10_i64.min(5), 5); - } - - #[test] - - - fn test_mod() { - assert_eq!(17 % 5, 2); - } - - #[test] - - - fn test_sgn() { - assert_eq!((-5_i64).signum(), -1); - assert_eq!(5_i64.signum(), 1); - assert_eq!(0_i64.signum(), 0); - } - - #[test] - - - fn test_sqrt() { - assert!((16_f64.sqrt() - 4.0).abs() < 0.0001); - } - - #[test] - - - fn test_pow() { - assert!((2_f64.powf(8.0) - 256.0).abs() < 0.0001); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_math_minmax.rs b/tests/unit/basic/basic_keywords_math_minmax.rs deleted file mode 100644 index 07eed94..0000000 --- a/tests/unit/basic/basic_keywords_math_minmax.rs +++ /dev/null @@ -1,24 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_max_values() { - assert_eq!(10_i64.max(5), 10); - assert_eq!(3.5_f64.max(7.2), 7.2); - } - - #[test] - - - fn test_min_values() { - assert_eq!(10_i64.min(5), 5); - assert_eq!(3.5_f64.min(7.2), 3.5); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_math_random.rs b/tests/unit/basic/basic_keywords_math_random.rs deleted file mode 100644 index e603edf..0000000 --- a/tests/unit/basic/basic_keywords_math_random.rs +++ /dev/null @@ -1,17 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_mod() { - assert_eq!(17 % 5, 2); - assert_eq!(10 % 3, 1); - assert_eq!(0 % 5, 0); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_math_round.rs b/tests/unit/basic/basic_keywords_math_round.rs deleted file mode 100644 index 81cbe2d..0000000 --- a/tests/unit/basic/basic_keywords_math_round.rs +++ /dev/null @@ -1,28 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_round_basic() { - assert_eq!(3.7_f64.round() as i64, 4); - assert_eq!(3.2_f64.round() as i64, 3); - assert_eq!((-3.7_f64).round() as i64, -4); - } - - #[test] - - - fn test_round_decimals() { - let n = 2.71828_f64; - let decimals = 2; - let factor = 10_f64.powi(decimals); - let result = (n * factor).round() / factor; - assert!((result - 2.72).abs() < 0.001); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_math_trig.rs b/tests/unit/basic/basic_keywords_math_trig.rs deleted file mode 100644 index b16eb73..0000000 --- a/tests/unit/basic/basic_keywords_math_trig.rs +++ /dev/null @@ -1,44 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_sin() { - assert!((0.0_f64.sin() - 0.0).abs() < 0.0001); - } - - #[test] - - - fn test_cos() { - assert!((0.0_f64.cos() - 1.0).abs() < 0.0001); - } - - #[test] - - - fn test_log() { - assert!((100.0_f64.log10() - 2.0).abs() < 0.0001); - } - - #[test] - - - fn test_exp() { - assert!((0.0_f64.exp() - 1.0).abs() < 0.0001); - } - - #[test] - - - fn test_pi() { - assert!(std::f64::consts::PI > 3.14); - assert!(std::f64::consts::PI < 3.15); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_mcp_directory.rs b/tests/unit/basic/basic_keywords_mcp_directory.rs deleted file mode 100644 index 4838083..0000000 --- a/tests/unit/basic/basic_keywords_mcp_directory.rs +++ /dev/null @@ -1,56 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_parse_csv_columns() { - let loader = McpCsvLoader::new("./work", "test"); - - let cols = loader.parse_csv_columns("name,type,command"); - assert_eq!(cols, vec!["name", "type", "command"]); - - let cols = loader.parse_csv_columns( - "filesystem,stdio,npx,\"-y @modelcontextprotocol/server-filesystem\"", - ); - assert_eq!(cols.len(), 4); - assert_eq!(cols[3], "-y @modelcontextprotocol/server-filesystem"); - } - - #[test] - - - fn test_parse_args() { - let loader = McpCsvLoader::new("./work", "test"); - - let args = loader.parse_args("-y @modelcontextprotocol/server-filesystem /data"); - assert_eq!( - args, - vec!["-y", "@modelcontextprotocol/server-filesystem", "/data"] - ); - } - - #[test] - - - fn test_infer_server_type() { - let loader = McpCsvLoader::new("./work", "test"); - - assert!(matches!( - loader.infer_server_type("filesystem", "stdio", "npx"), - McpServerType::Filesystem - )); - assert!(matches!( - loader.infer_server_type("postgres", "stdio", "npx"), - McpServerType::Database - )); - assert!(matches!( - loader.infer_server_type("myapi", "http", "https://api.example.com"), - McpServerType::Web - )); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_messaging_send_template.rs b/tests/unit/basic/basic_keywords_messaging_send_template.rs deleted file mode 100644 index 04e7e2b..0000000 --- a/tests/unit/basic/basic_keywords_messaging_send_template.rs +++ /dev/null @@ -1,89 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - #[test] - - - fn test_send_template_valid_email() { - let result = send_template_message("welcome", "user@example.com", "email", None); - assert!(result.get("success").unwrap().as_bool().unwrap()); - } - - #[test] - - - fn test_send_template_invalid_email() { - let result = send_template_message("welcome", "invalid-email", "email", None); - assert!(!result.get("success").unwrap().as_bool().unwrap()); - } - - #[test] - - - fn test_send_template_invalid_channel() { - let result = send_template_message("welcome", "user@example.com", "invalid", None); - assert!(!result.get("success").unwrap().as_bool().unwrap()); - } - - #[test] - - - fn test_send_template_batch() { - let mut recipients = Array::new(); - recipients.push(Dynamic::from("user1@example.com")); - recipients.push(Dynamic::from("user2@example.com")); - - let result = send_template_batch("welcome", &recipients, "email", None); - assert_eq!(result.get("total").unwrap().as_int().unwrap(), 2); - assert_eq!(result.get("sent").unwrap().as_int().unwrap(), 2); - } - - #[test] - - - fn test_create_template() { - let result = create_message_template("test", "email", Some("Subject"), "Hello {{name}}!"); - assert!(result.get("success").unwrap().as_bool().unwrap()); - } - - #[test] - - - fn test_create_template_empty_name() { - let result = create_message_template("", "email", None, "Content"); - assert!(!result.get("success").unwrap().as_bool().unwrap()); - } - - #[test] - - - fn test_extract_template_variables() { - let content = "Hello {{name}}, your order {{order_id}} is ready!"; - let vars = extract_template_variables(content); - assert_eq!(vars.len(), 2); - } - - #[test] - - - fn test_extract_template_variables_empty() { - let content = "Hello, no variables here!"; - let vars = extract_template_variables(content); - assert!(vars.is_empty()); - } - - #[test] - - - fn test_generate_message_id() { - let id = generate_message_id(); - assert!(id.starts_with("msg_")); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_model_routing.rs b/tests/unit/basic/basic_keywords_model_routing.rs deleted file mode 100644 index 53b4f45..0000000 --- a/tests/unit/basic/basic_keywords_model_routing.rs +++ /dev/null @@ -1,92 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_model_router_new() { - let router = ModelRouter::new(); - assert_eq!(router.default_model, "default"); - assert!(router.models.is_empty()); - assert_eq!(router.routing_strategy, RoutingStrategy::Manual); - } - - #[test] - - - fn test_auto_routing_code() { - let mut router = ModelRouter::new(); - router.models.insert( - "code".to_string(), - ModelConfig { - name: "code".to_string(), - url: "http://localhost:8081".to_string(), - model_path: "codellama.gguf".to_string(), - api_key: None, - max_tokens: None, - temperature: None, - }, - ); - router.routing_strategy = RoutingStrategy::Auto; - - let result = router.route_query("Help me debug this code"); - assert_eq!(result, "code"); - } - - #[test] - - - fn test_auto_routing_quality() { - let mut router = ModelRouter::new(); - router.models.insert( - "quality".to_string(), - ModelConfig { - name: "quality".to_string(), - url: "http://localhost:8081".to_string(), - model_path: "large-model.gguf".to_string(), - api_key: None, - max_tokens: None, - temperature: None, - }, - ); - router.routing_strategy = RoutingStrategy::Auto; - - let result = - router.route_query("Please analyze and compare these two approaches in detail"); - assert_eq!(result, "quality"); - } - - #[test] - - - fn test_auto_routing_fast() { - let mut router = ModelRouter::new(); - router.models.insert( - "fast".to_string(), - ModelConfig { - name: "fast".to_string(), - url: "http://localhost:8081".to_string(), - model_path: "small-model.gguf".to_string(), - api_key: None, - max_tokens: None, - temperature: None, - }, - ); - router.routing_strategy = RoutingStrategy::Auto; - - let result = router.route_query("What is AI?"); - assert_eq!(result, "fast"); - } - - #[test] - - - fn test_routing_strategy_default() { - let strategy = RoutingStrategy::default(); - assert_eq!(strategy, RoutingStrategy::Manual); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_on_change.rs b/tests/unit/basic/basic_keywords_on_change.rs deleted file mode 100644 index d002839..0000000 --- a/tests/unit/basic/basic_keywords_on_change.rs +++ /dev/null @@ -1,208 +0,0 @@ -use botserver::basic::keywords::on_change::{ - detect_provider_from_email, is_cloud_path, parse_folder_path, sanitize_path_for_filename, - ChangeEventType, FolderChangeEvent, FolderMonitor, FolderProvider, -}; -use uuid::Uuid; - -#[test] -fn test_parse_folder_path_account() { - let (provider, email, path) = parse_folder_path("account://user@gmail.com/Documents/invoices"); - assert_eq!(provider, FolderProvider::GDrive); - assert_eq!(email, Some("user@gmail.com".to_string())); - assert_eq!(path, "/Documents/invoices"); -} - -#[test] -fn test_parse_folder_path_gdrive() { - let (provider, email, path) = parse_folder_path("gdrive:///shared/reports"); - assert_eq!(provider, FolderProvider::GDrive); - assert_eq!(email, None); - assert_eq!(path, "/shared/reports"); -} - -#[test] -fn test_parse_folder_path_onedrive() { - let (provider, email, path) = parse_folder_path("onedrive:///business/docs"); - assert_eq!(provider, FolderProvider::OneDrive); - assert_eq!(email, None); - assert_eq!(path, "/business/docs"); -} - -#[test] -fn test_parse_folder_path_dropbox() { - let (provider, email, path) = parse_folder_path("dropbox:///team/assets"); - assert_eq!(provider, FolderProvider::Dropbox); - assert_eq!(email, None); - assert_eq!(path, "/team/assets"); -} - -#[test] -fn test_parse_folder_path_local() { - let (provider, email, path) = parse_folder_path("/home/user/documents"); - assert_eq!(provider, FolderProvider::Local); - assert_eq!(email, None); - assert_eq!(path, "/home/user/documents"); -} - -#[test] -fn test_is_cloud_path() { - assert!(is_cloud_path("account://user@gmail.com/docs")); - assert!(is_cloud_path("gdrive:///shared")); - assert!(is_cloud_path("onedrive:///files")); - assert!(is_cloud_path("dropbox:///folder")); - assert!(!is_cloud_path("/local/path")); - assert!(!is_cloud_path("./relative/path")); -} - -#[test] -fn test_folder_provider_from_str() { - assert_eq!( - FolderProvider::from_str("gdrive"), - Some(FolderProvider::GDrive) - ); - assert_eq!( - FolderProvider::from_str("GDRIVE"), - Some(FolderProvider::GDrive) - ); - assert_eq!( - FolderProvider::from_str("googledrive"), - Some(FolderProvider::GDrive) - ); - assert_eq!( - FolderProvider::from_str("onedrive"), - Some(FolderProvider::OneDrive) - ); - assert_eq!( - FolderProvider::from_str("microsoft"), - Some(FolderProvider::OneDrive) - ); - assert_eq!( - FolderProvider::from_str("dropbox"), - Some(FolderProvider::Dropbox) - ); - assert_eq!( - FolderProvider::from_str("dbx"), - Some(FolderProvider::Dropbox) - ); - assert_eq!( - FolderProvider::from_str("local"), - Some(FolderProvider::Local) - ); - assert_eq!( - FolderProvider::from_str("filesystem"), - Some(FolderProvider::Local) - ); - assert_eq!(FolderProvider::from_str("unknown"), None); -} - -#[test] -fn test_change_event_type_from_str() { - assert_eq!( - ChangeEventType::from_str("create"), - Some(ChangeEventType::Create) - ); - assert_eq!( - ChangeEventType::from_str("created"), - Some(ChangeEventType::Create) - ); - assert_eq!( - ChangeEventType::from_str("modify"), - Some(ChangeEventType::Modify) - ); - assert_eq!( - ChangeEventType::from_str("changed"), - Some(ChangeEventType::Modify) - ); - assert_eq!( - ChangeEventType::from_str("delete"), - Some(ChangeEventType::Delete) - ); - assert_eq!( - ChangeEventType::from_str("removed"), - Some(ChangeEventType::Delete) - ); - assert_eq!( - ChangeEventType::from_str("rename"), - Some(ChangeEventType::Rename) - ); - assert_eq!( - ChangeEventType::from_str("move"), - Some(ChangeEventType::Move) - ); - assert_eq!(ChangeEventType::from_str("invalid"), None); -} - -#[test] -fn test_sanitize_path() { - assert_eq!( - sanitize_path_for_filename("/home/user/docs"), - "_home_user_docs" - ); - assert_eq!( - sanitize_path_for_filename("C:\\Users\\docs"), - "c__users_docs" - ); - assert_eq!( - sanitize_path_for_filename("path with spaces"), - "path_with_spaces" - ); -} - -#[test] -fn test_folder_monitor_struct() { - let monitor = FolderMonitor { - id: Uuid::new_v4(), - bot_id: Uuid::new_v4(), - provider: "gdrive".to_string(), - account_email: Some("user@gmail.com".to_string()), - folder_path: "/my/folder".to_string(), - folder_id: Some("folder123".to_string()), - script_path: "on_change.rhai".to_string(), - is_active: true, - watch_subfolders: true, - event_types: vec!["create".to_string(), "modify".to_string()], - }; - - assert_eq!(monitor.provider, "gdrive"); - assert!(monitor.is_active); - assert!(monitor.watch_subfolders); - assert_eq!(monitor.account_email, Some("user@gmail.com".to_string())); -} - -#[test] -fn test_folder_change_event_struct() { - let event = FolderChangeEvent { - id: Uuid::new_v4(), - monitor_id: Uuid::new_v4(), - event_type: "create".to_string(), - file_path: "/docs/new_file.pdf".to_string(), - file_id: Some("file123".to_string()), - file_name: Some("new_file.pdf".to_string()), - file_size: Some(1024), - mime_type: Some("application/pdf".to_string()), - old_path: None, - }; - - assert_eq!(event.event_type, "create"); - assert_eq!(event.file_size, Some(1024)); -} - -#[test] -fn test_detect_provider_from_email() { - assert_eq!( - detect_provider_from_email("user@gmail.com"), - FolderProvider::GDrive - ); - assert_eq!( - detect_provider_from_email("user@outlook.com"), - FolderProvider::OneDrive - ); - assert_eq!( - detect_provider_from_email("user@hotmail.com"), - FolderProvider::OneDrive - ); - assert_eq!( - detect_provider_from_email("user@company.com"), - FolderProvider::GDrive - ); -} diff --git a/tests/unit/basic/basic_keywords_on_email.rs b/tests/unit/basic/basic_keywords_on_email.rs deleted file mode 100644 index 12e04f5..0000000 --- a/tests/unit/basic/basic_keywords_on_email.rs +++ /dev/null @@ -1,198 +0,0 @@ -use botserver::basic::keywords::on_email::{ - is_email_path, parse_email_path, sanitize_email_for_filename, EmailAttachment, EmailMonitor, - EmailReceivedEvent, -}; -use uuid::Uuid; - -#[test] -fn test_email_monitor_struct() { - let monitor = EmailMonitor { - id: Uuid::new_v4(), - bot_id: Uuid::new_v4(), - email_address: "test@example.com".to_string(), - script_path: "on_email_test.rhai".to_string(), - is_active: true, - filter_from: None, - filter_subject: None, - }; - - assert_eq!(monitor.email_address, "test@example.com"); - assert!(monitor.is_active); - assert!(monitor.filter_from.is_none()); - assert!(monitor.filter_subject.is_none()); -} - -#[test] -fn test_email_monitor_with_filters() { - let monitor = EmailMonitor { - id: Uuid::new_v4(), - bot_id: Uuid::new_v4(), - email_address: "orders@company.com".to_string(), - script_path: "on_email_orders.rhai".to_string(), - is_active: true, - filter_from: Some("supplier@vendor.com".to_string()), - filter_subject: Some("Invoice".to_string()), - }; - - assert_eq!(monitor.email_address, "orders@company.com"); - assert_eq!(monitor.filter_from, Some("supplier@vendor.com".to_string())); - assert_eq!(monitor.filter_subject, Some("Invoice".to_string())); -} - -#[test] -fn test_email_attachment_struct() { - let attachment = EmailAttachment { - filename: "document.pdf".to_string(), - mime_type: "application/pdf".to_string(), - size: 1024, - }; - - assert_eq!(attachment.filename, "document.pdf"); - assert_eq!(attachment.mime_type, "application/pdf"); - assert_eq!(attachment.size, 1024); -} - -#[test] -fn test_email_received_event_struct() { - let event = EmailReceivedEvent { - id: Uuid::new_v4(), - monitor_id: Uuid::new_v4(), - message_uid: 12345, - message_id: Some("".to_string()), - from_address: "sender@example.com".to_string(), - to_addresses: vec!["recipient@example.com".to_string()], - subject: Some("Test Subject".to_string()), - has_attachments: true, - attachments: vec![EmailAttachment { - filename: "file.pdf".to_string(), - mime_type: "application/pdf".to_string(), - size: 2048, - }], - }; - - assert_eq!(event.message_uid, 12345); - assert_eq!(event.from_address, "sender@example.com"); - assert!(event.has_attachments); - assert_eq!(event.attachments.len(), 1); - assert_eq!(event.attachments[0].filename, "file.pdf"); -} - -#[test] -fn test_parse_email_path_basic() { - let result = parse_email_path("email://user@gmail.com"); - assert!(result.is_some()); - let (email, folder) = result.unwrap(); - assert_eq!(email, "user@gmail.com"); - assert!(folder.is_none()); -} - -#[test] -fn test_parse_email_path_with_folder() { - let result = parse_email_path("email://user@gmail.com/INBOX"); - assert!(result.is_some()); - let (email, folder) = result.unwrap(); - assert_eq!(email, "user@gmail.com"); - assert_eq!(folder, Some("INBOX".to_string())); -} - -#[test] -fn test_parse_email_path_invalid() { - assert!(parse_email_path("user@gmail.com").is_none()); - assert!(parse_email_path("mailto:user@gmail.com").is_none()); - assert!(parse_email_path("/local/path").is_none()); -} - -#[test] -fn test_is_email_path() { - assert!(is_email_path("email://user@gmail.com")); - assert!(is_email_path("email://user@company.com/INBOX")); - assert!(!is_email_path("user@gmail.com")); - assert!(!is_email_path("mailto:user@gmail.com")); - assert!(!is_email_path("account://user@gmail.com")); -} - -#[test] -fn test_sanitize_email_for_filename() { - assert_eq!( - sanitize_email_for_filename("user@gmail.com"), - "user_at_gmail_com" - ); - assert_eq!( - sanitize_email_for_filename("test.user@company.co.uk"), - "test_user_at_company_co_uk" - ); - assert_eq!( - sanitize_email_for_filename("USER@EXAMPLE.COM"), - "user_at_example_com" - ); -} - -#[test] -fn test_email_event_without_attachments() { - let event = EmailReceivedEvent { - id: Uuid::new_v4(), - monitor_id: Uuid::new_v4(), - message_uid: 1, - message_id: None, - from_address: "no-reply@system.com".to_string(), - to_addresses: vec![], - subject: None, - has_attachments: false, - attachments: vec![], - }; - - assert!(!event.has_attachments); - assert!(event.attachments.is_empty()); - assert!(event.subject.is_none()); -} - -#[test] -fn test_multiple_to_addresses() { - let event = EmailReceivedEvent { - id: Uuid::new_v4(), - monitor_id: Uuid::new_v4(), - message_uid: 999, - message_id: Some("".to_string()), - from_address: "sender@example.com".to_string(), - to_addresses: vec![ - "user1@example.com".to_string(), - "user2@example.com".to_string(), - "user3@example.com".to_string(), - ], - subject: Some("Group Message".to_string()), - has_attachments: false, - attachments: vec![], - }; - - assert_eq!(event.to_addresses.len(), 3); - assert!(event - .to_addresses - .contains(&"user2@example.com".to_string())); -} - -#[test] -fn test_multiple_attachments() { - let attachments = vec![ - EmailAttachment { - filename: "doc1.pdf".to_string(), - mime_type: "application/pdf".to_string(), - size: 1024, - }, - EmailAttachment { - filename: "image.png".to_string(), - mime_type: "image/png".to_string(), - size: 2048, - }, - EmailAttachment { - filename: "data.xlsx".to_string(), - mime_type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" - .to_string(), - size: 4096, - }, - ]; - - assert_eq!(attachments.len(), 3); - assert_eq!(attachments[0].filename, "doc1.pdf"); - assert_eq!(attachments[1].mime_type, "image/png"); - assert_eq!(attachments[2].size, 4096); -} diff --git a/tests/unit/basic/basic_keywords_play.rs b/tests/unit/basic/basic_keywords_play.rs deleted file mode 100644 index 9895216..0000000 --- a/tests/unit/basic/basic_keywords_play.rs +++ /dev/null @@ -1,94 +0,0 @@ -use botserver::basic::keywords::play::{ - detect_content_type, extract_title_from_source, ContentType, PlayOptions, -}; - -#[test] -fn test_content_type_from_extension() { - assert_eq!(ContentType::from_extension("mp4"), ContentType::Video); - assert_eq!(ContentType::from_extension("MP3"), ContentType::Audio); - assert_eq!(ContentType::from_extension("png"), ContentType::Image); - assert_eq!(ContentType::from_extension("pdf"), ContentType::Pdf); - assert_eq!(ContentType::from_extension("rs"), ContentType::Code); - assert_eq!( - ContentType::from_extension("pptx"), - ContentType::Presentation - ); - assert_eq!( - ContentType::from_extension("xlsx"), - ContentType::Spreadsheet - ); - assert_eq!(ContentType::from_extension("md"), ContentType::Markdown); -} - -#[test] -fn test_content_type_from_mime() { - assert_eq!(ContentType::from_mime("video/mp4"), ContentType::Video); - assert_eq!(ContentType::from_mime("audio/mpeg"), ContentType::Audio); - assert_eq!(ContentType::from_mime("image/png"), ContentType::Image); - assert_eq!(ContentType::from_mime("application/pdf"), ContentType::Pdf); -} - -#[test] -fn test_play_options_from_string() { - let opts = PlayOptions::from_string("autoplay,loop,muted"); - assert!(opts.autoplay); - assert!(opts.loop_content); - assert!(opts.muted); - assert!(!opts.fullscreen); - assert!(opts.controls); - - let opts = PlayOptions::from_string("fullscreen,nocontrols,start=10,end=60"); - assert!(opts.fullscreen); - assert!(!opts.controls); - assert_eq!(opts.start_time, Some(10.0)); - assert_eq!(opts.end_time, Some(60.0)); - - let opts = PlayOptions::from_string("theme=dark,zoom=1.5,page=3"); - assert_eq!(opts.theme, Some("dark".to_string())); - assert_eq!(opts.zoom, Some(1.5)); - assert_eq!(opts.page, Some(3)); -} - -#[test] -fn test_detect_content_type() { - assert_eq!( - detect_content_type("https://youtube.com/watch?v=123"), - ContentType::Video - ); - assert_eq!( - detect_content_type("https://example.com/video.mp4"), - ContentType::Video - ); - assert_eq!( - detect_content_type("https://imgur.com/abc123"), - ContentType::Image - ); - assert_eq!( - detect_content_type("presentation.pptx"), - ContentType::Presentation - ); - assert_eq!(detect_content_type("report.pdf"), ContentType::Pdf); - assert_eq!(detect_content_type("main.rs"), ContentType::Code); -} - -#[test] -fn test_extract_title_from_source() { - assert_eq!(extract_title_from_source("documents/report.pdf"), "report"); - assert_eq!( - extract_title_from_source("https://example.com/video.mp4?token=abc"), - "video" - ); - assert_eq!( - extract_title_from_source("presentation.pptx"), - "presentation" - ); -} - -#[test] -fn test_player_component() { - assert_eq!(ContentType::Video.player_component(), "video-player"); - assert_eq!(ContentType::Audio.player_component(), "audio-player"); - assert_eq!(ContentType::Image.player_component(), "image-viewer"); - assert_eq!(ContentType::Pdf.player_component(), "pdf-viewer"); - assert_eq!(ContentType::Code.player_component(), "code-viewer"); -} diff --git a/tests/unit/basic/basic_keywords_procedures.rs b/tests/unit/basic/basic_keywords_procedures.rs deleted file mode 100644 index d460797..0000000 --- a/tests/unit/basic/basic_keywords_procedures.rs +++ /dev/null @@ -1,181 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - fn setup() { - clear_procedures(); - } - - #[test] - - - fn test_preprocess_sub() { - setup(); - - let input = r#" -x = 1 -SUB MySub(a, b) - TALK a + b -END SUB -y = 2 -"#; - - let result = preprocess_subs(input); - - - assert!(!result.contains("SUB MySub")); - assert!(!result.contains("END SUB")); - assert!(result.contains("x = 1")); - assert!(result.contains("y = 2")); - - - assert!(has_procedure("MYSUB")); - let proc = get_procedure("MYSUB").unwrap(); - assert_eq!(proc.params.len(), 2); - assert!(!proc.is_function); - } - - #[test] - - - fn test_preprocess_function() { - setup(); - - let input = r#" -FUNCTION Add(a, b) - RETURN a + b -END FUNCTION -result = Add(1, 2) -"#; - - let result = preprocess_functions(input); - - - assert!(!result.contains("FUNCTION Add")); - assert!(!result.contains("END FUNCTION")); - assert!(result.contains("result = Add(1, 2)")); - - - assert!(has_procedure("ADD")); - let proc = get_procedure("ADD").unwrap(); - assert!(proc.is_function); - } - - #[test] - - - fn test_preprocess_sub_no_params() { - setup(); - - let input = r#" -SUB PrintHello - TALK "Hello" -END SUB -"#; - - preprocess_subs(input); - - assert!(has_procedure("PRINTHELLO")); - let proc = get_procedure("PRINTHELLO").unwrap(); - assert!(proc.params.is_empty()); - } - - #[test] - - - fn test_preprocess_call() { - setup(); - - - let sub_input = r#" -SUB Greet(name) - TALK "Hello " + name -END SUB -"#; - preprocess_subs(sub_input); - - - let call_input = "CALL Greet(\"World\")"; - let result = preprocess_calls(call_input); - - - assert!(result.contains("let name = \"World\"")); - assert!(result.contains("TALK \"Hello \" + name")); - } - - #[test] - - - fn test_eval_bool_condition() { - assert!(eval_bool_condition(&Dynamic::from(true))); - assert!(!eval_bool_condition(&Dynamic::from(false))); - assert!(eval_bool_condition(&Dynamic::from(1))); - assert!(!eval_bool_condition(&Dynamic::from(0))); - assert!(eval_bool_condition(&Dynamic::from(1.5))); - assert!(!eval_bool_condition(&Dynamic::from(0.0))); - assert!(eval_bool_condition(&Dynamic::from("hello"))); - assert!(!eval_bool_condition(&Dynamic::from(""))); - assert!(!eval_bool_condition(&Dynamic::from("false"))); - assert!(!eval_bool_condition(&Dynamic::from("0"))); - } - - #[test] - - - fn test_clear_procedures() { - setup(); - - let input = "SUB Test\n TALK \"test\"\nEND SUB"; - preprocess_subs(input); - - assert!(has_procedure("TEST")); - - clear_procedures(); - - assert!(!has_procedure("TEST")); - } - - #[test] - - - fn test_full_pipeline() { - setup(); - - let input = r#" -SUB SendGreeting(name, greeting) - TALK greeting + ", " + name + "!" -END SUB - -FUNCTION Calculate(x, y) - result = x * y + 10 - RETURN result -END FUNCTION - -' Main code -CALL SendGreeting("User", "Hello") -total = Calculate(5, 3) -"#; - - let result = preprocess_procedures(input); - - - assert!(result.contains("let name = \"User\"")); - assert!(result.contains("let greeting = \"Hello\"")); - - - assert!(!result.contains("SUB SendGreeting")); - assert!(!result.contains("END SUB")); - assert!(!result.contains("FUNCTION Calculate")); - assert!(!result.contains("END FUNCTION")); - - - assert!(has_procedure("SENDGREETING")); - assert!(has_procedure("CALCULATE")); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_qrcode.rs b/tests/unit/basic/basic_keywords_qrcode.rs deleted file mode 100644 index 5c4d8e9..0000000 --- a/tests/unit/basic/basic_keywords_qrcode.rs +++ /dev/null @@ -1,52 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_qr_code_generation() { - - - let result = QrCode::new(b"https://example.com"); - assert!(result.is_ok()); - } - - #[test] - - - fn test_qr_code_with_unicode() { - let result = QrCode::new("Hello 世界 🌍".as_bytes()); - assert!(result.is_ok()); - } - - #[test] - - - fn test_qr_code_long_data() { - let long_data = "A".repeat(1000); - let result = QrCode::new(long_data.as_bytes()); - assert!(result.is_ok()); - } - - #[test] - - - fn test_qr_code_url() { - let url = "https://example.com/path?param=value&other=123"; - let result = QrCode::new(url.as_bytes()); - assert!(result.is_ok()); - } - - #[test] - - - fn test_qr_code_json() { - let json = r#"{"id": 123, "name": "Test", "active": true}"#; - let result = QrCode::new(json.as_bytes()); - assert!(result.is_ok()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_remember.rs b/tests/unit/basic/basic_keywords_remember.rs deleted file mode 100644 index 70fe00d..0000000 --- a/tests/unit/basic/basic_keywords_remember.rs +++ /dev/null @@ -1,19 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_parse_duration() { - - assert!(parse_duration("30 days").is_ok()); - assert!(parse_duration("1 hour").is_ok()); - assert!(parse_duration("forever").is_ok()); - assert!(parse_duration("5 minutes").is_ok()); - assert!(parse_duration("invalid").is_err()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_save_from_unstructured.rs b/tests/unit/basic/basic_keywords_save_from_unstructured.rs deleted file mode 100644 index 0e4e150..0000000 --- a/tests/unit/basic/basic_keywords_save_from_unstructured.rs +++ /dev/null @@ -1,28 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_clean_value_for_type() { - assert_eq!(clean_value_for_type(&json!("test"), "text"), json!("test")); - assert_eq!(clean_value_for_type(&json!("42"), "integer"), json!(42)); - assert_eq!(clean_value_for_type(&json!("3.14"), "numeric"), json!(3.14)); - assert_eq!(clean_value_for_type(&json!("true"), "boolean"), json!(true)); - } - - #[test] - - - fn test_get_default_schema() { - let leads_schema = get_default_schema("leads"); - assert!(leads_schema.is_array()); - - let tasks_schema = get_default_schema("tasks"); - assert!(tasks_schema.is_array()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_send_mail.rs b/tests/unit/basic/basic_keywords_send_mail.rs deleted file mode 100644 index e7e4623..0000000 --- a/tests/unit/basic/basic_keywords_send_mail.rs +++ /dev/null @@ -1,31 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_apply_template_variables() { - let template = "Hello {{name}}, your order {{order_id}} is ready!"; - let vars = json!({ - "name": "John", - "order_id": "12345" - }); - - let result = apply_template_variables(template, &vars, "john@example.com").unwrap(); - assert!(result.contains("John")); - assert!(result.contains("12345")); - } - - #[test] - - - fn test_extract_template_subject() { - let content = "Subject: Welcome to our service\n\nHello there!"; - let subject = extract_template_subject(content); - assert_eq!(subject, Some("Welcome to our service".to_string())); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_send_template.rs b/tests/unit/basic/basic_keywords_send_template.rs deleted file mode 100644 index c243b29..0000000 --- a/tests/unit/basic/basic_keywords_send_template.rs +++ /dev/null @@ -1,17 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_module_structure() { - - - assert!(true); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_set_schedule.rs b/tests/unit/basic/basic_keywords_set_schedule.rs deleted file mode 100644 index e1c012c..0000000 --- a/tests/unit/basic/basic_keywords_set_schedule.rs +++ /dev/null @@ -1,164 +0,0 @@ -use botserver::basic::keywords::set_schedule::parse_natural_schedule; - -#[test] -fn test_every_minute() { - assert_eq!(parse_natural_schedule("every minute").unwrap(), "* * * * *"); -} - -#[test] -fn test_every_n_minutes() { - assert_eq!( - parse_natural_schedule("every 5 minutes").unwrap(), - "*/5 * * * *" - ); - assert_eq!( - parse_natural_schedule("every 15 minutes").unwrap(), - "*/15 * * * *" - ); - assert_eq!( - parse_natural_schedule("every 30 minutes").unwrap(), - "*/30 * * * *" - ); -} - -#[test] -fn test_every_hour() { - assert_eq!(parse_natural_schedule("every hour").unwrap(), "0 * * * *"); - assert_eq!(parse_natural_schedule("hourly").unwrap(), "0 * * * *"); -} - -#[test] -fn test_every_n_hours() { - assert_eq!( - parse_natural_schedule("every 2 hours").unwrap(), - "0 */2 * * *" - ); - assert_eq!( - parse_natural_schedule("every 6 hours").unwrap(), - "0 */6 * * *" - ); -} - -#[test] -fn test_every_day() { - assert_eq!(parse_natural_schedule("every day").unwrap(), "0 0 * * *"); - assert_eq!(parse_natural_schedule("daily").unwrap(), "0 0 * * *"); -} - -#[test] -fn test_every_week() { - assert_eq!(parse_natural_schedule("every week").unwrap(), "0 0 * * 0"); - assert_eq!(parse_natural_schedule("weekly").unwrap(), "0 0 * * 0"); -} - -#[test] -fn test_every_month() { - assert_eq!(parse_natural_schedule("every month").unwrap(), "0 0 1 * *"); - assert_eq!(parse_natural_schedule("monthly").unwrap(), "0 0 1 * *"); -} - -#[test] -fn test_at_time() { - assert_eq!(parse_natural_schedule("at 9am").unwrap(), "0 9 * * *"); - assert_eq!(parse_natural_schedule("at 9:30am").unwrap(), "30 9 * * *"); - assert_eq!(parse_natural_schedule("at 2pm").unwrap(), "0 14 * * *"); - assert_eq!(parse_natural_schedule("at 14:00").unwrap(), "0 14 * * *"); - assert_eq!(parse_natural_schedule("at midnight").unwrap(), "0 0 * * *"); - assert_eq!(parse_natural_schedule("at noon").unwrap(), "0 12 * * *"); -} - -#[test] -fn test_day_of_week() { - assert_eq!(parse_natural_schedule("every monday").unwrap(), "0 0 * * 1"); - assert_eq!(parse_natural_schedule("every friday").unwrap(), "0 0 * * 5"); - assert_eq!(parse_natural_schedule("every sunday").unwrap(), "0 0 * * 0"); -} - -#[test] -fn test_day_with_time() { - assert_eq!( - parse_natural_schedule("every monday at 9am").unwrap(), - "0 9 * * 1" - ); - assert_eq!( - parse_natural_schedule("every friday at 5pm").unwrap(), - "0 17 * * 5" - ); -} - -#[test] -fn test_weekdays() { - assert_eq!(parse_natural_schedule("weekdays").unwrap(), "0 0 * * 1-5"); - assert_eq!( - parse_natural_schedule("every weekday").unwrap(), - "0 0 * * 1-5" - ); - assert_eq!( - parse_natural_schedule("weekdays at 8am").unwrap(), - "0 8 * * 1-5" - ); -} - -#[test] -fn test_weekends() { - assert_eq!(parse_natural_schedule("weekends").unwrap(), "0 0 * * 0,6"); - assert_eq!( - parse_natural_schedule("every weekend").unwrap(), - "0 0 * * 0,6" - ); -} - -#[test] -fn test_combined() { - assert_eq!( - parse_natural_schedule("every day at 9am").unwrap(), - "0 9 * * *" - ); - assert_eq!( - parse_natural_schedule("every day at 6:30pm").unwrap(), - "30 18 * * *" - ); -} - -#[test] -fn test_hour_range() { - assert_eq!( - parse_natural_schedule("every hour from 9 to 17").unwrap(), - "0 9-17 * * *" - ); -} - -#[test] -fn test_business_hours() { - assert_eq!( - parse_natural_schedule("business hours").unwrap(), - "0 9-17 * * 1-5" - ); - assert_eq!( - parse_natural_schedule("every 30 minutes during business hours").unwrap(), - "*/30 9-17 * * 1-5" - ); - assert_eq!( - parse_natural_schedule("every hour during business hours").unwrap(), - "0 9-17 * * 1-5" - ); -} - -#[test] -fn test_raw_cron_passthrough() { - assert_eq!(parse_natural_schedule("0 * * * *").unwrap(), "0 * * * *"); - assert_eq!( - parse_natural_schedule("*/5 * * * *").unwrap(), - "*/5 * * * *" - ); - assert_eq!( - parse_natural_schedule("0 9-17 * * 1-5").unwrap(), - "0 9-17 * * 1-5" - ); -} - -#[test] -fn test_invalid_input() { - assert!(parse_natural_schedule("potato salad").is_err()); - assert!(parse_natural_schedule("every 100 minutes").is_err()); -} diff --git a/tests/unit/basic/basic_keywords_sms.rs b/tests/unit/basic/basic_keywords_sms.rs deleted file mode 100644 index 65e0406..0000000 --- a/tests/unit/basic/basic_keywords_sms.rs +++ /dev/null @@ -1,57 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_normalize_phone_us_10_digit() { - assert_eq!(normalize_phone_number("5551234567"), "+15551234567"); - } - - #[test] - - - fn test_normalize_phone_us_11_digit() { - assert_eq!(normalize_phone_number("15551234567"), "+15551234567"); - } - - #[test] - - - fn test_normalize_phone_with_plus() { - assert_eq!(normalize_phone_number("+15551234567"), "+15551234567"); - } - - #[test] - - - fn test_normalize_phone_with_formatting() { - assert_eq!(normalize_phone_number("+1 (555) 123-4567"), "+15551234567"); - } - - #[test] - - - fn test_normalize_phone_international() { - assert_eq!(normalize_phone_number("+44 7911 123456"), "+447911123456"); - } - - #[test] - - - fn test_sms_provider_from_str() { - assert_eq!(SmsProvider::from("twilio"), SmsProvider::Twilio); - assert_eq!(SmsProvider::from("aws_sns"), SmsProvider::AwsSns); - assert_eq!(SmsProvider::from("vonage"), SmsProvider::Vonage); - assert_eq!(SmsProvider::from("nexmo"), SmsProvider::Vonage); - assert_eq!(SmsProvider::from("messagebird"), SmsProvider::MessageBird); - assert_eq!( - SmsProvider::from("custom"), - SmsProvider::Custom("custom".to_string()) - ); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_social_get_metrics.rs b/tests/unit/basic/basic_keywords_social_get_metrics.rs deleted file mode 100644 index a0a4308..0000000 --- a/tests/unit/basic/basic_keywords_social_get_metrics.rs +++ /dev/null @@ -1,24 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_engagement_to_dynamic() { - let engagement = PostEngagement { - likes: 100, - comments: 20, - shares: 5, - views: 1000, - clicks: 50, - reach: 500, - }; - - let dynamic = engagement.to_dynamic(); - assert!(dynamic.is_map()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_social_media.rs b/tests/unit/basic/basic_keywords_social_media.rs deleted file mode 100644 index c243b29..0000000 --- a/tests/unit/basic/basic_keywords_social_media.rs +++ /dev/null @@ -1,17 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_module_structure() { - - - assert!(true); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_social_post_to_scheduled.rs b/tests/unit/basic/basic_keywords_social_post_to_scheduled.rs deleted file mode 100644 index fb63644..0000000 --- a/tests/unit/basic/basic_keywords_social_post_to_scheduled.rs +++ /dev/null @@ -1,21 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_parse_schedule_time() { - let result = parse_schedule_time("2025-02-01 10:00"); - assert!(result.is_ok()); - - let result = parse_schedule_time("2025-02-01T10:00:00"); - assert!(result.is_ok()); - - let result = parse_schedule_time("invalid"); - assert!(result.is_err()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_string_functions.rs b/tests/unit/basic/basic_keywords_string_functions.rs deleted file mode 100644 index 42095c4..0000000 --- a/tests/unit/basic/basic_keywords_string_functions.rs +++ /dev/null @@ -1,71 +0,0 @@ - - - -use botserver::basic::keywords::string_functions::{instr_impl, is_numeric_impl}; - - #[test] - - - fn test_instr_basic() { - assert_eq!(instr_impl(1, "Hello, World!", "World"), 8); - assert_eq!(instr_impl(1, "Hello, World!", "o"), 5); - assert_eq!(instr_impl(1, "Hello, World!", "xyz"), 0); - } - - #[test] - - - fn test_instr_with_start() { - assert_eq!(instr_impl(1, "one two one", "one"), 1); - assert_eq!(instr_impl(2, "one two one", "one"), 9); - assert_eq!(instr_impl(10, "one two one", "one"), 0); - } - - #[test] - - - fn test_instr_edge_cases() { - assert_eq!(instr_impl(1, "", "test"), 0); - assert_eq!(instr_impl(1, "test", ""), 0); - assert_eq!(instr_impl(1, "", ""), 0); - } - - #[test] - - - fn test_is_numeric_integers() { - assert!(is_numeric_impl("42")); - assert!(is_numeric_impl("-17")); - assert!(is_numeric_impl("0")); - assert!(is_numeric_impl(" 42 ")); - } - - #[test] - - - fn test_is_numeric_decimals() { - assert!(is_numeric_impl("3.14")); - assert!(is_numeric_impl("-0.5")); - assert!(is_numeric_impl(".25")); - assert!(is_numeric_impl("0.0")); - } - - #[test] - - - fn test_is_numeric_scientific() { - assert!(is_numeric_impl("1e10")); - assert!(is_numeric_impl("2.5E-3")); - assert!(is_numeric_impl("-1.5e+2")); - } - - #[test] - - - fn test_is_numeric_invalid() { - assert!(!is_numeric_impl("")); - assert!(!is_numeric_impl("abc")); - assert!(!is_numeric_impl("12abc")); - assert!(!is_numeric_impl("$100")); - assert!(!is_numeric_impl("1,000")); - } diff --git a/tests/unit/basic/basic_keywords_switch_case.rs b/tests/unit/basic/basic_keywords_switch_case.rs deleted file mode 100644 index c6daa61..0000000 --- a/tests/unit/basic/basic_keywords_switch_case.rs +++ /dev/null @@ -1,92 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - #[test] - - - fn test_switch_match_strings() { - let a = Dynamic::from("hello"); - let b = Dynamic::from("hello"); - let c = Dynamic::from("world"); - - assert!(switch_match_impl(&a, &b)); - assert!(!switch_match_impl(&a, &c)); - } - - #[test] - - - fn test_switch_match_integers() { - let a = Dynamic::from(42_i64); - let b = Dynamic::from(42_i64); - let c = Dynamic::from(0_i64); - - assert!(switch_match_impl(&a, &b)); - assert!(!switch_match_impl(&a, &c)); - } - - #[test] - - - fn test_switch_match_floats() { - let a = Dynamic::from(3.14_f64); - let b = Dynamic::from(3.14_f64); - let c = Dynamic::from(2.71_f64); - - assert!(switch_match_impl(&a, &b)); - assert!(!switch_match_impl(&a, &c)); - } - - #[test] - - - fn test_switch_match_mixed_numeric() { - let int_val = Dynamic::from(42_i64); - let float_val = Dynamic::from(42.0_f64); - - assert!(switch_match_impl(&int_val, &float_val)); - } - - #[test] - - - fn test_preprocess_simple_switch() { - let input = r#" -SWITCH role - CASE "admin" - x = 1 - CASE "user" - x = 2 - DEFAULT - x = 0 -END SWITCH -"#; - let output = preprocess_switch(input); - assert!(output.contains("__switch_expr_")); - assert!(output.contains("if")); - assert!(output.contains("else")); - } - - #[test] - - - fn test_preprocess_multiple_values() { - let input = r#" -SWITCH day - CASE "saturday", "sunday" - weekend = true - DEFAULT - weekend = false -END SWITCH -"#; - let output = preprocess_switch(input); - assert!(output.contains("||")); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_table_definition.rs b/tests/unit/basic/basic_keywords_table_definition.rs deleted file mode 100644 index 7a7b332..0000000 --- a/tests/unit/basic/basic_keywords_table_definition.rs +++ /dev/null @@ -1,147 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_parse_table_definition() { - let source = r#" -TABLE Contacts ON maria - Id number key - Nome string(150) - Email string(255) - Telefone string(20) -END TABLE -"#; - - let tables = parse_table_definition(source).unwrap(); - assert_eq!(tables.len(), 1); - - let table = &tables[0]; - assert_eq!(table.name, "Contacts"); - assert_eq!(table.connection_name, "maria"); - assert_eq!(table.fields.len(), 4); - - assert_eq!(table.fields[0].name, "Id"); - assert_eq!(table.fields[0].field_type, "number"); - assert!(table.fields[0].is_key); - - assert_eq!(table.fields[1].name, "Nome"); - assert_eq!(table.fields[1].field_type, "string"); - assert_eq!(table.fields[1].length, Some(150)); - } - - #[test] - - - fn test_parse_field_with_precision() { - let field = parse_field_definition("Preco double(10,2)", 0).unwrap(); - assert_eq!(field.name, "Preco"); - assert_eq!(field.field_type, "double"); - assert_eq!(field.length, Some(10)); - assert_eq!(field.precision, Some(2)); - } - - #[test] - - - fn test_generate_create_table_sql() { - let table = TableDefinition { - name: "TestTable".to_string(), - connection_name: "default".to_string(), - fields: vec![ - FieldDefinition { - name: "id".to_string(), - field_type: "number".to_string(), - length: None, - precision: None, - is_key: true, - is_nullable: false, - default_value: None, - reference_table: None, - field_order: 0, - }, - FieldDefinition { - name: "name".to_string(), - field_type: "string".to_string(), - length: Some(100), - precision: None, - is_key: false, - is_nullable: true, - default_value: None, - reference_table: None, - field_order: 1, - }, - ], - }; - - let sql = generate_create_table_sql(&table, "postgres"); - assert!(sql.contains("CREATE TABLE IF NOT EXISTS TestTable")); - assert!(sql.contains("id INTEGER NOT NULL")); - assert!(sql.contains("name VARCHAR(100)")); - assert!(sql.contains("PRIMARY KEY (id)")); - } - - #[test] - - - fn test_map_types() { - let field = FieldDefinition { - name: "test".to_string(), - field_type: "string".to_string(), - length: Some(50), - precision: None, - is_key: false, - is_nullable: true, - default_value: None, - reference_table: None, - field_order: 0, - }; - assert_eq!(map_type_to_sql(&field, "postgres"), "VARCHAR(50)"); - - let date_field = FieldDefinition { - name: "created".to_string(), - field_type: "datetime".to_string(), - length: None, - precision: None, - is_key: false, - is_nullable: true, - default_value: None, - reference_table: None, - field_order: 0, - }; - assert_eq!(map_type_to_sql(&date_field, "mysql"), "DATETIME"); - assert_eq!(map_type_to_sql(&date_field, "postgres"), "TIMESTAMP"); - } - - #[test] - - - fn test_sanitize_identifier() { - assert_eq!(sanitize_identifier("valid_name"), "valid_name"); - assert_eq!(sanitize_identifier("DROP TABLE; --"), "DROPTABLE"); - assert_eq!(sanitize_identifier("name123"), "name123"); - } - - #[test] - - - fn test_build_connection_string() { - let conn = ExternalConnection { - name: "test".to_string(), - driver: "mysql".to_string(), - server: "localhost".to_string(), - port: Some(3306), - database: "testdb".to_string(), - username: "user".to_string(), - password: "pass".to_string(), - }; - - let conn_str = build_connection_string(&conn); - assert_eq!(conn_str, "mysql://user:pass@localhost:3306/testdb"); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_transfer_to_human.rs b/tests/unit/basic/basic_keywords_transfer_to_human.rs deleted file mode 100644 index f3fb583..0000000 --- a/tests/unit/basic/basic_keywords_transfer_to_human.rs +++ /dev/null @@ -1,99 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_priority_to_int() { - assert_eq!(priority_to_int(Some("urgent")), 3); - assert_eq!(priority_to_int(Some("high")), 2); - assert_eq!(priority_to_int(Some("normal")), 1); - assert_eq!(priority_to_int(Some("low")), 0); - assert_eq!(priority_to_int(None), 1); - } - - #[test] - - - fn test_find_attendant_by_name() { - let attendants = vec![ - Attendant { - id: "att-001".to_string(), - name: "John Smith".to_string(), - channel: "all".to_string(), - preferences: "sales".to_string(), - department: Some("commercial".to_string()), - aliases: vec!["johnny".to_string(), "js".to_string()], - status: AttendantStatus::Online, - }, - Attendant { - id: "att-002".to_string(), - name: "Jane Doe".to_string(), - channel: "web".to_string(), - preferences: "support".to_string(), - department: Some("customer-service".to_string()), - aliases: vec![], - status: AttendantStatus::Online, - }, - ]; - - - let found = find_attendant(&attendants, Some("John Smith"), None); - assert!(found.is_some()); - assert_eq!(found.unwrap().id, "att-001"); - - - let found = find_attendant(&attendants, Some("john"), None); - assert!(found.is_some()); - assert_eq!(found.unwrap().id, "att-001"); - - - let found = find_attendant(&attendants, Some("johnny"), None); - assert!(found.is_some()); - assert_eq!(found.unwrap().id, "att-001"); - - - let found = find_attendant(&attendants, None, Some("customer-service")); - assert!(found.is_some()); - assert_eq!(found.unwrap().id, "att-002"); - } - - #[test] - - - fn test_transfer_result_to_dynamic() { - let result = TransferResult { - success: true, - status: TransferStatus::Assigned, - queue_position: Some(1), - assigned_to: Some("att-001".to_string()), - assigned_to_name: Some("John Smith".to_string()), - estimated_wait_seconds: Some(30), - message: "Connected to John".to_string(), - }; - - let dynamic = result.to_dynamic(); - let map = dynamic.try_cast::().unwrap(); - - assert_eq!( - map.get("success") - .unwrap() - .clone() - .try_cast::() - .unwrap(), - true - ); - assert_eq!( - map.get("assigned_to_name") - .unwrap() - .clone() - .try_cast::() - .unwrap(), - "John Smith" - ); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_use_account.rs b/tests/unit/basic/basic_keywords_use_account.rs deleted file mode 100644 index b95025a..0000000 --- a/tests/unit/basic/basic_keywords_use_account.rs +++ /dev/null @@ -1,35 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_parse_account_path() { - let result = parse_account_path("account://user@gmail.com/Documents/file.pdf"); - assert!(result.is_some()); - let (email, path) = result.unwrap(); - assert_eq!(email, "user@gmail.com"); - assert_eq!(path, "Documents/file.pdf"); - } - - #[test] - - - fn test_parse_account_path_invalid() { - assert!(parse_account_path("local/file.pdf").is_none()); - assert!(parse_account_path("/absolute/path").is_none()); - } - - #[test] - - - fn test_is_account_path() { - assert!(is_account_path("account://user@gmail.com/file.pdf")); - assert!(!is_account_path("local/file.pdf")); - assert!(!is_account_path("file.pdf")); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_use_kb.rs b/tests/unit/basic/basic_keywords_use_kb.rs deleted file mode 100644 index a6d2bea..0000000 --- a/tests/unit/basic/basic_keywords_use_kb.rs +++ /dev/null @@ -1,23 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; -use rhai::Engine; - - - - #[test] - - - fn test_use_kb_syntax() { - let mut engine = Engine::new(); - - - assert!(engine - .register_custom_syntax(&["USE_KB", "$expr$"], true, |_, _| Ok(Dynamic::UNIT)) - .is_ok()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_use_website.rs b/tests/unit/basic/basic_keywords_use_website.rs deleted file mode 100644 index e6bb25b..0000000 --- a/tests/unit/basic/basic_keywords_use_website.rs +++ /dev/null @@ -1,42 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; -use rhai::Engine; - - - - #[test] - - - fn test_url_sanitization() { - assert_eq!( - sanitize_url_for_collection("https://docs.example.com/path"), - "docs_example_com_path" - ); - assert_eq!( - sanitize_url_for_collection("http://test.site:8080"), - "test_site_8080" - ); - } - - #[test] - - - fn test_use_website_syntax() { - let mut engine = Engine::new(); - - - assert!(engine - .register_custom_syntax(&["USE_WEBSITE", "$expr$"], true, |_, _| Ok(Dynamic::UNIT)) - .is_ok()); - - - assert!(engine - .register_custom_syntax(&["CLEAR_WEBSITES"], true, |_, _| Ok(Dynamic::UNIT)) - .is_ok()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_user_memory.rs b/tests/unit/basic/basic_keywords_user_memory.rs deleted file mode 100644 index 9908db3..0000000 --- a/tests/unit/basic/basic_keywords_user_memory.rs +++ /dev/null @@ -1,16 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_fact_key_generation() { - let fact_key = format!("fact_{}", Uuid::new_v4()); - assert!(fact_key.starts_with("fact_")); - assert!(fact_key.len() > 5); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_validation_isempty.rs b/tests/unit/basic/basic_keywords_validation_isempty.rs deleted file mode 100644 index 4766e33..0000000 --- a/tests/unit/basic/basic_keywords_validation_isempty.rs +++ /dev/null @@ -1,77 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - use rhai::{Array, Map}; - - #[test] - - - fn test_empty_string() { - let value = Dynamic::from(""); - assert!(check_empty(&value)); - } - - #[test] - - - fn test_non_empty_string() { - let value = Dynamic::from("hello"); - assert!(!check_empty(&value)); - } - - #[test] - - - fn test_empty_array() { - let value = Dynamic::from(Array::new()); - assert!(check_empty(&value)); - } - - #[test] - - - fn test_non_empty_array() { - let mut arr = Array::new(); - arr.push(Dynamic::from(1)); - let value = Dynamic::from(arr); - assert!(!check_empty(&value)); - } - - #[test] - - - fn test_empty_map() { - let value = Dynamic::from(Map::new()); - assert!(check_empty(&value)); - } - - #[test] - - - fn test_unit() { - let value = Dynamic::UNIT; - assert!(check_empty(&value)); - } - - #[test] - - - fn test_number_not_empty() { - let value = Dynamic::from(0); - assert!(!check_empty(&value)); - } - - #[test] - - - fn test_bool_not_empty() { - let value = Dynamic::from(false); - assert!(!check_empty(&value)); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_validation_isnull.rs b/tests/unit/basic/basic_keywords_validation_isnull.rs deleted file mode 100644 index 3d7a282..0000000 --- a/tests/unit/basic/basic_keywords_validation_isnull.rs +++ /dev/null @@ -1,38 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - #[test] - - - - fn test_isnull_unit() { - use rhai::Dynamic; - let value = Dynamic::UNIT; - assert!(value.is_unit()); - } - - #[test] - - - fn test_isnull_not_unit() { - use rhai::Dynamic; - let value = Dynamic::from("test"); - assert!(!value.is_unit()); - } - - #[test] - - - fn test_isnull_number() { - use rhai::Dynamic; - let value = Dynamic::from(42); - assert!(!value.is_unit()); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_validation_nvl_iif.rs b/tests/unit/basic/basic_keywords_validation_nvl_iif.rs deleted file mode 100644 index 3bd1e5d..0000000 --- a/tests/unit/basic/basic_keywords_validation_nvl_iif.rs +++ /dev/null @@ -1,56 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_nvl_logic() { - let value = ""; - let default = "default"; - let result = if value.is_empty() { default } else { value }; - assert_eq!(result, "default"); - } - - #[test] - - - fn test_nvl_with_value() { - let value = "actual"; - let default = "default"; - let result = if value.is_empty() { default } else { value }; - assert_eq!(result, "actual"); - } - - #[test] - - - fn test_iif_true() { - let condition = true; - let result = if condition { "yes" } else { "no" }; - assert_eq!(result, "yes"); - } - - #[test] - - - fn test_iif_false() { - let condition = false; - let result = if condition { "yes" } else { "no" }; - assert_eq!(result, "no"); - } - - #[test] - - - fn test_choose() { - let index = 2; - let values = vec!["first", "second", "third"]; - let result = values.get((index - 1) as usize).unwrap_or(&""); - assert_eq!(*result, "second"); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_validation_str_val.rs b/tests/unit/basic/basic_keywords_validation_str_val.rs deleted file mode 100644 index 5eb20de..0000000 --- a/tests/unit/basic/basic_keywords_validation_str_val.rs +++ /dev/null @@ -1,27 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - - fn test_val_parsing() { - assert_eq!("123.45".trim().parse::().unwrap_or(0.0), 123.45); - assert_eq!(" 456 ".trim().parse::().unwrap_or(0.0), 456.0); - assert_eq!("abc".trim().parse::().unwrap_or(0.0), 0.0); - } - - #[test] - - - fn test_cint_rounding() { - assert_eq!(2.4_f64.round() as i64, 2); - assert_eq!(2.5_f64.round() as i64, 3); - assert_eq!(2.6_f64.round() as i64, 3); - assert_eq!((-2.5_f64).round() as i64, -3); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_validation_typeof_check.rs b/tests/unit/basic/basic_keywords_validation_typeof_check.rs deleted file mode 100644 index 92b8d0c..0000000 --- a/tests/unit/basic/basic_keywords_validation_typeof_check.rs +++ /dev/null @@ -1,33 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - #[test] - - - fn test_get_type_name() { - assert_eq!(get_type_name(&Dynamic::UNIT), "null"); - assert_eq!(get_type_name(&Dynamic::from(true)), "boolean"); - assert_eq!(get_type_name(&Dynamic::from(42_i64)), "integer"); - assert_eq!(get_type_name(&Dynamic::from(3.14_f64)), "float"); - assert_eq!(get_type_name(&Dynamic::from("hello")), "string"); - } - - #[test] - - - fn test_is_numeric() { - assert!(is_numeric(&Dynamic::from(42_i64))); - assert!(is_numeric(&Dynamic::from(3.14_f64))); - assert!(is_numeric(&Dynamic::from("123"))); - assert!(is_numeric(&Dynamic::from("3.14"))); - assert!(!is_numeric(&Dynamic::from("hello"))); - assert!(!is_numeric(&Dynamic::from(true))); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_weather.rs b/tests/unit/basic/basic_keywords_weather.rs deleted file mode 100644 index 634ba22..0000000 --- a/tests/unit/basic/basic_keywords_weather.rs +++ /dev/null @@ -1,44 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_degrees_to_compass() { - assert_eq!(degrees_to_compass(0.0), "N"); - assert_eq!(degrees_to_compass(45.0), "NE"); - assert_eq!(degrees_to_compass(90.0), "E"); - assert_eq!(degrees_to_compass(180.0), "S"); - assert_eq!(degrees_to_compass(270.0), "W"); - assert_eq!(degrees_to_compass(315.0), "NW"); - } - - #[test] - - - fn test_format_weather_response() { - let weather = WeatherData { - location: "London".to_string(), - temperature: 15.0, - temperature_unit: "°C".to_string(), - description: "Partly cloudy".to_string(), - humidity: 65, - wind_speed: 3.5, - wind_direction: "NE".to_string(), - feels_like: 14.0, - pressure: 1013, - visibility: 10.0, - uv_index: Some(3.0), - forecast: Vec::new(), - }; - - let response = format_weather_response(&weather); - assert!(response.contains("London")); - assert!(response.contains("15.0")); - assert!(response.contains("Partly cloudy")); - } \ No newline at end of file diff --git a/tests/unit/basic/basic_keywords_webhook.rs b/tests/unit/basic/basic_keywords_webhook.rs deleted file mode 100644 index ee524eb..0000000 --- a/tests/unit/basic/basic_keywords_webhook.rs +++ /dev/null @@ -1,85 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use rhai::Dynamic; - - - - #[test] - - - fn test_webhook_request_to_dynamic() { - let mut headers = std::collections::HashMap::new(); - headers.insert("Content-Type".to_string(), "application/json".to_string()); - - let mut params = std::collections::HashMap::new(); - params.insert("id".to_string(), "123".to_string()); - - let request = WebhookRequest::new( - "POST", - headers, - params, - json!({"order": "test"}), - "/webhook/order-received", - ); - - let dynamic = request.to_dynamic(); - assert!(dynamic.is_map()); - } - - #[test] - - - fn test_webhook_response_from_dynamic() { - let mut map = rhai::Map::new(); - map.insert("status".into(), Dynamic::from(201_i64)); - map.insert( - "body".into(), - Dynamic::from(json!({"message": "created"}).to_string()), - ); - - let dynamic = Dynamic::from(map); - let response = WebhookResponse::from_dynamic(&dynamic); - - assert_eq!(response.status, 201); - } - - #[test] - - - fn test_json_to_dynamic_and_back() { - let original = json!({ - "name": "test", - "count": 42, - "active": true, - "items": [1, 2, 3] - }); - - let dynamic = json_to_dynamic(&original); - let back = dynamic_to_json(&dynamic); - - assert_eq!(original["name"], back["name"]); - assert_eq!(original["count"], back["count"]); - assert_eq!(original["active"], back["active"]); - } - - #[test] - - - fn test_webhook_response_default() { - let response = WebhookResponse::default(); - assert_eq!(response.status, 200); - } - - #[test] - - - fn test_webhook_response_error() { - let response = WebhookResponse::error(404, "Not found"); - assert_eq!(response.status, 404); - assert_eq!(response.body["error"], "Not found"); - } \ No newline at end of file diff --git a/tests/unit/basic/mod.rs b/tests/unit/basic/mod.rs deleted file mode 100644 index 6f83578..0000000 --- a/tests/unit/basic/mod.rs +++ /dev/null @@ -1,77 +0,0 @@ - -mod basic_compiler_goto_transform; -mod basic_keywords_a2a_protocol; -mod basic_keywords_add_bot; -mod basic_keywords_add_member; -mod basic_keywords_add_suggestion; -mod basic_keywords_agent_reflection; -mod basic_keywords_arrays_contains; -mod basic_keywords_arrays_push_pop; -mod basic_keywords_arrays; -mod basic_keywords_arrays_slice; -mod basic_keywords_arrays_sort; -mod basic_keywords_arrays_unique; -mod basic_keywords_book; -mod basic_keywords_card; -mod basic_keywords_clear_kb; -mod basic_keywords_code_sandbox; -mod basic_keywords_core_functions; -mod basic_keywords_create_task; -mod basic_keywords_crm_attendance; -mod basic_keywords_crm_score_lead; -mod basic_keywords_data_operations; -mod basic_keywords_datetime_dateadd; -mod basic_keywords_datetime_extract; -mod basic_keywords_datetime_now; -mod basic_keywords_episodic_memory; -mod basic_keywords_errors_on_error; -mod basic_keywords_errors; -mod basic_keywords_errors_throw; -mod basic_keywords_file_operations; -mod basic_keywords_hear_talk; -mod basic_keywords_http_operations; -mod basic_keywords_human_approval; -mod basic_keywords_import_export; -mod basic_keywords_kb_statistics; -mod basic_keywords_knowledge_graph; -mod basic_keywords_lead_scoring; -mod basic_keywords_llm_macros; -mod basic_keywords_math_abs; -mod basic_keywords_math_aggregate; -mod basic_keywords_math_basic_math; -mod basic_keywords_math_minmax; -mod basic_keywords_math_random; -mod basic_keywords_math_round; -mod basic_keywords_math_trig; -mod basic_keywords_mcp_directory; -mod basic_keywords_messaging_send_template; -mod basic_keywords_model_routing; -mod basic_keywords_on_change; -mod basic_keywords_on_email; -mod basic_keywords_play; -mod basic_keywords_procedures; -mod basic_keywords_qrcode; -mod basic_keywords_remember; -mod basic_keywords_save_from_unstructured; -mod basic_keywords_send_mail; -mod basic_keywords_send_template; -mod basic_keywords_set_schedule; -mod basic_keywords_sms; -mod basic_keywords_social_get_metrics; -mod basic_keywords_social_media; -mod basic_keywords_social_post_to_scheduled; -mod basic_keywords_string_functions; -mod basic_keywords_switch_case; -mod basic_keywords_table_definition; -mod basic_keywords_transfer_to_human; -mod basic_keywords_use_account; -mod basic_keywords_use_kb; -mod basic_keywords_user_memory; -mod basic_keywords_use_website; -mod basic_keywords_validation_isempty; -mod basic_keywords_validation_isnull; -mod basic_keywords_validation_nvl_iif; -mod basic_keywords_validation_str_val; -mod basic_keywords_validation_typeof_check; -mod basic_keywords_weather; -mod basic_keywords_webhook; diff --git a/tests/unit/calendar/calendar.rs b/tests/unit/calendar/calendar.rs deleted file mode 100644 index d9afe88..0000000 --- a/tests/unit/calendar/calendar.rs +++ /dev/null @@ -1,53 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_event_to_ical_roundtrip() { - let event = CalendarEvent { - id: Uuid::new_v4(), - title: "Test Meeting".to_string(), - description: Some("A test meeting".to_string()), - start_time: Utc::now(), - end_time: Utc::now() + chrono::Duration::hours(1), - location: Some("Room 101".to_string()), - attendees: vec!["user@example.com".to_string()], - organizer: "organizer@example.com".to_string(), - reminder_minutes: Some(15), - recurrence: None, - created_at: Utc::now(), - updated_at: Utc::now(), - }; - - let ical = event.to_ical(); - assert_eq!(ical.get_summary(), Some("Test Meeting")); - assert_eq!(ical.get_location(), Some("Room 101")); - } - - #[test] - - - fn test_export_import_ical() { - let mut engine = CalendarEngine::new(); - engine.create_event(CalendarEventInput { - title: "Event 1".to_string(), - description: None, - start_time: Utc::now(), - end_time: Utc::now() + chrono::Duration::hours(1), - location: None, - attendees: vec![], - organizer: "test@example.com".to_string(), - reminder_minutes: None, - recurrence: None, - }); - - let ical = engine.export_ical("Test Calendar"); - assert!(ical.contains("BEGIN:VCALENDAR")); - assert!(ical.contains("Event 1")); - } \ No newline at end of file diff --git a/tests/unit/calendar/mod.rs b/tests/unit/calendar/mod.rs deleted file mode 100644 index 62c6d95..0000000 --- a/tests/unit/calendar/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ - -mod calendar; diff --git a/tests/unit/compliance/compliance.rs b/tests/unit/compliance/compliance.rs deleted file mode 100644 index 1b5b9db..0000000 --- a/tests/unit/compliance/compliance.rs +++ /dev/null @@ -1,45 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[tokio::test] - async fn test_compliance_monitor() { - let monitor = ComplianceMonitor::new(vec![ComplianceFramework::GDPR]); - let results = monitor.run_checks().await.unwrap(); - assert!(!results.is_empty()); - } - - #[test] - - - fn test_compliance_score() { - let results = vec![ - ComplianceCheckResult { - framework: ComplianceFramework::GDPR, - control_id: "test_1".to_string(), - control_name: "Test Control 1".to_string(), - status: ComplianceStatus::Compliant, - score: 100.0, - checked_at: Utc::now(), - issues: vec![], - evidence: vec![], - }, - ComplianceCheckResult { - framework: ComplianceFramework::GDPR, - control_id: "test_2".to_string(), - control_name: "Test Control 2".to_string(), - status: ComplianceStatus::Compliant, - score: 90.0, - checked_at: Utc::now(), - issues: vec![], - evidence: vec![], - }, - ]; - - let score = ComplianceMonitor::calculate_compliance_score(&results); - assert_eq!(score, 95.0); - } \ No newline at end of file diff --git a/tests/unit/compliance/compliance_code_scanner.rs b/tests/unit/compliance/compliance_code_scanner.rs deleted file mode 100644 index 9daae22..0000000 --- a/tests/unit/compliance/compliance_code_scanner.rs +++ /dev/null @@ -1,92 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_pattern_matching() { - let scanner = CodeScanner::new("/tmp/test"); - - - let password_pattern = scanner - .patterns - .iter() - .find(|p| matches!(p.issue_type, IssueType::PasswordInConfig)) - .unwrap(); - assert!(password_pattern.regex.is_match(r#"password = "secret123""#)); - assert!(password_pattern.regex.is_match(r#"PASSWORD = 'mypass'"#)); - - - let underscore_pattern = scanner - .patterns - .iter() - .find(|p| matches!(p.issue_type, IssueType::UnderscoreInKeyword)) - .unwrap(); - assert!(underscore_pattern.regex.is_match("GET_BOT_MEMORY")); - assert!(underscore_pattern.regex.is_match("SET_USER_MEMORY")); - } - - #[test] - - - fn test_severity_ordering() { - assert!(IssueSeverity::Critical > IssueSeverity::High); - assert!(IssueSeverity::High > IssueSeverity::Medium); - assert!(IssueSeverity::Medium > IssueSeverity::Low); - assert!(IssueSeverity::Low > IssueSeverity::Info); - } - - #[test] - - - fn test_stats_merge() { - let mut stats1 = ScanStats { - critical: 1, - high: 2, - medium: 3, - low: 4, - info: 5, - total: 15, - }; - - let stats2 = ScanStats { - critical: 1, - high: 1, - medium: 1, - low: 1, - info: 1, - total: 5, - }; - - stats1.merge(&stats2); - - assert_eq!(stats1.critical, 2); - assert_eq!(stats1.high, 3); - assert_eq!(stats1.total, 20); - } - - #[test] - - - fn test_csv_escape() { - assert_eq!(escape_csv("simple"), "simple"); - assert_eq!(escape_csv("with,comma"), "\"with,comma\""); - assert_eq!(escape_csv("with\"quote"), "\"with\"\"quote\""); - } - - #[test] - - - fn test_redact_sensitive() { - let scanner = CodeScanner::new("/tmp/test"); - - let line = r#"password = "supersecretpassword123""#; - let redacted = scanner.redact_sensitive(line); - assert!(redacted.contains("***REDACTED***")); - assert!(!redacted.contains("supersecretpassword123")); - } \ No newline at end of file diff --git a/tests/unit/compliance/mod.rs b/tests/unit/compliance/mod.rs deleted file mode 100644 index 6a48246..0000000 --- a/tests/unit/compliance/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ - -mod compliance_code_scanner; -mod compliance; diff --git a/tests/unit/console/console_wizard.rs b/tests/unit/console/console_wizard.rs deleted file mode 100644 index 94bb7e6..0000000 --- a/tests/unit/console/console_wizard.rs +++ /dev/null @@ -1,34 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_default_config() { - let config = WizardConfig::default(); - assert_eq!(config.llm_provider, LlmProvider::None); - assert!(!config.components.is_empty()); - } - - #[test] - - - fn test_slug_generation() { - let mut config = WizardConfig::default(); - config.organization.name = "My Test Company".to_string(); - config.organization.slug = config - .organization - .name - .to_lowercase() - .replace(' ', "-") - .chars() - .filter(|c| c.is_alphanumeric() || *c == '-') - .collect(); - - assert_eq!(config.organization.slug, "my-test-company"); - } \ No newline at end of file diff --git a/tests/unit/console/mod.rs b/tests/unit/console/mod.rs deleted file mode 100644 index eaa28e8..0000000 --- a/tests/unit/console/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ - -mod console_wizard; diff --git a/tests/unit/core/core_bot_manager.rs b/tests/unit/core/core_bot_manager.rs deleted file mode 100644 index c6e1a7b..0000000 --- a/tests/unit/core/core_bot_manager.rs +++ /dev/null @@ -1,65 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_sanitize_bot_name() { - let manager = BotManager::new("", "", "", "", PathBuf::new()); - - assert_eq!(manager.sanitize_bot_name("My Bot"), "mybot"); - assert_eq!(manager.sanitize_bot_name("test-bot"), "test-bot"); - assert_eq!(manager.sanitize_bot_name("Bot 123"), "bot123"); - assert_eq!(manager.sanitize_bot_name("--invalid--"), "invalid"); - assert_eq!(manager.sanitize_bot_name("my_bot_name"), "my_bot_name"); - } - - #[test] - - - fn test_bot_config_default() { - let settings = BotSettings::default(); - assert!(settings.knowledge_bases.is_empty()); - assert!(settings.channels.is_empty()); - } - - #[test] - - - fn test_bot_status_display() { - assert_eq!(format!("{}", BotStatus::Active), "Active"); - assert_eq!(format!("{}", BotStatus::Creating), "Creating"); - } - - #[test] - - - fn test_bot_route_from_config() { - let config = BotConfig { - id: Uuid::new_v4(), - name: "testbot".to_string(), - display_name: "Test Bot".to_string(), - org_id: Uuid::new_v4(), - org_slug: "myorg".to_string(), - template: None, - status: BotStatus::Active, - bucket: "myorg_testbot".to_string(), - custom_ui: Some("custom".to_string()), - settings: BotSettings::default(), - access: BotAccess::default(), - created_at: Utc::now(), - updated_at: Utc::now(), - created_by: Uuid::new_v4(), - }; - - let route = BotRoute::from(&config); - assert_eq!(route.name, "testbot"); - assert_eq!(route.org_slug, "myorg"); - assert_eq!(route.bucket, "myorg_testbot"); - assert_eq!(route.custom_ui, Some("custom".to_string())); - } \ No newline at end of file diff --git a/tests/unit/core/core_config_model_routing_config.rs b/tests/unit/core/core_config_model_routing_config.rs deleted file mode 100644 index 349e049..0000000 --- a/tests/unit/core/core_config_model_routing_config.rs +++ /dev/null @@ -1,105 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_default_config() { - let config = ModelRoutingConfig::default(); - assert_eq!(config.routing_strategy, RoutingStrategy::Default); - assert_eq!(config.default_model, "gpt-4o"); - assert!(config.fallback_enabled); - assert!(!config.fallback_order.is_empty()); - } - - #[test] - - - fn test_routing_strategy_from_str() { - assert_eq!(RoutingStrategy::from("default"), RoutingStrategy::Default); - assert_eq!( - RoutingStrategy::from("task-based"), - RoutingStrategy::TaskBased - ); - assert_eq!( - RoutingStrategy::from("round-robin"), - RoutingStrategy::RoundRobin - ); - assert_eq!(RoutingStrategy::from("latency"), RoutingStrategy::Latency); - assert_eq!(RoutingStrategy::from("cost"), RoutingStrategy::Cost); - assert_eq!(RoutingStrategy::from("custom"), RoutingStrategy::Custom); - assert_eq!(RoutingStrategy::from("unknown"), RoutingStrategy::Default); - } - - #[test] - - - fn test_get_model_for_task_default_strategy() { - let config = ModelRoutingConfig::default(); - assert_eq!(config.get_model_for_task(TaskType::Simple), "gpt-4o"); - assert_eq!(config.get_model_for_task(TaskType::Complex), "gpt-4o"); - assert_eq!(config.get_model_for_task(TaskType::Code), "gpt-4o"); - } - - #[test] - - - fn test_get_model_for_task_based_strategy() { - let config = ModelRoutingConfig { - routing_strategy: RoutingStrategy::TaskBased, - ..Default::default() - }; - assert_eq!(config.get_model_for_task(TaskType::Simple), "gpt-4o-mini"); - assert_eq!(config.get_model_for_task(TaskType::Complex), "gpt-4o"); - assert_eq!(config.get_model_for_task(TaskType::Code), "gpt-4o"); - } - - #[test] - - - fn test_get_fallback_model() { - let config = ModelRoutingConfig::default(); - assert_eq!(config.get_fallback_model("gpt-4o"), Some("gpt-4o-mini")); - assert_eq!( - config.get_fallback_model("gpt-4o-mini"), - Some("gpt-3.5-turbo") - ); - assert_eq!(config.get_fallback_model("gpt-3.5-turbo"), None); - assert_eq!(config.get_fallback_model("unknown-model"), None); - } - - #[test] - - - fn test_get_fallback_model_disabled() { - let config = ModelRoutingConfig { - fallback_enabled: false, - ..Default::default() - }; - assert_eq!(config.get_fallback_model("gpt-4o"), None); - } - - #[test] - - - fn test_get_all_models() { - let config = ModelRoutingConfig::default(); - let models = config.get_all_models(); - assert!(models.contains(&"gpt-4o")); - assert!(models.contains(&"gpt-4o-mini")); - assert!(models.contains(&"gpt-3.5-turbo")); - } - - #[test] - - - fn test_routing_strategy_display() { - assert_eq!(format!("{}", RoutingStrategy::Default), "default"); - assert_eq!(format!("{}", RoutingStrategy::TaskBased), "task-based"); - assert_eq!(format!("{}", RoutingStrategy::RoundRobin), "round-robin"); - } \ No newline at end of file diff --git a/tests/unit/core/core_config_sse_config.rs b/tests/unit/core/core_config_sse_config.rs deleted file mode 100644 index 96a839a..0000000 --- a/tests/unit/core/core_config_sse_config.rs +++ /dev/null @@ -1,53 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_default_config() { - let config = SseConfig::default(); - assert!(config.enabled); - assert_eq!(config.heartbeat_seconds, 30); - assert_eq!(config.max_connections, 1000); - } - - #[test] - - - fn test_can_accept_connection() { - let config = SseConfig::default(); - assert!(config.can_accept_connection(0)); - assert!(config.can_accept_connection(999)); - assert!(!config.can_accept_connection(1000)); - assert!(!config.can_accept_connection(1001)); - } - - #[test] - - - fn test_can_accept_connection_disabled() { - let config = SseConfig { - enabled: false, - ..Default::default() - }; - assert!(!config.can_accept_connection(0)); - } - - #[test] - - - fn test_heartbeat_duration() { - let config = SseConfig { - heartbeat_seconds: 45, - ..Default::default() - }; - assert_eq!( - config.heartbeat_duration(), - std::time::Duration::from_secs(45) - ); - } \ No newline at end of file diff --git a/tests/unit/core/core_config_user_memory_config.rs b/tests/unit/core/core_config_user_memory_config.rs deleted file mode 100644 index 9ae8486..0000000 --- a/tests/unit/core/core_config_user_memory_config.rs +++ /dev/null @@ -1,79 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_default_config() { - let config = UserMemoryConfig::default(); - assert!(config.enabled); - assert_eq!(config.max_keys, 100); - assert_eq!(config.default_ttl, 86400); - } - - #[test] - - - fn test_can_add_key() { - let config = UserMemoryConfig::default(); - assert!(config.can_add_key(0)); - assert!(config.can_add_key(99)); - assert!(!config.can_add_key(100)); - assert!(!config.can_add_key(101)); - } - - #[test] - - - fn test_can_add_key_disabled() { - let config = UserMemoryConfig { - enabled: false, - ..Default::default() - }; - assert!(!config.can_add_key(0)); - } - - #[test] - - - fn test_ttl_duration() { - let config = UserMemoryConfig { - default_ttl: 3600, - ..Default::default() - }; - assert_eq!( - config.ttl_duration(), - Some(std::time::Duration::from_secs(3600)) - ); - } - - #[test] - - - fn test_ttl_duration_no_expiration() { - let config = UserMemoryConfig { - default_ttl: 0, - ..Default::default() - }; - assert_eq!(config.ttl_duration(), None); - assert!(!config.has_expiration()); - } - - #[test] - - - fn test_has_expiration() { - let config = UserMemoryConfig::default(); - assert!(config.has_expiration()); - - let no_expiry = UserMemoryConfig { - default_ttl: 0, - ..Default::default() - }; - assert!(!no_expiry.has_expiration()); - } \ No newline at end of file diff --git a/tests/unit/core/core_kb.rs b/tests/unit/core/core_kb.rs deleted file mode 100644 index c2853ca..0000000 --- a/tests/unit/core/core_kb.rs +++ /dev/null @@ -1,28 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - use tempfile::TempDir; - - #[tokio::test] - async fn test_kb_manager_creation() { - let temp_dir = TempDir::new().unwrap(); - let manager = KnowledgeBaseManager::new(temp_dir.path()); - - - assert!(manager.processor.chunk_size() == 1000); - assert!(manager.processor.chunk_overlap() == 200); - } - - #[test] - - - fn test_collection_naming() { - let bot_name = "testbot"; - let kb_name = "docs"; - let collection_name = format!("{}_{}", bot_name, kb_name); - assert_eq!(collection_name, "testbot_docs"); - } \ No newline at end of file diff --git a/tests/unit/core/core_kb_document_processor.rs b/tests/unit/core/core_kb_document_processor.rs deleted file mode 100644 index be852b5..0000000 --- a/tests/unit/core/core_kb_document_processor.rs +++ /dev/null @@ -1,70 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_chunk_creation() { - let processor = DocumentProcessor::default(); - let text = "This is a test document with some content that needs to be chunked properly. " - .repeat(20); - let chunks = processor.create_chunks(&text, Path::new("test.txt")); - - - assert!(!chunks.is_empty()); - - - for chunk in &chunks { - assert!(chunk.content.len() <= processor.chunk_size); - } - - - if chunks.len() > 1 { - let first_end = &chunks[0].content[chunks[0].content.len().saturating_sub(100)..]; - let second_start = &chunks[1].content[..100.min(chunks[1].content.len())]; - - - assert!(first_end.chars().any(|c| second_start.contains(c))); - } - } - - #[test] - - - fn test_format_detection() { - assert_eq!( - DocumentFormat::from_extension(Path::new("test.pdf")), - Some(DocumentFormat::PDF) - ); - assert_eq!( - DocumentFormat::from_extension(Path::new("test.docx")), - Some(DocumentFormat::DOCX) - ); - assert_eq!( - DocumentFormat::from_extension(Path::new("test.txt")), - Some(DocumentFormat::TXT) - ); - assert_eq!( - DocumentFormat::from_extension(Path::new("test.md")), - Some(DocumentFormat::MD) - ); - assert_eq!( - DocumentFormat::from_extension(Path::new("test.unknown")), - None - ); - } - - #[test] - - - fn test_text_cleaning() { - let processor = DocumentProcessor::default(); - let dirty_text = " This is\n\n\na test\r\nwith multiple spaces "; - let cleaned = processor.clean_text(dirty_text); - assert_eq!(cleaned, "This is a test with multiple spaces"); - } \ No newline at end of file diff --git a/tests/unit/core/core_kb_embedding_generator.rs b/tests/unit/core/core_kb_embedding_generator.rs deleted file mode 100644 index 52cc287..0000000 --- a/tests/unit/core/core_kb_embedding_generator.rs +++ /dev/null @@ -1,30 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_dimension_detection() { - assert_eq!(EmbeddingConfig::detect_dimensions("bge-small-en"), 384); - assert_eq!(EmbeddingConfig::detect_dimensions("all-mpnet-base-v2"), 768); - assert_eq!( - EmbeddingConfig::detect_dimensions("text-embedding-ada-002"), - 1536 - ); - assert_eq!(EmbeddingConfig::detect_dimensions("unknown-model"), 384); - } - - #[tokio::test] - async fn test_text_cleaning_for_embedding() { - let text = "This is a test\n\nWith multiple lines"; - let _generator = EmbeddingGenerator::new("http://localhost:8082".to_string()); - - - - assert!(!text.is_empty()); - } \ No newline at end of file diff --git a/tests/unit/core/core_kb_kb_indexer.rs b/tests/unit/core/core_kb_kb_indexer.rs deleted file mode 100644 index db153bd..0000000 --- a/tests/unit/core/core_kb_kb_indexer.rs +++ /dev/null @@ -1,52 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_collection_name_generation() { - let bot_name = "mybot"; - let kb_name = "docs"; - let collection_name = format!("{}_{}", bot_name, kb_name); - assert_eq!(collection_name, "mybot_docs"); - } - - #[test] - - - fn test_qdrant_point_creation() { - let chunk = TextChunk { - content: "Test content".to_string(), - metadata: super::super::document_processor::ChunkMetadata { - document_path: "test.txt".to_string(), - document_title: Some("Test".to_string()), - chunk_index: 0, - total_chunks: 1, - start_char: 0, - end_char: 12, - page_number: None, - }, - }; - - let embedding = Embedding { - vector: vec![0.1, 0.2, 0.3], - dimensions: 3, - model: "test".to_string(), - tokens_used: None, - }; - - let indexer = KbIndexer::new(EmbeddingConfig::default(), QdrantConfig::default()); - - let points = indexer - .create_qdrant_points("test.txt", vec![(chunk, embedding)]) - .unwrap(); - - assert_eq!(points.len(), 1); - assert_eq!(points[0].vector.len(), 3); - assert!(points[0].payload.contains_key("content")); - } \ No newline at end of file diff --git a/tests/unit/core/core_oauth.rs b/tests/unit/core/core_oauth.rs deleted file mode 100644 index fb68adf..0000000 --- a/tests/unit/core/core_oauth.rs +++ /dev/null @@ -1,57 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_provider_from_str() { - assert_eq!( - OAuthProvider::from_str("google"), - Some(OAuthProvider::Google) - ); - assert_eq!( - OAuthProvider::from_str("DISCORD"), - Some(OAuthProvider::Discord) - ); - assert_eq!( - OAuthProvider::from_str("Twitter"), - Some(OAuthProvider::Twitter) - ); - assert_eq!(OAuthProvider::from_str("x"), Some(OAuthProvider::Twitter)); - assert_eq!(OAuthProvider::from_str("invalid"), None); - } - - #[test] - - - fn test_oauth_state_encode_decode() { - let state = OAuthState::new(OAuthProvider::Google, Some("/dashboard".to_string())); - let encoded = state.encode(); - let decoded = OAuthState::decode(&encoded).unwrap(); - - assert_eq!(decoded.provider, OAuthProvider::Google); - assert_eq!(decoded.redirect_after, Some("/dashboard".to_string())); - assert!(!decoded.is_expired()); - } - - #[test] - - - fn test_oauth_config_validation() { - let valid_config = OAuthConfig::new( - OAuthProvider::Google, - "client_id".to_string(), - "client_secret".to_string(), - "http://localhost/callback".to_string(), - ); - assert!(valid_config.is_valid()); - - let mut invalid_config = valid_config.clone(); - invalid_config.client_id = String::new(); - assert!(!invalid_config.is_valid()); - } \ No newline at end of file diff --git a/tests/unit/core/core_oauth_providers.rs b/tests/unit/core/core_oauth_providers.rs deleted file mode 100644 index 4efa53c..0000000 --- a/tests/unit/core/core_oauth_providers.rs +++ /dev/null @@ -1,69 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_build_auth_url() { - let config = OAuthConfig::new( - OAuthProvider::Google, - "test_client_id".to_string(), - "test_secret".to_string(), - "http://localhost:8300/callback".to_string(), - ); - - let url = OAuthProvider::Google.build_auth_url(&config, "test_state"); - - assert!(url.starts_with("https://accounts.google.com/o/oauth2/v2/auth?")); - assert!(url.contains("client_id=test_client_id")); - assert!(url.contains("state=test_state")); - assert!(url.contains("response_type=code")); - } - - #[test] - - - fn test_load_oauth_config() { - let mut bot_config = HashMap::new(); - bot_config.insert("oauth-google-enabled".to_string(), "true".to_string()); - bot_config.insert( - "oauth-google-client-id".to_string(), - "my_client_id".to_string(), - ); - bot_config.insert( - "oauth-google-client-secret".to_string(), - "my_secret".to_string(), - ); - - let config = load_oauth_config(OAuthProvider::Google, &bot_config, "http://localhost:8300"); - - assert!(config.is_some()); - let config = config.unwrap(); - assert_eq!(config.client_id, "my_client_id"); - assert!(config.redirect_uri.contains("/auth/oauth/google/callback")); - } - - #[test] - - - fn test_disabled_provider() { - let mut bot_config = HashMap::new(); - bot_config.insert("oauth-google-enabled".to_string(), "false".to_string()); - bot_config.insert( - "oauth-google-client-id".to_string(), - "my_client_id".to_string(), - ); - bot_config.insert( - "oauth-google-client-secret".to_string(), - "my_secret".to_string(), - ); - - let config = load_oauth_config(OAuthProvider::Google, &bot_config, "http://localhost:8300"); - - assert!(config.is_none()); - } \ No newline at end of file diff --git a/tests/unit/core/core_package_manager_cache.rs b/tests/unit/core/core_package_manager_cache.rs deleted file mode 100644 index 8f2d503..0000000 --- a/tests/unit/core/core_package_manager_cache.rs +++ /dev/null @@ -1,199 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - use std::io::Write; - use tempfile::TempDir; - - fn create_test_config(dir: &Path) -> Result<()> { - let config = r#" -[cache_settings] -cache_dir = "test-cache" - -[components.test] -name = "Test Component" -url = "https://example.com/test.tar.gz" -filename = "test.tar.gz" -sha256 = "" - -[models.test_model] -name = "Test Model" -url = "https://example.com/model.gguf" -filename = "model.gguf" -sha256 = "" -"#; - let config_path = dir.join(CONFIG_FILE); - fs::write(config_path, config)?; - Ok(()) - } - - #[test] - - - fn test_extract_filename() { - assert_eq!( - DownloadCache::extract_filename("https://example.com/path/file.tar.gz"), - "file.tar.gz" - ); - assert_eq!( - DownloadCache::extract_filename("https://example.com/file.zip?token=abc"), - "file.zip" - ); - assert_eq!(DownloadCache::extract_filename("https://example.com/"), ""); - } - - #[test] - - - fn test_cache_creation() -> Result<()> { - let temp_dir = TempDir::new()?; - create_test_config(temp_dir.path())?; - - let cache = DownloadCache::new(temp_dir.path())?; - - assert!(cache.cache_dir().exists()); - assert_eq!(cache.cache_dir().file_name().unwrap(), "test-cache"); - - Ok(()) - } - - #[test] - - - fn test_is_cached() -> Result<()> { - let temp_dir = TempDir::new()?; - create_test_config(temp_dir.path())?; - - let cache = DownloadCache::new(temp_dir.path())?; - - - assert!(!cache.is_cached("test.tar.gz")); - - - let cache_path = cache.get_cache_path("test.tar.gz"); - let mut file = fs::File::create(&cache_path)?; - file.write_all(b"test content")?; - - - assert!(cache.is_cached("test.tar.gz")); - - - let empty_path = cache.get_cache_path("empty.tar.gz"); - fs::File::create(&empty_path)?; - assert!(!cache.is_cached("empty.tar.gz")); - - Ok(()) - } - - #[test] - - - fn test_resolve_url() -> Result<()> { - let temp_dir = TempDir::new()?; - create_test_config(temp_dir.path())?; - - let cache = DownloadCache::new(temp_dir.path())?; - - - let result = cache.resolve_url("https://example.com/newfile.tar.gz"); - assert!(!result.is_cached()); - assert_eq!(result.url(), Some("https://example.com/newfile.tar.gz")); - - - let cache_path = cache.get_cache_path("newfile.tar.gz"); - let mut file = fs::File::create(&cache_path)?; - file.write_all(b"cached content")?; - - - let result = cache.resolve_url("https://example.com/newfile.tar.gz"); - assert!(result.is_cached()); - assert!(result.url().is_none()); - - Ok(()) - } - - #[test] - - - fn test_get_component() -> Result<()> { - let temp_dir = TempDir::new()?; - create_test_config(temp_dir.path())?; - - let cache = DownloadCache::new(temp_dir.path())?; - - let component = cache.get_component("test"); - assert!(component.is_some()); - assert_eq!(component.unwrap().name, "Test Component"); - - let missing = cache.get_component("nonexistent"); - assert!(missing.is_none()); - - Ok(()) - } - - #[test] - - - fn test_list_cached() -> Result<()> { - let temp_dir = TempDir::new()?; - create_test_config(temp_dir.path())?; - - let cache = DownloadCache::new(temp_dir.path())?; - - - fs::write(cache.get_cache_path("file1.tar.gz"), "content1")?; - fs::write(cache.get_cache_path("file2.zip"), "content2")?; - - let files = cache.list_cached()?; - assert_eq!(files.len(), 2); - assert!(files.contains(&"file1.tar.gz".to_string())); - assert!(files.contains(&"file2.zip".to_string())); - - Ok(()) - } - - #[test] - - - fn test_cache_size() -> Result<()> { - let temp_dir = TempDir::new()?; - create_test_config(temp_dir.path())?; - - let cache = DownloadCache::new(temp_dir.path())?; - - - assert_eq!(cache.cache_size()?, 0); - - - fs::write(cache.get_cache_path("file1.txt"), "12345")?; - fs::write(cache.get_cache_path("file2.txt"), "1234567890")?; - - assert_eq!(cache.cache_size()?, 15); - - Ok(()) - } - - #[test] - - - fn test_clear_cache() -> Result<()> { - let temp_dir = TempDir::new()?; - create_test_config(temp_dir.path())?; - - let cache = DownloadCache::new(temp_dir.path())?; - - - fs::write(cache.get_cache_path("file1.tar.gz"), "content1")?; - fs::write(cache.get_cache_path("file2.zip"), "content2")?; - - assert_eq!(cache.list_cached()?.len(), 2); - - cache.clear_cache()?; - - assert_eq!(cache.list_cached()?.len(), 0); - - Ok(()) - } \ No newline at end of file diff --git a/tests/unit/core/core_package_manager_setup_directory_setup.rs b/tests/unit/core/core_package_manager_setup_directory_setup.rs deleted file mode 100644 index 209514e..0000000 --- a/tests/unit/core/core_package_manager_setup_directory_setup.rs +++ /dev/null @@ -1,18 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_directory_setup_creation() { - let setup = DirectorySetup::new( - "http://localhost:8080".to_string(), - PathBuf::from("/tmp/directory_config.json"), - ); - assert_eq!(setup.base_url, "http://localhost:8080"); - } \ No newline at end of file diff --git a/tests/unit/core/core_package_manager_setup_email_setup.rs b/tests/unit/core/core_package_manager_setup_email_setup.rs deleted file mode 100644 index ebf2f3b..0000000 --- a/tests/unit/core/core_package_manager_setup_email_setup.rs +++ /dev/null @@ -1,33 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_email_setup_creation() { - let setup = EmailSetup::new( - "http://localhost:8080".to_string(), - PathBuf::from("/tmp/email_config.json"), - ); - assert_eq!(setup.base_url, "http://localhost:8080"); - } - - #[tokio::test] - async fn test_generate_config() { - let config_path = std::env::temp_dir().join("email_test_config.toml"); - let data_path = std::env::temp_dir().join("email_data"); - - generate_email_config(config_path.clone(), data_path, false) - .await - .unwrap(); - - assert!(config_path.exists()); - - - let _ = std::fs::remove_file(config_path); - } \ No newline at end of file diff --git a/tests/unit/core/core_rate_limit.rs b/tests/unit/core/core_rate_limit.rs deleted file mode 100644 index 64a4f39..0000000 --- a/tests/unit/core/core_rate_limit.rs +++ /dev/null @@ -1,49 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[tokio::test] - async fn test_keyed_rate_limiter() { - let limiter = KeyedRateLimiter::new(2, 2); - - - assert!(limiter.check("test_ip").await); - assert!(limiter.check("test_ip").await); - - - assert!(!limiter.check("test_ip").await); - - - assert!(limiter.check("other_ip").await); - } - - #[test] - - - fn test_rate_limit_config_default() { - let config = RateLimitConfig::default(); - assert_eq!(config.api_rps, 100); - assert_eq!(config.auth_rps, 10); - assert_eq!(config.llm_rps, 5); - assert!(config.enabled); - } - - #[test] - - - fn test_get_limiter_type() { - assert!(matches!(get_limiter_type("/api/users"), LimiterType::Api)); - assert!(matches!(get_limiter_type("/auth/login"), LimiterType::Auth)); - assert!(matches!( - get_limiter_type("/api/llm/chat"), - LimiterType::Llm - )); - assert!(matches!( - get_limiter_type("/api/chat/send"), - LimiterType::Llm - )); - } \ No newline at end of file diff --git a/tests/unit/core/core_secrets.rs b/tests/unit/core/core_secrets.rs deleted file mode 100644 index e063b29..0000000 --- a/tests/unit/core/core_secrets.rs +++ /dev/null @@ -1,75 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - - fn parse_database_url(url: &str) -> Result> { - let mut result = HashMap::new(); - if let Some(stripped) = url.strip_prefix("postgres://") { - let parts: Vec<&str> = stripped.split('@').collect(); - if parts.len() == 2 { - let user_pass: Vec<&str> = parts[0].split(':').collect(); - let host_db: Vec<&str> = parts[1].split('/').collect(); - - result.insert( - "username".to_string(), - user_pass.get(0).unwrap_or(&"").to_string(), - ); - result.insert( - "password".to_string(), - user_pass.get(1).unwrap_or(&"").to_string(), - ); - - let host_port: Vec<&str> = host_db[0].split(':').collect(); - result.insert( - "host".to_string(), - host_port.get(0).unwrap_or(&"").to_string(), - ); - result.insert( - "port".to_string(), - host_port.get(1).unwrap_or(&"5432").to_string(), - ); - - if host_db.len() >= 2 { - result.insert("database".to_string(), host_db[1].to_string()); - } - } - } - Ok(result) - } - - #[test] - - - fn test_parse_database_url() { - let parsed = parse_database_url("postgres://user:pass@localhost:5432/mydb").unwrap(); - assert_eq!(parsed.get("username"), Some(&"user".to_string())); - assert_eq!(parsed.get("password"), Some(&"pass".to_string())); - assert_eq!(parsed.get("host"), Some(&"localhost".to_string())); - assert_eq!(parsed.get("port"), Some(&"5432".to_string())); - assert_eq!(parsed.get("database"), Some(&"mydb".to_string())); - } - - #[test] - - - fn test_parse_database_url_minimal() { - let parsed = parse_database_url("postgres://user@localhost/mydb").unwrap(); - assert_eq!(parsed.get("username"), Some(&"user".to_string())); - assert_eq!(parsed.get("password"), Some(&"".to_string())); - assert_eq!(parsed.get("host"), Some(&"localhost".to_string())); - assert_eq!(parsed.get("port"), Some(&"5432".to_string())); - } - - #[test] - - - fn test_secret_paths() { - assert_eq!(SecretPaths::DIRECTORY, "gbo/directory"); - assert_eq!(SecretPaths::TABLES, "gbo/tables"); - assert_eq!(SecretPaths::LLM, "gbo/llm"); - } \ No newline at end of file diff --git a/tests/unit/core/core_shared_models.rs b/tests/unit/core/core_shared_models.rs deleted file mode 100644 index 9474d83..0000000 --- a/tests/unit/core/core_shared_models.rs +++ /dev/null @@ -1,35 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_trigger_kind_conversion() { - assert_eq!(TriggerKind::from_i32(0), Some(TriggerKind::Scheduled)); - assert_eq!(TriggerKind::from_i32(1), Some(TriggerKind::TableUpdate)); - assert_eq!(TriggerKind::from_i32(2), Some(TriggerKind::TableInsert)); - assert_eq!(TriggerKind::from_i32(3), Some(TriggerKind::TableDelete)); - assert_eq!(TriggerKind::from_i32(4), Some(TriggerKind::Webhook)); - assert_eq!(TriggerKind::from_i32(5), Some(TriggerKind::EmailReceived)); - assert_eq!(TriggerKind::from_i32(6), Some(TriggerKind::FolderChange)); - assert_eq!(TriggerKind::from_i32(99), None); - assert_eq!(TriggerKind::from_i32(-1), None); - } - - #[test] - - - fn test_trigger_kind_as_i32() { - assert_eq!(TriggerKind::Scheduled as i32, 0); - assert_eq!(TriggerKind::TableUpdate as i32, 1); - assert_eq!(TriggerKind::TableInsert as i32, 2); - assert_eq!(TriggerKind::TableDelete as i32, 3); - assert_eq!(TriggerKind::Webhook as i32, 4); - assert_eq!(TriggerKind::EmailReceived as i32, 5); - assert_eq!(TriggerKind::FolderChange as i32, 6); - } \ No newline at end of file diff --git a/tests/unit/core/core_shared_state.rs b/tests/unit/core/core_shared_state.rs deleted file mode 100644 index d051a80..0000000 --- a/tests/unit/core/core_shared_state.rs +++ /dev/null @@ -1,63 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[tokio::test] - async fn test_extensions_insert_and_get() { - let ext = Extensions::new(); - ext.insert(42i32).await; - ext.insert("hello".to_string()).await; - - let num = ext.get::().await; - assert!(num.is_some()); - assert_eq!(*num.unwrap(), 42); - - let text = ext.get::().await; - assert!(text.is_some()); - assert_eq!(&*text.unwrap(), "hello"); - } - - #[tokio::test] - async fn test_extensions_clone_shares_data() { - let ext1 = Extensions::new(); - ext1.insert(100u64).await; - - let ext2 = ext1.clone(); - - let val = ext2.get::().await; - assert!(val.is_some()); - assert_eq!(*val.unwrap(), 100); - - ext2.insert(200u32).await; - - let val2 = ext1.get::().await; - assert!(val2.is_some()); - assert_eq!(*val2.unwrap(), 200); - } - - #[tokio::test] - async fn test_extensions_remove() { - let ext = Extensions::new(); - ext.insert(42i32).await; - - assert!(ext.contains::().await); - assert_eq!(ext.len().await, 1); - - let removed = ext.remove::().await; - assert!(removed.is_some()); - assert_eq!(*removed.unwrap(), 42); - - assert!(!ext.contains::().await); - assert!(ext.is_empty().await); - } - - #[tokio::test] - async fn test_extensions_get_nonexistent() { - let ext = Extensions::new(); - let val = ext.get::().await; - assert!(val.is_none()); - } \ No newline at end of file diff --git a/tests/unit/core/core_shared_test_utils.rs b/tests/unit/core/core_shared_test_utils.rs deleted file mode 100644 index c6f4ffe..0000000 --- a/tests/unit/core/core_shared_test_utils.rs +++ /dev/null @@ -1,70 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use serde_json; - - - - #[test] - - - fn test_mock_channel_adapter_creation() { - let adapter = MockChannelAdapter::new("test"); - assert_eq!(adapter.name(), "test"); - assert!(adapter.is_configured()); - } - - #[cfg(feature = "llm")] - #[test] - - fn test_mock_llm_provider_creation() { - let provider = MockLLMProvider::new(); - assert_eq!(provider.response, "Mock LLM response"); - - let custom = MockLLMProvider::with_response("Custom response"); - assert_eq!(custom.response, "Custom response"); - } - - #[test] - - - fn test_builder_defaults() { - let builder = TestAppStateBuilder::new(); - assert_eq!(builder.bucket_name, "test-bucket"); - assert!(builder.database_url.is_none()); - assert!(builder.config.is_none()); - } - - #[cfg(feature = "llm")] - #[tokio::test] - async fn test_mock_llm_generate() { - let provider = MockLLMProvider::with_response("Test output"); - let result = provider - .generate("test prompt", &serde_json::json!({}), "model", "key") - .await; - assert!(result.is_ok()); - assert_eq!(result.unwrap(), "Test output"); - } - - #[tokio::test] - async fn test_mock_channel_send_message() { - let adapter = MockChannelAdapter::new("test_channel"); - let response = BotResponse { - session_id: "sess-1".to_string(), - user_id: "user-1".to_string(), - content: "Hello".to_string(), - channel: "test".to_string(), - ..Default::default() - }; - - let result = adapter.send_message(response.clone()).await; - assert!(result.is_ok()); - - let messages = adapter.get_sent_messages().await; - assert_eq!(messages.len(), 1); - assert_eq!(messages[0].content, "Hello"); - } \ No newline at end of file diff --git a/tests/unit/core/core_urls.rs b/tests/unit/core/core_urls.rs deleted file mode 100644 index 9b0844c..0000000 --- a/tests/unit/core/core_urls.rs +++ /dev/null @@ -1,34 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_with_params() { - let url = ApiUrls::with_params(ApiUrls::USER_BY_ID, &[("id", "123")]); - assert_eq!(url, "/api/users/123"); - } - - #[test] - - - fn test_with_query() { - let url = ApiUrls::with_query(ApiUrls::USERS, &[("page", "1"), ("limit", "10")]); - assert_eq!(url, "/api/users?page=1&limit=10"); - } - - #[test] - - - fn test_multiple_params() { - let url = ApiUrls::with_params( - ApiUrls::EMAIL_CLICK, - &[("campaign_id", "camp123"), ("email", "user@example.com")], - ); - assert_eq!(url, "/api/email/click/camp123/user@example.com"); - } \ No newline at end of file diff --git a/tests/unit/core/mod.rs b/tests/unit/core/mod.rs deleted file mode 100644 index 94de12c..0000000 --- a/tests/unit/core/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ - -mod core_bot_manager; -mod core_config_model_routing_config; -mod core_config_sse_config; -mod core_config_user_memory_config; -mod core_kb_document_processor; -mod core_kb_embedding_generator; -mod core_kb_kb_indexer; -mod core_kb; -mod core_oauth_providers; -mod core_oauth; -mod core_package_manager_cache; -mod core_package_manager_setup_directory_setup; -mod core_package_manager_setup_email_setup; -mod core_rate_limit; -mod core_secrets; -mod core_shared_models; -mod core_shared_state; -mod core_shared_test_utils; -mod core_urls; diff --git a/tests/unit/drive/drive_vectordb.rs b/tests/unit/drive/drive_vectordb.rs deleted file mode 100644 index 1c98264..0000000 --- a/tests/unit/drive/drive_vectordb.rs +++ /dev/null @@ -1,52 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_file_document_creation() { - let file = FileDocument { - id: "test-123".to_string(), - file_path: "/test/file.txt".to_string(), - file_name: "file.txt".to_string(), - file_type: "text".to_string(), - file_size: 1024, - bucket: "test-bucket".to_string(), - content_text: "Test file content".to_string(), - content_summary: Some("Summary".to_string()), - created_at: Utc::now(), - modified_at: Utc::now(), - indexed_at: Utc::now(), - mime_type: Some("text/plain".to_string()), - tags: vec!["test".to_string()], - }; - - assert_eq!(file.id, "test-123"); - assert_eq!(file.file_name, "file.txt"); - } - - #[test] - - - fn test_should_index() { - assert!(FileContentExtractor::should_index("text/plain", 1024)); - assert!(FileContentExtractor::should_index("text/markdown", 5000)); - assert!(!FileContentExtractor::should_index( - "text/plain", - 20 * 1024 * 1024 - )); - assert!(!FileContentExtractor::should_index("video/mp4", 1024)); - } - - #[tokio::test] - async fn test_user_drive_vectordb_creation() { - let temp_dir = std::env::temp_dir().join("test_drive_vectordb"); - let db = UserDriveVectorDB::new(Uuid::new_v4(), Uuid::new_v4(), temp_dir); - - assert!(db.collection_name.starts_with("drive_")); - } \ No newline at end of file diff --git a/tests/unit/drive/mod.rs b/tests/unit/drive/mod.rs deleted file mode 100644 index 3eb4e40..0000000 --- a/tests/unit/drive/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ - -mod drive_vectordb; diff --git a/tests/unit/email/email_stalwart_client.rs b/tests/unit/email/email_stalwart_client.rs deleted file mode 100644 index 3a36348..0000000 --- a/tests/unit/email/email_stalwart_client.rs +++ /dev/null @@ -1,141 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use botserver::email::stalwart_client::AccountUpdate; -use botserver::email::stalwart_client::AutoResponderConfig; -use botserver::email::stalwart_client::DeliveryStatus; -use botserver::email::stalwart_client::EmailRule; -use chrono::NaiveDate; -use botserver::email::stalwart_client::RuleAction; -use botserver::email::stalwart_client::RuleCondition; -use botserver::email::stalwart_client::StalwartClient; -use serde_json; - - - - #[test] - - - fn test_generate_vacation_sieve_basic() { - let client = StalwartClient::new("http://localhost", "test"); - let config = AutoResponderConfig { - enabled: true, - subject: "Out of Office".to_string(), - body_plain: "I am away.".to_string(), - body_html: None, - start_date: None, - end_date: None, - only_contacts: false, - vacation_days: 1, - }; - - let sieve = client.generate_vacation_sieve(&config); - assert!(sieve.contains("require")); - assert!(sieve.contains("vacation")); - assert!(sieve.contains("Out of Office")); - assert!(sieve.contains("I am away.")); - } - - #[test] - - - fn test_generate_vacation_sieve_with_dates() { - let client = StalwartClient::new("http://localhost", "test"); - let config = AutoResponderConfig { - enabled: true, - subject: "Vacation".to_string(), - body_plain: "On vacation.".to_string(), - body_html: None, - start_date: Some(NaiveDate::from_ymd_opt(2024, 12, 20).expect("valid date")), - end_date: Some(NaiveDate::from_ymd_opt(2024, 12, 31).expect("valid date")), - only_contacts: false, - vacation_days: 7, - }; - - let sieve = client.generate_vacation_sieve(&config); - assert!(sieve.contains("2024-12-20")); - assert!(sieve.contains("2024-12-31")); - assert!(sieve.contains(":days 7")); - } - - #[test] - - - fn test_generate_filter_sieve_move_rule() { - let client = StalwartClient::new("http://localhost", "test"); - let rule = EmailRule { - id: "rule1".to_string(), - name: "Move newsletters".to_string(), - priority: 0, - enabled: true, - conditions: vec![RuleCondition { - field: "from".to_string(), - operator: "contains".to_string(), - value: "newsletter".to_string(), - header_name: None, - case_sensitive: false, - }], - actions: vec![RuleAction { - action_type: "move".to_string(), - value: "Newsletters".to_string(), - }], - stop_processing: true, - }; - - let sieve = client.generate_filter_sieve(&rule); - assert!(sieve.contains("fileinto")); - assert!(sieve.contains("Newsletters")); - assert!(sieve.contains("From")); - assert!(sieve.contains("newsletter")); - assert!(sieve.contains("stop")); - } - - #[test] - - - fn test_generate_filter_sieve_disabled() { - let client = StalwartClient::new("http://localhost", "test"); - let rule = EmailRule { - id: "rule2".to_string(), - name: "Disabled rule".to_string(), - priority: 0, - enabled: false, - conditions: vec![], - actions: vec![], - stop_processing: false, - }; - - let sieve = client.generate_filter_sieve(&rule); - assert!(sieve.contains("DISABLED")); - } - - #[test] - fn test_account_update_builders() { - let set = AccountUpdate::set("description", "New description"); - assert_eq!(set.action, "set"); - assert_eq!(set.field, "description"); - - let add = AccountUpdate::add_item("members", "user@example.com"); - assert_eq!(add.action, "addItem"); - - let remove = AccountUpdate::remove_item("members", "old@example.com"); - assert_eq!(remove.action, "removeItem"); - - let clear = AccountUpdate::clear("members"); - assert_eq!(clear.action, "clear"); - } - - #[test] - fn test_delivery_status_deserialize() { - let json = r#""pending""#; - let status: DeliveryStatus = serde_json::from_str(json).expect("deserialize"); - assert_eq!(status, DeliveryStatus::Pending); - - let json = r#""unknown_status""#; - let status: DeliveryStatus = serde_json::from_str(json).expect("deserialize"); - assert_eq!(status, DeliveryStatus::Unknown); - } diff --git a/tests/unit/email/email_stalwart_sync.rs b/tests/unit/email/email_stalwart_sync.rs deleted file mode 100644 index 113bdff..0000000 --- a/tests/unit/email/email_stalwart_sync.rs +++ /dev/null @@ -1,99 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use botserver::email::stalwart_client::RuleAction; -use botserver::email::stalwart_client::RuleCondition; - - - - #[test] - - - fn test_new_distribution_list() { - let list = NewDistributionList { - bot_id: Uuid::new_v4(), - owner_id: Uuid::new_v4(), - name: "Test List".to_string(), - email_alias: "test@example.com".to_string(), - description: Some("A test list".to_string()), - members: vec![ - "user1@example.com".to_string(), - "user2@example.com".to_string(), - ], - }; - - assert_eq!(list.name, "Test List"); - assert_eq!(list.members.len(), 2); - } - - #[test] - - - fn test_new_auto_responder() { - let responder = NewAutoResponder { - bot_id: Uuid::new_v4(), - user_id: Uuid::new_v4(), - subject: "Out of Office".to_string(), - body_html: "

I am away

".to_string(), - body_plain: Some("I am away".to_string()), - start_date: Some(Utc::now()), - end_date: None, - only_contacts: false, - }; - - assert_eq!(responder.subject, "Out of Office"); - } - - #[test] - - - fn test_new_email_rule() { - let rule = NewEmailRule { - bot_id: Uuid::new_v4(), - user_id: Uuid::new_v4(), - name: "Move newsletters".to_string(), - priority: 10, - conditions: vec![RuleCondition { - field: "from".to_string(), - operator: "contains".to_string(), - value: "newsletter".to_string(), - header_name: None, - case_sensitive: false, - }], - actions: vec![RuleAction { - action_type: "move".to_string(), - value: "Newsletters".to_string(), - }], - stop_processing: true, - }; - - assert_eq!(rule.name, "Move newsletters"); - assert_eq!(rule.conditions.len(), 1); - assert_eq!(rule.actions.len(), 1); - } - - #[test] - - - fn test_distribution_list_dto() { - let dto = DistributionListDto { - id: Uuid::new_v4(), - bot_id: Uuid::new_v4(), - owner_id: Uuid::new_v4(), - name: "Sales Team".to_string(), - email_alias: Some("sales@example.com".to_string()), - description: Some("Sales distribution list".to_string()), - members: vec!["alice@example.com".to_string()], - is_public: false, - stalwart_principal_id: Some("123".to_string()), - created_at: Utc::now(), - updated_at: Utc::now(), - }; - - assert_eq!(dto.name, "Sales Team"); - assert!(dto.stalwart_principal_id.is_some()); - } \ No newline at end of file diff --git a/tests/unit/email/email_vectordb.rs b/tests/unit/email/email_vectordb.rs deleted file mode 100644 index 4a3be62..0000000 --- a/tests/unit/email/email_vectordb.rs +++ /dev/null @@ -1,37 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_email_document_creation() { - let email = EmailDocument { - id: "test-123".to_string(), - account_id: "account-456".to_string(), - from_email: "sender@example.com".to_string(), - from_name: "Test Sender".to_string(), - to_email: "receiver@example.com".to_string(), - subject: "Test Subject".to_string(), - body_text: "Test email body".to_string(), - date: Utc::now(), - folder: "INBOX".to_string(), - has_attachments: false, - thread_id: None, - }; - - assert_eq!(email.id, "test-123"); - assert_eq!(email.subject, "Test Subject"); - } - - #[tokio::test] - async fn test_user_email_vectordb_creation() { - let temp_dir = std::env::temp_dir().join("test_vectordb"); - let db = UserEmailVectorDB::new(Uuid::new_v4(), Uuid::new_v4(), temp_dir); - - assert!(db.collection_name.starts_with("emails_")); - } \ No newline at end of file diff --git a/tests/unit/email/mod.rs b/tests/unit/email/mod.rs deleted file mode 100644 index 9737e92..0000000 --- a/tests/unit/email/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ - -mod email_stalwart_client; -mod email_stalwart_sync; -mod email_vectordb; diff --git a/tests/unit/llm/llm_cache_test.rs b/tests/unit/llm/llm_cache_test.rs deleted file mode 100644 index 89b4863..0000000 --- a/tests/unit/llm/llm_cache_test.rs +++ /dev/null @@ -1,342 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use serde_json; - - - - use async_trait::async_trait; - use serde_json::json; - use std::sync::Arc; - use tokio::sync::mpsc; - - - struct MockLLMProvider { - response: String, - call_count: std::sync::atomic::AtomicUsize, - } - - impl MockLLMProvider { - fn new(response: &str) -> Self { - Self { - response: response.to_string(), - call_count: std::sync::atomic::AtomicUsize::new(0), - } - } - - fn get_call_count(&self) -> usize { - self.call_count.load(std::sync::atomic::Ordering::SeqCst) - } - } - - #[async_trait] - impl LLMProvider for MockLLMProvider { - async fn generate( - &self, - _prompt: &str, - _messages: &serde_json::Value, - _model: &str, - _key: &str, - ) -> Result> { - self.call_count - .fetch_add(1, std::sync::atomic::Ordering::SeqCst); - Ok(self.response.clone()) - } - - async fn generate_stream( - &self, - _prompt: &str, - _messages: &serde_json::Value, - tx: mpsc::Sender, - _model: &str, - _key: &str, - ) -> Result<(), Box> { - self.call_count - .fetch_add(1, std::sync::atomic::Ordering::SeqCst); - let _ = tx.send(self.response.clone()).await; - Ok(()) - } - - async fn cancel_job( - &self, - _session_id: &str, - ) -> Result<(), Box> { - Ok(()) - } - } - - - struct MockEmbeddingService; - - #[async_trait] - impl EmbeddingService for MockEmbeddingService { - async fn get_embedding( - &self, - text: &str, - ) -> Result, Box> { - - let hash = text.bytes().fold(0u32, |acc, b| acc.wrapping_add(b as u32)); - Ok(vec![hash as f32 / 255.0; 10]) - } - - async fn compute_similarity(&self, embedding1: &[f32], embedding2: &[f32]) -> f32 { - if embedding1.len() != embedding2.len() { - return 0.0; - } - - - let diff: f32 = embedding1 - .iter() - .zip(embedding2.iter()) - .map(|(a, b)| (a - b).abs()) - .sum(); - - 1.0 - (diff / embedding1.len() as f32).min(1.0) - } - } - - #[tokio::test] - async fn test_exact_cache_hit() { - - let mock_provider = Arc::new(MockLLMProvider::new("Test response")); - let cache_client = Arc::new(redis::Client::open("redis://127.0.0.1/").unwrap()); - - let config = CacheConfig { - ttl: 60, - semantic_matching: false, - similarity_threshold: 0.95, - max_similarity_checks: 10, - key_prefix: "test_cache".to_string(), - }; - - let cached_provider = - CachedLLMProvider::new(mock_provider.clone(), cache_client, config, None); - - let prompt = "What is the weather?"; - let messages = json!([{"role": "user", "content": prompt}]); - let model = "test-model"; - let key = "test-key"; - - - let result1 = cached_provider - .generate(prompt, &messages, model, key) - .await - .unwrap(); - assert_eq!(result1, "Test response"); - assert_eq!(mock_provider.get_call_count(), 1); - - - let result2 = cached_provider - .generate(prompt, &messages, model, key) - .await - .unwrap(); - assert_eq!(result2, "Test response"); - assert_eq!(mock_provider.get_call_count(), 1); - } - - #[tokio::test] - async fn test_semantic_cache_hit() { - - let mock_provider = Arc::new(MockLLMProvider::new("Weather is sunny")); - let cache_client = Arc::new(redis::Client::open("redis://127.0.0.1/").unwrap()); - - let config = CacheConfig { - ttl: 60, - semantic_matching: true, - similarity_threshold: 0.8, - max_similarity_checks: 10, - key_prefix: "test_semantic".to_string(), - }; - - let embedding_service = Arc::new(MockEmbeddingService); - let cached_provider = CachedLLMProvider::new( - mock_provider.clone(), - cache_client, - config, - Some(embedding_service), - ); - - let messages = json!([{"role": "user", "content": "test"}]); - let model = "test-model"; - let key = "test-key"; - - - let result1 = cached_provider - .generate("What's the weather?", &messages, model, key) - .await - .unwrap(); - assert_eq!(result1, "Weather is sunny"); - assert_eq!(mock_provider.get_call_count(), 1); - - - let result2 = cached_provider - .generate("What is the weather?", &messages, model, key) - .await - .unwrap(); - - - - - assert_eq!(result2, "Weather is sunny"); - assert_eq!(mock_provider.get_call_count(), 2); - } - - #[tokio::test] - async fn test_cache_miss_different_model() { - - let mock_provider = Arc::new(MockLLMProvider::new("Response")); - let cache_client = Arc::new(redis::Client::open("redis://127.0.0.1/").unwrap()); - - let config = CacheConfig::default(); - let cached_provider = - CachedLLMProvider::new(mock_provider.clone(), cache_client, config, None); - - let prompt = "Same prompt"; - let messages = json!([{"role": "user", "content": prompt}]); - let key = "test-key"; - - - let _ = cached_provider - .generate(prompt, &messages, "model1", key) - .await - .unwrap(); - assert_eq!(mock_provider.get_call_count(), 1); - - - let _ = cached_provider - .generate(prompt, &messages, "model2", key) - .await - .unwrap(); - assert_eq!(mock_provider.get_call_count(), 2); - } - - #[tokio::test] - async fn test_cache_statistics() { - - let mock_provider = Arc::new(MockLLMProvider::new("Response")); - let cache_client = Arc::new(redis::Client::open("redis://127.0.0.1/").unwrap()); - - let config = CacheConfig { - ttl: 60, - semantic_matching: false, - similarity_threshold: 0.95, - max_similarity_checks: 10, - key_prefix: "test_stats".to_string(), - }; - - let cached_provider = CachedLLMProvider::new(mock_provider, cache_client, config, None); - - - let _ = cached_provider.clear_cache(None).await; - - - let messages = json!([]); - for i in 0..5 { - let _ = cached_provider - .generate(&format!("prompt_{}", i), &messages, "model", "key") - .await; - } - - - for i in 0..3 { - let _ = cached_provider - .generate(&format!("prompt_{}", i), &messages, "model", "key") - .await; - } - - - let stats = cached_provider.get_cache_stats().await.unwrap(); - assert_eq!(stats.total_entries, 5); - assert_eq!(stats.total_hits, 3); - assert!(stats.total_size_bytes > 0); - assert_eq!(stats.model_distribution.get("model"), Some(&5)); - } - - #[tokio::test] - async fn test_stream_generation_with_cache() { - - let mock_provider = Arc::new(MockLLMProvider::new("Streamed response")); - let cache_client = Arc::new(redis::Client::open("redis://127.0.0.1/").unwrap()); - - let config = CacheConfig { - ttl: 60, - semantic_matching: false, - similarity_threshold: 0.95, - max_similarity_checks: 10, - key_prefix: "test_stream".to_string(), - }; - - let cached_provider = - CachedLLMProvider::new(mock_provider.clone(), cache_client, config, None); - - let prompt = "Stream this"; - let messages = json!([{"role": "user", "content": prompt}]); - let model = "test-model"; - let key = "test-key"; - - - let (tx1, mut rx1) = mpsc::channel(100); - cached_provider - .generate_stream(prompt, &messages, tx1, model, key) - .await - .unwrap(); - - let mut result1 = String::new(); - while let Some(chunk) = rx1.recv().await { - result1.push_str(&chunk); - } - assert_eq!(result1, "Streamed response"); - assert_eq!(mock_provider.get_call_count(), 1); - - - let (tx2, mut rx2) = mpsc::channel(100); - cached_provider - .generate_stream(prompt, &messages, tx2, model, key) - .await - .unwrap(); - - let mut result2 = String::new(); - while let Some(chunk) = rx2.recv().await { - result2.push_str(&chunk); - } - assert!(result2.contains("Streamed response")); - assert_eq!(mock_provider.get_call_count(), 1); - } - - #[test] - - - fn test_cosine_similarity_calculation() { - let service = LocalEmbeddingService::new( - "http://localhost:8082".to_string(), - "test-model".to_string(), - ); - - - let vec1 = vec![0.5, 0.5, 0.5]; - let vec2 = vec![0.5, 0.5, 0.5]; - let similarity = tokio::runtime::Runtime::new() - .unwrap() - .block_on(service.compute_similarity(&vec1, &vec2)); - assert_eq!(similarity, 1.0); - - - let vec3 = vec![1.0, 0.0]; - let vec4 = vec![0.0, 1.0]; - let similarity = tokio::runtime::Runtime::new() - .unwrap() - .block_on(service.compute_similarity(&vec3, &vec4)); - assert_eq!(similarity, 0.0); - - - let vec5 = vec![1.0, 1.0]; - let vec6 = vec![-1.0, -1.0]; - let similarity = tokio::runtime::Runtime::new() - .unwrap() - .block_on(service.compute_similarity(&vec5, &vec6)); - assert_eq!(similarity, -1.0); - } \ No newline at end of file diff --git a/tests/unit/llm/llm_observability.rs b/tests/unit/llm/llm_observability.rs deleted file mode 100644 index 1abcc2d..0000000 --- a/tests/unit/llm/llm_observability.rs +++ /dev/null @@ -1,130 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_default_config() { - let config = ObservabilityConfig::default(); - assert!(config.enabled); - assert!(config.cost_tracking); - assert_eq!(config.budget_daily, 100.0); - } - - #[test] - - - fn test_calculate_cost() { - let manager = ObservabilityManager::new(ObservabilityConfig::default()); - - - let cost = manager.calculate_cost("gpt-4", 1000, 500); - assert!(cost > 0.0); - - - let cost = manager.calculate_cost("local", 1000, 500); - assert_eq!(cost, 0.0); - - - let cost = manager.calculate_cost("unknown-model", 1000, 500); - assert_eq!(cost, 0.0); - } - - #[test] - - - fn test_quick_stats() { - let manager = ObservabilityManager::new(ObservabilityConfig::default()); - let stats = manager.get_quick_stats(); - - assert_eq!(stats.total_requests, 0); - assert_eq!(stats.total_tokens, 0); - assert_eq!(stats.cache_hit_rate, 0.0); - } - - #[test] - - - fn test_start_span() { - let manager = ObservabilityManager::new(ObservabilityConfig::default()); - let trace_id = Uuid::new_v4(); - let span = manager.start_span(trace_id, "test_operation", "test_component", None); - - assert_eq!(span.name, "test_operation"); - assert_eq!(span.component, "test_component"); - assert_eq!(span.status, TraceStatus::InProgress); - assert!(span.duration_ms.is_none()); - } - - #[test] - - - fn test_end_span() { - let manager = ObservabilityManager::new(ObservabilityConfig::default()); - let trace_id = Uuid::new_v4(); - let mut span = manager.start_span(trace_id, "test_operation", "test_component", None); - - - std::thread::sleep(std::time::Duration::from_millis(10)); - - manager.end_span(&mut span, TraceStatus::Ok, None); - - assert_eq!(span.status, TraceStatus::Ok); - assert!(span.duration_ms.is_some()); - assert!(span.end_time.is_some()); - } - - #[tokio::test] - async fn test_budget_status() { - let manager = ObservabilityManager::new(ObservabilityConfig::default()); - let status = manager.get_budget_status().await; - - assert_eq!(status.daily_limit, 100.0); - assert_eq!(status.daily_spend, 0.0); - assert!(!status.daily_exceeded); - } - - #[tokio::test] - async fn test_budget_check() { - let manager = ObservabilityManager::new(ObservabilityConfig::default()); - - - let result = manager.check_budget(1.0).await; - assert_eq!(result, BudgetCheckResult::Ok); - - - let result = manager.check_budget(150.0).await; - assert_eq!(result, BudgetCheckResult::DailyExceeded); - } - - #[test] - - - fn test_metrics_to_dynamic() { - let metrics = LLMRequestMetrics { - request_id: Uuid::new_v4(), - session_id: Uuid::new_v4(), - bot_id: Uuid::new_v4(), - model: "gpt-4".to_string(), - request_type: RequestType::Chat, - input_tokens: 100, - output_tokens: 50, - total_tokens: 150, - latency_ms: 500, - ttft_ms: Some(100), - cached: false, - success: true, - error: None, - estimated_cost: 0.01, - timestamp: Utc::now(), - metadata: HashMap::new(), - }; - - let dynamic = metrics.to_dynamic(); - assert!(dynamic.is::()); - } \ No newline at end of file diff --git a/tests/unit/llm/mod.rs b/tests/unit/llm/mod.rs deleted file mode 100644 index f1552b5..0000000 --- a/tests/unit/llm/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ - -mod llm_cache_test; -mod llm_observability; diff --git a/tests/unit/math_functions.rs b/tests/unit/math_functions.rs deleted file mode 100644 index 4bd2d0b..0000000 --- a/tests/unit/math_functions.rs +++ /dev/null @@ -1,490 +0,0 @@ - -use rhai::Engine; - - -#[test] -fn test_abs_positive() { - let mut engine = Engine::new(); - engine.register_fn("ABS", |n: i64| -> i64 { n.abs() }); - engine.register_fn("ABS", |n: f64| -> f64 { n.abs() }); - - let result: i64 = engine.eval("ABS(42)").unwrap(); - assert_eq!(result, 42); -} - -#[test] -fn test_abs_negative() { - let mut engine = Engine::new(); - engine.register_fn("ABS", |n: i64| -> i64 { n.abs() }); - - let result: i64 = engine.eval("ABS(-42)").unwrap(); - assert_eq!(result, 42); -} - -#[test] -fn test_abs_zero() { - let mut engine = Engine::new(); - engine.register_fn("ABS", |n: i64| -> i64 { n.abs() }); - - let result: i64 = engine.eval("ABS(0)").unwrap(); - assert_eq!(result, 0); -} - -#[test] -fn test_abs_float() { - let mut engine = Engine::new(); - engine.register_fn("ABS", |n: f64| -> f64 { n.abs() }); - - let result: f64 = engine.eval("ABS(-3.14)").unwrap(); - assert!((result - 3.14).abs() < f64::EPSILON); -} - - -#[test] -fn test_round_up() { - let mut engine = Engine::new(); - engine.register_fn("ROUND", |n: f64| -> i64 { n.round() as i64 }); - - let result: i64 = engine.eval("ROUND(3.7)").unwrap(); - assert_eq!(result, 4); -} - -#[test] -fn test_round_down() { - let mut engine = Engine::new(); - engine.register_fn("ROUND", |n: f64| -> i64 { n.round() as i64 }); - - let result: i64 = engine.eval("ROUND(3.2)").unwrap(); - assert_eq!(result, 3); -} - -#[test] -fn test_round_half() { - let mut engine = Engine::new(); - engine.register_fn("ROUND", |n: f64| -> i64 { n.round() as i64 }); - - let result: i64 = engine.eval("ROUND(3.5)").unwrap(); - assert_eq!(result, 4); -} - -#[test] -fn test_round_negative() { - let mut engine = Engine::new(); - engine.register_fn("ROUND", |n: f64| -> i64 { n.round() as i64 }); - - let result: i64 = engine.eval("ROUND(-3.7)").unwrap(); - assert_eq!(result, -4); -} - - -#[test] -fn test_int_positive() { - let mut engine = Engine::new(); - engine.register_fn("INT", |n: f64| -> i64 { n.trunc() as i64 }); - - let result: i64 = engine.eval("INT(3.9)").unwrap(); - assert_eq!(result, 3); -} - -#[test] -fn test_int_negative() { - let mut engine = Engine::new(); - engine.register_fn("INT", |n: f64| -> i64 { n.trunc() as i64 }); - - let result: i64 = engine.eval("INT(-3.9)").unwrap(); - assert_eq!(result, -3); -} - -#[test] -fn test_fix_alias() { - let mut engine = Engine::new(); - engine.register_fn("FIX", |n: f64| -> i64 { n.trunc() as i64 }); - - let result: i64 = engine.eval("FIX(7.8)").unwrap(); - assert_eq!(result, 7); -} - - -#[test] -fn test_floor_positive() { - let mut engine = Engine::new(); - engine.register_fn("FLOOR", |n: f64| -> i64 { n.floor() as i64 }); - - let result: i64 = engine.eval("FLOOR(3.9)").unwrap(); - assert_eq!(result, 3); -} - -#[test] -fn test_floor_negative() { - let mut engine = Engine::new(); - engine.register_fn("FLOOR", |n: f64| -> i64 { n.floor() as i64 }); - - let result: i64 = engine.eval("FLOOR(-3.1)").unwrap(); - assert_eq!(result, -4); -} - -#[test] -fn test_ceil_positive() { - let mut engine = Engine::new(); - engine.register_fn("CEIL", |n: f64| -> i64 { n.ceil() as i64 }); - - let result: i64 = engine.eval("CEIL(3.1)").unwrap(); - assert_eq!(result, 4); -} - -#[test] -fn test_ceil_negative() { - let mut engine = Engine::new(); - engine.register_fn("CEIL", |n: f64| -> i64 { n.ceil() as i64 }); - - let result: i64 = engine.eval("CEIL(-3.9)").unwrap(); - assert_eq!(result, -3); -} - - -#[test] -fn test_max_basic() { - let mut engine = Engine::new(); - engine.register_fn("MAX", |a: i64, b: i64| -> i64 { a.max(b) }); - - let result: i64 = engine.eval("MAX(5, 10)").unwrap(); - assert_eq!(result, 10); -} - -#[test] -fn test_max_first_larger() { - let mut engine = Engine::new(); - engine.register_fn("MAX", |a: i64, b: i64| -> i64 { a.max(b) }); - - let result: i64 = engine.eval("MAX(10, 5)").unwrap(); - assert_eq!(result, 10); -} - -#[test] -fn test_max_equal() { - let mut engine = Engine::new(); - engine.register_fn("MAX", |a: i64, b: i64| -> i64 { a.max(b) }); - - let result: i64 = engine.eval("MAX(7, 7)").unwrap(); - assert_eq!(result, 7); -} - -#[test] -fn test_max_negative() { - let mut engine = Engine::new(); - engine.register_fn("MAX", |a: i64, b: i64| -> i64 { a.max(b) }); - - let result: i64 = engine.eval("MAX(-5, -10)").unwrap(); - assert_eq!(result, -5); -} - -#[test] -fn test_min_basic() { - let mut engine = Engine::new(); - engine.register_fn("MIN", |a: i64, b: i64| -> i64 { a.min(b) }); - - let result: i64 = engine.eval("MIN(5, 10)").unwrap(); - assert_eq!(result, 5); -} - -#[test] -fn test_min_first_smaller() { - let mut engine = Engine::new(); - engine.register_fn("MIN", |a: i64, b: i64| -> i64 { a.min(b) }); - - let result: i64 = engine.eval("MIN(3, 8)").unwrap(); - assert_eq!(result, 3); -} - -#[test] -fn test_min_negative() { - let mut engine = Engine::new(); - engine.register_fn("MIN", |a: i64, b: i64| -> i64 { a.min(b) }); - - let result: i64 = engine.eval("MIN(-5, -10)").unwrap(); - assert_eq!(result, -10); -} - - -#[test] -fn test_mod_basic() { - let mut engine = Engine::new(); - engine.register_fn("MOD", |a: i64, b: i64| -> i64 { a % b }); - - let result: i64 = engine.eval("MOD(17, 5)").unwrap(); - assert_eq!(result, 2); -} - -#[test] -fn test_mod_no_remainder() { - let mut engine = Engine::new(); - engine.register_fn("MOD", |a: i64, b: i64| -> i64 { a % b }); - - let result: i64 = engine.eval("MOD(10, 5)").unwrap(); - assert_eq!(result, 0); -} - -#[test] -fn test_mod_smaller_dividend() { - let mut engine = Engine::new(); - engine.register_fn("MOD", |a: i64, b: i64| -> i64 { a % b }); - - let result: i64 = engine.eval("MOD(3, 10)").unwrap(); - assert_eq!(result, 3); -} - - -#[test] -fn test_sgn_positive() { - let mut engine = Engine::new(); - engine.register_fn("SGN", |n: i64| -> i64 { n.signum() }); - - let result: i64 = engine.eval("SGN(42)").unwrap(); - assert_eq!(result, 1); -} - -#[test] -fn test_sgn_negative() { - let mut engine = Engine::new(); - engine.register_fn("SGN", |n: i64| -> i64 { n.signum() }); - - let result: i64 = engine.eval("SGN(-42)").unwrap(); - assert_eq!(result, -1); -} - -#[test] -fn test_sgn_zero() { - let mut engine = Engine::new(); - engine.register_fn("SGN", |n: i64| -> i64 { n.signum() }); - - let result: i64 = engine.eval("SGN(0)").unwrap(); - assert_eq!(result, 0); -} - - -#[test] -fn test_sqrt_perfect_square() { - let mut engine = Engine::new(); - engine.register_fn("SQRT", |n: f64| -> f64 { n.sqrt() }); - - let result: f64 = engine.eval("SQRT(16.0)").unwrap(); - assert!((result - 4.0).abs() < f64::EPSILON); -} - -#[test] -fn test_sqrt_non_perfect() { - let mut engine = Engine::new(); - engine.register_fn("SQRT", |n: f64| -> f64 { n.sqrt() }); - - let result: f64 = engine.eval("SQRT(2.0)").unwrap(); - assert!((result - std::f64::consts::SQRT_2).abs() < 0.00001); -} - -#[test] -fn test_sqr_alias() { - let mut engine = Engine::new(); - engine.register_fn("SQR", |n: f64| -> f64 { n.sqrt() }); - - let result: f64 = engine.eval("SQR(25.0)").unwrap(); - assert!((result - 5.0).abs() < f64::EPSILON); -} - - -#[test] -fn test_pow_basic() { - let mut engine = Engine::new(); - engine.register_fn("POW", |base: f64, exp: f64| -> f64 { base.powf(exp) }); - - let result: f64 = engine.eval("POW(2.0, 10.0)").unwrap(); - assert!((result - 1024.0).abs() < f64::EPSILON); -} - -#[test] -fn test_pow_zero_exponent() { - let mut engine = Engine::new(); - engine.register_fn("POW", |base: f64, exp: f64| -> f64 { base.powf(exp) }); - - let result: f64 = engine.eval("POW(5.0, 0.0)").unwrap(); - assert!((result - 1.0).abs() < f64::EPSILON); -} - -#[test] -fn test_pow_square_root() { - let mut engine = Engine::new(); - engine.register_fn("POW", |base: f64, exp: f64| -> f64 { base.powf(exp) }); - - let result: f64 = engine.eval("POW(9.0, 0.5)").unwrap(); - assert!((result - 3.0).abs() < 0.00001); -} - - -#[test] -fn test_log_e() { - let mut engine = Engine::new(); - engine.register_fn("LOG", |n: f64| -> f64 { n.ln() }); - - let e = std::f64::consts::E; - let result: f64 = engine.eval(&format!("LOG({})", e)).unwrap(); - assert!((result - 1.0).abs() < 0.00001); -} - -#[test] -fn test_log10_hundred() { - let mut engine = Engine::new(); - engine.register_fn("LOG10", |n: f64| -> f64 { n.log10() }); - - let result: f64 = engine.eval("LOG10(100.0)").unwrap(); - assert!((result - 2.0).abs() < f64::EPSILON); -} - -#[test] -fn test_exp_zero() { - let mut engine = Engine::new(); - engine.register_fn("EXP", |n: f64| -> f64 { n.exp() }); - - let result: f64 = engine.eval("EXP(0.0)").unwrap(); - assert!((result - 1.0).abs() < f64::EPSILON); -} - -#[test] -fn test_exp_one() { - let mut engine = Engine::new(); - engine.register_fn("EXP", |n: f64| -> f64 { n.exp() }); - - let result: f64 = engine.eval("EXP(1.0)").unwrap(); - assert!((result - std::f64::consts::E).abs() < 0.00001); -} - - -#[test] -fn test_sin_zero() { - let mut engine = Engine::new(); - engine.register_fn("SIN", |n: f64| -> f64 { n.sin() }); - - let result: f64 = engine.eval("SIN(0.0)").unwrap(); - assert!((result - 0.0).abs() < f64::EPSILON); -} - -#[test] -fn test_cos_zero() { - let mut engine = Engine::new(); - engine.register_fn("COS", |n: f64| -> f64 { n.cos() }); - - let result: f64 = engine.eval("COS(0.0)").unwrap(); - assert!((result - 1.0).abs() < f64::EPSILON); -} - -#[test] -fn test_tan_zero() { - let mut engine = Engine::new(); - engine.register_fn("TAN", |n: f64| -> f64 { n.tan() }); - - let result: f64 = engine.eval("TAN(0.0)").unwrap(); - assert!((result - 0.0).abs() < f64::EPSILON); -} - -#[test] -fn test_pi_constant() { - let mut engine = Engine::new(); - engine.register_fn("PI", || -> f64 { std::f64::consts::PI }); - - let result: f64 = engine.eval("PI()").unwrap(); - assert!((result - std::f64::consts::PI).abs() < f64::EPSILON); -} - - -#[test] -fn test_val_integer() { - let mut engine = Engine::new(); - engine.register_fn("VAL", |s: &str| -> f64 { - s.trim().parse::().unwrap_or(0.0) - }); - - let result: f64 = engine.eval(r#"VAL("42")"#).unwrap(); - assert!((result - 42.0).abs() < f64::EPSILON); -} - -#[test] -fn test_val_decimal() { - let mut engine = Engine::new(); - engine.register_fn("VAL", |s: &str| -> f64 { - s.trim().parse::().unwrap_or(0.0) - }); - - let result: f64 = engine.eval(r#"VAL("3.14")"#).unwrap(); - assert!((result - 3.14).abs() < f64::EPSILON); -} - -#[test] -fn test_val_negative() { - let mut engine = Engine::new(); - engine.register_fn("VAL", |s: &str| -> f64 { - s.trim().parse::().unwrap_or(0.0) - }); - - let result: f64 = engine.eval(r#"VAL("-17")"#).unwrap(); - assert!((result - (-17.0)).abs() < f64::EPSILON); -} - -#[test] -fn test_val_invalid_returns_zero() { - let mut engine = Engine::new(); - engine.register_fn("VAL", |s: &str| -> f64 { - s.trim().parse::().unwrap_or(0.0) - }); - - let result: f64 = engine.eval(r#"VAL("abc")"#).unwrap(); - assert!((result - 0.0).abs() < f64::EPSILON); -} - -#[test] -fn test_val_with_whitespace() { - let mut engine = Engine::new(); - engine.register_fn("VAL", |s: &str| -> f64 { - s.trim().parse::().unwrap_or(0.0) - }); - - let result: f64 = engine.eval(r#"VAL(" 42 ")"#).unwrap(); - assert!((result - 42.0).abs() < f64::EPSILON); -} - - -#[test] -fn test_combined_abs_sqrt() { - let mut engine = Engine::new(); - engine.register_fn("ABS", |n: f64| -> f64 { n.abs() }); - engine.register_fn("SQRT", |n: f64| -> f64 { n.sqrt() }); - - let result: f64 = engine.eval("SQRT(ABS(-16.0))").unwrap(); - assert!((result - 4.0).abs() < f64::EPSILON); -} - -#[test] -fn test_combined_round_after_division() { - let mut engine = Engine::new(); - engine.register_fn("ROUND", |n: f64| -> i64 { n.round() as i64 }); - - let result: i64 = engine.eval("ROUND(10.0 / 3.0)").unwrap(); - assert_eq!(result, 3); -} - -#[test] -fn test_combined_max_of_abs() { - let mut engine = Engine::new(); - engine.register_fn("ABS", |n: i64| -> i64 { n.abs() }); - engine.register_fn("MAX", |a: i64, b: i64| -> i64 { a.max(b) }); - - let result: i64 = engine.eval("MAX(ABS(-5), ABS(-10))").unwrap(); - assert_eq!(result, 10); -} - -#[test] -fn test_arithmetic_expression() { - let engine = Engine::new(); - - let result: i64 = engine.eval("2 + 3 * 4").unwrap(); - assert_eq!(result, 14); - - let result: i64 = engine.eval("(2 + 3) * 4").unwrap(); - assert_eq!(result, 20); -} diff --git a/tests/unit/mod.rs b/tests/unit/mod.rs index 4c2a971..908d0ae 100644 --- a/tests/unit/mod.rs +++ b/tests/unit/mod.rs @@ -1,24 +1,6 @@ - - -mod attendance; -mod basic; -mod calendar; -mod compliance; -mod console; -mod core; -mod drive; -mod email; -mod llm; -mod math_functions; -mod security; -mod sources; -mod string_functions; -mod timeseries; -mod vector_db; -mod weba; -mod whatsapp; - #[test] fn test_unit_module_loads() { + // Unit tests are now inline in botserver source files + // This module is kept for integration test infrastructure assert!(true); } diff --git a/tests/unit/security/mod.rs b/tests/unit/security/mod.rs deleted file mode 100644 index 32c4f18..0000000 --- a/tests/unit/security/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ - -mod security_antivirus; -mod security_ca; -mod security_cert_pinning; -mod security_integration; -mod security_mutual_tls; -mod security; -mod security_tls; diff --git a/tests/unit/security/security.rs b/tests/unit/security/security.rs deleted file mode 100644 index 797ccbc..0000000 --- a/tests/unit/security/security.rs +++ /dev/null @@ -1,43 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_convert_to_https() { - assert_eq!( - convert_to_https("http://localhost:8080"), - "https://localhost:8080" - ); - assert_eq!( - convert_to_https("https://localhost:8080"), - "https://localhost:8080" - ); - assert_eq!(convert_to_https("localhost:8080"), "https://localhost:8080"); - } - - #[test] - - - fn test_get_secure_port() { - assert_eq!(get_secure_port("api", 8080), 8443); - assert_eq!(get_secure_port("llm", 8081), 8444); - assert_eq!(get_secure_port("redis", 6379), 6380); - assert_eq!(get_secure_port("unknown", 3000), 3443); - } - - #[test] - - - fn test_security_config_default() { - let config = SecurityConfig::default(); - assert!(config.tls_enabled); - assert!(config.mtls_enabled); - assert!(config.auto_generate_certs); - assert_eq!(config.renewal_threshold_days, 30); - } \ No newline at end of file diff --git a/tests/unit/security/security_antivirus.rs b/tests/unit/security/security_antivirus.rs deleted file mode 100644 index 9f8dff0..0000000 --- a/tests/unit/security/security_antivirus.rs +++ /dev/null @@ -1,58 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_classify_threat() { - assert_eq!( - AntivirusManager::classify_threat("Win.Trojan.Generic"), - "Trojan" - ); - assert_eq!( - AntivirusManager::classify_threat("Ransomware.WannaCry"), - "Ransomware" - ); - assert_eq!( - AntivirusManager::classify_threat("PUP.Optional.Adware"), - "PUP" - ); - assert_eq!( - AntivirusManager::classify_threat("Unknown.Malware"), - "Malware" - ); - } - - #[test] - - - fn test_assess_severity() { - assert_eq!( - AntivirusManager::assess_severity("Ransomware.Test"), - ThreatSeverity::Critical - ); - assert_eq!( - AntivirusManager::assess_severity("Trojan.Generic"), - ThreatSeverity::High - ); - assert_eq!( - AntivirusManager::assess_severity("Virus.Test"), - ThreatSeverity::Medium - ); - assert_eq!( - AntivirusManager::assess_severity("PUP.Adware"), - ThreatSeverity::Low - ); - } - - #[tokio::test] - async fn test_antivirus_manager_creation() { - let config = AntivirusConfig::default(); - let manager = AntivirusManager::new(config); - assert!(manager.is_ok()); - } \ No newline at end of file diff --git a/tests/unit/security/security_ca.rs b/tests/unit/security/security_ca.rs deleted file mode 100644 index 6ffd8c9..0000000 --- a/tests/unit/security/security_ca.rs +++ /dev/null @@ -1,31 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - use tempfile::TempDir; - - #[test] - - - fn test_ca_config_default() { - let config = CaConfig::default(); - assert_eq!(config.validity_days, 365); - assert_eq!(config.key_size, 4096); - assert!(!config.external_ca_enabled); - } - - #[test] - - - fn test_ca_manager_creation() { - let temp_dir = TempDir::new().unwrap(); - let mut config = CaConfig::default(); - config.ca_cert_path = temp_dir.path().join("ca.crt"); - config.ca_key_path = temp_dir.path().join("ca.key"); - - let manager = CaManager::new(config); - assert!(manager.is_ok()); - } \ No newline at end of file diff --git a/tests/unit/security/security_cert_pinning.rs b/tests/unit/security/security_cert_pinning.rs deleted file mode 100644 index a80dc9b..0000000 --- a/tests/unit/security/security_cert_pinning.rs +++ /dev/null @@ -1,128 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_pinned_cert_creation() { - let pin = PinnedCert::new( - "api.example.com", - "sha256//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - ); - - assert_eq!(pin.hostname, "api.example.com"); - assert!(!pin.is_backup); - assert_eq!(pin.pin_type, PinType::Leaf); - } - - #[test] - - - fn test_backup_pin() { - let pin = PinnedCert::backup( - "api.example.com", - "sha256//BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=", - ); - - assert!(pin.is_backup); - assert!(pin.description.is_some()); - } - - #[test] - - - fn test_config_add_pin() { - let mut config = CertPinningConfig::default(); - config.add_pin(PinnedCert::new( - "example.com", - "sha256//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - )); - - assert!(config.get_pins("example.com").is_some()); - assert_eq!(config.get_pins("example.com").unwrap().len(), 1); - } - - #[test] - - - fn test_format_fingerprint() { - let hash = vec![0xAB, 0xCD, 0xEF, 0x12]; - let formatted = format_fingerprint(&hash); - assert_eq!(formatted, "AB:CD:EF:12"); - } - - #[test] - - - fn test_parse_fingerprint_hex() { - let result = parse_fingerprint("AB:CD:EF:12").unwrap(); - assert_eq!(result, vec![0xAB, 0xCD, 0xEF, 0x12]); - } - - #[test] - - - fn test_parse_fingerprint_base64() { - let original = vec![0xAB, 0xCD, 0xEF, 0x12]; - let base64 = format!("sha256//{}", BASE64.encode(&original)); - let result = parse_fingerprint(&base64).unwrap(); - assert_eq!(result, original); - } - - #[test] - - - fn test_pinning_stats() { - let mut config = CertPinningConfig::default(); - config.add_pin(PinnedCert::new( - "host1.com", - "sha256//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - )); - config.add_pin(PinnedCert::backup( - "host1.com", - "sha256//BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=", - )); - config.add_pin(PinnedCert::new( - "host2.com", - "sha256//CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=", - )); - - let manager = CertPinningManager::new(config); - let stats = manager.get_stats().unwrap(); - - assert!(stats.enabled); - assert_eq!(stats.total_hosts, 2); - assert_eq!(stats.total_pins, 3); - assert_eq!(stats.backup_pins, 1); - } - - #[test] - - - fn test_pem_to_der() { - - let mock_pem = b"-----BEGIN CERTIFICATE----- -MIIB ------END CERTIFICATE-----"; - - - let result = pem_to_der(mock_pem); - - assert!(result.is_err() || result.unwrap().len() > 0); - } - - #[test] - - - fn test_manager_disabled() { - let mut config = CertPinningConfig::default(); - config.enabled = false; - - let manager = CertPinningManager::new(config); - assert!(!manager.is_enabled()); - } \ No newline at end of file diff --git a/tests/unit/security/security_integration.rs b/tests/unit/security/security_integration.rs deleted file mode 100644 index f62f110..0000000 --- a/tests/unit/security/security_integration.rs +++ /dev/null @@ -1,75 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_url_conversion() { - let integration = TlsIntegration::new(true); - - assert_eq!( - integration.convert_url("http://localhost:8081"), - "https://localhost:8444" - ); - - assert_eq!( - integration.convert_url("redis://localhost:6379"), - "rediss://localhost:6380" - ); - - assert_eq!( - integration.convert_url("https://example.com"), - "https://example.com" - ); - } - - #[test] - - - fn test_postgres_url_update() { - let integration = TlsIntegration::new(true); - - assert_eq!( - integration.update_postgres_url("postgres://user:pass@localhost:5432/db"), - "postgres://user:pass@localhost:5433/db?sslmode=require" - ); - - assert_eq!( - integration.update_postgres_url("postgres://localhost:5432/db?foo=bar"), - "postgres://localhost:5433/db?foo=bar&sslmode=require" - ); - } - - #[test] - - - fn test_service_url() { - let integration = TlsIntegration::new(true); - - assert_eq!( - integration.get_service_url("llm"), - Some("https://localhost:8444".to_string()) - ); - - let integration_no_tls = TlsIntegration::new(false); - assert_eq!( - integration_no_tls.get_service_url("llm"), - Some("http://localhost:8081".to_string()) - ); - } - - #[test] - - - fn test_secure_port() { - let integration = TlsIntegration::new(true); - - assert_eq!(integration.get_secure_port("api"), Some(8443)); - assert_eq!(integration.get_secure_port("redis"), Some(6380)); - assert_eq!(integration.get_secure_port("unknown"), None); - } \ No newline at end of file diff --git a/tests/unit/security/security_mutual_tls.rs b/tests/unit/security/security_mutual_tls.rs deleted file mode 100644 index 30e3639..0000000 --- a/tests/unit/security/security_mutual_tls.rs +++ /dev/null @@ -1,78 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_mtls_config_default() { - let config = MtlsConfig::default(); - assert!(!config.enabled); - assert!(config.ca_cert.is_none()); - assert!(config.client_cert.is_none()); - assert!(config.client_key.is_none()); - } - - #[test] - - - fn test_mtls_config_new() { - let config = MtlsConfig::new( - Some("ca_cert".to_string()), - Some("client_cert".to_string()), - Some("client_key".to_string()), - ); - assert!(config.enabled); - assert!(config.is_configured()); - } - - #[test] - - - fn test_mtls_config_partial() { - let config = MtlsConfig::new(Some("ca_cert".to_string()), None, None); - assert!(!config.enabled); - assert!(!config.is_configured()); - } - - #[test] - - - fn test_mtls_manager_validation() { - let config = MtlsConfig { - enabled: true, - ca_cert: Some( - "-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----".to_string(), - ), - client_cert: Some( - "-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----".to_string(), - ), - client_key: Some( - "-----BEGIN PRIVATE KEY-----\ntest\n-----END PRIVATE KEY-----".to_string(), - ), - }; - let manager = MtlsManager::new(config); - assert!(manager.validate().is_ok()); - } - - #[test] - - - fn test_mtls_manager_invalid_cert() { - let config = MtlsConfig { - enabled: true, - ca_cert: Some("invalid".to_string()), - client_cert: Some( - "-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----".to_string(), - ), - client_key: Some( - "-----BEGIN PRIVATE KEY-----\ntest\n-----END PRIVATE KEY-----".to_string(), - ), - }; - let manager = MtlsManager::new(config); - assert!(manager.validate().is_err()); - } \ No newline at end of file diff --git a/tests/unit/security/security_tls.rs b/tests/unit/security/security_tls.rs deleted file mode 100644 index c9ad532..0000000 --- a/tests/unit/security/security_tls.rs +++ /dev/null @@ -1,49 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_tls_config_default() { - let config = TlsConfig::default(); - assert!(config.enabled); - assert_eq!(config.min_tls_version, Some("1.3".to_string())); - assert!(!config.require_client_cert); - } - - #[test] - - - fn test_service_tls_config() { - let config = ServiceTlsConfig::new("test-service", 8443).with_mtls(); - - assert_eq!(config.service_name, "test-service"); - assert_eq!(config.port, 8443); - assert!(config.tls_config.require_client_cert); - } - - #[test] - - - fn test_tls_registry() { - let mut registry = TlsRegistry::new(); - registry.register_defaults(); - - assert!(!registry.services().is_empty()); - - - let service_names: Vec<&str> = registry - .services() - .iter() - .map(|s| s.service_name.as_str()) - .collect(); - - assert!(service_names.contains(&"api")); - assert!(service_names.contains(&"llm")); - assert!(service_names.contains(&"embedding")); - } \ No newline at end of file diff --git a/tests/unit/sources/mod.rs b/tests/unit/sources/mod.rs deleted file mode 100644 index f20401d..0000000 --- a/tests/unit/sources/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ - -mod sources_mcp; diff --git a/tests/unit/sources/sources_mcp.rs b/tests/unit/sources/sources_mcp.rs deleted file mode 100644 index 209ecd2..0000000 --- a/tests/unit/sources/sources_mcp.rs +++ /dev/null @@ -1,36 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_server_type_icons() { - assert_eq!(get_server_type_icon("filesystem"), "📁"); - assert_eq!(get_server_type_icon("database"), "🗄️"); - assert_eq!(get_server_type_icon("github"), "🐙"); - assert_eq!(get_server_type_icon("unknown"), "🔌"); - } - - #[test] - - - fn test_risk_level_class() { - assert_eq!(get_risk_level_class(&ToolRiskLevel::Safe), "risk-safe"); - assert_eq!( - get_risk_level_class(&ToolRiskLevel::Critical), - "risk-critical" - ); - } - - #[test] - - - fn test_risk_level_name() { - assert_eq!(get_risk_level_name(&ToolRiskLevel::Safe), "Safe"); - assert_eq!(get_risk_level_name(&ToolRiskLevel::High), "High"); - } \ No newline at end of file diff --git a/tests/unit/string_functions.rs b/tests/unit/string_functions.rs deleted file mode 100644 index b4856af..0000000 --- a/tests/unit/string_functions.rs +++ /dev/null @@ -1,374 +0,0 @@ - -use rhai::Engine; - - -#[test] -fn test_instr_finds_substring() { - let mut engine = Engine::new(); - - engine.register_fn("INSTR", |haystack: &str, needle: &str| -> i64 { - if haystack.is_empty() || needle.is_empty() { - return 0; - } - match haystack.find(needle) { - Some(pos) => (pos + 1) as i64, - None => 0, - } - }); - - let result: i64 = engine.eval(r#"INSTR("Hello World", "World")"#).unwrap(); - assert_eq!(result, 7); -} - -#[test] -fn test_instr_not_found() { - let mut engine = Engine::new(); - - engine.register_fn("INSTR", |haystack: &str, needle: &str| -> i64 { - if haystack.is_empty() || needle.is_empty() { - return 0; - } - match haystack.find(needle) { - Some(pos) => (pos + 1) as i64, - None => 0, - } - }); - - let result: i64 = engine.eval(r#"INSTR("Hello World", "xyz")"#).unwrap(); - assert_eq!(result, 0); -} - -#[test] -fn test_instr_case_sensitive() { - let mut engine = Engine::new(); - - engine.register_fn("INSTR", |haystack: &str, needle: &str| -> i64 { - if haystack.is_empty() || needle.is_empty() { - return 0; - } - match haystack.find(needle) { - Some(pos) => (pos + 1) as i64, - None => 0, - } - }); - - let result: i64 = engine.eval(r#"INSTR("Hello", "hello")"#).unwrap(); - assert_eq!(result, 0); -} - - -#[test] -fn test_upper_basic() { - let mut engine = Engine::new(); - engine.register_fn("UPPER", |s: &str| -> String { s.to_uppercase() }); - - let result: String = engine.eval(r#"UPPER("hello")"#).unwrap(); - assert_eq!(result, "HELLO"); -} - -#[test] -fn test_upper_mixed_case() { - let mut engine = Engine::new(); - engine.register_fn("UPPER", |s: &str| -> String { s.to_uppercase() }); - - let result: String = engine.eval(r#"UPPER("HeLLo WoRLd")"#).unwrap(); - assert_eq!(result, "HELLO WORLD"); -} - -#[test] -fn test_ucase_alias() { - let mut engine = Engine::new(); - engine.register_fn("UCASE", |s: &str| -> String { s.to_uppercase() }); - - let result: String = engine.eval(r#"UCASE("test")"#).unwrap(); - assert_eq!(result, "TEST"); -} - - -#[test] -fn test_lower_basic() { - let mut engine = Engine::new(); - engine.register_fn("LOWER", |s: &str| -> String { s.to_lowercase() }); - - let result: String = engine.eval(r#"LOWER("HELLO")"#).unwrap(); - assert_eq!(result, "hello"); -} - -#[test] -fn test_lcase_alias() { - let mut engine = Engine::new(); - engine.register_fn("LCASE", |s: &str| -> String { s.to_lowercase() }); - - let result: String = engine.eval(r#"LCASE("TEST")"#).unwrap(); - assert_eq!(result, "test"); -} - - -#[test] -fn test_len_basic() { - let mut engine = Engine::new(); - engine.register_fn("LEN", |s: &str| -> i64 { s.len() as i64 }); - - let result: i64 = engine.eval(r#"LEN("Hello")"#).unwrap(); - assert_eq!(result, 5); -} - -#[test] -fn test_len_empty() { - let mut engine = Engine::new(); - engine.register_fn("LEN", |s: &str| -> i64 { s.len() as i64 }); - - let result: i64 = engine.eval(r#"LEN("")"#).unwrap(); - assert_eq!(result, 0); -} - -#[test] -fn test_len_with_spaces() { - let mut engine = Engine::new(); - engine.register_fn("LEN", |s: &str| -> i64 { s.len() as i64 }); - - let result: i64 = engine.eval(r#"LEN("Hello World")"#).unwrap(); - assert_eq!(result, 11); -} - - -#[test] -fn test_trim_both_sides() { - let mut engine = Engine::new(); - engine.register_fn("TRIM", |s: &str| -> String { s.trim().to_string() }); - - let result: String = engine.eval(r#"TRIM(" hello ")"#).unwrap(); - assert_eq!(result, "hello"); -} - -#[test] -fn test_ltrim() { - let mut engine = Engine::new(); - engine.register_fn("LTRIM", |s: &str| -> String { s.trim_start().to_string() }); - - let result: String = engine.eval(r#"LTRIM(" hello ")"#).unwrap(); - assert_eq!(result, "hello "); -} - -#[test] -fn test_rtrim() { - let mut engine = Engine::new(); - engine.register_fn("RTRIM", |s: &str| -> String { s.trim_end().to_string() }); - - let result: String = engine.eval(r#"RTRIM(" hello ")"#).unwrap(); - assert_eq!(result, " hello"); -} - - -#[test] -fn test_left_basic() { - let mut engine = Engine::new(); - engine.register_fn("LEFT", |s: &str, count: i64| -> String { - let count = count.max(0) as usize; - s.chars().take(count).collect() - }); - - let result: String = engine.eval(r#"LEFT("Hello World", 5)"#).unwrap(); - assert_eq!(result, "Hello"); -} - -#[test] -fn test_left_exceeds_length() { - let mut engine = Engine::new(); - engine.register_fn("LEFT", |s: &str, count: i64| -> String { - let count = count.max(0) as usize; - s.chars().take(count).collect() - }); - - let result: String = engine.eval(r#"LEFT("Hi", 10)"#).unwrap(); - assert_eq!(result, "Hi"); -} - -#[test] -fn test_left_zero() { - let mut engine = Engine::new(); - engine.register_fn("LEFT", |s: &str, count: i64| -> String { - let count = count.max(0) as usize; - s.chars().take(count).collect() - }); - - let result: String = engine.eval(r#"LEFT("Hello", 0)"#).unwrap(); - assert_eq!(result, ""); -} - - -#[test] -fn test_right_basic() { - let mut engine = Engine::new(); - engine.register_fn("RIGHT", |s: &str, count: i64| -> String { - let count = count.max(0) as usize; - let len = s.chars().count(); - if count >= len { - s.to_string() - } else { - s.chars().skip(len - count).collect() - } - }); - - let result: String = engine.eval(r#"RIGHT("Hello World", 5)"#).unwrap(); - assert_eq!(result, "World"); -} - -#[test] -fn test_right_exceeds_length() { - let mut engine = Engine::new(); - engine.register_fn("RIGHT", |s: &str, count: i64| -> String { - let count = count.max(0) as usize; - let len = s.chars().count(); - if count >= len { - s.to_string() - } else { - s.chars().skip(len - count).collect() - } - }); - - let result: String = engine.eval(r#"RIGHT("Hi", 10)"#).unwrap(); - assert_eq!(result, "Hi"); -} - - -#[test] -fn test_mid_with_length() { - let mut engine = Engine::new(); - engine.register_fn("MID", |s: &str, start: i64, length: i64| -> String { - let start_idx = if start < 1 { 0 } else { (start - 1) as usize }; - let len = length.max(0) as usize; - s.chars().skip(start_idx).take(len).collect() - }); - - let result: String = engine.eval(r#"MID("Hello World", 7, 5)"#).unwrap(); - assert_eq!(result, "World"); -} - -#[test] -fn test_mid_one_based_index() { - let mut engine = Engine::new(); - engine.register_fn("MID", |s: &str, start: i64, length: i64| -> String { - let start_idx = if start < 1 { 0 } else { (start - 1) as usize }; - let len = length.max(0) as usize; - s.chars().skip(start_idx).take(len).collect() - }); - - let result: String = engine.eval(r#"MID("ABCDE", 1, 1)"#).unwrap(); - assert_eq!(result, "A"); - - let result: String = engine.eval(r#"MID("ABCDE", 3, 1)"#).unwrap(); - assert_eq!(result, "C"); -} - - -#[test] -fn test_replace_basic() { - let mut engine = Engine::new(); - engine.register_fn("REPLACE", |s: &str, find: &str, replace: &str| -> String { - s.replace(find, replace) - }); - - let result: String = engine - .eval(r#"REPLACE("Hello World", "World", "Rust")"#) - .unwrap(); - assert_eq!(result, "Hello Rust"); -} - -#[test] -fn test_replace_multiple() { - let mut engine = Engine::new(); - engine.register_fn("REPLACE", |s: &str, find: &str, replace: &str| -> String { - s.replace(find, replace) - }); - - let result: String = engine.eval(r#"REPLACE("aaa", "a", "b")"#).unwrap(); - assert_eq!(result, "bbb"); -} - -#[test] -fn test_replace_not_found() { - let mut engine = Engine::new(); - engine.register_fn("REPLACE", |s: &str, find: &str, replace: &str| -> String { - s.replace(find, replace) - }); - - let result: String = engine.eval(r#"REPLACE("Hello", "xyz", "abc")"#).unwrap(); - assert_eq!(result, "Hello"); -} - - -#[test] -fn test_is_numeric_integer() { - let mut engine = Engine::new(); - engine.register_fn("IS_NUMERIC", |value: &str| -> bool { - let trimmed = value.trim(); - if trimmed.is_empty() { - return false; - } - trimmed.parse::().is_ok() || trimmed.parse::().is_ok() - }); - - let result: bool = engine.eval(r#"IS_NUMERIC("42")"#).unwrap(); - assert!(result); -} - -#[test] -fn test_is_numeric_decimal() { - let mut engine = Engine::new(); - engine.register_fn("IS_NUMERIC", |value: &str| -> bool { - let trimmed = value.trim(); - if trimmed.is_empty() { - return false; - } - trimmed.parse::().is_ok() || trimmed.parse::().is_ok() - }); - - let result: bool = engine.eval(r#"IS_NUMERIC("3.14")"#).unwrap(); - assert!(result); -} - -#[test] -fn test_is_numeric_invalid() { - let mut engine = Engine::new(); - engine.register_fn("IS_NUMERIC", |value: &str| -> bool { - let trimmed = value.trim(); - if trimmed.is_empty() { - return false; - } - trimmed.parse::().is_ok() || trimmed.parse::().is_ok() - }); - - let result: bool = engine.eval(r#"IS_NUMERIC("abc")"#).unwrap(); - assert!(!result); -} - -#[test] -fn test_is_numeric_empty() { - let mut engine = Engine::new(); - engine.register_fn("IS_NUMERIC", |value: &str| -> bool { - let trimmed = value.trim(); - if trimmed.is_empty() { - return false; - } - trimmed.parse::().is_ok() || trimmed.parse::().is_ok() - }); - - let result: bool = engine.eval(r#"IS_NUMERIC("")"#).unwrap(); - assert!(!result); -} - - -#[test] -fn test_combined_string_operations() { - let mut engine = Engine::new(); - engine.register_fn("UPPER", |s: &str| -> String { s.to_uppercase() }); - engine.register_fn("TRIM", |s: &str| -> String { s.trim().to_string() }); - engine.register_fn("LEN", |s: &str| -> i64 { s.len() as i64 }); - - let result: String = engine.eval(r#"UPPER(TRIM(" hello "))"#).unwrap(); - assert_eq!(result, "HELLO"); - - let result: i64 = engine.eval(r#"LEN(TRIM(" hi "))"#).unwrap(); - assert_eq!(result, 2); -} diff --git a/tests/unit/timeseries/mod.rs b/tests/unit/timeseries/mod.rs deleted file mode 100644 index 2068866..0000000 --- a/tests/unit/timeseries/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ - -mod timeseries; diff --git a/tests/unit/timeseries/timeseries.rs b/tests/unit/timeseries/timeseries.rs deleted file mode 100644 index e6fe414..0000000 --- a/tests/unit/timeseries/timeseries.rs +++ /dev/null @@ -1,53 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_metric_point_line_protocol() { - let point = MetricPoint::new("test_measurement") - .tag("host", "server01") - .tag("region", "us-west") - .field_f64("temperature", 23.5) - .field_i64("humidity", 45); - - let line = point.to_line_protocol(); - assert!(line.starts_with("test_measurement,")); - assert!(line.contains("host=server01")); - assert!(line.contains("region=us-west")); - assert!(line.contains("temperature=23.5")); - assert!(line.contains("humidity=45i")); - } - - #[test] - - - fn test_metric_point_escaping() { - let point = MetricPoint::new("test") - .tag("key with space", "value,with=special") - .field_str("message", "Hello \"world\""); - - let line = point.to_line_protocol(); - assert!(line.contains("key\\ with\\ space=value\\,with\\=special")); - assert!(line.contains("message=\"Hello \\\"world\\\"\"")); - } - - #[test] - - - fn test_predefined_metrics() { - let msg = Metrics::message("bot-1", "whatsapp", "incoming"); - assert_eq!(msg.measurement, "messages"); - assert_eq!(msg.tags.get("channel"), Some(&"whatsapp".to_string())); - - let resp = Metrics::response_time("bot-1", 150.5); - assert_eq!(resp.measurement, "response_time"); - - let tokens = Metrics::llm_tokens("bot-1", "gpt-4", 100, 50); - assert_eq!(tokens.measurement, "llm_tokens"); - } \ No newline at end of file diff --git a/tests/unit/vector_db/mod.rs b/tests/unit/vector_db/mod.rs deleted file mode 100644 index 20ed5cd..0000000 --- a/tests/unit/vector_db/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ - -mod vector_db_bm25_config; -mod vector_db_hybrid_search; -mod vector_db_vectordb_indexer; diff --git a/tests/unit/vector_db/vector_db_bm25_config.rs b/tests/unit/vector_db/vector_db_bm25_config.rs deleted file mode 100644 index b282004..0000000 --- a/tests/unit/vector_db/vector_db_bm25_config.rs +++ /dev/null @@ -1,129 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_default_config() { - let config = Bm25Config::default(); - assert!(config.enabled); - assert!((config.k1 - 1.2).abs() < f32::EPSILON); - assert!((config.b - 0.75).abs() < f32::EPSILON); - assert!(config.stemming); - assert!(config.stopwords); - } - - #[test] - - - fn test_disabled_config() { - let config = Bm25Config::disabled(); - assert!(!config.enabled); - assert!(!config.is_enabled()); - } - - #[test] - - - fn test_with_params() { - let config = Bm25Config::with_params(1.5, 0.5); - assert!((config.k1 - 1.5).abs() < f32::EPSILON); - assert!((config.b - 0.5).abs() < f32::EPSILON); - } - - #[test] - - - fn test_validation_negative_k1() { - let mut config = Bm25Config { - k1: -1.0, - ..Default::default() - }; - config.validate(); - assert!((config.k1 - 1.2).abs() < f32::EPSILON); - } - - #[test] - - - fn test_validation_high_k1() { - let mut config = Bm25Config { - k1: 15.0, - ..Default::default() - }; - config.validate(); - assert!((config.k1 - 10.0).abs() < f32::EPSILON); - } - - #[test] - - - fn test_validation_b_range() { - let mut config = Bm25Config { - b: -0.5, - ..Default::default() - }; - config.validate(); - assert!(config.b.abs() < f32::EPSILON); - - let mut config2 = Bm25Config { - b: 1.5, - ..Default::default() - }; - config2.validate(); - assert!((config2.b - 1.0).abs() < f32::EPSILON); - } - - #[test] - - - fn test_has_preprocessing() { - let config = Bm25Config::default(); - assert!(config.has_preprocessing()); - - let no_preprocess = Bm25Config { - stemming: false, - stopwords: false, - ..Default::default() - }; - assert!(!no_preprocess.has_preprocessing()); - } - - #[test] - - - fn test_describe() { - let config = Bm25Config::default(); - let desc = config.describe(); - assert!(desc.contains("k1=1.2")); - assert!(desc.contains("b=0.75")); - - let disabled = Bm25Config::disabled(); - assert_eq!(disabled.describe(), "BM25(disabled)"); - } - - #[test] - - - fn test_is_stopword() { - assert!(is_stopword("the")); - assert!(is_stopword("THE")); - assert!(is_stopword("and")); - assert!(is_stopword("is")); - assert!(!is_stopword("algorithm")); - assert!(!is_stopword("rust")); - assert!(!is_stopword("tantivy")); - } - - #[test] - - - fn test_stopwords_list() { - assert!(!DEFAULT_STOPWORDS.is_empty()); - assert!(DEFAULT_STOPWORDS.len() > 80); - } \ No newline at end of file diff --git a/tests/unit/vector_db/vector_db_hybrid_search.rs b/tests/unit/vector_db/vector_db_hybrid_search.rs deleted file mode 100644 index 6213f96..0000000 --- a/tests/unit/vector_db/vector_db_hybrid_search.rs +++ /dev/null @@ -1,152 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - -use serde_json; - - - - #[test] - - - fn test_hybrid_config_default() { - let config = HybridSearchConfig::default(); - - assert_eq!(config.dense_weight, 0.7); - assert_eq!(config.sparse_weight, 0.3); - assert!(!config.reranker_enabled); - assert_eq!(config.max_results, 10); - assert!(config.bm25_enabled); - } - - #[test] - - - fn test_hybrid_config_search_modes() { - let config = HybridSearchConfig::default(); - assert!(config.use_sparse_search()); - assert!(config.use_dense_search()); - - let dense_only = HybridSearchConfig { - bm25_enabled: false, - ..Default::default() - }; - assert!(!dense_only.use_sparse_search()); - assert!(dense_only.use_dense_search()); - - let sparse_only = HybridSearchConfig { - dense_weight: 0.0, - sparse_weight: 1.0, - ..Default::default() - }; - assert!(sparse_only.use_sparse_search()); - assert!(!sparse_only.use_dense_search()); - } - - #[test] - - - fn test_reciprocal_rank_fusion() { - let config = HybridSearchConfig::default(); - let engine = HybridSearchEngine::new(config, "http://localhost:6333", "test"); - - let sparse = vec![ - ("doc1".to_string(), 0.9), - ("doc2".to_string(), 0.7), - ("doc3".to_string(), 0.5), - ]; - - let dense = vec![ - ("doc2".to_string(), 0.95), - ("doc1".to_string(), 0.8), - ("doc4".to_string(), 0.6), - ]; - - let fused = engine.reciprocal_rank_fusion(&sparse, &dense); - - assert!(!fused.is_empty()); - - let top_ids: Vec<&str> = fused.iter().take(2).map(|(id, _)| id.as_str()).collect(); - assert!(top_ids.contains(&"doc1") || top_ids.contains(&"doc2")); - } - - #[test] - - - fn test_query_decomposer_simple() { - let decomposer = QueryDecomposer::new("http://localhost:8081", "none"); - - let rt = tokio::runtime::Runtime::new().unwrap(); - - let result = rt.block_on(async { - decomposer - .decompose("What is machine learning and how does it work?") - .await - }); - - assert!(result.is_ok()); - let queries = result.unwrap(); - assert!(!queries.is_empty()); - } - - #[test] - - - fn test_search_result_serialization() { - let result = SearchResult { - doc_id: "test123".to_string(), - content: "Test content".to_string(), - source: "/path/to/file".to_string(), - score: 0.85, - metadata: HashMap::new(), - search_method: SearchMethod::Hybrid, - }; - - let json = serde_json::to_string(&result); - assert!(json.is_ok()); - - let parsed: Result = serde_json::from_str(&json.unwrap()); - assert!(parsed.is_ok()); - assert_eq!(parsed.unwrap().doc_id, "test123"); - } - - #[cfg(not(feature = "vectordb"))] - #[test] - - fn test_fallback_bm25_index() { - let mut index = BM25Index::new(); - - index.add_document( - "doc1", - "machine learning artificial intelligence", - "source1", - ); - index.add_document("doc2", "natural language processing NLP", "source2"); - index.add_document("doc3", "computer vision image recognition", "source3"); - - let results = index.search("machine learning", 10); - - assert!(!results.is_empty()); - assert_eq!(results[0].0, "doc1"); - - let stats = index.stats(); - assert_eq!(stats.doc_count, 3); - assert!(stats.enabled); - } - - #[cfg(not(feature = "vectordb"))] - #[test] - - fn test_fallback_bm25_disabled() { - let mut index = BM25Index::new(); - index.set_enabled(false); - - index.add_document("doc1", "test content", "source1"); - let results = index.search("test", 10); - - assert!(results.is_empty()); - assert!(!index.stats().enabled); - } \ No newline at end of file diff --git a/tests/unit/vector_db/vector_db_vectordb_indexer.rs b/tests/unit/vector_db/vector_db_vectordb_indexer.rs deleted file mode 100644 index 09bee9c..0000000 --- a/tests/unit/vector_db/vector_db_vectordb_indexer.rs +++ /dev/null @@ -1,24 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_indexing_stats_creation() { - let stats = IndexingStats { - emails_indexed: 10, - files_indexed: 5, - emails_pending: 2, - files_pending: 3, - last_run: Some(Utc::now()), - errors: 0, - }; - - assert_eq!(stats.emails_indexed, 10); - assert_eq!(stats.files_indexed, 5); - } \ No newline at end of file diff --git a/tests/unit/weba/mod.rs b/tests/unit/weba/mod.rs deleted file mode 100644 index 95cc5bd..0000000 --- a/tests/unit/weba/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ - -mod weba; diff --git a/tests/unit/weba/weba.rs b/tests/unit/weba/weba.rs deleted file mode 100644 index 4161b05..0000000 --- a/tests/unit/weba/weba.rs +++ /dev/null @@ -1,39 +0,0 @@ - - - -use botserver::weba::{ - slugify, WebApp, WebAppConfig, WebAppStatus, WebAppTemplate, WebaState, -}; -use uuid::Uuid; - -#[test] -fn test_slugify() { - assert_eq!(slugify("Hello World"), "hello-world"); - assert_eq!(slugify("My App 123"), "my-app-123"); - assert_eq!(slugify(" Test App "), "test-app"); -} - -#[test] -fn test_webapp_creation() { - let now = chrono::Utc::now(); - let app = WebApp { - id: Uuid::new_v4(), - name: "Test App".to_string(), - slug: "test-app".to_string(), - description: None, - template: WebAppTemplate::Blank, - status: WebAppStatus::Draft, - config: WebAppConfig::default(), - created_at: now, - updated_at: now, - }; - assert_eq!(app.name, "Test App"); - assert_eq!(app.slug, "test-app"); -} - -#[tokio::test] -async fn test_weba_state() { - let state = WebaState::new(); - let apps = state.apps.read().await; - assert!(apps.is_empty()); -} diff --git a/tests/unit/whatsapp/mod.rs b/tests/unit/whatsapp/mod.rs deleted file mode 100644 index 8453468..0000000 --- a/tests/unit/whatsapp/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ - -mod whatsapp; diff --git a/tests/unit/whatsapp/whatsapp.rs b/tests/unit/whatsapp/whatsapp.rs deleted file mode 100644 index 9ef9589..0000000 --- a/tests/unit/whatsapp/whatsapp.rs +++ /dev/null @@ -1,62 +0,0 @@ - - - -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(dead_code)] - - - #[test] - - - fn test_extract_text_message() { - let message = WhatsAppMessage { - id: "msg123".to_string(), - from: "+1234567890".to_string(), - timestamp: "1234567890".to_string(), - message_type: "text".to_string(), - text: Some(WhatsAppText { - body: "Hello, world!".to_string(), - }), - image: None, - audio: None, - video: None, - document: None, - location: None, - interactive: None, - button: None, - }; - - let content = extract_message_content(&message); - assert_eq!(content, "Hello, world!"); - } - - #[test] - - - fn test_extract_interactive_button() { - let message = WhatsAppMessage { - id: "msg123".to_string(), - from: "+1234567890".to_string(), - timestamp: "1234567890".to_string(), - message_type: "interactive".to_string(), - text: None, - image: None, - audio: None, - video: None, - document: None, - location: None, - interactive: Some(WhatsAppInteractive { - interactive_type: "button_reply".to_string(), - button_reply: Some(WhatsAppButtonReply { - id: "btn1".to_string(), - title: "Yes".to_string(), - }), - list_reply: None, - }), - button: None, - }; - - let content = extract_message_content(&message); - assert_eq!(content, "Yes"); - } \ No newline at end of file