Update unit tests for basic keywords
This commit is contained in:
parent
3d0a9a843d
commit
56334dd7b1
8 changed files with 1010 additions and 1195 deletions
|
|
@ -1,133 +1,114 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
#![allow(unused_imports)]
|
#[test]
|
||||||
#![allow(unused_variables)]
|
fn test_reflection_result_new() {
|
||||||
#![allow(dead_code)]
|
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]
|
#[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,
|
||||||
|
);
|
||||||
|
|
||||||
fn test_reflection_type_from_str() {
|
assert_eq!(result.score, 7.5);
|
||||||
assert_eq!(
|
assert_eq!(result.insights.len(), 2);
|
||||||
ReflectionType::from("conversation_quality"),
|
assert_eq!(result.improvements.len(), 2);
|
||||||
ReflectionType::ConversationQuality
|
assert_eq!(result.positive_patterns.len(), 2);
|
||||||
);
|
}
|
||||||
assert_eq!(
|
|
||||||
ReflectionType::from("quality"),
|
|
||||||
ReflectionType::ConversationQuality
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
ReflectionType::from("tool_usage"),
|
|
||||||
ReflectionType::ToolUsage
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
ReflectionType::from("performance"),
|
|
||||||
ReflectionType::Performance
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[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));
|
||||||
|
|
||||||
fn test_reflection_config_default() {
|
result.score = 8.0;
|
||||||
let config = ReflectionConfig::default();
|
assert!(!result.needs_improvement(6.0));
|
||||||
assert!(!config.enabled);
|
}
|
||||||
assert_eq!(config.interval, 10);
|
|
||||||
assert!(!config.auto_apply);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[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());
|
||||||
|
}
|
||||||
|
|
||||||
fn test_reflection_result_new() {
|
#[test]
|
||||||
let bot_id = Uuid::new_v4();
|
fn test_reflection_type_prompt_template() {
|
||||||
let session_id = Uuid::new_v4();
|
let template = ReflectionType::ConversationQuality.prompt_template();
|
||||||
let result = ReflectionResult::new(bot_id, session_id, ReflectionType::ConversationQuality);
|
assert!(template.contains("{conversation}"));
|
||||||
|
assert!(template.contains("JSON format"));
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(result.bot_id, bot_id);
|
#[test]
|
||||||
assert_eq!(result.session_id, session_id);
|
fn test_reflection_result_summary() {
|
||||||
assert_eq!(result.score, 0.0);
|
let mut result =
|
||||||
assert!(result.insights.is_empty());
|
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()];
|
||||||
|
|
||||||
#[test]
|
let summary = result.summary();
|
||||||
|
assert!(summary.contains("7.5"));
|
||||||
|
assert!(summary.contains("15"));
|
||||||
fn test_reflection_result_from_json() {
|
assert!(summary.contains("2"));
|
||||||
let json_response = r#"{
|
assert!(summary.contains("1"));
|
||||||
"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"));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,102 +1,81 @@
|
||||||
|
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!");
|
||||||
|
}
|
||||||
|
|
||||||
#![allow(unused_imports)]
|
#[test]
|
||||||
#![allow(unused_variables)]
|
fn test_execution_result_error() {
|
||||||
#![allow(dead_code)]
|
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]
|
#[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");
|
||||||
|
}
|
||||||
|
|
||||||
fn test_sandbox_config_default() {
|
#[test]
|
||||||
let config = SandboxConfig::default();
|
fn test_code_language_interpreter() {
|
||||||
assert!(config.enabled);
|
assert_eq!(CodeLanguage::Python.interpreter(), "python3");
|
||||||
assert_eq!(config.timeout_seconds, 30);
|
assert_eq!(CodeLanguage::JavaScript.interpreter(), "node");
|
||||||
assert_eq!(config.memory_limit_mb, 256);
|
assert_eq!(CodeLanguage::Bash.interpreter(), "bash");
|
||||||
assert!(!config.network_enabled);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[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"));
|
||||||
|
|
||||||
fn test_execution_result_success() {
|
let node_config = generate_node_lxc_config();
|
||||||
let result = ExecutionResult::success("Hello, World!".to_string(), String::new(), 100);
|
assert!(node_config.contains("gb-sandbox-node"));
|
||||||
assert!(result.is_success());
|
assert!(node_config.contains("/usr/bin/node"));
|
||||||
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"));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,131 +1,114 @@
|
||||||
|
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()
|
||||||
|
});
|
||||||
|
|
||||||
#![allow(unused_imports)]
|
assert!(!manager.should_summarize(2));
|
||||||
#![allow(unused_variables)]
|
assert!(manager.should_summarize(4));
|
||||||
#![allow(dead_code)]
|
assert!(manager.should_summarize(10));
|
||||||
|
}
|
||||||
|
|
||||||
use serde_json;
|
#[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(),
|
||||||
|
}];
|
||||||
|
|
||||||
#[test]
|
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"
|
||||||
|
}"#;
|
||||||
|
|
||||||
fn test_default_config() {
|
let messages = vec![ConversationMessage {
|
||||||
let config = EpisodicMemoryConfig::default();
|
id: Uuid::new_v4(),
|
||||||
assert!(config.enabled);
|
role: "user".to_string(),
|
||||||
assert_eq!(config.threshold, 4);
|
content: "What's my balance?".to_string(),
|
||||||
assert_eq!(config.history, 2);
|
timestamp: Utc::now(),
|
||||||
assert_eq!(config.max_episodes, 100);
|
}];
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
fn test_should_summarize() {
|
#[test]
|
||||||
let manager = EpisodicMemoryManager::new(EpisodicMemoryConfig {
|
fn test_episode_to_dynamic() {
|
||||||
enabled: true,
|
let episode = Episode {
|
||||||
threshold: 4,
|
id: Uuid::new_v4(),
|
||||||
history: 2,
|
user_id: Uuid::new_v4(),
|
||||||
auto_summarize: true,
|
bot_id: Uuid::new_v4(),
|
||||||
..Default::default()
|
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!({}),
|
||||||
|
};
|
||||||
|
|
||||||
assert!(!manager.should_summarize(2));
|
let dynamic = episode.to_dynamic();
|
||||||
assert!(manager.should_summarize(4));
|
assert!(dynamic.is::<Map>());
|
||||||
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::<Map>());
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,167 +1,148 @@
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
|
||||||
#![allow(unused_imports)]
|
assert_eq!(request.status, ApprovalStatus::Pending);
|
||||||
#![allow(unused_variables)]
|
assert_eq!(request.approval_type, "expense_approval");
|
||||||
#![allow(dead_code)]
|
assert!(request.expires_at > Utc::now());
|
||||||
|
}
|
||||||
|
|
||||||
use serde_json;
|
#[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]
|
#[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()),
|
||||||
|
);
|
||||||
|
|
||||||
fn test_default_config() {
|
assert_eq!(request.status, ApprovalStatus::Approved);
|
||||||
let config = ApprovalConfig::default();
|
assert_eq!(request.decision, Some(ApprovalDecision::Approve));
|
||||||
assert!(config.enabled);
|
assert_eq!(request.decided_by, Some("manager@example.com".to_string()));
|
||||||
assert_eq!(config.default_timeout, 3600);
|
assert_eq!(request.comments, Some("Looks good!".to_string()));
|
||||||
assert_eq!(config.max_reminders, 3);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[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());
|
||||||
|
}
|
||||||
|
|
||||||
fn test_create_request() {
|
#[test]
|
||||||
let manager = ApprovalManager::new(ApprovalConfig::default());
|
fn test_handle_timeout_with_default() {
|
||||||
let request = manager.create_request(
|
let manager = ApprovalManager::new(ApprovalConfig::default());
|
||||||
Uuid::new_v4(),
|
let mut request = manager.create_request(
|
||||||
Uuid::new_v4(),
|
Uuid::new_v4(),
|
||||||
Uuid::new_v4(),
|
Uuid::new_v4(),
|
||||||
"expense_approval",
|
Uuid::new_v4(),
|
||||||
ApprovalChannel::Email,
|
"test",
|
||||||
"manager@example.com",
|
ApprovalChannel::Email,
|
||||||
serde_json::json!({"amount": 1000}),
|
"test@example.com",
|
||||||
"Please approve expense",
|
serde_json::json!({}),
|
||||||
None,
|
"Test",
|
||||||
None,
|
None,
|
||||||
);
|
Some(ApprovalDecision::Approve),
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(request.status, ApprovalStatus::Pending);
|
manager.handle_timeout(&mut request);
|
||||||
assert_eq!(request.approval_type, "expense_approval");
|
|
||||||
assert!(request.expires_at > Utc::now());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
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,
|
||||||
|
);
|
||||||
|
|
||||||
fn test_is_expired() {
|
let dynamic = request.to_dynamic();
|
||||||
let manager = ApprovalManager::new(ApprovalConfig::default());
|
assert!(dynamic.is::<Map>());
|
||||||
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::<Map>());
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,235 +1,208 @@
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
#![allow(unused_imports)]
|
#[test]
|
||||||
#![allow(unused_variables)]
|
fn test_parse_folder_path_onedrive() {
|
||||||
#![allow(dead_code)]
|
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]
|
#[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"));
|
||||||
|
}
|
||||||
|
|
||||||
fn test_parse_folder_path_account() {
|
#[test]
|
||||||
let (provider, email, path) =
|
fn test_folder_provider_from_str() {
|
||||||
parse_folder_path("account://user@gmail.com/Documents/invoices");
|
assert_eq!(
|
||||||
assert_eq!(provider, FolderProvider::GDrive);
|
FolderProvider::from_str("gdrive"),
|
||||||
assert_eq!(email, Some("user@gmail.com".to_string()));
|
Some(FolderProvider::GDrive)
|
||||||
assert_eq!(path, "/Documents/invoices");
|
);
|
||||||
}
|
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]
|
#[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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn test_parse_folder_path_gdrive() {
|
#[test]
|
||||||
let (provider, email, path) = parse_folder_path("gdrive:///shared/reports");
|
fn test_folder_monitor_struct() {
|
||||||
assert_eq!(provider, FolderProvider::GDrive);
|
let monitor = FolderMonitor {
|
||||||
assert_eq!(email, None);
|
id: Uuid::new_v4(),
|
||||||
assert_eq!(path, "/shared/reports");
|
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()],
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
fn test_parse_folder_path_onedrive() {
|
assert_eq!(event.event_type, "create");
|
||||||
let (provider, email, path) = parse_folder_path("onedrive:///business/docs");
|
assert_eq!(event.file_size, Some(1024));
|
||||||
assert_eq!(provider, FolderProvider::OneDrive);
|
}
|
||||||
assert_eq!(email, None);
|
|
||||||
assert_eq!(path, "/business/docs");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
fn test_detect_provider_from_email() {
|
||||||
|
assert_eq!(
|
||||||
fn test_parse_folder_path_dropbox() {
|
detect_provider_from_email("user@gmail.com"),
|
||||||
let (provider, email, path) = parse_folder_path("dropbox:///team/assets");
|
FolderProvider::GDrive
|
||||||
assert_eq!(provider, FolderProvider::Dropbox);
|
);
|
||||||
assert_eq!(email, None);
|
assert_eq!(
|
||||||
assert_eq!(path, "/team/assets");
|
detect_provider_from_email("user@outlook.com"),
|
||||||
}
|
FolderProvider::OneDrive
|
||||||
|
);
|
||||||
#[test]
|
assert_eq!(
|
||||||
|
detect_provider_from_email("user@hotmail.com"),
|
||||||
|
FolderProvider::OneDrive
|
||||||
fn test_parse_folder_path_local() {
|
);
|
||||||
let (provider, email, path) = parse_folder_path("/home/user/documents");
|
assert_eq!(
|
||||||
assert_eq!(provider, FolderProvider::Local);
|
detect_provider_from_email("user@company.com"),
|
||||||
assert_eq!(email, None);
|
FolderProvider::GDrive
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,224 +1,198 @@
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
#![allow(unused_imports)]
|
#[test]
|
||||||
#![allow(unused_variables)]
|
fn test_email_monitor_with_filters() {
|
||||||
#![allow(dead_code)]
|
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]
|
#[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);
|
||||||
|
}
|
||||||
|
|
||||||
fn test_email_monitor_struct() {
|
#[test]
|
||||||
let monitor = EmailMonitor {
|
fn test_email_received_event_struct() {
|
||||||
id: Uuid::new_v4(),
|
let event = EmailReceivedEvent {
|
||||||
bot_id: Uuid::new_v4(),
|
id: Uuid::new_v4(),
|
||||||
email_address: "test@example.com".to_string(),
|
monitor_id: Uuid::new_v4(),
|
||||||
script_path: "on_email_test.rhai".to_string(),
|
message_uid: 12345,
|
||||||
is_active: true,
|
message_id: Some("<msg123@example.com>".to_string()),
|
||||||
filter_from: None,
|
from_address: "sender@example.com".to_string(),
|
||||||
filter_subject: None,
|
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!(monitor.email_address, "test@example.com");
|
assert_eq!(event.message_uid, 12345);
|
||||||
assert!(monitor.is_active);
|
assert_eq!(event.from_address, "sender@example.com");
|
||||||
assert!(monitor.filter_from.is_none());
|
assert!(event.has_attachments);
|
||||||
assert!(monitor.filter_subject.is_none());
|
assert_eq!(event.attachments.len(), 1);
|
||||||
}
|
assert_eq!(event.attachments[0].filename, "file.pdf");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[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()));
|
||||||
|
}
|
||||||
|
|
||||||
fn test_email_monitor_with_filters() {
|
#[test]
|
||||||
let monitor = EmailMonitor {
|
fn test_parse_email_path_invalid() {
|
||||||
id: Uuid::new_v4(),
|
assert!(parse_email_path("user@gmail.com").is_none());
|
||||||
bot_id: Uuid::new_v4(),
|
assert!(parse_email_path("mailto:user@gmail.com").is_none());
|
||||||
email_address: "orders@company.com".to_string(),
|
assert!(parse_email_path("/local/path").is_none());
|
||||||
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");
|
#[test]
|
||||||
assert_eq!(monitor.filter_from, Some("supplier@vendor.com".to_string()));
|
fn test_is_email_path() {
|
||||||
assert_eq!(monitor.filter_subject, Some("Invoice".to_string()));
|
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]
|
#[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![],
|
||||||
|
};
|
||||||
|
|
||||||
fn test_email_attachment_struct() {
|
assert!(!event.has_attachments);
|
||||||
let attachment = EmailAttachment {
|
assert!(event.attachments.is_empty());
|
||||||
filename: "document.pdf".to_string(),
|
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("<multi@example.com>".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(),
|
mime_type: "application/pdf".to_string(),
|
||||||
size: 1024,
|
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!(attachment.filename, "document.pdf");
|
assert_eq!(attachments.len(), 3);
|
||||||
assert_eq!(attachment.mime_type, "application/pdf");
|
assert_eq!(attachments[0].filename, "doc1.pdf");
|
||||||
assert_eq!(attachment.size, 1024);
|
assert_eq!(attachments[1].mime_type, "image/png");
|
||||||
}
|
assert_eq!(attachments[2].size, 4096);
|
||||||
|
}
|
||||||
#[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("<msg123@example.com>".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("<multi@example.com>".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);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,110 +1,94 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
#![allow(unused_imports)]
|
#[test]
|
||||||
#![allow(unused_variables)]
|
fn test_play_options_from_string() {
|
||||||
#![allow(dead_code)]
|
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));
|
||||||
|
|
||||||
#[test]
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
fn test_content_type_from_extension() {
|
#[test]
|
||||||
assert_eq!(ContentType::from_extension("mp4"), ContentType::Video);
|
fn test_extract_title_from_source() {
|
||||||
assert_eq!(ContentType::from_extension("MP3"), ContentType::Audio);
|
assert_eq!(extract_title_from_source("documents/report.pdf"), "report");
|
||||||
assert_eq!(ContentType::from_extension("png"), ContentType::Image);
|
assert_eq!(
|
||||||
assert_eq!(ContentType::from_extension("pdf"), ContentType::Pdf);
|
extract_title_from_source("https://example.com/video.mp4?token=abc"),
|
||||||
assert_eq!(ContentType::from_extension("rs"), ContentType::Code);
|
"video"
|
||||||
assert_eq!(
|
);
|
||||||
ContentType::from_extension("pptx"),
|
assert_eq!(
|
||||||
ContentType::Presentation
|
extract_title_from_source("presentation.pptx"),
|
||||||
);
|
"presentation"
|
||||||
assert_eq!(
|
);
|
||||||
ContentType::from_extension("xlsx"),
|
}
|
||||||
ContentType::Spreadsheet
|
|
||||||
);
|
|
||||||
assert_eq!(ContentType::from_extension("md"), ContentType::Markdown);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
fn test_player_component() {
|
||||||
|
assert_eq!(ContentType::Video.player_component(), "video-player");
|
||||||
fn test_content_type_from_mime() {
|
assert_eq!(ContentType::Audio.player_component(), "audio-player");
|
||||||
assert_eq!(ContentType::from_mime("video/mp4"), ContentType::Video);
|
assert_eq!(ContentType::Image.player_component(), "image-viewer");
|
||||||
assert_eq!(ContentType::from_mime("audio/mpeg"), ContentType::Audio);
|
assert_eq!(ContentType::Pdf.player_component(), "pdf-viewer");
|
||||||
assert_eq!(ContentType::from_mime("image/png"), ContentType::Image);
|
assert_eq!(ContentType::Code.player_component(), "code-viewer");
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,204 +1,164 @@
|
||||||
|
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 * * * *"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#![allow(unused_imports)]
|
#[test]
|
||||||
#![allow(unused_variables)]
|
fn test_every_hour() {
|
||||||
#![allow(dead_code)]
|
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]
|
#[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");
|
||||||
|
}
|
||||||
|
|
||||||
fn test_every_minute() {
|
#[test]
|
||||||
assert_eq!(parse_natural_schedule("every minute").unwrap(), "* * * * *");
|
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]
|
#[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");
|
||||||
|
}
|
||||||
|
|
||||||
fn test_every_n_minutes() {
|
#[test]
|
||||||
assert_eq!(
|
fn test_day_with_time() {
|
||||||
parse_natural_schedule("every 5 minutes").unwrap(),
|
assert_eq!(
|
||||||
"*/5 * * * *"
|
parse_natural_schedule("every monday at 9am").unwrap(),
|
||||||
);
|
"0 9 * * 1"
|
||||||
assert_eq!(
|
);
|
||||||
parse_natural_schedule("every 15 minutes").unwrap(),
|
assert_eq!(
|
||||||
"*/15 * * * *"
|
parse_natural_schedule("every friday at 5pm").unwrap(),
|
||||||
);
|
"0 17 * * 5"
|
||||||
assert_eq!(
|
);
|
||||||
parse_natural_schedule("every 30 minutes").unwrap(),
|
}
|
||||||
"*/30 * * * *"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn test_every_hour() {
|
#[test]
|
||||||
assert_eq!(parse_natural_schedule("every hour").unwrap(), "0 * * * *");
|
fn test_combined() {
|
||||||
assert_eq!(parse_natural_schedule("hourly").unwrap(), "0 * * * *");
|
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]
|
#[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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn test_every_n_hours() {
|
#[test]
|
||||||
assert_eq!(
|
fn test_raw_cron_passthrough() {
|
||||||
parse_natural_schedule("every 2 hours").unwrap(),
|
assert_eq!(parse_natural_schedule("0 * * * *").unwrap(), "0 * * * *");
|
||||||
"0 */2 * * *"
|
assert_eq!(
|
||||||
);
|
parse_natural_schedule("*/5 * * * *").unwrap(),
|
||||||
assert_eq!(
|
"*/5 * * * *"
|
||||||
parse_natural_schedule("every 6 hours").unwrap(),
|
);
|
||||||
"0 */6 * * *"
|
assert_eq!(
|
||||||
);
|
parse_natural_schedule("0 9-17 * * 1-5").unwrap(),
|
||||||
}
|
"0 9-17 * * 1-5"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
fn test_invalid_input() {
|
||||||
|
assert!(parse_natural_schedule("potato salad").is_err());
|
||||||
fn test_every_day() {
|
assert!(parse_natural_schedule("every 100 minutes").is_err());
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue