content: module API.RequestSpec (spec) where
  
  import           Universum
  
  import           Data.Either (isLeft)
  import           Formatting (build, sformat)
  import           Test.Hspec
  
  import           Cardano.Wallet.API.Request.Filter
  import           Cardano.Wallet.API.Request.Sort
  import           Cardano.Wallet.API.V1.Types
  import qualified Pos.Core as Core
  
  spec :: Spec
  spec = describe "Request" $ do
      describe "Sort" sortSpec
      describe "Filter" filterSpec
  
  sortSpec :: Spec
  sortSpec =
      describe "parseSortOperation" $ do
          describe "Transaction" $ do
              let ptimestamp = Proxy @(V1 Core.Timestamp)
                  pt = Proxy @Transaction
  
              it "knows the query param" $ do
                  parseSortOperation pt ptimestamp "ASC[created_at]"
                      `shouldBe`
                          Right (SortByIndex SortAscending ptimestamp)
  
              it "infers DESC for nonspecified sort" $
                  parseSortOperation pt ptimestamp "created_at"
                      `shouldBe`
                          Right (SortByIndex SortDescending ptimestamp)
  
              it "fails if the param name is wrong" $ do
                  parseSortOperation pt ptimestamp "ASC[balance]"
                      `shouldSatisfy`
                          isLeft
  
              it "fails if the syntax is wrong" $ do
                  parseSortOperation pt ptimestamp "ASC[created_at"
                      `shouldSatisfy`
                          isLeft
  
  filterSpec :: Spec
  filterSpec = do
      describe "parseFilterOperation" $ do
          describe "Wallet" $ do
              let pw = Proxy @Wallet
                  pwid = Proxy @WalletId
                  pcoin = Proxy @Core.Coin
  
              it "supports index" $ do
                  parseFilterOperation pw pwid "asdf"
                      `shouldBe`
                          Right (FilterByIndex (WalletId "asdf"))
  
              forM_ [minBound .. maxBound] $ \p ->
                  it ("supports predicate: " <> show p) $ do
                      parseFilterOperation pw pwid
                          (sformat build p <> "[asdf]")
                          `shouldBe`
                              Right (FilterByPredicate p (WalletId "asdf"))
  
              it "supports range" $ do
                  parseFilterOperation pw pcoin "RANGE[123,456]"
                      `shouldBe`
                          Right
                              (FilterByRange (Core.mkCoin 123)
                                             (Core.mkCoin 456))
  
              it "fails if the thing can't be parsed" $ do
                  parseFilterOperation pw pcoin "nope"
                      `shouldSatisfy`
                          isLeft
  
              it "supports IN" $ do
                  parseFilterOperation pw pcoin "IN[1,2,3]"
                      `shouldBe`
                          Right
                              (FilterIn (map Core.mkCoin [1,2,3]))
  
      describe "toQueryString" $ do
          let ops = FilterByRange (Core.mkCoin 2345) (Core.mkCoin 2348)
                  `FilterOp` FilterByIndex (WalletId "hello")
                  `FilterOp` NoFilters
                  :: FilterOperations '[Core.Coin, WalletId] Wallet
          it "does what you'd want it to do" $ do
              toQueryString ops
                  `shouldBe`
                      [ ("balance", Just "RANGE[2345,2348]")
                      , ("id",      Just "hello")
                      ]
  
      describe "toFilterOperations" $ do
          let params :: [(Text, Maybe Text)]
              params =
                  [ ("id",      Just "3")
                  , ("balance", Just "RANGE[10,50]")
                  ]
              fops :: FilterOperations '[WalletId, Core.Coin] Wallet
              fops = FilterByIndex (WalletId "3")
                  `FilterOp` FilterByRange (Core.mkCoin 10) (Core.mkCoin 50)
                  `FilterOp` NoFilters
              prxy :: Proxy '[WalletId, Core.Coin]
              prxy = Proxy
  
          it "can parse the thing" $ do
              toFilterOperations params prxy
                  `shouldBe`
                      fops
  