module TestPsci.CommandTest where

import Prelude

import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.RWS.Strict (get)
import Language.PureScript (moduleNameFromString)
import Language.PureScript.Interactive (psciImportedModules, psciInteractivePrint)
import System.FilePath ((</>))
import System.Directory (getCurrentDirectory)
import Test.Hspec (Spec, context, shouldContain, shouldNotContain, specify)
import TestPsci.TestEnv (TestPSCi, equalsTo, execTestPSCi, printed, prints, run, simulateModuleEdit)

specPSCi :: String -> TestPSCi () -> Spec
specPSCi label = specify label . execTestPSCi

commandTests :: Spec
commandTests = context "commandTests" $ do
  specPSCi ":clear" $ do
    run "import Prelude"
    run "import Data.Functor"
    run "import Control.Monad"
    ms <- psciImportedModules <$> get
    length ms `equalsTo` 3
    run ":clear"
    ms' <- psciImportedModules <$> get
    length ms' `equalsTo` 0

  specPSCi ":reload" $ do
    run "import Prelude"
    run "import Data.Functor"
    run "import Control.Monad"
    ms <- psciImportedModules <$> get
    length ms `equalsTo` 3
    run ":reload"
    ms' <- psciImportedModules <$> get
    length ms' `equalsTo` 3

  specPSCi ":complete" $ do
    ":complete ma" `prints` []
    ":complete Data.Functor.ma" `prints` []
    run "import Data.Functor"
    ":complete ma" `prints` unlines ["map", "mapFlipped"]
    run "import Control.Monad as M"
    ":complete M.a" `prints` unlines ["M.ap", "M.apply"]

  specPSCi ":browse" $ do
    ":browse Data.Void" `printed` flip shouldContain "data Void"
    ":browse Data.Void" `printed` flip shouldContain "absurd ::"

  specPSCi ":reload, :browse" $ do
    cwd <- liftIO getCurrentDirectory
    let new = cwd </> "tests" </> "support" </> "psci" </> "Reload.edit"

    ":browse Reload" `printed` flip shouldContain    "reload ::"
    ":browse Reload" `printed` flip shouldNotContain "edited ::"

    simulateModuleEdit (moduleNameFromString "Reload") new $ do
      run ":reload"
      ":browse Reload" `printed` flip shouldNotContain "reload ::"
      ":browse Reload" `printed` flip shouldContain    "edited ::"

    ":browse Mirp" `printed` flip shouldContain "is not valid"
    ":browse Prim" `printed` flip shouldContain "class Partial"

  specPSCi ":print" $ do
    let failMsg = "Unable to set the repl's printing function"
    let interactivePrintModuleShouldBe modName = do
          modName' <- fst . psciInteractivePrint <$> get
          modName' `equalsTo` modName

    run "import Prelude"
    ":print Prelude.show" `printed` flip shouldContain failMsg
    interactivePrintModuleShouldBe (moduleNameFromString "PSCI.Support")

    ":print InteractivePrint.unsafeEval" `printed` flip shouldNotContain failMsg
    "(identity :: _ -> _)" `printed` flip shouldContain "[Function]"
    interactivePrintModuleShouldBe (moduleNameFromString "InteractivePrint")
    ":print" `printed` flip shouldContain "InteractivePrint"