diff --git a/CHANGELOG.md b/CHANGELOG.md index 7047dd1..4555d9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,16 @@ # Changelog -# v3.1.0 +## v3.1.0 - Replace structopts with clap [#10](https://github.com/KevinGimbel/mktoc/issues/10) by [@oylenshpeegul](https://github.com/oylenshpeegul) - wrap ToC in details block [#8](https://github.com/KevinGimbel/mktoc/issues/8) by [@KevinGimbel](https://github.com/KevinGimbel) - Links in Headlines produce wrong output [#12](https://github.com/KevinGimbel/mktoc/issues/12) by [@KevinGimbel](https://github.com/KevinGimbel) -# v3.0.0 +### Misc + +- add more tests + +## v3.0.0 - Implement JSON settings - Add build for GitHub Binary releases \ No newline at end of file diff --git a/helpers/coverage.sh b/helpers/coverage.sh index 0c01356..74ce10a 100755 --- a/helpers/coverage.sh +++ b/helpers/coverage.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -export LLVM_PROFILE_FILE="fd-%p-%m.profraw" +export LLVM_PROFILE_FILE="mktoc-%p-%m.profraw" export RUSTFLAGS="-Cinstrument-coverage" # build project diff --git a/src/lib.rs b/src/lib.rs index 5286100..ee8aa64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,23 @@ impl Default for Config { } } +impl PartialEq for Config { + fn eq(&self, other: &Self) -> bool { + return self.max_depth == other.max_depth + && self.min_depth == other.min_depth + && self.wrap_in_details == other.wrap_in_details + && self.start_comment == other.start_comment; + + } + + fn ne(&self, other: &Self) -> bool { + return self.max_depth != other.max_depth + || self.min_depth != other.min_depth + || self.wrap_in_details != other.wrap_in_details + || self.start_comment != other.start_comment; + } +} + fn default_min_depth() -> i32 { 1 } @@ -84,8 +101,7 @@ pub fn generate_toc(original_content: String, config: Config) -> String { let mut new_toc = String::from(""); let re = regex::Regex::new(r"((#{1,6}\s))((.*))").unwrap(); for line in original_content.lines() { - let line_s: String = line.chars().take(3).collect(); - if line_s == *"```" { + if line.starts_with("```") { code_block_found = true; } @@ -147,8 +163,8 @@ pub fn generate_toc(original_content: String, config: Config) -> String { } fn cleanup_wrapped_toc(input: String) -> String { - // starting with an indention of 4 GitHub will render code. So we strip away all lines - // staring with 4 spaces. + // 4 spaces will render a code block if wrapped inside a HTML element. + // So we strip away all lines staring with 4 spaces. let re = Regex::new(r"(?m)^ {4}").unwrap(); let new_content = re.replace_all(&input, "").to_string(); @@ -225,6 +241,257 @@ pub fn make_toc
(
#[cfg(test)]
mod tests {
use super::*;
+ #[test]
+ fn test_read_file() {
+ struct TestCase<'a> {
+ name: &'a str,
+ input: &'a str,
+ expect_error: bool,
+ }
+
+ let tests = [
+ TestCase{
+ name: "File exists and can be read",
+ input: "tests/files/README_01.md",
+ expect_error: false
+ },
+ TestCase{
+ name: "File does not exist",
+ input: "tests/files/doesnt-exists.md",
+ expect_error: true
+ },
+ TestCase{
+ name: "Directory does not exist",
+ input: "anywhere/but/here/README.md",
+ expect_error: true
+ }
+ ];
+
+ for test in tests {
+ dbg!(test.name);
+ match read_file(test.input) {
+ Ok(_content) => {
+ assert_eq!(false, test.expect_error)
+ }
+ Err(_err) => {
+ assert_eq!(true, test.expect_error)
+ }
+ }
+ }
+ }
+
+ #[test]
+ fn test_generate_toc() {
+ struct TestCase<'a> {
+ name: &'a str,
+ input: &'a str,
+ expected: &'a str,
+ }
+
+ let tests = [
+ TestCase{
+ name: "Can parse simple input to ToC",
+ input: r#"
+# Test
+
+
+## Hello
+### World"#,
+ expected: r#"
+
+- [Test](#test)
+- [Hello](#hello)
+ - [World](#world)
+"#
+ },
+ TestCase{
+ name: "Can find all heading levels",
+ input: r#"
+# Test 1
+
+
+## Test 2
+### Test 3
+#### Test 4
+##### Test 5
+###### Test 6"#,
+ expected: r#"
+
+- [Test 1](#test-1)
+- [Test 2](#test-2)
+ - [Test 3](#test-3)
+ - [Test 4](#test-4)
+ - [Test 5](#test-5)
+ - [Test 6](#test-6)
+"#
+ },
+ TestCase{
+ name: "Can parse with code in headings",
+ input: r#"
+# Test
+
+
+## `Hello`
+### World"#,
+ expected: r#"
+
+- [Test](#test)
+- [`Hello`](#hello)
+ - [World](#world)
+"#
+ },
+ TestCase{
+ name: "Can parse headings with emojis",
+ input: r#"
+# Test
+
+
+## Hello 🥳
+### World"#,
+ expected: r#"
+
+- [Test](#test)
+- [Hello 🥳](#hello-🥳)
+ - [World](#world)
+"#
+ },
+ TestCase{
+ name: "Can exclude code blocks",
+ input: r#"
+# Test
+
+
+## Hello
+
+Lorem Ipsum Dolor...
+
+```
+# inline comment
+fn some_func() -> bool {}
+```
+"#,
+ expected: r#"
+
+- [Test](#test)
+- [Hello](#hello)
+"#
+ }
+ ];
+
+ // (original_content: String, config: Config)
+
+ for test in tests {
+ dbg!(test.name);
+ let new_toc = generate_toc(test.input.to_string(), Config::default());
+ assert_eq!(new_toc, test.expected.to_string());
+ }
+ }
+
+ #[test]
+ fn test_generate_toc_wrap_details() {
+ struct TestCase<'a> {
+ name: &'a str,
+ input: &'a str,
+ expected: &'a str,
+ }
+
+ let tests = [
+ TestCase{
+ name: "Can wrap ToC in details",
+ input: r#"
+# Test
+
+
+## Hello
+### World"#,
+ expected: r#"
+Table of Contents
+
+- [Test](#test)
+- [Hello](#hello)
+ - [World](#world)
+
+