Skip to content

Commit

Permalink
Merge pull request #154 from nh2/fix-missing-space-in-shown-exceptions
Browse files Browse the repository at this point in the history
Fix missing space in shown exceptions; test both legacy and new Exception(s) module API
  • Loading branch information
roberth authored Dec 6, 2024
2 parents ef87fba + dee5eef commit 763fd98
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 17 deletions.
2 changes: 1 addition & 1 deletion inline-c-cpp/src/Language/C/Inline/Cpp/Exception.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ data CppException
| CppNonStdException CppExceptionPtr (Maybe ByteString)

instance Show CppException where
showsPrec p (CppStdException _ msg typ) = showParen (p >= 11) (showString "CppStdException e " . showsPrec 11 msg . showsPrec 11 typ)
showsPrec p (CppStdException _ msg typ) = showParen (p >= 11) (showString "CppStdException e " . showsPrec 11 msg . showChar ' ' . showsPrec 11 typ)
showsPrec p (CppHaskellException e) = showParen (p >= 11) (showString "CppHaskellException " . showsPrec 11 e)
showsPrec p (CppNonStdException _ typ) = showParen (p >= 11) (showString "CppOtherException e " . showsPrec 11 typ)

Expand Down
60 changes: 44 additions & 16 deletions inline-c-cpp/test/tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -121,21 +121,26 @@ main = Hspec.hspec $ do
throw std::runtime_error("C++ error message");
|]

result `shouldBeCppStdException` "Exception: C++ error message; type: std::runtime_error"
result `shouldBeCppStdException` ("C++ error message", Just "std::runtime_error")
result `shouldBeLegacyCppStdException` "Exception: C++ error message; type: std::runtime_error"
-- Test that we don't accidentally mess up formatting:
result `shouldBeShownException` "CppStdException e \"C++ error message\" (Just \"std::runtime_error\")"

Hspec.it "non-exceptions are caught (unsigned int)" $ do
result <- try [C.catchBlock|
throw 0xDEADBEEF;
|]

result `shouldBeCppOtherException` (Just "unsigned int")
result `shouldBeCppNonStdException` (Just "unsigned int")
result `shouldBeLegacyCppOtherException` (Just "unsigned int")

Hspec.it "non-exceptions are caught (void *)" $ do
result <- try [C.catchBlock|
throw (void *)0xDEADBEEF;
|]

result `shouldBeCppOtherException` (Just "void*")
result `shouldBeCppNonStdException` (Just "void*")
result `shouldBeLegacyCppOtherException` (Just "void*")

Hspec.it "non-exceptions are caught (std::string)" $ do
result <- try [C.catchBlock|
Expand Down Expand Up @@ -169,7 +174,8 @@ main = Hspec.hspec $ do
}
|]

result `shouldBeCppStdException` "Exception: C++ error message; type: std::runtime_error"
result `shouldBeCppStdException` ("C++ error message", Just "std::runtime_error")
result `shouldBeLegacyCppStdException` "Exception: C++ error message; type: std::runtime_error"

Hspec.it "try and return without throwing (pure)" $ do
result <- [C.tryBlock| int {
Expand All @@ -195,15 +201,17 @@ main = Hspec.hspec $ do
}
|]

result `shouldBeCppStdException` "Exception: C++ error message; type: std::runtime_error"
result `shouldBeCppStdException` ("C++ error message", Just "std::runtime_error")
result `shouldBeLegacyCppStdException` "Exception: C++ error message; type: std::runtime_error"

Hspec.it "catch without return (pure)" $ do
result <- [C.tryBlock| void {
throw std::runtime_error("C++ error message");
}
|]

result `shouldBeCppStdException` "Exception: C++ error message; type: std::runtime_error"
result `shouldBeCppStdException` ("C++ error message", Just "std::runtime_error")
result `shouldBeLegacyCppStdException` "Exception: C++ error message; type: std::runtime_error"

Hspec.it "try and return without throwing (throw)" $ do
result :: Either C.CppException C.CInt <- try [C.throwBlock| int {
Expand All @@ -229,7 +237,8 @@ main = Hspec.hspec $ do
}
|]

result `shouldBeCppStdException` "Exception: C++ error message; type: std::runtime_error"
result `shouldBeCppStdException` ("C++ error message", Just "std::runtime_error")
result `shouldBeLegacyCppStdException` "Exception: C++ error message; type: std::runtime_error"

Hspec.it "return throwing Haskell" $ do
let exc = toException $ userError "This is from Haskell"
Expand Down Expand Up @@ -275,7 +284,8 @@ main = Hspec.hspec $ do
}
|]

