github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/columns/columninfo_test.go (about) 1 // Copyright 2022 The Inspektor Gadget authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package columns 16 17 import ( 18 "reflect" 19 "testing" 20 21 "github.com/inspektor-gadget/inspektor-gadget/pkg/columns/ellipsis" 22 ) 23 24 func expectColumnsSuccess[T any](t *testing.T, options ...Option) *Columns[T] { 25 cols, err := NewColumns[T](options...) 26 if err != nil { 27 t.Fatalf("Failed to initialize: %v", err) 28 } 29 return cols 30 } 31 32 func expectColumnsFail[T any](t *testing.T, name string, options ...Option) { 33 t.Run(name, func(t *testing.T) { 34 _, err := NewColumns[T](options...) 35 if err == nil { 36 t.Errorf("Succeeded to initialize but expected error") 37 } 38 }) 39 } 40 41 func expectColumn[T any](t *testing.T, cols *Columns[T], columnName string) *Column[T] { 42 col, ok := cols.GetColumn(columnName) 43 if !ok { 44 t.Fatalf("Expected column with name %q", columnName) 45 } 46 return col 47 } 48 49 func expectColumnValue[T any](t *testing.T, col *Column[T], fieldName string, expectedValue interface{}) { 50 columnValue := reflect.ValueOf(col).Elem() 51 fieldValue := columnValue.FieldByName(fieldName) 52 if !fieldValue.IsValid() { 53 t.Errorf("Expected field %q", fieldName) 54 return 55 } 56 if fieldValue.Interface() != expectedValue { 57 t.Errorf("Expected field %q to equal %+v, got %+v", fieldName, expectedValue, fieldValue.Interface()) 58 } 59 } 60 61 func TestColumnsInvalid(t *testing.T) { 62 type testFail1 struct { 63 Unknown string `column:"left,unknown"` 64 } 65 type testFail2 struct { 66 Unknown1 string `column:"unknown"` 67 Unknown2 string `column:"unknown"` 68 } 69 type testFail3 struct { 70 testFail2 71 } 72 expectColumnsFail[testFail1](t, "unknown parameter") 73 expectColumnsFail[testFail2](t, "double name") 74 expectColumnsFail[testFail3](t, "nested double name") 75 } 76 77 func TestColumnsAlign(t *testing.T) { 78 type testSuccess1 struct { 79 AlignLeft string `column:"left,align:left"` 80 AlignRight string `column:"right,align:right"` 81 } 82 83 cols := expectColumnsSuccess[testSuccess1](t) 84 expectColumnValue(t, expectColumn(t, cols, "left"), "Alignment", AlignLeft) 85 expectColumnValue(t, expectColumn(t, cols, "right"), "Alignment", AlignRight) 86 87 expectColumnsFail[struct { 88 Field string `column:"fail,align"` 89 }](t, "missing parameter") 90 expectColumnsFail[struct { 91 Field string `column:"fail,align:"` 92 }](t, "empty parameter") 93 expectColumnsFail[struct { 94 Field string `column:"fail,align:foo"` 95 }](t, "invalid parameter") 96 expectColumnsFail[struct { 97 Field string `column:"fail,align:left:bar"` 98 }](t, "double parameter") 99 } 100 101 func TestColumnsEllipsis(t *testing.T) { 102 type testSuccess1 struct { 103 EllipsisEmpty string `column:"empty,ellipsis"` 104 EllipsisEmptyColon string `column:"emptyColon,ellipsis:"` 105 EllipsisNone string `column:"none,ellipsis:none"` 106 EllipsisStart string `column:"start,ellipsis:start"` 107 EllipsisEnd string `column:"end,ellipsis:end"` 108 EllipsisMiddle string `column:"middle,ellipsis:middle"` 109 } 110 111 cols := expectColumnsSuccess[testSuccess1](t) 112 expectColumnValue(t, expectColumn(t, cols, "empty"), "EllipsisType", cols.options.DefaultEllipsis) 113 expectColumnValue(t, expectColumn(t, cols, "emptyColon"), "EllipsisType", cols.options.DefaultEllipsis) 114 expectColumnValue(t, expectColumn(t, cols, "none"), "EllipsisType", ellipsis.None) 115 expectColumnValue(t, expectColumn(t, cols, "start"), "EllipsisType", ellipsis.Start) 116 expectColumnValue(t, expectColumn(t, cols, "end"), "EllipsisType", ellipsis.End) 117 expectColumnValue(t, expectColumn(t, cols, "middle"), "EllipsisType", ellipsis.Middle) 118 119 expectColumnsFail[struct { 120 Field string `column:"fail,ellipsis:foo"` 121 }](t, "invalid parameter") 122 expectColumnsFail[struct { 123 Field string `column:"fail,ellipsis:left:bar"` 124 }](t, "double parameter") 125 } 126 127 func TestColumnsFixed(t *testing.T) { 128 type testSuccess1 struct { 129 Field string `column:"field,fixed"` 130 } 131 132 cols := expectColumnsSuccess[testSuccess1](t) 133 expectColumnValue(t, expectColumn(t, cols, "field"), "FixedWidth", true) 134 135 expectColumnsFail[struct { 136 Field string `column:"fail,fixed:foo"` 137 }](t, "invalid parameter") 138 } 139 140 func TestColumnsGroup(t *testing.T) { 141 type testSuccess1 struct { 142 FieldInt int64 `column:"int,group:sum"` 143 FieldUint int64 `column:"uint,group:sum"` 144 FieldFloat32 float32 `column:"float32,group:sum"` 145 FieldFloat64 float64 `column:"float64,group:sum"` 146 } 147 148 cols := expectColumnsSuccess[testSuccess1](t) 149 expectColumnValue(t, expectColumn(t, cols, "int"), "GroupType", GroupTypeSum) 150 expectColumnValue(t, expectColumn(t, cols, "uint"), "GroupType", GroupTypeSum) 151 expectColumnValue(t, expectColumn(t, cols, "float32"), "GroupType", GroupTypeSum) 152 expectColumnValue(t, expectColumn(t, cols, "float64"), "GroupType", GroupTypeSum) 153 154 expectColumnsFail[struct { 155 Field int64 `column:"fail,group"` 156 }](t, "missing parameter") 157 expectColumnsFail[struct { 158 Field int64 `column:"fail,group:"` 159 }](t, "empty parameter") 160 expectColumnsFail[struct { 161 Field int64 `column:"fail,group:foo"` 162 }](t, "invalid parameter") 163 expectColumnsFail[struct { 164 Field int64 `column:"fail,group:sum:bar"` 165 }](t, "double parameter") 166 expectColumnsFail[struct { 167 Field string `column:"fail,group:sum"` 168 }](t, "wrong type") 169 } 170 171 func TestColumnsHide(t *testing.T) { 172 type testSuccess1 struct { 173 Field string `column:"field,hide"` 174 } 175 176 cols := expectColumnsSuccess[testSuccess1](t) 177 expectColumnValue(t, expectColumn(t, cols, "field"), "Visible", false) 178 179 expectColumnsFail[struct { 180 Field string `column:"fail,hide:foo"` 181 }](t, "invalid parameter") 182 } 183 184 func TestColumnsOrder(t *testing.T) { 185 type testSuccess1 struct { 186 FieldWidth int64 `column:"int,order:4"` 187 } 188 189 cols := expectColumnsSuccess[testSuccess1](t) 190 expectColumnValue(t, expectColumn(t, cols, "int"), "Order", 4) 191 192 expectColumnsFail[struct { 193 Field int64 `column:"fail,order"` 194 }](t, "missing parameter") 195 expectColumnsFail[struct { 196 Field int64 `column:"fail,order:"` 197 }](t, "empty parameter") 198 expectColumnsFail[struct { 199 Field int64 `column:"fail,order:foo"` 200 }](t, "invalid parameter") 201 expectColumnsFail[struct { 202 Field int64 `column:"fail,order:sum:bar"` 203 }](t, "double parameter") 204 } 205 206 func TestColumnsPrecision(t *testing.T) { 207 type testSuccess1 struct { 208 Float32 float32 `column:"float32,precision:4"` 209 Float64 float64 `column:"float64,precision:4"` 210 } 211 212 cols := expectColumnsSuccess[testSuccess1](t) 213 expectColumnValue(t, expectColumn(t, cols, "float32"), "Precision", 4) 214 expectColumnValue(t, expectColumn(t, cols, "float64"), "Precision", 4) 215 216 expectColumnsFail[struct { 217 Field1 float32 `column:"fail,precision"` 218 }](t, "float32: missing parameter") 219 expectColumnsFail[struct { 220 Field float32 `column:"fail,precision:"` 221 }](t, "float32: empty parameter") 222 expectColumnsFail[struct { 223 Field float32 `column:"fail,precision:foo"` 224 }](t, "float32: invalid parameter") 225 expectColumnsFail[struct { 226 Field float32 `column:"fail,precision:-2"` 227 }](t, "float32: double parameter") 228 expectColumnsFail[struct { 229 Field1 float64 `column:"fail,precision"` 230 }](t, "float64: missing parameter") 231 expectColumnsFail[struct { 232 Field float64 `column:"fail,precision:"` 233 }](t, "float64: empty parameter") 234 expectColumnsFail[struct { 235 Field float64 `column:"fail,precision:foo"` 236 }](t, "float64: invalid parameter") 237 expectColumnsFail[struct { 238 Field float64 `column:"fail,precision:-2"` 239 }](t, "float64: double parameter") 240 expectColumnsFail[struct { 241 Field string `column:"fail,precision:2"` 242 }](t, "invalid field") 243 } 244 245 func TestColumnsWidth(t *testing.T) { 246 type testSuccess1 struct { 247 FieldWidth int64 `column:"int,width:4"` 248 FieldWidthType int64 `column:"intType,width:type"` 249 } 250 251 cols := expectColumnsSuccess[testSuccess1](t) 252 expectColumnValue(t, expectColumn(t, cols, "int"), "Width", 4) 253 expectColumnValue(t, expectColumn(t, cols, "intType"), "Width", MaxCharsInt64) 254 255 expectColumnsFail[struct { 256 Field int64 `column:"fail,width"` 257 }](t, "missing parameter") 258 expectColumnsFail[struct { 259 Field int64 `column:"fail,width:"` 260 }](t, "empty parameter") 261 expectColumnsFail[struct { 262 Field int64 `column:"fail,width:foo"` 263 }](t, "invalid parameter") 264 expectColumnsFail[struct { 265 Field int64 `column:"fail,width:sum:bar"` 266 }](t, "double parameter") 267 } 268 269 func TestColumnsMaxWidth(t *testing.T) { 270 type testSuccess1 struct { 271 FieldMaxWidth int64 `column:"int,maxWidth:4"` 272 FieldMaxWidthType int64 `column:"intType,maxWidth:type"` 273 } 274 275 cols := expectColumnsSuccess[testSuccess1](t) 276 277 expectColumnValue(t, expectColumn(t, cols, "int"), "MaxWidth", 4) 278 expectColumnValue(t, expectColumn(t, cols, "intType"), "MaxWidth", MaxCharsInt64) 279 280 expectColumnsFail[struct { 281 Field int64 `column:"fail,maxWidth"` 282 }](t, "missing parameter") 283 expectColumnsFail[struct { 284 Field int64 `column:"fail,maxWidth:"` 285 }](t, "empty parameter") 286 expectColumnsFail[struct { 287 Field int64 `column:"fail,maxWidth:foo"` 288 }](t, "invalid parameter") 289 expectColumnsFail[struct { 290 Field int64 `column:"fail,maxWidth:sum:bar"` 291 }](t, "double parameter") 292 } 293 294 func TestColumnsMinWidth(t *testing.T) { 295 type testSuccess1 struct { 296 FieldMinWidth int64 `column:"int,minWidth:4"` 297 FieldMaxWidthType int64 `column:"intType,minWidth:type"` 298 } 299 300 cols := expectColumnsSuccess[testSuccess1](t) 301 expectColumnValue(t, expectColumn(t, cols, "int"), "MinWidth", 4) 302 expectColumnValue(t, expectColumn(t, cols, "intType"), "MinWidth", MaxCharsInt64) 303 304 expectColumnsFail[struct { 305 Field int64 `column:"fail,minWidth"` 306 }](t, "missing parameter") 307 expectColumnsFail[struct { 308 Field int64 `column:"fail,minWidth:"` 309 }](t, "empty parameter") 310 expectColumnsFail[struct { 311 Field int64 `column:"fail,minWidth:foo"` 312 }](t, "invalid parameter") 313 expectColumnsFail[struct { 314 Field int64 `column:"fail,minWidth:sum:bar"` 315 }](t, "double parameter") 316 } 317 318 func TestColumnsWidthFromType(t *testing.T) { 319 type testSuccess1 struct { 320 Int8 int8 `column:",minWidth:type,maxWidth:type,width:type"` 321 Int16 int16 `column:",minWidth:type,maxWidth:type,width:type"` 322 Int32 int32 `column:",minWidth:type,maxWidth:type,width:type"` 323 Int64 int64 `column:",minWidth:type,maxWidth:type,width:type"` 324 Uint8 uint8 `column:",minWidth:type,maxWidth:type,width:type"` 325 Uint16 uint16 `column:",minWidth:type,maxWidth:type,width:type"` 326 Uint32 uint32 `column:",minWidth:type,maxWidth:type,width:type"` 327 Uint64 uint64 `column:",minWidth:type,maxWidth:type,width:type"` 328 Bool bool `column:",minWidth:type,maxWidth:type,width:type"` 329 } 330 331 cols := expectColumnsSuccess[testSuccess1](t) 332 333 col := expectColumn(t, cols, "int8") 334 expectColumnValue(t, col, "Width", MaxCharsInt8) 335 expectColumnValue(t, col, "MinWidth", MaxCharsInt8) 336 expectColumnValue(t, col, "MaxWidth", MaxCharsInt8) 337 338 col = expectColumn(t, cols, "int16") 339 expectColumnValue(t, col, "Width", MaxCharsInt16) 340 expectColumnValue(t, col, "MinWidth", MaxCharsInt16) 341 expectColumnValue(t, col, "MaxWidth", MaxCharsInt16) 342 343 col = expectColumn(t, cols, "int32") 344 expectColumnValue(t, col, "Width", MaxCharsInt32) 345 expectColumnValue(t, col, "MinWidth", MaxCharsInt32) 346 expectColumnValue(t, col, "MaxWidth", MaxCharsInt32) 347 348 col = expectColumn(t, cols, "int64") 349 expectColumnValue(t, col, "Width", MaxCharsInt64) 350 expectColumnValue(t, col, "MinWidth", MaxCharsInt64) 351 expectColumnValue(t, col, "MaxWidth", MaxCharsInt64) 352 353 col = expectColumn(t, cols, "uint8") 354 expectColumnValue(t, col, "Width", MaxCharsUint8) 355 expectColumnValue(t, col, "MinWidth", MaxCharsUint8) 356 expectColumnValue(t, col, "MaxWidth", MaxCharsUint8) 357 358 col = expectColumn(t, cols, "uint16") 359 expectColumnValue(t, col, "Width", MaxCharsUint16) 360 expectColumnValue(t, col, "MinWidth", MaxCharsUint16) 361 expectColumnValue(t, col, "MaxWidth", MaxCharsUint16) 362 363 col = expectColumn(t, cols, "uint32") 364 expectColumnValue(t, col, "Width", MaxCharsUint32) 365 expectColumnValue(t, col, "MinWidth", MaxCharsUint32) 366 expectColumnValue(t, col, "MaxWidth", MaxCharsUint32) 367 368 col = expectColumn(t, cols, "uint64") 369 expectColumnValue(t, col, "Width", MaxCharsUint64) 370 expectColumnValue(t, col, "MinWidth", MaxCharsUint64) 371 expectColumnValue(t, col, "MaxWidth", MaxCharsUint64) 372 373 col = expectColumn(t, cols, "bool") 374 expectColumnValue(t, col, "Width", MaxCharsBool) 375 expectColumnValue(t, col, "MinWidth", MaxCharsBool) 376 expectColumnValue(t, col, "MaxWidth", MaxCharsBool) 377 378 expectColumnsFail[struct { 379 String string `column:",minWidth:type,maxWidth:type,width:type"` 380 }](t, "invalid field type") 381 } 382 383 func TestWithoutColumnTag(t *testing.T) { 384 type Main struct { 385 StringField string 386 IntField int 387 } 388 389 cols := expectColumnsSuccess[Main](t, WithRequireColumnDefinition(false)) 390 391 expectColumn(t, cols, "StringField") 392 } 393 394 func TestColumnFilters(t *testing.T) { 395 type Embedded struct { 396 EmbeddedString string `column:"embeddedString" columnTags:"test"` 397 } 398 type Main struct { 399 Embedded 400 MainString string `column:"mainString" columnTags:"test2"` 401 NoTags string `column:"noTags"` 402 } 403 404 cols := expectColumnsSuccess[Main](t) 405 406 expectColumn := func(columnName string, name string, filters ...ColumnFilter) { 407 t.Run(name, func(t *testing.T) { 408 colMap := cols.GetColumnMap(filters...) 409 if _, ok := colMap.GetColumn(columnName); !ok { 410 t.Errorf("Expected column %q to exist after applying filters", columnName) 411 } 412 }) 413 } 414 415 expectColumn("embeddedString", "embedded or WithTag(test)", Or(WithEmbedded(true), WithTag("test"))) 416 expectColumn("mainString", "not embedded or WithoutTag(test)", Or(WithEmbedded(false), WithoutTag("test"))) 417 expectColumn("mainString", "WithTags(test2) and WithoutTags(test)", And(WithTags([]string{"test2"}), WithoutTags([]string{"test"}))) 418 expectColumn("mainString", "WithTags(test2) and WithoutTags(test)", And(WithTags([]string{"test2"}), WithoutTags([]string{"test"}))) 419 420 orderedColumns := cols.GetOrderedColumns(WithoutTags([]string{"test"})) // missing path 421 if len(orderedColumns) != 2 || orderedColumns[0].Name != "mainString" { 422 t.Errorf("Expected a mainString column after getting ordered columns using filters") 423 } 424 425 orderedColumns = cols.GetOrderedColumns(WithNoTags()) 426 if len(orderedColumns) != 1 || orderedColumns[0].Name != "noTags" { 427 t.Errorf("Expected a noTags column after getting ordered columns using filters") 428 } 429 } 430 431 func TestColumnMatcher(t *testing.T) { 432 type Embedded struct { 433 EmbeddedString string `column:"embeddedString" columnTags:"test"` 434 } 435 type Main struct { 436 Embedded 437 MainString string `column:"mainString" columnTags:"test2"` 438 } 439 440 cols := expectColumnsSuccess[Main](t) 441 442 c := expectColumn(t, cols, "embeddedString") 443 if !c.IsEmbedded() { 444 t.Errorf("Expected the embedded field to be identified as embedded") 445 } 446 if !c.HasTag("test") { 447 t.Errorf("Expected the embedded field to have tag 'test'") 448 } 449 if c.HasTag("test2") { 450 t.Errorf("Didn't expect the embedded field to have tag 'test2'") 451 } 452 453 c = expectColumn(t, cols, "mainString") 454 if c.IsEmbedded() { 455 t.Errorf("Expected mainString to not be identified as embedded") 456 } 457 if !c.HasTag("test2") { 458 t.Errorf("Expected mainString to have tag 'test2'") 459 } 460 if c.HasTag("test") { 461 t.Errorf("Didn't expect mainString to have tag 'test'") 462 } 463 } 464 465 func TestColumnTemplates(t *testing.T) { 466 if RegisterTemplate("", "width:789") == nil { 467 t.Errorf("Expected error because of empty name") 468 } 469 if RegisterTemplate("demo", "") == nil { 470 t.Errorf("Expected error because of empty value") 471 } 472 473 if err := RegisterTemplate("numbers", "width:123"); err != nil { 474 t.Errorf("Expected success, got %v", err) 475 } 476 477 type testSuccess1 struct { 478 Int16 int16 `column:",template:numbers"` 479 Int32 int32 `column:",template:numbers,width:5"` 480 Int64 int64 `column:",template:numbers,hide"` 481 } 482 483 cols := expectColumnsSuccess[testSuccess1](t) 484 485 expectColumnValue(t, expectColumn(t, cols, "int16"), "Width", 123) 486 expectColumnValue(t, expectColumn(t, cols, "int32"), "Width", 5) 487 expectColumnValue(t, expectColumn(t, cols, "int64"), "Width", 123) 488 expectColumnValue(t, expectColumn(t, cols, "int64"), "Visible", false) 489 490 expectColumnsFail[struct { 491 String string `column:",template"` 492 }](t, "not template name given") 493 494 expectColumnsFail[struct { 495 String string `column:",template:foobar"` 496 }](t, "trying to use non-existing template") 497 } 498 499 func TestColumnTemplatesRegisterExisting(t *testing.T) { 500 t.Run("untyped", func(t *testing.T) { 501 defer func() { 502 if r := recover(); r == nil { 503 t.Errorf("expected panic") 504 } 505 }() 506 MustRegisterTemplate("abc", "width:123") 507 MustRegisterTemplate("abc", "width:123") 508 }) 509 }