packages feed

list-tuple-0.1.4.1: test/Data/Tuple/ListSpec.hs

{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications    #-}
{-# LANGUAGE TypeFamilies        #-}
{-# LANGUAGE TypeOperators       #-}

{-# OPTIONS_GHC -fdefer-type-errors -Wno-deferred-type-errors -Wno-redundant-constraints -Wno-incomplete-patterns #-}

module Data.Tuple.ListSpec (spec) where

import Data.Tuple.List

import Test.Hspec
import Test.ShouldNotTypecheck

import Prelude hiding (head, init, last, length, reverse, tail, (!!))

import Data.Proxy
import Data.Tuple.Single

spec :: Spec
spec = do
  describe "0-tuple" $ do
    describe "Unit" $ do
      it "head'" $ do
        shouldNotTypecheck (head' () :: ())

      it "tail'" $ do
        shouldNotTypecheck (tail' () :: ())

      it "init'" $ do
        shouldNotTypecheck (init' () :: ())

      it "last'" $ do
        shouldNotTypecheck (last' () :: ())

      it "cons'" $ do
        shouldNotTypecheck (cons' 'a' () :: ())

      it "uncons'" $ do
        shouldNotTypecheck (uncons' () :: ((), ()))

      it "head" $ do
        shouldNotTypecheck $ head ()

      it "tail" $ do
        shouldNotTypecheck $ tail ()

      it "init" $ do
        shouldNotTypecheck $ init ()

      it "last" $ do
        shouldNotTypecheck $ last ()

      it "cons" $ do
        shouldNotTypecheck (cons 'a' () :: ())

      it "uncons" $ do
        shouldNotTypecheck $ uncons ()

      it "Length" $ do
        (Proxy :: Proxy (Length ())) `shouldBe` (Proxy :: Proxy 0)

      it "length" $ do
        length () `shouldBe` (0 :: Int)

      it "Null" $ do
        case () of { Null -> True } `shouldBe` True

      describe "Cons'" $ do
        it "construct" $ do
          shouldNotTypecheck $ Cons' 'a' ()
        it "deconstruct" $ do
          shouldNotTypecheck $ case () of { Cons' _ _ -> () ; _ -> () }

      describe "Cons" $ do
        it "construct" $ do
          shouldNotTypecheck $ Cons 'a' ()
        it "deconstruct" $ do
          shouldNotTypecheck $ case () of { Cons _ _ -> () ; _ -> () }

      it "reverse'" $ do
        reverse' () `shouldBe` ()

      it "reverse" $ do
        reverse () `shouldBe` ()

      it "(!!!)" $ do
        shouldNotTypecheck (() !!! (Proxy :: Proxy 0) :: ())

      it "at'" $ do
        shouldNotTypecheck $ at' @() @0 @() ()

      it "(!!)" $ do
        shouldNotTypecheck $ () !! (Proxy :: Proxy 0)

      it "at" $ do
        shouldNotTypecheck $ at @() @0 ()

    describe "Proxy" $ do
      it "head'" $ do
        shouldNotTypecheck (head' (Proxy :: Proxy Int) :: ())

      -- When searching for "HasTail'" instance for "Proxy", "HasTail' (Proxy a) ()" is matched.
      -- But it is type error, because of "TypeError" constraint.
      -- However on deferred type error environent this does not throw type error,
      -- becouse the "tail'" implementation of "HasHead' (Proxy a) ()" does not call any "TypeError"'s functions.
      -- it "tail'" $ do
      --   shouldNotTypecheck (tail' (Proxy :: Proxy Int) :: ())

      -- The same to tail'.
      -- it "init'" $ do
      --   shouldNotTypecheck (init' (Proxy :: Proxy Int) :: ())

      it "last'" $ do
        shouldNotTypecheck (last' (Proxy :: Proxy Int) :: ())

      it "cons'" $ do
        let a = 0 :: Int
        shouldNotTypecheck (cons' a (Proxy :: Proxy Int) :: Proxy Int)

      it "uncons'" $ do
        shouldNotTypecheck (uncons' (Proxy :: Proxy Int) :: ((), ()))

      it "head" $ do
        shouldNotTypecheck $ head (Proxy :: Proxy Int)

      it "tail" $ do
        shouldNotTypecheck $ tail (Proxy :: Proxy Int)

      it "init" $ do
        shouldNotTypecheck $ init (Proxy :: Proxy Int)

      it "last" $ do
        shouldNotTypecheck $ last (Proxy :: Proxy Int)

      it "uncons" $ do
        shouldNotTypecheck $ uncons (Proxy :: Proxy Int)

      it "Length" $ do
        (Proxy :: Proxy (Length (Proxy ()))) `shouldBe` (Proxy :: Proxy 0)

      it "length" $ do
       length (Proxy :: Proxy Int) `shouldBe` (0 :: Int)

      it "Null" $ do
        case (Proxy :: Proxy Int) of { Null -> True } `shouldBe` True

      describe "Cons'" $ do
        it "construct" $ do
          shouldNotTypecheck $ Cons' 'a' ()
        it "deconstruct" $ do
          shouldNotTypecheck $ case (Proxy :: Proxy Int) of { Cons' _ _ -> () ; _ -> () }

      describe "Cons" $ do
        it "construct" $ do
          shouldNotTypecheck $ Cons 'a' ()
        it "deconstruct" $ do
          shouldNotTypecheck $ case (Proxy :: Proxy Int) of { Cons _ _ -> () ; _ -> () }

      it "reverse'" $ do
        reverse' (Proxy :: Proxy Int) `shouldBe` (Proxy :: Proxy Int)

      it "reverse" $ do
        reverse (Proxy :: Proxy Int) `shouldBe` (Proxy :: Proxy Int)

      it "(!!!)" $ do
        shouldNotTypecheck ((Proxy :: Proxy Int) !!! (Proxy :: Proxy 0) :: Int)

      it "at'" $ do
        shouldNotTypecheck $ at' @(Proxy Int) @0 @Int Proxy

      it "(!!)" $ do
        shouldNotTypecheck $ (Proxy :: Proxy Int) !! (Proxy :: Proxy 0)

      it "at" $ do
        shouldNotTypecheck $ at @(Proxy Int) @0 Proxy

  describe "2-tuple" $ do
    describe "Single" $ do
      it "head'" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        head' (a, b) `shouldBe` a

      it "tail'" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        shouldNotTypecheck $ tail' (a, b)

      it "init'" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        shouldNotTypecheck $ init' (a, b)

      it "last'" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        last' (a, b) `shouldBe` b

      it "head" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        head (a, b) `shouldBe` a

      it "tail" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        shouldNotTypecheck $ tail (a, b)

      it "init" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        shouldNotTypecheck $ init (a, b)

      it "last" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        last (a, b) `shouldBe` b

      it "cons" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        shouldNotTypecheck $ cons a (Single b)

      it "uncons" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        shouldNotTypecheck $ uncons (a, b)

      it "Length" $ do
        let
          target :: Length (Int, Int) ~ 2 => ()
          target = ()
        seq target $ pure () :: IO ()

      it "length" $ do
        length ((0, 1) :: (Int, Int)) `shouldBe` (2 :: Int)

      it "Null" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        shouldNotTypecheck $ case (a, b) of { Null -> () }

      describe "Cons'" $ do
        it "construct" $ do
          let
            a, b :: Int
            a = 0
            b = 1
          shouldNotTypecheck $ (Cons' a (Single b) :: (Int, Int))

        it "deconstruct" $ do
          let
            a, b :: Int
            a = 0
            b = 1
          shouldNotTypecheck $ case (a, b) of { Cons' _ (Single _) -> () }

      describe "Cons" $ do
        it "construct" $ do
          let
            a, b :: Int
            a = 0
            b = 1
          shouldNotTypecheck $ Cons a (Single b)

        it "deconstruct" $ do
          let
            a, b :: Int
            a = 0
            b = 1
          shouldNotTypecheck $ case (a, b) of { Cons _ (Single _) -> () }

      it "reverse'" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        reverse' (a, b) `shouldBe` (b, a)

      it "reverse" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        reverse (a, b) `shouldBe` (b, a)

      it "(!!!)" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        (a, b) !!! (Proxy :: Proxy 0) `shouldBe` a
        (a, b) !!! (Proxy :: Proxy 1) `shouldBe` b

      it "at'" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        at' @_ @0 @_ (a, b) `shouldBe` a
        at' @_ @1 @_ (a, b) `shouldBe` b

      it "(!!)" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        (a, b) !! (Proxy :: Proxy 0) `shouldBe` a
        (a, b) !! (Proxy :: Proxy 1) `shouldBe` b

      it "at" $ do
        let
          a, b :: Int
          a = 0
          b = 1
        at @_ @0 (a, b) `shouldBe` a
        at @_ @1 (a, b) `shouldBe` b

  describe "3-tuple" $ do
    it "head'" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      head' (a, b, c) `shouldBe` a

    it "tail'" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      tail' (a, b, c) `shouldBe` (b, c)

    it "init'" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      init' (a, b, c) `shouldBe` (a, b)

    it "last'" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      last' (a, b, c) `shouldBe` c

    it "cons'" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      cons' a (b, c) `shouldBe` (a, b, c)

    it "uncons'" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      uncons' (a, b, c) `shouldBe` (a, (b, c))

    it "head" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      head (a, b, c) `shouldBe` a

    it "tail" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      tail (a, b, c) `shouldBe` (b, c)

    it "init" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      init (a, b, c) `shouldBe` (a, b)

    it "last" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      last (a, b, c) `shouldBe` c

    it "cons" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      cons a (b, c) `shouldBe` (a, b, c)

    it "uncons" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      uncons (a, b, c) `shouldBe` (a, (b, c))

    it "Length" $ do
      let
        target :: Length (Int, Int, Int) ~ 3 => ()
        target = ()
      seq target $ pure () :: IO ()

    it "length" $ do
      length ((0, 1, 2) :: (Int, Int, Int)) `shouldBe` (3 :: Int)

    it "Null" $ do
      shouldNotTypecheck $ case (0, 1, 2) :: (Int, Int, Int) of { Null -> () }

    describe "Cons'" $ do
      it "construct" $ do
        let
          a, b, c :: Int
          a = 0
          b = 1
          c = 2
        Cons' a (b, c) `shouldBe` (a, b, c)

      it "deconstruct" $ do
        let
          a, b, c :: Int
          a = 0
          b = 1
          c = 2
        case (a, b, c) of { Cons' a' (b', c') -> (a, b, c) == (a', b', c') } `shouldBe` True

    describe "Cons" $ do
      it "construct" $ do
        let
          a, b, c :: Int
          a = 0
          b = 1
          c = 2
        Cons a (b, c) `shouldBe` (a, b, c)

      it "deconstruct" $ do
        let
          a, b, c :: Int
          a = 0
          b = 1
          c = 2
        case (a, b, c) of { Cons a' (b', c') -> (a, b, c) == (a', b', c') } `shouldBe` True

    it "reverse'" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      reverse' (a, b, c) `shouldBe` (c, b, a)

    it "reverse" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      reverse (a, b, c) `shouldBe` (c, b, a)

    it "(!!!)" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      (a, b, c) !!! (Proxy :: Proxy 0) `shouldBe` a
      (a, b, c) !!! (Proxy :: Proxy 1) `shouldBe` b
      (a, b, c) !!! (Proxy :: Proxy 2) `shouldBe` c

    it "at'" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      at' @_ @0 @_ (a, b, c) `shouldBe` a
      at' @_ @1 @_ (a, b, c) `shouldBe` b
      at' @_ @2 @_ (a, b, c) `shouldBe` c

    it "(!!)" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      (a, b, c) !! (Proxy :: Proxy 0) `shouldBe` a
      (a, b, c) !! (Proxy :: Proxy 1) `shouldBe` b
      (a, b, c) !! (Proxy :: Proxy 2) `shouldBe` c

    it "at" $ do
      let
        a, b, c :: Int
        a = 0
        b = 1
        c = 2
      at @_ @0 (a, b, c) `shouldBe` a
      at @_ @1 (a, b, c) `shouldBe` b
      at @_ @2 (a, b, c) `shouldBe` c