content: {-# LANGUAGE NumericUnderscores #-}
  
  module Test.Policeman.Version
      ( versionSpec
      , versionRoundtripText
      , versionRoundtripInts
      ) where
  
  import Hedgehog (MonadGen, Property, forAll, property, (===))
  import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)
  
  import Policeman.Core.Version (Version (..), versionFromIntList, versionFromText, versionToIntList,
                                 versionToText)
  
  import qualified Data.Text as Text
  import qualified Hedgehog.Gen as Gen
  import qualified Hedgehog.Range as Range
  
  
  -- | Version parsing unit tests.
  versionSpec :: Spec
  versionSpec = describe "Version parsing" $ do
      describe "From Text" $ do
          it "parses 1.2.3.4" $
              versionFromText "1.2.3.4" `shouldBe` Just (Version 1 2 3 4 "1.2.3.4")
          it "parses 1.2.3" $
              versionFromText "1.2.3" `shouldBe` Just (Version 1 2 3 0 "1.2.3")
          it "parses 1.2" $
              versionFromText "1.2" `shouldBe` Just (Version 1 2 0 0 "1.2")
          it "parses 1" $
              versionFromText "1" `shouldBe` Just (Version 1 0 0 0 "1")
          it "parses 00" $
              versionFromText "00" `shouldBe` Just (Version 0 0 0 0 "00")
          it "does not parse letters" $
              versionFromText "1.2.3.a" `shouldSatisfy` isNothing
          it "does not parse trailing dot" $
              versionFromText "1.2.3." `shouldSatisfy` isNothing
          it "does not parse leading dot" $
              versionFromText ".1.2.3" `shouldSatisfy` isNothing
      describe "From List of Ints" $ do
          it "parses [1,2,3,4]" $
              versionFromIntList [1,2,3,4] `shouldBe` Just (Version 1 2 3 4 "1.2.3.4")
          it "parses [1,2,3]" $
              versionFromIntList [1,2,3] `shouldBe` Just (Version 1 2 3 0 "1.2.3")
          it "parses [1,2]" $
              versionFromIntList [1,2] `shouldBe` Just (Version 1 2 0 0 "1.2")
          it "parses [1]" $
              versionFromIntList [1] `shouldBe` Just (Version 1 0 0 0 "1")
          it "parses [1,2,3,4,5]" $
              versionFromIntList [1,2,3,4,5] `shouldBe` Just (Version 1 2 3 4 "1.2.3.4.5")
  
  -- | Parsing to/from 'Text' works properly.
  versionRoundtripText :: Property
  versionRoundtripText = property $ do
      preVersion <- forAll genVersion
      let version = preVersion { versionText = versionToText preVersion }
      versionFromText (versionToText version) === Just version
  
  -- | Parsing to/from '[Int]' works properly.
  versionRoundtripInts :: Property
  versionRoundtripInts = property $ do
      version <- forAll genVersion
      versionFromIntList (versionToIntList version) === Just version
  
  -- | Generates random version.
  genVersion :: forall m . (MonadGen m) => m Version
  genVersion = do
      versionA <- genInt
      versionB <- genInt
      versionC <- genInt
      versionD <- genInt
      pure Version
          { versionText = Text.intercalate "." $ map show
              [ versionA
              , versionB
              , versionC
              , versionD
              ]
          , ..
          }
    where
      genInt :: m Int
      genInt = Gen.int (Range.constant 0 20_000)
  