packages feed

apply-merge-0.1.0.0: test/Test/Data/DoublyLinkedList/STRef.hs

-- SPDX-FileCopyrightText: Copyright Preetham Gujjula
-- SPDX-License-Identifier: BSD-3-Clause

module Test.Data.DoublyLinkedList.STRef (tests) where

import Control.Monad (void)
import Control.Monad.ST (runST)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT)
import Data.DoublyLinkedList.STRef
  ( cons,
    delete,
    empty,
    fromList,
    head,
    last,
    next,
    null,
    toList,
    value,
  )
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.ExpectedFailure (ignoreTest)
import Test.Tasty.HUnit (Assertion, assertBool, assertFailure, testCase, (@?=))
import Prelude hiding (head, last, null)

tests :: TestTree
tests =
  testGroup
    "Data.DoublyLinkedList.STRef"
    [ constructionTests,
      traversalTests,
      queryTests,
      insertionTests,
      deletionTests,
      listConversionTests,
      integrationTests
    ]

unimplemented :: Assertion
unimplemented = assertFailure "unimplemented"

-- Construction
constructionTests :: TestTree
constructionTests =
  testGroup
    "Construction"
    [ emptyTests,
      fromListTests
    ]

emptyTests :: TestTree
emptyTests = testCase "empty" (pure ())

fromListTests :: TestTree
fromListTests = testCase "fromList" (pure ())

-- Traversal
traversalTests :: TestTree
traversalTests =
  testGroup "Traversal" [headTests, lastTests, nextTests, prevTests]

headTests :: TestTree
headTests =
  testGroup
    "head"
    [ testCase "head of empty list" $ do
        -- Construct empty list using empty
        let firstNodeValue1 :: Maybe Int
            firstNodeValue1 = runST $ do
              list <- empty
              firstNode <- head list
              pure (value <$> firstNode)
        firstNodeValue1 @?= Nothing

        -- Construct empty list using fromList
        let firstNodeValue2 :: Maybe Int
            firstNodeValue2 = runST $ do
              list <- fromList []
              firstNode <- head list
              pure (value <$> firstNode)
        firstNodeValue2 @?= Nothing,
      testCase "head of non-empty lists" $ do
        let firstNodeValue1 :: Maybe Int
            firstNodeValue1 = runST $ do
              list <- fromList [1]
              firstNode <- head list
              pure (value <$> firstNode)
        firstNodeValue1 @?= Just 1
        let firstNodeValue2 :: Maybe Int
            firstNodeValue2 = runST $ do
              list <- fromList [2, 1]
              firstNode <- head list
              pure (value <$> firstNode)
        firstNodeValue2 @?= Just 2
        let firstNodeValue3 :: Maybe Int
            firstNodeValue3 = runST $ do
              list <- fromList [3, 2, 1]
              firstNode <- head list
              pure (value <$> firstNode)
        firstNodeValue3 @?= Just 3
    ]

lastTests :: TestTree
lastTests =
  testGroup
    "last"
    [ testCase "last of empty list" $ do
        -- Construct empty list using empty
        let lastNodeValue1 :: Maybe Int
            lastNodeValue1 = runST $ do
              list <- empty
              lastNode <- last list
              pure (value <$> lastNode)
        lastNodeValue1 @?= Nothing

        -- Construct empty list using fromList
        let lastNodeValue2 :: Maybe Int
            lastNodeValue2 = runST $ do
              list <- fromList []
              lastNode <- last list
              pure (value <$> lastNode)
        lastNodeValue2 @?= Nothing,
      testCase "last of non-empty lists" $ do
        let lastNodeValue1 :: Maybe Int
            lastNodeValue1 = runST $ do
              list <- fromList [1]
              lastNode <- last list
              pure (value <$> lastNode)
        lastNodeValue1 @?= Just 1
        let lastNodeValue2 :: Maybe Int
            lastNodeValue2 = runST $ do
              list <- fromList [1, 2]
              lastNode <- last list
              pure (value <$> lastNode)
        lastNodeValue2 @?= Just 2
        let lastNodeValue3 :: Maybe Int
            lastNodeValue3 = runST $ do
              list <- fromList [1, 2, 3]
              lastNode <- last list
              pure (value <$> lastNode)
        lastNodeValue3 @?= Just 3
    ]

nextTests :: TestTree
nextTests =
  ignoreTest $
    testGroup
      "next"
      [ testCase "next on empty list" unimplemented,
        testCase "next on [1]" unimplemented,
        testCase "next on [3, 2, 1]" unimplemented,
        testCase "next on [1, 1, 1, 1, 1]" unimplemented
      ]

prevTests :: TestTree
prevTests =
  ignoreTest $
    testGroup
      "prev"
      [ testCase "prev on empty list" unimplemented,
        testCase "prev on [1]" unimplemented,
        testCase "prev on [3, 2, 1]" unimplemented,
        testCase "prev on [1, 1, 1, 1, 1]" unimplemented
      ]

-- Query
queryTests :: TestTree
queryTests = testGroup "Query" [nullTests, valueTests]

