gofront 1.7.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/README.md +14 -14
  2. package/package.json +10 -38
  3. package/src/backend/js/expressions.js +2060 -389
  4. package/src/backend/js/index.js +586 -174
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +936 -1644
  7. package/src/backend/js/statements.js +1349 -132
  8. package/src/backend/js/stdlib/index.js +51 -94
  9. package/src/backend/js/templ.js +67 -118
  10. package/src/backend/js/type-info.js +436 -0
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +80 -0
  13. package/src/backend/shared/host-unicode.js +36 -0
  14. package/src/backend/wasm/boundary.js +753 -872
  15. package/src/backend/wasm/emit-builtins.js +914 -237
  16. package/src/backend/wasm/emit-exprs.js +1456 -195
  17. package/src/backend/wasm/emit-maps.js +78 -380
  18. package/src/backend/wasm/emit-stmts.js +1659 -214
  19. package/src/backend/wasm/emit.js +614 -88
  20. package/src/backend/wasm/encode.js +43 -13
  21. package/src/backend/wasm/globals.js +491 -0
  22. package/src/backend/wasm/glue.js +2 -4
  23. package/src/backend/wasm/index.js +406 -3195
  24. package/src/backend/wasm/method-expr.js +392 -0
  25. package/src/backend/wasm/module-emitter.js +1615 -0
  26. package/src/backend/wasm/monomorph.js +164 -9
  27. package/src/backend/wasm/natives.js +596 -0
  28. package/src/backend/wasm/prescan.js +249 -0
  29. package/src/backend/wasm/prune-funcs.js +89 -0
  30. package/src/backend/wasm/stdlib/index.js +2 -37
  31. package/src/backend/wasm/stdlib/simd.js +293 -28
  32. package/src/backend/wasm/types.js +260 -27
  33. package/src/backend/wasm/variadic.js +93 -0
  34. package/src/backend/wasm/wat.js +47 -20
  35. package/src/{cli-core.js → cli/cli-core.js} +241 -11
  36. package/src/{test-runner.js → cli/test-runner.js} +188 -122
  37. package/src/{vendor.js → cli/vendor.js} +3 -4
  38. package/src/compiler.js +202 -386
  39. package/src/index.js +15 -169
  40. package/src/{lexer.js → lexer/lexer.js} +203 -62
  41. package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
  42. package/src/{tokens.js → lexer/tokens.js} +2 -0
  43. package/src/link/sourcemap.js +97 -0
  44. package/src/link/stdlib.js +737 -0
  45. package/src/link/type-names.js +148 -0
  46. package/src/link/wasm.js +318 -0
  47. package/src/lower/bounds.js +547 -0
  48. package/src/lower/boxing.js +1 -1
  49. package/src/lower/captures.js +267 -64
  50. package/src/lower/embedding.js +32 -3
  51. package/src/lower/errors-as.js +196 -0
  52. package/src/lower/fmt-formatters.js +905 -0
  53. package/src/lower/functions.js +2 -0
  54. package/src/lower/gen-types.js +274 -0
  55. package/src/lower/index.js +33 -19
  56. package/src/lower/json-codecs.js +1379 -0
  57. package/src/lower/ownership.js +47 -8
  58. package/src/lower/range.js +86 -1
  59. package/src/lower/reachability.js +150 -0
  60. package/src/lower/walk.js +12 -0
  61. package/src/parser/declarations.js +83 -15
  62. package/src/parser/expressions.js +110 -18
  63. package/src/parser/index.js +2 -1
  64. package/src/parser/statements.js +38 -22
  65. package/src/{templ-parser.js → parser/templ.js} +179 -17
  66. package/src/parser/types.js +70 -9
  67. package/src/resolver.js +21 -1
  68. package/src/typechecker/assignability.js +291 -19
  69. package/src/typechecker/const-fold.js +399 -0
  70. package/src/typechecker/constants.js +282 -0
  71. package/src/typechecker/expressions.js +1220 -183
  72. package/src/typechecker/index.js +659 -92
  73. package/src/typechecker/init-order.js +426 -0
  74. package/src/typechecker/operand-text.js +40 -0
  75. package/src/typechecker/resolve.js +613 -62
  76. package/src/typechecker/statements.js +212 -20
  77. package/src/typechecker/stdlib/excluded.js +902 -0
  78. package/src/typechecker/stdlib/index.js +38 -0
  79. package/src/typechecker/stdlib/simd.js +65 -15
  80. package/src/typechecker/termination.js +11 -2
  81. package/src/typechecker/types.js +268 -514
  82. package/stdlib/bytes/buffer.go +479 -0
  83. package/stdlib/bytes/bytes.go +1010 -0
  84. package/stdlib/bytes/reader.go +161 -0
  85. package/stdlib/cmp/cmp.go +65 -0
  86. package/stdlib/context/context.go +115 -0
  87. package/stdlib/crypto/rand/rand.go +34 -0
  88. package/stdlib/crypto/sha256/sha256.go +249 -0
  89. package/stdlib/encoding/base64/base64.go +331 -0
  90. package/stdlib/encoding/binary/binary.go +332 -0
  91. package/stdlib/encoding/hex/hex.go +140 -0
  92. package/stdlib/encoding/json/errors.go +31 -0
  93. package/stdlib/encoding/json/indent.go +71 -0
  94. package/stdlib/encoding/json/json.go +62 -0
  95. package/stdlib/encoding/json/number.go +12 -0
  96. package/stdlib/encoding/json/stream.go +173 -0
  97. package/stdlib/errors/errors.go +174 -0
  98. package/stdlib/fmt/errors.go +110 -0
  99. package/stdlib/fmt/format.go +732 -0
  100. package/stdlib/fmt/print.go +1232 -0
  101. package/stdlib/gom/gom.go +293 -0
  102. package/stdlib/hash/hash.go +53 -0
  103. package/stdlib/html/html.go +251 -0
  104. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  105. package/stdlib/internal/jsonrt/dec.go +871 -0
  106. package/stdlib/internal/jsonrt/enc.go +516 -0
  107. package/stdlib/internal/jsonrt/indent.go +135 -0
  108. package/stdlib/internal/jsonrt/number.go +27 -0
  109. package/stdlib/internal/jsonrt/reader.go +73 -0
  110. package/stdlib/internal/jsonrt/scanner.go +658 -0
  111. package/stdlib/io/io.go +502 -0
  112. package/stdlib/iter/iter.go +18 -0
  113. package/stdlib/maps/maps.go +131 -0
  114. package/stdlib/math/bits/bits.go +507 -0
  115. package/stdlib/math/extra.go +272 -0
  116. package/stdlib/math/math.go +439 -0
  117. package/stdlib/math/rand/rand.go +297 -0
  118. package/stdlib/os/os.go +93 -0
  119. package/stdlib/path/filepath/filepath.go +47 -0
  120. package/stdlib/path/path.go +394 -0
  121. package/stdlib/regexp/regexp.go +231 -0
  122. package/stdlib/slices/slices.go +526 -0
  123. package/stdlib/slices/sort.go +209 -0
  124. package/stdlib/slices/zsort_cmp.go +480 -0
  125. package/stdlib/slices/zsort_ordered.go +482 -0
  126. package/stdlib/sort/sort.go +500 -0
  127. package/stdlib/sort/zsort_func.go +480 -0
  128. package/stdlib/sort/zsort_iface.go +480 -0
  129. package/stdlib/strconv/float.go +1699 -0
  130. package/stdlib/strconv/isprint.go +752 -0
  131. package/stdlib/strconv/quote.go +526 -0
  132. package/stdlib/strconv/strconv.go +616 -0
  133. package/stdlib/strings/builder.go +95 -0
  134. package/stdlib/strings/reader.go +163 -0
  135. package/stdlib/strings/replacer.go +102 -0
  136. package/stdlib/strings/strings.go +807 -0
  137. package/stdlib/sync/sync.go +268 -0
  138. package/stdlib/testing/async_js.go +61 -0
  139. package/stdlib/testing/benchmark.go +297 -0
  140. package/stdlib/testing/testing.go +523 -0
  141. package/stdlib/time/duration.go +233 -0
  142. package/stdlib/time/format.go +745 -0
  143. package/stdlib/time/parse.go +790 -0
  144. package/stdlib/time/sleep_js.go +63 -0
  145. package/stdlib/time/time.go +834 -0
  146. package/stdlib/unicode/unicode.go +250 -0
  147. package/stdlib/unicode/utf8/utf8.go +464 -0
  148. package/src/backend/js/stdlib/base64.js +0 -12
  149. package/src/backend/js/stdlib/binary.js +0 -102
  150. package/src/backend/js/stdlib/bits.js +0 -46
  151. package/src/backend/js/stdlib/builder.js +0 -63
  152. package/src/backend/js/stdlib/bytes.js +0 -122
  153. package/src/backend/js/stdlib/errors.js +0 -44
  154. package/src/backend/js/stdlib/fmt.js +0 -178
  155. package/src/backend/js/stdlib/gom.js +0 -155
  156. package/src/backend/js/stdlib/hex.js +0 -17
  157. package/src/backend/js/stdlib/html.js +0 -20
  158. package/src/backend/js/stdlib/io.js +0 -137
  159. package/src/backend/js/stdlib/json.js +0 -972
  160. package/src/backend/js/stdlib/maps.js +0 -45
  161. package/src/backend/js/stdlib/math.js +0 -69
  162. package/src/backend/js/stdlib/os.js +0 -13
  163. package/src/backend/js/stdlib/path.js +0 -48
  164. package/src/backend/js/stdlib/rand.js +0 -32
  165. package/src/backend/js/stdlib/regexp.js +0 -54
  166. package/src/backend/js/stdlib/sha256.js +0 -12
  167. package/src/backend/js/stdlib/shared.js +0 -17
  168. package/src/backend/js/stdlib/simd.js +0 -24
  169. package/src/backend/js/stdlib/slices.js +0 -77
  170. package/src/backend/js/stdlib/sort.js +0 -30
  171. package/src/backend/js/stdlib/strconv.js +0 -74
  172. package/src/backend/js/stdlib/strings.js +0 -222
  173. package/src/backend/js/stdlib/sync.js +0 -13
  174. package/src/backend/js/stdlib/testing.js +0 -34
  175. package/src/backend/js/stdlib/time.js +0 -128
  176. package/src/backend/js/stdlib/unicode.js +0 -25
  177. package/src/backend/js/stdlib/utf8.js +0 -26
  178. package/src/backend/wasm/const-fold.js +0 -205
  179. package/src/backend/wasm/emit-stdlib.js +0 -13
  180. package/src/backend/wasm/stdlib/bytes.js +0 -5039
  181. package/src/backend/wasm/stdlib/core.js +0 -8903
  182. package/src/backend/wasm/stdlib/io.js +0 -2161
  183. package/src/backend/wasm/stdlib/packages.js +0 -2400
  184. package/src/backend/wasm/stdlib/pure.js +0 -720
  185. package/src/backend/wasm/stdlib/time.js +0 -1200
  186. package/src/typechecker/stdlib/core.js +0 -801
  187. package/src/typechecker/stdlib/extended.js +0 -914
  188. package/src/typechecker/stdlib.js +0 -22
  189. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  190. /package/src/{colors.js → cli/colors.js} +0 -0
  191. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  192. /package/src/{minifier.js → cli/minifier.js} +0 -0
  193. /package/src/{project-config.js → cli/project-config.js} +0 -0
  194. /package/src/{pwa.js → cli/pwa.js} +0 -0
