Repository: taiki-e/cargo-llvm-cov
Pull request #37 (2021-06-18 15:51:44)

Automate update of help message in readme


Patch:
diff --git a/README.md b/README.md
index d1539ea..6be6ffe 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,7 @@ You can download prebuilt binaries from the [Release page](https://github.com/ta
 <details>
 <summary>Click to show a complete list of options</summary>
 
+<!-- readme-long-help:start -->
 ```console
 $ cargo llvm-cov --help
 cargo-llvm-cov
@@ -152,7 +153,9 @@ OPTIONS:
 ARGS:
     <args>...
             Arguments for the test binary
+
 ```
+<!-- readme-long-help:end -->
 
 </details>
 
diff --git a/src/cli.rs b/src/cli.rs
index 3b8fdb8..bbb5b23 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -17,8 +17,12 @@ pub(crate) enum Opts {
     LlvmCov(Args),
 }
 
+/// A wrapper for source based code coverage (-Zinstrument-coverage).
+///
+/// Use -h for short descriptions and --help for more details.
 #[derive(Debug, StructOpt)]
 #[structopt(
+    bin_name = "cargo llvm-cov",
     rename_all = "kebab-case",
     setting = AppSettings::DeriveDisplayOrder,
     setting = AppSettings::UnifiedHelpMessage,
@@ -216,3 +220,102 @@ impl FromStr for Coloring {
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use std::{env, path::Path, process::Command};
+
+    use anyhow::Result;
+    use structopt::StructOpt;
+    use tempfile::Builder;
+
+    use super::Args;
+    use crate::fs;
+
+    fn get_long_help() -> Result<String> {
+        let mut app = Args::clap();
+        let mut buf = vec![];
+        app.write_long_help(&mut buf)?;
+        let mut out = String::new();
+        for mut line in String::from_utf8(buf)?.lines() {
+            if let Some(new) = line.trim_end().strip_suffix(env!("CARGO_PKG_VERSION")) {
+                line = new;
+            }
+            out.push_str(line.trim_end());
+            out.push('\n');
+        }
+        Ok(out)
+    }
+
+    #[track_caller]
+    fn assert_diff(expected_path: impl AsRef<Path>, actual: impl AsRef<str>) {
+        let actual = actual.as_ref();
+        let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
+        let expected_path = &manifest_dir.join(expected_path);
+        if !expected_path.is_file() {
+            fs::write(expected_path, "").unwrap();
+        }
+        let expected = fs::read_to_string(expected_path).unwrap();
+        if expected != actual {
+            if env::var_os("CI").is_some() {
+                let outdir = Builder::new().prefix("assert_diff").tempdir().unwrap();
+                let actual_path = &outdir.path().join(expected_path.file_name().unwrap());
+                fs::write(actual_path, actual).unwrap();
+                let status = Command::new("git")
+                    .args(&["--no-pager", "diff", "--no-index", "--"])
+                    .args(&[expected_path, actual_path])
+                    .status()
+                    .unwrap();
+                assert!(!status.success());
+                panic!("assertion failed");
+            } else {
+                fs::write(expected_path, actual).unwrap();
+            }
+        }
+    }
+
+    #[test]
+    fn long_help() {
+        let actual = get_long_help().unwrap();
+        assert_diff("tests/long-help.txt", actual);
+    }
+
+    #[test]
+    fn update_readme() -> Result<()> {
+        let new = get_long_help()?;
+        let path = &Path::new(env!("CARGO_MANIFEST_DIR")).join("README.md");
+        let base = fs::read_to_string(path)?;
+        let mut out = String::with_capacity(base.capacity());
+        let mut lines = base.lines();
+        let mut start = false;
+        let mut end = false;
+        while let Some(line) = lines.next() {
+            out.push_str(line);
+            out.push('\n');
+            if line == "<!-- readme-long-help:start -->" {
+                start = true;
+                out.push_str("```console\n");
+                out.push_str("$ cargo llvm-cov --help\n");
+                out.push_str(&new);
+                out.push('\n');
+                for line in &mut lines {
+                    if line == "<!-- readme-long-help:end -->" {
+                        out.push_str("```\n");
+                        out.push_str(line);
+                        out.push('\n');
+                        end = true;
+                        break;
+                    }
+                }
+            }
+        }
+        if start && end {
+            fs::write(path, out)?;
+        } else if start {
+            panic!("missing `<!-- readme-long-help:end -->` comment in README.md");
+        } else {
+            panic!("missing `<!-- readme-long-help:start -->` comment in README.md");
+        }
+        Ok(())
+    }
+}


Test patch:
diff --git a/tests/long-help.txt b/tests/long-help.txt
new file mode 100644
index 0000000..0071014
--- /dev/null
+++ b/tests/long-help.txt
@@ -0,0 +1,110 @@
+cargo-llvm-cov
+A wrapper for source based code coverage (-Zinstrument-coverage).
+
+Use -h for short descriptions and --help for more details.
+
+USAGE:
+    cargo llvm-cov [OPTIONS] [-- <args>...]
+
+OPTIONS:
+        --json
+            Export coverage data in "json" format
+
+            If --output-path is not specified, the report will be printed to stdout.
+
+            This internally calls `llvm-cov export -format=text`. See <https://llvm.org/docs/CommandGuide/llvm-
+            cov.html#llvm-cov-export> for more.
+        --lcov
+            Export coverage data in "lcov" format.
+
+            If --output-path is not specified, the report will be printed to stdout.
+
+            This internally calls `llvm-cov export -format=lcov`. See <https://llvm.org/docs/CommandGuide/llvm-
+            cov.html#llvm-cov-export> for more.
+        --text
+            Generate coverage reports in “text” format.
+
+            If --output-path or --output-dir is not specified, the report will be printed to stdout.
+
+            This internally calls `llvm-cov show -format=text`. See <https://llvm.org/docs/CommandGuide/llvm-
+            cov.html#llvm-cov-show> for more.
+        --html
+            Generate coverage reports in "html" format. If --output-dir is not specified, the report will be generated
+            in `target/llvm-cov` directory.
+
+            This internally calls `llvm-cov show -format=html`. See <https://llvm.org/docs/CommandGuide/llvm-
+            cov.html#llvm-cov-show> for more.
+        --open
+            Generate coverage reports in "html" format and open them in a browser after the operation.
+
+            See --html for more.
+        --summary-only
+            Export only summary information for each file in the coverage data.
+
+            This flag can only be used together with either --json or --lcov.
+        --output-path <PATH>
+            Specify a file to write coverage data into.
+
+            This flag can only be used together with --json, --lcov, or --text. See --output-dir for --html and --open.
+        --output-dir <DIRECTORY>
+            Specify a directory to write coverage reports into (default to `target/llvm-cov`).
+
+            This flag can only be used together with --text, --html, or --open. See also --output-path.
+        --ignore-filename-regex <PATTERN>
+            Skip source code files with file paths that match the given regular expression
+
+        --doctests
+            Including doc tests (unstable)
+
+        --no-fail-fast
+            Run all tests regardless of failure
+
+        --workspace
+            Test all packages in the workspace [aliases: all]
+
+        --exclude <SPEC>...
+            Exclude packages from the test
+
+        --release
+            Build artifacts in release mode, with optimizations
+
+        --features <FEATURES>...
+            Space or comma separated list of features to activate
+
+        --all-features
+            Activate all available features
+
+        --no-default-features
+            Do not activate the `default` feature
+
+        --target <TRIPLE>
+            Build for the target triple
+
+        --manifest-path <PATH>
+            Path to Cargo.toml
+
+    -v, --verbose
+            Use verbose output (-vv very verbose/build.rs output)
+
+        --color <WHEN>
+            Coloring: auto, always, never
+
+        --frozen
+            Require Cargo.lock and cache are up to date
+
+        --locked
+            Require Cargo.lock is up to date
+
+    -Z <FLAG>...
+            Unstable (nightly-only) flags to Cargo
+
+    -h, --help
+            Prints help information
+
+    -V, --version
+            Prints version information
+
+
+ARGS:
+    <args>...
+            Arguments for the test binary