{-# LANGUAGE OverloadedStrings #-} module Main where import Data.Monoid ((<>)) import qualified Data.Text as T import Test.Tasty as T import Test.Tasty.QuickCheck as T -- For Arbitrary instance for Text import Data.Text.Arbitrary () import qualified Data.Text as Text import Data.Text.Markup arbitraryText :: Gen T.Text arbitraryText = T.pack <$> listOf (elements $ ' ':['a'..'z']<>['0'..'9']) propertyTests :: T.TestTree propertyTests = T.testGroup "Markup" -- Markup with no markings shall preserve the original text in one -- chunk. [ testProperty "no marking" $ property $ \t -> (fromMarkup $ toMarkup t ()) == [(t, ())] , testProperty "text preservation" $ property $ do txt <- arbitrary start <- arbitrary len <- arbitrary let m1 = markRegion start len 2 m0 m0 :: Markup Int m0 = toMarkup txt 1 return $ counterexample (show (txt, start, len, m1)) $ (Text.concat $ fst <$> fromMarkup m1) == txt -- A no-op marking on a valid range is ignored. , testProperty "no-op marking 1" $ property $ do txt <- arbitrary -- Generate a no-op edit: it starts and ends outside the text -- range. start <- arbitrary `suchThat` (\s -> (s < 0) || (s >= Text.length txt)) len <- arbitrary `suchThat` (\l -> (l >= 0)) return $ counterexample (show (txt, start, len)) $ let m1 = markRegion start len 1 m0 m0 :: Markup Int m0 = toMarkup txt 1 in m0 == m1 -- A marking that is outside the text range shall have no effect. , testProperty "no-op marking 2" $ property $ do txt <- arbitrary -- Generate a no-op edit: it starts and ends outside the text -- range. start <- arbitrary `suchThat` (\s -> (s < 0) || (s >= Text.length txt)) len <- arbitrary `suchThat` (\l -> (l >= 0) && ((start < 0 && start + l < 0) || (start >= Text.length txt))) return $ counterexample (show (txt, start, len)) $ let m1 = markRegion start len 2 m0 m0 :: Markup Int m0 = toMarkup txt 1 in m0 == m1 -- Adjancent markings are merged. , testProperty "merged marking" $ property $ do txt <- arbitrary -- Generate the first range... r1Start <- arbitrary `suchThat` (\s -> (s >= 0)) r1Len <- arbitrary `suchThat` (\l -> (l >= 0)) -- then an adjacent one. let r2Start = r1Start + r1Len r2Len <- arbitrary `suchThat` (\l -> (l >= 0)) let m1 = markRegion r1Start r1Len 2 m0 m2 = markRegion r2Start r2Len 2 m1 m0 :: Markup Int m0 = toMarkup txt 1 m3 = markRegion r1Start (r1Len + r2Len) 2 m0 return $ counterexample (show (txt, r1Start, r1Len, r2Len, fromMarkup m2, fromMarkup m3)) $ fromMarkup m2 == fromMarkup m3 -- Applying a small marking A followed by an enclosing marking B is -- equivalent to just applying B. , testProperty "containing marking" $ property $ do txt <- arbitraryText -- Generate the containing range... r1Start <- arbitrary `suchThat` (\s -> (s >= 0)) r1Len <- arbitrary `suchThat` (\l -> (l >= 3)) -- Then a contained one. let r2Start = r1Start + 1 r2Len = r1Len - 1 m0 :: Markup Int m0 = toMarkup txt 1 m1 = markRegion r2Start r2Len 2 m0 m2 = markRegion r1Start r1Len 3 m1 m3 = markRegion r1Start r1Len 3 m0 return $ counterexample (show (txt, (r1Start, r1Len), (r2Start, r2Len), fromMarkup m1, fromMarkup m2, fromMarkup m3)) $ fromMarkup m2 == fromMarkup m3 ] main :: IO () main = T.defaultMain propertyTests