{- -----------------------------------------------------------------------------
Copyright 2020 Kevin P. Barry

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
----------------------------------------------------------------------------- -}

-- Author: Kevin P. Barry [ta0kira@gmail.com]

{-# LANGUAGE Safe #-}

module Test.IntegrationTest (tests) where

import Control.Monad (when)
import System.FilePath
import Text.Parsec

import Base.CompileError
import Base.CompileInfo
import Parser.Common
import Parser.IntegrationTest ()
import Test.Common
import Types.DefinedCategory
import Types.IntegrationTest
import Types.Positional
import Types.Procedure
import Types.TypeCategory
import Types.TypeInstance


tests :: [IO (CompileInfo ())]
tests :: [IO (CompileInfo ())]
tests = [
    String
-> (IntegrationTest SourcePos -> IO (CompileInfo ()))
-> IO (CompileInfo ())
checkFileContents
      (String
"testfiles" String -> String -> String
</> String
"basic_error_test.0rt")
      (\IntegrationTest SourcePos
t -> CompileInfo () -> IO (CompileInfo ())
forall (m :: * -> *) a. Monad m => a -> m a
return (CompileInfo () -> IO (CompileInfo ()))
-> CompileInfo () -> IO (CompileInfo ())
forall a b. (a -> b) -> a -> b
$ do
        let h :: IntegrationTestHeader SourcePos
h = IntegrationTest SourcePos -> IntegrationTestHeader SourcePos
forall c. IntegrationTest c -> IntegrationTestHeader c
itHeader IntegrationTest SourcePos
t
        Bool -> CompileInfo () -> CompileInfo ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ExpectedResult SourcePos -> Bool
forall c. ExpectedResult c -> Bool
isExpectCompileError (ExpectedResult SourcePos -> Bool)
-> ExpectedResult SourcePos -> Bool
forall a b. (a -> b) -> a -> b
$ IntegrationTestHeader SourcePos -> ExpectedResult SourcePos
forall c. IntegrationTestHeader c -> ExpectedResult c
ithResult IntegrationTestHeader SourcePos
h) (CompileInfo () -> CompileInfo ())
-> CompileInfo () -> CompileInfo ()
forall a b. (a -> b) -> a -> b
$ String -> CompileInfo ()
forall (m :: * -> *) a. CompileErrorM m => String -> m a
compileErrorM String
"Expected ExpectCompileError"
        String -> String -> CompileInfo ()
forall a. (Eq a, Show a) => a -> a -> CompileInfo ()
checkEquals (IntegrationTestHeader SourcePos -> String
forall c. IntegrationTestHeader c -> String
ithTestName IntegrationTestHeader SourcePos
h) String
"basic error test"
        [OutputPattern] -> [OutputPattern] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (ExpectedResult SourcePos -> [OutputPattern]
forall c. ExpectedResult c -> [OutputPattern]
getRequirePattern (ExpectedResult SourcePos -> [OutputPattern])
-> ExpectedResult SourcePos -> [OutputPattern]
forall a b. (a -> b) -> a -> b
$ IntegrationTestHeader SourcePos -> ExpectedResult SourcePos
forall c. IntegrationTestHeader c -> ExpectedResult c
ithResult IntegrationTestHeader SourcePos
h) [
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputCompiler String
"pattern in output 1",
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputAny      String
"pattern in output 2"
          ]
        [OutputPattern] -> [OutputPattern] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (ExpectedResult SourcePos -> [OutputPattern]
forall c. ExpectedResult c -> [OutputPattern]
getExcludePattern (ExpectedResult SourcePos -> [OutputPattern])
-> ExpectedResult SourcePos -> [OutputPattern]
forall a b. (a -> b) -> a -> b
$ IntegrationTestHeader SourcePos -> ExpectedResult SourcePos
forall c. IntegrationTestHeader c -> ExpectedResult c
ithResult IntegrationTestHeader SourcePos
h) [
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputStderr String
"pattern not in output 1",
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputStdout String
"pattern not in output 2"
          ]
        [String] -> [String] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (IntegrationTest SourcePos -> [String]
forall c. IntegrationTest c -> [String]
extractCategoryNames IntegrationTest SourcePos
t) [String
"Test"]
        [String] -> [String] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (IntegrationTest SourcePos -> [String]
forall c. IntegrationTest c -> [String]
extractDefinitionNames IntegrationTest SourcePos
t) [String
"Test"]
        ),

    String
-> (IntegrationTest SourcePos -> IO (CompileInfo ()))
-> IO (CompileInfo ())
checkFileContents
      (String
"testfiles" String -> String -> String
</> String
"basic_crash_test.0rt")
      (\IntegrationTest SourcePos
t -> CompileInfo () -> IO (CompileInfo ())
forall (m :: * -> *) a. Monad m => a -> m a
return (CompileInfo () -> IO (CompileInfo ()))
-> CompileInfo () -> IO (CompileInfo ())
forall a b. (a -> b) -> a -> b
$ do
        let h :: IntegrationTestHeader SourcePos
h = IntegrationTest SourcePos -> IntegrationTestHeader SourcePos
forall c. IntegrationTest c -> IntegrationTestHeader c
itHeader IntegrationTest SourcePos
t
        Bool -> CompileInfo () -> CompileInfo ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ExpectedResult SourcePos -> Bool
forall c. ExpectedResult c -> Bool
isExpectRuntimeError (ExpectedResult SourcePos -> Bool)
-> ExpectedResult SourcePos -> Bool
forall a b. (a -> b) -> a -> b
$ IntegrationTestHeader SourcePos -> ExpectedResult SourcePos
forall c. IntegrationTestHeader c -> ExpectedResult c
ithResult IntegrationTestHeader SourcePos
h) (CompileInfo () -> CompileInfo ())
-> CompileInfo () -> CompileInfo ()
forall a b. (a -> b) -> a -> b
$ String -> CompileInfo ()
forall (m :: * -> *) a. CompileErrorM m => String -> m a
compileErrorM String
"Expected ExpectRuntimeError"
        String -> String -> CompileInfo ()
forall a. (Eq a, Show a) => a -> a -> CompileInfo ()
checkEquals (IntegrationTestHeader SourcePos -> String
forall c. IntegrationTestHeader c -> String
ithTestName IntegrationTestHeader SourcePos
h) String
"basic crash test"
        let match :: Bool
match = case ExpectedResult SourcePos -> Expression SourcePos
forall c. ExpectedResult c -> Expression c
ereExpression (ExpectedResult SourcePos -> Expression SourcePos)
-> ExpectedResult SourcePos -> Expression SourcePos
forall a b. (a -> b) -> a -> b
$ IntegrationTestHeader SourcePos -> ExpectedResult SourcePos
forall c. IntegrationTestHeader c -> ExpectedResult c
ithResult IntegrationTestHeader SourcePos
h of
                         (Expression [SourcePos]
_
                           (TypeCall [SourcePos]
_
                             (JustTypeInstance (TypeInstance (CategoryName String
"Test") (Positional [])))
                             (FunctionCall [SourcePos]
_ (FunctionName String
"execute") (Positional []) (Positional []))) []) -> Bool
True
                         Expression SourcePos
_ -> Bool
False
        Bool -> CompileInfo () -> CompileInfo ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
match) (CompileInfo () -> CompileInfo ())
-> CompileInfo () -> CompileInfo ()
forall a b. (a -> b) -> a -> b
$ String -> CompileInfo ()
forall (m :: * -> *) a. CompileErrorM m => String -> m a
compileErrorM String
"Expected test expression \"Test$execute()\""
        [OutputPattern] -> [OutputPattern] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (ExpectedResult SourcePos -> [OutputPattern]
forall c. ExpectedResult c -> [OutputPattern]
getRequirePattern (ExpectedResult SourcePos -> [OutputPattern])
-> ExpectedResult SourcePos -> [OutputPattern]
forall a b. (a -> b) -> a -> b
$ IntegrationTestHeader SourcePos -> ExpectedResult SourcePos
forall c. IntegrationTestHeader c -> ExpectedResult c
ithResult IntegrationTestHeader SourcePos
h) [
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputAny String
"pattern in output 1",
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputAny String
"pattern in output 2"
          ]
        [OutputPattern] -> [OutputPattern] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (ExpectedResult SourcePos -> [OutputPattern]
forall c. ExpectedResult c -> [OutputPattern]
getExcludePattern (ExpectedResult SourcePos -> [OutputPattern])
-> ExpectedResult SourcePos -> [OutputPattern]
forall a b. (a -> b) -> a -> b
$ IntegrationTestHeader SourcePos -> ExpectedResult SourcePos
forall c. IntegrationTestHeader c -> ExpectedResult c
ithResult IntegrationTestHeader SourcePos
h) [
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputAny String
"pattern not in output 1",
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputAny String
"pattern not in output 2"
          ]
        [String] -> [String] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (IntegrationTest SourcePos -> [String]
forall c. IntegrationTest c -> [String]
extractCategoryNames IntegrationTest SourcePos
t) [String
"Test"]
        [String] -> [String] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (IntegrationTest SourcePos -> [String]
forall c. IntegrationTest c -> [String]
extractDefinitionNames IntegrationTest SourcePos
t) [String
"Test"]
        ),

    String
