mirror of
https://github.com/github/semantic.git
synced 2024-11-28 10:15:55 +03:00
158 lines
5.4 KiB
Haskell
158 lines
5.4 KiB
Haskell
{-# LANGUAGE AllowAmbiguousTypes #-}
|
||
{-# LANGUAGE OverloadedStrings #-}
|
||
{-# LANGUAGE ScopedTypeVariables #-}
|
||
{-# LANGUAGE TypeApplications #-}
|
||
{-# LANGUAGE TypeOperators #-}
|
||
module Main (main) where
|
||
|
||
import Analysis.Name (Name)
|
||
import qualified Analysis.Name as Name
|
||
import Control.Algebra
|
||
import Control.Carrier.Lift
|
||
import Control.Carrier.Sketch.Fresh
|
||
import Control.Monad
|
||
import qualified Data.ByteString as ByteString
|
||
import qualified Data.ScopeGraph as ScopeGraph
|
||
import qualified Language.Python ()
|
||
import qualified Language.Python as Py (Term)
|
||
import ScopeGraph.Convert
|
||
import Source.Loc
|
||
import qualified Source.Source as Source
|
||
import System.Exit (die)
|
||
import System.Path ((</>))
|
||
import qualified System.Path as Path
|
||
import qualified System.Path.Directory as Path
|
||
import qualified Test.Tasty as Tasty
|
||
import qualified Test.Tasty.HUnit as HUnit
|
||
import qualified TreeSitter.Python as TSP
|
||
import qualified TreeSitter.Unmarshal as TS
|
||
|
||
{-
|
||
|
||
The Python code here is
|
||
|
||
hello = ()
|
||
goodbye = ()
|
||
|
||
The graph should be
|
||
|
||
🏁
|
||
|
|
||
1️⃣----"hello"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
2️⃣----"goodbye"
|
||
|
||
-}
|
||
|
||
|
||
runScopeGraph :: ToScopeGraph t => Path.AbsRelFile -> Source.Source -> t Loc -> (ScopeGraph.ScopeGraph Name, Result)
|
||
runScopeGraph p _src item = run . runSketch (Just p) $ scopeGraph item
|
||
|
||
sampleGraphThing :: (Has Sketch sig m) => m Result
|
||
sampleGraphThing = do
|
||
declare "hello" (DeclProperties ScopeGraph.Assignment ScopeGraph.Default Nothing)
|
||
declare "goodbye" (DeclProperties ScopeGraph.Assignment ScopeGraph.Default Nothing)
|
||
pure Complete
|
||
|
||
graphFile :: FilePath -> IO (ScopeGraph.ScopeGraph Name, Result)
|
||
graphFile fp = do
|
||
file <- ByteString.readFile fp
|
||
tree <- TS.parseByteString @Py.Term @Loc TSP.tree_sitter_python file
|
||
pyModule <- either die pure tree
|
||
pure $ runScopeGraph (Path.absRel fp) (Source.fromUTF8 file) pyModule
|
||
|
||
|
||
assertSimpleAssignment :: HUnit.Assertion
|
||
assertSimpleAssignment = do
|
||
let path = "semantic-python/test/fixtures/1-04-toplevel-assignment.py"
|
||
(result, Complete) <- graphFile path
|
||
(expecto, Complete) <- runM $ runSketch Nothing sampleGraphThing
|
||
HUnit.assertEqual "Should work for simple case" expecto result
|
||
|
||
expectedReference :: (Has Sketch sig m) => m Result
|
||
expectedReference = do
|
||
declare "x" (DeclProperties ScopeGraph.Assignment ScopeGraph.Default Nothing)
|
||
reference "x" "x" RefProperties
|
||
pure Complete
|
||
|
||
assertSimpleReference :: HUnit.Assertion
|
||
assertSimpleReference = do
|
||
let path = "semantic-python/test/fixtures/5-01-simple-reference.py"
|
||
(result, Complete) <- graphFile path
|
||
(expecto, Complete) <- runM $ runSketch Nothing expectedReference
|
||
|
||
HUnit.assertEqual "Should work for simple case" expecto result
|
||
|
||
expectedLexicalScope :: (Has Sketch sig m) => m Result
|
||
expectedLexicalScope = do
|
||
_ <- declareFunction (Just $ Name.name "foo") (FunProperties ScopeGraph.Function)
|
||
reference "foo" "foo" RefProperties {}
|
||
pure Complete
|
||
|
||
expectedFunctionArg :: (Has Sketch sig m) => m Result
|
||
expectedFunctionArg = do
|
||
(_, associatedScope) <- declareFunction (Just $ Name.name "foo") (FunProperties ScopeGraph.Function)
|
||
withScope associatedScope $ do
|
||
declare "x" (DeclProperties ScopeGraph.Identifier ScopeGraph.Default Nothing)
|
||
reference "x" "x" RefProperties
|
||
pure ()
|
||
reference "foo" "foo" RefProperties
|
||
pure Complete
|
||
|
||
expectedImportHole :: (Has Sketch sig m) => m Result
|
||
expectedImportHole = do
|
||
addImportEdge Import ["cheese", "ints"]
|
||
|
||
|
||
|
||
assertLexicalScope :: HUnit.Assertion
|
||
assertLexicalScope = do
|
||
let path = "semantic-python/test/fixtures/5-02-simple-function.py"
|
||
(graph, _) <- graphFile path
|
||
case run (runSketch Nothing expectedLexicalScope) of
|
||
(expecto, Complete) -> HUnit.assertEqual "Should work for simple case" expecto graph
|
||
(_, Todo msg) -> HUnit.assertFailure ("Failed to complete:" <> show msg)
|
||
|
||
assertFunctionArg :: HUnit.Assertion
|
||
assertFunctionArg = do
|
||
let path = "semantic-python/test/fixtures/5-03-function-argument.py"
|
||
(graph, _) <- graphFile path
|
||
case run (runSketch Nothing expectedFunctionArg) of
|
||
(expecto, Complete) -> HUnit.assertEqual "Should work for simple case" expecto graph
|
||
(_, Todo msg) -> HUnit.assertFailure ("Failed to complete:" <> show msg)
|
||
|
||
assertImportHole :: HUnit.Assertion
|
||
assertImportHole = do
|
||
let path = "semantic-python/test/fixtures/cheese/6-01-imports.py"
|
||
(graph, _) <- graphFile path
|
||
case run (runSketch Nothing expectedImportHole) of
|
||
(expecto, Complete) -> HUnit.assertEqual "Should work for simple case" expecto graph
|
||
(_, Todo msg) -> HUnit.assertFailure ("Failed to complete:" <> show msg)
|
||
|
||
main :: IO ()
|
||
main = do
|
||
-- make sure we're in the root directory so the paths resolve properly
|
||
cwd <- Path.getCurrentDirectory
|
||
when (Path.takeDirName cwd == Just (Path.relDir "semantic-python"))
|
||
(Path.setCurrentDirectory (cwd </> Path.relDir ".."))
|
||
|
||
Tasty.defaultMain $
|
||
Tasty.testGroup "Tests" [
|
||
Tasty.testGroup "declare" [
|
||
HUnit.testCase "toplevel assignment" assertSimpleAssignment
|
||
],
|
||
Tasty.testGroup "reference" [
|
||
HUnit.testCase "simple reference" assertSimpleReference
|
||
],
|
||
Tasty.testGroup "lexical scopes" [
|
||
HUnit.testCase "simple function scope" assertLexicalScope
|
||
, HUnit.testCase "simple function argument" assertFunctionArg
|
||
],
|
||
Tasty.testGroup "imports" [
|
||
HUnit.testCase "simple function argument" assertImportHole
|
||
]
|
||
]
|