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

     1  // Copyright ©2018 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
     6  
     7  import (
     8  	"io"
     9  	"os"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  
    14  	"go-hep.org/x/hep/groot/internal/rtests"
    15  	"go-hep.org/x/hep/groot/rbase"
    16  	"go-hep.org/x/hep/groot/rbytes"
    17  	"go-hep.org/x/hep/groot/root"
    18  	"go-hep.org/x/hep/groot/rtypes"
    19  )
    20  
    21  func TestWRBuffer(t *testing.T) {
    22  	for _, tc := range []struct {
    23  		name string
    24  		want rtests.ROOTer
    25  		cmp  func(a, b rtests.ROOTer) bool
    26  	}{
    27  		{
    28  			name: "TArrayC",
    29  			want: &ArrayC{Data: []int8{1, 2, 3, 4, 5, 6, 7, 8, 9}},
    30  		},
    31  		{
    32  			name: "TArrayS",
    33  			want: &ArrayS{Data: []int16{1, 2, 3, 4, 5, 6, 7, 8, 9}},
    34  		},
    35  		{
    36  			name: "TArrayI",
    37  			want: &ArrayI{Data: []int32{1, 2, 3, 4, 5, 6, 7, 8, 9}},
    38  		},
    39  		{
    40  			name: "TArrayL",
    41  			want: &ArrayL{Data: []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}},
    42  		},
    43  		{
    44  			name: "TArrayL64",
    45  			want: &ArrayL64{Data: []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}},
    46  		},
    47  		{
    48  			name: "TArrayF",
    49  			want: &ArrayF{Data: []float32{1, 2, 3, 4, 5, 6, 7, 8, 9}},
    50  		},
    51  		{
    52  			name: "TArrayD",
    53  			want: &ArrayD{Data: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}},
    54  		},
    55  		{
    56  			name: "TList",
    57  			want: &List{
    58  				obj:  rbase.Object{ID: 0x0, Bits: 0x3000000},
    59  				name: "list-name",
    60  				objs: []root.Object{
    61  					rbase.NewNamed("n0", "t0"),
    62  					rbase.NewNamed("n1", "t1"),
    63  				},
    64  				opts: []string{"opt1", "opt2"},
    65  			},
    66  		},
    67  		{
    68  			name: "TObjArray",
    69  			want: &ObjArray{
    70  				obj:  rbase.Object{ID: 0x0, Bits: 0x3000000},
    71  				name: "my-objs",
    72  				objs: []root.Object{
    73  					rbase.NewNamed("n0", "t0"),
    74  					rbase.NewNamed("n1", "t1"),
    75  					rbase.NewNamed("n2", "t2"),
    76  				},
    77  				last: 2,
    78  			},
    79  		},
    80  		{
    81  			name: "TRefArray",
    82  			want: &RefArray{
    83  				obj:   rbase.Object{ID: 0x0, Bits: 0x3000000},
    84  				name:  "my-refs",
    85  				refs:  []uint32{1, 2, 3, 4},
    86  				lower: 1,
    87  				last:  3,
    88  			},
    89  		},
    90  		{
    91  			name: "TRefTable",
    92  			want: &RefTable{
    93  				obj:   rbase.Object{ID: 0x0, Bits: 0x3000000},
    94  				size:  42,
    95  				guids: []string{"1", "2", "3ec87674-3aa2-11e9-bb02-0301a8c0beef"},
    96  			},
    97  		},
    98  		{
    99  			name: "TRefTable-owner",
   100  			want: &RefTable{
   101  				obj:   rbase.Object{ID: 0x0, Bits: 0x3000000},
   102  				size:  42,
   103  				owner: rbase.NewNamed("n1", "t1"),
   104  				guids: []string{"1", "2", "3ec87674-3aa2-11e9-bb02-0301a8c0beef"},
   105  			},
   106  		},
   107  		{
   108  			name: "TRefTable-parents",
   109  			want: &RefTable{
   110  				obj:  rbase.Object{ID: 0x0, Bits: 0x3000000},
   111  				size: 42,
   112  				parents: &ObjArray{
   113  					obj:  rbase.Object{ID: 0x0, Bits: 0x3000000},
   114  					name: "my-objs",
   115  					objs: []root.Object{
   116  						rbase.NewNamed("n0", "t0"),
   117  						rbase.NewNamed("n1", "t1"),
   118  						rbase.NewNamed("n2", "t2"),
   119  					},
   120  					last: 2,
   121  				},
   122  				guids: []string{"1", "2", "3ec87674-3aa2-11e9-bb02-0301a8c0beef"},
   123  			},
   124  		},
   125  		{
   126  			name: "TRefTable-full",
   127  			want: &RefTable{
   128  				obj:   rbase.Object{ID: 0x0, Bits: 0x3000000},
   129  				size:  42,
   130  				owner: rbase.NewNamed("n1", "t1"),
   131  				parents: &ObjArray{
   132  					obj:  rbase.Object{ID: 0x0, Bits: 0x3000000},
   133  					name: "my-objs",
   134  					objs: []root.Object{
   135  						rbase.NewNamed("n0", "t0"),
   136  						rbase.NewNamed("n1", "t1"),
   137  						rbase.NewNamed("n2", "t2"),
   138  					},
   139  					last: 2,
   140  				},
   141  				guids: []string{"1", "2", "3ec87674-3aa2-11e9-bb02-0301a8c0beef"},
   142  			},
   143  		},
   144  		{
   145  			name: "TMap",
   146  			want: &Map{
   147  				obj:  rbase.Object{ID: 0x0, Bits: 0x3000000},
   148  				name: "my-map",
   149  				tbl: map[root.Object]root.Object{
   150  					rbase.NewObjString("k1"): rbase.NewObjString("v1"),
   151  					rbase.NewObjString("k2"): rbase.NewObjString("v2"),
   152  					rbase.NewObjString("k3"): rbase.NewObjString("v3"),
   153  				},
   154  			},
   155  			cmp: func(a, b rtests.ROOTer) bool {
   156  				ma := a.(*Map)
   157  				mb := b.(*Map)
   158  				if ma.Name() != mb.Name() {
   159  					return false
   160  				}
   161  				if ma.Title() != mb.Title() {
   162  					return false
   163  				}
   164  				if len(ma.tbl) != len(mb.tbl) {
   165  					return false
   166  				}
   167  				var (
   168  					amap = make(map[string]string, len(ma.tbl))
   169  					bmap = make(map[string]string, len(mb.tbl))
   170  				)
   171  				for k, v := range ma.Table() {
   172  					amap[k.(*rbase.ObjString).String()] = v.(*rbase.ObjString).String()
   173  				}
   174  				for k, v := range mb.Table() {
   175  					bmap[k.(*rbase.ObjString).String()] = v.(*rbase.ObjString).String()
   176  				}
   177  
   178  				return reflect.DeepEqual(amap, bmap)
   179  			},
   180  		},
   181  	} {
   182  		t.Run(tc.name, func(t *testing.T) {
   183  			{
   184  				wbuf := rbytes.NewWBuffer(nil, nil, 0, nil)
   185  				wbuf.SetErr(io.EOF)
   186  				_, err := tc.want.MarshalROOT(wbuf)
   187  				if err == nil {
   188  					t.Fatalf("expected an error")
   189  				}
   190  				if err != io.EOF {
   191  					t.Fatalf("got=%v, want=%v", err, io.EOF)
   192  				}
   193  			}
   194  			wbuf := rbytes.NewWBuffer(nil, nil, 0, nil)
   195  			_, err := tc.want.MarshalROOT(wbuf)
   196  			if err != nil {
   197  				t.Fatalf("could not marshal ROOT: %v", err)
   198  			}
   199  
   200  			rbuf := rbytes.NewRBuffer(wbuf.Bytes(), nil, 0, nil)
   201  			class := tc.want.Class()
   202  			obj := rtypes.Factory.Get(class)().Interface().(rbytes.Unmarshaler)
   203  			{
   204  				rbuf.SetErr(io.EOF)
   205  				err = obj.UnmarshalROOT(rbuf)
   206  				if err == nil {
   207  					t.Fatalf("expected an error")
   208  				}
   209  				if err != io.EOF {
   210  					t.Fatalf("got=%v, want=%v", err, io.EOF)
   211  				}
   212  				rbuf.SetErr(nil)
   213  			}
   214  			err = obj.UnmarshalROOT(rbuf)
   215  			if err != nil {
   216  				t.Fatalf("could not unmarshal ROOT: %v", err)
   217  			}
   218  
   219  			switch tc.cmp {
   220  			case nil:
   221  				if !reflect.DeepEqual(obj, tc.want) {
   222  					t.Fatalf("error\ngot= %+v\nwant=%+v\n", obj, tc.want)
   223  				}
   224  			default:
   225  				obj := obj.(rtests.ROOTer)
   226  				if !tc.cmp(obj, tc.want) {
   227  					t.Fatalf("error\ngot= %+v\nwant=%+v\n", obj, tc.want)
   228  				}
   229  			}
   230  		})
   231  	}
   232  }
   233  
   234  func TestWriteWBuffer(t *testing.T) {
   235  	for _, test := range rwBufferCases {
   236  		t.Run("write-buffer="+test.file, func(t *testing.T) {
   237  			testWriteWBuffer(t, test.name, test.file, test.want)
   238  		})
   239  	}
   240  }
   241  
   242  func testWriteWBuffer(t *testing.T, name, file string, want any) {
   243  	rdata, err := os.ReadFile(file)
   244  	if err != nil {
   245  		t.Fatal(err)
   246  	}
   247  
   248  	{
   249  		wbuf := rbytes.NewWBuffer(nil, nil, 0, nil)
   250  		wbuf.SetErr(io.EOF)
   251  		_, err := want.(rbytes.Marshaler).MarshalROOT(wbuf)
   252  		if err == nil {
   253  			t.Fatalf("expected an error")
   254  		}
   255  		if err != io.EOF {
   256  			t.Fatalf("got=%v, want=%v", err, io.EOF)
   257  		}
   258  	}
   259  
   260  	w := rbytes.NewWBuffer(nil, nil, 0, nil)
   261  	_, err = want.(rbytes.Marshaler).MarshalROOT(w)
   262  	if err != nil {
   263  		t.Fatal(err)
   264  	}
   265  	wdata := w.Bytes()
   266  
   267  	r := rbytes.NewRBuffer(wdata, nil, 0, nil)
   268  	obj := rtypes.Factory.Get(name)().Interface().(rbytes.Unmarshaler)
   269  	{
   270  		r.SetErr(io.EOF)
   271  		err = obj.UnmarshalROOT(r)
   272  		if err == nil {
   273  			t.Fatalf("expected an error")
   274  		}
   275  		if err != io.EOF {
   276  			t.Fatalf("got=%v, want=%v", err, io.EOF)
   277  		}
   278  		r.SetErr(nil)
   279  	}
   280  	err = obj.UnmarshalROOT(r)
   281  	if err != nil {
   282  		t.Fatal(err)
   283  	}
   284  
   285  	err = os.WriteFile(file+".new", wdata, 0644)
   286  	if err != nil {
   287  		t.Fatal(err)
   288  	}
   289  
   290  	if !reflect.DeepEqual(obj, want) {
   291  		t.Fatalf("error: %q\ngot= %+v\nwant=%+v\ngot= %+v\nwant=%+v", file, wdata, rdata, obj, want)
   292  	}
   293  
   294  	os.Remove(file + ".new")
   295  }
   296  func TestReadRBuffer(t *testing.T) {
   297  	for _, test := range rwBufferCases {
   298  		test := test
   299  		file := test.file
   300  		if file == "" {
   301  			file = "../testdata/" + strings.ToLower(test.name) + ".dat"
   302  		}
   303  		t.Run("read-buffer="+file, func(t *testing.T) {
   304  			testReadRBuffer(t, test.name, file, test.want)
   305  		})
   306  	}
   307  }
   308  
   309  func testReadRBuffer(t *testing.T, name, file string, want any) {
   310  	data, err := os.ReadFile(file)
   311  	if err != nil {
   312  		t.Fatal(err)
   313  	}
   314  
   315  	r := rbytes.NewRBuffer(data, nil, 0, nil)
   316  	obj := rtypes.Factory.Get(name)().Interface().(rbytes.Unmarshaler)
   317  	err = obj.UnmarshalROOT(r)
   318  	if err != nil {
   319  		t.Fatal(err)
   320  	}
   321  
   322  	if !reflect.DeepEqual(obj, want) {
   323  		t.Fatalf("error: %q\ngot= %#v\nwant=%#v\n", file, obj, want)
   324  	}
   325  }
   326  
   327  var rwBufferCases = []struct {
   328  	name string
   329  	file string
   330  	want rbytes.Unmarshaler
   331  }{
   332  	{
   333  		name: "TList",
   334  		file: "../testdata/tlist.dat",
   335  		want: &List{
   336  			obj:  rbase.Object{ID: 0x0, Bits: 0x3000000},
   337  			name: "list-name",
   338  			objs: []root.Object{
   339  				rbase.NewNamed("n0", "t0"),
   340  				rbase.NewNamed("n1", "t1"),
   341  			},
   342  			opts: []string{"", ""},
   343  		},
   344  	},
   345  	{
   346  		name: "TObjArray",
   347  		file: "../testdata/tobjarray.dat",
   348  		want: &ObjArray{
   349  			obj:  rbase.Object{ID: 0x0, Bits: 0x3000000},
   350  			name: "my-objs",
   351  			objs: []root.Object{
   352  				rbase.NewNamed("n0", "t0"),
   353  				rbase.NewNamed("n1", "t1"),
   354  				rbase.NewNamed("n2", "t2"),
   355  			},
   356  			last: 2,
   357  		},
   358  	},
   359  	{
   360  		name: "TArrayI",
   361  		file: "../testdata/tarrayi.dat",
   362  		want: &ArrayI{Data: []int32{0, 1, 2, 3, 4}},
   363  	},
   364  	{
   365  		name: "TArrayL64",
   366  		file: "../testdata/tarrayl64.dat",
   367  		want: &ArrayL64{Data: []int64{0, 1, 2, 3, 4}},
   368  	},
   369  	{
   370  		name: "TArrayF",
   371  		file: "../testdata/tarrayf.dat",
   372  		want: &ArrayF{Data: []float32{0, 1, 2, 3, 4}},
   373  	},
   374  	{
   375  		name: "TArrayD",
   376  		file: "../testdata/tarrayd.dat",
   377  		want: &ArrayD{Data: []float64{0, 1, 2, 3, 4}},
   378  	},
   379  }