33//! These tests compile and run real binaries to verify the self-replacement
44//! behavior works correctly in realistic scenarios.
55
6+ use assert_cmd:: Command ;
7+ use predicates:: prelude:: * ;
68use std:: fs;
7- use std:: process:: Command ;
89use tempfile:: TempDir ;
910
1011mod test_helpers;
@@ -21,6 +22,8 @@ use self_replacer::{SelfReplacer, WindowsSelfReplacer};
2122// Common tests that run on all platforms
2223// ============================================================================
2324
25+ const TEST_EXEC_MODE : u32 = 0o754 ; // rwxr-xr--
26+
2427#[ test]
2528fn test_self_replacement_with_real_binary ( ) {
2629 let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
@@ -30,50 +33,24 @@ fn test_self_replacement_with_real_binary() {
3033 let binary_v2 = create_self_replacing_binary ( & test_dir, "test_app_v2" , "2.0.0" ) ;
3134
3235 // Verify v1 prints correct version
33- let output = Command :: new ( & binary_v1)
34- . output ( )
35- . expect ( "Failed to run v1 binary" ) ;
36- assert ! ( output. status. success( ) ) ;
37- let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
38- assert ! (
39- stdout. contains( "VERSION:1.0.0" ) ,
40- "Expected v1, got: {}" ,
41- stdout
42- ) ;
36+ Command :: new ( & binary_v1)
37+ . assert ( )
38+ . success ( )
39+ . stdout ( predicate:: str:: contains ( "VERSION:1.0.0" ) ) ;
4340
4441 // Perform self-replacement
45- let output = Command :: new ( & binary_v1)
42+ Command :: new ( & binary_v1)
4643 . arg ( "--replace" )
4744 . arg ( & binary_v2)
48- . output ( )
49- . expect ( "Failed to run self-replacement" ) ;
50-
51- let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
52- let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
53-
54- assert ! (
55- output. status. success( ) ,
56- "Self-replacement failed. stdout: {}, stderr: {}" ,
57- stdout,
58- stderr
59- ) ;
60- assert ! (
61- stdout. contains( "REPLACEMENT_SUCCESS" ) ,
62- "Expected success message, got: {}" ,
63- stdout
64- ) ;
45+ . assert ( )
46+ . success ( )
47+ . stdout ( predicate:: str:: contains ( "REPLACEMENT_SUCCESS" ) ) ;
6548
6649 // Verify the binary was replaced (should now be v2)
67- let output = Command :: new ( & binary_v1)
68- . output ( )
69- . expect ( "Failed to run replaced binary" ) ;
70- assert ! ( output. status. success( ) ) ;
71- let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
72- assert ! (
73- stdout. contains( "VERSION:2.0.0" ) ,
74- "Expected v2, got: {}" ,
75- stdout
76- ) ;
50+ Command :: new ( & binary_v1)
51+ . assert ( )
52+ . success ( )
53+ . stdout ( predicate:: str:: contains ( "VERSION:2.0.0" ) ) ;
7754
7855 // Verify backup was created
7956 // Backup appends .bak to the full filename (e.g., test_app.exe.bak on Windows)
@@ -144,20 +121,20 @@ mod unix_specific {
144121
145122 // Set specific permissions on v1
146123 let mut perms = fs:: metadata ( & binary_v1) . unwrap ( ) . permissions ( ) ;
147- perms. set_mode ( 0o754 ) ;
124+ perms. set_mode ( TEST_EXEC_MODE ) ;
148125 fs:: set_permissions ( & binary_v1, perms) . unwrap ( ) ;
149126
127+ // The bitmask 0o777 is needed to extract only the 9 permission bits (rwxrwxrwx) and ignore
128+ // the file type bits. This is the standard practice when comparing Unix file permissions.
150129 let original_mode = fs:: metadata ( & binary_v1) . unwrap ( ) . permissions ( ) . mode ( ) & 0o777 ;
151- assert_eq ! ( original_mode, 0o754 ) ;
130+ assert_eq ! ( original_mode, TEST_EXEC_MODE ) ;
152131
153132 // Perform replacement
154- let output = Command :: new ( & binary_v1)
133+ Command :: new ( & binary_v1)
155134 . arg ( "--replace" )
156135 . arg ( & binary_v2)
157- . output ( )
158- . expect ( "Failed to run self-replacement" ) ;
159-
160- assert ! ( output. status. success( ) ) ;
136+ . assert ( )
137+ . success ( ) ;
161138
162139 // Verify permissions were preserved
163140 let new_mode = fs:: metadata ( & binary_v1) . unwrap ( ) . permissions ( ) . mode ( ) & 0o777 ;
0 commit comments