######################################################################
# Custom Futures Unit Tests
# -----
# Licensed under Apache License 2.0
module TestFutures
using Test
using Pia.Futures
import ExtraFun: TimeoutError
import Pia: CancellationError

@testset "Futures" begin
    @testset "instantiate" begin
        @test Futures.ispending(Future())
        @test Futures.typevar(Future()) === Any
        @test Futures.issuccess(Future(42))
        @test Futures.typevar(Future(42)) === Int
        @test Futures.typevar(Future{Number}(42)) === Number
    end
    
    @testset "states" begin
        @testset "success {Any}" begin
            let future = Future()
                @test  Futures.ispending(future)
                @test !Futures.issuccess(future)
                @test !Futures.isfailure(future)
                @test !Futures.iscancelled(future)
                
                # Note: Julia automatically returns RHS on assignment regardless of setindex! return value
                @test ((future[] = 42);       future[] == 42)
                @test ((future[] = "foobar"); future[] == 42)
                
                @test !Futures.ispending(future)
                @test  Futures.issuccess(future)
                @test !Futures.isfailure(future)
                @test !Futures.iscancelled(future)
            end
        end
        
        @testset "success {Number}" begin
            let future = Future{Number}()
                @test  Futures.ispending(future)
                @test !Futures.issuccess(future)
                @test !Futures.isfailure(future)
                @test !Futures.iscancelled(future)
                
                # Note: Julia automatically returns RHS on assignment regardless of setindex! return value
                @test_throws MethodError future[] = "foobar"
                @test ((future[] = 42);    future[] == 42)
                @test ((future[] = 69.69); future[] == 42)
                
                @test !Futures.ispending(future)
                @test  Futures.issuccess(future)
                @test !Futures.isfailure(future)
                @test !Futures.iscancelled(future)
            end
        end
    end
    
    @testset "cancel & timeout" begin
        let future = Future()
            @async begin; sleep(0.01); cancel(future); end
            @test_throws CancellationError wait(future, timeout=1)
        end
        let future = Future()
            @test_throws TimeoutError wait(future, timeout=0.5)
        end
    end
end

end # module TestFutures
