content: module APL.Parser_Tests (tests) where
  
  import APL.AST (Exp (..))
  import APL.Parser (parseAPL)
  import Test.Tasty (TestTree, testGroup)
  import Test.Tasty.HUnit (assertFailure, testCase, (@?=))
  
  parserTest :: String -> Exp -> TestTree
  parserTest s e =
    testCase s $
      case parseAPL "input" s of
        Left err -> assertFailure err
        Right e' -> e' @?= e
  
  parserTestFail :: String -> TestTree
  parserTestFail s =
    testCase s $
      case parseAPL "input" s of
        Left _ -> pure ()
        Right e ->
          assertFailure $
            "Expected parse error but received this AST:\n" ++ show e
  
  tests :: TestTree
  tests =
    testGroup
      "Parsing"
      [ testGroup
          "Constants"
          [ parserTest "123" $ CstInt 123,
            parserTest " 123" $ CstInt 123,
            parserTest "123 " $ CstInt 123,
            parserTestFail "123f",
            parserTest "true" $ CstBool True,
            parserTest "false" $ CstBool False
          ],
        testGroup
          "Basic operators"
          [ parserTest "x+y" $ Add (Var "x") (Var "y"),
            parserTest "x-y" $ Sub (Var "x") (Var "y"),
            parserTest "x*y" $ Mul (Var "x") (Var "y"),
            parserTest "x/y" $ Div (Var "x") (Var "y")
          ],
        testGroup
          "Operator priority"
          [ parserTest "x+y+z" $ Add (Add (Var "x") (Var "y")) (Var "z"),
            parserTest "x+y-z" $ Sub (Add (Var "x") (Var "y")) (Var "z"),
            parserTest "x+y*z" $ Add (Var "x") (Mul (Var "y") (Var "z")),
            parserTest "x*y*z" $ Mul (Mul (Var "x") (Var "y")) (Var "z"),
            parserTest "x/y/z" $ Div (Div (Var "x") (Var "y")) (Var "z")
          ],
        testGroup
          "Conditional expressions"
          [ parserTest "if x then y else z" $ If (Var "x") (Var "y") (Var "z"),
            parserTest "if x then y else if x then y else z" $
              If (Var "x") (Var "y") $
                If (Var "x") (Var "y") (Var "z"),
            parserTest "if x then (if x then y else z) else z" $
              If (Var "x") (If (Var "x") (Var "y") (Var "z")) (Var "z"),
            parserTest "1 + if x then y else z" $
              Add (CstInt 1) (If (Var "x") (Var "y") (Var "z"))
          ],
        testGroup
          "Lexing edge cases"
          [ parserTest "2 " $ CstInt 2,
            parserTest " 2" $ CstInt 2
          ]
      ]
  