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 }