Skip to content

Commit 337529b

Browse files
1 parent 368167c commit 337529b

File tree

6 files changed

+78
-29
lines changed

6 files changed

+78
-29
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,15 @@ be.NilErr(t, err) // bad
5353
be.Nonzero(t, err) // good
5454
```
5555

56-
Check substring containment:
56+
Check for regexp matching:
5757

5858
```go
59-
be.In(t, "world", "hello, world") // good
60-
be.In(t, "World", "hello, world") // bad
61-
// t.Fatal("World" not in "hello, world")
62-
be.NotIn(t, "\x01", []byte("\a\b\x00\r\t")) // good
63-
be.NotIn(t, "\x00", []byte("\a\b\x00\r\t")) // bad
64-
// t.Fatal("\x00" in "\a\b\x00\r\t")
59+
be.Match(t, `world`, "hello, world") // good
60+
be.Match(t, `World`, "hello, world") // bad
61+
// t.Fatal(`/World/ !~ "hello, world"`)
62+
be.Match(t, `^\W*$`, []byte("\a\b\x00\r\t")) // good
63+
be.Match(t, `^\W*$`, []byte("\a\bo\r\t")) // bad
64+
// t.Fatal(`/^\W*$/ !~ "\a\bo\r\t"`)
6565
```
6666

6767
Check how long something rangeable is:
@@ -80,7 +80,7 @@ Test anything else:
8080

8181
```go
8282
be.True(t, o.IsValid())
83-
be.True(t, len(pages) >= 20)
83+
be.False(t, s.CanParse())
8484
```
8585

8686
Test using goldenfiles:
@@ -108,7 +108,7 @@ testfile.Run(t, "testdata/*.txt", func(t *testing.T, path string) {
108108
## Philosophy
109109
Tests usually should not fail. When they do fail, the failure should be repeatable. Therefore, it doesn't make sense to spend a lot of time writing good test messages. (This is unlike error messages, which should happen fairly often, and in production, irrepeatably.) Package be is designed to simply fail a test quickly and quietly if a condition is not met with a reference to the line number of the failing test. If the reason for having the test is not immediately clear from context, you can write a comment, just like in normal code. If you do need more extensive reporting to figure out why a test is failing, use `be.DebugLog` or `be.Debug` to capture more information.
110110

111-
Most tests just need simple equality testing, which is handled by `be.Equal` (for comparable types), `be.AllEqual` (for slices of comparable types), and `be.DeepEqual` (which relies on `reflect.DeepEqual`). Another common test is that a string or byte slice should contain or not some substring, which is handled by `be.In` and `be.NotIn`. Rather than package be providing every possible test helper, you are encouraged to write your own advanced helpers for use with `be.True`, while package be takes away the drudgery of writing yet another simple `func nilErr(t *testing.T, err) { ... }`.
111+
Most tests just need simple equality testing, which is handled by `be.Equal` (for comparable types), `be.AllEqual` (for slices of comparable types), and `be.DeepEqual` (which relies on `reflect.DeepEqual`). Another common test is that a string or byte slice should match some pattern, which is handled by `be.Match`. Rather than package be providing every possible test helper, you are encouraged to write your own advanced helpers for use with `be.True`, while package be takes away the drudgery of writing yet another simple `func nilErr(t *testing.T, err) { ... }`.
112112

113113
The testfile subpackage has functions that make it easy to write file-based tests that ensure that the output of some transformation matches a [golden file](https://softwareengineering.stackexchange.com/questions/358786/what-are-golden-files). Subtests can automatically be run for all files matching a glob pattern, such as `testfile.Run(t, "testdata/*/input.txt", ...)`. If the test fails, the failure output will be written to a file, such as "testdata/basic-test/-failed-output.txt", and then the output can be examined via diff testing with standard tools. Set the environmental variable `TESTFILE_UPDATE` to update the golden file.
114114

be_example_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ func Example() {
3535

3636
type mytype string
3737
var mystring mytype = "hello, world"
38-
be.In(t, "world", mystring) // good
39-
be.In(t, "World", mystring) // bad
40-
be.NotIn(t, "\x01", []byte("\a\b\x00\r\t")) // good
41-
be.NotIn(t, "\x00", []byte("\a\b\x00\r\t")) // bad
38+
be.Match(t, `world`, mystring) // good
39+
be.Match(t, `World`, mystring) // bad
40+
be.Match(t, `^\W*$`, []byte("\a\b\x00\r\t")) // good
41+
be.Match(t, `^\W*$`, []byte("\a\bo\r\t")) // bad
4242

4343
seq := strings.FieldsSeq("1 2 3 4")
4444
be.EqualLength(t, 4, seq) // good
@@ -55,8 +55,8 @@ func Example() {
5555
// got: <nil>
5656
// got errors.Is(<nil>, permission denied) == false
5757
// got errors.As((O_o), **fs.PathError) == false
58-
// "World" not in "hello, world"
59-
// "\x00" in "\a\b\x00\r\t"
58+
// /World/ !~ "hello, world"
59+
// /^\W*$/ !~ "\a\bo\r\t"
6060
// want len(seq) == 1; got at least 2
6161
// want len(seq) >= 5; got 4
6262
// want len(seq) >= 4; got 3

be_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ func Test(t *testing.T) {
4848
seq2 := maps.All(map[int]int{1: 1})
4949
be.EqualLength(tb, 1, seq2)
5050
},
51+
func(tb testing.TB) {
52+
be.In(tb, "world", "Hello, world!")
53+
be.NotIn(tb, "\x01", []byte("\a\b\x00\r\t"))
54+
},
5155
}
5256

5357
for _, test := range okayTests {
@@ -88,6 +92,12 @@ func Test(t *testing.T) {
8892
close(ch)
8993
be.EqualLength(tb, 1, ch)
9094
},
95+
func(tb testing.TB) {
96+
be.In(tb, "World", "Hello, world!")
97+
},
98+
func(tb testing.TB) {
99+
be.NotIn(tb, "\x00", []byte("\a\b\x00\r\t"))
100+
},
91101
}
92102

93103
for _, test := range badTests {

len_test.go

Lines changed: 0 additions & 14 deletions
This file was deleted.

match.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package be
2+
3+
import (
4+
"reflect"
5+
"regexp"
6+
"testing"
7+
)
8+
9+
// Match calls t.Fatalf if got does not match the [regexp] pattern.
10+
//
11+
// The pattern must compile.
12+
func Match[byteseq ~string | ~[]byte](t testing.TB, pattern string, got byteseq) {
13+
t.Helper()
14+
reg := regexp.MustCompile(pattern)
15+
if !match(reg, got) {
16+
t.Fatalf("/%s/ !~ %q", pattern, got)
17+
}
18+
}
19+
20+
func match[byteseq ~string | ~[]byte](reg *regexp.Regexp, got byteseq) bool {
21+
switch rv := reflect.ValueOf(got); rv.Kind() {
22+
case reflect.String:
23+
return reg.MatchString(rv.String())
24+
case reflect.Slice:
25+
return reg.Match(rv.Bytes())
26+
}
27+
panic("unreachable")
28+
}

panic_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package be_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/carlmjohnson/be"
7+
)
8+
9+
func TestLen(t *testing.T) {
10+
// Make sure integers aren't treated as rangeable
11+
be.Nonzero(t, be.Panicked(func() {
12+
be.EqualLength(t, 0, 0)
13+
}))
14+
}
15+
16+
func TestMatch(t *testing.T) {
17+
// Make sure bad regexp patterns panic
18+
pval := be.Panicked(func() {
19+
be.Match(t, `\`, "")
20+
})
21+
be.Nonzero(t, pval)
22+
s, ok := pval.(string)
23+
be.True(t, ok)
24+
be.Match(t, `^regexp: Compile\(`, s)
25+
}

0 commit comments

Comments
 (0)