packages feed

reroute-0.2.2.1: test/Web/Routing/TextRoutingSpec.hs

{-# LANGUAGE OverloadedStrings #-}
module Web.Routing.TextRoutingSpec (spec) where

import Test.Hspec

import Web.Routing.TextRouting
import qualified Web.Routing.AbstractRouter as R
import qualified Data.HashMap.Strict as HM

spec :: Spec
spec =
    do matchNodeDesc
       matchRouteDesc
       parseRouteNodeDesc

matchNodeDesc :: Spec
matchNodeDesc =
    describe "matchNode" $
    do it "shouldn't match to root node" $
          matchNode "foo" RouteNodeRoot `shouldBe` (False, Nothing)
       it "should capture basic variables" $
          matchNode "123" (RouteNodeCapture (R.CaptureVar "x")) `shouldBe` (True, Just (R.CaptureVar "x", "123"))
       it "should work with regex" $
          matchNode "123" (RouteNodeRegex (R.CaptureVar "x") (buildRegex "^[0-9]+$")) `shouldBe` (True, Just (R.CaptureVar "x", "123"))

matchRouteDesc :: Spec
matchRouteDesc =
    describe "matchRoute" $
    do it "shouldn't match unknown routes" $
          do matchRoute "random" routingTree `shouldBe` noMatches
             matchRoute "/baz" routingTree `shouldBe` noMatches
             matchRoute "/baz/" routingTree `shouldBe` noMatches
       it "should match known routes" $
          do matchRoute "/" routingTree `shouldBe` oneMatch emptyParamMap [1]
             matchRoute "" routingTree `shouldBe` oneMatch emptyParamMap [1]
             matchRoute "/bar" routingTree `shouldBe` oneMatch emptyParamMap [2]
       it "should capture variables in routes" $
          do matchRoute "/bar/5" routingTree `shouldBe` oneMatch (vMap [("baz", "5")]) [3]
             matchRoute "/bar/23/baz" routingTree `shouldBe` oneMatch (vMap [("baz", "23")]) [4]
             matchRoute "/bar/23/baz/100" routingTree `shouldBe` oneMatch (vMap [("baz", "23"), ("bim", "100")]) [4]
             matchRoute "/ba/23/100" routingTree `shouldBe` oneMatch (vMap [("baz", "23"), ("bim", "100")]) [4]
             matchRoute "/entry/344/2014-20-14T12:23" routingTree `shouldBe` oneMatch (vMap [("cid", "344"), ("since", "2014-20-14T12:23")]) [6]
             matchRoute "/entry/bytags/344/2014-20-14T12:23" routingTree `shouldBe` oneMatch (vMap [("cid", "344"), ("since", "2014-20-14T12:23")]) [7]
             matchRoute "/entry/2/rel/3" routingTree `shouldBe` oneMatch (vMap [("eid", "2"), ("cid", "3")]) [9]
       it "should handle multiple possibile matches correctly" $
          do matchRoute "/bar/bingo" routingTree `shouldBe` multiMatch
             matchRoute "/entry/1/audit" routingTree `shouldBe` multiMatch'
    where
      vMap kv =
          HM.fromList $ map (\(k, v) -> (R.CaptureVar k, v)) kv
      multiMatch =
          ((oneMatch emptyParamMap [5])
            ++ oneMatch (vMap [("baz", "bingo")]) [3])
      multiMatch' =
          ((oneMatch (vMap [("eid", "1")]) [8])
           ++ (oneMatch (vMap [("since", "audit"), ("cid", "1")]) [6]))
      noMatches = []
      oneMatch pm m = [(pm, m)]
      routingTree =
          foldl (\tree (route, action) -> addToRoutingTree route action tree) emptyRoutingTree routes
      routes =
          [ ("/", [1])
          , ("/bar", [2 :: Int])
          , ("/bar/:baz", [3])
          , ("/bar/bingo", [5])
          , ("/bar/:baz/baz", [4])
          , ("/bar/:baz/baz/:bim", [4])
          , ("/ba/:baz/:bim", [4])
          , ("/entry/:cid/:since", [6])
          , ("/entry/bytags/:cid/:since", [7])
          , ("/entry/:eid/audit", [8])
          , ("/entry/:eid/rel/:cid", [9])
          ]

parseRouteNodeDesc :: Spec
parseRouteNodeDesc =
    describe "parseRouteNode" $
    do it "parses text nodes correctly" $
          parseRouteNode "foo" `shouldBe` RouteNodeText "foo"
       it "parses capture variables" $
          parseRouteNode ":bar" `shouldBe` RouteNodeCapture (R.CaptureVar "bar")
       it "parses regex capture variables" $
          parseRouteNode "{bar:^[0-9]$}" `shouldBe` RouteNodeRegex (R.CaptureVar "bar") (buildRegex "^[0-9]$")