@@ -4263,8 +4263,7 @@ fn test_ls_context_long() {
42634263 let line: Vec < _ > = result. stdout_str ( ) . split ( ' ' ) . collect ( ) ;
42644264 assert ! ( line[ 0 ] . ends_with( '.' ) ) ;
42654265 assert ! ( line[ 4 ] . starts_with( "unconfined_u" ) ) ;
4266- let s: Vec < _ > = line[ 4 ] . split ( ':' ) . collect ( ) ;
4267- assert ! ( s. len( ) == 4 ) ;
4266+ validate_selinux_context ( line[ 4 ] ) ;
42684267 }
42694268}
42704269
@@ -4298,6 +4297,113 @@ fn test_ls_context_format() {
42984297 }
42994298}
43004299
4300+ /// Helper function to validate `SELinux` context format
4301+ #[ cfg( feature = "feat_selinux" ) ]
4302+ fn validate_selinux_context ( context : & str ) {
4303+ assert ! (
4304+ context. contains( ':' ) ,
4305+ "Expected SELinux context format (user:role:type:level), got: {}" ,
4306+ context
4307+ ) ;
4308+
4309+ assert_eq ! (
4310+ context. split( ':' ) . count( ) ,
4311+ 4 ,
4312+ "SELinux context should have 4 components separated by colons, got: {}" ,
4313+ context
4314+ ) ;
4315+ }
4316+
4317+ #[ test]
4318+ #[ cfg( feature = "feat_selinux" ) ]
4319+ fn test_ls_selinux_context_format ( ) {
4320+ if !uucore:: selinux:: is_selinux_enabled ( ) {
4321+ println ! ( "test skipped: Kernel has no support for SElinux context" ) ;
4322+ return ;
4323+ }
4324+
4325+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
4326+ let at = & scene. fixtures ;
4327+
4328+ at. touch ( "file" ) ;
4329+ at. symlink_file ( "file" , "link" ) ;
4330+
4331+ // Test that ls -lnZ properly shows the context
4332+ for file in [ "file" , "link" ] {
4333+ let result = scene. ucmd ( ) . args ( & [ "-lnZ" , file] ) . succeeds ( ) ;
4334+ let output = result. stdout_str ( ) ;
4335+
4336+ let lines: Vec < & str > = output. lines ( ) . collect ( ) ;
4337+ assert ! ( !lines. is_empty( ) , "Output should contain at least one line" ) ;
4338+
4339+ let first_line = lines[ 0 ] ;
4340+ let parts: Vec < & str > = first_line. split_whitespace ( ) . collect ( ) ;
4341+ assert ! ( parts. len( ) >= 6 , "Line should have at least 6 fields" ) ;
4342+
4343+ // The 5th field (0-indexed position 4) should contain the SELinux context
4344+ // Format: permissions links owner group context size date time name
4345+ let context = parts[ 4 ] ;
4346+ validate_selinux_context ( context) ;
4347+ }
4348+ }
4349+
4350+ #[ test]
4351+ #[ cfg( feature = "feat_selinux" ) ]
4352+ fn test_ls_selinux_context_indicator ( ) {
4353+ if !uucore:: selinux:: is_selinux_enabled ( ) {
4354+ println ! ( "test skipped: Kernel has no support for SElinux context" ) ;
4355+ return ;
4356+ }
4357+
4358+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
4359+ let at = & scene. fixtures ;
4360+
4361+ at. touch ( "file" ) ;
4362+ at. symlink_file ( "file" , "link" ) ;
4363+
4364+ // Test that ls -l shows "." indicator for files with SELinux contexts
4365+ for file in [ "file" , "link" ] {
4366+ let result = scene. ucmd ( ) . args ( & [ "-l" , file] ) . succeeds ( ) ;
4367+ let output = result. stdout_str ( ) ;
4368+
4369+ // The 11th character should be "." indicating SELinux context
4370+ // -rw-rw-r--. (permissions + context indicator)
4371+ let lines: Vec < & str > = output. lines ( ) . collect ( ) ;
4372+ assert ! ( !lines. is_empty( ) , "Output should contain at least one line" ) ;
4373+
4374+ let first_line = lines[ 0 ] ;
4375+ let chars: Vec < char > = first_line. chars ( ) . collect ( ) ;
4376+ assert ! (
4377+ chars. len( ) >= 11 ,
4378+ "Line should be at least 11 characters long"
4379+ ) ;
4380+
4381+ // The 11th character (0-indexed position 10) should be "." for SELinux context
4382+ assert_eq ! (
4383+ chars[ 10 ] , '.' ,
4384+ "Expected '.' indicator for SELinux context in position 11, got '{}' in line: {}" ,
4385+ chars[ 10 ] , first_line
4386+ ) ;
4387+ }
4388+
4389+ // Test that ls -lnZ properly shows the context
4390+ for file in [ "file" , "link" ] {
4391+ let result = scene. ucmd ( ) . args ( & [ "-lnZ" , file] ) . succeeds ( ) ;
4392+ let output = result. stdout_str ( ) ;
4393+
4394+ let lines: Vec < & str > = output. lines ( ) . collect ( ) ;
4395+ assert ! ( !lines. is_empty( ) , "Output should contain at least one line" ) ;
4396+
4397+ let first_line = lines[ 0 ] ;
4398+ let parts: Vec < & str > = first_line. split_whitespace ( ) . collect ( ) ;
4399+ assert ! ( parts. len( ) >= 6 , "Line should have at least 6 fields" ) ;
4400+
4401+ // The 5th field (0-indexed position 4) should contain the SELinux context
4402+ // Format: permissions links owner group context size date time name
4403+ validate_selinux_context ( parts[ 4 ] ) ;
4404+ }
4405+ }
4406+
43014407#[ test]
43024408#[ allow( non_snake_case) ]
43034409fn test_ls_a_A ( ) {
0 commit comments