content: module Language.PureScript.Ide.RebuildSpec where
  
  import Protolude
  
  import Data.Set qualified as Set
  import Language.PureScript qualified as P
  import Language.PureScript.AST.SourcePos (spanName)
  import Language.PureScript.Ide.Command (Command(..))
  import Language.PureScript.Ide.Completion (defaultCompletionOptions)
  import Language.PureScript.Ide.Matcher (flexMatcher)
  import Language.PureScript.Ide.Types (Completion(..), Success(..), emptyIdeState)
  import Language.PureScript.Ide.Test qualified as Test
  import System.FilePath ((</>))
  import System.Directory (doesFileExist, removePathForcibly)
  import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)
  
  defaultTarget :: Set P.CodegenTarget
  defaultTarget = Set.singleton P.JS
  
  load :: [Text] -> Command
  load = LoadSync . map Test.mn
  
  rebuild :: FilePath -> Command
  rebuild fp = Rebuild ("src" </> fp) Nothing defaultTarget
  
  rebuildSync :: FilePath -> Command
  rebuildSync fp = RebuildSync ("src" </> fp) Nothing defaultTarget
  
  spec :: Spec
  spec = describe "Rebuilding single modules" $ do
      it "rebuilds a correct module without dependencies successfully" $ do
        ([_, result], _) <- Test.inProject $
          Test.runIde [ load ["RebuildSpecSingleModule"]
                      , rebuild "RebuildSpecSingleModule.purs"
                      ]
        result `shouldSatisfy` isRight
      it "fails to rebuild an incorrect module without dependencies and returns the errors" $ do
        ([result], _) <- Test.inProject $
          Test.runIde [ rebuild "RebuildSpecSingleModule.fail" ]
        result `shouldSatisfy` isLeft
      it "rebuilds a correct module with its dependencies successfully" $ do
        ([_, result], _) <- Test.inProject $
          Test.runIde [ load ["RebuildSpecWithDeps", "RebuildSpecDep"]
                      , rebuild "RebuildSpecWithDeps.purs"
                      ]
        result `shouldSatisfy` isRight
      it "rebuilds a correct module that has reverse dependencies" $ do
        ([_, result], _) <- Test.inProject $
          Test.runIde [ load ["RebuildSpecWithDeps"], rebuild "RebuildSpecDep.purs" ]
        result `shouldSatisfy` isRight
      it "fails to rebuild a module if its dependencies are not loaded" $ do
        ([_, result], _) <- Test.inProject $
          Test.runIde [ load ["RebuildSpecWithDeps"], rebuild "RebuildSpecWithDeps.purs" ]
        result `shouldSatisfy` isLeft
      it "rebuilds a correct module with a foreign file" $ do
        ([_, result], _) <- Test.inProject $
          Test.runIde [ load ["RebuildSpecWithForeign"], rebuild "RebuildSpecWithForeign.purs" ]
        result `shouldSatisfy` isRight
      it "fails to rebuild a module with a foreign import but no file" $ do
        ([result], _) <- Test.inProject $
          Test.runIde [ rebuild "RebuildSpecWithMissingForeign.fail" ]
        result `shouldSatisfy` isLeft
      it "completes a hidden identifier after rebuilding" $ do
        ([_, Right (CompletionResult [ result ])], _) <- Test.inProject $
          Test.runIde [ rebuildSync "RebuildSpecWithHiddenIdent.purs"
                      , Complete [] (flexMatcher "hid") (Just (Test.mn "RebuildSpecWithHiddenIdent")) defaultCompletionOptions]
        complIdentifier result `shouldBe` "hidden"
      it "uses the specified `actualFile` for location information" $ do
        ([_, Right (CompletionResult [ result ])], _) <- Test.inProject $
          Test.runIde'
            Test.defConfig
            emptyIdeState
            [ RebuildSync ("src" </> "RebuildSpecWithHiddenIdent.purs") (Just "actualFile") defaultTarget
            , Complete [] (flexMatcher "hid") (Just (Test.mn "RebuildSpecWithHiddenIdent")) defaultCompletionOptions]
        map spanName (complLocation result) `shouldBe` Just "actualFile"
      it "doesn't produce JS when an empty target list is supplied" $ do
        exists <- Test.inProject $ do
          let indexJs = "output" </> "RebuildSpecSingleModule" </> "index.js"
          removePathForcibly ("output" </> "RebuildSpecSingleModule")
          _ <- Test.runIde [ RebuildSync ("src" </> "RebuildSpecSingleModule.purs") Nothing Set.empty ]
          doesFileExist indexJs
        exists `shouldBe` False
      it "does produce corefn if it's a codegen target" $ do
        exists <- Test.inProject $ do
          let corefn = "output" </> "RebuildSpecSingleModule" </> "corefn.json"
          removePathForcibly ("output" </> "RebuildSpecSingleModule")
          _ <- Test.runIde [ RebuildSync ("src" </> "RebuildSpecSingleModule.purs") Nothing (Set.singleton P.CoreFn) ]
          doesFileExist corefn
        exists `shouldBe` True
  