content: module Test.Spec.DeltaCompression (spec) where
  
  import           Universum
  
  import           Data.Map as M
  import qualified Data.SafeCopy as SC
  import           Data.Serialize (runGet, runPut)
  
  import           Test.Hspec
  import           Test.QuickCheck (arbitrary, resize, withMaxSuccess)
  import           Test.QuickCheck.Monadic (monadicIO, pick)
  
  import qualified Pos.Chain.Txp as Core
  
  import           Cardano.Wallet.Kernel.DB.BlockMeta
  import           Cardano.Wallet.Kernel.DB.Compression
  import           Cardano.Wallet.Kernel.DB.Spec
  import           Cardano.Wallet.Kernel.DB.Spec.Pending
  import           UTxO.Util
  
  import           Util.Buildable (ShowThroughBuild (..))
  
  import           Arbitrary ()
  
  {-# ANN module ("HLint: ignore Reduce duplication" :: Text) #-}
  
  spec :: Spec
  spec = do
      let pick' a = do
              un <- pick $ STB <$> a
              return $ unSTB un
      describe "roundtrips for findDeltas -> applyDeltas" $ do
          it "Map round trips" $ withMaxSuccess 5 $  monadicIO $ do
              (mp :: Map Int Int) <- pick arbitrary
              mp' <- pick arbitrary
              let d = findDelta mp mp'
              let mp'' = applyDelta mp' d
              return $ mp `shouldBe` mp''
  
          it "Map round trips, (one Map is strictly bigger)" $ withMaxSuccess 5 $ monadicIO $ do
              (mp1 :: Map Int Int) <- pick arbitrary
              mp2 <- pick arbitrary
              let mp = mp1 <> mp2
              let mp' = mp1
              let d = findDelta mp mp'
              let mp'' = applyDelta mp' d
              return $ mp'' `shouldBe` mp
  
          it "Map round trips, (Maps have intersection and no one is strictly bigger)" $ withMaxSuccess 5 $ monadicIO $ do
              (mp1 :: Map Int Int) <- pick arbitrary
              mp2 <- pick arbitrary
              mp3 <- pick arbitrary
              let mp = mp1 <> mp2
              let mp' = mp2 <> mp3
              let d = findDelta mp mp'
              let mp'' = applyDelta mp' d
              return $ mp'' `shouldBe` mp
  
          it "Map round trips, (Maps have no intersection)" $ withMaxSuccess 5 $ monadicIO $ do
              (mp :: Map Int Int) <- pick arbitrary
              mp1 <- pick arbitrary
              let mp' = mp1 M.\\ mp
              let d = findDelta mp mp'
              let mp'' = applyDelta mp' d
              return $ mp'' `shouldBe` mp
  
          it "Pending round trips" $ withMaxSuccess 5 $ monadicIO $ do
              (p :: Pending)<- pick' $ resize 10 arbitrary
              p' <- pick' $ resize 10 arbitrary
              let d = findDelta p p'
              let p'' = applyDelta p' d
              return $ (STB p'') `shouldBe` (STB p)
  
          it "InDb Utxo round trips" $ withMaxSuccess 5 $ monadicIO $ do
              (u :: Core.Utxo) <- pick arbitrary
              u' <- pick arbitrary
              let d = findDelta u u'
              let u'' = applyDelta u' d
              return $ u'' `shouldBe` u
  
          it "BlockMeta round trips" $ withMaxSuccess 5 $ monadicIO $ do
              (bm :: BlockMeta) <- pick' arbitrary
              bm' <- pick' arbitrary
              let (d :: BlockMetaDiff) = findDelta bm bm'
              let bm'' = applyDelta bm' d
              return $ (STB bm'') `shouldBe` (STB bm)
  
          it "Checkpoint round trips" $ withMaxSuccess 5 $ monadicIO $ do
              (c :: Checkpoint) <- pick' $ resize 30 arbitrary
              c' <- pick' $ resize 30 arbitrary
              let d = findDelta c c'
              let c'' = applyDelta c' d
              return $ (STB c'') `shouldBe` (STB c)
  
          it "Checkpoints round trips" $ withMaxSuccess 5 $ monadicIO $ do
              (cs  :: Checkpoints Checkpoint) <- pick' $ resize 10 arbitrary
              -- ^ limit here is important, because
              --   this creates a whole wallet state.
              let d = findDeltas cs
              let cs'' = applyDeltas d
              return $ (STB cs'') `shouldBe` (STB cs)
  
          it "Safecopy Checkpoints round trips" $ withMaxSuccess 5 $ monadicIO $ do
              (cs :: Checkpoints Checkpoint) <- pick' $ resize 10 arbitrary
              let ret = runGet SC.safeGet (runPut (SC.safePut cs))
              return $ (STB <$> ret) `shouldBe` (Right (STB cs))
  
          it "PartialCheckpoint round trips" $ withMaxSuccess 5 $ monadicIO $ do
              (c :: PartialCheckpoint) <- pick' arbitrary
              c' <- pick' $ resize 30 arbitrary
              let d = findDelta c c'
              let c'' = applyDelta c' d
              return $ (STB c'') `shouldBe` (STB c)
  
          it "PartialCheckpoints round trips" $ withMaxSuccess 5 $ monadicIO $ do
              (cs  :: Checkpoints PartialCheckpoint) <- pick' $ resize 10 arbitrary
              -- ^ limit here is important, because
              --   this creates a whole wallet state.
              let d = findDeltas cs
              let cs'' = applyDeltas d
              return $ (STB cs'') `shouldBe` (STB cs)
  
          it "Safecopy PartialCheckpoints round trips" $ withMaxSuccess 5 $ monadicIO $ do
              (cs :: Checkpoints PartialCheckpoint) <- pick' $ resize 10 arbitrary
              let ret = runGet SC.safeGet (runPut (SC.safePut cs))
              return $ (STB <$> ret) `shouldBe` (Right (STB cs))
  