diff --git a/benchmark/Octane/Type/ActorBench.hs b/benchmark/Octane/Type/ActorBench.hs
--- a/benchmark/Octane/Type/ActorBench.hs
+++ b/benchmark/Octane/Type/ActorBench.hs
@@ -10,8 +10,12 @@
 
 benchmarks :: Benchmark
 benchmarks = bgroup "Actor"
-    [ bench "decode basic" (nf decodeActor "\1\0\0\0\0\0\0\0\0")
-    , bench "encode basic" (nf Binary.encode (Actor (PCString "") (Int32LE 0)))
+    [ bench "decode basic" (nf decodeActor "\
+        \\1\0\0\0\0\
+        \\0\0\0\0")
+    , bench "encode basic" (nf Binary.encode (Actor
+        (PCString "")
+        (Int32LE 0)))
     ]
 
 decodeActor :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Actor)
diff --git a/benchmark/Octane/Type/CacheItemBench.hs b/benchmark/Octane/Type/CacheItemBench.hs
--- a/benchmark/Octane/Type/CacheItemBench.hs
+++ b/benchmark/Octane/Type/CacheItemBench.hs
@@ -10,8 +10,16 @@
 
 benchmarks :: Benchmark
 benchmarks = bgroup "CacheItem"
-    [ bench "decode basic" (nf decodeCacheItem "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
-    , bench "encode basic" (nf Binary.encode (CacheItem (Int32LE 0) (Int32LE 0) (Int32LE 0) (List [])))
+    [ bench "decode basic" (nf decodeCacheItem "\
+        \\0\0\0\0\
+        \\0\0\0\0\
+        \\0\0\0\0\
+        \\0\0\0\0")
+    , bench "encode basic" (nf Binary.encode (CacheItem
+        (Int32LE 0)
+        (Int32LE 0)
+        (Int32LE 0)
+        (List [])))
     ]
 
 decodeCacheItem :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, CacheItem)
diff --git a/benchmark/Octane/Type/CachePropertyBench.hs b/benchmark/Octane/Type/CachePropertyBench.hs
--- a/benchmark/Octane/Type/CachePropertyBench.hs
+++ b/benchmark/Octane/Type/CachePropertyBench.hs
@@ -10,8 +10,12 @@
 
 benchmarks :: Benchmark
 benchmarks = bgroup "CacheProperty"
-    [ bench "decode basic" (nf decodeCacheProperty "\0\0\0\0\0\0\0\0")
-    , bench "encode basic" (nf Binary.encode (CacheProperty (Int32LE 0) (Int32LE 0)))
+    [ bench "decode basic" (nf decodeCacheProperty "\
+        \\0\0\0\0\
+        \\0\0\0\0")
+    , bench "encode basic" (nf Binary.encode (CacheProperty
+        (Int32LE 0) 
+        (Int32LE 0)))
     ]
 
 decodeCacheProperty :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, CacheProperty)
diff --git a/benchmark/Octane/Type/FrameBench.hs b/benchmark/Octane/Type/FrameBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/FrameBench.hs
@@ -0,0 +1,22 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Octane.Type.FrameBench (benchmarks) where
+
+import Criterion
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import Octane
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Frame"
+    [ bench "decode basic" (nf decodeFrame "\
+        \\0\0\0\0\
+        \\0\0\0\0")
+    , bench "encode basic" (nf Binary.encode (Frame
+        (Float32LE 0.0)
+        (Float32LE 0.0)))
+    ]
+
+decodeFrame :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Frame)
+decodeFrame = Binary.decodeOrFail
diff --git a/benchmark/Octane/Type/KeyFrameBench.hs b/benchmark/Octane/Type/KeyFrameBench.hs
--- a/benchmark/Octane/Type/KeyFrameBench.hs
+++ b/benchmark/Octane/Type/KeyFrameBench.hs
@@ -10,8 +10,14 @@
 
 benchmarks :: Benchmark
 benchmarks = bgroup "KeyFrame"
-    [ bench "decode basic" (nf decodeKeyFrame "\0\0\0\0\0\0\0\0\0\0\0\0")
-    , bench "encode basic" (nf Binary.encode (KeyFrame (Float32LE 0.0) (Int32LE 0) (Int32LE 0)))
+    [ bench "decode basic" (nf decodeKeyFrame "\
+        \\0\0\0\0\
+        \\0\0\0\0\
+        \\0\0\0\0")
+    , bench "encode basic" (nf Binary.encode (KeyFrame
+        (Float32LE 0.0)
+        (Int32LE 0)
+        (Int32LE 0)))
     ]
 
 decodeKeyFrame :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, KeyFrame)
diff --git a/benchmark/Octane/Type/MarkBench.hs b/benchmark/Octane/Type/MarkBench.hs
--- a/benchmark/Octane/Type/MarkBench.hs
+++ b/benchmark/Octane/Type/MarkBench.hs
@@ -10,8 +10,12 @@
 
 benchmarks :: Benchmark
 benchmarks = bgroup "Mark"
-    [ bench "decode basic" (nf decodeMark "\1\0\0\0\0\0\0\0\0")
-    , bench "encode basic" (nf Binary.encode (Mark (PCString "") (Int32LE 0)))
+    [ bench "decode basic" (nf decodeMark "\
+        \\1\0\0\0\0\
+        \\0\0\0\0")
+    , bench "encode basic" (nf Binary.encode (Mark
+        (PCString "")
+        (Int32LE 0)))
     ]
 
 decodeMark :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Mark)
diff --git a/benchmark/Octane/Type/MessageBench.hs b/benchmark/Octane/Type/MessageBench.hs
--- a/benchmark/Octane/Type/MessageBench.hs
+++ b/benchmark/Octane/Type/MessageBench.hs
@@ -10,8 +10,14 @@
 
 benchmarks :: Benchmark
 benchmarks = bgroup "Message"
-    [ bench "decode basic" (nf decodeMessage "\0\0\0\0\1\0\0\0\0\1\0\0\0\0")
-    , bench "encode basic" (nf Binary.encode (Message (Int32LE 0) (PCString "") (PCString "")))
+    [ bench "decode basic" (nf decodeMessage "\
+        \\0\0\0\0\
+        \\1\0\0\0\0\
+        \\1\0\0\0\0")
+    , bench "encode basic" (nf Binary.encode (Message
+        (Int32LE 0)
+        (PCString "")
+        (PCString "")))
     ]
 
 decodeMessage :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Message)
diff --git a/benchmark/Octane/Type/Primitive/StreamBench.hs b/benchmark/Octane/Type/Primitive/StreamBench.hs
new file mode 100644
--- /dev/null
+++ b/benchmark/Octane/Type/Primitive/StreamBench.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Octane.Type.Primitive.StreamBench (benchmarks) where
+
+import Criterion
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import Octane
+
+benchmarks :: Benchmark
+benchmarks = bgroup "Stream"
+    [ bench "decode basic" (nf decodeStream "\0\0\0\0")
+    , bench "encode basic" (nf Binary.encode (Stream ""))
+    ]
+
+decodeStream :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Stream)
+decodeStream = Binary.decodeOrFail
diff --git a/benchmark/Octane/Type/PrimitiveBench.hs b/benchmark/Octane/Type/PrimitiveBench.hs
--- a/benchmark/Octane/Type/PrimitiveBench.hs
+++ b/benchmark/Octane/Type/PrimitiveBench.hs
@@ -8,6 +8,7 @@
 import qualified Octane.Type.Primitive.Int64LEBench
 import qualified Octane.Type.Primitive.ListBench
 import qualified Octane.Type.Primitive.PCStringBench
+import qualified Octane.Type.Primitive.StreamBench
 
 benchmarks :: Benchmark
 benchmarks = bgroup "Primitive"
@@ -18,4 +19,5 @@
     , Octane.Type.Primitive.Int64LEBench.benchmarks
     , Octane.Type.Primitive.ListBench.benchmarks
     , Octane.Type.Primitive.PCStringBench.benchmarks
+    , Octane.Type.Primitive.StreamBench.benchmarks
     ]
