use serde::{Deserialize, Serialize};
use crate::EngineCategory;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum SafeSearch {
#[default]
Off = 0,
Moderate = 1,
Strict = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TimeRange {
Day,
Week,
Month,
Year,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchQuery {
pub query: String,
pub categories: Vec<EngineCategory>,
pub language: Option<String>,
pub safesearch: SafeSearch,
pub page: u32,
pub time_range: Option<TimeRange>,
pub engines: Vec<String>,
}
impl SearchQuery {
pub fn new(query: impl Into<String>) -> Self {
Self {
query: query.into(),
categories: vec![EngineCategory::General],
language: None,
safesearch: SafeSearch::Off,
page: 1,
time_range: None,
engines: Vec::new(),
}
}
pub fn with_categories(mut self, categories: Vec<EngineCategory>) -> Self {
self.categories = categories;
self
}
pub fn with_language(mut self, language: impl Into<String>) -> Self {
self.language = Some(language.into());
self
}
pub fn with_safesearch(mut self, level: SafeSearch) -> Self {
self.safesearch = level;
self
}
pub fn with_page(mut self, page: u32) -> Self {
self.page = page;
self
}
pub fn with_time_range(mut self, range: TimeRange) -> Self {
self.time_range = Some(range);
self
}
pub fn with_engines(mut self, engines: Vec<String>) -> Self {
self.engines = engines;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_search_query_new() {
let query = SearchQuery::new("test query");
assert_eq!(query.query, "test query");
assert_eq!(query.categories, vec![EngineCategory::General]);
assert_eq!(query.safesearch, SafeSearch::Off);
assert_eq!(query.page, 1);
assert!(query.language.is_none());
assert!(query.time_range.is_none());
assert!(query.engines.is_empty());
}
#[test]
fn test_search_query_with_categories() {
let query = SearchQuery::new("test")
.with_categories(vec![EngineCategory::Images, EngineCategory::Videos]);
assert_eq!(query.categories, vec![EngineCategory::Images, EngineCategory::Videos]);
}
#[test]
fn test_search_query_with_language() {
let query = SearchQuery::new("test").with_language("en-US");
assert_eq!(query.language, Some("en-US".to_string()));
}
#[test]
fn test_search_query_with_safesearch() {
let query = SearchQuery::new("test").with_safesearch(SafeSearch::Strict);
assert_eq!(query.safesearch, SafeSearch::Strict);
}
#[test]
fn test_search_query_with_page() {
let query = SearchQuery::new("test").with_page(5);
assert_eq!(query.page, 5);
}
#[test]
fn test_search_query_with_time_range() {
let query = SearchQuery::new("test").with_time_range(TimeRange::Week);
assert_eq!(query.time_range, Some(TimeRange::Week));
}
#[test]
fn test_search_query_with_engines() {
let query = SearchQuery::new("test")
.with_engines(vec!["ddg".to_string(), "wiki".to_string()]);
assert_eq!(query.engines, vec!["ddg", "wiki"]);
}
#[test]
fn test_search_query_builder_chain() {
let query = SearchQuery::new("rust programming")
.with_categories(vec![EngineCategory::General])
.with_language("en")
.with_safesearch(SafeSearch::Moderate)
.with_page(2)
.with_time_range(TimeRange::Month)
.with_engines(vec!["ddg".to_string()]);
assert_eq!(query.query, "rust programming");
assert_eq!(query.language, Some("en".to_string()));
assert_eq!(query.safesearch, SafeSearch::Moderate);
assert_eq!(query.page, 2);
assert_eq!(query.time_range, Some(TimeRange::Month));
assert_eq!(query.engines, vec!["ddg"]);
}
#[test]
fn test_safe_search_default() {
let default: SafeSearch = Default::default();
assert_eq!(default, SafeSearch::Off);
}
#[test]
fn test_safe_search_values() {
assert_eq!(SafeSearch::Off as u8, 0);
assert_eq!(SafeSearch::Moderate as u8, 1);
assert_eq!(SafeSearch::Strict as u8, 2);
}
#[test]
fn test_time_range_variants() {
let day = TimeRange::Day;
let week = TimeRange::Week;
let month = TimeRange::Month;
let year = TimeRange::Year;
assert_ne!(day, week);
assert_ne!(month, year);
}
#[test]
fn test_search_query_serialization() {
let query = SearchQuery::new("test");
let json = serde_json::to_string(&query).unwrap();
assert!(json.contains("\"query\":\"test\""));
}
#[test]
fn test_search_query_deserialization() {
let json = r#"{"query":"test","categories":["general"],"language":null,"safesearch":"Off","page":1,"time_range":null,"engines":[]}"#;
let query: SearchQuery = serde_json::from_str(json).unwrap();
assert_eq!(query.query, "test");
}
}