Only invoke pretty/parser tests if PRETTY_TESTS=<N> for some N>0
This commit is contained in:
parent
ac3ab07b8b
commit
2457efdaa3
|
@ -2,7 +2,7 @@
|
||||||
--
|
--
|
||||||
-- see: https://github.com/sol/hpack
|
-- see: https://github.com/sol/hpack
|
||||||
--
|
--
|
||||||
-- hash: 5eba5b1b4e2ae5297dcad048052e5bc02fc2f42aa37016fbea866ecbf3f4a380
|
-- hash: cbc369801227ccd516b691c3f08a9aae9b5ac8723619706b83703a805d570972
|
||||||
|
|
||||||
name: hnix
|
name: hnix
|
||||||
version: 0.5.0
|
version: 0.5.0
|
||||||
|
@ -206,6 +206,7 @@ test-suite hnix-tests
|
||||||
, megaparsec
|
, megaparsec
|
||||||
, mtl
|
, mtl
|
||||||
, optparse-applicative
|
, optparse-applicative
|
||||||
|
, pretty-show
|
||||||
, process
|
, process
|
||||||
, quickcheck-instances
|
, quickcheck-instances
|
||||||
, serialise
|
, serialise
|
||||||
|
|
|
@ -134,6 +134,7 @@ tests:
|
||||||
- Diff
|
- Diff
|
||||||
- megaparsec
|
- megaparsec
|
||||||
- tasty-quickcheck
|
- tasty-quickcheck
|
||||||
|
- pretty-show
|
||||||
|
|
||||||
benchmarks:
|
benchmarks:
|
||||||
hnix-benchmarks:
|
hnix-benchmarks:
|
||||||
|
|
|
@ -11,7 +11,7 @@ import Control.Monad
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
import Data.Fix
|
import Data.Fix
|
||||||
import Data.List (isInfixOf)
|
import Data.List (isInfixOf)
|
||||||
import Data.Maybe (isJust)
|
import Data.Maybe (isJust, fromMaybe)
|
||||||
import Data.String.Interpolate.IsString
|
import Data.String.Interpolate.IsString
|
||||||
import Data.Text (unpack)
|
import Data.Text (unpack)
|
||||||
import Data.Time
|
import Data.Time
|
||||||
|
@ -25,7 +25,7 @@ import Nix.Value
|
||||||
import qualified NixLanguageTests
|
import qualified NixLanguageTests
|
||||||
import qualified ParserTests
|
import qualified ParserTests
|
||||||
import qualified PrettyTests
|
import qualified PrettyTests
|
||||||
-- import qualified PrettyParseTests
|
import qualified PrettyParseTests
|
||||||
import System.Environment
|
import System.Environment
|
||||||
import System.FilePath.Glob
|
import System.FilePath.Glob
|
||||||
import System.Posix.Files
|
import System.Posix.Files
|
||||||
|
@ -85,19 +85,18 @@ main = do
|
||||||
evalComparisonTests <- EvalTests.genEvalCompareTests
|
evalComparisonTests <- EvalTests.genEvalCompareTests
|
||||||
langTestsEnv <- lookupEnv "LANGUAGE_TESTS"
|
langTestsEnv <- lookupEnv "LANGUAGE_TESTS"
|
||||||
nixpkgsTestsEnv <- lookupEnv "NIXPKGS_TESTS"
|
nixpkgsTestsEnv <- lookupEnv "NIXPKGS_TESTS"
|
||||||
let runLangTests = isJust langTestsEnv
|
prettyTestsEnv <- lookupEnv "PRETTY_TESTS"
|
||||||
let runNixpkgsTests = isJust nixpkgsTestsEnv
|
|
||||||
|
|
||||||
defaultMain $ testGroup "hnix" $
|
defaultMain $ testGroup "hnix" $
|
||||||
[ testCase "hnix.cabal correctly generated" cabalCorrectlyGenerated ] ++
|
[ testCase "hnix.cabal correctly generated" cabalCorrectlyGenerated ] ++
|
||||||
[ ParserTests.tests
|
[ ParserTests.tests
|
||||||
, EvalTests.tests
|
, EvalTests.tests
|
||||||
, PrettyTests.tests
|
, PrettyTests.tests ] ++
|
||||||
-- , PrettyParseTests.tests
|
[ PrettyParseTests.tests (read (fromMaybe "0" prettyTestsEnv)) ] ++
|
||||||
, evalComparisonTests ] ++
|
[ evalComparisonTests ] ++
|
||||||
[ testCase "Nix language tests present" ensureLangTestsPresent
|
[ testCase "Nix language tests present" ensureLangTestsPresent
|
||||||
| runLangTests ] ++
|
| isJust langTestsEnv ] ++
|
||||||
[ nixLanguageTests | runLangTests ] ++
|
[ nixLanguageTests | isJust langTestsEnv ] ++
|
||||||
[ testCase "Nixpkgs parses without errors" ensureNixpkgsCanParse
|
[ testCase "Nixpkgs parses without errors" ensureNixpkgsCanParse
|
||||||
| runNixpkgsTests ]
|
| isJust nixpkgsTestsEnv ]
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,42 @@
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
|
||||||
{-# LANGUAGE UndecidableInstances #-}
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
{-# LANGUAGE TypeApplications #-}
|
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
|
||||||
{-# LANGUAGE NoMonomorphismRestriction #-}
|
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
{-# LANGUAGE MonoLocalBinds #-}
|
{-# LANGUAGE MonoLocalBinds #-}
|
||||||
|
{-# LANGUAGE NoMonomorphismRestriction #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
|
|
||||||
{-# OPTIONS -Wno-orphans#-}
|
{-# OPTIONS -Wno-orphans#-}
|
||||||
|
|
||||||
module PrettyParseTests where
|
module PrettyParseTests where
|
||||||
|
|
||||||
import Test.Tasty.QuickCheck hiding (Success, Failure)
|
import Control.Monad
|
||||||
import Test.Tasty
|
import Data.Algorithm.Diff
|
||||||
import Test.QuickCheck.Instances.Text ()
|
import Data.Algorithm.DiffOutput
|
||||||
import Test.QuickCheck.Instances.Semigroup ()
|
import Data.Char
|
||||||
|
import Data.Fix
|
||||||
|
import qualified Data.List.NonEmpty as NE
|
||||||
|
import Data.Text (Text, pack)
|
||||||
|
import qualified Data.Text as Text
|
||||||
|
import Generic.Random
|
||||||
|
import Nix.Atoms
|
||||||
|
import Nix.Expr
|
||||||
|
import Nix.Parser
|
||||||
|
import Nix.Pretty
|
||||||
|
import Test.QuickCheck.Instances.Semigroup ()
|
||||||
|
import Test.QuickCheck.Instances.Text ()
|
||||||
import qualified Test.QuickCheck.Property as P
|
import qualified Test.QuickCheck.Property as P
|
||||||
|
import Test.Tasty
|
||||||
|
import Test.Tasty.QuickCheck hiding (Success, Failure)
|
||||||
|
import Text.Megaparsec (Pos, SourcePos, mkPos)
|
||||||
|
import Text.PrettyPrint.ANSI.Leijen ((</>), text)
|
||||||
|
import qualified Text.PrettyPrint.ANSI.Leijen as P
|
||||||
|
import qualified Text.Show.Pretty as PS
|
||||||
|
|
||||||
import Nix.Expr (NExpr, NExprF(..), NString(..), NUnaryOp(..), NBinaryOp(..)
|
-- Instead of using the Generic arbitrary instance (which doesn't exist anyway
|
||||||
, Params(..), NKeyName(..), Antiquoted(..), Binding(..))
|
-- for Text), we use a different generator which just prints sensible looking
|
||||||
import Nix.Atoms
|
-- variable names
|
||||||
import Nix.Pretty
|
|
||||||
import Nix.Parser
|
|
||||||
import Generic.Random
|
|
||||||
import Data.Fix
|
|
||||||
import Data.Text (Text, pack, unpack)
|
|
||||||
import Text.Megaparsec (Pos, SourcePos, mkPos)
|
|
||||||
import Control.Monad
|
|
||||||
import Data.Algorithm.Diff
|
|
||||||
import Data.Algorithm.DiffOutput
|
|
||||||
import Data.Char
|
|
||||||
|
|
||||||
-- Instead of using the Generic arbitrary instance (which doesn't exist
|
|
||||||
-- anyway for Text), we use a different generator which just prints
|
|
||||||
-- sensible looking variable names
|
|
||||||
custom :: GenList '[Text]
|
custom :: GenList '[Text]
|
||||||
custom = asciiText :@ Nil
|
custom = asciiText :@ Nil
|
||||||
|
|
||||||
|
@ -45,11 +49,11 @@ asciiText :: Gen Text
|
||||||
asciiText = pack <$> asciiString
|
asciiText = pack <$> asciiString
|
||||||
|
|
||||||
pcustom :: GenList '[Pos]
|
pcustom :: GenList '[Pos]
|
||||||
pcustom = (arbitrary) :@ Nil
|
pcustom = arbitrary :@ Nil
|
||||||
|
|
||||||
-- | This generator generates selects one of the constructors uniformly
|
-- | This generator generates selects one of the constructors uniformly and
|
||||||
-- and also decreases the size of the generator by dividing by the
|
-- also decreases the size of the generator by dividing by the branching
|
||||||
-- branching factor. This ensures sensible termination.
|
-- factor. This ensures sensible termination.
|
||||||
genArb :: (GArbitrary (Options 'Sized '[Text]) a, GUniformWeight a) => Gen a
|
genArb :: (GArbitrary (Options 'Sized '[Text]) a, GUniformWeight a) => Gen a
|
||||||
genArb = genericArbitraryWith (setGenerators custom sizedOpts) uniform
|
genArb = genericArbitraryWith (setGenerators custom sizedOpts) uniform
|
||||||
|
|
||||||
|
@ -70,13 +74,23 @@ instance Arbitrary f => Arbitrary (Binding f) where
|
||||||
arbitrary = genArb
|
arbitrary = genArb
|
||||||
|
|
||||||
instance Arbitrary f => Arbitrary (NKeyName f) where
|
instance Arbitrary f => Arbitrary (NKeyName f) where
|
||||||
arbitrary = genArb
|
arbitrary = oneof [ DynamicKey <$> arbitrary
|
||||||
|
, StaticKey <$> asciiText <*> arbitrary ]
|
||||||
|
|
||||||
instance Arbitrary f => Arbitrary (Params f) where
|
instance Arbitrary f => Arbitrary (Params f) where
|
||||||
arbitrary = genArb
|
arbitrary =
|
||||||
|
oneof [ Param <$> asciiText
|
||||||
|
, ParamSet <$> listOf ((,) <$> asciiText <*> arbitrary) <*> arbitrary
|
||||||
|
<*> oneof [pure Nothing, Just <$> asciiText]
|
||||||
|
]
|
||||||
|
|
||||||
instance Arbitrary NAtom where
|
instance Arbitrary NAtom where
|
||||||
arbitrary = genArb
|
arbitrary =
|
||||||
|
oneof [ NInt <$> arbitrary `suchThat` (>= 0)
|
||||||
|
, NFloat <$> arbitrary `suchThat` (>= 0)
|
||||||
|
, NBool <$> arbitrary
|
||||||
|
, pure NNull
|
||||||
|
, NUri <$> asciiText `suchThat` (\x -> Text.length x > 0) ]
|
||||||
|
|
||||||
instance Arbitrary NUnaryOp where
|
instance Arbitrary NUnaryOp where
|
||||||
arbitrary = genArb
|
arbitrary = genArb
|
||||||
|
@ -90,76 +104,143 @@ instance (Arbitrary f) => Arbitrary (Antiquoted Text f) where
|
||||||
instance (Arbitrary f) => Arbitrary (Antiquoted (NString f) f) where
|
instance (Arbitrary f) => Arbitrary (Antiquoted (NString f) f) where
|
||||||
arbitrary = genArb
|
arbitrary = genArb
|
||||||
|
|
||||||
-- This is written by hand so we can use `fairList` rather than
|
-- This is written by hand so we can use `fairList` rather than the normal
|
||||||
-- the normal list Arbitrary instance which makes the generator
|
-- list Arbitrary instance which makes the generator terminate. The
|
||||||
-- terminate. The distribution is not scientifically chosen.
|
-- distribution is not scientifically chosen.
|
||||||
instance Arbitrary f => Arbitrary (NExprF f) where
|
instance Arbitrary f => Arbitrary (NExprF f) where
|
||||||
arbitrary =
|
arbitrary =
|
||||||
sized $ \n ->
|
sized $ \n ->
|
||||||
if n < 2
|
if n < 2
|
||||||
then oneof [nConstant, nStr, nSym, nLiteralPath, nEnvPath ]
|
then oneof [genConstant, genStr, genSym, genLiteralPath, genEnvPath ]
|
||||||
else
|
else
|
||||||
frequency
|
frequency
|
||||||
[ (1, nConstant)
|
[ ( 1, genConstant)
|
||||||
, (1, nSym)
|
, ( 1, genSym)
|
||||||
, (4, resize (n `div` 3) nIf)
|
, ( 4, resize (n `div` 3) genIf)
|
||||||
, (10, nRecSet )
|
, (10, genRecSet )
|
||||||
, (20, nSet )
|
, (20, genSet )
|
||||||
, (5, nList )
|
, ( 5, genList )
|
||||||
, (2, nUnary )
|
, ( 2, genUnary )
|
||||||
, (2, resize (n `div` 3) nBinary )
|
, ( 2, resize (n `div` 3) genBinary )
|
||||||
, (3, resize (n `div` 3) nSelect )
|
, ( 3, resize (n `div` 3) genSelect )
|
||||||
, (20, resize (n `div` 2) nAbs )
|
, (20, resize (n `div` 2) genAbs )
|
||||||
, (2, resize (n `div` 2) nHasAttr )
|
, ( 2, resize (n `div` 2) genHasAttr )
|
||||||
, (10, resize (n `div` 2) nLet )
|
, (10, resize (n `div` 2) genLet )
|
||||||
, (10, resize (n `div` 2) nWith )
|
, (10, resize (n `div` 2) genWith )
|
||||||
, (1, resize (n `div` 2) nAssert)
|
, ( 1, resize (n `div` 2) genAssert)
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
nConstant = NConstant <$> arbitrary
|
genConstant = NConstant <$> arbitrary
|
||||||
nStr = NStr <$> arbitrary
|
genStr = NStr <$> arbitrary
|
||||||
nSym = NSym <$> asciiText
|
genSym = NSym <$> asciiText
|
||||||
nList = NList <$> fairList arbitrary
|
genList = NList <$> fairList arbitrary
|
||||||
nSet = NSet <$> fairList arbitrary
|
genSet = NSet <$> fairList arbitrary
|
||||||
nRecSet = NRecSet <$> fairList arbitrary
|
genRecSet = NRecSet <$> fairList arbitrary
|
||||||
nLiteralPath = NLiteralPath <$> asciiString
|
genLiteralPath = NLiteralPath . ("./" ++) <$> asciiString
|
||||||
nEnvPath = NEnvPath <$> asciiString
|
genEnvPath = NEnvPath <$> asciiString
|
||||||
nUnary = NUnary <$> arbitrary <*> arbitrary
|
genUnary = NUnary <$> arbitrary <*> arbitrary
|
||||||
nBinary = NBinary <$> arbitrary <*> arbitrary <*> arbitrary
|
genBinary = NBinary <$> arbitrary <*> arbitrary <*> arbitrary
|
||||||
nSelect = NSelect <$> arbitrary <*> arbitrary <*> arbitrary
|
genSelect = NSelect <$> arbitrary <*> arbitrary <*> arbitrary
|
||||||
nHasAttr = NHasAttr <$> arbitrary <*> arbitrary
|
genHasAttr = NHasAttr <$> arbitrary <*> arbitrary
|
||||||
nAbs = NAbs <$> arbitrary <*> arbitrary
|
genAbs = NAbs <$> arbitrary <*> arbitrary
|
||||||
nLet = NLet <$> arbitrary <*> arbitrary
|
genLet = NLet <$> fairList arbitrary <*> arbitrary
|
||||||
nIf = NIf <$> arbitrary <*> arbitrary <*> arbitrary
|
genIf = NIf <$> arbitrary <*> arbitrary <*> arbitrary
|
||||||
nWith = NWith <$> arbitrary <*> arbitrary
|
genWith = NWith <$> arbitrary <*> arbitrary
|
||||||
nAssert = NAssert <$> arbitrary <*> arbitrary
|
genAssert = NAssert <$> arbitrary <*> arbitrary
|
||||||
|
|
||||||
-- | Useful when there are recursive positions at each element of the list
|
-- | Useful when there are recursive positions at each element of the list as
|
||||||
-- as it divides the size by the length of the generated list.
|
-- it divides the size by the length of the generated list.
|
||||||
fairList :: Gen a -> Gen [a]
|
fairList :: Gen a -> Gen [a]
|
||||||
fairList g = do
|
fairList g = do
|
||||||
s <- getSize
|
s <- getSize
|
||||||
k <- choose (0, s)
|
k <- choose (0, s)
|
||||||
-- Use max here to avoid dividing by zero when there is the empty list
|
-- Use max here to avoid dividing by zero when there is the empty list
|
||||||
resize (s `div` (max 1 k)) $ vectorOf k g
|
resize (s `div` max 1 k) $ vectorOf k g
|
||||||
|
|
||||||
-- | Test that pretty . parse . pretty == pretty
|
equivUpToNormalization :: NExpr -> NExpr -> Bool
|
||||||
|
equivUpToNormalization x y = normalize x == normalize y
|
||||||
|
|
||||||
|
normalize :: NExpr -> NExpr
|
||||||
|
normalize = cata $ \case
|
||||||
|
NConstant (NInt n) | n < 0 -> Fix (NUnary NNeg (Fix (NConstant (NInt (negate n)))))
|
||||||
|
NConstant (NFloat n) | n < 0 -> Fix (NUnary NNeg (Fix (NConstant (NFloat (negate n)))))
|
||||||
|
|
||||||
|
NSet binds -> Fix (NSet (map normBinding binds))
|
||||||
|
NRecSet binds -> Fix (NRecSet (map normBinding binds))
|
||||||
|
NLet binds r -> Fix (NLet (map normBinding binds) r)
|
||||||
|
|
||||||
|
NAbs params r -> Fix (NAbs (normParams params) r)
|
||||||
|
|
||||||
|
r -> Fix r
|
||||||
|
|
||||||
|
where
|
||||||
|
normBinding (NamedVar path r) = NamedVar (NE.map normKey path) r
|
||||||
|
normBinding (Inherit mr names) = Inherit mr (map normKey names)
|
||||||
|
|
||||||
|
normKey (DynamicKey quoted) = DynamicKey (normAntiquotedString quoted)
|
||||||
|
normKey (StaticKey name _) = StaticKey name Nothing
|
||||||
|
|
||||||
|
normAntiquotedString :: Antiquoted (NString NExpr) NExpr
|
||||||
|
-> Antiquoted (NString NExpr) NExpr
|
||||||
|
normAntiquotedString (Plain (DoubleQuoted [EscapedNewline])) =
|
||||||
|
EscapedNewline
|
||||||
|
normAntiquotedString (Plain (DoubleQuoted strs)) =
|
||||||
|
let strs' = map normAntiquotedText strs
|
||||||
|
in if strs == strs'
|
||||||
|
then Plain (DoubleQuoted strs)
|
||||||
|
else normAntiquotedString (Plain (DoubleQuoted strs'))
|
||||||
|
normAntiquotedString r = r
|
||||||
|
|
||||||
|
normAntiquotedText :: Antiquoted Text NExpr -> Antiquoted Text NExpr
|
||||||
|
normAntiquotedText (Plain "\n") = EscapedNewline
|
||||||
|
normAntiquotedText (Plain "''\n") = EscapedNewline
|
||||||
|
normAntiquotedText r = r
|
||||||
|
|
||||||
|
normParams (ParamSet binds var (Just "")) = ParamSet binds var Nothing
|
||||||
|
normParams r = r
|
||||||
|
|
||||||
|
-- | Test that parse . pretty == id up to attribute position information.
|
||||||
prop_prettyparse :: NExpr -> P.Result
|
prop_prettyparse :: NExpr -> P.Result
|
||||||
prop_prettyparse p =
|
prop_prettyparse p =
|
||||||
case parse (pretty p) of
|
let prog = show (pretty p)
|
||||||
Failure s -> P.rejected { P.reason = show s ++ show (pretty p) }
|
in case parse (pack prog) of
|
||||||
Success v ->
|
Failure s -> P.rejected
|
||||||
let pp = normalise (unpack (pretty p))
|
{ P.reason = show $
|
||||||
pv = normalise (unpack (pretty v))
|
text "Parse failed:" </> text (show s)
|
||||||
in (P.liftBool (pp == pv)) { P.reason = "Bad parse:" ++ pp ++ pv ++ ppDiff (diff pp pv) ++ show p ++ show v}
|
P.<$> P.indent 2 (pretty p) }
|
||||||
|
Success v
|
||||||
|
| equivUpToNormalization p v -> P.succeeded
|
||||||
|
| otherwise ->
|
||||||
|
let pp = normalise prog
|
||||||
|
pv = normalise (show (pretty v))
|
||||||
|
in (P.liftBool (pp == pv))
|
||||||
|
{ P.reason = show $
|
||||||
|
text "----------------------------------------"
|
||||||
|
P.<$> text "Expr before:" P.<$> P.indent 2 (text (PS.ppShow p))
|
||||||
|
P.<$> text "----------------------------------------"
|
||||||
|
P.<$> text "Expr after:" P.<$> P.indent 2 (text (PS.ppShow v))
|
||||||
|
P.<$> text "----------------------------------------"
|
||||||
|
P.<$> text "Pretty before:" P.<$> P.indent 2 (text prog)
|
||||||
|
P.<$> text "----------------------------------------"
|
||||||
|
P.<$> text "Pretty after:" P.<$> P.indent 2 (pretty v)
|
||||||
|
P.<$> text "----------------------------------------"
|
||||||
|
P.<$> text "Normalised before:" P.<$> P.indent 2 (text pp)
|
||||||
|
P.<$> text "----------------------------------------"
|
||||||
|
P.<$> text "Normalised after:" P.<$> P.indent 2 (text pv)
|
||||||
|
P.<$> text "========================================"
|
||||||
|
P.<$> text "Normalised diff:"
|
||||||
|
P.<$> text (ppDiff (diff pp pv))
|
||||||
|
P.<$> text "========================================"
|
||||||
|
}
|
||||||
where
|
where
|
||||||
pretty = pack . show . prettyNix
|
pretty = prettyNix
|
||||||
parse = parseNixText
|
parse = parseNixText
|
||||||
|
|
||||||
normalise = unlines . map (reverse . dropWhile isSpace . reverse) . lines
|
normalise = unlines . map (reverse . dropWhile isSpace . reverse) . lines
|
||||||
|
|
||||||
diff :: String -> String -> [Diff [String]]
|
diff :: String -> String -> [Diff [String]]
|
||||||
diff s1 s2 = getDiff (map (:[]) (lines s1)) (map (:[]) (lines s2))
|
diff s1 s2 = getDiff (map (:[]) (lines s1)) (map (:[]) (lines s2))
|
||||||
|
|
||||||
tests :: TestTree
|
tests :: Int -> TestTree
|
||||||
tests = testProperty "Pretty Parse Property" prop_prettyparse
|
tests n = testProperty "Pretty/Parse Property" $
|
||||||
|
withMaxSuccess n prop_prettyparse
|
||||||
|
|
Loading…
Reference in a new issue