content: module Language.PureScript.Ide.ReexportsSpec where
  
  import Protolude
  
  import Data.Map qualified as Map
  import Language.PureScript.Ide.Reexports (ReexportResult(..), reexportHasFailures, resolveReexports')
  import Language.PureScript.Ide.Types (IdeDeclarationAnn, ModuleMap)
  import Language.PureScript.Ide.Test (annExp, ideDtor, ideKind, ideSynonym, ideType, ideTypeClass, ideValue, mn)
  import Language.PureScript qualified as P
  import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)
  
  valueA, typeA, synonymA, classA, dtorA1, dtorA2, kindA :: IdeDeclarationAnn
  valueA = ideValue "valueA" Nothing
  typeA = ideType "TypeA" Nothing []
  synonymA = ideSynonym "SynonymA" Nothing Nothing
  classA = ideTypeClass "ClassA" P.kindType []
  dtorA1 = ideDtor "DtorA1" "TypeA" Nothing
  dtorA2 = ideDtor "DtorA2" "TypeA" Nothing
  kindA = ideKind "KindA"
  
  env :: ModuleMap [IdeDeclarationAnn]
  env = Map.fromList
    [ (mn "A", [valueA, typeA, synonymA, classA, dtorA1, dtorA2, kindA])
    ]
  
  type Refs = [(P.ModuleName, P.DeclarationRef)]
  
  testSpan :: P.SourceSpan
  testSpan = P.internalModuleSourceSpan "<test>"
  
  succTestCases :: [(Text, Refs, [IdeDeclarationAnn])]
  succTestCases =
    [ ("resolves a value reexport", [(mn "A", P.ValueRef testSpan (P.Ident "valueA"))], [valueA `annExp` "A"])
    , ("resolves a type reexport with explicit data constructors"
      , [(mn "A", P.TypeRef testSpan (P.ProperName "TypeA") (Just [P.ProperName "DtorA1"]))], [typeA `annExp` "A", dtorA1 `annExp` "A"])
    , ("resolves a type reexport with implicit data constructors"
      , [(mn "A", P.TypeRef testSpan (P.ProperName "TypeA") Nothing)], map (`annExp` "A") [typeA, dtorA1, dtorA2])
    , ("resolves a synonym reexport"
      , [(mn "A", P.TypeRef testSpan (P.ProperName "SynonymA") Nothing)], [synonymA `annExp` "A"])
    , ("resolves a class reexport", [(mn "A", P.TypeClassRef testSpan (P.ProperName "ClassA"))], [classA `annExp` "A"])
    ]
  
  failTestCases :: [(Text, Refs)]
  failTestCases =
    [ ("fails to resolve a non existing value", [(mn "A", P.ValueRef testSpan (P.Ident "valueB"))])
    , ("fails to resolve a non existing type reexport" , [(mn "A", P.TypeRef testSpan (P.ProperName "TypeB") Nothing)])
    , ("fails to resolve a non existing class reexport", [(mn "A", P.TypeClassRef testSpan (P.ProperName "ClassB"))])
    ]
  
  spec :: Spec
  spec = do
    describe "Successful Reexports" $
      for_ succTestCases $ \(desc, refs, result) ->
        it (toS desc) $ do
          let reResult = resolveReexports' env refs
          reResolved reResult `shouldBe` result
          reResult `shouldSatisfy` not . reexportHasFailures
    describe "Failed Reexports" $
      for_ failTestCases $ \(desc, refs) ->
        it (toS desc) $ do
          let reResult = resolveReexports'  env refs
          reFailed reResult `shouldBe` refs
          reResult `shouldSatisfy` reexportHasFailures
  