packages feed

hgg-frame-0.1.0.0: test/Spec.hs

-- | hgg-frame テスト。 A1 = class PlotData のゼロ依存 instance 検証。
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where

-- 注: renderBound (df |>> spec → SVG) の smoke は hgg-svg の test に置く。
-- frame:test が svg に依存すると cabal が frame↔svg をパッケージ循環と見なすため。
import           Graphics.Hgg.Frame
import           Graphics.Hgg.Spec     (ColData (..), layer, scatter)
import           Graphics.Hgg.Validate (PlotDiagnostic (..), PlotErrorKind (..),
                                        Severity (..), diagnosticSeverity)
import           Data.Map.Strict       (Map)
import qualified Data.Map.Strict       as M
import           Data.Text             (Text)
import qualified Data.Vector           as V
import           Test.Hspec

-- 長さ違いの列を含むサンプル (g が最長 = 4 行)
assocDF :: [(Text, ColData)]
assocDF =
  [ ("x", NumData (V.fromList [1, 2, 3]))
  , ("g", TxtData (V.fromList ["a", "b", "c", "d"]))
  ]

mapDF :: Map Text ColData
mapDF = M.fromList assocDF

-- scatter 用の x/y を持つ df (bind/render テスト用)。 列順違いで同一データ
xyAssoc :: [(Text, ColData)]
xyAssoc =
  [ ("x", NumData (V.fromList [1, 2, 3]))
  , ("y", NumData (V.fromList [4, 5, 6]))
  ]

xyMap :: Map Text ColData
xyMap = M.fromList xyAssoc

main :: IO ()
main = hspec $ do
  describe "PlotData [(Text, ColData)]" $ do
    it "columnNames は宣言順" $
      columnNames assocDF `shouldBe` ["x", "g"]
    it "nrows は最長列の長さ" $
      nrows assocDF `shouldBe` 4
    it "toResolver は列を引ける" $
      toResolver assocDF "x" `shouldBe` Just (NumData (V.fromList [1, 2, 3]))
    it "toResolver は不在列で Nothing" $
      toResolver assocDF "zzz" `shouldBe` Nothing

  describe "PlotData (Map Text ColData)" $ do
    it "columnNames は Map のキー (昇順)" $
      columnNames mapDF `shouldBe` ["g", "x"]
    it "nrows は最長列の長さ" $
      nrows mapDF `shouldBe` 4
    it "空 df の nrows は 0" $
      nrows (M.empty :: Map Text ColData) `shouldBe` 0

  describe "(|>>) バインド" $ do
    it "BoundPlot に resolver/spec を載せ、 診断は空 (A3 時点)" $ do
      let bp = xyMap |>> layer (scatter "x" "y")
      bpDiagnostics bp `shouldBe` []
      fmap colLen (bpResolver bp "x") `shouldBe` Just 3
    it "純値: unBound で (resolver, spec) を取り出せる" $ do
      let (r, _) = unBound (xyAssoc |>> layer (scatter "x" "y"))
      fmap colLen (r "y") `shouldBe` Just 3
    it "全列存在・数値なら診断ゼロ" $
      bpDiagnostics (xyMap |>> layer (scatter "x" "y")) `shouldBe` []

  describe "(|>>) 検証 (A5、 案1: 純値・例外なし)" $ do
    it "存在しない列 → ColumnNotFound Error (例外は投げない)" $ do
      let diags = bpDiagnostics (xyAssoc |>> layer (scatter "x" "nope"))
          isNopeNotFound (PlotError (ColumnNotFound n _) _) = n == "nope"
          isNopeNotFound _                                  = False
      any isNopeNotFound diags `shouldBe` True
      any ((== SevError) . diagnosticSeverity) diags `shouldBe` True
    it "空 df → PlotInfo (lenient、 Error ではない)" $ do
      let emptyAssoc = [] :: [(Text, ColData)]
          diags = bpDiagnostics (emptyAssoc |>> layer (scatter "x" "y"))
          isInfo (PlotInfo _) = True
          isInfo _            = False
      any isInfo diags `shouldBe` True