Skip to main content

omni_dev/cli/
coverage.rs

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