module FuzzySearch (tests) where
import Data.Maybe (isJust, mapMaybe)
import Data.Text (Text)
import qualified Data.Text as Text
import Prelude hiding (filter)
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck
import Text.Fuzzy.Parallel
tests :: TestTree
tests =
testGroup
"Fuzzy search"
[ testGroup "match"
[ testCase "empty" $
match "" "" @?= Just 0
, testCase "camel case" $
match "myImportantField" "myImportantField" @?= Just 262124
, testCase "a" $
mapMaybe (matchInput "a") ["", "a", "aa", "aaa", "A", "AA", "aA", "Aa"]
@?= [("a",3),("aa",3),("aaa",3),("aA",3),("Aa",1)]
, testCase "lowercase words" $
mapMaybe (matchInput "abc") ["abc", "abcd", "axbc", "axbxc", "def"]
@?= [("abc", 25), ("abcd", 25), ("axbc", 7), ("axbxc", 5)]
, testCase "lower upper mix" $
mapMaybe (matchInput "abc") ["abc", "aBc", "axbC", "axBxC", "def"]
@?= [("abc", 25), ("aBc", 25), ("axbC", 7), ("axBxC", 5)]
, testCase "prefixes" $
mapMaybe (matchInput "alpha") (Text.inits "alphabet")
@?= [("alpha", 119), ("alphab", 119), ("alphabe", 119), ("alphabet", 119)]
, testProperty "x `isSubsequenceOf` y => match x y returns Just"
prop_matchIfSubsequence
]
]
where
matchInput :: Text -> Text -> Maybe (Text, Int)
matchInput needle candidate = (candidate,) <$> match needle candidate
prop_matchIfSubsequence :: Property
prop_matchIfSubsequence =
forAll genNonEmptyText $ \haystack ->
forAll (genSubsequence haystack) $ \needle ->
isJust (match needle haystack)
where
genNonEmptyText =
Text.pack <$> listOf1 (elements $ ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'])
genSubsequence :: Text -> Gen Text
genSubsequence =
fmap Text.pack . sublistOf . Text.unpack