Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit 02b36d2

Browse files
author
Patrick Thomson
committed
Port Leancheck+Hspec properties to Tasty.Hedgehog.
1 parent e1d94f0 commit 02b36d2

File tree

1 file changed

+67
-69
lines changed

1 file changed

+67
-69
lines changed

test/Data/Source/Spec.hs

Lines changed: 67 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,90 @@
11
{-# LANGUAGE NamedFieldPuns #-}
22
module Data.Source.Spec (spec, testTree) where
33

4-
import Data.Char (chr)
54
import Data.Range
65
import Data.Source
76
import Data.Span
87
import qualified Data.Text as Text
98

10-
import Data.Functor.Listable
119
import Test.Hspec
12-
import Test.Hspec.LeanCheck
13-
import Test.LeanCheck
1410

15-
-- This file deals with Range values, which is unfortunate because
16-
-- Hedgehog has its own Range type. We solve this by importing
17-
-- everything qualified.
1811
import qualified Generators as Gen
12+
import qualified Hedgehog.Gen as Gen
1913
import Hedgehog ((===))
2014
import qualified Hedgehog.Range
21-
import qualified Hedgehog
15+
import Hedgehog hiding (Range)
2216
import qualified Test.Tasty as Tasty
23-
import qualified Test.Tasty.Hedgehog as Tasty
17+
import Test.Tasty.Hedgehog (testProperty)
18+
19+
prop :: HasCallStack => String -> (Source -> PropertyT IO ()) -> Tasty.TestTree
20+
prop desc f
21+
= testProperty desc
22+
. property
23+
$ forAll (Gen.source (Hedgehog.Range.linear 0 100))
24+
>>= f
2425

2526
testTree :: Tasty.TestTree
26-
testTree = Tasty.testGroup "Data.Source.spanToRange"
27-
[ Tasty.testProperty "computes single-line ranges" prop_computes_single_line_ranges
28-
]
27+
testTree = Tasty.testGroup "Data.Source"
28+
[ Tasty.testGroup "sourceLineRanges"
29+
[ prop "produces 1 more range than there are newlines" $
30+
\ source -> length (sourceLineRanges source) === succ (Text.count "\n" (toText source))
31+
32+
, prop "produces exhaustive ranges" $
33+
\ source -> foldMap (`slice` source) (sourceLineRanges source) === source
34+
]
35+
36+
, Tasty.testGroup "spanToRange"
37+
[ prop "computes single-line ranges" $ \ source -> do
38+
let ranges = sourceLineRanges source
39+
let spans = zipWith (\ i Range {..} -> Span (Pos i 1) (Pos i (succ (end - start)))) [1..] ranges
40+
fmap (spanToRange source) spans === ranges
41+
42+
, prop "computes multi-line ranges" $
43+
\ source ->
44+
spanToRange source (totalSpan source) === totalRange source
45+
46+
, prop "computes sub-line ranges" $
47+
\ s -> let source = "*" <> s <> "*" in
48+
spanToRange source (insetSpan (totalSpan source)) === insetRange (totalRange source)
49+
50+
, testProperty "inverse of rangeToSpan" . property $ do
51+
a <- forAll . Gen.source $ Hedgehog.Range.linear 0 100
52+
b <- forAll . Gen.source $ Hedgehog.Range.linear 0 100
53+
let s = a <> "\n" <> b in spanToRange s (totalSpan s) === totalRange s
54+
]
55+
56+
, testProperty "rangeToSpan inverse of spanToRange" . property $ do
57+
a <- forAll . Gen.source $ Hedgehog.Range.linear 0 100
58+
b <- forAll . Gen.source $ Hedgehog.Range.linear 0 100
59+
let s = a <> "\n" <> b in rangeToSpan s (totalRange s) === totalSpan s
60+
61+
, Tasty.testGroup "totalSpan"
62+
[ testProperty "covers single lines" . property $ do
63+
n <- forAll $ Gen.int (Hedgehog.Range.linear 0 100)
64+
totalSpan (fromText (Text.replicate n "*")) === Span (Pos 1 1) (Pos 1 (max 1 (succ n)))
65+
66+
, testProperty "covers multiple lines" . property $ do
67+
n <- forAll $ Gen.int (Hedgehog.Range.linear 0 100)
68+
totalSpan (fromText (Text.intersperse '\n' (Text.replicate n "*"))) === Span (Pos 1 1) (Pos (max 1 n) (if n > 0 then 2 else 1))
69+
]
2970

30-
prop_computes_single_line_ranges = Hedgehog.property $ do
31-
source <- Hedgehog.forAll . Gen.source $ Hedgehog.Range.linear 0 100
32-
let ranges = sourceLineRanges source
33-
spanFromRangeWithIndex i Range{start, end} = Span (Pos i 1) (Pos i (end - start + 1))
34-
spans = zipWith spanFromRangeWithIndex [1..] ranges
35-
fmap (spanToRange source) spans === ranges
71+
]
3672

3773
spec :: Spec
3874
spec = parallel $ do
39-
describe "sourceLineRanges" $ pure ()
40-
-- prop "produces 1 more range than there are newlines" $
41-
-- \ source -> length (sourceLineRanges source) `shouldBe` succ (Text.count "\n" (toText source))
42-
43-
-- prop "produces exhaustive ranges" $
44-
-- \ source -> foldMap (`slice` source) (sourceLineRanges source) `shouldBe` source
45-
46-
-- describe "spanToRange" $ do
47-
48-
-- prop "computes multi-line ranges" $
49-
-- \ source ->
50-
-- spanToRange source (totalSpan source) `shouldBe` totalRange source
51-
52-
-- prop "computes sub-line ranges" $
53-
-- \ s -> let source = "*" <> s <> "*" in
54-
-- spanToRange source (insetSpan (totalSpan source)) `shouldBe` insetRange (totalRange source)
55-
56-
-- prop "inverse of rangeToSpan" $
57-
-- \ a b -> let s = a <> "\n" <> b in spanToRange s (totalSpan s) `shouldBe` totalRange s
58-
59-
-- describe "rangeToSpan" $ do
60-
-- prop "inverse of spanToRange" $
61-
-- \ a b -> let s = a <> "\n" <> b in rangeToSpan s (totalRange s) `shouldBe` totalSpan s
62-
63-
-- describe "totalSpan" $ do
64-
-- prop "covers single lines" $
65-
-- \ n -> totalSpan (fromText (Text.replicate n "*")) `shouldBe` Span (Pos 1 1) (Pos 1 (max 1 (succ n)))
66-
67-
-- prop "covers multiple lines" $
68-
-- \ n -> totalSpan (fromText (Text.intersperse '\n' (Text.replicate n "*"))) `shouldBe` Span (Pos 1 1) (Pos (max 1 n) (if n > 0 then 2 else 1))
69-
70-
-- describe "newlineIndices" $ do
71-
-- it "finds \\n" $
72-
-- let source = "a\nb" in
73-
-- newlineIndices source `shouldBe` [1]
74-
-- it "finds \\r" $
75-
-- let source = "a\rb" in
76-
-- newlineIndices source `shouldBe` [1]
77-
-- it "finds \\r\\n" $
78-
-- let source = "a\r\nb" in
79-
-- newlineIndices source `shouldBe` [2]
80-
-- it "finds intermixed line endings" $
81-
-- let source = "hi\r}\r}\n xxx \r a" in
82-
-- newlineIndices source `shouldBe` [2, 4, 6, 12]
83-
84-
-- prop "preserves characters" . forAll (toTiers (list +| [chr 0xa0..chr 0x24f])) $
85-
-- \ c -> Text.unpack (toText (fromText (Text.singleton c))) `shouldBe` [c]
86-
87-
-- prop "preserves strings" $
88-
-- \ s -> fromText (toText s) `shouldBe` s
89-
75+
describe "newlineIndices" $ do
76+
it "finds \\n" $
77+
let source = "a\nb" in
78+
newlineIndices source `shouldBe` [1]
79+
it "finds \\r" $
80+
let source = "a\rb" in
81+
newlineIndices source `shouldBe` [1]
82+
it "finds \\r\\n" $
83+
let source = "a\r\nb" in
84+
newlineIndices source `shouldBe` [2]
85+
it "finds intermixed line endings" $
86+
let source = "hi\r}\r}\n xxx \r a" in
87+
newlineIndices source `shouldBe` [2, 4, 6, 12]
9088

9189
insetSpan :: Span -> Span
9290
insetSpan sourceSpan = sourceSpan { spanStart = (spanStart sourceSpan) { posColumn = succ (posColumn (spanStart sourceSpan)) }

0 commit comments

Comments
 (0)