diff --git a/benchmark/Octane/Type/PropertyBench.hs b/benchmark/Octane/Type/PropertyBench.hs
--- a/benchmark/Octane/Type/PropertyBench.hs
+++ b/benchmark/Octane/Type/PropertyBench.hs
@@ -14,8 +14,7 @@
         [ bench "decode basic" (nf decodeProperty "\
             \\14\0\0\0ArrayProperty\0\
             \\0\0\0\0\0\0\0\0\
-            \\0\0\0\0\
-            \")
+            \\0\0\0\0")
         , bench "encode basic" (nf Binary.encode (ArrayProperty
             (Int64LE 0)
             (List [])))
@@ -24,8 +23,7 @@
         [ bench "decode basic" (nf decodeProperty "\
             \\13\0\0\0BoolProperty\0\
             \\0\0\0\0\0\0\0\0\
-            \\0\
-            \")
+            \\0")
         , bench "encode basic" (nf Binary.encode (BoolProperty
             (Int64LE 0)
             (Boolean False)))
@@ -35,8 +33,7 @@
             \\13\0\0\0ByteProperty\0\
             \\0\0\0\0\0\0\0\0\
             \\1\0\0\0\0\
-            \\1\0\0\0\0\
-            \")
+            \\1\0\0\0\0")
         , bench "encode basic" (nf Binary.encode (ByteProperty
             (Int64LE 0)
             (PCString "", PCString "")))
@@ -45,8 +42,7 @@
         [ bench "decode basic" (nf decodeProperty "\
             \\14\0\0\0FloatProperty\0\
             \\4\0\0\0\0\0\0\0\
-            \\0\0\0\0\
-            \")
+            \\0\0\0\0")
         , bench "encode basic" (nf Binary.encode (FloatProperty
             (Int64LE 4)
             (Float32LE 0.0)))
@@ -55,8 +51,7 @@
         [ bench "decode basic" (nf decodeProperty "\
             \\12\0\0\0IntProperty\0\
             \\4\0\0\0\0\0\0\0\
-            \\0\0\0\0\
-            \")
+            \\0\0\0\0")
         , bench "encode basic" (nf Binary.encode (IntProperty
             (Int64LE 4)
             (Int32LE 0)))
@@ -65,8 +60,7 @@
         [ bench "decode basic" (nf decodeProperty "\
             \\13\0\0\0NameProperty\0\
             \\0\0\0\0\0\0\0\0\
-            \\1\0\0\0\0\
-            \")
+            \\1\0\0\0\0")
         , bench "encode basic" (nf Binary.encode (NameProperty
             (Int64LE 0)
             (PCString "")))
@@ -75,8 +69,7 @@
         [ bench "decode basic" (nf decodeProperty "\
             \\14\0\0\0QWordProperty\0\
             \\8\0\0\0\0\0\0\0\
-            \\0\0\0\0\0\0\0\0\
-            \")
+            \\0\0\0\0\0\0\0\0")
         , bench "encode basic" (nf Binary.encode (QWordProperty
             (Int64LE 8)
             (Int64LE 0)))
@@ -85,8 +78,7 @@
         [ bench "decode basic" (nf decodeProperty "\
             \\12\0\0\0StrProperty\0\
             \\0\0\0\0\0\0\0\0\
-            \\1\0\0\0\0\
-            \")
+            \\1\0\0\0\0")
         , bench "encode basic" (nf Binary.encode (StrProperty
             (Int64LE 0)
             (PCString "")))
diff --git a/benchmark/Octane/Type/ReplayBench.hs b/benchmark/Octane/Type/ReplayBench.hs
--- a/benchmark/Octane/Type/ReplayBench.hs
+++ b/benchmark/Octane/Type/ReplayBench.hs
@@ -29,8 +29,7 @@
         \\0\0\0\0\
         \\0\0\0\0\
         \\0\0\0\0\
-        \\0\0\0\0\
-        \")
+        \\0\0\0\0")
     , bench "encode basic" (nf Binary.encode (Replay
         (Int32LE 0)
         (Int32LE 0)
@@ -42,7 +41,7 @@
         (Int32LE 0)
         (List [])
         (List [])
-        ""
+        (Stream "")
         (List [])
         (List [])
         (List [])
diff --git a/benchmark/Octane/TypeBench.hs b/benchmark/Octane/TypeBench.hs
--- a/benchmark/Octane/TypeBench.hs
+++ b/benchmark/Octane/TypeBench.hs
@@ -4,6 +4,7 @@
 import qualified Octane.Type.ActorBench
 import qualified Octane.Type.CacheItemBench
 import qualified Octane.Type.CachePropertyBench
+import qualified Octane.Type.FrameBench
 import qualified Octane.Type.KeyFrameBench
 import qualified Octane.Type.MarkBench
 import qualified Octane.Type.MessageBench
@@ -16,6 +17,7 @@
     [ Octane.Type.ActorBench.benchmarks
     , Octane.Type.CacheItemBench.benchmarks
     , Octane.Type.CachePropertyBench.benchmarks
+    , Octane.Type.FrameBench.benchmarks
     , Octane.Type.KeyFrameBench.benchmarks
     , Octane.Type.MarkBench.benchmarks
     , Octane.Type.MessageBench.benchmarks
diff --git a/library/Octane/Type.hs b/library/Octane/Type.hs
--- a/library/Octane/Type.hs
+++ b/library/Octane/Type.hs
@@ -2,6 +2,7 @@
     ( module Octane.Type.Actor
     , module Octane.Type.CacheItem
     , module Octane.Type.CacheProperty
+    , module Octane.Type.Frame
     , module Octane.Type.KeyFrame
     , module Octane.Type.Mark
     , module Octane.Type.Message
@@ -13,6 +14,7 @@
 import Octane.Type.Actor
 import Octane.Type.CacheItem
 import Octane.Type.CacheProperty
+import Octane.Type.Frame
 import Octane.Type.KeyFrame
 import Octane.Type.Mark
 import Octane.Type.Message
diff --git a/library/Octane/Type/Frame.hs b/library/Octane/Type/Frame.hs
new file mode 100644
--- /dev/null
+++ b/library/Octane/Type/Frame.hs
@@ -0,0 +1,25 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DeriveGeneric #-}
+
+module Octane.Type.Frame (Frame(..)) where
+
+import Octane.Core
+import Octane.Type.Primitive.Float32LE
+
+data Frame = Frame
+    { frameTime :: Float32LE
+    , frameDelta :: Float32LE
+    } deriving (Eq, Generic, NFData, Show)
+
+instance Binary Frame where
+    get = do
+        time <- get
+        delta <- get
+        return Frame
+            { frameTime = time
+            , frameDelta = delta
+            }
+
+    put frame = do
+        frame & frameTime & put
+        frame & frameDelta & put
diff --git a/library/Octane/Type/Primitive.hs b/library/Octane/Type/Primitive.hs
--- a/library/Octane/Type/Primitive.hs
+++ b/library/Octane/Type/Primitive.hs
@@ -6,6 +6,7 @@
     , module Octane.Type.Primitive.List
     , module Octane.Type.Primitive.PCString
     , module Octane.Type.Primitive.Dictionary
+    , module Octane.Type.Primitive.Stream
     ) where
 
 import Octane.Type.Primitive.Boolean
@@ -15,3 +16,4 @@
 import Octane.Type.Primitive.List
 import Octane.Type.Primitive.PCString
 import Octane.Type.Primitive.Dictionary
+import Octane.Type.Primitive.Stream
diff --git a/library/Octane/Type/Primitive/Boolean.hs b/library/Octane/Type/Primitive/Boolean.hs
--- a/library/Octane/Type/Primitive/Boolean.hs
+++ b/library/Octane/Type/Primitive/Boolean.hs
@@ -14,7 +14,7 @@
     get = do
         boolean <- getWord8
         if boolean > 1
-        then fail "out of bounds"
+        then fail ("invalid Boolean value " ++ show boolean)
         else boolean & fromIntegral & toEnum & Boolean & return
 
     put (Boolean boolean) = do
diff --git a/library/Octane/Type/Primitive/PCString.hs b/library/Octane/Type/Primitive/PCString.hs
--- a/library/Octane/Type/Primitive/PCString.hs
+++ b/library/Octane/Type/Primitive/PCString.hs
@@ -17,7 +17,7 @@
     get = do
         (Int32LE size) <- get
         string <- if size == 0
-            then fail "invalid size"
+            then fail ("invalid PCString size " ++ show size)
             else if size < 0
             then do
                 let actualSize = 2 * negate size
diff --git a/library/Octane/Type/Primitive/Stream.hs b/library/Octane/Type/Primitive/Stream.hs
new file mode 100644
--- /dev/null
+++ b/library/Octane/Type/Primitive/Stream.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+
+module Octane.Type.Primitive.Stream (Stream(..)) where
+
+import qualified Data.ByteString as BS
+import Octane.Core
+import Octane.Type.Primitive.Int32LE
+
+newtype Stream = Stream
+    { getStream :: ByteString
+    } deriving (Eq, Generic, NFData, Show)
+
+instance Binary Stream where
+    get = do
+        size <- get
+        content <- size & getInt32LE & fromIntegral & getByteString
+        content & Stream & return
+
+    put stream = do
+        let content = getStream stream
+        let size = BS.length content
+        size & fromIntegral & Int32LE & put
+        content & putByteString
diff --git a/library/Octane/Type/Property.hs b/library/Octane/Type/Property.hs
--- a/library/Octane/Type/Property.hs
+++ b/library/Octane/Type/Property.hs
@@ -27,37 +27,44 @@
 instance Binary Property where
     get = do
         kind <- get
-        size <- get
         case getPCString kind of
             "ArrayProperty" -> do
+                size <- get
                 value <- get
                 ArrayProperty size value & return
             "BoolProperty" -> do
+                size <- get
                 value <- get
                 BoolProperty size value & return
             "ByteProperty" -> do
+                size <- get
                 key <- get
                 value <- get
                 ByteProperty size (key, value) & return
             "FloatProperty" -> do
+                size <- get
                 value <- case getInt64LE size of
                     4 -> get
                     x -> fail ("unknown FloatProperty size " ++ show x)
                 FloatProperty size value & return
             "IntProperty" -> do
+                size <- get
                 value <- case getInt64LE size of
                     4 -> get
                     x -> fail ("unknown IntProperty size " ++ show x)
                 IntProperty size value & return
             "NameProperty" -> do
+                size <- get
                 value <- get
                 NameProperty size value & return
             "QWordProperty" -> do
+                size <- get
                 value <- case getInt64LE size of
                     8 -> get
                     x -> fail ("unknown QWordProperty size " ++ show x)
                 QWordProperty size value & return
             "StrProperty" -> do
+                size <- get
                 value <- get
                 StrProperty size value & return
             x -> fail ("unknown property type " ++ show x)
diff --git a/library/Octane/Type/Replay.hs b/library/Octane/Type/Replay.hs
--- a/library/Octane/Type/Replay.hs
+++ b/library/Octane/Type/Replay.hs
@@ -3,7 +3,6 @@
 
 module Octane.Type.Replay (Replay(..)) where
 
-import qualified Data.ByteString as BS
 import Octane.Core
 import Octane.Type.Actor
 import Octane.Type.CacheItem
@@ -15,6 +14,7 @@
 import Octane.Type.Primitive.List
 import Octane.Type.Property
 import Octane.Type.Primitive.Dictionary
+import Octane.Type.Primitive.Stream
 
 data Replay = Replay
     { replaySize1 :: Int32LE
@@ -27,7 +27,7 @@
     , replayCRC2 :: Int32LE
     , replayEffects :: List PCString
     , replayKeyFrames :: List KeyFrame
-    , replayFrames :: ByteString
+    , replayStream :: Stream
     , replayMessages :: List Message
     , replayMarks :: List Mark
     , replayPackages :: List PCString
@@ -49,7 +49,7 @@
         crc2 <- get
         effects <- get
         keyFrames <- get
-        frames <- getFrameBytes
+        stream <- get
         messages <- get
         marks <- get
         packages <- get
@@ -68,7 +68,7 @@
             , replayCRC2 = crc2
             , replayEffects = effects
             , replayKeyFrames = keyFrames
-            , replayFrames = frames
+            , replayStream = stream
             , replayMessages = messages
             , replayMarks = marks
             , replayPackages = packages
@@ -89,7 +89,7 @@
         replay & replayCRC2 & put
         replay & replayEffects & put
         replay & replayKeyFrames & put
-        replay & replayFrames & putFrameBytes
+        replay & replayStream & put
         replay & replayMessages & put
         replay & replayMarks & put
         replay & replayPackages & put
@@ -97,14 +97,3 @@
         replay & replayNames & put
         replay & replayActors & put
         replay & replayCacheItems & put
-
-getFrameBytes :: Get ByteString
-getFrameBytes = do
-    Int32LE size <- get
-    frames <- getByteString (fromIntegral size)
-    return frames
-
-putFrameBytes :: ByteString -> Put
-putFrameBytes frames = do
-    frames & BS.length & fromIntegral & Int32LE & put
-    frames & putByteString
diff --git a/octane.cabal b/octane.cabal
--- a/octane.cabal
+++ b/octane.cabal
@@ -1,5 +1,5 @@
 name: octane
-version: 0.3.0
+version: 0.4.0
 cabal-version: >=1.10
 build-type: Simple
 license: MIT
@@ -27,6 +27,7 @@
         Octane.Type.Actor
         Octane.Type.CacheItem
         Octane.Type.CacheProperty
+        Octane.Type.Frame
         Octane.Type.KeyFrame
         Octane.Type.Mark
         Octane.Type.Message
@@ -40,6 +41,7 @@
         Octane.Type.Primitive.Dictionary
         Octane.Type.Property
         Octane.Type.Replay
+        Octane.Type.Primitive.Stream
     build-depends:
         base ==4.8.*,
         binary ==0.7.*,
@@ -83,6 +85,7 @@
         Octane.Type.ActorSpec
         Octane.Type.CacheItemSpec
         Octane.Type.CachePropertySpec
+        Octane.Type.FrameSpec
         Octane.Type.KeyFrameSpec
         Octane.Type.MarkSpec
         Octane.Type.MessageSpec
@@ -96,6 +99,7 @@
         Octane.Type.Primitive.DictionarySpec
         Octane.Type.PropertySpec
         Octane.Type.ReplaySpec
+        Octane.Type.Primitive.StreamSpec
     ghc-options: -threaded -Wall
 
 benchmark octane-benchmark
@@ -117,6 +121,7 @@
         Octane.Type.ActorBench
         Octane.Type.CacheItemBench
         Octane.Type.CachePropertyBench
+        Octane.Type.FrameBench
         Octane.Type.KeyFrameBench
         Octane.Type.MarkBench
         Octane.Type.MessageBench
@@ -130,4 +135,5 @@
         Octane.Type.Primitive.PCStringBench
         Octane.Type.PropertyBench
         Octane.Type.ReplayBench
+        Octane.Type.Primitive.StreamBench
     ghc-options: -threaded -Wall
diff --git a/test-suite/Octane/Type/ActorSpec.hs b/test-suite/Octane/Type/ActorSpec.hs
--- a/test-suite/Octane/Type/ActorSpec.hs
+++ b/test-suite/Octane/Type/ActorSpec.hs
@@ -11,11 +11,35 @@
 spec :: Spec
 spec = describe "Actor" $ do
     it "can be decoded" $ do
-        decodeActor "\1\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 9, Actor (PCString "") (Int32LE 0))
-        decodeActor "\2\0\0\0a\0\2\0\0\0" `shouldBe` Right ("", 10, Actor (PCString "a") (Int32LE 2))
+        shouldBe
+            (decodeActor "\
+                \\1\0\0\0\0\
+                \\0\0\0\0")
+            (Right ("", 9, Actor
+                (PCString "")
+                (Int32LE 0)))
+        shouldBe
+            (decodeActor "\
+                \\2\0\0\0a\0\
+                \\2\0\0\0")
+            (Right ("", 10, Actor
+                (PCString "a")
+                (Int32LE 2)))
     it "can be encoded" $ do
-        Binary.encode (Actor (PCString "") (Int32LE 0)) `shouldBe` "\1\0\0\0\0\0\0\0\0"
-        Binary.encode (Actor (PCString "a") (Int32LE 2)) `shouldBe` "\2\0\0\0a\0\2\0\0\0"
+        shouldBe
+            (Binary.encode (Actor
+                (PCString "")
+                (Int32LE 0)))
+            "\
+                \\1\0\0\0\0\
+                \\0\0\0\0"
+        shouldBe
+            (Binary.encode (Actor
+                (PCString "a")
+                (Int32LE 2)))
+            "\
+                \\2\0\0\0a\0\
+                \\2\0\0\0"
 
 decodeActor :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Actor)
 decodeActor = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/CacheItemSpec.hs b/test-suite/Octane/Type/CacheItemSpec.hs
--- a/test-suite/Octane/Type/CacheItemSpec.hs
+++ b/test-suite/Octane/Type/CacheItemSpec.hs
@@ -11,11 +11,53 @@
 spec :: Spec
 spec = describe "CacheItem" $ do
     it "can be decoded" $ do
-        decodeCacheItem "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 16, CacheItem (Int32LE 0) (Int32LE 0) (Int32LE 0) (List []))
-        decodeCacheItem "\1\0\0\0\2\0\0\0\3\0\0\0\1\0\0\0\4\0\0\0\5\0\0\0" `shouldBe` Right ("", 24, CacheItem (Int32LE 1) (Int32LE 2) (Int32LE 3) (List [CacheProperty (Int32LE 4) (Int32LE 5)]))
+        shouldBe
+            (decodeCacheItem "\
+                \\0\0\0\0\
+                \\0\0\0\0\
+                \\0\0\0\0\
+                \\0\0\0\0")
+            (Right ("", 16, CacheItem
+                (Int32LE 0)
+                (Int32LE 0)
+                (Int32LE 0)
+                (List [])))
+        shouldBe
+            (decodeCacheItem "\
+                \\1\0\0\0\
+                \\2\0\0\0\
+                \\3\0\0\0\
+                \\1\0\0\0\
+                \\4\0\0\0\5\0\0\0")
+            (Right ("", 24, CacheItem
+                (Int32LE 1)
+                (Int32LE 2)
+                (Int32LE 3)
+                (List [CacheProperty (Int32LE 4) (Int32LE 5)])))
     it "can be encoded" $ do
-        Binary.encode (CacheItem (Int32LE 0) (Int32LE 0) (Int32LE 0) (List [])) `shouldBe` "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
-        Binary.encode (CacheItem (Int32LE 1) (Int32LE 2) (Int32LE 3) (List [CacheProperty (Int32LE 4) (Int32LE 5)])) `shouldBe` "\1\0\0\0\2\0\0\0\3\0\0\0\1\0\0\0\4\0\0\0\5\0\0\0"
+        shouldBe
+            (Binary.encode (CacheItem
+                (Int32LE 0)
+                (Int32LE 0)
+                (Int32LE 0)
+                (List [])))
+            "\
+                \\0\0\0\0\
+                \\0\0\0\0\
+                \\0\0\0\0\
+                \\0\0\0\0"
+        shouldBe
+            (Binary.encode (CacheItem
+                (Int32LE 1)
+                (Int32LE 2)
+                (Int32LE 3)
+                (List [CacheProperty (Int32LE 4) (Int32LE 5)])))
+            "\
+                \\1\0\0\0\
+                \\2\0\0\0\
+                \\3\0\0\0\
+                \\1\0\0\0\
+                \\4\0\0\0\5\0\0\0"
 
 decodeCacheItem :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, CacheItem)
 decodeCacheItem = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/CachePropertySpec.hs b/test-suite/Octane/Type/CachePropertySpec.hs
--- a/test-suite/Octane/Type/CachePropertySpec.hs
+++ b/test-suite/Octane/Type/CachePropertySpec.hs
@@ -11,11 +11,35 @@
 spec :: Spec
 spec = describe "CacheProperty" $ do
     it "can be decoded" $ do
-        decodeCacheProperty "\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 8, CacheProperty (Int32LE 0) (Int32LE 0))
-        decodeCacheProperty "\1\0\0\0\2\0\0\0" `shouldBe` Right ("", 8, CacheProperty (Int32LE 1) (Int32LE 2))
+        shouldBe
+            (decodeCacheProperty "\
+                \\0\0\0\0\
+                \\0\0\0\0")
+            (Right ("", 8, CacheProperty
+                (Int32LE 0)
+                (Int32LE 0)))
+        shouldBe
+            (decodeCacheProperty "\
+                \\1\0\0\0\
+                \\2\0\0\0")
+            (Right ("", 8, CacheProperty
+                (Int32LE 1)
+                (Int32LE 2)))
     it "can be encoded" $ do
-        Binary.encode (CacheProperty (Int32LE 0) (Int32LE 0)) `shouldBe` "\0\0\0\0\0\0\0\0"
-        Binary.encode (CacheProperty (Int32LE 1) (Int32LE 2)) `shouldBe` "\1\0\0\0\2\0\0\0"
+        shouldBe
+            (Binary.encode (CacheProperty
+                (Int32LE 0)
+                (Int32LE 0)))
+            "\
+                \\0\0\0\0\
+                \\0\0\0\0"
+        shouldBe
+            (Binary.encode (CacheProperty
+                (Int32LE 1)
+                (Int32LE 2)))
+            "\
+                \\1\0\0\0\
+                \\2\0\0\0"
 
 decodeCacheProperty :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, CacheProperty)
 decodeCacheProperty = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/FrameSpec.hs b/test-suite/Octane/Type/FrameSpec.hs
new file mode 100644
--- /dev/null
+++ b/test-suite/Octane/Type/FrameSpec.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Octane.Type.FrameSpec (spec) where
+
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import Octane
+import Test.Tasty.Hspec
+
+spec :: Spec
+spec = describe "Frame" $ do
+    it "can be decoded" $ do
+        shouldBe
+            (decodeFrame "\
+                \\0\0\0\0\
+                \\0\0\0\0")
+            (Right ("", 8, Frame
+                (Float32LE 0.0)
+                (Float32LE 0.0)))
+    it "can be encoded" $ do
+        shouldBe
+            (Binary.encode (Frame
+                (Float32LE 0.0)
+                (Float32LE 0.0)))
+            "\
+                \\0\0\0\0\
+                \\0\0\0\0"
+
+decodeFrame :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Frame)
+decodeFrame = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/KeyFrameSpec.hs b/test-suite/Octane/Type/KeyFrameSpec.hs
--- a/test-suite/Octane/Type/KeyFrameSpec.hs
+++ b/test-suite/Octane/Type/KeyFrameSpec.hs
@@ -11,11 +11,43 @@
 spec :: Spec
 spec = describe "KeyFrame" $ do
     it "can be decoded" $ do
-        decodeKeyFrame "\0\0\0\0\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 12, KeyFrame (Float32LE 0.0) (Int32LE 0) (Int32LE 0))
-        decodeKeyFrame "\0\0\128\63\2\0\0\0\3\0\0\0" `shouldBe` Right ("", 12, KeyFrame (Float32LE 1.0) (Int32LE 2) (Int32LE 3))
+        shouldBe
+            (decodeKeyFrame "\
+                \\0\0\0\0\
+                \\0\0\0\0\
+                \\0\0\0\0")
+            (Right ("", 12, KeyFrame
+                (Float32LE 0.0)
+                (Int32LE 0)
+                (Int32LE 0)))
+        shouldBe
+            (decodeKeyFrame "\
+                \\0\0\128\63\
+                \\2\0\0\0\
+                \\3\0\0\0")
+            (Right ("", 12, KeyFrame
+                (Float32LE 1.0)
+                (Int32LE 2)
+                (Int32LE 3)))
     it "can be encoded" $ do
-        Binary.encode (KeyFrame (Float32LE 0.0) (Int32LE 0) (Int32LE 0)) `shouldBe` "\0\0\0\0\0\0\0\0\0\0\0\0"
-        Binary.encode (KeyFrame (Float32LE 1.0) (Int32LE 2) (Int32LE 3)) `shouldBe` "\0\0\128\63\2\0\0\0\3\0\0\0"
+        shouldBe
+            (Binary.encode (KeyFrame
+                (Float32LE 0.0)
+                (Int32LE 0)
+                (Int32LE 0)))
+            "\
+                \\0\0\0\0\
+                \\0\0\0\0\
+                \\0\0\0\0"
+        shouldBe
+            (Binary.encode (KeyFrame
+                (Float32LE 1.0)
+                (Int32LE 2)
+                (Int32LE 3)))
+            "\
+                \\0\0\128\63\
+                \\2\0\0\0\
+                \\3\0\0\0"
 
 decodeKeyFrame :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, KeyFrame)
 decodeKeyFrame = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/MarkSpec.hs b/test-suite/Octane/Type/MarkSpec.hs
--- a/test-suite/Octane/Type/MarkSpec.hs
+++ b/test-suite/Octane/Type/MarkSpec.hs
@@ -11,11 +11,35 @@
 spec :: Spec
 spec = describe "Mark" $ do
     it "can be decoded" $ do
-        decodeMark "\1\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 9, Mark (PCString "") (Int32LE 0))
-        decodeMark "\2\0\0\0a\0\1\0\0\0" `shouldBe` Right ("", 10, Mark (PCString "a") (Int32LE 1))
+        shouldBe
+            (decodeMark "\
+                \\1\0\0\0\0\
+                \\0\0\0\0")
+            (Right ("", 9, Mark
+                (PCString "")
+                (Int32LE 0)))
+        shouldBe
+            (decodeMark "\
+                \\2\0\0\0a\0\
+                \\1\0\0\0")
+            (Right ("", 10, Mark
+                (PCString "a")
+                (Int32LE 1)))
     it "can be encoded" $ do
-        Binary.encode (Mark (PCString "") (Int32LE 0)) `shouldBe` "\1\0\0\0\0\0\0\0\0"
-        Binary.encode (Mark (PCString "a") (Int32LE 1)) `shouldBe` "\2\0\0\0a\0\1\0\0\0"
+        shouldBe
+            (Binary.encode (Mark
+                (PCString "")
+                (Int32LE 0)))
+            "\
+                \\1\0\0\0\0\
+                \\0\0\0\0"
+        shouldBe
+            (Binary.encode (Mark
+                (PCString "a")
+                (Int32LE 1)))
+            "\
+                \\2\0\0\0a\0\
+                \\1\0\0\0"
 
 decodeMark :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Mark)
 decodeMark = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/MessageSpec.hs b/test-suite/Octane/Type/MessageSpec.hs
--- a/test-suite/Octane/Type/MessageSpec.hs
+++ b/test-suite/Octane/Type/MessageSpec.hs
@@ -11,11 +11,37 @@
 spec :: Spec
 spec = describe "Message" $ do
     it "can be decoded" $ do
-        decodeMessage "\0\0\0\0\1\0\0\0\0\1\0\0\0\0" `shouldBe` Right ("", 14, Message (Int32LE 0) (PCString "") (PCString ""))
-        decodeMessage "\1\0\0\0\2\0\0\0a\0\2\0\0\0b\0" `shouldBe` Right ("", 16, Message (Int32LE 1) (PCString "a") (PCString "b"))
+        shouldBe
+            (decodeMessage "\
+                \\0\0\0\0\
+                \\1\0\0\0\0\
+                \\1\0\0\0\0")
+            (Right ("", 14, Message
+                (Int32LE 0)
+                (PCString "")
+                (PCString "")))
+        shouldBe
+            (decodeMessage "\
+                \\1\0\0\0\
+                \\2\0\0\0a\0\
+                \\2\0\0\0b\0")
+            (Right ("", 16, Message
+                (Int32LE 1)
+                (PCString "a")
+                (PCString "b")))
     it "can be encoded" $ do
-        Binary.encode (Message (Int32LE 0) (PCString "") (PCString "")) `shouldBe` "\0\0\0\0\1\0\0\0\0\1\0\0\0\0"
-        Binary.encode (Message (Int32LE 1) (PCString "a") (PCString "b")) `shouldBe` "\1\0\0\0\2\0\0\0a\0\2\0\0\0b\0"
+        shouldBe
+            (Binary.encode (Message (Int32LE 0) (PCString "") (PCString "")))
+            "\
+                \\0\0\0\0\
+                \\1\0\0\0\0\
+                \\1\0\0\0\0"
+        shouldBe
+            (Binary.encode (Message (Int32LE 1) (PCString "a") (PCString "b")))
+            "\
+                \\1\0\0\0\
+                \\2\0\0\0a\0\
+                \\2\0\0\0b\0"
 
 decodeMessage :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Message)
 decodeMessage = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/BooleanSpec.hs b/test-suite/Octane/Type/Primitive/BooleanSpec.hs
--- a/test-suite/Octane/Type/Primitive/BooleanSpec.hs
+++ b/test-suite/Octane/Type/Primitive/BooleanSpec.hs
@@ -11,13 +11,23 @@
 spec :: Spec
 spec = describe "Boolean" $ do
     it "can be decoded" $ do
-        decodeBoolean "\0" `shouldBe` Right ("", 1, Boolean False)
-        decodeBoolean "\1" `shouldBe` Right ("", 1, Boolean True)
+        shouldBe
+            (decodeBoolean "\0")
+            (Right ("", 1, Boolean False))
+        shouldBe
+            (decodeBoolean "\1")
+            (Right ("", 1, Boolean True))
     it "can be encoded" $ do
-        Binary.encode (Boolean False) `shouldBe` "\0"
-        Binary.encode (Boolean True) `shouldBe` "\1"
+        shouldBe
+            (Binary.encode (Boolean False))
+            "\0"
+        shouldBe
+            (Binary.encode (Boolean True))
+            "\1"
     it "does not raise a runtime error when decoding garbage" $ do
-        decodeBoolean "garbage" `shouldBe` Left ("arbage", 1, "out of bounds")
+        shouldBe
+            (decodeBoolean "garbage")
+            (Left ("arbage", 1, "invalid Boolean value 103"))
 
 decodeBoolean :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Boolean)
 decodeBoolean = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/DictionarySpec.hs b/test-suite/Octane/Type/Primitive/DictionarySpec.hs
--- a/test-suite/Octane/Type/Primitive/DictionarySpec.hs
+++ b/test-suite/Octane/Type/Primitive/DictionarySpec.hs
@@ -12,13 +12,25 @@
 spec :: Spec
 spec = describe "Dictionary" $ do
     it "can be decoded" $ do
-        decodeDictionary "\5\0\0\0None\0" `shouldBe` Right ("", 9, Dictionary Map.empty :: Dictionary Boolean)
-        decodeDictionary "\6\0\0\0Hello\0\6\0\0\0World\0\5\0\0\0None\0" `shouldBe` Right ("", 29, Dictionary (Map.singleton (PCString "Hello") (PCString "World")))
-        decodeDictionary "\7\0\0\0falsey\0\0\7\0\0\0truthy\0\1\5\0\0\0None\0" `shouldBe` Right ("", 33, Dictionary (Map.fromList [(PCString "truthy", Boolean True), (PCString "falsey", Boolean False)]))
+        shouldBe
+            (decodeDictionary "\5\0\0\0None\0")
+            (Right ("", 9, Dictionary Map.empty :: Dictionary Boolean))
+        shouldBe
+            (decodeDictionary "\6\0\0\0Hello\0\6\0\0\0World\0\5\0\0\0None\0")
+            (Right ("", 29, Dictionary (Map.singleton (PCString "Hello") (PCString "World"))))
+        shouldBe
+            (decodeDictionary "\7\0\0\0falsey\0\0\7\0\0\0truthy\0\1\5\0\0\0None\0")
+            (Right ("", 33, Dictionary (Map.fromList [(PCString "truthy", Boolean True), (PCString "falsey", Boolean False)])))
     it "can be encoded" $ do
-        Binary.encode (Dictionary Map.empty :: Dictionary Boolean) `shouldBe` "\5\0\0\0None\0"
-        Binary.encode (Dictionary (Map.singleton (PCString "Hello") (PCString "World"))) `shouldBe` "\6\0\0\0Hello\0\6\0\0\0World\0\5\0\0\0None\0"
-        Binary.encode (Dictionary (Map.fromList [(PCString "truthy", Boolean True), (PCString "falsey", Boolean False)])) `shouldBe` "\7\0\0\0falsey\0\0\7\0\0\0truthy\0\1\5\0\0\0None\0"
+        shouldBe
+            (Binary.encode (Dictionary Map.empty :: Dictionary Boolean))
+            "\5\0\0\0None\0"
+        shouldBe
+            (Binary.encode (Dictionary (Map.singleton (PCString "Hello") (PCString "World"))))
+            "\6\0\0\0Hello\0\6\0\0\0World\0\5\0\0\0None\0"
+        shouldBe
+            (Binary.encode (Dictionary (Map.fromList [(PCString "truthy", Boolean True), (PCString "falsey", Boolean False)])))
+            "\7\0\0\0falsey\0\0\7\0\0\0truthy\0\1\5\0\0\0None\0"
 
 decodeDictionary :: (Binary.Binary a) => BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Dictionary a)
 decodeDictionary = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/Float32LESpec.hs b/test-suite/Octane/Type/Primitive/Float32LESpec.hs
--- a/test-suite/Octane/Type/Primitive/Float32LESpec.hs
+++ b/test-suite/Octane/Type/Primitive/Float32LESpec.hs
@@ -11,11 +11,19 @@
 spec :: Spec
 spec = describe "Float32LE" $ do
     it "can be decoded" $ do
-        decodeFloat32LE "\0\0\0\0" `shouldBe` Right ("", 4, Float32LE 0.0)
-        decodeFloat32LE "\0\0\128\63" `shouldBe` Right ("", 4, Float32LE 1.0)
+        shouldBe
+            (decodeFloat32LE "\0\0\0\0")
+            (Right ("", 4, Float32LE 0.0))
+        shouldBe
+            (decodeFloat32LE "\0\0\128\63")
+            (Right ("", 4, Float32LE 1.0))
     it "can be encoded" $ do
-        Binary.encode (Float32LE 0.0) `shouldBe` "\0\0\0\0"
-        Binary.encode (Float32LE 1.0) `shouldBe` "\0\0\128\63"
+        shouldBe
+            (Binary.encode (Float32LE 0.0))
+            "\0\0\0\0"
+        shouldBe
+            (Binary.encode (Float32LE 1.0))
+            "\0\0\128\63"
 
 decodeFloat32LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Float32LE)
 decodeFloat32LE = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/Int32LESpec.hs b/test-suite/Octane/Type/Primitive/Int32LESpec.hs
--- a/test-suite/Octane/Type/Primitive/Int32LESpec.hs
+++ b/test-suite/Octane/Type/Primitive/Int32LESpec.hs
@@ -11,11 +11,19 @@
 spec :: Spec
 spec = describe "Int32LE" $ do
     it "can be decoded" $ do
-        decodeInt32LE "\0\0\0\0" `shouldBe` Right ("", 4, Int32LE 0)
-        decodeInt32LE "\1\0\0\0" `shouldBe` Right ("", 4, Int32LE 1)
+        shouldBe
+            (decodeInt32LE "\0\0\0\0")
+            (Right ("", 4, Int32LE 0))
+        shouldBe
+            (decodeInt32LE "\1\0\0\0")
+            (Right ("", 4, Int32LE 1))
     it "can be encoded" $ do
-        Binary.encode (Int32LE 0) `shouldBe` "\0\0\0\0"
-        Binary.encode (Int32LE 1) `shouldBe` "\1\0\0\0"
+        shouldBe
+            (Binary.encode (Int32LE 0))
+            "\0\0\0\0"
+        shouldBe
+            (Binary.encode (Int32LE 1))
+            "\1\0\0\0"
 
 decodeInt32LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Int32LE)
 decodeInt32LE = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/Int64LESpec.hs b/test-suite/Octane/Type/Primitive/Int64LESpec.hs
--- a/test-suite/Octane/Type/Primitive/Int64LESpec.hs
+++ b/test-suite/Octane/Type/Primitive/Int64LESpec.hs
@@ -11,11 +11,19 @@
 spec :: Spec
 spec = describe "Int64LE" $ do
     it "can be decoded" $ do
-        decodeInt64LE "\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 8, Int64LE 0)
-        decodeInt64LE "\1\0\0\0\0\0\0\0" `shouldBe` Right ("", 8, Int64LE 1)
+        shouldBe
+            (decodeInt64LE "\0\0\0\0\0\0\0\0")
+            (Right ("", 8, Int64LE 0))
+        shouldBe
+            (decodeInt64LE "\1\0\0\0\0\0\0\0")
+            (Right ("", 8, Int64LE 1))
     it "can be encoded" $ do
-        Binary.encode (Int64LE 0) `shouldBe` "\0\0\0\0\0\0\0\0"
-        Binary.encode (Int64LE 1) `shouldBe` "\1\0\0\0\0\0\0\0"
+        shouldBe
+            (Binary.encode (Int64LE 0))
+            "\0\0\0\0\0\0\0\0"
+        shouldBe
+            (Binary.encode (Int64LE 1))
+            "\1\0\0\0\0\0\0\0"
 
 decodeInt64LE :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Int64LE)
 decodeInt64LE = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/ListSpec.hs b/test-suite/Octane/Type/Primitive/ListSpec.hs
--- a/test-suite/Octane/Type/Primitive/ListSpec.hs
+++ b/test-suite/Octane/Type/Primitive/ListSpec.hs
@@ -11,13 +11,25 @@
 spec :: Spec
 spec = describe "List" $ do
     it "can be decoded" $ do
-        decodeList "\0\0\0\0" `shouldBe` Right ("", 4, List [] :: List Boolean)
-        decodeList "\1\0\0\0\0\0\0\0" `shouldBe` Right ("", 8, List [Int32LE 0])
-        decodeList "\2\0\0\0\0\1" `shouldBe` Right ("", 6, List [Boolean False, Boolean True])
+        shouldBe
+            (decodeList "\0\0\0\0")
+            (Right ("", 4, List [] :: List Boolean))
+        shouldBe
+            (decodeList "\1\0\0\0\0\0\0\0")
+            (Right ("", 8, List [Int32LE 0]))
+        shouldBe
+            (decodeList "\2\0\0\0\0\1")
+            (Right ("", 6, List [Boolean False, Boolean True]))
     it "can be encoded" $ do
-        Binary.encode (List [] :: List Boolean) `shouldBe` "\0\0\0\0"
-        Binary.encode (List [Int32LE 0]) `shouldBe` "\1\0\0\0\0\0\0\0"
-        Binary.encode (List [Boolean False, Boolean True]) `shouldBe` "\2\0\0\0\0\1"
+        shouldBe
+            (Binary.encode (List [] :: List Boolean))
+            "\0\0\0\0"
+        shouldBe
+            (Binary.encode (List [Int32LE 0]))
+            "\1\0\0\0\0\0\0\0"
+        shouldBe
+            (Binary.encode (List [Boolean False, Boolean True]))
+            "\2\0\0\0\0\1"
 
 decodeList :: (Binary.Binary a) => BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, List a)
 decodeList = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/PCStringSpec.hs b/test-suite/Octane/Type/Primitive/PCStringSpec.hs
--- a/test-suite/Octane/Type/Primitive/PCStringSpec.hs
+++ b/test-suite/Octane/Type/Primitive/PCStringSpec.hs
@@ -11,15 +11,29 @@
 spec :: Spec
 spec = describe "PCString" $ do
     it "can be decoded" $ do
-        decodePCString "\1\0\0\0\0" `shouldBe` Right ("", 5, PCString "")
-        decodePCString "\6\0\0\0ascii\0" `shouldBe` Right ("", 10, PCString "ascii")
-        decodePCString "\8\0\0\0\251\241\239\231\248d\233\0" `shouldBe` Right ("", 12, PCString "ûñïçødé")
+        shouldBe
+            (decodePCString "\1\0\0\0\0")
+            (Right ("", 5, PCString ""))
+        shouldBe
+            (decodePCString "\6\0\0\0ascii\0")
+            (Right ("", 10, PCString "ascii"))
+        shouldBe
+            (decodePCString "\8\0\0\0\251\241\239\231\248d\233\0")
+            (Right ("", 12, PCString "ûñïçødé"))
     it "can be encoded" $ do
-        Binary.encode (PCString "") `shouldBe` "\1\0\0\0\0"
-        Binary.encode (PCString "ascii") `shouldBe` "\6\0\0\0ascii\0"
-        Binary.encode (PCString "ûñïçødé") `shouldBe` "\8\0\0\0\251\241\239\231\248d\233\0"
+        shouldBe
+            (Binary.encode (PCString ""))
+            "\1\0\0\0\0"
+        shouldBe
+            (Binary.encode (PCString "ascii"))
+            "\6\0\0\0ascii\0"
+        shouldBe
+            (Binary.encode (PCString "ûñïçødé"))
+            "\8\0\0\0\251\241\239\231\248d\233\0"
     it "does not decode strings of length 0" $ do
-        decodePCString "\0\0\0\0" `shouldBe` Left ("", 4, "invalid size")
+        shouldBe
+            (decodePCString "\0\0\0\0")
+            (Left ("", 4, "invalid PCString size 0"))
 
 decodePCString :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, PCString)
 decodePCString = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/Primitive/StreamSpec.hs b/test-suite/Octane/Type/Primitive/StreamSpec.hs
new file mode 100644
--- /dev/null
+++ b/test-suite/Octane/Type/Primitive/StreamSpec.hs
@@ -0,0 +1,23 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Octane.Type.Primitive.StreamSpec (spec) where
+
+import qualified Data.Binary as Binary
+import qualified Data.Binary.Get as Binary
+import qualified Data.ByteString.Lazy as BSL
+import Octane
+import Test.Tasty.Hspec
+
+spec :: Spec
+spec = describe "Stream" $ do
+    it "can be decoded" $ do
+        shouldBe
+            (decodeStream "\0\0\0\0")
+            (Right ("", 4, Stream ""))
+    it "can be encoded" $ do
+        shouldBe
+            (Binary.encode (Stream ""))
+            "\0\0\0\0"
+
+decodeStream :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Stream)
+decodeStream = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/PrimitiveSpec.hs b/test-suite/Octane/Type/PrimitiveSpec.hs
--- a/test-suite/Octane/Type/PrimitiveSpec.hs
+++ b/test-suite/Octane/Type/PrimitiveSpec.hs
@@ -1,20 +1,22 @@
 module Octane.Type.PrimitiveSpec (spec) where
 
 import qualified Octane.Type.Primitive.BooleanSpec
+import qualified Octane.Type.Primitive.DictionarySpec
 import qualified Octane.Type.Primitive.Float32LESpec
 import qualified Octane.Type.Primitive.Int32LESpec
 import qualified Octane.Type.Primitive.Int64LESpec
 import qualified Octane.Type.Primitive.ListSpec
 import qualified Octane.Type.Primitive.PCStringSpec
-import qualified Octane.Type.Primitive.DictionarySpec
+import qualified Octane.Type.Primitive.StreamSpec
 import Test.Tasty.Hspec
 
 spec :: Spec
 spec = describe "Primitive" $ do
     Octane.Type.Primitive.BooleanSpec.spec
+    Octane.Type.Primitive.DictionarySpec.spec
     Octane.Type.Primitive.Float32LESpec.spec
     Octane.Type.Primitive.Int32LESpec.spec
     Octane.Type.Primitive.Int64LESpec.spec
     Octane.Type.Primitive.ListSpec.spec
     Octane.Type.Primitive.PCStringSpec.spec
-    Octane.Type.Primitive.DictionarySpec.spec
+    Octane.Type.Primitive.StreamSpec.spec
diff --git a/test-suite/Octane/Type/PropertySpec.hs b/test-suite/Octane/Type/PropertySpec.hs
--- a/test-suite/Octane/Type/PropertySpec.hs
+++ b/test-suite/Octane/Type/PropertySpec.hs
@@ -11,59 +11,305 @@
 
 spec :: Spec
 spec = describe "Property" $ do
-    it "can decode arrays" $ do
-        decodeProperty "\14\0\0\0ArrayProperty\0\0\0\0\0\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 30, ArrayProperty (Int64LE 0) (List []))
-        decodeProperty "\14\0\0\0ArrayProperty\0\1\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\0\13\0\0\0BoolProperty\0\0\0\0\0\0\0\0\0\0\5\0\0\0None\0" `shouldBe` Right ("", 70, ArrayProperty (Int64LE 1) (List [Dictionary (Map.singleton (PCString "") (BoolProperty (Int64LE 0) (Boolean False)))]))
-    it "can decode booleans" $ do
-        decodeProperty "\13\0\0\0BoolProperty\0\0\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 26, BoolProperty (Int64LE 0) (Boolean False))
-        decodeProperty "\13\0\0\0BoolProperty\0\1\0\0\0\0\0\0\0\1" `shouldBe` Right ("", 26, BoolProperty (Int64LE 1) (Boolean True))
-    it "can decode bytes" $ do
-        decodeProperty "\13\0\0\0ByteProperty\0\0\0\0\0\0\0\0\0\1\0\0\0\0\1\0\0\0\0" `shouldBe` Right ("", 35, ByteProperty (Int64LE 0) (PCString "", PCString ""))
-        decodeProperty "\13\0\0\0ByteProperty\0\1\0\0\0\0\0\0\0\2\0\0\0a\0\2\0\0\0b\0" `shouldBe` Right ("", 37, ByteProperty (Int64LE 1) (PCString "a", PCString "b"))
-    it "can decode floats" $ do
-        decodeProperty "\14\0\0\0FloatProperty\0\4\0\0\0\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 30, FloatProperty (Int64LE 4) (Float32LE 0.0))
-        decodeProperty "\14\0\0\0FloatProperty\0\4\0\0\0\0\0\0\0\0\0\128\63" `shouldBe` Right ("", 30, FloatProperty (Int64LE 4) (Float32LE 1.0))
-    it "can decode integers" $ do
-        decodeProperty "\12\0\0\0IntProperty\0\4\0\0\0\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 28, IntProperty (Int64LE 4) (Int32LE 0))
-        decodeProperty "\12\0\0\0IntProperty\0\4\0\0\0\0\0\0\0\1\0\0\0" `shouldBe` Right ("", 28, IntProperty (Int64LE 4) (Int32LE 1))
-    it "can decode names" $ do
-        decodeProperty "\13\0\0\0NameProperty\0\0\0\0\0\0\0\0\0\1\0\0\0\0" `shouldBe` Right ("", 30, NameProperty (Int64LE 0) (PCString ""))
-        decodeProperty "\13\0\0\0NameProperty\0\1\0\0\0\0\0\0\0\2\0\0\0a\0" `shouldBe` Right ("", 31, NameProperty (Int64LE 1) (PCString "a"))
-    it "can decode qwords" $ do
-        decodeProperty "\14\0\0\0QWordProperty\0\8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" `shouldBe` Right ("", 34, QWordProperty (Int64LE 8) (Int64LE 0))
-        decodeProperty "\14\0\0\0QWordProperty\0\8\0\0\0\0\0\0\0\2\0\0\0\0\0\0\0" `shouldBe` Right ("", 34, QWordProperty (Int64LE 8) (Int64LE 2))
-    it "can decode strings" $ do
-        decodeProperty "\12\0\0\0StrProperty\0\0\0\0\0\0\0\0\0\1\0\0\0\0" `shouldBe` Right ("", 29, StrProperty (Int64LE 0) (PCString ""))
-        decodeProperty "\12\0\0\0StrProperty\0\1\0\0\0\0\0\0\0\2\0\0\0a\0" `shouldBe` Right ("", 30, StrProperty (Int64LE 1) (PCString "a"))
-    it "can encode arrays" $ do
-        Binary.encode (ArrayProperty (Int64LE 0) (List [])) `shouldBe` "\14\0\0\0ArrayProperty\0\0\0\0\0\0\0\0\0\0\0\0\0"
-        Binary.encode (ArrayProperty (Int64LE 1) (List [Dictionary (Map.singleton (PCString "a") (BoolProperty (Int64LE 2) (Boolean True)))])) `shouldBe` "\14\0\0\0ArrayProperty\0\1\0\0\0\0\0\0\0\1\0\0\0\2\0\0\0a\0\13\0\0\0BoolProperty\0\2\0\0\0\0\0\0\0\1\5\0\0\0None\0"
-    it "can encode booleans" $ do
-        Binary.encode (BoolProperty (Int64LE 0) (Boolean False)) `shouldBe` "\13\0\0\0BoolProperty\0\0\0\0\0\0\0\0\0\0"
-        Binary.encode (BoolProperty (Int64LE 1) (Boolean True)) `shouldBe` "\13\0\0\0BoolProperty\0\1\0\0\0\0\0\0\0\1"
-    it "can encode bytes" $ do
-        Binary.encode (ByteProperty (Int64LE 0) (PCString "", PCString "")) `shouldBe` "\13\0\0\0ByteProperty\0\0\0\0\0\0\0\0\0\1\0\0\0\0\1\0\0\0\0"
-        Binary.encode (ByteProperty (Int64LE 1) (PCString "a", PCString "b")) `shouldBe` "\13\0\0\0ByteProperty\0\1\0\0\0\0\0\0\0\2\0\0\0a\0\2\0\0\0b\0"
-    it "can encode floats" $ do
-        Binary.encode (FloatProperty (Int64LE 4) (Float32LE 0.0)) `shouldBe` "\14\0\0\0FloatProperty\0\4\0\0\0\0\0\0\0\0\0\0\0"
-        Binary.encode (FloatProperty (Int64LE 4) (Float32LE 1.0)) `shouldBe` "\14\0\0\0FloatProperty\0\4\0\0\0\0\0\0\0\0\0\128\63"
-    it "can encode integers" $ do
-        Binary.encode (IntProperty (Int64LE 4) (Int32LE 0)) `shouldBe` "\12\0\0\0IntProperty\0\4\0\0\0\0\0\0\0\0\0\0\0"
-        Binary.encode (IntProperty (Int64LE 4) (Int32LE 1)) `shouldBe` "\12\0\0\0IntProperty\0\4\0\0\0\0\0\0\0\1\0\0\0"
-    it "can encode names" $ do
-        Binary.encode (NameProperty (Int64LE 0) (PCString "")) `shouldBe` "\13\0\0\0NameProperty\0\0\0\0\0\0\0\0\0\1\0\0\0\0"
-        Binary.encode (NameProperty (Int64LE 1) (PCString "a")) `shouldBe` "\13\0\0\0NameProperty\0\1\0\0\0\0\0\0\0\2\0\0\0a\0"
-    it "can encode qwords" $ do
-        Binary.encode (QWordProperty (Int64LE 8) (Int64LE 0)) `shouldBe` "\14\0\0\0QWordProperty\0\8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
-        Binary.encode (QWordProperty (Int64LE 8) (Int64LE 2)) `shouldBe` "\14\0\0\0QWordProperty\0\8\0\0\0\0\0\0\0\2\0\0\0\0\0\0\0"
-    it "can encode strings" $ do
-        Binary.encode (StrProperty (Int64LE 0) (PCString "")) `shouldBe` "\12\0\0\0StrProperty\0\0\0\0\0\0\0\0\0\1\0\0\0\0"
-        Binary.encode (StrProperty (Int64LE 1) (PCString "a")) `shouldBe` "\12\0\0\0StrProperty\0\1\0\0\0\0\0\0\0\2\0\0\0a\0"
+    describe "Array" $ do
+        it "can be decoded" $ do
+            shouldBe
+                (decodeProperty "\
+                    \\14\0\0\0ArrayProperty\0\
+                    \\0\0\0\0\0\0\0\0\
+                    \\0\0\0\0")
+                (Right ("", 30, ArrayProperty
+                    (Int64LE 0)
+                    (List [])))
+            shouldBe
+                (decodeProperty "\
+                    \\14\0\0\0ArrayProperty\0\
+                    \\1\0\0\0\0\0\0\0\1\0\0\0\2\0\0\0a\0\13\0\0\0BoolProperty\0\2\0\0\0\0\0\0\0\1\5\0\0\0None\0")
+                (Right ("", 71, ArrayProperty
+                    (Int64LE 1)
+                    (List [Dictionary (Map.singleton (PCString "a") (BoolProperty (Int64LE 2) (Boolean True)))])))
+        it "can be encoded" $ do
+            shouldBe
+                (Binary.encode (ArrayProperty
+                    (Int64LE 0)
+                    (List [])))
+                "\
+                    \\14\0\0\0ArrayProperty\0\
+                    \\0\0\0\0\0\0\0\0\
+                    \\0\0\0\0"
+            shouldBe
+                (Binary.encode (ArrayProperty
+                    (Int64LE 1)
+                    (List [Dictionary (Map.singleton (PCString "a") (BoolProperty (Int64LE 2) (Boolean True)))])))
+                "\
+                    \\14\0\0\0ArrayProperty\0\
+                    \\1\0\0\0\0\0\0\0\1\0\0\0\2\0\0\0a\0\13\0\0\0BoolProperty\0\2\0\0\0\0\0\0\0\1\5\0\0\0None\0"
+    describe "Bool" $ do
+        it "can be decoded" $ do
+            shouldBe
+                (decodeProperty "\
+                    \\13\0\0\0BoolProperty\0\
+                    \\0\0\0\0\0\0\0\0\
+                    \\0")
+                (Right ("", 26, BoolProperty
+                    (Int64LE 0)
+                    (Boolean False)))
+            shouldBe
+                (decodeProperty "\
+                    \\13\0\0\0BoolProperty\0\
+                    \\1\0\0\0\0\0\0\0\
+                    \\1")
+                (Right ("", 26, BoolProperty
+                    (Int64LE 1)
+                    (Boolean True)))
+        it "can be encoded" $ do
+            shouldBe
+                (Binary.encode (BoolProperty
+                    (Int64LE 0)
+                    (Boolean False)))
+                "\
+                    \\13\0\0\0BoolProperty\0\
+                    \\0\0\0\0\0\0\0\0\
+                    \\0"
+            shouldBe
+                (Binary.encode (BoolProperty
+                    (Int64LE 1)
+                    (Boolean True)))
+                "\
+                    \\13\0\0\0BoolProperty\0\
+                    \\1\0\0\0\0\0\0\0\
+                    \\1"
+    describe "Byte" $ do
+        it "can be decoded" $ do
+            shouldBe
+                (decodeProperty "\
+                    \\13\0\0\0ByteProperty\0\
+                    \\0\0\0\0\0\0\0\0\
+                    \\1\0\0\0\0\1\0\0\0\0")
+                (Right ("", 35, ByteProperty
+                    (Int64LE 0)
+                    (PCString "", PCString "")))
+            shouldBe
+                (decodeProperty "\
+                    \\13\0\0\0ByteProperty\0\
+                    \\1\0\0\0\0\0\0\0\
+                    \\2\0\0\0a\0\2\0\0\0b\0")
+                (Right ("", 37, ByteProperty
+                    (Int64LE 1)
+                    (PCString "a", PCString "b")))
+        it "can be encoded" $ do
+            shouldBe
+                (Binary.encode (ByteProperty
+                    (Int64LE 0)
+                    (PCString "", PCString "")))
+                "\
+                    \\13\0\0\0ByteProperty\0\
+                    \\0\0\0\0\0\0\0\0\
+                    \\1\0\0\0\0\1\0\0\0\0"
+            shouldBe
+                (Binary.encode (ByteProperty
+                    (Int64LE 1)
+                    (PCString "a", PCString "b")))
+                "\
+                    \\13\0\0\0ByteProperty\0\
+                    \\1\0\0\0\0\0\0\0\
+                    \\2\0\0\0a\0\2\0\0\0b\0"
+    describe "Float" $ do
+        it "can be decoded" $ do
+            shouldBe
+                (decodeProperty "\
+                    \\14\0\0\0FloatProperty\0\
+                    \\4\0\0\0\0\0\0\0\
+                    \\0\0\0\0")
+                (Right ("", 30, FloatProperty
+                    (Int64LE 4)
+                    (Float32LE 0.0)))
+            shouldBe
+                (decodeProperty "\
+                    \\14\0\0\0FloatProperty\0\
+                    \\4\0\0\0\0\0\0\0\
+                    \\0\0\128\63")
+                (Right ("", 30, FloatProperty
+                    (Int64LE 4)
+                    (Float32LE 1.0)))
+        it "can be encoded" $ do
+            shouldBe
+                (Binary.encode (FloatProperty
+                    (Int64LE 4)
+                    (Float32LE 0.0)))
+                "\
+                    \\14\0\0\0FloatProperty\0\
+                    \\4\0\0\0\0\0\0\0\
+                    \\0\0\0\0"
+            shouldBe
+                (Binary.encode (FloatProperty
+                    (Int64LE 4)
+                    (Float32LE 1.0)))
+                "\
+                    \\14\0\0\0FloatProperty\0\
+                    \\4\0\0\0\0\0\0\0\
+                    \\0\0\128\63"
+        it "does not raise a runtime error when decoding garbage" $ do
+            shouldBe
+                (decodeProperty "\
+                    \\14\0\0\0FloatProperty\0\
+                    \\0\0\0\0\0\0\0\0")
+                (Left ("", 26, "unknown FloatProperty size 0"))
+    describe "Int" $ do
+        it "can be decoded" $ do
+            shouldBe
+                (decodeProperty "\
+                    \\12\0\0\0IntProperty\0\
+                    \\4\0\0\0\0\0\0\0\
+                    \\0\0\0\0")
+                (Right ("", 28, IntProperty
+                    (Int64LE 4)
+                    (Int32LE 0)))
+            shouldBe
+                (decodeProperty "\
+                    \\12\0\0\0IntProperty\0\
+                    \\4\0\0\0\0\0\0\0\
+                    \\1\0\0\0")
+                (Right ("", 28, IntProperty
+                    (Int64LE 4)
+                    (Int32LE 1)))
+        it "can be encoded" $ do
+            shouldBe
+                (Binary.encode (IntProperty
+                    (Int64LE 4)
+                    (Int32LE 0)))
+                "\
+                    \\12\0\0\0IntProperty\0\
+                    \\4\0\0\0\0\0\0\0\
+                    \\0\0\0\0"
+            shouldBe
+                (Binary.encode (IntProperty
+                    (Int64LE 4)
+                    (Int32LE 1)))
+                "\
+                    \\12\0\0\0IntProperty\0\
+                    \\4\0\0\0\0\0\0\0\
+                    \\1\0\0\0"
+        it "does not raise a runtime error when decoding garbage" $ do
+            shouldBe
+                (decodeProperty "\
+                    \\12\0\0\0IntProperty\0\
+                    \\0\0\0\0\0\0\0\0")
+                (Left ("", 24, "unknown IntProperty size 0"))
+    describe "Name" $ do
+        it "can be decoded" $ do
+            shouldBe
+                (decodeProperty "\
+                    \\13\0\0\0NameProperty\0\
+                    \\0\0\0\0\0\0\0\0\
+                    \\1\0\0\0\0")
+                (Right ("", 30, NameProperty
+                    (Int64LE 0)
+                    (PCString "")))
+            shouldBe
+                (decodeProperty "\
+                    \\13\0\0\0NameProperty\0\
+                    \\1\0\0\0\0\0\0\0\
+                    \\2\0\0\0a\0")
+                (Right ("", 31, NameProperty
+                    (Int64LE 1)
+                    (PCString "a")))
+        it "can be encoded" $ do
+            shouldBe
+                (Binary.encode (NameProperty
+                    (Int64LE 0)
+                    (PCString "")))
+                "\
+                    \\13\0\0\0NameProperty\0\
+                    \\0\0\0\0\0\0\0\0\
+                    \\1\0\0\0\0"
+            shouldBe
+                (Binary.encode (NameProperty
+                    (Int64LE 1)
+                    (PCString "a")))
+                "\
+                    \\13\0\0\0NameProperty\0\
+                    \\1\0\0\0\0\0\0\0\
+                    \\2\0\0\0a\0"
+    describe "QWord" $ do
+        it "can be decoded" $ do
+            shouldBe
+                (decodeProperty "\
+                    \\14\0\0\0QWordProperty\0\
+                    \\8\0\0\0\0\0\0\0\
+                    \\0\0\0\0\0\0\0\0")
+                (Right ("", 34, QWordProperty
+                    (Int64LE 8)
+                    (Int64LE 0)))
+            shouldBe
+                (decodeProperty "\
+                    \\14\0\0\0QWordProperty\0\
+                    \\8\0\0\0\0\0\0\0\
+                    \\2\0\0\0\0\0\0\0")
+                (Right ("", 34, QWordProperty
+                    (Int64LE 8)
+                    (Int64LE 2)))
+        it "can be encoded" $ do
+            shouldBe
+                (Binary.encode (QWordProperty
+                    (Int64LE 8)
+                    (Int64LE 0)))
+                "\
+                    \\14\0\0\0QWordProperty\0\
+                    \\8\0\0\0\0\0\0\0\
+                    \\0\0\0\0\0\0\0\0"
+            shouldBe
+                (Binary.encode (QWordProperty
+                    (Int64LE 8)
+                    (Int64LE 2)))
+                "\
+                    \\14\0\0\0QWordProperty\0\
+                    \\8\0\0\0\0\0\0\0\
+                    \\2\0\0\0\0\0\0\0"
+        it "does not raise a runtime error when decoding garbage" $ do
+            shouldBe
+                (decodeProperty "\14\0\0\0QWordProperty\0\0\0\0\0\0\0\0\0")
+                (Left ("", 26, "unknown QWordProperty size 0"))
+    describe "Str" $ do
+        it "can be decoded" $ do
+            shouldBe
+                (decodeProperty "\
+                    \\12\0\0\0StrProperty\0\
+                    \\0\0\0\0\0\0\0\0\
+                    \\1\0\0\0\0")
+                (Right ("", 29, StrProperty
+                    (Int64LE 0)
+                    (PCString "")))
+            shouldBe
+                (decodeProperty "\
+                    \\12\0\0\0StrProperty\0\
+                    \\1\0\0\0\0\0\0\0\
+                    \\2\0\0\0a\0")
+                (Right ("", 30, StrProperty
+                    (Int64LE 1)
+                    (PCString "a")))
+        it "can be encoded" $ do
+            shouldBe
+                (Binary.encode (StrProperty
+                    (Int64LE 0)
+                    (PCString "")))
+                "\
+                    \\12\0\0\0StrProperty\0\
+                    \\0\0\0\0\0\0\0\0\
+                    \\1\0\0\0\0"
+            shouldBe
+                (Binary.encode (StrProperty
+                    (Int64LE 1)
+                    (PCString "a")))
+                "\
+                    \\12\0\0\0StrProperty\0\
+                    \\1\0\0\0\0\0\0\0\
+                    \\2\0\0\0a\0"
     it "does not raise a runtime error when decoding garbage" $ do
-        decodeProperty "\14\0\0\0OtherProperty\0\0\0\0\0\0\0\0\0" `shouldBe` Left ("", 26, "unknown property type \"OtherProperty\"")
-        decodeProperty "\14\0\0\0FloatProperty\0\0\0\0\0\0\0\0\0" `shouldBe` Left ("", 26, "unknown FloatProperty size 0")
-        decodeProperty "\12\0\0\0IntProperty\0\0\0\0\0\0\0\0\0" `shouldBe` Left ("", 24, "unknown IntProperty size 0")
-        decodeProperty "\14\0\0\0QWordProperty\0\0\0\0\0\0\0\0\0" `shouldBe` Left ("", 26, "unknown QWordProperty size 0")
+        shouldBe
+            (decodeProperty "\
+                \\14\0\0\0OtherProperty\0")
+            (Left ("", 18, "unknown property type \"OtherProperty\""))
 
 decodeProperty :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Property)
 decodeProperty = Binary.decodeOrFail
diff --git a/test-suite/Octane/Type/ReplaySpec.hs b/test-suite/Octane/Type/ReplaySpec.hs
--- a/test-suite/Octane/Type/ReplaySpec.hs
+++ b/test-suite/Octane/Type/ReplaySpec.hs
@@ -31,8 +31,7 @@
                 \\0\0\0\0\
                 \\0\0\0\0\
                 \\0\0\0\0\
-                \\0\0\0\0\
-                \")
+                \\0\0\0\0")
             (Right ("", 78, Replay
                 (Int32LE 0)
                 (Int32LE 0)
@@ -44,7 +43,7 @@
                 (Int32LE 0)
                 (List [])
                 (List [])
-                ""
+                (Stream "")
                 (List [])
                 (List [])
                 (List [])
@@ -65,7 +64,7 @@
                 (Int32LE 0)
                 (List [])
                 (List [])
-                ""
+                (Stream "")
                 (List [])
                 (List [])
                 (List [])
@@ -91,8 +90,7 @@
                 \\0\0\0\0\
                 \\0\0\0\0\
                 \\0\0\0\0\
-                \\0\0\0\0\
-                \"
+                \\0\0\0\0"
 
 decodeReplay :: BSL.ByteString -> Either (BSL.ByteString, Binary.ByteOffset, String) (BSL.ByteString, Binary.ByteOffset, Replay)
 decodeReplay = Binary.decodeOrFail
diff --git a/test-suite/Octane/TypeSpec.hs b/test-suite/Octane/TypeSpec.hs
--- a/test-suite/Octane/TypeSpec.hs
+++ b/test-suite/Octane/TypeSpec.hs
@@ -3,6 +3,7 @@
 import qualified Octane.Type.ActorSpec
 import qualified Octane.Type.CacheItemSpec
 import qualified Octane.Type.CachePropertySpec
+import qualified Octane.Type.FrameSpec
 import qualified Octane.Type.KeyFrameSpec
 import qualified Octane.Type.MarkSpec
 import qualified Octane.Type.MessageSpec
@@ -16,6 +17,7 @@
     Octane.Type.ActorSpec.spec
     Octane.Type.CacheItemSpec.spec
     Octane.Type.CachePropertySpec.spec
+    Octane.Type.FrameSpec.spec
     Octane.Type.KeyFrameSpec.spec
     Octane.Type.MarkSpec.spec
     Octane.Type.MessageSpec.spec
