content: module Language.PureScript.Ide.UsageSpec where
  
  import Protolude
  
  import Data.Text qualified as Text
  import Language.PureScript.Ide.Command (Command(..))
  import Language.PureScript.Ide.Types (IdeNamespace(..), Success(..))
  import Language.PureScript.Ide.Test qualified as Test
  import Language.PureScript qualified as P
  import Test.Hspec (Expectation, Spec, describe, it, shouldBe)
  import Data.Text.Read (decimal)
  import System.FilePath ((</>))
  
  load :: [Text] -> Command
  load = LoadSync . map Test.mn
  
  usage :: P.ModuleName -> Text -> IdeNamespace -> Command
  usage = FindUsages
  
  shouldBeUsage :: P.SourceSpan -> (FilePath, Text) -> Expectation
  shouldBeUsage usage' (fp, range) =
    let
      [ start, end] = Text.splitOn "-" range
      unsafeReadInt = fst . either (panic "") identity . decimal
      [ startLine, startColumn ] = map unsafeReadInt (Text.splitOn ":" start)
      [ endLine, endColumn ] = map unsafeReadInt (Text.splitOn ":" end)
    in
      do
        projectDir <- Test.getProjectDirectory
        projectDir </> fp `shouldBe` P.spanName usage'
  
        (P.sourcePosLine (P.spanStart usage'), P.sourcePosColumn (P.spanStart usage'))
          `shouldBe`
          (startLine, startColumn)
  
        (P.sourcePosLine (P.spanEnd usage'), P.sourcePosColumn (P.spanEnd usage'))
          `shouldBe`
          (endLine, endColumn)
  
  spec :: Spec
  spec = describe "Finding Usages" $ do
      it "finds a simple usage" $ do
        ([_, Right (UsagesResult [usage1, usage2])], _) <- Test.inProject $
          Test.runIde [ load ["FindUsage", "FindUsage.Definition", "FindUsage.Reexport"]
                      , usage (Test.mn "FindUsage.Definition") "usageId" IdeNSValue
                      ]
        usage1 `shouldBeUsage` ("src" </> "FindUsage.purs", "12:11-12:18")
        usage2 `shouldBeUsage` ("src" </> "FindUsage" </> "Definition.purs", "13:18-13:25")
      it "finds a simple recursive usage" $ do
        ([_, Right (UsagesResult [usage1])], _) <- Test.inProject $
          Test.runIde [ load ["FindUsage.Recursive"]
                      , usage (Test.mn "FindUsage.Recursive") "recursiveUsage" IdeNSValue
                      ]
        usage1 `shouldBeUsage` ("src" </> "FindUsage" </> "Recursive.purs", "7:12-7:26")
      it "ignores a locally shadowed recursive usage" $ do
        ([_, Right (UsagesResult usageResult)], _) <- Test.inProject $
          Test.runIde [ load ["FindUsage.RecursiveShadowed"]
                      , usage (Test.mn "FindUsage.RecursiveShadowed") "recursiveUsage" IdeNSValue
                      ]
        usageResult `shouldBe` []
      it "finds a constructor usage" $ do
        ([_, Right (UsagesResult [usage1])], _) <- Test.inProject $
          Test.runIde [ load ["FindUsage", "FindUsage.Definition", "FindUsage.Reexport"]
                      , usage (Test.mn "FindUsage.Definition") "Used" IdeNSValue
                      ]
        usage1 `shouldBeUsage` ("src" </> "FindUsage.purs", "8:3-8:9")
      it "finds a constructor alias usage" $ do
        ([_, Right (UsagesResult [usage1])], _) <- Test.inProject $
          Test.runIde [ load ["FindUsage", "FindUsage.Definition", "FindUsage.Reexport"]
                      , usage (Test.mn "FindUsage.Definition") "$%" IdeNSValue
                      ]
        usage1 `shouldBeUsage` ("src" </> "FindUsage.purs", "9:5-9:7")
      it "finds a reexported usage" $ do
        ([_, Right (UsagesResult [usage1])], _) <- Test.inProject $
          Test.runIde [ load ["FindUsage", "FindUsage.Definition", "FindUsage.Reexport"]
                      , usage (Test.mn "FindUsage.Reexport") "toBeReexported" IdeNSValue
                      ]
        usage1 `shouldBeUsage` ("src" </> "FindUsage.purs", "12:19-12:33")
  