packages feed

wireform-arrow-0.1.0.0: test-derive/Test/Arrow/Derive.hs

{-# LANGUAGE OverloadedStrings #-}

module Test.Arrow.Derive (tests) where

import Arrow.Derive (hasTable)
import Arrow.Record (Table, decodeTable, encodeTable, tableSchema)
import Arrow.Types (Field (..), Schema (..))
import Data.Vector qualified as V
import Test.Arrow.Derive.Instances (outcomeIsRejected)
import Test.Arrow.Derive.Types
import Test.Syd


tests :: Spec
tests =
  describe "Arrow.Derive" $
    sequence_
      [ recordTests
      , newtypeTests
      , maybeTests
      , coercedTests
      , spliceFailureTests
      ]


recordTests :: Spec
recordTests =
  describe "record" $
    sequence_
      [ it "schema honours rename + renameStyle and drops skipped column" $ do
          let sch = tableSchema (hasTable :: Table Profile)
              names = V.toList (V.map fieldName (arrowFields sch))
          names `shouldBe` ["name", "profile_age", "email"]
      , it "round-trip restores skipped fields from defaults" $ do
          let rows =
                V.fromList
                  [ Profile "Alice" 30 "alice@x" "secret"
                  , Profile "Bob" 25 "bob@x" "hidden"
                  ]
              (sch, cols) = encodeTable hasTable rows
          (V.length cols == 3) `shouldBe` True
          case decodeTable hasTable sch cols of
            Right rs -> do
              V.length rs `shouldBe` V.length rows
              let r0 = V.head rs
                  r1 = V.last rs
              profileName r0 `shouldBe` "Alice"
              profileAge r0 `shouldBe` 30
              profileEmail r0 `shouldBe` "alice@x"
              profilePrivate r0 `shouldBe` defaultPrivate
              profileName r1 `shouldBe` "Bob"
              profileAge r1 `shouldBe` 25
              profileEmail r1 `shouldBe` "bob@x"
              profilePrivate r1 `shouldBe` defaultPrivate
            Left e -> expectationFailure e
      ]


newtypeTests :: Spec
newtypeTests =
  describe "newtype-passthrough" $
    sequence_
      [ it "WithTag round-trips Tag column via passthrough instance" $ do
          let rows =
                V.fromList
                  [ WithTag (Tag 7) "alpha"
                  , WithTag (Tag 9) "beta"
                  ]
              (sch, cols) = encodeTable hasTable rows
              names = V.toList (V.map fieldName (arrowFields sch))
          -- Arrow's idiomatic name style is snake_case, applied
          -- automatically when no explicit rename is set.
          names `shouldBe` ["wt_id", "wt_name"]
          V.length cols `shouldBe` 2
          case decodeTable hasTable sch cols of
            Right rs -> rs `shouldBe` rows
            Left e -> expectationFailure e
      ]


maybeTests :: Spec
maybeTests =
  describe "Maybe-fields" $
    sequence_
      [ it "Maybe Text column reflected in schema as nullable" $ do
          let sch = tableSchema (hasTable :: Table Event)
              flds = V.toList (arrowFields sch)
          map fieldName flds `shouldBe` ["event_id", "event_note"]
          map fieldNullable flds `shouldBe` [False, True]
      , it "Maybe Text round-trips with Just / Nothing values" $ do
          let rows =
                V.fromList
                  [ Event 1 (Just "first")
                  , Event 2 Nothing
                  , Event 3 (Just "third")
                  ]
              (sch, cols) = encodeTable hasTable rows
          case decodeTable hasTable sch cols of
            Right rs -> rs `shouldBe` rows
            Left e -> expectationFailure e
      ]


coercedTests :: Spec
coercedTests =
  describe "coerced" $
    sequence_
      [ it "coerced field uses underlying-type schema and round-trips" $ do
          let sch = tableSchema (hasTable :: Table Result)
              names = V.toList (V.map fieldName (arrowFields sch))
          names `shouldBe` ["result_name", "result_score"]
          let rows =
                V.fromList
                  [ Result "alpha" (Score 100)
                  , Result "beta" (Score 200)
                  ]
              (sch', cols) = encodeTable hasTable rows
          case decodeTable hasTable sch' cols of
            Right rs -> rs `shouldBe` rows
            Left e -> expectationFailure e
      ]


spliceFailureTests :: Spec
spliceFailureTests =
  describe "splice-time-rejection" $
    sequence_
      [ it "deriveArrow ''Outcome (a sum type) is rejected at splice time" $
          (outcomeIsRejected) `shouldBe` True
      ]