fix-imports-2.4.0: src/FixImports/Parse_test.hs
{-# LANGUAGE DisambiguateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
module FixImports.Parse_test where
import qualified Data.Maybe as Maybe
import Data.Maybe (fromMaybe)
import qualified Data.Set as Set
import qualified System.IO.Unsafe as Unsafe
import qualified GHC.Hs as Hs
import qualified GHC.Types.SrcLoc as SrcLoc
import qualified FixImports.Parse as Parse
import qualified FixImports.Types as Types
import EL.Test.Global
test_importRange = do
let f = fmap Parse.importRange . parse
rightEqual (f "") (0, 0)
rightEqual (f "module M where\n") (1, 1)
rightEqual (f "-- hi\nmodule M where\n") (2, 2)
rightEqual (f
"module M (\n\
\ x, y\n\
\) where\n\
\import A\n\
\import B\n\
\f = 42\n")
(3, 5)
rightEqual (f
"module M (\n\
\ x, y\n\
\) where\n\
\f = 42\n")
(3, 3)
rightEqual (f
"module M where\n\
\f = 42\n")
(1, 1)
test_extractImports = do
let f = fmap (head . map strip . Parse.extractImports) . parse
strip imp = imp { Types._importSpan = Types.noSpan }
rightEqual (f "import \"pkg\" A ()") $ (Types.makeImport "A")
{ Types._importPkgQualifier = Just "pkg"
, Types._importEntities = Just []
}
rightEqual (f "import {-# SOURCE #-} A") $ (Types.makeImport "A")
{ Types._importIsBoot = True }
rightEqual (f "import A as B hiding (a, b)") $ (Types.makeImport "A")
{ Types._importAs = Just "B"
, Types._importHiding = True
, Types._importEntities = Just
[ Right $ Types.Entity Nothing (Types.Name "a") Nothing
, Right $ Types.Entity Nothing (Types.Name "b") Nothing
]
}
test_extensions = do
let f exts = Parse.parse (map (expectRight . parseExtension) exts) "M.hs"
let extract = fmap (fmap (extractEntities . fst))
apply1 leftLike (extract $ f [] "import X (pattern A)") "parse error"
apply1 rightEqual (extract $ f ["PatternSynonyms"] "import X (pattern A)")
[Right ("pattern", Types.Name "A", "")]
apply1 rightEqual
(extract $ f []
"{-# LANGUAGE PatternSynonyms #-}\nimport X (pattern A)")
[Right ("pattern", Types.Name "A", "")]
parseExtension :: String -> Either String Types.Extension
parseExtension w = maybe (Left w) Right $ Types.parseExtension w
test_comments = do
let f = fmap (fmap (map extract . snd)) . Parse.parse [] "M.hs"
extract (Parse.Comment (Types.SrcSpan x1 y1 x2 y2) cmt) =
((x1, y1, x2, y2), cmt)
apply1 rightEqual (f "module M where\n") []
apply1 rightEqual (f "-- above\nimport X -- right\n")
[((0, 1, 0, 9), "-- above"), ((1, 10, 1, 18), "-- right")]
apply1 rightEqual (f "-- | above\nimport X {- right -}\n")
[((0, 1, 0, 11), "-- | above"), ((1, 10, 1, 21), "{- right -}")]
apply1 rightEqual (f "-- *** section\nimport X {- ^ right -}\n")
[((0, 1, 0, 15), "-- *** section"), ((1, 10, 1, 23), "{- ^ right -}")]
test_extractEntity = do
let f = fmap extractEntities . parse
extractEntities = map (fmap extractEntity) . fromMaybe []
. Types._importEntities . head . Parse.extractImports
extractEntity (Types.Entity qual name list) =
(fromMaybe "" qual, name, fromMaybe "" list)
let n = Types.Name
rightEqual (f "import X") []
rightEqual (f "import X (a, b)")
[Right ("", n "a", ""), Right ("", n "b", "")]
rightEqual (f "import X (type A)") [Right ("type", n "A", "")]
rightEqual (f "import X (A)") [Right ("", n "A", "")]
rightEqual (f "import X (A(..))") [Right ("", n "A", "(..)")]
rightEqual (f "import X (A())") [Right ("", n "A", "()")]
rightEqual (f "import X (A(b, c))") [Right ("", n "A", "(b, c)")]
rightEqual (f "import X (A(B))") [Right ("", n "A", "(B)")]
rightEqual (f "import X ((*))") [Right ("", Types.Operator "*", "")]
extractEntities = map (fmap extractEntity) . fromMaybe []
. Types._importEntities . head . Parse.extractImports
where
extractEntity (Types.Entity qual name list) =
(fromMaybe "" qual, name, fromMaybe "" list)
test_qualifications = do
let f = fmap (Set.toList . Parse.qualifications) . parse
rightEqual (f "f = x") []
rightEqual (f "f = A.x") ["A"]
rightEqual (f "f = A.B.x D.y") ["A.B", "D"]
rightEqual (f "f :: A.X -> B.Y") ["A", "B"]
rightEqual (f "f = x A.</> y") ["A"]
rightEqual (f "f = (A.</>) x y") ["A"]
rightEqual (f "f = g @A.B @C.D") ["A", "C"]
test_unqualifiedValues = do
let f = fmap (map unname . Set.toList . Parse.unqualifiedValues) . parse
unname (Types.Name s) = s
unname (Types.Operator s) = "(" <> s <> ")"
-- Don't pick up imports and exports.
rightEqual (f "module A (b) where\nimport C (d)\n") []
-- Don't pick up function lhs.
rightEqual (f "f x = 10") []
rightEqual (f "f x = y") ["y"]
rightEqual (f "x = y") ["y"]
-- TODO I'd rather just "pat", but I'd need to dig deeper into
-- the pattern AST which is complicated.
rightEqual (f "f | x <- pat = 10") ["pat", "x"]
rightEqual (f "f = 10 * 20") ["(*)"]
-- instance declarations
rightEqual (f "instance A B where f = x") ["x"]
test_unqualifiedTypes = do
let f = fmap (map unname . Set.toList . Parse.unqualifiedTypes) . parse
unname (Types.Name s) = s
unname (Types.Operator s) = "(" <> s <> ")"
-- Also look in type signatures.
rightEqual (f "f :: A -> B C") ["A", "B", "C"]
rightEqual (f "instance A b where f = x") ["A"]
rightEqual (f "instance A b where f = x") ["A"]
-- But not type declarations.
rightEqual (f "data A = B c | D e deriving (Z)") ["Z"]
rightEqual (f "class A where f :: A") ["A"]
apply1 :: Monad m => (a -> b -> m c) -> m a -> b -> m c
apply1 f ma b = do
a <- ma
f a b
parse :: String -> Either String Parse.Module
parse = Unsafe.unsafePerformIO . fmap (fmap fst) . Parse.parse [] "M.hs"