content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE TypeApplications #-}
  {-|
  Module      : HsLua.Class.ExposableTests
  Copyright   : © 2017-2024 Albert Krewinkel
  License     : MIT
  Maintainer  : Albert Krewinkel <tarleb@hslua.org>
  
  Tests that Haskell functions can be exposed to and called from Lua.
  -}
  module HsLua.Class.ExposableTests (tests) where
  
  import HsLua.Core (Lua)
  import HsLua.Class.Exposable as Lua
  import HsLua.Class.Peekable as Lua
  import Test.Tasty.HsLua ( (=:), pushLuaExpr, shouldBeErrorMessageOf
                         , shouldBeResultOf )
  import Test.Tasty (TestTree, testGroup)
  
  import qualified HsLua.Core as Lua
  
  -- | Specifications for Attributes parsing functions.
  tests :: TestTree
  tests =
    let integerOperation :: Lua.Integer -> Lua.Integer -> Lua Lua.Integer
        integerOperation i1 i2 =
          let (j1, j2) = (fromIntegral i1, fromIntegral i2)
          in return $ fromIntegral (product [1..j1] `mod` j2 :: Prelude.Integer)
    in testGroup "Exposable"
    [ "push Haskell function to Lua" =:
      (28 :: Lua.Integer) `shouldBeResultOf` do
        let add :: Lua Lua.Integer
            add = do
              i1 <- Lua.peek (-1)
              i2 <- Lua.peek (-2)
              return (i1 + i2)
        Lua.registerHaskellFunction "add" add
        Lua.loadstring "return add(23, 5)" *> Lua.call 0 1
        Lua.peek Lua.top <* Lua.pop 1
  
    , "push multi-argument Haskell function to Lua" =:
      (0 :: Lua.Integer) `shouldBeResultOf` do
        Lua.registerHaskellFunction "integerOp" integerOperation
        Lua.loadstring "return integerOp(23, 42)" *> Lua.call 0 1
        Lua.peek (-1) <* Lua.pop 1
  
    , "argument type errors are propagated" =:
       ("integer expected, got boolean" ++
        "\n\twhile retrieving argument 2" ++
        "\n\twhile executing function call") `shouldBeErrorMessageOf` do
            Lua.registerHaskellFunction "integerOp" integerOperation
            pushLuaExpr "integerOp(23, true)"
  
    , "Error in Haskell function is converted into Lua error" =:
      (False, "foo") `shouldBeResultOf` do
        Lua.openlibs
        Lua.pushAsHaskellFunction (Lua.failLua "foo" :: Lua ())
        Lua.setglobal "throw_foo"
        Lua.loadstring "return pcall(throw_foo)" *> Lua.call 0 2
        (,) <$> Lua.peek (Lua.nth 2) <*> Lua.peek @String (Lua.nth 1)
    ]
  