Use a dummy server for testing
[lsp-test.git] / test / Test.hs
index e38af42cf1b8de77c3ae025100d8cb32d9fb25f5..4cffda347f150c4de7a9ba6e9797dfa4c1fa196f 100644 (file)
@@ -23,29 +23,31 @@ import           Language.Haskell.LSP.Types
 import           Language.Haskell.LSP.Types.Lens as LSP hiding
   (capabilities, message, rename, applyEdit)
 import           Language.Haskell.LSP.Types.Capabilities as LSP
+import           System.Directory
+import           System.FilePath
 import           System.Timeout
 
 {-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}
 {-# ANN module ("HLint: ignore Unnecessary hiding" :: String) #-}
 
-main = hspec $ do
+
+main = findServer >>= \serverExe -> hspec $ do
   describe "Session" $ do
-    it "fails a test" $
-      let session = runSession "hie" fullCaps "test/data/renamePass" $ do
+    it "fails a test" $ do
+      let session = runSession serverExe fullCaps "test/data/renamePass" $ do
                       openDoc "Desktop/simple.hs" "haskell"
-                      skipMany loggingNotification
                       anyRequest
         in session `shouldThrow` anySessionException
-    it "initializeResponse" $ runSession "hie" fullCaps "test/data/renamePass" $ do
+    it "initializeResponse" $ runSession serverExe fullCaps "test/data/renamePass" $ do
       rsp <- initializeResponse
-      liftIO $ rsp ^. result `shouldSatisfy` isLeft
+      liftIO $ rsp ^. result `shouldSatisfy` isRight
 
     it "runSessionWithConfig" $
-      runSession "hie" didChangeCaps "test/data/renamePass" $ return ()
+      runSession serverExe didChangeCaps "test/data/renamePass" $ return ()
 
     describe "withTimeout" $ do
       it "times out" $
-        let sesh = runSession "hie" fullCaps "test/data/renamePass" $ do
+        let sesh = runSession serverExe fullCaps "test/data/renamePass" $ do
                     openDoc "Desktop/simple.hs" "haskell"
                     -- won't receive a request - will timeout
                     -- incoming logging requests shouldn't increase the
@@ -56,15 +58,13 @@ main = hspec $ do
           in timeout 6000000 sesh `shouldThrow` anySessionException
 
       it "doesn't time out" $
-        let sesh = runSession "hie" fullCaps "test/data/renamePass" $ do
+        let sesh = runSession serverExe fullCaps "test/data/renamePass" $ do
                     openDoc "Desktop/simple.hs" "haskell"
                     withTimeout 5 $ skipManyTill anyMessage publishDiagnosticsNotification
           in void $ timeout 6000000 sesh
 
-      it "further timeout messages are ignored" $ runSession "hie" fullCaps "test/data/renamePass" $ do
+      it "further timeout messages are ignored" $ runSession serverExe fullCaps "test/data/renamePass" $ do
         doc <- openDoc "Desktop/simple.hs" "haskell"
-        -- warm up the cache
-        getDocumentSymbols doc
         -- shouldn't timeout
         withTimeout 3 $ getDocumentSymbols doc
         -- longer than the original timeout
@@ -75,7 +75,7 @@ main = hspec $ do
 
       it "overrides global message timeout" $
         let sesh =
-              runSessionWithConfig (def { messageTimeout = 5 }) "hie" fullCaps "test/data/renamePass" $ do
+              runSessionWithConfig (def { messageTimeout = 5 }) serverExe fullCaps "test/data/renamePass" $ do
                 doc <- openDoc "Desktop/simple.hs" "haskell"
                 -- shouldn't time out in here since we are overriding it
                 withTimeout 10 $ liftIO $ threadDelay 7000000
@@ -85,7 +85,7 @@ main = hspec $ do
 
       it "unoverrides global message timeout" $
         let sesh =
-              runSessionWithConfig (def { messageTimeout = 5 }) "hie" fullCaps "test/data/renamePass" $ do
+              runSessionWithConfig (def { messageTimeout = 5 }) serverExe fullCaps "test/data/renamePass" $ do
                 doc <- openDoc "Desktop/simple.hs" "haskell"
                 -- shouldn't time out in here since we are overriding it
                 withTimeout 10 $ liftIO $ threadDelay 7000000
@@ -99,15 +99,15 @@ main = hspec $ do
 
     describe "SessionException" $ do
       it "throw on time out" $
-        let sesh = runSessionWithConfig (def {messageTimeout = 10}) "hie" fullCaps "test/data/renamePass" $ do
+        let sesh = runSessionWithConfig (def {messageTimeout = 10}) serverExe fullCaps "test/data/renamePass" $ do
                 skipMany loggingNotification
                 _ <- message :: Session ApplyWorkspaceEditRequest
                 return ()
         in sesh `shouldThrow` anySessionException
 
-      it "don't throw when no time out" $ runSessionWithConfig (def {messageTimeout = 5}) "hie" fullCaps "test/data/renamePass" $ do
+      it "don't throw when no time out" $ runSessionWithConfig (def {messageTimeout = 5}) serverExe fullCaps "test/data/renamePass" $ do
         loggingNotification
-        liftIO $ threadDelay $ 10 * 1000000
+        liftIO $ threadDelay $ 6 * 1000000
         _ <- openDoc "Desktop/simple.hs" "haskell"
         return ()
 
@@ -115,7 +115,7 @@ main = hspec $ do
         it "throws when there's an unexpected message" $
           let selector (UnexpectedMessage "Publish diagnostics notification" (NotLogMessage _)) = True
               selector _ = False
-            in runSession "hie" fullCaps "test/data/renamePass" publishDiagnosticsNotification `shouldThrow` selector
+            in runSession serverExe fullCaps "test/data/renamePass" publishDiagnosticsNotification `shouldThrow` selector
         it "provides the correct types that were expected and received" $
           let selector (UnexpectedMessage "ResponseMessage WorkspaceEdit" (RspDocumentSymbols _)) = True
               selector _ = False
@@ -124,40 +124,38 @@ main = hspec $ do
                 sendRequest TextDocumentDocumentSymbol (DocumentSymbolParams doc Nothing)
                 skipMany anyNotification
                 message :: Session RenameResponse -- the wrong type
-            in runSession "hie" fullCaps "test/data/renamePass" sesh
+            in runSession serverExe fullCaps "test/data/renamePass" sesh
               `shouldThrow` selector
 
   describe "replaySession" $
     -- This is too fickle at the moment
     -- it "passes a test" $
-    --   replaySession "hie" "test/data/renamePass"
+    --   replaySession serverExe "test/data/renamePass"
     it "fails a test" $
       let selector (ReplayOutOfOrder _ _) = True
           selector _ = False
-        in replaySession "hie" "test/data/renameFail" `shouldThrow` selector
+        in replaySession serverExe "test/data/renameFail" `shouldThrow` selector
 
-  describe "manual javascript session" $
-    it "passes a test" $
-      runSession "javascript-typescript-stdio" fullCaps "test/data/javascriptPass" $ do
-        doc <- openDoc "test.js" "javascript"
+  -- describe "manual javascript session" $
+  --   it "passes a test" $
+  --     runSession "javascript-typescript-stdio" fullCaps "test/data/javascriptPass" $ do
+  --       doc <- openDoc "test.js" "javascript"
 
-        noDiagnostics
+  --       noDiagnostics
 
-        Right (fooSymbol:_) <- getDocumentSymbols doc
+  --       Right (fooSymbol:_) <- getDocumentSymbols doc
 
-        liftIO $ do
-          fooSymbol ^. name `shouldBe` "foo"
-          fooSymbol ^. kind `shouldBe` SkFunction
+  --       liftIO $ do
+  --         fooSymbol ^. name `shouldBe` "foo"
+  --         fooSymbol ^. kind `shouldBe` SkFunction
 
   describe "text document VFS" $
     it "sends back didChange notifications" $
-      runSession "hie" def "test/data/refactor" $ do
+      runSession serverExe def "test/data/refactor" $ do
         doc <- openDoc "Main.hs" "haskell"
 
-        let args = toJSON $ AOP (doc ^. uri)
-                                (Position 1 14)
-                                "Redundant bracket"
-            reqParams = ExecuteCommandParams "applyrefact:applyOne" (Just (List [args])) Nothing
+        let args = toJSON (doc ^. uri)
+            reqParams = ExecuteCommandParams "doAnEdit" (Just (List [args])) Nothing
         request_ WorkspaceExecuteCommand reqParams
 
         editReq <- message :: Session ApplyWorkspaceEditRequest
@@ -165,169 +163,156 @@ main = hspec $ do
           let (Just cs) = editReq ^. params . edit . changes
               [(u, List es)] = HM.toList cs
           u `shouldBe` doc ^. uri
-          es `shouldBe` [TextEdit (Range (Position 1 0) (Position 1 18)) "main = return 42"]
-
-        noDiagnostics
-
+          es `shouldBe` [TextEdit (Range (Position 0 0) (Position 0 5)) "howdy"]
         contents <- documentContents doc
-        liftIO $ contents `shouldBe` "main :: IO Int\nmain = return 42\n"
+        liftIO $ contents `shouldBe` "howdy:: IO Int\nmain = return (42)\n"
 
   describe "getDocumentEdit" $
     it "automatically consumes applyedit requests" $
-      runSession "hie" fullCaps "test/data/refactor" $ do
+      runSession serverExe fullCaps "test/data/refactor" $ do
         doc <- openDoc "Main.hs" "haskell"
 
-        let args = toJSON $ AOP (doc ^. uri)
-                                (Position 1 14)
-                                "Redundant bracket"
-            reqParams = ExecuteCommandParams "applyrefact:applyOne" (Just (List [args])) Nothing
+        let args = toJSON (doc ^. uri)
+            reqParams = ExecuteCommandParams "doAnEdit" (Just (List [args])) Nothing
         request_ WorkspaceExecuteCommand reqParams
         contents <- getDocumentEdit doc
-        liftIO $ contents `shouldBe` "main :: IO Int\nmain = return 42\n"
-        noDiagnostics
+        liftIO $ contents `shouldBe` "howdy:: IO Int\nmain = return (42)\n"
 
-  describe "getCodeActions" $
-    it "works" $ runSession "hie" fullCaps "test/data/refactor" $ do
-      doc <- openDoc "Main.hs" "haskell"
-      waitForDiagnostics
-      [CACodeAction action] <- getCodeActions doc (Range (Position 1 14) (Position 1 18))
-      liftIO $ action ^. title `shouldBe` "Apply hint:Redundant bracket"
+  -- describe "getCodeActions" $
+  --   it "works" $ runSession serverExe fullCaps "test/data/refactor" $ do
+  --     doc <- openDoc "Main.hs" "haskell"
+  --     waitForDiagnostics
+  --     [CACodeAction action] <- getCodeActions doc (Range (Position 1 14) (Position 1 18))
+  --     liftIO $ action ^. title `shouldBe` "Apply hint:Redundant bracket"
 
   describe "getAllCodeActions" $
-    it "works" $ runSession "hie" fullCaps "test/data/refactor" $ do
+    it "works" $ runSession serverExe fullCaps "test/data/refactor" $ do
       doc <- openDoc "Main.hs" "haskell"
       _ <- waitForDiagnostics
       actions <- getAllCodeActions doc
       liftIO $ do
         let [CACodeAction action] = actions
-        action ^. title `shouldBe` "Apply hint:Redundant bracket"
-        action ^. command . _Just . command `shouldSatisfy` T.isSuffixOf ":applyrefact:applyOne"
+        action ^. title `shouldBe` "Delete this"
+        action ^. command . _Just . command `shouldBe` "deleteThis"
 
-  describe "getDocumentSymbols" $
-    it "works" $ runSession "hie" fullCaps "test/data/renamePass" $ do
-      doc <- openDoc "Desktop/simple.hs" "haskell"
+  -- describe "getDocumentSymbols" $
+  --   it "works" $ runSession serverExe fullCaps "test/data/renamePass" $ do
+  --     doc <- openDoc "Desktop/simple.hs" "haskell"
 
-      skipMany loggingNotification
+  --     skipMany loggingNotification
 
-      noDiagnostics
+  --     noDiagnostics
 
-      Left (mainSymbol:_) <- getDocumentSymbols doc
+  --     Left (mainSymbol:_) <- getDocumentSymbols doc
 
-      liftIO $ do
-        mainSymbol ^. name `shouldBe` "main"
-        mainSymbol ^. kind `shouldBe` SkFunction
-        mainSymbol ^. range `shouldBe` Range (Position 3 0) (Position 5 30)
+  --     liftIO $ do
+  --       mainSymbol ^. name `shouldBe` "main"
+  --       mainSymbol ^. kind `shouldBe` SkFunction
+  --       mainSymbol ^. range `shouldBe` Range (Position 3 0) (Position 5 30)
 
   describe "applyEdit" $ do
-    it "increments the version" $ runSession "hie" docChangesCaps "test/data/renamePass" $ do
+    it "increments the version" $ runSession serverExe docChangesCaps "test/data/renamePass" $ do
       doc <- openDoc "Desktop/simple.hs" "haskell"
       VersionedTextDocumentIdentifier _ (Just oldVersion) <- getVersionedDoc doc
       let edit = TextEdit (Range (Position 1 1) (Position 1 3)) "foo"
       VersionedTextDocumentIdentifier _ (Just newVersion) <- applyEdit doc edit
       liftIO $ newVersion `shouldBe` oldVersion + 1
-    it "changes the document contents" $ runSession "hie" fullCaps "test/data/renamePass" $ do
+    it "changes the document contents" $ runSession serverExe fullCaps "test/data/renamePass" $ do
       doc <- openDoc "Desktop/simple.hs" "haskell"
       let edit = TextEdit (Range (Position 0 0) (Position 0 2)) "foo"
       applyEdit doc edit
       contents <- documentContents doc
       liftIO $ contents `shouldSatisfy` T.isPrefixOf "foodule"
 
-  describe "getCompletions" $
-    it "works" $ runSession "hie" def "test/data/renamePass" $ do
-      doc <- openDoc "Desktop/simple.hs" "haskell"
-
-      -- wait for module to be loaded
-      skipMany loggingNotification
-      noDiagnostics
-      noDiagnostics
-
-      comps <- getCompletions doc (Position 5 5)
-      let item = head (filter (\x -> x ^. label == "interactWithUser") comps)
-      liftIO $ do
-        item ^. label `shouldBe` "interactWithUser"
-        item ^. kind `shouldBe` Just CiFunction
-        item ^. detail `shouldBe` Just "Items -> IO ()\nMain"
-
-  describe "getReferences" $
-    it "works" $ runSession "hie" fullCaps "test/data/renamePass" $ do
-      doc <- openDoc "Desktop/simple.hs" "haskell"
-      let pos = Position 40 3 -- interactWithUser
-          uri = doc ^. LSP.uri
-      refs <- getReferences doc pos True
-      liftIO $ refs `shouldContain` map (Location uri) [
-          mkRange 41 0 41 16
-        , mkRange 75 6 75 22
-        , mkRange 71 6 71 22
-        ]
-
-  describe "getDefinitions" $
-    it "works" $ runSession "hie" fullCaps "test/data/renamePass" $ do
-      doc <- openDoc "Desktop/simple.hs" "haskell"
-      let pos = Position 49 25 -- addItem
-      defs <- getDefinitions doc pos
-      liftIO $ defs `shouldBe` [Location (doc ^. uri) (mkRange 28 0 28 7)]
-
-  describe "getTypeDefinitions" $
-    it "works" $ runSession "hie" fullCaps "test/data/renamePass" $ do
-      doc <- openDoc "Desktop/simple.hs" "haskell"
-      let pos = Position 20 23  -- Quit value
-      defs <- getTypeDefinitions doc pos
-      liftIO $ defs `shouldBe` [Location (doc ^. uri) (mkRange 10 0 14 19)]  -- Type definition
-
-  describe "waitForDiagnosticsSource" $
-    it "works" $ runSession "hie" fullCaps "test/data" $ do
-      openDoc "Error.hs" "haskell"
-      [diag] <- waitForDiagnosticsSource "bios"
-      liftIO $ do
-        diag ^. severity `shouldBe` Just DsError
-        diag ^. source `shouldBe` Just "bios"
-
-  describe "rename" $ do
-    it "works" $ pendingWith "HaRe not in hie-bios yet"
-    it "works on javascript" $
-      runSession "javascript-typescript-stdio" fullCaps "test/data/javascriptPass" $ do
-        doc <- openDoc "test.js" "javascript"
-        rename doc (Position 2 11) "bar"
-        documentContents doc >>= liftIO . (`shouldContain` "function bar()") . T.unpack
-
-    -- runSession "hie" fullCaps "test/data" $ do
-    --   doc <- openDoc "Rename.hs" "haskell"
-    --   rename doc (Position 1 0) "bar"
-    --   documentContents doc >>= liftIO . shouldBe "main = bar\nbar = return 42\n"
-
-  describe "getHover" $
-    it "works" $ runSession "hie" fullCaps "test/data/renamePass" $ do
-      doc <- openDoc "Desktop/simple.hs" "haskell"
-      -- hover returns nothing until module is loaded
-      skipManyTill loggingNotification $ count 2 noDiagnostics
-      hover <- getHover doc (Position 45 9) -- putStrLn
-      liftIO $ hover `shouldSatisfy` isJust
-
-  describe "getHighlights" $
-    it "works" $ runSession "hie" fullCaps "test/data/renamePass" $ do
-      doc <- openDoc "Desktop/simple.hs" "haskell"
-      skipManyTill loggingNotification $ count 2 noDiagnostics
-      highlights <- getHighlights doc (Position 27 4) -- addItem
-      liftIO $ length highlights `shouldBe` 4
-
-  describe "formatDoc" $
-    it "works" $ runSession "hie" fullCaps "test/data" $ do
-      doc <- openDoc "Format.hs" "haskell"
-      oldContents <- documentContents doc
-      formatDoc doc (FormattingOptions 4 True)
-      documentContents doc >>= liftIO . (`shouldNotBe` oldContents)
-
-  describe "formatRange" $
-    it "works" $ runSession "hie" fullCaps "test/data" $ do
-      doc <- openDoc "Format.hs" "haskell"
-      oldContents <- documentContents doc
-      formatRange doc (FormattingOptions 4 True) (Range (Position 1 10) (Position 2 10))
-      documentContents doc >>= liftIO . (`shouldNotBe` oldContents)
+  -- describe "getCompletions" $
+  --   it "works" $ runSession serverExe def "test/data/renamePass" $ do
+  --     doc <- openDoc "Desktop/simple.hs" "haskell"
+
+  --     -- wait for module to be loaded
+  --     skipMany loggingNotification
+  --     noDiagnostics
+  --     noDiagnostics
+
+  --     comps <- getCompletions doc (Position 5 5)
+  --     let item = head (filter (\x -> x ^. label == "interactWithUser") comps)
+  --     liftIO $ do
+  --       item ^. label `shouldBe` "interactWithUser"
+  --       item ^. kind `shouldBe` Just CiFunction
+  --       item ^. detail `shouldBe` Just "Items -> IO ()\nMain"
+
+  -- describe "getReferences" $
+  --   it "works" $ runSession serverExe fullCaps "test/data/renamePass" $ do
+  --     doc <- openDoc "Desktop/simple.hs" "haskell"
+  --     let pos = Position 40 3 -- interactWithUser
+  --         uri = doc ^. LSP.uri
+  --     refs <- getReferences doc pos True
+  --     liftIO $ refs `shouldContain` map (Location uri) [
+  --         mkRange 41 0 41 16
+  --       , mkRange 75 6 75 22
+  --       , mkRange 71 6 71 22
+  --       ]
+
+  -- describe "getDefinitions" $
+  --   it "works" $ runSession serverExe fullCaps "test/data/renamePass" $ do
+  --     doc <- openDoc "Desktop/simple.hs" "haskell"
+  --     let pos = Position 49 25 -- addItem
+  --     defs <- getDefinitions doc pos
+  --     liftIO $ defs `shouldBe` [Location (doc ^. uri) (mkRange 28 0 28 7)]
+
+  -- describe "getTypeDefinitions" $
+  --   it "works" $ runSession serverExe fullCaps "test/data/renamePass" $ do
+  --     doc <- openDoc "Desktop/simple.hs" "haskell"
+  --     let pos = Position 20 23  -- Quit value
+  --     defs <- getTypeDefinitions doc pos
+  --     liftIO $ defs `shouldBe` [Location (doc ^. uri) (mkRange 10 0 14 19)]  -- Type definition
+
+  -- describe "waitForDiagnosticsSource" $
+  --   it "works" $ runSession serverExe fullCaps "test/data" $ do
+  --     openDoc "Error.hs" "haskell"
+  --     [diag] <- waitForDiagnosticsSource "bios"
+  --     liftIO $ do
+  --       diag ^. severity `shouldBe` Just DsError
+  --       diag ^. source `shouldBe` Just "bios"
+
+  -- describe "rename" $ do
+  --   it "works" $ pendingWith "HaRe not in hie-bios yet"
+  --   it "works on javascript" $
+  --     runSession "javascript-typescript-stdio" fullCaps "test/data/javascriptPass" $ do
+  --       doc <- openDoc "test.js" "javascript"
+  --       rename doc (Position 2 11) "bar"
+  --       documentContents doc >>= liftIO . (`shouldContain` "function bar()") . T.unpack
+
+  -- describe "getHover" $
+  --   it "works" $ runSession serverExe fullCaps "test/data/renamePass" $ do
+  --     doc <- openDoc "Desktop/simple.hs" "haskell"
+  --     hover <- getHover doc (Position 45 9)
+  --     liftIO $ hover `shouldSatisfy` isJust
+
+  -- describe "getHighlights" $
+  --   it "works" $ runSession serverExe fullCaps "test/data/renamePass" $ do
+  --     doc <- openDoc "Desktop/simple.hs" "haskell"
+  --     skipManyTill loggingNotification $ count 2 noDiagnostics
+  --     highlights <- getHighlights doc (Position 27 4) -- addItem
+  --     liftIO $ length highlights `shouldBe` 4
+
+  -- describe "formatDoc" $
+  --   it "works" $ runSession serverExe fullCaps "test/data" $ do
+  --     doc <- openDoc "Format.hs" "haskell"
+  --     oldContents <- documentContents doc
+  --     formatDoc doc (FormattingOptions 4 True)
+  --     documentContents doc >>= liftIO . (`shouldNotBe` oldContents)
+
+  -- describe "formatRange" $
+  --   it "works" $ runSession serverExe fullCaps "test/data" $ do
+  --     doc <- openDoc "Format.hs" "haskell"
+  --     oldContents <- documentContents doc
+  --     formatRange doc (FormattingOptions 4 True) (Range (Position 1 10) (Position 2 10))
+  --     documentContents doc >>= liftIO . (`shouldNotBe` oldContents)
 
   describe "closeDoc" $
     it "works" $
       let sesh =
-            runSession "hie" fullCaps "test/data" $ do
+            runSession serverExe fullCaps "test/data" $ do
               doc <- openDoc "Format.hs" "haskell"
               closeDoc doc
               -- need to evaluate to throw
@@ -335,7 +320,7 @@ main = hspec $ do
       in sesh `shouldThrow` anyException
 
   describe "satisfy" $
-    it "works" $ runSession "hie" fullCaps "test/data" $ do
+    it "works" $ runSession serverExe fullCaps "test/data" $ do
       openDoc "Format.hs" "haskell"
       let pred (NotLogMessage _) = True
           pred _ = False
@@ -343,7 +328,7 @@ main = hspec $ do
 
   describe "ignoreLogNotifications" $
     it "works" $
-      runSessionWithConfig (defaultConfig { ignoreLogNotifications = True }) "hie"  fullCaps "test/data" $ do
+      runSessionWithConfig (defaultConfig { ignoreLogNotifications = True }) serverExe  fullCaps "test/data" $ do
         openDoc "Format.hs" "haskell"
         void publishDiagnosticsNotification
 
@@ -361,8 +346,24 @@ docChangesCaps = def { _workspace = Just workspaceCaps }
     workspaceCaps = def { _workspaceEdit = Just editCaps }
     editCaps = WorkspaceEditClientCapabilities (Just True)
 
-data ApplyOneParams = AOP
-  { file      :: Uri
-  , start_pos :: Position
-  , hintTitle :: String
-  } deriving (Generic, ToJSON)
+
+findExeRecursive :: FilePath -> FilePath -> IO (Maybe FilePath)
+findExeRecursive exe dir = do
+  me <- listToMaybe <$> findExecutablesInDirectories [dir] exe
+  case me of
+    Just e -> return (Just e)
+    Nothing -> do
+      subdirs <- (fmap (dir </>)) <$> listDirectory dir >>= filterM doesDirectoryExist
+      foldM (\acc subdir -> case acc of
+                              Just y -> pure $ Just y
+                              Nothing -> findExeRecursive exe subdir)
+            Nothing
+            subdirs
+
+-- | So we can find the dummy-server with cabal run
+-- since it doesnt put build tools on the path (only cabal test)
+findServer = do
+  let serverName = "dummy-server"
+  e <- findExecutable serverName
+  e' <- findExeRecursive serverName "dist-newstyle"
+  pure $ fromJust $ e <|> e'
\ No newline at end of file