github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/errors/errors_collector_test.go (about) 1 package errors 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 ) 9 10 func TestErrorsCollector(t *testing.T) { 11 t.Run("basic collection", func(t *testing.T) { 12 collector := ErrorsCollector{} 13 14 // Collecting nil is ok 15 require.False(t, collector.Collect(nil).CollectedFailure()) 16 require.False(t, collector.CollectedError()) 17 require.Nil(t, collector.ErrorOrNil()) 18 19 // Collected non-fatal errors 20 err1 := NewOperationNotSupportedError("op1") 21 require.False( 22 t, 23 collector.Collect(fmt.Errorf("error wrapped: %w", err1)). 24 CollectedFailure()) 25 26 require.True(t, collector.CollectedError()) 27 err := collector.ErrorOrNil() 28 require.NotNil(t, err) 29 require.ErrorContains(t, err, "op1") 30 require.False(t, IsFailure(err)) 31 32 require.True(t, IsOperationNotSupportedError(err)) 33 found := Find(err, ErrCodeOperationNotSupportedError) 34 require.Equal(t, err1, found) 35 36 nonFatal, fatal := SplitErrorTypes(err) 37 require.Nil(t, fatal) 38 require.NotNil(t, nonFatal) 39 require.Equal(t, ErrCodeOperationNotSupportedError, nonFatal.Code()) 40 41 err2 := NewInvalidArgumentErrorf("bad arg") 42 require.False(t, collector.Collect(err2).CollectedFailure()) 43 44 require.True(t, collector.CollectedError()) 45 err = collector.ErrorOrNil() 46 require.NotNil(t, err) 47 require.ErrorContains(t, err, "error wrapped") 48 require.ErrorContains(t, err, "op1") 49 require.ErrorContains(t, err, "bad arg") 50 require.False(t, IsFailure(err)) 51 52 require.True(t, IsOperationNotSupportedError(err)) 53 found = Find(err, ErrCodeOperationNotSupportedError) 54 require.Equal(t, err1, found) 55 56 require.True(t, IsInvalidArgumentError(err)) 57 found = Find(err, ErrCodeInvalidArgumentError) 58 require.Equal(t, err2, found) 59 60 nonFatal, fatal = SplitErrorTypes(err) 61 require.Nil(t, fatal) 62 require.NotNil(t, nonFatal) 63 require.Equal(t, ErrCodeOperationNotSupportedError, nonFatal.Code()) 64 65 // Collected fatal error 66 require.True( 67 t, 68 collector.Collect( 69 fmt.Errorf( 70 "failure wrapped: %w", 71 NewLedgerFailure(fmt.Errorf("fatal1"))), 72 ).CollectedFailure()) 73 74 require.True(t, collector.CollectedError()) 75 err = collector.ErrorOrNil() 76 require.NotNil(t, err) 77 require.ErrorContains(t, err, "error wrapped") 78 require.ErrorContains(t, err, "op1") 79 require.ErrorContains(t, err, "bad arg") 80 require.ErrorContains(t, err, "failure wrapped") 81 require.ErrorContains(t, err, "fatal1") 82 require.True(t, IsFailure(err)) 83 84 // Note: when a fatal error is collected, the non-fatal errors are no 85 // longer accessible. 86 require.False(t, IsOperationNotSupportedError(err)) 87 require.False(t, IsInvalidArgumentError(err)) 88 require.True(t, IsLedgerFailure(err)) 89 90 nonFatal, fatal = SplitErrorTypes(err) 91 require.Nil(t, nonFatal) 92 require.NotNil(t, fatal) 93 require.Equal(t, FailureCodeLedgerFailure, fatal.Code()) 94 95 // Collecting a non-fatal error after a fatal error should still be 96 // fatal 97 require.True( 98 t, 99 collector.Collect( 100 NewOperationNotSupportedError("op3"), 101 ).CollectedFailure()) 102 103 require.True(t, collector.CollectedError()) 104 err = collector.ErrorOrNil() 105 require.NotNil(t, err) 106 require.ErrorContains(t, err, "error wrapped") 107 require.ErrorContains(t, err, "op1") 108 require.ErrorContains(t, err, "bad arg") 109 require.ErrorContains(t, err, "op3") 110 require.ErrorContains(t, err, "failure wrapped") 111 require.ErrorContains(t, err, "fatal1") 112 require.True(t, IsFailure(err)) 113 114 nonFatal, fatal = SplitErrorTypes(err) 115 require.Nil(t, nonFatal) 116 require.NotNil(t, fatal) 117 require.Equal(t, FailureCodeLedgerFailure, fatal.Code()) 118 119 // Collected multiple fatal errors (This should never happen, but just 120 // in case) 121 require.True( 122 t, 123 collector.Collect(fmt.Errorf("fatal2")).CollectedFailure()) 124 125 require.True(t, collector.CollectedError()) 126 err = collector.ErrorOrNil() 127 require.NotNil(t, err) 128 require.ErrorContains(t, err, "error wrapped") 129 require.ErrorContains(t, err, "op1") 130 require.ErrorContains(t, err, "bad arg") 131 require.ErrorContains(t, err, "op3") 132 require.ErrorContains(t, err, "failure wrapped") 133 require.ErrorContains(t, err, "fatal1") 134 require.ErrorContains(t, err, "fatal2") 135 require.True(t, IsFailure(err)) 136 137 nonFatal, fatal = SplitErrorTypes(err) 138 require.Nil(t, nonFatal) 139 require.NotNil(t, fatal) 140 require.Equal(t, FailureCodeLedgerFailure, fatal.Code()) 141 }) 142 143 t.Run("failure only", func(t *testing.T) { 144 collector := ErrorsCollector{} 145 146 require.True( 147 t, 148 collector.Collect(fmt.Errorf("fatal1")).CollectedFailure()) 149 150 require.True(t, collector.CollectedError()) 151 err := collector.ErrorOrNil() 152 require.NotNil(t, err) 153 require.ErrorContains(t, err, "fatal1") 154 require.True(t, IsFailure(err)) 155 156 nonFatal, fatal := SplitErrorTypes(err) 157 require.Nil(t, nonFatal) 158 require.NotNil(t, fatal) 159 require.Equal(t, FailureCodeUnknownFailure, fatal.Code()) 160 }) 161 }