diff --git a/LICENSE.markdown b/LICENSE.markdown
--- a/LICENSE.markdown
+++ b/LICENSE.markdown
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2022 Taylor Fausak
+Copyright (c) 2023 Taylor Fausak
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/burrito.cabal b/burrito.cabal
--- a/burrito.cabal
+++ b/burrito.cabal
@@ -1,7 +1,7 @@
 cabal-version: 2.2
 
 name: burrito
-version: 2.0.1.2
+version: 2.0.1.3
 
 synopsis: Parse and render URI templates.
 description:
@@ -39,12 +39,12 @@
 
 common library
   build-depends:
-    , base >= 4.13.0 && < 4.18
-    , bytestring >= 0.10.10 && < 0.12
-    , containers >= 0.6.2 && < 0.7
+    , base >= 4.15.0 && < 4.18
+    , bytestring >= 0.10.12 && < 0.12
+    , containers >= 0.6.4 && < 0.7
     , parsec >= 3.1.14 && < 3.2
-    , template-haskell >= 2.15.0 && < 2.20
-    , text >= 1.2.4 && < 1.3 || >= 2.0 && < 2.1
+    , template-haskell >= 2.17.0 && < 2.20
+    , text >= 1.2.5 && < 1.3 || >= 2.0 && < 2.1
     , transformers >= 0.5.6 && < 0.6
   default-language: Haskell2010
   ghc-options:
@@ -54,21 +54,18 @@
     -Wno-missed-specialisations
     -Wno-missing-deriving-strategies
     -Wno-missing-exported-signatures
+    -Wno-missing-safe-haskell-mode
+    -Wno-prepositive-qualified-module
     -Wno-safe
     -Wno-unsafe
 
-  if flag(pedantic)
-    ghc-options: -Werror
-
-  if impl(ghc >= 8.10)
-    ghc-options:
-      -Wno-missing-safe-haskell-mode
-      -Wno-prepositive-qualified-module
-
   if impl(ghc >= 9.2)
     ghc-options:
       -Wno-missing-kind-signatures
 
+  if flag(pedantic)
+    ghc-options: -Werror
+
 common executable
   import: library
 
@@ -105,7 +102,7 @@
     Burrito.Internal.Type.Variable
   hs-source-dirs: source/library
 
-test-suite test
+test-suite burrito-test-suite
   import: executable
 
   build-depends:
diff --git a/source/library/Burrito.hs b/source/library/Burrito.hs
--- a/source/library/Burrito.hs
+++ b/source/library/Burrito.hs
@@ -27,19 +27,20 @@
 --
 -- In short, use @parse@ to parse templates and @expand@ to render them.
 module Burrito
-  ( Parse.parse
-  , Template.render
-  , Expand.expand
-  , Expand.expandWith
-  , Match.match
-  , TH.uriTemplate
-  , TH.expandTH
-  , Template.Template
-  , Value.Value
-  , stringValue
-  , listValue
-  , dictionaryValue
-  ) where
+  ( Parse.parse,
+    Template.render,
+    Expand.expand,
+    Expand.expandWith,
+    Match.match,
+    TH.uriTemplate,
+    TH.expandTH,
+    Template.Template,
+    Value.Value,
+    stringValue,
+    listValue,
+    dictionaryValue,
+  )
+where
 
 import qualified Burrito.Internal.Expand as Expand
 import qualified Burrito.Internal.Match as Match
diff --git a/source/library/Burrito/Internal/Expand.hs b/source/library/Burrito/Internal/Expand.hs
--- a/source/library/Burrito/Internal/Expand.hs
+++ b/source/library/Burrito/Internal/Expand.hs
@@ -43,9 +43,10 @@
 expand :: [(String, Value.Value)] -> Template.Template -> String
 expand values =
   let m = Map.mapKeys Text.pack $ Map.fromList values
-  in
-    Render.builderToString . Identity.runIdentity . expandWith
-      (pure . flip Map.lookup m)
+   in Render.builderToString
+        . Identity.runIdentity
+        . expandWith
+          (pure . flip Map.lookup m)
 
 -- | This is like @expand@ except that it gives you more control over how
 -- variables are expanded. If you can, use @expand@. It's simpler.
@@ -68,20 +69,20 @@
 -- >>> expandWith (\ x -> do { putStrLn $ "-- expanding " <> show x; pure . Just $ Burrito.stringValue "A" }) template
 -- -- expanding "a"
 -- "AA"
-expandWith
-  :: Monad m
-  => (Text.Text -> m (Maybe Value.Value))
-  -> Template.Template
-  -> m Builder.Builder
+expandWith ::
+  (Monad m) =>
+  (Text.Text -> m (Maybe Value.Value)) ->
+  Template.Template ->
+  m Builder.Builder
 expandWith f = flip State.evalStateT Map.empty . template (cached f)
 
 type CacheT = State.StateT (Map.Map Text.Text (Maybe Value.Value))
 
-cached
-  :: Monad m
-  => (Text.Text -> m (Maybe Value.Value))
-  -> Name.Name
-  -> CacheT m (Maybe Value.Value)
+cached ::
+  (Monad m) =>
+  (Text.Text -> m (Maybe Value.Value)) ->
+  Name.Name ->
+  CacheT m (Maybe Value.Value)
 cached f x = do
   let key = LazyText.toStrict . Builder.toLazyText $ name x
   cache <- State.get
@@ -92,39 +93,38 @@
       State.modify $ Map.insert key result
       pure result
 
-template
-  :: Monad m
-  => (Name.Name -> CacheT m (Maybe Value.Value))
-  -> Template.Template
-  -> CacheT m Builder.Builder
+template ::
+  (Monad m) =>
+  (Name.Name -> CacheT m (Maybe Value.Value)) ->
+  Template.Template ->
+  CacheT m Builder.Builder
 template f = fmap mconcat . traverse (token f) . Template.tokens
 
-token
-  :: Monad m
-  => (Name.Name -> CacheT m (Maybe Value.Value))
-  -> Token.Token
-  -> CacheT m Builder.Builder
+token ::
+  (Monad m) =>
+  (Name.Name -> CacheT m (Maybe Value.Value)) ->
+  Token.Token ->
+  CacheT m Builder.Builder
 token f x = case x of
   Token.Expression y -> expression f y
   Token.Literal y -> pure $ literal y
 
-expression
-  :: Monad m
-  => (Name.Name -> CacheT m (Maybe Value.Value))
-  -> Expression.Expression
-  -> CacheT m Builder.Builder
+expression ::
+  (Monad m) =>
+  (Name.Name -> CacheT m (Maybe Value.Value)) ->
+  Expression.Expression ->
+  CacheT m Builder.Builder
 expression f ex =
   let op = Expression.operator ex
-  in
-    fmap
-      (mconcat
-      . (\xs -> if null xs then xs else prefix op : xs)
-      . List.intersperse (separator op)
-      . Maybe.catMaybes
-      )
-    . traverse (variable f op)
-    . NonEmpty.toList
-    $ Expression.variables ex
+   in fmap
+        ( mconcat
+            . (\xs -> if null xs then xs else prefix op : xs)
+            . List.intersperse (separator op)
+            . Maybe.catMaybes
+        )
+        . traverse (variable f op)
+        . NonEmpty.toList
+        $ Expression.variables ex
 
 separator :: Operator.Operator -> Builder.Builder
 separator op = Builder.singleton $ case op of
@@ -148,79 +148,79 @@
   Operator.Semicolon -> Builder.singleton ';'
   Operator.Solidus -> Builder.singleton '/'
 
-variable
-  :: Monad m
-  => (Name.Name -> CacheT m (Maybe Value.Value))
-  -> Operator.Operator
-  -> Variable.Variable
-  -> CacheT m (Maybe Builder.Builder)
+variable ::
+  (Monad m) =>
+  (Name.Name -> CacheT m (Maybe Value.Value)) ->
+  Operator.Operator ->
+  Variable.Variable ->
+  CacheT m (Maybe Builder.Builder)
 variable f op var = do
   res <- f $ Variable.name var
   pure $ case res of
     Nothing -> Nothing
     Just val -> value op var val
 
-value
-  :: Operator.Operator
-  -> Variable.Variable
-  -> Value.Value
-  -> Maybe Builder.Builder
+value ::
+  Operator.Operator ->
+  Variable.Variable ->
+  Value.Value ->
+  Maybe Builder.Builder
 value op var val = case val of
   Value.Dictionary xs -> dictionaryValue op var $ Map.toAscList xs
   Value.List xs -> listValue op var xs
   Value.String x -> Just $ stringValue op var x
 
-dictionaryValue
-  :: Operator.Operator
-  -> Variable.Variable
-  -> [(Text.Text, Text.Text)]
-  -> Maybe Builder.Builder
+dictionaryValue ::
+  Operator.Operator ->
+  Variable.Variable ->
+  [(Text.Text, Text.Text)] ->
+  Maybe Builder.Builder
 dictionaryValue = items $ \op var (k, v) ->
   let f = string op Modifier.None
-  in
-    case Variable.modifier var of
-      Modifier.Asterisk -> [f k <> Builder.singleton '=' <> f v]
-      _ -> [f k, f v]
+   in case Variable.modifier var of
+        Modifier.Asterisk -> [f k <> Builder.singleton '=' <> f v]
+        _ -> [f k, f v]
 
-listValue
-  :: Operator.Operator
-  -> Variable.Variable
-  -> [Text.Text]
-  -> Maybe Builder.Builder
-listValue = items $ \op var -> pure . stringValue
-  (case Variable.modifier var of
-    Modifier.Asterisk -> op
-    _ -> Operator.None
-  )
-  var { Variable.modifier = Modifier.None }
+listValue ::
+  Operator.Operator ->
+  Variable.Variable ->
+  [Text.Text] ->
+  Maybe Builder.Builder
+listValue = items $ \op var ->
+  pure
+    . stringValue
+      ( case Variable.modifier var of
+          Modifier.Asterisk -> op
+          _ -> Operator.None
+      )
+      var {Variable.modifier = Modifier.None}
 
-items
-  :: (Operator.Operator -> Variable.Variable -> a -> [Builder.Builder])
-  -> Operator.Operator
-  -> Variable.Variable
-  -> [a]
-  -> Maybe Builder.Builder
+items ::
+  (Operator.Operator -> Variable.Variable -> a -> [Builder.Builder]) ->
+  Operator.Operator ->
+  Variable.Variable ->
+  [a] ->
+  Maybe Builder.Builder
 items f op var xs =
-  let
-    md = Variable.modifier var
-    sep = case md of
-      Modifier.Asterisk -> separator op
-      _ -> Builder.singleton ','
-    p = case md of
-      Modifier.Asterisk -> False
-      _ -> case op of
-        Operator.Ampersand -> True
-        Operator.QuestionMark -> True
-        Operator.Semicolon -> True
-        _ -> False
-  in if null xs
-    then Nothing
-    else
-      Just
-      . mconcat
-      . (if p then (label True var :) else id)
-      . List.intersperse sep
-      $ concatMap (f op var) xs
+  let md = Variable.modifier var
+      sep = case md of
+        Modifier.Asterisk -> separator op
+        _ -> Builder.singleton ','
+      p = case md of
+        Modifier.Asterisk -> False
+        _ -> case op of
+          Operator.Ampersand -> True
+          Operator.QuestionMark -> True
+          Operator.Semicolon -> True
+          _ -> False
+   in if null xs
+        then Nothing
+        else
+          Just
+            . mconcat
+            . (if p then (label True var :) else id)
+            . List.intersperse sep
+            $ concatMap (f op var) xs
 
 label :: Bool -> Variable.Variable -> Builder.Builder
 label p v =
@@ -242,29 +242,27 @@
   Character.Encoded y z -> Render.encodedCharacter y z
   Character.Unencoded y -> unencodedCharacter f y
 
-stringValue
-  :: Operator.Operator -> Variable.Variable -> Text.Text -> Builder.Builder
+stringValue ::
+  Operator.Operator -> Variable.Variable -> Text.Text -> Builder.Builder
 stringValue op var str =
-  let
-    pre = case op of
-      Operator.Ampersand -> label True var
-      Operator.QuestionMark -> label True var
-      Operator.Semicolon -> label (not $ Text.null str) var
-      _ -> mempty
-  in pre <> string op (Variable.modifier var) str
+  let pre = case op of
+        Operator.Ampersand -> label True var
+        Operator.QuestionMark -> label True var
+        Operator.Semicolon -> label (not $ Text.null str) var
+        _ -> mempty
+   in pre <> string op (Variable.modifier var) str
 
-string
-  :: Operator.Operator -> Modifier.Modifier -> Text.Text -> Builder.Builder
+string ::
+  Operator.Operator -> Modifier.Modifier -> Text.Text -> Builder.Builder
 string op md =
-  let
-    allowed x = case op of
-      Operator.NumberSign -> isAllowed x
-      Operator.PlusSign -> isAllowed x
-      _ -> isUnreserved x
-    trim = case md of
-      Modifier.Colon ml -> Text.take $ MaxLength.count ml
-      _ -> id
-  in foldMap (unencodedCharacter allowed) . Text.unpack . trim
+  let allowed x = case op of
+        Operator.NumberSign -> isAllowed x
+        Operator.PlusSign -> isAllowed x
+        _ -> isUnreserved x
+      trim = case md of
+        Modifier.Colon ml -> Text.take $ MaxLength.count ml
+        _ -> id
+   in foldMap (unencodedCharacter allowed) . Text.unpack . trim
 
 isAllowed :: Char -> Bool
 isAllowed x = isUnreserved x || isReserved x
@@ -300,9 +298,10 @@
   _ -> False
 
 unencodedCharacter :: (Char -> Bool) -> Char -> Builder.Builder
-unencodedCharacter f x = if f x
-  then Builder.singleton x
-  else foldMap (uncurry Render.encodedCharacter) $ encodeCharacter x
+unencodedCharacter f x =
+  if f x
+    then Builder.singleton x
+    else foldMap (uncurry Render.encodedCharacter) $ encodeCharacter x
 
 encodeCharacter :: Char -> [(Digit.Digit, Digit.Digit)]
 encodeCharacter =
diff --git a/source/library/Burrito/Internal/Match.hs b/source/library/Burrito/Internal/Match.hs
--- a/source/library/Burrito/Internal/Match.hs
+++ b/source/library/Burrito/Internal/Match.hs
@@ -70,8 +70,8 @@
     Just (Render.builderToString $ Render.name n, Value.String v)
   Match.Undefined -> Nothing
 
-keepConsistent
-  :: [(Name.Name, Match.Match)] -> Maybe [(Name.Name, Match.Match)]
+keepConsistent ::
+  [(Name.Name, Match.Match)] -> Maybe [(Name.Name, Match.Match)]
 keepConsistent xs = case xs of
   [] -> Just xs
   (k, v) : ys -> do
@@ -90,8 +90,8 @@
     Match.Prefix n t -> case y of
       Match.Defined u | t == Text.take (MaxLength.count n) u -> combine y zs
       Match.Prefix m u
-        | let c = MaxLength.count (min n m) in Text.take c t == Text.take c u
-        -> combine (if m > n then y else x) zs
+        | let c = MaxLength.count (min n m) in Text.take c t == Text.take c u ->
+            combine (if m > n then y else x) zs
       _ -> Nothing
     Match.Undefined -> case y of
       Match.Undefined -> combine x zs
@@ -111,10 +111,10 @@
 expression :: Expression.Expression -> ReadP.ReadP [(Name.Name, Match.Match)]
 expression x = variables (Expression.operator x) (Expression.variables x)
 
-variables
-  :: Operator.Operator
-  -> NonEmpty.NonEmpty Variable.Variable
-  -> ReadP.ReadP [(Name.Name, Match.Match)]
+variables ::
+  Operator.Operator ->
+  NonEmpty.NonEmpty Variable.Variable ->
+  ReadP.ReadP [(Name.Name, Match.Match)]
 variables op vs = case op of
   Operator.Ampersand -> vars vs (Just '&') '&' varEq
   Operator.FullStop -> vars vs (Just '.') '.' $ variable Expand.isUnreserved
@@ -130,43 +130,41 @@
       variable Expand.isUnreserved v
   Operator.Solidus -> vars vs (Just '/') '/' $ variable Expand.isUnreserved
 
-vars
-  :: NonEmpty.NonEmpty Variable.Variable
-  -> Maybe Char
-  -> Char
-  -> (Variable.Variable -> ReadP.ReadP [(Name.Name, Match.Match)])
-  -> ReadP.ReadP [(Name.Name, Match.Match)]
+vars ::
+  NonEmpty.NonEmpty Variable.Variable ->
+  Maybe Char ->
+  Char ->
+  (Variable.Variable -> ReadP.ReadP [(Name.Name, Match.Match)]) ->
+  ReadP.ReadP [(Name.Name, Match.Match)]
 vars vs m c f = do
-  let
-    ctx = case m of
-      Nothing -> id
-      Just o -> \p -> ReadP.option (undef <$> NonEmpty.toList vs) $ do
-        char_ o
-        xs <- p
-        Monad.guard . not $ all isUndefined xs
-        pure xs
+  let ctx = case m of
+        Nothing -> id
+        Just o -> \p -> ReadP.option (undef <$> NonEmpty.toList vs) $ do
+          char_ o
+          xs <- p
+          Monad.guard . not $ all isUndefined xs
+          pure xs
   ctx . vars' c f $ NonEmpty.toList vs
 
 isUndefined :: (Name.Name, Match.Match) -> Bool
 isUndefined = (== Match.Undefined) . snd
 
-vars'
-  :: Char
-  -> (Variable.Variable -> ReadP.ReadP [(Name.Name, Match.Match)])
-  -> [Variable.Variable]
-  -> ReadP.ReadP [(Name.Name, Match.Match)]
+vars' ::
+  Char ->
+  (Variable.Variable -> ReadP.ReadP [(Name.Name, Match.Match)]) ->
+  [Variable.Variable] ->
+  ReadP.ReadP [(Name.Name, Match.Match)]
 vars' c f vs = case vs of
   [] -> pure []
   v : ws ->
-    let
-      this = do
-        x <- f v
-        xs <- ReadP.option (undef <$> ws) $ do
-          char_ c
-          vars' c f ws
-        pure $ x <> xs
-      that = (undef v :) <$> vars' c f ws
-    in this ReadP.+++ that
+    let this = do
+          x <- f v
+          xs <- ReadP.option (undef <$> ws) $ do
+            char_ c
+            vars' c f ws
+          pure $ x <> xs
+        that = (undef v :) <$> vars' c f ws
+     in this ReadP.+++ that
 
 undef :: Variable.Variable -> (Name.Name, Match.Match)
 undef v = (Variable.name v, Match.Undefined)
@@ -183,10 +181,10 @@
 name :: Name.Name -> ReadP.ReadP ()
 name = Monad.void . ReadP.string . Render.builderToString . Render.name
 
-variable
-  :: (Char -> Bool)
-  -> Variable.Variable
-  -> ReadP.ReadP [(Name.Name, Match.Match)]
+variable ::
+  (Char -> Bool) ->
+  Variable.Variable ->
+  ReadP.ReadP [(Name.Name, Match.Match)]
 variable f x = do
   v <- case Variable.modifier x of
     Modifier.Asterisk -> ReadP.pfail
@@ -196,9 +194,8 @@
 
 manyCharacters :: (Char -> Bool) -> ReadP.ReadP Text.Text
 manyCharacters f = do
-  let
-    f1 = (:) <$> someEncodedCharacters <*> ReadP.option [] f2
-    f2 = (:) <$> someUnencodedCharacters f <*> ReadP.option [] f1
+  let f1 = (:) <$> someEncodedCharacters <*> ReadP.option [] f2
+      f2 = (:) <$> someUnencodedCharacters f <*> ReadP.option [] f1
   fmap mconcat . ReadP.option [] $ f1 ReadP.<++ f2
 
 someEncodedCharacters :: ReadP.ReadP Text.Text
@@ -268,6 +265,7 @@
   Digit.OxF Case.Lower -> 'f'
 
 unencodedCharacter :: (Char -> Bool) -> Char -> ReadP.ReadP ()
