Skip to content

Commit fb4810d

Browse files
committed
feat: machinery for unit + golden file tests
Also wrote some initial unit and golden file tests.
1 parent 3708adc commit fb4810d

File tree

14 files changed

+201
-2
lines changed

14 files changed

+201
-2
lines changed

fp.cabal

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,15 @@ test-suite tasty
110110
ghc-options: -Wall
111111
build-depends:
112112
base
113+
, directory
114+
, filepath
113115
, fp
116+
, mtl
117+
, prettyprinter
118+
, safe-exceptions
119+
, tasty
120+
, tasty-hunit
121+
, tasty-silver
122+
, text
114123

115124
default-language: Haskell2010

hie.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ cradle:
22
cabal:
33
- path: "app"
44
component: "exe:fp"
5-
- path: "tests"
5+
- path: "tasty"
66
component: "test:tasty"
77
- path: "doctest"
88
component: "test:doctest"

package.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ tests:
6464
dependencies:
6565
- base
6666
- fp
67+
- directory
68+
- filepath
69+
- mtl
70+
- prettyprinter
71+
- safe-exceptions
72+
- tasty
73+
- tasty-hunit
74+
- tasty-silver
75+
- text
6776
doctest:
6877
main: Main.hs
6978
source-dirs: doctest

tasty/Main.hs

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,149 @@
1+
{-# LANGUAGE BlockArguments #-}
2+
{-# LANGUAGE LambdaCase #-}
3+
14
module Main where
25

6+
import Control.Exception.Safe (Exception)
7+
import Data.Text (Text)
8+
import Fp.Interpret (Input (..), InterpretError)
9+
import Fp.Pretty (Pretty (..))
10+
import System.FilePath ((</>))
11+
import Test.Tasty (TestTree)
12+
13+
import qualified Control.Exception.Safe as Exception
14+
import qualified Control.Monad.Except as Except
15+
import qualified Data.Text as Text
16+
import qualified Fp.Interpret as Interpret
17+
import qualified Fp.Normalize as Normalize
18+
import qualified Fp.Pretty
19+
import qualified Fp.Syntax as Syntax
20+
import qualified Fp.Value as Value
21+
import qualified Fp.Width as Width
22+
import qualified Prettyprinter as Pretty
23+
import qualified System.Directory as Directory
24+
import qualified System.FilePath as FilePath
25+
import qualified Test.Tasty as Tasty
26+
import qualified Test.Tasty.HUnit as Tasty.HUnit
27+
import qualified Test.Tasty.Silver as Silver
28+
29+
pretty_ :: Pretty a => a -> Text
30+
pretty_ x =
31+
Fp.Pretty.renderStrict
32+
False
33+
Width.defaultWidth
34+
(pretty x <> Pretty.hardline)
35+
36+
interpret :: Input -> IO (Either InterpretError [Value.Value])
37+
interpret = Except.runExceptT . fmap fst . Interpret.interpret
38+
39+
throws :: Exception e => IO (Either e a) -> IO a
40+
throws io =
41+
io >>= \case
42+
Left e -> Exception.throw e
43+
Right a -> pure a
44+
45+
fileToTestTree :: FilePath -> IO TestTree
46+
fileToTestTree prefix = do
47+
let input = prefix <> "-input.fp"
48+
let expectedOutputFile = prefix <> "-output.fp"
49+
let expectedStderrFile = prefix <> "-stderr.txt"
50+
51+
let name = FilePath.takeBaseName input
52+
53+
eitherResult <- interpret (Path input)
54+
55+
case eitherResult of
56+
Left e -> do
57+
return
58+
( Tasty.testGroup
59+
name
60+
[ Silver.goldenVsAction
61+
(name <> " - error")
62+
expectedStderrFile
63+
(return (Text.pack (Exception.displayException e)))
64+
id
65+
]
66+
)
67+
Right values -> do
68+
let generateOutputFile =
69+
pure @IO . Text.unlines . map (pretty_ . Normalize.quote [])
70+
71+
return
72+
( Tasty.testGroup
73+
name
74+
[ Silver.goldenVsAction
75+
(name <> " - output")
76+
expectedOutputFile
77+
(generateOutputFile values)
78+
id
79+
]
80+
)
81+
82+
inputFilePrefix :: FilePath -> Maybe FilePath
83+
inputFilePrefix = fmap Text.unpack . Text.stripSuffix "-input.fp" . Text.pack
84+
85+
directoryToTestTree :: FilePath -> IO TestTree
86+
directoryToTestTree directory = do
87+
let name = FilePath.takeBaseName directory
88+
children <- Directory.listDirectory directory
89+
90+
let process child = do
91+
let childPath = directory </> child
92+
isDirectory <- Directory.doesDirectoryExist childPath
93+
if isDirectory
94+
then do
95+
testTree <- directoryToTestTree childPath
96+
pure [testTree]
97+
else case inputFilePrefix childPath of
98+
Nothing -> pure []
99+
Just prefix -> do
100+
testTree <- fileToTestTree prefix
101+
pure [testTree]
102+
103+
testTrees <- traverse process children
104+
pure (Tasty.testGroup name (concat testTrees))
105+
3106
main :: IO ()
4-
main = print "hello from tasty tests!"
107+
main = do
108+
autoGenerated <- directoryToTestTree "tasty/data"
109+
let manualTestTree =
110+
Tasty.testGroup
111+
"Manual tests"
112+
[ innerProduct
113+
, matrixMul
114+
]
115+
let tests = Tasty.testGroup "Tests" [autoGenerated, manualTestTree]
116+
Tasty.defaultMain tests
117+
118+
innerProduct :: TestTree
119+
innerProduct = Tasty.HUnit.testCase "inner product" do
120+
actualValue <- throws (interpret (Code "" "/+∘α*∘⍉:<<1,2,3>,<6,5,4>>"))
121+
122+
let expectedValue =
123+
[Value.Atom (Syntax.Int 28)]
124+
125+
Tasty.HUnit.assertEqual "" expectedValue actualValue
126+
127+
matrixMul :: TestTree
128+
matrixMul = Tasty.HUnit.testCase "inner product" do
129+
let input =
130+
Text.unlines
131+
[ "Def ip ≡ /+∘α*∘⍉\n"
132+
, "Def mm ≡ α(α ip) ∘ α distl ∘ distr ∘ [~0, ⍉∘~1]\n"
133+
, "mm:< < <1,2>, <4,5> >, < <6,8>, <7,9>> >"
134+
]
135+
actualValue <- last <$> throws (interpret (Code "" input))
136+
137+
let expectedValue =
138+
Value.List
139+
[ Value.List
140+
[ Value.Atom (Syntax.Int 20)
141+
, Value.Atom (Syntax.Int 26)
142+
]
143+
, Value.List
144+
[ Value.Atom (Syntax.Int 59)
145+
, Value.Atom (Syntax.Int 77)
146+
]
147+
]
148+
149+
Tasty.HUnit.assertEqual "" expectedValue actualValue

tasty/data/primitives/and-input.fp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:<T,T>
2+
:<F,T>

tasty/data/primitives/and-output.fp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
T
2+
3+
F
4+

tasty/data/primitives/apndl-input.fp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
apndl:<6, ⌽>
2+
apndl:<6, <1,2,3>>

tasty/data/primitives/apndl-output.fp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
< 6 >
2+
3+
< 6, 1, 2, 3 >
4+

tasty/data/primitives/apndr-input.fp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
apndr:<⌽, 6>
2+
apndr:<<1,2,3>, 6>

tasty/data/primitives/apndr-output.fp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
< 6 >
2+
3+
< 1, 2, 3, 6 >
4+

0 commit comments

Comments
 (0)