use Forks::Super ':test', 'overload';
use Test::More tests => 56;
use strict;
use warnings;

# return value from Forks::Super::fork
# can be an overloaded Forks::Super::Job object
# that should behave like a numerical pid
# but can also invoke the F::S::J methods
# like $job->status, etc.

my $job_pid = fork();
if (!defined $job_pid) {
    die "fork() returned undefined value.\n";
}
if ($job_pid == 0) {
    # child.
    exit;
}

ok(ref $job_pid eq 'Forks::Super::Job', 
   "fork returns Forks::Super::Job object in overloaded mode");

my $pid = $job_pid->{pid};
ok($pid != 0 && ref $pid eq '', "can access member of Job object");
ok($job_pid->is_started, "can access method of Job object ");

# arithmetic operations
ok($pid + 10 == $job_pid + 10, "+ operation");
ok($pid - 10 == $job_pid - 10, "- operation");
ok(99999 - $job_pid == 99999 - $job_pid, "- operation");
ok($pid * 5 == 5 * $job_pid, "* operation");
ok($pid / 14 == $job_pid / 14, "/ operation");
ok($pid % 16 == $job_pid % 16, "% operation");
ok(($pid & 1023) == ($job_pid & 1023), "& operation");
ok($pid ** 2 == $job_pid ** 2, "** operation");
ok(1.001 ** $pid == 1.001 ** $job_pid, "** operation");
ok(($pid | 757) - (757 | $job_pid) == 0, "| operation");
ok($job_pid =~ /-?\d+/, "regex operation ok");
ok(($pid ^ 1254) - ($job_pid ^ 1254) == 0, "^ operation ok");
SKIP: {
    if ($job_pid < 0) {
	skip "bit shift operation on negative job id", 2;
    }
    ok($job_pid << 4 == $pid * 16, "<< operation ok  $job_pid >> 4 == $pid*16");
    ok($job_pid >> 3 == int($pid/8), ">> operation ok $job_pid << 3 == $pid/8");
}
ok(abs($job_pid) == abs($pid), "abs operation ok");
ok($pid == $job_pid, "== operation ok");
ok($job_pid == $pid, "== operation ok");
ok($job_pid != 52.6, "!= operation ok");
ok($job_pid > $pid - 1, "> operation ok");
ok($job_pid >= $pid - 1, ">= operation ok");
ok($job_pid <= $pid, "<= operation ok");
ok($job_pid < $pid + 3, "< operation ok");
ok(~$job_pid, "~ operation ok");
ok((~$job_pid ^ (~0)) == ~~(0+$job_pid), "~ operation ok");


# string operations
ok(0 == ($pid cmp $job_pid), "cmp operation");
ok($job_pid lt $pid . "x", "lt operation");
ok("zz$pid" gt $job_pid, "gt operation");
ok($job_pid ne "foo", "ne operation");
ok($job_pid eq $job_pid, "eq operation");
ok(length($job_pid x 4) == 4 * length($pid), "x operation");

ok(atan2($job_pid,1) == atan2($pid,1), "atan2 operation");

# unary operations
ok(cos($job_pid) == cos($pid), "cos operation");
ok(sin($job_pid) == sin($pid), "sin operation");
ok(exp($job_pid) eq exp($pid), "exp operation");
if ($pid > 0) {
    ok(log($job_pid) == log($pid), "log operation");
    ok(sqrt($job_pid) == sqrt($pid), "sqrt operation");
} else {
    ok(1, "skip log operation on negative pid");
    ok(1, "skip sqrt operation on negative pid");
}
ok(int($job_pid) == $pid, "int operation");

# assignment operators ... should fail.
my $job = $job_pid;
ok(ref $job eq 'Forks::Super::Job', "= operation ok");
$job += 1;
ok(ref $job eq '', "+= removes Forks::Super::Job reference");

$job = $job_pid; $job x= 1;
ok(ref $job eq '', "x= removes Forks::Super::Job reference");

$job = $job_pid;
$job--;
ok(ref $job eq '', "-- operation removes Forks::Super::Job reference");


my $state = eval { $job_pid->state };
ok(!$@ && defined($state), "->state() method");

my $pid2 = waitpid $job_pid, 0;
ok($pid2 == $pid, "waitpid on job object ok");
ok(ref $pid2 eq 'Forks::Super::Job',
   "waitpid return value is also overloaded");

my $status = eval { $job_pid->status };
ok(!$@ && $status eq "0", "->status() method");

##################################################################

ok($Forks::Super::Job::OVERLOAD_ENABLED != 0,
   "\$OVERLOAD_ENABLED is set");
Forks::Super::Job::disable_overload();
ok($Forks::Super::Job::OVERLOAD_ENABLED == 0,
   "FSJ::disable_overload resets \$OVERLOAD_ENABLED");

$job_pid = fork { sub => sub { sleep 1 } };
ok(!ref($job_pid),
   "overload disabled fork returns simple number");

$state = eval { $job_pid->{state} };
ok(!defined($state) && $@,
   "job member not accessible through fork return when overload disabled");

##################################################################

Forks::Super::Job::enable_overload();
ok($Forks::Super::Job::OVERLOAD_ENABLED != 0,
   "\$OVERLOAD_ENABLED is set on renable");
$job_pid = fork { sub => sub { sleep 1 } };
ok(ref($job_pid), "reenabled overload fork returns ref to FSJ");

Forks::Super::Job::disable_overload();
ok($Forks::Super::Job::OVERLOAD_ENABLED == 0,
   "\$OVERLOAD_ENABLED is unset on redisable");
$job_pid = fork { sub => sub { sleep 1 } };
ok(!ref($job_pid), "redisabled overload fork returns simple num");


waitall;


