module Expect
(
Expectation,
equal,
notEqual,
all,
concat,
lessThan,
atMost,
greaterThan,
atLeast,
true,
false,
ok,
err,
pass,
fail,
onFail,
equalToContentsOf,
withIO,
)
where
import qualified Data.Text
import qualified Data.Text.IO
import qualified Debug
import qualified List
import List (List)
import NriPrelude
import qualified Platform.Internal
import qualified Pretty.Diff as Diff
import qualified System.Console.Terminal.Size as Terminal
import qualified System.Directory as Directory
import qualified System.FilePath as FilePath
import qualified Task
import qualified Test.Internal as Internal
import Test.Internal (Expectation)
import qualified Text.Show.Pretty
import Prelude (Eq, IO, Ord, Show, show)
withIO :: (a -> Expectation) -> IO a -> Expectation
withIO :: (a -> Expectation) -> IO a -> Expectation
withIO a -> Expectation
fn IO a
io =
IO a -> Task Never a
forall a e. IO a -> Task e a
fromIO IO a
io
Task Never a
-> (Task Never a -> Task Never TestResult) -> Task Never TestResult
forall a b. a -> (a -> b) -> b
|> (a -> Task Never TestResult)
-> Task Never a -> Task Never TestResult
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
andThen (Expectation -> Task Never TestResult
Internal.unExpectation (Expectation -> Task Never TestResult)
-> (a -> Expectation) -> a -> Task Never TestResult
forall b c a. (b -> c) -> (a -> b) -> a -> c
<< a -> Expectation
fn)
Task Never TestResult
-> (Task Never TestResult -> Expectation) -> Expectation
forall a b. a -> (a -> b) -> b
|> Task Never TestResult -> Expectation
Internal.Expectation
pass :: Expectation
pass :: Expectation
pass = Task Never TestResult -> Expectation
Internal.Expectation (TestResult -> Task Never TestResult
forall a x. a -> Task x a
Task.succeed TestResult
Internal.Succeeded)
fail :: Text -> Expectation
fail :: Text -> Expectation
fail Text
msg =
Text
msg
Text -> (Text -> Failure) -> Failure
forall a b. a -> (a -> b) -> b
|> Text -> Failure
Internal.FailedAssertion
Failure -> (Failure -> TestResult) -> TestResult
forall a b. a -> (a -> b) -> b
|> Failure -> TestResult
Internal.Failed
TestResult
-> (TestResult -> Task Never TestResult) -> Task Never TestResult
forall a b. a -> (a -> b) -> b
|> TestResult -> Task Never TestResult
forall a x. a -> Task x a
Task.succeed
Task Never TestResult
-> (Task Never TestResult -> Expectation) -> Expectation
forall a b. a -> (a -> b) -> b
|> Task Never TestResult -> Expectation
Internal.Expectation
onFail :: Text -> Expectation -> Expectation
onFail :: Text -> Expectation -> Expectation
onFail Text
msg (Internal.Expectation Task Never TestResult
task) =
Task Never TestResult
task
Task Never TestResult
-> (Task Never TestResult -> Task Never TestResult)
-> Task Never TestResult
forall a b. a -> (a -> b) -> b
|> (TestResult -> TestResult)
-> Task Never TestResult -> Task Never TestResult
forall a b x. (a -> b) -> Task x a -> Task x b
Task.map
( \TestResult
res ->
case TestResult
res of
TestResult
Internal.Succeeded -> TestResult
Internal.Succeeded
Internal.Failed Failure
_ -> Failure -> TestResult
Internal.Failed (Text -> Failure
Internal.FailedAssertion Text
msg)
)
Task Never TestResult
-> (Task Never TestResult -> Expectation) -> Expectation
forall a b. a -> (a -> b) -> b
|> Task Never TestResult -> Expectation
Internal.Expectation
equal :: (Show a, Eq a) => a -> a -> Expectation
equal :: a -> a -> Expectation
equal = (a -> a -> Bool) -> Text -> a -> a -> Expectation
forall a.
Show a =>
(a -> a -> Bool) -> Text -> a -> a -> Expectation
assert a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(==) Text
"Expect.equal"
notEqual :: (Show a, Eq a) => a -> a -> Expectation
notEqual :: a -> a -> Expectation
notEqual = (a -> a -> Bool) -> Text -> a -> a -> Expectation
forall a.
Show a =>
(a -> a -> Bool) -> Text -> a -> a -> Expectation
assert a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(/=) Text
"Expect.notEqual"
lessThan :: (Show a, Ord a) => a -> a -> Expectation
lessThan :: a -> a -> Expectation
lessThan = (a -> a -> Bool) -> Text -> a -> a -> Expectation
forall a.
Show a =>
(a -> a -> Bool) -> Text -> a -> a -> Expectation
assert a -> a -> Bool
forall comparable.
Ord comparable =>
comparable -> comparable -> Bool
(>) Text
"Expect.lessThan"
atMost :: (Show a, Ord a) => a -> a -> Expectation
atMost :: a -> a -> Expectation
atMost = (a -> a -> Bool) -> Text -> a -> a -> Expectation
forall a.
Show a =>
(a -> a -> Bool) -> Text -> a -> a -> Expectation
assert a -> a -> Bool
forall comparable.
Ord comparable =>
comparable -> comparable -> Bool
(>=) Text
"Expect.atMost"
greaterThan :: (Show a, Ord a) => a -> a -> Expectation
greaterThan :: a -> a -> Expectation
greaterThan = (a -> a -> Bool) -> Text -> a -> a -> Expectation
forall a.
Show a =>
(a -> a -> Bool) -> Text -> a -> a -> Expectation
assert a -> a -> Bool
forall comparable.
Ord comparable =>
comparable -> comparable -> Bool
(<) Text
"Expect.greaterThan"
atLeast :: (Show a, Ord a) => a -> a -> Expectation
atLeast :: a -> a -> Expectation
atLeast = (a -> a -> Bool) -> Text -> a -> a -> Expectation
forall a.
Show a =>
(a -> a -> Bool) -> Text -> a -> a -> Expectation
assert a -> a -> Bool
forall comparable.
Ord comparable =>
comparable -> comparable -> Bool
(<=) Text
"Expect.atLeast"
true :: Bool -> Expectation
true :: Bool -> Expectation
true Bool
x = (Bool -> Bool -> Bool) -> Text -> Bool -> Bool -> Expectation
forall a.
Show a =>
(a -> a -> Bool) -> Text -> a -> a -> Expectation
assert Bool -> Bool -> Bool
(&&) Text
"Expect.true" Bool
x Bool
True
false :: Bool -> Expectation
false :: Bool -> Expectation
false Bool
x = (Bool -> Bool -> Bool) -> Text -> Bool -> Bool -> Expectation
forall a.
Show a =>
(a -> a -> Bool) -> Text -> a -> a -> Expectation
assert Bool -> Bool -> Bool
xor Text
"Expect.false" Bool
x Bool
True
all :: List (subject -> Expectation) -> subject -> Expectation
all :: List (subject -> Expectation) -> subject -> Expectation
all List (subject -> Expectation)
expectations subject
subject =
((subject -> Expectation) -> Expectation -> Expectation)
-> Expectation -> List (subject -> Expectation) -> Expectation
forall a b. (a -> b -> b) -> b -> List a -> b
List.foldl
( \subject -> Expectation
expectation Expectation
acc ->
Expectation -> Expectation -> Expectation
Internal.append
Expectation
acc
(subject -> Expectation
expectation subject
subject)
)
Expectation
pass
List (subject -> Expectation)
expectations
concat :: List Expectation -> Expectation
concat :: List Expectation -> Expectation
concat List Expectation
expectations =
(Expectation -> Expectation -> Expectation)
-> Expectation -> List Expectation -> Expectation
forall a b. (a -> b -> b) -> b -> List a -> b
List.foldl
( \Expectation
expectation Expectation
acc ->
Expectation -> Expectation -> Expectation
Internal.append
Expectation
acc
Expectation
expectation
)
Expectation
pass
List Expectation
expectations
ok :: Show b => Result b a -> Expectation
ok :: Result b a -> Expectation
ok Result b a
res =
case Result b a
res of
Ok a
_ -> Expectation
pass
Err b
message -> Text -> Expectation
fail (Text
"I expected a Ok but got Err (" Text -> Text -> Text
forall appendable.
Semigroup appendable =>
appendable -> appendable -> appendable
++ b -> Text
forall a. Show a => a -> Text
Debug.toString b
message Text -> Text -> Text
forall appendable.
Semigroup appendable =>
appendable -> appendable -> appendable
++ Text
")")
err :: Show a => Result b a -> Expectation
err :: Result b a -> Expectation
err Result b a
res =
case Result b a
res of
Ok a
value -> Text -> Expectation
fail (Text
"I expected a Err but got Ok (" Text -> Text -> Text
forall appendable.
Semigroup appendable =>
appendable -> appendable -> appendable
++ a -> Text
forall a. Show a => a -> Text
Debug.toString a
value Text -> Text -> Text
forall appendable.
Semigroup appendable =>
appendable -> appendable -> appendable
++ Text
")")
Err b
_ -> Expectation
pass
equalToContentsOf :: Text -> Text -> Expectation
equalToContentsOf :: Text -> Text -> Expectation
equalToContentsOf Text
filepath' Text
actual =
Task Never TestResult -> Expectation
Internal.Expectation (Task Never TestResult -> Expectation)
-> Task Never TestResult -> Expectation
forall a b. (a -> b) -> a -> b
<| do
let filepath :: String
filepath = Text -> String
Data.Text.unpack Text
filepath'
Bool
exists <- IO Bool -> Task Never Bool
forall a e. IO a -> Task e a
fromIO (IO Bool -> Task Never Bool) -> IO Bool -> Task Never Bool
forall a b. (a -> b) -> a -> b
<| do
Bool -> String -> IO ()
Directory.createDirectoryIfMissing Bool
True (String -> String
FilePath.takeDirectory String
filepath)
String -> IO Bool
Directory.doesFileExist String
filepath
if Bool
exists
then do
Text
expected <- IO Text -> Task Never Text
forall a e. IO a -> Task e a
fromIO (String -> IO Text
Data.Text.IO.readFile String
filepath)
(UnescapedShow -> UnescapedShow -> Bool)
-> Text -> UnescapedShow -> UnescapedShow -> Expectation
forall a.
Show a =>
(a -> a -> Bool) -> Text -> a -> a -> Expectation
assert
UnescapedShow -> UnescapedShow -> Bool
forall a. Eq a => a -> a -> Bool
(==)
Text
"Expect.equalToContentsOf"
(Text -> UnescapedShow
UnescapedShow Text
expected)
(Text -> UnescapedShow
UnescapedShow Text
actual)
Expectation
-> (Expectation -> Task Never TestResult) -> Task Never TestResult
forall a b. a -> (a -> b) -> b
|> Expectation -> Task Never TestResult
Internal.unExpectation
else do
IO () -> Task Never ()
forall a e. IO a -> Task e a
fromIO (String -> Text -> IO ()
Data.Text.IO.writeFile String
filepath Text
actual)
Expectation -> Task Never TestResult
Internal.unExpectation Expectation
pass
newtype UnescapedShow = UnescapedShow Text deriving (UnescapedShow -> UnescapedShow -> Bool
(UnescapedShow -> UnescapedShow -> Bool)
-> (UnescapedShow -> UnescapedShow -> Bool) -> Eq UnescapedShow
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UnescapedShow -> UnescapedShow -> Bool
$c/= :: UnescapedShow -> UnescapedShow -> Bool
== :: UnescapedShow -> UnescapedShow -> Bool
$c== :: UnescapedShow -> UnescapedShow -> Bool
Eq)
instance Show UnescapedShow where
show :: UnescapedShow -> String
show (UnescapedShow Text
text) = Text -> String
Data.Text.unpack Text
text
assert :: Show a => (a -> a -> Bool) -> Text -> a -> a -> Expectation
assert :: (a -> a -> Bool) -> Text -> a -> a -> Expectation
assert a -> a -> Bool
pred Text
funcName a
actual a
expected =
if a -> a -> Bool
pred a
actual a
expected
then Expectation
pass
else Task Never TestResult -> Expectation
Internal.Expectation (Task Never TestResult -> Expectation)
-> Task Never TestResult -> Expectation
forall a b. (a -> b) -> a -> b
<| do
Maybe (Window Int)
window <- IO (Maybe (Window Int)) -> Task Never (Maybe (Window Int))
forall a e. IO a -> Task e a
fromIO IO (Maybe (Window Int))
forall n. Integral n => IO (Maybe (Window n))
Terminal.size
let terminalWidth :: Int
terminalWidth = case Maybe (Window Int)
window of
Just Terminal.Window {Int
width :: forall a. Window a -> a
width :: Int
Terminal.width} -> Int
width Int -> Int -> Int
forall number. Num number => number -> number -> number
- Int
4
Maybe (Window Int)
Nothing -> Int
80
Config -> PrettyShow a -> PrettyShow a -> Text
forall a. Show a => Config -> a -> a -> Text
Diff.pretty
Config :: Maybe Text -> Wrapping -> Config
Diff.Config
{ separatorText :: Maybe Text
Diff.separatorText = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
funcName,
wrapping :: Wrapping
Diff.wrapping = Int -> Wrapping
Diff.Wrap Int
terminalWidth
}
(a -> PrettyShow a
forall a. a -> PrettyShow a
PrettyShow a
expected)
(a -> PrettyShow a
forall a. a -> PrettyShow a
PrettyShow a
actual)
Text -> (Text -> Expectation) -> Expectation
forall a b. a -> (a -> b) -> b
|> Text -> Expectation
fail
Expectation
-> (Expectation -> Task Never TestResult) -> Task Never TestResult
forall a b. a -> (a -> b) -> b
|> Expectation -> Task Never TestResult
Internal.unExpectation
fromIO :: Prelude.IO a -> Task e a
fromIO :: IO a -> Task e a
fromIO IO a
io = (LogHandler -> IO (Result e a)) -> Task e a
forall x a. (LogHandler -> IO (Result x a)) -> Task x a
Platform.Internal.Task (\LogHandler
_ -> (a -> Result e a) -> IO a -> IO (Result e a)
forall (m :: * -> *) a value.
Functor m =>
(a -> value) -> m a -> m value
map a -> Result e a
forall error value. value -> Result error value
Ok IO a
io)
newtype PrettyShow a = PrettyShow a
instance Show a => Show (PrettyShow a) where
show :: PrettyShow a -> String
show (PrettyShow a
x) = a -> String
forall a. Show a => a -> String
Text.Show.Pretty.ppShow a
x