go-hep.org/x/hep@v0.38.1/groot/rdict/rdict_test.go (about) 1 // Copyright ©2020 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package rdict 6 7 import ( 8 "fmt" 9 "math" 10 "reflect" 11 "testing" 12 13 "go-hep.org/x/hep/groot/rbase" 14 "go-hep.org/x/hep/groot/rbytes" 15 "go-hep.org/x/hep/groot/rmeta" 16 ) 17 18 func TestElementGetRange(t *testing.T) { 19 for _, tc := range []struct { 20 name string 21 title string 22 rtype rmeta.Enum 23 xmin, xmax, factor float64 24 }{ 25 { 26 name: "empty", 27 title: "", 28 rtype: rmeta.Double32, 29 }, 30 { 31 name: "normal-d32", 32 title: "var/d", 33 rtype: rmeta.Double32, 34 }, 35 { 36 name: "normal-f64", 37 title: "var/D", 38 rtype: rmeta.Float64, 39 }, 40 { 41 name: "normal-f64-ndims", 42 title: "var[10][20][30]/D", 43 rtype: rmeta.OffsetL + rmeta.Float64, 44 }, 45 { 46 name: "normal-1d", 47 title: "var[3]/d", 48 rtype: rmeta.OffsetL + rmeta.Double32, 49 }, 50 { 51 name: "normal-2d", 52 title: "var[3][4]/d", 53 rtype: rmeta.OffsetL + rmeta.Double32, 54 }, 55 { 56 name: "normal-3d", 57 title: "var[3][4][5]/d", 58 rtype: rmeta.OffsetL + rmeta.Double32, 59 }, 60 { 61 name: "normal-with-brackets", 62 title: "From [tleft,tright+10 ns]", 63 rtype: rmeta.Double32, 64 }, 65 { 66 name: "normal-with-brackets-2", 67 title: "Bias voltage [V]", 68 rtype: rmeta.Double32, 69 }, 70 { 71 name: "normal-with-brackets-3", 72 title: "Bias voltage [0, 100]", 73 rtype: rmeta.Double32, 74 }, 75 { 76 name: "normal-with-brackets-4", 77 title: "Bias/voltage [0, 100]", 78 rtype: rmeta.Double32, 79 }, 80 { 81 name: "normal-with-brackets-5", 82 title: "Bias voltage [0]", 83 rtype: rmeta.Double32, 84 }, 85 { 86 name: "range", 87 title: "[ 0 , 100 ]", 88 rtype: rmeta.Double32, 89 xmin: 0, 90 xmax: 100, 91 factor: float64(0xffffffff) / 100, 92 }, 93 { 94 name: "range-ndim", 95 title: "var[3]/d[ 0 , 100 ]", 96 rtype: rmeta.OffsetL + rmeta.Double32, 97 xmin: 0, 98 xmax: 100, 99 factor: float64(0xffffffff) / 100, 100 }, 101 { 102 name: "range-ndim-slice", 103 title: "var[N]/d[ 0 , 100 ]", 104 rtype: rmeta.OffsetP + rmeta.Double32, 105 xmin: 0, 106 xmax: 100, 107 factor: float64(0xffffffff) / 100, 108 }, 109 { 110 name: "range-nbits", 111 title: "[ 10 , 100, 30 ]", 112 rtype: rmeta.Double32, 113 xmin: 10, 114 xmax: 100, 115 factor: float64(1<<30) / 90, 116 }, 117 { 118 name: "range-nbits-1d", 119 title: "var[3]/d[ 10 , 100, 30 ]", 120 rtype: rmeta.OffsetL + rmeta.Double32, 121 xmin: 10, 122 xmax: 100, 123 factor: float64(1<<30) / 90, 124 }, 125 { 126 name: "range-nbits-slice-1d", 127 title: "var[N]/d[ 10 , 100, 30 ]", 128 rtype: rmeta.OffsetP + rmeta.Double32, 129 xmin: 10, 130 xmax: 100, 131 factor: float64(1<<30) / 90, 132 }, 133 { 134 name: "range-pi", 135 title: "[ -pi , pi ]", 136 rtype: rmeta.Double32, 137 xmin: -math.Pi, 138 xmax: +math.Pi, 139 factor: float64(0xffffffff) / (2 * math.Pi), 140 }, 141 { 142 name: "range-pi/2", 143 title: "[ -pi/2 , 2pi ]", 144 rtype: rmeta.Double32, 145 xmin: -math.Pi / 2, 146 xmax: 2 * math.Pi, 147 factor: float64(0xffffffff) / (2*math.Pi + math.Pi/2), 148 }, 149 { 150 name: "range-twopi/4", 151 title: "[ -pi/4 , twopi ]", 152 rtype: rmeta.Double32, 153 xmin: -math.Pi / 4, 154 xmax: 2 * math.Pi, 155 factor: float64(0xffffffff) / (2*math.Pi + math.Pi/4), 156 }, 157 { 158 name: "range-2pi", 159 title: "[ -2*pi , 2*pi ]", 160 rtype: rmeta.Double32, 161 xmin: -2 * math.Pi, 162 xmax: +2 * math.Pi, 163 factor: float64(0xffffffff) / (4 * math.Pi), 164 }, 165 { 166 name: "float32-15bits", 167 title: "[ 0 , 0 , 15 ]", 168 rtype: rmeta.Double32, 169 }, 170 { 171 name: "float32-14bits", 172 title: "[ 0 , 0 , 14 ]", 173 rtype: rmeta.Double32, 174 xmin: float64(14) + 0.1, 175 }, 176 { 177 name: "float32-3bits", 178 title: "[ 10 , 10 , 3 ]", 179 rtype: rmeta.Double32, 180 xmin: float64(3) + 0.1, 181 xmax: 10, 182 }, 183 { 184 name: "float32-2bits", 185 title: "[ 0 , 0 , 2 ]", 186 rtype: rmeta.Double32, 187 xmin: float64(2) + 0.1, 188 }, 189 } { 190 t.Run(tc.name, func(t *testing.T) { 191 elmt := Element{ 192 Name: *rbase.NewNamed(tc.name, tc.title), 193 Type: tc.rtype, 194 }.New() 195 if got, want := elmt.xmin, tc.xmin; got != want { 196 t.Fatalf("invalid xmin: got=%v, want=%v", got, want) 197 } 198 if got, want := elmt.xmax, tc.xmax; got != want { 199 t.Fatalf("invalid xmax: got=%v, want=%v", got, want) 200 } 201 if got, want := elmt.factor, tc.factor; got != want { 202 t.Fatalf("invalid factor: got=%v, want=%v", got, want) 203 } 204 }) 205 } 206 } 207 208 func TestStreamerSTLElemTypeName(t *testing.T) { 209 for _, tc := range []struct { 210 typ rmeta.ESTLType 211 name string 212 want []string 213 }{ 214 { 215 typ: rmeta.STLvector, 216 name: "vector<T>", 217 want: []string{"T"}, 218 }, 219 { 220 typ: rmeta.STLlist, 221 name: "list<T>", 222 want: []string{"T"}, 223 }, 224 { 225 typ: rmeta.STLdeque, 226 name: "deque<T>", 227 want: []string{"T"}, 228 }, 229 { 230 typ: rmeta.STLset, 231 name: "set<T>", 232 want: []string{"T"}, 233 }, 234 { 235 typ: rmeta.STLunorderedset, 236 name: "unordered_set<T>", 237 want: []string{"T"}, 238 }, 239 { 240 typ: rmeta.STLmap, 241 name: "map<K,V>", 242 want: []string{"K", "V"}, 243 }, 244 { 245 typ: rmeta.STLunorderedmap, 246 name: "unordered_map<K,V>", 247 want: []string{"K", "V"}, 248 }, 249 { 250 typ: rmeta.STLbitset, 251 name: "bitset<8>", 252 want: []string{"8"}, 253 }, 254 } { 255 t.Run(tc.name, func(t *testing.T) { 256 ts := StreamerSTL{ 257 StreamerElement: StreamerElement{ 258 ename: tc.name, 259 }, 260 vtype: tc.typ, 261 } 262 got := ts.ElemTypeName() 263 if got, want := got, tc.want; !reflect.DeepEqual(got, want) { 264 t.Fatalf("invalid ElemTypeName:\ngot= %q\nwant=%q", got, want) 265 } 266 }) 267 } 268 } 269 270 func TestGenChecksum(t *testing.T) { 271 sbt := func(n string, t rmeta.Enum, et string) *StreamerBasicType { 272 return &StreamerBasicType{ 273 StreamerElement: Element{ 274 Name: *rbase.NewNamed(n, ""), 275 Type: t, 276 EName: et, 277 }.New(), 278 } 279 } 280 sbsli := func(n, t string, typ rmeta.Enum, et string) *StreamerBasicType { 281 return &StreamerBasicType{ 282 StreamerElement: Element{ 283 Name: *rbase.NewNamed(n, t), 284 Type: typ + rmeta.OffsetP, 285 EName: et + "*", 286 }.New(), 287 } 288 } 289 sbarr := func(n string, t rmeta.Enum, et string, i int) *StreamerBasicType { 290 return &StreamerBasicType{ 291 StreamerElement: Element{ 292 Name: *rbase.NewNamed(n, ""), 293 Type: t + rmeta.OffsetL, 294 ArrDim: 1, 295 ArrLen: int32(i), 296 MaxIdx: [5]int32{int32(i)}, 297 EName: et, 298 }.New(), 299 } 300 } 301 tstr := func(n string) *StreamerString { 302 return &StreamerString{ 303 StreamerElement: Element{ 304 Name: *rbase.NewNamed(n, ""), 305 Type: rmeta.TString, 306 EName: "TString", 307 }.New(), 308 } 309 } 310 stlstr := func(n string) *StreamerSTLstring { 311 return &StreamerSTLstring{ 312 StreamerSTL: StreamerSTL{ 313 StreamerElement: Element{ 314 Name: *rbase.NewNamed(n, ""), 315 Type: rmeta.TString, 316 EName: "string", 317 }.New(), 318 }, 319 } 320 } 321 stlvec := func(n, et string) *StreamerSTL { 322 return &StreamerSTL{ 323 StreamerElement: Element{ 324 Name: *rbase.NewNamed(n, ""), 325 Type: rmeta.STL, 326 EName: "vector<" + et + ">", 327 }.New(), 328 } 329 } 330 soa := func(n, et string) *StreamerObjectAny { 331 return &StreamerObjectAny{ 332 StreamerElement: Element{ 333 Name: *rbase.NewNamed(n, ""), 334 Type: rmeta.Any, 335 EName: et, 336 }.New(), 337 } 338 } 339 340 for _, tc := range []struct { 341 name string 342 elems []rbytes.StreamerElement 343 want uint32 344 }{ 345 { 346 name: "P3", 347 elems: []rbytes.StreamerElement{ 348 sbt("Px", rmeta.Int32, "int"), 349 sbt("Py", rmeta.Float64, "double"), 350 sbt("Pz", rmeta.Int32, "int"), 351 }, 352 want: 1678002455, // obtained w/ 6.20/04 353 }, 354 { 355 name: "ArrF64", 356 elems: []rbytes.StreamerElement{ 357 sbarr("Arr", rmeta.Float64, "double", 10), 358 }, 359 want: 1711917547, // obtained w/ 6.20/04 360 }, 361 { 362 name: "SliF64", 363 elems: []rbytes.StreamerElement{ 364 sbt("N", rmeta.Int32, "int"), 365 sbsli("Sli", "[N]", rmeta.Float64, "double"), 366 }, 367 want: 193076120, // obtained w/ 6.20/04 368 }, 369 { 370 name: "StlVecF64", 371 elems: []rbytes.StreamerElement{ 372 stlvec("Stl", "double"), 373 }, 374 want: 2364618348, // obtained w/ 6.20/04 375 }, 376 { 377 name: "Event", 378 elems: []rbytes.StreamerElement{ 379 tstr("Beg"), 380 sbt("I16", rmeta.Int16, "short"), 381 sbt("I32", rmeta.Int32, "int"), 382 sbt("I64", rmeta.Int64, "long"), 383 sbt("U16", rmeta.Uint16, "unsigned short"), 384 sbt("U32", rmeta.Uint32, "unsigned int"), 385 sbt("U64", rmeta.Uint64, "unsigned long"), 386 sbt("F32", rmeta.Float32, "float"), 387 sbt("F64", rmeta.Float64, "double"), 388 tstr("Str"), 389 soa("P3", "P3"), 390 sbarr("ArrayI16", rmeta.Int16, "short", 10), 391 sbarr("ArrayI32", rmeta.Int32, "int", 10), 392 sbarr("ArrayI64", rmeta.Int64, "long", 10), 393 sbarr("ArrayU16", rmeta.Uint16, "unsigned short", 10), 394 sbarr("ArrayU32", rmeta.Uint32, "unsigned int", 10), 395 sbarr("ArrayU64", rmeta.Uint64, "unsigned long", 10), 396 sbarr("ArrayF32", rmeta.Float32, "float", 10), 397 sbarr("ArrayF64", rmeta.Float64, "double", 10), 398 sbt("N", rmeta.Int32, "int"), 399 sbsli("SliceI16", "[N]", rmeta.Int16, "short"), 400 sbsli("SliceI32", "[N]", rmeta.Int32, "int"), 401 sbsli("SliceI64", "[N]", rmeta.Int64, "long"), 402 sbsli("SliceU16", "[N]", rmeta.Uint16, "unsigned short"), 403 sbsli("SliceU32", "[N]", rmeta.Uint32, "unsigned int"), 404 sbsli("SliceU64", "[N]", rmeta.Uint64, "unsigned long"), 405 sbsli("SliceF32", "[N]", rmeta.Float32, "float"), 406 sbsli("SliceF64", "[N]", rmeta.Float64, "double"), 407 stlstr("StdStr"), 408 stlvec("StlVecI16", "short"), 409 stlvec("StlVecI32", "int"), 410 stlvec("StlVecI64", "long"), 411 stlvec("StlVecU16", "unsigned short"), 412 stlvec("StlVecU32", "unsigned int"), 413 stlvec("StlVecU64", "unsigned long"), 414 stlvec("StlVecF32", "float"), 415 stlvec("StlVecF64", "double"), 416 stlvec("StlVecStr", "string"), 417 tstr("End"), 418 }, 419 want: 1123173915, // obtained w/ 6.20/04 420 }, 421 } { 422 t.Run(tc.name, func(t *testing.T) { 423 chksum := genChecksum(tc.name, tc.elems) 424 if got, want := chksum, tc.want; got != want { 425 t.Fatalf("invalid checksum: got=%d, want=%d", got, want) 426 } 427 }) 428 } 429 } 430 431 func TestFindCounterOffset(t *testing.T) { 432 ctx := StreamerInfos 433 for _, tc := range []struct { 434 name string 435 vers int 436 count string 437 se int 438 want []int 439 }{ 440 { 441 // StreamerInfo for "TArrayD" version=1 title="" 442 // BASE TArray offset= 0 type= 0 size= 0 Abstract array base class 443 // double* fArray offset= 0 type= 48 size= 8 [fN] Array of fN doubles 444 // 445 // StreamerInfo for "TArray" version=1 title="" 446 // int fN offset= 0 type= 6 size= 4 Number of array elements 447 name: "TArrayD", 448 vers: -1, 449 count: "fN", 450 se: 1, 451 want: []int{0, 0}, 452 }, 453 { 454 name: "TArrayD", 455 vers: -1, 456 count: "fNotThere", 457 se: 1, 458 want: nil, 459 }, 460 { 461 // StreamerInfo for "TRefArray" version=1 title="" 462 // BASE TSeqCollection offset= 0 type= 0 size= 0 Sequenceable collection ABC 463 // TProcessID* fPID offset= 0 type= 64 size= 8 Pointer to Process Unique Identifier 464 // unsigned int* fUIDs offset= 0 type= 53 size= 4 [fSize] To store uids of referenced objects 465 // int fLowerBound offset= 0 type= 3 size= 4 Lower bound of the array 466 // int fLast offset= 0 type= 3 size= 4 Last element in array containing an object 467 // 468 // StreamerInfo for "TSeqCollection" version=0 title="" 469 // BASE TCollection offset= 0 type= 0 size= 0 Collection abstract base class 470 // 471 // StreamerInfo for "TCollection" version=3 title="" 472 // BASE TObject offset= 0 type= 66 size= 0 Basic ROOT object 473 // TString fName offset= 0 type= 65 size= 24 name of the collection 474 // int fSize offset= 0 type= 6 size= 4 number of elements in collection 475 name: "TRefArray", 476 vers: -1, 477 count: "fSize", 478 se: 2, 479 want: []int{0, 0, 2}, 480 }, 481 { 482 // StreamerInfo for "TH2Poly" version=3 title="" 483 // BASE TH2 offset= 0 type= 0 size= 0 2-Dim histogram base class 484 // double fOverflow offset= 0 type= 28 size= 72 Overflow bins 485 // int fCellX offset= 0 type= 3 size= 4 Number of partition cells in the x-direction of the histogram 486 // int fCellY offset= 0 type= 3 size= 4 Number of partition cells in the y-direction of the histogram 487 // int fNCells offset= 0 type= 6 size= 4 Number of partition cells: fCellX*fCellY 488 // TList* fCells offset= 0 type=501 size= 8 [fNCells] The array of TLists that store the bins that intersect with each cell. List do not own the contained objects 489 // double fStepX offset= 0 type= 8 size= 8 Dimensions of a partition cell 490 // double fStepY offset= 0 type= 8 size= 8 Dimensions of a partition cell 491 // bool* fIsEmpty offset= 0 type= 58 size= 1 [fNCells] The array that returns true if the cell at the given coordinate is empty 492 // bool* fCompletelyInside offset= 0 type= 58 size= 1 [fNCells] The array that returns true if the cell at the given coordinate is completely inside a bin 493 // bool fFloat offset= 0 type= 18 size= 1 When set to kTRUE, allows the histogram to expand if a bin outside the limits is added. 494 // TList* fBins offset= 0 type= 64 size= 8 List of bins. The list owns the contained objects 495 name: "TH2Poly", 496 vers: -1, 497 count: "fNCells", 498 se: 5, 499 want: []int{4}, 500 }, 501 } { 502 t.Run(tc.name, func(t *testing.T) { 503 esi, err := ctx.StreamerInfo(tc.name, tc.vers) 504 if err != nil { 505 t.Fatalf("could not find streamer for (%q, v=%d): %+v", tc.name, tc.vers, err) 506 } 507 si := esi.(*StreamerInfo) 508 509 err = si.BuildStreamers() 510 if err != nil { 511 t.Fatalf("could not build streamers for %q: %+v", tc.name, err) 512 } 513 514 se := si.Elements()[tc.se] 515 got := si.findField(ctx, tc.count, se, nil) 516 if got, want := got, tc.want; !reflect.DeepEqual(got, want) { 517 t.Fatalf("invalid offset:\ngot= %v\nwant=%v\nstreamer:\n%v", got, want, si) 518 } 519 }) 520 } 521 } 522 523 func TestNdimsFromType(t *testing.T) { 524 for _, tc := range []struct { 525 typ reflect.Type 526 want string 527 }{ 528 { 529 typ: reflect.TypeOf([]bool{}), 530 want: "", 531 }, 532 { 533 typ: reflect.TypeOf([0]bool{}), 534 want: "[0]", 535 }, 536 { 537 typ: reflect.TypeOf([1]bool{}), 538 want: "[1]", 539 }, 540 { 541 typ: reflect.TypeOf([1][2]bool{}), 542 want: "[1][2]", 543 }, 544 { 545 typ: reflect.TypeOf([1][2][3]bool{}), 546 want: "[1][2][3]", 547 }, 548 { 549 typ: reflect.TypeOf([1][2][3][4]bool{}), 550 want: "[1][2][3][4]", 551 }, 552 { 553 typ: reflect.TypeOf([1][2][3][4][5]bool{}), 554 want: "[1][2][3][4][5]", 555 }, 556 { 557 typ: reflect.TypeOf([1][2][3][4][5][6]bool{}), 558 want: "[1][2][3][4][5][6]", 559 }, 560 } { 561 t.Run(fmt.Sprintf("%v", tc.typ), func(t *testing.T) { 562 got := ndimsFromType(tc.typ) 563 if got != tc.want { 564 t.Fatalf("invalid type:\ngot= %q\nwant=%q", got, tc.want) 565 } 566 }) 567 } 568 }