### ----------------------------------------------------
### -- ReadWriteLock
### -- Licenses: Artistic-2.0
### -- Authors: Robert Lemmen <robertle@semistable.com>
### -- File: t/01-basic.rakutest
### ----------------------------------------------------
use Test;

use lib 't/lib';
use LockTestSupport;
use ReadWriteLock;

plan 2;

subtest "AccessMode ordering", {
    plan 4;
    my AccessMode $a = shared;
    my AccessMode $b = exclusive;
    ok $a <= $a, "shared is less/equal than shared";
    ok $a <= $b, "shared is less/equal than exclusive";
    ok $b >= $a, "exclusive is greateer/equal than shared";
    ok $b >= $b, "exclusive is greater/equal than exclusive";
    done-testing;
}

subtest "Basic Lock operations", {
    my $lock-under-test = ReadWriteLock.new();
    my $lts = LockTestSupport.new(
        num-steps => 7,
        testsubs => [
            sub ($ltsr) {
                given $ltsr.current-time() {
                    when 1 {
                        $lock-under-test.lock-exclusive();
                        return "L1";
                    }
                    when 2 {
                        $lock-under-test.lock-exclusive();
                        return "L2";
                    }
                    when 3 {
                        $lock-under-test.unlock();
                        return "U3";
                    }
                    when 4 {
                        $lock-under-test.unlock();
                        return "U4";
                    }
                    default {
                        return "--";
                    }
                }
            },
            sub ($ltsr) {
                given $ltsr.current-time() {
                    when 0 {
                        try {
                            $lock-under-test.unlock();
                            return "U0";
                        }
                        if $! {
                            return "EX";
                        }
                    }
                    when 2 {
                        $lock-under-test.lock-exclusive();
                        return "L2";
                    }
                    when 6 {
                        $lock-under-test.unlock();
                        return "U6";
                    }
                    default {
                        return "--";
                    }
                }
            },
        ]
    );

    plan 9;

    my $result = $lts.run-sequence();
    diag $result.gist;

    is $result[1][0], "EX", "attempting to unlock a lock we do not hold throws";

    is $result[0][1], "L1", "clean lock can be taken";
    is $result[0][2], "L2", "relocking accepted with lock already held";
    is $result[0][3], "U3", "unlocking works and returns";
    is $result[0][4], "U4", "unlocking again on lock taken twice does not throw";

    ok (!defined $result[1][2]), "attempting to lock an already taken lock blocks";
    ok (!defined $result[1][3]), "double-taken lock blocks other thread after first unlock";
    is $result[1][4], "L2", "blocked lock attempt suceeds after second unlock by other thread";
    is $result[1][6], "U6", "unlocking returns as expected";

    done-testing;
}

done-testing;


