Commit e58c6ea2 authored by Kirill Smelkov's avatar Kirill Smelkov

xerr: Clarify that it is safe to compare Errorv to errors like io.EOF

Commit 79e328c5 (xerr += First, Merge) was not right saying that

	if err == io.EOF

will panic if err has dynamic type Errorv. It will not because
interfaces with different dynamic types are always not equal.
However Errorv == Errorv will indeed panic.

Document and test that it is safe to compare error vectors to other
errors, e.g. to io.EOF, and that Errorv == Errorv panics.
parent 7e9d3221
...@@ -59,6 +59,16 @@ ...@@ -59,6 +59,16 @@
// //
// There is also First counterpart to Merge, which returns only first !nil // There is also First counterpart to Merge, which returns only first !nil
// error. // error.
//
// Since Errorv is actually a slice it cannot be generally compared - for example
// comparing 2 error interfaces that both have dynamic type Errorv will panic
// at runtime. However it is possible to compare Errorv to other error types,
// because interfaces with different dynamic types are always not equal. For
// example the following works:
//
// var err error = Errorv{...} // received as result from a function
// if err == io.EOF {
// ...
package xerr package xerr
import ( import (
......
// Copyright (C) 2016-2017 Nexedi SA and Contributors. // Copyright (C) 2016-2018 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com> // Kirill Smelkov <kirr@nexedi.com>
// //
// This program is free software: you can Use, Study, Modify and Redistribute // This program is free software: you can Use, Study, Modify and Redistribute
...@@ -21,6 +21,7 @@ package xerr ...@@ -21,6 +21,7 @@ package xerr
import ( import (
"errors" "errors"
"io"
"reflect" "reflect"
"testing" "testing"
...@@ -29,9 +30,13 @@ import ( ...@@ -29,9 +30,13 @@ import (
func TestErrorv(t *testing.T) { func TestErrorv(t *testing.T) {
var errv Errorv var errv Errorv
// check verifies that:
// 1. errv.Err() == aserr
// 2. errv.Error() == errmsg
check := func(aserr error, errmsg string) { check := func(aserr error, errmsg string) {
err := errv.Err() err := errv.Err()
// cannot use err != aserr as Errorv is not comparable (it is a slice) // cannot use err != aserr as Errorv is not generally comparable (it is a slice)
if !reflect.DeepEqual(err, aserr) { if !reflect.DeepEqual(err, aserr) {
t.Fatalf("%#v: Err() -> %#v ; want %#v", errv, err, aserr) t.Fatalf("%#v: Err() -> %#v ; want %#v", errv, err, aserr)
} }
...@@ -66,6 +71,40 @@ func TestErrorv(t *testing.T) { ...@@ -66,6 +71,40 @@ func TestErrorv(t *testing.T) {
- err2 - err2
- err3 "hello world" - err3 "hello world"
`) `)
// since Errorv is a slice it cannot be generally compared - for
// example comparing 2 error interfaces that both have dynamic type
// Errorv will panic. However it is possible to compare Errorv to other
// types, because interfaces with different dynamic types are always
// not equal.
eqcheck := func(a, b error, expect bool) {
t.Helper()
eq := (a == b)
ne := (a != b)
if eq != expect {
t.Fatalf("%#v == %#v -> %v; want %v", a, b, eq, expect)
}
if ne != !expect {
t.Fatalf("%#v != %#v -> %v; want %v", a, b, ne, !expect)
}
}
eqcheck(err1, nil, false)
eqcheck(err1, err1, true)
eqcheck(errv, nil, false)
eqcheck(errv, err1, false)
eqcheck(errv, io.EOF, false)
// check Errorv == Errorv panics.
func() {
defer func() {
if r := recover(); r == nil {
t.Fatal("Errorv == Errorv -> not paniced")
}
}()
eqcheck(errv, errv, true)
}()
} }
func TestMerge(t *testing.T) { func TestMerge(t *testing.T) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment