content: module Language.PureScript.Ide.CompletionSpec where
  
  import Protolude
  
  import Language.PureScript qualified as P
  import Language.PureScript.Ide.Test as Test
  import Language.PureScript.Ide.Command as Command
  import Language.PureScript.Ide.Completion (CompletionOptions(..), applyCompletionOptions, defaultCompletionOptions)
  import Language.PureScript.Ide.Filter.Declaration qualified as DeclarationType
  import Language.PureScript.Ide.Types (Completion(..), IdeDeclarationAnn, Match(..), Success(..))
  import Test.Hspec (Spec, describe, it, shouldBe, shouldMatchList, shouldSatisfy)
  
  reexportMatches :: [Match IdeDeclarationAnn]
  reexportMatches =
    map (\d -> Match (mn "A", d)) moduleA
    ++ map (\d -> Match (mn "B", d)) moduleB
    where
      moduleA = [ideKind "Kind"]
      moduleB = [ideKind "Kind" `annExp` "A"]
  
  matches :: [(Match IdeDeclarationAnn, [P.ModuleName])]
  matches = map (\d -> (Match (mn "Main", d), [mn "Main"])) [ ideKind "Kind", ideType "Type" Nothing [] ]
  
  typ :: Text -> Command
  typ txt = Type txt [] Nothing
  
  load :: [Text] -> Command
  load = LoadSync . map Test.mn
  
  spec :: Spec
  spec = describe "Applying completion options" $ do
    it "keeps all matches if maxResults is not specified" $ do
      applyCompletionOptions (defaultCompletionOptions { coMaxResults = Nothing })
        (map fst matches) `shouldMatchList` matches
    it "keeps only the specified amount of maxResults" $ do
      applyCompletionOptions (defaultCompletionOptions { coMaxResults = Just 1 })
        (map fst matches) `shouldMatchList` take 1 matches
    it "groups reexports for a single identifier" $ do
      applyCompletionOptions (defaultCompletionOptions { coGroupReexports = True })
        reexportMatches `shouldBe` [(Match (mn "A", ideKind "Kind"), [mn "A", mn "B"])]
  
    it "gets simple docs on definition itself" $ do
      ([_, Right (CompletionResult [ result ])], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpecDocs"]
                    , typ "something"
                    ]
      result `shouldSatisfy` \res -> complDocumentation res == Just "Doc x\n"
  
    it "gets multiline docs" $ do
      ([_, Right (CompletionResult [ result ])], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpecDocs"]
                    , typ "multiline"
                    ]
      result `shouldSatisfy` \res -> complDocumentation res == Just "This is\na multi-line\ncomment\n"
  
    it "gets simple docs on type annotation" $ do
      ([_, Right (CompletionResult [ result ])], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpecDocs"]
                    , typ "withType"
                    ]
      result `shouldSatisfy` \res -> complDocumentation res == Just "Doc *123*\n"
  
    it "gets docs on module declaration" $ do
      ([_, Right (CompletionResult [ result ])], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpecDocs"]
                    , typ "CompletionSpecDocs"
                    ]
      result `shouldSatisfy` \res -> complDocumentation res == Just "Module Documentation\n"
  
    it "gets docs on type class declaration" $ do
      ([_, Right (CompletionResult [ result ])], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpecDocs"]
                    , typ "DocClass"
                    ]
      result `shouldSatisfy` \res -> complDocumentation res == Just "Doc for class\n"
  
    it "gets docs on type class members" $ do
      ([_, Right (CompletionResult [ result ])], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpecDocs"]
                    , typ "member"
                    ]
      result `shouldSatisfy` \res -> complDocumentation res == Just "doc for member\n"
  
    it "includes declarationType in completions for values" $ do
      ([_, Right (CompletionResult [ result ])], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpec"]
                    , typ "exampleValue"
                    ]
      result `shouldSatisfy` \res ->
        complDeclarationType res == Just DeclarationType.Value
  
    it "includes declarationType in completions for functions" $ do
      ([_, Right (CompletionResult [ result ])], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpec"]
                    , typ "exampleFunction"
                    ]
      result `shouldSatisfy` \res ->
        complDeclarationType res == Just DeclarationType.Value
  
    it "includes declarationType in completions for inferred values" $ do
      ([_, Right (CompletionResult [ result ])], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpec"]
                    , typ "exampleInferredString"
                    ]
      result `shouldSatisfy` \res ->
        complDeclarationType res == Just DeclarationType.Value
  
    it "includes declarationType in completions for operators" $ do
      ([_, Right (CompletionResult results)], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpec"]
                    , typ "\\°/"
                    ]
      length results `shouldBe` 2
      results `shouldSatisfy` any (\res ->
        complDeclarationType res == Just DeclarationType.ValueOperator)
      results `shouldSatisfy` any (\res ->
        complDeclarationType res == Just DeclarationType.TypeOperator)
  
    it "includes declarationType in completions for type constructors with \
        \conflicting names" $ do
      ([_, Right (CompletionResult results)], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpec"]
                    , typ "ExampleTypeConstructor"
                    ]
      length results `shouldBe` 2
      results `shouldSatisfy` any (\res ->
          complDeclarationType res == Just DeclarationType.DataConstructor)
      results `shouldSatisfy` any (\res ->
          complDeclarationType res == Just DeclarationType.Type)
  
    it "includes declarationType in completions for type classes" $ do
      ([_, Right (CompletionResult [result])], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpec"]
                    , typ "ExampleClass"
                    ]
      result `shouldSatisfy` \res ->
        complDeclarationType res == Just DeclarationType.TypeClass
  
    it "includes declarationType in completions for type class members" $ do
      ([_, Right (CompletionResult [result])], _) <- Test.inProject $
        Test.runIde [ load ["CompletionSpec"]
                    , typ "exampleMember"
                    ]
      result `shouldSatisfy` \res ->
        complDeclarationType res == Just DeclarationType.Value
  