1
1
mirror of https://github.com/github/semantic.git synced 2024-12-19 21:01:35 +03:00
semantic/semantic-python/test/Test.hs

122 lines
5.1 KiB
Haskell
Raw Normal View History

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
2020-01-07 00:38:00 +03:00
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
2019-08-13 21:01:50 +03:00
module Main (main) where
import Analysis.Concrete (Concrete)
import qualified Analysis.Concrete as Concrete
2019-10-11 19:37:11 +03:00
import Analysis.File
2019-11-09 06:37:17 +03:00
import Control.Algebra
import Control.Carrier.Fail.Either
import Control.Carrier.Reader
2019-08-16 19:34:56 +03:00
import Control.Monad hiding (fail)
2019-08-13 21:01:50 +03:00
import Control.Monad.IO.Class
import Core.Core
2019-10-11 19:23:13 +03:00
import qualified Core.Eval as Eval
import Core.Name
import qualified Core.Parser
import Core.Pretty
2019-08-16 19:34:56 +03:00
import qualified Data.ByteString.Char8 as ByteString
2019-08-13 21:01:50 +03:00
import Data.Foldable
2019-08-16 20:20:08 +03:00
import Data.Function
import qualified Data.IntMap as IntMap
2019-08-29 16:32:39 +03:00
import Data.List (sort)
import qualified Data.Map as Map
2019-08-16 20:20:08 +03:00
import Data.Maybe
import Data.Text (Text)
2019-08-13 21:01:50 +03:00
import GHC.Stack
import qualified Language.Python.Core as Py
import Language.Python.Failure
2019-08-16 20:20:08 +03:00
import Prelude hiding (fail)
2019-10-10 21:18:56 +03:00
import Source.Span
2019-10-10 22:17:22 +03:00
import Syntax.Term
2019-12-20 19:04:42 +03:00
import Syntax.Var (closed)
2019-08-13 21:01:50 +03:00
import System.Directory
2019-08-16 20:20:08 +03:00
import System.Exit
import System.Path ((</>))
2019-09-18 21:41:58 +03:00
import qualified System.Path as Path
import qualified System.Path.Directory as Path
2019-10-15 20:10:18 +03:00
import qualified Text.Trifecta as Trifecta
2019-10-10 22:17:22 +03:00
import qualified TreeSitter.Python as TSP
import qualified TreeSitter.Unmarshal as TS
2019-08-13 21:01:50 +03:00
import qualified Test.Tasty as Tasty
import qualified Test.Tasty.HUnit as HUnit
2019-09-03 20:34:00 +03:00
import qualified Directive
import Instances ()
2019-08-16 19:34:56 +03:00
parsePrelude :: IO (Term (Ann Span :+: Core) Name)
parsePrelude = do
2019-10-15 20:10:18 +03:00
preludesrc <- ByteString.readFile "semantic-python/src/Prelude.score"
let ePrelude = Trifecta.parseByteString (Core.Parser.core <* Trifecta.eof) mempty preludesrc
case Trifecta.foldResult (Left . show) Right ePrelude of
2019-10-15 20:10:18 +03:00
Right r -> pure r
Left s -> HUnit.assertFailure ("Couldn't parse prelude: " <> s)
2019-10-15 20:10:18 +03:00
2019-10-30 20:40:36 +03:00
-- handles CHECK-RESULT directives
2019-12-20 18:57:33 +03:00
assertEvaluatesTo :: Term (Ann Span :+: Core) Name -> Text -> Concrete (Term (Ann Span :+: Core)) -> HUnit.Assertion
assertEvaluatesTo core k val = do
prelude <- parsePrelude
2019-12-20 19:04:42 +03:00
let withPrelude = (named' "__semantic_prelude" :<- prelude) >>>= core
allTogether <- maybe (HUnit.assertFailure ("Cant evaluate open term: " <> showCore (stripAnnotations withPrelude))) pure (closed withPrelude)
let filius = [File (Path.absRel "<interactive>") (Span (Pos 1 1) (Pos 1 1)) allTogether]
(heap, env) <- case Concrete.concrete Eval.eval filius of
2019-10-30 20:40:36 +03:00
(heap, [File _ _ (Right (Concrete.Record env))]) ->
pure (heap, env)
(_, [File _ _ (Left (_, span, err))]) ->
HUnit.assertFailure ("Failed evaluation (" <> show span <> "): " <> err)
(_, files) ->
HUnit.assertFailure ("Unexpected number of files: " <> show (length files))
let found = Map.lookup (name k) env >>= flip IntMap.lookup heap
found HUnit.@?= Just val
2020-01-07 00:37:49 +03:00
{-# HLINT ignore assertEvaluatesTo #-}
2019-10-30 20:40:36 +03:00
-- handles CHECK-TREE directives
assertTreeEqual :: Term Core Name -> Term Core Name -> HUnit.Assertion
assertTreeEqual t item = HUnit.assertEqual ("got (pretty)" <> showCore item) t item
2019-10-30 20:20:26 +03:00
checkPythonFile :: HasCallStack => Path.RelFile -> Tasty.TestTree
checkPythonFile fp = HUnit.testCaseSteps (Path.toString fp) $ \step -> withFrozenCallStack $ do
-- Extract the directives and the core associated with the provided file
2019-09-24 07:57:22 +03:00
let fullPath = Path.relDir "semantic-python/test/fixtures" </> fp
directives <- Directive.readDirectivesFromFile fullPath
result <- ByteString.readFile (Path.toString fullPath) >>= TS.parseByteString TSP.tree_sitter_python
-- Run the compiler
2019-11-09 06:37:17 +03:00
let coreResult = Control.Algebra.run
2019-09-19 22:35:25 +03:00
. runFail
. eliminateFailures
2019-12-11 23:47:03 +03:00
. Control.Algebra.run
2019-09-23 18:06:10 +03:00
. runReader @Py.Bindings mempty
. Py.toplevelCompile @(Failure :+: Ann Span :+: Core) @(Term _)
2019-09-19 22:35:25 +03:00
<$> result
2019-10-30 20:40:36 +03:00
-- Dispatch based on the result-directive pair
for_ directives $ \directive -> do
step (Directive.describe directive)
case (coreResult, directive) of
(Right (Left _), Directive.Fails) -> pure ()
(Left err, _) -> HUnit.assertFailure ("Parsing failed: " <> err)
(Right (Left err), _) -> HUnit.assertFailure ("Compilation failed: " <> err)
2019-10-31 21:17:45 +03:00
(Right (Right _), Directive.Fails) -> HUnit.assertFailure "Expected translation to fail"
(Right (Right item), Directive.Result k v) -> assertEvaluatesTo item k v
(Right (Right item), Directive.Tree t) -> assertTreeEqual (stripAnnotations item) t
2019-08-13 21:01:50 +03:00
milestoneFixtures :: IO Tasty.TestTree
2019-10-30 20:20:26 +03:00
milestoneFixtures = buildTests <$> readFiles
where
readFiles = liftIO . Path.filesInDir . Path.relDir $ "semantic-python/test/fixtures"
buildTests = Tasty.testGroup "Python" . fmap checkPythonFile . sort . filter (Path.hasExtension ".py")
2019-08-13 21:01:50 +03:00
main :: IO ()
2019-08-16 19:34:56 +03:00
main = do
jq <- findExecutable "jq"
when (isNothing jq) (die "Error: jq(1) not found in $PATH.")
milestoneFixtures >>= Tasty.defaultMain