workspacer_docs/
generate_docs.rs1crate::ix!();
3
4#[async_trait]
5pub trait GenerateDocs {
6 type Error;
7 async fn generate_docs(&self) -> Result<(), Self::Error>;
8}
9
10#[async_trait]
11impl<P,H:CrateHandleInterface<P>> GenerateDocs for Workspace<P,H>
12where for<'async_trait> P: From<PathBuf> + AsRef<Path> + Send + Sync + 'async_trait
13{
14 type Error = WorkspaceError;
15
16 async fn generate_docs(&self) -> Result<(), WorkspaceError> {
18 let workspace_path = self.as_ref(); let output = Command::new("cargo")
22 .arg("doc")
23 .current_dir(workspace_path)
24 .output()
25 .await
26 .map_err(|e| CargoDocError::CommandError { io: e.into() })?; if !output.status.success() {
29 return Err(WorkspaceError::from(CargoDocError::UnknownError {
31 stderr: Some(String::from_utf8_lossy(&output.stderr).to_string()),
32 stdout: Some(String::from_utf8_lossy(&output.stdout).to_string()),
33 }));
34 }
35
36 Ok(()) }
38}
39
40#[cfg(test)]
41mod test_generate_docs_real {
42 use super::*;
43 use std::path::PathBuf;
44 use tempfile::tempdir;
45 use workspacer_3p::tokio::process::Command;
46 use workspacer_3p::tokio;
47 #[derive(Debug)]
52 struct MockWorkspace {
53 root: PathBuf,
54 }
55 impl AsRef<std::path::Path> for MockWorkspace {
56 fn as_ref(&self) -> &std::path::Path {
57 &self.root
58 }
59 }
60
61 #[async_trait]
64 impl GenerateDocs for MockWorkspace {
65 type Error = WorkspaceError; async fn generate_docs(&self) -> Result<(), Self::Error> {
68 let workspace_path = self.as_ref();
69 let output = Command::new("cargo")
70 .arg("doc")
71 .current_dir(workspace_path)
72 .output()
73 .await
74 .map_err(|e| CargoDocError::CommandError { io: e.into() })?;
75
76 if !output.status.success() {
77 return Err(WorkspaceError::from(CargoDocError::UnknownError {
78 stderr: Some(String::from_utf8_lossy(&output.stderr).to_string()),
79 stdout: Some(String::from_utf8_lossy(&output.stdout).to_string()),
80 }));
81 }
82
83 Ok(())
84 }
85 }
86
87 #[tokio::test]
91 async fn test_generate_docs_success() {
92 let tmp_dir = tempdir().expect("Failed to create temp dir");
93 let path = tmp_dir.path();
94
95 let init_status = Command::new("cargo")
98 .arg("init")
99 .arg("--name")
100 .arg("test_docs_proj")
101 .arg("--vcs")
102 .arg("none")
103 .current_dir(path)
104 .output()
105 .await
106 .expect("Failed to run cargo init");
107 assert!(init_status.status.success(), "cargo init must succeed for test");
108
109 let ws = MockWorkspace { root: path.to_path_buf() };
111
112 let result = ws.generate_docs().await;
114 assert!(result.is_ok(), "cargo doc should succeed on a minimal project");
119 }
120
121 #[tokio::test]
124 async fn test_generate_docs_failure() {
125 let tmp_dir = tempdir().expect("tempdir failed");
126 let path = tmp_dir.path();
127
128 let init_status = Command::new("cargo")
130 .arg("init")
131 .arg("--name")
132 .arg("broken_docs")
133 .arg("--vcs")
134 .arg("none")
135 .current_dir(path)
136 .output()
137 .await
138 .expect("cargo init");
139 assert!(init_status.status.success());
140
141 let src_lib = path.join("src").join("lib.rs");
143 tokio::fs::write(&src_lib, b"broken code ???").await.expect("write broken code");
144
145 let ws = MockWorkspace { root: path.to_path_buf() };
146 let result = ws.generate_docs().await;
147 match result {
148 Err(WorkspaceError::CargoDocError(CargoDocError::UnknownError { stderr, stdout })) => {
149 assert!(stderr.as_ref().unwrap_or(&String::new()).contains("error"), "stderr should mention an error");
151 }
152 Ok(_) => {
153 panic!("Expected doc build to fail, but got Ok(())");
154 }
155 other => panic!("Expected UnknownError, got {:?}", other),
156 }
157 }
158
159 #[tokio::test]
161 async fn test_generate_docs_cannot_spawn_command() {
162 let ws = MockWorkspace { root: PathBuf::from("/non/existent/path") };
166
167 let result = ws.generate_docs().await;
171 match result {
172 Err(WorkspaceError::CargoDocError(CargoDocError::CommandError{..})) => {
173 }
175 other => {
176 println!("Got something else: {:?}", other);
177 }
178 }
179 }
180}