go-hep.org/x/hep@v0.38.1/groot/rtree/reader_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 rtree
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"path/filepath"
    11  	"reflect"
    12  	"testing"
    13  
    14  	"go-hep.org/x/hep/groot/internal/rtests"
    15  	"go-hep.org/x/hep/groot/riofs"
    16  	_ "go-hep.org/x/hep/groot/riofs/plugin/xrootd"
    17  	"go-hep.org/x/hep/groot/root"
    18  )
    19  
    20  func TestReader(t *testing.T) {
    21  	f, err := riofs.Open("../testdata/simple.root")
    22  	if err != nil {
    23  		t.Fatalf("could not open ROOT file: %+v", err)
    24  	}
    25  	defer f.Close()
    26  
    27  	o, err := f.Get("tree")
    28  	if err != nil {
    29  		t.Fatalf("could not retrieve ROOT tree: %+v", err)
    30  	}
    31  	tree := o.(Tree)
    32  
    33  	for _, tc := range []struct {
    34  		name  string
    35  		rvars []ReadVar
    36  		ropts []ReadOption
    37  		beg   int64
    38  		end   int64
    39  		fun   func(RCtx) error
    40  		enew  error
    41  		eloop error
    42  	}{
    43  		{
    44  			name: "ok",
    45  			beg:  0, end: -1,
    46  			fun: func(RCtx) error { return nil },
    47  		},
    48  		{
    49  			name: "empty-range",
    50  			beg:  4, end: -1,
    51  			fun: func(RCtx) error { return nil },
    52  		},
    53  		{
    54  			name:  "invalid-rvar",
    55  			rvars: []ReadVar{{Name: "not-there", Value: new(int16)}},
    56  			beg:   0, end: -1,
    57  			fun:  func(RCtx) error { return nil },
    58  			enew: fmt.Errorf(`rtree: could not create reader: rtree: tree "tree" has no branch named "not-there"`),
    59  		},
    60  		{
    61  			name:  "invalid-ropt",
    62  			ropts: []ReadOption{func(r *Reader) error { return io.EOF }},
    63  			beg:   0, end: -1,
    64  			fun:  func(RCtx) error { return nil },
    65  			enew: fmt.Errorf(`rtree: could not set reader option 1: EOF`),
    66  		},
    67  		{
    68  			name: "negative-start",
    69  			beg:  -1, end: -1,
    70  			fun:  func(RCtx) error { return nil },
    71  			enew: fmt.Errorf("rtree: invalid event reader range [-1, 4) (start=-1 < 0)"),
    72  		},
    73  		{
    74  			name: "start-greater-than-end",
    75  			beg:  2, end: 1,
    76  			fun:  func(RCtx) error { return nil },
    77  			enew: fmt.Errorf("rtree: invalid event reader range [2, 1) (start=2 > end=1)"),
    78  		},
    79  		{
    80  			name: "start-greater-than-nentries",
    81  			beg:  5, end: 10,
    82  			fun:  func(RCtx) error { return nil },
    83  			enew: fmt.Errorf("rtree: invalid event reader range [5, 10) (start=5 > tree-entries=4)"),
    84  		},
    85  		{
    86  			name: "end-greater-than-nentries",
    87  			beg:  0, end: 5,
    88  			fun:  func(RCtx) error { return nil },
    89  			enew: fmt.Errorf("rtree: invalid event reader range [0, 5) (end=5 > tree-entries=4)"),
    90  		},
    91  		{
    92  			name: "process-error",
    93  			beg:  0, end: 4,
    94  			fun: func(ctx RCtx) error {
    95  				if ctx.Entry == 2 {
    96  					return io.EOF
    97  				}
    98  				return nil
    99  			},
   100  			eloop: fmt.Errorf("rtree: could not process entry 2: EOF"),
   101  		},
   102  	} {
   103  		t.Run(tc.name, func(t *testing.T) {
   104  			var (
   105  				v1 int32
   106  				v2 float32
   107  				v3 string
   108  
   109  				rvars = []ReadVar{
   110  					{Name: "one", Value: &v1},
   111  					{Name: "two", Value: &v2},
   112  					{Name: "three", Value: &v3},
   113  				}
   114  			)
   115  
   116  			if tc.rvars != nil {
   117  				rvars = tc.rvars
   118  			}
   119  
   120  			ropts := []ReadOption{WithRange(tc.beg, tc.end)}
   121  			if tc.ropts != nil {
   122  				ropts = append(ropts, tc.ropts...)
   123  			}
   124  
   125  			r, err := NewReader(tree, rvars, ropts...)
   126  			switch {
   127  			case err != nil && tc.enew != nil:
   128  				if got, want := err.Error(), tc.enew.Error(); got != want {
   129  					t.Fatalf("invalid error:\ngot= %v\nwant=%v", got, want)
   130  				}
   131  				return
   132  			case err != nil && tc.enew == nil:
   133  				t.Fatalf("unexpected error: %v", err)
   134  			case err == nil && tc.enew != nil:
   135  				t.Fatalf("expected an error: got=%v, want=%v", err, tc.enew)
   136  			case err == nil && tc.enew == nil:
   137  				// ok.
   138  			}
   139  			defer r.Close()
   140  
   141  			err = r.Read(tc.fun)
   142  
   143  			switch {
   144  			case err != nil && tc.eloop != nil:
   145  				if got, want := err.Error(), tc.eloop.Error(); got != want {
   146  					t.Fatalf("invalid error:\ngot= %v\nwant=%v", got, want)
   147  				}
   148  			case err != nil && tc.eloop == nil:
   149  				t.Fatalf("unexpected error: %v", err)
   150  			case err == nil && tc.eloop != nil:
   151  				t.Fatalf("expected an error: got=%v, want=%v", err, tc.eloop)
   152  			case err == nil && tc.eloop == nil:
   153  				// ok.
   154  			}
   155  
   156  			err = r.Close()
   157  			if err != nil {
   158  				t.Fatalf("could not close tree reader: %+v", err)
   159  			}
   160  
   161  			// check r.Close is idem-potent.
   162  			err = r.Close()
   163  			if err != nil {
   164  				t.Fatalf("tree reader close not idem-potent: %+v", err)
   165  			}
   166  		})
   167  	}
   168  }
   169  
   170  type ScannerData struct {
   171  	B      bool              `groot:"B"`
   172  	Str    string            `groot:"Str"`
   173  	I8     int8              `groot:"I8"`
   174  	I16    int16             `groot:"I16"`
   175  	I32    int32             `groot:"I32"`
   176  	I64    int64             `groot:"I64"`
   177  	U8     uint8             `groot:"U8"`
   178  	U16    uint16            `groot:"U16"`
   179  	U32    uint32            `groot:"U32"`
   180  	U64    uint64            `groot:"U64"`
   181  	F32    float32           `groot:"F32"`
   182  	F64    float64           `groot:"F64"`
   183  	D16    root.Float16      `groot:"D16"`
   184  	D32    root.Double32     `groot:"D32"`
   185  	ArrBs  [10]bool          `groot:"ArrBs[10]"`
   186  	ArrI8  [10]int8          `groot:"ArrI8[10]"`
   187  	ArrI16 [10]int16         `groot:"ArrI16[10]"`
   188  	ArrI32 [10]int32         `groot:"ArrI32[10]"`
   189  	ArrI64 [10]int64         `groot:"ArrI64[10]"`
   190  	ArrU8  [10]uint8         `groot:"ArrU8[10]"`
   191  	ArrU16 [10]uint16        `groot:"ArrU16[10]"`
   192  	ArrU32 [10]uint32        `groot:"ArrU32[10]"`
   193  	ArrU64 [10]uint64        `groot:"ArrU64[10]"`
   194  	ArrF32 [10]float32       `groot:"ArrF32[10]"`
   195  	ArrF64 [10]float64       `groot:"ArrF64[10]"`
   196  	ArrD16 [10]root.Float16  `groot:"ArrD16[10]"`
   197  	ArrD32 [10]root.Double32 `groot:"ArrD32[10]"`
   198  	N      int32             `groot:"N"`
   199  	SliBs  []bool            `groot:"SliBs[N]"`
   200  	SliI8  []int8            `groot:"SliI8[N]"`
   201  	SliI16 []int16           `groot:"SliI16[N]"`
   202  	SliI32 []int32           `groot:"SliI32[N]"`
   203  	SliI64 []int64           `groot:"SliI64[N]"`
   204  	SliU8  []uint8           `groot:"SliU8[N]"`
   205  	SliU16 []uint16          `groot:"SliU16[N]"`
   206  	SliU32 []uint32          `groot:"SliU32[N]"`
   207  	SliU64 []uint64          `groot:"SliU64[N]"`
   208  	SliF32 []float32         `groot:"SliF32[N]"`
   209  	SliF64 []float64         `groot:"SliF64[N]"`
   210  	SliD16 []root.Float16    `groot:"SliD16[N]"`
   211  	SliD32 []root.Double32   `groot:"SliD32[N]"`
   212  }
   213  
   214  func (ScannerData) want(i int64) (data ScannerData) {
   215  	data.B = i%2 == 0
   216  	data.Str = fmt.Sprintf("str-%d", i)
   217  	data.I8 = int8(-i)
   218  	data.I16 = int16(-i)
   219  	data.I32 = int32(-i)
   220  	data.I64 = int64(-i)
   221  	data.U8 = uint8(i)
   222  	data.U16 = uint16(i)
   223  	data.U32 = uint32(i)
   224  	data.U64 = uint64(i)
   225  	data.F32 = float32(i)
   226  	data.F64 = float64(i)
   227  	data.D16 = root.Float16(i)
   228  	data.D32 = root.Double32(i)
   229  	for ii := range data.ArrI32 {
   230  		data.ArrBs[ii] = ii == int(i)
   231  		data.ArrI8[ii] = int8(-i)
   232  		data.ArrI16[ii] = int16(-i)
   233  		data.ArrI32[ii] = int32(-i)
   234  		data.ArrI64[ii] = int64(-i)
   235  		data.ArrU8[ii] = uint8(i)
   236  		data.ArrU16[ii] = uint16(i)
   237  		data.ArrU32[ii] = uint32(i)
   238  		data.ArrU64[ii] = uint64(i)
   239  		data.ArrF32[ii] = float32(i)
   240  		data.ArrF64[ii] = float64(i)
   241  		data.ArrD16[ii] = root.Float16(i)
   242  		data.ArrD32[ii] = root.Double32(i)
   243  	}
   244  	data.N = int32(i) % 10
   245  	data.SliBs = make([]bool, int(data.N))
   246  	data.SliI8 = make([]int8, int(data.N))
   247  	data.SliI16 = make([]int16, int(data.N))
   248  	data.SliI32 = make([]int32, int(data.N))
   249  	data.SliI64 = make([]int64, int(data.N))
   250  	data.SliU8 = make([]uint8, int(data.N))
   251  	data.SliU16 = make([]uint16, int(data.N))
   252  	data.SliU32 = make([]uint32, int(data.N))
   253  	data.SliU64 = make([]uint64, int(data.N))
   254  	data.SliF32 = make([]float32, int(data.N))
   255  	data.SliF64 = make([]float64, int(data.N))
   256  	data.SliD16 = make([]root.Float16, int(data.N))
   257  	data.SliD32 = make([]root.Double32, int(data.N))
   258  	for ii := range int(data.N) {
   259  		data.SliBs[ii] = (ii + 1) == int(i)
   260  		data.SliI8[ii] = int8(-i)
   261  		data.SliI16[ii] = int16(-i)
   262  		data.SliI32[ii] = int32(-i)
   263  		data.SliI64[ii] = int64(-i)
   264  		data.SliU8[ii] = uint8(i)
   265  		data.SliU16[ii] = uint16(i)
   266  		data.SliU32[ii] = uint32(i)
   267  		data.SliU64[ii] = uint64(i)
   268  		data.SliF32[ii] = float32(i)
   269  		data.SliF64[ii] = float64(i)
   270  		data.SliD16[ii] = root.Float16(i)
   271  		data.SliD32[ii] = root.Double32(i)
   272  	}
   273  	return data
   274  }
   275  
   276  func TestReaderStruct(t *testing.T) {
   277  	files := []string{
   278  		"../testdata/x-flat-tree.root",
   279  		rtests.XrdRemote("testdata/x-flat-tree.root"),
   280  	}
   281  	for i := range files {
   282  		fname := files[i]
   283  		t.Run(fname, func(t *testing.T) {
   284  			t.Parallel()
   285  
   286  			f, err := riofs.Open(fname)
   287  			if err != nil {
   288  				t.Fatal(err.Error())
   289  			}
   290  			defer f.Close()
   291  
   292  			obj, err := f.Get("tree")
   293  			if err != nil {
   294  				t.Fatal(err)
   295  			}
   296  			tree := obj.(Tree)
   297  
   298  			var (
   299  				want = ScannerData{}.want
   300  				data ScannerData
   301  			)
   302  			r, err := NewReader(tree, ReadVarsFromStruct(&data))
   303  			if err != nil {
   304  				t.Fatal(err)
   305  			}
   306  			defer r.Close()
   307  			err = r.Read(func(ctx RCtx) error {
   308  				if got, want := data, want(ctx.Entry); !reflect.DeepEqual(got, want) {
   309  					return fmt.Errorf(
   310  						"entry[%d]:\ngot= %#v\nwant=%#v\n",
   311  						ctx.Entry, got, want,
   312  					)
   313  				}
   314  				return nil
   315  			})
   316  			if err != nil && err != io.EOF {
   317  				t.Fatal(err)
   318  			}
   319  		})
   320  	}
   321  }
   322  
   323  func TestReaderWithBufferEvent(t *testing.T) {
   324  	type Event struct {
   325  		B      bool        `groot:"B"`
   326  		Str    string      `groot:"Str"`
   327  		I8     int8        `groot:"I8"`
   328  		I16    int16       `groot:"I16"`
   329  		I32    int32       `groot:"I32"`
   330  		I64    int64       `groot:"I64"`
   331  		U8     uint8       `groot:"U8"`
   332  		U16    uint16      `groot:"U16"`
   333  		U32    uint32      `groot:"U32"`
   334  		U64    uint64      `groot:"U64"`
   335  		F32    float32     `groot:"F32"`
   336  		F64    float64     `groot:"F64"`
   337  		ArrBs  [10]bool    `groot:"ArrBs[10]"`
   338  		ArrI8  [10]int8    `groot:"ArrI8[10]"`
   339  		ArrI16 [10]int16   `groot:"ArrI16[10]"`
   340  		ArrI32 [10]int32   `groot:"ArrI32[10]"`
   341  		ArrI64 [10]int64   `groot:"ArrI64[10]"`
   342  		ArrU8  [10]uint8   `groot:"ArrU8[10]"`
   343  		ArrU16 [10]uint16  `groot:"ArrU16[10]"`
   344  		ArrU32 [10]uint32  `groot:"ArrU32[10]"`
   345  		ArrU64 [10]uint64  `groot:"ArrU64[10]"`
   346  		ArrF32 [10]float32 `groot:"ArrF32[10]"`
   347  		ArrF64 [10]float64 `groot:"ArrF64[10]"`
   348  	}
   349  	wantEvent := func(i int64) (evt Event) {
   350  		evt.B = i%2 == 0
   351  		evt.Str = fmt.Sprintf("str-%d", i)
   352  		evt.I8 = int8(-i)
   353  		evt.I16 = int16(-i)
   354  		evt.I32 = int32(-i)
   355  		evt.I64 = int64(-i)
   356  		evt.U8 = uint8(i)
   357  		evt.U16 = uint16(i)
   358  		evt.U32 = uint32(i)
   359  		evt.U64 = uint64(i)
   360  		evt.F32 = float32(i)
   361  		evt.F64 = float64(i)
   362  		for ii := range evt.ArrI32 {
   363  			evt.ArrBs[ii] = ii == int(i)
   364  			evt.ArrI8[ii] = int8(-i)
   365  			evt.ArrI16[ii] = int16(-i)
   366  			evt.ArrI32[ii] = int32(-i)
   367  			evt.ArrI64[ii] = int64(-i)
   368  			evt.ArrU8[ii] = uint8(i)
   369  			evt.ArrU16[ii] = uint16(i)
   370  			evt.ArrU32[ii] = uint32(i)
   371  			evt.ArrU64[ii] = uint64(i)
   372  			evt.ArrF32[ii] = float32(i)
   373  			evt.ArrF64[ii] = float64(i)
   374  		}
   375  		return evt
   376  	}
   377  
   378  	files := []string{
   379  		"../testdata/x-flat-bufevt.root",
   380  	}
   381  	for i := range files {
   382  		fname := files[i]
   383  		t.Run(fname, func(t *testing.T) {
   384  			t.Parallel()
   385  
   386  			f, err := riofs.Open(fname)
   387  			if err != nil {
   388  				t.Fatal(err.Error())
   389  			}
   390  			defer f.Close()
   391  
   392  			obj, err := f.Get("tree")
   393  			if err != nil {
   394  				t.Fatal(err)
   395  			}
   396  			tree := obj.(Tree)
   397  
   398  			var (
   399  				want = wantEvent
   400  				data Event
   401  			)
   402  			r, err := NewReader(tree, []ReadVar{{Name: "Event", Value: &data}})
   403  			if err != nil {
   404  				t.Fatal(err)
   405  			}
   406  			defer r.Close()
   407  			err = r.Read(func(ctx RCtx) error {
   408  				if got, want := data, want(ctx.Entry); !reflect.DeepEqual(got, want) {
   409  					return fmt.Errorf(
   410  						"entry[%d]:\ngot= %#v\nwant=%#v\n",
   411  						ctx.Entry, got, want,
   412  					)
   413  				}
   414  				return nil
   415  			})
   416  			if err != nil && err != io.EOF {
   417  				t.Fatal(err)
   418  			}
   419  		})
   420  	}
   421  }
   422  
   423  func TestReaderVars(t *testing.T) {
   424  	files := []string{
   425  		"../testdata/x-flat-tree.root",
   426  		rtests.XrdRemote("testdata/x-flat-tree.root"),
   427  	}
   428  	for i := range files {
   429  		fname := files[i]
   430  		t.Run(fname, func(t *testing.T) {
   431  			t.Parallel()
   432  
   433  			f, err := riofs.Open(fname)
   434  			if err != nil {
   435  				t.Fatal(err.Error())
   436  			}
   437  			defer f.Close()
   438  
   439  			obj, err := f.Get("tree")
   440  			if err != nil {
   441  				t.Fatal(err)
   442  			}
   443  
   444  			tree := obj.(Tree)
   445  
   446  			want := ScannerData{}.want
   447  
   448  			var (
   449  				data  ScannerData
   450  				rvars = ReadVarsFromStruct(&data)
   451  			)
   452  			r, err := NewReader(tree, rvars)
   453  			if err != nil {
   454  				t.Fatal(err)
   455  			}
   456  			defer r.Close()
   457  
   458  			err = r.Read(func(ctx RCtx) error {
   459  				if got, want := data, want(ctx.Entry); !reflect.DeepEqual(got, want) {
   460  					return fmt.Errorf(
   461  						"entry[%d]:\ngot= %#v\nwant=%#v\n",
   462  						ctx.Entry, got, want,
   463  					)
   464  				}
   465  				return nil
   466  			})
   467  			if err != nil && err != io.EOF {
   468  				t.Fatal(err)
   469  			}
   470  		})
   471  	}
   472  }
   473  
   474  func TestReaderVarsMultipleTimes(t *testing.T) {
   475  	files := []string{
   476  		"../testdata/mc_105986.ZZ.root",
   477  		rtests.XrdRemote("testdata/mc_105986.ZZ.root"),
   478  	}
   479  	for i := range files {
   480  		fname := files[i]
   481  		t.Run(fname, func(t *testing.T) {
   482  			t.Parallel()
   483  
   484  			f, err := riofs.Open(fname)
   485  			if err != nil {
   486  				t.Skip(err)
   487  			}
   488  
   489  			obj, err := f.Get("mini")
   490  			if err != nil {
   491  				t.Fatal(err)
   492  			}
   493  			tree := obj.(Tree)
   494  
   495  			for range 2 {
   496  				var (
   497  					data  []float32
   498  					rvars = []ReadVar{
   499  						{Name: "lep_pt", Value: &data},
   500  					}
   501  				)
   502  				r, err := NewReader(tree, rvars)
   503  				if err != nil {
   504  					t.Fatal(err)
   505  				}
   506  				defer r.Close()
   507  
   508  				err = r.Read(func(ctx RCtx) error {
   509  					return nil
   510  				})
   511  				if err != nil {
   512  					t.Error(err)
   513  				}
   514  			}
   515  		})
   516  	}
   517  }
   518  
   519  func TestReaderStructWithCounterLeaf(t *testing.T) {
   520  	files := []string{
   521  		"../testdata/x-flat-tree.root",
   522  		rtests.XrdRemote("testdata/x-flat-tree.root"),
   523  	}
   524  	for i := range files {
   525  		fname := files[i]
   526  		t.Run(fname, func(t *testing.T) {
   527  			t.Parallel()
   528  
   529  			f, err := riofs.Open(fname)
   530  			if err != nil {
   531  				t.Fatal(err.Error())
   532  			}
   533  			defer f.Close()
   534  
   535  			obj, err := f.Get("tree")
   536  			if err != nil {
   537  				t.Fatal(err)
   538  			}
   539  
   540  			tree := obj.(Tree)
   541  
   542  			type Data struct {
   543  				Sli []int32 `groot:"SliI32"`
   544  			}
   545  			var data Data
   546  
   547  			want := func(i int64) Data {
   548  				var data Data
   549  				n := int32(i) % 10
   550  				data.Sli = make([]int32, int(n))
   551  				for ii := range int(n) {
   552  					data.Sli[ii] = int32(-i)
   553  				}
   554  				return data
   555  			}
   556  
   557  			r, err := NewReader(tree, ReadVarsFromStruct(&data))
   558  			if err != nil {
   559  				t.Fatal(err)
   560  			}
   561  			defer r.Close()
   562  
   563  			err = r.Read(func(ctx RCtx) error {
   564  				if got, want := data, want(ctx.Entry); !reflect.DeepEqual(got, want) {
   565  					return fmt.Errorf(
   566  						"entry[%d]:\ngot= %#v\nwant=%#v\n",
   567  						ctx.Entry, got, want,
   568  					)
   569  				}
   570  				return nil
   571  			})
   572  			if err != nil && err != io.EOF {
   573  				t.Fatal(err)
   574  			}
   575  		})
   576  	}
   577  }
   578  
   579  func TestReaderVarsWithCounterLeaf(t *testing.T) {
   580  	files := []string{
   581  		"../testdata/x-flat-tree.root",
   582  		rtests.XrdRemote("testdata/x-flat-tree.root"),
   583  	}
   584  	for i := range files {
   585  		fname := files[i]
   586  		t.Run(fname, func(t *testing.T) {
   587  			t.Parallel()
   588  
   589  			f, err := riofs.Open(fname)
   590  			if err != nil {
   591  				t.Fatal(err.Error())
   592  			}
   593  			defer f.Close()
   594  
   595  			obj, err := f.Get("tree")
   596  			if err != nil {
   597  				t.Fatal(err)
   598  			}
   599  
   600  			tree := obj.(Tree)
   601  
   602  			want := func(i int64) []int32 {
   603  				n := int32(i) % 10
   604  				data := make([]int32, int(n))
   605  				for ii := range int(n) {
   606  					data[ii] = int32(-i)
   607  				}
   608  				return data
   609  			}
   610  
   611  			var (
   612  				data  []int32
   613  				rvars = []ReadVar{
   614  					{Name: "SliI32", Value: &data},
   615  				}
   616  			)
   617  			r, err := NewReader(tree, rvars)
   618  			if err != nil {
   619  				t.Fatal(err)
   620  			}
   621  			defer r.Close()
   622  
   623  			err = r.Read(func(ctx RCtx) error {
   624  				if got, want := data, want(ctx.Entry); !reflect.DeepEqual(got, want) {
   625  					return fmt.Errorf(
   626  						"entry[%d]:\ngot= %#v\nwant=%#v\n",
   627  						ctx.Entry, got, want,
   628  					)
   629  				}
   630  				return nil
   631  			})
   632  			if err != nil && err != io.EOF {
   633  				t.Fatal(err)
   634  			}
   635  		})
   636  	}
   637  }
   638  
   639  func TestScannerStructWithStdVectorBool(t *testing.T) {
   640  	files, err := filepath.Glob("../testdata/stdvec-bool-*.root")
   641  	if err != nil {
   642  		t.Fatal(err)
   643  	}
   644  
   645  	for i := range files {
   646  		fname := files[i]
   647  		t.Run(fname, func(t *testing.T) {
   648  			t.Parallel()
   649  
   650  			f, err := riofs.Open(fname)
   651  			if err != nil {
   652  				t.Fatal(err.Error())
   653  			}
   654  			defer f.Close()
   655  
   656  			obj, err := f.Get("tree")
   657  			if err != nil {
   658  				t.Fatal(err)
   659  			}
   660  			tree := obj.(Tree)
   661  
   662  			type Data struct {
   663  				Bool    bool     `groot:"Bool"`
   664  				ArrBool [10]bool `groot:"ArrayBool"`
   665  				N       int32    `groot:"N"`
   666  				SliBool []bool   `groot:"SliceBool[N]"`
   667  				StlBool []bool   `groot:"StlVecBool"`
   668  			}
   669  			type Event struct {
   670  				Data Data `groot:"evt"`
   671  			}
   672  
   673  			want := func(i int64) Event {
   674  				var data Data
   675  				data.Bool = i%2 == 0
   676  				for ii := range data.ArrBool {
   677  					data.ArrBool[ii] = i%2 == 0
   678  				}
   679  				data.N = int32(i) % 10
   680  				switch i {
   681  				case 0:
   682  					data.SliBool = nil
   683  					data.StlBool = nil
   684  				default:
   685  					data.SliBool = make([]bool, int(data.N))
   686  					data.StlBool = make([]bool, int(data.N))
   687  				}
   688  				for ii := range int(data.N) {
   689  					data.SliBool[ii] = i%2 == 0
   690  					data.StlBool[ii] = i%2 == 0
   691  				}
   692  				return Event{data}
   693  			}
   694  
   695  			var data Event
   696  			r, err := NewReader(tree, ReadVarsFromStruct(&data))
   697  			if err != nil {
   698  				t.Fatal(err)
   699  			}
   700  			defer r.Close()
   701  
   702  			err = r.Read(func(ctx RCtx) error {
   703  				if got, want := data, want(ctx.Entry); !reflect.DeepEqual(got, want) {
   704  					return fmt.Errorf(
   705  						"entry[%d]:\ngot= %#v\nwant=%#v\n",
   706  						ctx.Entry, got, want,
   707  					)
   708  				}
   709  				return nil
   710  
   711  			})
   712  			if err != nil && err != io.EOF {
   713  				t.Fatal(err)
   714  			}
   715  		})
   716  	}
   717  }
   718  
   719  func TestNewReadVarsLeaves(t *testing.T) {
   720  	f, err := riofs.Open("../testdata/leaves.root")
   721  	if err != nil {
   722  		t.Fatal(err)
   723  	}
   724  	defer f.Close()
   725  
   726  	o, err := f.Get("tree")
   727  	if err != nil {
   728  		t.Fatal(err)
   729  	}
   730  
   731  	tree := o.(Tree)
   732  
   733  	vars := NewReadVars(tree)
   734  	want := []ReadVar{
   735  		{Name: "B", Leaf: "B", Value: new(bool)},
   736  		{Name: "Str", Leaf: "Str", Value: new(string)},
   737  		{Name: "I8", Leaf: "I8", Value: new(int8)},
   738  		{Name: "I16", Leaf: "I16", Value: new(int16)},
   739  		{Name: "I32", Leaf: "I32", Value: new(int32)},
   740  		{Name: "I64", Leaf: "I64", Value: new(int64)},
   741  		{Name: "G64", Leaf: "G64", Value: new(int64)},
   742  		{Name: "U8", Leaf: "U8", Value: new(uint8)},
   743  		{Name: "U16", Leaf: "U16", Value: new(uint16)},
   744  		{Name: "U32", Leaf: "U32", Value: new(uint32)},
   745  		{Name: "U64", Leaf: "U64", Value: new(uint64)},
   746  		{Name: "UGG", Leaf: "UGG", Value: new(uint64)},
   747  		{Name: "F32", Leaf: "F32", Value: new(float32)},
   748  		{Name: "F64", Leaf: "F64", Value: new(float64)},
   749  		{Name: "D16", Leaf: "D16", Value: new(root.Float16)},
   750  		{Name: "D32", Leaf: "D32", Value: new(root.Double32)},
   751  		// arrays
   752  		{Name: "ArrBs", Leaf: "ArrBs", Value: new([10]bool)},
   753  		{Name: "ArrI8", Leaf: "ArrI8", Value: new([10]int8)},
   754  		{Name: "ArrI16", Leaf: "ArrI16", Value: new([10]int16)},
   755  		{Name: "ArrI32", Leaf: "ArrI32", Value: new([10]int32)},
   756  		{Name: "ArrI64", Leaf: "ArrI64", Value: new([10]int64)},
   757  		{Name: "ArrG64", Leaf: "ArrG64", Value: new([10]int64)},
   758  		{Name: "ArrU8", Leaf: "ArrU8", Value: new([10]uint8)},
   759  		{Name: "ArrU16", Leaf: "ArrU16", Value: new([10]uint16)},
   760  		{Name: "ArrU32", Leaf: "ArrU32", Value: new([10]uint32)},
   761  		{Name: "ArrU64", Leaf: "ArrU64", Value: new([10]uint64)},
   762  		{Name: "ArrUGG", Leaf: "ArrUGG", Value: new([10]uint64)},
   763  		{Name: "ArrF32", Leaf: "ArrF32", Value: new([10]float32)},
   764  		{Name: "ArrF64", Leaf: "ArrF64", Value: new([10]float64)},
   765  		{Name: "ArrD16", Leaf: "ArrD16", Value: new([10]root.Float16)},
   766  		{Name: "ArrD32", Leaf: "ArrD32", Value: new([10]root.Double32)},
   767  		// slices
   768  		{Name: "N", Leaf: "N", Value: new(int32)},
   769  		{Name: "SliBs", Leaf: "SliBs", Value: new([]bool)},
   770  		{Name: "SliI8", Leaf: "SliI8", Value: new([]int8)},
   771  		{Name: "SliI16", Leaf: "SliI16", Value: new([]int16)},
   772  		{Name: "SliI32", Leaf: "SliI32", Value: new([]int32)},
   773  		{Name: "SliI64", Leaf: "SliI64", Value: new([]int64)},
   774  		{Name: "SliG64", Leaf: "SliG64", Value: new([]int64)},
   775  		{Name: "SliU8", Leaf: "SliU8", Value: new([]uint8)},
   776  		{Name: "SliU16", Leaf: "SliU16", Value: new([]uint16)},
   777  		{Name: "SliU32", Leaf: "SliU32", Value: new([]uint32)},
   778  		{Name: "SliU64", Leaf: "SliU64", Value: new([]uint64)},
   779  		{Name: "SliUGG", Leaf: "SliUGG", Value: new([]uint64)},
   780  		{Name: "SliF32", Leaf: "SliF32", Value: new([]float32)},
   781  		{Name: "SliF64", Leaf: "SliF64", Value: new([]float64)},
   782  		{Name: "SliD16", Leaf: "SliD16", Value: new([]root.Float16)},
   783  		{Name: "SliD32", Leaf: "SliD32", Value: new([]root.Double32)},
   784  	}
   785  
   786  	n := min(len(vars), len(want))
   787  
   788  	for i := range n {
   789  		got := vars[i]
   790  		if got.Name != want[i].Name {
   791  			t.Fatalf("invalid read-var name[%d]: got=%q, want=%q", i, got.Name, want[i].Name)
   792  		}
   793  		if got.Leaf != want[i].Leaf {
   794  			t.Fatalf("invalid read-var (name=%q) leaf-name[%d]: got=%q, want=%q", got.Name, i, got.Leaf, want[i].Leaf)
   795  		}
   796  		if got, want := reflect.TypeOf(got.Value), reflect.TypeOf(want[i].Value); got != want {
   797  			t.Fatalf("invalid read-var (name=%q) type[%d]: got=%v, want=%v", vars[i].Name, i, got, want)
   798  		}
   799  	}
   800  
   801  	if len(want) != len(vars) {
   802  		t.Fatalf("invalid lengths. got=%d, want=%d", len(vars), len(want))
   803  	}
   804  }
   805  
   806  func TestG4LikeTree(t *testing.T) {
   807  	t.Parallel()
   808  	fname := rtests.XrdRemote("testdata/g4-like.root")
   809  
   810  	f, err := riofs.Open(fname)
   811  	if err != nil {
   812  		t.Fatal(err.Error())
   813  	}
   814  	defer f.Close()
   815  
   816  	obj, err := f.Get("mytree")
   817  	if err != nil {
   818  		t.Fatal(err)
   819  	}
   820  
   821  	tree := obj.(Tree)
   822  
   823  	type EventData struct {
   824  		I32 int32     `groot:"i32"`
   825  		F64 float64   `groot:"f64"`
   826  		Sli []float64 `groot:"slif64"`
   827  	}
   828  
   829  	want := func(i int64) (data EventData) {
   830  		data.I32 = int32(i + 1)
   831  		data.F64 = float64(i + 1)
   832  		data.Sli = make([]float64, i)
   833  		for ii := range data.Sli {
   834  			data.Sli[ii] = float64(ii) + float64(i)
   835  		}
   836  		return data
   837  	}
   838  
   839  	data := EventData{
   840  		Sli: make([]float64, 0),
   841  	}
   842  	rvars := []ReadVar{
   843  		{Name: "i32", Value: &data.I32},
   844  		{Name: "f64", Value: &data.F64},
   845  		{Name: "slif64", Value: &data.Sli},
   846  	}
   847  	r, err := NewReader(tree, rvars)
   848  	if err != nil {
   849  		t.Fatal(err)
   850  	}
   851  	defer r.Close()
   852  
   853  	err = r.Read(func(ctx RCtx) error {
   854  		if got, want := data, want(ctx.Entry); !reflect.DeepEqual(got, want) {
   855  			return fmt.Errorf(
   856  				"entry[%d]:\ngot= %#v\nwant=%#v\n",
   857  				ctx.Entry, got, want,
   858  			)
   859  		}
   860  		return nil
   861  	})
   862  	if err != nil && err != io.EOF {
   863  		t.Fatal(err)
   864  	}
   865  }
   866  
   867  func TestMultiLeafBranchWithReadVars(t *testing.T) {
   868  	t.Parallel()
   869  
   870  	f, err := riofs.Open("../testdata/root_numpy_struct.root")
   871  	if err != nil {
   872  		t.Fatalf("%+v", err)
   873  	}
   874  	defer f.Close()
   875  
   876  	obj, err := f.Get("test")
   877  	if err != nil {
   878  		t.Fatalf("%+v", err)
   879  	}
   880  
   881  	tree := obj.(Tree)
   882  
   883  	type Data struct {
   884  		b1l1 int32
   885  		b1l2 float32
   886  		b2l1 int32
   887  		b2l2 float32
   888  	}
   889  
   890  	var (
   891  		data Data
   892  		want = []Data{
   893  			{10, 15.5, 20, 781.2},
   894  		}
   895  	)
   896  
   897  	rvars := []ReadVar{
   898  		{
   899  			Name:  "branch1",
   900  			Leaf:  "intleaf",
   901  			Value: &data.b1l1,
   902  		},
   903  		{
   904  			Name:  "branch1",
   905  			Leaf:  "floatleaf",
   906  			Value: &data.b1l2,
   907  		},
   908  		{
   909  			Name:  "branch2",
   910  			Leaf:  "intleaf",
   911  			Value: &data.b2l1,
   912  		},
   913  		{
   914  			Name:  "branch2",
   915  			Leaf:  "floatleaf",
   916  			Value: &data.b2l2,
   917  		},
   918  	}
   919  
   920  	r, err := NewReader(tree, rvars)
   921  	if err != nil {
   922  		t.Fatalf("could not create reader: %+v", err)
   923  	}
   924  	defer r.Close()
   925  
   926  	err = r.Read(func(ctx RCtx) error {
   927  		if got, want := data, want[ctx.Entry]; !reflect.DeepEqual(got, want) {
   928  			return fmt.Errorf(
   929  				"entry[%d]:\ngot= %#v\nwant=%#v\n",
   930  				ctx.Entry, got, want,
   931  			)
   932  		}
   933  		return nil
   934  	})
   935  
   936  	if err != nil {
   937  		t.Fatal(err)
   938  	}
   939  }
   940  
   941  func TestMultiLeafBranchWithTreeReadVars(t *testing.T) {
   942  	t.Parallel()
   943  
   944  	f, err := riofs.Open("../testdata/root_numpy_struct.root")
   945  	if err != nil {
   946  		t.Fatalf("%+v", err)
   947  	}
   948  	defer f.Close()
   949  
   950  	obj, err := f.Get("test")
   951  	if err != nil {
   952  		t.Fatalf("%+v", err)
   953  	}
   954  
   955  	tree := obj.(Tree)
   956  
   957  	type B struct {
   958  		L1 int32   `groot:"intleaf"`
   959  		L2 float32 `groot:"floatleaf"`
   960  	}
   961  
   962  	type Data struct {
   963  		B1 B `groot:"branch1"`
   964  		B2 B `groot:"branch2"`
   965  	}
   966  
   967  	var (
   968  		data Data
   969  		want = []Data{
   970  			{B{10, 15.5}, B{20, 781.2}},
   971  		}
   972  	)
   973  
   974  	rvars := []ReadVar{
   975  		{
   976  			Name:  "branch1",
   977  			Leaf:  "intleaf",
   978  			Value: &data.B1.L1,
   979  		},
   980  		{
   981  			Name:  "branch1",
   982  			Leaf:  "floatleaf",
   983  			Value: &data.B1.L2,
   984  		},
   985  		{
   986  			Name:  "branch2",
   987  			Leaf:  "intleaf",
   988  			Value: &data.B2.L1,
   989  		},
   990  		{
   991  			Name:  "branch2",
   992  			Leaf:  "floatleaf",
   993  			Value: &data.B2.L2,
   994  		},
   995  	}
   996  
   997  	r, err := NewReader(tree, rvars)
   998  	if err != nil {
   999  		t.Fatalf("could not create reader: %+v", err)
  1000  	}
  1001  	defer r.Close()
  1002  
  1003  	err = r.Read(func(ctx RCtx) error {
  1004  		if got, want := data, want[ctx.Entry]; !reflect.DeepEqual(got, want) {
  1005  			return fmt.Errorf(
  1006  				"entry[%d]:\ngot= %#v\nwant=%#v\n",
  1007  				ctx.Entry, got, want,
  1008  			)
  1009  		}
  1010  		return nil
  1011  	})
  1012  	if err != nil {
  1013  		t.Fatal(err)
  1014  	}
  1015  }