-> (IntegrationTest SourcePos -> IO (CompileInfo ()))
-> IO (CompileInfo ())
checkFileContents
      (String
"testfiles" String -> String -> String
</> String
"basic_success_test.0rt")
      (\IntegrationTest SourcePos
t -> CompileInfo () -> IO (CompileInfo ())
forall (m :: * -> *) a. Monad m => a -> m a
return (CompileInfo () -> IO (CompileInfo ()))
-> CompileInfo () -> IO (CompileInfo ())
forall a b. (a -> b) -> a -> b
$ do
        let h :: IntegrationTestHeader SourcePos
h = IntegrationTest SourcePos -> IntegrationTestHeader SourcePos
forall c. IntegrationTest c -> IntegrationTestHeader c
itHeader IntegrationTest SourcePos
t
        Bool -> CompileInfo () -> CompileInfo ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ExpectedResult SourcePos -> Bool
forall c. ExpectedResult c -> Bool
isExpectRuntimeSuccess (ExpectedResult SourcePos -> Bool)
-> ExpectedResult SourcePos -> Bool
forall a b. (a -> b) -> a -> b
$ IntegrationTestHeader SourcePos -> ExpectedResult SourcePos
forall c. IntegrationTestHeader c -> ExpectedResult c
ithResult IntegrationTestHeader SourcePos
h) (CompileInfo () -> CompileInfo ())
-> CompileInfo () -> CompileInfo ()
forall a b. (a -> b) -> a -> b
$ String -> CompileInfo ()
forall (m :: * -> *) a. CompileErrorM m => String -> m a
compileErrorM String
"Expected ExpectRuntimeSuccess"
        String -> String -> CompileInfo ()
