packages feed

dawgdic-1.0.0: test/Data/DAWG/CompleterSpec.hs

{-# LANGUAGE BlockArguments #-}
module Data.DAWG.CompleterSpec where

import Data.DAWG.Internal.BaseType

import Data.DAWG.Completer (keyToString, start, next)

import qualified Data.DAWG.Completer as C
import qualified Data.DAWG.Guide as G
import qualified Data.DAWG.DAWG as DAWG
import qualified Data.DAWG.Dictionary as Dict

import Control.Monad (forM_)
import Data.Maybe (fromMaybe, isJust)
import Test.Hspec
import Text.Read (readMaybe)

import qualified Data.Binary as Binary
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Vector as Vector

main :: IO ()
main = hspec spec

spec :: Spec
spec = do
  describe "Completer" do
    it "Builds a completer from a lexicon" do
      db <- DAWG.new
      contents <- readFile "data/lexicon"
      forM_ (lines contents) \l -> do
        let (w, strVal) = break (== '\t') l
            mVal = readMaybe . drop 1 $ strVal
            value = fromMaybe maxBound mVal :: ValueType
        DAWG.insert (Vector.fromList w) (Just value) db
      dawg <- DAWG.freeze db
      -- it must not fail since the DictionarySpec covers it
      dict <- Dict.build' dawg
      mGuide <- G.build dawg dict
      isJust mGuide `shouldBe` True
      forM_ mGuide \guide -> G.write "lexicon.dic" guide
    
    it "Completes keys from a lexicon" do
      let completerResultFile = "completer-result"
          goNext w c = case next c of
            Nothing -> pure ()
            Just !nc -> do
              appendFile completerResultFile $ concat
                [ " ", w, keyToString nc, " = ", show $ C.value nc ]
              goNext w nc

          go :: BaseType -> String -> String -> G.Guide -> IO ()
          go _dictIx _fullWord [] _guide = pure ()
          go dictIx fw w g = do
            let d = G.guideDictionary g
            case Dict.followPrefixLength w (fromIntegral $ length w) dictIx d of
              Nothing -> pure ()
              Just nextDictIx -> do
                let !nc = start nextDictIx "" g
                goNext fw nc
                go nextDictIx fw w g

      writeFile completerResultFile ""
      guide <- G.read "lexicon.dic"
      
      contents <- readFile "data/query"
      forM_ (lines contents) \l -> do
        appendFile completerResultFile $ concat [ l, ":" ]
        go Dict.root l l guide
        appendFile completerResultFile "\n"

      True `shouldBe` True

    it "Checks results" do
      let completerResultFile = "completer-result"
      testResult <- readFile completerResultFile
      testExpectation <- readFile "data/completer-answer"
      testResult `shouldBe` testExpectation

    it "Ensures binary compatibility with C++" do
      cppContents <- BSL.readFile "data/lexicon.guide.dic"
      let cppGuide = Binary.decode cppContents
      guide <- G.read "lexicon.dic"
      cppGuide `shouldBe` guide
      Binary.encode guide `shouldBe` cppContents