blob: 0be9c6cd15f48de9501dcb34b63697b0089195e3 [file] [log] [blame]
-- | A test of the FSATrace program
module Test(main) where
import Parse
import Utils
import Control.Monad.Extra
import Control.Monad.IO.Class
import Control.Monad.Trans.Reader
import Data.Maybe
import System.Directory
import System.Environment (lookupEnv)
import System.Exit
import System.FilePath
import System.IO.Temp
import Test.QuickCheck
import Test.QuickCheck.Monadic
--import Debug.Trace
lookupCC :: IO Path
lookupCC = Path . fromMaybe "cc" <$> lookupEnv "CC"
-- Confirm that we pass the arguments through properly
-- using the helper executable @dumpargs@.
prop_ArgsRoundtrip :: [Arg] -> Prop
prop_ArgsRoundtrip args = do
isShell <- asks shellMode
let safe = if isShell == Shelled then filter (`notElem` "\n\r\"%$\\`") else id
c <- command "x" $ "dumpargs" : map (safe . unarg) args
return $ monadicIO $ do
mout <- liftIO $ systemStdout c
assert $ case mout of
Just out -> map (safe . unarg) args == read (head $ lines out)
Nothing -> False
prop_Tester :: (FSATest, [Act]) -> Prop
prop_Tester (p, actLong) = do
e <- ask
act <- return $ limitCmdLine 1500 e $ map (no32to64 p) actLong
let ans = concatMap (predict e) act
yieldsPrepare False
(sequence_ [writeFile x "" | R (Path x) <- ans])
(command "rwx" ((pwdDir e </> ".." </> show p) : showAct e act))
ans
where
predict e (ActR x) = [R $ Path $ tmpDir e </> x]
predict e (ActW x) = [W $ Path $ tmpDir e </> x]
predict e (ActE _ x) = concatMap (predict e) x
predict _ ActF = []
limitCmdLine :: Int -> Env -> [Act] -> [Act]
limitCmdLine n e (x:xs) | n2 > 0 = x : limitCmdLine n2 e xs
where n2 = n - (length (unwords $ showAct e [x]) + 1)
limitCmdLine _ _ _ = []
prop_echo :: Path -> Path -> Prop
prop_echo src dst = command "rwmd" ["echo", unpath src, "|", "sort" , ">", unpath dst] `yields` [W dst]
prop_cp :: Path -> Path -> Prop
prop_cp src dst = command "rwmd" ["cp", unpath src, unpath dst] `yields` [R src, W dst]
prop_mv :: Path -> Path -> Prop
prop_mv src dst = command "rwmd" ["mv", unpath src, unpath dst] `yields` [M dst src]
prop_touch :: Path -> Prop
prop_touch dst = command "t" ["touch", unpath dst] `yields` [T dst]
prop_rm :: Path -> Prop
prop_rm dst = command "rwmd" ["rm", unpath dst] `yields` [D dst]
prop_gcc :: Path -> Path -> [Access Path] -> Prop
prop_gcc cc src deps = command "r" [unpath cc, "-E", unpath src] `yields` deps
prop_cl :: Path -> [Access Path] -> Prop
prop_cl src deps = command "r" ["cl", "/nologo", "/E", unpath src] `yields` deps
main :: IO ()
main = do
results <- sequence [allTests sp sm | sp <- [minBound..], sm <- [minBound..]]
when (any (not . isSuccess) $ concat results) exitFailure
noisy :: String -> IO ()
noisy s = putStrLn ("Testing " ++ s)
allTests :: SpaceMode -> ShellMode -> IO [Result]
allTests sp sm = withSystemTempDirectory (if sp == Spaced then "fsatrace with spaces" else "fsatrace") $ \utmp -> do
putStrLn $ "================ " ++ show sp ++ " " ++ show sm ++ " ================"
tmp <- canonicalizePath utmp
src <- canonicalizePath $ ".." </> "src"
pwd <- canonicalizePath =<< getCurrentDirectory
let tsrc = tmp </> "src"
void $ systemStdout ["cp", "-R", src, tsrc]
let emitc = Path $ tsrc </> "emit.c"
srcc = Path $ tsrc </> "src.c"
rpaths = map (R . Path)
e = Env {shellMode = sm, tmpDir = tmp, pwdDir = pwd}
qc s p = noisy s >> quickCheckWithResult (stdArgs {maxSuccess=1}) (runReader p e)
cc <- lookupCC
gccTests <- do
deps <- systemStdout [unpath cc, "-MM", unpath emitc]
ndeps <- mapM canonicalizePath (parseMakefileDeps deps)
return [qc (unpath cc) $ prop_gcc cc emitc (rpaths ndeps)]
clTests <- ifM (isNothing <$> findExecutable "cl.exe") (return []) $ do
let clcsrc = Path $ tsrc </> "win" </> "handle.c"
cldeps <- fromMaybe [] <$> systemStderr ["cl", "/nologo", "/showIncludes", "/E", "/DPATH_MAX=4096", unpath clcsrc]
ncldeps <- mapM canonicalizePath (unpath clcsrc : parseClDeps cldeps)
return [qc "cl" $ prop_cl clcsrc (rpaths ncldeps)]
sequence $
[ noisy "args" >> quickCheckWithResult (stdArgs {maxSuccess=10}) (\x -> runReader (prop_ArgsRoundtrip x) e) -- qc 10 "args" prop_args
] ++ gccTests ++
[ qc "cp" $ prop_cp emitc srcc
, qc "touch" $ prop_touch srcc
, qc "rm" $ prop_rm srcc
, qc "mv" $ prop_mv emitc srcc
]
++ clTests
++ [qc "echo" $ prop_echo emitc srcc | sm == Shelled]
++ [ noisy "random" >> quickCheckWithResult (stdArgs {maxSuccess=100}) (\x -> runReader (prop_Tester x) e) | sp == Unspaced]