result `shouldBeCppStdException` "Exception: C++ error message; type: std::runtime_error"
result `shouldBeCppStdException` ("C++ error message", Just "std::runtime_error")
result `shouldBeLegacyCppStdException` "Exception: C++ error message; type: std::runtime_error"

Hspec.it "code without exceptions works normally" $ do
result :: Either C.CppException C.CInt <- try $ C.withPtr_ $ \resPtr -> [C.catchBlock|
Expand Down Expand Up @@ -368,19 +378,37 @@ main = Hspec.hspec $ do
tag :: C.CppException -> String
tag (C.CppStdException {}) = "CppStdException"
tag (C.CppHaskellException {}) = "CppHaskellException"
tag (Legacy.CppOtherException {}) = "CppStdException"
tag (C.CppNonStdException {}) = "CppNonStdException"

shouldBeCppStdException :: Either C.CppException a -> String -> IO ()
shouldBeCppStdException (Left (Legacy.CppStdException actualMsg)) expectedMsg = do
actualMsg `Hspec.shouldBe` expectedMsg
shouldBeShownException :: Either C.CppException a -> String -> IO ()
shouldBeShownException (Left e) expectedStr = show e `shouldBe` expectedStr
shouldBeShownException (Right _) _expectedStr = "Right _" `Hspec.shouldBe` "Left _"

shouldBeCppStdException :: Either C.CppException a -> (ByteString, Maybe ByteString) -> IO ()
shouldBeCppStdException (Left (C.CppStdException _ actualMsg actualType)) (expectedMsg, expectedType) = do
(actualMsg, actualType) `shouldBe` (expectedMsg, expectedType)
shouldBeCppStdException (Left x) expectedMsg = tag x `Hspec.shouldBe` ("CppStdException " <> show expectedMsg)
shouldBeCppStdException (Right _) expectedMsg = "Right _" `Hspec.shouldBe` ("Left (CppStdException " <> show expectedMsg <> ")")

shouldBeCppOtherException :: Either C.CppException a -> Maybe String -> IO ()
shouldBeCppOtherException (Left (Legacy.CppOtherException actualType)) expectedType = do
-- | Tests that the old, deprecated exception's module and error messages still work.
shouldBeLegacyCppStdException :: Either Legacy.CppException a -> String -> IO ()
shouldBeLegacyCppStdException (Left (Legacy.CppStdException actualMsg)) expectedMsg = do
actualMsg `Hspec.shouldBe` expectedMsg
shouldBeLegacyCppStdException (Left x) expectedMsg = tag x `Hspec.shouldBe` ("CppStdException " <> show expectedMsg)
shouldBeLegacyCppStdException (Right _) expectedMsg = "Right _" `Hspec.shouldBe` ("Left (CppStdException " <> show expectedMsg <> ")")

shouldBeCppNonStdException :: Either C.CppException a -> Maybe ByteString -> IO ()
shouldBeCppNonStdException (Left (C.CppNonStdException _ actualType)) expectedType = do
actualType `Hspec.shouldBe` expectedType
shouldBeCppNonStdException (Left x) expectedType = tag x `Hspec.shouldBe` ("CppOtherException " <> show expectedType)
shouldBeCppNonStdException (Right _) expectedType = "Right _" `Hspec.shouldBe` ("Left (CppOtherException " <> show expectedType <> ")")

-- | Tests that the old, deprecated exception's module and error messages still work.
shouldBeLegacyCppOtherException :: Either Legacy.CppException a -> Maybe String -> IO ()
shouldBeLegacyCppOtherException (Left (Legacy.CppOtherException actualType)) expectedType = do
actualType `Hspec.shouldBe` expectedType
shouldBeCppOtherException (Left x) expectedType = tag x `Hspec.shouldBe` ("CppOtherException " <> show expectedType)
shouldBeCppOtherException (Right _) expectedType = "Right _" `Hspec.shouldBe` ("Left (CppOtherException " <> show expectedType <> ")")
shouldBeLegacyCppOtherException (Left x) expectedType = tag x `Hspec.shouldBe` ("CppOtherException " <> show expectedType)
shouldBeLegacyCppOtherException (Right _) expectedType = "Right _" `Hspec.shouldBe` ("Left (CppOtherException " <> show expectedType <> ")")

shouldBeRight :: (Eq a, Show a) => Either C.CppException a -> a -> IO ()
shouldBeRight (Right actual) expected = actual `Hspec.shouldBe` expected
Expand Down

0 comments on commit 763fd98

Please sign in to comment.