{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE ScopedTypeVariables #-} import Control.Exception.Safe import Control.Monad import qualified Language.C.Inline.Cpp as C import qualified Language.C.Inline.Cpp.Exceptions as C import qualified Test.Hspec as Hspec C.context C.cppCtx C.include "" C.include "" main :: IO () main = Hspec.hspec $ do Hspec.describe "Basic C++" $ do Hspec.it "Hello World" $ do let x = 3 [C.block| void { std::cout << "Hello, world!" << $(int x) << std::endl; } |] Hspec.describe "Exception handling" $ do Hspec.it "std::exceptions are caught" $ do result <- try [C.catchBlock| throw std::runtime_error("C++ error message"); |] result `Hspec.shouldBe` Left (C.CppStdException "C++ error message") Hspec.it "non-exceptions are caught" $ do result <- try [C.catchBlock| throw 0xDEADBEEF; |] result `Hspec.shouldBe` Left C.CppOtherException Hspec.it "catch without return (pure)" $ do result <- [C.tryBlock| void { throw std::runtime_error("C++ error message"); } |] result `Hspec.shouldBe` Left (C.CppStdException "C++ error message") Hspec.it "try and return without throwing (pure)" $ do result <- [C.tryBlock| int { return 123; } |] result `Hspec.shouldBe` Right 123 Hspec.it "return maybe throwing (pure)" $ do result <- [C.tryBlock| int { if(1) return 123; else throw std::runtime_error("C++ error message"); } |] result `Hspec.shouldBe` Right 123 Hspec.it "return definitely throwing (pure)" $ do result <- [C.tryBlock| int { if(0) return 123; else throw std::runtime_error("C++ error message"); } |] result `Hspec.shouldBe` Left (C.CppStdException "C++ error message") Hspec.it "catch without return (pure)" $ do result <- [C.tryBlock| void { throw std::runtime_error("C++ error message"); } |] result `Hspec.shouldBe` Left (C.CppStdException "C++ error message") Hspec.it "try and return without throwing (throw)" $ do result :: Either C.CppException C.CInt <- try [C.throwBlock| int { return 123; } |] result `Hspec.shouldBe` Right 123 Hspec.it "return maybe throwing (throw)" $ do result :: Either C.CppException C.CInt <- try [C.throwBlock| int { if(1) return 123; else throw std::runtime_error("C++ error message"); } |] result `Hspec.shouldBe` Right 123 Hspec.it "return definitely throwing (throw)" $ do result <- try [C.throwBlock| int { if(0) return 123; else throw std::runtime_error("C++ error message"); } |] result `Hspec.shouldBe` Left (C.CppStdException "C++ error message") Hspec.it "catch without return (throw)" $ do result <- try [C.throwBlock| void { throw std::runtime_error("C++ error message"); } |] result `Hspec.shouldBe` Left (C.CppStdException "C++ error message") Hspec.it "code without exceptions works normally" $ do result :: Either C.CppException C.CInt <- try $ C.withPtr_ $ \resPtr -> [C.catchBlock| *$(int* resPtr) = 0xDEADBEEF; |] result `Hspec.shouldBe` Right 0xDEADBEEF