module Main (main) where

import           Data.Version                   (showVersion)
import           System.Process                 (readProcess)

import           Test.Framework                 (defaultMain)
import           Test.Framework.Providers.HUnit (hUnitTestToTests)
import           Test.HUnit

import           Language.Egison                (version)

main :: IO ()
main = defaultMain . hUnitTestToTests . test $ TestList
    [ TestLabel "load-file option" . TestCase $ assertEgisonCmd
        (interpreter "1\n")
        ["--load-file", "test/fixture/a.egi"]
        "x"
    , TestLabel "test option" . TestCase $ assertEgisonCmd
        "3\n\"This is the third line\"\n"
        ["--test", "test/fixture/b.egi"]
        ""
    , TestLabel "eval option" . TestCase $ assertEgisonCmd
        "[[], [1], [1, 2], [1, 2, 3]]\n"
        ["--eval", "matchAll [1,2,3] as list something with $x ++ _ -> x"]
        ""
    , TestLabel "command option" . TestCase $ assertEgisonCmd
        "1\n"
        ["--command", "print (show 1)"]
        ""
    , TestLabel "TSV option" . TestCase $ assertEgisonCmd
        "2\n3\n5\n7\n11\n13\n17\n19\n23\n29\n"
        ["-T", "-e", "take 10 primes"]
        ""
    , TestLabel "TSV option with tab" . TestCase $ assertEgisonCmd
        "1\t2\t3\n4\t5\n"
        ["-T", "-e", "[[1, 2, 3], [4, 5]]"]
        ""
    , TestLabel "substitute option" . TestCase $ assertEgisonCmd
        "10\n11\n12\n13\n14\n15\n"
        ["--substitute", "\\matchAll as list integer with _ ++ $x :: _ ++ #(x + 5) :: _ -> x"]
        "10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20"
    , TestLabel "map option" . TestCase $ assertEgisonCmd
        "3\n4\n5\n6\n7\n"
        ["--map", "\\x -> x + 2"]
        "1\n2\n3\n4\n5"
    , TestLabel "filter option" . TestCase $ assertEgisonCmd
        "2\n3\n5\n7\n"
        ["--filter", "isPrime"]
        "1\n2\n3\n4\n5\n6\n7\n8\n9\n10"
    , TestLabel "field option" . TestCase $ assertEgisonCmd
        "(10, [2, 5])\n(11, [11])\n(12, [2, 2, 3])\n(13, [13])\n(14, [2, 7])\n(15, [3, 5])\n"
        ["--field", "2c", "-m", "\\x -> x"]
        "10\t2\t5\n11\t11\n12\t2\t2\t3\n13\t13\n14\t2\t7\n15\t3\t5"
    , TestLabel "math option" . TestCase $ assertEgisonCmd
        (interpreter "#latex|\\frac{x}{y}|#\n")
        ["--math", "latex"]
        "x / y"
    , TestLabel "sexpr option" . TestCase $ assertEgisonCmd
        (interpreter "3\n")
        ["--sexpr-syntax"]
        "(+ 1 2)"
    , TestLabel "execute main function" . TestCase $ assertEgisonCmd
        "[\"a\", \"b\", \"c\"]\n"
        ["test/fixture/c.egi", "a", "b", "c"]
        ""
    , TestLabel "io function" . TestCase $ assertEgisonCmd
        "display write print\n3\n1 + 2 = 3\n"
        ["test/lib/core/io.egi"]
        ""
    ]

assertEgisonCmd
  :: String   -- The expected value
  -> [String] -- any arguments for egison command
  -> String   -- standard input for egison command
  -> Assertion
assertEgisonCmd expected args input = do
  actual <- readProcess "stack" ("exec" : "--" : "egison" : args) input
  assertEqual "" expected actual

interpreter :: String -> String
interpreter output = concat
  [ "Egison Version ", showVersion version, "\n"
  , "https://www.egison.org\n"
  , "Welcome to Egison Interpreter!\n"
  , "> ", output
  , "> Leaving Egison Interpreter.\n"
  ]
