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  }