forall a. (Eq a, Show a) => a -> a -> CompileInfo ()
checkEquals (IntegrationTestHeader SourcePos -> String
forall c. IntegrationTestHeader c -> String
ithTestName IntegrationTestHeader SourcePos
h) String
"basic success test"
        let match :: Bool
match = case ExpectedResult SourcePos -> Expression SourcePos
forall c. ExpectedResult c -> Expression c
ersExpression (ExpectedResult SourcePos -> Expression SourcePos)
-> ExpectedResult SourcePos -> Expression SourcePos
forall a b. (a -> b) -> a -> b
$ IntegrationTestHeader SourcePos -> ExpectedResult SourcePos
forall c. IntegrationTestHeader c -> ExpectedResult c
ithResult IntegrationTestHeader SourcePos
h of
                         (Expression [SourcePos]
_
                           (TypeCall [SourcePos]
_
                             (JustTypeInstance (TypeInstance (CategoryName String
"Test") (Positional [])))
                             (FunctionCall [SourcePos]
_ (FunctionName String
"execute") (Positional []) (Positional []))) []) -> Bool
True
                         Expression SourcePos
_ -> Bool
False
        Bool -> CompileInfo () -> CompileInfo ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
match) (CompileInfo () -> CompileInfo ())
-> CompileInfo () -> CompileInfo ()
forall a b. (a -> b) -> a -> b
$ String -> CompileInfo ()
forall (m :: * -> *) a. CompileErrorM m => String -> m a
compileErrorM String
"Expected test expression \"Test$execute()\""
        [OutputPattern] -> [OutputPattern] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (ExpectedResult SourcePos -> [OutputPattern]
forall c. ExpectedResult c -> [OutputPattern]
getRequirePattern (ExpectedResult SourcePos -> [OutputPattern])
-> ExpectedResult SourcePos -> [OutputPattern]
forall a b. (a -> b) -> a -> b
$ IntegrationTestHeader SourcePos -> ExpectedResult SourcePos
forall c. IntegrationTestHeader c -> ExpectedResult c
ithResult IntegrationTestHeader SourcePos
h) [
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputAny String
"pattern in output 1",
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputAny String
"pattern in output 2"
          ]
        [OutputPattern] -> [OutputPattern] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (ExpectedResult SourcePos -> [OutputPattern]
forall c. ExpectedResult c -> [OutputPattern]
getExcludePattern (ExpectedResult SourcePos -> [OutputPattern])
-> ExpectedResult SourcePos -> [OutputPattern]
forall a b. (a -> b) -> a -> b
$ IntegrationTestHeader SourcePos -> ExpectedResult SourcePos
forall c. IntegrationTestHeader c -> ExpectedResult c
ithResult IntegrationTestHeader SourcePos
h) [
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputAny String
"pattern not in output 1",
            OutputScope -> String -> OutputPattern
OutputPattern OutputScope
OutputAny String
"pattern not in output 2"
          ]
        [String] -> [String] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (IntegrationTest SourcePos -> [String]
forall c. IntegrationTest c -> [String]
extractCategoryNames IntegrationTest SourcePos
t) [String
"Test"]
        [String] -> [String] -> CompileInfo ()
