all repos

clerk @ 1f3a17349e37c8189adb11b8d956acbf3b2080d1

missing tooling for ledger/hledger

clerk/internal/analyzer/analyzer_test.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
improve loader, 1 day ago
1
package analyzer
2
3
import (
4
	"fmt"
5
	"io"
6
	"path/filepath"
7
	"sort"
8
	"strings"
9
	"testing"
10
11
	"olexsmir.xyz/clerk/internal/testutil/golden"
12
	"olexsmir.xyz/clerk/journal"
13
	"olexsmir.xyz/clerk/journal/ast"
14
)
15
16
func TestAnalysis(t *testing.T) {
17
	tests := []string{
18
		"empty",
19
		"include",
20
		"journal",
21
		"typed-entries",
22
		"account-indexing",
23
		"account-usage",
24
		"commodity-usage",
25
		"payees",
26
		"periodic-automated",
27
		"directives",
28
		"cost-balance",
29
		"posting-types",
30
		"dates",
31
		"tags",
32
		"decimal-marks",
33
		"duplicate-transactions",
34
	}
35
36
	for _, tname := range tests {
37
		t.Run(tname, func(t *testing.T) {
38
			a := golden.Read(t, tname)
39
			fsys, err := a.FS()
40
			if err != nil {
41
				t.Fatal(err)
42
			}
43
44
			l := journal.NewLoader()
45
			rj, err := l.ResolveFS(fsys, "in.journal")
46
			if err != nil {
47
				t.Fatalf("failed to load test journal: %v", err)
48
			}
49
50
			ctx := Build(rj)
51
			var b strings.Builder
52
			fprint(&b, ctx)
53
			golden.Assert(t, a, b.String())
54
		})
55
	}
56
}
57
58
func fprint(w io.Writer, a *Analysis) {
59
	fmt.Fprintf(w, "files (%d):\n", len(a.Files))
60
	for i, pf := range a.Files {
61
		fmt.Fprintf(w, "  %d: %s\n", i, filepath.Base(pf.Path))
62
	}
63
64
	// commodities
65
	csyms := make([]string, 0, len(a.Commodities))
66
	for sym := range a.Commodities {
67
		csyms = append(csyms, sym)
68
	}
69
	sort.Strings(csyms)
70
71
	fmt.Fprintf(w, "\ncommodities (%d):\n", len(a.Commodities))
72
	for _, sym := range csyms {
73
		info := a.Commodities[sym]
74
		fmt.Fprintf(w, "  %s\n", sym)
75
		fmt.Fprintf(w, "    directives: %d\n", len(info.Directives))
76
		fmt.Fprintf(w, "    used: %d\n", info.UsedCount)
77
		for _, cd := range info.Directives {
78
			fmt.Fprintf(w, "      commodity %s\n", cd.Commodity)
79
		}
80
		fmt.Fprintf(w, "    usages: %d\n", len(info.Usages))
81
		for _, u := range info.Usages {
82
			fmt.Fprintf(w, "      file %d: %s (%q)\n", u.FileIndex, u.Amount.Commodity, u.Amount.Quantity.String())
83
		}
84
		if info.LastUsed.Year != 0 {
85
			fmt.Fprintf(w, "    last-used: %d-%02d-%02d\n", info.LastUsed.Year, info.LastUsed.Month, info.LastUsed.Day)
86
		}
87
	}
88
89
	// accounts
90
	anames := make([]string, 0, len(a.Accounts))
91
	for name := range a.Accounts {
92
		anames = append(anames, name)
93
	}
94
	sort.Strings(anames)
95
96
	fmt.Fprintf(w, "\naccounts (%d):\n", len(a.Accounts))
97
	for _, name := range anames {
98
		info := a.Accounts[name]
99
		fmt.Fprintf(w, "  %s\n", name)
100
		fmt.Fprintf(w, "    directives: %d\n", len(info.Directives))
101
		fmt.Fprintf(w, "    used: %d\n", info.UsedCount)
102
		for _, d := range info.Directives {
103
			fmt.Fprintf(w, "      account %s\n", d.Account.String())
104
		}
105
		fmt.Fprintf(w, "    usages: %d\n", len(info.Usages))
106
		for _, u := range info.Usages {
107
			fmt.Fprintf(w, "      file %d: %s\n", u.FileIndex, u.Posting.Account.String())
108
		}
109
		if info.LastUsed.Year != 0 {
110
			fmt.Fprintf(w, "    last-used: %d-%02d-%02d\n", info.LastUsed.Year, info.LastUsed.Month, info.LastUsed.Day)
111
		}
112
	}
113
114
	// payees
115
	pnames := make([]string, 0, len(a.Payees))
116
	for name := range a.Payees {
117
		pnames = append(pnames, name)
118
	}
119
	sort.Strings(pnames)
120
121
	fmt.Fprintf(w, "\npayees (%d):\n", len(a.Payees))
122
	for _, name := range pnames {
123
		info := a.Payees[name]
124
		fmt.Fprintf(w, "  %s\n", name)
125
		fmt.Fprintf(w, "    directives: %d\n", len(info.Directives))
126
		fmt.Fprintf(w, "    used: %d\n", info.UsedCount)
127
		for _, d := range info.Directives {
128
			fmt.Fprintf(w, "      payee %s\n", d.Name)
129
		}
130
		fmt.Fprintf(w, "    usages: %d\n", len(info.Usage))
131
		for _, u := range info.Usage {
132
			fmt.Fprintf(w, "      file %d: %s\n", u.FileIndex, u.Payee.Name)
133
		}
134
		if info.LastUsed.Year != 0 {
135
			fmt.Fprintf(w, "    last-used: %d-%02d-%02d\n", info.LastUsed.Year, info.LastUsed.Month, info.LastUsed.Day)
136
		}
137
	}
138
139
	// prefix index
140
	prefixes := make([]string, 0, len(a.AccountsByPrefix))
141
	for p := range a.AccountsByPrefix {
142
		prefixes = append(prefixes, p)
143
	}
144
	sort.Strings(prefixes)
145
	fmt.Fprintf(w, "\nprefixes (%d):\n", len(a.AccountsByPrefix))
146
	for _, p := range prefixes {
147
		names := a.AccountsByPrefix[p]
148
		sort.Strings(names)
149
		fmt.Fprintf(w, "  %s\n", p)
150
		for _, n := range names {
151
			fmt.Fprintf(w, "    %s\n", n)
152
		}
153
	}
154
155
	// typed entry counts
156
	fmt.Fprintf(w, "\ntransactions: %d\n", len(a.Transactions))
157
	fmt.Fprintf(w, "periodic transactions: %d\n", len(a.PeriodicTransactions))
158
	fmt.Fprintf(w, "automated transactions: %d\n", len(a.AutomatedTransactions))
159
160
	// directives
161
	fmt.Fprintf(w, "\ndirectives (%d):\n", len(a.Directives))
162
	for _, d := range a.Directives {
163
		switch d := d.(type) {
164
		case *ast.AccountDirective:
165
			fmt.Fprintf(w, "  account %s\n", d.Account.String())
166
		case *ast.CommodityDirective:
167
			fmt.Fprintf(w, "  commodity %s\n", d.Commodity)
168
		case *ast.PayeeDirective:
169
			fmt.Fprintf(w, "  payee %s\n", d.Name)
170
		case *ast.TagDirective:
171
			fmt.Fprintf(w, "  tag %s\n", d.Name)
172
		case *ast.IncludeDirective:
173
			fmt.Fprintf(w, "  include %s\n", d.Path)
174
		case *ast.AliasDirective:
175
			fmt.Fprintf(w, "  alias %s = %s\n", d.From.String(), d.To.String())
176
		case *ast.YearDirective:
177
			fmt.Fprintf(w, "  year %d\n", d.Year)
178
		case *ast.DecimalMarkDirective:
179
			fmt.Fprintf(w, "  decimal-mark %c\n", d.Mark)
180
		case *ast.DefaultCommodityDirective:
181
			fmt.Fprintf(w, "  D %s%s\n", d.Amount.Commodity, d.Amount.Quantity.String())
182
		case *ast.MarketPriceDirective:
183
			fmt.Fprintf(w, "  P %s %s\n", d.Commodity, d.Amount.Quantity.String())
184
		case *ast.ConversionDirective:
185
			fmt.Fprintf(w, "  C %s%s @@ %s%s\n", d.From.Commodity, d.From.Quantity.String(), d.To.Commodity, d.To.Quantity.String())
186
		case *ast.ApplyDirective:
187
			fmt.Fprintf(w, "  apply %s\n", d.Expr)
188
		case *ast.EndDirective:
189
			fmt.Fprintf(w, "  end %s\n", d.Expr)
190
		case *ast.CommentBlockDirective:
191
			fmt.Fprintf(w, "  comment\n")
192
		case *ast.IgnoredDirective:
193
			fmt.Fprintf(w, "  N %s\n", d.Text)
194
		}
195
	}
196
197
	// transaction duplicate keys
198
	keys := make([]string, 0, len(a.TransactionsByKey))
199
	for k := range a.TransactionsByKey {
200
		keys = append(keys, k)
201
	}
202
	sort.Strings(keys)
203
	fmt.Fprintf(w, "\ntransaction keys (%d):\n", len(a.TransactionsByKey))
204
	for _, k := range keys {
205
		txs := a.TransactionsByKey[k]
206
		if len(txs) > 1 {
207
			fmt.Fprintf(w, "  %s (dup: %d)\n", k, len(txs))
208
		} else {
209
			fmt.Fprintf(w, "  %s\n", k)
210
		}
211
	}
212
213
	// payee templates
214
	payeeNames := make([]string, 0, len(a.PayeeTemplates))
215
	for name := range a.PayeeTemplates {
216
		payeeNames = append(payeeNames, name)
217
	}
218
	sort.Strings(payeeNames)
219
	fmt.Fprintf(w, "\npayee templates (%d):\n", len(a.PayeeTemplates))
220
	for _, name := range payeeNames {
221
		templates := a.PayeeTemplates[name]
222
		fmt.Fprintf(w, "  %s\n", name)
223
		for _, t := range templates {
224
			fmt.Fprintf(w, "    %s", t.Account)
225
			if t.Amount != "" {
226
				fmt.Fprintf(w, "  %s%s", t.Commodity, t.Amount)
227
			}
228
			if t.IsInferred {
229
				fmt.Fprintf(w, " (inferred)")
230
			}
231
			fmt.Fprintln(w)
232
		}
233
	}
234
235
	// dates
236
	fmt.Fprintf(w, "\ndates (%d):\n", len(a.Dates))
237
	for _, d := range a.Dates {
238
		fmt.Fprintf(w, "  %d-%02d-%02d\n", d.Year, d.Month, d.Day)
239
	}
240
241
	// tag names
242
	fmt.Fprintf(w, "\ntag names (%d):\n", len(a.TagNames))
243
	for _, t := range a.TagNames {
244
		fmt.Fprintf(w, "  %s\n", t)
245
	}
246
247
	// commodity decimal marks
248
	csyms2 := make([]string, 0, len(a.CommodityDecimalMarks))
249
	for sym := range a.CommodityDecimalMarks {
250
		csyms2 = append(csyms2, sym)
251
	}
252
	sort.Strings(csyms2)
253
	fmt.Fprintf(w, "\ncommodity decimal marks (%d):\n", len(a.CommodityDecimalMarks))
254
	for _, sym := range csyms2 {
255
		fmt.Fprintf(w, "  %s: %c\n", sym, a.CommodityDecimalMarks[sym])
256
	}
257
}