-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU Affero General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-- details.
--
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module Test.Domain
  ( tests,
  )
where

import Data.Domain (DomainText (DomainText), domainText, mkDomain)
import Data.Text qualified as Text
import Imports
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck

tests :: TestTree
tests =
  testGroup
    "Domain"
    [ testGroup "serialization" testDomainSerialization
    ]

testDomainSerialization :: [TestTree]
testDomainSerialization =
  [ testCase "parses some example domains" $ do
      let validDomains =
            [ "wire.com",
              "some.long.example.with.lots.of.labels.com",
              "multiple-------dashes.co.uk",
              "0123456789.abcdefghijklmnopqrstuvwxyz.ABCDEFGHIJKLMNOPQRSTUVWXYZ",
              "Domain-with-dashes-and-Uppercase.Even-in-TLD",
              "1.1.1.g1", -- just TLD can't start with digit
              Text.replicate 63 "x" <> ".foo",
              Text.intercalate "." (replicate 127 "h") -- 253 chars
            ]
      for_ validDomains $ \d ->
        case mkDomain d of
          Right _ -> pure ()
          Left err -> assertFailure $ "valid domain " <> show d <> " not parsed successfully: " <> err,
    testCase "rejects invalid domains" $ do
      let invalidDomains =
            [ "dotless-domain",
              "label.starting.with.-dash.com",
              "label.ending.with.dash-.com",
              "exämple.com",
              "(comment)domain.com",
              "[1.1.1.1]", -- bracketed IP
              "192.168.1.65", -- IP
              Text.replicate 64 "x" <> ".foo",
              Text.intercalate "." (replicate 128 "h") -- 255 chars
            ]
      for_ invalidDomains $ \h ->
        case mkDomain h of
          Left _ -> pure ()
          Right parsed -> assertFailure $ "invalid domain parsed successfully: " <> show (h, parsed),
    testProperty "Arbitrary DomainText generates valid domains" $
      \(DomainText x) ->
        isRight $ mkDomain x,
    testProperty "parsing a domain normalizes it" $
      \(DomainText x) ->
        (domainText <$> mkDomain x) === Right (Text.toCaseFold x)
  ]
