|
2 | 2 | #include <vector> |
3 | 3 | #include <string> |
4 | 4 | #include <array> |
| 5 | +#include <algorithm> |
| 6 | +#include <fstream> |
5 | 7 |
|
6 | 8 | #include "gtest/gtest.h" |
7 | 9 |
|
|
16 | 18 | #include "TROOT.h" // gROOT |
17 | 19 | #include "TSystem.h" |
18 | 20 | #include "TEnv.h" // gEnv |
| 21 | +#include "TFree.h" |
| 22 | +#include "TError.h" |
19 | 23 |
|
20 | 24 | TEST(TFile, WriteObjectTObject) |
21 | 25 | { |
@@ -332,3 +336,117 @@ TEST(TFile, UUID) |
332 | 336 | TMemFile f("uuidtest.root", "RECREATE"); |
333 | 337 | EXPECT_EQ('4', f.GetUUID().AsString()[14]); |
334 | 338 | } |
| 339 | + |
| 340 | +namespace { |
| 341 | +std::string gCollectedDiags; |
| 342 | +void CollectDiags(int /*level*/, Bool_t /*abort*/, const char *location, const char *msg) |
| 343 | +{ |
| 344 | + gCollectedDiags += location; |
| 345 | + gCollectedDiags += ": "; |
| 346 | + gCollectedDiags += msg; |
| 347 | + gCollectedDiags += '\n'; |
| 348 | +} |
| 349 | +} // namespace |
| 350 | + |
| 351 | +TEST(TFile, ReadKeysValid) |
| 352 | +{ |
| 353 | + ROOT::TestSupport::FileRaii fileGuard("tfile_readkeys_valid.root"); |
| 354 | + { |
| 355 | + TFile f(fileGuard.GetPath().c_str(), "RECREATE"); |
| 356 | + TNamed named("short", "t"); |
| 357 | + named.Write(); |
| 358 | + } |
| 359 | + TFile in(fileGuard.GetPath().c_str()); |
| 360 | + ASSERT_FALSE(in.IsZombie()); |
| 361 | + EXPECT_EQ(in.GetNkeys(), 1); |
| 362 | + auto *named = in.Get<TNamed>("short"); |
| 363 | + ASSERT_NE(named, nullptr); |
| 364 | + EXPECT_STREQ(named->GetTitle(), "t"); |
| 365 | +} |
| 366 | + |
| 367 | +TEST(TFile, ReadKeysOversizedString) |
| 368 | +{ |
| 369 | + ROOT::TestSupport::FileRaii fileGuard("tfile_readkeys_oversize.root"); |
| 370 | + Long64_t seekKeys = 0; |
| 371 | + Int_t nbytesKeys = 0; |
| 372 | + { |
| 373 | + TFile f(fileGuard.GetPath().c_str(), "RECREATE"); |
| 374 | + TNamed named("short", "t"); |
| 375 | + named.Write(); |
| 376 | + f.Write(); |
| 377 | + seekKeys = f.GetSeekKeys(); |
| 378 | + nbytesKeys = f.GetNbytesKeys(); |
| 379 | + } |
| 380 | + ASSERT_GT(seekKeys, 0); |
| 381 | + ASSERT_GT(nbytesKeys, 0); |
| 382 | + |
| 383 | + { |
| 384 | + std::fstream fs(fileGuard.GetPath(), std::ios::in | std::ios::out | std::ios::binary); |
| 385 | + ASSERT_TRUE(fs.good()); |
| 386 | + std::vector<char> rec(static_cast<std::size_t>(nbytesKeys)); |
| 387 | + fs.seekg(seekKeys); |
| 388 | + fs.read(rec.data(), nbytesKeys); |
| 389 | + ASSERT_EQ(fs.gcount(), nbytesKeys); |
| 390 | + |
| 391 | + const char needle[] = {'\x05', 's', 'h', 'o', 'r', 't'}; |
| 392 | + auto it = std::search(rec.begin(), rec.end(), std::begin(needle), std::end(needle)); |
| 393 | + ASSERT_NE(it, rec.end()); |
| 394 | + *it = static_cast<char>(255); |
| 395 | + fs.seekp(seekKeys); |
| 396 | + fs.write(rec.data(), nbytesKeys); |
| 397 | + ASSERT_TRUE(fs.good()); |
| 398 | + } |
| 399 | + |
| 400 | + gCollectedDiags.clear(); |
| 401 | + { |
| 402 | + ROOT::TestSupport::FilterDiagsRAII capture(CollectDiags); |
| 403 | + TFile in(fileGuard.GetPath().c_str()); |
| 404 | + // Opening must return; do not walk off the keys buffer. |
| 405 | + EXPECT_TRUE(in.IsZombie() || in.GetNkeys() >= 0); |
| 406 | + } |
| 407 | + EXPECT_NE(gCollectedDiags.find("given buffer is too small"), std::string::npos); |
| 408 | +} |
| 409 | + |
| 410 | +TEST(TFile, ReadFreeValid) |
| 411 | +{ |
| 412 | + ROOT::TestSupport::FileRaii fileGuard("tfile_readfree_valid.root"); |
| 413 | + { |
| 414 | + TFile f(fileGuard.GetPath().c_str(), "RECREATE"); |
| 415 | + TNamed named("n", "t"); |
| 416 | + named.Write(); |
| 417 | + } |
| 418 | + { |
| 419 | + TFile f(fileGuard.GetPath().c_str(), "UPDATE"); |
| 420 | + ASSERT_FALSE(f.IsZombie()); |
| 421 | + TNamed named2("n2", "t"); |
| 422 | + named2.Write(); |
| 423 | + } |
| 424 | + TFile in(fileGuard.GetPath().c_str()); |
| 425 | + ASSERT_FALSE(in.IsZombie()); |
| 426 | + EXPECT_NE(in.Get<TNamed>("n"), nullptr); |
| 427 | + EXPECT_NE(in.Get<TNamed>("n2"), nullptr); |
| 428 | +} |
| 429 | + |
| 430 | +TEST(TFree, ReadBufferBounds) |
| 431 | +{ |
| 432 | + char packed[10] = {}; |
| 433 | + char *p = packed; |
| 434 | + TFree out; |
| 435 | + out.SetFirst(100); |
| 436 | + out.SetLast(200); |
| 437 | + out.FillBuffer(p); |
| 438 | + ASSERT_EQ(p - packed, 10); |
| 439 | + |
| 440 | + p = packed; |
| 441 | + TFree in; |
| 442 | + EXPECT_TRUE(in.ReadBuffer(p, sizeof(packed))); |
| 443 | + EXPECT_EQ(in.GetFirst(), 100); |
| 444 | + EXPECT_EQ(in.GetLast(), 200); |
| 445 | + |
| 446 | + char tooSmall[3] = {}; |
| 447 | + p = tooSmall; |
| 448 | + TFree truncated; |
| 449 | + ROOT::TestSupport::CheckDiagsRAII diags; |
| 450 | + diags.requiredDiag(kError, "TFree::ReadBuffer", "The given buffer is too small", false); |
| 451 | + EXPECT_FALSE(truncated.ReadBuffer(p, sizeof(tooSmall))); |
| 452 | +} |
0 commit comments