1use std::process::Command;
2
3#[derive(Debug, Clone)]
5pub struct CommandResult {
6 pub stdout: String,
7 pub stderr: String,
8 pub success: bool,
9 pub code: i32,
10}
11
12#[derive(Debug)]
14pub enum PackageError {
15 CommandFailed(String),
17 CommandExecutionFailed(std::io::Error),
19 UnsupportedPlatform(String),
21 Other(String),
23}
24
25impl std::fmt::Display for PackageError {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 match self {
28 PackageError::CommandFailed(msg) => write!(f, "Command failed: {}", msg),
29 PackageError::CommandExecutionFailed(e) => write!(f, "Command execution failed: {}", e),
30 PackageError::UnsupportedPlatform(msg) => write!(f, "Unsupported platform: {}", msg),
31 PackageError::Other(msg) => write!(f, "Error: {}", msg),
32 }
33 }
34}
35
36impl std::error::Error for PackageError {}
37
38#[derive(Debug, Clone, Copy, PartialEq)]
40pub enum Platform {
41 Ubuntu,
43 MacOS,
45 Unknown,
47}
48
49impl Platform {
50 pub fn detect() -> Self {
52 if std::path::Path::new("/usr/bin/sw_vers").exists() {
54 return Platform::MacOS;
55 }
56
57 if std::path::Path::new("/etc/lsb-release").exists() {
59 if let Ok(content) = std::fs::read_to_string("/etc/lsb-release") {
61 if content.contains("Ubuntu") {
62 return Platform::Ubuntu;
63 }
64 }
65 }
66
67 Platform::Unknown
68 }
69}
70
71thread_local! {
73 static DEBUG: std::cell::RefCell<bool> = std::cell::RefCell::new(false);
74}
75
76pub fn set_thread_local_debug(debug: bool) {
78 DEBUG.with(|cell| {
79 *cell.borrow_mut() = debug;
80 });
81}
82
83pub fn thread_local_debug() -> bool {
85 DEBUG.with(|cell| *cell.borrow())
86}
87
88pub fn execute_package_command(args: &[&str], debug: bool) -> Result<CommandResult, PackageError> {
90 let previous_debug = thread_local_debug();
92
93 set_thread_local_debug(debug);
95
96 if debug {
97 println!("Executing command: {}", args.join(" "));
98 }
99
100 let output = Command::new(args[0]).args(&args[1..]).output();
101
102 set_thread_local_debug(previous_debug);
104
105 match output {
106 Ok(output) => {
107 let stdout = String::from_utf8_lossy(&output.stdout).to_string();
108 let stderr = String::from_utf8_lossy(&output.stderr).to_string();
109
110 let result = CommandResult {
111 stdout,
112 stderr,
113 success: output.status.success(),
114 code: output.status.code().unwrap_or(-1),
115 };
116
117 if debug {
119 if !result.stdout.is_empty() {
120 println!("Command stdout: {}", result.stdout);
121 }
122
123 if !result.stderr.is_empty() {
124 println!("Command stderr: {}", result.stderr);
125 }
126
127 if result.success {
128 println!("Command succeeded with code {}", result.code);
129 } else {
130 println!("Command failed with code {}", result.code);
131 }
132 }
133
134 if result.success {
135 Ok(result)
136 } else {
137 if !debug {
139 println!(
140 "Command failed with code {}: {}",
141 result.code,
142 result.stderr.trim()
143 );
144 }
145 Err(PackageError::CommandFailed(format!(
146 "Command failed with code {}: {}",
147 result.code,
148 result.stderr.trim()
149 )))
150 }
151 }
152 Err(e) => {
153 println!("Command execution failed: {}", e);
155 Err(PackageError::CommandExecutionFailed(e))
156 }
157 }
158}
159
160pub trait PackageManager {
162 fn install(&self, package: &str) -> Result<CommandResult, PackageError>;
164
165 fn remove(&self, package: &str) -> Result<CommandResult, PackageError>;
167
168 fn update(&self) -> Result<CommandResult, PackageError>;
170
171 fn upgrade(&self) -> Result<CommandResult, PackageError>;
173
174 fn list_installed(&self) -> Result<Vec<String>, PackageError>;
176
177 fn search(&self, query: &str) -> Result<Vec<String>, PackageError>;
179
180 fn is_installed(&self, package: &str) -> Result<bool, PackageError>;
182}
183
184pub struct AptPackageManager {
186 debug: bool,
187}
188
189impl AptPackageManager {
190 pub fn new(debug: bool) -> Self {
192 Self { debug }
193 }
194}
195
196impl PackageManager for AptPackageManager {
197 fn install(&self, package: &str) -> Result<CommandResult, PackageError> {
198 execute_package_command(
200 &["apt-get", "install", "-y", "--quiet", package],
201 self.debug,
202 )
203 }
204
205 fn remove(&self, package: &str) -> Result<CommandResult, PackageError> {
206 execute_package_command(&["apt-get", "remove", "-y", "--quiet", package], self.debug)
208 }
209
210 fn update(&self) -> Result<CommandResult, PackageError> {
211 execute_package_command(&["apt-get", "update", "-y", "--quiet"], self.debug)
213 }
214
215 fn upgrade(&self) -> Result<CommandResult, PackageError> {
216 execute_package_command(&["apt-get", "upgrade", "-y", "--quiet"], self.debug)
218 }
219
220 fn list_installed(&self) -> Result<Vec<String>, PackageError> {
221 let result = execute_package_command(&["dpkg", "--get-selections"], self.debug)?;
222 let packages = result
223 .stdout
224 .lines()
225 .filter_map(|line| {
226 let parts: Vec<&str> = line.split_whitespace().collect();
227 if parts.len() >= 2 && parts[1] == "install" {
228 Some(parts[0].to_string())
229 } else {
230 None
231 }
232 })
233 .collect();
234 Ok(packages)
235 }
236
237 fn search(&self, query: &str) -> Result<Vec<String>, PackageError> {
238 let result = execute_package_command(&["apt-cache", "search", query], self.debug)?;
239 let packages = result
240 .stdout
241 .lines()
242 .map(|line| {
243 let parts: Vec<&str> = line.split_whitespace().collect();
244 if !parts.is_empty() {
245 parts[0].to_string()
246 } else {
247 String::new()
248 }
249 })
250 .filter(|s| !s.is_empty())
251 .collect();
252 Ok(packages)
253 }
254
255 fn is_installed(&self, package: &str) -> Result<bool, PackageError> {
256 let result = execute_package_command(&["dpkg", "-s", package], self.debug);
257 match result {
258 Ok(cmd_result) => Ok(cmd_result.success),
259 Err(_) => Ok(false),
260 }
261 }
262}
263
264pub struct BrewPackageManager {
266 debug: bool,
267}
268
269impl BrewPackageManager {
270 pub fn new(debug: bool) -> Self {
272 Self { debug }
273 }
274}
275
276impl PackageManager for BrewPackageManager {
277 fn install(&self, package: &str) -> Result<CommandResult, PackageError> {
278 execute_package_command(&["brew", "install", "--quiet", package], self.debug)
280 }
281
282 fn remove(&self, package: &str) -> Result<CommandResult, PackageError> {
283 execute_package_command(&["brew", "uninstall", "--quiet", package], self.debug)
285 }
286
287 fn update(&self) -> Result<CommandResult, PackageError> {
288 execute_package_command(&["brew", "update", "--quiet"], self.debug)
290 }
291
292 fn upgrade(&self) -> Result<CommandResult, PackageError> {
293 execute_package_command(&["brew", "upgrade", "--quiet"], self.debug)
295 }
296
297 fn list_installed(&self) -> Result<Vec<String>, PackageError> {
298 let result = execute_package_command(&["brew", "list", "--formula"], self.debug)?;
299 let packages = result
300 .stdout
301 .lines()
302 .map(|line| line.trim().to_string())
303 .filter(|s| !s.is_empty())
304 .collect();
305 Ok(packages)
306 }
307
308 fn search(&self, query: &str) -> Result<Vec<String>, PackageError> {
309 let result = execute_package_command(&["brew", "search", query], self.debug)?;
310 let packages = result
311 .stdout
312 .lines()
313 .map(|line| line.trim().to_string())
314 .filter(|s| !s.is_empty())
315 .collect();
316 Ok(packages)
317 }
318
319 fn is_installed(&self, package: &str) -> Result<bool, PackageError> {
320 let result = execute_package_command(&["brew", "list", package], self.debug);
321 match result {
322 Ok(cmd_result) => Ok(cmd_result.success),
323 Err(_) => Ok(false),
324 }
325 }
326}
327
328pub struct PackHero {
330 platform: Platform,
331 debug: bool,
332}
333
334impl PackHero {
335 pub fn new() -> Self {
337 let platform = Platform::detect();
338 Self {
339 platform,
340 debug: false,
341 }
342 }
343
344 pub fn set_debug(&mut self, debug: bool) -> &mut Self {
346 self.debug = debug;
347 self
348 }
349
350 pub fn debug(&self) -> bool {
352 self.debug
353 }
354
355 pub fn platform(&self) -> Platform {
357 self.platform
358 }
359
360 fn get_package_manager(&self) -> Result<Box<dyn PackageManager>, PackageError> {
362 match self.platform {
363 Platform::Ubuntu => Ok(Box::new(AptPackageManager::new(self.debug))),
364 Platform::MacOS => Ok(Box::new(BrewPackageManager::new(self.debug))),
365 Platform::Unknown => Err(PackageError::UnsupportedPlatform(
366 "Unsupported platform".to_string(),
367 )),
368 }
369 }
370
371 pub fn install(&self, package: &str) -> Result<CommandResult, PackageError> {
373 let pm = self.get_package_manager()?;
374 pm.install(package)
375 }
376
377 pub fn remove(&self, package: &str) -> Result<CommandResult, PackageError> {
379 let pm = self.get_package_manager()?;
380 pm.remove(package)
381 }
382
383 pub fn update(&self) -> Result<CommandResult, PackageError> {
385 let pm = self.get_package_manager()?;
386 pm.update()
387 }
388
389 pub fn upgrade(&self) -> Result<CommandResult, PackageError> {
391 let pm = self.get_package_manager()?;
392 pm.upgrade()
393 }
394
395 pub fn list_installed(&self) -> Result<Vec<String>, PackageError> {
397 let pm = self.get_package_manager()?;
398 pm.list_installed()
399 }
400
401 pub fn search(&self, query: &str) -> Result<Vec<String>, PackageError> {
403 let pm = self.get_package_manager()?;
404 pm.search(query)
405 }
406
407 pub fn is_installed(&self, package: &str) -> Result<bool, PackageError> {
409 let pm = self.get_package_manager()?;
410 pm.is_installed(package)
411 }
412}
413
414#[cfg(test)]
415mod tests {
416 use super::*;
418 use std::process::Command as StdCommand;
419 use std::sync::{Arc, Mutex};
420
421 #[test]
422 fn test_platform_detection() {
423 let platform = Platform::detect();
425 println!("Detected platform: {:?}", platform);
426
427 match platform {
429 Platform::Ubuntu | Platform::MacOS | Platform::Unknown => {
430 }
432 }
433
434 let platform2 = Platform::detect();
436 assert_eq!(platform, platform2);
437
438 match platform {
440 Platform::MacOS => {
441 assert!(std::path::Path::new("/usr/bin/sw_vers").exists());
443 }
444 Platform::Ubuntu => {
445 assert!(std::path::Path::new("/etc/lsb-release").exists());
447 if let Ok(content) = std::fs::read_to_string("/etc/lsb-release") {
448 assert!(content.contains("Ubuntu"));
449 }
450 }
451 Platform::Unknown => {
452 if std::path::Path::new("/usr/bin/sw_vers").exists() {
455 panic!("sw_vers exists but platform detected as Unknown");
457 }
458 }
459 }
460 }
461
462 #[test]
463 fn test_debug_flag() {
464 set_thread_local_debug(true);
466 assert_eq!(thread_local_debug(), true);
467
468 set_thread_local_debug(false);
469 assert_eq!(thread_local_debug(), false);
470 }
471
472 #[test]
473 fn test_package_error_display() {
474 let err1 = PackageError::CommandFailed("command failed".to_string());
476 assert_eq!(err1.to_string(), "Command failed: command failed");
477
478 let err2 = PackageError::UnsupportedPlatform("test platform".to_string());
479 assert_eq!(err2.to_string(), "Unsupported platform: test platform");
480
481 let err3 = PackageError::Other("other error".to_string());
482 assert_eq!(err3.to_string(), "Error: other error");
483
484 }
486
487 struct MockPackageManager {
489 #[allow(dead_code)]
491 debug: bool,
492 install_called: Arc<Mutex<bool>>,
493 remove_called: Arc<Mutex<bool>>,
494 update_called: Arc<Mutex<bool>>,
495 upgrade_called: Arc<Mutex<bool>>,
496 list_installed_called: Arc<Mutex<bool>>,
497 search_called: Arc<Mutex<bool>>,
498 is_installed_called: Arc<Mutex<bool>>,
499 should_succeed: bool,
501 }
502
503 impl MockPackageManager {
504 fn new(debug: bool, should_succeed: bool) -> Self {
505 Self {
506 debug,
507 install_called: Arc::new(Mutex::new(false)),
508 remove_called: Arc::new(Mutex::new(false)),
509 update_called: Arc::new(Mutex::new(false)),
510 upgrade_called: Arc::new(Mutex::new(false)),
511 list_installed_called: Arc::new(Mutex::new(false)),
512 search_called: Arc::new(Mutex::new(false)),
513 is_installed_called: Arc::new(Mutex::new(false)),
514 should_succeed,
515 }
516 }
517 }
518
519 impl PackageManager for MockPackageManager {
520 fn install(&self, package: &str) -> Result<CommandResult, PackageError> {
521 *self.install_called.lock().unwrap() = true;
522 if self.should_succeed {
523 Ok(CommandResult {
524 stdout: format!("Installed package {}", package),
525 stderr: String::new(),
526 success: true,
527 code: 0,
528 })
529 } else {
530 Err(PackageError::CommandFailed(
531 "Mock install failed".to_string(),
532 ))
533 }
534 }
535
536 fn remove(&self, package: &str) -> Result<CommandResult, PackageError> {
537 *self.remove_called.lock().unwrap() = true;
538 if self.should_succeed {
539 Ok(CommandResult {
540 stdout: format!("Removed package {}", package),
541 stderr: String::new(),
542 success: true,
543 code: 0,
544 })
545 } else {
546 Err(PackageError::CommandFailed(
547 "Mock remove failed".to_string(),
548 ))
549 }
550 }
551
552 fn update(&self) -> Result<CommandResult, PackageError> {
553 *self.update_called.lock().unwrap() = true;
554 if self.should_succeed {
555 Ok(CommandResult {
556 stdout: "Updated package lists".to_string(),
557 stderr: String::new(),
558 success: true,
559 code: 0,
560 })
561 } else {
562 Err(PackageError::CommandFailed(
563 "Mock update failed".to_string(),
564 ))
565 }
566 }
567
568 fn upgrade(&self) -> Result<CommandResult, PackageError> {
569 *self.upgrade_called.lock().unwrap() = true;
570 if self.should_succeed {
571 Ok(CommandResult {
572 stdout: "Upgraded packages".to_string(),
573 stderr: String::new(),
574 success: true,
575 code: 0,
576 })
577 } else {
578 Err(PackageError::CommandFailed(
579 "Mock upgrade failed".to_string(),
580 ))
581 }
582 }
583
584 fn list_installed(&self) -> Result<Vec<String>, PackageError> {
585 *self.list_installed_called.lock().unwrap() = true;
586 if self.should_succeed {
587 Ok(vec!["package1".to_string(), "package2".to_string()])
588 } else {
589 Err(PackageError::CommandFailed(
590 "Mock list_installed failed".to_string(),
591 ))
592 }
593 }
594
595 fn search(&self, query: &str) -> Result<Vec<String>, PackageError> {
596 *self.search_called.lock().unwrap() = true;
597 if self.should_succeed {
598 Ok(vec![
599 format!("result1-{}", query),
600 format!("result2-{}", query),
601 ])
602 } else {
603 Err(PackageError::CommandFailed(
604 "Mock search failed".to_string(),
605 ))
606 }
607 }
608
609 fn is_installed(&self, package: &str) -> Result<bool, PackageError> {
610 *self.is_installed_called.lock().unwrap() = true;
611 if self.should_succeed {
612 Ok(package == "installed-package")
613 } else {
614 Err(PackageError::CommandFailed(
615 "Mock is_installed failed".to_string(),
616 ))
617 }
618 }
619 }
620
621 struct TestPackHero {
623 platform: Platform,
624 #[allow(dead_code)]
625 debug: bool,
626 mock_manager: MockPackageManager,
627 }
628
629 impl TestPackHero {
630 fn new(platform: Platform, debug: bool, should_succeed: bool) -> Self {
631 Self {
632 platform,
633 debug,
634 mock_manager: MockPackageManager::new(debug, should_succeed),
635 }
636 }
637
638 fn get_package_manager(&self) -> Result<&dyn PackageManager, PackageError> {
639 match self.platform {
640 Platform::Ubuntu | Platform::MacOS => Ok(&self.mock_manager),
641 Platform::Unknown => Err(PackageError::UnsupportedPlatform(
642 "Unsupported platform".to_string(),
643 )),
644 }
645 }
646
647 fn install(&self, package: &str) -> Result<CommandResult, PackageError> {
648 let pm = self.get_package_manager()?;
649 pm.install(package)
650 }
651
652 fn remove(&self, package: &str) -> Result<CommandResult, PackageError> {
653 let pm = self.get_package_manager()?;
654 pm.remove(package)
655 }
656
657 fn update(&self) -> Result<CommandResult, PackageError> {
658 let pm = self.get_package_manager()?;
659 pm.update()
660 }
661
662 fn upgrade(&self) -> Result<CommandResult, PackageError> {
663 let pm = self.get_package_manager()?;
664 pm.upgrade()
665 }
666
667 fn list_installed(&self) -> Result<Vec<String>, PackageError> {
668 let pm = self.get_package_manager()?;
669 pm.list_installed()
670 }
671
672 fn search(&self, query: &str) -> Result<Vec<String>, PackageError> {
673 let pm = self.get_package_manager()?;
674 pm.search(query)
675 }
676
677 fn is_installed(&self, package: &str) -> Result<bool, PackageError> {
678 let pm = self.get_package_manager()?;
679 pm.is_installed(package)
680 }
681 }
682
683 #[test]
684 fn test_packhero_with_mock_success() {
685 let hero = TestPackHero::new(Platform::Ubuntu, false, true);
687
688 let result = hero.install("test-package");
690 assert!(result.is_ok());
691 assert!(*hero.mock_manager.install_called.lock().unwrap());
692
693 let result = hero.remove("test-package");
695 assert!(result.is_ok());
696 assert!(*hero.mock_manager.remove_called.lock().unwrap());
697
698 let result = hero.update();
700 assert!(result.is_ok());
701 assert!(*hero.mock_manager.update_called.lock().unwrap());
702
703 let result = hero.upgrade();
705 assert!(result.is_ok());
706 assert!(*hero.mock_manager.upgrade_called.lock().unwrap());
707
708 let result = hero.list_installed();
710 assert!(result.is_ok());
711 assert_eq!(
712 result.unwrap(),
713 vec!["package1".to_string(), "package2".to_string()]
714 );
715 assert!(*hero.mock_manager.list_installed_called.lock().unwrap());
716
717 let result = hero.search("query");
719 assert!(result.is_ok());
720 assert_eq!(
721 result.unwrap(),
722 vec!["result1-query".to_string(), "result2-query".to_string()]
723 );
724 assert!(*hero.mock_manager.search_called.lock().unwrap());
725
726 let result = hero.is_installed("installed-package");
728 assert!(result.is_ok());
729 assert!(result.unwrap());
730 assert!(*hero.mock_manager.is_installed_called.lock().unwrap());
731
732 let result = hero.is_installed("not-installed-package");
733 assert!(result.is_ok());
734 assert!(!result.unwrap());
735 }
736
737 #[test]
738 fn test_packhero_with_mock_failure() {
739 let hero = TestPackHero::new(Platform::Ubuntu, false, false);
741
742 let result = hero.install("test-package");
744 assert!(result.is_err());
745 assert!(*hero.mock_manager.install_called.lock().unwrap());
746
747 let result = hero.remove("test-package");
749 assert!(result.is_err());
750 assert!(*hero.mock_manager.remove_called.lock().unwrap());
751
752 let result = hero.update();
754 assert!(result.is_err());
755 assert!(*hero.mock_manager.update_called.lock().unwrap());
756
757 let result = hero.upgrade();
759 assert!(result.is_err());
760 assert!(*hero.mock_manager.upgrade_called.lock().unwrap());
761
762 let result = hero.list_installed();
764 assert!(result.is_err());
765 assert!(*hero.mock_manager.list_installed_called.lock().unwrap());
766
767 let result = hero.search("query");
769 assert!(result.is_err());
770 assert!(*hero.mock_manager.search_called.lock().unwrap());
771
772 let result = hero.is_installed("installed-package");
774 assert!(result.is_err());
775 assert!(*hero.mock_manager.is_installed_called.lock().unwrap());
776 }
777
778 #[test]
779 fn test_packhero_unsupported_platform() {
780 let hero = TestPackHero::new(Platform::Unknown, false, true);
782
783 let result = hero.install("test-package");
785 assert!(result.is_err());
786 match result {
787 Err(PackageError::UnsupportedPlatform(_)) => (),
788 _ => panic!("Expected UnsupportedPlatform error"),
789 }
790
791 let result = hero.remove("test-package");
792 assert!(result.is_err());
793 match result {
794 Err(PackageError::UnsupportedPlatform(_)) => (),
795 _ => panic!("Expected UnsupportedPlatform error"),
796 }
797
798 let result = hero.update();
799 assert!(result.is_err());
800 match result {
801 Err(PackageError::UnsupportedPlatform(_)) => (),
802 _ => panic!("Expected UnsupportedPlatform error"),
803 }
804 }
805
806 #[test]
809 fn test_real_package_operations_on_ubuntu() {
810 let platform = Platform::detect();
812 if platform != Platform::Ubuntu {
813 println!(
814 "Skipping real package operations test on non-Ubuntu platform: {:?}",
815 platform
816 );
817 return;
818 }
819
820 println!("Running real package operations test on Ubuntu");
821
822 let mut hero = PackHero::new();
824 hero.set_debug(true);
825
826 let test_package = "wget";
828
829 let is_installed_before = match hero.is_installed(test_package) {
831 Ok(result) => result,
832 Err(e) => {
833 println!("Error checking if package is installed: {}", e);
834 return;
835 }
836 };
837
838 println!(
839 "Package {} is installed before test: {}",
840 test_package, is_installed_before
841 );
842
843 if is_installed_before {
845 println!("Removing existing package {} before test", test_package);
846 match hero.remove(test_package) {
847 Ok(_) => println!("Successfully removed package {}", test_package),
848 Err(e) => {
849 println!("Error removing package {}: {}", test_package, e);
850 return;
851 }
852 }
853
854 match hero.is_installed(test_package) {
856 Ok(is_installed) => {
857 if is_installed {
858 println!("Failed to remove package {}", test_package);
859 return;
860 } else {
861 println!("Verified package {} was removed", test_package);
862 }
863 }
864 Err(e) => {
865 println!(
866 "Error checking if package is installed after removal: {}",
867 e
868 );
869 return;
870 }
871 }
872 }
873
874 println!("Installing package {}", test_package);
876 match hero.install(test_package) {
877 Ok(_) => println!("Successfully installed package {}", test_package),
878 Err(e) => {
879 println!("Error installing package {}: {}", test_package, e);
880 return;
881 }
882 }
883
884 match hero.is_installed(test_package) {
886 Ok(is_installed) => {
887 if !is_installed {
888 println!("Failed to install package {}", test_package);
889 return;
890 } else {
891 println!("Verified package {} was installed", test_package);
892 }
893 }
894 Err(e) => {
895 println!(
896 "Error checking if package is installed after installation: {}",
897 e
898 );
899 return;
900 }
901 }
902
903 println!("Searching for packages with 'wget'");
905 match hero.search("wget") {
906 Ok(results) => {
907 println!("Search results: {:?}", results);
908 assert!(
909 results.iter().any(|r| r.contains("wget")),
910 "Search results should contain wget"
911 );
912 }
913 Err(e) => {
914 println!("Error searching for packages: {}", e);
915 return;
916 }
917 }
918
919 println!("Listing installed packages");
921 match hero.list_installed() {
922 Ok(packages) => {
923 println!("Found {} installed packages", packages.len());
924 assert!(
926 packages.iter().any(|p| p == test_package),
927 "Installed packages list should contain {}",
928 test_package
929 );
930 }
931 Err(e) => {
932 println!("Error listing installed packages: {}", e);
933 return;
934 }
935 }
936
937 if !is_installed_before {
939 println!("Removing package {} after test", test_package);
940 match hero.remove(test_package) {
941 Ok(_) => println!("Successfully removed package {}", test_package),
942 Err(e) => {
943 println!("Error removing package {}: {}", test_package, e);
944 return;
945 }
946 }
947
948 match hero.is_installed(test_package) {
950 Ok(is_installed) => {
951 if is_installed {
952 println!("Failed to remove package {}", test_package);
953 return;
954 } else {
955 println!("Verified package {} was removed", test_package);
956 }
957 }
958 Err(e) => {
959 println!(
960 "Error checking if package is installed after removal: {}",
961 e
962 );
963 return;
964 }
965 }
966 }
967
968 println!("Testing package list update");
970 match hero.update() {
971 Ok(_) => println!("Successfully updated package lists"),
972 Err(e) => {
973 println!("Error updating package lists: {}", e);
974 return;
975 }
976 }
977
978 println!("All real package operations tests passed on Ubuntu");
979 }
980
981 #[test]
983 fn test_apt_get_availability() {
984 let output = StdCommand::new("which")
986 .arg("apt-get")
987 .output()
988 .expect("Failed to execute which apt-get");
989
990 let success = output.status.success();
991 let stdout = String::from_utf8_lossy(&output.stdout).to_string();
992
993 println!("apt-get available: {}", success);
994 if success {
995 println!("apt-get path: {}", stdout.trim());
996 }
997
998 if Platform::detect() == Platform::Ubuntu {
1000 assert!(success, "apt-get should be available on Ubuntu");
1001 }
1002 }
1003}