packages feed

wasmedge-hs-0.17.1.0: test/Test/Unit/VMSpec.hs

-- | VM integration tests
module Test.Unit.VMSpec (spec) where

import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Test.Hspec

import WasmEdge.Types
import WasmEdge.VM

-- Minimal valid WASM module (empty):
-- (module)
emptyWasm :: ByteString
emptyWasm =
  BS.pack
    [ 0x00
    , 0x61
    , 0x73
    , 0x6D -- magic: \0asm
    , 0x01
    , 0x00
    , 0x00
    , 0x00 -- version: 1
    ]

-- Minimal add function WASM:
-- (module
--   (func (export "add") (param i32 i32) (result i32)
--     local.get 0
--     local.get 1
--     i32.add))
addWasm :: ByteString
addWasm =
  BS.pack
    [ 0x00
    , 0x61
    , 0x73
    , 0x6D
    , 0x01
    , 0x00
    , 0x00
    , 0x00
    , -- type section: (i32 i32) -> (i32)
      0x01
    , 0x07
    , 0x01
    , 0x60
    , 0x02
    , 0x7F
    , 0x7F
    , 0x01
    , 0x7F
    , -- function section: func 0
      0x03
    , 0x02
    , 0x01
    , 0x00
    , -- export section: "add" -> func 0
      0x07
    , 0x07
    , 0x01
    , 0x03
    , 0x61
    , 0x64
    , 0x64
    , 0x00
    , 0x00
    , -- code section
      0x0A
    , 0x09
    , 0x01
    , 0x07
    , 0x00
    , 0x20
    , 0x00 -- local.get 0
    , 0x20
    , 0x01 -- local.get 1
    , 0x6A -- i32.add
    , 0x0B -- end
    ]

spec :: Spec
spec = describe "WasmEdge VM" $ do
  it "creates and deletes VM without crashing" $
    withVM Nothing Nothing $
      \_ -> pure ()

  describe "runWasmBytes" $ do
    it "runs empty module without crashing" $
      withVM Nothing Nothing $ \vm -> do
        -- Running an empty module with a non-existent function should return Left
        r <- runWasmBytes vm emptyWasm "nonexistent" []
        r `shouldSatisfy` isLeft

    it "add(3, 4) = 7" $
      withVM Nothing Nothing $ \vm -> do
        r <- runWasmBytes vm addWasm "add" [WasmI32 3, WasmI32 4]
        case r of
          Left err -> expectationFailure $ "Expected success, got: " ++ show err
          Right [WasmI32 7] -> pure ()
          Right other -> expectationFailure $ "Expected [WasmI32 7], got: " ++ show other

    it "add(maxBound, 1) wraps to minBound" $
      withVM Nothing Nothing $ \vm -> do
        r <- runWasmBytes vm addWasm "add" [WasmI32 maxBound, WasmI32 1]
        case r of
          Left err -> expectationFailure $ show err
          Right [WasmI32 v] -> v `shouldBe` minBound
          Right other -> expectationFailure $ "Unexpected: " ++ show other

  describe "load/validate/instantiate/execute pipeline" $ do
    it "runs the step-by-step pipeline correctly" $
      withVM Nothing Nothing $ \vm -> do
        loadR <- loadWasmBytes vm addWasm
        loadR `shouldBe` Right ()
        valR <- validate vm
        valR `shouldBe` Right ()
        instR <- instantiate vm
        instR `shouldBe` Right ()
        r <- execute vm "add" [WasmI32 10, WasmI32 20]
        case r of
          Left err -> expectationFailure $ show err
          Right [WasmI32 30] -> pure ()
          Right other -> expectationFailure $ "Got: " ++ show other

  describe "error propagation" $ do
    it "returns Left for invalid WASM bytes" $
      withVM Nothing Nothing $ \vm -> do
        r <- loadWasmBytes vm (BS.pack [0x00, 0x01, 0x02, 0x03])
        r `shouldSatisfy` isLeft

isLeft :: Either a b -> Bool
isLeft (Left _) = True
isLeft _ = False