packages feed

debugger-hs-0.1.0.0: test/Test/Debugger/RenderSpec.hs

{-# LANGUAGE QuasiQuotes #-}

module Test.Debugger.RenderSpec
  ( module Test.Debugger.RenderSpec
  ) where

import Prelude hiding (break, print)
import qualified Data.Text as T
import Test.Hspec
import NeatInterpolation
import Debugger.Builder
import Debugger.Render
import Debugger.Statement
import Control.Monad.Cont


-- NOTE: 2 $s is to escape the quasiquoter, renders as 1 $


shouldRenderAs :: Builder a -> T.Text -> IO ()
shouldRenderAs script expected =
  renderScript (runBuilder script) `shouldBe` expected

spec :: Spec
spec = describe "rendering scripts" $ parallel $ do
  it "handles empty scripts" $ do
    pure () `shouldRenderAs` ""

  it "renders break statements" $ do
    break (Function "main") `shouldRenderAs` [text|
      break main
      set $$var0 = $$bpnum
      |]
    break (File "./a/b.c" 42) `shouldRenderAs` [text|
      break ./a/b.c:42
      set $$var0 = $$bpnum
      |]

  it "renders command statements" $ do
    let script = do
          bp <- break (Function "main")
          command bp $ do
            print "42"
            continue
    script `shouldRenderAs` [text|
      break main
      set $$var0 = $$bpnum
      command $$var0
        print "42"
        continue
      end
      |]

  it "renders nested command statements" $ do
    let script = do
          bp1 <- break (Function "main")
          command bp1 $ do
            bp2 <- break (File "file.cpp" 1234)
            command bp2 $ do
              print "42"
              continue
    script `shouldRenderAs` [text|
      break main
      set $$var0 = $$bpnum
      command $$var0
        break file.cpp:1234
        set $$var1 = $$bpnum
        command $$var1
          print "42"
          continue
        end
      end
      |]

  it "renders continue statements" $ do
    continue `shouldRenderAs` [text|
      continue
      |]

  it "renders next statements" $ do
    let script1 = next
        script2 = nextN 10
    script1 `shouldRenderAs` [text|
      next
      |]
    script2 `shouldRenderAs` [text|
      next 10
      |]

  it "renders step statements" $ do
    let script1 = step
        script2 = stepN 10
    script1 `shouldRenderAs` [text|
      step
      |]
    script2 `shouldRenderAs` [text|
      step 10
      |]

  it "renders reset statements" $ do
    reset `shouldRenderAs` [text|
      monitor reset
      |]

  it "renders set statements" $ do
    set "$var" "123" `shouldRenderAs` [text|
      set $$var = 123
      |]

  it "renders call statements" $ do
    call "function(123)" `shouldRenderAs` [text|
      call function(123)
      |]

  it "renders delete statements" $ do
    let script1 = do
          bp <- break (Function "main")
          delete bp
        script2 = do
          bp1 <- break (Function "f")
          bp2 <- break (Function "g")
          delete [bp1, bp2]
        script3 = delete All
    script1 `shouldRenderAs` [text|
      break main
      set $$var0 = $$bpnum
      delete $$var0
      |]
    script2 `shouldRenderAs` [text|
      break f
      set $$var0 = $$bpnum
      break g
      set $$var1 = $$bpnum
      delete $$var0 $$var1
      |]
    script3 `shouldRenderAs` [text|
      delete
      |]

  it "renders disable statements" $ do
    let script1 = do
          bp <- break (Function "main")
          disable bp
        script2 = do
          bp1 <- break (Function "f")
          bp2 <- break (Function "g")
          disable [bp1, bp2]
        script3 = disable All
    script1 `shouldRenderAs` [text|
      break main
      set $$var0 = $$bpnum
      disable $$var0
      |]
    script2 `shouldRenderAs` [text|
      break f
      set $$var0 = $$bpnum
      break g
      set $$var1 = $$bpnum
      disable $$var0 $$var1
      |]
    script3 `shouldRenderAs` [text|
      disable
      |]

  it "renders enable statements" $ do
    let script1 = do
          bp <- break (Function "main")
          enable bp
        script2 = do
          bp1 <- break (Function "f")
          bp2 <- break (Function "g")
          enable [bp1, bp2]
        script3 = enable All
    script1 `shouldRenderAs` [text|
      break main
      set $$var0 = $$bpnum
      enable $$var0
      |]
    script2 `shouldRenderAs` [text|
      break f
      set $$var0 = $$bpnum
      break g
      set $$var1 = $$bpnum
      enable $$var0 $$var1
      |]
    script3 `shouldRenderAs` [text|
      enable
      |]

  it "renders print statements" $ do
    print "42" `shouldRenderAs` [text|
      print "42"
      |]

  it "renders shell statements" $ do
    shell "sleep 1" `shouldRenderAs` [text|
      shell sleep 1
      |]

  it "renders source statements" $ do
    source "./other_script.gdb" `shouldRenderAs` [text|
      source ./other_script.gdb
      |]

  it "renders target statements" $ do
    let script = target (Remote 9001)
    script `shouldRenderAs` [text|
      target remote tcp:localhost:9001
      |]

  it "renders target statements" $ do
    let script = info Breakpoints
    script `shouldRenderAs` [text|
      info breakpoints
      |]

  it "mixes well with other Haskell concepts" $ do
    let script = flip runContT delete $ do
          bp1 <- ContT $ withBreakpoint (Function "func1")
          bp2 <- ContT $ withBreakpoint (Function "func2")
          pure [bp1, bp2]
        withBreakpoint :: Location -> (Id -> Builder ()) -> Builder ()
        withBreakpoint loc f = do
          bp <- break loc
          command bp $ f bp

    script `shouldRenderAs` [text|
      break func1
      set $$var0 = $$bpnum
      command $$var0
        break func2
        set $$var1 = $$bpnum
        command $$var1
          delete $$var0 $$var1
        end
      end
      |]