packages feed

link-canonical-0.1.0.0: test/Link/Canonical/TwitterSpec.hs

module Link.Canonical.TwitterSpec (tests) where

import Data.Maybe (fromJust)
import Data.Text qualified as T
import Link.Canonical (applyDomainRules, defaultDomainRules)
import Test.Tasty
import Test.Tasty.HUnit
import Text.URI (URI, mkURI, render)

tests :: TestTree
tests =
  testGroup
    "Twitter/X"
    [ testGroup
        "Host normalization"
        [ testCase "normalizes twitter.com to x.com" $
            normalizeTwitter "https://twitter.com/elikiw/status/1234567890"
              @?= "https://x.com/elikiw/status/1234567890",
          testCase "normalizes www.twitter.com to x.com" $
            normalizeTwitter "https://www.twitter.com/elikiw/status/1234567890"
              @?= "https://x.com/elikiw/status/1234567890",
          testCase "normalizes mobile.twitter.com to x.com" $
            normalizeTwitter "https://mobile.twitter.com/elikiw/status/1234567890"
              @?= "https://x.com/elikiw/status/1234567890",
          testCase "keeps x.com as x.com" $
            normalizeTwitter "https://x.com/elikiw/status/1234567890"
              @?= "https://x.com/elikiw/status/1234567890"
        ],
      testGroup
        "Media suffix stripping"
        [ testCase "strips /photo/1 from status URL" $
            normalizeTwitter "https://twitter.com/elikiw/status/1234567890/photo/1"
              @?= "https://x.com/elikiw/status/1234567890",
          testCase "strips /photo/2 from status URL" $
            normalizeTwitter "https://x.com/elikiw/status/1234567890/photo/2"
              @?= "https://x.com/elikiw/status/1234567890",
          testCase "strips /video/1 from status URL" $
            normalizeTwitter "https://twitter.com/elikiw/status/1234567890/video/1"
              @?= "https://x.com/elikiw/status/1234567890"
        ],
      testGroup
        "Parameter stripping"
        [ testCase "strips s parameter" $
            normalizeTwitter "https://twitter.com/elikiw/status/1234567890?s=20"
              @?= "https://x.com/elikiw/status/1234567890",
          testCase "strips t parameter" $
            normalizeTwitter "https://x.com/elikiw/status/1234567890?t=abc123"
              @?= "https://x.com/elikiw/status/1234567890",
          testCase "strips ref_src parameter" $
            normalizeTwitter "https://twitter.com/elikiw/status/1234567890?ref_src=twsrc"
              @?= "https://x.com/elikiw/status/1234567890",
          testCase "strips multiple parameters" $
            normalizeTwitter "https://twitter.com/elikiw/status/1234567890?s=20&t=abc"
              @?= "https://x.com/elikiw/status/1234567890"
        ],
      testGroup
        "Profile URLs"
        [ testCase "normalizes profile URL" $
            normalizeTwitter "https://twitter.com/elikiw"
              @?= "https://x.com/elikiw",
          testCase "normalizes profile URL with trailing slash" $
            normalizeTwitter "https://twitter.com/elikiw/"
              @?= "https://x.com/elikiw/"
        ],
      testGroup
        "Non-Twitter URLs"
        [ testCase "leaves non-Twitter URLs unchanged" $
            let uri = parseURI "https://example.com/elikiw/status/123"
             in applyDomainRules defaultDomainRules uri @?= uri
        ]
    ]

-- | Helper to normalize a Twitter URL string and return the result as Text
normalizeTwitter :: Text -> Text
normalizeTwitter urlStr =
  let uri = parseURI urlStr
      normalized = applyDomainRules defaultDomainRules uri
   in render normalized

-- | Helper to parse a URI, failing the test if invalid
parseURI :: Text -> URI
parseURI s = fromJust $ mkURI s

type Text = T.Text