1use std::collections::HashMap;
18use std::path::{Path, PathBuf};
19
20use crate::error::CargoDebError;
21use crate::listener::Listener;
22use crate::util::{is_path_file, read_file_to_string};
23use crate::CDResult;
24
25static AUTOSCRIPTS: [(&str, &[u8]); 11] = [
31 ("postinst-init-tmpfiles", include_bytes!("../../autoscripts/postinst-init-tmpfiles")),
32 ("postinst-systemd-dont-enable", include_bytes!("../../autoscripts/postinst-systemd-dont-enable")),
33 ("postinst-systemd-enable", include_bytes!("../../autoscripts/postinst-systemd-enable")),
34 ("postinst-systemd-restart", include_bytes!("../../autoscripts/postinst-systemd-restart")),
35 ("postinst-systemd-restartnostart", include_bytes!("../../autoscripts/postinst-systemd-restartnostart")),
36 ("postinst-systemd-start", include_bytes!("../../autoscripts/postinst-systemd-start")),
37 ("postrm-systemd", include_bytes!("../../autoscripts/postrm-systemd")),
38 ("postrm-systemd-reload-only", include_bytes!("../../autoscripts/postrm-systemd-reload-only")),
39 ("prerm-systemd", include_bytes!("../../autoscripts/prerm-systemd")),
40 ("prerm-systemd-restart", include_bytes!("../../autoscripts/prerm-systemd-restart")),
41 ("postinst-sysusers", include_bytes!("../../autoscripts/postinst-sysusers")),
42];
43pub(crate) type ScriptFragments = HashMap<String, String>;
44
45pub(crate) fn pkgfile(dir: &Path, main_package: &str, package: &str, filename: &str, unit_name: Option<&str>) -> Option<PathBuf> {
75 let mut paths_to_try = Vec::new();
76 let is_main_package = main_package == package;
77
78 if let Some(str) = unit_name {
90 let named_filename = format!("{str}.{filename}");
91 paths_to_try.push(dir.join(format!("{package}.{named_filename}")));
92 if is_main_package {
93 paths_to_try.push(dir.join(named_filename));
94 }
95 }
96
97 paths_to_try.push(dir.join(format!("{package}.{filename}")));
98 if is_main_package {
99 paths_to_try.push(dir.join(filename));
100 }
101
102 paths_to_try.into_iter().find(|p| {
103 log::debug!("Looking for a systemd unit in {}", p.display());
104 is_path_file(p)
105 })
106}
107
108pub(crate) fn get_embedded_autoscript(snippet_filename: &str) -> String {
113 let mut snippet: Option<String> = None;
114
115 if cfg!(test) {
117 let path = Path::new(snippet_filename);
118 if is_path_file(path) {
119 snippet = read_file_to_string(path).ok();
120 }
121 }
122
123 let mut snippet = snippet.unwrap_or_else(|| {
125 let (_, snippet_bytes) = AUTOSCRIPTS.iter().find(|(s, _)| *s == snippet_filename)
126 .unwrap_or_else(|| panic!("Unknown autoscript '{snippet_filename}'"));
127
128 String::from_utf8_lossy(snippet_bytes).into_owned()
130 });
131
132 if !snippet.ends_with('\n') {
134 snippet.push('\n');
135 }
136
137 snippet
139}
140
141pub(crate) fn autoscript(
164 scripts: &mut ScriptFragments,
165 package: &str,
166 script: &str,
167 snippet_filename: &str,
168 replacements: &HashMap<&str, String>,
169 service_order: bool,
170 listener: &dyn Listener,
171) -> CDResult<()> {
172 let bin_name = std::env::current_exe().unwrap();
173 let bin_name = bin_name.file_name().unwrap();
174 let bin_name = bin_name.to_str().unwrap();
175 let outfile_ext = if service_order { "service" } else { "debhelper" };
176 let outfile = format!("{package}.{script}.{outfile_ext}");
177
178 listener.progress("Applying", format!("autoscript {snippet_filename} to maintainer script {script}"));
179
180 if replacements.is_empty() {
181 return Err(CargoDebError::Str("unsupported"));
183 }
184
185 let new_block = [
186 &format!("# Automatically added by {bin_name}\n"),
187 &autoscript_sed(snippet_filename, replacements),
188 "# End automatically added section\n",
189 ].concat();
190
191 let existing_text = scripts.get(&outfile).map(String::as_str).unwrap_or_default();
192
193 if existing_text.contains(&new_block) {
195 return Ok(());
196 }
197
198 let new_text = if script == "postrm" || script == "prerm" {
199 [new_block.as_str(), existing_text].concat()
202 } else {
203 [existing_text, new_block.as_str()].concat()
205 };
206
207 scripts.insert(outfile, new_text);
208
209 Ok(())
210}
211
212fn autoscript_sed(snippet_filename: &str, replacements: &HashMap<&str, String>) -> String {
224 let mut snippet = get_embedded_autoscript(snippet_filename);
225
226 for (from, to) in replacements {
227 snippet = snippet.replace(&format!("#{from}#"), to);
228 }
229
230 snippet
231}
232
233fn debhelper_script_subst(user_scripts_dir: &Path, scripts: &mut ScriptFragments, package: &str, script: &str, unit_name: Option<&str>,
252 listener: &dyn Listener) -> CDResult<()>
253{
254 let user_file = pkgfile(user_scripts_dir, package, package, script, unit_name);
255 let mut generated_scripts: Vec<String> = vec![
256 format!("{package}.{script}.debhelper"),
257 format!("{package}.{script}.service"),
258 ];
259
260 if let "prerm" | "postrm" = script {
261 generated_scripts.reverse();
262 }
263
264 let mut generated_text = String::new();
266 for generated_file_name in &generated_scripts {
267 if let Some(contents) = scripts.get(generated_file_name) {
268 generated_text.push_str(contents);
269 }
270 }
271
272 if let Some(user_file_path) = user_file {
273 listener.progress("Augmenting", format!("maintainer script {}", user_file_path.display()));
274
275 let user_text = read_file_to_string(&user_file_path)
279 .map_err(|e| CargoDebError::IoFile("Unable to read maintainer script file", e, user_file_path.clone()))?;
280 let new_text = user_text.replace("#DEBHELPER#", &generated_text);
281 if new_text == user_text {
282 return Err(CargoDebError::DebHelperReplaceFailed(user_file_path));
283 }
284 scripts.insert(script.into(), new_text);
285 } else if !generated_text.is_empty() {
286 listener.progress("Generating", format!("maintainer script {script}"));
287
288 let mut new_text = String::new();
290 new_text.push_str("#!/bin/sh\n");
291 new_text.push_str("set -e\n");
292 new_text.push_str(&generated_text);
293
294 scripts.insert(script.into(), new_text);
295 }
296
297 Ok(())
298}
299
300pub(crate) fn apply(user_scripts_dir: &Path, scripts: &mut ScriptFragments, package: &str, unit_name: Option<&str>, listener: &dyn Listener) -> CDResult<()> {
306 for script in &["postinst", "preinst", "prerm", "postrm"] {
307 debhelper_script_subst(user_scripts_dir, scripts, package, script, unit_name, listener)?;
310 }
311
312 Ok(())
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318 use crate::util::tests::{add_test_fs_paths, set_test_fs_path_content};
319 use rstest::*;
320
321 #[derive(Debug)]
325 struct LocalOptionPathBuf(Option<PathBuf>);
326 impl PartialEq<LocalOptionPathBuf> for &str {
328 fn eq(&self, other: &LocalOptionPathBuf) -> bool {
329 Some(Path::new(self).to_path_buf()) == other.0
330 }
331 }
332 impl PartialEq<&str> for LocalOptionPathBuf {
334 fn eq(&self, other: &&str) -> bool {
335 self.0 == Some(Path::new(*other).to_path_buf())
336 }
337 }
338
339 #[test]
340 fn pkgfile_finds_most_specific_match_with_pkg_unit_file() {
341 let _g = add_test_fs_paths(&[
342 "/parent/dir/postinst",
343 "/parent/dir/myunit.postinst",
344 "/parent/dir/mypkg.postinst",
345 "/parent/dir/mypkg.myunit.postinst",
346 "/parent/dir/nested/mypkg.myunit.postinst",
347 "/parent/mypkg.myunit.postinst",
348 ]);
349
350 let r = pkgfile(Path::new("/parent/dir/"), "mypkg", "mypkg", "postinst", Some("myunit"));
351 assert_eq!("/parent/dir/mypkg.myunit.postinst", LocalOptionPathBuf(r));
352
353 let r = pkgfile(Path::new("/parent/dir/"), "mypkg", "mypkg", "postinst", None);
354 assert_eq!("/parent/dir/mypkg.postinst", LocalOptionPathBuf(r));
355 }
356
357 #[test]
358 fn pkgfile_finds_most_specific_match_without_unit_file() {
359 let _g = add_test_fs_paths(&["/parent/dir/postinst", "/parent/dir/mypkg.postinst"]);
360
361 let r = pkgfile(Path::new("/parent/dir/"), "mypkg", "mypkg", "postinst", Some("myunit"));
362 assert_eq!("/parent/dir/mypkg.postinst", LocalOptionPathBuf(r));
363
364 let r = pkgfile(Path::new("/parent/dir/"), "mypkg", "mypkg", "postinst", None);
365 assert_eq!("/parent/dir/mypkg.postinst", LocalOptionPathBuf(r));
366 }
367
368 #[test]
369 fn pkgfile_finds_most_specific_match_without_pkg_file() {
370 let _g = add_test_fs_paths(&["/parent/dir/postinst", "/parent/dir/myunit.postinst"]);
371
372 let r = pkgfile(Path::new("/parent/dir/"), "mypkg", "mypkg", "postinst", Some("myunit"));
373 assert_eq!("/parent/dir/myunit.postinst", LocalOptionPathBuf(r));
374
375 let r = pkgfile(Path::new("/parent/dir/"), "mypkg", "mypkg", "postinst", None);
376 assert_eq!("/parent/dir/postinst", LocalOptionPathBuf(r));
377 }
378
379 #[test]
380 fn pkgfile_finds_a_fallback_match() {
381 let _g = add_test_fs_paths(&[
382 "/parent/dir/postinst",
383 "/parent/dir/myunit.postinst",
384 "/parent/dir/mypkg.postinst",
385 "/parent/dir/mypkg.myunit.postinst",
386 "/parent/dir/nested/mypkg.myunit.postinst",
387 "/parent/mypkg.myunit.postinst",
388 ]);
389
390 let r = pkgfile(Path::new("/parent/dir/"), "mypkg", "mypkg", "postinst", Some("wrongunit"));
391 assert_eq!("/parent/dir/mypkg.postinst", LocalOptionPathBuf(r));
392
393 let r = pkgfile(Path::new("/parent/dir/"), "wrongpkg", "wrongpkg", "postinst", None);
394 assert_eq!("/parent/dir/postinst", LocalOptionPathBuf(r));
395 }
396
397 #[test]
398 fn pkgfile_fails_to_find_a_match() {
399 let _g = add_test_fs_paths(&[
400 "/parent/dir/postinst",
401 "/parent/dir/myunit.postinst",
402 "/parent/dir/mypkg.postinst",
403 "/parent/dir/mypkg.myunit.postinst",
404 "/parent/dir/nested/mypkg.myunit.postinst",
405 "/parent/mypkg.myunit.postinst",
406 ]);
407
408 let r = pkgfile(Path::new("/parent/dir/"), "mypkg", "mypkg", "wrongfile", None);
409 assert_eq!(None, r);
410
411 let r = pkgfile(Path::new("/wrong/dir/"), "mypkg", "mypkg", "postinst", None);
412 assert_eq!(None, r);
413 }
414
415 fn autoscript_test_wrapper(pkg: &str, script: &str, snippet: &str, unit: &str, scripts: Option<ScriptFragments>) -> ScriptFragments {
416 let mut mock_listener = crate::listener::MockListener::new();
417 mock_listener.expect_progress().times(1).return_const(());
418 let mut scripts = scripts.unwrap_or_default();
419 let replacements = map! { "UNITFILES" => unit.to_owned() };
420 autoscript(&mut scripts, pkg, script, snippet, &replacements, false, &mock_listener).unwrap();
421 scripts
422 }
423
424 #[test]
425 #[should_panic(expected = "Unknown autoscript 'idontexist'")]
426 fn autoscript_panics_with_unknown_autoscript() {
427 autoscript_test_wrapper("mypkg", "somescript", "idontexist", "dummyunit", None);
428 }
429
430 #[test]
431 fn autoscript_panics_in_sed_mode() {
432 let mut mock_listener = crate::listener::MockListener::new();
433 mock_listener.expect_progress().times(1).return_const(());
434 let mut scripts = ScriptFragments::new();
435
436 let sed_mode = &HashMap::new();
438
439 assert!(autoscript(&mut scripts, "mypkg", "somescript", "idontexist", sed_mode, false, &mock_listener).is_err());
440 }
441
442 #[test]
443 fn autoscript_check_embedded_files() {
444 let mut actual_scripts: Vec<_> = AUTOSCRIPTS.iter().map(|(name, _)| *name).collect();
445 actual_scripts.sort_unstable();
446
447 let expected_scripts = vec![
448 "postinst-init-tmpfiles",
449 "postinst-systemd-dont-enable",
450 "postinst-systemd-enable",
451 "postinst-systemd-restart",
452 "postinst-systemd-restartnostart",
453 "postinst-systemd-start",
454 "postinst-sysusers",
455 "postrm-systemd",
456 "postrm-systemd-reload-only",
457 "prerm-systemd",
458 "prerm-systemd-restart",
459 ];
460
461 assert_eq!(expected_scripts, actual_scripts);
462 }
463
464 #[test]
465 fn autoscript_sanity_check_all_embedded_autoscripts() {
466 for (autoscript_filename, _) in &AUTOSCRIPTS {
467 autoscript_test_wrapper("mypkg", "somescript", autoscript_filename, "dummyunit", None);
468 }
469 }
470
471 #[rstest(maintainer_script, prepend,
472 case::prerm("prerm", true),
473 case::preinst("preinst", false),
474 case::postinst("postinst", false),
475 case::postrm("postrm", true),
476 )]
477 fn autoscript_detailed_check(maintainer_script: &str, prepend: bool) {
478 let autoscript_name = "postrm-systemd";
479
480 let scripts = autoscript_test_wrapper("mypkg", maintainer_script, autoscript_name, "dummyunit", None);
483
484 assert_eq!(1, scripts.len());
487
488 let expected_created_name = &format!("mypkg.{maintainer_script}.debhelper");
489 let (created_name, created_text) = scripts.iter().next().unwrap();
490
491 assert_eq!(expected_created_name, created_name);
493
494 let autoscript_text = get_embedded_autoscript(autoscript_name);
500 let autoscript_line_count = autoscript_text.lines().count();
501 let created_line_count = created_text.lines().count();
502 assert_eq!(autoscript_line_count + 2, created_line_count);
503
504 let mut lines = created_text.lines();
506 assert!(lines.next().unwrap().starts_with("# Automatically added by"));
507 assert_eq!(lines.nth_back(0).unwrap(), "# End automatically added section");
508
509 let expected_autoscript_text1 = autoscript_text.replace("#UNITFILES#", "dummyunit");
512 let expected_autoscript_text1 = expected_autoscript_text1.trim_end();
513 let start1 = 1;
514 let end1 = start1 + autoscript_line_count;
515 let created_autoscript_text1 = created_text.lines().collect::<Vec<&str>>()[start1..end1].join("\n");
516 assert_ne!(expected_autoscript_text1, autoscript_text);
517 assert_eq!(expected_autoscript_text1, created_autoscript_text1);
518
519 let scripts = autoscript_test_wrapper("mypkg", maintainer_script, autoscript_name, "otherunit", Some(scripts));
525
526 assert_eq!(1, scripts.len());
528 let (created_name, created_text) = scripts.iter().next().unwrap();
529 assert_eq!(expected_created_name, created_name);
530
531 let created_line_count = created_text.lines().count();
533 assert_eq!((autoscript_line_count + 2) * 2, created_line_count);
534
535 let mut lines = created_text.lines();
536 assert!(lines.next().unwrap().starts_with("# Automatically added by"));
537 assert_eq!(lines.nth_back(0).unwrap(), "# End automatically added section");
538
539 let expected_autoscript_text2 = autoscript_text.replace("#UNITFILES#", "otherunit");
541 let expected_autoscript_text2 = expected_autoscript_text2.trim_end();
542 let start2 = end1 + 2;
543 let end2 = start2 + autoscript_line_count;
544 let created_autoscript_text1 = created_text.lines().collect::<Vec<&str>>()[start1..end1].join("\n");
545 let created_autoscript_text2 = created_text.lines().collect::<Vec<&str>>()[start2..end2].join("\n");
546 assert_ne!(expected_autoscript_text1, autoscript_text);
547 assert_ne!(expected_autoscript_text2, autoscript_text);
548
549 if prepend {
550 assert_eq!(expected_autoscript_text1, created_autoscript_text2);
551 assert_eq!(expected_autoscript_text2, created_autoscript_text1);
552 } else {
553 assert_eq!(expected_autoscript_text1, created_autoscript_text1);
554 assert_eq!(expected_autoscript_text2, created_autoscript_text2);
555 }
556 }
557
558 #[test]
559 fn autoscript_does_not_duplicate_identical_fragments() {
560 let scripts = autoscript_test_wrapper("mypkg", "postinst", "postrm-systemd", "dummyunit", None);
561 let text_after_first = scripts.get("mypkg.postinst.debhelper").unwrap().clone();
562
563 let scripts = autoscript_test_wrapper("mypkg", "postinst", "postrm-systemd", "dummyunit", Some(scripts));
565 let text_after_second = scripts.get("mypkg.postinst.debhelper").unwrap();
566
567 assert_eq!(&text_after_first, text_after_second);
568 }
569
570 #[test]
571 fn autoscript_check_service_order() {
572 let mut mock_listener = crate::listener::MockListener::new();
573 mock_listener.expect_progress().return_const(());
574 let replacements = map! { "UNITFILES" => "someunit".to_owned() };
575
576 let in_out = vec![(false, "debhelper"), (true, "service")];
577
578 for (service_order, expected_ext) in in_out {
579 let mut scripts = ScriptFragments::new();
580 autoscript(&mut scripts, "mypkg", "prerm", "postrm-systemd", &replacements, service_order, &mock_listener).unwrap();
581
582 assert_eq!(1, scripts.len());
583
584 let expected_path = &format!("mypkg.prerm.{expected_ext}");
585 let actual_path = scripts.keys().next().unwrap();
586 assert_eq!(expected_path, actual_path);
587 }
588 }
589
590 #[fixture]
591 #[allow(unused_braces)]
592 fn empty_user_file() -> String { String::new() }
593
594 #[fixture]
595 #[allow(unused_braces)]
596 fn invalid_user_file() -> String { "some content".to_owned() }
597
598 #[fixture]
599 #[allow(unused_braces)]
600 fn valid_user_file() -> String { "some #DEBHELPER# content".to_owned() }
601
602 #[test]
603 fn debhelper_script_subst_with_no_matching_files() {
604 let mut mock_listener = crate::listener::MockListener::new();
605 mock_listener.expect_info().times(0).return_const(());
606
607 let mut scripts = ScriptFragments::new();
608
609 assert_eq!(0, scripts.len());
610 debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener).unwrap();
611 assert_eq!(0, scripts.len());
612 }
613
614 #[rstest]
615 #[should_panic(expected = "Test failed as expected")]
616 fn debhelper_script_subst_errs_if_user_file_lacks_token(invalid_user_file: String) {
617 let _g = add_test_fs_paths(&[]);
618 set_test_fs_path_content("myscript", invalid_user_file);
619
620 let mut mock_listener = crate::listener::MockListener::new();
621 mock_listener.expect_progress().times(1).return_const(());
622
623 let mut scripts = ScriptFragments::new();
624
625 match debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener) {
626 Ok(()) => (),
627 Err(CargoDebError::DebHelperReplaceFailed(_)) => panic!("Test failed as expected"),
628 Err(err) => panic!("Unexpected error {err:?}"),
629 }
630 }
631
632 #[rstest]
633 #[test]
634 fn debhelper_script_subst_with_user_file_only(valid_user_file: String) {
635 let _g = add_test_fs_paths(&[]);
636 set_test_fs_path_content("myscript", valid_user_file);
637
638 let mut mock_listener = crate::listener::MockListener::new();
639 mock_listener.expect_progress().times(1).return_const(());
640
641 let mut scripts = ScriptFragments::new();
642
643 assert_eq!(0, scripts.len());
644 debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener).unwrap();
645 assert_eq!(1, scripts.len());
646 assert!(scripts.contains_key("myscript"));
647 }
648
649 fn script_to_string<'a>(scripts: &'a ScriptFragments, script: &str) -> &'a str {
650 scripts.get(script).unwrap()
651 }
652
653 #[test]
654 fn debhelper_script_subst_with_generated_file_only() {
655 let _g = add_test_fs_paths(&[]);
656 let mut mock_listener = crate::listener::MockListener::new();
657 mock_listener.expect_progress().times(1).return_const(());
658
659 let mut scripts = ScriptFragments::new();
660 scripts.insert("mypkg.myscript.debhelper".to_owned(), "injected".into());
661
662 assert_eq!(1, scripts.len());
663 debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener).unwrap();
664 assert_eq!(2, scripts.len());
665 assert!(scripts.contains_key("mypkg.myscript.debhelper"));
666 assert!(scripts.contains_key("myscript"));
667
668 assert_eq!(script_to_string(&scripts, "mypkg.myscript.debhelper"), "injected");
669 assert_eq!(script_to_string(&scripts, "myscript"), "#!/bin/sh\nset -e\ninjected");
670 }
671
672 #[rstest]
673 #[test]
674 fn debhelper_script_subst_with_user_and_generated_file(valid_user_file: String) {
675 let _g = add_test_fs_paths(&[]);
676 set_test_fs_path_content("myscript", valid_user_file);
677
678 let mut mock_listener = crate::listener::MockListener::new();
679 mock_listener.expect_progress().times(1).return_const(());
680
681 let mut scripts = ScriptFragments::new();
682 scripts.insert("mypkg.myscript.debhelper".to_owned(), "injected".into());
683
684 assert_eq!(1, scripts.len());
685 debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener).unwrap();
686 assert_eq!(2, scripts.len());
687 assert!(scripts.contains_key("mypkg.myscript.debhelper"));
688 assert!(scripts.contains_key("myscript"));
689
690 assert_eq!(script_to_string(&scripts, "mypkg.myscript.debhelper"), "injected");
691 assert_eq!(script_to_string(&scripts, "myscript"), "some injected content");
692 }
693
694 #[rstest(maintainer_script, service_order,
695 case("preinst", false),
696 case("prerm", true),
697 case("postinst", false),
698 case("postrm", true),
699 )]
700 #[test]
701 fn debhelper_script_subst_with_user_and_generated_files(
702 valid_user_file: String,
703 maintainer_script: &'static str,
704 service_order: bool,
705 ) {
706 let _g = add_test_fs_paths(&[]);
707 set_test_fs_path_content(maintainer_script, valid_user_file);
708
709 let mut mock_listener = crate::listener::MockListener::new();
710 mock_listener.expect_progress().times(1).return_const(());
711
712 let mut scripts = ScriptFragments::new();
713 scripts.insert(format!("mypkg.{maintainer_script}.debhelper"), "first".into());
714 scripts.insert(format!("mypkg.{maintainer_script}.service"), "second".into());
715
716 assert_eq!(2, scripts.len());
717 debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", maintainer_script, None, &mock_listener).unwrap();
718 assert_eq!(3, scripts.len());
719 assert!(scripts.contains_key(&format!("mypkg.{maintainer_script}.debhelper")));
720 assert!(scripts.contains_key(&format!("mypkg.{maintainer_script}.service")));
721 assert!(scripts.contains_key(maintainer_script));
722
723 assert_eq!(script_to_string(&scripts, &format!("mypkg.{maintainer_script}.debhelper")), "first");
724 assert_eq!(script_to_string(&scripts, &format!("mypkg.{maintainer_script}.service")), "second");
725 if service_order {
726 assert_eq!(script_to_string(&scripts, maintainer_script), "some secondfirst content");
727 } else {
728 assert_eq!(script_to_string(&scripts, maintainer_script), "some firstsecond content");
729 }
730 }
731
732 #[rstest(
733 error,
734 case::invalid_input("InvalidInput"),
735 case::interrupted("Interrupted"),
736 case::permission_denied("PermissionDenied"),
737 case::not_found("NotFound"),
738 case::other("Other")
739 )]
740 #[test]
741 fn debhelper_script_subst_with_user_file_access_error(error: &str) {
742 let _g = add_test_fs_paths(&[]);
743 set_test_fs_path_content("myscript", format!("error:{error}"));
744
745 let mut mock_listener = crate::listener::MockListener::new();
746 mock_listener.expect_progress().times(1).return_const(());
747
748 let mut scripts = ScriptFragments::new();
749
750 assert_eq!(0, scripts.len());
751 let result = debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener);
752
753 assert!(matches!(result, Err(CargoDebError::IoFile(..))));
754 if let CargoDebError::IoFile(_, err, _) = result.unwrap_err() {
755 assert_eq!(error, format!("{:?}", err.kind()));
756 } else {
757 unreachable!()
758 }
759 }
760
761 #[test]
762 fn apply_with_no_matching_files() {
763 let mut mock_listener = crate::listener::MockListener::new();
764 mock_listener.expect_info().times(0).return_const(());
765 apply(Path::new(""), &mut ScriptFragments::new(), "mypkg", None, &mock_listener).unwrap();
766 }
767
768 #[rstest]
769 #[test]
770 fn apply_with_valid_user_files(valid_user_file: String) {
771 let _g = add_test_fs_paths(&[]);
772 let scripts = &["postinst", "preinst", "prerm", "postrm"];
773
774 for script in scripts {
775 set_test_fs_path_content(script, valid_user_file.clone());
776 }
777
778 let mut mock_listener = crate::listener::MockListener::new();
779 mock_listener.expect_progress().times(scripts.len()).return_const(());
780
781 apply(Path::new(""), &mut ScriptFragments::new(), "mypkg", None, &mock_listener).unwrap();
782 }
783}