content: {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE TypeApplications  #-}
  {-| Tests for the auxiliary library.
  -}
  module HsLua.Core.AuxiliaryTests (tests) where
  
  import Data.ByteString (ByteString)
  import Data.Maybe (fromMaybe)
  import HsLua.Core (nth)
  import Test.Tasty.HsLua ( (?:), (=:), pushLuaExpr, shouldBeResultOf
                          , shouldBeErrorMessageOf)
  import Test.Tasty (TestTree, testGroup)
  import Test.Tasty.HUnit ((@=?))
  
  import qualified Lua
  import qualified HsLua.Core as Lua
  
  -- | Specifications for Attributes parsing functions.
  tests :: TestTree
  tests = testGroup "Auxiliary"
    [ testGroup "checkstack'"
      [ "returns unit if stack space can be provided" =:
        () `shouldBeResultOf` Lua.checkstack' 2 "test"
  
        -- testing the error case is not possible for some reason
        -- , "fails if too much stack space is requested" =:
        --    "stack overflow (test)"`shouldBeErrorMessageOf`
        --    Lua.checkstack' maxBound "test"
      ]
  
    , testGroup "getsubtable"
      [ "gets a subtable from field" =:
        [5, 8] `shouldBeResultOf` do
          pushLuaExpr @Lua.Exception "{foo = {5, 8}}"
          _ <- Lua.getsubtable Lua.top "foo"
          Lua.rawgeti (nth 1) 1
          Lua.rawgeti (nth 2) 2
          i1 <- fromMaybe 0 <$> Lua.tointeger (nth 2)
          i2 <- fromMaybe 0 <$> Lua.tointeger (nth 1)
          return [i1, i2]
  
      , "creates new table at field if necessary" =:
        Lua.TypeTable `shouldBeResultOf` do
          Lua.newtable
          _ <- Lua.getsubtable Lua.top "new"
          Lua.getfield (Lua.nth 2) "new"
          Lua.ltype Lua.top
  
      , "returns True if a table exists" ?: do
          pushLuaExpr @Lua.Exception "{yep = {}}"
          Lua.getsubtable Lua.top "yep"
  
      , "returns False if field does not contain a table" ?: do
          pushLuaExpr @Lua.Exception "{nope = 5}"
          not <$> Lua.getsubtable Lua.top "nope"
  
      ]
  
    , testGroup "getmetafield'"
      [ "gets field from the object's metatable" =:
        ("testing" :: ByteString) `shouldBeResultOf` do
          Lua.newtable
          pushLuaExpr "{foo = 'testing'}"
          Lua.setmetatable (Lua.nth 2)
          _ <- Lua.getmetafield Lua.top "foo"
          Lua.tostring' Lua.top
  
      , "returns TypeNil if the object doesn't have a metatable" =:
        Lua.TypeNil `shouldBeResultOf` do
          Lua.newtable
          Lua.getmetafield Lua.top "foo"
      ]
  
    , testGroup "getmetatable'"
      [ "gets table created with newmetatable" =:
        ("__name" :: ByteString, "testing" :: ByteString) `shouldBeResultOf` do
          Lua.newmetatable "testing" *> Lua.pop 1
          _ <- Lua.getmetatable' "testing"
          Lua.pushnil
          Lua.next (nth 2)
          key <- Lua.tostring' (nth 2) <* Lua.pop 1
          value <- Lua.tostring' (nth 1) <* Lua.pop 1
          return (key, value)
  
      , "returns nil if there is no such metatable" =:
        Lua.TypeNil `shouldBeResultOf` do
          _ <- Lua.getmetatable' "nope"
          Lua.ltype Lua.top
  
      , "returns TypeTable if metatable exists" =:
        Lua.TypeTable `shouldBeResultOf` do
          _ <- Lua.newmetatable "yep"
          Lua.getmetatable' "yep"
      ]
  
    , testGroup "requiref"
      [ "can load a module" =: do
          Lua.TypeTable `shouldBeResultOf` do
            Lua.openlibs
            Lua.requiref "mathematics" Lua.luaopen_math False
            Lua.ltype Lua.top
  
      , "returns () on success" =: do
          () `shouldBeResultOf` do
            Lua.openlibs
            -- already loaded
            Lua.requiref "math" Lua.luaopen_math False
  
      , "sets global if flag is set" =: do
          Lua.TypeTable `shouldBeResultOf` do
            Lua.openlibs
            Lua.requiref "foo" Lua.luaopen_math True
            Lua.pop 1
            Lua.getglobal "foo"
  
      , "catches errors" =: do
          "attempt to index a nil value" `shouldBeErrorMessageOf` do
            -- unset registry
            Lua.pushnil
            Lua.copy Lua.top Lua.registryindex
            Lua.requiref "math" Lua.luaopen_package False
      ]
  
    , testGroup "where'"
      [ "return location in chunk" =:
        "test:1: nope, not yet" `shouldBeResultOf` do
          Lua.openlibs
          Lua.pushHaskellFunction $ 1 <$ do
            Lua.settop 1
            Lua.where' 2
            Lua.pushstring "nope, "
            Lua.pushvalue 1
            Lua.concat 3
          Lua.setglobal "frob"
          Lua.OK <- Lua.loadbuffer
            "return frob('not yet')"
            "@test"
          result <- Lua.pcall 0 1 Nothing
          if result /= Lua.OK
            then Lua.throwErrorAsException
            else Lua.tostring' Lua.top
      ]
  
    , "loaded" =: ("_LOADED" @=? Lua.loaded)
    , "preload" =: ("_PRELOAD" @=? Lua.preload)
    ]
  