packages feed

hgeometry-0.8.0.0: test/Util.hs

module Util where

import           Control.Exception.Base (bracket)
import           Control.Monad (when)
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as LB
import           Data.Ext
import           Data.Function (on)
import           Data.Geometry.Ipe
import qualified Data.List as L
import           Data.Proxy
import           Data.Singletons (Apply)
import           Data.Vinyl
import           System.Directory (removeFile, getTemporaryDirectory)
import           System.FilePath (takeExtension)
import           System.IO (hClose,openTempFile, Handle)
import           Test.Hspec

--------------------------------------------------------------------------------

byStrokeColour :: (Stroke ∈ ats, Ord (Apply f Stroke))
               => [a :+ Attributes f ats] -> [[a :+ Attributes f ats]]
byStrokeColour = map (map fst) . L.groupBy ((==) `on` snd) . L.sortOn snd
               . map (\x -> (x,lookup' x))
  where
    lookup' (_ :+ ats) = lookupAttr (Proxy :: Proxy Stroke) ats

-- | Computes all elements on which the two lists differ
difference :: Eq a => [a] -> [a] -> [a]
difference xs ys = (xs L.\\ ys) ++ (ys L.\\ xs)

-- differenceBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]


diffBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]
diffBy p xs ys = foldr (L.deleteBy p) ys xs

-- | \(O(n^2)\) set that ignores duplicates and order
newtype NaiveSet a = NaiveSet [a] deriving (Show)

instance Eq a => Eq (NaiveSet a) where
  (NaiveSet xs) == (NaiveSet ys) = L.null $ difference xs ys


-- | Given a file with some file contents and a procedure that produces a
-- bytestring. Verify that the bytestring that we produce is the same as the
-- one stored in the file. If not, the output is stored in a temporary file so
-- that we can later look at the details.
runOnFile             :: String    -- ^ the description
                      -> FilePath  -- ^ the expected output file
                      -> IO B.ByteString -- ^ the algorithm to run.
                      -> Spec
runOnFile s expFP alg = runOnFile' s expFP (\h -> alg >>= B.hPut h)


data Res = Res Bool FilePath FilePath
         | True' deriving (Show)

instance Eq Res where
  Res b _ _ == _ = b
  True'     == _ = True

-- | Given a file with some file contents and a procedure that produces a
-- bytestring. Verify that the bytestring that we produce is the same as the
-- one stored in the file. If not, the output is stored in a temporary file so
-- that we can later look at the details.
runOnFile'                 :: String    -- ^ the description
                           -> FilePath  -- ^ the expected output file
                           -> (Handle -> IO ()) -- ^ the algorithm to run.
                           -> Spec
runOnFile' descr expFP alg = it descr $ do
                               runAlgo `shouldReturn` True'
  where
    runAlgo = do
                dir <- getTemporaryDirectory
                outFP <- bracket (openTempFile dir outFPName)
                                 (hClose . snd)
                                 (\(fp,h) -> do
                                     alg h
                                     pure fp)
                res <- sameFile expFP outFP
                when res $ removeFile outFP
                pure $ Res res expFP outFP
    outFPName = "hgeometry_runOnFile_algo" <> takeExtension expFP


-- | Test if two files are the same. Warning: uses lazy IO.
sameFile       :: FilePath -> FilePath -> IO Bool
sameFile fa fb = do a <- LB.readFile fa
                    b <- LB.readFile fb
                    pure $ a == b