packages feed

nvim-hs-0.2.0: test-suite/Neovim/API/THSpec.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell   #-}
module Neovim.API.THSpec
    where

import           Neovim.API.THSpecFunctions

import           Neovim.API.TH
import           Neovim.Context
import qualified Neovim.Context.Internal    as Internal
import           Neovim.Plugin.Classes
import           Neovim.Plugin.Internal

import           Data.Default
import qualified Data.Map                   as Map

import           Test.Hspec
import           Test.QuickCheck

import           Control.Applicative

call :: ([Object] -> Neovim () () Object) -> [Object]
     -> IO Object
call f args = do
    cfg <- Internal.newConfig (pure Nothing) (pure ())
    res <- fmap fst <$> runNeovim cfg () (f args)
    case res of
        Right x -> return x
        Left e -> (throw . ErrorMessage) e


isNeovimException :: NeovimException -> Bool
isNeovimException _ = True


spec :: Spec
spec = do
  describe "calling function without an argument" $ do
    let EF (Function fname _, testFun) = $(function  "TestFunction0" 'testFunction0) Sync
    it "should have a capitalized prefix" $
        fname `shouldBe` (F "TestFunction0")

    it "should return the consant value" $
      call testFun [] `shouldReturn` ObjectInt 42

    it "should fail if supplied an argument" $
        call testFun [ObjectNil] `shouldThrow` isNeovimException


  describe "calling testFunction with two arguments" $ do
    let EF (Function fname _, testFun) = $(function' 'testFunction2) Sync
    it "should have a capitalized prefix" $
        fname `shouldBe` (F "TestFunction2")

    it "should return 2 for proper arguments" $
      call testFun [ ObjectNil
                   , ObjectString "ignored"
                   , ObjectArray [ObjectString "42"]
                   ]
        `shouldReturn` ObjectDouble 2

    it "should throw an exception for the wrong number of arguments" $
      call testFun [ObjectNil] `shouldThrow` isNeovimException

    it "should throw an exception for incompatible types" $
      call testFun [ObjectNil, ObjectBinary "ignored", ObjectString "42"]
        `shouldThrow` isNeovimException

    it "should cast arguments to similar types" $
      call testFun [ObjectNil, ObjectString "ignored", ObjectArray []]
        `shouldReturn` ObjectDouble 2


  describe "generating a command from the two argument test function" $ do
      let EF (Command fname _, testFun) = $(command' 'testFunction2) []
      it "should capitalize the first character" $
        fname `shouldBe` (F "TestFunction2")

  describe "generating the test successor functions" $ do
      let EF (Function fname _, testFun) = $(function' 'testSucc) Sync
      it "should be named TestSucc" $
          fname `shouldBe` (F "TestSucc")

      it "should return the old value + 1" . property $
          \x -> call testFun [ObjectInt x] `shouldReturn` ObjectInt (x+1)

  describe "calling test function with a map argument" $ do
      let EF (Function fname _, testFun) = $(function "TestFunctionMap" 'testFunctionMap) Sync
      it "should capitalize the first letter" $
          fname `shouldBe` (F "TestFunctionMap")

      it "should fail for the wrong number of arguments" $
        call testFun [] `shouldThrow` isNeovimException

      it "should fail for the wrong type of arguments" $
        call testFun [ObjectInt 7, ObjectString "FOO"] `shouldThrow` isNeovimException

      it "should return Nothing for an empty map" $
          call testFun [toObject (Map.empty :: Map.Map String Int), ObjectString "FOO"]
            `shouldReturn` ObjectNil

      it "should return just the value for the singletion entry" $
          call testFun [toObject (Map.singleton "FOO" 7 :: Map.Map String Int), ObjectString "FOO"]
            `shouldReturn` ObjectInt 7


  describe "Calling function with an optional argument" $ do
    let EF (Command cname _, testFun) = $(command' 'testCommandOptArgument) []
        defCmdArgs = toObject (def :: CommandArguments)
    it "should capitalize the first letter" $
        cname `shouldBe` (F "TestCommandOptArgument")

    it "should return \"defalt\" when passed no argument" $ do
        call testFun [defCmdArgs] `shouldReturn` toObject ("default" :: String)

    it "should return what is passed otherwise" . property $ do
        \str -> call testFun [defCmdArgs, toObject str]
            `shouldReturn` toObject (str :: String)