diff --git a/flake.nix b/flake.nix index a676f27..9938e84 100644 --- a/flake.nix +++ b/flake.nix @@ -67,6 +67,7 @@ nixfmt hpack hlint + haskellPackages.doctest ]; inputsFrom = builtins.attrValues self.packages.${system}; }; diff --git a/src/HCat/Internal.hs b/src/HCat/Internal.hs index 4661a89..c0ec415 100644 --- a/src/HCat/Internal.hs +++ b/src/HCat/Internal.hs @@ -1,8 +1,30 @@ -- | Internal module in order to facilitate testability. module HCat.Internal where +-- | @parseArgs@ takes a list of strings and returns a single FilePath if there was exactly one element. +-- +-- >>> parseArgs ["foo"] +-- Right "foo" parseArgs :: [String] -> Either String FilePath parseArgs args = case args of [] -> Left "No filename given!" [arg] -> Right arg _ -> Left "Only a single file is supported" + +-- | @chunksOf n@ splits a list into chunks of at most @n@ items. +-- +-- >>> chunksOf 3 "abcdefgh" +-- ["abc","def","gh"] +-- +-- >>> chunksOf 0 "abcdefgh" +-- [] +-- +-- >>> chunksOf (-1) "abcdefgh" +-- [] +chunksOf :: Int -> [a] -> [[a]] +chunksOf _ [] = [] +chunksOf n xs@(_ : _) + | n <= 0 = [] + | otherwise = + let (chunk, rest) = splitAt n xs + in chunk : chunksOf n rest diff --git a/test/HCatSpec.hs b/test/HCatSpec.hs index 82f487b..6862706 100644 --- a/test/HCatSpec.hs +++ b/test/HCatSpec.hs @@ -2,9 +2,11 @@ module HCatSpec (spec) where -import HCat.Internal (parseArgs) +import HCat.Internal (chunksOf, parseArgs) import Test.Hspec +import Test.Hspec.QuickCheck (prop) +import Test.QuickCheck (Positive (getPositive)) spec :: Spec spec = do @@ -13,3 +15,13 @@ spec = do parseArgs ["foo"] `shouldBe` Right "foo" parseArgs [] `shouldBe` Left "No filename given!" parseArgs ["foo", "bar"] `shouldBe` Left "Only a single file is supported" + describe "chunksOf" $ do + prop "each chunk contains at most N items" $ \n xs -> + let chunkLengths = length <$> chunksOf n (xs :: [Int]) + in case chunkLengths of + [] -> pure () + ns -> maximum ns `shouldSatisfy` (<= n) + + prop "the sum of all lengths is equal to the length of the input" $ \n xs -> + let chunkLengths = length <$> chunksOf (getPositive n) (xs :: [Int]) + in sum chunkLengths `shouldBe` length xs