|
| 1 | +{-# LANGUAGE ScopedTypeVariables #-} |
| 2 | +{-# LANGUAGE TypeApplications #-} |
| 3 | +module ArrayFire.ExceptionSpec where |
| 4 | + |
| 5 | +import Control.Exception (evaluate, try) |
| 6 | +import qualified ArrayFire as A |
| 7 | +import ArrayFire.Exception |
| 8 | +import ArrayFire.Internal.Defines (AFErr (..)) |
| 9 | +import Test.Hspec |
| 10 | + |
| 11 | +spec :: Spec |
| 12 | +spec = describe "Exception spec" $ do |
| 13 | + |
| 14 | + -- The error-code → constructor table is the heart of the FFI error path; |
| 15 | + -- a wrong entry silently mislabels every failure of that kind. |
| 16 | + describe "toAFExceptionType" $ do |
| 17 | + |
| 18 | + it "maps every documented AFErr code to its constructor" $ |
| 19 | + map (toAFExceptionType . AFErr) |
| 20 | + [101,102,103,201,202,203,204,205,207,208,301,302,303,401,402,501,502,503,998,999] |
| 21 | + `shouldBe` |
| 22 | + [ NoMemoryError, DriverError, RuntimeError, InvalidArrayError, ArgError |
| 23 | + , SizeError, TypeError, DiffTypeError, BatchError, DeviceError |
| 24 | + , NotSupportedError, NotConfiguredError, NonFreeError, NoDblError |
| 25 | + , NoGfxError, LoadLibError, LoadSymError, BackendMismatchError |
| 26 | + , InternalError, UnknownError |
| 27 | + ] |
| 28 | + |
| 29 | + it "maps unrecognized codes to UnhandledError" $ do |
| 30 | + toAFExceptionType (AFErr 0) `shouldBe` UnhandledError |
| 31 | + toAFExceptionType (AFErr 12345) `shouldBe` UnhandledError |
| 32 | + |
| 33 | + -- End-to-end: a genuine ArrayFire failure must cross the FFI boundary as a |
| 34 | + -- typed 'AFException', not a crash or an opaque error. |
| 35 | + describe "library errors surface as AFException" $ |
| 36 | + |
| 37 | + it "a matmul dimension mismatch throws a typed AFException" $ do |
| 38 | + let a = A.mkArray @Double [2,3] [1..6] -- 2x3 |
| 39 | + b = A.mkArray @Double [2,2] [1..4] -- 2x2 (inner dims 3 /= 2) |
| 40 | + r <- try (evaluate (A.getElements (A.matmul a b A.None A.None))) |
| 41 | + :: IO (Either AFException Int) |
| 42 | + case r of |
| 43 | + Right n -> |
| 44 | + expectationFailure ("expected an AFException, but got " ++ show n) |
| 45 | + Left (AFException ty code _msg) -> do |
| 46 | + ty `shouldSatisfy` (`elem` [SizeError, ArgError]) |
| 47 | + code `shouldSatisfy` (> 0) |
0 commit comments