glsl-0.0.1.0: test/Language/GLSL/BitCodeSpec.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
module Language.GLSL.BitCodeSpec where
import Test.GLSL.Arbitrary ()
import Test.Hspec (Spec, describe, it, runIO,
shouldBe, shouldNotBe)
import Test.Hspec.QuickCheck (prop)
import Test.QuickCheck (forAllShrink, shrink)
import qualified Test.QuickCheck.Gen as Gen
import Control.Monad (forM_, unless, when)
import qualified Data.Text.Lazy.IO as IO
import qualified Data.Vector as V
import Language.GLSL.AST
import Language.GLSL.BitCode (encodeStmt)
import qualified Language.GLSL.ConstExpr as ConstExpr
import Language.GLSL.Parser (parseShader)
import Language.GLSL.StructuralEquality (eqStmt)
import qualified System.Directory as Dir
-- Run an exhaustive n^2 test comparing every line to every other line in the
-- test file. This takes around 13 seconds on my laptop.
exhaustive :: Bool
exhaustive = False
getStatements :: FilePath -> IO (V.Vector (Stmt ()))
getStatements path = do
inTopDir <- Dir.doesDirectoryExist "glsl"
when inTopDir $ Dir.setCurrentDirectory "glsl"
glsl <- parseShader <$> IO.readFile path
case glsl of
Left err ->
fail err
Right (GLSL _ (reverse -> (ProcDecl _ _ ss):_)) ->
return . V.fromList . map unAnnot $ ss
Right _ ->
fail "test file does not end with a main function"
encodeStmtSpec :: Maybe ConstExpr.ConstExprs -> Spec
encodeStmtSpec ce = do
prop "should produce the same encoding for structurally equal statements" $
\(s1 :: Stmt ()) (s2 :: Stmt ()) ->
let enc1 = encodeStmt ce s1
enc2 = encodeStmt ce s2
in
when (eqStmt ce s1 s2) $
enc1 `shouldBe` enc2
prop "should produce different encoding for structurally different statements" $
\(s1 :: Stmt ()) (s2 :: Stmt ()) ->
let enc1 = encodeStmt ce s1
enc2 = encodeStmt ce s2
in
unless (eqStmt ce s1 s2) $
enc1 `shouldNotBe` enc2
testFileSpec :: FilePath -> Spec
testFileSpec filename = do
stmts <- runIO $ getStatements $ "test/data/large-shaders/" <> filename
let forAllStmt p = forAllShrink (
(stmts V.!) <$> Gen.chooseBoundedIntegral (0, V.length stmts - 1))
shrink p
it ("should be able to encode all statements from " <> filename) $ do
forM_ stmts $ \s ->
encodeStmt Nothing s
`shouldBe`
encodeStmt Nothing s
prop ("should obey (a = b) => enc a = enc b for all pairs in " <> filename) $
forAllStmt $ \s1 -> forAllStmt $ \s2 ->
let enc1 = encodeStmt Nothing s1
enc2 = encodeStmt Nothing s2
in
if eqStmt Nothing s1 s2
then enc1 `shouldBe` enc2
else enc1 `shouldNotBe` enc2
when exhaustive $
it ("should obey (a = b) => enc a = enc b for every single pair in " <> filename) $
forM_ [0..V.length stmts - 1] $ \i -> forM_ [i..V.length stmts - 1] $ \j ->
let s1 = stmts V.! i
s2 = stmts V.! j
enc1 = encodeStmt Nothing s1
enc2 = encodeStmt Nothing s2
in
if eqStmt Nothing s1 s2
then enc1 `shouldBe` enc2
else enc1 `shouldNotBe` enc2
spec :: Spec
spec = do
describe "encodeStmt" $ do
encodeStmtSpec Nothing
describe "encodeStmt with ConstExpr" $ do
encodeStmtSpec $ Just ConstExpr.empty
-- testFileSpec "lambdacnc.frag"
-- testFileSpec "lambdacnc.vert"
testFileSpec "xax.frag"
-- testFileSpec "xax.vert"