packages feed

nri-prelude-0.7.0.0: tests/ArraySpec.hs

module ArraySpec (tests) where

import Array
import qualified Expect
import qualified Fuzz
import qualified List
import NriPrelude hiding (map)
import Test (Test, describe, fuzz, fuzz2, test)

tests :: Test
tests =
  describe
    "Array tests"
    [ initTests,
      isEmptyTests,
      lengthTests,
      getSetTests,
      conversionTests,
      transformTests,
      sliceTests
    ]

limit :: Int
limit = 10000

size :: Fuzz.Fuzzer Int
size = Fuzz.intRange 1 limit

toLimit :: Int -> Fuzz.Fuzzer Int
toLimit x = Fuzz.intRange x limit

initTests :: Test
initTests =
  describe
    "Initialization"
    [ fuzz size "initialize" <| \size_ ->
        initialize size_ identity
          |> toList
          |> Expect.equal (List.range 0 (size_ - 1)),
      fuzz size "push" <| \size_ ->
        size_
          - 1
          |> List.range 0
          |> List.foldl push empty
          |> Expect.equal (initialize size_ identity),
      test "initialize non-identity" <| \() ->
        initialize 4 (\n -> n * n)
          |> toList
          |> Expect.equal
            [0, 1, 4, 9],
      test "initialize empty" <| \() ->
        initialize 0 identity
          |> toList
          |> Expect.equal [],
      test "initialize negative" <| \() ->
        initialize (-2) identity
          |> toList
          |> Expect.equal []
    ]

isEmptyTests :: Test
isEmptyTests =
  describe
    "isEmpty"
    [ test "all empty arrays are equal" <| \() ->
        empty
          |> Expect.equal
            (fromList [] :: Array ()),
      test "empty array" <| \() ->
        isEmpty empty
          |> Expect.equal True,
      test "empty converted array" <| \() ->
        isEmpty (fromList [])
          |> Expect.equal True,
      test "non-empty array" <| \() ->
        isEmpty (fromList [1 :: Int])
          |> Expect.equal False
    ]

