Added a convention that sentinel errors go near the top of the file, and applied it
This commit is contained in:
1 parent
848edc73e2
commit
e32e270db0
5 files changed
+44
-16
No files matched your search
+30
-4
@@ -589,10 +589,36 @@ Two kinds of error are exempt and have no prefix:
|
|||||||
an internal package name.
|
an internal package name.
|
||||||
- Error text that is part of a protocol sent to a client, such as the
|
- Error text that is part of a protocol sent to a client, such as the
|
||||||
mock Find a Tender API's error responses, which match the real API's.
|
mock Find a Tender API's error responses, which match the real API's.
|
||||||
- Errors that callers test for are sentinel values named `Err…`
|
|
||||||
(exported) or `err…` (unexported), checked with `errors.Is`. A
|
### Sentinel errors
|
||||||
package's sentinels go in one commented `var` block (see
|
|
||||||
[Grouped declarations](#grouped-declarations)).
|
Errors that callers test for are sentinel values named `Err…` (exported)
|
||||||
|
or `err…` (unexported), checked with `errors.Is`. The sentinels in a file
|
||||||
|
go in one commented `var` block (see
|
||||||
|
[Grouped declarations](#grouped-declarations)).
|
||||||
|
|
||||||
|
They are declared near the top of the file: straight after the imports
|
||||||
|
and any constants, before the file's types and functions. A reader then
|
||||||
|
sees what the file can fail with before reading how, and finds a
|
||||||
|
sentinel without searching the file. This applies to every package-level
|
||||||
|
error variable, in tests as well.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrWonAndLost is returned by OpportunityMarks.Validate when both Won and
|
||||||
|
// Lost are set.
|
||||||
|
var ErrWonAndLost = errors.New("types: an opportunity cannot be both won and lost")
|
||||||
|
|
||||||
|
// Opportunity is a procurement opportunity ...
|
||||||
|
type Opportunity struct {
|
||||||
|
```
|
||||||
|
|
||||||
|
Not declared next to the type or function that returns it, partway down
|
||||||
|
the file.
|
||||||
|
|
||||||
### Ignoring an error
|
### Ignoring an error
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import (
|
|||||||
"github.com/pressly/goose/v3"
|
"github.com/pressly/goose/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// errWrite is the error failingWriter fails every write with.
|
||||||
|
var errWrite = errors.New("write failed")
|
||||||
|
|
||||||
// The commands are tested through the real command tree in cmd/jobsearch.
|
// The commands are tested through the real command tree in cmd/jobsearch.
|
||||||
// These tests cover reporting a failed migration, which a working set of
|
// These tests cover reporting a failed migration, which a working set of
|
||||||
// migrations can't trigger.
|
// migrations can't trigger.
|
||||||
@@ -92,8 +95,6 @@ func TestPrintResults(t *testing.T) {
|
|||||||
// failingWriter fails every write.
|
// failingWriter fails every write.
|
||||||
type failingWriter struct{}
|
type failingWriter struct{}
|
||||||
|
|
||||||
var errWrite = errors.New("write failed")
|
|
||||||
|
|
||||||
func (failingWriter) Write([]byte) (int, error) { return 0, errWrite }
|
func (failingWriter) Write([]byte) (int, error) { return 0, errWrite }
|
||||||
|
|
||||||
// A write error is returned, and the failed migration is still reported.
|
// A write error is returned, and the failed migration is still reported.
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import (
|
|||||||
"git.avsdev.uk/Go/job-search/internal/util"
|
"git.avsdev.uk/Go/job-search/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// errRejected is the error testValidated.validate rejects "bad" with.
|
||||||
|
var errRejected = errors.New("rejected")
|
||||||
|
|
||||||
// Test sections exercising every field shape section.go supports.
|
// Test sections exercising every field shape section.go supports.
|
||||||
type testInner struct {
|
type testInner struct {
|
||||||
Name string `cfg:"name" default:"inner"`
|
Name string `cfg:"name" default:"inner"`
|
||||||
@@ -51,8 +54,6 @@ type testValidated struct {
|
|||||||
Value string `cfg:"value"`
|
Value string `cfg:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var errRejected = errors.New("rejected")
|
|
||||||
|
|
||||||
func (c *testValidated) validate(key string, value any) error {
|
func (c *testValidated) validate(key string, value any) error {
|
||||||
if key == "value" && value.(string) == "bad" {
|
if key == "value" && value.(string) == "bad" {
|
||||||
return errRejected
|
return errRejected
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrWonAndLost is returned by OpportunityMarks.Validate when both Won and
|
||||||
|
// Lost are set.
|
||||||
|
var ErrWonAndLost = errors.New("types: an opportunity cannot be both won and lost")
|
||||||
|
|
||||||
// Opportunity is a procurement opportunity (an OCDS contracting process,
|
// Opportunity is a procurement opportunity (an OCDS contracting process,
|
||||||
// identified by UUID) as of its latest release, with its classifications,
|
// identified by UUID) as of its latest release, with its classifications,
|
||||||
// releases and the user's marks. Fields tagged db:"-" are stored in their
|
// releases and the user's marks. Fields tagged db:"-" are stored in their
|
||||||
@@ -51,10 +55,6 @@ type OpportunityReleaseTag struct {
|
|||||||
Tag string `db:"tag" json:"tag"`
|
Tag string `db:"tag" json:"tag"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrWonAndLost is returned by OpportunityMarks.Validate when both Won and
|
|
||||||
// Lost are set.
|
|
||||||
var ErrWonAndLost = errors.New("types: an opportunity cannot be both won and lost")
|
|
||||||
|
|
||||||
// OpportunityMarks are the user's own marks on an opportunity, kept apart
|
// OpportunityMarks are the user's own marks on an opportunity, kept apart
|
||||||
// from the fetched data so saving a newer release never changes them. The
|
// from the fetched data so saving a newer release never changes them. The
|
||||||
// marks are independent except that Won and Lost exclude each other (see
|
// marks are independent except that Won and Lost exclude each other (see
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ const clientSendBuffer = 256
|
|||||||
// cut short and logged as truncated.
|
// cut short and logged as truncated.
|
||||||
const logMessageLimit = 1 << 10
|
const logMessageLimit = 1 << 10
|
||||||
|
|
||||||
|
// errUnsupportedData is returned by readLoop (and a tcpConn's Write) for a
|
||||||
|
// binary message.
|
||||||
|
var errUnsupportedData = errors.New("websocket: binary frames are not supported")
|
||||||
|
|
||||||
// msgConn is the connection a client reads and writes messages on: a
|
// msgConn is the connection a client reads and writes messages on: a
|
||||||
// *websocket.Conn, or a tcpConn for plain TCP clients (see tcp.go).
|
// *websocket.Conn, or a tcpConn for plain TCP clients (see tcp.go).
|
||||||
type msgConn interface {
|
type msgConn interface {
|
||||||
@@ -51,10 +55,6 @@ type client struct {
|
|||||||
closeOnce sync.Once
|
closeOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
// errUnsupportedData is returned by readLoop (and a tcpConn's Write) for a
|
|
||||||
// binary message.
|
|
||||||
var errUnsupportedData = errors.New("websocket: binary frames are not supported")
|
|
||||||
|
|
||||||
// newClient creates a client for conn. cancel cancels the context the client
|
// newClient creates a client for conn. cancel cancels the context the client
|
||||||
// runs with; the client calls it when it finishes or is closed. The client's
|
// runs with; the client calls it when it finishes or is closed. The client's
|
||||||
// messages are limited by websocket.message_rate_limit if it is enabled.
|
// messages are limited by websocket.message_rate_limit if it is enabled.
|
||||||
|
|||||||
Reference in new issue
Block a user