-unencodedCharacter f x = if f x
-  then char_ x
-  else mapM_ (uncurry encodedCharacter) $ Expand.encodeCharacter x
+unencodedCharacter f x =
+  if f x
+    then char_ x
+    else mapM_ (uncurry encodedCharacter) $ Expand.encodeCharacter x
diff --git a/source/library/Burrito/Internal/Parse.hs b/source/library/Burrito/Internal/Parse.hs
--- a/source/library/Burrito/Internal/Parse.hs
+++ b/source/library/Burrito/Internal/Parse.hs
@@ -1,6 +1,5 @@
-{-# OPTIONS_GHC -Wno-missing-export-lists #-}
-
 {-# LANGUAGE FlexibleContexts #-}
+{-# OPTIONS_GHC -Wno-missing-export-lists #-}
 
 module Burrito.Internal.Parse where
 
@@ -37,72 +36,74 @@
 parse :: String -> Maybe Template.Template
 parse = either (const Nothing) Just . Parsec.parse template ""
 
-template :: Parsec.Stream s m Char => Parsec.ParsecT s u m Template.Template
+template :: (Parsec.Stream s m Char) => Parsec.ParsecT s u m Template.Template
 template = Template.Template <$> Parsec.many token <* Parsec.eof
 
-token :: Parsec.Stream s m Char => Parsec.ParsecT s u m Token.Token
+token :: (Parsec.Stream s m Char) => Parsec.ParsecT s u m Token.Token
 token = choice (Token.Expression <$> expression) (Token.Literal <$> literal)
 
-choice
-  :: Parsec.ParsecT s u m a -> Parsec.ParsecT s u m a -> Parsec.ParsecT s u m a
+choice ::
+  Parsec.ParsecT s u m a -> Parsec.ParsecT s u m a -> Parsec.ParsecT s u m a
 choice = (Parsec.<|>)
 
-expression
-  :: Parsec.Stream s m Char => Parsec.ParsecT s u m Expression.Expression
+expression ::
+  (Parsec.Stream s m Char) => Parsec.ParsecT s u m Expression.Expression
 expression =
-  Parsec.between (Parsec.char '{') (Parsec.char '}')
-    $ Expression.Expression
-    <$> operator
-    <*> sepBy1 variable (Parsec.char ',')
+  Parsec.between (Parsec.char '{') (Parsec.char '}') $
+    Expression.Expression
+      <$> operator
+      <*> sepBy1 variable (Parsec.char ',')
 
-operator :: Parsec.Stream s m Char => Parsec.ParsecT s u m Operator.Operator
-operator = Parsec.option Operator.None $ Parsec.choice
-  [ Operator.Ampersand <$ Parsec.char '&'
-  , Operator.FullStop <$ Parsec.char '.'
-  , Operator.NumberSign <$ Parsec.char '#'
-  , Operator.PlusSign <$ Parsec.char '+'
-  , Operator.QuestionMark <$ Parsec.char '?'
-  , Operator.Semicolon <$ Parsec.char ';'
-  , Operator.Solidus <$ Parsec.char '/'
-  ]
+operator :: (Parsec.Stream s m Char) => Parsec.ParsecT s u m Operator.Operator
+operator =
+  Parsec.option Operator.None $
+    Parsec.choice
+      [ Operator.Ampersand <$ Parsec.char '&',
+        Operator.FullStop <$ Parsec.char '.',
+        Operator.NumberSign <$ Parsec.char '#',
+        Operator.PlusSign <$ Parsec.char '+',
+        Operator.QuestionMark <$ Parsec.char '?',
+        Operator.Semicolon <$ Parsec.char ';',
+        Operator.Solidus <$ Parsec.char '/'
+      ]
 
-sepBy1
-  :: Parsec.ParsecT s u m a
-  -> Parsec.ParsecT s u m x
-  -> Parsec.ParsecT s u m (NonEmpty.NonEmpty a)
+sepBy1 ::
+  Parsec.ParsecT s u m a ->
+  Parsec.ParsecT s u m x ->
+  Parsec.ParsecT s u m (NonEmpty.NonEmpty a)
 sepBy1 p s = (NonEmpty.:|) <$> p <*> Parsec.many (s *> p)
 
-variable :: Parsec.Stream s m Char => Parsec.ParsecT s u m Variable.Variable
+variable :: (Parsec.Stream s m Char) => Parsec.ParsecT s u m Variable.Variable
 variable = Variable.Variable <$> name <*> modifier
 
-name :: Parsec.Stream s m Char => Parsec.ParsecT s u m Name.Name
+name :: (Parsec.Stream s m Char) => Parsec.ParsecT s u m Name.Name
 name = Name.Name <$> sepBy1 field (Parsec.char '.')
 
-field :: Parsec.Stream s m Char => Parsec.ParsecT s u m Field.Field
+field :: (Parsec.Stream s m Char) => Parsec.ParsecT s u m Field.Field
 field = Field.Field <$> nonEmpty fieldCharacter
 
-nonEmpty
-  :: Parsec.ParsecT s u m a -> Parsec.ParsecT s u m (NonEmpty.NonEmpty a)
+nonEmpty ::
+  Parsec.ParsecT s u m a -> Parsec.ParsecT s u m (NonEmpty.NonEmpty a)
 nonEmpty p = (NonEmpty.:|) <$> p <*> Parsec.many p
 
-fieldCharacter
-  :: Parsec.Stream s m Char
-  => Parsec.ParsecT s u m (Character.Character Field.Field)
+fieldCharacter ::
+  (Parsec.Stream s m Char) =>
+  Parsec.ParsecT s u m (Character.Character Field.Field)
 fieldCharacter = choice encodedCharacter (unencodedCharacter isFieldCharacter)
 
-encodedCharacter
-  :: Parsec.Stream s m Char => Parsec.ParsecT s u m (Character.Character tag)
+encodedCharacter ::
+  (Parsec.Stream s m Char) => Parsec.ParsecT s u m (Character.Character tag)
 encodedCharacter = Parsec.char '%' >> Character.Encoded <$> digit <*> digit
 
-digit :: Parsec.Stream s m Char => Parsec.ParsecT s u m Digit.Digit
+digit :: (Parsec.Stream s m Char) => Parsec.ParsecT s u m Digit.Digit
 digit = do
   x <- Parsec.satisfy Char.isHexDigit
   maybe (fail "invalid Digit") pure $ Digit.fromChar x
 
-unencodedCharacter
-  :: Parsec.Stream s m Char
-  => (Char -> Bool)
-  -> Parsec.ParsecT s u m (Character.Character tag)
+unencodedCharacter ::
+  (Parsec.Stream s m Char) =>
+  (Char -> Bool) ->
+  Parsec.ParsecT s u m (Character.Character tag)
 unencodedCharacter = fmap Character.Unencoded . Parsec.satisfy
 
 isFieldCharacter :: Char -> Bool
@@ -110,14 +111,16 @@
   '_' -> True
   _ -> Char.isAsciiUpper x || Char.isAsciiLower x || Char.isDigit x
 
-modifier :: Parsec.Stream s m Char => Parsec.ParsecT s u m Modifier.Modifier
-modifier = Parsec.option Modifier.None $ Parsec.choice
-  [ Modifier.Asterisk <$ Parsec.char '*'
-  , Parsec.char ':' >> Modifier.Colon <$> maxLength
-  ]
+modifier :: (Parsec.Stream s m Char) => Parsec.ParsecT s u m Modifier.Modifier
+modifier =
+  Parsec.option Modifier.None $
+    Parsec.choice
+      [ Modifier.Asterisk <$ Parsec.char '*',
+        Parsec.char ':' >> Modifier.Colon <$> maxLength
+      ]
 
-maxLength
-  :: Parsec.Stream s m Char => Parsec.ParsecT s u m MaxLength.MaxLength
+maxLength ::
+  (Parsec.Stream s m Char) => Parsec.ParsecT s u m MaxLength.MaxLength
 maxLength = do
   x <- Parsec.satisfy $ Ix.inRange ('1', '9')
   xs <- Parsec.many $ Parsec.satisfy Char.isDigit
@@ -129,12 +132,12 @@
 isMaxLength :: Int -> Bool
 isMaxLength = Ix.inRange (1, 9999)
 
-literal :: Parsec.Stream s m Char => Parsec.ParsecT s u m Literal.Literal
+literal :: (Parsec.Stream s m Char) => Parsec.ParsecT s u m Literal.Literal
 literal = Literal.Literal <$> nonEmpty literalCharacter
 
-literalCharacter
-  :: Parsec.Stream s m Char
-  => Parsec.ParsecT s u m (Character.Character Literal.Literal)
+literalCharacter ::
+  (Parsec.Stream s m Char) =>
+  Parsec.ParsecT s u m (Character.Character Literal.Literal)
 literalCharacter =
   choice encodedCharacter (unencodedCharacter isLiteralCharacter)
 
diff --git a/source/library/Burrito/Internal/Render.hs b/source/library/Burrito/Internal/Render.hs
--- a/source/library/Burrito/Internal/Render.hs
+++ b/source/library/Burrito/Internal/Render.hs
@@ -45,11 +45,11 @@
   Operator.Semicolon -> Builder.singleton ';'
   Operator.Solidus -> Builder.singleton '/'
 
-sepBy1
-  :: (a -> Builder.Builder)
-  -> Builder.Builder
-  -> NonEmpty.NonEmpty a
-  -> Builder.Builder
+sepBy1 ::
+  (a -> Builder.Builder) ->
+  Builder.Builder ->
+  NonEmpty.NonEmpty a ->
+  Builder.Builder
 sepBy1 f x = mconcat . List.intersperse x . fmap f . NonEmpty.toList
 
 variable :: Variable.Variable -> Builder.Builder
diff --git a/source/library/Burrito/Internal/TH.hs b/source/library/Burrito/Internal/TH.hs
--- a/source/library/Burrito/Internal/TH.hs
+++ b/source/library/Burrito/Internal/TH.hs
@@ -1,7 +1,8 @@
 module Burrito.Internal.TH
-  ( expandTH
-  , uriTemplate
-  ) where
+  ( expandTH,
+    uriTemplate,
+  )
+where
 
 import qualified Burrito.Internal.Expand as Expand
 import qualified Burrito.Internal.Parse as Parse
@@ -27,14 +28,13 @@
 -- "l-bar-r"
 expandTH :: [(String, Value.Value)] -> Template.Template -> TH.Q TH.Exp
 expandTH xs t = do
-  let
-    m = Map.fromList $ fmap (Bifunctor.first Text.pack) xs
-    f k =
-      maybe (Left $ "missing variable: " <> show k) (Right . Just)
-        $ Map.lookup k m
+  let m = Map.fromList $ fmap (Bifunctor.first Text.pack) xs
+      f k =
+        maybe (Left $ "missing variable: " <> show k) (Right . Just) $
+          Map.lookup k m
   x <-
-    either fail (pure . LazyText.unpack . Builder.toLazyText)
-      $ Expand.expandWith f t
+    either fail (pure . LazyText.unpack . Builder.toLazyText) $
+      Expand.expandWith f t
   TH.lift x
 
 -- | This can be used together with the @QuasiQuotes@ language extension to
@@ -53,9 +53,10 @@
 -- this is invalid: @[uriTemplate|\\xa0|]@. You can however use percent encoded
 -- triples as normal. So this is valid: @[uriTemplate|%c2%a0|]@.
 uriTemplate :: TH.QuasiQuoter
-uriTemplate = TH.QuasiQuoter
-  { TH.quoteDec = const $ fail "cannot be used as a declaration"
-  , TH.quoteExp = maybe (fail "invalid URI template") TH.liftData . Parse.parse
-  , TH.quotePat = const $ fail "cannot be used as a pattern"
-  , TH.quoteType = const $ fail "cannot be used as a type"
-  }
+uriTemplate =
+  TH.QuasiQuoter
+    { TH.quoteDec = const $ fail "cannot be used as a declaration",
+      TH.quoteExp = maybe (fail "invalid URI template") TH.liftData . Parse.parse,
+      TH.quotePat = const $ fail "cannot be used as a pattern",
+      TH.quoteType = const $ fail "cannot be used as a type"
+    }
diff --git a/source/library/Burrito/Internal/Type/Case.hs b/source/library/Burrito/Internal/Type/Case.hs
--- a/source/library/Burrito/Internal/Type/Case.hs
+++ b/source/library/Burrito/Internal/Type/Case.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Case
-  ( Case(..)
-  ) where
+  ( Case (..),
+  )
+where
 
 import qualified Data.Data as Data
 
diff --git a/source/library/Burrito/Internal/Type/Character.hs b/source/library/Burrito/Internal/Type/Character.hs
--- a/source/library/Burrito/Internal/Type/Character.hs
+++ b/source/library/Burrito/Internal/Type/Character.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Character
-  ( Character(..)
-  ) where
+  ( Character (..),
+  )
+where
 
 import qualified Burrito.Internal.Type.Digit as Digit
 import qualified Data.Data as Data
diff --git a/source/library/Burrito/Internal/Type/Digit.hs b/source/library/Burrito/Internal/Type/Digit.hs
--- a/source/library/Burrito/Internal/Type/Digit.hs
+++ b/source/library/Burrito/Internal/Type/Digit.hs
@@ -1,11 +1,12 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Digit
-  ( Digit(..)
-  , fromChar
-  , fromWord8
-  , toWord8
-  ) where
+  ( Digit (..),
+    fromChar,
+    fromWord8,
+    toWord8,
+  )
+where
 
 import qualified Burrito.Internal.Type.Case as Case
 import qualified Data.Bits as Bits
@@ -59,47 +60,45 @@
 
 fromWord8 :: Word.Word8 -> (Digit, Digit)
 fromWord8 x =
-  let
-    f :: Word.Word8 -> Digit
-    f y = case y of
-      0x0 -> Ox0
-      0x1 -> Ox1
-      0x2 -> Ox2
-      0x3 -> Ox3
-      0x4 -> Ox4
-      0x5 -> Ox5
-      0x6 -> Ox6
-      0x7 -> Ox7
-      0x8 -> Ox8
-      0x9 -> Ox9
-      0xA -> OxA Case.Upper
-      0xB -> OxB Case.Upper
-      0xC -> OxC Case.Upper
-      0xD -> OxD Case.Upper
-      0xE -> OxE Case.Upper
-      0xF -> OxF Case.Upper
-      _ -> error $ "invalid nibble: " <> show y
-  in (f $ Bits.shiftR x 4, f $ x Bits..&. 0x0F)
+  let f :: Word.Word8 -> Digit
+      f y = case y of
+        0x0 -> Ox0
+        0x1 -> Ox1
+        0x2 -> Ox2
+        0x3 -> Ox3
+        0x4 -> Ox4
+        0x5 -> Ox5
+        0x6 -> Ox6
+        0x7 -> Ox7
+        0x8 -> Ox8
+        0x9 -> Ox9
+        0xA -> OxA Case.Upper
+        0xB -> OxB Case.Upper
+        0xC -> OxC Case.Upper
+        0xD -> OxD Case.Upper
+        0xE -> OxE Case.Upper
+        0xF -> OxF Case.Upper
+        _ -> error $ "invalid nibble: " <> show y
+   in (f $ Bits.shiftR x 4, f $ x Bits..&. 0x0F)
 
 toWord8 :: Digit -> Digit -> Word.Word8
 toWord8 x y =
-  let
-    f :: Digit -> Word.Word8
-    f z = case z of
-      Ox0 -> 0x0
-      Ox1 -> 0x1
-      Ox2 -> 0x2
-      Ox3 -> 0x3
-      Ox4 -> 0x4
-      Ox5 -> 0x5
-      Ox6 -> 0x6
-      Ox7 -> 0x7
-      Ox8 -> 0x8
-      Ox9 -> 0x9
-      OxA _ -> 0xA
-      OxB _ -> 0xB
-      OxC _ -> 0xC
-      OxD _ -> 0xD
-      OxE _ -> 0xE
-      OxF _ -> 0xF
-  in Bits.shiftL (f x) 4 Bits..|. f y
+  let f :: Digit -> Word.Word8
+      f z = case z of
+        Ox0 -> 0x0
+        Ox1 -> 0x1
+        Ox2 -> 0x2
+        Ox3 -> 0x3
+        Ox4 -> 0x4
+        Ox5 -> 0x5
+        Ox6 -> 0x6
+        Ox7 -> 0x7
+        Ox8 -> 0x8
+        Ox9 -> 0x9
+        OxA _ -> 0xA
+        OxB _ -> 0xB
+        OxC _ -> 0xC
+        OxD _ -> 0xD
+        OxE _ -> 0xE
+        OxF _ -> 0xF
+   in Bits.shiftL (f x) 4 Bits..|. f y
diff --git a/source/library/Burrito/Internal/Type/Expression.hs b/source/library/Burrito/Internal/Type/Expression.hs
--- a/source/library/Burrito/Internal/Type/Expression.hs
+++ b/source/library/Burrito/Internal/Type/Expression.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Expression
-  ( Expression(..)
-  ) where
+  ( Expression (..),
+  )
+where
 
 import qualified Burrito.Internal.Type.Operator as Operator
 import qualified Burrito.Internal.Type.Variable as Variable
@@ -10,7 +11,7 @@
 import qualified Data.List.NonEmpty as NonEmpty
 
 data Expression = Expression
-  { operator :: Operator.Operator
-  , variables :: NonEmpty.NonEmpty Variable.Variable
+  { operator :: Operator.Operator,
+    variables :: NonEmpty.NonEmpty Variable.Variable
   }
   deriving (Data.Data, Eq, Ord, Show)
diff --git a/source/library/Burrito/Internal/Type/Field.hs b/source/library/Burrito/Internal/Type/Field.hs
--- a/source/library/Burrito/Internal/Type/Field.hs
+++ b/source/library/Burrito/Internal/Type/Field.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Field
-  ( Field(..)
-  ) where
+  ( Field (..),
+  )
+where
 
 import qualified Burrito.Internal.Type.Character as Character
 import qualified Data.Data as Data
@@ -10,4 +11,5 @@
 
 newtype Field = Field
   { characters :: NonEmpty.NonEmpty (Character.Character Field)
-  } deriving (Data.Data, Eq, Ord, Show)
+  }
+  deriving (Data.Data, Eq, Ord, Show)
diff --git a/source/library/Burrito/Internal/Type/Literal.hs b/source/library/Burrito/Internal/Type/Literal.hs
--- a/source/library/Burrito/Internal/Type/Literal.hs
+++ b/source/library/Burrito/Internal/Type/Literal.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Literal
-  ( Literal(..)
-  ) where
+  ( Literal (..),
+  )
+where
 
 import qualified Burrito.Internal.Type.Character as Character
 import qualified Data.Data as Data
@@ -10,4 +11,5 @@
 
 newtype Literal = Literal
   { characters :: NonEmpty.NonEmpty (Character.Character Literal)
-  } deriving (Data.Data, Eq, Ord, Show)
+  }
+  deriving (Data.Data, Eq, Ord, Show)
diff --git a/source/library/Burrito/Internal/Type/Match.hs b/source/library/Burrito/Internal/Type/Match.hs
--- a/source/library/Burrito/Internal/Type/Match.hs
+++ b/source/library/Burrito/Internal/Type/Match.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Match
-  ( Match(..)
-  ) where
+  ( Match (..),
+  )
+where
 
 import qualified Burrito.Internal.Type.MaxLength as MaxLength
 import qualified Data.Data as Data
diff --git a/source/library/Burrito/Internal/Type/MaxLength.hs b/source/library/Burrito/Internal/Type/MaxLength.hs
--- a/source/library/Burrito/Internal/Type/MaxLength.hs
+++ b/source/library/Burrito/Internal/Type/MaxLength.hs
@@ -1,11 +1,13 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.MaxLength
-  ( MaxLength(..)
-  ) where
+  ( MaxLength (..),
+  )
+where
 
 import qualified Data.Data as Data
 
 newtype MaxLength = MaxLength
   { count :: Int
-  } deriving (Data.Data, Eq, Ord, Show)
+  }
+  deriving (Data.Data, Eq, Ord, Show)
diff --git a/source/library/Burrito/Internal/Type/Modifier.hs b/source/library/Burrito/Internal/Type/Modifier.hs
--- a/source/library/Burrito/Internal/Type/Modifier.hs
+++ b/source/library/Burrito/Internal/Type/Modifier.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Modifier
-  ( Modifier(..)
-  ) where
+  ( Modifier (..),
+  )
+where
 
 import qualified Burrito.Internal.Type.MaxLength as MaxLength
 import qualified Data.Data as Data
diff --git a/source/library/Burrito/Internal/Type/Name.hs b/source/library/Burrito/Internal/Type/Name.hs
--- a/source/library/Burrito/Internal/Type/Name.hs
+++ b/source/library/Burrito/Internal/Type/Name.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Name
-  ( Name(..)
-  ) where
+  ( Name (..),
+  )
+where
 
 import qualified Burrito.Internal.Type.Field as Field
 import qualified Data.Data as Data
@@ -10,4 +11,5 @@
 
 newtype Name = Name
   { fields :: NonEmpty.NonEmpty Field.Field
-  } deriving (Data.Data, Eq, Ord, Show)
+  }
+  deriving (Data.Data, Eq, Ord, Show)
diff --git a/source/library/Burrito/Internal/Type/Operator.hs b/source/library/Burrito/Internal/Type/Operator.hs
--- a/source/library/Burrito/Internal/Type/Operator.hs
+++ b/source/library/Burrito/Internal/Type/Operator.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Operator
-  ( Operator(..)
-  ) where
+  ( Operator (..),
+  )
+where
 
 import qualified Data.Data as Data
 
diff --git a/source/library/Burrito/Internal/Type/Template.hs b/source/library/Burrito/Internal/Type/Template.hs
--- a/source/library/Burrito/Internal/Type/Template.hs
+++ b/source/library/Burrito/Internal/Type/Template.hs
@@ -1,9 +1,10 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Template
-  ( Template(..)
-  , render
-  ) where
+  ( Template (..),
+    render,
+  )
+where
 
 import qualified Burrito.Internal.Render as Render
 import qualified Burrito.Internal.Type.Token as Token
@@ -13,7 +14,8 @@
 -- | Represents a URI template.
 newtype Template = Template
   { tokens :: [Token.Token]
-  } deriving (Data.Data, Eq, Ord)
+  }
+  deriving (Data.Data, Eq, Ord)
 
 instance Show Template where
   show = render
diff --git a/source/library/Burrito/Internal/Type/Token.hs b/source/library/Burrito/Internal/Type/Token.hs
--- a/source/library/Burrito/Internal/Type/Token.hs
+++ b/source/library/Burrito/Internal/Type/Token.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Token
-  ( Token(..)
-  ) where
+  ( Token (..),
+  )
+where
 
 import qualified Burrito.Internal.Type.Expression as Expression
 import qualified Burrito.Internal.Type.Literal as Literal
diff --git a/source/library/Burrito/Internal/Type/Value.hs b/source/library/Burrito/Internal/Type/Value.hs
--- a/source/library/Burrito/Internal/Type/Value.hs
+++ b/source/library/Burrito/Internal/Type/Value.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Value
-  ( Value(..)
-  ) where
+  ( Value (..),
+  )
+where
 
 import qualified Data.Data as Data
 import qualified Data.Map as Map
