packages feed

text-rope-0.3: test/Utils.hs

-- |
-- Copyright:   (c) 2021-2022 Andrew Lelechenko
-- Licence:     BSD3
-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>

{-# OPTIONS_GHC -fno-warn-orphans #-}

module Utils
  ( utf8Length
  , utf16Length
  ) where

import Prelude (mod, (+), (-), maxBound)
import Control.Applicative (pure, (<$>), (<*>))
import Data.Char (Char)
import Data.Function (($), (.))
import qualified Data.List as L
import Data.Ord ((>), (>=))
import qualified Data.Text as T
import Data.Text.Internal (Text(..))
import qualified Data.Text.Lines as Char
import qualified Data.Text.Rope as CharRope
import qualified Data.Text.Utf8.Lines as Utf8
import qualified Data.Text.Utf8.Rope as Utf8Rope
import qualified Data.Text.Utf16.Lines as Utf16
import qualified Data.Text.Utf16.Rope as Utf16Rope
import qualified Data.Text.Utf16.Rope.Mixed as MixedRope
import Data.Word (Word)
import Test.Tasty.QuickCheck (Gen, Arbitrary (arbitrary), arbitrary, shrink, frequency, arbitraryASCIIChar, arbitraryUnicodeChar, listOf, oneof)
import Data.Monoid (mconcat, mappend)
import Data.Bool (otherwise)
import Data.Maybe (maybe)

utf8Length :: Text -> Word
utf8Length t =
  L.genericLength xs +
  L.genericLength (L.filter (>= '\x0080') xs) +
  L.genericLength (L.filter (>= '\x0800') xs) +
  L.genericLength (L.filter (>= '\x10000') xs)
  where
    xs = T.unpack t

utf16Length :: Text -> Word
utf16Length t = L.genericLength xs + L.genericLength (L.filter (> '\xFFFF') xs)
  where
    xs = T.unpack t

charGen :: Gen Char
charGen = frequency
  [ (1, pure '\n')
  , (1, arbitraryASCIIChar)
  , (1, arbitraryUnicodeChar)
  ]

instance Arbitrary Text where
  arbitrary = do
    xs <- T.pack <$> listOf charGen
    d <- (`mod` (T.length xs + 1)) <$> arbitrary
    pure $ T.drop d xs
  shrink t@(Text arr off len)
    =    L.map (T.drop d . T.pack) (shrink ys)
    L.++ L.map (\d' -> T.drop d' $ T.pack $ L.drop (d - d') ys) (shrink d)
    where
      xs = T.unpack t
      ys = T.unpack (Text arr 0 (off + len))
      d  = L.length ys - L.length xs

instance Arbitrary Char.TextLines where
  arbitrary = Char.fromText <$> arbitrary
  shrink = L.map Char.fromText . shrink . Char.toText

instance Arbitrary Char.Position where
  arbitrary = oneof
    [ Char.Position <$> arbitrary <*> arbitrary
    , (\l -> Char.Position (maxBound - l)) <$> arbitrary <*> arbitrary
    , (\l c -> Char.Position l (maxBound - c)) <$> arbitrary <*> arbitrary
    , (\l c -> Char.Position (maxBound - l) (maxBound - c)) <$> arbitrary <*> arbitrary
    ]
  shrink (Char.Position x y) =
    [Char.Position x' y | x' <- shrink x] L.++ [Char.Position x y' | y' <- shrink y]

instance Arbitrary Utf8.Position where
  arbitrary = oneof
    [ Utf8.Position <$> arbitrary <*> arbitrary
    , (\l -> Utf8.Position (maxBound - l)) <$> arbitrary <*> arbitrary
    , (\l c -> Utf8.Position l (maxBound - c)) <$> arbitrary <*> arbitrary
    , (\l c -> Utf8.Position (maxBound - l) (maxBound - c)) <$> arbitrary <*> arbitrary
    ]
  shrink (Utf8.Position x y) =
    [Utf8.Position x' y | x' <- shrink x] L.++ [Utf8.Position x y' | y' <- shrink y]

instance Arbitrary Utf16.Position where
  arbitrary = oneof
    [ Utf16.Position <$> arbitrary <*> arbitrary
    , (\l -> Utf16.Position (maxBound - l)) <$> arbitrary <*> arbitrary
    , (\l c -> Utf16.Position l (maxBound - c)) <$> arbitrary <*> arbitrary
    , (\l c -> Utf16.Position (maxBound - l) (maxBound - c)) <$> arbitrary <*> arbitrary
    ]
  shrink (Utf16.Position x y) =
    [Utf16.Position x' y | x' <- shrink x] L.++ [Utf16.Position x y' | y' <- shrink y]

instance Arbitrary CharRope.Rope where
  arbitrary = frequency
    [ (9, mconcat . L.map CharRope.fromText <$> arbitrary)
    , (1, mappend <$> arbitrary <*> arbitrary)
    ]
  shrink rp
    | CharRope.null rp = []
    | otherwise = L.concatMap (\i -> (\(x, y) -> [x, y]) (CharRope.splitAt i rp))
                  [1..CharRope.length rp - 1]

instance Arbitrary Utf8Rope.Rope where
  arbitrary = frequency
    [ (9, mconcat . L.map Utf8Rope.fromText <$> arbitrary)
    , (1, mappend <$> arbitrary <*> arbitrary)
    ]
  shrink rp
    | Utf8Rope.null rp = []
    | otherwise = L.concatMap (\i -> maybe [] (\(x, y) -> [x, y]) (Utf8Rope.splitAt i rp))
                  [1..Utf8Rope.length rp - 1]

instance Arbitrary Utf16Rope.Rope where
  arbitrary = frequency
    [ (9, mconcat . L.map Utf16Rope.fromText <$> arbitrary)
    , (1, mappend <$> arbitrary <*> arbitrary)
    ]
  shrink rp
    | Utf16Rope.null rp = []
    | otherwise = L.concatMap (\i -> maybe [] (\(x, y) -> [x, y]) (Utf16Rope.splitAt i rp))
                  [1..Utf16Rope.length rp - 1]

instance Arbitrary MixedRope.Rope where
  arbitrary = frequency
    [ (9, mconcat . L.map MixedRope.fromText <$> arbitrary)
    , (1, mappend <$> arbitrary <*> arbitrary)
    ]
  shrink rp
    | MixedRope.null rp = []
    | otherwise = L.concatMap (\i -> (\(x, y) -> [x, y]) (MixedRope.charSplitAt i rp))
                  [1..MixedRope.charLength rp - 1]