workspacer_toml/
get_package_section.rs

1// ---------------- [ File: workspacer-toml/src/get_package_section.rs ]
2crate::ix!();
3
4impl GetPackageSection for CargoToml {
5
6    type Error = CargoTomlError;
7
8    /// Helper to retrieve the `package` section from `Cargo.toml`
9    fn get_package_section(&self) -> Result<&toml::Value, Self::Error> {
10        self.content().get("package").ok_or_else(|| CargoTomlError::MissingPackageSection {
11            cargo_toml_file: self.path().clone(),
12        })
13    }
14}
15
16impl GetPackageSectionMut for CargoToml {
17
18    type Error = CargoTomlError;
19
20    /// Helper to retrieve the `package` section from `Cargo.toml`
21    fn get_package_section_mut(&mut self) -> Result<&mut toml::Value, Self::Error> {
22
23        let possible_error = CargoTomlError::MissingPackageSection {
24            cargo_toml_file: self.path().clone(),
25        };
26
27        self.content_mut().get_mut("package").ok_or_else(|| possible_error)
28    }
29}
30
31#[async_trait]
32impl GatherBinTargetNames for CargoToml {
33    type Error = CargoTomlError;
34
35    async fn gather_bin_target_names(&self) -> Result<Vec<String>, Self::Error> {
36        let binding = Vec::new();
37        // 1) Look up `[bin]` array if it exists
38        let bin_array = self
39            .content()
40            .get("bin")
41            .and_then(|val| val.as_array())
42            .unwrap_or(&binding);
43
44        // 2) For each bin entry, if there's a `name` field, we produce "name.rs"
45        let mut result = Vec::new();
46        for bin_val in bin_array {
47            if let Some(tbl) = bin_val.as_table() {
48                if let Some(name_val) = tbl.get("name").and_then(|nv| nv.as_str()) {
49                    let fname = format!("{}.rs", name_val);
50                    result.push(fname);
51                }
52            }
53        }
54
55        Ok(result)
56    }
57}
58
59#[cfg(test)]
60mod test_get_package_section {
61    use super::*;
62    use std::io::Write;
63    use tempfile::NamedTempFile;
64    use tokio::fs;
65    
66    
67
68    /// Helper function to create a Cargo.toml file with given contents,
69    /// then build a `CargoToml` from it asynchronously.
70    /// Returns the created `CargoToml` or an error.
71    async fn create_cargo_toml_file(contents: &str) -> Result<CargoToml, CargoTomlError> {
72        // Create a temporary file on disk
73        let mut temp = NamedTempFile::new().expect("Failed to create temp file");
74        write!(temp, "{}", contents).expect("Failed to write to temp file");
75        let path = temp.into_temp_path();
76
77        // We'll copy these bytes into a path we control in async style
78        // so that `CargoToml::new` (which uses async fs ops) can read it.
79        let path_buf = path.to_path_buf();
80        let cargo_data = contents.as_bytes();
81
82        // In an actual test scenario, you might just do `fs::write(path_buf, contents).await`,
83        // but NamedTempFile requires a little extra dance to preserve the path.
84        fs::write(&path_buf, cargo_data)
85            .await
86            .expect("Failed to write async to temp file");
87
88        // Now create the CargoToml struct from this path
89        CargoToml::new(&path_buf).await
90    }
91
92    /// Tests a valid `[package]` section is properly retrieved.
93    #[tokio::test]
94    async fn test_get_package_section_ok() {
95        let toml_str = r#"
96            [package]
97            name = "test-crate"
98            version = "0.1.0"
99        "#;
100
101        let cargo_toml = create_cargo_toml_file(toml_str).await
102            .expect("Failed to create CargoToml");
103
104        // Now call get_package_section:
105        let package_section = cargo_toml
106            .get_package_section()
107            .expect("Expected package section to be present");
108
109        // Basic checks: we at least expect the `package` to have name & version
110        assert!(package_section.is_table(), "package section should be a table");
111        assert_eq!(
112            package_section.get("name").and_then(|v| v.as_str()),
113            Some("test-crate"),
114            "package.name not matching"
115        );
116        assert_eq!(
117            package_section.get("version").and_then(|v| v.as_str()),
118            Some("0.1.0"),
119            "package.version not matching"
120        );
121    }
122
123    /// Tests that `get_package_section` returns an error if the `[package]` key is missing.
124    #[tokio::test]
125    async fn test_get_package_section_missing() {
126        let toml_str = r#"
127            [dependencies]
128            serde = "1.0"
129        "#;
130
131        let cargo_toml = create_cargo_toml_file(toml_str).await
132            .expect("Failed to create CargoToml");
133
134        let result = cargo_toml.get_package_section();
135        match result {
136            Ok(_) => panic!("Expected an error since there's no [package] section"),
137            Err(e) => {
138                // Ensure we got the right variant
139                match e {
140                    CargoTomlError::MissingPackageSection { .. } => {
141                        // success: error variant is correct
142                    }
143                    _ => panic!("Unexpected error variant: {e:?}"),
144                }
145            }
146        }
147    }
148
149    /// Tests that `get_package_section` still returns Ok if `[package]` is present,
150    /// even if it’s not a table. (Implementation detail: it only checks existence,
151    /// not that it’s actually a table.)
152    #[tokio::test]
153    async fn test_get_package_section_weird_but_present() {
154        // This is contrived: "package" is just a string, not a table
155        let toml_str = r#"
156            package = "not-actually-a-table"
157        "#;
158
159        let cargo_toml = create_cargo_toml_file(toml_str).await
160            .expect("Failed to create CargoToml");
161
162        let package_section = cargo_toml
163            .get_package_section()
164            .expect("Should still find the 'package' key, even if not a table");
165
166        // It's a string in this weird scenario
167        assert_eq!(
168            package_section.as_str(),
169            Some("not-actually-a-table"),
170            "Expected the 'package' entry to be a string"
171        );
172    }
173
174    /// Tests that a minimal `[package]` table with no fields is still considered present.
175    #[tokio::test]
176    async fn test_get_package_section_empty_table() {
177        let toml_str = r#"
178            [package]
179        "#;
180
181        let cargo_toml = create_cargo_toml_file(toml_str).await
182            .expect("Failed to create CargoToml");
183
184        // Should be Ok, but it's an empty table
185        let package_section = cargo_toml
186            .get_package_section()
187            .expect("Expected empty [package] to exist");
188
189        assert!(package_section.is_table(), "Expected an empty table");
190        let tbl = package_section.as_table().unwrap();
191        assert!(tbl.is_empty(), "Should be an empty table");
192    }
193}