lab.nexedi.com/kirr/go123@v0.0.0-20240207185015-8299741fa871/xerr/xerr_test.go (about)

     1  // Copyright (C) 2016-2018  Nexedi SA and Contributors.
     2  //                          Kirill Smelkov <kirr@nexedi.com>
     3  //
     4  // This program is free software: you can Use, Study, Modify and Redistribute
     5  // it under the terms of the GNU General Public License version 3, or (at your
     6  // option) any later version, as published by the Free Software Foundation.
     7  //
     8  // You can also Link and Combine this program with other software covered by
     9  // the terms of any of the Free Software licenses or any of the Open Source
    10  // Initiative approved licenses and Convey the resulting work. Corresponding
    11  // source of such a combination shall include the source code for all other
    12  // software used.
    13  //
    14  // This program is distributed WITHOUT ANY WARRANTY; without even the implied
    15  // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    16  //
    17  // See COPYING file for full licensing terms.
    18  // See https://www.nexedi.com/licensing for rationale and options.
    19  
    20  package xerr
    21  
    22  import (
    23  	"errors"
    24  	"io"
    25  	"reflect"
    26  	"testing"
    27  
    28  	pkgerrors "github.com/pkg/errors"
    29  )
    30  
    31  func TestErrorv(t *testing.T) {
    32  	var errv Errorv
    33  
    34  	// check verifies that:
    35  	// 1. errv.Err() == aserr
    36  	// 2. errv.Error() == errmsg
    37  	check := func(aserr error, errmsg string) {
    38  		err := errv.Err()
    39  		// cannot use err != aserr as Errorv is not generally comparable (it is a slice)
    40  		if !reflect.DeepEqual(err, aserr) {
    41  			t.Fatalf("%#v: Err() -> %#v  ; want %#v", errv, err, aserr)
    42  		}
    43  		msg := errv.Error()
    44  		if msg != errmsg {
    45  			t.Fatalf("%#v: Error() -> %q  ; want %q", errv, msg, errmsg)
    46  		}
    47  	}
    48  
    49  	check(nil, "")
    50  
    51  	err1 := errors.New("err1")
    52  	err2 := errors.New("err2")
    53  
    54  	errv.Append(err1)
    55  	check(err1, "err1")
    56  
    57  	errv.Appendif(nil)
    58  	check(err1, "err1")
    59  
    60  	errv.Appendif(err2)
    61  	check(errv,
    62  `2 errors:
    63  	- err1
    64  	- err2
    65  `)
    66  
    67  	errv.Appendf("err3 %q", "hello world")
    68  	check(errv,
    69  `3 errors:
    70  	- err1
    71  	- err2
    72  	- err3 "hello world"
    73  `)
    74  
    75  	// since Errorv is a slice it cannot be generally compared - for
    76  	// example comparing 2 error interfaces that both have dynamic type
    77  	// Errorv will panic. However it is possible to compare Errorv to other
    78  	// types, because interfaces with different dynamic types are always
    79  	// not equal.
    80  	eqcheck := func(a, b error, expect bool) {
    81  		t.Helper()
    82  		eq := (a == b)
    83  		ne := (a != b)
    84  		if eq != expect {
    85  			t.Fatalf("%#v == %#v -> %v; want %v", a, b, eq, expect)
    86  		}
    87  		if ne != !expect {
    88  			t.Fatalf("%#v != %#v -> %v; want %v", a, b, ne, !expect)
    89  		}
    90  	}
    91  
    92  	eqcheck(err1, nil, false)
    93  	eqcheck(err1, err1, true)
    94  	eqcheck(errv, nil, false)
    95  	eqcheck(errv, err1, false)
    96  	eqcheck(errv, io.EOF, false)
    97  
    98  	// check Errorv == Errorv panics.
    99  	func() {
   100  		defer func() {
   101  			if r := recover(); r == nil {
   102  				t.Fatal("Errorv == Errorv -> not paniced")
   103  			}
   104  		}()
   105  
   106  		eqcheck(errv, errv, true)
   107  	}()
   108  }
   109  
   110  func TestMerge(t *testing.T) {
   111  	e := errors.New("e")
   112  	e2 := errors.New("e2")
   113  
   114  	testv := []struct {
   115  		in  []error
   116  		out error
   117  	}{
   118  		{nil, nil},
   119  		{[]error{}, nil},
   120  		{[]error{nil}, nil},
   121  		{[]error{nil, nil}, nil},
   122  		{[]error{e}, e},
   123  		{[]error{e, nil}, e},
   124  		{[]error{nil, e}, e},
   125  		{[]error{nil, e, nil}, e},
   126  		{[]error{nil, e, e2}, Errorv{e, e2}},
   127  		{[]error{nil, e2, e}, Errorv{e2, e}},
   128  		{[]error{nil, e2, nil, e}, Errorv{e2, e}},
   129  		{[]error{nil, e2, nil, e, nil}, Errorv{e2, e}},
   130  	}
   131  
   132  	for _, tt := range testv {
   133  		err := Merge(tt.in...)
   134  		//if err != tt.out {
   135  		// XXX Errorv is uncomparable because it is []
   136  		if !reflect.DeepEqual(err, tt.out) {
   137  			t.Errorf("Merge(%v) -> %v  ; want %v", tt.in, err, tt.out)
   138  		}
   139  	}
   140  }
   141  
   142  func TestFirst(t *testing.T) {
   143  	e := errors.New("e")
   144  	e2 := errors.New("e2")
   145  
   146  	testv := []struct {
   147  		in  []error
   148  		out error
   149  	}{
   150  		{nil, nil},
   151  		{[]error{}, nil},
   152  		{[]error{nil}, nil},
   153  		{[]error{nil, nil}, nil},
   154  		{[]error{e}, e},
   155  		{[]error{e, nil}, e},
   156  		{[]error{nil, e}, e},
   157  		{[]error{nil, e, nil}, e},
   158  		{[]error{nil, e, e2}, e},
   159  		{[]error{nil, e2, e}, e2},
   160  	}
   161  
   162  	for _, tt := range testv {
   163  		err := First(tt.in...)
   164  		if err != tt.out {
   165  			t.Errorf("First(%v) -> %v  ; want %v", tt.in, err, tt.out)
   166  		}
   167  	}
   168  }
   169  
   170  func TestContext(t *testing.T) {
   171  	test := func(e error) (err error) {
   172  		defer Context(&err, "test ctx")
   173  		return e
   174  	}
   175  
   176  	testf := func(e error) (err error) {
   177  		defer Contextf(&err, "testf ctx %d %q", 123, "hello")
   178  		return e
   179  	}
   180  
   181  	if test(nil) != nil {
   182  		t.Error("Context(nil) -> !nil")
   183  	}
   184  	if testf(nil) != nil {
   185  		t.Error("Contextf(nil) -> !nil")
   186  	}
   187  
   188  	err := errors.New("an error")
   189  
   190  	e := test(err)
   191  	want := "test ctx: an error"
   192  	if !(e != nil && e.Error() == want) {
   193  		t.Errorf("Context(%v) -> %v  ; want %v", err, e, want)
   194  	}
   195  	if ec := pkgerrors.Cause(e); ec != err {
   196  		t.Errorf("Context(%v) -> %v -> cause %v  ; want %v", err, e, ec, err)
   197  	}
   198  
   199  	e = testf(err)
   200  	want = `testf ctx 123 "hello": an error`
   201  	if !(e != nil && e.Error() == want) {
   202  		t.Errorf("Contextf(%v) -> %v  ; want %v", err, e, want)
   203  	}
   204  	if ec := pkgerrors.Cause(e); ec != err {
   205  		t.Errorf("Contextf(%v) -> %v -> cause %v  ; want %v", err, e, ec, err)
   206  	}
   207  }