1
1
mirror of https://github.com/github/semantic.git synced 2024-11-28 18:23:44 +03:00
semantic/test/SplitSpec.hs

119 lines
6.2 KiB
Haskell
Raw Normal View History

module SplitSpec where
import Test.Hspec
import Split
import qualified Data.Set as Set
import Diff
import Range
import Test.Hspec.QuickCheck
import Test.QuickCheck hiding (Fixed)
import Control.Comonad.Cofree
import Control.Monad.Free hiding (unfold)
import qualified Data.Maybe as Maybe
2015-12-30 18:26:40 +03:00
import Data.Functor.Identity
2015-12-24 07:44:02 +03:00
import Source hiding ((++))
2015-12-23 01:22:07 +03:00
import Line
2015-12-23 01:24:58 +03:00
import Row
import Patch
import Syntax
import ArbitraryTerm
instance Arbitrary a => Arbitrary (Row a) where
arbitrary = oneof [
Row <$> arbitrary <*> arbitrary ]
instance Arbitrary a => Arbitrary (Line a) where
arbitrary = oneof [
makeLine <$> arbitrary,
const EmptyLine <$> (arbitrary :: Gen ()) ]
2015-12-24 06:18:01 +03:00
instance Arbitrary a => Arbitrary (Source a) where
2015-12-24 07:37:51 +03:00
arbitrary = fromList <$> arbitrary
2015-12-24 06:18:01 +03:00
arbitraryLeaf :: Gen (Source Char, Info, Syntax String f)
2015-12-22 21:38:44 +03:00
arbitraryLeaf = toTuple <$> arbitrary
where toTuple source = (source, Info (Range 0 $ length source) mempty, Leaf (toString source))
spec :: Spec
spec = do
describe "splitAnnotatedByLines" $ do
prop "outputs one row for single-line unchanged leaves" $
2015-12-22 22:44:57 +03:00
forAll (arbitraryLeaf `suchThat` isOnSingleLine) $
\ (source, info@(Info range categories), syntax) -> splitAnnotatedByLines (source, source) (range, range) (categories, categories) syntax `shouldBe` [
Row (makeLine [ Free $ Annotated info $ Leaf (toString source) ]) (makeLine [ Free $ Annotated info $ Leaf (toString source) ]) ]
prop "outputs one row for single-line empty unchanged indexed nodes" $
2015-12-24 07:36:49 +03:00
forAll (arbitrary `suchThat` (\ a -> filter (/= '\n') (toList a) == toList a)) $
2015-12-24 06:18:10 +03:00
\ source -> splitAnnotatedByLines (source, source) (getTotalRange source, getTotalRange source) (mempty, mempty) (Indexed [] :: Syntax String (Diff String Info)) `shouldBe` [
Row (makeLine [ Free $ Annotated (Info (getTotalRange source) mempty) $ Indexed [] ]) (makeLine [ Free $ Annotated (Info (getTotalRange source) mempty) $ Indexed [] ]) ]
prop "preserves line counts in equal sources" $
2015-12-22 23:55:59 +03:00
\ source ->
2015-12-24 07:26:37 +03:00
length (splitAnnotatedByLines (source, source) (getTotalRange source, getTotalRange source) (mempty, mempty) (Indexed . fst $ foldl combineIntoLeaves ([], 0) source)) `shouldBe` length (filter (== '\n') $ toList source) + 1
prop "produces the maximum line count in inequal sources" $
\ sourceA sourceB ->
2015-12-24 07:26:37 +03:00
length (splitAnnotatedByLines (sourceA, sourceB) (getTotalRange sourceA, getTotalRange sourceB) (mempty, mempty) (Indexed $ zipWith (leafWithRangesInSources sourceA sourceB) (actualLineRanges (getTotalRange sourceA) sourceA) (actualLineRanges (getTotalRange sourceB) sourceB))) `shouldBe` max (length (filter (== '\n') $ toList sourceA) + 1) (length (filter (== '\n') $ toList sourceB) + 1)
2015-12-21 20:57:50 +03:00
describe "adjoinRowsBy" $ do
prop "is identity on top of no rows" $
2015-12-23 01:06:51 +03:00
\ a -> adjoinRowsBy openMaybe openMaybe [] a == [ a ]
2015-12-18 21:04:52 +03:00
prop "appends onto open rows" $
forAll ((arbitrary `suchThat` isOpenBy openMaybe) >>= \ a -> (,) a <$> (arbitrary `suchThat` isOpenBy openMaybe)) $
\ (a@(Row a1 b1), b@(Row a2 b2)) ->
adjoinRowsBy openMaybe openMaybe [ a ] b `shouldBe` [ Row (makeLine $ unLine a1 ++ unLine a2) (makeLine $ unLine b1 ++ unLine b2) ]
prop "does not append onto closed rows" $
forAll ((arbitrary `suchThat` isClosedBy openMaybe) >>= \ a -> (,) a <$> (arbitrary `suchThat` isClosedBy openMaybe)) $
\ (a, b) -> adjoinRowsBy openMaybe openMaybe [ a ] b `shouldBe` [ b, a ]
prop "does not promote elements through empty lines onto closed lines" $
forAll ((arbitrary `suchThat` isClosedBy openMaybe) >>= \ a -> (,) a <$> (arbitrary `suchThat` isClosedBy openMaybe)) $
\ (a, b) -> adjoinRowsBy openMaybe openMaybe [ Row EmptyLine EmptyLine, a ] b `shouldBe` [ b, Row EmptyLine EmptyLine, a ]
2015-12-18 21:58:02 +03:00
prop "promotes elements through empty lines onto open lines" $
forAll ((arbitrary `suchThat` isOpenBy openMaybe) >>= \ a -> (,) a <$> (arbitrary `suchThat` isOpenBy openMaybe)) $
\ (a, b) -> adjoinRowsBy openMaybe openMaybe [ Row EmptyLine EmptyLine, a ] b `shouldBe` Row EmptyLine EmptyLine : adjoinRowsBy openMaybe openMaybe [ a ] b
2015-12-18 21:58:02 +03:00
describe "splitTermByLines" $ do
prop "preserves line count" $
2015-12-24 06:18:10 +03:00
\ source -> let range = getTotalRange source in
2015-12-30 18:28:40 +03:00
splitTermByLines (Info range mempty :< Leaf (toString source)) source `shouldBe` (pure . (:< Leaf (toString source)) . (`Info` mempty) <$> actualLineRanges range source, range)
2015-12-21 18:01:00 +03:00
describe "openLineBy" $ do
2015-12-22 04:23:56 +03:00
it "produces the earliest non-empty line in a list, if open" $
2015-12-24 07:37:51 +03:00
openLineBy (openTerm $ fromList "\n ") [
makeLine [ Info (Range 1 2) mempty :< Leaf "" ],
makeLine [ Info (Range 0 1) mempty :< Leaf "" ]
] `shouldBe` (Just $ makeLine [ Info (Range 1 2) mempty :< Leaf "" ])
2015-12-22 04:04:05 +03:00
2015-12-22 04:23:56 +03:00
it "returns Nothing if the earliest non-empty line is closed" $
2015-12-24 07:37:51 +03:00
openLineBy (openTerm $ fromList "\n") [
makeLine [ Info (Range 0 1) mempty :< Leaf "" ]
2015-12-22 04:04:05 +03:00
] `shouldBe` Nothing
describe "openTerm" $ do
it "returns Just the term if its substring does not end with a newline" $
2015-12-30 18:26:40 +03:00
let term = Info (Range 0 2) mempty :< Leaf "" in openTerm (fromList " ") (Identity term) `shouldBe` Just (Identity term)
2015-12-22 04:07:53 +03:00
it "returns Nothing for terms whose substring ends with a newline" $
2015-12-30 18:26:40 +03:00
openTerm (fromList " \n") (Identity $ Info (Range 0 2) mempty :< Leaf "") `shouldBe` Nothing
where
2015-12-23 00:55:18 +03:00
isOpenBy f (Row a b) = Maybe.isJust (openLineBy f [ a ]) && Maybe.isJust (openLineBy f [ b ])
2015-12-23 00:55:13 +03:00
isClosedBy f (Row a@(Line _) b@(Line _)) = Maybe.isNothing (openLineBy f [ a ]) && Maybe.isNothing (openLineBy f [ b ])
isClosedBy _ (Row _ _) = False
2015-12-24 07:36:49 +03:00
isOnSingleLine (a, _, _) = filter (/= '\n') (toList a) == toList a
2015-12-24 07:36:49 +03:00
getTotalRange (Source vector) = Range 0 $ length vector
combineIntoLeaves (leaves, start) char = (leaves ++ [ Free $ Annotated (Info (Range start $ start + 1) mempty, Info (Range start $ start + 1) mempty) (Leaf [ char ]) ], start + 1)
2015-12-24 07:26:37 +03:00
leafWithRangesInSources sourceA sourceB rangeA rangeB = Free $ Annotated (Info rangeA mempty, Info rangeB mempty) (Leaf $ toList sourceA ++ toList sourceB)
2015-12-23 00:52:20 +03:00
2015-12-30 18:27:45 +03:00
openMaybe :: Maybe a -> Maybe (Maybe a)
openMaybe (Just a) = Just (Just a)
2015-12-30 18:28:16 +03:00
openMaybe Nothing = Nothing