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  }