{-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- -- | -- Module : Distribution.Simple.Test -- Copyright : Thomas Tuegel 2010 -- License : BSD3 -- -- Maintainer : cabal-devel@haskell.org -- Portability : portable -- -- This is the entry point into testing a built package. It performs the -- \"@.\/setup test@\" action. It runs test suites designated in the package -- description and reports on the results. module Distribution.Simple.Test ( test ) where import Distribution.Compat.Prelude import Prelude () import qualified Distribution.PackageDescription as PD import Distribution.Pretty import Distribution.Simple.Build (addInternalBuildTools) import Distribution.Simple.Compiler import Distribution.Simple.Hpc import Distribution.Simple.InstallDirs import qualified Distribution.Simple.LocalBuildInfo as LBI import Distribution.Simple.Setup.Test import qualified Distribution.Simple.Test.ExeV10 as ExeV10 import qualified Distribution.Simple.Test.LibV09 as LibV09 import Distribution.Simple.Test.Log import Distribution.Simple.UserHooks import Distribution.Simple.Utils import Distribution.TestSuite import qualified Distribution.Types.LocalBuildInfo as LBI import Distribution.Types.UnqualComponentName import Distribution.Utils.Path import Distribution.Simple.Configure (getInstalledPackagesById) import Distribution.Simple.Errors import Distribution.Simple.Register (internalPackageDBPath) import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Config import Distribution.Types.ExposedModule import Distribution.Types.InstalledPackageInfo (InstalledPackageInfo (libraryDirs), exposedModules) import Distribution.Types.LocalBuildInfo (LocalBuildInfo (..)) import System.Directory ( createDirectoryIfMissing , doesFileExist , getDirectoryContents , removeFile ) -- | Perform the \"@.\/setup test@\" action. test :: Args -- ^ positional command-line arguments -> PD.PackageDescription -- ^ information from the .cabal file -> LBI.LocalBuildInfo -- ^ information from the configure step -> TestFlags -- ^ flags sent to test -> IO () test args pkg_descr lbi0 flags = do curDir <- LBI.absoluteWorkingDirLBI lbi0 let common = testCommonFlags flags verbosity = fromFlag $ setupVerbosity common distPref = fromFlag $ setupDistPref common i = LBI.interpretSymbolicPathLBI lbi -- See Note [Symbolic paths] in Distribution.Utils.Path machineTemplate = fromFlag $ testMachineLog flags testLogDir = distPref makeRelativePathEx "test" testNames = args pkgTests = PD.testSuites pkg_descr enabledTests = LBI.enabledTestLBIs pkg_descr lbi -- We must add the internalPkgDB to the package database stack to lookup -- the path to HPC dirs of libraries local to this package internalPkgDb = internalPackageDBPath lbi0 distPref lbi = lbi0{withPackageDB = withPackageDB lbi0 ++ [SpecificPackageDB internalPkgDb]} doTest :: HPCMarkupInfo -> ( (PD.TestSuite, LBI.ComponentLocalBuildInfo) , Maybe TestSuiteLog ) -> IO TestSuiteLog doTest hpcMarkupInfo ((suite, clbi), _) = do let lbiForTest = lbi { withPrograms = -- Include any build-tool-depends on build tools internal to the current package. addInternalBuildTools curDir pkg_descr lbi (PD.testBuildInfo suite) (withPrograms lbi) } case PD.testInterface suite of PD.TestSuiteExeV10 _ _ -> ExeV10.runTest pkg_descr lbiForTest clbi hpcMarkupInfo flags suite PD.TestSuiteLibV09 _ _ -> LibV09.runTest pkg_descr lbiForTest clbi hpcMarkupInfo flags suite _ -> return TestSuiteLog { testSuiteName = PD.testName suite , testLogs = TestLog { testName = unUnqualComponentName $ PD.testName suite , testOptionsReturned = [] , testResult = Error $ "No support for running test suite type: " ++ show (pretty $ PD.testType suite) } , logFile = "" } unless (PD.hasTests pkg_descr) $ do notice verbosity "Package has no test suites." exitSuccess when (PD.hasTests pkg_descr && null enabledTests) $ dieWithException verbosity NoTestSuitesEnabled testsToRun <- case testNames of [] -> return $ zip enabledTests $ repeat Nothing names -> for names $ \tName -> let testMap = zip enabledNames enabledTests enabledNames = map (PD.testName . fst) enabledTests allNames = map PD.testName pkgTests tCompName = mkUnqualComponentName tName in case lookup tCompName testMap of Just t -> return (t, Nothing) _ | tCompName `elem` allNames -> dieWithException verbosity $ TestNameDisabled tName | otherwise -> dieWithException verbosity $ NoSuchTest tName createDirectoryIfMissing True $ i testLogDir -- Delete ordinary files from test log directory. getDirectoryContents (i testLogDir) >>= filterM doesFileExist . map (i testLogDir ) >>= traverse_ removeFile -- We configured the unit-ids of libraries we should cover in our coverage -- report at configure time into the local build info. At build time, we built -- the hpc artifacts into the extraCompilationArtifacts directory, which, at -- install time, is copied into the ghc-pkg database files. -- Now, we get the path to the HPC artifacts and exposed modules of each -- library by querying the package database keyed by unit-id: let coverageFor = nub $ fromFlagOrDefault [] (configCoverageFor (configFlags lbi)) <> extraCoverageFor lbi ipkginfos <- getInstalledPackagesById verbosity lbi MissingCoveredInstalledLibrary coverageFor let ( concat -> pathsToLibsArtifacts , concat -> libsModulesToInclude ) = unzip $ map ( \ip -> ( map (( coerceSymbolicPath extraCompilationArtifacts) . makeSymbolicPath) $ libraryDirs ip , map exposedName $ exposedModules ip ) ) ipkginfos hpcMarkupInfo = HPCMarkupInfo{pathsToLibsArtifacts, libsModulesToInclude} let totalSuites = length testsToRun notice verbosity $ "Running " ++ show totalSuites ++ " test suites..." suites <- traverse (doTest hpcMarkupInfo) testsToRun let packageLog = (localPackageLog pkg_descr lbi){testSuites = suites} packageLogFile = i testLogDir packageLogPath machineTemplate pkg_descr lbi allOk <- summarizePackage verbosity packageLog writeFile packageLogFile $ show packageLog when (LBI.testCoverage lbi) $ markupPackage verbosity hpcMarkupInfo lbi distPref pkg_descr $ map (fst . fst) testsToRun unless allOk exitFailure packageLogPath :: PathTemplate -> PD.PackageDescription -> LBI.LocalBuildInfo -> FilePath packageLogPath template pkg_descr lbi = fromPathTemplate $ substPathTemplate env template where env = initialPathTemplateEnv (PD.package pkg_descr) (LBI.localUnitId lbi) (compilerInfo $ LBI.compiler lbi) (LBI.hostPlatform lbi)