go-hep.org/x/hep@v0.38.1/groot/rcont/clonesarray_test.go (about)

     1  // Copyright ©2019 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 rcont_test
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"path/filepath"
    12  	"reflect"
    13  	"testing"
    14  
    15  	"go-hep.org/x/hep/groot"
    16  	"go-hep.org/x/hep/groot/internal/rtests"
    17  	"go-hep.org/x/hep/groot/rbase"
    18  	"go-hep.org/x/hep/groot/rbytes"
    19  	"go-hep.org/x/hep/groot/rcont"
    20  	"go-hep.org/x/hep/groot/root"
    21  	"go-hep.org/x/hep/groot/rtypes"
    22  )
    23  
    24  func TestTClonesArray(t *testing.T) {
    25  	for _, fname := range []string{
    26  		"../testdata/tclonesarray-no-streamerbypass.root",
    27  		// "../testdata/tclonesarray-with-streamerbypass.root", // FIXME(sbinet): needs member-wise streaming.
    28  	} {
    29  		t.Run(fname, func(t *testing.T) {
    30  			f, err := groot.Open(fname)
    31  			if err != nil {
    32  				t.Fatal(err)
    33  			}
    34  			defer f.Close()
    35  
    36  			o, err := f.Get("clones")
    37  			if err != nil {
    38  				t.Fatal(err)
    39  			}
    40  
    41  			tca := o.(*rcont.ClonesArray)
    42  			if got, want := tca.Len(), 3; got != want {
    43  				t.Fatalf("invalid length: got=%d, want=%d", got, want)
    44  			}
    45  			if got, want := tca.Last(), 2; got != want {
    46  				t.Fatalf("invalid last: got=%d, want=%d", got, want)
    47  			}
    48  
    49  			for i, want := range []root.Object{
    50  				rbase.NewObjString("Elem-0"),
    51  				rbase.NewObjString("elem-1"),
    52  				rbase.NewObjString("Elem-20"),
    53  			} {
    54  				got := tca.At(i)
    55  				if !reflect.DeepEqual(got, want) {
    56  					t.Errorf("invalid obj[%d]: got=%+v, want=%+v", i, got, want)
    57  				}
    58  			}
    59  		})
    60  	}
    61  }
    62  
    63  func TestTClonesArrayRW(t *testing.T) {
    64  	dir, err := os.MkdirTemp("", "groot-")
    65  	if err != nil {
    66  		t.Fatal(err)
    67  	}
    68  	defer os.RemoveAll(dir)
    69  
    70  	for i, tc := range []struct {
    71  		name string
    72  		want *rcont.ClonesArray
    73  		cmp  func(a, b *rcont.ClonesArray) bool
    74  	}{
    75  		{
    76  			name: "TClonesArray",
    77  			want: func() *rcont.ClonesArray {
    78  				o := rcont.NewClonesArray()
    79  				o.SetElems([]root.Object{
    80  					rbase.NewObjString("Elem-0"),
    81  					rbase.NewObjString("elem-1"),
    82  					rbase.NewObjString("Elem-20"),
    83  				})
    84  				return o
    85  			}(),
    86  			cmp: func(got, want *rcont.ClonesArray) bool {
    87  				if g, w := got.Len(), want.Len(); g != w {
    88  					return false
    89  				}
    90  				if g, w := got.Last(), want.Last(); g != w {
    91  					return false
    92  				}
    93  				for i := range got.Len() {
    94  					if g, w := got.At(i), want.At(i); !reflect.DeepEqual(g, w) {
    95  						return false
    96  					}
    97  				}
    98  				return true
    99  			},
   100  		},
   101  	} {
   102  		fname := filepath.Join(dir, fmt.Sprintf("tclonesarray-%d.root", i))
   103  		t.Run(tc.name, func(t *testing.T) {
   104  			const kname = "my-key"
   105  
   106  			w, err := groot.Create(fname)
   107  			if err != nil {
   108  				t.Fatal(err)
   109  			}
   110  			defer w.Close()
   111  
   112  			err = w.Put(kname, tc.want)
   113  			if err != nil {
   114  				t.Fatal(err)
   115  			}
   116  
   117  			if got, want := len(w.Keys()), 1; got != want {
   118  				t.Fatalf("invalid number of keys. got=%d, want=%d", got, want)
   119  			}
   120  
   121  			{
   122  				wbuf := rbytes.NewWBuffer(nil, nil, 0, w)
   123  				wbuf.SetErr(io.EOF)
   124  				_, err := tc.want.MarshalROOT(wbuf)
   125  				if err == nil {
   126  					t.Fatalf("expected an error")
   127  				}
   128  				if err != io.EOF {
   129  					t.Fatalf("got=%v, want=%v", err, io.EOF)
   130  				}
   131  
   132  				rbuf := rbytes.NewRBuffer(wbuf.Bytes(), nil, 0, w)
   133  				class := tc.want.Class()
   134  				obj := rtypes.Factory.Get(class)().Interface().(rbytes.Unmarshaler)
   135  				rbuf.SetErr(io.EOF)
   136  				err = obj.UnmarshalROOT(rbuf)
   137  				if err == nil {
   138  					t.Fatalf("expected an error")
   139  				}
   140  				if err != io.EOF {
   141  					t.Fatalf("got=%v, want=%v", err, io.EOF)
   142  				}
   143  				rbuf.SetErr(nil)
   144  			}
   145  
   146  			err = w.Close()
   147  			if err != nil {
   148  				t.Fatalf("error closing file: %v", err)
   149  			}
   150  
   151  			r, err := groot.Open(fname)
   152  			if err != nil {
   153  				t.Fatal(err)
   154  			}
   155  			defer r.Close()
   156  
   157  			si := r.StreamerInfos()
   158  			if len(si) == 0 {
   159  				t.Fatalf("empty list of streamers")
   160  			}
   161  
   162  			if got, want := len(r.Keys()), 1; got != want {
   163  				t.Fatalf("invalid number of keys. got=%d, want=%d", got, want)
   164  			}
   165  
   166  			rgot, err := r.Get(kname)
   167  			if err != nil {
   168  				t.Fatal(err)
   169  			}
   170  
   171  			if got, want := rgot.(*rcont.ClonesArray), tc.want; !tc.cmp(got, want) {
   172  				t.Fatalf("error reading back objstring.\ngot = %#v\nwant = %#v", got, want)
   173  			}
   174  
   175  			err = r.Close()
   176  			if err != nil {
   177  				t.Fatalf("error closing file: %v", err)
   178  			}
   179  
   180  			if !rtests.HasROOT {
   181  				t.Logf("skip test with ROOT/C++")
   182  				return
   183  			}
   184  
   185  			const rootls = `#include <iostream>
   186  #include "TFile.h"
   187  #include "TClonesArray.h"
   188  
   189  void rootls(const char *fname, const char *kname) {
   190  	auto f = TFile::Open(fname);
   191  	auto o = f->Get<TClonesArray>(kname);
   192  	if (o == NULL) {
   193  		std:cerr << "could not retrieve [" << kname << "]" << std::endl;
   194  		o->ClassName();
   195  	}
   196  	std::cout << "retrieved TClonesArray: [" << kname << "]" << std::endl;
   197  }
   198  `
   199  			out, err := rtests.RunCxxROOT("rootls", []byte(rootls), fname, kname)
   200  			if err != nil {
   201  				t.Fatalf("ROOT/C++ could not open file %q:\n%s", fname, string(out))
   202  			}
   203  		})
   204  	}
   205  }