package ledger import ( "strings" "testing" "time" ) func TestJournalValidationBalancesEachAsset(t *testing.T) { journal := validJournal(t) if err := journal.Validate(); err != nil { t.Fatal(err) } journal.Entries[1].Amount, _ = ParseAmount("9") if err := journal.Validate(); err == nil || !strings.Contains(err.Error(), "unbalanced") { t.Fatalf("expected unbalanced error, got %v", err) } } func TestJournalValidationRejectsDuplicateLines(t *testing.T) { journal := validJournal(t) journal.Entries[1].LineNumber = journal.Entries[0].LineNumber if err := journal.Validate(); err == nil || !strings.Contains(err.Error(), "duplicate") { t.Fatalf("expected duplicate line error, got %v", err) } } func validJournal(t *testing.T) Journal { t.Helper() debit, err := ParseAmount("-10") if err != nil { t.Fatal(err) } credit := debit.Negate() return Journal{ ID: "11111111-1111-4111-8111-111111111111", SourceService: "wallet", IdempotencyKey: "wallet:1:internal-transfer:v1", SourceTransactionID: "1", EffectKind: "internal-transfer", EventVersion: 1, OccurredAt: time.Unix(1, 0).UTC(), PayloadHash: strings.Repeat("a", 64), Entries: []Entry{ {LineNumber: 1, Account: AccountReference{Class: AccountClassUserAvailable, OwnerType: "user", OwnerID: "1", AssetID: 5}, Amount: debit}, {LineNumber: 2, Account: AccountReference{Class: AccountClassUserAvailable, OwnerType: "user", OwnerID: "2", AssetID: 5}, Amount: credit}, }, } }