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]); 10] = [
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];
42pub(crate) type ScriptFragments = HashMap<String, String>;
43
44pub(crate) fn pkgfile(dir: &Path, main_package: &str, package: &str, filename: &str, unit_name: Option<&str>) -> Option<PathBuf> {
74 let mut paths_to_try = Vec::new();
75 let is_main_package = main_package == package;
76
77 if let Some(str) = unit_name {
89 let named_filename = format!("{str}.{filename}");
90 paths_to_try.push(dir.join(format!("{package}.{named_filename}")));
91 if is_main_package {
92 paths_to_try.push(dir.join(named_filename));
93 }
94 }
95
96 paths_to_try.push(dir.join(format!("{package}.{filename}")));
97 if is_main_package {
98 paths_to_try.push(dir.join(filename));
99 }
100
101 paths_to_try.into_iter().find(|p| {
102 log::debug!("Looking for a systemd unit in {}", p.display());
103 is_path_file(p)
104 })
105}
106
107pub(crate) fn get_embedded_autoscript(snippet_filename: &str) -> String {
112 let mut snippet: Option<String> = None;
113
114 if cfg!(test) {
116 let path = Path::new(snippet_filename);
117 if is_path_file(path) {
118 snippet = read_file_to_string(path).ok();
119 }
120 }
121
122 let mut snippet = snippet.unwrap_or_else(|| {
124 let (_, snippet_bytes) = AUTOSCRIPTS.iter().find(|(s, _)| *s == snippet_filename)
125 .unwrap_or_else(|| panic!("Unknown autoscript '{snippet_filename}'"));
126
127 String::from_utf8_lossy(snippet_bytes).into_owned()
129 });
130
131 if !snippet.ends_with('\n') {
133 snippet.push('\n');
134 }
135
136 snippet
138}
139
140pub(crate) fn autoscript(
163 scripts: &mut ScriptFragments,
164 package: &str,
165 script: &str,
166 snippet_filename: &str,
167 replacements: &HashMap<&str, String>,
168 service_order: bool,
169 listener: &dyn Listener,
170) -> CDResult<()> {
171 let bin_name = std::env::current_exe().unwrap();
172 let bin_name = bin_name.file_name().unwrap();
173 let bin_name = bin_name.to_str().unwrap();
174 let outfile_ext = if service_order { "service" } else { "debhelper" };
175 let outfile = format!("{package}.{script}.{outfile_ext}");
176
177 listener.progress("Applying", format!("autoscript {snippet_filename} to maintainer script {script}"));
178
179 if scripts.contains_key(&outfile) && (script == "postrm" || script == "prerm") {
180 if !replacements.is_empty() {
181 let existing_text = scripts.get(&outfile).unwrap();
182
183 let new_text = [
185 &format!("# Automatically added by {bin_name}\n"),
186 &autoscript_sed(snippet_filename, replacements),
187 "# End automatically added section\n",
188 existing_text,
189 ].concat();
190 scripts.insert(outfile, new_text);
191 } else {
192 return Err(CargoDebError::Str("unsupported"));
194 }
195 } else if !replacements.is_empty() {
196 let new_text = [
198 scripts.get(&outfile).unwrap_or(&String::new()),
199 &format!("# Automatically added by {bin_name}\n"),
200 &autoscript_sed(snippet_filename, replacements),
201 "# End automatically added section\n",
202 ].concat();
203 scripts.insert(outfile, new_text);
204 } else {
205 return Err(CargoDebError::Str("unsupported"));
207 }
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 "postrm-systemd",
455 "postrm-systemd-reload-only",
456 "prerm-systemd",
457 "prerm-systemd-restart",
458 ];
459
460 assert_eq!(expected_scripts, actual_scripts);
461 }
462
463 #[test]
464 fn autoscript_sanity_check_all_embedded_autoscripts() {
465 for (autoscript_filename, _) in &AUTOSCRIPTS {
466 autoscript_test_wrapper("mypkg", "somescript", autoscript_filename, "dummyunit", None);
467 }
468 }
469
470 #[rstest(maintainer_script, prepend,
471 case::prerm("prerm", true),
472 case::preinst("preinst", false),
473 case::postinst("postinst", false),
474 case::postrm("postrm", true),
475 )]
476 fn autoscript_detailed_check(maintainer_script: &str, prepend: bool) {
477 let autoscript_name = "postrm-systemd";
478
479 let scripts = autoscript_test_wrapper("mypkg", maintainer_script, autoscript_name, "dummyunit", None);
482
483 assert_eq!(1, scripts.len());
486
487 let expected_created_name = &format!("mypkg.{maintainer_script}.debhelper");
488 let (created_name, created_text) = scripts.iter().next().unwrap();
489
490 assert_eq!(expected_created_name, created_name);
492
493 let autoscript_text = get_embedded_autoscript(autoscript_name);
499 let autoscript_line_count = autoscript_text.lines().count();
500 let created_line_count = created_text.lines().count();
501 assert_eq!(autoscript_line_count + 2, created_line_count);
502
503 let mut lines = created_text.lines();
505 assert!(lines.next().unwrap().starts_with("# Automatically added by"));
506 assert_eq!(lines.nth_back(0).unwrap(), "# End automatically added section");
507
508 let expected_autoscript_text1 = autoscript_text.replace("#UNITFILES#", "dummyunit");
511 let expected_autoscript_text1 = expected_autoscript_text1.trim_end();
512 let start1 = 1;
513 let end1 = start1 + autoscript_line_count;
514 let created_autoscript_text1 = created_text.lines().collect::<Vec<&str>>()[start1..end1].join("\n");
515 assert_ne!(expected_autoscript_text1, autoscript_text);
516 assert_eq!(expected_autoscript_text1, created_autoscript_text1);
517
518 let scripts = autoscript_test_wrapper("mypkg", maintainer_script, autoscript_name, "otherunit", Some(scripts));
524
525 assert_eq!(1, scripts.len());
527 let (created_name, created_text) = scripts.iter().next().unwrap();
528 assert_eq!(expected_created_name, created_name);
529
530 let created_line_count = created_text.lines().count();
532 assert_eq!((autoscript_line_count + 2) * 2, created_line_count);
533
534 let mut lines = created_text.lines();
535 assert!(lines.next().unwrap().starts_with("# Automatically added by"));
536 assert_eq!(lines.nth_back(0).unwrap(), "# End automatically added section");
537
538 let expected_autoscript_text2 = autoscript_text.replace("#UNITFILES#", "otherunit");
540 let expected_autoscript_text2 = expected_autoscript_text2.trim_end();
541 let start2 = end1 + 2;
542 let end2 = start2 + autoscript_line_count;
543 let created_autoscript_text1 = created_text.lines().collect::<Vec<&str>>()[start1..end1].join("\n");
544 let created_autoscript_text2 = created_text.lines().collect::<Vec<&str>>()[start2..end2].join("\n");
545 assert_ne!(expected_autoscript_text1, autoscript_text);
546 assert_ne!(expected_autoscript_text2, autoscript_text);
547
548 if prepend {
549 assert_eq!(expected_autoscript_text1, created_autoscript_text2);
550 assert_eq!(expected_autoscript_text2, created_autoscript_text1);
551 } else {
552 assert_eq!(expected_autoscript_text1, created_autoscript_text1);
553 assert_eq!(expected_autoscript_text2, created_autoscript_text2);
554 }
555 }
556
557 #[test]
558 fn autoscript_check_service_order() {
559 let mut mock_listener = crate::listener::MockListener::new();
560 mock_listener.expect_progress().return_const(());
561 let replacements = map! { "UNITFILES" => "someunit".to_owned() };
562
563 let in_out = vec![(false, "debhelper"), (true, "service")];
564
565 for (service_order, expected_ext) in in_out {
566 let mut scripts = ScriptFragments::new();
567 autoscript(&mut scripts, "mypkg", "prerm", "postrm-systemd", &replacements, service_order, &mock_listener).unwrap();
568
569 assert_eq!(1, scripts.len());
570
571 let expected_path = &format!("mypkg.prerm.{expected_ext}");
572 let actual_path = scripts.keys().next().unwrap();
573 assert_eq!(expected_path, actual_path);
574 }
575 }
576
577 #[fixture]
578 #[allow(unused_braces)]
579 fn empty_user_file() -> String { String::new() }
580
581 #[fixture]
582 #[allow(unused_braces)]
583 fn invalid_user_file() -> String { "some content".to_owned() }
584
585 #[fixture]
586 #[allow(unused_braces)]
587 fn valid_user_file() -> String { "some #DEBHELPER# content".to_owned() }
588
589 #[test]
590 fn debhelper_script_subst_with_no_matching_files() {
591 let mut mock_listener = crate::listener::MockListener::new();
592 mock_listener.expect_info().times(0).return_const(());
593
594 let mut scripts = ScriptFragments::new();
595
596 assert_eq!(0, scripts.len());
597 debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener).unwrap();
598 assert_eq!(0, scripts.len());
599 }
600
601 #[rstest]
602 #[should_panic(expected = "Test failed as expected")]
603 fn debhelper_script_subst_errs_if_user_file_lacks_token(invalid_user_file: String) {
604 let _g = add_test_fs_paths(&[]);
605 set_test_fs_path_content("myscript", invalid_user_file);
606
607 let mut mock_listener = crate::listener::MockListener::new();
608 mock_listener.expect_progress().times(1).return_const(());
609
610 let mut scripts = ScriptFragments::new();
611
612 match debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener) {
613 Ok(()) => (),
614 Err(CargoDebError::DebHelperReplaceFailed(_)) => panic!("Test failed as expected"),
615 Err(err) => panic!("Unexpected error {err:?}"),
616 }
617 }
618
619 #[rstest]
620 #[test]
621 fn debhelper_script_subst_with_user_file_only(valid_user_file: String) {
622 let _g = add_test_fs_paths(&[]);
623 set_test_fs_path_content("myscript", valid_user_file);
624
625 let mut mock_listener = crate::listener::MockListener::new();
626 mock_listener.expect_progress().times(1).return_const(());
627
628 let mut scripts = ScriptFragments::new();
629
630 assert_eq!(0, scripts.len());
631 debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener).unwrap();
632 assert_eq!(1, scripts.len());
633 assert!(scripts.contains_key("myscript"));
634 }
635
636 fn script_to_string<'a>(scripts: &'a ScriptFragments, script: &str) -> &'a str {
637 scripts.get(script).unwrap()
638 }
639
640 #[test]
641 fn debhelper_script_subst_with_generated_file_only() {
642 let _g = add_test_fs_paths(&[]);
643 let mut mock_listener = crate::listener::MockListener::new();
644 mock_listener.expect_progress().times(1).return_const(());
645
646 let mut scripts = ScriptFragments::new();
647 scripts.insert("mypkg.myscript.debhelper".to_owned(), "injected".into());
648
649 assert_eq!(1, scripts.len());
650 debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener).unwrap();
651 assert_eq!(2, scripts.len());
652 assert!(scripts.contains_key("mypkg.myscript.debhelper"));
653 assert!(scripts.contains_key("myscript"));
654
655 assert_eq!(script_to_string(&scripts, "mypkg.myscript.debhelper"), "injected");
656 assert_eq!(script_to_string(&scripts, "myscript"), "#!/bin/sh\nset -e\ninjected");
657 }
658
659 #[rstest]
660 #[test]
661 fn debhelper_script_subst_with_user_and_generated_file(valid_user_file: String) {
662 let _g = add_test_fs_paths(&[]);
663 set_test_fs_path_content("myscript", valid_user_file);
664
665 let mut mock_listener = crate::listener::MockListener::new();
666 mock_listener.expect_progress().times(1).return_const(());
667
668 let mut scripts = ScriptFragments::new();
669 scripts.insert("mypkg.myscript.debhelper".to_owned(), "injected".into());
670
671 assert_eq!(1, scripts.len());
672 debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener).unwrap();
673 assert_eq!(2, scripts.len());
674 assert!(scripts.contains_key("mypkg.myscript.debhelper"));
675 assert!(scripts.contains_key("myscript"));
676
677 assert_eq!(script_to_string(&scripts, "mypkg.myscript.debhelper"), "injected");
678 assert_eq!(script_to_string(&scripts, "myscript"), "some injected content");
679 }
680
681 #[rstest(maintainer_script, service_order,
682 case("preinst", false),
683 case("prerm", true),
684 case("postinst", false),
685 case("postrm", true),
686 )]
687 #[test]
688 fn debhelper_script_subst_with_user_and_generated_files(
689 valid_user_file: String,
690 maintainer_script: &'static str,
691 service_order: bool,
692 ) {
693 let _g = add_test_fs_paths(&[]);
694 set_test_fs_path_content(maintainer_script, valid_user_file);
695
696 let mut mock_listener = crate::listener::MockListener::new();
697 mock_listener.expect_progress().times(1).return_const(());
698
699 let mut scripts = ScriptFragments::new();
700 scripts.insert(format!("mypkg.{maintainer_script}.debhelper"), "first".into());
701 scripts.insert(format!("mypkg.{maintainer_script}.service"), "second".into());
702
703 assert_eq!(2, scripts.len());
704 debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", maintainer_script, None, &mock_listener).unwrap();
705 assert_eq!(3, scripts.len());
706 assert!(scripts.contains_key(&format!("mypkg.{maintainer_script}.debhelper")));
707 assert!(scripts.contains_key(&format!("mypkg.{maintainer_script}.service")));
708 assert!(scripts.contains_key(maintainer_script));
709
710 assert_eq!(script_to_string(&scripts, &format!("mypkg.{maintainer_script}.debhelper")), "first");
711 assert_eq!(script_to_string(&scripts, &format!("mypkg.{maintainer_script}.service")), "second");
712 if service_order {
713 assert_eq!(script_to_string(&scripts, maintainer_script), "some secondfirst content");
714 } else {
715 assert_eq!(script_to_string(&scripts, maintainer_script), "some firstsecond content");
716 }
717 }
718
719 #[rstest(
720 error,
721 case::invalid_input("InvalidInput"),
722 case::interrupted("Interrupted"),
723 case::permission_denied("PermissionDenied"),
724 case::not_found("NotFound"),
725 case::other("Other")
726 )]
727 #[test]
728 fn debhelper_script_subst_with_user_file_access_error(error: &str) {
729 let _g = add_test_fs_paths(&[]);
730 set_test_fs_path_content("myscript", format!("error:{error}"));
731
732 let mut mock_listener = crate::listener::MockListener::new();
733 mock_listener.expect_progress().times(1).return_const(());
734
735 let mut scripts = ScriptFragments::new();
736
737 assert_eq!(0, scripts.len());
738 let result = debhelper_script_subst(Path::new(""), &mut scripts, "mypkg", "myscript", None, &mock_listener);
739
740 assert!(matches!(result, Err(CargoDebError::IoFile(..))));
741 if let CargoDebError::IoFile(_, err, _) = result.unwrap_err() {
742 assert_eq!(error, format!("{:?}", err.kind()));
743 } else {
744 unreachable!()
745 }
746 }
747
748 #[test]
749 fn apply_with_no_matching_files() {
750 let mut mock_listener = crate::listener::MockListener::new();
751 mock_listener.expect_info().times(0).return_const(());
752 apply(Path::new(""), &mut ScriptFragments::new(), "mypkg", None, &mock_listener).unwrap();
753 }
754
755 #[rstest]
756 #[test]
757 fn apply_with_valid_user_files(valid_user_file: String) {
758 let _g = add_test_fs_paths(&[]);
759 let scripts = &["postinst", "preinst", "prerm", "postrm"];
760
761 for script in scripts {
762 set_test_fs_path_content(script, valid_user_file.clone());
763 }
764
765 let mut mock_listener = crate::listener::MockListener::new();
766 mock_listener.expect_progress().times(scripts.len()).return_const(());
767
768 apply(Path::new(""), &mut ScriptFragments::new(), "mypkg", None, &mock_listener).unwrap();
769 }
770}