1use std::path::PathBuf;
2
3use super::{Runner, RunnerError, UnloadError};
4use crate::logger::LoggerOutput;
5use crate::trace::PkgTrace;
6
7impl<O: LoggerOutput> Runner<O> {
8 pub fn unload_module(&mut self, name: &str, trace: &PkgTrace) -> Result<(), RunnerError> {
9 self.logger.unload_module(name);
10 self.unload_module_inner(trace)
11 .map_err(|e| RunnerError::UnloadModuleError {
12 source: e,
13 module: name.to_string(),
14 })
15 }
16
17 fn unload_module_inner(&mut self, trace: &PkgTrace) -> Result<(), UnloadError> {
18 let pkg_dir = self.cwd.join(&trace.directory);
19
20 for (src, dst) in &trace.maps {
21 let dst_path = PathBuf::from(dst);
22 if !dst_path.exists() {
23 return Err(UnloadError::DstNotFound {
24 src: src.clone(),
25 dst: dst_path,
26 });
27 }
28 if !dst_path.is_symlink() {
29 return Err(UnloadError::DstNotSymlink {
30 src: src.clone(),
31 dst: dst_path,
32 });
33 }
34
35 let src_path = pkg_dir.join(src);
36 self.remove_symlink(src_path, dst_path)?;
37 }
38
39 Ok(())
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use std::fs;
46
47 use super::*;
48 use crate::test_utils::prelude::*;
49
50 fn setup() -> Result<(TempDir, PkgTrace, Runner<NullOutput>)> {
51 let (td, pkg, mut runner) = common_local_pkg()?;
52 let trace = runner.load_module(&pkg, None)?;
53 let runner = common_runner(td.path());
54 Ok((td, trace, runner))
55 }
56
57 #[gtest]
58 fn it_works() -> Result<()> {
59 let (td, trace, mut runner) = setup()?;
60 runner.unload_module("test_package", &trace)?;
61
62 expect_pred!(!td.join(DST_FILE_PATH).exists());
63 expect_pred!(!td.join(DST_DIR_PATH).exists());
64
65 let messages = runner.messages();
66 expect_eq!(messages.len(), 3);
67 expect_that!(messages[0], pat!(LogMessage::UnloadModule("test_package")));
68 expect_that!(
69 messages,
70 contains(pat!(LogMessage::RemoveSymlink {
71 src: &td.join(SRC_DIR_PATH),
72 dst: &td.join(DST_DIR_PATH),
73 }))
74 );
75 expect_that!(
76 messages,
77 contains(pat!(LogMessage::RemoveSymlink {
78 src: &td.join(SRC_FILE_PATH),
79 dst: &td.join(DST_FILE_PATH),
80 }))
81 );
82
83 Ok(())
84 }
85
86 #[gtest]
87 fn dst_not_exists() -> Result<()> {
88 let (td, trace, mut runner) = setup()?;
89 fs::remove_file(td.join(DST_FILE_PATH))?;
90
91 let err = runner
92 .unload_module("test_package", &trace)
93 .unwrap_err()
94 .unwrap_unload();
95 expect_that!(
96 err,
97 pat!(UnloadError::DstNotFound {
98 src: "src_file",
99 dst: &td.join(DST_FILE_PATH)
100 })
101 );
102
103 Ok(())
104 }
105
106 #[gtest]
107 fn dst_is_not_symlink() -> Result<()> {
108 let (td, trace, mut runner) = setup()?;
109 fs::remove_file(td.join(DST_FILE_PATH))?;
110 fs::write(td.join(DST_FILE_PATH), "not_a_symlink")?;
111
112 let err = runner
113 .unload_module("test_package", &trace)
114 .unwrap_err()
115 .unwrap_unload();
116 expect_that!(
117 err,
118 pat!(UnloadError::DstNotSymlink {
119 src: "src_file",
120 dst: &td.join(DST_FILE_PATH)
121 })
122 );
123
124 Ok(())
125 }
126}