{- -----------------------------------------------------------------------------
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.TypeCategory


tests :: [IO (CompileInfo ())]
tests :: [IO (CompileInfo ())]
tests = [
    String
-> (IntegrationTest SourcePos -> CompileInfo ())
-> IO (CompileInfo ())
checkFileContents
      (String
"testfiles" String -> String -> String
</> String
"basic_compiles_test.0rt")
      (\IntegrationTest SourcePos
t -> 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
isExpectCompiles (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 ExpectCompiles"
        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 compiles 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 -> CompileInfo ())
-> IO (CompileInfo ())
checkFileContents
      (String
"testfiles" String -> String -> String
</> String
"basic_error_test.0rt")
      (\IntegrationTest SourcePos
t -> 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 -> CompileInfo ())
-> IO (CompileInfo ())
checkFileContents
      (String
"testfiles" String -> String -> String
</> String
"basic_crash_test.0rt")
      (\IntegrationTest SourcePos
t -> 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"
        [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 -> CompileInfo ())
-> IO (CompileInfo ())
checkFileContents
      (String
"testfiles" String -> String -> String
</> String
"basic_success_test.0rt")
      (\IntegrationTest SourcePos
t -> 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"
        [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 -> CompileInfo ()) -> IO (CompileInfo ())
checkFileContents :: String
-> (IntegrationTest SourcePos -> CompileInfo ())
-> IO (CompileInfo ())
checkFileContents String
f IntegrationTest SourcePos -> CompileInfo ()
o = CompileInfoT IO () -> IO (CompileInfo ())
forall (m :: * -> *) a.
Monad m =>
CompileInfoT m a -> m (CompileInfo a)
toCompileInfo (CompileInfoT IO () -> IO (CompileInfo ()))
-> CompileInfoT IO () -> IO (CompileInfo ())
forall a b. (a -> b) -> a -> b
$ do
  String
s <- IO String -> CompileInfoT IO String
forall (m :: * -> *) a. (MonadIO m, CompileErrorM m) => IO a -> m a
errorFromIO (IO String -> CompileInfoT IO String)
-> IO String -> CompileInfoT IO String
forall a b. (a -> b) -> a -> b
$ String -> IO String
loadFile String
f
  IntegrationTest SourcePos
t <- ParserE (CompileInfoT IO) (IntegrationTest SourcePos)
-> String -> String -> CompileInfoT IO (IntegrationTest SourcePos)
forall (m :: * -> *) a.
CompileErrorM m =>
ParserE m a -> String -> String -> m a
runParserE (ParsecT String () (CompileInfoT IO) ()
-> ParsecT String () (CompileInfoT IO) ()
-> ParserE (CompileInfoT IO) (IntegrationTest SourcePos)
-> ParserE (CompileInfoT IO) (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 () (CompileInfoT IO) ()
forall (m :: * -> *). Monad m => ParserE m ()
optionalSpace ParsecT String () (CompileInfoT IO) ()
forall (m :: * -> *). Monad m => ParserE m ()
endOfDoc ParserE (CompileInfoT IO) (IntegrationTest SourcePos)
forall a (m :: * -> *).
(ParseFromSource a, CompileErrorM m) =>
ParserE m a
sourceParser) String
f String
s
  CompileInfo () -> CompileInfoT IO ()
forall (m :: * -> *) a.
Monad m =>
CompileInfo a -> CompileInfoT m a
fromCompileInfo (CompileInfo () -> CompileInfoT IO ())
-> CompileInfo () -> CompileInfoT IO ()
forall a b. (a -> b) -> a -> b
$ IntegrationTest SourcePos -> CompileInfo ()
o IntegrationTest SourcePos
t CompileInfo () -> String -> CompileInfo ()
forall (m :: * -> *) a. CompileErrorM m => m a -> String -> m a
<!! String
"Check " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
f String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
":"

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