diff --git a/source/library/Burrito/Internal/Type/Variable.hs b/source/library/Burrito/Internal/Type/Variable.hs
--- a/source/library/Burrito/Internal/Type/Variable.hs
+++ b/source/library/Burrito/Internal/Type/Variable.hs
@@ -1,15 +1,16 @@
 {-# LANGUAGE DeriveDataTypeable #-}
 
 module Burrito.Internal.Type.Variable
-  ( Variable(..)
-  ) where
+  ( Variable (..),
+  )
+where
 
 import qualified Burrito.Internal.Type.Modifier as Modifier
 import qualified Burrito.Internal.Type.Name as Name
 import qualified Data.Data as Data
 
 data Variable = Variable
-  { name :: Name.Name
-  , modifier :: Modifier.Modifier
+  { name :: Name.Name,
+    modifier :: Modifier.Modifier
   }
   deriving (Data.Data, Eq, Ord, Show)
diff --git a/source/test-suite/Main.hs b/source/test-suite/Main.hs
--- a/source/test-suite/Main.hs
+++ b/source/test-suite/Main.hs
@@ -1,1466 +1,1459 @@
-{-# OPTIONS_GHC -Wno-monomorphism-restriction #-}
-
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE QuasiQuotes #-}
-
-module Main
-  ( main
-  ) where
-
-import qualified Burrito
-import qualified Burrito.Internal.Parse as Parse
-import qualified Burrito.Internal.Render as Render
-import qualified Burrito.Internal.Type.Case as Case
-import qualified Burrito.Internal.Type.Character as Character
-import qualified Burrito.Internal.Type.Digit as Digit
-import qualified Burrito.Internal.Type.Expression as Expression
-import qualified Burrito.Internal.Type.Field as Field
-import qualified Burrito.Internal.Type.Literal as Literal
-import qualified Burrito.Internal.Type.MaxLength as MaxLength
-import qualified Burrito.Internal.Type.Modifier as Modifier
-import qualified Burrito.Internal.Type.Name as Name
-import qualified Burrito.Internal.Type.Operator as Operator
-import qualified Burrito.Internal.Type.Template as Template
-import qualified Burrito.Internal.Type.Token as Token
-import qualified Burrito.Internal.Type.Value as Value
-import qualified Burrito.Internal.Type.Variable as Variable
-import qualified Control.Monad as Monad
-import qualified Data.List as List
-import qualified Data.List.NonEmpty as NonEmpty
-import qualified Data.Map as Map
-import qualified Data.Maybe as Maybe
-import qualified Data.Set as Set
-import qualified Data.String as String
-import qualified Data.Text as Text
-import qualified GHC.Stack as Stack
-import qualified Test.Hspec as Hspec
-import qualified Test.Hspec.QuickCheck as Hspec
-import qualified Test.QuickCheck as QC
-
-main :: IO ()
-main = Hspec.hspec . Hspec.describe "Burrito" $ do
-
-  Monad.forM_ tests $ \test ->
-    Hspec.it (show (testInput test, unwrapOutput $ testOutput test))
-      $ runTest test
-
-  Hspec.describe "match" $ do
-    let
-      matchTest
-        :: Stack.HasCallStack
-        => String
-        -> [(String, Burrito.Value)]
-        -> String
-        -> Hspec.Spec
-      matchTest input values output = Hspec.it (show (input, output)) $ do
-        template <- maybe (fail "invalid Template") pure $ Burrito.parse input
-        let matches = Burrito.match output template
-        matches `Hspec.shouldSatisfy` elem values
-        Monad.forM_ matches $ \match -> do
-          let it = Burrito.expand match template
-          Monad.when (it /= output) . fail $ show
-            (input, values, output, matches, match, it)
-
-    matchTest "" [] ""
-    matchTest "a" [] "a"
-    matchTest "!" [] "!"
-    matchTest "\xa0" [] "%C2%A0"
-
-    matchTest "{a}" ["a" =: s ""] ""
-    matchTest "{a}" ["a" =: s "A"] "A"
-    matchTest "{a}" ["a" =: s "AB"] "AB"
-
-    matchTest "a{b}" ["b" =: s ""] "a"
-    matchTest "a{b}" ["b" =: s "B"] "aB"
-    matchTest "a{b}" ["b" =: s "BC"] "aBC"
-
-    matchTest "{a}b" ["a" =: s ""] "b"
-    matchTest "{a}b" ["a" =: s "A"] "Ab"
-    matchTest "{a}b" ["a" =: s "AB"] "ABb"
-
-    matchTest "{a}{a}" ["a" =: s "A"] "AA"
-    matchTest "{a}{a}" ["a" =: s "AB"] "ABAB"
-
-    matchTest "{a}" ["a" =: s "%"] "%25"
-    matchTest "{a}" ["a" =: s "/"] "%2F"
-    matchTest "{a}" ["a" =: s "\xa0"] "%C2%A0"
-    matchTest "{a}" ["a" =: s "\xd7ff"] "%ED%9F%BF"
-    matchTest "{a}" ["a" =: s "\x10000"] "%F0%90%80%80"
-    matchTest "{a}" ["a" =: s "A/B"] "A%2FB"
-    matchTest "{a}" ["a" =: s "WX\xa0\xa1YZ"] "WX%C2%A0%C2%A1YZ"
-
-    matchTest "{+a}" ["a" =: s "%"] "%25"
-    matchTest "{+a}" ["a" =: s "/"] "/"
-
-    matchTest "{#a}" [] ""
-    matchTest "{#a}" ["a" =: s ""] "#"
-    matchTest "{#a}" ["a" =: s "A"] "#A"
-    matchTest "{#a}" ["a" =: s "%"] "#%25"
-    matchTest "{#a}" ["a" =: s "/"] "#/"
-
-    matchTest "{.a}" [] ""
-    matchTest "{.a}" ["a" =: s ""] "."
-    matchTest "{.a}" ["a" =: s "A"] ".A"
-    matchTest "{.a}" ["a" =: s "%"] ".%25"
-    matchTest "{.a}" ["a" =: s "/"] ".%2F"
-
-    matchTest "{/a}" [] ""
-    matchTest "{/a}" ["a" =: s ""] "/"
-    matchTest "{/a}" ["a" =: s "A"] "/A"
-    matchTest "{/a}" ["a" =: s "%"] "/%25"
-    matchTest "{/a}" ["a" =: s "/"] "/%2F"
-
-    matchTest "{;a}" [] ""
-    matchTest "{;a}" ["a" =: s ""] ";a"
-    matchTest "{;a}" ["a" =: s "A"] ";a=A"
-    matchTest "{;a}" ["a" =: s "%"] ";a=%25"
-    matchTest "{;a}" ["a" =: s "/"] ";a=%2F"
-
-    matchTest "{?a}" [] ""
-    matchTest "{?a}" ["a" =: s ""] "?a="
-    matchTest "{?a}" ["a" =: s "A"] "?a=A"
-    matchTest "{?a}" ["a" =: s "%"] "?a=%25"
-    matchTest "{?a}" ["a" =: s "/"] "?a=%2F"
-
-    matchTest "{&a}" [] ""
-    matchTest "{&a}" ["a" =: s ""] "&a="
-    matchTest "{&a}" ["a" =: s "A"] "&a=A"
-    matchTest "{&a}" ["a" =: s "%"] "&a=%25"
-    matchTest "{&a}" ["a" =: s "/"] "&a=%2F"
-
-    matchTest "{a,b}" ["a" =: s "A", "b" =: s "B"] "A,B"
-    matchTest "{+a,b}" ["a" =: s "A", "b" =: s "B"] "A,B"
-    matchTest "{#a,b}" ["a" =: s "A", "b" =: s "B"] "#A,B"
-    matchTest "{.a,b}" ["a" =: s "A", "b" =: s "B"] ".A.B"
-    matchTest "{/a,b}" ["a" =: s "A", "b" =: s "B"] "/A/B"
-    matchTest "{;a,b}" ["a" =: s "A", "b" =: s "B"] ";a=A;b=B"
-    matchTest "{?a,b}" ["a" =: s "A", "b" =: s "B"] "?a=A&b=B"
-    matchTest "{&a,b}" ["a" =: s "A", "b" =: s "B"] "&a=A&b=B"
-
-    matchTest "{a,b}" ["a" =: s "A"] "A"
-    matchTest "{a,b,c}" ["a" =: s "A"] "A"
-    matchTest "{a,b,c}" ["a" =: s "A", "b" =: s "B"] "A,B"
-    matchTest "{a}{a,b}" ["b" =: s "B"] "B"
-    matchTest "{a}{a,b,c}" ["b" =: s "B"] "B"
-    matchTest "{a,b}{a,b,c}" ["c" =: s "C"] "C"
-    matchTest "{b}{a,b,c}" ["a" =: s "A", "c" =: s "C"] "A,C"
-    matchTest "{a}{a,b,c}" ["b" =: s "B", "c" =: s "C"] "B,C"
-
-    matchTest "{a:1}/{a}" ["a" =: s "AB"] "A/AB"
-
-    -- TODO: Test matching on explode modifier.
-    -- matchTest "{a*}" ["a" =: s "A"] "A"
-
-    -- TODO: Test matching on lists.
-    -- matchTest "{a}" ["a" =: l ["A", "B"]] "A,B"
-
-    -- TODO: Test matching on dictionaries.
-    -- matchTest "{a}" ["a" =: d ["k" =: "v"]] "k,v"
-
-  Hspec.describe "uriTemplate"
-    . Hspec.it "works as an expression"
-    $ Just [Burrito.uriTemplate|a{b}c|]
-    `Hspec.shouldBe` Burrito.parse "a{b}c"
-
-  Hspec.modifyMaxSize (const 10)
-    . Hspec.it "round trips"
-    . QC.property
-    $ \(Template template) -> Burrito.parse (show template) == Just template
-
--- brittany-next-binding --columns 160
-tests :: [Test]
-tests = mconcat
-  [ [ Test "" [] ""
-    , Test "" ["a" =: s ""] ""
-    , Test "" ["a" =: l []] ""
-    , Test "" ["a" =: d []] ""
-    , Test "!" [] "!"
-    , Test "#" [] "#"
-    , Test "$" [] "$"
-    , Test "&" [] "&"
-    , Test "(" [] "("
-    , Test ")" [] ")"
-    , Test "*" [] "*"
-    , Test "+" [] "+"
-    , Test "," [] ","
-    , Test "-" [] "-"
-    , Test "." [] "."
-    , Test "/" [] "/"
-    , Test "0" [] "0"
-    , Test "9" [] "9"
-    , Test ":" [] ":"
-    , Test ";" [] ";"
-    , Test "=" [] "="
-    , Test "?" [] "?"
-    , Test "@" [] "@"
-    , Test "A" [] "A"
-    , Test "Z" [] "Z"
-    , Test "[" [] "["
-    , Test "]" [] "]"
-    , Test "_" [] "_"
-    , Test "a" [] "a"
-    , Test "z" [] "z"
-    , Test "~" [] "~"
-    , Test "\xa0" [] "%C2%A0"
-    , Test "\xd7ff" [] "%ED%9F%BF"
-    , Test "\xf900" [] "%EF%A4%80"
-    , Test "\xfdcf" [] "%EF%B7%8F"
-    , Test "\xfdf0" [] "%EF%B7%B0"
-    , Test "\xffef" [] "%EF%BF%AF"
-    , Test "\x10000" [] "%F0%90%80%80"
-    , Test "\x1fffd" [] "%F0%9F%BF%BD"
-    , Test "\x20000" [] "%F0%A0%80%80"
-    , Test "\x2fffd" [] "%F0%AF%BF%BD"
-    , Test "\x30000" [] "%F0%B0%80%80"
-    , Test "\x3fffd" [] "%F0%BF%BF%BD"
-    , Test "\x40000" [] "%F1%80%80%80"
-    , Test "\x4fffd" [] "%F1%8F%BF%BD"
-    , Test "\x50000" [] "%F1%90%80%80"
-    , Test "\x5fffd" [] "%F1%9F%BF%BD"
-    , Test "\x60000" [] "%F1%A0%80%80"
-    , Test "\x6fffd" [] "%F1%AF%BF%BD"
-    , Test "\x70000" [] "%F1%B0%80%80"
-    , Test "\x7fffd" [] "%F1%BF%BF%BD"
-    , Test "\x80000" [] "%F2%80%80%80"
-    , Test "\x8fffd" [] "%F2%8F%BF%BD"
-    , Test "\x90000" [] "%F2%90%80%80"
-    , Test "\x9fffd" [] "%F2%9F%BF%BD"
-    , Test "\xa0000" [] "%F2%A0%80%80"
-    , Test "\xafffd" [] "%F2%AF%BF%BD"
-    , Test "\xb0000" [] "%F2%B0%80%80"
-    , Test "\xbfffd" [] "%F2%BF%BF%BD"
-    , Test "\xc0000" [] "%F3%80%80%80"
-    , Test "\xcfffd" [] "%F3%8F%BF%BD"
-    , Test "\xd0000" [] "%F3%90%80%80"
-    , Test "\xdfffd" [] "%F3%9F%BF%BD"
-    , Test "\xe1000" [] "%F3%A1%80%80"
-    , Test "\xefffd" [] "%F3%AF%BF%BD"
-    , Test "\xe000" [] "%EE%80%80"
-    , Test "\xf8ff" [] "%EF%A3%BF"
-    , Test "\xf0000" [] "%F3%B0%80%80"
-    , Test "\xffffd" [] "%F3%BF%BF%BD"
-    , Test "\x100000" [] "%F4%80%80%80"
-    , Test "\x10fffd" [] "%F4%8F%BF%BD"
-    , Test "%00" [] "%00"
-    , Test "%AA" [] "%AA"
-    , Test "%Aa" [] "%Aa"
-    , Test "%aA" [] "%aA"
-    , Test "%aa" [] "%aa"
-    , Test "%" [] noParse
-    , Test "%0" [] noParse
-    , Test "%0z" [] noParse
-    , Test "%z" [] noParse
-    , Test "%30" [] "%30"
-    , Test " " [] noParse
-    , Test "\"" [] noParse
-    , Test "'" [] noParse
-    , Test "%" [] noParse
-    , Test "<" [] noParse
-    , Test ">" [] noParse
-    , Test "\\" [] noParse
-    , Test "^" [] noParse
-    , Test "`" [] noParse
-    , Test "{" [] noParse
-    , Test "|" [] noParse
-    , Test "}" [] noParse
-    , Test "{}" [] noParse
-    , Test "{,}" [] noParse
-    , Test "{a,,b}" [] noParse
-    , Test "{+}" [] noParse
-    , Test "{:1}" [] noParse
-    , Test "{*}" [] noParse
-    , Test "{AZ}" [] ""
-    , Test "{az}" [] ""
-    , Test "{09}" [] ""
-    , Test "{_a}" [] ""
-    , Test "{a_}" [] ""
-    , Test "{_}" [] ""
-    , Test "{A.A}" [] ""
-    , Test "{a.a}" [] ""
-    , Test "{0.0}" [] ""
-    , Test "{_._}" [] ""
-    , Test "{%aa.%aa}" [] ""
-    , Test "{.}" [] noParse
-    , Test "{a.}" [] noParse
-    , Test "{+.a}" [] noParse
-    , Test "{a..b}" [] noParse
-    , Test "{%00}" [] ""
-    , Test "{%}" [] noParse
-    , Test "{%0}" [] noParse
-    , Test "{%0z}" [] noParse
-    , Test "{%z}" [] noParse
-    , Test "{!}" [] noParse
-    , Test "{" [] noParse
-    , Test "{{}" [] noParse
-    , Test "}" [] noParse
-    , Test "{}}" [] noParse
-    , Test "{a,b}" [] ""
-    , Test "{a,b,c,d}" [] ""
-    , Test "{a,a}" [] ""
-    , Test "{a:5}" [] ""
-    , Test "{a:67}" [] ""
-    , Test "{a:801}" [] ""
-    , Test "{a:234}" [] ""
-    , Test "{a:9999}" [] ""
-    , Test "{a:123}" ["a" =: s (replicate 200 'a')] . Output . Just $ replicate 123 'a'
-    , Test "{a:}" [] noParse
-    , Test "{a:0}" [] noParse
-    , Test "{a:10000}" [] noParse
-    , Test "{a:-1}" [] noParse
-    , Test "{a*}" [] ""
-    , Test "{a:1*}" [] noParse
-    , Test "{a*:1}" [] noParse
-    , Test "{a,b:1,c*}" [] ""
-    , Test "{+a}" [] ""
-    , Test "{#a}" [] ""
-    , Test "{.a}" [] ""
-    , Test "{/a}" [] ""
-    , Test "{;a}" [] ""
-    , Test "{?a}" [] ""
-    , Test "{&a}" [] ""
-    , Test "{=a}" [] noParse
-    , Test "{,a}" [] noParse
-    , Test "{!a}" [] noParse
-    , Test "{@a}" [] noParse
-    , Test "{|a}" [] noParse
-    , Test "{+#a}" [] noParse
-    , Test "{+a,#b}" [] noParse
-    , Test "{+a:1}" [] ""
-    , Test "{#a*}" [] ""
-    , Test "{+a,b}" [] ""
-    , Test "{#a,b}" [] ""
-    , Test "{.a,b}" [] ""
-    , Test "{/a,b}" [] ""
-    , Test "{;a,b}" [] ""
-    , Test "{?a,b}" [] ""
-    , Test "{&a,b}" [] ""
-    , Test "{a}{b}" [] ""
-    , Test "{a}{b}{c}{d}" [] ""
-    , Test "{a}{a}" [] ""
-    , Test "{{}}" [] noParse
-    , Test "{a{b}}" [] noParse
-    , Test "{{a}b}" [] noParse
-    , Test "{a{b}c}" [] noParse
-    , Test "a{b}" [] "a"
-    , Test "{a}b" [] "b"
-    , Test "a{b}c" [] "ac"
-    , Test "{a}b{c}" [] "b"
-    , Test "{a}" [] ""
-    , Test "{+a}" [] ""
-    , Test "{#a}" [] ""
-    , Test "{.a}" [] ""
-    , Test "{/a}" [] ""
-    , Test "{;a}" [] ""
-    , Test "{?a}" [] ""
-    , Test "{&a}" [] ""
-    , Test "http://example.com/~{username}/" ["username" =: s "fred"] "http://example.com/~fred/"
-    , Test "http://example.com/~{username}/" ["username" =: s "mark"] "http://example.com/~mark/"
-    , Test "http://example.com/dictionary/{term:1}/{term}" ["term" =: s "cat"] "http://example.com/dictionary/c/cat"
-    , Test "http://example.com/dictionary/{term:1}/{term}" ["term" =: s "dog"] "http://example.com/dictionary/d/dog"
-    , Test "http://example.com/search{?q,lang}" ["q" =: s "cat", "lang" =: s "en"] "http://example.com/search?q=cat&lang=en"
-    , Test "http://example.com/search{?q,lang}" ["q" =: s "chien", "lang" =: s "fr"] "http://example.com/search?q=chien&lang=fr"
-    , Test "http://www.example.com/foo{?query,number}" ["query" =: s "mycelium", "number" =: s "100"] "http://www.example.com/foo?query=mycelium&number=100"
-    , Test "http://www.example.com/foo{?query,number}" ["number" =: s "100"] "http://www.example.com/foo?number=100"
-    , Test "http://www.example.com/foo{?query,number}" [] "http://www.example.com/foo"
-    , Test "{a}" [] ""
-    , Test "{a}" ["a" =: l []] ""
-    , Test "{a}" ["a" =: d []] ""
-    , Test "{a}" ["a" =: s ""] ""
-    , Test "{a}" ["a" =: s "A"] "A"
-    , Test "{a}" ["a" =: s "~"] "~"
-    , Test "{a}" ["a" =: s "%"] "%25"
-    , Test "{a}" ["a" =: s "?"] "%3F"
-    , Test "{a}" ["a" =: s "&"] "%26"
-    , Test "{a}" ["a" =: s "\xa0"] "%C2%A0"
-    , Test "{a}" ["a" =: s "\xd7ff"] "%ED%9F%BF"
-    , Test "{a}" ["a" =: s "\x10000"] "%F0%90%80%80"
-    , Test "{a}" ["a" =: l ["A"]] "A"
-    , Test "{a}" ["a" =: l ["A", "B"]] "A,B"
-    , Test "{a}" ["a" =: l ["%"]] "%25"
-    , Test "{a}" ["a" =: l ["\xa0"]] "%C2%A0"
-    , Test "{a}" ["a" =: d ["A" =: "1"]] "A,1"
-    , Test "{a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "A,1,B,2"
-    , Test "{a}" ["a" =: d ["A" =: "%"]] "A,%25"
-    , Test "{a}" ["a" =: d ["A" =: "\xa0"]] "A,%C2%A0"
-    , Test "{a}" ["a" =: d ["%" =: "1"]] "%25,1"
-    , Test "{a*}" [] ""
-    , Test "{a*}" ["a" =: s ""] ""
-    , Test "{a*}" ["a" =: s "A"] "A"
-    , Test "{a*}" ["a" =: l []] ""
-    , Test "{a*}" ["a" =: l ["A"]] "A"
-    , Test "{a*}" ["a" =: l ["A", "B"]] "A,B"
-    , Test "{a*}" ["a" =: d []] ""
-    , Test "{a*}" ["a" =: d ["A" =: "1"]] "A=1"
-    , Test "{a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "A=1,B=2"
-    , Test "{a:1}" [] ""
-    , Test "{a:1}" ["a" =: s ""] ""
-    , Test "{a:1}" ["a" =: s "A"] "A"
-    , Test "{a:1}" ["a" =: s "AB"] "A"
-    , Test "{a:1}" ["a" =: s "%B"] "%25"
-    , Test "{a:1}" ["a" =: s "\xa0\&B"] "%C2%A0"
-    , Test "{a:1}" ["a" =: s "\xd7ff\&B"] "%ED%9F%BF"
-    , Test "{a:1}" ["a" =: s "\x10000\&B"] "%F0%90%80%80"
-    , Test "{a:1}" ["a" =: l []] ""
-    , Test "{a:1}" ["a" =: l ["AB"]] "AB"
-    , Test "{a:1}" ["a" =: l ["AB", "CD"]] "AB,CD"
-    , Test "{a:1}" ["a" =: d []] ""
-    , Test "{a:1}" ["a" =: d ["AB" =: "12"]] "AB,12"
-    , Test "{a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "AB,12,CD,34"
-    , Test "{a,a}" [] ""
-    , Test "{a,a}" ["a" =: l []] ""
-    , Test "{a,a}" ["a" =: d []] ""
-    , Test "{a,a}" ["a" =: s ""] ","
-    , Test "{a,b}" ["a" =: s ""] ""
-    , Test "{a,b}" ["b" =: s ""] ""
-    , Test "{%aa}" ["%aa" =: s "A"] "A"
-    , Test "{%aa}" ["%aa" =: l ["A", "B"]] "A,B"
-    , Test "{%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "A,1,B,2"
-    , Test "{%aa*}" ["%aa" =: s "A"] "A"
-    , Test "{%aa*}" ["%aa" =: l ["A", "B"]] "A,B"
-    , Test "{%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "A=1,B=2"
-    , Test "{+a}" [] ""
-    , Test "{+a}" ["a" =: l []] ""
-    , Test "{+a}" ["a" =: d []] ""
-    , Test "{+a}" ["a" =: s ""] ""
-    , Test "{+a}" ["a" =: s "A"] "A"
-    , Test "{+a}" ["a" =: s "~"] "~"
-    , Test "{+a}" ["a" =: s "%"] "%25"
-    , Test "{+a}" ["a" =: s "?"] "?"
-    , Test "{+a}" ["a" =: s "&"] "&"
-    , Test "{+a}" ["a" =: s "\xa0"] "%C2%A0"
-    , Test "{+a}" ["a" =: s "\xd7ff"] "%ED%9F%BF"
-    , Test "{+a}" ["a" =: s "\x10000"] "%F0%90%80%80"
-    , Test "{+a}" ["a" =: l ["A"]] "A"
-    , Test "{+a}" ["a" =: l ["A", "B"]] "A,B"
-    , Test "{+a}" ["a" =: l ["%"]] "%25"
-    , Test "{+a}" ["a" =: l ["\xa0"]] "%C2%A0"
-    , Test "{+a}" ["a" =: d ["A" =: "1"]] "A,1"
-    , Test "{+a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "A,1,B,2"
-    , Test "{+a}" ["a" =: d ["A" =: "%"]] "A,%25"
-    , Test "{+a}" ["a" =: d ["A" =: "\xa0"]] "A,%C2%A0"
-    , Test "{+a}" ["a" =: d ["%" =: "1"]] "%25,1"
-    , Test "{+a*}" [] ""
-    , Test "{+a*}" ["a" =: s ""] ""
-    , Test "{+a*}" ["a" =: s "A"] "A"
-    , Test "{+a*}" ["a" =: l []] ""
-    , Test "{+a*}" ["a" =: l ["A"]] "A"
-    , Test "{+a*}" ["a" =: l ["A", "B"]] "A,B"
-    , Test "{+a*}" ["a" =: d []] ""
-    , Test "{+a*}" ["a" =: d ["A" =: "1"]] "A=1"
-    , Test "{+a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "A=1,B=2"
-    , Test "{+a:1}" [] ""
-    , Test "{+a:1}" ["a" =: s ""] ""
-    , Test "{+a:1}" ["a" =: s "A"] "A"
-    , Test "{+a:1}" ["a" =: s "AB"] "A"
-    , Test "{+a:1}" ["a" =: s "%B"] "%25"
-    , Test "{+a:1}" ["a" =: s "\xa0\&B"] "%C2%A0"
-    , Test "{+a:1}" ["a" =: s "\xd7ff\&B"] "%ED%9F%BF"
-    , Test "{+a:1}" ["a" =: s "\x10000\&B"] "%F0%90%80%80"
-    , Test "{+a:1}" ["a" =: l []] ""
-    , Test "{+a:1}" ["a" =: l ["AB"]] "AB"
-    , Test "{+a:1}" ["a" =: l ["AB", "CD"]] "AB,CD"
-    , Test "{+a:1}" ["a" =: d []] ""
-    , Test "{+a:1}" ["a" =: d ["AB" =: "12"]] "AB,12"
-    , Test "{+a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "AB,12,CD,34"
-    , Test "{+a,a}" [] ""
-    , Test "{+a,a}" ["a" =: l []] ""
-    , Test "{+a,a}" ["a" =: d []] ""
-    , Test "{+a,a}" ["a" =: s ""] ","
-    , Test "{+a,b}" ["a" =: s ""] ""
-    , Test "{+a,b}" ["b" =: s ""] ""
-    , Test "{+%aa}" ["%aa" =: s "A"] "A"
-    , Test "{+%aa}" ["%aa" =: l ["A", "B"]] "A,B"
-    , Test "{+%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "A,1,B,2"
-    , Test "{+%aa*}" ["%aa" =: s "A"] "A"
-    , Test "{+%aa*}" ["%aa" =: l ["A", "B"]] "A,B"
-    , Test "{+%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "A=1,B=2"
-    , Test "{#a}" [] ""
-    , Test "{#a}" ["a" =: l []] ""
-    , Test "{#a}" ["a" =: d []] ""
-    , Test "{#a}" ["a" =: s ""] "#"
-    , Test "{#a}" ["a" =: s "A"] "#A"
-    , Test "{#a}" ["a" =: s "~"] "#~"
-    , Test "{#a}" ["a" =: s "%"] "#%25"
-    , Test "{#a}" ["a" =: s "?"] "#?"
-    , Test "{#a}" ["a" =: s "&"] "#&"
-    , Test "{#a}" ["a" =: s "\xa0"] "#%C2%A0"
-    , Test "{#a}" ["a" =: s "\xd7ff"] "#%ED%9F%BF"
-    , Test "{#a}" ["a" =: s "\x10000"] "#%F0%90%80%80"
-    , Test "{#a}" ["a" =: l ["A"]] "#A"
-    , Test "{#a}" ["a" =: l ["A", "B"]] "#A,B"
-    , Test "{#a}" ["a" =: l ["%"]] "#%25"
-    , Test "{#a}" ["a" =: l ["\xa0"]] "#%C2%A0"
-    , Test "{#a}" ["a" =: d ["A" =: "1"]] "#A,1"
-    , Test "{#a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "#A,1,B,2"
-    , Test "{#a}" ["a" =: d ["A" =: "%"]] "#A,%25"
-    , Test "{#a}" ["a" =: d ["A" =: "\xa0"]] "#A,%C2%A0"
-    , Test "{#a}" ["a" =: d ["%" =: "1"]] "#%25,1"
-    , Test "{#a*}" [] ""
-    , Test "{#a*}" ["a" =: s ""] "#"
-    , Test "{#a*}" ["a" =: s "A"] "#A"
-    , Test "{#a*}" ["a" =: l []] ""
-    , Test "{#a*}" ["a" =: l ["A"]] "#A"
-    , Test "{#a*}" ["a" =: l ["A", "B"]] "#A,B"
-    , Test "{#a*}" ["a" =: d []] ""
-    , Test "{#a*}" ["a" =: d ["A" =: "1"]] "#A=1"
-    , Test "{#a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "#A=1,B=2"
-    , Test "{#a:1}" [] ""
-    , Test "{#a:1}" ["a" =: s ""] "#"
-    , Test "{#a:1}" ["a" =: s "A"] "#A"
-    , Test "{#a:1}" ["a" =: s "AB"] "#A"
-    , Test "{#a:1}" ["a" =: s "%B"] "#%25"
-    , Test "{#a:1}" ["a" =: s "\xa0\&B"] "#%C2%A0"
-    , Test "{#a:1}" ["a" =: s "\xd7ff\&B"] "#%ED%9F%BF"
-    , Test "{#a:1}" ["a" =: s "\x10000\&B"] "#%F0%90%80%80"
-    , Test "{#a:1}" ["a" =: l []] ""
-    , Test "{#a:1}" ["a" =: l ["AB"]] "#AB"
-    , Test "{#a:1}" ["a" =: l ["AB", "CD"]] "#AB,CD"
-    , Test "{#a:1}" ["a" =: d []] ""
-    , Test "{#a:1}" ["a" =: d ["AB" =: "12"]] "#AB,12"
-    , Test "{#a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "#AB,12,CD,34"
-    , Test "{#a,a}" [] ""
-    , Test "{#a,a}" ["a" =: l []] ""
-    , Test "{#a,a}" ["a" =: d []] ""
-    , Test "{#a,a}" ["a" =: s ""] "#,"
-    , Test "{#a,b}" ["a" =: s ""] "#"
-    , Test "{#a,b}" ["b" =: s ""] "#"
-    , Test "{#%aa}" ["%aa" =: s "A"] "#A"
-    , Test "{#%aa}" ["%aa" =: l ["A", "B"]] "#A,B"
-    , Test "{#%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "#A,1,B,2"
-    , Test "{#%aa*}" ["%aa" =: s "A"] "#A"
-    , Test "{#%aa*}" ["%aa" =: l ["A", "B"]] "#A,B"
-    , Test "{#%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "#A=1,B=2"
-    , Test "{.a}" [] ""
-    , Test "{.a}" ["a" =: l []] ""
-    , Test "{.a}" ["a" =: d []] ""
-    , Test "{.a}" ["a" =: s ""] "."
-    , Test "{.a}" ["a" =: s "A"] ".A"
-    , Test "{.a}" ["a" =: s "~"] ".~"
-    , Test "{.a}" ["a" =: s "%"] ".%25"
-    , Test "{.a}" ["a" =: s "?"] ".%3F"
-    , Test "{.a}" ["a" =: s "&"] ".%26"
-    , Test "{.a}" ["a" =: s "\xa0"] ".%C2%A0"
-    , Test "{.a}" ["a" =: s "\xd7ff"] ".%ED%9F%BF"
-    , Test "{.a}" ["a" =: s "\x10000"] ".%F0%90%80%80"
-    , Test "{.a}" ["a" =: l ["A"]] ".A"
-    , Test "{.a}" ["a" =: l ["A", "B"]] ".A,B"
-    , Test "{.a}" ["a" =: l ["%"]] ".%25"
-    , Test "{.a}" ["a" =: l ["\xa0"]] ".%C2%A0"
-    , Test "{.a}" ["a" =: d ["A" =: "1"]] ".A,1"
-    , Test "{.a}" ["a" =: d ["A" =: "1", "B" =: "2"]] ".A,1,B,2"
-    , Test "{.a}" ["a" =: d ["A" =: "%"]] ".A,%25"
-    , Test "{.a}" ["a" =: d ["A" =: "\xa0"]] ".A,%C2%A0"
-    , Test "{.a}" ["a" =: d ["%" =: "1"]] ".%25,1"
-    , Test "{.a*}" [] ""
-    , Test "{.a*}" ["a" =: s ""] "."
-    , Test "{.a*}" ["a" =: s "A"] ".A"
-    , Test "{.a*}" ["a" =: l []] ""
-    , Test "{.a*}" ["a" =: l ["A"]] ".A"
-    , Test "{.a*}" ["a" =: l ["A", "B"]] ".A.B"
-    , Test "{.a*}" ["a" =: d []] ""
-    , Test "{.a*}" ["a" =: d ["A" =: "1"]] ".A=1"
-    , Test "{.a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] ".A=1.B=2"
-    , Test "{.a:1}" [] ""
-    , Test "{.a:1}" ["a" =: s ""] "."
-    , Test "{.a:1}" ["a" =: s "A"] ".A"
-    , Test "{.a:1}" ["a" =: s "AB"] ".A"
-    , Test "{.a:1}" ["a" =: s "%B"] ".%25"
-    , Test "{.a:1}" ["a" =: s "\xa0\&B"] ".%C2%A0"
-    , Test "{.a:1}" ["a" =: s "\xd7ff\&B"] ".%ED%9F%BF"
-    , Test "{.a:1}" ["a" =: s "\x10000\&B"] ".%F0%90%80%80"
-    , Test "{.a:1}" ["a" =: l []] ""
-    , Test "{.a:1}" ["a" =: l ["AB"]] ".AB"
-    , Test "{.a:1}" ["a" =: l ["AB", "CD"]] ".AB,CD"
-    , Test "{.a:1}" ["a" =: d []] ""
-    , Test "{.a:1}" ["a" =: d ["AB" =: "12"]] ".AB,12"
-    , Test "{.a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] ".AB,12,CD,34"
-    , Test "{.a,a}" [] ""
-    , Test "{.a,a}" ["a" =: l []] ""
-    , Test "{.a,a}" ["a" =: d []] ""
-    , Test "{.a,a}" ["a" =: s ""] ".."
-    , Test "{.a,b}" ["a" =: s ""] "."
-    , Test "{.a,b}" ["b" =: s ""] "."
-    , Test "{.%aa}" ["%aa" =: s "A"] ".A"
-    , Test "{.%aa}" ["%aa" =: l ["A", "B"]] ".A,B"
-    , Test "{.%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] ".A,1,B,2"
-    , Test "{.%aa*}" ["%aa" =: s "A"] ".A"
-    , Test "{.%aa*}" ["%aa" =: l ["A", "B"]] ".A.B"
-    , Test "{.%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] ".A=1.B=2"
-    , Test "{/a}" [] ""
-    , Test "{/a}" ["a" =: l []] ""
-    , Test "{/a}" ["a" =: d []] ""
-    , Test "{/a}" ["a" =: s ""] "/"
-    , Test "{/a}" ["a" =: s "A"] "/A"
-    , Test "{/a}" ["a" =: s "~"] "/~"
-    , Test "{/a}" ["a" =: s "%"] "/%25"
-    , Test "{/a}" ["a" =: s "?"] "/%3F"
-    , Test "{/a}" ["a" =: s "&"] "/%26"
-    , Test "{/a}" ["a" =: s "\xa0"] "/%C2%A0"
-    , Test "{/a}" ["a" =: s "\xd7ff"] "/%ED%9F%BF"
-    , Test "{/a}" ["a" =: s "\x10000"] "/%F0%90%80%80"
-    , Test "{/a}" ["a" =: l ["A"]] "/A"
-    , Test "{/a}" ["a" =: l ["A", "B"]] "/A,B"
-    , Test "{/a}" ["a" =: l ["%"]] "/%25"
-    , Test "{/a}" ["a" =: l ["\xa0"]] "/%C2%A0"
-    , Test "{/a}" ["a" =: d ["A" =: "1"]] "/A,1"
-    , Test "{/a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "/A,1,B,2"
-    , Test "{/a}" ["a" =: d ["A" =: "%"]] "/A,%25"
-    , Test "{/a}" ["a" =: d ["A" =: "\xa0"]] "/A,%C2%A0"
-    , Test "{/a}" ["a" =: d ["%" =: "1"]] "/%25,1"
-    , Test "{/a*}" [] ""
-    , Test "{/a*}" ["a" =: s ""] "/"
-    , Test "{/a*}" ["a" =: s "A"] "/A"
-    , Test "{/a*}" ["a" =: l []] ""
-    , Test "{/a*}" ["a" =: l ["A"]] "/A"
-    , Test "{/a*}" ["a" =: l ["A", "B"]] "/A/B"
-    , Test "{/a*}" ["a" =: d []] ""
-    , Test "{/a*}" ["a" =: d ["A" =: "1"]] "/A=1"
-    , Test "{/a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "/A=1/B=2"
-    , Test "{/a:1}" [] ""
-    , Test "{/a:1}" ["a" =: s ""] "/"
-    , Test "{/a:1}" ["a" =: s "A"] "/A"
-    , Test "{/a:1}" ["a" =: s "AB"] "/A"
-    , Test "{/a:1}" ["a" =: s "%B"] "/%25"
-    , Test "{/a:1}" ["a" =: s "\xa0\&B"] "/%C2%A0"
-    , Test "{/a:1}" ["a" =: s "\xd7ff\&B"] "/%ED%9F%BF"
-    , Test "{/a:1}" ["a" =: s "\x10000\&B"] "/%F0%90%80%80"
-    , Test "{/a:1}" ["a" =: l []] ""
-    , Test "{/a:1}" ["a" =: l ["AB"]] "/AB"
-    , Test "{/a:1}" ["a" =: l ["AB", "CD"]] "/AB,CD"
-    , Test "{/a:1}" ["a" =: d []] ""
-    , Test "{/a:1}" ["a" =: d ["AB" =: "12"]] "/AB,12"
-    , Test "{/a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "/AB,12,CD,34"
-    , Test "{/a,a}" [] ""
-    , Test "{/a,a}" ["a" =: l []] ""
-    , Test "{/a,a}" ["a" =: d []] ""
-    , Test "{/a,a}" ["a" =: s ""] "//"
-    , Test "{/a,b}" ["a" =: s ""] "/"
-    , Test "{/a,b}" ["b" =: s ""] "/"
-    , Test "{/%aa}" ["%aa" =: s "A"] "/A"
-    , Test "{/%aa}" ["%aa" =: l ["A", "B"]] "/A,B"
-    , Test "{/%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "/A,1,B,2"
-    , Test "{/%aa*}" ["%aa" =: s "A"] "/A"
-    , Test "{/%aa*}" ["%aa" =: l ["A", "B"]] "/A/B"
-    , Test "{/%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "/A=1/B=2"
-    , Test "{;a}" [] ""
-    , Test "{;a}" ["a" =: l []] ""
-    , Test "{;a}" ["a" =: d []] ""
-    , Test "{;a}" ["a" =: s ""] ";a"
-    , Test "{;a}" ["a" =: s "A"] ";a=A"
-    , Test "{;a}" ["a" =: s "~"] ";a=~"
-    , Test "{;a}" ["a" =: s "%"] ";a=%25"
-    , Test "{;a}" ["a" =: s "?"] ";a=%3F"
-    , Test "{;a}" ["a" =: s "&"] ";a=%26"
-    , Test "{;a}" ["a" =: s "\xa0"] ";a=%C2%A0"
-    , Test "{;a}" ["a" =: s "\xd7ff"] ";a=%ED%9F%BF"
-    , Test "{;a}" ["a" =: s "\x10000"] ";a=%F0%90%80%80"
-    , Test "{;a}" ["a" =: l ["A"]] ";a=A"
-    , Test "{;a}" ["a" =: l ["A", "B"]] ";a=A,B"
-    , Test "{;a}" ["a" =: l ["%"]] ";a=%25"
-    , Test "{;a}" ["a" =: l ["\xa0"]] ";a=%C2%A0"
-    , Test "{;a}" ["a" =: d ["A" =: "1"]] ";a=A,1"
-    , Test "{;a}" ["a" =: d ["A" =: "1", "B" =: "2"]] ";a=A,1,B,2"
-    , Test "{;a}" ["a" =: d ["A" =: "%"]] ";a=A,%25"
-    , Test "{;a}" ["a" =: d ["A" =: "\xa0"]] ";a=A,%C2%A0"
-    , Test "{;a}" ["a" =: d ["%" =: "1"]] ";a=%25,1"
-    , Test "{;a*}" [] ""
-    , Test "{;a*}" ["a" =: s ""] ";a"
-    , Test "{;a*}" ["a" =: s "A"] ";a=A"
-    , Test "{;a*}" ["a" =: l []] ""
-    , Test "{;a*}" ["a" =: l ["A"]] ";a=A"
-    , Test "{;a*}" ["a" =: l ["A", "B"]] ";a=A;a=B"
-    , Test "{;a*}" ["a" =: d []] ""
-    , Test "{;a*}" ["a" =: d ["A" =: "1"]] ";A=1"
-    , Test "{;a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] ";A=1;B=2"
-    , Test "{;a:1}" [] ""
-    , Test "{;a:1}" ["a" =: s ""] ";a"
-    , Test "{;a:1}" ["a" =: s "A"] ";a=A"
-    , Test "{;a:1}" ["a" =: s "AB"] ";a=A"
-    , Test "{;a:1}" ["a" =: s "%B"] ";a=%25"
-    , Test "{;a:1}" ["a" =: s "\xa0\&B"] ";a=%C2%A0"
-    , Test "{;a:1}" ["a" =: s "\xd7ff\&B"] ";a=%ED%9F%BF"
-    , Test "{;a:1}" ["a" =: s "\x10000\&B"] ";a=%F0%90%80%80"
-    , Test "{;a:1}" ["a" =: l []] ""
-    , Test "{;a:1}" ["a" =: l ["AB"]] ";a=AB"
-    , Test "{;a:1}" ["a" =: l ["AB", "CD"]] ";a=AB,CD"
-    , Test "{;a:1}" ["a" =: d []] ""
-    , Test "{;a:1}" ["a" =: d ["AB" =: "12"]] ";a=AB,12"
-    , Test "{;a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] ";a=AB,12,CD,34"
-    , Test "{;a,a}" [] ""
-    , Test "{;a,a}" ["a" =: l []] ""
-    , Test "{;a,a}" ["a" =: d []] ""
-    , Test "{;a,a}" ["a" =: s ""] ";a;a"
-    , Test "{;a,b}" ["a" =: s ""] ";a"
-    , Test "{;a,b}" ["b" =: s ""] ";b"
-    , Test "{;%aa}" ["%aa" =: s "A"] ";%aa=A"
-    , Test "{;%aa}" ["%aa" =: l ["A", "B"]] ";%aa=A,B"
-    , Test "{;%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] ";%aa=A,1,B,2"
-    , Test "{;%aa*}" ["%aa" =: s "A"] ";%aa=A"
-    , Test "{;%aa*}" ["%aa" =: l ["A", "B"]] ";%aa=A;%aa=B"
-    , Test "{;%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] ";A=1;B=2"
-    , Test "{?a}" [] ""
-    , Test "{?a}" ["a" =: l []] ""
-    , Test "{?a}" ["a" =: d []] ""
-    , Test "{?a}" ["a" =: s ""] "?a="
-    , Test "{?a}" ["a" =: s "A"] "?a=A"
-    , Test "{?a}" ["a" =: s "~"] "?a=~"
-    , Test "{?a}" ["a" =: s "%"] "?a=%25"
-    , Test "{?a}" ["a" =: s "?"] "?a=%3F"
-    , Test "{?a}" ["a" =: s "&"] "?a=%26"
-    , Test "{?a}" ["a" =: s "\xa0"] "?a=%C2%A0"
-    , Test "{?a}" ["a" =: s "\xd7ff"] "?a=%ED%9F%BF"
-    , Test "{?a}" ["a" =: s "\x10000"] "?a=%F0%90%80%80"
-    , Test "{?a}" ["a" =: l ["A"]] "?a=A"
-    , Test "{?a}" ["a" =: l ["A", "B"]] "?a=A,B"
-    , Test "{?a}" ["a" =: l ["%"]] "?a=%25"
-    , Test "{?a}" ["a" =: l ["\xa0"]] "?a=%C2%A0"
-    , Test "{?a}" ["a" =: d ["A" =: "1"]] "?a=A,1"
-    , Test "{?a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "?a=A,1,B,2"
-    , Test "{?a}" ["a" =: d ["A" =: "%"]] "?a=A,%25"
-    , Test "{?a}" ["a" =: d ["A" =: "\xa0"]] "?a=A,%C2%A0"
-    , Test "{?a}" ["a" =: d ["%" =: "1"]] "?a=%25,1"
-    , Test "{?a*}" [] ""
-    , Test "{?a*}" ["a" =: s ""] "?a="
-    , Test "{?a*}" ["a" =: s "A"] "?a=A"
-    , Test "{?a*}" ["a" =: l []] ""
-    , Test "{?a*}" ["a" =: l ["A"]] "?a=A"
-    , Test "{?a*}" ["a" =: l ["A", "B"]] "?a=A&a=B"
-    , Test "{?a*}" ["a" =: d []] ""
-    , Test "{?a*}" ["a" =: d ["A" =: "1"]] "?A=1"
-    , Test "{?a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "?A=1&B=2"
-    , Test "{?a:1}" [] ""
-    , Test "{?a:1}" ["a" =: s ""] "?a="
-    , Test "{?a:1}" ["a" =: s "A"] "?a=A"
-    , Test "{?a:1}" ["a" =: s "AB"] "?a=A"
-    , Test "{?a:1}" ["a" =: s "%B"] "?a=%25"
-    , Test "{?a:1}" ["a" =: s "\xa0\&B"] "?a=%C2%A0"
-    , Test "{?a:1}" ["a" =: s "\xd7ff\&B"] "?a=%ED%9F%BF"
-    , Test "{?a:1}" ["a" =: s "\x10000\&B"] "?a=%F0%90%80%80"
-    , Test "{?a:1}" ["a" =: l []] ""
-    , Test "{?a:1}" ["a" =: l ["AB"]] "?a=AB"
-    , Test "{?a:1}" ["a" =: l ["AB", "CD"]] "?a=AB,CD"
-    , Test "{?a:1}" ["a" =: d []] ""
-    , Test "{?a:1}" ["a" =: d ["AB" =: "12"]] "?a=AB,12"
-    , Test "{?a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "?a=AB,12,CD,34"
-    , Test "{?a,a}" [] ""
-    , Test "{?a,a}" ["a" =: l []] ""
-    , Test "{?a,a}" ["a" =: d []] ""
-    , Test "{?a,a}" ["a" =: s ""] "?a=&a="
-    , Test "{?a,b}" ["a" =: s ""] "?a="
-    , Test "{?a,b}" ["b" =: s ""] "?b="
-    , Test "{?%aa}" ["%aa" =: s "A"] "?%aa=A"
-    , Test "{?%aa}" ["%aa" =: l ["A", "B"]] "?%aa=A,B"
-    , Test "{?%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "?%aa=A,1,B,2"
-    , Test "{?%aa*}" ["%aa" =: s "A"] "?%aa=A"
-    , Test "{?%aa*}" ["%aa" =: l ["A", "B"]] "?%aa=A&%aa=B"
-    , Test "{?%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "?A=1&B=2"
-    , Test "{&a}" [] ""
-    , Test "{&a}" ["a" =: l []] ""
-    , Test "{&a}" ["a" =: d []] ""
-    , Test "{&a}" ["a" =: s ""] "&a="
-    , Test "{&a}" ["a" =: s "A"] "&a=A"
-    , Test "{&a}" ["a" =: s "~"] "&a=~"
-    , Test "{&a}" ["a" =: s "%"] "&a=%25"
-    , Test "{&a}" ["a" =: s "?"] "&a=%3F"
-    , Test "{&a}" ["a" =: s "&"] "&a=%26"
-    , Test "{&a}" ["a" =: s "\xa0"] "&a=%C2%A0"
-    , Test "{&a}" ["a" =: s "\xd7ff"] "&a=%ED%9F%BF"
-    , Test "{&a}" ["a" =: s "\x10000"] "&a=%F0%90%80%80"
-    , Test "{&a}" ["a" =: l ["A"]] "&a=A"
-    , Test "{&a}" ["a" =: l ["A", "B"]] "&a=A,B"
-    , Test "{&a}" ["a" =: l ["%"]] "&a=%25"
-    , Test "{&a}" ["a" =: l ["\xa0"]] "&a=%C2%A0"
-    , Test "{&a}" ["a" =: d ["A" =: "1"]] "&a=A,1"
-    , Test "{&a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "&a=A,1,B,2"
-    , Test "{&a}" ["a" =: d ["A" =: "%"]] "&a=A,%25"
-    , Test "{&a}" ["a" =: d ["A" =: "\xa0"]] "&a=A,%C2%A0"
-    , Test "{&a}" ["a" =: d ["%" =: "1"]] "&a=%25,1"
-    , Test "{&a*}" [] ""
-    , Test "{&a*}" ["a" =: s ""] "&a="
-    , Test "{&a*}" ["a" =: s "A"] "&a=A"
-    , Test "{&a*}" ["a" =: l []] ""
-    , Test "{&a*}" ["a" =: l ["A"]] "&a=A"
-    , Test "{&a*}" ["a" =: l ["A", "B"]] "&a=A&a=B"
-    , Test "{&a*}" ["a" =: d []] ""
-    , Test "{&a*}" ["a" =: d ["A" =: "1"]] "&A=1"
-    , Test "{&a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "&A=1&B=2"
-    , Test "{&a:1}" [] ""
-    , Test "{&a:1}" ["a" =: s ""] "&a="
-    , Test "{&a:1}" ["a" =: s "A"] "&a=A"
-    , Test "{&a:1}" ["a" =: s "AB"] "&a=A"
-    , Test "{&a:1}" ["a" =: s "%B"] "&a=%25"
-    , Test "{&a:1}" ["a" =: s "\xa0\&B"] "&a=%C2%A0"
-    , Test "{&a:1}" ["a" =: s "\xd7ff\&B"] "&a=%ED%9F%BF"
-    , Test "{&a:1}" ["a" =: s "\x10000\&B"] "&a=%F0%90%80%80"
-    , Test "{&a:1}" ["a" =: l []] ""
-    , Test "{&a:1}" ["a" =: l ["AB"]] "&a=AB"
-    , Test "{&a:1}" ["a" =: l ["AB", "CD"]] "&a=AB,CD"
-    , Test "{&a:1}" ["a" =: d []] ""
-    , Test "{&a:1}" ["a" =: d ["AB" =: "12"]] "&a=AB,12"
-    , Test "{&a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "&a=AB,12,CD,34"
-    , Test "{&a,a}" [] ""
-    , Test "{&a,a}" ["a" =: l []] ""
-    , Test "{&a,a}" ["a" =: d []] ""
-    , Test "{&a,a}" ["a" =: s ""] "&a=&a="
-    , Test "{&a,b}" ["a" =: s ""] "&a="
-    , Test "{&a,b}" ["b" =: s ""] "&b="
-    , Test "{&%aa}" ["%aa" =: s "A"] "&%aa=A"
-    , Test "{&%aa}" ["%aa" =: l ["A", "B"]] "&%aa=A,B"
-    , Test "{&%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "&%aa=A,1,B,2"
-    , Test "{&%aa*}" ["%aa" =: s "A"] "&%aa=A"
-    , Test "{&%aa*}" ["%aa" =: l ["A", "B"]] "&%aa=A&%aa=B"
-    , Test "{&%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "&A=1&B=2"
-    ]
-  , let values = ["%AA" =: s "1", "%Aa" =: s "2", "%aA" =: s "3", "%aa" =: s "4"]
-    in
-      [ Test "{%AA}" values "1"
-      , Test "{%Aa}" values "2"
-      , Test "{%aA}" values "3"
-      , Test "{%aa}" values "4"
-          -- This comment forces Brittany to use a multi-line layout.
-      ]
-  , let values = ["a" =: s "abcdefghijklmnopqrstuvwxyz"]
-    in
-      [ Test "{a:1}" values "a"
-      , Test "{a:5}" values "abcde"
-      , Test "{a:10}" values "abcdefghij"
-      , Test "{a:15}" values "abcdefghijklmno"
-      , Test "{a:20}" values "abcdefghijklmnopqrst"
-      , Test "{a:25}" values "abcdefghijklmnopqrstuvwxy"
-      , Test "{a:26}" values "abcdefghijklmnopqrstuvwxyz"
-      , Test "{a:30}" values "abcdefghijklmnopqrstuvwxyz"
-      ]
-  , let values = ["a" =: l []]
-    in
-      [ Test "{a}" values ""
-      , Test "{+a}" values ""
-      , Test "{#a}" values ""
-      , Test "{.a}" values ""
-      , Test "{/a}" values ""
-      , Test "{;a}" values ""
-      , Test "{?a}" values ""
-      , Test "{&a}" values ""
-      ]
-  , let values = ["a" =: d []]
-    in
-      [ Test "{a}" values ""
-      , Test "{+a}" values ""
-      , Test "{#a}" values ""
-      , Test "{.a}" values ""
-      , Test "{/a}" values ""
-      , Test "{;a}" values ""
-      , Test "{?a}" values ""
-      , Test "{&a}" values ""
-      ]
-  , let values = ["a" =: s ""]
-    in
-      [ Test "{a}" values ""
-      , Test "{+a}" values ""
-      , Test "{#a}" values "#"
-      , Test "{.a}" values "."
-      , Test "{/a}" values "/"
-      , Test "{;a}" values ";a"
-      , Test "{?a}" values "?a="
-      , Test "{&a}" values "&a="
-      ]
-  , let values = ["a" =: s "A"]
-    in
-      [ Test "{a}" values "A"
-      , Test "{+a}" values "A"
-      , Test "{#a}" values "#A"
-      , Test "{.a}" values ".A"
-      , Test "{/a}" values "/A"
-      , Test "{;a}" values ";a=A"
-      , Test "{?a}" values "?a=A"
-      , Test "{&a}" values "&a=A"
-      ]
-  , let values = ["b" =: s "B"]
-    in
-      [ Test "{a,b}" values "B"
-      , Test "{+a,b}" values "B"
-      , Test "{#a,b}" values "#B"
-      , Test "{.a,b}" values ".B"
-      , Test "{/a,b}" values "/B"
-      , Test "{;a,b}" values ";b=B"
-      , Test "{?a,b}" values "?b=B"
-      , Test "{&a,b}" values "&b=B"
-      ]
-  , let values = ["a" =: s ""]
-    in
-      [ Test "{a,a}" values ","
-      , Test "{+a,a}" values ","
-      , Test "{#a,a}" values "#,"
-      , Test "{.a,a}" values ".."
-      , Test "{/a,a}" values "//"
-      , Test "{;a,a}" values ";a;a"
-      , Test "{?a,a}" values "?a=&a="
-      , Test "{&a,a}" values "&a=&a="
-      ]
-  , let values = ["a" =: s "A", "b" =: s "B"]
-    in
-      [ Test "{a,b}" values "A,B"
-      , Test "{+a,b}" values "A,B"
-      , Test "{#a,b}" values "#A,B"
-      , Test "{.a,b}" values ".A.B"
-      , Test "{/a,b}" values "/A/B"
-      , Test "{;a,b}" values ";a=A;b=B"
-      , Test "{?a,b}" values "?a=A&b=B"
-      , Test "{&a,b}" values "&a=A&b=B"
-      ]
-  , let values = ["a" =: d ["K! \xa0\xd7ff\x10000" =: "V! \xa0\xd7ff\x10000"]]
-    in
-      [ Test "{a*}" values "K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80"
-      , Test "{+a*}" values "K!%20%C2%A0%ED%9F%BF%F0%90%80%80=V!%20%C2%A0%ED%9F%BF%F0%90%80%80"
-      , Test "{#a*}" values "#K!%20%C2%A0%ED%9F%BF%F0%90%80%80=V!%20%C2%A0%ED%9F%BF%F0%90%80%80"
-      , Test "{.a*}" values ".K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80"
-      , Test "{/a*}" values "/K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80"
-      , Test "{;a*}" values ";K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80"
-      , Test "{?a*}" values "?K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80"
-      , Test "{&a*}" values "&K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80"
-      ]
-  , let
-      values =
-        [ "empty" =: s ""
-        , "hello" =: s "Hello World!"
-        , "keys" =: d ["semi" =: ";", "dot" =: ".", "comma" =: ","]
-        , "list" =: l ["red", "green", "blue"]
-        , "path" =: s "/foo/bar"
-        , "var" =: s "value"
-        , "x" =: s "1024"
-        , "y" =: s "768"
-        ]
-    in
-      [ Test "{var}" values "value"
-      , Test "{hello}" values "Hello%20World%21"
-      , Test "{+var}" values "value"
-      , Test "{+hello}" values "Hello%20World!"
-      , Test "{+path}/here" values "/foo/bar/here"
-      , Test "here?ref={+path}" values "here?ref=/foo/bar"
-      , Test "X{#var}" values "X#value"
-      , Test "X{#hello}" values "X#Hello%20World!"
-      , Test "map?{x,y}" values "map?1024,768"
-      , Test "{x,hello,y}" values "1024,Hello%20World%21,768"
-      , Test "{+x,hello,y}" values "1024,Hello%20World!,768"
-      , Test "{+path,x}/here" values "/foo/bar,1024/here"
-      , Test "{#x,hello,y}" values "#1024,Hello%20World!,768"
-      , Test "{#path,x}/here" values "#/foo/bar,1024/here"
-      , Test "X{.var}" values "X.value"
-      , Test "X{.x,y}" values "X.1024.768"
-      , Test "{/var}" values "/value"
-      , Test "{/var,x}/here" values "/value/1024/here"
-      , Test "{;x,y}" values ";x=1024;y=768"
-      , Test "{;x,y,empty}" values ";x=1024;y=768;empty"
-      , Test "{?x,y}" values "?x=1024&y=768"
-      , Test "{?x,y,empty}" values "?x=1024&y=768&empty="
-      , Test "?fixed=yes{&x}" values "?fixed=yes&x=1024"
-      , Test "{&x,y,empty}" values "&x=1024&y=768&empty="
-      , Test "{var:3}" values "val"
-      , Test "{var:30}" values "value"
-      , Test "{list}" values "red,green,blue"
-      , Test "{list*}" values "red,green,blue"
-      , Test "{keys}" values "comma,%2C,dot,.,semi,%3B"
-      , Test "{keys*}" values "comma=%2C,dot=.,semi=%3B"
-      , Test "{+path:6}/here" values "/foo/b/here"
-      , Test "{+list}" values "red,green,blue"
-      , Test "{+list*}" values "red,green,blue"
-      , Test "{+keys}" values "comma,,,dot,.,semi,;"
-      , Test "{+keys*}" values "comma=,,dot=.,semi=;"
-      , Test "{#path:6}/here" values "#/foo/b/here"
-      , Test "{#list}" values "#red,green,blue"
-      , Test "{#list*}" values "#red,green,blue"
-      , Test "{#keys}" values "#comma,,,dot,.,semi,;"
-      , Test "{#keys*}" values "#comma=,,dot=.,semi=;"
-      , Test "X{.var:3}" values "X.val"
-      , Test "X{.list}" values "X.red,green,blue"
-      , Test "X{.list*}" values "X.red.green.blue"
-      , Test "X{.keys}" values "X.comma,%2C,dot,.,semi,%3B"
-      , Test "X{.keys*}" values "X.comma=%2C.dot=..semi=%3B"
-      , Test "{/var:1,var}" values "/v/value"
-      , Test "{/list}" values "/red,green,blue"
-      , Test "{/list*}" values "/red/green/blue"
-      , Test "{/list*,path:4}" values "/red/green/blue/%2Ffoo"
-      , Test "{/keys}" values "/comma,%2C,dot,.,semi,%3B"
-      , Test "{/keys*}" values "/comma=%2C/dot=./semi=%3B"
-      , Test "{;hello:5}" values ";hello=Hello"
-      , Test "{;list}" values ";list=red,green,blue"
-      , Test "{;list*}" values ";list=red;list=green;list=blue"
-      , Test "{;keys}" values ";keys=comma,%2C,dot,.,semi,%3B"
-      , Test "{;keys*}" values ";comma=%2C;dot=.;semi=%3B"
-      , Test "{?var:3}" values "?var=val"
-      , Test "{?list}" values "?list=red,green,blue"
-      , Test "{?list*}" values "?list=red&list=green&list=blue"
-      , Test "{?keys}" values "?keys=comma,%2C,dot,.,semi,%3B"
-      , Test "{?keys*}" values "?comma=%2C&dot=.&semi=%3B"
-      , Test "{&var:3}" values "&var=val"
-      , Test "{&list}" values "&list=red,green,blue"
-      , Test "{&list*}" values "&list=red&list=green&list=blue"
-      , Test "{&keys}" values "&keys=comma,%2C,dot,.,semi,%3B"
-      , Test "{&keys*}" values "&comma=%2C&dot=.&semi=%3B"
-      ]
-  , let values = ["var" =: s "value", "semi" =: s ";"]
-    in
-      [ Test "{var}" values "value"
-      , Test "{var:20}" values "value"
-      , Test "{var:3}" values "val"
-      , Test "{semi}" values "%3B"
-      , Test "{semi:2}" values "%3B"
-          -- This comment forces Brittany to use a multi-line layout.
-      ]
-  , let values = ["year" =: l ["1965", "2000", "2012"], "dom" =: l ["example", "com"]]
-    in
-      [ Test "find{?year*}" values "find?year=1965&year=2000&year=2012"
-      , Test "www{.dom*}" values "www.example.com"
-          -- This comment forces Brittany to use a multi-line layout.
-      ]
-  , let
-      values =
-        [ "base" =: s "http://example.com/home/"
-        , "count" =: l ["one", "two", "three"]
-        , "dom" =: l ["example", "com"]
-        , "dub" =: s "me/too"
-        , "empty_keys" =: d []
-        , "empty" =: s ""
-        , "half" =: s "50%"
-        , "hello" =: s "Hello World!"
-        , "keys" =: d ["semi" =: ";", "dot" =: ".", "comma" =: ","]
-        , "list" =: l ["red", "green", "blue"]
-        , "path" =: s "/foo/bar"
-        , "v" =: s "6"
-        , "var" =: s "value"
-        , "who" =: s "fred"
-        , "x" =: s "1024"
-        , "y" =: s "768"
-        ]
-    in
-      [ Test "{count}" values "one,two,three"
-      , Test "{count*}" values "one,two,three"
-      , Test "{/count}" values "/one,two,three"
-      , Test "{/count*}" values "/one/two/three"
-      , Test "{;count}" values ";count=one,two,three"
-      , Test "{;count*}" values ";count=one;count=two;count=three"
-      , Test "{?count}" values "?count=one,two,three"
-      , Test "{?count*}" values "?count=one&count=two&count=three"
-      , Test "{&count*}" values "&count=one&count=two&count=three"
-      , Test "{var}" values "value"
-      , Test "{hello}" values "Hello%20World%21"
-      , Test "{half}" values "50%25"
-      , Test "O{empty}X" values "OX"
-      , Test "O{undef}X" values "OX"
-      , Test "{x,y}" values "1024,768"
-      , Test "{x,hello,y}" values "1024,Hello%20World%21,768"
-      , Test "?{x,empty}" values "?1024,"
-      , Test "?{x,undef}" values "?1024"
-      , Test "?{undef,y}" values "?768"
-      , Test "{var:3}" values "val"
-      , Test "{var:30}" values "value"
-      , Test "{list}" values "red,green,blue"
-      , Test "{list*}" values "red,green,blue"
-      , Test "{keys}" values "comma,%2C,dot,.,semi,%3B"
-      , Test "{keys*}" values "comma=%2C,dot=.,semi=%3B"
-      , Test "{+var}" values "value"
-      , Test "{+hello}" values "Hello%20World!"
-      , Test "{+half}" values "50%25"
-      , Test "{base}index" values "http%3A%2F%2Fexample.com%2Fhome%2Findex"
-      , Test "{+base}index" values "http://example.com/home/index"
-      , Test "O{+empty}X" values "OX"
-      , Test "O{+undef}X" values "OX"
-      , Test "{+path}/here" values "/foo/bar/here"
-      , Test "here?ref={+path}" values "here?ref=/foo/bar"
-      , Test "up{+path}{var}/here" values "up/foo/barvalue/here"
-      , Test "{+x,hello,y}" values "1024,Hello%20World!,768"
-      , Test "{+path,x}/here" values "/foo/bar,1024/here"
-      , Test "{+path:6}/here" values "/foo/b/here"
-      , Test "{+list}" values "red,green,blue"
-      , Test "{+list*}" values "red,green,blue"
-      , Test "{+keys}" values "comma,,,dot,.,semi,;"
-      , Test "{+keys*}" values "comma=,,dot=.,semi=;"
-      , Test "{#var}" values "#value"
-      , Test "{#hello}" values "#Hello%20World!"
-      , Test "{#half}" values "#50%25"
-      , Test "foo{#empty}" values "foo#"
-      , Test "foo{#undef}" values "foo"
-      , Test "{#x,hello,y}" values "#1024,Hello%20World!,768"
-      , Test "{#path,x}/here" values "#/foo/bar,1024/here"
-      , Test "{#path:6}/here" values "#/foo/b/here"
-      , Test "{#list}" values "#red,green,blue"
-      , Test "{#list*}" values "#red,green,blue"
-      , Test "{#keys}" values "#comma,,,dot,.,semi,;"
-      , Test "{#keys*}" values "#comma=,,dot=.,semi=;"
-      , Test "{.who}" values ".fred"
-      , Test "{.who,who}" values ".fred.fred"
-      , Test "{.half,who}" values ".50%25.fred"
-      , Test "www{.dom*}" values "www.example.com"
-      , Test "X{.var}" values "X.value"
-      , Test "X{.empty}" values "X."
-      , Test "X{.undef}" values "X"
-      , Test "X{.var:3}" values "X.val"
-      , Test "X{.list}" values "X.red,green,blue"
-      , Test "X{.list*}" values "X.red.green.blue"
-      , Test "X{.keys}" values "X.comma,%2C,dot,.,semi,%3B"
-      , Test "X{.keys*}" values "X.comma=%2C.dot=..semi=%3B"
-      , Test "X{.empty_keys}" values "X"
-      , Test "X{.empty_keys*}" values "X"
-      , Test "{/who}" values "/fred"
-      , Test "{/who,who}" values "/fred/fred"
-      , Test "{/half,who}" values "/50%25/fred"
-      , Test "{/who,dub}" values "/fred/me%2Ftoo"
-      , Test "{/var}" values "/value"
-      , Test "{/var,empty}" values "/value/"
-      , Test "{/var,undef}" values "/value"
-      , Test "{/var,x}/here" values "/value/1024/here"
-      , Test "{/var:1,var}" values "/v/value"
-      , Test "{/list}" values "/red,green,blue"
-      , Test "{/list*}" values "/red/green/blue"
-      , Test "{/list*,path:4}" values "/red/green/blue/%2Ffoo"
-      , Test "{/keys}" values "/comma,%2C,dot,.,semi,%3B"
-      , Test "{/keys*}" values "/comma=%2C/dot=./semi=%3B"
-      , Test "{;who}" values ";who=fred"
-      , Test "{;half}" values ";half=50%25"
-      , Test "{;empty}" values ";empty"
-      , Test "{;v,empty,who}" values ";v=6;empty;who=fred"
-      , Test "{;v,bar,who}" values ";v=6;who=fred"
-      , Test "{;x,y}" values ";x=1024;y=768"
-      , Test "{;x,y,empty}" values ";x=1024;y=768;empty"
-      , Test "{;x,y,undef}" values ";x=1024;y=768"
-      , Test "{;hello:5}" values ";hello=Hello"
-      , Test "{;list}" values ";list=red,green,blue"
-      , Test "{;list*}" values ";list=red;list=green;list=blue"
-      , Test "{;keys}" values ";keys=comma,%2C,dot,.,semi,%3B"
-      , Test "{;keys*}" values ";comma=%2C;dot=.;semi=%3B"
-      , Test "{?who}" values "?who=fred"
-      , Test "{?half}" values "?half=50%25"
-      , Test "{?x,y}" values "?x=1024&y=768"
-      , Test "{?x,y,empty}" values "?x=1024&y=768&empty="
-      , Test "{?x,y,undef}" values "?x=1024&y=768"
-      , Test "{?var:3}" values "?var=val"
-      , Test "{?list}" values "?list=red,green,blue"
-      , Test "{?list*}" values "?list=red&list=green&list=blue"
-      , Test "{?keys}" values "?keys=comma,%2C,dot,.,semi,%3B"
-      , Test "{?keys*}" values "?comma=%2C&dot=.&semi=%3B"
-      , Test "{&who}" values "&who=fred"
-      , Test "{&half}" values "&half=50%25"
-      , Test "?fixed=yes{&x}" values "?fixed=yes&x=1024"
-      , Test "{&x,y,empty}" values "&x=1024&y=768&empty="
-      , Test "{&x,y,undef}" values "&x=1024&y=768"
-      , Test "{&var:3}" values "&var=val"
-      , Test "{&list}" values "&list=red,green,blue"
-      , Test "{&list*}" values "&list=red&list=green&list=blue"
-      , Test "{&keys}" values "&keys=comma,%2C,dot,.,semi,%3B"
-      , Test "{&keys*}" values "&comma=%2C&dot=.&semi=%3B"
-      ]
-  ]
-
-data Test = Test
-  { testInput :: String
-  , testValues :: [(String, Burrito.Value)]
-  , testOutput :: Output
-  }
-  deriving (Eq, Show)
-
-runTest :: Test -> Hspec.Expectation
-runTest test =
-  case (Burrito.parse $ testInput test, unwrapOutput $ testOutput test) of
-    (Nothing, Nothing) -> pure ()
-    (Nothing, Just _) -> Hspec.expectationFailure "should have parsed"
-    (Just _, Nothing) -> Hspec.expectationFailure "should not have parsed"
-    (Just template, Just expected) -> do
-      let
-        values = testValues test
-        actual = Burrito.expand values template
-      actual `Hspec.shouldBe` expected
-      Burrito.parse (show template) `Hspec.shouldBe` Just template
-      let
-        relevant =
-          List.sort $ keepRelevant (templateVariables template) values
-      Monad.when (isMatchable template relevant) $ do
-        let matches = List.sort <$> Burrito.match expected template
-        matches `Hspec.shouldSatisfy` elem relevant
-
-isMatchable :: Template.Template -> [(String, Burrito.Value)] -> Bool
-isMatchable template values =
-  (not . any (isAsterisk . Variable.modifier) $ templateVariables template)
-    && all (isString . snd) values
-
-isString :: Burrito.Value -> Bool
-isString value = case value of
-  Value.String _ -> True
-  _ -> False
-
-isAsterisk :: Modifier.Modifier -> Bool
-isAsterisk modifier = case modifier of
-  Modifier.Asterisk -> True
-  _ -> False
-
-keepRelevant
-  :: Set.Set Variable.Variable
-  -> [(String, Burrito.Value)]
-  -> [(String, Burrito.Value)]
-keepRelevant variables =
-  let
-    vs =
-      Map.fromListWith
-          (\mx my -> case (mx, my) of
-            (Just x, Just y) -> Just $ max x y
-            _ -> Nothing
-          )
-        . fmap
-            (\v ->
-              ( Render.builderToString . Render.name $ Variable.name v
-              , case Variable.modifier v of
-                Modifier.Colon n -> Just $ MaxLength.count n
-                _ -> Nothing
-              )
-            )
-        $ Set.toList variables
-  in
-    Maybe.mapMaybe $ \(k, v) -> do
-      m <- Map.lookup k vs
-      pure . (,) k $ case m of
-        Nothing -> v
-        Just n -> case v of
-          Value.String t -> Value.String $ Text.take n t
-          _ -> v
-
-templateVariables :: Template.Template -> Set.Set Variable.Variable
-templateVariables =
-  Set.fromList
-    . concatMap
-        (\token -> case token of
-          Token.Expression expression ->
-            NonEmpty.toList $ Expression.variables expression
-          Token.Literal _ -> []
-        )
-    . Template.tokens
-
-newtype Output = Output
-  { unwrapOutput :: Maybe String
-  } deriving (Eq, Show)
-
-instance String.IsString Output where
-  fromString = Output . Just
-
-noParse :: Output
-noParse = Output Nothing
-
-(=:) :: a -> b -> (a, b)
-(=:) = (,)
-
-s :: String -> Burrito.Value
-s = Burrito.stringValue
-
-l :: [String] -> Burrito.Value
-l = Burrito.listValue
-
-d :: [(String, String)] -> Burrito.Value
-d = Burrito.dictionaryValue
-
-newtype Template = Template
-  { unwrapTemplate :: Template.Template
-  } deriving (Eq)
-
-instance Show Template where
-  show (Template template) =
-    unwords [show $ show template, "{-", show (Template.tokens template), "-}"]
-
-instance QC.Arbitrary Template where
-  arbitrary = Template <$> arbitraryTemplate
-  shrink = fmap Template . shrinkTemplate . unwrapTemplate
-
-type Shrink a = a -> [a]
-
-arbitraryTemplate :: QC.Gen Template.Template
-arbitraryTemplate = Template.Template . simplify <$> QC.listOf arbitraryToken
-
-shrinkTemplate :: Shrink Template.Template
-shrinkTemplate =
-  fmap (Template.Template . simplify)
-    . QC.shrinkList shrinkToken
-    . Template.tokens
-
-simplify :: [Token.Token] -> [Token.Token]
-simplify tokens = case tokens of
-  t1 : t2 : ts -> case (t1, t2) of
-    (Token.Literal l1, Token.Literal l2) ->
-      simplify $ Token.Literal (appendLiteral l1 l2) : ts
-    _ -> t1 : simplify (t2 : ts)
-  _ -> tokens
-
-appendLiteral :: Literal.Literal -> Literal.Literal -> Literal.Literal
-appendLiteral x y =
-  Literal.Literal $ Literal.characters x <> Literal.characters y
-
-arbitraryToken :: QC.Gen Token.Token
-arbitraryToken = QC.oneof
-  [ Token.Expression <$> arbitraryExpression
-  , Token.Literal <$> arbitraryLiteral
-  ]
-
-shrinkToken :: Shrink Token.Token
-shrinkToken x = case x of
-  Token.Expression y -> Token.Expression <$> shrinkExpression y
-  Token.Literal y -> Token.Literal <$> shrinkLiteral y
-
-arbitraryExpression :: QC.Gen Expression.Expression
-arbitraryExpression =
-  Expression.Expression
-    <$> arbitraryOperator
-    <*> arbitraryNonEmpty arbitraryVariable
-
-shrinkExpression :: Shrink Expression.Expression
-shrinkExpression x = uncurry Expression.Expression <$> shrinkTuple
-  shrinkOperator
-  (shrinkNonEmpty shrinkVariable)
-  (Expression.operator x, Expression.variables x)
-
-arbitraryOperator :: QC.Gen Operator.Operator
-arbitraryOperator = QC.elements
-  [ Operator.Ampersand
-  , Operator.FullStop
-  , Operator.None
-  , Operator.NumberSign
-  , Operator.PlusSign
-  , Operator.QuestionMark
-  , Operator.Semicolon
-  , Operator.Solidus
-  ]
-
-shrinkOperator :: Shrink Operator.Operator
-shrinkOperator x = case x of
-  Operator.None -> []
-  _ -> [Operator.None]
-
-arbitraryNonEmpty :: QC.Gen a -> QC.Gen (NonEmpty.NonEmpty a)
-arbitraryNonEmpty g = (NonEmpty.:|) <$> g <*> QC.listOf g
-
-shrinkNonEmpty :: Shrink a -> Shrink (NonEmpty.NonEmpty a)
-shrinkNonEmpty f x = uncurry (NonEmpty.:|)
-  <$> shrinkTuple f (QC.shrinkList f) (NonEmpty.head x, NonEmpty.tail x)
-
-arbitraryVariable :: QC.Gen Variable.Variable
-arbitraryVariable = Variable.Variable <$> arbitraryName <*> arbitraryModifier
-
-shrinkVariable :: Shrink Variable.Variable
-shrinkVariable variable = uncurry Variable.Variable <$> shrinkTuple
-  shrinkName
-  shrinkModifier
-  (Variable.name variable, Variable.modifier variable)
-
-shrinkTuple :: Shrink a -> Shrink b -> Shrink (a, b)
-shrinkTuple f g (x, y) =
-  fmap (\a -> (a, y)) (f x) <> fmap (\b -> (x, b)) (g y)
-
-arbitraryName :: QC.Gen Name.Name
-arbitraryName = Name.Name <$> arbitraryNonEmpty arbitraryField
-
-shrinkName :: Shrink Name.Name
-shrinkName = fmap Name.Name . shrinkNonEmpty shrinkField . Name.fields
-
-arbitraryField :: QC.Gen Field.Field
-arbitraryField = Field.Field <$> arbitraryNonEmpty arbitraryFieldCharacter
-
-shrinkField :: Shrink Field.Field
-shrinkField =
-  fmap Field.Field . shrinkNonEmpty shrinkFieldCharacter . Field.characters
-
-arbitraryFieldCharacter :: QC.Gen (Character.Character Field.Field)
-arbitraryFieldCharacter = QC.oneof
-  [ Character.Encoded <$> arbitraryDigit <*> arbitraryDigit
-  , Character.Unencoded <$> QC.suchThat QC.arbitrary Parse.isFieldCharacter
-  ]
-
-shrinkFieldCharacter :: Shrink (Character.Character Field.Field)
-shrinkFieldCharacter x = case x of
-  Character.Encoded y z ->
-    uncurry Character.Encoded <$> shrinkTuple shrinkDigit shrinkDigit (y, z)
-  Character.Unencoded y ->
-    fmap Character.Unencoded . filter Parse.isFieldCharacter $ QC.shrink y
-
-arbitraryDigit :: QC.Gen Digit.Digit
-arbitraryDigit = QC.oneof
-  [ pure Digit.Ox0
-  , pure Digit.Ox1
-  , pure Digit.Ox2
-  , pure Digit.Ox3
-  , pure Digit.Ox4
-  , pure Digit.Ox5
-  , pure Digit.Ox6
-  , pure Digit.Ox7
-  , pure Digit.Ox8
-  , pure Digit.Ox9
-  , Digit.OxA <$> arbitraryCase
-  , Digit.OxB <$> arbitraryCase
-  , Digit.OxC <$> arbitraryCase
-  , Digit.OxD <$> arbitraryCase
-  , Digit.OxE <$> arbitraryCase
-  , Digit.OxF <$> arbitraryCase
-  ]
-
-shrinkDigit :: Shrink Digit.Digit
-shrinkDigit x = case x of
-  Digit.Ox0 -> []
-  Digit.Ox1 -> [Digit.Ox0]
-  Digit.Ox2 -> [Digit.Ox0]
-  Digit.Ox3 -> [Digit.Ox0]
-  Digit.Ox4 -> [Digit.Ox0]
-  Digit.Ox5 -> [Digit.Ox0]
-  Digit.Ox6 -> [Digit.Ox0]
-  Digit.Ox7 -> [Digit.Ox0]
-  Digit.Ox8 -> [Digit.Ox0]
-  Digit.Ox9 -> [Digit.Ox0]
-  Digit.OxA y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
-  Digit.OxB y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
-  Digit.OxC y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
-  Digit.OxD y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
-  Digit.OxE y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
-  Digit.OxF y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
-
-arbitraryCase :: QC.Gen Case.Case
-arbitraryCase = QC.elements [Case.Lower, Case.Upper]
-
-shrinkCase :: Shrink Case.Case
-shrinkCase x = case x of
-  Case.Lower -> []
-  Case.Upper -> [Case.Lower]
-
-arbitraryModifier :: QC.Gen Modifier.Modifier
-arbitraryModifier = QC.oneof
-  [ pure Modifier.Asterisk
-  , Modifier.Colon <$> arbitraryMaxLength
-  , pure Modifier.None
-  ]
-
-shrinkModifier :: Shrink Modifier.Modifier
-shrinkModifier x = case x of
-  Modifier.Asterisk -> [Modifier.None]
-  Modifier.Colon y -> Modifier.None : fmap Modifier.Colon (shrinkMaxLength y)
-  Modifier.None -> []
-
-arbitraryMaxLength :: QC.Gen MaxLength.MaxLength
-arbitraryMaxLength =
-  MaxLength.MaxLength <$> QC.suchThat QC.arbitrary Parse.isMaxLength
-
-shrinkMaxLength :: Shrink MaxLength.MaxLength
-shrinkMaxLength =
-  fmap MaxLength.MaxLength
-    . filter Parse.isMaxLength
-    . QC.shrink
-    . MaxLength.count
-
-arbitraryLiteral :: QC.Gen Literal.Literal
-arbitraryLiteral =
-  Literal.Literal <$> arbitraryNonEmpty arbitraryLiteralCharacter
-
-shrinkLiteral :: Shrink Literal.Literal
-shrinkLiteral =
-  fmap Literal.Literal
-    . shrinkNonEmpty shrinkLiteralCharacter
-    . Literal.characters
-
-arbitraryLiteralCharacter :: QC.Gen (Character.Character Literal.Literal)
-arbitraryLiteralCharacter = QC.oneof
-  [ Character.Encoded <$> arbitraryDigit <*> arbitraryDigit
-  , Character.Unencoded <$> QC.suchThat QC.arbitrary Parse.isLiteralCharacter
-  ]
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# OPTIONS_GHC -Wno-monomorphism-restriction #-}
+
+module Main
+  ( main,
+  )
+where
+
+import qualified Burrito
+import qualified Burrito.Internal.Parse as Parse
+import qualified Burrito.Internal.Render as Render
+import qualified Burrito.Internal.Type.Case as Case
+import qualified Burrito.Internal.Type.Character as Character
+import qualified Burrito.Internal.Type.Digit as Digit
+import qualified Burrito.Internal.Type.Expression as Expression
+import qualified Burrito.Internal.Type.Field as Field
+import qualified Burrito.Internal.Type.Literal as Literal
+import qualified Burrito.Internal.Type.MaxLength as MaxLength
+import qualified Burrito.Internal.Type.Modifier as Modifier
+import qualified Burrito.Internal.Type.Name as Name
+import qualified Burrito.Internal.Type.Operator as Operator
+import qualified Burrito.Internal.Type.Template as Template
+import qualified Burrito.Internal.Type.Token as Token
+import qualified Burrito.Internal.Type.Value as Value
+import qualified Burrito.Internal.Type.Variable as Variable
+import qualified Control.Monad as Monad
+import qualified Data.List as List
+import qualified Data.List.NonEmpty as NonEmpty
+import qualified Data.Map as Map
+import qualified Data.Maybe as Maybe
+import qualified Data.Set as Set
+import qualified Data.String as String
+import qualified Data.Text as Text
+import qualified GHC.Stack as Stack
+import qualified Test.Hspec as Hspec
+import qualified Test.Hspec.QuickCheck as Hspec
+import qualified Test.QuickCheck as QC
+
+main :: IO ()
+main = Hspec.hspec . Hspec.describe "Burrito" $ do
+  Monad.forM_ tests $ \test ->
+    Hspec.it (show (testInput test, unwrapOutput $ testOutput test)) $
+      runTest test
+
+  Hspec.describe "match" $ do
+    let matchTest ::
+          (Stack.HasCallStack) =>
+          String ->
+          [(String, Burrito.Value)] ->
+          String ->
+          Hspec.Spec
+        matchTest input values output = Hspec.it (show (input, output)) $ do
+          template <- maybe (fail "invalid Template") pure $ Burrito.parse input
+          let matches = Burrito.match output template
+          matches `Hspec.shouldSatisfy` elem values
+          Monad.forM_ matches $ \match -> do
+            let it = Burrito.expand match template
+            Monad.when (it /= output) . fail $
+              show
+                (input, values, output, matches, match, it)
+
+    matchTest "" [] ""
+    matchTest "a" [] "a"
+    matchTest "!" [] "!"
+    matchTest "\xa0" [] "%C2%A0"
+
+    matchTest "{a}" ["a" =: s ""] ""
+    matchTest "{a}" ["a" =: s "A"] "A"
+    matchTest "{a}" ["a" =: s "AB"] "AB"
+
+    matchTest "a{b}" ["b" =: s ""] "a"
+    matchTest "a{b}" ["b" =: s "B"] "aB"
+    matchTest "a{b}" ["b" =: s "BC"] "aBC"
+
+    matchTest "{a}b" ["a" =: s ""] "b"
+    matchTest "{a}b" ["a" =: s "A"] "Ab"
+    matchTest "{a}b" ["a" =: s "AB"] "ABb"
+
+    matchTest "{a}{a}" ["a" =: s "A"] "AA"
+    matchTest "{a}{a}" ["a" =: s "AB"] "ABAB"
+
+    matchTest "{a}" ["a" =: s "%"] "%25"
+    matchTest "{a}" ["a" =: s "/"] "%2F"
+    matchTest "{a}" ["a" =: s "\xa0"] "%C2%A0"
+    matchTest "{a}" ["a" =: s "\xd7ff"] "%ED%9F%BF"
+    matchTest "{a}" ["a" =: s "\x10000"] "%F0%90%80%80"
+    matchTest "{a}" ["a" =: s "A/B"] "A%2FB"
+    matchTest "{a}" ["a" =: s "WX\xa0\xa1YZ"] "WX%C2%A0%C2%A1YZ"
+
+    matchTest "{+a}" ["a" =: s "%"] "%25"
+    matchTest "{+a}" ["a" =: s "/"] "/"
+
+    matchTest "{#a}" [] ""
+    matchTest "{#a}" ["a" =: s ""] "#"
+    matchTest "{#a}" ["a" =: s "A"] "#A"
+    matchTest "{#a}" ["a" =: s "%"] "#%25"
+    matchTest "{#a}" ["a" =: s "/"] "#/"
+
+    matchTest "{.a}" [] ""
+    matchTest "{.a}" ["a" =: s ""] "."
+    matchTest "{.a}" ["a" =: s "A"] ".A"
+    matchTest "{.a}" ["a" =: s "%"] ".%25"
+    matchTest "{.a}" ["a" =: s "/"] ".%2F"
+
+    matchTest "{/a}" [] ""
+    matchTest "{/a}" ["a" =: s ""] "/"
+    matchTest "{/a}" ["a" =: s "A"] "/A"
+    matchTest "{/a}" ["a" =: s "%"] "/%25"
+    matchTest "{/a}" ["a" =: s "/"] "/%2F"
+
+    matchTest "{;a}" [] ""
+    matchTest "{;a}" ["a" =: s ""] ";a"
+    matchTest "{;a}" ["a" =: s "A"] ";a=A"
+    matchTest "{;a}" ["a" =: s "%"] ";a=%25"
+    matchTest "{;a}" ["a" =: s "/"] ";a=%2F"
+
+    matchTest "{?a}" [] ""
+    matchTest "{?a}" ["a" =: s ""] "?a="
+    matchTest "{?a}" ["a" =: s "A"] "?a=A"
+    matchTest "{?a}" ["a" =: s "%"] "?a=%25"
+    matchTest "{?a}" ["a" =: s "/"] "?a=%2F"
+
+    matchTest "{&a}" [] ""
+    matchTest "{&a}" ["a" =: s ""] "&a="
+    matchTest "{&a}" ["a" =: s "A"] "&a=A"
+    matchTest "{&a}" ["a" =: s "%"] "&a=%25"
+    matchTest "{&a}" ["a" =: s "/"] "&a=%2F"
+
+    matchTest "{a,b}" ["a" =: s "A", "b" =: s "B"] "A,B"
+    matchTest "{+a,b}" ["a" =: s "A", "b" =: s "B"] "A,B"
+    matchTest "{#a,b}" ["a" =: s "A", "b" =: s "B"] "#A,B"
+    matchTest "{.a,b}" ["a" =: s "A", "b" =: s "B"] ".A.B"
+    matchTest "{/a,b}" ["a" =: s "A", "b" =: s "B"] "/A/B"
+    matchTest "{;a,b}" ["a" =: s "A", "b" =: s "B"] ";a=A;b=B"
+    matchTest "{?a,b}" ["a" =: s "A", "b" =: s "B"] "?a=A&b=B"
+    matchTest "{&a,b}" ["a" =: s "A", "b" =: s "B"] "&a=A&b=B"
+
+    matchTest "{a,b}" ["a" =: s "A"] "A"
+    matchTest "{a,b,c}" ["a" =: s "A"] "A"
+    matchTest "{a,b,c}" ["a" =: s "A", "b" =: s "B"] "A,B"
+    matchTest "{a}{a,b}" ["b" =: s "B"] "B"
+    matchTest "{a}{a,b,c}" ["b" =: s "B"] "B"
+    matchTest "{a,b}{a,b,c}" ["c" =: s "C"] "C"
+    matchTest "{b}{a,b,c}" ["a" =: s "A", "c" =: s "C"] "A,C"
+    matchTest "{a}{a,b,c}" ["b" =: s "B", "c" =: s "C"] "B,C"
+
+    matchTest "{a:1}/{a}" ["a" =: s "AB"] "A/AB"
+
+  -- TODO: Test matching on explode modifier.
+  -- matchTest "{a*}" ["a" =: s "A"] "A"
+
+  -- TODO: Test matching on lists.
+  -- matchTest "{a}" ["a" =: l ["A", "B"]] "A,B"
+
+  -- TODO: Test matching on dictionaries.
+  -- matchTest "{a}" ["a" =: d ["k" =: "v"]] "k,v"
+
+  Hspec.describe "uriTemplate"
+    . Hspec.it "works as an expression"
+    $ Just [Burrito.uriTemplate|a{b}c|]
+      `Hspec.shouldBe` Burrito.parse "a{b}c"
+
+  Hspec.modifyMaxSize (const 10)
+    . Hspec.it "round trips"
+    . QC.property
+    $ \(Template template) -> Burrito.parse (show template) == Just template
+
+-- brittany-next-binding --columns 160
+tests :: [Test]
+tests =
+  mconcat
+    [ [ Test "" [] "",
+        Test "" ["a" =: s ""] "",
+        Test "" ["a" =: l []] "",
+        Test "" ["a" =: d []] "",
+        Test "!" [] "!",
+        Test "#" [] "#",
+        Test "$" [] "$",
+        Test "&" [] "&",
+        Test "(" [] "(",
+        Test ")" [] ")",
+        Test "*" [] "*",
+        Test "+" [] "+",
+        Test "," [] ",",
+        Test "-" [] "-",
+        Test "." [] ".",
+        Test "/" [] "/",
+        Test "0" [] "0",
+        Test "9" [] "9",
+        Test ":" [] ":",
+        Test ";" [] ";",
+        Test "=" [] "=",
+        Test "?" [] "?",
+        Test "@" [] "@",
+        Test "A" [] "A",
+        Test "Z" [] "Z",
+        Test "[" [] "[",
+        Test "]" [] "]",
+        Test "_" [] "_",
+        Test "a" [] "a",
+        Test "z" [] "z",
+        Test "~" [] "~",
+        Test "\xa0" [] "%C2%A0",
+        Test "\xd7ff" [] "%ED%9F%BF",
+        Test "\xf900" [] "%EF%A4%80",
+        Test "\xfdcf" [] "%EF%B7%8F",
+        Test "\xfdf0" [] "%EF%B7%B0",
+        Test "\xffef" [] "%EF%BF%AF",
+        Test "\x10000" [] "%F0%90%80%80",
+        Test "\x1fffd" [] "%F0%9F%BF%BD",
+        Test "\x20000" [] "%F0%A0%80%80",
+        Test "\x2fffd" [] "%F0%AF%BF%BD",
+        Test "\x30000" [] "%F0%B0%80%80",
+        Test "\x3fffd" [] "%F0%BF%BF%BD",
+        Test "\x40000" [] "%F1%80%80%80",
+        Test "\x4fffd" [] "%F1%8F%BF%BD",
+        Test "\x50000" [] "%F1%90%80%80",
+        Test "\x5fffd" [] "%F1%9F%BF%BD",
+        Test "\x60000" [] "%F1%A0%80%80",
+        Test "\x6fffd" [] "%F1%AF%BF%BD",
+        Test "\x70000" [] "%F1%B0%80%80",
+        Test "\x7fffd" [] "%F1%BF%BF%BD",
+        Test "\x80000" [] "%F2%80%80%80",
+        Test "\x8fffd" [] "%F2%8F%BF%BD",
+        Test "\x90000" [] "%F2%90%80%80",
+        Test "\x9fffd" [] "%F2%9F%BF%BD",
+        Test "\xa0000" [] "%F2%A0%80%80",
+        Test "\xafffd" [] "%F2%AF%BF%BD",
+        Test "\xb0000" [] "%F2%B0%80%80",
+        Test "\xbfffd" [] "%F2%BF%BF%BD",
+        Test "\xc0000" [] "%F3%80%80%80",
+        Test "\xcfffd" [] "%F3%8F%BF%BD",
+        Test "\xd0000" [] "%F3%90%80%80",
+        Test "\xdfffd" [] "%F3%9F%BF%BD",
+        Test "\xe1000" [] "%F3%A1%80%80",
+        Test "\xefffd" [] "%F3%AF%BF%BD",
+        Test "\xe000" [] "%EE%80%80",
+        Test "\xf8ff" [] "%EF%A3%BF",
+        Test "\xf0000" [] "%F3%B0%80%80",
+        Test "\xffffd" [] "%F3%BF%BF%BD",
+        Test "\x100000" [] "%F4%80%80%80",
+        Test "\x10fffd" [] "%F4%8F%BF%BD",
+        Test "%00" [] "%00",
+        Test "%AA" [] "%AA",
+        Test "%Aa" [] "%Aa",
+        Test "%aA" [] "%aA",
+        Test "%aa" [] "%aa",
+        Test "%" [] noParse,
+        Test "%0" [] noParse,
+        Test "%0z" [] noParse,
+        Test "%z" [] noParse,
+        Test "%30" [] "%30",
+        Test " " [] noParse,
+        Test "\"" [] noParse,
+        Test "'" [] noParse,
+        Test "%" [] noParse,
+        Test "<" [] noParse,
+        Test ">" [] noParse,
+        Test "\\" [] noParse,
+        Test "^" [] noParse,
+        Test "`" [] noParse,
+        Test "{" [] noParse,
+        Test "|" [] noParse,
+        Test "}" [] noParse,
+        Test "{}" [] noParse,
+        Test "{,}" [] noParse,
+        Test "{a,,b}" [] noParse,
+        Test "{+}" [] noParse,
+        Test "{:1}" [] noParse,
+        Test "{*}" [] noParse,
+        Test "{AZ}" [] "",
+        Test "{az}" [] "",
+        Test "{09}" [] "",
+        Test "{_a}" [] "",
+        Test "{a_}" [] "",
+        Test "{_}" [] "",
+        Test "{A.A}" [] "",
+        Test "{a.a}" [] "",
+        Test "{0.0}" [] "",
+        Test "{_._}" [] "",
+        Test "{%aa.%aa}" [] "",
+        Test "{.}" [] noParse,
+        Test "{a.}" [] noParse,
+        Test "{+.a}" [] noParse,
+        Test "{a..b}" [] noParse,
+        Test "{%00}" [] "",
+        Test "{%}" [] noParse,
+        Test "{%0}" [] noParse,
+        Test "{%0z}" [] noParse,
+        Test "{%z}" [] noParse,
+        Test "{!}" [] noParse,
+        Test "{" [] noParse,
+        Test "{{}" [] noParse,
+        Test "}" [] noParse,
+        Test "{}}" [] noParse,
+        Test "{a,b}" [] "",
+        Test "{a,b,c,d}" [] "",
+        Test "{a,a}" [] "",
+        Test "{a:5}" [] "",
+        Test "{a:67}" [] "",
+        Test "{a:801}" [] "",
+        Test "{a:234}" [] "",
+        Test "{a:9999}" [] "",
+        Test "{a:123}" ["a" =: s (replicate 200 'a')] . Output . Just $ replicate 123 'a',
+        Test "{a:}" [] noParse,
+        Test "{a:0}" [] noParse,
+        Test "{a:10000}" [] noParse,
+        Test "{a:-1}" [] noParse,
+        Test "{a*}" [] "",
+        Test "{a:1*}" [] noParse,
+        Test "{a*:1}" [] noParse,
+        Test "{a,b:1,c*}" [] "",
+        Test "{+a}" [] "",
+        Test "{#a}" [] "",
+        Test "{.a}" [] "",
+        Test "{/a}" [] "",
+        Test "{;a}" [] "",
+        Test "{?a}" [] "",
+        Test "{&a}" [] "",
+        Test "{=a}" [] noParse,
+        Test "{,a}" [] noParse,
+        Test "{!a}" [] noParse,
+        Test "{@a}" [] noParse,
+        Test "{|a}" [] noParse,
+        Test "{+#a}" [] noParse,
+        Test "{+a,#b}" [] noParse,
+        Test "{+a:1}" [] "",
+        Test "{#a*}" [] "",
+        Test "{+a,b}" [] "",
+        Test "{#a,b}" [] "",
+        Test "{.a,b}" [] "",
+        Test "{/a,b}" [] "",
+        Test "{;a,b}" [] "",
+        Test "{?a,b}" [] "",
+        Test "{&a,b}" [] "",
+        Test "{a}{b}" [] "",
+        Test "{a}{b}{c}{d}" [] "",
+        Test "{a}{a}" [] "",
+        Test "{{}}" [] noParse,
+        Test "{a{b}}" [] noParse,
+        Test "{{a}b}" [] noParse,
+        Test "{a{b}c}" [] noParse,
+        Test "a{b}" [] "a",
+        Test "{a}b" [] "b",
+        Test "a{b}c" [] "ac",
+        Test "{a}b{c}" [] "b",
+        Test "{a}" [] "",
+        Test "{+a}" [] "",
+        Test "{#a}" [] "",
+        Test "{.a}" [] "",
+        Test "{/a}" [] "",
+        Test "{;a}" [] "",
+        Test "{?a}" [] "",
+        Test "{&a}" [] "",
+        Test "http://example.com/~{username}/" ["username" =: s "fred"] "http://example.com/~fred/",
+        Test "http://example.com/~{username}/" ["username" =: s "mark"] "http://example.com/~mark/",
+        Test "http://example.com/dictionary/{term:1}/{term}" ["term" =: s "cat"] "http://example.com/dictionary/c/cat",
+        Test "http://example.com/dictionary/{term:1}/{term}" ["term" =: s "dog"] "http://example.com/dictionary/d/dog",
+        Test "http://example.com/search{?q,lang}" ["q" =: s "cat", "lang" =: s "en"] "http://example.com/search?q=cat&lang=en",
+        Test "http://example.com/search{?q,lang}" ["q" =: s "chien", "lang" =: s "fr"] "http://example.com/search?q=chien&lang=fr",
+        Test "http://www.example.com/foo{?query,number}" ["query" =: s "mycelium", "number" =: s "100"] "http://www.example.com/foo?query=mycelium&number=100",
+        Test "http://www.example.com/foo{?query,number}" ["number" =: s "100"] "http://www.example.com/foo?number=100",
+        Test "http://www.example.com/foo{?query,number}" [] "http://www.example.com/foo",
+        Test "{a}" [] "",
+        Test "{a}" ["a" =: l []] "",
+        Test "{a}" ["a" =: d []] "",
+        Test "{a}" ["a" =: s ""] "",
+        Test "{a}" ["a" =: s "A"] "A",
+        Test "{a}" ["a" =: s "~"] "~",
+        Test "{a}" ["a" =: s "%"] "%25",
+        Test "{a}" ["a" =: s "?"] "%3F",
+        Test "{a}" ["a" =: s "&"] "%26",
+        Test "{a}" ["a" =: s "\xa0"] "%C2%A0",
+        Test "{a}" ["a" =: s "\xd7ff"] "%ED%9F%BF",
+        Test "{a}" ["a" =: s "\x10000"] "%F0%90%80%80",
+        Test "{a}" ["a" =: l ["A"]] "A",
+        Test "{a}" ["a" =: l ["A", "B"]] "A,B",
+        Test "{a}" ["a" =: l ["%"]] "%25",
+        Test "{a}" ["a" =: l ["\xa0"]] "%C2%A0",
+        Test "{a}" ["a" =: d ["A" =: "1"]] "A,1",
+        Test "{a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "A,1,B,2",
+        Test "{a}" ["a" =: d ["A" =: "%"]] "A,%25",
+        Test "{a}" ["a" =: d ["A" =: "\xa0"]] "A,%C2%A0",
+        Test "{a}" ["a" =: d ["%" =: "1"]] "%25,1",
+        Test "{a*}" [] "",
+        Test "{a*}" ["a" =: s ""] "",
+        Test "{a*}" ["a" =: s "A"] "A",
+        Test "{a*}" ["a" =: l []] "",
+        Test "{a*}" ["a" =: l ["A"]] "A",
+        Test "{a*}" ["a" =: l ["A", "B"]] "A,B",
+        Test "{a*}" ["a" =: d []] "",
+        Test "{a*}" ["a" =: d ["A" =: "1"]] "A=1",
+        Test "{a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "A=1,B=2",
+        Test "{a:1}" [] "",
+        Test "{a:1}" ["a" =: s ""] "",
+        Test "{a:1}" ["a" =: s "A"] "A",
+        Test "{a:1}" ["a" =: s "AB"] "A",
+        Test "{a:1}" ["a" =: s "%B"] "%25",
+        Test "{a:1}" ["a" =: s "\xa0\&B"] "%C2%A0",
+        Test "{a:1}" ["a" =: s "\xd7ff\&B"] "%ED%9F%BF",
+        Test "{a:1}" ["a" =: s "\x10000\&B"] "%F0%90%80%80",
+        Test "{a:1}" ["a" =: l []] "",
+        Test "{a:1}" ["a" =: l ["AB"]] "AB",
+        Test "{a:1}" ["a" =: l ["AB", "CD"]] "AB,CD",
+        Test "{a:1}" ["a" =: d []] "",
+        Test "{a:1}" ["a" =: d ["AB" =: "12"]] "AB,12",
+        Test "{a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "AB,12,CD,34",
+        Test "{a,a}" [] "",
+        Test "{a,a}" ["a" =: l []] "",
+        Test "{a,a}" ["a" =: d []] "",
+        Test "{a,a}" ["a" =: s ""] ",",
+        Test "{a,b}" ["a" =: s ""] "",
+        Test "{a,b}" ["b" =: s ""] "",
+        Test "{%aa}" ["%aa" =: s "A"] "A",
+        Test "{%aa}" ["%aa" =: l ["A", "B"]] "A,B",
+        Test "{%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "A,1,B,2",
+        Test "{%aa*}" ["%aa" =: s "A"] "A",
+        Test "{%aa*}" ["%aa" =: l ["A", "B"]] "A,B",
+        Test "{%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "A=1,B=2",
+        Test "{+a}" [] "",
+        Test "{+a}" ["a" =: l []] "",
+        Test "{+a}" ["a" =: d []] "",
+        Test "{+a}" ["a" =: s ""] "",
+        Test "{+a}" ["a" =: s "A"] "A",
+        Test "{+a}" ["a" =: s "~"] "~",
+        Test "{+a}" ["a" =: s "%"] "%25",
+        Test "{+a}" ["a" =: s "?"] "?",
+        Test "{+a}" ["a" =: s "&"] "&",
+        Test "{+a}" ["a" =: s "\xa0"] "%C2%A0",
+        Test "{+a}" ["a" =: s "\xd7ff"] "%ED%9F%BF",
+        Test "{+a}" ["a" =: s "\x10000"] "%F0%90%80%80",
+        Test "{+a}" ["a" =: l ["A"]] "A",
+        Test "{+a}" ["a" =: l ["A", "B"]] "A,B",
+        Test "{+a}" ["a" =: l ["%"]] "%25",
+        Test "{+a}" ["a" =: l ["\xa0"]] "%C2%A0",
+        Test "{+a}" ["a" =: d ["A" =: "1"]] "A,1",
+        Test "{+a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "A,1,B,2",
+        Test "{+a}" ["a" =: d ["A" =: "%"]] "A,%25",
+        Test "{+a}" ["a" =: d ["A" =: "\xa0"]] "A,%C2%A0",
+        Test "{+a}" ["a" =: d ["%" =: "1"]] "%25,1",
+        Test "{+a*}" [] "",
+        Test "{+a*}" ["a" =: s ""] "",
+        Test "{+a*}" ["a" =: s "A"] "A",
+        Test "{+a*}" ["a" =: l []] "",
+        Test "{+a*}" ["a" =: l ["A"]] "A",
+        Test "{+a*}" ["a" =: l ["A", "B"]] "A,B",
+        Test "{+a*}" ["a" =: d []] "",
+        Test "{+a*}" ["a" =: d ["A" =: "1"]] "A=1",
+        Test "{+a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "A=1,B=2",
+        Test "{+a:1}" [] "",
+        Test "{+a:1}" ["a" =: s ""] "",
+        Test "{+a:1}" ["a" =: s "A"] "A",
+        Test "{+a:1}" ["a" =: s "AB"] "A",
+        Test "{+a:1}" ["a" =: s "%B"] "%25",
+        Test "{+a:1}" ["a" =: s "\xa0\&B"] "%C2%A0",
+        Test "{+a:1}" ["a" =: s "\xd7ff\&B"] "%ED%9F%BF",
+        Test "{+a:1}" ["a" =: s "\x10000\&B"] "%F0%90%80%80",
+        Test "{+a:1}" ["a" =: l []] "",
+        Test "{+a:1}" ["a" =: l ["AB"]] "AB",
+        Test "{+a:1}" ["a" =: l ["AB", "CD"]] "AB,CD",
+        Test "{+a:1}" ["a" =: d []] "",
+        Test "{+a:1}" ["a" =: d ["AB" =: "12"]] "AB,12",
+        Test "{+a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "AB,12,CD,34",
+        Test "{+a,a}" [] "",
+        Test "{+a,a}" ["a" =: l []] "",
+        Test "{+a,a}" ["a" =: d []] "",
+        Test "{+a,a}" ["a" =: s ""] ",",
+        Test "{+a,b}" ["a" =: s ""] "",
+        Test "{+a,b}" ["b" =: s ""] "",
+        Test "{+%aa}" ["%aa" =: s "A"] "A",
+        Test "{+%aa}" ["%aa" =: l ["A", "B"]] "A,B",
+        Test "{+%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "A,1,B,2",
+        Test "{+%aa*}" ["%aa" =: s "A"] "A",
+        Test "{+%aa*}" ["%aa" =: l ["A", "B"]] "A,B",
+        Test "{+%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "A=1,B=2",
+        Test "{#a}" [] "",
+        Test "{#a}" ["a" =: l []] "",
+        Test "{#a}" ["a" =: d []] "",
+        Test "{#a}" ["a" =: s ""] "#",
+        Test "{#a}" ["a" =: s "A"] "#A",
+        Test "{#a}" ["a" =: s "~"] "#~",
+        Test "{#a}" ["a" =: s "%"] "#%25",
+        Test "{#a}" ["a" =: s "?"] "#?",
+        Test "{#a}" ["a" =: s "&"] "#&",
+        Test "{#a}" ["a" =: s "\xa0"] "#%C2%A0",
+        Test "{#a}" ["a" =: s "\xd7ff"] "#%ED%9F%BF",
+        Test "{#a}" ["a" =: s "\x10000"] "#%F0%90%80%80",
+        Test "{#a}" ["a" =: l ["A"]] "#A",
+        Test "{#a}" ["a" =: l ["A", "B"]] "#A,B",
+        Test "{#a}" ["a" =: l ["%"]] "#%25",
+        Test "{#a}" ["a" =: l ["\xa0"]] "#%C2%A0",
+        Test "{#a}" ["a" =: d ["A" =: "1"]] "#A,1",
+        Test "{#a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "#A,1,B,2",
+        Test "{#a}" ["a" =: d ["A" =: "%"]] "#A,%25",
+        Test "{#a}" ["a" =: d ["A" =: "\xa0"]] "#A,%C2%A0",
+        Test "{#a}" ["a" =: d ["%" =: "1"]] "#%25,1",
+        Test "{#a*}" [] "",
+        Test "{#a*}" ["a" =: s ""] "#",
+        Test "{#a*}" ["a" =: s "A"] "#A",
+        Test "{#a*}" ["a" =: l []] "",
+        Test "{#a*}" ["a" =: l ["A"]] "#A",
+        Test "{#a*}" ["a" =: l ["A", "B"]] "#A,B",
+        Test "{#a*}" ["a" =: d []] "",
+        Test "{#a*}" ["a" =: d ["A" =: "1"]] "#A=1",
+        Test "{#a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "#A=1,B=2",
+        Test "{#a:1}" [] "",
+        Test "{#a:1}" ["a" =: s ""] "#",
+        Test "{#a:1}" ["a" =: s "A"] "#A",
+        Test "{#a:1}" ["a" =: s "AB"] "#A",
+        Test "{#a:1}" ["a" =: s "%B"] "#%25",
+        Test "{#a:1}" ["a" =: s "\xa0\&B"] "#%C2%A0",
+        Test "{#a:1}" ["a" =: s "\xd7ff\&B"] "#%ED%9F%BF",
+        Test "{#a:1}" ["a" =: s "\x10000\&B"] "#%F0%90%80%80",
+        Test "{#a:1}" ["a" =: l []] "",
+        Test "{#a:1}" ["a" =: l ["AB"]] "#AB",
+        Test "{#a:1}" ["a" =: l ["AB", "CD"]] "#AB,CD",
+        Test "{#a:1}" ["a" =: d []] "",
+        Test "{#a:1}" ["a" =: d ["AB" =: "12"]] "#AB,12",
+        Test "{#a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "#AB,12,CD,34",
+        Test "{#a,a}" [] "",
+        Test "{#a,a}" ["a" =: l []] "",
+        Test "{#a,a}" ["a" =: d []] "",
+        Test "{#a,a}" ["a" =: s ""] "#,",
+        Test "{#a,b}" ["a" =: s ""] "#",
+        Test "{#a,b}" ["b" =: s ""] "#",
+        Test "{#%aa}" ["%aa" =: s "A"] "#A",
+        Test "{#%aa}" ["%aa" =: l ["A", "B"]] "#A,B",
+        Test "{#%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "#A,1,B,2",
+        Test "{#%aa*}" ["%aa" =: s "A"] "#A",
+        Test "{#%aa*}" ["%aa" =: l ["A", "B"]] "#A,B",
+        Test "{#%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "#A=1,B=2",
+        Test "{.a}" [] "",
+        Test "{.a}" ["a" =: l []] "",
+        Test "{.a}" ["a" =: d []] "",
+        Test "{.a}" ["a" =: s ""] ".",
+        Test "{.a}" ["a" =: s "A"] ".A",
+        Test "{.a}" ["a" =: s "~"] ".~",
+        Test "{.a}" ["a" =: s "%"] ".%25",
+        Test "{.a}" ["a" =: s "?"] ".%3F",
+        Test "{.a}" ["a" =: s "&"] ".%26",
+        Test "{.a}" ["a" =: s "\xa0"] ".%C2%A0",
+        Test "{.a}" ["a" =: s "\xd7ff"] ".%ED%9F%BF",
+        Test "{.a}" ["a" =: s "\x10000"] ".%F0%90%80%80",
+        Test "{.a}" ["a" =: l ["A"]] ".A",
+        Test "{.a}" ["a" =: l ["A", "B"]] ".A,B",
+        Test "{.a}" ["a" =: l ["%"]] ".%25",
+        Test "{.a}" ["a" =: l ["\xa0"]] ".%C2%A0",
+        Test "{.a}" ["a" =: d ["A" =: "1"]] ".A,1",
+        Test "{.a}" ["a" =: d ["A" =: "1", "B" =: "2"]] ".A,1,B,2",
+        Test "{.a}" ["a" =: d ["A" =: "%"]] ".A,%25",
+        Test "{.a}" ["a" =: d ["A" =: "\xa0"]] ".A,%C2%A0",
+        Test "{.a}" ["a" =: d ["%" =: "1"]] ".%25,1",
+        Test "{.a*}" [] "",
+        Test "{.a*}" ["a" =: s ""] ".",
+        Test "{.a*}" ["a" =: s "A"] ".A",
+        Test "{.a*}" ["a" =: l []] "",
+        Test "{.a*}" ["a" =: l ["A"]] ".A",
+        Test "{.a*}" ["a" =: l ["A", "B"]] ".A.B",
+        Test "{.a*}" ["a" =: d []] "",
+        Test "{.a*}" ["a" =: d ["A" =: "1"]] ".A=1",
+        Test "{.a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] ".A=1.B=2",
+        Test "{.a:1}" [] "",
+        Test "{.a:1}" ["a" =: s ""] ".",
+        Test "{.a:1}" ["a" =: s "A"] ".A",
+        Test "{.a:1}" ["a" =: s "AB"] ".A",
+        Test "{.a:1}" ["a" =: s "%B"] ".%25",
+        Test "{.a:1}" ["a" =: s "\xa0\&B"] ".%C2%A0",
+        Test "{.a:1}" ["a" =: s "\xd7ff\&B"] ".%ED%9F%BF",
+        Test "{.a:1}" ["a" =: s "\x10000\&B"] ".%F0%90%80%80",
+        Test "{.a:1}" ["a" =: l []] "",
+        Test "{.a:1}" ["a" =: l ["AB"]] ".AB",
+        Test "{.a:1}" ["a" =: l ["AB", "CD"]] ".AB,CD",
+        Test "{.a:1}" ["a" =: d []] "",
+        Test "{.a:1}" ["a" =: d ["AB" =: "12"]] ".AB,12",
+        Test "{.a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] ".AB,12,CD,34",
+        Test "{.a,a}" [] "",
+        Test "{.a,a}" ["a" =: l []] "",
+        Test "{.a,a}" ["a" =: d []] "",
+        Test "{.a,a}" ["a" =: s ""] "..",
+        Test "{.a,b}" ["a" =: s ""] ".",
+        Test "{.a,b}" ["b" =: s ""] ".",
+        Test "{.%aa}" ["%aa" =: s "A"] ".A",
+        Test "{.%aa}" ["%aa" =: l ["A", "B"]] ".A,B",
+        Test "{.%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] ".A,1,B,2",
+        Test "{.%aa*}" ["%aa" =: s "A"] ".A",
+        Test "{.%aa*}" ["%aa" =: l ["A", "B"]] ".A.B",
+        Test "{.%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] ".A=1.B=2",
+        Test "{/a}" [] "",
+        Test "{/a}" ["a" =: l []] "",
+        Test "{/a}" ["a" =: d []] "",
+        Test "{/a}" ["a" =: s ""] "/",
+        Test "{/a}" ["a" =: s "A"] "/A",
+        Test "{/a}" ["a" =: s "~"] "/~",
+        Test "{/a}" ["a" =: s "%"] "/%25",
+        Test "{/a}" ["a" =: s "?"] "/%3F",
+        Test "{/a}" ["a" =: s "&"] "/%26",
+        Test "{/a}" ["a" =: s "\xa0"] "/%C2%A0",
+        Test "{/a}" ["a" =: s "\xd7ff"] "/%ED%9F%BF",
+        Test "{/a}" ["a" =: s "\x10000"] "/%F0%90%80%80",
+        Test "{/a}" ["a" =: l ["A"]] "/A",
+        Test "{/a}" ["a" =: l ["A", "B"]] "/A,B",
+        Test "{/a}" ["a" =: l ["%"]] "/%25",
+        Test "{/a}" ["a" =: l ["\xa0"]] "/%C2%A0",
+        Test "{/a}" ["a" =: d ["A" =: "1"]] "/A,1",
+        Test "{/a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "/A,1,B,2",
+        Test "{/a}" ["a" =: d ["A" =: "%"]] "/A,%25",
+        Test "{/a}" ["a" =: d ["A" =: "\xa0"]] "/A,%C2%A0",
+        Test "{/a}" ["a" =: d ["%" =: "1"]] "/%25,1",
+        Test "{/a*}" [] "",
+        Test "{/a*}" ["a" =: s ""] "/",
+        Test "{/a*}" ["a" =: s "A"] "/A",
+        Test "{/a*}" ["a" =: l []] "",
+        Test "{/a*}" ["a" =: l ["A"]] "/A",
+        Test "{/a*}" ["a" =: l ["A", "B"]] "/A/B",
+        Test "{/a*}" ["a" =: d []] "",
+        Test "{/a*}" ["a" =: d ["A" =: "1"]] "/A=1",
+        Test "{/a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "/A=1/B=2",
+        Test "{/a:1}" [] "",
+        Test "{/a:1}" ["a" =: s ""] "/",
+        Test "{/a:1}" ["a" =: s "A"] "/A",
+        Test "{/a:1}" ["a" =: s "AB"] "/A",
+        Test "{/a:1}" ["a" =: s "%B"] "/%25",
+        Test "{/a:1}" ["a" =: s "\xa0\&B"] "/%C2%A0",
+        Test "{/a:1}" ["a" =: s "\xd7ff\&B"] "/%ED%9F%BF",
+        Test "{/a:1}" ["a" =: s "\x10000\&B"] "/%F0%90%80%80",
+        Test "{/a:1}" ["a" =: l []] "",
+        Test "{/a:1}" ["a" =: l ["AB"]] "/AB",
+        Test "{/a:1}" ["a" =: l ["AB", "CD"]] "/AB,CD",
+        Test "{/a:1}" ["a" =: d []] "",
+        Test "{/a:1}" ["a" =: d ["AB" =: "12"]] "/AB,12",
+        Test "{/a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "/AB,12,CD,34",
+        Test "{/a,a}" [] "",
+        Test "{/a,a}" ["a" =: l []] "",
+        Test "{/a,a}" ["a" =: d []] "",
+        Test "{/a,a}" ["a" =: s ""] "//",
+        Test "{/a,b}" ["a" =: s ""] "/",
+        Test "{/a,b}" ["b" =: s ""] "/",
+        Test "{/%aa}" ["%aa" =: s "A"] "/A",
+        Test "{/%aa}" ["%aa" =: l ["A", "B"]] "/A,B",
+        Test "{/%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "/A,1,B,2",
+        Test "{/%aa*}" ["%aa" =: s "A"] "/A",
+        Test "{/%aa*}" ["%aa" =: l ["A", "B"]] "/A/B",
+        Test "{/%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "/A=1/B=2",
+        Test "{;a}" [] "",
+        Test "{;a}" ["a" =: l []] "",
+        Test "{;a}" ["a" =: d []] "",
+        Test "{;a}" ["a" =: s ""] ";a",
+        Test "{;a}" ["a" =: s "A"] ";a=A",
+        Test "{;a}" ["a" =: s "~"] ";a=~",
+        Test "{;a}" ["a" =: s "%"] ";a=%25",
+        Test "{;a}" ["a" =: s "?"] ";a=%3F",
+        Test "{;a}" ["a" =: s "&"] ";a=%26",
+        Test "{;a}" ["a" =: s "\xa0"] ";a=%C2%A0",
+        Test "{;a}" ["a" =: s "\xd7ff"] ";a=%ED%9F%BF",
+        Test "{;a}" ["a" =: s "\x10000"] ";a=%F0%90%80%80",
+        Test "{;a}" ["a" =: l ["A"]] ";a=A",
+        Test "{;a}" ["a" =: l ["A", "B"]] ";a=A,B",
+        Test "{;a}" ["a" =: l ["%"]] ";a=%25",
+        Test "{;a}" ["a" =: l ["\xa0"]] ";a=%C2%A0",
+        Test "{;a}" ["a" =: d ["A" =: "1"]] ";a=A,1",
+        Test "{;a}" ["a" =: d ["A" =: "1", "B" =: "2"]] ";a=A,1,B,2",
+        Test "{;a}" ["a" =: d ["A" =: "%"]] ";a=A,%25",
+        Test "{;a}" ["a" =: d ["A" =: "\xa0"]] ";a=A,%C2%A0",
+        Test "{;a}" ["a" =: d ["%" =: "1"]] ";a=%25,1",
+        Test "{;a*}" [] "",
+        Test "{;a*}" ["a" =: s ""] ";a",
+        Test "{;a*}" ["a" =: s "A"] ";a=A",
+        Test "{;a*}" ["a" =: l []] "",
+        Test "{;a*}" ["a" =: l ["A"]] ";a=A",
+        Test "{;a*}" ["a" =: l ["A", "B"]] ";a=A;a=B",
+        Test "{;a*}" ["a" =: d []] "",
+        Test "{;a*}" ["a" =: d ["A" =: "1"]] ";A=1",
+        Test "{;a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] ";A=1;B=2",
+        Test "{;a:1}" [] "",
+        Test "{;a:1}" ["a" =: s ""] ";a",
+        Test "{;a:1}" ["a" =: s "A"] ";a=A",
+        Test "{;a:1}" ["a" =: s "AB"] ";a=A",
+        Test "{;a:1}" ["a" =: s "%B"] ";a=%25",
+        Test "{;a:1}" ["a" =: s "\xa0\&B"] ";a=%C2%A0",
+        Test "{;a:1}" ["a" =: s "\xd7ff\&B"] ";a=%ED%9F%BF",
+        Test "{;a:1}" ["a" =: s "\x10000\&B"] ";a=%F0%90%80%80",
+        Test "{;a:1}" ["a" =: l []] "",
+        Test "{;a:1}" ["a" =: l ["AB"]] ";a=AB",
+        Test "{;a:1}" ["a" =: l ["AB", "CD"]] ";a=AB,CD",
+        Test "{;a:1}" ["a" =: d []] "",
+        Test "{;a:1}" ["a" =: d ["AB" =: "12"]] ";a=AB,12",
+        Test "{;a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] ";a=AB,12,CD,34",
+        Test "{;a,a}" [] "",
+        Test "{;a,a}" ["a" =: l []] "",
+        Test "{;a,a}" ["a" =: d []] "",
+        Test "{;a,a}" ["a" =: s ""] ";a;a",
+        Test "{;a,b}" ["a" =: s ""] ";a",
+        Test "{;a,b}" ["b" =: s ""] ";b",
+        Test "{;%aa}" ["%aa" =: s "A"] ";%aa=A",
+        Test "{;%aa}" ["%aa" =: l ["A", "B"]] ";%aa=A,B",
+        Test "{;%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] ";%aa=A,1,B,2",
+        Test "{;%aa*}" ["%aa" =: s "A"] ";%aa=A",
+        Test "{;%aa*}" ["%aa" =: l ["A", "B"]] ";%aa=A;%aa=B",
+        Test "{;%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] ";A=1;B=2",
+        Test "{?a}" [] "",
+        Test "{?a}" ["a" =: l []] "",
+        Test "{?a}" ["a" =: d []] "",
+        Test "{?a}" ["a" =: s ""] "?a=",
+        Test "{?a}" ["a" =: s "A"] "?a=A",
+        Test "{?a}" ["a" =: s "~"] "?a=~",
+        Test "{?a}" ["a" =: s "%"] "?a=%25",
+        Test "{?a}" ["a" =: s "?"] "?a=%3F",
+        Test "{?a}" ["a" =: s "&"] "?a=%26",
+        Test "{?a}" ["a" =: s "\xa0"] "?a=%C2%A0",
+        Test "{?a}" ["a" =: s "\xd7ff"] "?a=%ED%9F%BF",
+        Test "{?a}" ["a" =: s "\x10000"] "?a=%F0%90%80%80",
+        Test "{?a}" ["a" =: l ["A"]] "?a=A",
+        Test "{?a}" ["a" =: l ["A", "B"]] "?a=A,B",
+        Test "{?a}" ["a" =: l ["%"]] "?a=%25",
+        Test "{?a}" ["a" =: l ["\xa0"]] "?a=%C2%A0",
+        Test "{?a}" ["a" =: d ["A" =: "1"]] "?a=A,1",
+        Test "{?a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "?a=A,1,B,2",
+        Test "{?a}" ["a" =: d ["A" =: "%"]] "?a=A,%25",
+        Test "{?a}" ["a" =: d ["A" =: "\xa0"]] "?a=A,%C2%A0",
+        Test "{?a}" ["a" =: d ["%" =: "1"]] "?a=%25,1",
+        Test "{?a*}" [] "",
+        Test "{?a*}" ["a" =: s ""] "?a=",
+        Test "{?a*}" ["a" =: s "A"] "?a=A",
+        Test "{?a*}" ["a" =: l []] "",
+        Test "{?a*}" ["a" =: l ["A"]] "?a=A",
+        Test "{?a*}" ["a" =: l ["A", "B"]] "?a=A&a=B",
+        Test "{?a*}" ["a" =: d []] "",
+        Test "{?a*}" ["a" =: d ["A" =: "1"]] "?A=1",
+        Test "{?a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "?A=1&B=2",
+        Test "{?a:1}" [] "",
+        Test "{?a:1}" ["a" =: s ""] "?a=",
+        Test "{?a:1}" ["a" =: s "A"] "?a=A",
+        Test "{?a:1}" ["a" =: s "AB"] "?a=A",
+        Test "{?a:1}" ["a" =: s "%B"] "?a=%25",
+        Test "{?a:1}" ["a" =: s "\xa0\&B"] "?a=%C2%A0",
+        Test "{?a:1}" ["a" =: s "\xd7ff\&B"] "?a=%ED%9F%BF",
+        Test "{?a:1}" ["a" =: s "\x10000\&B"] "?a=%F0%90%80%80",
+        Test "{?a:1}" ["a" =: l []] "",
+        Test "{?a:1}" ["a" =: l ["AB"]] "?a=AB",
+        Test "{?a:1}" ["a" =: l ["AB", "CD"]] "?a=AB,CD",
+        Test "{?a:1}" ["a" =: d []] "",
+        Test "{?a:1}" ["a" =: d ["AB" =: "12"]] "?a=AB,12",
+        Test "{?a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "?a=AB,12,CD,34",
+        Test "{?a,a}" [] "",
+        Test "{?a,a}" ["a" =: l []] "",
+        Test "{?a,a}" ["a" =: d []] "",
+        Test "{?a,a}" ["a" =: s ""] "?a=&a=",
+        Test "{?a,b}" ["a" =: s ""] "?a=",
+        Test "{?a,b}" ["b" =: s ""] "?b=",
+        Test "{?%aa}" ["%aa" =: s "A"] "?%aa=A",
+        Test "{?%aa}" ["%aa" =: l ["A", "B"]] "?%aa=A,B",
+        Test "{?%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "?%aa=A,1,B,2",
+        Test "{?%aa*}" ["%aa" =: s "A"] "?%aa=A",
+        Test "{?%aa*}" ["%aa" =: l ["A", "B"]] "?%aa=A&%aa=B",
+        Test "{?%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "?A=1&B=2",
+        Test "{&a}" [] "",
+        Test "{&a}" ["a" =: l []] "",
+        Test "{&a}" ["a" =: d []] "",
+        Test "{&a}" ["a" =: s ""] "&a=",
+        Test "{&a}" ["a" =: s "A"] "&a=A",
+        Test "{&a}" ["a" =: s "~"] "&a=~",
+        Test "{&a}" ["a" =: s "%"] "&a=%25",
+        Test "{&a}" ["a" =: s "?"] "&a=%3F",
+        Test "{&a}" ["a" =: s "&"] "&a=%26",
+        Test "{&a}" ["a" =: s "\xa0"] "&a=%C2%A0",
+        Test "{&a}" ["a" =: s "\xd7ff"] "&a=%ED%9F%BF",
+        Test "{&a}" ["a" =: s "\x10000"] "&a=%F0%90%80%80",
+        Test "{&a}" ["a" =: l ["A"]] "&a=A",
+        Test "{&a}" ["a" =: l ["A", "B"]] "&a=A,B",
+        Test "{&a}" ["a" =: l ["%"]] "&a=%25",
+        Test "{&a}" ["a" =: l ["\xa0"]] "&a=%C2%A0",
+        Test "{&a}" ["a" =: d ["A" =: "1"]] "&a=A,1",
+        Test "{&a}" ["a" =: d ["A" =: "1", "B" =: "2"]] "&a=A,1,B,2",
+        Test "{&a}" ["a" =: d ["A" =: "%"]] "&a=A,%25",
+        Test "{&a}" ["a" =: d ["A" =: "\xa0"]] "&a=A,%C2%A0",
+        Test "{&a}" ["a" =: d ["%" =: "1"]] "&a=%25,1",
+        Test "{&a*}" [] "",
+        Test "{&a*}" ["a" =: s ""] "&a=",
+        Test "{&a*}" ["a" =: s "A"] "&a=A",
+        Test "{&a*}" ["a" =: l []] "",
+        Test "{&a*}" ["a" =: l ["A"]] "&a=A",
+        Test "{&a*}" ["a" =: l ["A", "B"]] "&a=A&a=B",
+        Test "{&a*}" ["a" =: d []] "",
+        Test "{&a*}" ["a" =: d ["A" =: "1"]] "&A=1",
+        Test "{&a*}" ["a" =: d ["A" =: "1", "B" =: "2"]] "&A=1&B=2",
+        Test "{&a:1}" [] "",
+        Test "{&a:1}" ["a" =: s ""] "&a=",
+        Test "{&a:1}" ["a" =: s "A"] "&a=A",
+        Test "{&a:1}" ["a" =: s "AB"] "&a=A",
+        Test "{&a:1}" ["a" =: s "%B"] "&a=%25",
+        Test "{&a:1}" ["a" =: s "\xa0\&B"] "&a=%C2%A0",
+        Test "{&a:1}" ["a" =: s "\xd7ff\&B"] "&a=%ED%9F%BF",
+        Test "{&a:1}" ["a" =: s "\x10000\&B"] "&a=%F0%90%80%80",
+        Test "{&a:1}" ["a" =: l []] "",
+        Test "{&a:1}" ["a" =: l ["AB"]] "&a=AB",
+        Test "{&a:1}" ["a" =: l ["AB", "CD"]] "&a=AB,CD",
+        Test "{&a:1}" ["a" =: d []] "",
+        Test "{&a:1}" ["a" =: d ["AB" =: "12"]] "&a=AB,12",
+        Test "{&a:1}" ["a" =: d ["AB" =: "12", "CD" =: "34"]] "&a=AB,12,CD,34",
+        Test "{&a,a}" [] "",
+        Test "{&a,a}" ["a" =: l []] "",
+        Test "{&a,a}" ["a" =: d []] "",
+        Test "{&a,a}" ["a" =: s ""] "&a=&a=",
+        Test "{&a,b}" ["a" =: s ""] "&a=",
+        Test "{&a,b}" ["b" =: s ""] "&b=",
+        Test "{&%aa}" ["%aa" =: s "A"] "&%aa=A",
+        Test "{&%aa}" ["%aa" =: l ["A", "B"]] "&%aa=A,B",
+        Test "{&%aa}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "&%aa=A,1,B,2",
+        Test "{&%aa*}" ["%aa" =: s "A"] "&%aa=A",
+        Test "{&%aa*}" ["%aa" =: l ["A", "B"]] "&%aa=A&%aa=B",
+        Test "{&%aa*}" ["%aa" =: d ["A" =: "1", "B" =: "2"]] "&A=1&B=2"
+      ],
+      let values = ["%AA" =: s "1", "%Aa" =: s "2", "%aA" =: s "3", "%aa" =: s "4"]
+       in [ Test "{%AA}" values "1",
+            Test "{%Aa}" values "2",
+            Test "{%aA}" values "3",
+            Test "{%aa}" values "4"
+            -- This comment forces Brittany to use a multi-line layout.
+          ],
+      let values = ["a" =: s "abcdefghijklmnopqrstuvwxyz"]
+       in [ Test "{a:1}" values "a",
+            Test "{a:5}" values "abcde",
+            Test "{a:10}" values "abcdefghij",
+            Test "{a:15}" values "abcdefghijklmno",
+            Test "{a:20}" values "abcdefghijklmnopqrst",
+            Test "{a:25}" values "abcdefghijklmnopqrstuvwxy",
+            Test "{a:26}" values "abcdefghijklmnopqrstuvwxyz",
+            Test "{a:30}" values "abcdefghijklmnopqrstuvwxyz"
+          ],
+      let values = ["a" =: l []]
+       in [ Test "{a}" values "",
+            Test "{+a}" values "",
+            Test "{#a}" values "",
+            Test "{.a}" values "",
+            Test "{/a}" values "",
+            Test "{;a}" values "",
+            Test "{?a}" values "",
+            Test "{&a}" values ""
+          ],
+      let values = ["a" =: d []]
+       in [ Test "{a}" values "",
+            Test "{+a}" values "",
+            Test "{#a}" values "",
+            Test "{.a}" values "",
+            Test "{/a}" values "",
+            Test "{;a}" values "",
+            Test "{?a}" values "",
+            Test "{&a}" values ""
+          ],
+      let values = ["a" =: s ""]
+       in [ Test "{a}" values "",
+            Test "{+a}" values "",
+            Test "{#a}" values "#",
+            Test "{.a}" values ".",
+            Test "{/a}" values "/",
+            Test "{;a}" values ";a",
+            Test "{?a}" values "?a=",
+            Test "{&a}" values "&a="
+          ],
+      let values = ["a" =: s "A"]
+       in [ Test "{a}" values "A",
+            Test "{+a}" values "A",
+            Test "{#a}" values "#A",
+            Test "{.a}" values ".A",
+            Test "{/a}" values "/A",
+            Test "{;a}" values ";a=A",
+            Test "{?a}" values "?a=A",
+            Test "{&a}" values "&a=A"
+          ],
+      let values = ["b" =: s "B"]
+       in [ Test "{a,b}" values "B",
+            Test "{+a,b}" values "B",
+            Test "{#a,b}" values "#B",
+            Test "{.a,b}" values ".B",
+            Test "{/a,b}" values "/B",
+            Test "{;a,b}" values ";b=B",
+            Test "{?a,b}" values "?b=B",
+            Test "{&a,b}" values "&b=B"
+          ],
+      let values = ["a" =: s ""]
+       in [ Test "{a,a}" values ",",
+            Test "{+a,a}" values ",",
+            Test "{#a,a}" values "#,",
+            Test "{.a,a}" values "..",
+            Test "{/a,a}" values "//",
+            Test "{;a,a}" values ";a;a",
+            Test "{?a,a}" values "?a=&a=",
+            Test "{&a,a}" values "&a=&a="
+          ],
+      let values = ["a" =: s "A", "b" =: s "B"]
+       in [ Test "{a,b}" values "A,B",
+            Test "{+a,b}" values "A,B",
+            Test "{#a,b}" values "#A,B",
+            Test "{.a,b}" values ".A.B",
+            Test "{/a,b}" values "/A/B",
+            Test "{;a,b}" values ";a=A;b=B",
+            Test "{?a,b}" values "?a=A&b=B",
+            Test "{&a,b}" values "&a=A&b=B"
+          ],
+      let values = ["a" =: d ["K! \xa0\xd7ff\x10000" =: "V! \xa0\xd7ff\x10000"]]
+       in [ Test "{a*}" values "K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80",
+            Test "{+a*}" values "K!%20%C2%A0%ED%9F%BF%F0%90%80%80=V!%20%C2%A0%ED%9F%BF%F0%90%80%80",
+            Test "{#a*}" values "#K!%20%C2%A0%ED%9F%BF%F0%90%80%80=V!%20%C2%A0%ED%9F%BF%F0%90%80%80",
+            Test "{.a*}" values ".K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80",
+            Test "{/a*}" values "/K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80",
+            Test "{;a*}" values ";K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80",
+            Test "{?a*}" values "?K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80",
+            Test "{&a*}" values "&K%21%20%C2%A0%ED%9F%BF%F0%90%80%80=V%21%20%C2%A0%ED%9F%BF%F0%90%80%80"
+          ],
+      let values =
+            [ "empty" =: s "",
+              "hello" =: s "Hello World!",
+              "keys" =: d ["semi" =: ";", "dot" =: ".", "comma" =: ","],
+              "list" =: l ["red", "green", "blue"],
+              "path" =: s "/foo/bar",
+              "var" =: s "value",
+              "x" =: s "1024",
+              "y" =: s "768"
+            ]
+       in [ Test "{var}" values "value",
+            Test "{hello}" values "Hello%20World%21",
+            Test "{+var}" values "value",
+            Test "{+hello}" values "Hello%20World!",
+            Test "{+path}/here" values "/foo/bar/here",
+            Test "here?ref={+path}" values "here?ref=/foo/bar",
+            Test "X{#var}" values "X#value",
+            Test "X{#hello}" values "X#Hello%20World!",
+            Test "map?{x,y}" values "map?1024,768",
+            Test "{x,hello,y}" values "1024,Hello%20World%21,768",
+            Test "{+x,hello,y}" values "1024,Hello%20World!,768",
+            Test "{+path,x}/here" values "/foo/bar,1024/here",
+            Test "{#x,hello,y}" values "#1024,Hello%20World!,768",
+            Test "{#path,x}/here" values "#/foo/bar,1024/here",
+            Test "X{.var}" values "X.value",
+            Test "X{.x,y}" values "X.1024.768",
+            Test "{/var}" values "/value",
+            Test "{/var,x}/here" values "/value/1024/here",
+            Test "{;x,y}" values ";x=1024;y=768",
+            Test "{;x,y,empty}" values ";x=1024;y=768;empty",
+            Test "{?x,y}" values "?x=1024&y=768",
+            Test "{?x,y,empty}" values "?x=1024&y=768&empty=",
+            Test "?fixed=yes{&x}" values "?fixed=yes&x=1024",
+            Test "{&x,y,empty}" values "&x=1024&y=768&empty=",
+            Test "{var:3}" values "val",
+            Test "{var:30}" values "value",
+            Test "{list}" values "red,green,blue",
+            Test "{list*}" values "red,green,blue",
+            Test "{keys}" values "comma,%2C,dot,.,semi,%3B",
+            Test "{keys*}" values "comma=%2C,dot=.,semi=%3B",
+            Test "{+path:6}/here" values "/foo/b/here",
+            Test "{+list}" values "red,green,blue",
+            Test "{+list*}" values "red,green,blue",
+            Test "{+keys}" values "comma,,,dot,.,semi,;",
+            Test "{+keys*}" values "comma=,,dot=.,semi=;",
+            Test "{#path:6}/here" values "#/foo/b/here",
+            Test "{#list}" values "#red,green,blue",
+            Test "{#list*}" values "#red,green,blue",
+            Test "{#keys}" values "#comma,,,dot,.,semi,;",
+            Test "{#keys*}" values "#comma=,,dot=.,semi=;",
+            Test "X{.var:3}" values "X.val",
+            Test "X{.list}" values "X.red,green,blue",
+            Test "X{.list*}" values "X.red.green.blue",
+            Test "X{.keys}" values "X.comma,%2C,dot,.,semi,%3B",
+            Test "X{.keys*}" values "X.comma=%2C.dot=..semi=%3B",
+            Test "{/var:1,var}" values "/v/value",
+            Test "{/list}" values "/red,green,blue",
+            Test "{/list*}" values "/red/green/blue",
+            Test "{/list*,path:4}" values "/red/green/blue/%2Ffoo",
+            Test "{/keys}" values "/comma,%2C,dot,.,semi,%3B",
+            Test "{/keys*}" values "/comma=%2C/dot=./semi=%3B",
+            Test "{;hello:5}" values ";hello=Hello",
+            Test "{;list}" values ";list=red,green,blue",
+            Test "{;list*}" values ";list=red;list=green;list=blue",
+            Test "{;keys}" values ";keys=comma,%2C,dot,.,semi,%3B",
+            Test "{;keys*}" values ";comma=%2C;dot=.;semi=%3B",
+            Test "{?var:3}" values "?var=val",
+            Test "{?list}" values "?list=red,green,blue",
+            Test "{?list*}" values "?list=red&list=green&list=blue",
+            Test "{?keys}" values "?keys=comma,%2C,dot,.,semi,%3B",
+            Test "{?keys*}" values "?comma=%2C&dot=.&semi=%3B",
+            Test "{&var:3}" values "&var=val",
+            Test "{&list}" values "&list=red,green,blue",
+            Test "{&list*}" values "&list=red&list=green&list=blue",
+            Test "{&keys}" values "&keys=comma,%2C,dot,.,semi,%3B",
+            Test "{&keys*}" values "&comma=%2C&dot=.&semi=%3B"
+          ],
+      let values = ["var" =: s "value", "semi" =: s ";"]
+       in [ Test "{var}" values "value",
+            Test "{var:20}" values "value",
+            Test "{var:3}" values "val",
+            Test "{semi}" values "%3B",
+            Test "{semi:2}" values "%3B"
+            -- This comment forces Brittany to use a multi-line layout.
+          ],
+      let values = ["year" =: l ["1965", "2000", "2012"], "dom" =: l ["example", "com"]]
+       in [ Test "find{?year*}" values "find?year=1965&year=2000&year=2012",
+            Test "www{.dom*}" values "www.example.com"
+            -- This comment forces Brittany to use a multi-line layout.
+          ],
+      let values =
+            [ "base" =: s "http://example.com/home/",
+              "count" =: l ["one", "two", "three"],
+              "dom" =: l ["example", "com"],
+              "dub" =: s "me/too",
+              "empty_keys" =: d [],
+              "empty" =: s "",
+              "half" =: s "50%",
+              "hello" =: s "Hello World!",
+              "keys" =: d ["semi" =: ";", "dot" =: ".", "comma" =: ","],
+              "list" =: l ["red", "green", "blue"],
+              "path" =: s "/foo/bar",
+              "v" =: s "6",
+              "var" =: s "value",
+              "who" =: s "fred",
+              "x" =: s "1024",
+              "y" =: s "768"
+            ]
+       in [ Test "{count}" values "one,two,three",
+            Test "{count*}" values "one,two,three",
+            Test "{/count}" values "/one,two,three",
+            Test "{/count*}" values "/one/two/three",
+            Test "{;count}" values ";count=one,two,three",
+            Test "{;count*}" values ";count=one;count=two;count=three",
+            Test "{?count}" values "?count=one,two,three",
+            Test "{?count*}" values "?count=one&count=two&count=three",
+            Test "{&count*}" values "&count=one&count=two&count=three",
+            Test "{var}" values "value",
+            Test "{hello}" values "Hello%20World%21",
+            Test "{half}" values "50%25",
+            Test "O{empty}X" values "OX",
+            Test "O{undef}X" values "OX",
+            Test "{x,y}" values "1024,768",
+            Test "{x,hello,y}" values "1024,Hello%20World%21,768",
+            Test "?{x,empty}" values "?1024,",
+            Test "?{x,undef}" values "?1024",
+            Test "?{undef,y}" values "?768",
+            Test "{var:3}" values "val",
+            Test "{var:30}" values "value",
+            Test "{list}" values "red,green,blue",
+            Test "{list*}" values "red,green,blue",
+            Test "{keys}" values "comma,%2C,dot,.,semi,%3B",
+            Test "{keys*}" values "comma=%2C,dot=.,semi=%3B",
+            Test "{+var}" values "value",
+            Test "{+hello}" values "Hello%20World!",
+            Test "{+half}" values "50%25",
+            Test "{base}index" values "http%3A%2F%2Fexample.com%2Fhome%2Findex",
+            Test "{+base}index" values "http://example.com/home/index",
+            Test "O{+empty}X" values "OX",
+            Test "O{+undef}X" values "OX",
+            Test "{+path}/here" values "/foo/bar/here",
+            Test "here?ref={+path}" values "here?ref=/foo/bar",
+            Test "up{+path}{var}/here" values "up/foo/barvalue/here",
+            Test "{+x,hello,y}" values "1024,Hello%20World!,768",
+            Test "{+path,x}/here" values "/foo/bar,1024/here",
+            Test "{+path:6}/here" values "/foo/b/here",
+            Test "{+list}" values "red,green,blue",
+            Test "{+list*}" values "red,green,blue",
+            Test "{+keys}" values "comma,,,dot,.,semi,;",
+            Test "{+keys*}" values "comma=,,dot=.,semi=;",
+            Test "{#var}" values "#value",
+            Test "{#hello}" values "#Hello%20World!",
+            Test "{#half}" values "#50%25",
+            Test "foo{#empty}" values "foo#",
+            Test "foo{#undef}" values "foo",
+            Test "{#x,hello,y}" values "#1024,Hello%20World!,768",
+            Test "{#path,x}/here" values "#/foo/bar,1024/here",
+            Test "{#path:6}/here" values "#/foo/b/here",
+            Test "{#list}" values "#red,green,blue",
+            Test "{#list*}" values "#red,green,blue",
+            Test "{#keys}" values "#comma,,,dot,.,semi,;",
+            Test "{#keys*}" values "#comma=,,dot=.,semi=;",
+            Test "{.who}" values ".fred",
+            Test "{.who,who}" values ".fred.fred",
+            Test "{.half,who}" values ".50%25.fred",
+            Test "www{.dom*}" values "www.example.com",
+            Test "X{.var}" values "X.value",
+            Test "X{.empty}" values "X.",
+            Test "X{.undef}" values "X",
+            Test "X{.var:3}" values "X.val",
+            Test "X{.list}" values "X.red,green,blue",
+            Test "X{.list*}" values "X.red.green.blue",
+            Test "X{.keys}" values "X.comma,%2C,dot,.,semi,%3B",
+            Test "X{.keys*}" values "X.comma=%2C.dot=..semi=%3B",
+            Test "X{.empty_keys}" values "X",
+            Test "X{.empty_keys*}" values "X",
+            Test "{/who}" values "/fred",
+            Test "{/who,who}" values "/fred/fred",
+            Test "{/half,who}" values "/50%25/fred",
+            Test "{/who,dub}" values "/fred/me%2Ftoo",
+            Test "{/var}" values "/value",
+            Test "{/var,empty}" values "/value/",
+            Test "{/var,undef}" values "/value",
+            Test "{/var,x}/here" values "/value/1024/here",
+            Test "{/var:1,var}" values "/v/value",
+            Test "{/list}" values "/red,green,blue",
+            Test "{/list*}" values "/red/green/blue",
+            Test "{/list*,path:4}" values "/red/green/blue/%2Ffoo",
+            Test "{/keys}" values "/comma,%2C,dot,.,semi,%3B",
+            Test "{/keys*}" values "/comma=%2C/dot=./semi=%3B",
+            Test "{;who}" values ";who=fred",
+            Test "{;half}" values ";half=50%25",
+            Test "{;empty}" values ";empty",
+            Test "{;v,empty,who}" values ";v=6;empty;who=fred",
+            Test "{;v,bar,who}" values ";v=6;who=fred",
+            Test "{;x,y}" values ";x=1024;y=768",
+            Test "{;x,y,empty}" values ";x=1024;y=768;empty",
+            Test "{;x,y,undef}" values ";x=1024;y=768",
+            Test "{;hello:5}" values ";hello=Hello",
+            Test "{;list}" values ";list=red,green,blue",
+            Test "{;list*}" values ";list=red;list=green;list=blue",
+            Test "{;keys}" values ";keys=comma,%2C,dot,.,semi,%3B",
+            Test "{;keys*}" values ";comma=%2C;dot=.;semi=%3B",
+            Test "{?who}" values "?who=fred",
+            Test "{?half}" values "?half=50%25",
+            Test "{?x,y}" values "?x=1024&y=768",
+            Test "{?x,y,empty}" values "?x=1024&y=768&empty=",
+            Test "{?x,y,undef}" values "?x=1024&y=768",
+            Test "{?var:3}" values "?var=val",
+            Test "{?list}" values "?list=red,green,blue",
+            Test "{?list*}" values "?list=red&list=green&list=blue",
+            Test "{?keys}" values "?keys=comma,%2C,dot,.,semi,%3B",
+            Test "{?keys*}" values "?comma=%2C&dot=.&semi=%3B",
+            Test "{&who}" values "&who=fred",
+            Test "{&half}" values "&half=50%25",
+            Test "?fixed=yes{&x}" values "?fixed=yes&x=1024",
+            Test "{&x,y,empty}" values "&x=1024&y=768&empty=",
+            Test "{&x,y,undef}" values "&x=1024&y=768",
+            Test "{&var:3}" values "&var=val",
+            Test "{&list}" values "&list=red,green,blue",
+            Test "{&list*}" values "&list=red&list=green&list=blue",
+            Test "{&keys}" values "&keys=comma,%2C,dot,.,semi,%3B",
+            Test "{&keys*}" values "&comma=%2C&dot=.&semi=%3B"
+          ]
+    ]
+
+data Test = Test
+  { testInput :: String,
+    testValues :: [(String, Burrito.Value)],
+    testOutput :: Output
+  }
+  deriving (Eq, Show)
+
+runTest :: Test -> Hspec.Expectation
+runTest test =
+  case (Burrito.parse $ testInput test, unwrapOutput $ testOutput test) of
+    (Nothing, Nothing) -> pure ()
+    (Nothing, Just _) -> Hspec.expectationFailure "should have parsed"
+    (Just _, Nothing) -> Hspec.expectationFailure "should not have parsed"
+    (Just template, Just expected) -> do
+      let values = testValues test
+          actual = Burrito.expand values template
+      actual `Hspec.shouldBe` expected
+      Burrito.parse (show template) `Hspec.shouldBe` Just template
+      let relevant =
+            List.sort $ keepRelevant (templateVariables template) values
+      Monad.when (isMatchable template relevant) $ do
+        let matches = List.sort <$> Burrito.match expected template
+        matches `Hspec.shouldSatisfy` elem relevant
+
+isMatchable :: Template.Template -> [(String, Burrito.Value)] -> Bool
+isMatchable template values =
+  (not . any (isAsterisk . Variable.modifier) $ templateVariables template)
+    && all (isString . snd) values
+
+isString :: Burrito.Value -> Bool
+isString value = case value of
+  Value.String _ -> True
+  _ -> False
+
+isAsterisk :: Modifier.Modifier -> Bool
+isAsterisk modifier = case modifier of
+  Modifier.Asterisk -> True
+  _ -> False
+
+keepRelevant ::
+  Set.Set Variable.Variable ->
+  [(String, Burrito.Value)] ->
+  [(String, Burrito.Value)]
+keepRelevant variables =
+  let vs =
+        Map.fromListWith
+          ( \mx my -> case (mx, my) of
+              (Just x, Just y) -> Just $ max x y
+              _ -> Nothing
+          )
+          . fmap
+            ( \v ->
+                ( Render.builderToString . Render.name $ Variable.name v,
+                  case Variable.modifier v of
+                    Modifier.Colon n -> Just $ MaxLength.count n
+                    _ -> Nothing
+                )
+            )
+          $ Set.toList variables
+   in Maybe.mapMaybe $ \(k, v) -> do
+        m <- Map.lookup k vs
+        pure . (,) k $ case m of
+          Nothing -> v
+          Just n -> case v of
+            Value.String t -> Value.String $ Text.take n t
+            _ -> v
+
+templateVariables :: Template.Template -> Set.Set Variable.Variable
+templateVariables =
+  Set.fromList
+    . concatMap
+      ( \token -> case token of
+          Token.Expression expression ->
+            NonEmpty.toList $ Expression.variables expression
+          Token.Literal _ -> []
+      )
+    . Template.tokens
+
+newtype Output = Output
+  { unwrapOutput :: Maybe String
+  }
+  deriving (Eq, Show)
+
+instance String.IsString Output where
+  fromString = Output . Just
+
+noParse :: Output
+noParse = Output Nothing
+
+(=:) :: a -> b -> (a, b)
+(=:) = (,)
+
+s :: String -> Burrito.Value
+s = Burrito.stringValue
+
+l :: [String] -> Burrito.Value
+l = Burrito.listValue
+
+d :: [(String, String)] -> Burrito.Value
+d = Burrito.dictionaryValue
+
+newtype Template = Template
+  { unwrapTemplate :: Template.Template
+  }
+  deriving (Eq)
+
+instance Show Template where
+  show (Template template) =
+    unwords [show $ show template, "{-", show (Template.tokens template), "-}"]
+
+instance QC.Arbitrary Template where
+  arbitrary = Template <$> arbitraryTemplate
+  shrink = fmap Template . shrinkTemplate . unwrapTemplate
+
+type Shrink a = a -> [a]
+
+arbitraryTemplate :: QC.Gen Template.Template
+arbitraryTemplate = Template.Template . simplify <$> QC.listOf arbitraryToken
+
+shrinkTemplate :: Shrink Template.Template
+shrinkTemplate =
+  fmap (Template.Template . simplify)
+    . QC.shrinkList shrinkToken
+    . Template.tokens
+
+simplify :: [Token.Token] -> [Token.Token]
+simplify tokens = case tokens of
+  t1 : t2 : ts -> case (t1, t2) of
+    (Token.Literal l1, Token.Literal l2) ->
+      simplify $ Token.Literal (appendLiteral l1 l2) : ts
+    _ -> t1 : simplify (t2 : ts)
+  _ -> tokens
+
+appendLiteral :: Literal.Literal -> Literal.Literal -> Literal.Literal
+appendLiteral x y =
+  Literal.Literal $ Literal.characters x <> Literal.characters y
+
+arbitraryToken :: QC.Gen Token.Token
+arbitraryToken =
+  QC.oneof
+    [ Token.Expression <$> arbitraryExpression,
+      Token.Literal <$> arbitraryLiteral
+    ]
+
+shrinkToken :: Shrink Token.Token
+shrinkToken x = case x of
+  Token.Expression y -> Token.Expression <$> shrinkExpression y
+  Token.Literal y -> Token.Literal <$> shrinkLiteral y
+
+arbitraryExpression :: QC.Gen Expression.Expression
+arbitraryExpression =
+  Expression.Expression
+    <$> arbitraryOperator
+    <*> arbitraryNonEmpty arbitraryVariable
+
+shrinkExpression :: Shrink Expression.Expression
+shrinkExpression x =
+  uncurry Expression.Expression
+    <$> shrinkTuple
+      shrinkOperator
+      (shrinkNonEmpty shrinkVariable)
+      (Expression.operator x, Expression.variables x)
+
+arbitraryOperator :: QC.Gen Operator.Operator
+arbitraryOperator =
+  QC.elements
+    [ Operator.Ampersand,
+      Operator.FullStop,
+      Operator.None,
+      Operator.NumberSign,
+      Operator.PlusSign,
+      Operator.QuestionMark,
+      Operator.Semicolon,
+      Operator.Solidus
+    ]
+
+shrinkOperator :: Shrink Operator.Operator
+shrinkOperator x = case x of
+  Operator.None -> []
+  _ -> [Operator.None]
+
+arbitraryNonEmpty :: QC.Gen a -> QC.Gen (NonEmpty.NonEmpty a)
+arbitraryNonEmpty g = (NonEmpty.:|) <$> g <*> QC.listOf g
+
+shrinkNonEmpty :: Shrink a -> Shrink (NonEmpty.NonEmpty a)
+shrinkNonEmpty f x =
+  uncurry (NonEmpty.:|)
+    <$> shrinkTuple f (QC.shrinkList f) (NonEmpty.head x, NonEmpty.tail x)
+
+arbitraryVariable :: QC.Gen Variable.Variable
+arbitraryVariable = Variable.Variable <$> arbitraryName <*> arbitraryModifier
+
+shrinkVariable :: Shrink Variable.Variable
+shrinkVariable variable =
+  uncurry Variable.Variable
+    <$> shrinkTuple
+      shrinkName
+      shrinkModifier
+      (Variable.name variable, Variable.modifier variable)
+
+shrinkTuple :: Shrink a -> Shrink b -> Shrink (a, b)
+shrinkTuple f g (x, y) =
+  fmap (\a -> (a, y)) (f x) <> fmap (\b -> (x, b)) (g y)
+
+arbitraryName :: QC.Gen Name.Name
+arbitraryName = Name.Name <$> arbitraryNonEmpty arbitraryField
+
+shrinkName :: Shrink Name.Name
+shrinkName = fmap Name.Name . shrinkNonEmpty shrinkField . Name.fields
+
+arbitraryField :: QC.Gen Field.Field
+arbitraryField = Field.Field <$> arbitraryNonEmpty arbitraryFieldCharacter
+
+shrinkField :: Shrink Field.Field
+shrinkField =
+  fmap Field.Field . shrinkNonEmpty shrinkFieldCharacter . Field.characters
+
+arbitraryFieldCharacter :: QC.Gen (Character.Character Field.Field)
+arbitraryFieldCharacter =
+  QC.oneof
+    [ Character.Encoded <$> arbitraryDigit <*> arbitraryDigit,
+      Character.Unencoded <$> QC.suchThat QC.arbitrary Parse.isFieldCharacter
+    ]
+
+shrinkFieldCharacter :: Shrink (Character.Character Field.Field)
+shrinkFieldCharacter x = case x of
+  Character.Encoded y z ->
+    uncurry Character.Encoded <$> shrinkTuple shrinkDigit shrinkDigit (y, z)
+  Character.Unencoded y ->
+    fmap Character.Unencoded . filter Parse.isFieldCharacter $ QC.shrink y
+
+arbitraryDigit :: QC.Gen Digit.Digit
+arbitraryDigit =
+  QC.oneof
+    [ pure Digit.Ox0,
+      pure Digit.Ox1,
+      pure Digit.Ox2,
+      pure Digit.Ox3,
+      pure Digit.Ox4,
+      pure Digit.Ox5,
+      pure Digit.Ox6,
+      pure Digit.Ox7,
+      pure Digit.Ox8,
+      pure Digit.Ox9,
+      Digit.OxA <$> arbitraryCase,
+      Digit.OxB <$> arbitraryCase,
+      Digit.OxC <$> arbitraryCase,
+      Digit.OxD <$> arbitraryCase,
+      Digit.OxE <$> arbitraryCase,
+      Digit.OxF <$> arbitraryCase
+    ]
+
+shrinkDigit :: Shrink Digit.Digit
+shrinkDigit x = case x of
+  Digit.Ox0 -> []
+  Digit.Ox1 -> [Digit.Ox0]
+  Digit.Ox2 -> [Digit.Ox0]
+  Digit.Ox3 -> [Digit.Ox0]
+  Digit.Ox4 -> [Digit.Ox0]
+  Digit.Ox5 -> [Digit.Ox0]
+  Digit.Ox6 -> [Digit.Ox0]
+  Digit.Ox7 -> [Digit.Ox0]
+  Digit.Ox8 -> [Digit.Ox0]
+  Digit.Ox9 -> [Digit.Ox0]
+  Digit.OxA y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
+  Digit.OxB y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
+  Digit.OxC y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
+  Digit.OxD y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
+  Digit.OxE y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
+  Digit.OxF y -> Digit.Ox0 : fmap Digit.OxA (shrinkCase y)
+
+arbitraryCase :: QC.Gen Case.Case
+arbitraryCase = QC.elements [Case.Lower, Case.Upper]
+
+shrinkCase :: Shrink Case.Case
+shrinkCase x = case x of
+  Case.Lower -> []
+  Case.Upper -> [Case.Lower]
+
+arbitraryModifier :: QC.Gen Modifier.Modifier
+arbitraryModifier =
+  QC.oneof
+    [ pure Modifier.Asterisk,
+      Modifier.Colon <$> arbitraryMaxLength,
+      pure Modifier.None
+    ]
+
+shrinkModifier :: Shrink Modifier.Modifier
+shrinkModifier x = case x of
+  Modifier.Asterisk -> [Modifier.None]
+  Modifier.Colon y -> Modifier.None : fmap Modifier.Colon (shrinkMaxLength y)
+  Modifier.None -> []
+
+arbitraryMaxLength :: QC.Gen MaxLength.MaxLength
+arbitraryMaxLength =
+  MaxLength.MaxLength <$> QC.suchThat QC.arbitrary Parse.isMaxLength
+
+shrinkMaxLength :: Shrink MaxLength.MaxLength
+shrinkMaxLength =
+  fmap MaxLength.MaxLength
+    . filter Parse.isMaxLength
+    . QC.shrink
+    . MaxLength.count
+
+arbitraryLiteral :: QC.Gen Literal.Literal
+arbitraryLiteral =
+  Literal.Literal <$> arbitraryNonEmpty arbitraryLiteralCharacter
+
+shrinkLiteral :: Shrink Literal.Literal
+shrinkLiteral =
+  fmap Literal.Literal
+    . shrinkNonEmpty shrinkLiteralCharacter
+    . Literal.characters
+
+arbitraryLiteralCharacter :: QC.Gen (Character.Character Literal.Literal)
+arbitraryLiteralCharacter =
+  QC.oneof
+    [ Character.Encoded <$> arbitraryDigit <*> arbitraryDigit,
+      Character.Unencoded <$> QC.suchThat QC.arbitrary Parse.isLiteralCharacter
+    ]
 
 shrinkLiteralCharacter :: Shrink (Character.Character Literal.Literal)
 shrinkLiteralCharacter x = case x of
