File: GeneratorTestUtil.hs

package info (click to toggle)
haskell-yesod-static 1.6.1.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 204 kB
  • sloc: haskell: 1,381; makefile: 2
file content (65 lines) | stat: -rw-r--r-- 2,957 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
{-# LANGUAGE TemplateHaskell, QuasiQuotes, OverloadedStrings #-}
module GeneratorTestUtil where

import Control.Applicative
import Control.Monad (when)
import Data.List (sortBy)
import Language.Haskell.TH
import Test.HUnit
import Yesod.EmbeddedStatic.Types as Y
import qualified Data.ByteString.Lazy as BL
import RIO (HasCallStack)

-- We test the generators by executing them at compile time
-- and sticking the result into the GenTestResult.  We then
-- test the GenTestResult at runtime.  But to test the ebDevelReload
-- we must run the action at runtime so that is also embedded.
-- Because of template haskell stage restrictions, this code
-- needs to be in a separate module.

data GenTestResult = GenError String
                   | GenSuccessWithDevel (IO BL.ByteString)

-- | Creates a GenTestResult at compile time by testing the entry.
testEntry :: Maybe String -> Y.Location -> IO BL.ByteString -> Entry -> ExpQ
testEntry name _ _ e | ebHaskellName e /= (mkName Control.Applicative.<$> name) =
    [| GenError ("haskell name " ++ $(litE $ stringL $ show $ ebHaskellName e)
                                 ++ " /= "
                                 ++ $(litE $ stringL $ show name)) |]
testEntry _ loc _ e  | ebLocation e /= loc =
    [| GenError ("location " ++ $(litE $ stringL $ show $ ebLocation e)) |]
testEntry _ _ act e = do
    expected <- fmap stripCR $ runIO act
    actual <- fmap stripCR $ runIO $ ebProductionContent e
    if expected == actual
        then [| GenSuccessWithDevel $(ebDevelReload e) |]
        else [| GenError $ "production content: " ++ $(litE $ stringL $ show (expected, actual)) |]

-- | Remove all carriage returns, for Windows testing
stripCR :: BL.ByteString -> BL.ByteString
stripCR = BL.filter (/= 13)

testOneEntry :: Maybe String -> Y.Location -> IO BL.ByteString -> [Entry] -> ExpQ
testOneEntry name loc ct [e] = testEntry name loc ct e
testOneEntry _ _ _ _ = [| GenError "not exactly one entry" |]

-- | Tests a list of entries
testEntries :: [(Maybe String, Y.Location, IO BL.ByteString)] -> [Entry] -> ExpQ
testEntries a b | length a /= length b = [| [GenError "lengths differ"] |]
testEntries a b = listE $ zipWith f a' b'
    where
        a' = sortBy (\(_,l1,_) (_,l2,_) -> compare l1 l2) a
        b' = sortBy (\e1 e2 -> ebLocation e1 `compare` ebLocation e2) b
        f (name, loc, ct) e = testEntry name loc ct e

-- | Use this at runtime to assert the 'GenTestResult' is OK
assertGenResult :: HasCallStack
                => (IO BL.ByteString) -- ^ expected development content
                -> GenTestResult -- ^ test result created at compile time
                -> Assertion
assertGenResult _ (GenError e) = assertFailure ("invalid " ++ e)
assertGenResult mexpected (GenSuccessWithDevel mactual) = do
    expected <- fmap stripCR mexpected
    actual <- fmap stripCR mactual
    when (expected /= actual) $
        assertFailure $ "invalid devel content: " ++ show (expected, actual)