mirror of
https://github.com/github/semantic.git
synced 2025-01-05 05:58:34 +03:00
Merge branch 'second-wait' of https://github.com/github/semantic into second-wait
This commit is contained in:
commit
9f2820feaa
@ -15,8 +15,9 @@ import qualified Semantic.AST as AST
|
||||
import Semantic.Config
|
||||
import qualified Semantic.Graph as Graph
|
||||
import qualified Semantic.Task as Task
|
||||
import Semantic.Task.Files
|
||||
import qualified Semantic.Telemetry.Log as Log
|
||||
import Semantic.Task.Files
|
||||
import Semantic.Telemetry
|
||||
import Semantic.Version
|
||||
import System.Exit (die)
|
||||
import System.FilePath
|
||||
@ -26,8 +27,9 @@ import Text.Read
|
||||
main :: IO ()
|
||||
main = do
|
||||
(options, task) <- customExecParser (prefs showHelpOnEmpty) arguments
|
||||
res <- Task.withOptions options $ \ config logger statter ->
|
||||
Task.runTaskWithConfig config { configSHA = Just buildSHA } logger statter task
|
||||
config <- defaultConfig options
|
||||
res <- withTelemetry config $ \ (TelemetryQueues logger statter _) ->
|
||||
Task.runTask (Task.TaskSession config "-" logger statter) task
|
||||
either (die . displayException) pure res
|
||||
|
||||
-- | A parser for the application's command-line arguments.
|
||||
@ -46,7 +48,7 @@ optionsParser = do
|
||||
(long "log-level" <> value (Just Log.Warning) <> help "Log messages at or above this level, or disable logging entirely.")
|
||||
failOnWarning <- switch (long "fail-on-warning" <> help "Fail on assignment warnings.")
|
||||
failOnParseError <- switch (long "fail-on-parse-error" <> help "Fail on tree-sitter parse errors.")
|
||||
pure $ Options logLevel Nothing failOnWarning failOnParseError
|
||||
pure $ Options logLevel failOnWarning failOnParseError
|
||||
|
||||
argumentsParser :: Parser (Task.TaskEff ())
|
||||
argumentsParser = do
|
||||
|
@ -52,16 +52,15 @@ data Config
|
||||
data Options
|
||||
= Options
|
||||
{ optionsLogLevel :: Maybe Level -- ^ What level of messages to log. 'Nothing' disables logging.
|
||||
, optionsRequestID :: Maybe String -- ^ Optional request id for tracing across systems.
|
||||
, optionsFailOnWarning :: Bool -- ^ Should semantic fail fast on assignment warnings (for testing)
|
||||
, optionsFailOnParseError :: Bool -- ^ Should semantic fail fast on tree-sitter parser errors (for testing)
|
||||
}
|
||||
|
||||
defaultOptions :: Options
|
||||
defaultOptions = Options (Just Warning) Nothing False False
|
||||
defaultOptions = Options (Just Warning) False False
|
||||
|
||||
debugOptions :: Options
|
||||
debugOptions = Options (Just Debug) Nothing False False
|
||||
debugOptions = Options (Just Debug) False False
|
||||
|
||||
defaultConfig :: Options -> IO Config
|
||||
defaultConfig options@Options{..} = do
|
||||
@ -111,8 +110,7 @@ logOptionsFromConfig Config{..} = LogOptions
|
||||
, ("hostname", configHostName)
|
||||
, ("sha", fromMaybe "development" configSHA)
|
||||
]
|
||||
<> [("request_id", x) | x <- toList (optionsRequestID configOptions) ]
|
||||
_ -> []
|
||||
_ -> []
|
||||
|
||||
|
||||
withLoggerFromConfig :: Config -> (LogQueue -> IO c) -> IO c
|
||||
|
@ -32,6 +32,7 @@ module Semantic.Task
|
||||
, distributeFoldMap
|
||||
-- * Configuration
|
||||
, debugOptions
|
||||
, defaultOptions
|
||||
, defaultConfig
|
||||
, terminalFormatter
|
||||
, logfmtFormatter
|
||||
@ -39,7 +40,7 @@ module Semantic.Task
|
||||
, runTask
|
||||
, runTaskWithOptions
|
||||
, withOptions
|
||||
, runTaskWithConfig
|
||||
, TaskSession(..)
|
||||
, runTraceInTelemetry
|
||||
, runTaskF
|
||||
-- * Exceptions
|
||||
@ -91,7 +92,6 @@ import Semantic.Timeout
|
||||
import Semantic.Resolution
|
||||
import Semantic.Telemetry
|
||||
import Serializing.Format hiding (Options)
|
||||
import System.Exit (die)
|
||||
|
||||
-- | A high-level task producing some result, e.g. parsing, diffing, rendering. 'Task's can also specify explicit concurrency via 'distribute', 'distributeFor', and 'distributeFoldMap'
|
||||
type TaskEff
|
||||
@ -150,33 +150,17 @@ serialize :: (Member Task sig, Carrier sig m)
|
||||
-> m Builder
|
||||
serialize format input = send (Serialize format input ret)
|
||||
|
||||
-- | Execute a 'Task' with the 'defaultOptions', yielding its result value in 'IO'.
|
||||
--
|
||||
-- > runTask = runTaskWithOptions defaultOptions
|
||||
runTask :: TaskEff a
|
||||
-> IO a
|
||||
runTask = runTaskWithOptions defaultOptions
|
||||
|
||||
-- | Execute a 'TaskEff' with the passed 'Options', yielding its result value in 'IO'.
|
||||
runTaskWithOptions :: Options
|
||||
-> TaskEff a
|
||||
-> IO a
|
||||
runTaskWithOptions opts task = withOptions opts (\ config logger statter -> runTaskWithConfig config logger statter task) >>= either (die . displayException) pure
|
||||
|
||||
withOptions :: Options
|
||||
-> (Config -> LogQueue -> StatQueue -> IO a)
|
||||
-> IO a
|
||||
withOptions options with = do
|
||||
config <- defaultConfig options
|
||||
withTelemetry config (\ (TelemetryQueues logger statter _) -> with config logger statter)
|
||||
data TaskSession
|
||||
= TaskSession
|
||||
{ config :: Config
|
||||
, requestID :: String
|
||||
, logger :: LogQueue
|
||||
, statter :: StatQueue
|
||||
}
|
||||
|
||||
-- | Execute a 'TaskEff' yielding its result value in 'IO'.
|
||||
runTaskWithConfig :: Config
|
||||
-> LogQueue
|
||||
-> StatQueue
|
||||
-> TaskEff a
|
||||
-> IO (Either SomeException a)
|
||||
runTaskWithConfig options logger statter task = do
|
||||
runTask :: TaskSession -> TaskEff a -> IO (Either SomeException a)
|
||||
runTask TaskSession{..} task = do
|
||||
(result, stat) <- withTiming "run" [] $ do
|
||||
let run :: TaskEff a -> IO (Either SomeException a)
|
||||
run
|
||||
@ -187,7 +171,7 @@ runTaskWithConfig options logger statter task = do
|
||||
. runError
|
||||
. runTelemetry logger statter
|
||||
. runTraceInTelemetry
|
||||
. runReader options
|
||||
. runReader config
|
||||
. Files.runFiles
|
||||
. runResolution
|
||||
. runTaskF
|
||||
@ -195,6 +179,17 @@ runTaskWithConfig options logger statter task = do
|
||||
queueStat statter stat
|
||||
pure result
|
||||
|
||||
-- | Execute a 'TaskEff' yielding its result value in 'IO' using all default options and configuration.
|
||||
runTaskWithOptions :: Options -> TaskEff a -> IO (Either SomeException a)
|
||||
runTaskWithOptions options task = withOptions options $ \ config logger statter ->
|
||||
runTask (TaskSession config "-" logger statter) task
|
||||
|
||||
-- | Yield config and telemetry queues for options.
|
||||
withOptions :: Options -> (Config -> LogQueue -> StatQueue -> IO a) -> IO a
|
||||
withOptions options with = do
|
||||
config <- defaultConfig options
|
||||
withTelemetry config (\ (TelemetryQueues logger statter _) -> with config logger statter)
|
||||
|
||||
runTraceInTelemetry :: (Member Telemetry sig, Carrier sig m, Monad m)
|
||||
=> Eff (TraceInTelemetryC m) a
|
||||
-> m a
|
||||
|
@ -33,7 +33,6 @@ import Semantic.Analysis
|
||||
import Semantic.Config
|
||||
import Semantic.Graph
|
||||
import Semantic.Task
|
||||
import Semantic.Telemetry (LogQueue, StatQueue)
|
||||
import System.Exit (die)
|
||||
import System.FilePath.Posix (takeDirectory)
|
||||
|
||||
@ -83,7 +82,7 @@ evalTypeScriptProject = justEvaluating <=< evaluateProject (Proxy :: Proxy 'Lang
|
||||
typecheckGoFile = checking <=< evaluateProjectWithCaching (Proxy :: Proxy 'Language.Go) goParser
|
||||
typecheckRubyFile = checking <=< evaluateProjectWithCaching (Proxy :: Proxy 'Language.Ruby) rubyParser
|
||||
|
||||
callGraphProject parser proxy opts paths = runTaskWithOptions opts $ do
|
||||
callGraphProject parser proxy paths = runTask' $ do
|
||||
blobs <- catMaybes <$> traverse readBlobFromFile (flip File (Language.reflect proxy) <$> paths)
|
||||
package <- fmap snd <$> parsePackage parser (Project (takeDirectory (maybe "/" fst (uncons paths))) blobs (Language.reflect proxy) [])
|
||||
modules <- topologicalSort <$> runImportGraphToModules proxy package
|
||||
@ -92,28 +91,29 @@ callGraphProject parser proxy opts paths = runTaskWithOptions opts $ do
|
||||
|
||||
evaluatePythonProject = justEvaluating <=< evaluatePythonProjects (Proxy @'Language.Python) pythonParser Language.Python
|
||||
|
||||
callGraphRubyProject = callGraphProject rubyParser (Proxy @'Language.Ruby) debugOptions
|
||||
callGraphRubyProject = callGraphProject rubyParser (Proxy @'Language.Ruby)
|
||||
|
||||
evaluateProject proxy parser paths = withOptions debugOptions $ \ config logger statter ->
|
||||
evaluateProject' (TaskSession config "-" logger statter) proxy parser paths
|
||||
|
||||
-- Evaluate a project consisting of the listed paths.
|
||||
evaluateProject proxy parser paths = withOptions debugOptions $ \ config logger statter ->
|
||||
evaluateProject' (TaskConfig config logger statter) proxy parser paths
|
||||
-- TODO: This is used by our specs and should be moved into SpecHelpers.hs
|
||||
evaluateProject' session proxy parser paths = do
|
||||
res <- runTask session $ do
|
||||
blobs <- catMaybes <$> traverse readBlobFromFile (flip File (Language.reflect proxy) <$> paths)
|
||||
package <- fmap (quieterm . snd) <$> parsePackage parser (Project (takeDirectory (maybe "/" fst (uncons paths))) blobs (Language.reflect proxy) [])
|
||||
modules <- topologicalSort <$> runImportGraphToModules proxy package
|
||||
trace $ "evaluating with load order: " <> show (map (modulePath . moduleInfo) modules)
|
||||
pure (id @(Evaluator _ Precise (Value _ Precise) _ _)
|
||||
(runModuleTable
|
||||
(runModules (ModuleTable.modulePaths (packageModules package))
|
||||
(raiseHandler (runReader (packageInfo package))
|
||||
(raiseHandler (evalState (lowerBound @Span))
|
||||
(raiseHandler (runReader (lowerBound @Span))
|
||||
(evaluate proxy (runDomainEffects (evalTerm withTermSpans)) modules)))))))
|
||||
either (die . displayException) pure res
|
||||
|
||||
data TaskConfig = TaskConfig Config LogQueue StatQueue
|
||||
|
||||
evaluateProject' (TaskConfig config logger statter) proxy parser paths = either (die . displayException) pure <=< runTaskWithConfig config logger statter $ do
|
||||
blobs <- catMaybes <$> traverse readBlobFromFile (flip File (Language.reflect proxy) <$> paths)
|
||||
package <- fmap (quieterm . snd) <$> parsePackage parser (Project (takeDirectory (maybe "/" fst (uncons paths))) blobs (Language.reflect proxy) [])
|
||||
modules <- topologicalSort <$> runImportGraphToModules proxy package
|
||||
trace $ "evaluating with load order: " <> show (map (modulePath . moduleInfo) modules)
|
||||
pure (id @(Evaluator _ Precise (Value _ Precise) _ _)
|
||||
(runModuleTable
|
||||
(runModules (ModuleTable.modulePaths (packageModules package))
|
||||
(raiseHandler (runReader (packageInfo package))
|
||||
(raiseHandler (evalState (lowerBound @Span))
|
||||
(raiseHandler (runReader (lowerBound @Span))
|
||||
(evaluate proxy (runDomainEffects (evalTerm withTermSpans)) modules)))))))
|
||||
|
||||
evaluatePythonProjects proxy parser lang path = runTaskWithOptions debugOptions $ do
|
||||
evaluatePythonProjects proxy parser lang path = runTask' $ do
|
||||
project <- readProject Nothing path lang []
|
||||
package <- fmap quieterm <$> parsePythonPackage parser project
|
||||
modules <- topologicalSort <$> runImportGraphToModules proxy package
|
||||
@ -127,7 +127,7 @@ evaluatePythonProjects proxy parser lang path = runTaskWithOptions debugOptions
|
||||
(evaluate proxy (runDomainEffects (evalTerm withTermSpans)) modules)))))))
|
||||
|
||||
|
||||
evaluateProjectWithCaching proxy parser path = runTaskWithOptions debugOptions $ do
|
||||
evaluateProjectWithCaching proxy parser path = runTask' $ do
|
||||
project <- readProject Nothing path (Language.reflect proxy) []
|
||||
package <- fmap (quieterm . snd) <$> parsePackage parser project
|
||||
modules <- topologicalSort <$> runImportGraphToModules proxy package
|
||||
@ -141,10 +141,13 @@ evaluateProjectWithCaching proxy parser path = runTaskWithOptions debugOptions $
|
||||
|
||||
|
||||
parseFile :: Parser term -> FilePath -> IO term
|
||||
parseFile parser = runTask . (parse parser <=< readBlob . file)
|
||||
parseFile parser = runTask' . (parse parser <=< readBlob . file)
|
||||
|
||||
blob :: FilePath -> IO Blob
|
||||
blob = runTask . readBlob . file
|
||||
blob = runTask' . readBlob . file
|
||||
|
||||
runTask' :: TaskEff a -> IO a
|
||||
runTask' task = runTaskWithOptions debugOptions task >>= either (die . displayException) pure
|
||||
|
||||
mergeErrors :: Either (SomeError (Sum errs)) (Either (SomeError err) result) -> Either (SomeError (Sum (err ': errs))) result
|
||||
mergeErrors = either (\ (SomeError sum) -> Left (SomeError (weaken sum))) (either (\ (SomeError err) -> Left (SomeError (inject err))) Right)
|
||||
|
@ -7,8 +7,8 @@ import qualified Language.Go.Assignment as Go
|
||||
import SpecHelpers
|
||||
|
||||
|
||||
spec :: TaskConfig -> Spec
|
||||
spec config = parallel $ do
|
||||
spec :: TaskSession -> Spec
|
||||
spec session = parallel $ do
|
||||
describe "Go" $ do
|
||||
it "imports and wildcard imports" $ do
|
||||
(scopeGraph, (heap, res)) <- evaluate ["main.go", "foo/foo.go", "bar/bar.go", "bar/rab.go"]
|
||||
@ -33,4 +33,4 @@ spec config = parallel $ do
|
||||
where
|
||||
fixtures = "test/fixtures/go/analysis/"
|
||||
evaluate = evalGoProject . map (fixtures <>)
|
||||
evalGoProject = testEvaluating <=< evaluateProject' config (Proxy :: Proxy 'Language.Go) goParser
|
||||
evalGoProject = testEvaluating <=< evaluateProject' session (Proxy :: Proxy 'Language.Go) goParser
|
||||
|
@ -9,8 +9,8 @@ import qualified Language.PHP.Assignment as PHP
|
||||
import SpecHelpers
|
||||
|
||||
|
||||
spec :: TaskConfig -> Spec
|
||||
spec config = parallel $ do
|
||||
spec :: TaskSession -> Spec
|
||||
spec session = parallel $ do
|
||||
describe "PHP" $ do
|
||||
xit "evaluates include and require" $ do
|
||||
(scopeGraph, (heap, res)) <- evaluate ["main.php", "foo.php", "bar.php"]
|
||||
@ -46,4 +46,4 @@ spec config = parallel $ do
|
||||
where
|
||||
fixtures = "test/fixtures/php/analysis/"
|
||||
evaluate = evalPHPProject . map (fixtures <>)
|
||||
evalPHPProject = testEvaluating <=< evaluateProject' config (Proxy :: Proxy 'Language.PHP) phpParser
|
||||
evalPHPProject = testEvaluating <=< evaluateProject' session (Proxy :: Proxy 'Language.PHP) phpParser
|
||||
|
@ -9,8 +9,8 @@ import qualified Data.Language as Language
|
||||
import SpecHelpers
|
||||
|
||||
|
||||
spec :: TaskConfig -> Spec
|
||||
spec config = parallel $ do
|
||||
spec :: TaskSession -> Spec
|
||||
spec session = parallel $ do
|
||||
describe "Python" $ do
|
||||
it "imports" $ do
|
||||
(scopeGraph, (heap, res)) <- evaluate ["main.py", "a.py", "b/__init__.py", "b/c.py"]
|
||||
@ -72,4 +72,4 @@ spec config = parallel $ do
|
||||
where
|
||||
fixtures = "test/fixtures/python/analysis/"
|
||||
evaluate = evalPythonProject . map (fixtures <>)
|
||||
evalPythonProject = testEvaluating <=< evaluateProject' config (Proxy :: Proxy 'Language.Python) pythonParser
|
||||
evalPythonProject = testEvaluating <=< evaluateProject' session (Proxy :: Proxy 'Language.Python) pythonParser
|
||||
|
@ -14,8 +14,8 @@ import Data.Sum
|
||||
import SpecHelpers
|
||||
|
||||
|
||||
spec :: TaskConfig -> Spec
|
||||
spec config = parallel $ do
|
||||
spec :: TaskSession -> Spec
|
||||
spec session = parallel $ do
|
||||
describe "Ruby" $ do
|
||||
it "evaluates require_relative" $ do
|
||||
(scopeGraph, (heap, res)) <- evaluate ["main.rb", "foo.rb"]
|
||||
@ -101,4 +101,4 @@ spec config = parallel $ do
|
||||
where
|
||||
fixtures = "test/fixtures/ruby/analysis/"
|
||||
evaluate = evalRubyProject . map (fixtures <>)
|
||||
evalRubyProject = testEvaluating <=< evaluateProject' config (Proxy :: Proxy 'Language.Ruby) rubyParser
|
||||
evalRubyProject = testEvaluating <=< evaluateProject' session (Proxy :: Proxy 'Language.Ruby) rubyParser
|
||||
|
@ -24,8 +24,8 @@ import Data.Text (pack)
|
||||
import qualified Language.TypeScript.Assignment as TypeScript
|
||||
import SpecHelpers
|
||||
|
||||
spec :: TaskConfig -> Spec
|
||||
spec config = parallel $ do
|
||||
spec :: TaskSession -> Spec
|
||||
spec session = parallel $ do
|
||||
describe "TypeScript" $ do
|
||||
it "qualified export from" $ do
|
||||
(scopeGraph, (heap, res)) <- evaluate ["main6.ts", "baz.ts", "foo.ts"]
|
||||
@ -184,7 +184,7 @@ spec config = parallel $ do
|
||||
where
|
||||
fixtures = "test/fixtures/typescript/analysis/"
|
||||
evaluate = evalTypeScriptProject . map (fixtures <>)
|
||||
evalTypeScriptProject = testEvaluating <=< (evaluateProject' config (Proxy :: Proxy 'Language.TypeScript) typescriptParser)
|
||||
evalTypeScriptProject = testEvaluating <=< (evaluateProject' session (Proxy :: Proxy 'Language.TypeScript) typescriptParser)
|
||||
|
||||
type TypeScriptTerm = Quieterm (Sum TypeScript.Syntax) Location
|
||||
type TypeScriptEvalError = BaseError (EvalError TypeScriptTerm Precise (Concrete.Value TypeScriptTerm Precise))
|
||||
|
@ -22,7 +22,6 @@ import Semantic.Config (Config (..), Options (..), defaultOptions)
|
||||
import qualified Semantic.IO as IO
|
||||
import Semantic.Task
|
||||
import Semantic.Task.Files
|
||||
import Semantic.Util (TaskConfig (..))
|
||||
import System.Directory
|
||||
import System.Exit (die)
|
||||
import System.FilePath.Glob
|
||||
@ -33,7 +32,7 @@ import Test.Hspec
|
||||
|
||||
main :: IO ()
|
||||
main = withOptions opts $ \ config logger statter -> hspec . parallel $ do
|
||||
let args = TaskConfig config logger statter
|
||||
let args = TaskSession config "-" logger statter
|
||||
|
||||
runIO setupExampleRepos
|
||||
|
||||
@ -42,11 +41,11 @@ main = withOptions opts $ \ config logger statter -> hspec . parallel $ do
|
||||
parallel . describe languageName $ parseExamples args lang tsDir
|
||||
|
||||
where
|
||||
parseExamples (TaskConfig config logger statter) LanguageExample{..} tsDir = do
|
||||
parseExamples session LanguageExample{..} tsDir = do
|
||||
knownFailures <- runIO $ knownFailuresForPath tsDir languageKnownFailuresTxt
|
||||
files <- runIO $ globDir1 (compile ("**/*" <> languageExtension)) (tsDir </> languageExampleDir)
|
||||
for_ files $ \file -> it file $ do
|
||||
res <- runTaskWithConfig config logger statter (parseFilePath file)
|
||||
res <- runTask session (parseFilePath file)
|
||||
case res of
|
||||
Left (SomeException e) -> case cast e of
|
||||
-- We have a number of known assignment timeouts, consider these pending specs instead of failing the build.
|
||||
|
@ -18,7 +18,7 @@ import Semantic.Config (defaultOptions)
|
||||
import Semantic.Graph
|
||||
import Semantic.IO
|
||||
|
||||
callGraphPythonProject paths = runTask $ do
|
||||
callGraphPythonProject paths = runTaskOrDie $ do
|
||||
let proxy = Proxy @'Language.Python
|
||||
let lang = Language.Python
|
||||
blobs <- catMaybes <$> traverse readBlobFromFile (flip File lang <$> paths)
|
||||
|
@ -11,7 +11,7 @@ import SpecHelpers
|
||||
languages :: [FilePath]
|
||||
languages = ["go", "javascript", "json", "python", "ruby", "typescript"]
|
||||
|
||||
spec :: TaskConfig -> Spec
|
||||
spec :: TaskSession -> Spec
|
||||
spec config = parallel $ do
|
||||
for_ languages $ \language -> do
|
||||
let dir = "test/fixtures" </> language </> "corpus"
|
||||
@ -81,13 +81,13 @@ examples directory = do
|
||||
normalizeName :: FilePath -> FilePath
|
||||
normalizeName path = dropExtension $ dropExtension path
|
||||
|
||||
testParse :: TaskConfig -> FilePath -> FilePath -> Expectation
|
||||
testParse config path expectedOutput = do
|
||||
actual <- verbatim <$> parseFilePath config path
|
||||
testParse :: TaskSession -> FilePath -> FilePath -> Expectation
|
||||
testParse session path expectedOutput = do
|
||||
actual <- verbatim <$> parseFilePath session path
|
||||
expected <- verbatim <$> B.readFile expectedOutput
|
||||
actual `shouldBe` expected
|
||||
|
||||
testDiff :: TaskConfig -> Both FilePath -> FilePath -> Expectation
|
||||
testDiff :: TaskSession -> Both FilePath -> FilePath -> Expectation
|
||||
testDiff config paths expectedOutput = do
|
||||
actual <- verbatim <$> diffFilePaths config paths
|
||||
expected <- verbatim <$> B.readFile expectedOutput
|
||||
|
@ -57,7 +57,7 @@ spec = parallel $ do
|
||||
|
||||
it "summarizes changed methods" $ do
|
||||
sourceBlobs <- blobsForPaths (Both "ruby/toc/methods.A.rb" "ruby/toc/methods.B.rb")
|
||||
diff <- runTask $ diffWithParser rubyParser sourceBlobs
|
||||
diff <- runTaskOrDie $ diffWithParser rubyParser sourceBlobs
|
||||
diffTOC diff `shouldBe`
|
||||
[ TOCSummary "Method" "self.foo" (Span (Pos 1 1) (Pos 2 4)) "added"
|
||||
, TOCSummary "Method" "bar" (Span (Pos 4 1) (Pos 6 4)) "modified"
|
||||
@ -66,7 +66,7 @@ spec = parallel $ do
|
||||
|
||||
xit "summarizes changed classes" $ do
|
||||
sourceBlobs <- blobsForPaths (Both "ruby/toc/classes.A.rb" "ruby/toc/classes.B.rb")
|
||||
diff <- runTask $ diffWithParser rubyParser sourceBlobs
|
||||
diff <- runTaskOrDie $ diffWithParser rubyParser sourceBlobs
|
||||
diffTOC diff `shouldBe`
|
||||
[ TOCSummary "Class" "Baz" (Span (Pos 1 1) (Pos 2 4)) "removed"
|
||||
, TOCSummary "Class" "Foo" (Span (Pos 1 1) (Pos 3 4)) "modified"
|
||||
@ -75,37 +75,37 @@ spec = parallel $ do
|
||||
|
||||
it "dedupes changes in same parent method" $ do
|
||||
sourceBlobs <- blobsForPaths (Both "javascript/toc/duplicate-parent.A.js" "javascript/toc/duplicate-parent.B.js")
|
||||
diff <- runTask $ diffWithParser typescriptParser sourceBlobs
|
||||
diff <- runTaskOrDie $ diffWithParser typescriptParser sourceBlobs
|
||||
diffTOC diff `shouldBe`
|
||||
[ TOCSummary "Function" "myFunction" (Span (Pos 1 1) (Pos 6 2)) "modified" ]
|
||||
|
||||
it "dedupes similar methods" $ do
|
||||
sourceBlobs <- blobsForPaths (Both "javascript/toc/erroneous-duplicate-method.A.js" "javascript/toc/erroneous-duplicate-method.B.js")
|
||||
diff <- runTask $ diffWithParser typescriptParser sourceBlobs
|
||||
diff <- runTaskOrDie $ diffWithParser typescriptParser sourceBlobs
|
||||
diffTOC diff `shouldBe`
|
||||
[ TOCSummary "Function" "performHealthCheck" (Span (Pos 8 1) (Pos 29 2)) "modified" ]
|
||||
|
||||
it "summarizes Go methods with receivers with special formatting" $ do
|
||||
sourceBlobs <- blobsForPaths (Both "go/toc/method-with-receiver.A.go" "go/toc/method-with-receiver.B.go")
|
||||
diff <- runTask $ diffWithParser goParser sourceBlobs
|
||||
diff <- runTaskOrDie $ diffWithParser goParser sourceBlobs
|
||||
diffTOC diff `shouldBe`
|
||||
[ TOCSummary "Method" "(*apiClient) CheckAuth" (Span (Pos 3 1) (Pos 3 101)) "added" ]
|
||||
|
||||
it "summarizes Ruby methods that start with two identifiers" $ do
|
||||
sourceBlobs <- blobsForPaths (Both "ruby/toc/method-starts-with-two-identifiers.A.rb" "ruby/toc/method-starts-with-two-identifiers.B.rb")
|
||||
diff <- runTask $ diffWithParser rubyParser sourceBlobs
|
||||
diff <- runTaskOrDie $ diffWithParser rubyParser sourceBlobs
|
||||
diffTOC diff `shouldBe`
|
||||
[ TOCSummary "Method" "foo" (Span (Pos 1 1) (Pos 4 4)) "modified" ]
|
||||
|
||||
it "handles unicode characters in file" $ do
|
||||
sourceBlobs <- blobsForPaths (Both "ruby/toc/unicode.A.rb" "ruby/toc/unicode.B.rb")
|
||||
diff <- runTask $ diffWithParser rubyParser sourceBlobs
|
||||
diff <- runTaskOrDie $ diffWithParser rubyParser sourceBlobs
|
||||
diffTOC diff `shouldBe`
|
||||
[ TOCSummary "Method" "foo" (Span (Pos 6 1) (Pos 7 4)) "added" ]
|
||||
|
||||
it "properly slices source blob that starts with a newline and has multi-byte chars" $ do
|
||||
sourceBlobs <- blobsForPaths (Both "javascript/toc/starts-with-newline.js" "javascript/toc/starts-with-newline.js")
|
||||
diff <- runTaskWithOptions (defaultOptions { optionsLogLevel = Nothing }) $ diffWithParser typescriptParser sourceBlobs
|
||||
diff <- runTaskOrDie $ diffWithParser typescriptParser sourceBlobs
|
||||
diffTOC diff `shouldBe` []
|
||||
|
||||
prop "inserts of methods and functions are summarized" . forAll ((not . isMethodOrFunction . Prelude.snd) `filterT` tiers) $
|
||||
@ -148,22 +148,22 @@ spec = parallel $ do
|
||||
describe "diff with ToCDiffRenderer'" $ do
|
||||
it "produces JSON output" $ do
|
||||
blobs <- blobsForPaths (Both "ruby/toc/methods.A.rb" "ruby/toc/methods.B.rb")
|
||||
output <- runTask (diffSummaryBuilder Format.JSON [blobs])
|
||||
output <- runTaskOrDie (diffSummaryBuilder Format.JSON [blobs])
|
||||
runBuilder output `shouldBe` ("{\"changes\":{\"test/fixtures/ruby/toc/methods.A.rb -> test/fixtures/ruby/toc/methods.B.rb\":[{\"span\":{\"start\":[1,1],\"end\":[2,4]},\"category\":\"Method\",\"term\":\"self.foo\",\"changeType\":\"added\"},{\"span\":{\"start\":[4,1],\"end\":[6,4]},\"category\":\"Method\",\"term\":\"bar\",\"changeType\":\"modified\"},{\"span\":{\"start\":[4,1],\"end\":[5,4]},\"category\":\"Method\",\"term\":\"baz\",\"changeType\":\"removed\"}]},\"errors\":{}}\n" :: ByteString)
|
||||
|
||||
it "produces JSON output if there are parse errors" $ do
|
||||
blobs <- blobsForPaths (Both "ruby/toc/methods.A.rb" "ruby/toc/methods.X.rb")
|
||||
output <- runTaskWithOptions (defaultOptions { optionsLogLevel = Nothing }) (diffSummaryBuilder Format.JSON [blobs])
|
||||
output <- runTaskOrDie (diffSummaryBuilder Format.JSON [blobs])
|
||||
runBuilder output `shouldBe` ("{\"changes\":{\"test/fixtures/ruby/toc/methods.A.rb -> test/fixtures/ruby/toc/methods.X.rb\":[{\"span\":{\"start\":[1,1],\"end\":[2,4]},\"category\":\"Method\",\"term\":\"bar\",\"changeType\":\"removed\"},{\"span\":{\"start\":[4,1],\"end\":[5,4]},\"category\":\"Method\",\"term\":\"baz\",\"changeType\":\"removed\"}]},\"errors\":{\"test/fixtures/ruby/toc/methods.A.rb -> test/fixtures/ruby/toc/methods.X.rb\":[{\"span\":{\"start\":[1,1],\"end\":[2,3]},\"error\":\"expected end of input nodes, but got ParseError\",\"language\":\"Ruby\"}]}}\n" :: ByteString)
|
||||
|
||||
it "ignores anonymous functions" $ do
|
||||
blobs <- blobsForPaths (Both "ruby/toc/lambda.A.rb" "ruby/toc/lambda.B.rb")
|
||||
output <- runTask (diffSummaryBuilder Format.JSON [blobs])
|
||||
output <- runTaskOrDie (diffSummaryBuilder Format.JSON [blobs])
|
||||
runBuilder output `shouldBe` ("{\"changes\":{},\"errors\":{}}\n" :: ByteString)
|
||||
|
||||
it "summarizes Markdown headings" $ do
|
||||
blobs <- blobsForPaths (Both "markdown/toc/headings.A.md" "markdown/toc/headings.B.md")
|
||||
output <- runTask (diffSummaryBuilder Format.JSON [blobs])
|
||||
output <- runTaskOrDie (diffSummaryBuilder Format.JSON [blobs])
|
||||
runBuilder output `shouldBe` ("{\"changes\":{\"test/fixtures/markdown/toc/headings.A.md -> test/fixtures/markdown/toc/headings.B.md\":[{\"span\":{\"start\":[1,1],\"end\":[3,16]},\"category\":\"Heading 1\",\"term\":\"Introduction\",\"changeType\":\"removed\"},{\"span\":{\"start\":[5,1],\"end\":[7,4]},\"category\":\"Heading 2\",\"term\":\"Two\",\"changeType\":\"modified\"},{\"span\":{\"start\":[9,1],\"end\":[11,10]},\"category\":\"Heading 3\",\"term\":\"This heading is new\",\"changeType\":\"added\"},{\"span\":{\"start\":[13,1],\"end\":[14,4]},\"category\":\"Heading 1\",\"term\":\"Final\",\"changeType\":\"added\"}]},\"errors\":{}}\n" :: ByteString)
|
||||
|
||||
|
||||
|
@ -65,7 +65,7 @@ spec = describe "reprinting" $ do
|
||||
printed `shouldBe` Right src
|
||||
|
||||
it "should be able to parse the output of a refactor" $ do
|
||||
let (Just tagged) = rewrite (mark Unmodified tree) (topDownAny increaseNumbers)
|
||||
let (Just tagged) = rewrite (mark Unmodified tree) (topDownAny increaseNumbers)
|
||||
let (Right printed) = runReprinter src defaultJSONPipeline tagged
|
||||
tree' <- runTask (parse jsonParser (Blob printed path Language.JSON))
|
||||
tree' <- runTaskOrDie (parse jsonParser (Blob printed path Language.JSON))
|
||||
length tree' `shouldSatisfy` (/= 0)
|
||||
|
@ -18,13 +18,13 @@ spec = parallel $ do
|
||||
describe "parseDiffBuilder" $
|
||||
for_ diffFixtures $ \ (diffRenderer, runDiff, files, expected) ->
|
||||
it ("renders to " <> diffRenderer <> " with files " <> show files) $ do
|
||||
output <- runTask $ readBlobPairs (Right files) >>= runDiff
|
||||
output <- runTaskOrDie $ readBlobPairs (Right files) >>= runDiff
|
||||
runBuilder output `shouldBe'` expected
|
||||
|
||||
describe "parseTermBuilder" $
|
||||
for_ parseFixtures $ \ (format, runParse, files, expected) ->
|
||||
it ("renders to " <> format <> " with files " <> show files) $ do
|
||||
output <- runTask $ readBlobs (Right files) >>= runParse
|
||||
output <- runTaskOrDie $ readBlobs (Right files) >>= runParse
|
||||
runBuilder output `shouldBe'` expected
|
||||
where
|
||||
shouldBe' actual' expectedFile = do
|
||||
|
@ -12,14 +12,14 @@ spec :: Spec
|
||||
spec = parallel $ do
|
||||
describe "parseBlob" $ do
|
||||
it "returns error if given an unknown language (json)" $ do
|
||||
output <- fmap runBuilder . runTask $ parseTermBuilder TermJSONTree [ methodsBlob { blobLanguage = Unknown } ]
|
||||
output <- fmap runBuilder . runTaskOrDie $ parseTermBuilder TermJSONTree [ methodsBlob { blobLanguage = Unknown } ]
|
||||
output `shouldBe` "{\"trees\":[{\"path\":\"methods.rb\",\"error\":\"NoLanguageForBlob \\\"methods.rb\\\"\",\"language\":\"Unknown\"}]}\n"
|
||||
|
||||
it "throws if given an unknown language for sexpression output" $ do
|
||||
runTask (parseTermBuilder TermSExpression [methodsBlob { blobLanguage = Unknown }]) `shouldThrow` (== ExitFailure 1)
|
||||
runTaskOrDie (parseTermBuilder TermSExpression [methodsBlob { blobLanguage = Unknown }]) `shouldThrow` (== ExitFailure 1)
|
||||
|
||||
it "renders with the specified renderer" $ do
|
||||
output <- fmap runBuilder . runTask $ parseTermBuilder TermSExpression [methodsBlob]
|
||||
output <- fmap runBuilder . runTaskOrDie $ parseTermBuilder TermSExpression [methodsBlob]
|
||||
output `shouldBe` "(Statements\n (Method\n (Empty)\n (Identifier)\n (Statements)))\n"
|
||||
where
|
||||
methodsBlob = Blob "def foo\nend\n" "methods.rb" Ruby
|
||||
|
@ -33,16 +33,15 @@ import qualified Semantic.Spec
|
||||
import qualified Semantic.CLI.Spec
|
||||
import qualified Semantic.IO.Spec
|
||||
import qualified Semantic.Stat.Spec
|
||||
import Semantic.Config (defaultOptions)
|
||||
import Semantic.Task (withOptions)
|
||||
import Semantic.Util (TaskConfig(..))
|
||||
import Semantic.Config (defaultOptions, optionsLogLevel)
|
||||
import Semantic.Task (withOptions, TaskSession(..))
|
||||
import qualified Proto3.Roundtrip
|
||||
import Test.Hspec
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
withOptions defaultOptions $ \ config logger statter -> hspec $ do
|
||||
let args = TaskConfig config logger statter
|
||||
withOptions defaultOptions { optionsLogLevel = Nothing } $ \ config logger statter -> hspec $ do
|
||||
let args = TaskSession config "-" logger statter
|
||||
describe "Semantic.Stat" Semantic.Stat.Spec.spec
|
||||
parallel $ do
|
||||
describe "Analysis.Go" (Analysis.Go.Spec.spec args)
|
||||
|
@ -7,6 +7,8 @@ module SpecHelpers
|
||||
, parseFilePath
|
||||
, parseTestFile
|
||||
, readFilePair
|
||||
, runTaskOrDie
|
||||
, TaskSession(..)
|
||||
, testEvaluating
|
||||
, verbatim
|
||||
, Verbatim(..)
|
||||
@ -78,7 +80,7 @@ import qualified Data.ByteString as B
|
||||
import qualified Data.Set as Set
|
||||
import Data.Set (Set)
|
||||
import qualified Semantic.IO as IO
|
||||
import Semantic.Config (Config)
|
||||
import Semantic.Config (Config(..), optionsLogLevel)
|
||||
import Semantic.Telemetry (LogQueue, StatQueue)
|
||||
import Semantic.API hiding (File, Blob, BlobPair)
|
||||
import System.Exit (die)
|
||||
@ -92,12 +94,12 @@ instance IsString Name where
|
||||
fromString = X.name . fromString
|
||||
|
||||
-- | Returns an s-expression formatted diff for the specified FilePath pair.
|
||||
diffFilePaths :: TaskConfig -> Both FilePath -> IO ByteString
|
||||
diffFilePaths (TaskConfig config logger statter) paths = readFilePair paths >>= runTaskWithConfig config logger statter . parseDiffBuilder @[] DiffSExpression . pure >>= either (die . displayException) (pure . runBuilder)
|
||||
diffFilePaths :: TaskSession -> Both FilePath -> IO ByteString
|
||||
diffFilePaths session paths = readFilePair paths >>= runTask session . parseDiffBuilder @[] DiffSExpression . pure >>= either (die . displayException) (pure . runBuilder)
|
||||
|
||||
-- | Returns an s-expression parse tree for the specified FilePath.
|
||||
parseFilePath :: TaskConfig -> FilePath -> IO ByteString
|
||||
parseFilePath (TaskConfig config logger statter) path = (fromJust <$> readBlobFromFile (file path)) >>= runTaskWithConfig config logger statter . parseTermBuilder @[] TermSExpression . pure >>= either (die . displayException) (pure . runBuilder)
|
||||
parseFilePath :: TaskSession -> FilePath -> IO ByteString
|
||||
parseFilePath session path = (fromJust <$> readBlobFromFile (file path)) >>= runTask session . parseTermBuilder @[] TermSExpression . pure >>= either (die . displayException) (pure . runBuilder)
|
||||
|
||||
-- | Read two files to a BlobPair.
|
||||
readFilePair :: Both FilePath -> IO BlobPair
|
||||
@ -105,11 +107,15 @@ readFilePair paths = let paths' = fmap file paths in
|
||||
runBothWith F.readFilePair paths'
|
||||
|
||||
parseTestFile :: Parser term -> FilePath -> IO (Blob, term)
|
||||
parseTestFile parser path = runTask $ do
|
||||
parseTestFile parser path = runTaskOrDie $ do
|
||||
blob <- readBlob (file path)
|
||||
term <- parse parser blob
|
||||
pure (blob, term)
|
||||
|
||||
-- Run a Task and call `die` if it returns an Exception.
|
||||
runTaskOrDie :: TaskEff a -> IO a
|
||||
runTaskOrDie task = runTaskWithOptions defaultOptions { optionsLogLevel = Nothing } task >>= either (die . displayException) pure
|
||||
|
||||
type TestEvaluatingC term
|
||||
= ResumableC (BaseError (AddressError Precise (Val term))) (Eff
|
||||
( ResumableC (BaseError (ValueError term Precise)) (Eff
|
||||
|
Loading…
Reference in New Issue
Block a user