cargo_detect_package/
types.rs1use std::path::PathBuf;
6use std::str::FromStr;
7use std::{error, fmt, io};
8
9#[derive(Clone, Debug, Eq, PartialEq)]
11#[non_exhaustive]
12pub enum OutsidePackageAction {
13 Workspace,
15 Ignore,
17 Error,
19}
20
21#[cfg_attr(test, mutants::skip)]
23impl FromStr for OutsidePackageAction {
24 type Err = String;
25
26 fn from_str(s: &str) -> Result<Self, Self::Err> {
27 match s.to_lowercase().as_str() {
28 "workspace" => Ok(Self::Workspace),
29 "ignore" => Ok(Self::Ignore),
30 "error" => Ok(Self::Error),
31 _ => Err(format!(
32 "Invalid outside-package action: '{s}'. Valid options are: workspace, ignore, error"
33 )),
34 }
35 }
36}
37
38#[doc(hidden)]
42#[derive(Debug)]
43#[expect(
44 clippy::exhaustive_structs,
45 reason = "This is a hidden struct for internal/test use only"
46)]
47pub struct RunInput {
48 pub path: PathBuf,
50 pub via_env: Option<String>,
52 pub outside_package: OutsidePackageAction,
54 pub subcommand: Vec<String>,
56}
57
58#[doc(hidden)]
60#[derive(Clone, Debug, Eq, PartialEq)]
61#[expect(
62 clippy::exhaustive_enums,
63 reason = "This is a hidden enum for internal/test use only"
64)]
65pub enum RunOutcome {
66 PackageDetected {
68 package_name: String,
69 subcommand_succeeded: bool,
70 },
71 WorkspaceScope { subcommand_succeeded: bool },
73 Ignored,
75}
76
77#[doc(hidden)]
79#[derive(Debug)]
80#[expect(
81 clippy::exhaustive_enums,
82 reason = "This is a hidden enum for internal/test use only"
83)]
84pub enum RunError {
85 WorkspaceValidation(String),
87 PackageDetection(String),
89 OutsidePackage,
91 CommandExecution(io::Error),
93}
94
95impl fmt::Display for RunError {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 match self {
98 Self::WorkspaceValidation(msg) => write!(f, "{msg}"),
99 Self::PackageDetection(msg) => write!(f, "Error detecting package: {msg}"),
100 Self::OutsidePackage => write!(f, "Path is not in any package"),
101 Self::CommandExecution(e) => write!(f, "Error executing command: {e}"),
102 }
103 }
104}
105
106impl error::Error for RunError {}
107
108#[cfg(test)]
109#[cfg_attr(coverage_nightly, coverage(off))]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn outside_package_action_parsing() {
115 assert_eq!(
116 "workspace".parse::<OutsidePackageAction>().unwrap(),
117 OutsidePackageAction::Workspace
118 );
119 assert_eq!(
120 "Workspace".parse::<OutsidePackageAction>().unwrap(),
121 OutsidePackageAction::Workspace
122 );
123 assert_eq!(
124 "WORKSPACE".parse::<OutsidePackageAction>().unwrap(),
125 OutsidePackageAction::Workspace
126 );
127
128 assert_eq!(
129 "ignore".parse::<OutsidePackageAction>().unwrap(),
130 OutsidePackageAction::Ignore
131 );
132 assert_eq!(
133 "Ignore".parse::<OutsidePackageAction>().unwrap(),
134 OutsidePackageAction::Ignore
135 );
136
137 assert_eq!(
138 "error".parse::<OutsidePackageAction>().unwrap(),
139 OutsidePackageAction::Error
140 );
141 assert_eq!(
142 "Error".parse::<OutsidePackageAction>().unwrap(),
143 OutsidePackageAction::Error
144 );
145
146 let result = "invalid".parse::<OutsidePackageAction>();
147 result.unwrap_err();
148 }
149
150 #[test]
151 fn run_error_display_workspace_validation() {
152 let error = RunError::WorkspaceValidation("some validation error".to_string());
153 let display = format!("{error}");
154 assert!(!display.is_empty());
155 }
156
157 #[test]
158 fn run_error_display_package_detection() {
159 let error = RunError::PackageDetection("could not find package".to_string());
160 let display = format!("{error}");
161 assert!(!display.is_empty());
162 }
163
164 #[test]
165 fn run_error_display_outside_package() {
166 let error = RunError::OutsidePackage;
167 let display = format!("{error}");
168 assert!(!display.is_empty());
169 }
170
171 #[test]
172 fn run_error_display_command_execution() {
173 let io_error = io::Error::new(io::ErrorKind::NotFound, "command not found");
174 let error = RunError::CommandExecution(io_error);
175 let display = format!("{error}");
176 assert!(!display.is_empty());
177 }
178}