packages feed

zim-parser-0.2.1.0: test/Codec/Archive/Zim/ParserSpec.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
module Codec.Archive.Zim.ParserSpec (main, spec) where

import Prelude ()
import Prelude.Compat
import Control.Monad (forM_)
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy as BL
import Data.Maybe (fromJust, isJust)
import System.IO (Handle, openBinaryFile, IOMode(ReadMode))

import Data.Array.IArray (bounds, (!))

import Test.Hspec

import Codec.Archive.Zim.Parser

testSmallFilePath :: FilePath
testSmallFilePath = "test/wikipedia_en_ray_charles_2015-06.zim"

main :: IO ()
main = hspec spec

setup :: IO (Handle, ZimHeader)
setup = do
    small <- openBinaryFile testSmallFilePath ReadMode
    smallZim <- getHeader small
    return (small, smallZim)

spec :: Spec
spec = do
    describe "zim" $ do
      beforeAll setup $ do

        it "can open Ray Charles ZIM" $ \(_, smallZim) -> do
            zimMagicNumber smallZim `shouldBe` 72173914

        it "can get version" $ \(_, smallZim) -> do
            zimVersion smallZim `shouldBe` 5

        it "can get article count" $ \(_, smallZim) -> do
            zimArticleCount smallZim `shouldBe` 458

        it "can get cluster count" $ \(_, smallZim) -> do
            zimClusterCount smallZim `shouldBe` 215

        it "can parse MIME list" $ \h -> do
            mimeList <- getMimeList h
            mimeList ! 0 `shouldBe` "application/javascript"
            bounds mimeList `shouldBe` (0, 9)

        it "can get main page" $ \(_, smallZim) -> do
            zimMainPage smallZim `shouldBe` Just 238

        it "can get main page URL" $ \_ -> do
            url <- getMainPageUrl testSmallFilePath
            url `shouldBe` Just (Url "A/index.htm")

        it "can lookup directory entry by URL index" $ \h -> do
            de <- h `getDE` UrlIndex 0
            zimDeType de `shouldBe` ZimRedirectEntry
            zimDeUrl de `shouldBe` "favicon"

        it "can lookup directory entry by Title index" $ \h -> do
            de <- h `getDE` TitleIndex 3
            zimDeTitle de `shouldBe` "(The Night Time Is) The Right Time"
            zimDeNamespace de `shouldBe` 'A'

        it "can lookup cluster 0" $ \h -> do
            cluster <- unCluster <$> h `getCluster` ClusterNumber 0
            BL.length  cluster `shouldBe` 2160083

        it "can get cluster 2 blob 0" $ \h -> do
            Blob blob <- h `getBlob` (ClusterNumber 2, BlobNumber 0)
            BL.take 4 blob `shouldBe` "\137PNG"

        it "can get blob for article 11" $ \h -> do
            bs <- h `getContent` UrlIndex 11
            BL.take 12 (snd $ fromJust bs) `shouldBe` "<html><head>"

        it "can search for title" $ \h -> do
            let title = B8.pack "(The Night Time Is) The Right Time"
            res <- h `searchDE` mkNsTitle 'A' title
            length res `shouldBe` 1
            (fst . head) res `shouldBe` 3

        it "can search for non-existent title" $ \h -> do
            let title = B8.pack "nonexistent-title"
            res <- h `searchDE` mkNsTitle 'z' title
            length res `shouldBe` 0

        it "can search for title prefix" $ \h -> do
            let title = B8.pack "Blue"
            res <- h `searchDE` mkNsTitlePrefix 'A' title
            length res `shouldBe` 2
            let [(lb, _), (ub, _)] = res
            (lb, ub) `shouldBe` (22, 25)

        it "can search for non-existent title prefix" $ \h -> do
            let title = B8.pack "ZZZ"
            res <-h `searchDE` mkNsTitlePrefix 'A' title
            length res `shouldBe` 0

        it "can search for first title prefix" $ \h -> do
            let title = B8.pack "fav"
            res <- h `searchDE` mkNsTitlePrefix '-' title
            length res `shouldBe` 2
            let [(lb, _), (ub, _)] = res
            (lb, ub) `shouldBe` (0, 0)

        it "can search for last title prefix" $ \h -> do
            let title = B8.pack "Title"
            res <- h `searchDE` mkNsTitlePrefix 'M' title
            length res `shouldBe` 2
            let [(lb, _), (ub, _)] = res
            (lb, ub) `shouldBe` (457, 457)

        it "can search for URLs" $ \h -> do
            let url = "A/A_Fool_for_You.html"
            res <- h `searchDE` Url url
            length res `shouldBe` 1
            let [(r, _)] = res
            r `shouldBe` 4

        it "can search for non-existent URL" $ \h -> do
            let url = "a/zzz.html"
            res <- h `searchDE` Url url
            length res `shouldBe` 0

        it "can get (mimetype, content)" $ \_ -> do
            res <- testSmallFilePath `getContent` Url "A/index.htm"
            res `shouldSatisfy` isJust
            let Just (m, c) = res
            (m, BL.length c) `shouldBe` ("text/html", 8637)

        let searchAllUrls hdl hdr des =
              forM_ des $ \de -> do
                let ns = zimDeNamespace de
                    url = zimDeUrl de
                    url' = mkNsUrl ns url
                res <- (hdl, hdr) `searchDE` url'
                length res `shouldBe` 1
                (zimDeUrl . snd . head $ res) `shouldBe` url
            getAllArticles hdl hdr n = do
              let ns = [0 .. n - 1]
              forM_ ns $ \i -> do
                de <- (hdl, hdr) `getDE` UrlIndex i
                let url = zimDeUrl de
                res <- (hdl, hdr) `getContent` UrlIndex i
                res `shouldSatisfy` isJust
                (url, res) `shouldSatisfy` (\(_, Just (_, bs)) -> BL.length bs > 0)

        it "can search all URLs" $ \(hdl, hdr) -> do
          deList <- mapM (((hdl, hdr) `getDE`) . UrlIndex) [0 .. zimArticleCount hdr - 1]
          searchAllUrls hdl hdr deList

        it "can get content from all URLs" $ \(hdl, hdr) -> do
          getAllArticles hdl hdr 457