@@ -56,7 +56,7 @@ fn test_invalid_group() {
5656}
5757
5858#[ test]
59- fn test_1 ( ) {
59+ fn test_error_1 ( ) {
6060 if getegid ( ) != 0 {
6161 new_ucmd ! ( ) . arg ( "bin" ) . arg ( DIR ) . fails ( ) . stderr_contains (
6262 // linux fails with "Operation not permitted (os error 1)"
@@ -417,3 +417,179 @@ fn test_traverse_symlinks() {
417417 ) ;
418418 }
419419}
420+
421+ #[ test]
422+ #[ cfg( not( target_vendor = "apple" ) ) ]
423+ fn test_from_option ( ) {
424+ use std:: os:: unix:: fs:: MetadataExt ;
425+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
426+ let at = & scene. fixtures ;
427+ let groups = nix:: unistd:: getgroups ( ) . unwrap ( ) ;
428+ // Skip test if we don't have at least two different groups to work with
429+ if groups. len ( ) < 2 {
430+ return ;
431+ }
432+ let ( first_group, second_group) = ( groups[ 0 ] , groups[ 1 ] ) ;
433+
434+ at. touch ( "test_file" ) ;
435+ scene
436+ . ucmd ( )
437+ . arg ( first_group. to_string ( ) )
438+ . arg ( "test_file" )
439+ . succeeds ( ) ;
440+
441+ // Test successful group change with --from
442+ scene
443+ . ucmd ( )
444+ . arg ( "--from" )
445+ . arg ( first_group. to_string ( ) )
446+ . arg ( second_group. to_string ( ) )
447+ . arg ( "test_file" )
448+ . succeeds ( )
449+ . no_stderr ( ) ;
450+
451+ // Verify the group was changed
452+ let new_gid = at. plus ( "test_file" ) . metadata ( ) . unwrap ( ) . gid ( ) ;
453+ assert_eq ! ( new_gid, second_group. as_raw( ) ) ;
454+
455+ scene
456+ . ucmd ( )
457+ . arg ( "--from" )
458+ . arg ( first_group. to_string ( ) )
459+ . arg ( first_group. to_string ( ) )
460+ . arg ( "test_file" )
461+ . succeeds ( )
462+ . no_stderr ( ) ;
463+
464+ let unchanged_gid = at. plus ( "test_file" ) . metadata ( ) . unwrap ( ) . gid ( ) ;
465+ assert_eq ! ( unchanged_gid, second_group. as_raw( ) ) ;
466+ }
467+
468+ #[ test]
469+ #[ cfg( not( any( target_os = "android" , target_os = "macos" ) ) ) ]
470+ fn test_from_with_invalid_group ( ) {
471+ let ( at, mut ucmd) = at_and_ucmd ! ( ) ;
472+ at. touch ( "test_file" ) ;
473+ #[ cfg( not( target_os = "android" ) ) ]
474+ let err_msg = "chgrp: invalid user: 'nonexistent_group'\n " ;
475+ #[ cfg( target_os = "android" ) ]
476+ let err_msg = "chgrp: invalid user: 'staff'\n " ;
477+
478+ ucmd. arg ( "--from" )
479+ . arg ( "nonexistent_group" )
480+ . arg ( "staff" )
481+ . arg ( "test_file" )
482+ . fails ( )
483+ . stderr_is ( err_msg) ;
484+ }
485+
486+ #[ test]
487+ #[ cfg( not( target_vendor = "apple" ) ) ]
488+ fn test_verbosity_messages ( ) {
489+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
490+ let at = & scene. fixtures ;
491+ let groups = nix:: unistd:: getgroups ( ) . unwrap ( ) ;
492+ // Skip test if we don't have at least one group to work with
493+ if groups. is_empty ( ) {
494+ return ;
495+ }
496+
497+ at. touch ( "ref_file" ) ;
498+ at. touch ( "target_file" ) ;
499+
500+ scene
501+ . ucmd ( )
502+ . arg ( "-v" )
503+ . arg ( "--reference=ref_file" )
504+ . arg ( "target_file" )
505+ . succeeds ( )
506+ . stderr_contains ( "group of 'target_file' retained as " ) ;
507+ }
508+
509+ #[ test]
510+ #[ cfg( not( target_vendor = "apple" ) ) ]
511+ fn test_from_with_reference ( ) {
512+ use std:: os:: unix:: fs:: MetadataExt ;
513+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
514+ let at = & scene. fixtures ;
515+ let groups = nix:: unistd:: getgroups ( ) . unwrap ( ) ;
516+ if groups. len ( ) < 2 {
517+ return ;
518+ }
519+ let ( first_group, second_group) = ( groups[ 0 ] , groups[ 1 ] ) ;
520+
521+ at. touch ( "ref_file" ) ;
522+ at. touch ( "test_file" ) ;
523+
524+ scene
525+ . ucmd ( )
526+ . arg ( first_group. to_string ( ) )
527+ . arg ( "test_file" )
528+ . succeeds ( ) ;
529+
530+ scene
531+ . ucmd ( )
532+ . arg ( second_group. to_string ( ) )
533+ . arg ( "ref_file" )
534+ . succeeds ( ) ;
535+
536+ // Test --from with --reference
537+ scene
538+ . ucmd ( )
539+ . arg ( "--from" )
540+ . arg ( first_group. to_string ( ) )
541+ . arg ( "--reference=ref_file" )
542+ . arg ( "test_file" )
543+ . succeeds ( )
544+ . no_stderr ( ) ;
545+
546+ let new_gid = at. plus ( "test_file" ) . metadata ( ) . unwrap ( ) . gid ( ) ;
547+ let ref_gid = at. plus ( "ref_file" ) . metadata ( ) . unwrap ( ) . gid ( ) ;
548+ assert_eq ! ( new_gid, ref_gid) ;
549+ }
550+
551+ #[ test]
552+ #[ cfg( not( target_vendor = "apple" ) ) ]
553+ fn test_numeric_group_formats ( ) {
554+ use std:: os:: unix:: fs:: MetadataExt ;
555+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
556+ let at = & scene. fixtures ;
557+
558+ let groups = nix:: unistd:: getgroups ( ) . unwrap ( ) ;
559+ if groups. len ( ) < 2 {
560+ return ;
561+ }
562+ let ( first_group, second_group) = ( groups[ 0 ] , groups[ 1 ] ) ;
563+
564+ at. touch ( "test_file" ) ;
565+
566+ scene
567+ . ucmd ( )
568+ . arg ( first_group. to_string ( ) )
569+ . arg ( "test_file" )
570+ . succeeds ( ) ;
571+
572+ // Test :gid format in --from
573+ scene
574+ . ucmd ( )
575+ . arg ( format ! ( "--from=:{}" , first_group. as_raw( ) ) )
576+ . arg ( second_group. to_string ( ) )
577+ . arg ( "test_file" )
578+ . succeeds ( )
579+ . no_stderr ( ) ;
580+
581+ let new_gid = at. plus ( "test_file" ) . metadata ( ) . unwrap ( ) . gid ( ) ;
582+ assert_eq ! ( new_gid, second_group. as_raw( ) ) ;
583+
584+ // Test :gid format in target group
585+ scene
586+ . ucmd ( )
587+ . arg ( format ! ( "--from={}" , second_group. as_raw( ) ) )
588+ . arg ( format ! ( ":{}" , first_group. as_raw( ) ) )
589+ . arg ( "test_file" )
590+ . succeeds ( )
591+ . no_stderr ( ) ;
592+
593+ let final_gid = at. plus ( "test_file" ) . metadata ( ) . unwrap ( ) . gid ( ) ;
594+ assert_eq ! ( final_gid, first_group. as_raw( ) ) ;
595+ }
0 commit comments