1
1
mirror of https://github.com/github/semantic.git synced 2024-11-25 11:04:00 +03:00
semantic/semantic-core/test/Test.hs

120 lines
4.1 KiB
Haskell
Raw Normal View History

2019-10-10 21:06:47 +03:00
{-# LANGUAGE OverloadedStrings, TypeApplications, TypeOperators #-}
2019-06-04 18:26:42 +03:00
module Main (main) where
import qualified Text.Trifecta as Trifecta
import Hedgehog hiding (Var)
import Test.Tasty
import Test.Tasty.Hedgehog
import Test.Tasty.HUnit
import Core.Core
import Core.Core.Pretty
import Core.Core.Parser as Parse
2019-10-11 19:22:12 +03:00
import qualified Core.Eval as Eval
import Core.File
import Core.Name
import qualified Generators as Gen
2019-10-10 21:06:47 +03:00
import Source.Span
2019-10-10 22:17:22 +03:00
import Syntax.Term
2019-06-04 18:26:42 +03:00
-- * Helpers
2019-10-10 21:06:47 +03:00
true, false :: Term Core Name
2019-07-17 19:55:05 +03:00
true = bool True
false = bool False
2019-06-04 18:26:42 +03:00
parseEither :: Trifecta.Parser a -> String -> Either String a
parseEither p = Trifecta.foldResult (Left . show . Trifecta._errDoc) Right . Trifecta.parseString (p <* Trifecta.eof) mempty
-- * Parser roundtripping properties. Note that parsing and prettyprinting is generally
-- not a roundtrip, because the parser inserts 'Ann' nodes itself.
2019-10-10 21:06:47 +03:00
prop_roundtrips :: Gen (Term Core Name) -> Property
2019-06-04 18:26:42 +03:00
prop_roundtrips gen = property $ do
input <- forAll gen
2019-10-10 21:06:47 +03:00
tripping input showCore (parseEither (Parse.core <* Trifecta.eof))
2019-06-04 18:26:42 +03:00
parserProps :: TestTree
parserProps = testGroup "Parsing: roundtripping"
[ testProperty "literals" $ prop_roundtrips Gen.literal
, testProperty "if/then/else" . prop_roundtrips . Gen.ifthenelse $ Gen.variable
, testProperty "lambda" . prop_roundtrips $ Gen.lambda Gen.literal
, testProperty "function application" . prop_roundtrips $ Gen.apply Gen.variable
, testProperty "expressions" . prop_roundtrips $ Gen.expr
2019-06-04 18:26:42 +03:00
]
-- * Parser specs
2019-10-10 21:06:47 +03:00
parsesInto :: String -> Term Core Name -> Assertion
2019-06-04 18:26:42 +03:00
parsesInto str res = case parseEither Parse.core str of
Right x -> x @?= res
Left m -> assertFailure m
assert_booleans_parse :: Assertion
assert_booleans_parse = do
parseEither Parse.core "#true" @?= Right true
parseEither Parse.core "#false" @?= Right false
2019-10-10 21:06:47 +03:00
a, f, g, h :: Term Core Name
2019-07-17 19:55:05 +03:00
(a, f, g, h) = (pure "a", pure "f", pure "g", pure "h")
2019-06-04 18:26:42 +03:00
assert_ifthen_parse :: Assertion
2019-07-17 19:55:05 +03:00
assert_ifthen_parse = "if #true then #true else #false" `parsesInto` (if' true true false)
2019-06-04 18:26:42 +03:00
assert_application_parse :: Assertion
2019-07-17 19:55:05 +03:00
assert_application_parse = "f g" `parsesInto` (f $$ g)
2019-06-04 18:26:42 +03:00
assert_application_left_associative :: Assertion
2019-07-17 19:55:05 +03:00
assert_application_left_associative = "f g h" `parsesInto` (f $$ g $$ h)
2019-06-04 18:26:42 +03:00
assert_push_left_associative :: Assertion
2019-07-22 21:27:03 +03:00
assert_push_left_associative = "f.g.h" `parsesInto` (f ... "g" ... "h")
2019-06-04 18:26:42 +03:00
assert_ascii_lambda_parse :: Assertion
2019-07-17 19:55:05 +03:00
assert_ascii_lambda_parse = "\\a -> a" `parsesInto` lam (named' "a") a
2019-06-04 18:26:42 +03:00
assert_unicode_lambda_parse :: Assertion
2019-07-17 19:55:05 +03:00
assert_unicode_lambda_parse = "λa → a" `parsesInto` lam (named' "a") a
2019-06-04 18:26:42 +03:00
assert_quoted_name_parse :: Assertion
2019-07-17 19:55:05 +03:00
assert_quoted_name_parse = "#{(NilClass)}" `parsesInto` pure "(NilClass)"
2019-06-04 18:26:42 +03:00
parserSpecs :: TestTree
parserSpecs = testGroup "Parsing: simple specs"
[ testCase "true/false" assert_booleans_parse
, testCase "if/then/else" assert_ifthen_parse
, testCase "function application" assert_application_parse
, testCase "application is left-associative" assert_application_left_associative
, testCase "dotted push is left-associative" assert_push_left_associative
, testCase "lambda with ASCII syntax" assert_ascii_lambda_parse
, testCase "lambda with unicode syntax" assert_unicode_lambda_parse
, testCase "quoted names" assert_quoted_name_parse
]
2019-10-10 21:06:47 +03:00
assert_roundtrips :: File (Term Core Name) -> Assertion
assert_roundtrips (File _ _ core) = case parseEither Parse.core (showCore core) of
Right v -> v @?= core
Left e -> assertFailure e
2019-06-04 18:26:42 +03:00
parserExamples :: TestTree
parserExamples = testGroup "Parsing: Eval.hs examples"
[ testCase "prog1" (assert_roundtrips Eval.prog1)
, testCase "prog2" (assert_roundtrips Eval.prog2)
, testCase "prog3" (assert_roundtrips Eval.prog3)
, testCase "prog4" (assert_roundtrips Eval.prog4)
, testCase "prog6.1" (assert_roundtrips (head Eval.prog6))
, testCase "prog6.2" (assert_roundtrips (last Eval.prog6))
2019-10-10 21:11:34 +03:00
, testCase "ruby" (assert_roundtrips (stripAnnotations @Span <$> Eval.ruby))
2019-06-04 18:26:42 +03:00
]
tests :: TestTree
tests = testGroup "semantic-core"
[ parserSpecs
, parserExamples
, parserProps
]
main :: IO ()
main = defaultMain tests