forall a. (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
containsExactly (IntegrationTest SourcePos -> [String]
forall c. IntegrationTest c -> [String]
extractDefinitionNames IntegrationTest SourcePos
t) [String
"Test"]
        )
  ]

checkFileContents ::
  String -> (IntegrationTest SourcePos -> IO (CompileInfo ())) -> IO (CompileInfo ())
checkFileContents :: String
-> (IntegrationTest SourcePos -> IO (CompileInfo ()))
-> IO (CompileInfo ())
checkFileContents String
f IntegrationTest SourcePos -> IO (CompileInfo ())
o = do
  String
s <- String -> IO String
loadFile String
f
  Either ParseError (IntegrationTest SourcePos)
-> IO (CompileInfo ())
forall a.
Show a =>
Either a (IntegrationTest SourcePos) -> IO (CompileInfo ())
unwrap (Either ParseError (IntegrationTest SourcePos)
 -> IO (CompileInfo ()))
-> Either ParseError (IntegrationTest SourcePos)
-> IO (CompileInfo ())
forall a b. (a -> b) -> a -> b
$ Parsec String () (IntegrationTest SourcePos)
-> String
-> String
-> Either ParseError (IntegrationTest SourcePos)
forall s t a.
Stream s Identity t =>
Parsec s () a -> String -> s -> Either ParseError a
parse (ParsecT String () Identity ()
-> ParsecT String () Identity ()
-> Parsec String () (IntegrationTest SourcePos)
-> Parsec String () (IntegrationTest SourcePos)
forall s (m :: * -> *) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
between ParsecT String () Identity ()
optionalSpace ParsecT String () Identity ()
endOfDoc Parsec String () (IntegrationTest SourcePos)
forall a. ParseFromSource a => Parser a
sourceParser) String
f String
s
  where
    unwrap :: Either a (IntegrationTest SourcePos) -> IO (CompileInfo ())
unwrap (Left a
e)  = CompileInfo () -> IO (CompileInfo ())
forall (m :: * -> *) a. Monad m => a -> m a
return (CompileInfo () -> IO (CompileInfo ()))
-> CompileInfo () -> IO (CompileInfo ())
forall a b. (a -> b) -> a -> b
$ String -> CompileInfo ()
forall (m :: * -> *) a. CompileErrorM m => String -> m a
compileErrorM (a -> String
forall a. Show a => a -> String
show a
e)
    unwrap (Right IntegrationTest SourcePos
t) = (CompileInfo () -> CompileInfo ())
-> IO (CompileInfo ()) -> IO (CompileInfo ())
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((String
"Check " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
f String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
":") String -> CompileInfo () -> CompileInfo ()
forall (m :: * -> *) a. CompileErrorM m => String -> m a -> m a
??>) (IO (CompileInfo ()) -> IO (CompileInfo ()))
-> IO (CompileInfo ()) -> IO (CompileInfo ())
forall a b. (a -> b) -> a -> b
$ IntegrationTest SourcePos -> IO (CompileInfo ())
o IntegrationTest SourcePos
t

extractCategoryNames :: IntegrationTest c -> [String]
extractCategoryNames :: IntegrationTest c -> [String]
extractCategoryNames = (AnyCategory c -> String) -> [AnyCategory c] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (CategoryName -> String
forall a. Show a => a -> String
show (CategoryName -> String)
-> (AnyCategory c -> CategoryName) -> AnyCategory c -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnyCategory c -> CategoryName
forall c. AnyCategory c -> CategoryName
getCategoryName) ([AnyCategory c] -> [String])
-> (IntegrationTest c -> [AnyCategory c])
-> IntegrationTest c
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IntegrationTest c -> [AnyCategory c]
forall c. IntegrationTest c -> [AnyCategory c]
itCategory

extractDefinitionNames :: IntegrationTest c -> [String]
extractDefinitionNames :: IntegrationTest c -> [String]
extractDefinitionNames = (DefinedCategory c -> String) -> [DefinedCategory c] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (CategoryName -> String
forall a. Show a => a -> String
show (CategoryName -> String)
-> (DefinedCategory c -> CategoryName)
-> DefinedCategory c
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DefinedCategory c -> CategoryName
forall c. DefinedCategory c -> CategoryName
dcName) ([DefinedCategory c] -> [String])
-> (IntegrationTest c -> [DefinedCategory c])
-> IntegrationTest c
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IntegrationTest c -> [DefinedCategory c]
forall c. IntegrationTest c -> [DefinedCategory c]
itDefinition