nirum-0.2.0: test/Nirum/PackageSpec.hs
{-# LANGUAGE OverloadedLists #-}
module Nirum.PackageSpec where
import Data.Either (isRight)
import qualified Data.Map.Strict as M
import System.FilePath ((</>))
import Test.Hspec.Meta
import Nirum.Constructs.Annotation (empty)
import Nirum.Constructs.Module (Module(Module), coreModulePath)
import Nirum.Constructs.ModulePath (ModulePath)
import Nirum.Constructs.TypeDeclaration ( JsonType(String)
, PrimitiveTypeIdentifier(Text)
, Type(Alias, PrimitiveType)
, TypeDeclaration ( Import
, TypeDeclaration
)
)
import Nirum.Package ( BoundModule(boundPackage, modulePath)
, ImportError ( CircularImportError
, MissingImportError
, MissingModulePathError
)
, Package
, PackageError (ImportError)
, TypeLookup(Imported, Local, Missing)
, docs
, lookupType
, makePackage
, resolveBoundModule
, resolveModule
, scanModules
, scanPackage
, types
)
import Nirum.Parser (parseFile)
createPackage :: M.Map ModulePath Module -> Package
createPackage modules' =
case makePackage modules' of
Right pkg -> pkg
Left e -> error $ "errored: " ++ show e
validPackage :: Package
validPackage =
createPackage [ (["foo", "bar"], Module [] $ Just "foo.bar")
, (["foo", "baz"], Module [] $ Just "foo.baz")
, (["foo"], Module [] $ Just "foo")
, (["qux"], Module [] $ Just "qux")
, ( ["abc"]
, Module [TypeDeclaration "a" (Alias "text") empty]
Nothing
)
, ( ["xyz"]
, Module [ Import ["abc"] "a" empty
, TypeDeclaration "x" (Alias "text") empty
] Nothing
)
]
missingImportsModules :: M.Map ModulePath Module
missingImportsModules =
[ ( ["foo"]
, Module [ Import ["foo", "bar"] "xyz" empty -- MissingModulePathError
, Import ["foo", "bar"] "zzz" empty -- MissingModulePathError
, Import ["baz"] "qux" empty
] Nothing
)
, ( ["baz"]
, Module [ TypeDeclaration "qux" (Alias "text") empty ] Nothing
)
, (["qux"], Module [ Import ["foo"] "abc" empty -- MissingImportError
, Import ["foo"] "def" empty -- MissingImportError
] Nothing)
]
circularImportsModules :: M.Map ModulePath Module
circularImportsModules =
[ (["asdf"], Module [ Import ["asdf"] "foo" empty
, TypeDeclaration "bar" (Alias "text") empty
] Nothing)
, (["abc", "def"], Module [ Import ["abc", "ghi"] "bar" empty
, TypeDeclaration
"foo" (Alias "text") empty
] Nothing)
, (["abc", "ghi"], Module [ Import ["abc", "xyz"] "baz" empty
, TypeDeclaration
"bar" (Alias "text") empty
] Nothing)
, (["abc", "xyz"], Module [ Import ["abc", "def"] "foo" empty
, TypeDeclaration
"baz" (Alias "text") empty
] Nothing)
]
spec :: Spec
spec = do
describe "Package" $ do
specify "resolveModule" $ do
resolveModule ["foo"] validPackage `shouldBe`
Just (Module [] $ Just "foo")
resolveModule ["foo", "bar"] validPackage `shouldBe`
Just (Module [] $ Just "foo.bar")
resolveModule ["qux"] validPackage `shouldBe`
Just (Module [] $ Just "qux")
resolveModule ["baz"] validPackage `shouldBe` Nothing
specify "resolveBoundModule" $ do
let Just bm = resolveBoundModule ["foo"] validPackage
boundPackage bm `shouldBe` validPackage
modulePath bm `shouldBe` ["foo"]
resolveBoundModule ["baz"] validPackage `shouldBe` Nothing
specify "detectMissingImports" $
makePackage missingImportsModules `shouldBe`
Left [ MissingModulePathError ["foo"] ["foo", "bar"]
, MissingImportError ["qux"] ["foo"] "abc"
, MissingImportError ["qux"] ["foo"] "def"
]
specify "detectCircularImports" $
makePackage circularImportsModules `shouldBe`
Left [ CircularImportError [["asdf"], ["asdf"]]
, MissingImportError ["asdf"] ["asdf"] "foo"
, CircularImportError [ ["abc", "def"]
, ["abc", "ghi"]
, ["abc", "xyz"]
, ["abc", "def"]
]
, CircularImportError [ ["abc", "ghi"]
, ["abc", "xyz"]
, ["abc", "def"]
, ["abc", "ghi"]
]
, CircularImportError [ ["abc", "xyz"]
, ["abc", "def"]
, ["abc", "ghi"]
, ["abc", "xyz"]
]
]
specify "scanPackage" $ do
let path = "." </> "examples"
package' <- scanPackage path
package' `shouldSatisfy` isRight
let Right package = package'
Right builtinsM <- parseFile (path </> "builtins.nrm")
Right productM <- parseFile (path </> "product.nrm")
Right shapesM <- parseFile (path </> "shapes.nrm")
Right countriesM <- parseFile (path </> "countries.nrm")
Right addressM <- parseFile (path </> "address.nrm")
Right pdfServiceM <- parseFile (path </> "pdf-service.nrm")
let modules = [ (["builtins"], builtinsM)
, (["product"], productM)
, (["shapes"], shapesM)
, (["countries"], countriesM)
, (["address"], addressM)
, (["pdf-service"], pdfServiceM)
] :: M.Map ModulePath Module
package `shouldBe` createPackage modules
Left error' <- scanPackage $ "." </> "test" </> "import_error"
error' `shouldBe`
ImportError [MissingModulePathError ["import_error"] ["foo"]]
specify "scanModules" $ do
let path = "." </> "examples"
mods <- scanModules "."
mods `shouldBe`
[ (["examples", "builtins"], path </> "builtins.nrm")
, (["examples", "product"], path </> "product.nrm")
, (["examples", "shapes"], path </> "shapes.nrm")
, (["examples", "countries"], path </> "countries.nrm")
, (["examples", "address"], path </> "address.nrm")
, (["examples", "pdf-service"], path </> "pdf-service.nrm")
, ( ["test", "import_error", "import_error"]
, "." </> "test" </> "import_error" </> "import_error.nrm"
)
]
mods' <- scanModules path
mods' `shouldBe` [ (["builtins"], path </> "builtins.nrm")
, (["product"], path </> "product.nrm")
, (["shapes"], path </> "shapes.nrm")
, (["countries"], path </> "countries.nrm")
, (["address"], path </> "address.nrm")
, (["pdf-service"], path </> "pdf-service.nrm")
]
describe "BoundModule" $ do
let Just bm = resolveBoundModule ["foo", "bar"] validPackage
Just abc = resolveBoundModule ["abc"] validPackage
Just xyz = resolveBoundModule ["xyz"] validPackage
specify "docs" $ do
docs bm `shouldBe` Just "foo.bar"
let Just bm' = resolveBoundModule ["foo"] validPackage
docs bm' `shouldBe` Just "foo"
specify "types" $ do
types bm `shouldBe` []
types abc `shouldBe` [TypeDeclaration "a" (Alias "text") empty]
types xyz `shouldBe` [ Import ["abc"] "a" empty
, TypeDeclaration "x" (Alias "text") empty
]
specify "lookupType" $ do
lookupType "a" bm `shouldBe` Missing
lookupType "a" abc `shouldBe` Local (Alias "text")
lookupType "a" xyz `shouldBe` Imported ["abc"] (Alias "text")
lookupType "x" bm `shouldBe` Missing
lookupType "x" abc `shouldBe` Missing
lookupType "x" xyz `shouldBe` Local (Alias "text")
lookupType "text" bm `shouldBe`
Imported coreModulePath (PrimitiveType Text String)
lookupType "text" abc `shouldBe` lookupType "text" bm
lookupType "text" xyz `shouldBe` lookupType "text" bm