packages feed

gitlab-haskell-1.0.0.1: tests/API/Common.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module API.Common where

import Data.Aeson hiding (Key)
import qualified Data.Aeson.KeyMap as KeyMap
import qualified Data.ByteString.Lazy.Char8 as BSL
import Data.Maybe
import Data.TreeDiff.Class
import Data.TreeDiff.Pretty
import qualified Data.Vector as Vec
import GHC.Generics
import GitLab
  ( ArchiveFormat (..),
    Artifact (Artifact),
    BoardIssue (BoardIssue),
    BoardIssueLabel (BoardIssueLabel),
    Branch (Branch),
    Change (Change),
    CommandsChanges (CommanandsChanges),
    Commit (Commit),
    CommitNote (CommitNote),
    CommitStats (CommitStats),
    CommitTodo (CommitTodo),
    Contributor (Contributor),
    DetailedStatus (DetailedStatus),
    Diff (Diff),
    DiffRefs (DiffRefs),
    Discussion (Discussion),
    EditIssueReq (EditIssueReq),
    Email (..),
    Epic (Epic),
    Event (..),
    EventActionName (..),
    EventTargetType (..),
    ExpirationPolicy (ExpirationPolicy),
    Group (Group),
    GroupShare (GroupShare),
    Identity (Identity),
    Issue (Issue),
    IssueBoard (IssueBoard),
    IssueCounts (IssueCounts),
    IssueStatistics (IssueStatistics),
    IssueStats (IssueStats),
    Job (Job),
    Key (..),
    License (License),
    Links (Links),
    Member (Member),
    MergeRequest (MergeRequest),
    Milestone (Milestone),
    MilestoneState (..),
    Namespace (Namespace),
    Note (Note),
    Owner (Ownwer),
    Permissions (Permissions),
    Pipeline (Pipeline),
    Project (Project),
    ProjectAvatar (ProjectAvatar),
    PushData (..),
    References (References),
    Release (Release),
    Repository (Repository),
    RepositoryFile (RepositoryFile),
    RepositoryFileBlame (RepositoryFileBlame),
    RepositoryFileSimple (RepositoryFileSimple),
    RepositoryStorage (RepositoryStorage),
    SamlIdentity (SamlIdentity),
    Starrer (Starrer),
    Statistics (Statistics),
    Tag (Tag),
    TaskCompletionStatus (TaskCompletionStatus),
    TestCase (TestCase),
    TestReport (TestReport),
    TestSuite (TestSuite),
    TimeEstimate (TimeEstimate),
    TimeStats (TimeStats),
    Todo (Todo),
    TodoAction (..),
    TodoProject (TodoProject),
    TodoState (..),
    TodoTarget (..),
    TodoTargetType (..),
    User (User),
    UserCount (..),
    UserPrefs (..),
    UserStatus (..),
    Version (Version),
    Visibility (..),
  )
import Test.Tasty
import Test.Tasty.HUnit
import qualified Text.PrettyPrint.ANSI.Leijen as WL

removeNulls :: Value -> Maybe Value
removeNulls Null = Nothing
removeNulls (Array vec) = Just (Array (Vec.mapMaybe removeNulls vec))
removeNulls (String x) = Just $ String x
removeNulls (Number x) = Just $ Number x
removeNulls (Bool x) = Just $ Bool x
removeNulls (Object keyMap) = Just $ Object (KeyMap.mapMaybe removeNulls keyMap)

gitlabJsonParserTests :: (ToExpr a, FromJSON a, ToJSON a, Eq a, Show a) => String -> FilePath -> IO a -> IO a -> [TestTree]
gitlabJsonParserTests testPrefix jsonFilename parseFileF decodedCustomTypeF = do
  [ testCase
      (testPrefix <> "-decode-encode-decode")
      (decodeEncodeDecode parseFileF),
    testCase
      (testPrefix <> "-json-values-equal")
      (jsonValuesEqual jsonFilename decodedCustomTypeF)
    ]

decodeEncodeDecode :: (ToExpr a, FromJSON a, ToJSON a, Eq a, Show a) => IO a -> Assertion
decodeEncodeDecode parseFileF = do
  decodedFromFile <- parseFileF
  decodedAgain <- parseOne (encode decodedFromFile)
  (decodedFromFile == decodedAgain)
    @? showWL (ansiWlEditExprCompact (ediff decodedFromFile decodedAgain))

jsonValuesEqual :: (ToExpr a, FromJSON a, ToJSON a, Eq a, Show a) => FilePath -> IO a -> Assertion
jsonValuesEqual jsonFilename decodedCustomTypeF = do
  jsonValueFromFile <- parseValuesFromFile jsonFilename
  decodedCustomType <- decodedCustomTypeF
  let (Just jsonFromCustomType) = decode (encode decodedCustomType) :: Maybe Value
  (jsonValueFromFile == jsonFromCustomType)
    @? showWL (ansiWlEditExprCompact (ediff jsonValueFromFile jsonFromCustomType))

parseValuesFromFile :: String -> IO Value
parseValuesFromFile fname =
  fromJust . removeNulls . fromJust . decode <$> BSL.readFile fname

gitlabParseTestOne :: (ToExpr a, FromJSON a, Eq a, Show a) => a -> String -> Assertion
gitlabParseTestOne expectedHaskellValue filename = do
  raw <- BSL.readFile filename
  result <- parseOne raw
  (expectedHaskellValue == result)
    @? showWL (ansiWlEditExprCompact (ediff expectedHaskellValue result))

showWL :: WL.Doc -> String
showWL doc = WL.displayS (WL.renderSmart 0.4 80 doc) ""