@@ -0,0 +1,523 @@
1
+ //go:build gofront
2
+
3
+ //gofront:target both
4
+
5
+ // Package testing provides support for automated testing of Go packages.
6
+ //
7
+ // Tests and benchmarks run inside the compiled package, on either target: a
8
+ // generated driver (the runner writes it in memory next to the _test.go
9
+ // files) builds the tests table, calls GofrontMain and runs it. Output
10
+ // follows `go test`: "=== RUN", "--- PASS/FAIL/SKIP" lines, indented t.Log
11
+ // output, and a PASS or FAIL trailer with the package line.
12
+ //
13
+ // Tests run one at a time. Parallel, Helper, Attr and the allocation
14
+ // counters are accepted and do nothing.
15
+ package testing
16
+
17
+ import (
18
+ "context"
19
+ "fmt"
20
+ "io"
21
+ "os"
22
+ "strings"
23
+ "time"
24
+ )
25
+
26
+ // nanotime returns a monotonic clock reading in nanoseconds.
27
+ //
28
+ //gofront:intrinsic testing_nanotime
29
+ func nanotime() int64
30
+
31
+ // match reports whether the regular expression pattern matches s anywhere.
32
+ //
33
+ //gofront:intrinsic testing_match
34
+ func match(pattern, s string) bool
35
+
36
+ // TB is the interface common to T and B.
37
+ type TB interface {
38
+ Attr(key, value string)
39
+ Cleanup(func())
40
+ Context() context.Context
41
+ Error(args ...any)
42
+ Errorf(format string, args ...any)
43
+ Fail()
44
+ FailNow()
45
+ Failed() bool
46
+ Fatal(args ...any)
47
+ Fatalf(format string, args ...any)
48
+ Helper()
49
+ Log(args ...any)
50
+ Logf(format string, args ...any)
51
+ Name() string
52
+ Output() io.Writer
53
+ Setenv(key, value string)
54
+ Skip(args ...any)
55
+ SkipNow()
56
+ Skipf(format string, args ...any)
57
+ Skipped() bool
58
+ }
59
+
60
+ // sentinel is what FailNow and SkipNow panic with; the test runner swallows
61
+ // it.
62
+ type sentinel struct {
63
+ name string
64
+ }
65
+
66
+ var (
67
+ failNowSentinel = &sentinel{"FailNow"}
68
+ skipNowSentinel = &sentinel{"SkipNow"}
69
+ )
70
+
71
+ // settings are the flags of the current run, set by GofrontMain. They sit
72
+ // behind a pointer because a package for both targets may not assign its
73
+ // package-level variables.
74
+ type settings struct {
75
+ verbose bool
76
+ color bool
77
+ pats []string
78
+ }
79
+
80
+ var cfg = &settings{}
81
+
82
+ func (s *settings) set(verbose, color bool, run string) {
83
+ s.verbose = verbose
84
+ s.color = color
85
+ s.pats = nil
86
+ if run != "" {
87
+ s.pats = strings.Split(run, "/")
88
+ }
89
+ }
90
+
91
+ // Short reports whether the -short flag is set. It never is.
92
+ func Short() bool { return false }
93
+
94
+ // Verbose reports whether the -v flag is set.
95
+ func Verbose() bool { return cfg.verbose }
96
+
97
+ // Testing reports whether the program is a test binary. It always is.
98
+ func Testing() bool { return true }
99
+
100
+ // Init registers testing flags. There are none.
101
+ func Init() {}
102
+
103
+ func paint(code, s string) string {
104
+ if !cfg.color {
105
+ return s
106
+ }
107
+ return "\x1b[" + code + "m" + s + "\x1b[0m"
108
+ }
109
+
110
+ func red(s string) string { return paint("31", s) }
111
+ func green(s string) string { return paint("32", s) }
112
+ func yellow(s string) string { return paint("33", s) }
113
+ func dim(s string) string { return paint("2", s) }
114
+ func bold(s string) string { return paint("1", s) }
115
+
116
+ func say(s string) {
117
+ os.Stdout.WriteString(s + "\n")
118
+ }
119
+
120
+ // pendingSub is a subtest whose body returned a promise (js packages).
121
+ type pendingSub struct {
122
+ sub *T
123
+ res any
124
+ }
125
+
126
+ // common holds the state shared by T and B.
127
+ type common struct {
128
+ name string
129
+ logs []string
130
+ failed bool
131
+ skipped bool
132
+ parent *common
133
+ cleanups []func()
134
+ start int64
135
+ ctx context.Context
136
+ cancelCtx func()
137
+ pending []pendingSub
138
+ }
139
+
140
+ // T is a type passed to Test functions to manage test state and support
141
+ // formatted test logs.
142
+ type T struct {
143
+ common
144
+ }
145
+
146
+ func (c *common) Name() string { return c.name }
147
+
148
+ // Fail marks the function as having failed but continues execution.
149
+ func (c *common) Fail() {
150
+ c.failed = true
151
+ if c.parent != nil {
152
+ c.parent.Fail()
153
+ }
154
+ }
155
+
156
+ // Failed reports whether the function has failed.
157
+ func (c *common) Failed() bool { return c.failed }
158
+
159
+ // FailNow marks the function as having failed and stops its execution.
160
+ func (c *common) FailNow() {
161
+ c.Fail()
162
+ panic(failNowSentinel)
163
+ }
164
+
165
+ func (c *common) log(s string) {
166
+ c.logs = append(c.logs, s)
167
+ }
168
+
169
+ func sprintln(args []any) string {
170
+ s := fmt.Sprintln(args...)
171
+ return s[:len(s)-1]
172
+ }
173
+
174
+ // Log formats its arguments using default formatting, analogous to Println,
175
+ // and records the text in the error log.
176
+ func (c *common) Log(args ...any) { c.log(sprintln(args)) }
177
+
178
+ // Logf formats its arguments according to the format, analogous to Printf.
179
+ func (c *common) Logf(format string, args ...any) { c.log(fmt.Sprintf(format, args...)) }
180
+
181
+ // Error is equivalent to Log followed by Fail.
182
+ func (c *common) Error(args ...any) {
183
+ c.Log(args...)
184
+ c.Fail()
185
+ }
186
+
187
+ // Errorf is equivalent to Logf followed by Fail.
188
+ func (c *common) Errorf(format string, args ...any) {
189
+ c.Logf(format, args...)
190
+ c.Fail()
191
+ }
192
+
193
+ // Fatal is equivalent to Log followed by FailNow.
194
+ func (c *common) Fatal(args ...any) {
195
+ c.Log(args...)
196
+ c.FailNow()
197
+ }
198
+
199
+ // Fatalf is equivalent to Logf followed by FailNow.
200
+ func (c *common) Fatalf(format string, args ...any) {
201
+ c.Logf(format, args...)
202
+ c.FailNow()
203
+ }
204
+
205
+ // SkipNow marks the test as having been skipped and stops its execution.
206
+ func (c *common) SkipNow() {
207
+ c.skipped = true
208
+ panic(skipNowSentinel)
209
+ }
210
+
211
+ // Skip is equivalent to Log followed by SkipNow.
212
+ func (c *common) Skip(args ...any) {
213
+ c.Log(args...)
214
+ c.SkipNow()
215
+ }
216
+
217
+ // Skipf is equivalent to Logf followed by SkipNow.
218
+ func (c *common) Skipf(format string, args ...any) {
219
+ c.Logf(format, args...)
220
+ c.SkipNow()
221
+ }
222
+
223
+ // Skipped reports whether the test was skipped.
224
+ func (c *common) Skipped() bool { return c.skipped }
225
+
226
+ // Helper marks the calling function as a test helper function.
227
+ func (c *common) Helper() {}
228
+
229
+ // Attr emits a test attribute. It is not recorded.
230
+ func (c *common) Attr(key, value string) {}
231
+
232
+ // Output returns a Writer that writes to the standard output.
233
+ func (c *common) Output() io.Writer { return os.Stdout }
234
+
235
+ // Cleanup registers a function to be called when the test completes.
236
+ // Cleanup functions are called last added, first called.
237
+ func (c *common) Cleanup(f func()) {
238
+ c.cleanups = append(c.cleanups, f)
239
+ }
240
+
241
+ // Setenv calls os.Setenv(key, value) and uses Cleanup to restore the
242
+ // environment variable to its original value after the test.
243
+ func (c *common) Setenv(key, value string) {
244
+ prev := os.Getenv(key)
245
+ os.Setenv(key, value)
246
+ c.Cleanup(func() { os.Setenv(key, prev) })
247
+ }
248
+
249
+ // Context returns a context that is canceled just before Cleanup-registered
250
+ // functions are called.
251
+ func (c *common) Context() context.Context {
252
+ if c.ctx == nil {
253
+ ctx, cancel := context.WithCancel(context.Background())
254
+ c.ctx = ctx
255
+ c.cancelCtx = cancel
256
+ }
257
+ return c.ctx
258
+ }
259
+
260
+ // Guard is deferred around a test body: it turns a panic into a failed test
261
+ // and swallows the panics FailNow and SkipNow raise. The generated driver
262
+ // uses it; tests do not call it.
263
+ func (c *common) Guard() {
264
+ r := recover()
265
+ if r == nil {
266
+ return
267
+ }
268
+ if s, ok := r.(*sentinel); ok && (s == failNowSentinel || s == skipNowSentinel) {
269
+ return
270
+ }
271
+ c.Fail()
272
+ c.log("panic: " + fmt.Sprint(r))
273
+ }
274
+
275
+ // runCleanups calls the cleanup functions, last added first. A panic in one
276
+ // fails the test.
277
+ func (c *common) runCleanups() {
278
+ if c.cancelCtx != nil {
279
+ c.cancelCtx()
280
+ c.cancelCtx = nil
281
+ }
282
+ for len(c.cleanups) > 0 {
283
+ n := len(c.cleanups) - 1
284
+ f := c.cleanups[n]
285
+ c.cleanups = c.cleanups[:n]
286
+ c.runCleanup(f)
287
+ }
288
+ }
289
+
290
+ func (c *common) runCleanup(f func()) {
291
+ defer func() {
292
+ r := recover()
293
+ if r == nil {
294
+ return
295
+ }
296
+ if s, ok := r.(*sentinel); ok && (s == failNowSentinel || s == skipNowSentinel) {
297
+ return
298
+ }
299
+ c.Fail()
300
+ c.log("panic in cleanup: " + fmt.Sprint(r))
301
+ }()
302
+ f()
303
+ }
304
+
305
+ // Deadline reports the time at which the test binary will have exceeded the
306
+ // timeout. There is never one.
307
+ func (c *common) Deadline() (deadline time.Time, ok bool) {
308
+ return
309
+ }
310
+
311
+ // Parallel does nothing: tests run one at a time.
312
+ func (t *T) Parallel() {}
313
+
314
+ // selected reports whether the -run patterns let the test with this full
315
+ // name run: each slash-separated element is matched at its level.
316
+ func selected(full string) bool {
317
+ runPats := cfg.pats
318
+ if len(runPats) == 0 {
319
+ return true
320
+ }
321
+ elems := strings.Split(full, "/")
322
+ for i, e := range elems {
323
+ if i < len(runPats) && !match(runPats[i], e) {
324
+ return false
325
+ }
326
+ }
327
+ return true
328
+ }
329
+
330
+ // elapsed is the seconds since the test started, as Go prints it.
331
+ func (c *common) elapsed() string {
332
+ return dim(fmt.Sprintf("(%.2fs)", float64(nanotime()-c.start)/1e9))
333
+ }
334
+
335
+ func (c *common) printLogs(paintLog func(string) string) {
336
+ for _, l := range c.logs {
337
+ lines := strings.Split(l, "\n")
338
+ for i, line := range lines {
339
+ if i == 0 {
340
+ say(" " + paintLog(line))
341
+ } else {
342
+ say(" " + paintLog(line))
343
+ }
344
+ }
345
+ }
346
+ }
347
+
348
+ func plain(s string) string { return s }
349
+
350
+ // begin announces the test (always when verbose; failing tests announce
351
+ // themselves when they report).
352
+ func (c *common) begin() {
353
+ c.start = nanotime()
354
+ if cfg.verbose {
355
+ say(dim("=== RUN ") + c.name)
356
+ }
357
+ }
358
+
359
+ // report prints what a finished test produced.
360
+ func (c *common) report() {
361
+ switch {
362
+ case c.failed:
363
+ if !cfg.verbose {
364
+ say(dim("=== RUN ") + c.name)
365
+ }
366
+ c.printLogs(red)
367
+ say("--- " + bold(red("FAIL")) + ": " + c.name + " " + c.elapsed())
368
+ case c.skipped:
369
+ say("--- " + yellow("SKIP") + ": " + c.name + " " + c.elapsed())
370
+ c.printLogs(plain)
371
+ case cfg.verbose:
372
+ c.printLogs(plain)
373
+ say("--- " + green("PASS") + ": " + c.name + " " + c.elapsed())
374
+ }
375
+ }
376
+
377
+ // finish runs the cleanups and reports.
378
+ func (c *common) finish() {
379
+ c.runCleanups()
380
+ c.report()
381
+ }
382
+
383
+ // callHook calls a test body and returns what it returned, so a js package
384
+ // can wait for an async body (async_js.go). Without it a body is called
385
+ // directly.
386
+ var callHook func(f func(*T), t *T) any
387
+
388
+ // invoke runs the body of a test, turning a panic into a failure.
389
+ func (t *T) invoke(f func(*T)) any {
390
+ defer t.Guard()
391
+ if callHook != nil {
392
+ return callHook(f, t)
393
+ }
394
+ f(t)
395
+ return nil
396
+ }
397
+
398
+ // Run runs f as a subtest of t called name. It reports whether f succeeded
399
+ // (or has not finished yet, for an async subtest of a js package).
400
+ func (t *T) Run(name string, f func(t *T)) bool {
401
+ full := name
402
+ if t.name != "" {
403
+ full = t.name + "/" + name
404
+ }
405
+ if !selected(full) {
406
+ return true
407
+ }
408
+ sub := &T{common: common{name: full, parent: &t.common}}
409
+ sub.begin()
410
+ if res := sub.invoke(f); res != nil {
411
+ t.pending = append(t.pending, pendingSub{sub, res})
412
+ return true
413
+ }
414
+ sub.finish()
415
+ return !sub.failed
416
+ }
417
+
418
+ // GofrontTest is an entry of the generated driver's table of tests.
419
+ type GofrontTest struct {
420
+ Name string
421
+ F func(*T)
422
+ }
423
+
424
+ // GofrontBenchmark is an entry of the generated driver's table of
425
+ // benchmarks.
426
+ type GofrontBenchmark struct {
427
+ Name string
428
+ F func(*B)
429
+ }
430
+
431
+ // M is a type passed to a TestMain function to run the actual tests.
432
+ type M struct {
433
+ pkg string
434
+ run, bench string
435
+ tests []GofrontTest
436
+ benches []GofrontBenchmark
437
+ failures int
438
+ startedAt int64
439
+ exit int
440
+ ran bool
441
+ }
442
+
443
+ // GofrontMain makes the M the generated driver runs: the package's name, the
444
+ // -run and -bench patterns, -v, and the package's tests and benchmarks. The
445
+ // GOFRONT_TEST_LABEL and GOFRONT_TEST_COLOR environment variables name the
446
+ // package in the summary line and turn on colour.
447
+ func GofrontMain(pkg, run, bench string, v bool, tests []GofrontTest, benches []GofrontBenchmark) *M {
448
+ cfg.set(v, os.Getenv("GOFRONT_TEST_COLOR") == "1", run)
449
+ if label := os.Getenv("GOFRONT_TEST_LABEL"); label != "" {
450
+ pkg = label
451
+ }
452
+ return &M{pkg: pkg, run: run, bench: bench, tests: tests, benches: benches}
453
+ }
454
+
455
+ // ExitCode is the status the test binary exits with once TestMain returns:
456
+ // the result of Run, or 0 when TestMain never called it.
457
+ func (m *M) ExitCode() int { return m.exit }
458
+
459
+ // plan returns the tests and benchmarks the patterns select, and warns when
460
+ // there are none.
461
+ func (m *M) plan() ([]GofrontTest, []GofrontBenchmark) {
462
+ m.startedAt = nanotime()
463
+ m.ran = true
464
+ var tests []GofrontTest
465
+ for _, tt := range m.tests {
466
+ if selected(tt.Name) {
467
+ tests = append(tests, tt)
468
+ }
469
+ }
470
+ var benches []GofrontBenchmark
471
+ if m.bench != "" {
472
+ for _, bb := range m.benches {
473
+ if match(m.bench, bb.Name) {
474
+ benches = append(benches, bb)
475
+ }
476
+ }
477
+ }
478
+ if len(tests) == 0 && len(benches) == 0 {
479
+ if len(m.tests) > 0 && m.run != "" {
480
+ say(yellow(fmt.Sprintf("testing: warning: no tests to run matching %q", m.run)))
481
+ }
482
+ if len(m.benches) > 0 && m.bench != "" {
483
+ say(yellow(fmt.Sprintf("testing: warning: no benchmarks to run matching %q", m.bench)))
484
+ }
485
+ }
486
+ return tests, benches
487
+ }
488
+
489
+ // conclude prints the trailer and the package line and returns the exit
490
+ // code.
491
+ func (m *M) conclude() int {
492
+ secs := dim(fmt.Sprintf("%.3fs", float64(nanotime()-m.startedAt)/1e9))
493
+ code := 0
494
+ if m.failures > 0 {
495
+ say(bold(red("FAIL")))
496
+ say(bold(red("FAIL")) + "\t" + m.pkg + "\t" + secs)
497
+ code = 1
498
+ } else {
499
+ say(green("PASS"))
500
+ say(green("ok ") + "\t" + m.pkg + "\t" + secs)
501
+ }
502
+ m.exit = code
503
+ return code
504
+ }
505
+
506
+ // Run runs the tests, then the selected benchmarks, and returns the exit
507
+ // code: 0 when everything passed.
508
+ func (m *M) Run() int {
509
+ tests, benches := m.plan()
510
+ for _, tt := range tests {
511
+ t := &T{common: common{name: tt.Name}}
512
+ t.begin()
513
+ t.invoke(tt.F)
514
+ t.finish()
515
+ if t.failed {
516
+ m.failures++
517
+ }
518
+ }
519
+ for _, bb := range benches {
520
+ m.runBenchmark(bb)
521
+ }
522
+ return m.conclude()
523
+ }