summaryrefslogtreecommitdiff
path: root/src/generator/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/generator/mod.rs')
-rw-r--r--src/generator/mod.rs268
1 files changed, 167 insertions, 101 deletions
diff --git a/src/generator/mod.rs b/src/generator/mod.rs
index 07bdf1f..81e2420 100644
--- a/src/generator/mod.rs
+++ b/src/generator/mod.rs
@@ -10,7 +10,6 @@ use crate::{
const DEFAULT_PROJECT_NAME: &str = "Project Outline";
pub struct MarkdownGenerator<'a> {
- logger: Logger,
origin_base: &'a Path,
paths: &'a [&'a Path],
project_title: Option<&'a str>,
@@ -21,7 +20,6 @@ pub struct MarkdownGenerator<'a> {
impl<'a> MarkdownGenerator<'a> {
pub fn new(paths: &'a [&'a Path]) -> Self {
MarkdownGenerator {
- logger: Logger::default(),
origin_base: Path::new("."),
paths,
project_title: None,
@@ -45,11 +43,6 @@ impl<'a> MarkdownGenerator<'a> {
self
}
- pub fn with_logger(mut self, logger: Logger) -> Self {
- self.logger = logger;
- self
- }
-
pub fn with_render_options(mut self, render_options: RenderOptions) -> Self {
self.render_options = render_options;
self
@@ -67,16 +60,21 @@ impl<'a> MarkdownGenerator<'a> {
}
}
- pub fn generate<W: Write>(self, output: W) -> Result<(), Box<dyn std::error::Error>> {
- MarkdownGeneration::new(self, output)?.run()
+ pub fn generate<W: Write, LW: Write>(
+ self,
+ output: W,
+ logger: &Logger<LW>,
+ ) -> Result<(), Box<dyn std::error::Error>> {
+ MarkdownGeneration::new(self, output, logger)?.run()
}
- pub fn generate_fenced<W: Write>(
+ pub fn generate_fenced<W: Write, LW: Write>(
self,
mut output: W,
+ logger: &Logger<LW>,
) -> Result<(), Box<dyn std::error::Error>> {
let mut md_output = Vec::new();
- self.generate(&mut md_output)?;
+ self.generate(&mut md_output, logger)?;
let fence = generate_outer_backticks(&md_output);
writeln!(output, "{}markdown", fence)?;
@@ -92,40 +90,32 @@ mod tests {
use tempfile::tempdir;
- use crate::{logger::Logger, renderer::RenderOptions};
+ use crate::{
+ logger::Verbosity,
+ renderer::RenderOptions,
+ util::test_support::{logger_with_shared_log, quiet_logger},
+ };
use super::MarkdownGenerator;
fn generate_to_string(
- paths: &[&Path],
- root: &Path,
- origin: &Path,
- project_title: Option<&str>,
+ generator: MarkdownGenerator,
) -> Result<String, Box<dyn std::error::Error>> {
let mut output = Vec::new();
+ let logger = quiet_logger();
- MarkdownGenerator::new(paths)
- .with_root(root)
- .with_origin(origin)
- .with_project_title(project_title)
- .generate(&mut output)?;
+ generator.generate(&mut output, &logger)?;
Ok(String::from_utf8(output).unwrap())
}
fn generate_fenced_to_string(
- paths: &[&Path],
- root: &Path,
- origin: &Path,
- project_title: Option<&str>,
+ generator: MarkdownGenerator,
) -> Result<String, Box<dyn std::error::Error>> {
let mut output = Vec::new();
+ let logger = quiet_logger();
- MarkdownGenerator::new(paths)
- .with_root(root)
- .with_origin(origin)
- .with_project_title(project_title)
- .generate_fenced(&mut output)?;
+ generator.generate_fenced(&mut output, &logger)?;
Ok(String::from_utf8(output).unwrap())
}
@@ -135,13 +125,11 @@ mod tests {
let temp_dir = tempdir().unwrap();
let paths = [];
- let output = generate_to_string(
- &paths,
- temp_dir.path(),
- temp_dir.path(),
- Some("Project name"),
- )
- .unwrap();
+ let generator = MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"));
+ let output = generate_to_string(generator).unwrap();
assert_eq!(output, "# Project name\n");
}
@@ -152,7 +140,11 @@ mod tests {
let paths = [];
let root = temp_dir.path().join("repo2markdown");
- let output = generate_to_string(&paths, &root, temp_dir.path(), None).unwrap();
+ let generator = MarkdownGenerator::new(&paths)
+ .with_root(&root)
+ .with_origin(temp_dir.path())
+ .with_project_title(None);
+ let output = generate_to_string(generator).unwrap();
assert_eq!(output, "# repo2markdown\n");
}
@@ -164,13 +156,11 @@ mod tests {
let paths = [Path::new("main.rs")];
- let output = generate_to_string(
- &paths,
- temp_dir.path(),
- temp_dir.path(),
- Some("Project name"),
- )
- .unwrap();
+ let generator = MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"));
+ let output = generate_to_string(generator).unwrap();
assert!(output.contains("# Project name\n"));
assert!(output.contains("## File: main.rs"));
@@ -186,13 +176,11 @@ mod tests {
let paths = [Path::new("a.rs"), Path::new("b.rs")];
- let output = generate_to_string(
- &paths,
- temp_dir.path(),
- temp_dir.path(),
- Some("Project name"),
- )
- .unwrap();
+ let generator = MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"));
+ let output = generate_to_string(generator).unwrap();
let a_pos = output.find("## File: a.rs").unwrap();
let b_pos = output.find("## File: b.rs").unwrap();
@@ -212,8 +200,11 @@ mod tests {
let paths = [Path::new("main.rs")];
- let output =
- generate_to_string(&paths, temp_dir.path(), &origin, Some("Project name")).unwrap();
+ let generator = MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(&origin)
+ .with_project_title(Some("Project name"));
+ let output = generate_to_string(generator).unwrap();
assert!(output.contains("## File: src/main.rs"));
assert!(output.contains("fn main() {}"));
@@ -230,7 +221,11 @@ mod tests {
let paths = [Path::new("main.rs")];
- let output = generate_to_string(&paths, &root, &origin, Some("Project name")).unwrap();
+ let generator = MarkdownGenerator::new(&paths)
+ .with_root(&root)
+ .with_origin(&origin)
+ .with_project_title(Some("Project name"));
+ let output = generate_to_string(generator).unwrap();
assert!(output.contains("## File: src/main.rs"));
assert!(output.contains("fn main() {}"));
@@ -244,13 +239,11 @@ mod tests {
let paths = [Path::new("a.rs"), Path::new("a.rs")];
- let output = generate_to_string(
- &paths,
- temp_dir.path(),
- temp_dir.path(),
- Some("Project name"),
- )
- .unwrap();
+ let generator = MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"));
+ let output = generate_to_string(generator).unwrap();
assert_eq!(output.matches("## File: a.rs").count(), 1);
}
@@ -264,13 +257,11 @@ mod tests {
let paths = [Path::new("a.rs"), Path::new("src/../a.rs")];
- let output = generate_to_string(
- &paths,
- temp_dir.path(),
- temp_dir.path(),
- Some("Project name"),
- )
- .unwrap();
+ let generator = MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"));
+ let output = generate_to_string(generator).unwrap();
assert_eq!(output.matches("## File: a.rs").count(), 1);
}
@@ -278,29 +269,21 @@ mod tests {
#[test]
fn uses_render_options_for_large_file_placeholders() {
let temp_dir = tempdir().unwrap();
-
fs::write(temp_dir.path().join("big.txt"), "A".repeat(10)).unwrap();
-
let paths = [Path::new("big.txt")];
- let mut output = Vec::new();
-
let render_options = RenderOptions {
max_file_size: 5,
placeholder_for_binary_files: false,
placeholder_for_large_files: true,
};
- MarkdownGenerator::new(&paths)
+ let generator = MarkdownGenerator::new(&paths)
.with_root(temp_dir.path())
.with_origin(temp_dir.path())
.with_project_title(Some("Project name"))
- .with_render_options(render_options)
- .with_logger(Logger::default())
- .generate(&mut output)
- .unwrap();
-
- let output = String::from_utf8(output).unwrap();
+ .with_render_options(render_options);
+ let output = generate_to_string(generator).unwrap();
assert!(output.contains("## File: big.txt"));
assert!(output.contains("[FILE TOO LARGE]"));
@@ -311,13 +294,11 @@ mod tests {
let temp_dir = tempdir().unwrap();
let paths: [&Path; 0] = [];
- let output = generate_fenced_to_string(
- &paths,
- temp_dir.path(),
- temp_dir.path(),
- Some("Project name"),
- )
- .unwrap();
+ let generator = MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"));
+ let output = generate_fenced_to_string(generator).unwrap();
assert_eq!(output, "```markdown\n# Project name\n```\n");
}
@@ -330,13 +311,11 @@ mod tests {
let paths = [Path::new("main.rs")];
- let output = generate_fenced_to_string(
- &paths,
- temp_dir.path(),
- temp_dir.path(),
- Some("Project name"),
- )
- .unwrap();
+ let generator = MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"));
+ let output = generate_fenced_to_string(generator).unwrap();
assert!(output.starts_with("````markdown\n"));
assert!(output.ends_with("\n````\n"));
@@ -353,16 +332,103 @@ mod tests {
let paths = [Path::new("backticks.rs")];
- let output = generate_fenced_to_string(
- &paths,
- temp_dir.path(),
- temp_dir.path(),
- Some("Project name"),
- )
- .unwrap();
+ let generator = MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"));
+ let output = generate_fenced_to_string(generator).unwrap();
assert!(output.starts_with("``````markdown\n"));
assert!(output.ends_with("\n``````\n"));
assert!(output.contains("`````rust\n````\n`````"));
}
+
+ #[test]
+ fn normal_verbosity_logs_duplicate_paths() {
+ let temp_dir = tempdir().unwrap();
+ fs::write(temp_dir.path().join("a.rs"), "A").unwrap();
+
+ let paths = [Path::new("a.rs"), Path::new("a.rs")];
+
+ let mut output = Vec::new();
+ let (logger, logs) = logger_with_shared_log(Verbosity::Normal);
+
+ MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"))
+ .generate(&mut output, &logger)
+ .unwrap();
+
+ assert_eq!(logs.contents(), "Warning: skipping duplicate file: a.rs\n");
+ }
+
+ #[test]
+ fn quiet_verbosity_suppresses_duplicate_path_warning() {
+ let temp_dir = tempdir().unwrap();
+ fs::write(temp_dir.path().join("a.rs"), "A").unwrap();
+
+ let paths = [Path::new("a.rs"), Path::new("a.rs")];
+
+ let mut output = Vec::new();
+ let (logger, logs) = logger_with_shared_log(Verbosity::Quiet);
+
+ MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"))
+ .generate(&mut output, &logger)
+ .unwrap();
+
+ assert_eq!(logs.contents(), "");
+ }
+
+ #[test]
+ fn normal_verbosity_logs_lexically_equivalent_duplicate_paths() {
+ let temp_dir = tempdir().unwrap();
+
+ fs::create_dir_all(temp_dir.path().join("src")).unwrap();
+ fs::write(temp_dir.path().join("a.rs"), "A").unwrap();
+
+ let paths = [Path::new("a.rs"), Path::new("src/../a.rs")];
+
+ let mut output = Vec::new();
+ let (logger, logs) = logger_with_shared_log(Verbosity::Normal);
+
+ MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"))
+ .generate(&mut output, &logger)
+ .unwrap();
+
+ assert_eq!(logs.contents(), "Warning: skipping duplicate file: a.rs\n");
+ }
+
+ #[test]
+ fn verbose_verbosity_logs_rendered_files_and_duplicates_in_order() {
+ let temp_dir = tempdir().unwrap();
+
+ fs::write(temp_dir.path().join("a.rs"), "A").unwrap();
+ fs::write(temp_dir.path().join("b.rs"), "B").unwrap();
+
+ let paths = [Path::new("a.rs"), Path::new("a.rs"), Path::new("b.rs")];
+
+ let mut output = Vec::new();
+ let (logger, logs) = logger_with_shared_log(Verbosity::Verbose);
+
+ MarkdownGenerator::new(&paths)
+ .with_root(temp_dir.path())
+ .with_origin(temp_dir.path())
+ .with_project_title(Some("Project name"))
+ .generate(&mut output, &logger)
+ .unwrap();
+
+ assert_eq!(
+ logs.contents(),
+ "Info: rendering file: a.rs\n\
+ Warning: skipping duplicate file: a.rs\n\
+ Info: rendering file: b.rs\n"
+ );
+ }
}