on master help sign in
Merge pull request #421 from maxsnew/test

Test Re-org and Start Property Testing

commitb0a856eb5f253b67f1fb992fbd49f7cde3c02718 authorEvan Czaplicki <info@elm-lang.org> dateMon 30 Dec 2013, 00:27 (13 years ago) parente34245adcac0e0
23 files changed+213−24
.gitignore+1 Elm.cabal+37−2 compiler/SourceSyntax/Literal.hs+2−2 compiler/SourceSyntax/Pattern.hs+2−2 tests/Main.hs+7−18 tests/Tests/Compiler.hs+38 tests/Tests/Property.hs+51 tests/Tests/Property/Arbitrary.hs+75 tests/bad/BBTArgs → tests/data/bad/BBTArgs tests/bad/InfiniteType.elm → tests/data/bad/InfiniteType.elm tests/bad/NonElementMain.elm → tests/data/bad/NonElementMain.elm tests/good/AliasSubstitution.elm → tests/data/good/AliasSubstitution.elm tests/good/NoExpressions.elm → tests/data/good/NoExpressions.elm tests/good/Otherwise.elm → tests/data/good/Otherwise.elm tests/good/QuotesAndComments.elm → tests/data/good/QuotesAndComments.elm tests/good/Soundness/Apply.elm → tests/data/good/Soundness/Apply.elm tests/good/Soundness/ApplyAnnotated.elm → tests/data/good/Soundness/ApplyAnnotated.elm tests/good/Soundness/Id.elm → tests/data/good/Soundness/Id.elm tests/good/Soundness/IdAnnotated.elm → tests/data/good/Soundness/IdAnnotated.elm tests/good/Soundness/TrickyId.elm → tests/data/good/Soundness/TrickyId.elm tests/good/Soundness/TrickyIdAnnotated.elm → tests/data/good/Soundness/TrickyIdAnnotated.elm tests/good/Unify/LockedVars.elm → tests/data/good/Unify/LockedVars.elm tests/good/Unify/NonHomogeneousRecords.elm → tests/data/good/Unify/NonHomogeneousRecords.elm
.gitignore+1
@@ -10,3 +10,4 @@ cabal-dev
1010data
1111*/ElmFiles/*
1212.DS_Store
13+*~
Elm.cabal+37−2
@@ -228,6 +228,41 @@ Executable elm-doc
228228
229229Test-Suite test-elm
230230 Type: exitcode-stdio-1.0
231− Hs-Source-Dirs: tests
231+ Hs-Source-Dirs: tests, compiler
232232 Main-is: Main.hs
233− build-depends: base, directory, HTF
233+ other-modules: Tests.Compiler
234+ Tests.Property
235+ Tests.Property.Arbitrary
236+ SourceSyntax.Helpers
237+ SourceSyntax.Literal
238+ SourceSyntax.PrettyPrint
239+ build-depends: base,
240+ directory,
241+ Elm,
242+ test-framework,
243+ test-framework-hunit,
244+ test-framework-quickcheck2,
245+ HUnit,
246+ pretty,
247+ QuickCheck >= 2 && < 3,
248+ filemanip,
249+ aeson,
250+ base >=4.2 && <5,
251+ binary >= 0.6.4.0,
252+ blaze-html == 0.5.* || == 0.6.*,
253+ blaze-markup == 0.5.1.*,
254+ bytestring,
255+ cmdargs,
256+ containers >= 0.3,
257+ directory,
258+ filepath,
259+ indents,
260+ language-ecmascript >=0.15 && < 1.0,
261+ mtl >= 2,
262+ pandoc >= 1.10,
263+ parsec >= 3.1.1,
264+ pretty,
265+ text,
266+ transformers >= 0.2,
267+ union-find,
268+ unordered-containers
compiler/SourceSyntax/Literal.hs+2−2
@@ -8,7 +8,7 @@ data Literal = IntNum Int
88 | Chr Char
99 | Str String
1010 | Boolean Bool
11− deriving (Eq, Ord, Show)
11+ deriving (Eq, Ord, Show)
1212
1313instance Pretty Literal where
1414 pretty literal =
@@ -17,4 +17,4 @@ instance Pretty Literal where
1717 FloatNum n -> PP.double n
1818 Chr c -> PP.quotes (PP.char c)
1919 Str s -> PP.text (show s)
20− Boolean bool -> PP.text (show bool)
20+ Boolean bool -> PP.text (show bool)
compiler/SourceSyntax/Pattern.hs+2−2
@@ -35,7 +35,7 @@ instance Pretty Pattern where
3535 PData name ps ->
3636 if isTuple name then
3737 PP.parens . commaCat $ map pretty ps
38− else sep (PP.text name : map prettyParens ps)
38+ else hsep (PP.text name : map prettyParens ps)
3939
4040prettyParens pattern = parensIf needsThem (pretty pattern)
4141 where
@@ -43,4 +43,4 @@ prettyParens pattern = parensIf needsThem (pretty pattern)
4343 case pattern of
4444 PData name (_:_) | not (isTuple name) -> True
4545 PAlias _ _ -> True
46− _ -> False
46+ _ -> False
tests/Main.hs+7−18
@@ -1,22 +1,11 @@
11module Main where
22
3−import System.Directory
4−import System.Exit (exitWith)
5−import System.Environment (getArgs)
6−import Test.Framework.TestManager
7−import Test.Framework.BlackBoxTest
3+import Test.Framework
84
9−main :: IO ()
10−main = do
11− args <- getArgs
12− tests <- blackBoxTests "tests" "dist/build/elm/elm" ".elm" bbtArgs
13− code <- runTestWithArgs args tests
14− removeDirectoryRecursive "cache"
15− removeDirectoryRecursive "build"
16− exitWith code
17−
18−bbtArgs = defaultBBTArgs { bbtArgs_stdoutDiff = ignoreDiff
19− , bbtArgs_stderrDiff = ignoreDiff }
5+import Tests.Compiler
6+import Tests.Property
207
21−ignoreDiff :: Diff
22−ignoreDiff _ _ = return Nothing
8+main :: IO ()
9+main = defaultMain [ compilerTests
10+ , propertyTests
11+ ]
tests/Tests/Compiler.hsnew file+38
@@ -0,0 +1,38 @@
1+module Tests.Compiler (compilerTests)
2+ where
3+
4+import Data.Functor ((<$>))
5+import Data.Traversable (traverse)
6+import System.FilePath ((</>))
7+import System.FilePath.Find (find, (==?), extension)
8+import Test.Framework
9+import Test.Framework.Providers.HUnit (testCase)
10+import Test.HUnit ((@=?), Assertion)
11+
12+import Elm.Internal.Utils as Elm
13+
14+compilerTests :: Test
15+compilerTests = buildTest $ do
16+ goods <- mkTests True =<< getElms "good"
17+ bads <- mkTests False =<< getElms "bad"
18+ return $ testGroup "Compile Tests"
19+ [
20+ testGroup "Good Tests" goods
21+ , testGroup "Bad Tests" bads
22+ ]
23+
24+ where getElms :: FilePath -> IO [FilePath]
25+ getElms fname = find (return True) (extension ==? ".elm") (testsDir </> fname)
26+
27+ mkTests :: Bool -> [FilePath] -> IO [Test]
28+ mkTests b = traverse setupTest
29+ where setupTest f = testCase f . mkCompileTest b <$> readFile f
30+
31+ testsDir = "tests" </> "data"
32+
33+mkCompileTest :: Bool -- ^ Expect success?
34+ -> String -- ^ File Contents
35+ -> Assertion
36+mkCompileTest succ modul = noCompileErr @=? succ
37+ where noCompileErr = either (const False) (const True) . Elm.compile $ modul
38+ expectation = "Compile " ++ if succ then "Success" else "Error"
tests/Tests/Property.hsnew file+51
@@ -0,0 +1,51 @@
1+module Tests.Property where
2+
3+import Control.Applicative ((<*))
4+import Test.Framework
5+import Test.Framework.Providers.HUnit
6+import Test.Framework.Providers.QuickCheck2
7+import Test.HUnit (assert)
8+import Test.QuickCheck
9+import Text.Parsec.Combinator (eof)
10+
11+import SourceSyntax.Literal as Lit
12+import SourceSyntax.Pattern as Pat
13+import SourceSyntax.PrettyPrint (Pretty, pretty)
14+import Parse.Helpers (IParser, iParse)
15+import Parse.Literal (literal)
16+import Parse.Pattern (expr)
17+import Tests.Property.Arbitrary
18+
19+propertyTests :: Test
20+propertyTests =
21+ testGroup "Parse/Print Agreement Tests"
22+ [
23+ testCase "Long Pattern test" $ assert (prop_parse_print expr longPat)
24+ , testProperty "Literal test" $ prop_parse_print literal
25+ , testProperty "Pattern test" $ prop_parse_print expr
26+ ]
27+
28+ where
29+ -- This test was autogenerated from the Pattern test and should be
30+ -- left in all its ugly glory.
31+ longPat = Pat.PData "I" [ Pat.PLiteral (Lit.Chr '+')
32+ , Pat.PRecord [
33+ "q7yclkcm7k_ikstrczv_"
34+ , "wQRv6gKsvvkjw4b5F"
35+ ,"c9'eFfhk9FTvsMnwF_D"
36+ ,"yqxhEkHvRFwZ"
37+ ,"o"
38+ ,"nbUlCn3y3NnkVoxhW"
39+ ,"iJ0MNy3KZ_lrs"
40+ ,"ug"
41+ ,"sHHsX"
42+ ,"mRKs9d"
43+ ,"o2KiCX5'ZRzHJfRi8" ]
44+ , Pat.PVar "su'BrrbPUK6I33Eq" ]
45+
46+prop_parse_print :: (Pretty a, Arbitrary a, Eq a) => IParser a -> a -> Bool
47+prop_parse_print p x =
48+ either (const False) (== x) . parse_print p $ x
49+
50+parse_print :: (Pretty a) => IParser a -> a -> Either String a
51+parse_print p = either (Left . show) (Right) . iParse (p <* eof) . show . pretty
tests/Tests/Property/Arbitrary.hsnew file+75
@@ -0,0 +1,75 @@
1+{-# OPTIONS_GHC -fno-warn-orphans #-}
2+module Tests.Property.Arbitrary where
3+
4+import Control.Applicative ((<$>), (<*>), pure)
5+import Test.QuickCheck.Arbitrary
6+import Test.QuickCheck.Gen
7+
8+import qualified Data.Set as Set
9+import qualified Parse.Helpers (reserveds)
10+
11+import SourceSyntax.Literal
12+import SourceSyntax.Pattern
13+
14+instance Arbitrary Literal where
15+ arbitrary = oneof [ IntNum <$> arbitrary
16+ , FloatNum <$> (arbitrary `suchThat` noE)
17+ , Chr <$> arbitrary
18+ -- This is too permissive
19+ , Str <$> arbitrary
20+ -- Booleans aren't actually source syntax
21+ -- , Boolean <$> arbitrary
22+ ]
23+ shrink l = case l of
24+ IntNum n -> IntNum <$> shrink n
25+ FloatNum f -> FloatNum <$> (filter noE . shrink $ f)
26+ Chr c -> Chr <$> shrink c
27+ Str s -> Str <$> shrink s
28+ Boolean b -> Boolean <$> shrink b
29+
30+noE :: Double -> Bool
31+noE = notElem 'e' . show
32+
33+
34+instance Arbitrary Pattern where
35+ arbitrary = sized pat
36+ where pat :: Int -> Gen Pattern
37+ pat n = oneof [ pure PAnything
38+ , PVar <$> lowVar
39+ , PRecord <$> (listOf1 lowVar)
40+ , PLiteral <$> arbitrary
41+ , PAlias <$> lowVar <*> pat (n-1)
42+ , PData <$> capVar <*> sizedPats
43+ ]
44+ where sizedPats = do
45+ len <- choose (0,n)
46+ let m = n `div` len in
47+ vectorOf len $ pat m
48+
49+ shrink pat = case pat of
50+ PAnything -> []
51+ PVar v -> PVar <$> shrinkWHead v
52+ PRecord fs -> PRecord <$> (filter (all $ not . null) . filter (not . null) $ shrink fs)
53+ PLiteral l -> PLiteral <$> shrink l
54+ PAlias s p -> p : (PAlias <$> shrinkWHead s <*> shrink p)
55+ PData s ps -> ps ++ (PData <$> shrinkWHead s <*> shrink ps)
56+ where shrinkWHead (x:xs) = (x:) <$> shrink xs
57+
58+lowVar :: Gen String
59+lowVar = notReserved $ (:) <$> lower <*> listOf varLetter
60+ where lower = elements ['a'..'z']
61+
62+capVar :: Gen String
63+capVar = notReserved $ (:) <$> upper <*> listOf varLetter
64+ where upper = elements ['A'..'Z']
65+
66+varLetter :: Gen Char
67+varLetter = elements $ ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ ['\'', '_']
68+
69+notReserved :: Gen String -> Gen String
70+notReserved = flip exceptFor Parse.Helpers.reserveds
71+
72+exceptFor :: (Ord a) => Gen a -> [a] -> Gen a
73+exceptFor g xs = g `suchThat` notAnX
74+ where notAnX = flip Set.notMember xset
75+ xset = Set.fromList xs
tests/bad/BBTArgs → tests/data/bad/BBTArgsrenamed

The content is the same.

tests/bad/InfiniteType.elm → tests/data/bad/InfiniteType.elmrenamed

The content is the same.

tests/bad/NonElementMain.elm → tests/data/bad/NonElementMain.elmrenamed

The content is the same.

tests/good/AliasSubstitution.elm → tests/data/good/AliasSubstitution.elmrenamed

The content is the same.

tests/good/NoExpressions.elm → tests/data/good/NoExpressions.elmrenamed

The content is the same.

tests/good/Otherwise.elm → tests/data/good/Otherwise.elmrenamed

The content is the same.

tests/good/QuotesAndComments.elm → tests/data/good/QuotesAndComments.elmrenamed

The content is the same.

tests/good/Soundness/Apply.elm → tests/data/good/Soundness/Apply.elmrenamed

The content is the same.

tests/good/Soundness/ApplyAnnotated.elm → tests/data/good/Soundness/ApplyAnnotated.elmrenamed

The content is the same.

tests/good/Soundness/Id.elm → tests/data/good/Soundness/Id.elmrenamed

The content is the same.

tests/good/Soundness/IdAnnotated.elm → tests/data/good/Soundness/IdAnnotated.elmrenamed

The content is the same.

tests/good/Soundness/TrickyId.elm → tests/data/good/Soundness/TrickyId.elmrenamed

The content is the same.

tests/good/Soundness/TrickyIdAnnotated.elm → tests/data/good/Soundness/TrickyIdAnnotated.elmrenamed

The content is the same.

tests/good/Unify/LockedVars.elm → tests/data/good/Unify/LockedVars.elmrenamed

The content is the same.

tests/good/Unify/NonHomogeneousRecords.elm → tests/data/good/Unify/NonHomogeneousRecords.elmrenamed

The content is the same.