gofront 1.8.0 → 1.9.1
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.
- package/README.md +3 -3
- package/package.json +6 -5
- package/src/backend/js/expressions.js +1157 -408
- package/src/backend/js/index.js +327 -153
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +559 -2552
- package/src/backend/js/statements.js +670 -158
- package/src/backend/js/stdlib/index.js +45 -93
- package/src/backend/js/templ.js +32 -45
- package/src/backend/js/type-info.js +298 -19
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +91 -170
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +490 -965
- package/src/backend/wasm/emit-builtins.js +884 -256
- package/src/backend/wasm/emit-exprs.js +185 -77
- package/src/backend/wasm/emit-maps.js +17 -367
- package/src/backend/wasm/emit-shared.js +4 -1
- package/src/backend/wasm/emit-stmts.js +524 -240
- package/src/backend/wasm/emit.js +176 -38
- package/src/backend/wasm/globals.js +48 -8
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +44 -530
- package/src/backend/wasm/method-expr.js +12 -1
- package/src/backend/wasm/module-emitter.js +299 -770
- package/src/backend/wasm/monomorph.js +139 -8
- package/src/backend/wasm/natives.js +600 -0
- package/src/backend/wasm/prescan.js +5 -153
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -32
- package/src/backend/wasm/types.js +97 -20
- package/src/backend/wasm/variadic.js +9 -4
- package/src/cli/cli-core.js +5 -1
- package/src/cli/test-runner.js +115 -342
- package/src/compiler.js +113 -130
- package/src/lexer/lexer.js +106 -11
- package/src/lexer/templ-lexer.js +61 -18
- package/src/lexer/tokens.js +1 -0
- package/src/link/stdlib.js +355 -132
- package/src/link/type-names.js +204 -0
- package/src/link/wasm.js +30 -6
- package/src/lower/bounds.js +153 -0
- package/src/lower/captures.js +92 -33
- package/src/lower/embedding.js +62 -5
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +929 -0
- package/src/lower/functions.js +225 -7
- package/src/lower/gen-types.js +293 -0
- package/src/lower/index.js +14 -2
- package/src/lower/json-codecs.js +334 -245
- package/src/lower/ownership.js +25 -7
- package/src/lower/reachability.js +69 -51
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +30 -5
- package/src/parser/expressions.js +111 -57
- package/src/parser/statements.js +108 -0
- package/src/parser/templ.js +44 -5
- package/src/parser/types.js +12 -0
- package/src/resolver.js +1 -2
- package/src/typechecker/assignability.js +214 -19
- package/src/typechecker/const-fold.js +70 -27
- package/src/typechecker/constants.js +156 -8
- package/src/typechecker/expressions.js +490 -108
- package/src/typechecker/index.js +346 -42
- package/src/typechecker/init-order.js +136 -40
- package/src/typechecker/operand-text.js +41 -0
- package/src/typechecker/resolve.js +490 -65
- package/src/typechecker/statements.js +288 -27
- package/src/typechecker/stdlib/excluded.js +9 -5
- package/src/typechecker/stdlib/index.js +25 -9
- package/src/typechecker/termination.js +10 -1
- package/src/typechecker/types.js +287 -575
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +171 -38
- package/stdlib/internal/jsonrt/enc.go +186 -36
- package/stdlib/internal/jsonrt/scanner.go +17 -8
- package/stdlib/io/io.go +157 -1
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +16 -14
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +391 -452
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +235 -50
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +141 -3
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/fmt-runtime.js +0 -573
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -119
- package/src/backend/js/stdlib/builder.js +0 -98
- package/src/backend/js/stdlib/bytes.js +0 -368
- package/src/backend/js/stdlib/errors.js +0 -45
- package/src/backend/js/stdlib/fmt.js +0 -517
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -1167
- package/src/backend/js/stdlib/maps.js +0 -37
- package/src/backend/js/stdlib/math.js +0 -85
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -34
- package/src/backend/js/stdlib/slices.js +0 -107
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -79
- package/src/backend/js/stdlib/strings.js +0 -301
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -41
- package/src/backend/js/stdlib/time.js +0 -152
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/stdlib/bytes.js +0 -6716
- package/src/backend/wasm/stdlib/core.js +0 -10278
- package/src/backend/wasm/stdlib/io.js +0 -3578
- package/src/backend/wasm/stdlib/packages.js +0 -2402
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -2229
- package/src/typechecker/stdlib/core.js +0 -1079
- package/src/typechecker/stdlib/extended.js +0 -1210
- package/stdlib/bytes/iter.go +0 -192
- package/stdlib/bytes/search.go +0 -240
- package/stdlib/bytes/split.go +0 -218
- package/stdlib/errors/overlay.go +0 -12
- package/stdlib/maps/iter.go +0 -65
- package/stdlib/slices/extra.go +0 -73
- package/stdlib/slices/iter.go +0 -113
- package/stdlib/strings/extra.go +0 -35
- package/stdlib/strings/iter.go +0 -122
- package/stdlib/sync/extra.go +0 -105
- package/stdlib/unicode/utf8/bytes.go +0 -239
|
@@ -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
|
+
}
|