From 2004e3c87b6b1e486d83fefb6d187039ad461093 Mon Sep 17 00:00:00 2001
From: Matthew Craven <5086-clyring@users.noreply.gitlab.haskell.org>
Date: Thu, 2 Jun 2022 19:24:00 -0400
Subject: [PATCH] Add a basic test for ByteArray's Monoid instance

---
 testsuite/tests/lib/base/Monoid_ByteArray.hs | 83 ++++++++++++++++++++
 testsuite/tests/lib/base/all.T               |  1 +
 2 files changed, 84 insertions(+)
 create mode 100644 testsuite/tests/lib/base/Monoid_ByteArray.hs

diff --git a/testsuite/tests/lib/base/Monoid_ByteArray.hs b/testsuite/tests/lib/base/Monoid_ByteArray.hs
new file mode 100644
index 000000000000..0fe9e91a8bd3
--- /dev/null
+++ b/testsuite/tests/lib/base/Monoid_ByteArray.hs
@@ -0,0 +1,83 @@
+{-# LANGUAGE DerivingVia, TypeApplications, OverloadedLists #-}
+
+module Main where
+
+import Control.Exception
+import Control.Monad
+import Data.Array.Byte
+import Data.Bits
+import Data.Either
+import Data.List (tails)
+import Data.Ord
+import Data.Semigroup
+import GHC.Exts (IsList(..))
+
+
+newtype Tricky = Tricky Int
+  deriving (Eq, Num, Real, Enum, Integral) via Int
+  deriving Ord via Down Int
+
+smallArrs :: [ByteArray]
+-- 40 arrays, of total length 600
+smallArrs = [[], [3,8,1], [0], [255], [1,6,1,8,2]] ++
+  map fromList (replicate 29 0 : tails [0..32])
+
+shouldError :: a -> IO () -> IO ()
+shouldError val ifNoError = do
+  res <- try @ErrorCall (evaluate val)
+  when (isRight res) ifNoError
+
+testConcat :: [ByteArray] -> IO ()
+testConcat arrs = do
+  let lis = map toList arrs
+      expected = mconcat lis
+      actual = toList (mconcat arrs)
+  when (expected /= actual) $
+    putStrLn $ unwords ["mconcat", show lis, "/=", show actual]
+
+main :: IO ()
+main = do
+  when (toList @ByteArray mempty /= []) $
+    putStrLn "mempty /= []"
+
+  -- test <>
+  forM_ smallArrs $ \x -> do
+    let xli = toList x
+    forM_ smallArrs $ \y -> do
+      let yli = toList y
+          expected = xli <> yli
+          actual   = toList (x <> y)
+      when (expected /= actual) $
+        putStrLn $ unwords [show xli, "<>", show yli, "/=", show actual]
+
+  -- test stimes
+  forM_ smallArrs $ \x -> do
+    let xli = toList x
+    shouldError (stimes (-1 :: Integer) x) $
+      putStrLn $ unwords ["stimes (-1 :: Integer)", show xli, "didn't fail??"]
+    shouldError (stimes (-1 :: Tricky) x) $
+      putStrLn $ unwords ["stimes (-1 :: Tricky)",  show xli, "didn't fail??"]
+    when (length xli > 1) $ shouldError (stimes (maxBound @Int) x) $
+      putStrLn $ unwords ["stimes (maxBound @Int)", show xli, "didn't fail??"]
+    forM_ (10000 : [0 :: Int .. 32]) $ \n -> do
+      let expected = stimes n xli
+          actual   = toList (stimes n x)
+      when (expected /= actual) $
+        putStrLn $ unwords ["stimes", show n, show xli, "/=", show actual]
+  evaluate $ stimes @ByteArray @Int maxBound []
+  evaluate $ stimes @ByteArray @Integer (10^100) []
+
+  -- test mconcat
+  testConcat []
+  forM_ smallArrs $ \x -> do
+    testConcat [x]
+    forM_ smallArrs $ \y -> do
+      testConcat [x, y]
+      forM_ smallArrs $ \z -> do -- OK, 40^3 = 64K
+        testConcat [x, y, z]
+
+  -- test mconcat's overflow-handling
+  let  bigArr = stimes (bit 18 :: Int) [0] :: ByteArray
+  when (finiteBitSize @Int 0 == 32) $
+    shouldError (mconcat $ replicate (bit 14) bigArr) $
+      putStrLn "Impossible mconcat succeeded???"
diff --git a/testsuite/tests/lib/base/all.T b/testsuite/tests/lib/base/all.T
index 18c3f5814f93..5e3cf28f686b 100644
--- a/testsuite/tests/lib/base/all.T
+++ b/testsuite/tests/lib/base/all.T
@@ -7,3 +7,4 @@ test('T19691', normal, compile, [''])
 test('executablePath', extra_run_opts(config.os), compile_and_run, [''])
 test('T17472', normal, compile_and_run, [''])
 test('T19569b', normal, compile_and_run, [''])
+test('Monoid_ByteArray', normal, compile_and_run, [''])
-- 
GitLab