module Tests.Regress.Issue162 ( testTree ) where

import           Control.Monad (void)
import           Control.Applicative ((<$), (<*))
import           Data.Word
import           Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as LBS
import           Codec.CBOR.Decoding
import           Codec.CBOR.Read
import           Test.Tasty
import           Test.Tasty.HUnit

-- This example demonstrates a bug in cborg canonical decoding.
-- The bytes used here were drawn from a real application.

-- Decodes bigBytes x assuming x is a canonical integer encoding.
bigBytesDecoder :: Decoder s ()
bigBytesDecoder = ()
  <$ decodeListLenCanonical
  <* decodeMapLenCanonical
  <* decodeListLenCanonical
  <* decodeListLenCanonical
  <* decodeWord16Canonical
  <* decodeWord16Canonical
  <* decodeWord8Canonical
  <* decodeMapLenCanonical
  <* decodeMapLenCanonical
  <* decodeMapLenCanonical
  <* decodeListLenCanonical
  <* decodeWord8Canonical
  <* decodeListLenCanonical
  <* decodeListLenCanonical
  <* decodeMapLenCanonical
  <* decodeWord8Canonical
  <* decodeListLenCanonical
  <* decodeIntegerCanonical
  <* decodeWord32Canonical
  <* decodeWord8Canonical
  <* decodeListLenCanonical
  <* decodeIntegerCanonical
  <* decodeWord32Canonical

-- Encoding of 592033 :: BigInteger
-- 0xc2 means bignum, 0x43 means a 3-byte sequence
bigBytes :: [Word8] -> ByteString
bigBytes someEncodedInteger = LBS.pack $
    [ -- list of length 7
      0x87
      -- empty map
    , 0xa0
      -- Just
    , 0x81
      -- list of length 3, all items are 0
    , 0x83
    , 0x00, 0x00, 0x00
      -- empty maps
    , 0xa0
    , 0xa0
    , 0xa0
      -- singleton list (encoded Just)
    , 0x81
    , 0x00
    , 0x80
      -- singleton list (encoded Just)
    , 0x81
    , 0xa2
      -- key 0
    , 0x00
      -- value 0: a pair of numbers.
    , 0x82
    , 0x1a, 0x00, 0x04, 0xec, 0xf9
    , 0x1a, 0x1a, 0xeb, 0x97, 0x7a
      -- key 1
    , 0x01
      -- value 1: a pair of numbers.
    , 0x82 
    ] ++ someEncodedInteger ++
    [ 0x1a, 0x05, 0xee, 0x4d, 0x20
    ]

nonCanonicalInteger :: [Word8]
nonCanonicalInteger = [0xc2, 0x43, 0x09, 0x08, 0xa1]

shouldFailSimple :: Either DeserialiseFailure (LBS.ByteString, ())
shouldFailSimple = deserialiseFromBytes (void decodeIntegerCanonical) (LBS.pack nonCanonicalInteger)

shouldFailComposite :: Either DeserialiseFailure (LBS.ByteString, ())
shouldFailComposite = deserialiseFromBytes bigBytesDecoder (bigBytes nonCanonicalInteger)

testTree :: TestTree
testTree =
    testGroup "Issue 162 - canonical decoding"
        [ testCase "simple" (Left (DeserialiseFailure 0 "non-canonical integer") @=? shouldFailSimple)
        , testCase "composite" (Left (DeserialiseFailure 34 "non-canonical integer") @=? shouldFailComposite)
        ]
