summaryrefslogtreecommitdiff
path: root/assert/errequal_test.go
blob: b97342a241e808697c4afbc299265ee285d99608 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// SPDX-FileCopyrightText: 2026 Stefan Majewsky <majewsky@gmx.net>
// SPDX-License-Identifier: Apache-2.0

package assert_test

import (
	"errors"
	"fmt"
	"os"
	"regexp"
	"testing"

	"go.xyrillian.de/gg/assert"
	"go.xyrillian.de/gg/testcapture"
)

func TestErrEqual(t *testing.T) {
	noError := error(nil)
	fooError := errors.New("foo error")
	barError := errors.New("bar error")
	nestedFooError := fmt.Errorf("nested error: %w", fooError)

	// test matching against nil
	assert.ErrEqual(t, noError, nil)
	assert.ErrEqual(t, noError, (*os.PathError)(nil))
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrEqual(t, fooError, nil)
	}, `expected no error, but got "foo error"`)
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrEqual(t, fooError, (*os.PathError)(nil))
	}, `expected no error, but got "foo error"`)

	// test matching against error
	assert.ErrEqual(t, fooError, fooError)
	assert.ErrEqual(t, nestedFooError, fooError)
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrEqual(t, fooError, nestedFooError) // error nesting does not work the other way, we need to see the full `expected`error in`actual`
	}, `expected "nested error: foo error", but got "foo error"`)
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrEqual(t, barError, fooError) // check with unrelated errors for completeness
	}, `expected "foo error", but got "bar error"`)
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrEqual(t, nil, fooError)
	}, `expected "foo error", but got no error`)

	// test matching against string
	assert.ErrEqual(t, fooError, "foo error")
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrEqual(t, nestedFooError, "foo error") // partial matches do not work
	}, `expected "foo error", but got "nested error: foo error"`)
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrEqual(t, barError, "foo error") // check with unrelated errors for completeness
	}, `expected "foo error", but got "bar error"`)
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrEqual(t, nil, "foo error")
	}, `expected "foo error", but got no error`)

	// test matching against regexp
	fooRegexp := regexp.MustCompile(`foo`)
	assert.ErrEqual(t, fooError, fooRegexp) // partial matches allowed here as long as regexp does not use ^ and $
	assert.ErrEqual(t, nestedFooError, fooRegexp)
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrEqual(t, barError, fooRegexp) // check with unrelated errors for completeness
	}, `expected an error matching /foo/, but got "bar error"`)
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrEqual(t, nil, fooRegexp)
	}, `expected an error matching /foo/, but got no error`)

	// test matching against unexpected type
	result := testcapture.Capture(t.Context(), t.Name(), func(t assert.TestingTB) {
		assert.ErrEqual(t, errors.New("42"), 42)
	})
	assert.Equal(t, result, testcapture.Result{
		Outcome: testcapture.OutcomePanicked,
		Panic:   "cannot handle `expected` of type int",
	})

	// an earlier version had a bug because this call caused reflect.Value.IsNil() to be called on a value of kind Struct
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrEqual(t, nil, structTypedError{"foo"})
	}, `expected "foo", but got no error`)
}

type structTypedError struct {
	Message string
}

// Error implements the builtin/error interface.
func (e structTypedError) Error() string {
	return e.Message
}

func TestErrsEqual(t *testing.T) {
	// NOTE: ErrsEqual() uses the same basic machinery as ErrEqual(), so we're not comparing all types here.
	// We just need to check the machinery of iterating over `actual` and `expected` and dealing with slice length mismatches.

	errs := []error{
		errors.New("first error"),
		errors.New("second error"),
	}

	assert.ErrsEqual(t, errs, []string{"first error", "second error"})
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrsEqual(t, errs, []string{"second error", "first error"})
	}, `
		in actual[0]: expected "second error", but got "first error"
		in actual[1]: expected "first error", but got "second error"
	`)
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrsEqual(t, errs, []string{"first error"})
	}, `in actual[1]: expected <missing>, but got "second error"`)
	expectErrors(t, func(t assert.TestingTB) {
		assert.ErrsEqual(t, errs, []string{"first error", "second error", "third error"})
	}, `in actual[2]: expected "third error", but got <missing>`)
}