fix-imports-2.1.0: src/Config_test.hs
{-# LANGUAGE DisambiguateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
module Config_test where
import qualified Data.Map as Map
import qualified Data.Text as Text
import EL.Test.Global
import qualified EL.Test.Testing as Testing
import qualified Language.Haskell.Exts as Haskell
import qualified Config
import qualified FixImports
import qualified Types
test_parse = do
let f = check . Config.parse . Text.unlines
check (config, errs)
| null errs = Right config
| otherwise = Left $ Text.unlines errs
equal (f []) $ Right Config.empty
leftLike (f ["include: a", "include: b"]) "duplicate fields"
equal (Config._order <$>
f ["import-order-first: A", "import-order-last: B"]) $
Right $ Config.Order
{ _importOrder = Config.Priority ["A"] ["B"]
, _sortUnqualifiedLast = False
}
test_parseUnqualified = do
let f = Config._unqualified . parseConfig
equal (f ["unqualified: A.B (c); D.E ((+))"]) $ Map.fromList
[ (Haskell.Ident () "c", "A.B")
, (Haskell.Symbol () "+", "D.E")
]
equal (f ["unqualified: A.B(c, d)"]) $ Map.fromList
[ (Haskell.Ident () "c", "A.B")
, (Haskell.Ident () "d", "A.B")
]
equal (f ["unqualified: A.B (c,(+))"]) $ Map.fromList
[ (Haskell.Ident () "c", "A.B")
, (Haskell.Symbol () "+", "A.B")
]
test_parseQualifyAs = do
let f = Config._qualifyAs . parseConfig
equal (f ["qualify-as: A.B as AB, E as F"]) $ Map.fromList
[ ("AB", "A.B")
, ("F", "E")
]
stringsLike (snd $ Config.parse "qualify-as: gibble gabble")
["stanza should look like"]
test_pickModule = do
let f config modulePath candidates = Config.pickModule
(Config._modulePriority (parseConfig config))
modulePath candidates
equal (f [] "X.hs" []) Nothing
let localAB = [(Nothing, "A.M"), (Nothing, "B.M")]
equal (f [] "X.hs" localAB) $
Just (Nothing, "A.M")
equal (f ["prio-module-high: B.M"] "X.hs" localAB) $
Just (Nothing, "B.M")
-- Has to be an exact match.
equal (f ["prio-module-high: B"] "X.hs" localAB) $
Just (Nothing, "A.M")
-- Local modules take precedence.
equal (f [] "A/B.hs" [(Nothing, "B.M"), (Just "pkg", "B.M")]) $
Just (Nothing, "B.M")
equal (f [] "A/B/C.hs" [(Nothing, "A.B.M"), (Just "pkg", "B.M")]) $
Just (Nothing, "A.B.M")
-- Closer local modules precede further ones.
equal (f [] "A/B/C.hs" [(Nothing, "A.B.M"), (Nothing, "A.M")]) $
Just (Nothing, "A.B.M")
-- Prefer fewer dots.
equal (f [] "X.hs" [(Just "p1", "A.B.M"), (Just "p2", "Z.M")]) $
Just (Just "p2", "Z.M")
test_formatGroups = do
let f config imports = lines $ Config.formatGroups Config.defaultFormat
(Config._order (parseConfig config))
(Testing.expectRight (parse (unlines imports)))
equal (f [] []) []
-- Unqualified import-all goes last.
equal (f ["sort-unqualified-last: t"]
[ "import Z", "import A"
, "import qualified C", "import qualified B"
, "import C (a)"
])
[ "import qualified B"
, "import qualified C"
, "import C (a)"
, ""
, "import A"
, "import Z"
]
equal (f [] ["import qualified Z", "import qualified A"])
[ "import qualified A"
, "import qualified Z"
]
equal (f ["import-order-first: Z"]
["import qualified Z", "import qualified A"])
[ "import qualified Z"
, "import qualified A"
]
equal (f ["import-order-last: A"]
["import qualified Z", "import qualified A"])
[ "import qualified Z"
, "import qualified A"
]
-- Exact match.
equal (f ["import-order-first: Z"]
["import qualified Z.A", "import qualified A"])
[ "import qualified A"
, "import qualified Z.A"
]
-- Unless it's a prefix match.
equal (f ["import-order-first: Z."]
["import qualified Z.A", "import qualified A"])
[ "import qualified Z.A"
, "import qualified A"
]
test_showImportLine = do
let f = fmap (Config.showImportDecl style . Types.importDecl . head)
. parse
style = Config.defaultFormat
{ Config._ppConfig = Just $ Config.PPConfig
{ _leaveSpaceForQualified = True }
}
-- pprint $ fmap (Types.importDecl . head) . parse $ "import A.B as C (x)"
equal (f "import A.B as C (x)") $ Right "import A.B as C (x)"
-- * util
importLine :: Types.ImportDecl -> Types.ImportLine
importLine decl = Types.ImportLine
{ importDecl = decl
, importComments = []
, importSource = Types.Local
}
parse :: String -> Either String [Types.ImportLine]
parse source = case FixImports.parse [] "" source of
Haskell.ParseFailed srcloc err ->
Left $ Haskell.prettyPrint srcloc ++ ": " ++ err
Haskell.ParseOk (mod, _cmts) ->
Right $ map importLine $ FixImports.moduleImportDecls mod
parseConfig :: [Text.Text] -> Config.Config
parseConfig lines
| null errs = config
| otherwise = error $ "parsing " <> show lines <> ": "
<> Text.unpack (Text.unlines errs)
where (config, errs) = Config.parse (Text.unlines lines)