Skip to content

Commit

Permalink
chore: refactor types and add common mocks module
Browse files Browse the repository at this point in the history
  • Loading branch information
eredotpkfr committed Sep 17, 2024
1 parent f8d14d3 commit cd043e4
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 55 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pre-commit-update-hooks:
@pre-commit autoupdate
rustfmt-check:
@cargo fmt --all -- --check
rustfmt:
rustfmt: fix
@cargo fmt --all
test:
@cargo test
Expand Down
2 changes: 1 addition & 1 deletion src/bin/subscan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use subscan::{
#[tokio::main]
async fn main() {
let cli = Cli::parse();
let config = RequesterConfig::from_cli(&cli);
let config = RequesterConfig::from(&cli);

cache::requesters::configure_all(config).await;

Expand Down
16 changes: 8 additions & 8 deletions src/types/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub const DEFAULT_HTTP_TIMEOUT: Duration = Duration::from_secs(10);
/// Type definition for store [`RequesterInterface`](crate::interfaces::requester::RequesterInterface)
/// configurations in a struct. Also it has helpful
/// methods to manage configs
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct RequesterConfig {
/// Stores header values for HTTP requests as a [`HeaderMap`]
pub headers: HeaderMap,
Expand All @@ -28,7 +28,7 @@ impl Default for RequesterConfig {
}
}

impl RequesterConfig {
impl From<&Cli> for RequesterConfig {
/// Build [`RequesterConfig`] object from given
/// [`Cli`] object
///
Expand All @@ -47,16 +47,14 @@ impl RequesterConfig {
/// proxy: None,
/// };
///
/// let config = RequesterConfig::from_cli(&cli);
/// let config = RequesterConfig::from(&cli);
/// let user_agent = config.headers.get(USER_AGENT).unwrap();
///
/// assert_eq!(config.timeout.as_secs(), cli.timeout);
/// assert_eq!(config.proxy, cli.proxy);
/// assert_eq!(
/// config.headers.get(USER_AGENT).unwrap().to_str().unwrap(),
/// cli.user_agent
/// );
/// assert_eq!(user_agent.to_str().unwrap(), cli.user_agent);
/// ```
pub fn from_cli(cli: &Cli) -> Self {
fn from(cli: &Cli) -> Self {
Self {
headers: HeaderMap::from_iter([(
USER_AGENT,
Expand All @@ -66,7 +64,9 @@ impl RequesterConfig {
proxy: cli.proxy.clone(),
}
}
}

impl RequesterConfig {
/// Converts [`HeaderMap`] headers to [`HashMap`] mappings and returns them
///
/// # Examples
Expand Down
21 changes: 13 additions & 8 deletions src/types/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use std::collections::BTreeSet;
/// Data type to store search URL query param
/// for search engines like `Google`, `Yahoo`, `Bing`, etc.
#[derive(Debug, Clone)]
pub struct SearchQueryParam(pub String);
pub struct SearchQueryParam(String);

impl SearchQueryParam {
impl From<&str> for SearchQueryParam {
/// Create query param from static str
///
/// # Examples
Expand All @@ -19,10 +19,13 @@ impl SearchQueryParam {
///
/// // do something with param
/// ```
pub fn from(param: &str) -> Self {
Self(param.to_string())
fn from(value: &str) -> Self {
Self(value.to_string())
}
}

#[allow(clippy::to_string_trait_impl)]
impl ToString for SearchQueryParam {
/// Clones inner value and returns it as a [`String`]
///
/// # Examples
Expand All @@ -32,14 +35,16 @@ impl SearchQueryParam {
///
/// let param = SearchQueryParam::from("q");
///
/// let as_string = param.as_string();
/// let as_string = param.to_string();
///
/// // do something with string query param
/// ```
pub fn as_string(&self) -> String {
fn to_string(&self) -> String {
self.0.clone()
}
}

impl SearchQueryParam {
/// Get fully [`SearchQuery`] object from [`SearchQueryParam`]
/// configured by the given `domain` and `prefix` params
///
Expand Down Expand Up @@ -188,7 +193,7 @@ impl SearchQuery {
///
/// let mut query = SearchQuery::new(param, prefix, domain);
///
/// assert_eq!(query.as_search_str(), String::from("site:foo.com"));
/// assert_eq!(query.as_search_str(), "site:foo.com".to_string());
/// ````
pub fn as_search_str(&mut self) -> String {
let asvec = Vec::from_iter(self.state.clone());
Expand Down Expand Up @@ -224,7 +229,7 @@ impl SearchQuery {
/// assert_eq!(query.as_url(base_url, extra_params), expected_url);
/// ````
pub fn as_url(&mut self, base_url: Url, extra_params: &[(String, String)]) -> Url {
let query_param = &[(self.param.as_string(), self.as_search_str())];
let query_param = &[(self.param.to_string(), self.as_search_str())];
let params = [extra_params, query_param].concat();

Url::parse_with_params(base_url.as_ref(), params).expect("URL parse error!")
Expand Down
30 changes: 15 additions & 15 deletions tests/cache_test.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use reqwest::header::HeaderMap;
mod common;

use common::constants::TEST_URL;
use reqwest::header::{HeaderMap, HeaderValue, CONTENT_LENGTH, USER_AGENT};
use std::time::Duration;
use strum::IntoEnumIterator;

#[cfg(test)]
mod requesters {
use super::*;
use subscan::{
cache,
enums::RequesterType,
interfaces::requester::RequesterInterface,
types::config::{RequesterConfig, DEFAULT_HTTP_TIMEOUT},
cache, enums::RequesterType, interfaces::requester::RequesterInterface,
types::config::RequesterConfig,
};

#[tokio::test]
Expand All @@ -25,24 +26,23 @@ mod requesters {
async fn configure_all_test() {
let new_config = RequesterConfig {
timeout: Duration::from_secs(120),
headers: HeaderMap::default(),
proxy: None,
headers: HeaderMap::from_iter([
(USER_AGENT, HeaderValue::from_static("x-api-key")),
(CONTENT_LENGTH, HeaderValue::from_static("10000")),
]),
proxy: Some(TEST_URL.to_string()),
};

for requester in cache::ALL_REQUESTERS.values() {
assert_eq!(
requester.lock().await.config().await.timeout,
DEFAULT_HTTP_TIMEOUT
);
let requester = requester.lock().await;

assert_eq!(requester.config().await, RequesterConfig::default());
}

cache::requesters::configure_all(new_config.clone()).await;

for requester in cache::ALL_REQUESTERS.values() {
assert_eq!(
requester.lock().await.config().await.timeout,
new_config.timeout
);
assert_eq!(requester.lock().await.config().await, new_config);
}
}
}
20 changes: 20 additions & 0 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,23 @@ pub mod funcs {
fs::read_to_string(testdata_path().join(path)).expect(READ_ERROR)
}
}

pub mod mocks {
#![allow(dead_code)]
use super::constants::TEST_MODULE_NAME;
use reqwest::Url;
use subscan::{
cache::requesters, enums::RequesterType, extractors::regex::RegexExtractor,
modules::generics::searchengine::GenericSearchEngineModule, types::query::SearchQueryParam,
};

pub fn generic_search_engine<'a>(url: &str) -> GenericSearchEngineModule<'a> {
GenericSearchEngineModule {
name: TEST_MODULE_NAME.to_string(),
url: Url::parse(url).unwrap(),
param: SearchQueryParam::from("q"),
requester: requesters::get_by_type(&RequesterType::HTTPClient),
extractor: RegexExtractor::default().into(),
}
}
}
30 changes: 8 additions & 22 deletions tests/module_generics_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,30 @@ mod common;

#[cfg(test)]
mod searchengine {
use super::common::constants::{TEST_BAR_SUBDOMAIN, TEST_DOMAIN, TEST_MODULE_NAME, TEST_URL};
use reqwest::Url;
use subscan::{
cache::requesters, enums::RequesterType, extractors::regex::RegexExtractor,
interfaces::module::SubscanModuleInterface,
modules::generics::searchengine::GenericSearchEngineModule, types::query::SearchQueryParam,
use super::common::{
constants::{TEST_BAR_SUBDOMAIN, TEST_DOMAIN, TEST_MODULE_NAME, TEST_URL},
mocks::generic_search_engine,
};
use subscan::interfaces::module::SubscanModuleInterface;

#[tokio::test]
async fn get_search_query_test() {
let module = GenericSearchEngineModule {
name: TEST_MODULE_NAME.to_string(),
url: Url::parse(TEST_URL).unwrap(),
param: SearchQueryParam::from("q"),
requester: requesters::get_by_type(&RequesterType::HTTPClient),
extractor: RegexExtractor::default().into(),
};
let module = generic_search_engine(TEST_URL);

let mut query = module.get_search_query(TEST_DOMAIN.to_string()).await;

assert_eq!(query.as_search_str(), "site:foo.com");
assert_eq!(module.name().await, "foo-module");
assert_eq!(module.name().await, TEST_MODULE_NAME.to_string());
}

#[tokio::test]
#[stubr::mock("module/generics/search-engine.json")]
async fn run_test() {
let mut module = GenericSearchEngineModule {
name: TEST_MODULE_NAME.to_string(),
url: Url::parse(&stubr.path("/search")).unwrap(),
param: SearchQueryParam::from("q"),
requester: requesters::get_by_type(&RequesterType::HTTPClient),
extractor: RegexExtractor::default().into(),
};
let mut module = generic_search_engine(&stubr.path("/search"));

let result = module.run(TEST_DOMAIN.to_string()).await;

assert_eq!(module.name().await, "foo-module");
assert_eq!(module.name().await, TEST_MODULE_NAME.to_string());
assert_eq!(result, [TEST_BAR_SUBDOMAIN.to_string()].into());
}
}

0 comments on commit cd043e4

Please sign in to comment.