packages feed

libheif-hs-0.1.0.0: test/Main.hs

{-# LANGUAGE CPP #-}

module Main (main) where

import Codec.HEIF
import Control.Monad
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as BSL
import Data.Map qualified as M
import SampleImage
import System.Directory (doesFileExist)
import System.IO.Temp (withSystemTempFile)
import Test.Hspec

main :: IO ()
main = hspec spec

inWasm :: Bool
#if defined(__wasm32__) || defined(__wasm__) || defined(wasm32_HOST_ARCH)
inWasm = True
#else
inWasm = False
#endif

isHEIFException :: HeifError -> HeifSubError -> HeifException -> Bool
isHEIFException expectedCode expectedSubcode (LibraryException (Library {..})) =
  code == expectedCode && subcode == expectedSubcode
isHEIFException _ _ _ = False

-- wasm has a virtual file system, some test steps are not executed there
itOnNative :: String -> Expectation -> Spec
itOnNative label test = it label $ do
  when inWasm $ pendingWith "Test not supported on WASM target"
  test

spec :: Spec
spec = describe "libheif-hs tests" $ do
  describe "HEIF library inclusion" $ do
    it "The linked library version is 1.23.1" $ do
      x <- heifVersion
      x `shouldBe` "1.23.1"
    describe "Image RGB decoding" $ do
      it "Fails with an empty image" $ do
        decodeThrow defaultDecodeOptions mempty
          `shouldThrow` isHEIFException HeifErrorInvalidInput HeifSubErrorUnspecified
    itOnNative "Can decode a HEIC file to raw RGB pixels and metadata" $ do
      let testFile = "./samples/heic-100x100.heic"
      exists <- doesFileExist testFile
      exists `shouldBe` True
      Decoded {..} <- decodeFromFileThrow defaultDecodeOptions testFile
      let Image {..} = decodedImage
          expectedWidth = 100
          expectedHeight = 100
      imageWidth `shouldBe` expectedWidth
      imageHeight `shouldBe` expectedHeight
    it "Can decode HEIC file ByteString to raw RGB pixels and metadata" $ do
      Decoded {..} <- decodeThrow defaultDecodeOptions sampleHEICFile
      let Image {..} = decodedImage
          expectedWidth = 100
          expectedHeight = 100
      imageWidth `shouldBe` expectedWidth
      imageHeight `shouldBe` expectedHeight
      BS.length imagePixelsRGB `shouldBe` fromIntegral (expectedWidth * expectedHeight * 3)
      BS.unpack (BS.take 10 imagePixelsRGB)
        `shouldBe` [59, 130, 246, 59, 130, 246, 59, 130, 246, 59]

      let Metadata {..} = decodedMetadata
      length metadataBlocks `shouldBe` 1
      case M.toList metadataBlocks of
        [(_, MetadataBlock {..})] -> do
          metadataBlockType `shouldBe` Exif
          BS.take 4 metadataBlockData `shouldBe` "Exif"
        _ -> pure ()
    it "Can decode encoded HEIC file" $ do
      decoded <- decodeThrow defaultDecodeOptions sampleHEICFile
      encoded <- encodeThrow defaultEncodeOptions decoded
      decoded' <- decodeThrow defaultDecodeOptions $ BSL.toStrict encoded
      decodedMetadata decoded `shouldBe` decodedMetadata decoded'
      let image = decodedImage decoded
          image' = decodedImage decoded'
          compareNumberOfBytes = 10
      imageWidth image `shouldBe` imageWidth image'
      imageHeight image `shouldBe` imageHeight image'
      -- The sample image contains solid colors in the beginning so we can compare only the first
      -- part of the image, otherwise because of compression/decompression differences the RGB
      -- data is not be byte-to-byte identical
      BS.take compareNumberOfBytes (imagePixelsRGB image)
        `shouldBe` BS.take compareNumberOfBytes (imagePixelsRGB image')
    itOnNative "Can encode HEIC to file" $ do
      withSystemTempFile "test.heic" $ \testFile _ -> do
        decoded <- decodeThrow defaultDecodeOptions sampleHEICFile
        encodeToFileThrow defaultEncodeOptions testFile decoded
        doesFileExist testFile >>= (`shouldBe` True)