purescript-0.10.2: tests/Language/PureScript/Ide/ImportsSpec.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Language.PureScript.Ide.ImportsSpec where
import Protolude
import Data.Maybe (fromJust)
import qualified Language.PureScript as P
import Language.PureScript.Ide.Imports
import Language.PureScript.Ide.Types
import Test.Hspec
simpleFile :: [Text]
simpleFile =
[ "module Main where"
, "import Prelude"
, ""
, "myFunc x y = x + y"
]
splitSimpleFile :: (P.ModuleName, [Text], [Import], [Text])
splitSimpleFile = fromRight (sliceImportSection simpleFile)
where
fromRight = fromJust . rightToMaybe
withImports :: [Text] -> [Text]
withImports is =
take 2 simpleFile ++ is ++ drop 2 simpleFile
testParseImport :: Text -> Import
testParseImport = fromJust . parseImport
preludeImport, arrayImport, listImport, consoleImport, maybeImport :: Import
preludeImport = testParseImport "import Prelude"
arrayImport = testParseImport "import Data.Array (head, cons)"
listImport = testParseImport "import Data.List as List"
consoleImport = testParseImport "import Control.Monad.Eff.Console (log) as Console"
maybeImport = testParseImport "import Data.Maybe (Maybe(Just))"
wildcard :: P.Type
wildcard = P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
spec :: Spec
spec = do
describe "determining the importsection" $ do
let moduleSkeleton imports =
Right (P.moduleNameFromString "Main", take 1 simpleFile, imports, drop 2 simpleFile)
it "finds a simple import" $
shouldBe (sliceImportSection simpleFile) (moduleSkeleton [preludeImport])
it "allows multiline import statements" $
shouldBe
(sliceImportSection (withImports [ "import Data.Array (head,"
, " cons)"
]))
(moduleSkeleton [preludeImport, arrayImport])
describe "pretty printing imports" $ do
it "pretty prints a simple import" $
shouldBe (prettyPrintImport' preludeImport) "import Prelude"
it "pretty prints an explicit import" $
shouldBe (prettyPrintImport' arrayImport) "import Data.Array (head, cons)"
it "pretty prints a qualified import" $
shouldBe (prettyPrintImport' listImport) "import Data.List as List"
it "pretty prints a qualified explicit import" $
shouldBe (prettyPrintImport' consoleImport) "import Control.Monad.Eff.Console (log) as Console"
it "pretty prints an import with a datatype (and PositionedRef's for the dtors)" $
shouldBe (prettyPrintImport' maybeImport) "import Data.Maybe (Maybe(Just))"
describe "import commands" $ do
let simpleFileImports = let (_, _, i, _) = splitSimpleFile in i
addValueImport i mn is =
prettyPrintImportSection (addExplicitImport' (IdeDeclValue (IdeValue (P.Ident i) wildcard)) mn is)
addOpImport op mn is =
prettyPrintImportSection (addExplicitImport' (IdeDeclValueOperator (IdeValueOperator op (P.Qualified Nothing (Left (P.Ident ""))) 2 P.Infix Nothing)) mn is)
addDtorImport i t mn is =
prettyPrintImportSection (addExplicitImport' (IdeDeclDataConstructor (IdeDataConstructor (P.ProperName i) t wildcard)) mn is)
addTypeImport i mn is =
prettyPrintImportSection (addExplicitImport' (IdeDeclType (IdeType (P.ProperName i) P.Star)) mn is)
it "adds an implicit unqualified import" $
shouldBe
(addImplicitImport' simpleFileImports (P.moduleNameFromString "Data.Map"))
[ "import Prelude"
, "import Data.Map"
]
it "adds an explicit unqualified import" $
shouldBe
(addValueImport "head" (P.moduleNameFromString "Data.Array") simpleFileImports)
[ "import Prelude"
, "import Data.Array (head)"
]
it "doesn't add an import if the containing module is imported implicitly" $
shouldBe
(addValueImport "const" (P.moduleNameFromString "Prelude") simpleFileImports)
["import Prelude"]
let Right (_, _, explicitImports, _) = sliceImportSection (withImports ["import Data.Array (tail)"])
it "adds an identifier to an explicit import list" $
shouldBe
(addValueImport "head" (P.moduleNameFromString "Data.Array") explicitImports)
[ "import Prelude"
, "import Data.Array (head, tail)"
]
it "adds an operator to an explicit import list" $
shouldBe
(addOpImport (P.OpName "<~>") (P.moduleNameFromString "Data.Array") explicitImports)
[ "import Prelude"
, "import Data.Array (tail, (<~>))"
]
it "adds a type with constructors without automatically adding an open import of said constructors " $
shouldBe
(addTypeImport "Maybe" (P.moduleNameFromString "Data.Maybe") simpleFileImports)
[ "import Prelude"
, "import Data.Maybe (Maybe)"
]
it "adds the type for a given DataConstructor" $
shouldBe
(addDtorImport "Just" (P.ProperName "Maybe") (P.moduleNameFromString "Data.Maybe") simpleFileImports)
[ "import Prelude"
, "import Data.Maybe (Maybe(..))"
]
it "adds a dataconstructor to an existing type import" $ do
let Right (_, _, typeImports, _) = sliceImportSection (withImports ["import Data.Maybe (Maybe)"])
shouldBe
(addDtorImport "Just" (P.ProperName "Maybe") (P.moduleNameFromString "Data.Maybe") typeImports)
[ "import Prelude"
, "import Data.Maybe (Maybe(..))"
]
it "doesn't add a dataconstructor to an existing type import with open dtors" $ do
let Right (_, _, typeImports, _) = sliceImportSection (withImports ["import Data.Maybe (Maybe(..))"])
shouldBe
(addDtorImport "Just" (P.ProperName "Maybe") (P.moduleNameFromString "Data.Maybe") typeImports)
[ "import Prelude"
, "import Data.Maybe (Maybe(..))"
]
it "doesn't add an identifier to an explicit import list if it's already imported" $
shouldBe
(addValueImport "tail" (P.moduleNameFromString "Data.Array") explicitImports)
[ "import Prelude"
, "import Data.Array (tail)"
]
describe "explicit import sorting" $ do
-- given some basic import skeleton
let Right (_, _, baseImports, _) = sliceImportSection $ withImports ["import Control.Monad (ap)"]
moduleName = (P.moduleNameFromString "Control.Monad")
addImport imports import' = addExplicitImport' import' moduleName imports
valueImport ident = (IdeDeclValue (IdeValue (P.Ident ident) wildcard))
typeImport name = (IdeDeclType (IdeType (P.ProperName name) P.Star))
classImport name = (IdeDeclTypeClass (P.ProperName name))
dtorImport name typeName = (IdeDeclDataConstructor (IdeDataConstructor (P.ProperName name) (P.ProperName typeName) wildcard))
-- expect any list of provided identifiers, when imported, to come out as specified
expectSorted imports expected = shouldBe
(ordNub $ map
(prettyPrintImportSection . foldl addImport baseImports)
(permutations imports))
[expected]
it "sorts class" $
expectSorted (map classImport ["Applicative", "Bind"])
["import Prelude", "import Control.Monad (class Applicative, class Bind, ap)"]
it "sorts value" $
expectSorted (map valueImport ["unless", "where"])
["import Prelude", "import Control.Monad (ap, unless, where)"]
it "sorts type, value" $
expectSorted
((map valueImport ["unless", "where"]) ++ (map typeImport ["Foo", "Bar"]))
["import Prelude", "import Control.Monad (Bar, Foo, ap, unless, where)"]
it "sorts class, type, value" $
expectSorted
((map valueImport ["unless", "where"]) ++ (map typeImport ["Foo", "Bar"]) ++ (map classImport ["Applicative", "Bind"]))
["import Prelude", "import Control.Monad (class Applicative, class Bind, Bar, Foo, ap, unless, where)"]
it "sorts types with constructors, using open imports for the constructors" $
expectSorted
-- the imported names don't actually have to exist!
(map (uncurry dtorImport) [("Just", "Maybe"), ("Nothing", "Maybe"), ("SomeOtherConstructor", "SomeDataType")])
["import Prelude", "import Control.Monad (Maybe(..), SomeDataType(..), ap)"]