packages feed

elm-repl-0.4.1: tests/Main.hs

module Main where

import qualified Data.Char as Char
import qualified Data.List as List
import Data.Maybe (isJust)
import Test.Framework (Test, defaultMain, testGroup)
import Test.Framework.Providers.HUnit (testCase)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Test.HUnit ((@=?))
import qualified Test.HUnit.Base as HUnit
import Test.QuickCheck

import qualified Input as I
import qualified Parse

main :: IO ()
main = defaultMain tests

tests :: [Test]
tests =
    [ testGroup "Parse tests"
        [ testGroup "Command parse tests" cmdParseTests
        , testGroup "Code parse tests"  codeParseTests
        , testGroup "Whitespace parse tests" skipTests
        ]
    ]

cmdParseTests :: [Test]
cmdParseTests =
    [ testGroup "Good commands tests"
        [ testCase ":help parses"                    $ cmdParses (I.Help Nothing) ":help"
        , testCase ":reset parses after whitespace"  $ cmdParses I.Reset "  :reset"
        , testCase ":exit parses before whitespace"  $ cmdParses I.Exit ":exit   "
        ]
    , testGroup ":flags parse tests"
        [ testCase ":flags parses with Info"         $ cmdParses (I.InfoFlags Nothing) ":flags"
        , testCase ":flags + space parses with Info" $ cmdParses (I.InfoFlags Nothing) ":flags    "
        , testCase ":flags list parses"              $ cmdParses I.ListFlags ":flags list"
        , testCase ":flags clear parses w/ whitespace between" $
            cmdParses I.ClearFlags ":flags     clear"
        , testCase ":flags add source parses" $
            cmdParses (I.AddFlag "--src-dir=\"\"") ":flags add --src-dir=\"\""
        , testCase ":flags remove source parses" $
            cmdParses (I.RemoveFlag "--src-dir=bleh") ":flags remove --src-dir=bleh"
        ]
    , testGroup "Bad commands tests"
        [ testCase ":flagsgrbl triggers help" $ helpErr ":flagsg"
        , testProperty "bad :commands trigger help" badCommandHelp
        ]
    ]
  where
    cmdParses cmd = actionParses (I.Meta cmd)
    helpErr cmd =
        case Parse.rawInput cmd of
          I.Meta (I.Help message) ->
              HUnit.assert (isJust message)
          action ->
              HUnit.assertFailure (errorMessage action)

    errorMessage action =
        "Should display help with an error message, instead got: " ++ show action

codeParseTests :: [Test]
codeParseTests =
    [ testCase "number parses" $ codeParses Nothing "3"
    , testCase "number parses after newlines" $ codeParses Nothing "\n\n3"
    , testCase "data def parses"  $ codeParses (Just $ I.DataDef "Baz")  "type Baz = B { }"
    , testCase "var def parses" $ codeParses (Just $ I.VarDef "x") "x = 3"
    , testCase "var fun def parses" $ codeParses (Just $ I.VarDef "f") "f x = x"
    ]

skipTests :: [Test]
skipTests =
    [ testCase "empty is skipped" (skipped "")
    , testCase "newlines are skipped" (skipped "\n\n\n")
    , testProperty "skip all whitespace" skipAllSpace
    , testProperty "never skip non-whitespace" dontSkipNonSpace
    ]
  where
    skipped = actionParses I.Skip

-- | Test Helpers
codeParses :: Maybe I.DefName -> String -> HUnit.Assertion
codeParses name src =
    actionParses (I.Code (name, trimSpace src)) src
  where
    trimSpace = dropWhile Char.isSpace

actionParses :: I.Input -> String -> HUnit.Assertion
actionParses input rawString =
    input @=? Parse.rawInput rawString

badCommandHelp :: Property
badCommandHelp =
    forAll nonFlags helpParses
  where
    nonFlags =
        oneof
            [ arbitrary `suchThat` notFlag
            , badFlag
            ]

    helpParses s =
        case Parse.rawInput (':':s) of
          I.Meta (I.Help (Just _)) -> True
          _ -> False

    -- | TODO: things like help3
    notFlag s =
        not $ any (s `List.isPrefixOf`) flags

    badFlag =
      do  flag <- elements flags
          c <- arbitrary `suchThat` (not . Char.isSpace)
          return $ flag ++ [c]

    flags =
        [ "help", "reset", "flags", "exit" ]

skipAllSpace :: Property
skipAllSpace =
    forAll spaces $ (==I.Skip) . Parse.rawInput
  where
    spaces =
        listOf . elements $ filter Char.isSpace [toEnum 0..]

dontSkipNonSpace :: Property
dontSkipNonSpace =
    forAll notAllSpace $ (/= I.Skip) . Parse.rawInput
  where
    notAllSpace =
        arbitrary `suchThat` (not . all Char.isSpace)