content: {-# LANGUAGE QuasiQuotes #-}
  {-# LANGUAGE OverloadedStrings #-}
  module Text where
  
  import Control.Lens
  import Control.Lens.Regex.Text
  import qualified Data.Text as T
  import qualified Data.Map as M
  import Test.Hspec
  
  spec :: Spec
  spec = do
      describe "regex" $ do
          describe "match" $ do
              describe "getting" $ do
                  it "should find one match" $ do
                      "abc" ^.. [regex|b|] . match
                      `shouldBe` ["b"]
  
                  it "should find many matches" $ do
                      "a b c" ^.. [regex|\w|] . match
                      `shouldBe` ["a", "b", "c"]
  
                  it "should fold" $ do
                      "a b c" ^. [regex|\w|] . match
                      `shouldBe` "abc"
  
                  it "should match with a group" $ do
                      "a b c" ^.. [regex|(\w)|] . match
                      `shouldBe` ["a", "b", "c"]
  
                  it "should match with many groups" $ do
                      "a b c" ^.. [regex|(\w) (\w)|] . match
                      `shouldBe` ["a b"]
  
                  it "should be greedy when overlapping" $ do
                      "abc" ^.. [regex|\w+|] . match
                      `shouldBe`["abc"]
  
                  it "should respect lazy modifiers" $ do
                      "abc" ^.. [regex|\w+?|] . match
                      `shouldBe`["a", "b", "c"]
  
                  it "should handle unicode in source text properly" $ do
                      "🍕 test 🍔" ^. [regex|test|] . match
                          `shouldBe` "test"
                      ("🍕 test 🍔" & [regex|🍔|] . match .~ "👻🙈")
                          `shouldBe` "🍕 test 👻🙈"
  
                  it "should handle unicode in patterns properly" $ do
                      "*🍕 test 🍔*" ^. [regex|🍕 \w+ 🍔|] . match
                      `shouldBe` "🍕 test 🍔"
  
              describe "setting" $ do
                  it "should allow setting" $ do
                      ("one two three" & [regex|two|] . match .~ "new")
                      `shouldBe` "one new three"
  
                  it "should allow setting many" $ do
                      ("one <two> three" & [regex|\w+|] . match .~ "new")
                      `shouldBe` "new <new> new"
  
                  it "should allow mutating" $ do
                      ("one two three" & [regex|two|] . match %~ (<> "!!"). T.toUpper)
                      `shouldBe` "one TWO!! three"
  
                  it "should allow mutating many" $ do
                      ("one two three" & [regex|two|] . match %~ T.toUpper)
                      `shouldBe` "one TWO three"
  
          describe "indexed" $ do
              it "should allow folding with index" $ do
                  ("one two three" ^.. ([regex|\w+|] <. match) . withIndex)
                  `shouldBe` [(0, "one"), (1, "two"), (2, "three")]
  
              it "should allow getting with index" $ do
                  ("one two three" ^.. [regex|\w+|] . index 1 . match)
                  `shouldBe` ["two"]
  
              it "should allow setting with index" $ do
                  ("one two three" & [regex|\w+|] <. match .@~ T.pack . show)
                  `shouldBe` "0 1 2"
  
              it "should allow mutating with index" $ do
                  ("one two three" & [regex|\w+|] <. match %@~ \i s -> (T.pack $ show i) <> ": " <> s)
                  `shouldBe` "0: one 1: two 2: three"
  
      describe "groups" $ do
          describe "getting" $ do
              it "should get groups" $ do
                  "a b c" ^.. [regex|(\w)|] . groups
                  `shouldBe` [["a"], ["b"], ["c"]]
  
              it "should get multiple groups" $ do
                  "raindrops on roses and whiskers on kittens" ^.. [regex|(\w+) on (\w+)|] . groups
                  `shouldBe` [["raindrops","roses"],["whiskers","kittens"]]
  
              it "should allow getting a specific index" $ do
                  ("one two three four" ^.. [regex|(\w+) (\w+)|] . groups . ix 1)
                  `shouldBe` ["two", "four"]
  
              it "should handle weird group alternation" $ do
                  ("AB" ^.. [regex|A(x)?(B)|] . groups `shouldBe` [["", "B"]])
                  ("B" ^.. [regex|(A)|(B)|] . groups `shouldBe` [["", "B"]])
                  -- This behaviour is consistent with pcre-heavy
                  ("A" ^.. [regex|(A)|(B)|] . groups `shouldBe` [["A"]])
  
          describe "setting" $ do
              it "should allow setting groups as a list" $ do
                  ("one two three" & [regex|(\w+) (\w+)|] . groups .~ ["1", "2"])
                  `shouldBe` "1 2 three"
  
              it "should allow editing when result list is the same length" $ do
                  ("raindrops on roses and whiskers on kittens" & [regex|(\w+) on (\w+)|] . groups %~ reverse)
                  `shouldBe` "roses on raindrops and kittens on whiskers"
  
      describe "group" $ do
          it "should get a single group" $ do
                  "a:b c:d" ^.. [regex|(\w):(\w)|] . group 1
                  `shouldBe` ["b", "d"]
  
          it "should set a single group" $ do
                  "a:b c:d" & [regex|(\w):(\w)|] . group 1 %~ T.toUpper
                  `shouldBe` "a:B c:D"
  
          describe "traversed" $ do
              it "should allow setting all group matches" $ do
                  ("one two three" & [regex|(\w+) (\w+)|] . groups . traversed .~ "new")
                  `shouldBe` "new new three"
  
              it "should allow mutating" $ do
                  ("one two three four" & [regex|one (two) (three)|] . groups . traversed %~ (<> "!!") . T.toUpper)
                  `shouldBe` "one TWO!! THREE!! four"
  
              it "should allow folding with index" $ do
                  ("one two three four" ^.. [regex|(\w+) (\w+)|] . groups . traversed . withIndex)
                  `shouldBe` [(0, "one"), (1, "two"), (0, "three"), (1, "four")]
  
              it "should allow setting with index" $ do
                  ("one two three four" & [regex|(\w+) (\w+)|] . groups . traversed .@~ T.pack . show)
                  `shouldBe` "0 1 0 1"
  
              it "should allow mutating with index" $ do
                  ("one two three four" & [regex|(\w+) (\w+)|] . groups . traversed %@~ \i s -> (T.pack $ show i) <> ": " <> s)
                  `shouldBe` "0: one 1: two 0: three 1: four"
  
              it "should compose indices with matches" $ do
                  ("one two three four" ^.. ([regex|(\w+) (\w+)|] <.> groups . traversed) . withIndex)
                  `shouldBe` [((0, 0), "one"), ((0, 1), "two"), ((1, 0), "three"), ((1, 1), "four")]
  
      describe "namedGroups" $ do
          describe "getting" $ do
              it "should get named groups" $ do
                  "a b c" ^.. [regex|(?<mygroup>\w)|] . namedGroups
                  `shouldBe` [M.fromList [("mygroup", "a")], M.fromList [("mygroup", "b")], M.fromList [("mygroup", "c")]]
  
              it "should get multiple named groups" $ do
                  "raindrops on roses and whiskers on kittens" ^.. [regex|(?<one>\w+) on (?<two>\w+)|] . namedGroups
                  `shouldBe` [M.fromList [("one", "raindrops"), ("two", "roses")], M.fromList [("one", "whiskers"), ("two", "kittens")]]
  
              it "should allow getting a specific named group" $ do
                  ("raindrops on roses and whiskers on kittens" ^.. [regex|(?<one>\w+) on (?<two>\w+)|] . namedGroups . ix "two")
                  `shouldBe` ["roses", "kittens"]
  
              it "should handle weird group alternation" $ do
                  ("AB" ^.. [regex|A(?<opt>x)?(?<always>B)|] . namedGroups `shouldBe` [M.fromList [("opt", ""), ("always", "B")]])
                  ("B" ^.. [regex|(?<a>A)|(?<b>B)|] . namedGroups `shouldBe` [M.fromList [("a", ""), ("b", "B")]])
                  -- This is the behaviour of pcre-heavy, it's a bit unfortunate
                  ("A" ^.. [regex|(?<a>A)|(?<b>B)|] . namedGroups `shouldBe` [M.fromList [("a", "A")]])
  
          describe "setting" $ do
              it "should allow setting groups as a map" $ do
                  ("one two three" & [regex|(?<a>\w+) (?<b>\w+)|] . namedGroups .~ M.fromList [("a", "1"), ("b", "2")])
                  `shouldBe` "1 2 three"
  
      describe "namedGroup" $ do
          it "should get a single named group" $ do
                  "a:b c:d" ^.. [regex|(?<before>\w):(?<after>\w)|] . namedGroup "after"
                  `shouldBe` ["b", "d"]
  
          it "should set a single group" $ do
                  "a:b c:d" & [regex|(\w):(?<after>\w)|] . namedGroup "after" %~ T.toUpper
                  `shouldBe` "a:B c:D"
  
      describe "matchAndGroups" $ do
          it "should get match and groups" $ do
              "raindrops on roses and whiskers on kittens" ^.. [regex|(\w+) on (\w+)|] . matchAndGroups
              `shouldBe` [("raindrops on roses",["raindrops","roses"]),("whiskers on kittens",["whiskers","kittens"])]
  
  