packages feed

stgi-1.1: test/Testsuite/Test/ExamplePrograms.hs

{-# LANGUAGE BangPatterns        #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Test.ExamplePrograms (tests) where



import qualified Data.List as L

import Stg.ExamplePrograms
import Stg.Machine.Types

import qualified Test.Machine.Evaluate.TestTemplates.MachineState    as MST
import           Test.Machine.Evaluate.TestTemplates.MarshalledValue
import           Test.Orphans                                        ()
import           Test.QuickCheck.Modifiers
import           Test.Tasty



tests :: TestTree
tests = testGroup "Example programs"
    [ testGroup "Simple examples"
        [testImplies
        , testAddTwoNumbers
        , testCalculateLength ]
    , testGroup "map"
        [ testMapNot
        , testMapNotForced ]
    , testGroup "Sum using folds"
        [ testSumFoldl'
        , testSumFoldl
        , testSumFoldl'ViaFoldr
        , testSumFoldr ]
    , testGroup "Fibonacci"
        [ testFibonacciNaive
        , testFibonacciImproved
        , testFibonacciZipWith ]
    , testGroup "Concatenation"
        [ testListConcatLeftAssociated
        , testListConcatRightAssociated ]
    , testGroup "Sorting"
        [ testNaiveSort
        , testLibrarySort ]
    ]



testImplies :: TestTree
testImplies = marshalledValueTest defSpec
    { testName = "Implication"
    , sourceSpec = \(x,y) -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = x <= y
        , source = implies x y }}

testAddTwoNumbers :: TestTree
testAddTwoNumbers = marshalledValueTest defSpec
    { testName = "Add two numbers"
    , sourceSpec = \(x,y) -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = x+y
        , source = addTwoNumbers x y }}

testCalculateLength :: TestTree
testCalculateLength = marshalledValueTest defSpec
    { testName = "Length of a list"
    , sourceSpec = \(xs :: [Integer]) -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = fromIntegral (length xs) :: Integer
        , source = calculateLength xs }}

testMapNot :: TestTree
testMapNot = MST.machineStateTest MST.defSpec
    { MST.testName = "map not, not forced"
    , MST.successPredicate = \state -> case stgInfo state of
        Info short _long -> short == NoRulesApply
    , MST.source = mapNot [True, False, True]
    , MST.maxSteps = 20}

testMapNotForced :: TestTree
testMapNotForced = marshalledValueTest defSpec
    { testName = "map not, forced"
    , sourceSpec = \xs -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = map not xs
        , source = mapNotForced xs }}

testSumFoldl' :: TestTree
testSumFoldl' = marshalledValueTest defSpec
    { testName = "Sum via foldl'"
    , sourceSpec = \xs -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = sum xs :: Integer
        , source = sum_foldl' xs }}

testSumFoldl :: TestTree
testSumFoldl = marshalledValueTest defSpec
    { testName = "Sum via foldl"
    , sourceSpec = \xs -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = sum xs :: Integer
        , source = sum_foldl xs }}

testSumFoldl'ViaFoldr :: TestTree
testSumFoldl'ViaFoldr = marshalledValueTest defSpec
    { testName = "Sum via foldl' implemented with foldr"
    , sourceSpec = \xs -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = sum xs :: Integer
        , source = sum_foldl'ViaFoldr xs }}

testSumFoldr :: TestTree
testSumFoldr = marshalledValueTest defSpec
    { testName = "Sum via foldr"
    , sourceSpec = \xs -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = sum xs :: Integer
        , source = sum_foldr xs }}

fibo :: Integer -> Integer
fibo = fibo' 0 1
  where
    fibo' !a !_b n | n <= 0 = a
    fibo'  a   b n = fibo' b (a+b) (n-1)

testFibonacciNaive :: TestTree
testFibonacciNaive = marshalledValueTest defSpec
    { testName = "Naive Fibonacci"
    , sourceSpec = \(NonNegative n) ->
        let smallerN = mod n 16
        in MarshalSourceSpec
            { resultVar = "main"
            , expectedValue = fibo smallerN
            , source = fibonacciNaive smallerN }}

testFibonacciImproved :: TestTree
testFibonacciImproved = marshalledValueTest defSpec
    { testName = "Improved linear Fibonacci"
    , sourceSpec = \(NonNegative n) -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = fibo n
        , source = fibonacciImproved n }}

testFibonacciZipWith :: TestTree
testFibonacciZipWith = MST.machineStateTest MST.defSpec
    { MST.testName = "Fibonacci via zipWith"
    , MST.successPredicate = \state -> case stgCode state of
        ReturnCon "Int#" [PrimInt n] -> n == fibo 10
        _otherwise  -> False
    , MST.source = fibonacciZipWith }

testListConcatLeftAssociated :: TestTree
testListConcatLeftAssociated = marshalledValueTest defSpec
    { testName = "List concatenation, left-associated"
    , sourceSpec = \xss -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = concat xss :: [Integer]
        , source = listConcatLeftAssociated xss }}

testListConcatRightAssociated :: TestTree
testListConcatRightAssociated = marshalledValueTest defSpec
    { testName = "List concatenation, right-associated"
    , sourceSpec = \xss -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = concat xss :: [Integer]
        , source = listConcatRightAssociated xss }}

testNaiveSort :: TestTree
testNaiveSort = marshalledValueTest defSpec
    { testName = "Sort using naive Quicksort-inspired algorithm"
    , sourceSpec = \xs -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = L.sort xs :: [Integer]
        , source = naiveSort xs }}

testLibrarySort :: TestTree
testLibrarySort = marshalledValueTest defSpec
    { testName = "Sort using the standard Haskell list sort"
    , sourceSpec = \xs -> MarshalSourceSpec
        { resultVar = "main"
        , expectedValue = L.sort xs :: [Integer]
        , source = librarySort xs }}