go-hep.org/x/hep@v0.38.1/groot/riofs/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 riofs 6 7 import ( 8 "io" 9 "os" 10 "path/filepath" 11 "reflect" 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/rtypes" 18 ) 19 20 func TestWRBuffer(t *testing.T) { 21 for _, tc := range []struct { 22 name string 23 want rtests.ROOTer 24 }{ 25 { 26 name: "TFree", 27 want: &freeSegment{ 28 first: 21, 29 last: 24, 30 }, 31 }, 32 { 33 name: "TFree", 34 want: &freeSegment{ 35 first: 21, 36 last: kStartBigFile + 24, 37 }, 38 }, 39 { 40 name: "TKey", 41 want: &Key{ 42 nbytes: 1024, 43 rvers: 4, // small file 44 objlen: 10, 45 datetime: datime2time(1576331001), 46 keylen: 12, 47 cycle: 2, 48 seekkey: 1024, 49 seekpdir: 2048, 50 class: "MyClass", 51 name: "my-key", 52 title: "my key title", 53 }, 54 }, 55 { 56 name: "TKey", 57 want: &Key{ 58 nbytes: 1024, 59 rvers: 1004, // big file 60 objlen: 10, 61 datetime: datime2time(1576331001), 62 keylen: 12, 63 cycle: 2, 64 seekkey: 1024, 65 seekpdir: 2048, 66 class: "MyClass", 67 name: "my-key", 68 title: "my key title", 69 }, 70 }, 71 { 72 name: "TDirectory", 73 want: &tdirectory{ 74 rvers: 4, // small file 75 named: *rbase.NewNamed("my-name", "my-title"), 76 uuid: rbase.UUID{ 77 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 78 10, 11, 12, 13, 14, 15, 79 }, 80 }, 81 }, 82 { 83 name: "TDirectory", 84 want: &tdirectory{ 85 rvers: 1004, // big file 86 named: *rbase.NewNamed("my-name", "my-title"), 87 uuid: rbase.UUID{ 88 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 89 10, 11, 12, 13, 14, 15, 90 }, 91 }, 92 }, 93 { 94 name: "TDirectoryFile", 95 want: &tdirectoryFile{ 96 dir: tdirectory{ 97 rvers: 4, // small file 98 named: *rbase.NewNamed("", ""), 99 uuid: rbase.UUID{ 100 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 101 10, 11, 12, 13, 14, 15, 102 }, 103 }, 104 ctime: datime2time(1576331001), 105 mtime: datime2time(1576331010), 106 nbyteskeys: 1, 107 nbytesname: 2, 108 seekdir: 3, 109 seekparent: 4, 110 seekkeys: 5, 111 }, 112 }, 113 { 114 name: "TDirectoryFile", 115 want: &tdirectoryFile{ 116 dir: tdirectory{ 117 rvers: 1004, // big file 118 named: *rbase.NewNamed("", ""), 119 uuid: rbase.UUID{ 120 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 121 10, 11, 12, 13, 14, 15, 122 }, 123 }, 124 ctime: datime2time(1576331001), 125 mtime: datime2time(1576331010), 126 nbyteskeys: 1, 127 nbytesname: 2, 128 seekdir: 3, 129 seekparent: 4, 130 seekkeys: 5, 131 }, 132 }, 133 } { 134 t.Run(tc.name, func(t *testing.T) { 135 { 136 wbuf := rbytes.NewWBuffer(nil, nil, 0, nil) 137 wbuf.SetErr(io.EOF) 138 _, err := tc.want.MarshalROOT(wbuf) 139 if err == nil { 140 t.Fatalf("expected an error") 141 } 142 if err != io.EOF { 143 t.Fatalf("got=%v, want=%v", err, io.EOF) 144 } 145 } 146 wbuf := rbytes.NewWBuffer(nil, nil, 0, nil) 147 _, err := tc.want.MarshalROOT(wbuf) 148 if err != nil { 149 t.Fatalf("could not marshal ROOT: %v", err) 150 } 151 152 rbuf := rbytes.NewRBuffer(wbuf.Bytes(), nil, 0, nil) 153 class := tc.want.Class() 154 obj := rtypes.Factory.Get(class)().Interface().(rbytes.Unmarshaler) 155 { 156 rbuf.SetErr(io.EOF) 157 err = obj.UnmarshalROOT(rbuf) 158 if err == nil { 159 t.Fatalf("expected an error") 160 } 161 if err != io.EOF { 162 t.Fatalf("got=%v, want=%v", err, io.EOF) 163 } 164 rbuf.SetErr(nil) 165 } 166 err = obj.UnmarshalROOT(rbuf) 167 if err != nil { 168 t.Fatalf("could not unmarshal ROOT: %v", err) 169 } 170 171 if !reflect.DeepEqual(obj, tc.want) { 172 t.Fatalf("error\ngot= %+v\nwant=%+v\n", obj, tc.want) 173 } 174 }) 175 } 176 } 177 178 func TestWriteBigFile(t *testing.T) { 179 tmp, err := os.MkdirTemp("", "groot-riofs-") 180 if err != nil { 181 t.Fatalf("could not create tmp dir: %+v", err) 182 } 183 defer os.RemoveAll(tmp) 184 185 fname := filepath.Join(tmp, "big-file.root") 186 187 kvals := []struct { 188 k string 189 v string 190 }{ 191 {k: "key1", v: "obj1"}, 192 {k: "key2", v: "obj2"}, 193 } 194 195 func() { 196 f, err := Create(fname) 197 if err != nil { 198 t.Fatalf("could not create output file: %+v", err) 199 } 200 defer f.Close() 201 202 kv := kvals[0] 203 err = f.Put(kv.k, rbase.NewObjString(kv.v)) 204 if err != nil { 205 t.Fatalf("could not write %s: %+v", kv.k, err) 206 } 207 208 _, err = f.WriteAt([]byte{1}, kStartBigFile+1) 209 if err != nil { 210 t.Fatalf("could not write past big-file-mark: %+v", err) 211 } 212 f.end = kStartBigFile + 1 213 214 kv = kvals[1] 215 err = f.Put(kv.k, rbase.NewObjString(kv.v)) 216 if err != nil { 217 t.Fatalf("could not write %s: %+v", kv.k, err) 218 } 219 220 err = f.Close() 221 if err != nil { 222 t.Fatalf("could not close ROOT file: %+v", err) 223 } 224 225 if f.units != 8 { 226 t.Fatalf("not a big file") 227 } 228 }() 229 230 f, err := Open(fname) 231 if err != nil { 232 t.Fatalf("could not open ROOT file: %+v", err) 233 } 234 defer f.Close() 235 236 for _, kv := range kvals { 237 obj, err := f.Get(kv.k) 238 if err != nil { 239 t.Fatalf("could not get %s: %+v", kv.k, err) 240 } 241 if got, want := obj.(*rbase.ObjString).String(), kv.v; got != want { 242 t.Fatalf("invalid %s value: got=%q, want=%q", kv.k, got, want) 243 } 244 } 245 246 if f.units != 8 { 247 t.Fatalf("not a big file") 248 } 249 250 if !rtests.HasROOT { 251 t.Logf("skip test with ROOT/C++") 252 return 253 } 254 255 const rootls = `#include <iostream> 256 #include "TFile.h" 257 #include "TNamed.h" 258 #include "TObjString.h" 259 260 #include <string> 261 262 void rootls(const char *fname, const char *kname, const char *v) { 263 auto f = TFile::Open(fname); 264 auto o = f->Get<TObjString>(kname); 265 if (o == NULL) { 266 std:cerr << "could not retrieve [" << kname << "]" << std::endl; 267 o->ClassName(); 268 } 269 std::cout << "retrieved: [" << kname << "]: [" << o->GetString() << "]" << std::endl; 270 271 auto got = std::string(o->GetString()); 272 auto want = std::string(v); 273 if (got != want) { 274 std::cerr << "invalid key value for [" << kname << "]: got=[" << got << "], want=[" << want << "]\n"; 275 exit(1); 276 } 277 } 278 ` 279 for _, kv := range kvals { 280 out, err := rtests.RunCxxROOT("rootls", []byte(rootls), fname, kv.k, kv.v) 281 if err != nil { 282 t.Fatalf("ROOT/C++ could not process file %q:\n%s", fname, string(out)) 283 } 284 } 285 }