use strict;
use Test::More;
use Unix::SavedIDs;
use Carp;
use warnings;
use Data::Dumper;
use POSIX qw(getuid getgid geteuid getegid);

$Unix::SavedIDs::DEBUG = 1;

if ( $< != 0 ) {
	plan skip_all => "Only root can change user, so please run these tests as root.";
}
else {
	plan tests => 88;
}

# check getresuid
print "getresuid() before running setresuid\n";
check_values('uid',0,0,0);
# check getresgid
print "getresgid() before running setresgid\n";
check_values('gid',0,0,0);

eval { setresgid() };
ok ( !$@ , "setresgid() - should do nothing" ) || diag($@); 
check_values('gid',0,0,0);

#show_all();

eval { setresgid(50,60,70) };
ok ( !$@ , "setresgid(50,60,70)" ) || diag($@); 
check_values('gid',50,60,70);

#show_all();

eval { setresgid(51,61) };
ok ( !$@ , "setresgid(51,61) ie not with 3 args " ) || diag($@); 
check_values('gid',51,61,70);

eval { setresgid(undef,undef,25) };
ok ( !$@, "setresgid(undef,undef,25) - set sgid only") || diag($@);
check_values('gid',51,61,25);

eval { setresgid(-1,-1,30) };
ok ( !$@ , "setresgid(-1,-1,30) - also set sgid only" ) || diag($@); 
check_values('gid',51,61,30);

eval { setresuid() };
ok ( !$@, "setresuid() - do nothing ") || diag($@);
check_values('uid',0,0,0);

setresuid(0,0,0);
eval { setresuid(undef,undef,25) };
ok ( !$@, "setresuid(undef,undef,25) - set suid only") || diag($@);
check_values('uid',0,0,25);
setresuid(0,0,0);

eval { setresuid(-1,-1,30) };
ok ( !$@ , "setresuid(-1,-1,30) - also set suid only" ) || diag($@); 
check_values('uid',0,0,30);

eval { setresuid(50,60,70) };
ok ( !$@ , "setresuid(50,60,70) didn't crash" ) || diag($@); 
check_values('uid',50,60,70);

eval { setresuid(55,66,77) };
ok ( $@ , "setresuid while not root should crash" ) 
	|| diag("Didn't crash while running setresuid(55,66,77) as non root user!"); 
eval { setresgid(55,66,77) };
ok ( $@ , "setresgid while not root should crash" ) 
	|| diag("Didn't crash while running setresgid(55,66,77) as non root user!");

sub check_values {
	#warn "Posix sez uid = ".getuid().', euid = '.geteuid().', gid = '.getgid()
		#.', egid = '.getegid()."\n";
	my $type = shift;
	if ( $type ne 'uid' && $type ne 'gid' ) {
		croak "Specify type as 'uid' or 'gid'";
	}
	my($rid,$eid,$sid) = @_;

	# uncomment to make arg vars go bad to test this sub
	#$rid++; $eid++; $sid++;
	my @ids;
	if ( $type eq 'uid' ) {
		@ids = eval{ getresuid() };
	} 
	else {
		@ids = eval{ getresgid() };
	}
	# uncomment to make getre(u|g)suid output go bad
	# don't  uncomment both go-bad sections, they will cancel out
	#map { $ids[$_]++ } (0 ... 2);
	
	#my $args_as_string = defined($rid) ? $rid : 'undef';
	#$args_as_string .= ", ".( defined($eid) ? $eid : 'undef' );
	#$args_as_string .= ", ".( defined($sid) ? $sid : 'undef' );
	#print Dumper(\@ids)."\n";

	ok( !$@ ,'getres'.$type.'() didn\'t crash' ) || diag($@);
	ok ( @ids == 3 , "returned 3 elem array" ) || diag(Dumper(\@ids)); 
	ok ( $ids[0] == $rid, 'r'.$type.' is '.$rid ) || diag("r$type is ".$ids[0]);
	ok ( $ids[1] == $eid, 'e'.$type.' is '.$eid ) || diag("e$type is ".$ids[1]);
	ok ( $ids[2] == $sid, 's'.$type.' is '.$sid ) || diag("s$type is ".$ids[2]);
	if ( $type eq 'gid' ) {
		if ( $( !~ /^(\d+)/ ) { 
			croak "Can't parse \$( '$(' This shouldn't happen"; 
		}
		my $rgid_from_perl = $1;
		ok ( $rgid_from_perl == $ids[0], '$( agrees with getresid()') 
			|| diag("\$( = '$(', rgid part of that is '$rgid_from_perl'"
				." getresgid() says '".$ids[0]."'"
			);
		if ( $) !~ /^(\d+)/ ) { 
			croak "Can't parse \$) '$)' This shouldn't happen"; 
		}
		my $egid_from_perl = $1;
		ok ( $egid_from_perl == $ids[1], '$) agrees with getresgid()') 
			|| diag("\$) = '$)', egid part of that is '$egid_from_perl'"
			." getresgid() says '".$ids[1]."'");
	}
	else {
		ok ( $< == $ids[0], '$< agrees with getresuid()') 
			|| diag("\$< = '$<', getresuid() says '".$ids[0]."'".show_all());
		ok ( $> == $ids[1], '$> agrees with getresuid()') 
			|| diag("\$> = '$>', getresuid() says '".$ids[1]."'".show_all());
	}
}

sub show_all {
	print <<"END";
	\$< = '$<', \$> = '$>'
	\$( = '$('
	\$) = '$)'
END
	print "\tgetresuid() = ".join(', ',getresuid())."\n";
	print "\tgetresgid() = ".join(', ',getresgid())."\n";
}

		
