packages feed

sdp-quickcheck-0.2: src/Test/SDP/Linear.hs

{- |
    Module      :  Test.SDP.Linear
    Copyright   :  (c) Andrey Mulik 2019
    License     :  BSD-style
    Maintainer  :  work.a.mulik@gmail.com
    Portability :  non-portable (requires non-portable modules)
    
    @Test.SDP.Linear@ provides basic test suite for 'Linear' class.
-}
module Test.SDP.Linear
(
  -- * Default Linear test
  TestLinear, TestLinear1, TestLinear2, linearTest,
  
  -- ** Particular tests
  deconstructionLinearTest, constructionLinearTest, basicLinearTest,
  replicateTest, reverseTest, concatTest
)
where

import Prelude ()
import SDP.SafePrelude
import SDP.Linear

default ()

--------------------------------------------------------------------------------

-- | 'TestLinear' is service type synonym for more comfortable quickCheck using.
type TestLinear  l e = Int -> e -> l -> Bool

-- | 'TestLinear1' is service type synonym for more comfortable quickCheck using.
type TestLinear1 f e = Int -> e -> f e -> Bool

-- | 'TestLinear2' is service type synonym for more comfortable quickCheck using.
type TestLinear2 f i e = Int -> e -> f i e -> Bool

--------------------------------------------------------------------------------

{- |
  'basicLinearTest' checks relations of 'isNull', 'lzero', 'single' and
  'fromList'.
-}
basicLinearTest :: (Linear l e, Eq l) => e -> l -> Bool
basicLinearTest e line = and
  [
    isNull (   lzero    `asTypeOf` line),
    isNull (fromList [] `asTypeOf` line),
    
    single  e == (fromList [e] `asTypeOf` line),
    not $ isNull (  single e   `asTypeOf` line),
    
    fromList (listL line) == line
  ]

{- |
  'deconstructionLinearTest' checks relations of 'isNull', 'head', 'last',
  'init' and 'tail'.
-}
deconstructionLinearTest :: (Linear l e, Eq e) => l -> Bool
deconstructionLinearTest line = and
  [
    isNull line || head line == head (listL line),
    isNull line || last line == last (listL line),
    
    isNull line || listL (init line) == init (listL line),
    isNull line || listL (tail line) == tail (listL line)
  ]

{- |
  'constructionLinearTest' checks relations of 'toHead', 'toLast' and
  'fromList'.
-}
constructionLinearTest :: (Linear l e, Eq l) => e -> l -> Bool
constructionLinearTest e line = and
  [
    toHead e line == fromList (e  :  listL  line),
    toLast line e == fromList (listL line ++ [e]),
    
    not . isNull $ toHead e line,
    not . isNull $ toLast line e
  ]

-- | 'reverseTest' checks rules of 'reverse', 'listL' and 'listR'.
reverseTest :: (Linear l e, Eq e) => l -> Bool
reverseTest line = and
  [
    reverse (listL line) == listL (reverse line),
    reverse (listL line) == listR line
  ]

-- | 'replicateTest' checks rules of 'replicate'.
replicateTest :: (Linear l e, Eq l, Bordered l i) => Int -> e -> l -> Bool
replicateTest n e line = and
  [
    line' == fromList (replicate n e),
    n < 0 || sizeOf line' == n,
    not $ n > 0 && isNull line'
  ]
  where
    line' = (replicate n e) `asTypeOf` line

-- | 'concatTest' checks rules of ('++') and 'concat'.
concatTest :: (Linear l e, Eq e, Eq l) => l -> Bool
concatTest line = and
  [
    listL line ++ listR line == listL (line ++ reverse line),
    
    Z ++ line == line,
    line ++ Z == line,
    
    concat [line, reverse line] == fromList (concat [listL line, listR line]),
    concat [line, reverse line] == line ++ reverse line
  ]

-- | 'linearTest' is complex test, that includes all ther tests.
linearTest :: (Linear l e, Eq e, Eq l, Bordered l i) => Int -> e -> l -> Bool
linearTest n e line = and
  [
    basicLinearTest e line,
    deconstructionLinearTest line,
    constructionLinearTest e line,
    replicateTest n e line,
    reverseTest line,
    concatTest line
  ]