go-hep.org/x/hep@v0.38.1/sio/stream_test.go (about) 1 // Copyright ©2017 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 sio_test 6 7 import ( 8 "io" 9 "os" 10 "reflect" 11 "testing" 12 13 "go-hep.org/x/hep/sio" 14 ) 15 16 type RunHeader struct { 17 RunNbr int32 18 Detector string 19 Descr string 20 SubDets []string 21 //Params Parameters 22 23 Ints []int64 24 Floats []float64 25 } 26 27 func TestStreamOpen(t *testing.T) { 28 const fname = "testdata/runhdr.sio" 29 f, err := sio.Open(fname) 30 if err != nil { 31 t.Fatalf("could not open [%s]: %v", fname, err) 32 } 33 defer f.Close() 34 35 if f.Name() != fname { 36 t.Fatalf("sio.Stream.Name: expected [%s]. got [%s]", fname, f.Name()) 37 } 38 39 if f.FileName() != fname { 40 t.Fatalf("sio.Stream.FileName: expected [%s]. got [%s]", fname, f.FileName()) 41 } 42 43 fi, err := f.Mode() 44 if err != nil { 45 t.Fatalf("could not retrieve stream mode: %v", err) 46 } 47 48 if !fi.IsRegular() { 49 t.Fatalf("sio.Stream.Mode: expected regular file") 50 } 51 52 if f.CurPos() != 0 { 53 t.Fatalf("expected pos=%v. got=%v", 0, f.CurPos()) 54 } 55 } 56 57 func TestStreamCreate(t *testing.T) { 58 const fname = "testdata/out.sio" 59 defer os.RemoveAll(fname) 60 61 f, err := sio.Create(fname) 62 if err != nil { 63 t.Fatalf("could not create [%s]: %v", fname, err) 64 } 65 66 if f.Name() != fname { 67 t.Fatalf("sio.Stream.Name: expected [%s]. got [%s]", fname, f.Name()) 68 } 69 70 if f.FileName() != fname { 71 t.Fatalf("sio.Stream.FileName: expected [%s]. got [%s]", fname, f.FileName()) 72 } 73 74 fi, err := f.Mode() 75 if err != nil { 76 t.Fatalf("could not retrieve stream mode: %v", err) 77 } 78 79 if !fi.IsRegular() { 80 t.Fatalf("sio.Stream.Mode: expected regular file") 81 } 82 83 if f.CurPos() != 0 { 84 t.Fatalf("expected pos=%v. got=%v", 0, f.CurPos()) 85 } 86 } 87 88 func TestReadRunHeader(t *testing.T) { 89 testReadStream(t, "testdata/runhdr.sio") 90 } 91 92 func TestReadRunHeaderCompr(t *testing.T) { 93 testReadStream(t, "testdata/runhdr-compr.sio") 94 } 95 96 func TestWriteRunHeader(t *testing.T) { 97 const fname = "testdata/out.sio" 98 defer os.RemoveAll(fname) 99 testWriteStream(t, fname) 100 } 101 102 func TestReadWrite(t *testing.T) { 103 const fname = "testdata/rw.sio" 104 defer os.RemoveAll(fname) 105 testWriteStream(t, fname) 106 testReadStream(t, fname) 107 } 108 109 func testReadStream(t *testing.T, fname string) { 110 111 f, err := sio.Open(fname) 112 if err != nil { 113 t.Fatalf("could not open [%s]: %v", fname, err) 114 } 115 defer f.Close() 116 117 runhdr := RunHeader{ 118 RunNbr: 42, 119 Detector: "---", 120 Descr: "---", 121 SubDets: []string{}, 122 Floats: []float64{}, 123 Ints: []int64{}, 124 } 125 126 rec := f.Record("RioRunHeader") 127 if !f.HasRecord("RioRunHeader") { 128 t.Fatalf("expected stream to have LCRunHeader record") 129 } 130 if rec.Unpack() { 131 t.Fatalf("expected record to NOT unpack by default") 132 } 133 if rec.Name() != "RioRunHeader" { 134 t.Fatalf("expected record name=[%s]. got=[%s]", "RioRunHeader", rec.Name()) 135 } 136 137 rec.SetUnpack(true) 138 if !rec.Unpack() { 139 t.Fatalf("expected record to unpack now") 140 } 141 142 err = rec.Connect("RunHeader", &runhdr) 143 if err != nil { 144 t.Fatalf("error connecting [RunHeader]: %v", err) 145 } 146 147 for nrecs := range 100 { 148 //fmt.Printf("::: irec=%d, fname=%q\n", nrecs, fname) 149 rec, err := f.ReadRecord() 150 if err != nil { 151 if err == io.EOF && nrecs == 10 { 152 break 153 } 154 t.Fatalf("error reading record: %v (nrecs=%d)", err, nrecs) 155 } 156 157 if rec == nil { 158 t.Fatalf("got nil record! (nrecs=%d)", nrecs) 159 } 160 161 if rec.Name() != "RioRunHeader" { 162 t.Fatalf("expected record name=[%s]. got=[%s]. (nrecs=%d)", 163 "RioRunHeader", 164 rec.Name(), 165 nrecs, 166 ) 167 } 168 169 if int(runhdr.RunNbr) != nrecs { 170 t.Fatalf("expected runnbr=%d. got=%d.", nrecs, runhdr.RunNbr) 171 } 172 if runhdr.Detector != "MyDetector" { 173 t.Fatalf("expected detector=[%s]. got=[%s]. (nrecs=%d)", 174 "MyDetector", 175 runhdr.Detector, 176 nrecs, 177 ) 178 } 179 if runhdr.Descr != "dummy run number" { 180 t.Fatalf("expected descr=[%s]. got=[%s]. (nrecs=%d)", 181 "dummy run number", 182 runhdr.Descr, 183 nrecs, 184 ) 185 } 186 subdets := []string{"subdet 0", "subdet 1"} 187 if !reflect.DeepEqual(runhdr.SubDets, subdets) { 188 t.Fatalf("expected subdets=%v. got=%v (nrecs=%d)", 189 subdets, 190 runhdr.SubDets, 191 nrecs, 192 ) 193 } 194 195 floats := []float64{ 196 float64(nrecs) + 100, 197 float64(nrecs) + 200, 198 float64(nrecs) + 300, 199 } 200 if !reflect.DeepEqual(runhdr.Floats, floats) { 201 t.Fatalf("expected floats=%v. got=%v (nrecs=%d)", 202 floats, 203 runhdr.Floats, 204 nrecs, 205 ) 206 } 207 208 ints := []int64{ 209 int64(nrecs) + 100, 210 int64(nrecs) + 200, 211 int64(nrecs) + 300, 212 } 213 if !reflect.DeepEqual(runhdr.Ints, ints) { 214 t.Fatalf("expected ints=%v. got=%v (nrecs=%d)", 215 floats, 216 runhdr.Floats, 217 nrecs, 218 ) 219 } 220 } 221 } 222 223 func testWriteStream(t *testing.T, fname string) { 224 f, err := sio.Create(fname) 225 if err != nil { 226 t.Fatalf("could not create [%s]: %v", fname, err) 227 } 228 229 defer f.Close() 230 231 var runhdr RunHeader 232 runhdr.RunNbr = 42 233 234 rec := f.Record("RioRunHeader") 235 if rec == nil { 236 t.Fatalf("could not create record [RioRunHeader]") 237 } 238 rec.SetUnpack(true) 239 if !rec.Unpack() { 240 t.Fatalf("expected record to unpack now") 241 } 242 243 err = rec.Connect("RunHeader", &runhdr) 244 if err != nil { 245 t.Fatalf("error connecting [RunHeader]: %v", err) 246 } 247 248 for irec := range 10 { 249 runhdr = RunHeader{ 250 RunNbr: int32(irec), 251 Detector: "MyDetector", 252 Descr: "dummy run number", 253 SubDets: []string{"subdet 0", "subdet 1"}, 254 Floats: []float64{ 255 float64(irec) + 100, 256 float64(irec) + 200, 257 float64(irec) + 300, 258 }, 259 Ints: []int64{ 260 int64(irec) + 100, 261 int64(irec) + 200, 262 int64(irec) + 300, 263 }, 264 } 265 err = f.WriteRecord(rec) 266 if err != nil { 267 t.Fatalf("error writing record: %v (irec=%d)", err, irec) 268 } 269 270 err = f.Sync() 271 if err != nil { 272 t.Fatalf("error flushing record: %v (irec=%d)", err, irec) 273 } 274 } 275 } 276 277 type T1 struct { 278 Name string 279 T2 *T2 280 T3 *T2 281 T4 *T2 282 T5 *T5 283 T6 *T2 284 T7 *T2 285 } 286 287 func (t1 *T1) MarshalSio(w sio.Writer) error { 288 enc := sio.NewEncoder(w) 289 enc.Encode(t1.Name) 290 enc.Pointer(&t1.T2) 291 enc.Pointer(&t1.T3) 292 enc.Pointer(&t1.T4) 293 enc.Pointer(&t1.T5) 294 enc.Pointer(&t1.T6) 295 enc.Pointer(&t1.T7) 296 enc.Tag(t1) 297 return enc.Err() 298 } 299 300 func (t1 *T1) UnmarshalSio(r sio.Reader) error { 301 dec := sio.NewDecoder(r) 302 dec.Decode(&t1.Name) 303 dec.Pointer(&t1.T2) 304 dec.Pointer(&t1.T3) 305 dec.Pointer(&t1.T4) 306 dec.Pointer(&t1.T5) 307 dec.Pointer(&t1.T6) 308 dec.Pointer(&t1.T7) 309 dec.Tag(t1) 310 return dec.Err() 311 } 312 313 type T2 struct { 314 Name string 315 } 316 317 func (t2 *T2) MarshalSio(w sio.Writer) error { 318 enc := sio.NewEncoder(w) 319 enc.Encode(t2.Name) 320 enc.Tag(t2) 321 return enc.Err() 322 } 323 324 func (t2 *T2) UnmarshalSio(r sio.Reader) error { 325 dec := sio.NewDecoder(r) 326 dec.Decode(&t2.Name) 327 dec.Tag(t2) 328 return dec.Err() 329 } 330 331 type T5 struct { 332 Name string 333 } 334 335 func (t2 *T5) MarshalSio(w sio.Writer) error { 336 enc := sio.NewEncoder(w) 337 enc.Encode(t2.Name) 338 // no ptag 339 return enc.Err() 340 } 341 342 func (t2 *T5) UnmarshalSio(r sio.Reader) error { 343 dec := sio.NewDecoder(r) 344 dec.Decode(&t2.Name) 345 // no ptag 346 return dec.Err() 347 } 348 349 var ( 350 _ sio.Codec = (*T1)(nil) 351 _ sio.Codec = (*T2)(nil) 352 _ sio.Codec = (*T5)(nil) 353 ) 354 355 func TestPointerStream(t *testing.T) { 356 const name = "testdata/ptr.sio" 357 func() { 358 f, err := sio.Create(name) 359 if err != nil { 360 t.Fatal(err) 361 } 362 defer f.Close() 363 364 t7 := T2{Name: "t7"} 365 t6 := T2{Name: "t6"} 366 t5 := T5{Name: "t5"} 367 t4 := T2{Name: "t4"} 368 t3 := T2{Name: "t3"} 369 t2 := T2{Name: "t2"} 370 t1 := T1{ 371 Name: "t1", 372 T2: &t2, T3: &t3, T4: &t4, 373 T5: &t5, T6: &t6, T7: &t7, 374 } 375 rec := f.Record("Data") 376 rec.SetUnpack(true) 377 378 for _, v := range []struct { 379 n string 380 ptr any 381 }{ 382 {"T1", &t1}, 383 {"T2", &t2}, 384 {"T3", &t3}, 385 {"T4", &t4}, 386 {"T5", &t5}, 387 {"T6", &t6}, 388 // {"T7", &t7}, // drop it 389 } { 390 err = rec.Connect(v.n, v.ptr) 391 if err != nil { 392 t.Fatalf("error connecting %q: %v", v.n, err) 393 } 394 } 395 396 err = f.WriteRecord(rec) 397 if err != nil { 398 t.Fatalf("error writing record: %v", err) 399 } 400 err = f.Sync() 401 if err != nil { 402 t.Fatalf("error flushing record: %v", err) 403 } 404 }() 405 406 func() { 407 f, err := sio.Open(name) 408 if err != nil { 409 t.Fatal(err) 410 } 411 defer f.Close() 412 413 var ( 414 t1 T1 415 t2 T2 416 t3 T2 417 t4 T2 418 t5 T5 419 // t6 T2 420 t7 T2 421 ) 422 423 rec := f.Record("Data") 424 rec.SetUnpack(true) 425 426 for _, v := range []struct { 427 n string 428 ptr any 429 }{ 430 {"T1", &t1}, 431 {"T2", &t2}, 432 {"T3", &t3}, 433 {"T4", &t4}, 434 {"T5", &t5}, 435 // {"T6",&t6}, // drop it 436 {"T7", &t7}, 437 } { 438 err = rec.Connect(v.n, v.ptr) 439 if err != nil { 440 t.Fatalf("error connecting %q: %v", v.n, err) 441 } 442 } 443 444 rec, err = f.ReadRecord() 445 if err != nil { 446 t.Fatalf("error reading record: %v", err) 447 } 448 if !rec.Unpack() { 449 t.Fatalf("error unpacking record") 450 } 451 452 if t1.Name != "t1" { 453 t.Errorf("t1.Name = %q", t1.Name) 454 } 455 456 if t2.Name != "t2" { 457 t.Errorf("t2.Name = %q", t2.Name) 458 } 459 460 if t3.Name != "t3" { 461 t.Errorf("t3.Name = %q", t3.Name) 462 } 463 464 if t4.Name != "t4" { 465 t.Errorf("t4.Name = %q", t4.Name) 466 } 467 468 if t5.Name != "t5" { 469 t.Errorf("t5.Name = %q", t5.Name) 470 } 471 472 if t7.Name != "" { 473 t.Errorf("t7.Name = %q", t7.Name) 474 } 475 476 for _, v := range []struct { 477 n string 478 ptr *T2 479 }{ 480 {"t2", t1.T2}, 481 {"t3", t1.T3}, 482 {"t4", t1.T4}, 483 } { 484 if v.ptr == nil { 485 t.Fatalf("t1.%s == nil", v.n) 486 } 487 488 if got, want := v.ptr.Name, v.n; got != want { 489 t.Fatalf("t1.%s.Name=%q. want=%q", v.n, got, want) 490 } 491 } 492 if t1.T5 != nil { 493 t.Fatalf("t1.T5 = %v. want=nil", t1.T5) 494 } 495 496 if t1.T6 != nil { 497 t.Fatalf("t1.T6 = %v. want=nil", t1.T6) 498 } 499 500 if t1.T7 != nil { 501 t.Fatalf("t1.T7 = %v. want=nil", t1.T7) 502 } 503 }() 504 } 505 506 type C1 struct { 507 Name string 508 C2 *C2 509 } 510 511 func (c1 *C1) MarshalSio(w sio.Writer) error { 512 enc := sio.NewEncoder(w) 513 enc.Encode(c1.Name) 514 enc.Pointer(&c1.C2) 515 enc.Tag(c1) 516 return enc.Err() 517 } 518 519 func (c1 *C1) UnmarshalSio(r sio.Reader) error { 520 dec := sio.NewDecoder(r) 521 dec.Decode(&c1.Name) 522 dec.Pointer(&c1.C2) 523 dec.Tag(c1) 524 return dec.Err() 525 } 526 527 type C2 struct { 528 Name string 529 C3 *C3 530 } 531 532 func (c2 *C2) MarshalSio(w sio.Writer) error { 533 enc := sio.NewEncoder(w) 534 enc.Encode(c2.Name) 535 enc.Pointer(&c2.C3) 536 enc.Tag(c2) 537 return enc.Err() 538 } 539 540 func (c2 *C2) UnmarshalSio(r sio.Reader) error { 541 dec := sio.NewDecoder(r) 542 dec.Decode(&c2.Name) 543 dec.Pointer(&c2.C3) 544 dec.Tag(c2) 545 return dec.Err() 546 } 547 548 type C3 struct { 549 Name string 550 C1 *C1 551 } 552 553 func (c3 *C3) MarshalSio(w sio.Writer) error { 554 enc := sio.NewEncoder(w) 555 enc.Encode(c3.Name) 556 enc.Pointer(&c3.C1) 557 enc.Tag(c3) 558 return enc.Err() 559 } 560 561 func (c3 *C3) UnmarshalSio(r sio.Reader) error { 562 dec := sio.NewDecoder(r) 563 dec.Decode(&c3.Name) 564 dec.Pointer(&c3.C1) 565 dec.Tag(c3) 566 return dec.Err() 567 } 568 569 var ( 570 _ sio.Codec = (*C1)(nil) 571 _ sio.Codec = (*C2)(nil) 572 _ sio.Codec = (*C3)(nil) 573 ) 574 575 func TestPointerCycleStream(t *testing.T) { 576 const name = "testdata/cycle-ptr.sio" 577 func() { 578 f, err := sio.Create(name) 579 if err != nil { 580 t.Fatal(err) 581 } 582 defer f.Close() 583 584 c3 := C3{Name: "c3"} 585 c2 := C2{Name: "c2"} 586 c1 := C1{Name: "c1", C2: &c2} 587 c2.C3 = &c3 588 c3.C1 = &c1 589 rec := f.Record("Data") 590 rec.SetUnpack(true) 591 592 for _, v := range []struct { 593 n string 594 ptr any 595 }{ 596 {"C1", &c1}, 597 {"C2", &c2}, 598 {"C3", &c3}, 599 } { 600 err = rec.Connect(v.n, v.ptr) 601 if err != nil { 602 t.Fatalf("error connecting %q: %v", v.n, err) 603 } 604 } 605 606 err = f.WriteRecord(rec) 607 if err != nil { 608 t.Fatalf("error writing record: %v", err) 609 } 610 err = f.Sync() 611 if err != nil { 612 t.Fatalf("error flushing record: %v", err) 613 } 614 }() 615 616 func() { 617 f, err := sio.Open(name) 618 if err != nil { 619 t.Fatal(err) 620 } 621 defer f.Close() 622 623 var ( 624 c1 C1 625 c2 C2 626 c3 C3 627 ) 628 629 rec := f.Record("Data") 630 rec.SetUnpack(true) 631 632 for _, v := range []struct { 633 n string 634 ptr any 635 }{ 636 {"C1", &c1}, 637 {"C2", &c2}, 638 {"C3", &c3}, 639 } { 640 err = rec.Connect(v.n, v.ptr) 641 if err != nil { 642 t.Fatalf("error connecting %q: %v", v.n, err) 643 } 644 } 645 646 rec, err = f.ReadRecord() 647 if err != nil { 648 t.Fatalf("error reading record: %v", err) 649 } 650 if !rec.Unpack() { 651 t.Fatalf("error unpacking record") 652 } 653 654 if c1.Name != "c1" { 655 t.Errorf("c1.Name = %q", c1.Name) 656 } 657 658 if c2.Name != "c2" { 659 t.Errorf("c2.Name = %q", c2.Name) 660 } 661 662 if c3.Name != "c3" { 663 t.Errorf("c3.Name = %q", c3.Name) 664 } 665 666 switch { 667 case c1.C2 == nil: 668 t.Errorf("c1.C2 == nil") 669 case c1.C2.Name != "c2": 670 t.Errorf("c1.C2.Name = %q", c1.C2.Name) 671 case c1.C2 != &c2: 672 t.Errorf("c1.C2 = %v", c1.C2) 673 } 674 675 switch { 676 case c2.C3 == nil: 677 t.Errorf("c2.C3 == nil") 678 case c2.C3.Name != "c3": 679 t.Errorf("c2.C3.Name = %q", c2.C3.Name) 680 case c2.C3 != &c3: 681 t.Errorf("c2.C3 = %v", c2.C3) 682 } 683 684 switch { 685 case c3.C1 == nil: 686 t.Errorf("c3.C1 == nil") 687 case c3.C1.Name != "c1": 688 t.Errorf("c3.C1.Name = %q", c3.C1.Name) 689 case c3.C1 != &c1: 690 t.Errorf("c3.C1 = %v", c3.C1) 691 } 692 }() 693 } 694 695 type ShortBlock struct { 696 Name string 697 Value int32 698 } 699 700 func (blk *ShortBlock) MarshalSio(w sio.Writer) error { 701 enc := sio.NewEncoder(w) 702 enc.Encode(blk.Name) 703 enc.Encode(blk.Value) 704 return enc.Err() 705 } 706 707 func (blk *ShortBlock) UnmarshalSio(r sio.Reader) error { 708 dec := sio.NewDecoder(r) 709 dec.Decode(&blk.Name) 710 // drop reading of blk.Value 711 //dec.Decode(&blk.Value) 712 return dec.Err() 713 } 714 715 var _ sio.Codec = (*ShortBlock)(nil) 716 717 func TestShortBlockRead(t *testing.T) { 718 const fname = "testdata/short-read.sio" 719 func() { 720 f, err := sio.Create(fname) 721 if err != nil { 722 t.Fatal(err) 723 } 724 defer f.Close() 725 726 v := ShortBlock{"block", 42} 727 rec := f.Record("Data") 728 rec.SetUnpack(true) 729 730 err = rec.Connect("my-block", &v) 731 if err != nil { 732 t.Fatal(err) 733 } 734 735 err = f.WriteRecord(rec) 736 if err != nil { 737 t.Fatal(err) 738 } 739 740 err = f.Sync() 741 if err != nil { 742 t.Fatal(err) 743 } 744 745 err = f.Close() 746 if err != nil { 747 t.Fatal(err) 748 } 749 }() 750 751 func() { 752 f, err := sio.Open(fname) 753 if err != nil { 754 t.Fatal(err) 755 } 756 defer f.Close() 757 758 var v ShortBlock 759 rec := f.Record("Data") 760 rec.SetUnpack(true) 761 err = rec.Connect("my-block", &v) 762 if err != nil { 763 t.Fatal(err) 764 } 765 766 _, err = f.ReadRecord() 767 if err == nil { 768 t.Fatalf("expected error reading record") 769 } 770 }() 771 }