nullTests :: TestTree
nullTests =
  testGroup
    "null"
    [ testCase "null of empty list" $ do
        -- Construct empty list using empty
        let isNull1 :: Bool
            isNull1 = runST (empty >>= null)
        assertBool "empty list is null" isNull1

        -- Construct empty list using fromList
        let isNull2 :: Bool
            isNull2 = runST (fromList [] >>= null)
        assertBool "empty list is null" isNull2,
      testCase "null of non-empty list" $ do
        let isNull1 :: Bool
            isNull1 = runST (fromList [1 :: Int] >>= null)
        assertBool "non-empty list is not null" (not isNull1)
        let isNull2 :: Bool
            isNull2 = runST (fromList [1 :: Int, 2] >>= null)
        assertBool "non-empty list is not null" (not isNull2)
        let isNull3 :: Bool
            isNull3 = runST (fromList [1 :: Int, 2, 3] >>= null)
        assertBool "non-empty list is not null" (not isNull3)
    ]

valueTests :: TestTree
valueTests = testCase "value" (pure ())

-- Insertion
insertionTests :: TestTree
insertionTests =
  testGroup
    "Insertion"
    [ consTests,
      snocTests,
      insertBeforeTests,
      insertAfterTests,
      insertBeforeAfterTests
    ]

consTests :: TestTree
consTests =
  testGroup
    "cons"
    [ testCase "Create [1] with cons" $
        let xs :: [Int]
            xs = runST $ do
              ys <- empty
              void (cons ys 1)
              toList ys
         in xs @?= [1],
      testCase "Create [1, 2] with cons" $
        let xs :: [Int]
            xs = runST $ do
              ys <- empty
              void (cons ys 2)
              void (cons ys 1)
              toList ys
         in xs @?= [1, 2],
      testCase "Create [1, 2, 3] with cons" $
        let xs :: [Int]
            xs = runST $ do
              ys <- empty
              void (cons ys 3)
              void (cons ys 2)
              void (cons ys 1)
              toList ys
         in xs @?= [1, 2, 3]
    ]

snocTests :: TestTree
snocTests =
  testGroup
    "snoc"
    [ ignoreTest $ testCase "Create [1] with snoc" unimplemented,
      ignoreTest $ testCase "Create [1, 2] with snoc" unimplemented,
      ignoreTest $ testCase "Create [1, 2, 3] with snoc" unimplemented
    ]

insertBeforeTests :: TestTree
insertBeforeTests =
  testGroup
    "insertBefore"
    [ ignoreTest $ testCase "Create [1, 0] with insertBefore" unimplemented,
      ignoreTest $ testCase "Create [1, 2, 0] with insertBefore" unimplemented,
      ignoreTest $
        testCase "Create [1, 2, 3, 0] with insertBefore" unimplemented
    ]

insertAfterTests :: TestTree
insertAfterTests =
  testGroup
    "insertAfter"
    [ ignoreTest $ testCase "Create [0, 1] with insertAfter" unimplemented,
      ignoreTest $ testCase "Create [0, 1, 2] with insertAfter" unimplemented,
      ignoreTest $ testCase "Create [0, 1, 2, 3] with insertAfter" unimplemented
    ]

insertBeforeAfterTests :: TestTree
insertBeforeAfterTests =
  testGroup
    "insertBefore and insertAfter"
    [ ignoreTest $
        testCase
          "Create [-1, 0, 1] with insertBefore and insertAfter"
          unimplemented,
      ignoreTest $
        testCase
          "Create [-2, -1, 0, 1, 2] with insertBefore and insertAfter"
          unimplemented,
      ignoreTest $
        testCase
          "Create [-3, -2, -1, 0, 1, 2, 3] with insertBefore and insertAfter"
          unimplemented
    ]

-- Deletion
deletionTests :: TestTree
deletionTests = testGroup "Deletion" [deleteTests]

deleteTests :: TestTree
deleteTests =
  testGroup
    "delete"
    [ testCase "Turn [-2, -1, 0, 1, 2] -> [-2, -1, 1, 2] using delete" $ do
        let xs :: Maybe [Int]
            xs = runST $ runMaybeT $ do
              dllist <- lift $ fromList [-2 .. 2]
              node1 <- MaybeT $ head dllist
              node2 <- MaybeT $ next node1
              node3 <- MaybeT $ next node2
              lift (delete node3)
              lift (toList dllist)
         in xs @?= Just [-2, -1, 1, 2],
      testCase "Turn [1, 2, 3, 4, 5, 6] -> [2, 4, 6] using delete" $
        let xs :: Maybe [Int]
            xs = runST $ runMaybeT $ do
              dlist <- lift $ fromList [1 .. 6]
              node1 <- MaybeT (head dlist)
              lift (delete node1)
              node2 <- MaybeT (next node1)
              node3 <- MaybeT (next node2)
              node4 <- MaybeT (next node3)
              lift (delete node3)
              node5 <- MaybeT (next node4)
              lift (delete node5)
              lift (toList dlist)
         in xs @?= Just [2, 4, 6]
    ]

-- List conversion
listConversionTests :: TestTree
listConversionTests = testGroup "List conversion" [toListTests]

toListTests :: TestTree
toListTests = testCase "toList" (pure ())

-- Integration
integrationTests :: TestTree
integrationTests = ignoreTest $ testCase "Integration" unimplemented