packages feed

bitfield-0.0.0.0: test/BitfieldSpec.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
#if __GLASGOW_HASKELL__ >= 902
{-# LANGUAGE OverloadedRecordDot #-}
#endif
module BitfieldSpec where

import Test.Syd
import Test.Syd.Validity

import Test.QuickCheck

import Data.Word

import Data.Bitfield as Bitfield
import GHC.Generics
import Data.Bits (unsafeShiftL)

data Example = Example { a :: Bool, b :: Word8, c :: Word16, d :: Bool } deriving stock (Eq, Show, Generic)

instance GenValid Example where
instance Validity Example where

spec :: Spec
spec = do
  it "pack should work on simple examples" $ do
    let t1 = pack @Word32 $ Example False 0 0 False
    let t2 = pack @Word32 $ Example True 0 0 False
    let t3 = pack @Word32 $ Example False 0 0 True
    let t4 = pack @Word32 $ Example True 12 0 False
    (Bitfield.unwrap t1) `shouldBe` 0
    (Bitfield.unwrap t2) `shouldBe` 1
    (Bitfield.unwrap t3) `shouldBe` (unsafeShiftL 1 25)
    (Bitfield.unwrap t4) `shouldBe` 25

  it "get @name b == name (unpack b)" $ forAllValid $ \(t :: Example) ->
    let bf = Bitfield.pack @Word32 t
    in get @"d" bf === d t

#if __GLASGOW_HASKELL__ >= 902
  it "get @name b == b.name" $ forAllValid $ \(t :: Example) ->
    let bf = Bitfield.pack @Word32 t
    in get @"d" bf === bf.d

  it "get @name b == (unpack b).name" $ forAllValid $ \(t :: Example) ->
    let bf = Bitfield.pack @Word32 t
    in (get @"b" bf === (unpack bf).b)
#endif
  
  it "get @name (set @name b x) == x" $ forAllValid $ \(t :: Example, x :: Word16) ->
    x === Bitfield.get @"c" (Bitfield.set @"c" (Bitfield.pack @Word32 t) x)
  
  it "unpack . pack = id" $ forAllValid $ \(t :: Example) ->
    t === (unpack $ pack @Word32 t)

data AEnum = A1 | A2 | A3 | A4
  deriving stock (Eq, Show, Enum, Generic)
  deriving (HasFixedBitSize, AsRep r) via GenericEnum AEnum

data ATest = ATest { a1 :: AEnum, b1 :: AEnum, c1 :: AEnum, d1 :: Bool, e1 :: Bool } deriving stock (Eq, Show, Generic)

-- AText fits into exactly 8 bits. This verifies that it compiles. Adding another constructor to AEnum changes its size and should not compile
compileTestAEnum :: Bitfield Word8 ATest
compileTestAEnum = pack $ ATest A1 A1 A1 True True

newtype SmallInt = SmallInt Int
  deriving newtype (Show, Eq)
  deriving (HasFixedBitSize, AsRep r) via (ViaIntegral 5 Int)

data AnotherTest = AnotherTest { a2 :: Bitfield Word8 ATest, b2 :: Bool, c2 :: SmallInt } deriving stock (Eq, Show, Generic)

compileAnotherTest :: Bitfield Word16 AnotherTest
compileAnotherTest = pack $ AnotherTest { a2 = pack $ ATest A1 A1 A1 True True, b2 = True, c2 = SmallInt 5 }