stim-parser-0.2.0.0: test/Test/DEM/Expr.hs
module Test.DEM.Expr where
import Test.HUnit
import StimParser.DEM.Expr
-- Helper to compare using show
tAssertShowEqual :: (Show a) => String -> a -> a -> Test
tAssertShowEqual msg expected actual = TestCase $
assertEqual msg (show expected) (show actual)
tests :: Test
tests = TestList
[ testFlattenDEMSimple
, testFlattenDEMRepeat
, testFlattenDEMShift
, testFlattenDEMShiftAndRepeat
, testFlattenDEMDetIdShift
, testFlattenDEMDimensionMismatch
, testFlattenDEMIdempotent
]
-- | Flattening a DEM with no repeats or shifts is identity
testFlattenDEMSimple :: Test
testFlattenDEMSimple = TestList
[ "flatten simple error" ~:
let dem = DEM [DEMInstrError (DEMError 0.01 [TargetDetector (DetectorId 0)])]
in dem ~=? flattenDEM dem
, "flatten multiple instructions" ~:
let dem = DEM
[ DEMInstrError (DEMError 0.01 [TargetDetector (DetectorId 0)])
, DEMInstrError (DEMError 0.02 [TargetDetector (DetectorId 1), TargetObservable (ObservableId 0)])
, DEMInstrDetector (DEMDetector (DetectorId 0) [0.0, 0.0])
, DEMInstrObservable (DEMObservable (ObservableId 0))
]
in dem ~=? flattenDEM dem
]
-- | Repeat blocks are expanded
testFlattenDEMRepeat :: Test
testFlattenDEMRepeat = TestList
[ "flatten repeat 2" ~:
let input = DEM
[ DEMInstrRepeat 2
[ DEMInstrError (DEMError 0.01 [TargetDetector (DetectorId 0)])
]
]
expected = DEM
[ DEMInstrError (DEMError 0.01 [TargetDetector (DetectorId 0)])
, DEMInstrError (DEMError 0.01 [TargetDetector (DetectorId 0)])
]
in expected ~=? flattenDEM input
, "flatten repeat 0" ~:
let input = DEM [DEMInstrRepeat 0 [DEMInstrError (DEMError 0.01 [])]]
in DEM [] ~=? flattenDEM input
, "flatten nested repeat" ~:
let input = DEM
[ DEMInstrRepeat 2
[ DEMInstrRepeat 3
[ DEMInstrError (DEMError 0.01 []) ]
]
]
expected = DEM (replicate 6 (DEMInstrError (DEMError 0.01 [])))
in expected ~=? flattenDEM input
]
-- | shift_detectors coordinates are applied to subsequent detectors
testFlattenDEMShift :: Test
testFlattenDEMShift = TestList
[ "flatten shift detectors" ~:
let input = DEM
[ DEMInstrShift (DEMShift [1.0, 0.0] 0)
, DEMInstrDetector (DEMDetector (DetectorId 0) [0.0, 0.0])
, DEMInstrDetector (DEMDetector (DetectorId 1) [2.0, 3.0])
]
expected = DEM
[ DEMInstrDetector (DEMDetector (DetectorId 0) [1.0, 0.0])
, DEMInstrDetector (DEMDetector (DetectorId 1) [3.0, 3.0])
]
in expected ~=? flattenDEM input
, "flatten cumulative shift" ~:
let input = DEM
[ DEMInstrShift (DEMShift [1.0] 0)
, DEMInstrDetector (DEMDetector (DetectorId 0) [0.0])
, DEMInstrShift (DEMShift [2.0] 0)
, DEMInstrDetector (DEMDetector (DetectorId 1) [0.0])
]
expected = DEM
[ DEMInstrDetector (DEMDetector (DetectorId 0) [1.0])
, DEMInstrDetector (DEMDetector (DetectorId 1) [3.0])
]
in expected ~=? flattenDEM input
]
-- | Combined shift and repeat
testFlattenDEMShiftAndRepeat :: Test
testFlattenDEMShiftAndRepeat = TestList
[ "flatten shift inside repeat" ~:
let input = DEM
[ DEMInstrRepeat 2
[ DEMInstrShift (DEMShift [1.0] 0)
, DEMInstrDetector (DEMDetector (DetectorId 0) [0.0])
]
]
-- Note: shifts are cumulative across repeat iterations.
-- Iteration 1: shift=[1.0], detector gets [1.0]
-- Iteration 2: shift becomes [2.0], detector gets [2.0]
expected = DEM
[ DEMInstrDetector (DEMDetector (DetectorId 0) [1.0])
, DEMInstrDetector (DEMDetector (DetectorId 0) [2.0])
]
in expected ~=? flattenDEM input
]
-- | Detector ID shifting
testFlattenDEMDetIdShift :: Test
testFlattenDEMDetIdShift = TestList
[ "flatten detector id shift" ~:
let input = DEM
[ DEMInstrShift (DEMShift [0.0] 5)
, DEMInstrDetector (DEMDetector (DetectorId 0) [1.0])
, DEMInstrDetector (DEMDetector (DetectorId 1) [2.0])
]
expected = DEM
[ DEMInstrDetector (DEMDetector (DetectorId 5) [1.0])
, DEMInstrDetector (DEMDetector (DetectorId 6) [2.0])
]
in expected ~=? flattenDEM input
, "flatten combined coord and id shift" ~:
let input = DEM
[ DEMInstrShift (DEMShift [1.0, 0.0] 10)
, DEMInstrDetector (DEMDetector (DetectorId 0) [0.0, 0.0])
]
expected = DEM
[ DEMInstrDetector (DEMDetector (DetectorId 10) [1.0, 0.0])
]
in expected ~=? flattenDEM input
]
-- | Dimension mismatch between shift and detector coordinates
testFlattenDEMDimensionMismatch :: Test
testFlattenDEMDimensionMismatch = TestList
[ "2D shift on 3D detector" ~:
let input = DEM
[ DEMInstrShift (DEMShift [1.0, 0.0] 0)
, DEMInstrDetector (DEMDetector (DetectorId 0) [0.0, 0.0, 0.0])
]
expected = DEM
[ DEMInstrDetector (DEMDetector (DetectorId 0) [1.0, 0.0, 0.0])
]
in expected ~=? flattenDEM input
, "3D shift on 2D detector" ~:
let input = DEM
[ DEMInstrShift (DEMShift [1.0, 0.0, 0.0] 0)
, DEMInstrDetector (DEMDetector (DetectorId 0) [0.0, 0.0])
]
expected = DEM
[ DEMInstrDetector (DEMDetector (DetectorId 0) [1.0, 0.0])
]
in expected ~=? flattenDEM input
]
-- | Idempotency: flattening an already-flattened DEM is a no-op
testFlattenDEMIdempotent :: Test
testFlattenDEMIdempotent = TestList
[ "flatten is idempotent on simple" ~:
let dem = DEM
[ DEMInstrError (DEMError 0.01 [TargetDetector (DetectorId 0)])
, DEMInstrDetector (DEMDetector (DetectorId 1) [1.0, 2.0])
, DEMInstrObservable (DEMObservable (ObservableId 0))
]
in flattenDEM dem ~=? flattenDEM (flattenDEM dem)
, "flatten is idempotent on nested" ~:
let dem = DEM
[ DEMInstrRepeat 2
[ DEMInstrShift (DEMShift [1.0] 0)
, DEMInstrDetector (DEMDetector (DetectorId 0) [0.0])
]
]
in flattenDEM dem ~=? flattenDEM (flattenDEM dem)
]