lengthTests :: Test
lengthTests =
  describe
    "Length"
    [ test "empty array" <| \() ->
        Expect.equal (length empty) 0,
      fuzz size "non-empty array" <| \size_ ->
        initialize size_ identity
          |> length
          |> Expect.equal size_,
      fuzz size "push" <| \size_ ->
        initialize size_ identity
          |> push size_
          |> length
          |> Expect.equal (size_ + 1),
      fuzz size "append" <| \size_ ->
        initialize (size_ // 2) identity
          |> append (initialize size_ identity)
          |> length
          |> Expect.equal (size_ + (size_ // 2)),
      fuzz size "set does not increase" <| \size_ ->
        initialize size_ identity
          |> set (size_ // 2) 1
          |> length
          |> Expect.equal size_,
      fuzz (toLimit 100) "big slice" <| \size_ ->
        initialize size_ identity
          |> slice 35 (-35)
          |> length
          |> Expect.equal (size_ - 70),
      fuzz2
        (Fuzz.intRange (-32) (-1))
        (toLimit 100)
        "small slice end"
        <| \n size_ ->
          initialize size_ identity
            |> slice 0 n
            |> length
            |> Expect.equal (size_ + n)
    ]

getSetTests :: Test
getSetTests =
  describe
    "Get and set"
    [ fuzz2 size size "can retrieve element" <| \x y ->
        let n = min x y
            size_ = max x y
         in get n (initialize (size_ + 1) identity)
              |> Expect.equal (Just n),
      fuzz2
        (Fuzz.intRange 1 50)
        (toLimit 100)
        "out of bounds retrieval returns nothing"
        <| \n size_ ->
          let arr = initialize size_ identity
           in Expect.all
                [ \() -> Expect.equal (get (negate n) arr) Nothing,
                  \() -> Expect.equal (get (size_ + n) arr) Nothing
                ]
                (),
      fuzz2 size size "set replaces value" <| \x y ->
        let n = min x y
            size_ = max x y
         in initialize (size_ + 1) identity
              |> set n 5
              |> get n
              |> Expect.equal (Just 5),
      fuzz2
        (Fuzz.intRange 1 50)
        size
        "set out of bounds returns original array"
        <| \n size_ ->
          let arr = initialize size_ identity
           in set (negate n) 5 arr
                |> set (size_ + n) 5
                |> Expect.equal arr,
      test "Retrieval works from tail" <| \() ->
        initialize 1035 identity
          |> set 1030 5
          |> get 1030
          |> Expect.equal (Just 5)
    ]

conversionTests :: Test
conversionTests =
  describe
    "Conversion"
    [ fuzz size "back and forth" <| \size_ ->
        let ls = List.range 0 (size_ - 1)
         in fromList ls
              |> toList
              |> Expect.equal ls,
      fuzz size "indexed" <| \size_ ->
        initialize size_ (1 +)
          |> toIndexedList
          |> Expect.equal
            ( toList
                ( initialize
                    size_
                    (\idx -> (idx, idx + 1))
                )
            )
    ]

transformTests :: Test
transformTests =
  describe
    "Transform"
    [ fuzz size "foldl" <| \size_ ->
        initialize size_ identity
          |> foldl (:) []
          |> Expect.equal
            ( List.reverse (List.range 0 (size_ - 1))
            ),
      fuzz size "foldr" <| \size_ ->
        initialize size_ identity
          |> foldr (:) []
          |> Expect.equal (List.range 0 (size_ - 1)),
      fuzz size "filter" <| \size_ ->
        initialize size_ identity
          |> filter (\a -> modBy 2 a == 0)
          |> toList
          |> Expect.equal
            ( List.filter
                (\a -> modBy 2 a == 0)
                (List.range 0 (size_ - 1))
            ),
      fuzz size "map" <| \size_ ->
        initialize size_ identity
          |> map (1 +)
          |> Expect.equal (initialize size_ (1 +)),
      fuzz size "indexedMap" <| \size_ ->
        repeat size_ 5
          |> indexedMap (*)
          |> Expect.equal (initialize size_ (5 *)),
      fuzz size "push appends one element" <| \size_ ->
        initialize size_ identity
          |> push size_
          |> Expect.equal (initialize (size_ + 1) identity),
      fuzz (Fuzz.intRange 1 1050) "append" <| \size_ ->
        initialize size_ (size_ +)
          |> append (initialize size_ identity)
          |> Expect.equal (initialize (size_ * 2) identity),
      fuzz2 size (Fuzz.intRange 1 32) "small appends" <| \s1 s2 ->
        initialize s2 (s1 +)
          |> append (initialize s1 identity)
          |> Expect.equal (initialize (s1 + s2) identity)
    ]

sliceTests :: Test
sliceTests =
  let smallSample = fromList (List.range 1 8)
   in describe
        "Slice"
        [ fuzz2 (Fuzz.intRange (-50) (-1)) (toLimit 100) "both" <| \n size_ ->
            initialize size_ identity
              |> slice (abs n) n
              |> Expect.equal
                ( initialize
                    (size_ + n + n)
                    (\idx -> idx - n)
                ),
          fuzz2 (Fuzz.intRange (-50) (-1)) (toLimit 100) "left" <| \n size_ ->
            let arr = initialize size_ identity
             in slice (abs n) (length arr) arr
                  |> Expect.equal
                    ( initialize (size_ + n) (\idx -> idx - n)
                    ),
          fuzz2 (Fuzz.intRange (-50) (-1)) (toLimit 100) "right" <| \n size_ ->
            initialize size_ identity
              |> slice 0 n
              |> Expect.equal (initialize (size_ + n) identity),
          fuzz size "slicing all but the last item" <| \size_ ->
            initialize size_ identity
              |> slice (-1) size_
              |> toList
              |> Expect.equal [size_ - 1],
          test "both small" <| \() ->
            slice 2 5 smallSample
              |> toList
              |> Expect.equal (List.range 3 5),
          test "start small" <| \() ->
            slice 2 (length smallSample) smallSample
              |> toList
              |> Expect.equal (List.range 3 8),
          test "negative" <| \() ->
            slice (-5) (-2) smallSample
              |> toList
              |> Expect.equal (List.range 4 6),
          test "impossible" <| \() ->
            slice (-1) (-2) smallSample
              |> toList
              |> Expect.equal [],
          test "crash" <| \() ->
            repeat (33 * 32) 1
              |> slice 0 1
              |> Expect.equal (repeat 1 1 :: Array Int)
        ]