github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/cmd/syft/internal/commands/packages_test.go (about) 1 package commands 2 3 import ( 4 "errors" 5 "fmt" 6 "testing" 7 8 "github.com/hashicorp/go-multierror" 9 "github.com/stretchr/testify/assert" 10 11 "github.com/anchore/syft/internal/task" 12 ) 13 14 func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) { 15 tests := []struct { 16 name string 17 err error 18 wantExpErrs []task.ErrInvalidExpression 19 wantErr assert.ErrorAssertionFunc 20 wantHelp string 21 }{ 22 { 23 name: "no errors", 24 err: nil, 25 wantExpErrs: nil, 26 wantErr: assert.NoError, 27 wantHelp: "", 28 }, 29 { 30 name: "single non-expression error is retained", 31 err: errors.New("foo"), 32 wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { 33 return assert.Equal(t, "foo", err.Error()) 34 }, 35 wantHelp: "", 36 }, 37 { 38 name: "multiple non-expression sibling errors are retained", 39 err: func() error { 40 var err error 41 err = multierror.Append(err, errors.New("foo")) 42 err = multierror.Append(err, errors.New("bar")) 43 return err 44 }(), 45 wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { 46 // note: this is the default formatting from the hashicorp multierror object 47 expected := `2 errors occurred: 48 * foo 49 * bar 50 51 ` 52 return assert.Equal(t, expected, err.Error()) 53 }, 54 wantHelp: "", 55 }, 56 { 57 name: "has multiple expression errors (with sibling errors)", 58 err: func() error { 59 var err error 60 err = multierror.Append(err, errors.New("foo")) 61 err = multierror.Append(err, task.ErrInvalidExpression{Expression: "foo", Operation: task.AddOperation, Err: task.ErrTagsNotAllowed}) 62 err = multierror.Append(err, errors.New("bar")) 63 err = multierror.Append(err, task.ErrInvalidExpression{Expression: "bar", Operation: task.SubSelectOperation, Err: task.ErrNamesNotAllowed}) 64 err = multierror.Append(err, errors.New("last")) 65 return err 66 }(), 67 wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { 68 expected := `5 errors occurred: 69 * foo 70 * invalid expression: "foo": tags are not allowed with this operation (must use exact names) 71 * bar 72 * invalid expression: "bar": names are not allowed with this operation (must use tags) 73 * last 74 75 ` 76 return assert.Equal(t, expected, err.Error()) 77 }, 78 wantExpErrs: []task.ErrInvalidExpression{ 79 {Expression: "foo", Operation: task.AddOperation, Err: task.ErrTagsNotAllowed}, 80 {Expression: "bar", Operation: task.SubSelectOperation, Err: task.ErrNamesNotAllowed}, 81 }, 82 wantHelp: `Suggestions: 83 84 ❖ Given expression "--select-catalogers foo" 85 However, tags are not allowed with this operation (must use exact names). 86 Adding groups of catalogers may result in surprising behavior (create inaccurate SBOMs). 87 If you are certain this is what you want to do, use "--override-default-catalogers foo" instead. 88 89 ❖ Given expression "--select-catalogers bar" 90 However, names are not allowed with this operation (must use tags). 91 It seems like you are intending to add a cataloger in addition to the default set. 92 ... Did you mean "--select-catalogers +bar" instead? 93 `, 94 }, 95 { 96 name: "has multiple expression errors (with error chains and sibling errors)", 97 err: func() error { 98 var err error 99 err = multierror.Append(err, fmt.Errorf("foo: %w", fmt.Errorf("bar: %w", errors.New("last")))) 100 err = multierror.Append(err, task.ErrInvalidExpression{Expression: "foo", Operation: task.AddOperation, Err: task.ErrTagsNotAllowed}) 101 err = multierror.Append(err, task.ErrInvalidExpression{Expression: "bar", Operation: task.SubSelectOperation, Err: task.ErrNamesNotAllowed}) 102 err = multierror.Append(err, errors.New("bottom")) 103 104 return fmt.Errorf("top: %w", fmt.Errorf("middle: %w", err)) 105 }(), 106 wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { 107 expected := `top: middle: 4 errors occurred: 108 * foo: bar: last 109 * invalid expression: "foo": tags are not allowed with this operation (must use exact names) 110 * invalid expression: "bar": names are not allowed with this operation (must use tags) 111 * bottom 112 113 ` 114 return assert.Equal(t, expected, err.Error()) 115 }, 116 wantExpErrs: []task.ErrInvalidExpression{ 117 {Expression: "foo", Operation: task.AddOperation, Err: task.ErrTagsNotAllowed}, 118 {Expression: "bar", Operation: task.SubSelectOperation, Err: task.ErrNamesNotAllowed}, 119 }, 120 wantHelp: `Suggestions: 121 122 ❖ Given expression "--select-catalogers foo" 123 However, tags are not allowed with this operation (must use exact names). 124 Adding groups of catalogers may result in surprising behavior (create inaccurate SBOMs). 125 If you are certain this is what you want to do, use "--override-default-catalogers foo" instead. 126 127 ❖ Given expression "--select-catalogers bar" 128 However, names are not allowed with this operation (must use tags). 129 It seems like you are intending to add a cataloger in addition to the default set. 130 ... Did you mean "--select-catalogers +bar" instead? 131 `, 132 }, 133 { 134 name: "has multiple expression errors (with error chains and sibling errors)", 135 err: func() error { 136 var err error 137 err = multierror.Append(err, fmt.Errorf("foo: %w", fmt.Errorf("bar: %w", errors.New("last")))) 138 err = multierror.Append(err, task.ErrInvalidExpression{Expression: "foo", Operation: task.AddOperation, Err: task.ErrTagsNotAllowed}) 139 err = multierror.Append(err, task.ErrInvalidExpression{Expression: "bar", Operation: task.SubSelectOperation, Err: task.ErrNamesNotAllowed}) 140 err = multierror.Append(err, errors.New("bottom")) 141 142 // note we wrap the top error in a chain 143 return fmt.Errorf("top: %w", fmt.Errorf("middle: %w", err)) 144 }(), 145 wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { 146 expected := `top: middle: 4 errors occurred: 147 * foo: bar: last 148 * invalid expression: "foo": tags are not allowed with this operation (must use exact names) 149 * invalid expression: "bar": names are not allowed with this operation (must use tags) 150 * bottom 151 152 ` 153 return assert.Equal(t, expected, err.Error()) 154 }, 155 wantExpErrs: []task.ErrInvalidExpression{ 156 {Expression: "foo", Operation: task.AddOperation, Err: task.ErrTagsNotAllowed}, 157 {Expression: "bar", Operation: task.SubSelectOperation, Err: task.ErrNamesNotAllowed}, 158 }, 159 wantHelp: `Suggestions: 160 161 ❖ Given expression "--select-catalogers foo" 162 However, tags are not allowed with this operation (must use exact names). 163 Adding groups of catalogers may result in surprising behavior (create inaccurate SBOMs). 164 If you are certain this is what you want to do, use "--override-default-catalogers foo" instead. 165 166 ❖ Given expression "--select-catalogers bar" 167 However, names are not allowed with this operation (must use tags). 168 It seems like you are intending to add a cataloger in addition to the default set. 169 ... Did you mean "--select-catalogers +bar" instead? 170 `, 171 }, 172 { 173 name: "preserve for any errors within ErrInvalidExpression types", 174 err: func() error { 175 var err error 176 err = multierror.Append(err, task.ErrInvalidExpression{Expression: "foo", Operation: task.AddOperation, Err: task.ErrTagsNotAllowed}) 177 err = multierror.Append(err, task.ErrInvalidExpression{Expression: "bar", Operation: task.SubSelectOperation, Err: errors.New("explanation")}) // this is what makes this test different... 178 179 return err 180 }(), 181 wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { 182 // note: the errors are removed and the help text shows the enriched error help 183 expected := `2 errors occurred: 184 * invalid expression: "foo": tags are not allowed with this operation (must use exact names) 185 * invalid expression: "bar": explanation 186 187 ` 188 return assert.Equal(t, expected, err.Error()) 189 }, 190 wantExpErrs: []task.ErrInvalidExpression{ 191 {Expression: "foo", Operation: task.AddOperation, Err: task.ErrTagsNotAllowed}, 192 {Expression: "bar", Operation: task.SubSelectOperation, Err: errors.New("explanation")}, 193 }, 194 wantHelp: `Suggestions: 195 196 ❖ Given expression "--select-catalogers foo" 197 However, tags are not allowed with this operation (must use exact names). 198 Adding groups of catalogers may result in surprising behavior (create inaccurate SBOMs). 199 If you are certain this is what you want to do, use "--override-default-catalogers foo" instead. 200 201 `, 202 }, 203 } 204 for _, tt := range tests { 205 t.Run(tt.name, func(t *testing.T) { 206 gotExpErrs := filterExpressionErrors(tt.err) 207 tt.wantErr(t, tt.err) // ensure the error still remains 208 assert.Equal(t, tt.wantExpErrs, gotExpErrs) 209 210 gotHelp := expressionErrorsHelp(gotExpErrs) 211 assert.Equal(t, tt.wantHelp, gotHelp) 212 }) 213 } 214 } 215 216 func Test_expressionSuggestions(t *testing.T) { 217 tests := []struct { 218 name string 219 expErr task.ErrInvalidExpression 220 want string 221 }{ 222 { 223 name: "no embedded error", 224 expErr: task.ErrInvalidExpression{ 225 Expression: "example", 226 }, 227 want: ``, 228 }, 229 { 230 name: "general error", 231 expErr: task.ErrInvalidExpression{ 232 Err: errors.New("general error message"), 233 Expression: "example", 234 }, 235 want: ``, 236 }, 237 { 238 name: "ErrUnknownNameOrTag with add operation", 239 expErr: task.ErrInvalidExpression{ 240 Err: task.ErrUnknownNameOrTag, 241 Operation: task.AddOperation, 242 Expression: "+example", 243 }, 244 want: ``, 245 }, 246 { 247 name: "ErrUnknownNameOrTag with subselect operation", 248 expErr: task.ErrInvalidExpression{ 249 Err: task.ErrUnknownNameOrTag, 250 Operation: task.SubSelectOperation, 251 Expression: "example", 252 }, 253 want: ``, 254 }, 255 { 256 name: "ErrNamesNotAllowed with subselect operator", 257 expErr: task.ErrInvalidExpression{ 258 Err: task.ErrNamesNotAllowed, 259 Operation: task.SubSelectOperation, 260 Expression: "example", 261 }, 262 want: ` ❖ Given expression "--select-catalogers example" 263 However, names are not allowed with this operation (must use tags). 264 It seems like you are intending to add a cataloger in addition to the default set. 265 ... Did you mean "--select-catalogers +example" instead? 266 `, 267 }, 268 { 269 name: "ErrTagsNotAllowed with add operation", 270 expErr: task.ErrInvalidExpression{ 271 Err: task.ErrTagsNotAllowed, 272 Operation: task.AddOperation, 273 Expression: "+example", 274 }, 275 want: ` ❖ Given expression "--select-catalogers +example" 276 However, tags are not allowed with this operation (must use exact names). 277 Adding groups of catalogers may result in surprising behavior (create inaccurate SBOMs). 278 If you are certain this is what you want to do, use "--override-default-catalogers example" instead. 279 `, 280 }, 281 { 282 name: "ErrAllNotAllowed with subselect operation", 283 expErr: task.ErrInvalidExpression{ 284 Err: task.ErrAllNotAllowed, 285 Operation: task.SubSelectOperation, 286 Expression: "example", 287 }, 288 want: ` ❖ Given expression "--select-catalogers example" 289 However, you cannot use the 'all' operand in this context. 290 It seems like you are intending to use all catalogers (which is not recommended). 291 ... Did you mean "--override-default-catalogers example" instead? 292 `, 293 }, 294 } 295 for _, tt := range tests { 296 t.Run(tt.name, func(t *testing.T) { 297 assert.Equal(t, tt.want, expressionSuggetions(tt.expErr)) 298 }) 299 } 300 }