1 {-# LANGUAGE StandaloneDeriving #-}
2 {-# LANGUAGE NoMonomorphismRestriction #-}
3 {-# LANGUAGE UndecidableInstances #-}
4 {-# OPTIONS_GHC -fno-warn-orphans #-}
5 {-# OPTIONS_GHC -O0 #-}
9 import Test.Tasty.HUnit
11 import Control.Applicative (Applicative(..), Alternative(..))
12 -- import Control.Arrow (first)
13 import Control.Monad (Monad(..), MonadPlus(..))
14 import Control.Monad.Trans.Class (MonadTrans(..))
16 import Data.Char (Char)
17 import qualified Data.Kind as Kind
19 -- import Data.Decimal (DecimalRaw(..))
20 import Data.Either (Either(..))
22 import Data.Fixed (Pico)
23 import Data.Function (($), (.), const, flip)
24 import Data.Functor (Functor(..), (<$>))
25 import Data.Functor.Identity (Identity(..))
27 import Data.List.NonEmpty (NonEmpty(..))
28 import Data.Map.Strict (Map)
29 import Data.Maybe (Maybe(..))
30 import Data.Monoid (Monoid(..), (<>))
31 import Data.Ord (Ord(..))
33 import Data.String (String)
34 import Data.Text (Text)
35 import Data.Type.Equality ((:~:)(..))
36 import Data.Word (Word)
37 import Prelude (Integer)
38 import System.FilePath.Posix (FilePath)
39 import Text.Show (Show(..))
40 import qualified Control.Exception.Safe as Exn
41 import qualified Control.Monad.Classes as MC
42 import qualified Control.Monad.Trans.State.Strict as SS
43 import qualified Data.Char as Char
44 import qualified Data.Foldable as Foldable
45 import qualified Data.List as List
46 -- import qualified Data.List.NonEmpty as NonEmpty
47 import qualified Data.Map.Strict as Map
48 import qualified Data.NonNull as NonNull
49 -- import qualified Data.Set as Set
50 import qualified Data.Strict as S
51 import qualified Data.Text as Text
52 import qualified Data.Time.Calendar as Time
53 import qualified Data.Time.LocalTime as Time
54 import qualified Data.TreeMap.Strict as TreeMap
55 import qualified Data.TreeMap.Strict.Zipper as TreeMap
56 import qualified Language.Symantic as Sym
57 import qualified Language.Symantic.Lib as Sym
58 -- import qualified Language.Symantic.Parsing as Sym
59 import qualified System.FilePath.Posix as FilePath
60 import qualified System.IO.Error as IO
61 import qualified Text.Megaparsec as P
62 import qualified Text.Megaparsec.Prim as P
64 import qualified Hcompta as H
65 import qualified Hcompta.LCC as LCC
66 import qualified Hcompta.LCC.Lib.Strict as S
67 import qualified Hcompta.LCC.Sym as Sym
68 -- import System.IO (IO)
69 import Prelude (Bounded)
70 -- import Control.Applicative (Alternative)
71 import Data.NonNull (NonNull)
73 test :: Text -> Assertion -> TestTree
74 test = testCase . elide . Foldable.foldMap escapeChar . Text.unpack
76 escapeChar :: Char -> String
77 escapeChar c | Char.isPrint c = [c]
78 escapeChar c = Char.showLitChar c ""
80 elide :: String -> String
81 elide s | List.length s > 42 = List.take 42 s <> ['…']
84 account :: [Text] -> LCC.Account
85 account = LCC.Account . NonNull.impureNonNull . (LCC.Name <$>)
87 tag :: [Text] -> Text -> LCC.Tag
89 (LCC.Tag_Path $ NonNull.impureNonNull (LCC.Name <$> p))
92 account_ref :: [Text] -> LCC.Tag_Path
93 account_ref p = LCC.Tag_Path $ NonNull.impureNonNull $ LCC.Name <$> p
95 account_refs :: [([Text], [[Text]])] -> Map LCC.Tag_Path (Map LCC.Account ())
98 (<$> l) $ \(anch, accts) ->
99 ( LCC.Tag_Path $ NonNull.impureNonNull $ LCC.Name <$> anch
100 , Map.fromList $ (,()) . account <$> accts
103 tags :: [([Text], Text)] -> LCC.Tags
106 TreeMap.from_List (flip (<>)) $
108 (NonNull.impureNonNull (LCC.Name <$> p), [LCC.Tag_Data v])
110 amounts :: [(Text, LCC.Quantity)] -> LCC.Amounts
117 postings :: [LCC.Posting] -> LCC.Postings
120 Map.fromListWith (flip (<>)) $
122 (LCC.posting_account p, [p])
124 comments :: [Text] -> [LCC.Comment]
125 comments = (LCC.Comment <$>)
127 sourcePos :: FilePath -> Word -> Word -> P.SourcePos
128 sourcePos fp l c = P.SourcePos fp (P.unsafePos l) (P.unsafePos c)
130 date :: Integer -> Int -> Int -> Int -> Int -> Pico -> Time.TimeZone -> LCC.Date
131 date y m d h m' s tz =
132 Time.zonedTimeToUTC $
135 (Time.fromGregorian y m d)
136 (Time.TimeOfDay h m' s))
140 newtype Parsec e s m a
141 = Parsec { unParsec :: P.ParsecT e s m a }
142 deriving (Functor, Applicative, Monad, MonadTrans, Alternative, MonadPlus, P.MonadParsec e s)
144 type instance MC.CanDo (Parsec e s m) (MC.EffState a) = 'False
145 type instance MC.CanDo (Parsec e s m) (MC.EffReader P.SourcePos) = 'True
146 type instance MC.CanDo (Parsec e s m) (MC.EffReader (S.Either Exn.IOException LCC.CanonFile)) = 'True
148 instance -- Gram_File
151 , MC.MonadState Context_Test (Parsec e s m)
152 , P.MonadParsec e s (P.ParsecT e s m)
153 , P.MonadParsec e s (Parsec e s m)
155 ) => LCC.Gram_IO (Parsec e Text m) where
158 return (fp, Right $ LCC.CanonFile fp)
163 S.Left e -> return $ \at -> S.Left $ at e
165 db <- context_test_files <$> MC.get
166 case Map.lookup fp db of
167 Nothing -> return $ \at -> S.Left $ at $
168 LCC.Error_Journal_Read fp $
169 IO.userError $ show db
170 Just txt -> return $ const $ S.Right (fp, txt)
172 S.Left e -> return $ S.Left [e]
173 S.Right (LCC.PathFile fp_new, s_new) -> do
174 P.pushPosition $ P.initialPos fp_new
175 s_old <- P.getInput; P.setInput s_new
183 deriving instance LCC.ParsecC e s => Sym.Alter (Parsec e s m)
184 deriving instance LCC.ParsecC e s => Sym.Alt (Parsec e s m)
185 deriving instance LCC.ParsecC e s => Sym.App (Parsec e s m)
186 deriving instance LCC.ParsecC e s => Sym.Try (Parsec e s m)
187 deriving instance LCC.ParsecC e s => Sym.Gram_Rule (Parsec e s m)
188 deriving instance LCC.ParsecC e s => Sym.Gram_Terminal (Parsec e s m)
189 deriving instance LCC.ParsecC e s => Sym.Gram_RegR (Parsec e s m)
190 deriving instance LCC.ParsecC e s => Sym.Gram_RegL (Parsec e s m)
191 deriving instance LCC.ParsecC e s => Sym.Gram_CF (Parsec e s m)
192 deriving instance LCC.ParsecC e s => Sym.Gram_Meta P.SourcePos (Parsec e s m)
193 deriving instance LCC.ParsecC e s => Sym.Gram_Lexer (Parsec e s m)
194 deriving instance LCC.ParsecC e s => Sym.Gram_Op (Parsec e s m)
195 deriving instance LCC.ParsecC e s => LCC.Gram_Count (Parsec e s m)
196 deriving instance LCC.ParsecC e s => LCC.Gram_At (Parsec e s m)
197 deriving instance LCC.ParsecC e s => LCC.Gram_Char (Parsec e s m)
198 deriving instance LCC.ParsecC e s => LCC.Gram_Comment (Parsec e s m)
199 deriving instance LCC.ParsecC e s => LCC.Gram_Tag (Parsec e s m)
200 deriving instance LCC.ParsecC e s => LCC.Gram_Account (Parsec e s m)
201 deriving instance LCC.ParsecC e s => LCC.Gram_Amount (Parsec e s m)
202 deriving instance -- Gram_Posting
204 , LCC.Gram_Posting (P.ParsecT e s m)
205 , MC.MonadState (S.Maybe LCC.Unit) m
206 , MC.MonadState LCC.Chart m
207 , MC.MonadState LCC.Style_Amounts m
208 , MC.MonadState LCC.Year m
209 ) => LCC.Gram_Posting (Parsec e s m)
210 deriving instance -- Gram_Date
212 , LCC.Gram_Date (P.ParsecT e s m)
213 , MC.MonadState LCC.Year m
214 ) => LCC.Gram_Date (Parsec e s m)
215 deriving instance -- Gram_Transaction
217 , LCC.Gram_Transaction (P.ParsecT e s m)
218 , MC.MonadState (S.Maybe LCC.Unit) m
219 , MC.MonadState LCC.Chart m
220 , MC.MonadState LCC.Section m
221 , MC.MonadState LCC.Style_Amounts m
222 , MC.MonadState LCC.Year m
223 ) => LCC.Gram_Transaction (Parsec e s m)
224 deriving instance -- Gram_Chart
226 , LCC.Gram_Chart (P.ParsecT e s m)
227 , MC.MonadState LCC.Chart m
228 , MC.MonadState LCC.Section m
229 ) => LCC.Gram_Chart (Parsec e s m)
230 deriving instance (LCC.ParsecC e s, LCC.Gram_File (P.ParsecT e s m))
231 => LCC.Gram_File (Parsec e s m)
232 instance -- Gram_Journal
238 , LCC.Gram_Reader (S.Either Exn.IOException LCC.CanonFile) g
239 , LCC.Gram_State Context_Test g
240 , LCC.Gram_State (LCC.Context_Read j) g
241 , LCC.Gram_State (LCC.Journal j) g
242 , LCC.Gram_State (LCC.Journals j) g
243 , LCC.Gram_State (LCC.Env cs is) g
244 , LCC.Gram_State (LCC.ProtoEnv cs is) g
245 , LCC.Gram_Transaction g
246 , LCC.Gram_Term cs is (Parsec e Text m)
251 , g ~ Parsec e Text m
252 ) => LCC.Gram_Journal cs is j (Parsec e Text m)
253 deriving instance -- Gram_Term
254 ( Sym.Gram_Term is LCC.Meta (P.ParsecT e s m)
255 , Sym.Gram_Term_AtomsR LCC.Meta is is (Parsec e s m)
257 ) => Sym.Gram_Term is LCC.Meta (Parsec e s m)
258 deriving instance LCC.ParsecC e s => Sym.Gram_Meta LCC.Meta (Parsec e s m)
259 deriving instance LCC.ParsecC e s => Sym.Gram_Error (Parsec e s m)
260 deriving instance LCC.ParsecC e s => Sym.Gram_Name (Parsec e s m)
261 deriving instance LCC.ParsecC e s => Sym.Gram_Term_Type LCC.Meta (Parsec e s m)
262 deriving instance LCC.ParsecC e s => Sym.Gram_Type LCC.Meta (Parsec e s m)
263 deriving instance -- Gram_Term
264 ( LCC.Gram_Term cs is (P.ParsecT e s m)
265 , Sym.Gram_Term is LCC.Meta (Parsec e s m)
266 , MC.MonadState (LCC.Env cs is) m
267 , MC.MonadState (LCC.ProtoEnv cs is) m
269 ) => LCC.Gram_Term cs is (Parsec e s m)
270 instance -- Gram_State
272 , MC.MonadState ctx (Parsec e s m)
273 ) => LCC.Gram_State ctx (Parsec e s m) where
288 instance -- Gram_Reader
290 , MC.MonadReader ctx (Parsec e s m)
291 ) => LCC.Gram_Reader ctx (Parsec e s m) where
300 instance LCC.ParsecC e s => MC.MonadReaderN 'MC.Zero
301 P.SourcePos (Parsec e s m) where
302 askN _px = Parsec P.getPosition
303 instance LCC.ParsecC e s => MC.MonadReaderN 'MC.Zero
304 (NonEmpty P.SourcePos) (Parsec e s m) where
305 askN _px = Parsec $ P.statePos <$> P.getParserState
306 instance LCC.ParsecC e s => MC.MonadReaderN 'MC.Zero
307 (S.Either Exn.IOException LCC.CanonFile) (Parsec e s m) where
308 askN _px = Parsec $ S.Right . LCC.CanonFile . LCC.PathFile . P.sourceName <$> P.getPosition
310 -- * Type 'Context_Test'
313 { context_test_files :: Map LCC.PathFile Text
314 } deriving (Eq, Show)
315 type instance MC.CanDo (S.StateT (LCC.Context_Read j) m) (MC.EffState Context_Test) = 'False
316 type instance MC.CanDo (S.StateT Context_Test m) (MC.EffState Context_Test) = 'True
317 type instance MC.CanDo (S.StateT (LCC.Context_Sym cs is) m) (MC.EffState Context_Test) = 'False
318 instance Monad m => MC.MonadStateN 'MC.Zero Context_Test (S.StateT Context_Test m) where
319 stateN _px = S.StateT . SS.state
321 type instance MC.CanDo (S.StateT Context_Test m) (MC.EffState (Sym.Tokenizers meta is)) = 'False
324 :: forall is j cs e m a.
326 , LCC.Gram_File (P.ParsecT P.Dec Text m)
327 , Sym.Tokenize LCC.Meta is
328 , m ~ S.StateT (LCC.Context_Read j)
329 (S.StateT (LCC.Context_Sym cs is)
330 (S.StateT Context_Test Identity))
331 , e ~ P.ParseError Char P.Dec
332 , cs ~ Sym.TyConsts_of_Ifaces is
333 ) => Sym.CF (Parsec P.Dec Text m) a
334 -> [(LCC.PathFile, Text)]
337 -> Either (P.ParseError Char P.Dec) a
338 read g files fp inp =
340 S.evalState Context_Test{ context_test_files = Map.fromList files } $
341 S.evalState LCC.context_sym $
342 S.evalState LCC.context_read $
343 P.runParserT (unParsec . Sym.unCF $ g <* Sym.eoi)
344 (case fp of "" -> ""; _ -> FilePath.normalise fp) inp
347 = S.StateT (LCC.Context_Read j)
348 (S.StateT (LCC.Context_Sym cs is)
349 (S.StateT Context_Test Identity))
352 :: forall is is' cs h j.
354 , is ~ (Proxy LCC.Quantity ': Proxy Bool ': {-Proxy LCC.Journal ': Proxy LCC.Transaction ': Proxy [] ':-} is')
355 , Sym.Tokenize LCC.Meta is
356 , Sym.Inj_Token LCC.Meta is (->)
357 , Sym.Inj_TyConst cs (->)
358 , Sym.Inj_TyConst cs Bool
359 , Sym.Inj_TyConst cs LCC.Journal
360 , Sym.Inj_TyConst cs LCC.Transaction
361 , Sym.Inj_TyConst cs LCC.Quantity
362 , Sym.Inj_TyConst cs []
363 -- , Sym.Inj_TyConst cs Show
364 -- , Sym.Inj_TyConst cs Eq
366 , Sym.Show_Token LCC.Meta is
367 , Sym.Show_TyConst cs
369 , Sym.Eq_Token LCC.Meta is
370 , Sym.Gram_Term is LCC.Meta (P.ParsecT P.Dec Text (M cs is j))
371 , Sym.Sym_of_Ifaces is Sym.HostI
372 , Sym.Gram_Term_AtomsR LCC.Meta is is (P.ParsecT P.Dec Text (M cs is j))
373 , Sym.Gram_Term_AtomsR LCC.Meta is is (Parsec P.Dec Text (M cs is j))
374 , cs ~ Sym.TyConsts_of_Ifaces is
380 , Either (Either (P.ParseError Char P.Dec)
381 (LCC.At (Sym.Error_Term LCC.Meta cs is)))
385 test_compile _j i (n_exp, ty_exp, lr_exp) =
386 let inp = Text.intercalate "\n" i in
388 let env :: LCC.Env cs is = Map.fromList
389 [ ("j" , Sym.ETermClosed (Sym.ty @Bool) $
390 Sym.TermClosed $ Sym.bool True)
391 , ("jnl", Sym.ETermClosed (Sym.ty @LCC.Journal Sym.:$ (Sym.ty @[] Sym.:$ Sym.ty @LCC.Transaction)) $
392 Sym.TermClosed $ Sym.journal LCC.journal)
396 case read @is @j ({-LCC.g_put (pure (env, ())) *>-} LCC.g_term) [] "" inp of
397 Left err_syn -> Left (Left err_syn) @?= lr_exp
398 Right (n_got, lr_sem) ->
400 Left err_sem -> Left (Right err_sem) @?= lr_exp
403 Left err -> Right ("…"::Text) @?= Left err
404 Right (_te_exp::h) ->
405 (>>= (@?= (n_exp, lr_exp))) $
408 case got `Sym.feed_args`
410 (Sym.ty @LCC.Quantity)
411 (Sym.TermClosed $ Sym.quantity 42)
414 (Sym.TermClosed $ Sym.bool True)
416 Sym.ETermClosed ty_got (Sym.TermClosed te_got) ->
417 case ty_got `Sym.eq_Type` ty_exp of
418 Nothing -> err_type (Sym.EType ty_got)
419 Just Refl -> Right $ Sym.host_from_term te_got
423 LCC.At (P.initialPos "" :| []) (P.initialPos "") $
424 Sym.Error_Term_Con_Type $ Right $
426 (Right $ Sym.At Nothing ty_got)
427 (Sym.At Nothing $ Sym.EType ty_exp)
430 :: forall is cs j e m a.
432 , LCC.Gram_File (P.ParsecT P.Dec Text m)
433 , Sym.Tokenize LCC.Meta is
434 , m ~ S.StateT (LCC.Context_Read j)
435 (S.StateT (LCC.Context_Sym cs is)
436 (S.StateT Context_Test Identity))
437 , e ~ P.ParseError Char P.Dec
438 , j ~ [LCC.Transaction]
439 , cs ~ Sym.TyConsts_of_Ifaces is
442 => Sym.CF (Parsec P.Dec Text m) a
444 -> Either (P.ParseError Char P.Dec) a
447 S.evalState Context_Test{ context_test_files = Map.fromList [] } $
448 S.evalState LCC.context_sym $
449 S.evalState LCC.context_read $
450 P.runParserT (unParsec . Sym.unCF $ g <* Sym.eoi) "" inp
453 tests = testGroup "Read"
454 [{- testGroup "Date" $
457 read_gram LCC.g_date inp @?= Right (S.Right exp) in
458 [ "2000-01-13" ==> date 2000 01 13 0 0 0 Time.utc
459 , "2000-01-13_12:34" ==> date 2000 01 13 12 34 0 Time.utc
460 , "2000-01-13_12:34:56" ==> date 2000 01 13 12 34 56 Time.utc
461 , "2000-01-13_12:34_CET" ==> date 2000 01 13 12 34 0 (Time.TimeZone 60 True "CET")
462 , "2000-01-13_12:34+01:30" ==> date 2000 01 13 12 34 0 (Time.TimeZone 90 False "+01:30")
463 , "2000-01-13_12:34:56_CET" ==> date 2000 01 13 12 34 56 (Time.TimeZone 60 True "CET")
464 , "01-01" ==> date 1970 01 01 0 0 0 Time.utc
465 , testGroup "Parsing errors" $
468 read_gram LCC.g_date inp @?= Left exp in
469 [ "2000/01/13" !=> P.ParseError
470 { P.errorPos = sourcePos "" 1 5 :| []
471 , P.errorUnexpected = Set.fromList [P.Tokens ('/' :| "")]
472 , P.errorExpected = Set.fromList [P.Tokens ('-' :| "")]
473 , P.errorCustom = Set.fromList []
476 , testGroup "Semantic errors" $
479 read_gram LCC.g_date inp @?= Right (S.Left exp) in
480 [ "2000-13-01" =!> LCC.At
481 { LCC.atBegin = pure $ sourcePos "" 1 1
482 , LCC.atEnd = sourcePos "" 1 11
483 , LCC.atItem = LCC.Error_Date_Day_invalid (2000, 13, 01) }
484 , "2001-02-29" =!> LCC.At
485 { LCC.atBegin = pure $ sourcePos "" 1 1
486 , LCC.atEnd = sourcePos "" 1 11
487 , LCC.atItem = LCC.Error_Date_Day_invalid (2001, 2, 29) }
488 , "2000-01-13_12:60" =!> LCC.At
489 { LCC.atBegin = pure $ sourcePos "" 1 12
490 , LCC.atEnd = sourcePos "" 1 17
491 , LCC.atItem = LCC.Error_Date_TimeOfDay_invalid (12, 60, 0) }
494 , testGroup "Account_Section" $
497 rights [read_gram LCC.g_account_section inp]
498 @?= [LCC.Name inp | exp] in
506 , testGroup "Parsing errors"
525 , testGroup "Account" $
528 read_gram LCC.g_account inp
529 @?= Right (account exp) in
531 , "/A/B" ==> ["A", "B"]
532 , "/A/B/C" ==> ["A", "B","C"]
533 , "/Aa/Bbb/Cccc" ==> ["Aa", "Bbb", "Cccc"]
534 , "/A/B/(C)" ==> ["A", "B", "(C)"]
535 , testGroup "Parsing errors" $
538 rights [read_gram LCC.g_account inp]
547 , "/A a / B b b / C c c c" !=> []
550 , testGroup "Amount" $
553 read_gram LCC.g_amount inp @?= Right exp in
556 , LCC.amount { LCC.amount_quantity = Decimal 0 0 } )
559 , LCC.amount { LCC.amount_quantity = Decimal 0 0 } )
561 ( LCC.style_amount { LCC.style_amount_fractioning = pure '.' }
562 , LCC.amount { LCC.amount_quantity = Decimal 0 0 } )
564 ( LCC.style_amount { LCC.style_amount_fractioning = pure ',' }
565 , LCC.amount { LCC.amount_quantity = Decimal 0 0 } )
567 ( LCC.style_amount { LCC.style_amount_fractioning = pure '.' }
568 , LCC.amount { LCC.amount_quantity = Decimal 1 0 } )
570 ( LCC.style_amount { LCC.style_amount_fractioning = pure '.' }
571 , LCC.amount { LCC.amount_quantity = Decimal 2 0 } )
573 ( LCC.style_amount { LCC.style_amount_fractioning = pure ',' }
574 , LCC.amount { LCC.amount_quantity = Decimal 1 0 } )
576 ( LCC.style_amount { LCC.style_amount_fractioning = pure ',' }
577 , LCC.amount { LCC.amount_quantity = Decimal 2 0 } )
579 ( LCC.style_amount { LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '_' [1] }
580 , LCC.amount { LCC.amount_quantity = Decimal 0 0 } )
582 ( LCC.style_amount { LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '_' [2] }
583 , LCC.amount { LCC.amount_quantity = Decimal 0 0 } )
586 { LCC.style_amount_fractioning = pure '.'
587 , LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping ',' [3] }
588 , LCC.amount { LCC.amount_quantity = Decimal 2 0 } )
591 { LCC.style_amount_fractioning = pure ','
592 , LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '.' [3] }
593 , LCC.amount { LCC.amount_quantity = Decimal 2 0 } )
596 { LCC.style_amount_fractioning = pure '.'
597 , LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping ',' [3] }
598 , LCC.amount { LCC.amount_quantity = Decimal 2 100000 } )
601 { LCC.style_amount_fractioning = pure ','
602 , LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '.' [3] }
603 , LCC.amount { LCC.amount_quantity = Decimal 2 100000 } )
606 , LCC.amount { LCC.amount_quantity = Decimal 0 123 } )
608 ( LCC.style_amount { LCC.style_amount_fractioning = pure '.' }
609 , LCC.amount { LCC.amount_quantity = Decimal 1 12 } )
611 ( LCC.style_amount { LCC.style_amount_fractioning = pure ',' }
612 , LCC.amount { LCC.amount_quantity = Decimal 1 12 } )
614 ( LCC.style_amount { LCC.style_amount_fractioning = pure '.' }
615 , LCC.amount { LCC.amount_quantity = Decimal 2 1234 } )
617 ( LCC.style_amount { LCC.style_amount_fractioning = pure ',' }
618 , LCC.amount { LCC.amount_quantity = Decimal 2 1234 } )
620 ( LCC.style_amount { LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '_' [1] }
621 , LCC.amount { LCC.amount_quantity = Decimal 0 12 } )
623 ( LCC.style_amount { LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '_' [2] }
624 , LCC.amount { LCC.amount_quantity = Decimal 0 123 } )
626 ( LCC.style_amount { LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '_' [3, 2] }
627 , LCC.amount { LCC.amount_quantity = Decimal 0 123456 } )
628 , "1_23_456,7890_12345_678901" ==>
630 { LCC.style_amount_fractioning = pure ','
631 , LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '_' [3, 2]
632 , LCC.style_amount_grouping_fractional = pure $ LCC.Style_Amount_Grouping '_' [4, 5, 6] }
633 , LCC.amount { LCC.amount_quantity = Decimal 15 123456789012345678901 } )
634 , "1_23_456.7890_12345_678901" ==>
636 { LCC.style_amount_fractioning = pure '.'
637 , LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '_' [3, 2]
638 , LCC.style_amount_grouping_fractional = pure $ LCC.Style_Amount_Grouping '_' [4, 5, 6] }
639 , LCC.amount { LCC.amount_quantity = Decimal 15 123456789012345678901 } )
640 , "1,23,456.7890_12345_678901" ==>
642 { LCC.style_amount_fractioning = pure '.'
643 , LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping ',' [3, 2]
644 , LCC.style_amount_grouping_fractional = pure $ LCC.Style_Amount_Grouping '_' [4, 5, 6] }
645 , LCC.amount { LCC.amount_quantity = Decimal 15 123456789012345678901 } )
646 , "1.23.456,7890_12345_678901" ==>
648 { LCC.style_amount_fractioning = pure ','
649 , LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '.' [3, 2]
650 , LCC.style_amount_grouping_fractional = pure $ LCC.Style_Amount_Grouping '_' [4, 5, 6] }
651 , LCC.amount { LCC.amount_quantity = Decimal 15 123456789012345678901 } )
652 , "123456_78901_2345.678_90_1" ==>
654 { LCC.style_amount_fractioning = pure '.'
655 , LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '_' [4, 5, 6]
656 , LCC.style_amount_grouping_fractional = pure $ LCC.Style_Amount_Grouping '_' [3, 2] }
657 , LCC.amount { LCC.amount_quantity = Decimal 6 123456789012345678901 } )
660 { LCC.style_amount_unit_side = pure LCC.L
661 , LCC.style_amount_unit_spaced = pure False }
663 { LCC.amount_quantity = Decimal 0 1
664 , LCC.amount_unit = "$" } )
667 { LCC.style_amount_unit_side = pure LCC.R
668 , LCC.style_amount_unit_spaced = pure False }
670 { LCC.amount_quantity = Decimal 0 1
671 , LCC.amount_unit = "$" } )
674 { LCC.style_amount_unit_side = pure LCC.L
675 , LCC.style_amount_unit_spaced = pure True }
677 { LCC.amount_quantity = Decimal 0 1
678 , LCC.amount_unit = "$" } )
681 { LCC.style_amount_unit_side = pure LCC.R
682 , LCC.style_amount_unit_spaced = pure True }
684 { LCC.amount_quantity = Decimal 0 1
685 , LCC.amount_unit = "$" } )
688 { LCC.style_amount_unit_side = pure LCC.L
689 , LCC.style_amount_unit_spaced = pure False }
691 { LCC.amount_quantity = Decimal 0 (-1)
692 , LCC.amount_unit = "$" } )
695 { LCC.style_amount_fractioning = pure ','
696 , LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '.' [3]
697 , LCC.style_amount_unit_side = pure LCC.L
698 , LCC.style_amount_unit_spaced = pure False }
700 { LCC.amount_quantity = Decimal 2 100000
701 , LCC.amount_unit = "$" } )
704 { LCC.style_amount_fractioning = pure ','
705 , LCC.style_amount_grouping_integral = pure $ LCC.Style_Amount_Grouping '.' [3]
706 , LCC.style_amount_unit_side = pure LCC.R
707 , LCC.style_amount_unit_spaced = pure False }
709 { LCC.amount_quantity = Decimal 2 100000
710 , LCC.amount_unit = "$" } )
711 , testGroup "Parsing errors" $
714 rights [read_gram LCC.g_amount inp] @?= [] in
725 , testGroup "Comment" $
726 let (==>) (inp, post) exp =
728 rights [read_gram (LCC.g_comment <* post) inp]
729 @?= (LCC.Comment <$> exp) in
730 [ ("; a b c" , Sym.eoi) ==> [ "a b c" ]
731 , ("; #a" , Sym.eoi) ==> [ "#a" ]
732 , ("; a b c \n" , Sym.string " \n") ==> [ "a b c" ]
733 , ("; a b c \r\n", Sym.string " \r\n") ==> [ "a b c" ]
734 -- , ("; a b c\n ; d e f", Sym.eoi) ==> [ ["a b c", "d e f"] ]
735 -- , ("; a b c \n", Sym.string " \n") ==> [ ["a b c"] ]
737 , testGroup "Transaction_Tag" $
740 read_gram LCC.g_transaction_tag inp
741 @?= Right (LCC.Transaction_Tag exp) in
742 [ "#Name" ==> tag ["Name"] ""
743 , "#Name:name" ==> tag ["Name", "name"] ""
744 , "#Name=Value" ==> tag ["Name"] "Value"
745 , "#Name = Value" ==> tag ["Name"] "Value"
746 , "#Name=Val ue" ==> tag ["Name"] "Val ue"
747 , "#Name=," ==> tag ["Name"] ","
748 , "#Name=Val,ue" ==> tag ["Name"] "Val,ue"
749 , "#Name=Val,ue:" ==> tag ["Name"] "Val,ue:"
750 , "#Name=Val,ue :" ==> tag ["Name"] "Val,ue :"
751 , testGroup "Parsing errors" $
754 rights [read_gram LCC.g_transaction_tag inp] @?= [] in
756 , "#Name=Value\n" !=> []
759 , testGroup "Posting" $
762 read_gram LCC.g_posting inp @?= Right (S.Right exp) in
763 [ "/A/B/C" ==> LCC.posting (account ["A", "B", "C"])
764 , "/A/B/C $1" ==> (LCC.posting $ account ["A", "B", "C"])
765 { LCC.posting_amounts = amounts [("$", 1)] }
766 , "/A/B/C $1" ==> (LCC.posting $ account ["A", "B", "C"])
767 { LCC.posting_amounts = amounts [("$", 1)] }
768 , "/A/B/C 1€" ==> (LCC.posting $ account ["A", "B", "C"])
769 { LCC.posting_amounts = amounts [("€", 1)] }
770 , "/A/B/C $1; some comment" ==> (LCC.posting $ account ["A", "B", "C"])
771 { LCC.posting_amounts = amounts [("$", 1)]
772 , LCC.posting_comments = comments ["some comment"] }
773 , "/A/B/C; some comment" ==>
774 (LCC.posting $ account ["A", "B", "C"])
775 { LCC.posting_comments = comments ["some comment"] }
776 , "/A/B/C ; some comment" ==> (LCC.posting $ account ["A", "B", "C"])
777 { LCC.posting_amounts = amounts []
778 , LCC.posting_comments = comments ["some comment"] }
779 , "/A/B/C ; some comment\n ; some other comment" ==>
780 (LCC.posting $ account ["A", "B", "C"])
781 { LCC.posting_amounts = amounts []
782 , LCC.posting_comments = comments ["some comment", "some other comment"] }
783 , "/A/B/C $1 ; some comment" ==>
784 (LCC.posting $ account ["A", "B", "C"])
785 { LCC.posting_amounts = amounts [("$", 1)]
786 , LCC.posting_comments = comments ["some comment"] }
788 (LCC.posting $ account ["A", "B", "C"])
789 { LCC.posting_tags = LCC.Posting_Tags $ tags [ (["N"], "V") ] }
790 , "/A/B/C #N:O=V" ==>
791 (LCC.posting $ account ["A", "B", "C"])
792 { LCC.posting_tags = LCC.Posting_Tags $ tags [ (["N", "O"], "V") ] }
793 , "/A/B/C #N=Val;ue" ==>
794 (LCC.posting $ account ["A", "B", "C"])
795 { LCC.posting_tags = LCC.Posting_Tags $ tags [ (["N"], "Val;ue") ] }
796 , "/A/B/C #N=Val#ue" ==>
797 (LCC.posting $ account ["A", "B", "C"])
798 { LCC.posting_tags = LCC.Posting_Tags $ tags [ (["N"], "Val#ue") ] }
799 , "/A/B/C #N=V ; not a comment" ==>
800 (LCC.posting $ account ["A", "B", "C"])
801 { LCC.posting_tags = LCC.Posting_Tags $ tags [ (["N"], "V ; not a comment") ] }
802 , "/A/B/C #N=V #O" ==>
803 (LCC.posting $ account ["A", "B", "C"])
804 { LCC.posting_tags = LCC.Posting_Tags $ tags [ (["N"], "V #O") ] }
806 (LCC.posting $ account ["A", "B", "C"])
807 { LCC.posting_tags = LCC.Posting_Tags $ tags [ (,) ["N"] "", (,) ["O"] "" ] }
808 , "/A/B/C #N; #O" ==>
809 (LCC.posting $ account ["A", "B", "C"])
810 { LCC.posting_tags = LCC.Posting_Tags $ tags [ (["N"], "") ]
811 , LCC.posting_comments = comments ["#O"] }
813 (LCC.posting $ account ["A", "B", "C"])
814 { LCC.posting_tags = LCC.Posting_Tags $ tags [ (,) ["N"] "", (,) ["O"] "" ] }
815 , "/A/B/C \n #N=V" ==>
816 (LCC.posting $ account ["A", "B", "C"])
817 { LCC.posting_tags = LCC.Posting_Tags $ tags [ (["N"], "V") ] }
818 , "/A/B/C ; some comment\n #N=V" ==>
819 (LCC.posting $ account ["A", "B", "C"])
820 { LCC.posting_comments = comments ["some comment"]
821 , LCC.posting_tags = LCC.Posting_Tags $ tags [ (["N"], "V") ] }
822 , "/A/B/C ; some comment\n #N=V v\n #N2=V2 v2" ==>
823 (LCC.posting $ account ["A", "B", "C"])
824 { LCC.posting_comments = comments ["some comment"]
825 , LCC.posting_tags = LCC.Posting_Tags $ tags
827 , (["N2"], "V2 v2") ] }
828 , "/A/B/C\n #N=V\n #N=V2" ==>
829 (LCC.posting $ account ["A", "B", "C"])
830 { LCC.posting_tags = LCC.Posting_Tags $ tags
834 , "/A/B/C\n #N=V\n #N2=V" ==>
835 (LCC.posting $ account ["A", "B", "C"])
836 { LCC.posting_tags = LCC.Posting_Tags $ tags
841 , testGroup "Transaction" $
843 let inp = Text.intercalate "\n" i in
845 read_gram LCC.g_transaction inp @?= Right (S.Right e) in
846 [ [ "2000-01-01 some wording"
849 ] ==> LCC.transaction
850 { LCC.transaction_dates = date 2000 01 01 0 0 0 Time.utc `NonNull.ncons` []
851 , LCC.transaction_wording = "some wording"
852 , LCC.transaction_postings = postings
853 [ (LCC.posting $ account ["A", "B", "C"])
854 { LCC.posting_amounts = amounts [ ("$", 1) ]
855 , LCC.posting_sourcepos = sourcePos "" 2 2 }
856 , (LCC.posting $ account ["D", "E", "F"])
857 { LCC.posting_amounts = amounts [ ("$", -1) ]
858 , LCC.posting_sourcepos = sourcePos "" 3 2 }
861 , [ "2000-01-01 some wording ; not a comment"
862 , "; some other;comment"
863 , " ; some last comment"
866 ] ==> LCC.transaction
867 { LCC.transaction_comments = comments
868 [ "some other;comment"
869 , "some last comment"
871 , LCC.transaction_dates = date 2000 01 01 0 0 0 Time.utc `NonNull.ncons` []
872 , LCC.transaction_wording = "some wording ; not a comment"
873 , LCC.transaction_postings = postings
874 [ (LCC.posting $ account ["A", "B", "C"])
875 { LCC.posting_amounts = amounts [ ("$", 1) ]
876 , LCC.posting_sourcepos = sourcePos "" 4 2 }
877 , (LCC.posting $ account ["D", "E", "F"])
878 { LCC.posting_amounts = amounts [ ("$", -1) ]
879 , LCC.posting_sourcepos = sourcePos "" 5 2 }
882 , testGroup "Semantic errors" $
884 let inp = Text.intercalate "\n" i in
886 read_gram LCC.g_transaction inp @?= Right (S.Left e) in
887 [ [ "2000-01-01 wording"
891 { LCC.atBegin = pure $ sourcePos "" 1 1
892 , LCC.atEnd = sourcePos "" 3 12
893 , LCC.atItem = LCC.Error_Transaction_not_equilibrated
895 { LCC.transaction_dates = date 2000 01 01 0 0 0 Time.utc `NonNull.ncons` []
896 , LCC.transaction_wording = "wording"
897 , LCC.transaction_postings = postings
898 [ (LCC.posting $ account ["A", "B", "C"])
899 { LCC.posting_amounts = amounts [ ("$", 1) ]
900 , LCC.posting_sourcepos = sourcePos "" 2 2 }
901 , (LCC.posting $ account ["D", "E", "F"])
902 { LCC.posting_amounts = amounts [ ("$", -2) ]
903 , LCC.posting_sourcepos = sourcePos "" 3 2 }
908 { H.sumByUnit_quantity = H.Polarized_Both (-2) 1
909 , H.sumByUnit_accounts = Map.fromList []
914 ,-} testGroup "Term" $
915 let (==>) = test_compile
916 @'[ Proxy LCC.Quantity
919 , Proxy LCC.Transaction
921 -- , Proxy LCC.Postings
937 , Proxy TreeMap.Zipper
940 ] (Proxy @[LCC.Transaction]) in
941 [ [ "x = 42" ] ==> ("x", Sym.ty @LCC.Quantity, Right 42.0)
942 , [ "x = 40 + 2" ] ==> ("x", Sym.ty @LCC.Quantity, Right 42.0)
943 , [ "x = $4.2" ] ==> ("x", Sym.ty @LCC.Amounts, Right $ amounts [ ("$", 4.2) ])
944 , [ "x = 4,2€" ] ==> ("x", Sym.ty @LCC.Amounts, Right $ amounts [ ("€", 4.2) ])
945 , [ "x = 4,2€ + $2.4" ] ==> ("x", Sym.ty @LCC.Amounts, Right $ amounts [ ("$", 2.4), ("€", 4.2) ])
946 , [ "x = 4,0€ + 0.2€" ] ==> ("x", Sym.ty @LCC.Amounts, Right $ amounts [ ("€", 4.2) ])
947 , [ "x (q:Quantity) = q" ] ==> ("x", Sym.ty @LCC.Quantity, Right 42.0)
948 , [ "x (b:Bool) = b" ] ==> ("x", Sym.ty @Bool, Right True)
949 , [ "x (b:Bool) = (b,b)" ] ==> ("x", Sym.ty @(,) Sym.:$ Sym.ty @Bool Sym.:$ Sym.ty @Bool, Right (True, True))
950 , [ "x (b:Bool) (q:Quantity) = (b,q)" ] ==> ("x", Sym.ty @(,) Sym.:$ Sym.ty @Bool Sym.:$ Sym.ty @LCC.Quantity, Right (True, 42))
951 -- , [ "x = j" ] ==> ("x", Sym.ty @Bool, Right $ True )
952 -- , [ "x = q" ] ==> ("x", Sym.ty @LCC.Quantity, Right $ 42 )
953 , testGroup "Semantic errors" $
955 let inp = Text.intercalate "\n" i in
957 read_gram LCC.g_transaction inp @?= Right (S.Left e) in
961 {-, testGroup "Chart" $
963 let inp = Text.intercalate "\n" i in
966 LCC.g_get $ (\_txn ch -> ch) <$>
967 LCC.g_journal @(Sym.TyConsts_of_Ifaces '[Proxy (->)]) @'[Proxy (->)] (:)
969 let acct_path = NonEmpty.fromList . (LCC.Name <$>) in
970 let acct_tags = LCC.Account_Tags . tags in
975 { LCC.chart_accounts = TreeMap.from_List (<>)
976 [ (acct_path ["A", "B", "C"], acct_tags [])
977 , (acct_path ["D", "E", "F"], acct_tags [])
979 , LCC.chart_tags = Map.empty
989 { LCC.chart_accounts = TreeMap.from_List (<>)
990 [ (acct_path ["A", "B", "C"], acct_tags
992 , (["a0", "a1", "a2"], "")
994 , (acct_path ["D", "E", "F"], acct_tags
995 [ (["t0", "t1"], "v0")
996 , (["t0", "t1"], "v1") ])
998 , LCC.chart_tags = account_refs
1002 , (,) ["a0", "a1", "a2"]
1007 , testGroup "Journal" $
1009 let inp = (Text.intercalate "\n" <$>) <$> i in
1010 let jnl = fromMaybe "" $ List.lookup "" inp in
1011 let exp = ((LCC.Journals . Map.fromList . (first LCC.CanonFile <$>)) <$>) <$> fe e in
1013 read @'[Proxy (->)] @[LCC.Transaction] (
1014 LCC.g_get $ (\j (js::LCC.Journals [LCC.Transaction]) -> const js <$> j) <$>
1016 @(Sym.TyConsts_of_Ifaces '[Proxy (->)])
1019 ) inp "" jnl @?= exp in
1020 let (==>) = run (Right . S.Right) ; infixr 0 ==> in
1021 let jnl :: LCC.Journal [LCC.Transaction] = LCC.journal in
1023 [ "2000-01-01 wording"
1029 { LCC.journal_content =
1031 { LCC.transaction_dates = date 2000 01 01 0 0 0 Time.utc `NonNull.ncons` []
1032 , LCC.transaction_wording = "wording"
1033 , LCC.transaction_sourcepos = sourcePos "" 1 1
1034 , LCC.transaction_postings = postings
1035 [ (LCC.posting $ account ["A", "B", "C"])
1036 { LCC.posting_amounts = amounts [ ("$", 1) ]
1037 , LCC.posting_sourcepos = sourcePos "" 2 2
1039 , (LCC.posting $ account ["D", "E", "F"])
1040 { LCC.posting_amounts = amounts [ ("$", -1) ]
1041 , LCC.posting_sourcepos = sourcePos "" 3 2
1046 {-, LCC.journal_amount_styles = LCC.Amount_Styles $ Map.fromList
1049 { LCC.amount_style_unit_side = Just LCC.L
1050 , LCC.amount_style_unit_spaced = Just False }
1057 [ "2000-01-01 1° wording"
1060 , "2000-01-02 2° wording"
1066 { LCC.journal_content =
1068 { LCC.transaction_dates = date 2000 01 02 0 0 0 Time.utc `NonNull.ncons` []
1069 , LCC.transaction_wording = "2° wording"
1070 , LCC.transaction_sourcepos = sourcePos "" 4 1
1071 , LCC.transaction_postings = postings
1072 [ (LCC.posting $ account ["A", "B", "C"])
1073 { LCC.posting_amounts = amounts [ ("$", 1) ]
1074 , LCC.posting_sourcepos = sourcePos "" 5 2
1076 , (LCC.posting $ account ["x", "y", "z"])
1077 { LCC.posting_amounts = amounts [ ("$", -1) ]
1078 , LCC.posting_sourcepos = sourcePos "" 6 2
1083 { LCC.transaction_dates = date 2000 01 01 0 0 0 Time.utc `NonNull.ncons` []
1084 , LCC.transaction_wording = "1° wording"
1085 , LCC.transaction_sourcepos = sourcePos "" 1 1
1086 , LCC.transaction_postings = postings
1087 [ (LCC.posting $ account ["A", "B", "C"])
1088 { LCC.posting_amounts = amounts [ ("$", 1) ]
1089 , LCC.posting_sourcepos = sourcePos "" 2 2
1091 , (LCC.posting $ account ["D", "E", "F"])
1092 { LCC.posting_amounts = amounts [ ("$", -1) ]
1093 , LCC.posting_sourcepos = sourcePos "" 3 2
1103 , "2000-01-01 wording"
1109 { LCC.journal_content =
1111 { LCC.transaction_dates = date 2000 01 01 0 0 0 Time.utc `NonNull.ncons` []
1112 , LCC.transaction_wording = "wording"
1113 , LCC.transaction_sourcepos = sourcePos "" 3 1
1114 , LCC.transaction_postings = postings
1115 [ (LCC.posting $ account ["A", "B", "C"])
1116 { LCC.posting_amounts = amounts [ ("$", 1) ]
1117 , LCC.posting_account_ref = S.Just $ account_ref ["AB"] S.:!: S.Just (account ["C"])
1118 , LCC.posting_sourcepos = sourcePos "" 4 2
1120 , (LCC.posting $ account ["D", "E", "F"])
1121 { LCC.posting_amounts = amounts [ ("$", -1) ]
1122 , LCC.posting_sourcepos = sourcePos "" 5 2
1132 , "2000-01-01 wording"
1144 { LCC.journal_includes =
1145 [ LCC.CanonFile "chart"
1147 , LCC.journal_content =
1149 { LCC.transaction_dates = date 2000 01 01 0 0 0 Time.utc `NonNull.ncons` []
1150 , LCC.transaction_wording = "wording"
1151 , LCC.transaction_sourcepos = sourcePos "" 3 1
1152 , LCC.transaction_postings = postings
1153 [ (LCC.posting $ account ["A", "B", "C"])
1154 { LCC.posting_amounts = amounts [ ("$", 1) ]
1155 , LCC.posting_account_ref = S.Just $ account_ref ["AB"] S.:!: S.Just (account ["C"])
1156 , LCC.posting_sourcepos = sourcePos "" 4 2
1158 , (LCC.posting $ account ["D", "E", "F"])
1159 { LCC.posting_amounts = amounts [ ("$", -1) ]
1160 , LCC.posting_account_ref = S.Just $ account_ref ["D"] S.:!: S.Just (account ["E", "F"])
1161 , LCC.posting_sourcepos = sourcePos "" 5 2
1168 { LCC.journal_file = "chart"
1190 { LCC.journal_includes =
1194 , LCC.journal_content =
1196 { LCC.transaction_dates = date 2000 01 01 0 0 0 Time.utc `NonNull.ncons` []
1197 , LCC.transaction_wording = "w"
1198 , LCC.transaction_sourcepos = sourcePos "" 1 1
1199 , LCC.transaction_postings = postings
1200 [ (LCC.posting $ account ["A", "B", "C"])
1201 { LCC.posting_amounts = amounts [ ("$", 1) ]
1202 , LCC.posting_sourcepos = sourcePos "" 2 2
1204 , (LCC.posting $ account ["D", "E", "F"])
1205 { LCC.posting_amounts = amounts [ ("$", -1) ]
1206 , LCC.posting_sourcepos = sourcePos "" 3 2
1213 { LCC.journal_file = "0"
1214 , LCC.journal_content =
1216 { LCC.transaction_dates = date 2000 01 02 0 0 0 Time.utc `NonNull.ncons` []
1217 , LCC.transaction_wording = "w0"
1218 , LCC.transaction_sourcepos = sourcePos "0" 1 1
1219 , LCC.transaction_postings = postings
1220 [ (LCC.posting $ account ["A", "B", "C"])
1221 { LCC.posting_amounts = amounts [ ("$", 2) ]
1222 , LCC.posting_sourcepos = sourcePos "0" 2 2
1224 , (LCC.posting $ account ["D", "E", "F"])
1225 { LCC.posting_amounts = amounts [ ("$", -2) ]
1226 , LCC.posting_sourcepos = sourcePos "0" 3 2
1233 { LCC.journal_file = "1"
1234 , LCC.journal_content =
1236 { LCC.transaction_dates = date 2000 01 03 0 0 0 Time.utc `NonNull.ncons` []
1237 , LCC.transaction_wording = "w1"
1238 , LCC.transaction_sourcepos = sourcePos "1" 1 1
1239 , LCC.transaction_postings = postings
1240 [ (LCC.posting $ account ["A", "B", "C"])
1241 { LCC.posting_amounts = amounts [ ("$", 3) ]
1242 , LCC.posting_sourcepos = sourcePos "1" 2 2
1244 , (LCC.posting $ account ["D", "E", "F"])
1245 { LCC.posting_amounts = amounts [ ("$", -3) ]
1246 , LCC.posting_sourcepos = sourcePos "1" 3 2
1253 , testGroup "Parsing errors" $
1254 let (!=>) = run Left ; infixr 0 !=> in
1259 [ "2000-01_01 wording"
1264 { P.errorPos = sourcePos "j" 1 8 :| [sourcePos "" 1 4]
1265 , P.errorUnexpected = Set.fromList [P.Tokens ('_' :| "")]
1266 , P.errorExpected = Set.fromList [P.Tokens ('-' :| "")]
1267 , P.errorCustom = Set.fromList []
1270 , testGroup "Semantic errors" $
1271 let (=!>) = run (Right . S.Left) ; infixr 0 =!> in
1273 [ "2000-01-01 wording"
1279 , "2000-01-01 wording"
1288 { LCC.atBegin = sourcePos "chart" 1 1 :| [sourcePos "" 5 8]
1289 , LCC.atEnd = sourcePos "chart" 1 9
1291 LCC.Error_Journal_Section
1292 LCC.Section_Transaction
1296 { LCC.atBegin = sourcePos "" 8 2 :| []
1297 , LCC.atEnd = sourcePos "" 8 5
1299 LCC.Error_Journal_Transaction $
1300 LCC.Error_Transaction_Posting $
1301 LCC.Error_Posting_Account_Ref_unknown $
1309 [ "2000-01-01 wording"
1317 { LCC.atBegin = sourcePos "j" 5 1 :| [sourcePos "" 1 4]
1318 , LCC.atEnd = sourcePos "j" 5 4
1319 , LCC.atItem = LCC.Error_Journal_Include_loop $ LCC.CanonFile "j"