export TestSuite

"""
Abstract test suite that can be used for all packages inheriting from GPUArray
"""
module TestSuite

using Base.Test

toarray(T, x::Tuple{X, Vararg{Int}}) where X = fill(first(x), Base.tail(x))
toarray(::Type{T}, x::NTuple{N, Int}) where {T <: Bool, N} = rand(T, x)
toarray(::Type{T}, x::NTuple{N, Int}) where {T <: Integer, N} = rand(T(1):T(10), x)
toarray(T, x::NTuple{N, Int}) where N = rand(T, x)
toarray(T, x) = x
togpu(T, x::AbstractArray) = T(x)
togpu(T, x) = x

"""
Calls function `f` on input arrays generated by `sizes` as Base.Array and converted to `Typ`.
Compares the result of `f` and tests if they agree.
`sizes` can be the shape of the array, a value or a tuple `(val, shape...)` which will create
a `fill(val, shape...)`.
"""
function against_base(f, Typ, sizes...)
    jl_arrays = toarray.(eltype(Typ), sizes)
    gpu_arrays = togpu.(Typ, jl_arrays)
    res_jl = f(jl_arrays...)
    res_gpu = f(gpu_arrays...)
    pass = res_jl ≈ Array(res_gpu) # all the array printing in @test A ≈ B is just too bad
    @test pass
end


include("blas.jl")
include("broadcasting.jl")
include("construction.jl")
include("fft.jl")
include("gpuinterface.jl")
include("linalg.jl")
include("mapreduce.jl")
include("base.jl")
include("indexing.jl")
# include("vector.jl")
include("random.jl")

function supported_eltypes()
    (Float32, Float64, Int32, Int64, Complex64, Complex128)
end

"""
Runs the test suite on array type `Typ`
"""
function run_tests(Typ)
    GPUArrays.allowslow(false)
    run_gpuinterface(Typ)
    run_base(Typ)
    run_blas(Typ)
    run_broadcasting(Typ)
    run_construction(Typ)
    run_fft(Typ)
    run_linalg(Typ)
    run_mapreduce(Typ)
    run_indexing(Typ)
    run_random(Typ)
end

export against_base, run_tests, supported_eltypes

end
