Documentation
¶
Overview ¶
Package errdare exemplifies some of the challenges of Go error handling by daring anyone to fix them.
go get github.com/mpvl/errdare
To fastest way to get started is to open dares_test.go, set dareOn to true, and fix the tests until they pass. See the errdare.go file or the godoc documentation for a description of each dare.
Index ¶
- Variables
- func RunCloudStorage(t *testing.T, cfg *errtest.Config, f func(t *CloudStorage) error)
- func RunPipeConvert(t *testing.T, cfg *errtest.Config, f func(t *PipeConvert, r Reader) error)
- func RunTrickyCatch(t *testing.T, cfg *errtest.Config, f func(t *TrickyCatch) error)
- type Aborter
- type Client
- type CloudStorage
- type PipeConvert
- type Reader
- type TrickyCatch
- type Value
- type Writer
Constants ¶
This section is empty.
Variables ¶
var PanicError = errtest.NewPanicError("user")
PanicError is an error that users may return if the IgnorePanicOrder option is set and a panic is detected.
Functions ¶
func RunCloudStorage ¶
RunCloudStorage runs the CloudStorage dare as a test.
func RunPipeConvert ¶
RunPipeConvert runs the PipeConvert dare as a test.
func RunTrickyCatch ¶
Types ¶
type CloudStorage ¶
type CloudStorage struct {
// contains filtered or unexported fields
}
The CloudStorage challenge: open the client, reader, and writer and copy the contents of the reader to the writer. Any error while copying the contents should result in a non-nil error being passed to the Writer's CloseWithError method.
A simplistic, but incorrect, implementation is:
func TestCloudStorage(t *testing.T) {
errdare.RunCloudStorage(t, nil, func(tc *CloudStorage) error {
c, err := tc.NewClient()
if err != nil {
return err
}
defer c.Close()
r, err := tc.NewReader()
if err != nil {
return err
}
defer r.Close()
w := tc.NewWriter(c)
defer func() { w.CloseWithError(err) }()
_, err = tc.Copy(w, r)
return err
})
}
func (*CloudStorage) Copy ¶
func (c *CloudStorage) Copy(w Writer, r Reader) (n int, err error)
Copy takes a Reader and Writer and reports any error.
func (*CloudStorage) NewClient ¶
func (c *CloudStorage) NewClient() (Client, error)
NewClient returns a client that must be closed. The error of the close may be ignored.
func (*CloudStorage) NewReader ¶
func (c *CloudStorage) NewReader() (Reader, error)
NewReader returns a reader. The caller must call Close on the reader.
func (*CloudStorage) NewWriter ¶
func (c *CloudStorage) NewWriter(client Client) Writer
NewWriter returns a writer. The caller must call CloseWithError with a non-nil value if there was any error.
type PipeConvert ¶
type PipeConvert struct {
// contains filtered or unexported fields
}
The PipeConvert challenge: given a reader, wrap the reader in a scanner and copy the result of repeated scans into a newly created pipe. Return the reader passing it to Wait().
An almost correct implementation is:
func TestPipeConvert(t *testing.T) {
RunPipeConvert(t, skip, func(t *PipeConvert, r Reader) error {
pipeReader, pipeWriter := t.Pipe()
go func() {
var err error
defer func() { pipeWriter.CloseWithError(err) }()
scanner := t.NewScanner(r)
for t.Scan(scanner) {
err = t.WriteScanned(pipeWriter, scanner)
if err != nil {
return
}
}
err = t.ScanErr(scanner)
}()
return t.Wait(pipeReader)
})
}
func (*PipeConvert) NewScanner ¶
func (p *PipeConvert) NewScanner(r Reader) Value
NewScanner returns a new Scanner that readers from the Reader passed to the test.
func (*PipeConvert) Pipe ¶
func (p *PipeConvert) Pipe() (Reader, Writer)
Pipe returns a Reader and Writer. The Writer must be closed upon completion. It must be closed with CloseWithError and a non-nil error if any error occurs. The Reader must be passed to Wait to await completion.
func (*PipeConvert) Scan ¶
func (p *PipeConvert) Scan(scanner Value) bool
Scan must be called with the Scanner created from NewScanner until it returs false.
func (*PipeConvert) ScanErr ¶
func (p *PipeConvert) ScanErr(scan Value) error
ScanErr must be called after the last call to Scan.
func (*PipeConvert) Wait ¶
func (p *PipeConvert) Wait(r Reader) error
Wait must be called on the Reader returned from Pipe.
func (*PipeConvert) WriteScanned ¶
func (p *PipeConvert) WriteScanned(w Writer, scanner Value) error
WriteScanned must be called after each successful call to Scan.
type TrickyCatch ¶
type TrickyCatch struct {
// contains filtered or unexported fields
}
The TrickyCatch challenge: create a writer, wrap it, and write something to it. If any error occurs during writing or wrapping, the original writer should be called with CloseWithError. Any error encountered should be returned.
A simple, but incorrect implementation is:
func TestTrickyCatch(t *testing.T) {
RunTrickyCatch(t, skip, func(t *TrickyCatch) (err error) {
w, err := t.NewWriter()
if err != nil {
return err
}
defer func() { w.CloseWithError(err) }() // Close may return error, even if err is not
ww, err := t.NewWrapper(w)
if err != nil {
return err
}
defer ww.Close() // must catch error, but may also panic.
err = t.WriteSomething(ww)
return err
})
}
func (*TrickyCatch) NewWrapper ¶
func (t *TrickyCatch) NewWrapper(w Writer) (Writer, error)
NewWrapper returns a Writer, given the Writer returned by NewWriter. It must be Closed and the error returned by the close must be observed.
func (*TrickyCatch) NewWriter ¶
func (t *TrickyCatch) NewWriter() (Writer, error)
NewWriter returns a Writer. It must be closed with CloseWithError and a non-nil error if any error occurred.
func (*TrickyCatch) WriteSomething ¶
func (t *TrickyCatch) WriteSomething(w Writer) error
WriteSomething writes something to the Writer returned by NewWrapper. It may return an error.