2018-03-29 01:27:35 +02:00
|
|
|
{-# LANGUAGE LambdaCase #-}
|
2018-02-09 15:32:53 +01:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2018-03-29 01:27:35 +02:00
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
2018-02-09 15:32:53 +01:00
|
|
|
|
2018-04-07 00:24:46 +02:00
|
|
|
module NixLanguageTests (genTests) where
|
2018-02-09 15:32:53 +01:00
|
|
|
|
2018-03-28 06:59:27 +02:00
|
|
|
import Control.Arrow ((&&&))
|
|
|
|
import Control.Exception
|
2018-04-01 19:55:23 +02:00
|
|
|
import Control.Monad
|
2018-04-04 22:33:53 +02:00
|
|
|
import Control.Monad.ST
|
2018-04-24 20:12:20 +02:00
|
|
|
import Control.Monad.Trans.Reader
|
2018-03-29 01:27:35 +02:00
|
|
|
import Data.List (delete, sort)
|
2018-03-28 06:59:27 +02:00
|
|
|
import Data.List.Split (splitOn)
|
|
|
|
import Data.Map (Map)
|
2018-02-09 15:32:53 +01:00
|
|
|
import qualified Data.Map as Map
|
2018-03-28 06:59:27 +02:00
|
|
|
import qualified Data.Text as Text
|
|
|
|
import qualified Data.Text.IO as Text
|
|
|
|
import GHC.Exts
|
2018-04-24 11:14:27 +02:00
|
|
|
import Nix.Frames
|
2018-04-13 01:46:34 +02:00
|
|
|
import Nix.Lint
|
2018-04-12 06:02:37 +02:00
|
|
|
import Nix.Options
|
2018-03-28 06:59:27 +02:00
|
|
|
import Nix.Parser
|
|
|
|
import Nix.Pretty
|
2018-04-24 20:12:20 +02:00
|
|
|
import Nix.Render.Frame
|
2018-04-12 06:02:37 +02:00
|
|
|
import Nix.Utils
|
2018-04-05 16:39:35 +02:00
|
|
|
import Nix.XML
|
2018-04-12 06:02:37 +02:00
|
|
|
import qualified Options.Applicative as Opts
|
2018-03-30 11:00:36 +02:00
|
|
|
import System.FilePath
|
2018-03-28 06:59:27 +02:00
|
|
|
import System.FilePath.Glob (compile, globDir1)
|
|
|
|
import Test.Tasty
|
|
|
|
import Test.Tasty.HUnit
|
2018-04-07 00:20:21 +02:00
|
|
|
import TestCommon
|
2018-02-09 15:32:53 +01:00
|
|
|
|
|
|
|
{-
|
|
|
|
From (git://nix)/tests/lang.sh we see that
|
|
|
|
|
|
|
|
lang/parse-fail-*.nix -> parsing should fail
|
|
|
|
lang/parse-okay-*.nix -> parsing should succeed
|
|
|
|
lang/eval-fail-*.nix -> eval should fail
|
|
|
|
|
|
|
|
lang/eval-okay-*.{nix,xml} -> eval should succeed,
|
|
|
|
xml dump should be the same as the .xml
|
|
|
|
lang/eval-okay-*.{nix,exp} -> eval should succeed,
|
|
|
|
plain text output should be the same as the .exp
|
|
|
|
lang/eval-okay-*.{nix,exp,flags} -> eval should succeed,
|
|
|
|
plain text output should be the same as the .exp,
|
|
|
|
pass the extra flags to nix-instantiate
|
|
|
|
|
2018-03-30 23:08:38 +02:00
|
|
|
NIX_PATH=lang/dir3:lang/dir4 should be in the environment of all
|
|
|
|
eval-okay-*.nix evaluations
|
2018-02-09 15:32:53 +01:00
|
|
|
TEST_VAR=foo should be in all the environments # for eval-okay-getenv.nix
|
|
|
|
-}
|
|
|
|
|
|
|
|
groupBy :: Ord k => (v -> k) -> [v] -> Map k [v]
|
|
|
|
groupBy key = Map.fromListWith (++) . map (key &&& pure)
|
|
|
|
|
|
|
|
genTests :: IO TestTree
|
|
|
|
genTests = do
|
2018-03-29 01:27:35 +02:00
|
|
|
testFiles <- sort . filter ((/= ".xml") . takeExtension)
|
|
|
|
<$> globDir1 (compile "*-*-*.*") "data/nix/tests/lang"
|
2018-04-04 05:54:29 +02:00
|
|
|
let testsByName = groupBy (takeFileName . dropExtensions) testFiles
|
2018-02-09 15:32:53 +01:00
|
|
|
let testsByType = groupBy testType (Map.toList testsByName)
|
|
|
|
let testGroups = map mkTestGroup (Map.toList testsByType)
|
2018-04-09 09:52:10 +02:00
|
|
|
return $ localOption (mkTimeout 2000000)
|
2018-03-29 01:27:35 +02:00
|
|
|
$ testGroup "Nix (upstream) language tests" testGroups
|
2018-02-09 15:32:53 +01:00
|
|
|
where
|
2018-04-07 20:38:12 +02:00
|
|
|
testType (fullpath, _files) =
|
|
|
|
take 2 $ splitOn "-" $ takeFileName fullpath
|
2018-03-29 01:27:35 +02:00
|
|
|
mkTestGroup (kind, tests) =
|
|
|
|
testGroup (unwords kind) $ map (mkTestCase kind) tests
|
|
|
|
mkTestCase kind (basename, files) =
|
|
|
|
testCase (takeFileName basename) $ case kind of
|
2018-04-18 02:25:59 +02:00
|
|
|
["parse", "okay"] -> assertParse defaultOptions $ the files
|
|
|
|
["parse", "fail"] -> assertParseFail defaultOptions $ the files
|
2018-04-24 20:12:20 +02:00
|
|
|
["eval", "okay"] -> assertEval defaultOptions files
|
|
|
|
["eval", "fail"] -> assertEvalFail $ the files
|
2018-03-31 08:00:06 +02:00
|
|
|
_ -> error $ "Unexpected: " ++ show kind
|
2018-02-09 15:32:53 +01:00
|
|
|
|
2018-04-18 02:25:59 +02:00
|
|
|
assertParse :: Options -> FilePath -> Assertion
|
|
|
|
assertParse _opts file = parseNixFileLoc file >>= \case
|
2018-04-11 06:01:48 +02:00
|
|
|
-- jww (2018-04-10): TODO
|
2018-04-18 02:25:59 +02:00
|
|
|
Success _expr -> return () -- pure $! runST $ void $ lint opts expr
|
2018-04-07 20:38:12 +02:00
|
|
|
Failure err ->
|
|
|
|
assertFailure $ "Failed to parse " ++ file ++ ":\n" ++ show err
|
2018-02-09 15:32:53 +01:00
|
|
|
|
2018-04-18 02:25:59 +02:00
|
|
|
assertParseFail :: Options -> FilePath -> Assertion
|
|
|
|
assertParseFail opts file = do
|
2018-04-11 06:01:48 +02:00
|
|
|
eres <- parseNixFileLoc file
|
2018-03-29 01:27:35 +02:00
|
|
|
catch (case eres of
|
|
|
|
Success expr -> do
|
2018-04-18 02:25:59 +02:00
|
|
|
_ <- pure $! runST $ void $ lint opts expr
|
2018-03-29 01:27:35 +02:00
|
|
|
assertFailure $ "Unexpected success parsing `"
|
|
|
|
++ file ++ ":\nParsed value: " ++ show expr
|
|
|
|
Failure _ -> return ()) $ \(_ :: SomeException) ->
|
|
|
|
return ()
|
2018-02-09 15:32:53 +01:00
|
|
|
|
2018-04-18 02:25:59 +02:00
|
|
|
assertLangOk :: Options -> FilePath -> Assertion
|
|
|
|
assertLangOk opts file = do
|
|
|
|
actual <- printNix <$> hnixEvalFile opts (file ++ ".nix")
|
2018-03-28 06:59:27 +02:00
|
|
|
expected <- Text.readFile $ file ++ ".exp"
|
2018-03-30 11:07:08 +02:00
|
|
|
assertEqual "" expected $ Text.pack (actual ++ "\n")
|
2018-02-09 15:32:53 +01:00
|
|
|
|
2018-04-18 02:25:59 +02:00
|
|
|
assertLangOkXml :: Options -> FilePath -> Assertion
|
|
|
|
assertLangOkXml opts file = do
|
|
|
|
actual <- toXML <$> hnixEvalFile opts (file ++ ".nix")
|
2018-04-05 16:39:35 +02:00
|
|
|
expected <- Text.readFile $ file ++ ".exp.xml"
|
2018-04-06 00:09:54 +02:00
|
|
|
assertEqual "" expected $ Text.pack actual
|
2018-02-09 15:32:53 +01:00
|
|
|
|
2018-04-24 20:12:20 +02:00
|
|
|
assertEval :: Options -> [FilePath] -> Assertion
|
|
|
|
assertEval opts files = catch go $ \case
|
|
|
|
NixException frames -> do
|
|
|
|
msg <- runReaderT (renderFrames frames) opts
|
|
|
|
error $ "Evaluation error: " ++ show msg
|
2018-02-09 15:32:53 +01:00
|
|
|
where
|
2018-04-07 23:33:15 +02:00
|
|
|
go = case delete ".nix" $ sort $ map takeExtensions files of
|
2018-04-18 02:25:59 +02:00
|
|
|
[] -> assertLangOkXml defaultOptions name
|
|
|
|
[".exp"] -> assertLangOk defaultOptions name
|
2018-04-07 23:33:15 +02:00
|
|
|
[".exp.disabled"] -> return ()
|
|
|
|
[".exp-disabled"] -> return ()
|
2018-04-12 06:02:37 +02:00
|
|
|
[".exp", ".flags"] -> do
|
|
|
|
flags <- Text.readFile (name ++ ".flags")
|
2018-04-15 11:22:33 +02:00
|
|
|
let flags' | Text.last flags == '\n' = Text.init flags
|
|
|
|
| otherwise = flags
|
2018-04-12 06:02:37 +02:00
|
|
|
case Opts.execParserPure Opts.defaultPrefs nixOptionsInfo
|
2018-04-15 11:22:33 +02:00
|
|
|
(fixup (map Text.unpack (Text.splitOn " " flags'))) of
|
2018-04-12 06:02:37 +02:00
|
|
|
Opts.Failure err -> errorWithoutStackTrace $
|
|
|
|
"Error parsing flags from " ++ name ++ ".flags: "
|
|
|
|
++ show err
|
2018-04-24 20:12:20 +02:00
|
|
|
Opts.Success opts' ->
|
2018-04-18 02:25:59 +02:00
|
|
|
assertLangOk
|
2018-04-24 20:12:20 +02:00
|
|
|
(opts' { include = include opts' ++
|
|
|
|
[ "nix=../../../../data/nix/corepkgs"
|
|
|
|
, "lang/dir4" ] })
|
2018-04-15 11:16:06 +02:00
|
|
|
name
|
2018-04-12 06:02:37 +02:00
|
|
|
Opts.CompletionInvoked _ -> error "unused"
|
2018-04-07 23:33:15 +02:00
|
|
|
_ -> assertFailure $ "Unknown test type " ++ show files
|
|
|
|
where
|
|
|
|
name = "data/nix/tests/lang/"
|
|
|
|
++ the (map (takeFileName . dropExtensions) files)
|
2018-02-09 15:32:53 +01:00
|
|
|
|
2018-04-15 11:16:06 +02:00
|
|
|
fixup ("--arg":x:y:rest) = "--arg":(x ++ "=" ++ y):fixup rest
|
|
|
|
fixup ("--argstr":x:y:rest) = "--argstr":(x ++ "=" ++ y):fixup rest
|
|
|
|
fixup (x:rest) = x:fixup rest
|
|
|
|
fixup [] = []
|
|
|
|
|
2018-02-09 15:32:53 +01:00
|
|
|
assertEvalFail :: FilePath -> Assertion
|
2018-04-07 23:33:15 +02:00
|
|
|
assertEvalFail file = catch ?? (\(_ :: SomeException) -> return ()) $ do
|
2018-04-18 02:25:59 +02:00
|
|
|
evalResult <- printNix <$> hnixEvalFile defaultOptions file
|
2018-04-07 20:38:12 +02:00
|
|
|
evalResult `seq` assertFailure $
|
|
|
|
file ++ " should not evaluate.\nThe evaluation result was `"
|
|
|
|
++ evalResult ++ "`."
|