feat: QuickCheck testing
This commit is contained in:
parent
cbccc8253b
commit
95f86c8660
5 changed files with 101 additions and 2 deletions
|
@ -62,6 +62,8 @@ test-suite bf-optimize-test
|
||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
main-is: Spec.hs
|
main-is: Spec.hs
|
||||||
other-modules:
|
other-modules:
|
||||||
|
Arbitrary.InvalidBrainfuckProgram
|
||||||
|
Arbitrary.ValidBrainfuckProgram
|
||||||
Paths_bf_optimize
|
Paths_bf_optimize
|
||||||
autogen-modules:
|
autogen-modules:
|
||||||
Paths_bf_optimize
|
Paths_bf_optimize
|
||||||
|
@ -69,7 +71,8 @@ test-suite bf-optimize-test
|
||||||
test
|
test
|
||||||
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
|
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
|
||||||
build-depends:
|
build-depends:
|
||||||
base >=4.7 && <5
|
QuickCheck
|
||||||
|
, base >=4.7 && <5
|
||||||
, bf-optimize
|
, bf-optimize
|
||||||
, text
|
, text
|
||||||
, vector
|
, vector
|
||||||
|
|
|
@ -59,3 +59,4 @@ tests:
|
||||||
- -with-rtsopts=-N
|
- -with-rtsopts=-N
|
||||||
dependencies:
|
dependencies:
|
||||||
- bf-optimize
|
- bf-optimize
|
||||||
|
- QuickCheck
|
||||||
|
|
26
test/Arbitrary/InvalidBrainfuckProgram.hs
Normal file
26
test/Arbitrary/InvalidBrainfuckProgram.hs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{-# LANGUAGE InstanceSigs #-}
|
||||||
|
{-# LANGUAGE DerivingStrategies #-}
|
||||||
|
module Arbitrary.InvalidBrainfuckProgram (InvalidBrainfuckProgram(..)) where
|
||||||
|
|
||||||
|
import Data.Text (Text)
|
||||||
|
import Test.QuickCheck.Gen (Gen)
|
||||||
|
import Test.QuickCheck.Arbitrary (Arbitrary (arbitrary))
|
||||||
|
|
||||||
|
import qualified Data.Text as Text
|
||||||
|
import qualified Test.QuickCheck.Gen as Gen
|
||||||
|
import qualified Arbitrary.ValidBrainfuckProgram as ValidBrainfuckProgram
|
||||||
|
|
||||||
|
newtype InvalidBrainfuckProgram = InvalidBrainfuckProgram { get :: Text }
|
||||||
|
deriving stock Show
|
||||||
|
|
||||||
|
instance Arbitrary InvalidBrainfuckProgram where
|
||||||
|
arbitrary :: Gen InvalidBrainfuckProgram
|
||||||
|
arbitrary = do
|
||||||
|
validProgram <- ValidBrainfuckProgram.get <$> arbitrary
|
||||||
|
|
||||||
|
index <- Gen.choose (0, Text.length validProgram)
|
||||||
|
badBrace <- Gen.oneof $ map pure "[]"
|
||||||
|
let (prefix, suffix) = Text.splitAt index validProgram
|
||||||
|
|
||||||
|
pure . InvalidBrainfuckProgram $ Text.concat [prefix, Text.singleton badBrace, suffix]
|
||||||
|
|
47
test/Arbitrary/ValidBrainfuckProgram.hs
Normal file
47
test/Arbitrary/ValidBrainfuckProgram.hs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
{-# LANGUAGE InstanceSigs #-}
|
||||||
|
{-# LANGUAGE DerivingStrategies #-}
|
||||||
|
module Arbitrary.ValidBrainfuckProgram (ValidBrainfuckProgram(..)) where
|
||||||
|
import Data.Text (Text)
|
||||||
|
import Test.QuickCheck.Arbitrary (Arbitrary (arbitrary))
|
||||||
|
import Test.QuickCheck.Gen (Gen, sized, frequency, oneof, resize)
|
||||||
|
import Data.Coerce (coerce)
|
||||||
|
|
||||||
|
import qualified Data.Text as Text
|
||||||
|
|
||||||
|
newtype ValidBrainfuckProgram = ValidBrainfuckProgram { get :: Text }
|
||||||
|
deriving stock Show
|
||||||
|
|
||||||
|
instance Arbitrary ValidBrainfuckProgram where
|
||||||
|
arbitrary :: Gen ValidBrainfuckProgram
|
||||||
|
arbitrary = coerce . fmap Text.pack $ character []
|
||||||
|
where
|
||||||
|
character rest = do
|
||||||
|
body <- frequency
|
||||||
|
[ (1, comment)
|
||||||
|
, (9, operator)
|
||||||
|
]
|
||||||
|
|
||||||
|
sized $ \ size -> frequency
|
||||||
|
[ (1 , pure body)
|
||||||
|
, (size, character body)
|
||||||
|
]
|
||||||
|
|
||||||
|
where
|
||||||
|
operator = let
|
||||||
|
|
||||||
|
simpleOperator = oneof $ map (pure . (:rest)) "+-<>,."
|
||||||
|
loopOperator = fmap ('[':) . sized $ \ s -> resize (s `div` 8) (character (']':rest))
|
||||||
|
|
||||||
|
in frequency
|
||||||
|
[ (3, simpleOperator)
|
||||||
|
, (1, loopOperator)
|
||||||
|
]
|
||||||
|
|
||||||
|
comment = do
|
||||||
|
commentChar <- oneof $ map pure "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
pure $ commentChar : rest
|
||||||
|
|
||||||
|
-- >>> import Test.QuickCheck.Gen (generate)
|
||||||
|
-- >>> generate $ (arbitrary :: Gen ValidBrainfuckProgram)
|
||||||
|
-- ValidBrainfuckProgram {get = "<-"}
|
||||||
|
|
24
test/Spec.hs
24
test/Spec.hs
|
@ -1,2 +1,24 @@
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
import Test.QuickCheck.All (quickCheckAll)
|
||||||
|
import System.Exit (exitFailure, exitSuccess)
|
||||||
|
|
||||||
|
import qualified Data.Either as Either
|
||||||
|
import qualified Language.Brainfuck as Brainfuck
|
||||||
|
import qualified Arbitrary.ValidBrainfuckProgram as ValidBrainfuckProgram
|
||||||
|
import qualified Arbitrary.InvalidBrainfuckProgram as InValidBrainfuckProgram
|
||||||
|
|
||||||
|
prop_acceptValidPrograms :: ValidBrainfuckProgram.ValidBrainfuckProgram -> Bool
|
||||||
|
prop_acceptValidPrograms = Either.isRight . Brainfuck.parse . ValidBrainfuckProgram.get
|
||||||
|
|
||||||
|
prop_rejectInvalidPrograms :: InValidBrainfuckProgram.InvalidBrainfuckProgram -> Bool
|
||||||
|
prop_rejectInvalidPrograms = Either.isLeft . Brainfuck.parse . InValidBrainfuckProgram.get
|
||||||
|
|
||||||
|
return [] -- template haskell guard
|
||||||
|
runQuickCheck :: IO Bool
|
||||||
|
runQuickCheck = $quickCheckAll
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = putStrLn "Test suite not yet implemented"
|
main = do
|
||||||
|
quickCheckGood <- runQuickCheck
|
||||||
|
|
||||||
|
if quickCheckGood then exitSuccess else exitFailure
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue