{-# LANGUAGE BangPatterns #-}
# LANGUAGE NamedFieldPuns #
{-# LANGUAGE OverloadedStrings #-}

module Main (main) where

import           Control.Monad (when, void)
import           Control.Monad.IO.Class (liftIO)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Conduit as C
import           Data.Conduit.Combinators (sinkNull)
import           Data.Foldable (for_)
import qualified Data.Text as T
import           Data.Time.LocalTime (utc, utcToLocalTime)
import           Data.Time.Clock.POSIX (posixSecondsToUTCTime)
import           GHC.Stats (getRTSStats, RTSStats(..), GCDetails(..))
import           System.Mem (performMajorGC)
import           Test.Hspec (hspec, describe, it)

import           Codec.Archive.Zip.Conduit.Zip


main :: IO ()
main = hspec $ do
  describe "zipping" $ do
    it "ZipDataByteString streams in constant memory" $ do
      C.runConduitRes $
        (do
  Stream 1000 * 4 MiB = 4 
          for_ [(1::Int)..1024] $ \i -> do
  ` bs ` needs to depend on loop variable ` i ` , otherwise GHC may hoist
            -- it out of the loop ("floating"), making the memory constant
            -- even for incorrect implementations, thus making the test useless.
  4 MiB

            C.yield
              ( ZipEntry
                  { zipEntryName = Left ("file-" <> T.pack (show i) <> ".bin")
                  , zipEntryTime = utcToLocalTime utc (posixSecondsToUTCTime 0)
                  , zipEntrySize = Nothing
                  , zipEntryExternalAttributes = Nothing
                  }
              , ZipDataByteString (BSL.fromStrict bs) -- `copy` to avoid sharing
              )

            liftIO $ do
  GC every 40 MB to make it easy to observe constant memory .
              when (i `mod` 10 == 0) performMajorGC

              RTSStats{ gc = GCDetails{ gcdetails_live_bytes } } <- getRTSStats
  3 
                error $ "Memory usage too high (" ++ show gcdetails_live_bytes ++ " B), probably streaming is not constant-memory"

        )
        C..| void (zipStream defaultZipOptions{ zipOptCompressLevel = 0 })
        C..| sinkNull
        :: IO ()


# LANGUAGE BangPatterns #
# LANGUAGE OverloadedStrings #
 it out of the loop ("floating"), making the memory constant
 even for incorrect implementations, thus making the test useless.
 `copy` to avoid sharing
# LANGUAGE NamedFieldPuns #

module Main (main) where

import           Control.Monad (when, void)
import           Control.Monad.IO.Class (liftIO)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Conduit as C
import           Data.Conduit.Combinators (sinkNull)
import           Data.Foldable (for_)
import qualified Data.Text as T
import           Data.Time.LocalTime (utc, utcToLocalTime)
import           Data.Time.Clock.POSIX (posixSecondsToUTCTime)
import           GHC.Stats (getRTSStats, RTSStats(..), GCDetails(..))
import           System.Mem (performMajorGC)
import           Test.Hspec (hspec, describe, it)

import           Codec.Archive.Zip.Conduit.Zip


main :: IO ()
main = hspec $ do
  describe "zipping" $ do
    it "ZipDataByteString streams in constant memory" $ do
      C.runConduitRes $
        (do
  Stream 1000 * 4 MiB = 4 
          for_ [(1::Int)..1024] $ \i -> do
  ` bs ` needs to depend on loop variable ` i ` , otherwise GHC may hoist
  4 MiB

            C.yield
              ( ZipEntry
                  { zipEntryName = Left ("file-" <> T.pack (show i) <> ".bin")
                  , zipEntryTime = utcToLocalTime utc (posixSecondsToUTCTime 0)
                  , zipEntrySize = Nothing
                  , zipEntryExternalAttributes = Nothing
                  }
              )

            liftIO $ do
  GC every 40 MB to make it easy to observe constant memory .
              when (i `mod` 10 == 0) performMajorGC

              RTSStats{ gc = GCDetails{ gcdetails_live_bytes } } <- getRTSStats
  3 
                error $ "Memory usage too high (" ++ show gcdetails_live_bytes ++ " B), probably streaming is not constant-memory"

        )
        C..| void (zipStream defaultZipOptions{ zipOptCompressLevel = 0 })
        C..| sinkNull
        :: IO ()

