Skip to main content

omni_dev/cli/
coverage.rs

1//! Coverage analysis CLI commands.
2
3pub(crate) mod diff;
4
5use anyhow::Result;
6use clap::{Parser, Subcommand};
7
8/// Coverage analysis: diff/patch coverage for PR comments.
9#[derive(Parser)]
10pub struct CoverageCommand {
11    /// The coverage subcommand to execute.
12    #[command(subcommand)]
13    pub command: CoverageSubcommands,
14
15    /// `-C/--repo`, inherited by every coverage subcommand.
16    #[command(flatten)]
17    pub repo: crate::cli::repo_arg::RepoArg,
18}
19
20/// Coverage subcommands.
21#[derive(Subcommand)]
22pub enum CoverageSubcommands {
23    /// Analyses diff/patch coverage from a per-line report and a git diff.
24    Diff(diff::DiffCommand),
25}
26
27impl CoverageCommand {
28    /// Executes the coverage command.
29    ///
30    /// `-C/--repo` is resolved here (`None` = current working directory) and
31    /// threaded explicitly to the leaf.
32    pub fn execute(self) -> Result<()> {
33        let repo = self.repo.path();
34        match self.command {
35            CoverageSubcommands::Diff(cmd) => cmd.execute(repo),
36        }
37    }
38}
39
40#[cfg(test)]
41#[allow(clippy::unwrap_used, clippy::expect_used)]
42mod tests {
43    use super::*;
44
45    /// The `coverage` command dispatches to `diff`; a missing report makes the
46    /// leaf command error, which exercises the dispatch path end-to-end.
47    #[test]
48    fn dispatches_to_diff() {
49        let cmd = CoverageCommand {
50            command: CoverageSubcommands::Diff(diff::DiffCommand {
51                report: std::path::PathBuf::from("/nonexistent/report.lcov"),
52                report_format: diff::ReportFormat::Auto,
53                base_ref: Some("HEAD".to_string()),
54                head_ref: None,
55                baseline_report: None,
56                baseline_report_format: diff::ReportFormat::Auto,
57                output: diff::OutputFormatArg::Markdown,
58                format: None,
59                fail_under_patch: None,
60                strip_prefix: None,
61                ignore_filename_regex: Vec::new(),
62                context_dir: None,
63                collapse_ranges: false,
64                all_files: false,
65                artifact_url: None,
66                run_url: None,
67                base_sha: None,
68                head_sha: None,
69                commit_url: None,
70            }),
71            repo: crate::cli::repo_arg::RepoArg::default(),
72        };
73        // Reaches the leaf command and fails on the missing report file.
74        assert!(cmd.execute().is_err());
75    }
76}