Skip to content

Commit

Permalink
Support transaction deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
mput committed Jul 24, 2024
1 parent 57234c4 commit ba01852
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 22 deletions.
92 changes: 89 additions & 3 deletions app/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func (l *Ledger) addTransaction(transaction string) error {
if err != nil {
return fmt.Errorf("unable to open main ledger file: %v", err)
}
_, err = fmt.Fprintf(r, "\n%s\n", transaction)
_, err = fmt.Fprintf(r, "\n%s", transaction)
defer r.Close()
if err != nil {
return fmt.Errorf("unable to write main ledger file: %v", err)
Expand Down Expand Up @@ -238,6 +238,94 @@ func (l *Ledger) AddTransactionWithID(transaction , id string) error {
return l.AddTransaction(fmt.Sprintf("%s%s\n%s",transactionIDPrefix, id, transaction))
}

func filterOutTransactionWithID(r io.Reader, id string) (content []byte, err error) {
scanner := bufio.NewScanner(r)
marker := transactionIDPrefix + id

afterMarker := 0

for scanner.Scan() {
txt := scanner.Text()

if (afterMarker == 0 && txt == marker) {
afterMarker++
if len(content) > 0 && content[len(content) - 1] == '\n' {
content = content[:len(content) - 1]
}
continue
}
if (afterMarker == 1 && txt == "") {
afterMarker++
content = append(content, '\n')
continue
}
if afterMarker == 1 {
continue
}
content = append(content, scanner.Bytes()...)
content = append(content, '\n')
}
if err := scanner.Err(); err != nil {
return content, fmt.Errorf("reading standard input: %v", err)
}
if afterMarker == 0 {
return content, fmt.Errorf("no transaction with id '%s' was found", id)
}
return content, nil

}

func (l *Ledger) DeleteTransactionWithID(id string) error {
err := l.repo.Init()
defer l.repo.Free()
if err != nil {
return fmt.Errorf("unable to init repo: %v", err)
}
err = l.setConfig()
if err != nil {
return fmt.Errorf("unable to set config: %v", err)
}

f, err := l.repo.OpenFile(l.Config.MainFile, os.O_RDWR, 0)
if err != nil {
return fmt.Errorf("unable to open main ledger file: %v", err)
}

newContent, err := filterOutTransactionWithID(f, id)
if err != nil {
return err
}

err = f.Truncate(0)
if err != nil {
return err
}

_, err = f.Seek(0, 0)

if err != nil {
return err
}

_, err = f.Write(newContent)

if err != nil {
return err
}

err = f.Close()
if err != nil {
return fmt.Errorf("unable to close main ledger file: %v", err)
}

err = l.repo.CommitPush("New comment", "teledger", "teledger@example.com")
if err != nil {
return fmt.Errorf("unable to commit: %v", err)
}

return nil
}

func (l *Ledger) validate() error {
_, err := l.execute("balance")
return err
Expand Down Expand Up @@ -576,13 +664,11 @@ type ProposeTransactionRespones struct {
func (l *Ledger) AddOrProposeTransaction(userInput string, attempts int) ProposeTransactionRespones {
resp := ProposeTransactionRespones{}

// wasGenerated = false
err := l.repo.Init()
defer l.repo.Free()
if err != nil {
resp.Error = err
return resp
// return wasGenerated, tr, err
}

err = l.setConfig()
Expand Down
1 change: 0 additions & 1 deletion app/ledger/ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ strict: true

assert.True(t, ledger.Config.StrictMode)

// assert.True(t, wasGenerated)
assert.Equal(t, "", resp.UserProvidedTransaction)

assert.NoError(t, resp.Error)
Expand Down
2 changes: 1 addition & 1 deletion app/repo/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (r *Mock) Open(filename string) (billy.File, error) {
}

func (r *Mock) OpenForAppend(filename string) (billy.File, error) {
return r.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600)
return r.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0)
}


Expand Down
8 changes: 4 additions & 4 deletions app/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,16 @@ func (imr *InMemoryRepo) Open(filename string) (billy.File, error) {


func (imr *InMemoryRepo) OpenForAppend(filename string) (billy.File, error) {
return imr.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600)
return imr.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0)
}

type RepoCloser struct {
type Closer struct {
billy.File
r *InMemoryRepo
path string
}

func (w *RepoCloser) Close() error {
func (w *Closer) Close() error {
w.r.dirtyFiles[w.path] = true
return w.File.Close()
}
Expand All @@ -110,7 +110,7 @@ func (imr *InMemoryRepo) OpenFile(file string, flag int, perm os.FileMode) (bill
return nil, fmt.Errorf("worktree receiving error: %v", err)
}
f, err := wtr.Filesystem.OpenFile(file, flag, perm)
wc := RepoCloser{
wc := Closer{
r: imr,
path: file,
File: f,
Expand Down
6 changes: 4 additions & 2 deletions app/teledger/teledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,14 @@ func (tel *Teledger) ConfirmTransaction(pendingKey string) (*PendingTransaction,
err := tel.Ledger.AddTransactionWithID(pendTr.GeneratedTransaction.Format(true), pendingKey)

if err != nil {
// pendTr.Error = err
return nil, err
}


pendTr.Committed = true
delete(*tel.WaitingToBeConfirmedResponses, pendingKey)
return pendTr, nil
}

func (tel *Teledger) DeleteTransaction(pendingKey string) error {
return tel.Ledger.DeleteTransactionWithID(pendingKey)
}
132 changes: 121 additions & 11 deletions app/teledger/teledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ strict: true
resp := tldgr.ProposeTransaction("valid")
assert.NotEmpty(t, resp.PendingKey)
assert.Empty(t, resp.Error)
assert.NotEmpty(t, resp.PendingKey)

t.Run("attempt to concurrently confirm the same transaction", func(t *testing.T) {
(*tldgr.WaitingToBeConfirmedResponses)[resp.PendingKey].Mu.Lock()
Expand All @@ -117,14 +118,14 @@ strict: true
(*tldgr.WaitingToBeConfirmedResponses)[resp.PendingKey].Mu.Unlock()
})

assert.NotEmpty(t, resp.PendingKey)
_, err := tldgr.ConfirmTransaction(resp.PendingKey)
assert.Empty(t, err)
t.Run("Success Confirmation", func(t *testing.T) {
_, err := tldgr.ConfirmTransaction(resp.PendingKey)
assert.Empty(t, err)

assert.Equal(
t,
r.Files["main.ledger"],
`
assert.Equal(
t,
r.Files["main.ledger"],
`
account Food
account Assets:Cash
account Equity
Expand All @@ -139,22 +140,131 @@ commodity EUR
2014-11-30 * My tr
Assets:Cash -10,00 EUR
Food 10,00 EUR
`,
)
)

})

t.Run("attempt to confirm for the second time", func(t *testing.T) {
_, err = tldgr.ConfirmTransaction(resp.PendingKey)
_, err := tldgr.ConfirmTransaction(resp.PendingKey)
assert.ErrorContains(t, err, "missing pending transaction")

})


t.Run("attempt to confirm with unknonw key", func(t *testing.T) {
_, err = tldgr.ConfirmTransaction("unk")
_, err := tldgr.ConfirmTransaction("unk")
assert.ErrorContains(t, err, "missing pending transaction")
})

t.Run("delete previously confirmed transaction", func(t *testing.T) {
err := tldgr.DeleteTransaction(resp.PendingKey)
assert.Empty(t, err)

assert.Equal(
t,
initContent,
r.Files["main.ledger"],
)

})

t.Run("delete unknown transaction", func(t *testing.T) {
err := tldgr.DeleteTransaction("unknowntrr")
assert.ErrorContains(t, err, "no transaction with id")

assert.Equal(
t,
initContent,
r.Files["main.ledger"],
)

})

t.Run("delete transaction corner cases", func(t *testing.T) {
initCoreners := `
commodity EUR
;; tid:2014-11-30 11:45:26.111 Sun
;; valid
2014-11-30 * My tr
Assets:Cash -10,00 EUR
Food 10,00 EUR
;; tid:2014-11-30 11:45:26.371 Sun
;; valid
2014-11-30 * My tr
Assets:Cash -10,00 EUR
Food 10,00 EUR
;; tid:2014-11-30 11:45:26.371 Sun
;; valid
2014-11-30 * My tr
Assets:Cash -10,00 EUR
Food 10,00 EUR
`


r := &repo.Mock{
Files: map[string]string{"main.ledger": initCoreners},
}

l := ledger.NewLedger(r, nil)

tldgr := &Teledger{
Ledger: l,
}

t.Run("transaction in the middle", func(t *testing.T) {
err :=tldgr.DeleteTransaction("2014-11-30 11:45:26.111 Sun")
assert.Empty(t, err)

assert.Equal(
t,
`
commodity EUR
;; tid:2014-11-30 11:45:26.371 Sun
;; valid
2014-11-30 * My tr
Assets:Cash -10,00 EUR
Food 10,00 EUR
;; tid:2014-11-30 11:45:26.371 Sun
;; valid
2014-11-30 * My tr
Assets:Cash -10,00 EUR
Food 10,00 EUR
`,
r.Files["main.ledger"],
)

})

t.Run("repeating transaction", func(t *testing.T) {
err :=tldgr.DeleteTransaction("2014-11-30 11:45:26.371 Sun")
assert.Empty(t, err)

assert.Equal(
t,
`
commodity EUR
;; tid:2014-11-30 11:45:26.371 Sun
;; valid
2014-11-30 * My tr
Assets:Cash -10,00 EUR
Food 10,00 EUR
`,
r.Files["main.ledger"],
)

})



})

t.Run("propose valid transaction, not free form explanation", func(t *testing.T) {
resp := tldgr.ProposeTransaction(`
2014-11-30 * My tr
Expand Down

0 comments on commit ba01852

Please sign in to comment.