{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications    #-}
module ArrayFire.ArraySpec where

import Control.Exception
import Data.Complex
import Data.Word
import Foreign.C.Types
import GHC.Int
import Test.Hspec

import ArrayFire

spec :: Spec
spec =
  describe "Array tests" $ do
    it "Should perform Array tests" $ do
      (1 + 1) `shouldBe` 2
    it "Should fail to create 0 dimension arrays" $ do
      let arr = mkArray @Int [0,0,0,0] [1..]
      evaluate arr `shouldThrow` anyException
    it "Should fail to create 0 length arrays" $ do
      let arr = mkArray @Int [0,0,0,1] []
      evaluate arr `shouldThrow` anyException
    it "Should fail to create 0 length arrays w/ 0 dimensions" $ do
      let arr = mkArray @Int [0,0,0,0] []
      evaluate arr `shouldThrow` anyException
    it "Should create a column vector" $ do
      let arr = mkArray @Int [9,1,1,1] (repeat 9)
      isColumn arr `shouldBe` True
    it "Should create a row vector" $ do
      let arr = mkArray @Int [1,9,1,1] (repeat 9)
      isRow arr `shouldBe` True
    it "Should create a vector" $ do
      let arr = mkArray @Int [9,1,1,1] (repeat 9)
      isVector arr `shouldBe` True
    it "Should create a vector" $ do
      let arr = mkArray @Int [1,9,1,1] (repeat 9)
      isVector arr `shouldBe` True
    it "Should copy an array" $ do
      let arr = mkArray @Int [9,9,1,1] (repeat 9)
      let newArray = copyArray arr
      newArray `shouldBe` arr
    it "Should modify manual eval flag" $ do
      setManualEvalFlag False
      (`shouldBe` False) =<< getManualEvalFlag
    it "Should return the number of elements" $ do
      let arr = mkArray @Int [9,9,1,1] [1..]
      getElements arr `shouldBe` 81
--    it "Should give an empty array" $ do
--      let arr = mkArray @Int [-1,1,1,1] []
--      getElements arr `shouldBe` 0
--      isEmpty arr `shouldBe` True
    it "Should create a scalar array" $ do
      let arr = mkArray @Int [1] [1]
      isScalar arr `shouldBe` True
    it "Should get number of dims specified" $ do
      let arr = mkArray @Int [1,1,1,1] [1]
      getNumDims arr `shouldBe` 1
      let arr = mkArray @Int [2,3,4,5] [1..]
      getNumDims arr `shouldBe` 4
      let arr = mkArray @Int [2,3,4] [1..]
      getNumDims arr `shouldBe` 3
    it "Should get value of dims specified" $ do
      let arr = mkArray @Int [2,3,4,5] (repeat 1)
      getDims arr `shouldBe` (2,3,4,5)

    it "Should test Sparsity" $ do
      let arr = mkArray @Double [2,2,1,1] (repeat 1)
      isSparse arr `shouldBe` False

    it "Should make a Bit array" $ do
      let arr = mkArray @CBool [2,2] [1,1,1,1]
      isBool arr `shouldBe` True

    it "Should make an integer array" $ do
      let arr = mkArray @Int [2,2] (repeat 1)
      isInteger arr `shouldBe` True

    it "Should make a Floating array" $ do
      let arr = mkArray @Double [2,2] (repeat 1)
      isFloating arr `shouldBe` True
      let arr = mkArray @CBool [2,2] (repeat 1)
      isFloating arr `shouldBe` False

    it "Should make a Complex array" $ do
      let arr = mkArray @(Complex Double) [2,2] (repeat 1)
      isComplex arr `shouldBe` True
      isReal arr `shouldBe` False

    it "Should make a Real array" $ do
      let arr = mkArray @Double [2,2] (repeat 1)
      isReal arr `shouldBe` True
      isComplex arr `shouldBe` False

    it "Should make a Double precision array" $ do
      let arr = mkArray @Double [2,2] (repeat 1)
      isDouble arr `shouldBe` True
      isSingle arr `shouldBe` False

    it "Should make a Single precision array" $ do
      let arr = mkArray @Float [2,2] (repeat 1)
      isDouble arr `shouldBe` False
      isSingle arr `shouldBe` True

    it "Should make a Real floating array" $ do
      let arr = mkArray @Float [2,2] (repeat 1)
      isRealFloating arr `shouldBe` True
      let arr = mkArray @Double [2,2] (repeat 1)
      isRealFloating arr `shouldBe` True

    it "Should get reference count" $ do
      let arr1 = mkArray @Float [2,2] (repeat 1)
          arr2 = retainArray arr1
          arr3 = retainArray arr2
      getDataRefCount arr3 `shouldBe` 3

    it "Should convert an array to a list" $ do
      let arr = mkArray @Double [30,30] (repeat 1)
      toList arr `shouldBe` Prelude.replicate (30 * 30) 1

      let arr = mkArray @Float [10,10] (repeat (5.5))
      toList arr `shouldBe` Prelude.replicate 100 5.5

      let arr = mkArray @CBool [4] [1,1,0,1]
      toList arr `shouldBe` [1,1,0,1]

      let arr = mkArray @Int16 [10] [1..]
      toList arr `shouldBe` [1..10]

      let arr = mkArray @Int32 [100] [1..100]
      toList arr `shouldBe` [1..100]

      let arr = mkArray @Int64 [100] [1..100]
      toList arr `shouldBe` [1..100]

      let arr = mkArray @Int [100] [1..100]
      toList arr `shouldBe` [1..100]

      let arr = mkArray @(Complex Float) [1] [1 :+ 1]
      toList arr `shouldBe` [1 :+ 1]

      let arr = mkArray @(Complex Double) [1] [1 :+ 1]
      toList arr `shouldBe` [1 :+ 1]

      let arr = mkArray @Word16 [10] [1..10]
      toList arr `shouldBe` [1..10]

      let arr = mkArray @Word32 [10] [1..10]
      toList arr `shouldBe` [1..10]

      let arr = mkArray @Word64 [10] [1..10]
      toList arr `shouldBe` [1..10]

      let arr = mkArray @Word [10] [1..10]
      toList arr `shouldBe` [1..10]
