{- |
    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 -> l -> Bool
basicLinearTest e
e l
line = [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and
  [
    l -> Bool
forall e. Nullable e => e -> Bool
isNull (   l
forall e. Nullable e => e
lzero    l -> l -> l
forall a. a -> a -> a
`asTypeOf` l
line),
    l -> Bool
forall e. Nullable e => e -> Bool
isNull ([e] -> l
forall l e. Linear l e => [e] -> l
fromList [] l -> l -> l
forall a. a -> a -> a
`asTypeOf` l
line),
    
    e -> l
forall l e. Linear l e => e -> l
single  e
e l -> l -> Bool
forall a. Eq a => a -> a -> Bool
== ([e] -> l
forall l e. Linear l e => [e] -> l
fromList [e
e] l -> l -> l
forall a. a -> a -> a
`asTypeOf` l
line),
    Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ l -> Bool
forall e. Nullable e => e -> Bool
isNull (  e -> l
forall l e. Linear l e => e -> l
single e
e   l -> l -> l
forall a. a -> a -> a
`asTypeOf` l
line),
    
    [e] -> l
forall l e. Linear l e => [e] -> l
fromList (l -> [e]
forall l e. Linear l e => l -> [e]
listL l
line) l -> l -> Bool
forall a. Eq a => a -> a -> Bool
== l
line
  ]

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

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

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

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

-- | 'concatTest' checks rules of ('++') and 'concat'.
concatTest :: (Linear l e, Eq e, Eq l) => l -> Bool
concatTest :: l -> Bool
concatTest l
line = [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and
  [
    l -> [e]
forall l e. Linear l e => l -> [e]
listL l
line [e] -> [e] -> [e]
forall l e. Linear l e => l -> l -> l
++ l -> [e]
forall l e. Linear l e => l -> [e]
listR l
line [e] -> [e] -> Bool
forall a. Eq a => a -> a -> Bool
== l -> [e]
forall l e. Linear l e => l -> [e]
listL (l
line l -> l -> l
forall l e. Linear l e => l -> l -> l
++ l -> l
forall l e. Linear l e => l -> l
reverse l
line),
    
    l
forall e. Nullable e => e
Z l -> l -> l
forall l e. Linear l e => l -> l -> l
++ l
line l -> l -> Bool
forall a. Eq a => a -> a -> Bool
== l
line,
    l
line l -> l -> l
forall l e. Linear l e => l -> l -> l
++ l
forall e. Nullable e => e
Z l -> l -> Bool
forall a. Eq a => a -> a -> Bool
== l
line,
    
    [l] -> l
forall l e (f :: * -> *). (Linear l e, Foldable f) => f l -> l
concat [l
line, l -> l
forall l e. Linear l e => l -> l
reverse l
line] l -> l -> Bool
forall a. Eq a => a -> a -> Bool
== [e] -> l
forall l e. Linear l e => [e] -> l
fromList ([[e]] -> [e]
forall l e (f :: * -> *). (Linear l e, Foldable f) => f l -> l
concat [l -> [e]
forall l e. Linear l e => l -> [e]
listL l
line, l -> [e]
forall l e. Linear l e => l -> [e]
listR l
line]),
    [l] -> l
forall l e (f :: * -> *). (Linear l e, Foldable f) => f l -> l
concat [l
line, l -> l
forall l e. Linear l e => l -> l
reverse l
line] l -> l -> Bool
forall a. Eq a => a -> a -> Bool
== l
line l -> l -> l
forall l e. Linear l e => l -> l -> l
++ l -> l
forall l e. Linear l e => l -> l
reverse l
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 :: Int -> e -> l -> Bool
linearTest Int
n e
e l
line = [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and
  [
    e -> l -> Bool
forall l e. (Linear l e, Eq l) => e -> l -> Bool
basicLinearTest e
e l
line,
    l -> Bool
forall l e. (Linear l e, Eq e) => l -> Bool
deconstructionLinearTest l
line,
    e -> l -> Bool
forall l e. (Linear l e, Eq l) => e -> l -> Bool
constructionLinearTest e
e l
line,
    Int -> e -> l -> Bool
forall l e i.
(Linear l e, Eq l, Bordered l i) =>
Int -> e -> l -> Bool
replicateTest Int
n e
e l
line,
    l -> Bool
forall l e. (Linear l e, Eq e) => l -> Bool
reverseTest l
line,
    l -> Bool
forall l e. (Linear l e, Eq e, Eq l) => l -> Bool
concatTest l
line
  ]