Repository: cargo-generate/cargo-generate
Pull request #1346 (2024-12-23 21:55:38)

fix tests and copy path simplifiation
(should) solve #1345

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/cargo-generate/cargo-generate/pull/1346?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate) Report
Attention: Patch coverage is `76.42276%` with `58 lines` in your changes missing coverage. Please review.
> Project coverage is 79.26%. Comparing base [(`483c89f`)](https://app.codecov.io/gh/cargo-generate/cargo-generate/commit/483c89fd2234056f28bf84f05c6f8ac890e23a7c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate) to head [(`0a6dea5`)](https://app.codecov.io/gh/cargo-generate/cargo-generate/commit/0a6dea5b23025fbd0d4c6dafa4a4475a2e068f95?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate).

| [Files with missing lines](https://app.codecov.io/gh/cargo-generate/cargo-generate/pull/1346?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate) | Patch % | Lines |
|---|---|---|
| [src/copy.rs](https://app.codecov.io/gh/cargo-generate/cargo-generate/pull/1346?src=pr&el=tree&filepath=src%2Fcopy.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate#diff-c3JjL2NvcHkucnM=) | 78.26% | [14 Missing and 11 partials :warning: ](https://app.codecov.io/gh/cargo-generate/cargo-generate/pull/1346?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate) |
| [src/workspace\_member.rs](https://app.codecov.io/gh/cargo-generate/cargo-generate/pull/1346?src=pr&el=tree&filepath=src%2Fworkspace_member.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate#diff-c3JjL3dvcmtzcGFjZV9tZW1iZXIucnM=) | 69.35% | [9 Missing and 10 partials :warning: ](https://app.codecov.io/gh/cargo-generate/cargo-generate/pull/1346?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate) |
| [src/template\_variables/project\_dir.rs](https://app.codecov.io/gh/cargo-generate/cargo-generate/pull/1346?src=pr&el=tree&filepath=src%2Ftemplate_variables%2Fproject_dir.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate#diff-c3JjL3RlbXBsYXRlX3ZhcmlhYmxlcy9wcm9qZWN0X2Rpci5ycw==) | 46.66% | [7 Missing and 1 partial :warning: ](https://app.codecov.io/gh/cargo-generate/cargo-generate/pull/1346?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate) |
| [src/lib.rs](https://app.codecov.io/gh/cargo-generate/cargo-generate/pull/1346?src=pr&el=tree&filepath=src%2Flib.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate#diff-c3JjL2xpYi5ycw==) | 86.36% | [1 Missing and 5 partials :warning: ](https://app.codecov.io/gh/cargo-generate/cargo-generate/pull/1346?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #1346      +/-   ##
==========================================
- Coverage   79.58%   79.26%   -0.33%     
==========================================
  Files          31       33       +2     
  Lines        4252     4369     +117     
  Branches     4252     4369     +117     
==========================================
+ Hits         3384     3463      +79     
- Misses        620      650      +30     
- Partials      248      256       +8     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/cargo-generate/cargo-generate/pull/1346?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cargo-generate).


Patch:
diff --git a/src/copy.rs b/src/copy.rs
new file mode 100644
index 0000000..9e46215
--- /dev/null
+++ b/src/copy.rs
@@ -0,0 +1,172 @@
+use anyhow::{bail, Ok, Result};
+use console::style;
+use log::{debug, warn};
+use std::{
+    fs::{copy, read_dir, remove_file},
+    path::Path,
+};
+
+const LIQUID_SUFFIX: &str = ".liquid";
+
+pub fn copy_files_recursively(
+    src: impl AsRef<Path>,
+    dst: impl AsRef<Path>,
+    overwrite: bool,
+) -> Result<()> {
+    let dst_path = dst.as_ref();
+
+    for src_entry in read_dir(src.as_ref())? {
+        let src_entry = src_entry?;
+        let filename = src_entry.file_name().to_string_lossy().to_string();
+        let entry_type = src_entry.file_type()?;
+
+        if entry_type.is_dir() {
+            // we skip the .git directory
+            if filename == ".git" {
+                continue;
+            }
+            let dst_dir = dst_path.join(filename);
+            if !dst_dir.exists() {
+                std::fs::create_dir(&dst_dir)?;
+            }
+            copy_files_recursively(src_entry.path(), dst_dir, overwrite)?;
+        } else if entry_type.is_file() {
+            copy_file(&src_entry.path(), dst_path, overwrite)?;
+        } else {
+            // todo: maybe we better emit a warning but continue processing the other files
+            warn!(
+                "{} {} `{}`",
+                crate::emoji::WARN,
+                style("[Skipping] Symbolic links not supported")
+                    .bold()
+                    .red(),
+                style(src_entry.path().display()).bold(),
+            )
+        }
+    }
+
+    Ok(())
+}
+
+/// move a file from src to dst, possibly overwriting existing files if overwrite is true
+/// if the file has a .liquid suffix, the suffix will be removed in the destination, and overwritten if existing
+fn copy_file(src_path: &Path, dst: &Path, overwrite: bool) -> Result<()> {
+    let filename = src_path.file_name().unwrap().to_string_lossy().to_string();
+    let dst_path = dst.join(&filename);
+    let mut overwrite = overwrite;
+
+    if let Some(new_filename) = filename.strip_suffix(LIQUID_SUFFIX) {
+        if src_path.with_file_name(new_filename).exists() {
+            // if there is a file without the .liquid suffix, we want to set overwrite to true
+            // so that this liquid file takes precedence over the existing file
+            debug!("A non-liquid file exists for {filename}, overwriting it with the liquid file");
+            overwrite = true;
+        }
+
+        // move the file to a new filename without the .liquid suffix, in any case
+        let dst_path = dst.join(new_filename);
+        safe_copy(src_path, &dst_path, overwrite)?;
+    } else if src_path
+        .with_file_name(format!("{filename}{LIQUID_SUFFIX}"))
+        .exists()
+    {
+        // there is a liquid file for this non-liquid file,
+        // so we skip this one, so that the liquid file takes precedence
+        debug!("A liquid file exists for {filename}, skipping the non-liquid file");
+        return Ok(());
+    } else {
+        // if the file doesn't have a .liquid suffix, just copy it
+        // possibly overwriting existing files if overwrite is true
+        safe_copy(src_path, &dst_path, overwrite)?;
+    }
+
+    Ok(())
+}
+
+fn safe_copy(src_path: &Path, dst_path: &Path, overwrite: bool) -> Result<()> {
+    if dst_path.exists() && !overwrite {
+        bail!(
+            "{} {} `{}` {}",
+            crate::emoji::ERROR,
+            style("File already exists").bold().red(),
+            style(dst_path.display()).bold(),
+            style("and `--overwrite` was not passed")
+        )
+    }
+
+    if dst_path.exists() && overwrite {
+        remove_file(dst_path)?;
+        copy(src_path, dst_path)?;
+    } else if !dst_path.exists() {
+        copy(src_path, dst_path)?;
+    }
+
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use tempfile::tempdir;
+
+    #[test]
+    fn test_overwriting_behavior() {
+        let tmp = tempdir().unwrap();
+        let f1 = tmp.path().join("README.md");
+        std::fs::write(&f1, "A README").unwrap();
+        let f2 = tmp.path().join("README.md.liquid");
+        std::fs::write(&f2, "A README liquid file").unwrap();
+
+        assert!(
+            safe_copy(f1.as_path(), f2.as_path(), false).is_err(),
+            "we do not allow overwriting without the flag set"
+        );
+        assert!(
+            safe_copy(f1.as_path(), f2.as_path(), true).is_ok(),
+            "we do allow overwriting with the flag set"
+        );
+        assert_eq!(std::fs::read_to_string(f2.as_path()).unwrap(), "A README");
+    }
+
+    #[test]
+    fn test_special_liquid_file_handling() {
+        let tmp = tempdir().unwrap();
+        let f1 = tmp.path().join("README.md");
+        std::fs::write(&f1, "A README").unwrap();
+        let f2 = tmp.path().join("README.md.liquid");
+        std::fs::write(&f2, "A README liquid file").unwrap();
+
+        let tmp2 = tempdir().unwrap();
+
+        // copy the non liquid file first, should not copy anything
+        copy_file(f1.as_path(), tmp2.path(), false).unwrap();
+        assert!(
+            !tmp2.path().join("README.md").exists(),
+            "the file should not be copied"
+        );
+
+        // copy the liquid file, should copy the liquid file and remove the .liquid suffix
+        copy_file(f2.as_path(), tmp2.path(), false).unwrap();
+        assert!(
+            tmp2.path().join("README.md").exists(),
+            "the file should be copied and the .liquid suffix removed"
+        );
+        assert_eq!(
+            std::fs::read_to_string(tmp2.path().join("README.md")).unwrap(),
+            "A README liquid file"
+        );
+
+        // copy the liquid file, while the same file without the .liquid suffix exists,
+        // should overwrite the existing file, as if the overwrite flag was set
+        let f4 = tmp2.path().join("README.md");
+        std::fs::write(&f4, "Existing file, should be overwritten").unwrap();
+        assert!(
+            copy_file(f2.as_path(), tmp2.path(), false).is_ok(),
+            "the file should be copied"
+        );
+        assert_eq!(
+            std::fs::read_to_string(tmp2.path().join("README.md")).unwrap(),
+            "A README liquid file"
+        );
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 4717626..fa0cc5b 100755
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -25,6 +25,7 @@
 mod app_config;
 mod args;
 mod config;
+mod copy;
 mod emoji;
 mod favorites;
 mod filenames;
@@ -49,6 +50,7 @@ pub use args::*;
 use anyhow::{anyhow, bail, Context, Result};
 use config::{locate_template_configs, Config, CONFIG_FILE_NAME};
 use console::style;
+use copy::copy_files_recursively;
 use env_logger::fmt::Formatter;
 use fs_err as fs;
 use hooks::execute_hooks;
@@ -202,7 +204,7 @@ fn copy_expanded_template(
         style(project_dir.display()).bold().yellow(),
         style("...").bold()
     );
-    copy_dir_all(template_dir, &project_dir, user_parsed_input.overwrite())?;
+    copy_files_recursively(template_dir, &project_dir, user_parsed_input.overwrite())?;
 
     Ok(project_dir)
 }
@@ -261,37 +263,18 @@ fn get_source_template_into_temp(
             );
             if let Ok((ref temp_dir, _)) = result {
                 git::remove_history(temp_dir.path())?;
-                strip_liquid_suffixes(temp_dir.path())?;
             };
             result
         }
         TemplateLocation::Path(path) => {
             let temp_dir = tmp_dir()?;
-            copy_dir_all(path, temp_dir.path(), false)?;
+            copy_files_recursively(path, temp_dir.path(), false)?;
             git::remove_history(temp_dir.path())?;
             Ok((temp_dir, try_get_branch_from_path(path)))
         }
     }
 }
 
-/// remove .liquid suffixes from git templates for parity with path templates
-fn strip_liquid_suffixes(dir: impl AsRef<Path>) -> Result<()> {
-    for entry in fs::read_dir(dir.as_ref())? {
-        let entry = entry?;
-        let entry_type = entry.file_type()?;
-
-        if entry_type.is_dir() {
-            strip_liquid_suffixes(entry.path())?;
-        } else if entry_type.is_file() {
-            let path = entry.path().to_string_lossy().to_string();
-            if let Some(new_path) = path.clone().strip_suffix(".liquid") {
-                fs::rename(path, new_path)?;
-            }
-        }
-    }
-    Ok(())
-}
-
 /// resolve the template location for the actual template to expand
 fn resolve_template_dir(template_base_dir: &TempDir, subfolder: Option<&str>) -> Result<PathBuf> {
     let template_dir = resolve_template_dir_subfolder(template_base_dir.path(), subfolder)?;
@@ -422,86 +405,6 @@ fn resolve_configured_sub_templates(
         )
 }
 
-pub(crate) fn copy_dir_all(
-    src: impl AsRef<Path>,
-    dst: impl AsRef<Path>,
-    overwrite: bool,
-) -> Result<()> {
-    fn check_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>, overwrite: bool) -> Result<()> {
-        if !dst.as_ref().exists() {
-            return Ok(());
-        }
-
-        for src_entry in fs::read_dir(src.as_ref())? {
-            let src_entry = src_entry?;
-            let filename = src_entry.file_name().to_string_lossy().to_string();
-            let entry_type = src_entry.file_type()?;
-
-            if entry_type.is_dir() {
-                if filename == ".git" {
-                    continue;
-                }
-                let dst_path = dst.as_ref().join(filename);
-                check_dir_all(src_entry.path(), dst_path, overwrite)?;
-            } else if entry_type.is_file() {
-                let filename = filename.strip_suffix(".liquid").unwrap_or(&filename);
-                let dst_path = dst.as_ref().join(filename);
-                match (dst_path.exists(), overwrite) {
-                    (true, false) => {
-                        bail!(
-                            "{} {} {}",
-                            crate::emoji::WARN,
-                            style("File already exists:").bold().red(),
-                            style(dst_path.display()).bold().red(),
-                        )
-                    }
-                    (true, true) => {
-                        warn!(
-                            "{} {}",
-                            style("Overwriting file:").bold().red(),
-                            style(dst_path.display()).bold().red(),
-                        );
-                    }
-                    _ => {}
-                };
-            } else {
-                bail!(
-                    "{} {}",
-                    crate::emoji::WARN,
-                    style("Symbolic links not supported").bold().red(),
-                )
-            }
-        }
-        Ok(())
-    }
-    fn copy_all(src: impl AsRef<Path>, dst: impl AsRef<Path>, overwrite: bool) -> Result<()> {
-        fs::create_dir_all(&dst)?;
-        for src_entry in fs::read_dir(src.as_ref())? {
-            let src_entry = src_entry?;
-            let filename = src_entry.file_name().to_string_lossy().to_string();
-            let entry_type = src_entry.file_type()?;
-            if entry_type.is_dir() {
-                let dst_path = dst.as_ref().join(filename);
-                if ".git" == src_entry.file_name() {
-                    continue;
-                }
-                copy_dir_all(src_entry.path(), dst_path, overwrite)?;
-            } else if entry_type.is_file() {
-                let filename = filename.strip_suffix(".liquid").unwrap_or(&filename);
-                let dst_path = dst.as_ref().join(filename);
-                if dst_path.exists() && overwrite {
-                    fs::remove_file(&dst_path)?;
-                }
-                fs::copy(src_entry.path(), dst_path)?;
-            }
-        }
-        Ok(())
-    }
-
-    check_dir_all(&src, &dst, overwrite)?;
-    copy_all(src, dst, overwrite)
-}
-
 fn locate_template_file(
     name: &str,
     template_base_folder: impl AsRef<Path>,
@@ -547,8 +450,12 @@ fn expand_template(
 
     let project_name_input = ProjectNameInput::try_from((&liquid_object, user_parsed_input))?;
     let project_name = ProjectName::from((&project_name_input, user_parsed_input));
-    let destination = ProjectDir::try_from((&project_name_input, user_parsed_input))?;
     let crate_name = CrateName::from(&project_name_input);
+    let destination = ProjectDir::try_from((&project_name_input, user_parsed_input))?;
+    if !user_parsed_input.init() {
+        destination.create()?;
+    }
+
     set_project_name_variables(&liquid_object, &destination, &project_name, &crate_name)?;
 
     info!(
diff --git a/src/template_variables/project_dir.rs b/src/template_variables/project_dir.rs
index e9844c8..23a5b2e 100644
--- a/src/template_variables/project_dir.rs
+++ b/src/template_variables/project_dir.rs
@@ -79,6 +79,25 @@ impl TryFrom<(&ProjectNameInput, &UserParsedInput)> for ProjectDir {
     }
 }
 
+impl ProjectDir {
+    pub fn create(&self) -> anyhow::Result<()> {
+        let path = self.0.as_path();
+        if path.exists() {
+            bail!(
+                "{} {}",
+                emoji::ERROR,
+                style("Target directory already exists, aborting!")
+                    .bold()
+                    .red()
+            );
+        }
+
+        std::fs::create_dir(&self.0)?;
+
+        Ok(())
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;


Test patch:
diff --git a/tests/integration/basics.rs b/tests/integration/basics.rs
index e52078c..3960b06 100644
--- a/tests/integration/basics.rs
+++ b/tests/integration/basics.rs
@@ -2,16 +2,7 @@ use crate::helpers::prelude::*;
 
 #[test]
 fn it_can_use_a_plain_folder() {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .build();
+    let template = tempdir().with_default_manifest().build();
 
     let dir = tempdir().build();
 
@@ -37,16 +28,7 @@ version = "0.1.0"
 
 #[test]
 fn it_can_use_a_specified_path() {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .build();
+    let template = tempdir().with_default_manifest().build();
 
     let dir = tempdir().build();
 
@@ -65,17 +47,7 @@ version = "0.1.0"
 
 #[test]
 fn it_substitutes_projectname_in_cargo_toml() {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
 
     let dir = tempdir().build();
 
@@ -156,17 +128,7 @@ fn it_substitutes_os_arch() {
 
 #[test]
 fn it_keeps_snake_case_projectname() {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
 
     let dir = tempdir().build();
 
@@ -214,17 +176,7 @@ extern crate {{crate_name}};
 
 #[test]
 fn short_commands_work() {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
 
     let dir = tempdir().build();
 
@@ -244,17 +196,7 @@ version = "0.1.0"
 
 #[test]
 fn it_can_generate_inside_existing_repository() -> anyhow::Result<()> {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
     let dir = tempdir().build();
     binary()
         .arg_git(template.path())
@@ -283,18 +225,13 @@ version = "0.1.0"
 
 #[test]
 fn it_can_generate_into_cwd() -> anyhow::Result<()> {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
     let dir = tempdir().build();
+    assert!(
+        !dir.path().join(".git").exists(),
+        "Pre-condition: there should not be a .git dir in CWD"
+    );
+
     binary()
         .arg_git(template.path())
         .arg_name("my-proj")
@@ -304,24 +241,23 @@ version = "0.1.0"
         .success()
         .stdout(predicates::str::contains("Done!").from_utf8());
     assert!(dir.read("Cargo.toml").contains("my-proj"));
-    assert!(!dir.path().join(".git").exists());
+
+    assert!(
+        !dir.path().join(".git").exists(),
+        "Post-condition: there should not be a .git dir in CWD"
+    );
     Ok(())
 }
 
 #[test]
 fn it_can_generate_into_existing_git_dir() -> anyhow::Result<()> {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
     let dir = tempdir().file(".git/config", "foobar").build();
+    assert!(
+        dir.path().join(".git").exists(),
+        "Pre-condition: there is a .git dir in CWD"
+    );
+
     binary()
         .arg_git(template.path())
         .arg_name("my-proj")
@@ -331,23 +267,16 @@ version = "0.1.0"
         .success()
         .stdout(predicates::str::contains("Done!").from_utf8());
     assert!(dir.read("Cargo.toml").contains("my-proj"));
-    assert!(dir.read(".git/config").contains("foobar"));
+    assert!(
+        dir.read(".git/config").contains("foobar"),
+        "Post-condition: .git/config is preserved"
+    );
     Ok(())
 }
 
 #[test]
 fn it_can_generate_at_given_path() -> anyhow::Result<()> {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
     let dir = tempdir().build();
     let dest = dir.path().join("destination");
     fs::create_dir(&dest).expect("can create directory");
@@ -368,17 +297,7 @@ version = "0.1.0"
 
 #[test]
 fn it_refuses_to_overwrite_files() -> anyhow::Result<()> {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
     let dir = tempdir().build();
     let _ = binary()
         .arg_git(template.path())
@@ -399,17 +318,7 @@ version = "0.1.0"
 
 #[test]
 fn it_can_overwrite_files() -> anyhow::Result<()> {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
     let dir = tempdir().build();
     let _ = binary()
         .arg_git(template.path())
@@ -431,17 +340,7 @@ version = "0.1.0"
 
 #[test]
 fn it_allows_user_defined_projectname_when_passing_force_flag() {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
 
     let dir = tempdir().build();
 
@@ -463,14 +362,7 @@ version = "0.1.0"
 #[test]
 fn it_removes_files_listed_in_genignore() {
     let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
+        .with_default_manifest()
         .file(
             ".genignore",
             r#"deleteme.sh
@@ -502,14 +394,7 @@ version = "0.1.0"
 #[test]
 fn it_prints_ignored_files_with_verbose() {
     let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
+        .with_default_manifest()
         .file(
             ".genignore",
             r#"deleteme.sh
@@ -536,14 +421,7 @@ version = "0.1.0"
 #[test]
 fn it_always_removes_genignore_file() {
     let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
+        .with_default_manifest()
         .file(".genignore", r#"farts"#)
         .init_git()
         .build();
@@ -823,17 +701,7 @@ fn it_respects_template_branch_name() {
 
 #[test]
 fn it_doesnt_warn_with_neither_config_nor_ignore() {
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
     let dir = tempdir().build();
 
     binary()
@@ -911,17 +779,7 @@ _This README was generated with [cargo-readme](https://github.com/livioribeiro/c
 #[test]
 fn it_uses_vsc_none_to_avoid_initializing_repository() {
     // Build and commit on branch named 'main'
-    let template = tempdir()
-        .file(
-            "Cargo.toml",
-            r#"[package]
-name = "{{project-name}}"
-description = "A wonderful project"
-version = "0.1.0"
-"#,
-        )
-        .init_git()
-        .build();
+    let template = tempdir().init_default_template().build();
 
     let dir = tempdir().build();
 
diff --git a/tests/integration/filenames.rs b/tests/integration/filenames.rs
index 2dcff63..be0cd61 100644
--- a/tests/integration/filenames.rs
+++ b/tests/integration/filenames.rs
@@ -91,7 +91,6 @@ fn assert_liquid_paths(location: Location) {
     }
 
     let target = tempdir().build();
-
     binary_command
         .arg_name("foobar-project")
         .current_dir(target.path())
diff --git a/tests/integration/helpers/project_builder.rs b/tests/integration/helpers/project_builder.rs
index 2e5b2cd..da7cc7f 100644
--- a/tests/integration/helpers/project_builder.rs
+++ b/tests/integration/helpers/project_builder.rs
@@ -36,11 +36,11 @@ impl ProjectBuilder {
     /// - one file `Cargo.toml` in it
     /// - one placeholder `project-name`
     pub fn init_default_template(self) -> Self {
-        self.default_manifest().init_git()
+        self.with_default_manifest().init_git()
     }
 
     /// creates a `Cargo.toml` manifest with a `project-name` placeholder
-    pub fn default_manifest(self) -> Self {
+    pub fn with_default_manifest(self) -> Self {
         self.file(
             "Cargo.toml",
             indoc! {r#"
diff --git a/tests/integration/template_config_file/misc.rs b/tests/integration/template_config_file/misc.rs
index df2a1d0..9708d8b 100644
--- a/tests/integration/template_config_file/misc.rs
+++ b/tests/integration/template_config_file/misc.rs
@@ -3,7 +3,7 @@ use crate::helpers::prelude::*;
 #[test]
 fn it_always_removes_config_file() {
     let template = tempdir()
-        .default_manifest()
+        .with_default_manifest()
         .file(
             "cargo-generate.toml",
             r#"[template]
@@ -30,7 +30,7 @@ fn it_always_removes_config_file() {
 #[test]
 fn it_doesnt_warn_on_config_with_no_ignore() {
     let template = tempdir()
-        .default_manifest()
+        .with_default_manifest()
         .file(
             "cargo-generate.toml",
             r#"[template]
@@ -56,7 +56,7 @@ fn it_doesnt_warn_on_config_with_no_ignore() {
 #[test]
 fn a_template_can_specify_to_be_generated_into_cwd() -> anyhow::Result<()> {
     let template = tempdir()
-        .default_manifest()
+        .with_default_manifest()
         .file(
             "cargo-generate.toml",
             indoc! {r#"
@@ -87,7 +87,7 @@ fn a_template_can_specify_to_be_generated_into_cwd() -> anyhow::Result<()> {
 fn vsc_none_can_be_specified_in_the_template() {
     // Build and commit on branch named 'main'
     let template = tempdir()
-        .default_manifest()
+        .with_default_manifest()
         .file(
             "cargo-generate.toml",
             indoc! {r#"
diff --git a/tests/integration/template_config_file/placeholders.rs b/tests/integration/template_config_file/placeholders.rs
index 61e2f12..31186cb 100644
--- a/tests/integration/template_config_file/placeholders.rs
+++ b/tests/integration/template_config_file/placeholders.rs
@@ -3,7 +3,7 @@ use crate::helpers::prelude::*;
 #[test]
 fn it_prompts_for_placeholders_in_the_config_file_defined_order() {
     let template = tempdir()
-        .default_manifest()
+        .with_default_manifest()
         .file(
             "cargo-generate.toml",
             indoc! {r#"