gitlabParseTestMany :: (ToExpr a, FromJSON a, Eq a, Show a) => [a] -> String -> Assertion
gitlabParseTestMany expectedHaskellValue filename = do
  raw <- BSL.readFile filename
  result <- parseMany raw
  (expectedHaskellValue == result)
    @? showWL (ansiWlEditExprCompact (ediff expectedHaskellValue result))

parseOne :: FromJSON a => BSL.ByteString -> IO a
parseOne bs =
  case eitherDecode bs of
    Left err -> assertFailure err
    Right xs -> return xs

parseMany :: FromJSON a => BSL.ByteString -> IO [a]
parseMany bs =
  case eitherDecode bs of
    Left err -> assertFailure err
    Right xs -> return xs

-------------
-- Generic instances

deriving instance Generic ArchiveFormat

deriving instance Generic Member

deriving instance Generic SamlIdentity

deriving instance Generic Identity

deriving instance Generic Namespace

deriving instance Generic Links

deriving instance Generic Owner

deriving instance Generic Permissions

deriving instance Generic Project

deriving instance Generic License

deriving instance Generic ExpirationPolicy

deriving instance Generic RepositoryStorage

deriving instance Generic Statistics

deriving instance Generic User

deriving instance Generic MilestoneState

deriving instance Generic Milestone

deriving instance Generic TimeStats

deriving instance Generic Issue

deriving instance Generic Pipeline

deriving instance Generic DetailedStatus

deriving instance Generic Commit

deriving instance Generic CommitTodo

deriving instance Generic CommitStats

deriving instance Generic Tag

deriving instance Generic Release

deriving instance Generic Repository

deriving instance Generic Job

deriving instance Generic Artifact

deriving instance Generic Group

deriving instance Generic GroupShare

deriving instance Generic MergeRequest

deriving instance Generic TaskCompletionStatus

deriving instance Generic References

deriving instance Generic Change

deriving instance Generic DiffRefs

deriving instance Generic TodoAction

deriving instance Generic TodoTarget

deriving instance Generic TodoState

deriving instance Generic TodoProject

deriving instance Generic Todo

deriving instance Generic TodoTargetType

deriving instance Generic EditIssueReq

deriving instance Generic Discussion

deriving instance Generic CommitNote

deriving instance Generic Note

deriving instance Generic IssueBoard

deriving instance Generic BoardIssue

deriving instance Generic BoardIssueLabel

deriving instance Generic Visibility

deriving instance Generic TestSuite

deriving instance Generic TestCase

deriving instance Generic TimeEstimate

deriving instance Generic ProjectAvatar

deriving instance Generic Starrer

deriving instance Generic Branch

deriving instance Generic Diff

deriving instance Generic Epic

deriving instance Generic CommandsChanges

deriving instance Generic Contributor

deriving instance Generic RepositoryFile

deriving instance Generic RepositoryFileSimple

deriving instance Generic RepositoryFileBlame

deriving instance Generic Version

deriving instance Generic IssueStatistics

deriving instance Generic IssueStats

deriving instance Generic IssueCounts

deriving instance Generic TestReport

deriving instance Generic Email

deriving instance Generic Key

deriving instance Generic UserPrefs

deriving instance Generic UserStatus

deriving instance Generic UserCount

deriving instance Generic Event

deriving instance Generic EventActionName

deriving instance Generic EventTargetType

deriving instance Generic PushData

-------------
-- ToExpr instances

instance ToExpr ArchiveFormat

instance ToExpr Member

instance ToExpr SamlIdentity

instance ToExpr Identity

instance ToExpr Namespace

instance ToExpr Links

instance ToExpr Owner

instance ToExpr Permissions

instance ToExpr Project

instance ToExpr Statistics

instance ToExpr User

instance ToExpr Milestone

instance ToExpr MilestoneState

instance ToExpr TimeStats

instance ToExpr Issue

instance ToExpr Pipeline

instance ToExpr Commit

instance ToExpr CommitTodo

instance ToExpr CommitStats

instance ToExpr Tag

instance ToExpr Release

instance ToExpr Diff

instance ToExpr Repository

instance ToExpr Job

instance ToExpr Artifact

instance ToExpr Group

instance ToExpr GroupShare

instance ToExpr Branch

instance ToExpr RepositoryFile

instance ToExpr RepositoryFileSimple

instance ToExpr RepositoryFileBlame

instance ToExpr MergeRequest

instance ToExpr Todo

instance ToExpr TodoProject

instance ToExpr TodoAction

instance ToExpr TodoTarget

instance ToExpr TodoState

instance ToExpr Version

instance ToExpr EditIssueReq

instance ToExpr Discussion

instance ToExpr CommitNote

instance ToExpr Note

instance ToExpr IssueStatistics

instance ToExpr IssueStats

instance ToExpr IssueCounts

instance ToExpr IssueBoard

instance ToExpr BoardIssue

instance ToExpr BoardIssueLabel

instance ToExpr Visibility

instance ToExpr TestReport

instance ToExpr TestSuite

instance ToExpr TestCase

instance ToExpr TimeEstimate

instance ToExpr TaskCompletionStatus

instance ToExpr References

instance ToExpr Change

instance ToExpr DiffRefs

instance ToExpr DetailedStatus

instance ToExpr TodoTargetType

instance ToExpr License

instance ToExpr ExpirationPolicy

instance ToExpr RepositoryStorage

instance ToExpr Starrer

instance ToExpr ProjectAvatar

instance ToExpr Epic

instance ToExpr CommandsChanges

instance ToExpr Contributor

instance ToExpr Email

instance ToExpr Key

instance ToExpr UserPrefs

instance ToExpr UserStatus

instance ToExpr UserCount

instance ToExpr Event

instance ToExpr EventActionName

instance ToExpr EventTargetType

instance ToExpr PushData