mirror of
https://github.com/anoma/juvix.git
synced 2024-11-30 14:13:27 +03:00
Use JuvixError instead of Text for errors in Package file loading (#2459)
Depends on: * https://github.com/anoma/juvix/pull/2458 This PR is part of a series implementing: * https://github.com/anoma/juvix/issues/2336 In attempt to make the main PR: * https://github.com/anoma/juvix/pull/2434 easier to review. This PR introduces standard JuvixError handling for errors related to the loading of the juvix.yaml file. Before this PR errors were thrown as Text and then communicated to the user using the `error` function.
This commit is contained in:
parent
7b7f06f81a
commit
8e6c1c8f07
@ -147,7 +147,7 @@ loadDefaultPrelude = whenJustM defaultPreludeEntryPoint $ \e -> do
|
||||
. runM
|
||||
. evalInternet hasInternet
|
||||
. runFilesIO
|
||||
. runError @Text
|
||||
. runError @JuvixError
|
||||
. runReader e
|
||||
. runLogIO
|
||||
. runProcessIO
|
||||
|
@ -30,7 +30,7 @@ import Juvix.Prelude
|
||||
|
||||
mkPackage ::
|
||||
forall r.
|
||||
(Members '[Files, Error Text, Reader ResolverEnv, GitClone] r) =>
|
||||
(Members '[Files, Error JuvixError, Reader ResolverEnv, GitClone] r) =>
|
||||
Maybe EntryPoint ->
|
||||
Path Abs Dir ->
|
||||
Sem r Package
|
||||
@ -43,7 +43,7 @@ mkPackage mpackageEntry _packageRoot = do
|
||||
|
||||
mkPackageInfo ::
|
||||
forall r.
|
||||
(Members '[Files, Error Text, Reader ResolverEnv, Error DependencyError, GitClone] r) =>
|
||||
(Members '[Files, Error JuvixError, Reader ResolverEnv, Error DependencyError, GitClone] r) =>
|
||||
Maybe EntryPoint ->
|
||||
Path Abs Dir ->
|
||||
Package ->
|
||||
@ -162,7 +162,7 @@ resolveDependency i = case i ^. packageDepdendencyInfoDependency of
|
||||
|
||||
registerDependencies' ::
|
||||
forall r.
|
||||
(Members '[Reader EntryPoint, State ResolverState, Reader ResolverEnv, Files, Error Text, Error DependencyError, GitClone] r) =>
|
||||
(Members '[Reader EntryPoint, State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone] r) =>
|
||||
DependenciesConfig ->
|
||||
Sem r ()
|
||||
registerDependencies' conf = do
|
||||
@ -186,7 +186,7 @@ registerDependencies' conf = do
|
||||
|
||||
addRootDependency ::
|
||||
forall r.
|
||||
(Members '[State ResolverState, Reader ResolverEnv, Files, Error Text, Error DependencyError, GitClone] r) =>
|
||||
(Members '[State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone] r) =>
|
||||
DependenciesConfig ->
|
||||
EntryPoint ->
|
||||
Path Abs Dir ->
|
||||
@ -207,7 +207,7 @@ addRootDependency conf e root = do
|
||||
|
||||
addDependency ::
|
||||
forall r.
|
||||
(Members '[State ResolverState, Reader ResolverEnv, Files, Error Text, Error DependencyError, GitClone] r) =>
|
||||
(Members '[State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone] r) =>
|
||||
Maybe EntryPoint ->
|
||||
PackageDependencyInfo ->
|
||||
Sem r LockfileDependency
|
||||
@ -224,7 +224,7 @@ addDependency me d = do
|
||||
|
||||
addDependency' ::
|
||||
forall r.
|
||||
(Members '[State ResolverState, Reader ResolverEnv, Files, Error Text, Error DependencyError, GitClone] r) =>
|
||||
(Members '[State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone] r) =>
|
||||
Package ->
|
||||
Maybe EntryPoint ->
|
||||
ResolvedDependency ->
|
||||
@ -319,7 +319,7 @@ expectedPath' actualPath m = do
|
||||
|
||||
re ::
|
||||
forall r a.
|
||||
(Members '[Reader EntryPoint, Files, Error Text, Error DependencyError, GitClone] r) =>
|
||||
(Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone] r) =>
|
||||
Sem (PathResolver ': r) a ->
|
||||
Sem (Reader ResolverEnv ': State ResolverState ': r) a
|
||||
re = reinterpret2H helper
|
||||
@ -342,13 +342,13 @@ re = reinterpret2H helper
|
||||
Right (r, _) -> r
|
||||
raise (evalPathResolver' st' root' (a' x'))
|
||||
|
||||
evalPathResolver' :: (Members '[Reader EntryPoint, Files, Error Text, Error DependencyError, GitClone] r) => ResolverState -> Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r a
|
||||
evalPathResolver' :: (Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone] r) => ResolverState -> Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r a
|
||||
evalPathResolver' st root = fmap snd . runPathResolver' st root
|
||||
|
||||
runPathResolver :: (Members '[Reader EntryPoint, Files, Error Text, Error DependencyError, GitClone] r) => Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
|
||||
runPathResolver :: (Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone] r) => Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
|
||||
runPathResolver = runPathResolver' iniResolverState
|
||||
|
||||
runPathResolver' :: (Members '[Reader EntryPoint, Files, Error Text, Error DependencyError, GitClone] r) => ResolverState -> Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
|
||||
runPathResolver' :: (Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone] r) => ResolverState -> Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
|
||||
runPathResolver' st root x = do
|
||||
e <- ask
|
||||
let _envSingleFile :: Maybe (Path Abs File)
|
||||
@ -364,15 +364,15 @@ runPathResolver' st root x = do
|
||||
}
|
||||
runState st (runReader env (re x))
|
||||
|
||||
runPathResolverPipe' :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone] r) => ResolverState -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
|
||||
runPathResolverPipe' :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone, Error JuvixError] r) => ResolverState -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
|
||||
runPathResolverPipe' iniState a = do
|
||||
r <- asks (^. entryPointResolverRoot)
|
||||
runError (runPathResolver' iniState r (raiseUnder a)) >>= either error return
|
||||
runPathResolver' iniState r a
|
||||
|
||||
runPathResolverPipe :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone] r) => Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
|
||||
runPathResolverPipe :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone, Error JuvixError] r) => Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
|
||||
runPathResolverPipe a = do
|
||||
r <- asks (^. entryPointResolverRoot)
|
||||
runError (runPathResolver r (raiseUnder a)) >>= either error return
|
||||
runPathResolver r a
|
||||
|
||||
evalPathResolverPipe :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone] r) => Sem (PathResolver ': r) a -> Sem r a
|
||||
evalPathResolverPipe :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone, Error JuvixError] r) => Sem (PathResolver ': r) a -> Sem r a
|
||||
evalPathResolverPipe = fmap snd . runPathResolverPipe
|
||||
|
@ -6,5 +6,5 @@ import Juvix.Compiler.Pipeline.EntryPoint
|
||||
import Juvix.Data.Effect.Git
|
||||
import Juvix.Prelude
|
||||
|
||||
runPathResolverArtifacts :: (Members '[Files, Reader EntryPoint, State Artifacts, Error DependencyError, GitClone] r) => Sem (PathResolver ': r) a -> Sem r a
|
||||
runPathResolverArtifacts :: (Members '[Files, Reader EntryPoint, State Artifacts, Error DependencyError, GitClone, Error JuvixError] r) => Sem (PathResolver ': r) a -> Sem r a
|
||||
runPathResolverArtifacts = runStateLikeArtifacts runPathResolverPipe' artifactResolver
|
||||
|
@ -10,6 +10,7 @@ import Data.String.Interpolate (i)
|
||||
import Data.Yaml
|
||||
import Data.Yaml.Pretty
|
||||
import Juvix.Compiler.Pipeline.Package.Dependency
|
||||
import Juvix.Compiler.Pipeline.Package.Loader.Error
|
||||
import Juvix.Extra.Paths
|
||||
import Juvix.Extra.Strings qualified as Str
|
||||
import Juvix.Extra.Version
|
||||
@ -84,21 +85,33 @@ mkPackageLockfilePath = (<//> juvixLockfile)
|
||||
|
||||
mayReadLockfile ::
|
||||
forall r.
|
||||
(Members '[Files, Error Text] r) =>
|
||||
(Members '[Files, Error PackageLoaderError] r) =>
|
||||
Path Abs Dir ->
|
||||
Sem r (Maybe LockfileInfo)
|
||||
mayReadLockfile root = do
|
||||
let lockfilePath = mkPackageLockfilePath root
|
||||
lockfileExists <- fileExists' lockfilePath
|
||||
if
|
||||
| lockfileExists -> do
|
||||
bs <- readFileBS' lockfilePath
|
||||
either (throw . pack . prettyPrintParseException) ((return . Just) . mkLockfileInfo lockfilePath) (decodeEither' @Lockfile bs)
|
||||
either (throwErr . pack . prettyPrintParseException) ((return . Just) . mkLockfileInfo lockfilePath) (decodeEither' @Lockfile bs)
|
||||
| otherwise -> return Nothing
|
||||
where
|
||||
mkLockfileInfo :: Path Abs File -> Lockfile -> LockfileInfo
|
||||
mkLockfileInfo _lockfileInfoPath _lockfileInfoLockfile = LockfileInfo {..}
|
||||
|
||||
lockfilePath :: Path Abs File
|
||||
lockfilePath = mkPackageLockfilePath root
|
||||
|
||||
throwErr :: Text -> Sem r a
|
||||
throwErr e =
|
||||
throw
|
||||
PackageLoaderError
|
||||
{ _packageLoaderErrorPath = lockfilePath,
|
||||
_packageLoaderErrorCause =
|
||||
ErrLockfileYamlParseError
|
||||
LockfileYamlParseError {_lockfileYamlParseErrorError = e}
|
||||
}
|
||||
|
||||
lockfileEncodeConfig :: Config
|
||||
lockfileEncodeConfig = setConfCompare keyCompare defConfig
|
||||
where
|
||||
|
@ -13,10 +13,11 @@ import Data.Versions
|
||||
import Data.Yaml
|
||||
import Juvix.Compiler.Pipeline.Lockfile
|
||||
import Juvix.Compiler.Pipeline.Package.Base
|
||||
import Juvix.Compiler.Pipeline.Package.Loader.Error
|
||||
import Juvix.Extra.Paths
|
||||
import Juvix.Prelude
|
||||
|
||||
processPackage :: forall r. (Members '[Error Text] r) => Path Abs File -> BuildDir -> Maybe LockfileInfo -> RawPackage -> Sem r Package
|
||||
processPackage :: forall r. (Members '[Error PackageLoaderError] r) => Path Abs File -> BuildDir -> Maybe LockfileInfo -> RawPackage -> Sem r Package
|
||||
processPackage _packageFile buildDir lockfile pkg = do
|
||||
let _packageName = fromMaybe defaultPackageName (pkg ^. packageName)
|
||||
_packageDependencies = resolveDependencies
|
||||
@ -35,7 +36,14 @@ processPackage _packageFile buildDir lockfile pkg = do
|
||||
Nothing -> return defaultVersion
|
||||
Just ver -> case semver ver of
|
||||
Right v -> return v
|
||||
Left err -> throw (pack (errorBundlePretty err))
|
||||
Left err ->
|
||||
throw
|
||||
PackageLoaderError
|
||||
{ _packageLoaderErrorCause =
|
||||
ErrVersionParseError
|
||||
VersionParseError {_versionParseErrorError = (pack (errorBundlePretty err))},
|
||||
_packageLoaderErrorPath = _packageFile
|
||||
}
|
||||
|
||||
checkNoDuplicateDepNames :: [Dependency] -> Sem r ()
|
||||
checkNoDuplicateDepNames deps = go HashSet.empty (deps ^.. traversed . _GitDependency . gitDependencyName)
|
||||
@ -43,15 +51,17 @@ processPackage _packageFile buildDir lockfile pkg = do
|
||||
go :: HashSet Text -> [Text] -> Sem r ()
|
||||
go _ [] = return ()
|
||||
go s (x : xs)
|
||||
| x `HashSet.member` s = throw (errMsg x)
|
||||
| x `HashSet.member` s =
|
||||
throw
|
||||
PackageLoaderError
|
||||
{ _packageLoaderErrorPath = _packageFile,
|
||||
_packageLoaderErrorCause =
|
||||
ErrDuplicateDependencyError
|
||||
DuplicateDependencyError
|
||||
{ _duplicateDependencyErrorName = x
|
||||
}
|
||||
}
|
||||
| otherwise = go (HashSet.insert x s) xs
|
||||
where
|
||||
errMsg :: Text -> Text
|
||||
errMsg dupName =
|
||||
"Juvix package file at: "
|
||||
<> pack (toFilePath _packageFile)
|
||||
<> " contains the duplicate dependency name: "
|
||||
<> dupName
|
||||
|
||||
resolveDependencies :: [Dependency]
|
||||
resolveDependencies = fromMaybe [stdlib] (pkg ^. packageDependencies)
|
||||
@ -62,36 +72,37 @@ processPackage _packageFile buildDir lockfile pkg = do
|
||||
-- | Given some directory d it tries to read the file d/juvix.yaml and parse its contents
|
||||
readPackage ::
|
||||
forall r.
|
||||
(Members '[Files, Error Text] r) =>
|
||||
(Members '[Files, Error JuvixError] r) =>
|
||||
Path Abs Dir ->
|
||||
BuildDir ->
|
||||
Sem r Package
|
||||
readPackage root buildDir = do
|
||||
readPackage root buildDir = mapError (JuvixError @PackageLoaderError) $ do
|
||||
bs <- readFileBS' yamlPath
|
||||
mLockfile <- mayReadLockfile root
|
||||
if
|
||||
| ByteString.null bs -> return (emptyPackage buildDir yamlPath)
|
||||
| otherwise -> either (throw . pack . prettyPrintParseException) (processPackage yamlPath buildDir mLockfile) (decodeEither' bs)
|
||||
| otherwise -> either (throwErr . pack . prettyPrintParseException) (processPackage yamlPath buildDir mLockfile) (decodeEither' bs)
|
||||
where
|
||||
yamlPath = mkPackageFilePath root
|
||||
|
||||
throwErr e =
|
||||
throw
|
||||
PackageLoaderError
|
||||
{ _packageLoaderErrorPath = yamlPath,
|
||||
_packageLoaderErrorCause =
|
||||
ErrPackageYamlParseError
|
||||
PackageYamlParseError
|
||||
{ _packageYamlParseErrorError = e
|
||||
}
|
||||
}
|
||||
|
||||
readPackageIO :: Path Abs Dir -> BuildDir -> IO Package
|
||||
readPackageIO root buildDir = do
|
||||
let x :: Sem '[Error Text, Files, Embed IO] Package
|
||||
x = readPackage root buildDir
|
||||
m <- runM $ runFilesIO (runError x)
|
||||
case m of
|
||||
Left err -> putStrLn err >> exitFailure
|
||||
Right r -> return r
|
||||
readPackageIO root buildDir = runM (runFilesIO (runErrorIO' @JuvixError (readPackage root buildDir)))
|
||||
|
||||
readGlobalPackageIO :: IO Package
|
||||
readGlobalPackageIO = do
|
||||
m <- runM . runFilesIO . runError $ readGlobalPackage
|
||||
case m of
|
||||
Left err -> putStrLn err >> exitFailure
|
||||
Right r -> return r
|
||||
readGlobalPackageIO = runM (runFilesIO . runErrorIO' @JuvixError $ readGlobalPackage)
|
||||
|
||||
readGlobalPackage :: (Members '[Error Text, Files] r) => Sem r Package
|
||||
readGlobalPackage :: (Members '[Error JuvixError, Files] r) => Sem r Package
|
||||
readGlobalPackage = do
|
||||
yamlPath <- globalYaml
|
||||
unlessM (fileExists' yamlPath) writeGlobalPackage
|
||||
|
85
src/Juvix/Compiler/Pipeline/Package/Loader/Error.hs
Normal file
85
src/Juvix/Compiler/Pipeline/Package/Loader/Error.hs
Normal file
@ -0,0 +1,85 @@
|
||||
module Juvix.Compiler.Pipeline.Package.Loader.Error where
|
||||
|
||||
import Juvix.Data.CodeAnn
|
||||
import Juvix.Prelude
|
||||
|
||||
data PackageLoaderError = PackageLoaderError
|
||||
{ _packageLoaderErrorPath :: Path Abs File,
|
||||
_packageLoaderErrorCause :: PackageLoaderErrorCause
|
||||
}
|
||||
|
||||
data PackageLoaderErrorCause
|
||||
= ErrPackageYamlParseError PackageYamlParseError
|
||||
| ErrLockfileYamlParseError LockfileYamlParseError
|
||||
| ErrVersionParseError VersionParseError
|
||||
| ErrDuplicateDependencyError DuplicateDependencyError
|
||||
|
||||
newtype PackageYamlParseError = PackageYamlParseError
|
||||
{ _packageYamlParseErrorError :: Text
|
||||
}
|
||||
|
||||
newtype LockfileYamlParseError = LockfileYamlParseError
|
||||
{ _lockfileYamlParseErrorError :: Text
|
||||
}
|
||||
|
||||
newtype VersionParseError = VersionParseError
|
||||
{ _versionParseErrorError :: Text
|
||||
}
|
||||
|
||||
newtype DuplicateDependencyError = DuplicateDependencyError
|
||||
{ _duplicateDependencyErrorName :: Text
|
||||
}
|
||||
|
||||
makeLenses ''PackageLoaderError
|
||||
makeLenses ''PackageYamlParseError
|
||||
makeLenses ''LockfileYamlParseError
|
||||
makeLenses ''VersionParseError
|
||||
makeLenses ''DuplicateDependencyError
|
||||
|
||||
instance ToGenericError PackageLoaderError where
|
||||
genericError e = do
|
||||
let msg = mkAnsiText (ppCodeAnn e)
|
||||
return
|
||||
GenericError
|
||||
{ _genericErrorMessage = msg,
|
||||
_genericErrorLoc = i,
|
||||
_genericErrorIntervals = [i]
|
||||
}
|
||||
where
|
||||
i = getLoc e
|
||||
|
||||
instance PrettyCodeAnn PackageLoaderError where
|
||||
ppCodeAnn e = ppCodeAnn (e ^. packageLoaderErrorCause)
|
||||
|
||||
instance PrettyCodeAnn PackageLoaderErrorCause where
|
||||
ppCodeAnn = \case
|
||||
ErrPackageYamlParseError e -> ppCodeAnn e
|
||||
ErrLockfileYamlParseError e -> ppCodeAnn e
|
||||
ErrVersionParseError e -> ppCodeAnn e
|
||||
ErrDuplicateDependencyError e -> ppCodeAnn e
|
||||
|
||||
instance PrettyCodeAnn PackageYamlParseError where
|
||||
ppCodeAnn e =
|
||||
"The package file is invalid"
|
||||
<> line
|
||||
<+> pretty (e ^. packageYamlParseErrorError)
|
||||
|
||||
instance PrettyCodeAnn LockfileYamlParseError where
|
||||
ppCodeAnn e =
|
||||
"The lock file is invalid"
|
||||
<> line
|
||||
<+> pretty (e ^. lockfileYamlParseErrorError)
|
||||
|
||||
instance PrettyCodeAnn VersionParseError where
|
||||
ppCodeAnn e =
|
||||
"The package version is invalid"
|
||||
<> line
|
||||
<+> pretty (e ^. versionParseErrorError)
|
||||
|
||||
instance PrettyCodeAnn DuplicateDependencyError where
|
||||
ppCodeAnn e =
|
||||
"Juvix package file contains the duplicate dependency name:"
|
||||
<+> pretty (e ^. duplicateDependencyErrorName)
|
||||
|
||||
instance HasLoc PackageLoaderError where
|
||||
getLoc e = singletonInterval (mkInitialLoc (e ^. packageLoaderErrorPath))
|
@ -10,6 +10,7 @@ import Examples qualified
|
||||
import Format qualified
|
||||
import Formatter qualified
|
||||
import Internal qualified
|
||||
import Package qualified
|
||||
import Parsing qualified
|
||||
import Reachability qualified
|
||||
import Runtime qualified
|
||||
@ -43,7 +44,8 @@ fastTests =
|
||||
Typecheck.allTests,
|
||||
Reachability.allTests,
|
||||
Format.allTests,
|
||||
Formatter.allTests
|
||||
Formatter.allTests,
|
||||
Package.allTests
|
||||
]
|
||||
|
||||
main :: IO ()
|
||||
|
11
test/Package.hs
Normal file
11
test/Package.hs
Normal file
@ -0,0 +1,11 @@
|
||||
module Package
|
||||
( allTests,
|
||||
)
|
||||
where
|
||||
|
||||
import Base
|
||||
import Package.Negative qualified as N
|
||||
import Package.Positive qualified as P
|
||||
|
||||
allTests :: TestTree
|
||||
allTests = testGroup "Package loading tests" [N.allTests, P.allTests]
|
68
test/Package/Negative.hs
Normal file
68
test/Package/Negative.hs
Normal file
@ -0,0 +1,68 @@
|
||||
module Package.Negative where
|
||||
|
||||
import Base
|
||||
import Juvix.Compiler.Pipeline.Package
|
||||
import Juvix.Compiler.Pipeline.Package.Loader.Error
|
||||
|
||||
type FailMsg = String
|
||||
|
||||
data NegTest a = NegTest
|
||||
{ _name :: String,
|
||||
_relDir :: Path Rel Dir,
|
||||
_checkErr :: a -> Maybe FailMsg
|
||||
}
|
||||
|
||||
root :: Path Abs Dir
|
||||
root = relToProject $(mkRelDir "tests/negative/Package")
|
||||
|
||||
testDescr :: (Typeable a) => NegTest a -> TestDescr
|
||||
testDescr NegTest {..} =
|
||||
let tRoot = root <//> _relDir
|
||||
in TestDescr
|
||||
{ _testName = _name,
|
||||
_testRoot = tRoot,
|
||||
_testAssertion = Single $ do
|
||||
res <- withTempDir' (runM . runError . runFilesIO . readPackage tRoot . CustomBuildDir . Abs)
|
||||
case mapLeft fromJuvixError res of
|
||||
Left (Just err) -> whenJust (_checkErr err) assertFailure
|
||||
Left Nothing -> assertFailure "An error ocurred but it was not when reading the package."
|
||||
Right {} -> assertFailure "There was no error when reading the package"
|
||||
}
|
||||
|
||||
allTests :: TestTree
|
||||
allTests =
|
||||
testGroup
|
||||
"Package loading negative tests"
|
||||
( map (mkTest . testDescr) packageErrorTests
|
||||
)
|
||||
|
||||
wrongError :: Maybe FailMsg
|
||||
wrongError = Just "Incorrect error"
|
||||
|
||||
packageErrorTests :: [NegTest PackageLoaderError]
|
||||
packageErrorTests =
|
||||
[ NegTest
|
||||
"package YAML parse error"
|
||||
$(mkRelDir "YamlParseError")
|
||||
$ \case
|
||||
PackageLoaderError _ ErrPackageYamlParseError {} -> Nothing
|
||||
_ -> wrongError,
|
||||
NegTest
|
||||
"lockfile YAML parse error"
|
||||
$(mkRelDir "InvalidLockfile")
|
||||
$ \case
|
||||
PackageLoaderError _ ErrLockfileYamlParseError {} -> Nothing
|
||||
_ -> wrongError,
|
||||
NegTest
|
||||
"package YAML invalid version"
|
||||
$(mkRelDir "YamlInvalidVersion")
|
||||
$ \case
|
||||
PackageLoaderError _ ErrVersionParseError {} -> Nothing
|
||||
_ -> wrongError,
|
||||
NegTest
|
||||
"package YAML duplicate dependencies"
|
||||
$(mkRelDir "YamlDuplicateDependencies")
|
||||
$ \case
|
||||
PackageLoaderError _ ErrDuplicateDependencyError {} -> Nothing
|
||||
_ -> wrongError
|
||||
]
|
64
test/Package/Positive.hs
Normal file
64
test/Package/Positive.hs
Normal file
@ -0,0 +1,64 @@
|
||||
module Package.Positive where
|
||||
|
||||
import Base
|
||||
import Juvix.Compiler.Pipeline.Package
|
||||
|
||||
type FailMsg = String
|
||||
|
||||
data PosTest = PosTest
|
||||
{ _name :: String,
|
||||
_relDir :: Path Rel Dir,
|
||||
_checkPackage :: Package -> BuildDir -> Maybe FailMsg
|
||||
}
|
||||
|
||||
root :: Path Abs Dir
|
||||
root = relToProject $(mkRelDir "tests/positive/PackageLoader")
|
||||
|
||||
testDescr :: PosTest -> TestDescr
|
||||
testDescr PosTest {..} =
|
||||
let tRoot = root <//> _relDir
|
||||
in TestDescr
|
||||
{ _testName = _name,
|
||||
_testRoot = tRoot,
|
||||
_testAssertion = Single $ do
|
||||
withTempDir' $ \d -> do
|
||||
let buildDir = CustomBuildDir (Abs d)
|
||||
res <- runM . runError @JuvixError . runFilesIO . readPackage tRoot $ buildDir
|
||||
case res of
|
||||
Right p -> whenJust (_checkPackage p buildDir) assertFailure
|
||||
Left {} -> assertFailure "An error ocurred when reading the package."
|
||||
}
|
||||
|
||||
allTests :: TestTree
|
||||
allTests =
|
||||
testGroup
|
||||
"Package loading positive tests"
|
||||
( map (mkTest . testDescr) packageLoadingTests
|
||||
)
|
||||
|
||||
packageLoadingTests :: [PosTest]
|
||||
packageLoadingTests =
|
||||
[ PosTest
|
||||
"empty YAML is valid"
|
||||
$(mkRelDir "YamlEmpty")
|
||||
$ \p _ ->
|
||||
if
|
||||
| p ^. packageName == defaultPackageName -> Nothing
|
||||
| otherwise -> Just "Package did not have default name",
|
||||
PosTest
|
||||
"no dependencies uses default stdlib"
|
||||
$(mkRelDir "YamlNoDependencies")
|
||||
$ \p b -> case p ^? packageDependencies . _head of
|
||||
Just d ->
|
||||
if
|
||||
| d == defaultStdlibDep b -> Nothing
|
||||
| otherwise -> Just "Package dependency is not the default standard library"
|
||||
_ -> Just "The package has no dependencies",
|
||||
PosTest
|
||||
"empty dependencies does not use default stdlib"
|
||||
$(mkRelDir "YamlEmptyDependencies")
|
||||
$ \p _ ->
|
||||
if
|
||||
| null (p ^. packageDependencies) -> Nothing
|
||||
| otherwise -> Just "Expected dependencies to be empty"
|
||||
]
|
1
tests/negative/Package/InvalidLockfile/juvix.lock.yaml
Normal file
1
tests/negative/Package/InvalidLockfile/juvix.lock.yaml
Normal file
@ -0,0 +1 @@
|
||||
dependencies: 123
|
0
tests/negative/Package/InvalidLockfile/juvix.yaml
Normal file
0
tests/negative/Package/InvalidLockfile/juvix.yaml
Normal file
10
tests/negative/Package/YamlDuplicateDependencies/juvix.yaml
Normal file
10
tests/negative/Package/YamlDuplicateDependencies/juvix.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
name: abc
|
||||
dependencies:
|
||||
- git:
|
||||
url: repo
|
||||
name: dep
|
||||
ref: abc
|
||||
- git:
|
||||
url: repo
|
||||
name: dep
|
||||
ref: abc
|
2
tests/negative/Package/YamlInvalidVersion/juvix.yaml
Normal file
2
tests/negative/Package/YamlInvalidVersion/juvix.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
name: abc
|
||||
version: def
|
1
tests/negative/Package/YamlParseError/juvix.yaml
Normal file
1
tests/negative/Package/YamlParseError/juvix.yaml
Normal file
@ -0,0 +1 @@
|
||||
name: 123
|
0
tests/positive/PackageLoader/YamlEmpty/juvix.yaml
Normal file
0
tests/positive/PackageLoader/YamlEmpty/juvix.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
name: abc
|
||||
dependencies: []
|
@ -0,0 +1 @@
|
||||
name: abc
|
@ -1056,6 +1056,8 @@ tests:
|
||||
# compile project
|
||||
juvix compile HelloWorld.juvix
|
||||
stdout:
|
||||
contains: ""
|
||||
stderr:
|
||||
contains: duplicate
|
||||
exit-status: 1
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user