1use cuenv_release::Target;
6use std::collections::HashMap;
7
8#[derive(Debug, Clone)]
10pub struct BinaryInfo {
11 pub url: String,
13 pub sha256: String,
15}
16
17#[derive(Debug, Clone)]
19pub struct FormulaData {
20 pub class_name: String,
22 pub desc: String,
24 pub homepage: String,
26 pub license: String,
28 pub version: String,
30 pub binaries: HashMap<Target, BinaryInfo>,
32}
33
34pub struct FormulaGenerator;
36
37impl FormulaGenerator {
38 #[must_use]
40 #[allow(clippy::format_push_string, clippy::too_many_lines)]
41 pub fn generate(data: &FormulaData) -> String {
42 let mut formula = format!(
43 r#"class {} < Formula
44 desc "{}"
45 homepage "{}"
46 version "{}"
47 license "{}"
48"#,
49 data.class_name, data.desc, data.homepage, data.version, data.license
50 );
51
52 formula.push_str("\n on_macos do\n");
54 if let Some(info) = data.binaries.get(&Target::DarwinArm64) {
55 formula.push_str(&format!(
56 r#" on_arm do
57 url "{}"
58 sha256 "{}"
59 end
60"#,
61 info.url, info.sha256
62 ));
63 }
64 formula.push_str(" end\n");
65
66 formula.push_str("\n on_linux do\n");
68 if let Some(info) = data.binaries.get(&Target::LinuxArm64) {
69 formula.push_str(&format!(
70 r#" on_arm do
71 url "{}"
72 sha256 "{}"
73 end
74"#,
75 info.url, info.sha256
76 ));
77 }
78 if let Some(info) = data.binaries.get(&Target::LinuxX64) {
79 formula.push_str(&format!(
80 r#" on_intel do
81 url "{}"
82 sha256 "{}"
83 end
84"#,
85 info.url, info.sha256
86 ));
87 }
88 formula.push_str(" end\n");
89
90 let binary_name = data.class_name.to_lowercase();
92 formula.push_str("\n def install\n");
93 formula.push_str(&format!(" bin.install \"{binary_name}\"\n"));
94 formula.push_str(" end\n\n");
95 formula.push_str(" test do\n");
96 formula.push_str(&format!(
98 " assert_match version.to_s, shell_output(\"#{{bin}}/{binary_name} --version\")\n"
99 ));
100 formula.push_str(" end\nend\n");
101
102 formula
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn test_generate_formula() {
112 let mut binaries = HashMap::new();
113 binaries.insert(
114 Target::DarwinArm64,
115 BinaryInfo {
116 url: "https://example.com/darwin-arm64.tar.gz".to_string(),
117 sha256: "abc123".to_string(),
118 },
119 );
120 binaries.insert(
121 Target::LinuxX64,
122 BinaryInfo {
123 url: "https://example.com/linux-x64.tar.gz".to_string(),
124 sha256: "def456".to_string(),
125 },
126 );
127
128 let data = FormulaData {
129 class_name: "Cuenv".to_string(),
130 desc: "Test description".to_string(),
131 homepage: "https://github.com/cuenv/cuenv".to_string(),
132 license: "AGPL-3.0-or-later".to_string(),
133 version: "0.16.0".to_string(),
134 binaries,
135 };
136
137 let formula = FormulaGenerator::generate(&data);
138
139 assert!(formula.contains("class Cuenv < Formula"));
140 assert!(formula.contains("version \"0.16.0\""));
141 assert!(formula.contains("on_macos do"));
142 assert!(formula.contains("on_linux do"));
143 assert!(formula.contains("sha256 \"abc123\""));
144 }
145
146 #[test]
147 fn test_binary_info_clone() {
148 let info = BinaryInfo {
149 url: "https://example.com/binary.tar.gz".to_string(),
150 sha256: "abc123def456".to_string(),
151 };
152 let cloned = info.clone();
153 assert_eq!(info.url, cloned.url);
154 assert_eq!(info.sha256, cloned.sha256);
155 }
156
157 #[test]
158 fn test_binary_info_debug() {
159 let info = BinaryInfo {
160 url: "https://example.com/binary.tar.gz".to_string(),
161 sha256: "abc123".to_string(),
162 };
163 let debug_str = format!("{info:?}");
164 assert!(debug_str.contains("BinaryInfo"));
165 assert!(debug_str.contains("https://example.com"));
166 assert!(debug_str.contains("abc123"));
167 }
168
169 #[test]
170 fn test_formula_data_clone() {
171 let data = FormulaData {
172 class_name: "Test".to_string(),
173 desc: "Test desc".to_string(),
174 homepage: "https://test.com".to_string(),
175 license: "MIT".to_string(),
176 version: "1.0.0".to_string(),
177 binaries: HashMap::new(),
178 };
179 let cloned = data.clone();
180 assert_eq!(data.class_name, cloned.class_name);
181 assert_eq!(data.version, cloned.version);
182 }
183
184 #[test]
185 fn test_formula_data_debug() {
186 let data = FormulaData {
187 class_name: "Myapp".to_string(),
188 desc: "My app".to_string(),
189 homepage: "https://myapp.com".to_string(),
190 license: "Apache-2.0".to_string(),
191 version: "2.1.0".to_string(),
192 binaries: HashMap::new(),
193 };
194 let debug_str = format!("{data:?}");
195 assert!(debug_str.contains("FormulaData"));
196 assert!(debug_str.contains("Myapp"));
197 }
198
199 #[test]
200 fn test_generate_formula_linux_arm64() {
201 let mut binaries = HashMap::new();
202 binaries.insert(
203 Target::LinuxArm64,
204 BinaryInfo {
205 url: "https://example.com/linux-arm64.tar.gz".to_string(),
206 sha256: "arm64hash".to_string(),
207 },
208 );
209
210 let data = FormulaData {
211 class_name: "Test".to_string(),
212 desc: "Test".to_string(),
213 homepage: "https://test.com".to_string(),
214 license: "MIT".to_string(),
215 version: "1.0.0".to_string(),
216 binaries,
217 };
218
219 let formula = FormulaGenerator::generate(&data);
220 assert!(formula.contains("on_arm do"));
221 assert!(formula.contains("arm64hash"));
222 }
223
224 #[test]
225 fn test_generate_formula_all_platforms() {
226 let mut binaries = HashMap::new();
227 binaries.insert(
228 Target::DarwinArm64,
229 BinaryInfo {
230 url: "https://example.com/darwin-arm64.tar.gz".to_string(),
231 sha256: "darwin_arm_hash".to_string(),
232 },
233 );
234 binaries.insert(
235 Target::LinuxArm64,
236 BinaryInfo {
237 url: "https://example.com/linux-arm64.tar.gz".to_string(),
238 sha256: "linux_arm_hash".to_string(),
239 },
240 );
241 binaries.insert(
242 Target::LinuxX64,
243 BinaryInfo {
244 url: "https://example.com/linux-x64.tar.gz".to_string(),
245 sha256: "linux_x64_hash".to_string(),
246 },
247 );
248
249 let data = FormulaData {
250 class_name: "Multiplatform".to_string(),
251 desc: "Multi-platform app".to_string(),
252 homepage: "https://example.com".to_string(),
253 license: "BSD-3-Clause".to_string(),
254 version: "3.2.1".to_string(),
255 binaries,
256 };
257
258 let formula = FormulaGenerator::generate(&data);
259 assert!(formula.contains("darwin_arm_hash"));
260 assert!(formula.contains("linux_arm_hash"));
261 assert!(formula.contains("linux_x64_hash"));
262 assert!(formula.contains("on_intel do"));
263 }
264
265 #[test]
266 fn test_generate_formula_install_section() {
267 let data = FormulaData {
268 class_name: "Myapp".to_string(),
269 desc: "desc".to_string(),
270 homepage: "https://x.com".to_string(),
271 license: "MIT".to_string(),
272 version: "1.0.0".to_string(),
273 binaries: HashMap::new(),
274 };
275
276 let formula = FormulaGenerator::generate(&data);
277 assert!(formula.contains("def install"));
278 assert!(formula.contains("bin.install \"myapp\""));
279 }
280
281 #[test]
282 fn test_generate_formula_test_section() {
283 let data = FormulaData {
284 class_name: "Cuenv".to_string(),
285 desc: "desc".to_string(),
286 homepage: "https://x.com".to_string(),
287 license: "MIT".to_string(),
288 version: "1.0.0".to_string(),
289 binaries: HashMap::new(),
290 };
291
292 let formula = FormulaGenerator::generate(&data);
293 assert!(formula.contains("test do"));
294 assert!(formula.contains("assert_match version.to_s"));
295 assert!(formula.contains("cuenv --version"));
296 }
297
298 #[test]
299 fn test_generate_formula_empty_binaries() {
300 let data = FormulaData {
301 class_name: "Empty".to_string(),
302 desc: "No binaries".to_string(),
303 homepage: "https://empty.com".to_string(),
304 license: "GPL-3.0".to_string(),
305 version: "0.0.1".to_string(),
306 binaries: HashMap::new(),
307 };
308
309 let formula = FormulaGenerator::generate(&data);
310 assert!(formula.contains("class Empty < Formula"));
312 assert!(formula.contains("on_macos do"));
313 assert!(formula.contains("on_linux do"));
314 assert!(formula.ends_with("end\n"));
315 }
316
317 #[test]
318 fn test_formula_special_characters_in_desc() {
319 let data = FormulaData {
320 class_name: "Test".to_string(),
321 desc: "App with special chars: &, <, >, quotes".to_string(),
322 homepage: "https://test.com".to_string(),
323 license: "MIT".to_string(),
324 version: "1.0.0".to_string(),
325 binaries: HashMap::new(),
326 };
327
328 let formula = FormulaGenerator::generate(&data);
329 assert!(formula.contains("App with special chars"));
330 }
331}