From 0fd29a7cb0b292637188732f9621233315d8c5ec Mon Sep 17 00:00:00 2001 From: ShiXin Huang Date: Sat, 20 Jan 2024 19:46:15 +0800 Subject: [PATCH] test: test utils (#53) --- src/config.rs | 74 ++++--- src/github_api/mod.rs | 144 +++++++----- src/json.rs | 105 +++++---- src/repository.rs | 10 +- src/repository_config.rs | 60 ++++- src/scafalra.rs | 457 +++++++++++++++++++++++---------------- src/store.rs | 224 ++++++++++--------- 7 files changed, 653 insertions(+), 421 deletions(-) diff --git a/src/config.rs b/src/config.rs index 296f43d..c1916e0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -44,57 +44,79 @@ impl Config { } #[cfg(test)] -mod tests { +mod test_utils { use std::fs; - use anyhow::Result; use tempfile::{tempdir, TempDir}; use super::Config; - fn mock_config(create_file: bool) -> Result<(Config, TempDir)> { - let temp_dir = tempdir()?; - let temp_dir_path = temp_dir.path(); + pub struct ConfigMock { + pub config: Config, + pub tmpdir: TempDir, + } + + impl ConfigMock { + pub fn new() -> Self { + let tmpdir = tempdir().unwrap(); + let config = Config::new(tmpdir.path()).unwrap(); + + Self { + tmpdir, + config, + } + } + + pub fn with_content(self) -> Self { + let tmpdir_path = self.tmpdir.path(); - if create_file { fs::write( - temp_dir_path.join(Config::FILE_NAME), + tmpdir_path.join(Config::FILE_NAME), "{\n \"token\": \"token\"\n}", - )?; - } + ) + .unwrap(); - let config = Config::new(temp_dir_path)?; + let config = Config::new(tmpdir_path).unwrap(); - Ok((config, temp_dir)) + Self { + config, + ..self + } + } } +} - #[test] - fn test_config_new_not_exists() -> Result<()> { - let (config, _dir) = mock_config(false)?; +#[cfg(test)] +mod tests { + use std::fs; - assert_eq!(config.token(), None); + use anyhow::Result; - Ok(()) - } + use super::test_utils::ConfigMock; #[test] - fn test_config_new_exists() -> Result<()> { - let (config, _dir) = mock_config(true)?; + fn test_config_new_not_exists() { + let config_mock = ConfigMock::new(); - assert_eq!(config.token(), Some("token")); + assert_eq!(config_mock.config.token(), None); + } - Ok(()) + #[test] + fn test_config_new_exists() { + let config_mock = ConfigMock::new().with_content(); + + assert_eq!(config_mock.config.token(), Some("token")); } #[test] fn test_config_save() -> Result<()> { - let (mut config, _dir) = mock_config(false)?; + let mut config_mock = ConfigMock::new(); - config.set_token("token2"); - config.save()?; + config_mock.config.set_token("token2"); + config_mock.config.save()?; - let content = fs::read_to_string(&config.path)?; - assert_eq!(content, "{\n \"token\": \"token2\"\n}"); + let actual = fs::read_to_string(&config_mock.config.path)?; + assert_eq!(actual, "{\n \"token\": \"token2\"\n}"); Ok(()) } diff --git a/src/github_api/mod.rs b/src/github_api/mod.rs index e85d0b1..d6c3880 100644 --- a/src/github_api/mod.rs +++ b/src/github_api/mod.rs @@ -107,38 +107,97 @@ impl GitHubApi { } #[cfg(test)] -mod tests { - use anyhow::Result; +mod test_utils { + use mockito::{Mock, ServerGuard}; use super::GitHubApi; use crate::repository::Repository; - fn mock_repo() -> Repository { - Repository { - owner: "shixinhuang99".to_string(), - name: "scafalra".to_string(), - ..Repository::default() + pub struct RepositoryMock { + owner: String, + name: String, + } + + impl RepositoryMock { + pub fn new() -> Self { + Self { + owner: "shixinhuang99".to_string(), + name: "scafalra".to_string(), + } + } + + pub fn build(self) -> Repository { + Repository { + owner: self.owner, + name: self.name, + ..Repository::default() + } + } + + pub fn owner(self, owner: &str) -> Self { + Self { + owner: owner.to_string(), + ..self + } + } + + pub fn name(self, name: &str) -> Self { + Self { + name: name.to_string(), + ..self + } } } - #[test] - fn test_repo_query() -> Result<()> { - let mut server = mockito::Server::new(); + pub struct GitHubApiMock { + pub github_api: GitHubApi, + pub server: ServerGuard, + pub mock: Mock, + } - let mock = server - .mock("POST", "/") - .with_status(200) - .with_header("content-type", "application/json") - .with_body_from_file("fixtures/repo-query-response.json") - .create(); + impl GitHubApiMock { + pub fn new(fixture: &str) -> Self { + let mut server = mockito::Server::new(); - let github_api = GitHubApi::new(Some(&server.url())); + let mock = server + .mock("POST", "/") + .with_status(200) + .with_header("content-type", "application/json") + .with_body_from_file(fixture) + .create(); - github_api.set_token("token"); + let github_api = GitHubApi::new(Some(&server.url())); - let repo_urls = github_api.query_remote_repo(&mock_repo())?; + Self { + github_api, + server, + mock, + } + } + } +} - mock.assert(); +#[cfg(test)] +mod tests { + use anyhow::Result; + + use super::{ + test_utils::{GitHubApiMock, RepositoryMock}, + GitHubApi, + }; + + #[test] + fn test_repo_query() -> Result<()> { + let github_api_mock = + GitHubApiMock::new("fixtures/repo-query-response.json"); + + github_api_mock.github_api.set_token("token"); + + let repo_urls = github_api_mock + .github_api + .query_remote_repo(&RepositoryMock::new().build())?; + + github_api_mock.mock.assert(); assert_eq!(repo_urls.url, "url"); assert_eq!(repo_urls.tarball_url, "tarballUrl"); @@ -148,33 +207,24 @@ mod tests { #[test] fn test_github_api_request_no_token() { let github_api = GitHubApi::new(None); - let api_result = github_api.query_remote_repo(&mock_repo()); + let api_result = + github_api.query_remote_repo(&RepositoryMock::new().build()); assert!(api_result.is_err()); } #[test] fn test_github_api_request_error() -> Result<()> { - let mut server = mockito::Server::new(); + let github_api_mock = + GitHubApiMock::new("fixtures/repo-query-error.json"); - let mock = server - .mock("POST", "/") - .with_status(200) - .with_header("content-type", "application/json") - .with_body_from_file("fixtures/repo-query-error.json") - .create(); + github_api_mock.github_api.set_token("token"); - let github_api = GitHubApi::new(Some(&server.url())); + let api_result = github_api_mock.github_api.query_remote_repo( + &RepositoryMock::new().owner("foo").name("bar").build(), + ); - github_api.set_token("token"); - - let api_result = github_api.query_remote_repo(&Repository { - owner: "foo".to_string(), - name: "bar".to_string(), - ..Repository::default() - }); - - mock.assert(); + github_api_mock.mock.assert(); assert!(api_result.is_err()); Ok(()) @@ -183,22 +233,14 @@ mod tests { #[test] #[cfg(feature = "self_update")] fn test_release_query() -> Result<()> { - let mut server = mockito::Server::new(); - - let mock = server - .mock("POST", "/") - .with_status(200) - .with_header("content-type", "application/json") - .with_body_from_file("fixtures/release-query-response.json") - .create(); - - let github_api = GitHubApi::new(Some(&server.url())); + let github_api_mock = + GitHubApiMock::new("fixtures/release-query-response.json"); - github_api.set_token("token"); + github_api_mock.github_api.set_token("token"); - let release = github_api.query_release()?; + let release = github_api_mock.github_api.query_release()?; - mock.assert(); + github_api_mock.mock.assert(); assert_eq!(release.version.to_string(), "0.6.0"); Ok(()) diff --git a/src/json.rs b/src/json.rs index e3ea9bf..f867a9e 100644 --- a/src/json.rs +++ b/src/json.rs @@ -13,7 +13,6 @@ where let content = fs::read_to_string(file_path)?; if !content.is_empty() { let value: Self = serde_json::from_str(&content)?; - return Ok(value); } } @@ -41,79 +40,103 @@ where } #[cfg(test)] -mod tests { +mod test_utils { use std::{fs, path::PathBuf}; - use anyhow::Result; use serde::{Deserialize, Serialize}; use tempfile::{tempdir, TempDir}; use super::JsonContent; #[derive(Deserialize, Serialize, Default)] - struct Foo { - bar: String, + pub struct Foo { + pub bar: String, } impl JsonContent for Foo {} - fn mock_foo( - create_file: bool, - init_content: bool, - ) -> Result<(Foo, TempDir, PathBuf)> { - let temp_dir = tempdir()?; - let file_path = temp_dir.path().join("foo.json"); - - if create_file { - if init_content { - fs::write(&file_path, "{\n \"bar\": \"bar\"\n}")?; - } else { - fs::write(&file_path, "")?; + pub struct JsonContentMock { + pub foo: Foo, + pub tmpdir: TempDir, + pub path: PathBuf, + } + + impl JsonContentMock { + pub fn new() -> Self { + let tmpdir = tempdir().unwrap(); + let file_path = tmpdir.path().join("foo.json"); + let foo = Foo::load(&file_path).unwrap(); + + Self { + foo, + tmpdir, + path: file_path, } } - let foo = Foo::load(&file_path)?; + pub fn with_empty_content(self) -> Self { + fs::write(&self.path, "").unwrap(); - Ok((foo, temp_dir, file_path)) - } + let foo = Foo::load(&self.path).unwrap(); - #[test] - fn test_load_file_exists() -> Result<()> { - let (foo, _dir, _file_path) = mock_foo(true, true)?; + Self { + foo, + ..self + } + } - assert_eq!(foo.bar, "bar"); + pub fn with_content(self) -> Self { + fs::write(&self.path, "{\n \"bar\": \"bar\"\n}").unwrap(); - Ok(()) + let foo = Foo::load(&self.path).unwrap(); + + Self { + foo, + ..self + } + } } +} - #[test] - fn test_load_file_exists_empty_content() -> Result<()> { - let (foo, _tmpdir, _file_path) = mock_foo(true, false)?; +#[cfg(test)] +mod tests { + use std::fs; - assert_eq!(foo.bar, ""); + use anyhow::Result; - Ok(()) + use super::{test_utils::JsonContentMock, JsonContent}; + + #[test] + fn test_json_load_file() { + let json_content_mock = JsonContentMock::new().with_content(); + + assert_eq!(json_content_mock.foo.bar, "bar"); } #[test] - fn test_load_file_not_exists() -> Result<()> { - let (foo, _dir, file_path) = mock_foo(false, false)?; + fn test_json_load_empty_content() { + let json_content_mock = JsonContentMock::new().with_empty_content(); + + assert_eq!(json_content_mock.foo.bar, ""); + } - assert_eq!(foo.bar, ""); - assert!(file_path.exists()); + #[test] + fn test_json_load_file_not_exists() { + let json_content_mock = JsonContentMock::new(); - Ok(()) + assert_eq!(json_content_mock.foo.bar, ""); + assert!(json_content_mock.path.exists()); } #[test] - fn test_save() -> Result<()> { - let (mut foo, _dir, file_path) = mock_foo(true, true)?; + fn test_json_save() -> Result<()> { + let mut json_content_mock = JsonContentMock::new().with_content(); - foo.bar = "bar2".to_string(); - foo.save(&file_path)?; + json_content_mock.foo.bar = "bar2".to_string(); + json_content_mock.foo.save(&json_content_mock.path)?; - let content = fs::read_to_string(&file_path)?; - assert_eq!(content, "{\n \"bar\": \"bar2\"\n}"); + let actual = fs::read_to_string(&json_content_mock.path)?; + assert_eq!(actual, "{\n \"bar\": \"bar2\"\n}"); Ok(()) } diff --git a/src/repository.rs b/src/repository.rs index 01446e3..546d952 100644 --- a/src/repository.rs +++ b/src/repository.rs @@ -14,9 +14,9 @@ use crate::{ utils::{download, tar_unpack}, }; -static REPO_RE: OnceLock = OnceLock::new(); - fn repo_re() -> &'static Regex { + static REPO_RE: OnceLock = OnceLock::new(); + REPO_RE.get_or_init(|| { Regex::new( r"^([^/\s]+)/([^/\s?]+)(?:((?:/[^/\s?]+)+))?(?:\?(branch|tag|commit)=([^\s]+))?$", @@ -41,7 +41,7 @@ pub enum Query { } impl Repository { - pub const TMP_REPO_DIR_NAME: &'static str = "t"; + pub const TMP_DIR_NAME: &'static str = "t"; pub const TARBALL_EXT: &'static str = "tar.gz"; pub fn parse(input: &str) -> Result { @@ -72,7 +72,7 @@ impl Repository { } pub fn cache(&self, url: &str, cache_dir: &Path) -> Result { - let temp_dir = cache_dir.join(Self::TMP_REPO_DIR_NAME); + let temp_dir = cache_dir.join(Self::TMP_DIR_NAME); let tarball = temp_dir.with_extension(Self::TARBALL_EXT); download(url, &tarball)?; @@ -227,7 +227,7 @@ mod tests { let repo = Repository::parse("shixinhuang99/scafalra")?; repo.cache(&server.url(), temp_dir_path)?; - let tmp_repo_dir = temp_dir_path.join(Repository::TMP_REPO_DIR_NAME); + let tmp_repo_dir = temp_dir_path.join(Repository::TMP_DIR_NAME); let tarball = tmp_repo_dir.with_extension(Repository::TARBALL_EXT); mock.assert(); diff --git a/src/repository_config.rs b/src/repository_config.rs index 9f9430b..71199de 100644 --- a/src/repository_config.rs +++ b/src/repository_config.rs @@ -29,33 +29,69 @@ impl RepositoryConfig { } } +#[cfg(test)] +mod test_utils { + use std::path::PathBuf; + + use tempfile::{tempdir, TempDir}; + + use super::RepositoryConfig; + + pub struct RepositoryConfigMock { + pub repo_cfg: RepositoryConfig, + pub tmpdir: TempDir, + pub path: PathBuf, + } + + impl RepositoryConfigMock { + pub fn new() -> Self { + let tmpdir = tempdir().unwrap(); + let tmpdir_path = tmpdir.path().to_path_buf(); + let repo_cfg = RepositoryConfig::load(&tmpdir_path); + + Self { + repo_cfg, + tmpdir, + path: tmpdir_path, + } + } + + pub fn with_fixture(self) -> Self { + let fixture_path = PathBuf::from("fixtures"); + let repo_cfg = RepositoryConfig::load(&fixture_path); + + Self { + repo_cfg, + path: fixture_path, + ..self + } + } + } +} + #[cfg(test)] mod tests { - use std::{collections::HashMap, path::PathBuf}; + use std::collections::HashMap; use anyhow::Result; - use super::RepositoryConfig; + use super::test_utils::RepositoryConfigMock; #[test] - fn test_config_file_exists() -> Result<()> { - let template_dir = PathBuf::from("fixtures"); - let repo_cfg = RepositoryConfig::load(&template_dir); + fn test_config_file_load() { + let repo_cfg_mock = RepositoryConfigMock::new().with_fixture(); assert_eq!( - repo_cfg.copy_on_add, + repo_cfg_mock.repo_cfg.copy_on_add, HashMap::from_iter([("foo".to_string(), vec!["baz".to_string()])]) ); - - Ok(()) } #[test] - fn test_config_file_not_exists() -> Result<()> { - let template_dir = tempfile::tempdir()?; - let repo_cfg = RepositoryConfig::load(template_dir.path()); + fn test_config_load_file_not_exists() -> Result<()> { + let repo_cfg_mock = RepositoryConfigMock::new(); - assert!(repo_cfg.copy_on_add.is_empty()); + assert!(repo_cfg_mock.repo_cfg.copy_on_add.is_empty()); Ok(()) } diff --git a/src/scafalra.rs b/src/scafalra.rs index 50487ea..1408abe 100644 --- a/src/scafalra.rs +++ b/src/scafalra.rs @@ -199,7 +199,7 @@ impl Scafalra { .collect::>(); for (template, gw) in template_gw_list { - copy_by_glob_walker(gw, &template.path); + glob_walk_and_copy(gw, &template.path); } } @@ -262,7 +262,7 @@ impl Scafalra { .case_insensitive(true) .build() { - copy_by_glob_walker(gw, dest); + glob_walk_and_copy(gw, dest); } } @@ -374,7 +374,7 @@ impl Scafalra { } } -fn copy_by_glob_walker(gw: globwalk::GlobWalker, dest: &Path) { +fn glob_walk_and_copy(gw: globwalk::GlobWalker, dest: &Path) { for matching in gw.filter_map(|ret| ret.ok()) { let matching_path = matching.path(); debug!("matching_path: {:?}", matching_path); @@ -393,297 +393,386 @@ fn copy_by_glob_walker(gw: globwalk::GlobWalker, dest: &Path) { } #[cfg(test)] -mod tests { +mod test_utils { use std::{fs, path::PathBuf}; - use anyhow::Result; use mockito::{Mock, ServerGuard}; - use similar_asserts::assert_eq; use tempfile::{tempdir, TempDir}; use super::Scafalra; - use crate::{ - cli::{AddArgs, CreateArgs}, - github_api::mock_repo_response_json, - path_ext::*, - store::{test_utils::StoreJsonMocker, Store}, - }; #[cfg(feature = "self_update")] use crate::{ - cli::{UninstallArgs, UpdateArgs}, github_api::mock_release_response_json, utils::{get_self_target, get_self_version}, }; + use crate::{ + github_api::mock_repo_response_json, + store::{test_utils::StoreJsonMock, Store}, + }; - fn mock_scafalra( - endpoint: &str, - init_content: bool, - ) -> Result<(Scafalra, TempDir)> { - let temp_dir = tempdir()?; - let proj_dir = temp_dir.path().join("scafalra"); - - if init_content { - let store_file = proj_dir.join(Store::FILE_NAME); - let bar_dir = - proj_dir.join_iter([Scafalra::CACHE_DIR_NAME, "foo", "bar"]); - fs::create_dir_all(&bar_dir)?; - fs::write(bar_dir.join("baz.txt"), "")?; - fs::write( - store_file, - StoreJsonMocker::new().push("bar", bar_dir).build(), - )?; + pub struct ScafalraMock { + pub scafalra: Scafalra, + pub tmpdir: TempDir, + endpoint_cache: Option, + } + + impl ScafalraMock { + pub fn new() -> Self { + let tmpdir = tempdir().unwrap(); + let scafalra = Scafalra::new( + tmpdir.path().join("scafalra"), + None, + Some("token"), + ) + .unwrap(); + + Self { + scafalra, + tmpdir, + endpoint_cache: None, + } } - let scafalra = Scafalra::new(proj_dir, Some(endpoint), Some("token"))?; + pub fn endpoint(self, endpoint: &str) -> Self { + let scafalra = Scafalra::new( + self.scafalra.path, + Some(endpoint), + Some("token"), + ) + .unwrap(); - Ok((scafalra, temp_dir)) - } + Self { + scafalra, + endpoint_cache: Some(endpoint.to_string()), + ..self + } + } - fn mock_repo_server() -> Result<(ServerGuard, Mock, Mock)> { - let mut server = mockito::Server::new(); + pub fn with_content(self) -> Self { + use crate::path_ext::*; + + let store_file = self.scafalra.path.join(Store::FILE_NAME); + let bar_dir = self.scafalra.path.join_iter([ + Scafalra::CACHE_DIR_NAME, + "foo", + "bar", + ]); + fs::create_dir_all(&bar_dir).unwrap(); + fs::write(bar_dir.join("baz.txt"), "").unwrap(); + fs::write( + store_file, + StoreJsonMock::new().push("bar", bar_dir).build(), + ) + .unwrap(); + let scafalra = Scafalra::new( + self.scafalra.path, + self.endpoint_cache.as_deref(), + Some("token"), + ) + .unwrap(); - let query_repo_mock = server - .mock("POST", "/") - .with_status(200) - .with_header("content-type", "application/json") - .with_body(mock_repo_response_json(&server.url())) - .create(); + Self { + scafalra, + ..self + } + } + } - let downlowd_mock = server - .mock("GET", "/tarball") - .with_status(200) - .with_header("content-type", "application/gzip") - .with_body_from_file("fixtures/scafalra-test.tar.gz") - .create(); + pub struct RepoServerMock { + pub server: ServerGuard, + pub query_repo_mock: Mock, + pub download_mock: Mock, + } - Ok((server, query_repo_mock, downlowd_mock)) + impl RepoServerMock { + pub fn new() -> Self { + let mut server = mockito::Server::new(); + + let query_repo_mock = server + .mock("POST", "/") + .with_status(200) + .with_header("content-type", "application/json") + .with_body(mock_repo_response_json(&server.url())) + .create(); + + let download_mock = server + .mock("GET", "/tarball") + .with_status(200) + .with_header("content-type", "application/gzip") + .with_body_from_file("fixtures/scafalra-test.tar.gz") + .create(); + + Self { + server, + query_repo_mock, + download_mock, + } + } } #[cfg(feature = "self_update")] - fn mock_release_server() -> Result<(ServerGuard, Mock, Mock)> { - let mut server = mockito::Server::new(); - - let higher_ver = { - let mut v = semver::Version::parse(get_self_version()).unwrap(); - v.major += 1; - v.to_string() - }; + pub struct ReleaseServerMock { + pub server: ServerGuard, + pub query_release_mock: Mock, + pub download_mock: Mock, + } - let query_release_mock = server - .mock("POST", "/") - .with_status(200) - .with_header("content-type", "application/json") - .with_body(mock_release_response_json(&server.url(), &higher_ver)) - .create(); - - let download_mock = server - .mock( - "GET", - format!( - "/scafalra-{}-{}{}", - higher_ver, - get_self_target(), + #[cfg(feature = "self_update")] + impl ReleaseServerMock { + pub fn new() -> Self { + let mut server = mockito::Server::new(); + + let higher_ver = { + let mut v = semver::Version::parse(get_self_version()).unwrap(); + v.major += 1; + v.to_string() + }; + + let query_release_mock = server + .mock("POST", "/") + .with_status(200) + .with_header("content-type", "application/json") + .with_body(mock_release_response_json( + &server.url(), + &higher_ver, + )) + .create(); + + let download_mock = server + .mock( + "GET", + format!( + "/scafalra-{}-{}{}", + higher_ver, + get_self_target(), + if cfg!(windows) { + ".zip" + } else { + ".tar.gz" + } + ) + .as_str(), + ) + .with_status(200) + .with_header( + "content-type", if cfg!(windows) { - ".zip" + "application/zip" } else { - ".tar.gz" - } + "application/gzip" + }, ) - .as_str(), - ) - .with_status(200) - .with_header( - "content-type", - if cfg!(windows) { - "application/zip" - } else { - "application/gzip" - }, - ) - .with_body_from_file(PathBuf::from_iter([ - "fixtures", - if cfg!(windows) { - "scafalra-update-windows.zip" - } else { - "scafalra-update-unix.tar.gz" - }, - ])) - .create(); - - Ok((server, query_release_mock, download_mock)) + .with_body_from_file(PathBuf::from_iter([ + "fixtures", + if cfg!(windows) { + "scafalra-update-windows.zip" + } else { + "scafalra-update-unix.tar.gz" + }, + ])) + .create(); + + Self { + server, + query_release_mock, + download_mock, + } + } } +} - #[test] - fn test_scafalra_new() -> Result<()> { - let (scafalra, _dir) = mock_scafalra("", false)?; +#[cfg(test)] +mod tests { + use std::{fs, path::PathBuf}; - assert!(scafalra.cache_dir.exists()); - assert!(scafalra.store.path.exists()); - assert!(scafalra.config.path.exists()); + use anyhow::Result; + use similar_asserts::assert_eq; + use tempfile::tempdir; - Ok(()) + use super::test_utils::{ReleaseServerMock, RepoServerMock, ScafalraMock}; + #[cfg(feature = "self_update")] + use crate::cli::{UninstallArgs, UpdateArgs}; + use crate::{ + cli::{AddArgs, CreateArgs}, + path_ext::*, + store::test_utils::StoreJsonMock, + }; + + #[test] + fn test_scafalra_new() { + let scafalra_mock = ScafalraMock::new(); + + assert!(scafalra_mock.scafalra.cache_dir.exists()); + assert!(scafalra_mock.scafalra.store.path.exists()); + assert!(scafalra_mock.scafalra.config.path.exists()); } #[test] fn test_scafalra_add() -> Result<()> { - let (server, query_repo_mock, download_mock) = mock_repo_server()?; - let (mut scafalra, _dir) = mock_scafalra(&server.url(), false)?; + let repo_server_mock = RepoServerMock::new(); + let mut scafalra_mock = + ScafalraMock::new().endpoint(&repo_server_mock.server.url()); - scafalra.add(AddArgs { + scafalra_mock.scafalra.add(AddArgs { repository: "foo/bar".to_string(), depth: 0, name: None, })?; - query_repo_mock.assert(); - download_mock.assert(); + repo_server_mock.query_repo_mock.assert(); + repo_server_mock.download_mock.assert(); - let store_content = fs::read_to_string(&scafalra.store.path)?; - let bar_dir = scafalra.cache_dir.join_slash("foo/bar"); - let expected = StoreJsonMocker::new().push("bar", &bar_dir).build(); + let bar_dir = scafalra_mock.scafalra.cache_dir.join_slash("foo/bar"); + let actual = fs::read_to_string(&scafalra_mock.scafalra.store.path)?; + let expect = StoreJsonMock::new().push("bar", &bar_dir).build(); assert!(bar_dir.exists()); - assert_eq!(store_content, expected); + assert_eq!(actual, expect); Ok(()) } #[test] fn test_scafalra_add_specified_name() -> Result<()> { - let (server, query_repo_mock, download_mock) = mock_repo_server()?; - let (mut scafalra, _dir) = mock_scafalra(&server.url(), false)?; + let repo_server_mock = RepoServerMock::new(); + let mut scafalra_mock = + ScafalraMock::new().endpoint(&repo_server_mock.server.url()); - scafalra.add(AddArgs { + scafalra_mock.scafalra.add(AddArgs { repository: "foo/bar".to_string(), depth: 0, name: Some("foo".to_string()), })?; - query_repo_mock.assert(); - download_mock.assert(); + repo_server_mock.query_repo_mock.assert(); + repo_server_mock.download_mock.assert(); - let store_content = fs::read_to_string(&scafalra.store.path)?; - let bar_dir = scafalra.cache_dir.join_slash("foo/bar"); - let expected = StoreJsonMocker::new().push("foo", &bar_dir).build(); + let bar_dir = scafalra_mock.scafalra.cache_dir.join_slash("foo/bar"); + let actual = fs::read_to_string(&scafalra_mock.scafalra.store.path)?; + let expect = StoreJsonMock::new().push("foo", &bar_dir).build(); assert!(bar_dir.exists()); - assert_eq!(store_content, expected); + assert_eq!(actual, expect); Ok(()) } #[test] fn test_scafalra_add_depth_1() -> Result<()> { - let (server, query_repo_mock, download_mock) = mock_repo_server()?; - let (mut scafalra, _dir) = mock_scafalra(&server.url(), false)?; + let repo_server_mock = RepoServerMock::new(); + let mut scafalra_mock = + ScafalraMock::new().endpoint(&repo_server_mock.server.url()); - scafalra.add(AddArgs { + scafalra_mock.scafalra.add(AddArgs { repository: "foo/bar".to_string(), depth: 1, name: Some("foo".to_string()), })?; - query_repo_mock.assert(); - download_mock.assert(); + repo_server_mock.query_repo_mock.assert(); + repo_server_mock.download_mock.assert(); - let store_content = fs::read_to_string(&scafalra.store.path)?; - let bar_dir = scafalra.cache_dir.join_slash("foo/bar"); - let expected = StoreJsonMocker::new() + let bar_dir = scafalra_mock.scafalra.cache_dir.join_slash("foo/bar"); + let actual = fs::read_to_string(&scafalra_mock.scafalra.store.path)?; + let expect = StoreJsonMock::new() .push("a", bar_dir.join("a")) .push("b", bar_dir.join("b")) .push("c", bar_dir.join("c")) .push("node_modules", bar_dir.join("node_modules")) - .all_to_sub_template() + .all_sub_template() .build(); assert!(bar_dir.exists()); - assert_eq!(store_content, expected); + assert_eq!(actual, expect); Ok(()) } #[test] fn test_scafalra_add_subdir() -> Result<()> { - let (server, query_repo_mock, download_mock) = mock_repo_server()?; - let (mut scafalra, _dir) = mock_scafalra(&server.url(), false)?; + let repo_server_mock = RepoServerMock::new(); + let mut scafalra_mock = + ScafalraMock::new().endpoint(&repo_server_mock.server.url()); - scafalra.add(AddArgs { + scafalra_mock.scafalra.add(AddArgs { repository: "foo/bar/a/a1".to_string(), depth: 0, name: None, })?; - query_repo_mock.assert(); - download_mock.assert(); + repo_server_mock.query_repo_mock.assert(); + repo_server_mock.download_mock.assert(); - let store_content = fs::read_to_string(&scafalra.store.path)?; - let a1_dir = scafalra.cache_dir.join_slash("foo/bar/a/a1"); - let expected = StoreJsonMocker::new().push("a1", &a1_dir).build(); + let a1_dir = + scafalra_mock.scafalra.cache_dir.join_slash("foo/bar/a/a1"); + let actual = fs::read_to_string(&scafalra_mock.scafalra.store.path)?; + let expect = StoreJsonMock::new().push("a1", &a1_dir).build(); assert!(a1_dir.exists()); - assert_eq!(store_content, expected); + assert_eq!(actual, expect); Ok(()) } #[test] fn test_scafalra_add_subdir_and_depth_1() -> Result<()> { - let (server, query_repo_mock, download_mock) = mock_repo_server()?; - let (mut scafalra, _dir) = mock_scafalra(&server.url(), false)?; + let repo_server_mock = RepoServerMock::new(); + let mut scafalra_mock = + ScafalraMock::new().endpoint(&repo_server_mock.server.url()); - scafalra.add(AddArgs { + scafalra_mock.scafalra.add(AddArgs { repository: "foo/bar/a".to_string(), depth: 1, name: None, })?; - query_repo_mock.assert(); - download_mock.assert(); + repo_server_mock.query_repo_mock.assert(); + repo_server_mock.download_mock.assert(); - let store_content = fs::read_to_string(&scafalra.store.path)?; - let a_dir = scafalra.cache_dir.join_slash("foo/bar/a"); + let a_dir = scafalra_mock.scafalra.cache_dir.join_slash("foo/bar/a"); let a1_dir = a_dir.join("a1"); let a2_dir = a_dir.join("a2"); let a3_dir = a_dir.join("a3"); - let expected = StoreJsonMocker::new() + let actual = fs::read_to_string(&scafalra_mock.scafalra.store.path)?; + let expect = StoreJsonMock::new() .push("a1", &a1_dir) .push("a2", &a2_dir) .push("a3", &a3_dir) - .all_to_sub_template() + .all_sub_template() .build(); assert!(a1_dir.exists()); assert!(a2_dir.exists()); assert!(a3_dir.exists()); - assert_eq!(store_content, expected); + assert_eq!(actual, expect); Ok(()) } #[test] fn test_scafalra_create() -> Result<()> { - let (scafalra, temp_dir) = mock_scafalra("", true)?; + let scafalra_mock = ScafalraMock::new().with_content(); - let temp_dir_path = temp_dir.path(); + let tmpdir_path = scafalra_mock.tmpdir.path(); - scafalra.create(CreateArgs { + scafalra_mock.scafalra.create(CreateArgs { name: "bar".to_string(), // Due to chroot restrictions, a directory is specified here to // simulate the current working directory - directory: Some(temp_dir_path.join("bar")), + directory: Some(tmpdir_path.join("bar")), with: None, })?; - assert!(temp_dir_path.join_slash("bar/baz.txt").exists()); + assert!(tmpdir_path.join_slash("bar/baz.txt").exists()); Ok(()) } #[test] fn test_scafalra_create_not_found() -> Result<()> { - let (scafalra, _dir) = mock_scafalra("", false)?; + let scafalra_mock = ScafalraMock::new(); - let ret = scafalra.create(CreateArgs { + let ret = scafalra_mock.scafalra.create(CreateArgs { name: "bar".to_string(), directory: None, with: None, @@ -697,15 +786,16 @@ mod tests { #[test] #[cfg(feature = "self_update")] fn test_scafalra_update_check() -> Result<()> { - let (server, query_release_mock, _) = mock_release_server()?; - let (scafalra, _temp_dir) = mock_scafalra(&server.url(), false)?; + let release_server_mock = ReleaseServerMock::new(); + let scafalra_mock = + ScafalraMock::new().endpoint(&release_server_mock.server.url()); - scafalra.update(UpdateArgs { + scafalra_mock.scafalra.update(UpdateArgs { check: true, })?; - query_release_mock.assert(); - assert!(!scafalra.update_dir.exists()); + release_server_mock.query_release_mock.assert(); + assert!(!scafalra_mock.scafalra.update_dir.exists()); Ok(()) } @@ -713,17 +803,17 @@ mod tests { #[test] #[cfg(feature = "self_update")] fn test_scafalra_update() -> Result<()> { - let (server, query_release_mock, download_mock) = - mock_release_server()?; - let (scafalra, _temp_dir) = mock_scafalra(&server.url(), false)?; + let release_server_mock = ReleaseServerMock::new(); + let scafalra_mock = + ScafalraMock::new().endpoint(&release_server_mock.server.url()); - scafalra.update(UpdateArgs { + scafalra_mock.scafalra.update(UpdateArgs { check: false, })?; - query_release_mock.assert(); - download_mock.assert(); - assert!(!scafalra.update_dir.exists()); + release_server_mock.query_release_mock.assert(); + release_server_mock.download_mock.assert(); + assert!(!scafalra_mock.scafalra.update_dir.exists()); Ok(()) } @@ -731,13 +821,13 @@ mod tests { #[test] #[cfg(feature = "self_update")] fn test_scafalra_uninstall() -> Result<()> { - let (scafalra, _temp_dir) = mock_scafalra("", false)?; + let scafalra_mock = ScafalraMock::new(); - scafalra.uninstall(UninstallArgs { + scafalra_mock.scafalra.uninstall(UninstallArgs { keep_data: false, })?; - assert!(!scafalra.path.exists()); + assert!(!scafalra_mock.scafalra.path.exists()); Ok(()) } @@ -745,13 +835,13 @@ mod tests { #[test] #[cfg(feature = "self_update")] fn test_scafalra_uninstall_keep_data() -> Result<()> { - let (scafalra, _temp_dir) = mock_scafalra("", false)?; + let scafalra_mock = ScafalraMock::new(); - scafalra.uninstall(UninstallArgs { + scafalra_mock.scafalra.uninstall(UninstallArgs { keep_data: true, })?; - assert!(scafalra.path.exists()); + assert!(scafalra_mock.scafalra.path.exists()); Ok(()) } @@ -762,16 +852,18 @@ mod tests { #[test] fn test_scafalra_copy_on_add() -> Result<()> { - let (server, _query_repo_mock, _download_mock) = mock_repo_server()?; - let (mut scafalra, _dir) = mock_scafalra(&server.url(), false)?; + let repo_server_mock = RepoServerMock::new(); + let mut scafalra_mock = + ScafalraMock::new().endpoint(&repo_server_mock.server.url()); - scafalra.add(AddArgs { + scafalra_mock.scafalra.add(AddArgs { repository: "foo/bar".to_string(), depth: 1, name: Some("foo".to_string()), })?; - let template_dir = scafalra.cache_dir.join_slash("foo/bar"); + let template_dir = + scafalra_mock.scafalra.cache_dir.join_slash("foo/bar"); let a_dir = template_dir.join("a"); assert!(is_all_exists(&[ @@ -794,10 +886,11 @@ mod tests { #[test] fn test_scafalra_copy_on_create() -> Result<()> { - let (server, _query_repo_mock, _download_mock) = mock_repo_server()?; - let (mut scafalra, _dir) = mock_scafalra(&server.url(), false)?; + let repo_server_mock = RepoServerMock::new(); + let mut scafalra_mock = + ScafalraMock::new().endpoint(&repo_server_mock.server.url()); - scafalra.add(AddArgs { + scafalra_mock.scafalra.add(AddArgs { repository: "foo/bar".to_string(), depth: 1, name: Some("foo".to_string()), @@ -806,7 +899,7 @@ mod tests { let tmp_dir = tempdir()?; let dest = tmp_dir.path().join("dest"); - scafalra.create(CreateArgs { + scafalra_mock.scafalra.create(CreateArgs { name: "b".to_string(), directory: Some(dest.clone()), with: Some("common.txt,copy-dir,copy-all-in-dir/**".to_string()), diff --git a/src/store.rs b/src/store.rs index cedcf26..38e9dc3 100644 --- a/src/store.rs +++ b/src/store.rs @@ -273,15 +273,21 @@ impl Store { #[cfg(test)] pub mod test_utils { - use std::{collections::BTreeMap, path::Path}; + use std::{ + collections::BTreeMap, + fs, + path::{Path, PathBuf}, + }; - use super::{Template, TemplateMap}; + use tempfile::{tempdir, TempDir}; + + use super::{Store, Template, TemplateMap}; - pub struct StoreJsonMocker { + pub struct StoreJsonMock { data: Vec