|
1 | 1 | #include "ntuple_test.hxx" |
| 2 | +#include "SimpleCollectionProxy.hxx" |
| 3 | +#include "STLContainerEvolution.hxx" |
2 | 4 |
|
3 | 5 | #include <memory> |
4 | 6 | #include <new> |
@@ -251,3 +253,298 @@ TEST(RNTupleEvolution, ArrayAsRVec) |
251 | 253 | EXPECT_EQ(1, a(0)[0]); |
252 | 254 | EXPECT_EQ(2, a(0)[1]); |
253 | 255 | } |
| 256 | + |
| 257 | +TEST(RNTupleEvolution, NullableToVector) |
| 258 | +{ |
| 259 | + FileRaii fileGuard("test_ntuple_evolution_nullable_to_vector.root"); |
| 260 | + { |
| 261 | + auto model = ROOT::RNTupleModel::Create(); |
| 262 | + auto o = model->MakeField<std::optional<int>>("o"); |
| 263 | + auto u = model->MakeField<std::unique_ptr<int>>("u"); |
| 264 | + auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); |
| 265 | + |
| 266 | + *o = 137; |
| 267 | + *u = std::make_unique<int>(42); |
| 268 | + writer->Fill(); |
| 269 | + o->reset(); |
| 270 | + u->reset(); |
| 271 | + writer->Fill(); |
| 272 | + } |
| 273 | + |
| 274 | + auto reader = RNTupleReader::Open("ntpl", fileGuard.GetPath()); |
| 275 | + auto v1 = reader->GetView<std::vector<short int>>("o"); |
| 276 | + auto v2 = reader->GetView<ROOT::RVec<short int>>("o"); |
| 277 | + auto v3 = reader->GetView<std::vector<short int>>("u"); |
| 278 | + auto v4 = reader->GetView<ROOT::RVec<short int>>("u"); |
| 279 | + EXPECT_EQ(137, v1(0)[0]); |
| 280 | + EXPECT_EQ(137, v2(0)[0]); |
| 281 | + EXPECT_EQ(42, v3(0)[0]); |
| 282 | + EXPECT_EQ(42, v4(0)[0]); |
| 283 | + EXPECT_TRUE(v1(1).empty()); |
| 284 | + EXPECT_TRUE(v2(1).empty()); |
| 285 | + EXPECT_TRUE(v3(1).empty()); |
| 286 | + EXPECT_TRUE(v4(1).empty()); |
| 287 | +} |
| 288 | + |
| 289 | +namespace { |
| 290 | +template <typename CollectionT, bool OfPairsT> |
| 291 | +void WriteCollection(std::string_view ntplName, TFile &f) |
| 292 | +{ |
| 293 | + auto model = RNTupleModel::Create(); |
| 294 | + auto ptrCollection = model->MakeField<CollectionT>("f"); |
| 295 | + auto writer = ROOT::RNTupleWriter::Append(std::move(model), ntplName, f); |
| 296 | + if constexpr (OfPairsT) { |
| 297 | + *ptrCollection = {{1, 2}, {3, 4}, {5, 6}}; |
| 298 | + } else { |
| 299 | + *ptrCollection = {1, 2, 3}; |
| 300 | + } |
| 301 | + writer->Fill(); |
| 302 | + ptrCollection->clear(); |
| 303 | + writer->Fill(); |
| 304 | + if constexpr (OfPairsT) { |
| 305 | + *ptrCollection = {{7, 8}}; |
| 306 | + } else { |
| 307 | + *ptrCollection = {4}; |
| 308 | + } |
| 309 | + writer->Fill(); |
| 310 | +} |
| 311 | + |
| 312 | +template <typename CollectionT, bool OfPairsT> |
| 313 | +void ReadCollection(std::string_view ntplName, std::string_view path) |
| 314 | +{ |
| 315 | + auto reader = RNTupleReader::Open(ntplName, path); |
| 316 | + ASSERT_EQ(3u, reader->GetNEntries()); |
| 317 | + |
| 318 | + auto view = reader->GetView<CollectionT>("f"); |
| 319 | + CollectionT exp0; |
| 320 | + CollectionT exp2; |
| 321 | + if constexpr (OfPairsT) { |
| 322 | + exp0 = {{1, 2}, {3, 4}, {5, 6}}; |
| 323 | + exp2 = {{7, 8}}; |
| 324 | + } else { |
| 325 | + exp0 = {1, 2, 3}; |
| 326 | + exp2 = {4}; |
| 327 | + } |
| 328 | + EXPECT_EQ(exp0.size(), view(0).size()); |
| 329 | + for (const auto &elem : exp0) { |
| 330 | + const auto &ref = view(0); |
| 331 | + EXPECT_TRUE(std::find(ref.begin(), ref.end(), elem) != ref.end()); |
| 332 | + } |
| 333 | + EXPECT_TRUE(view(1).empty()); |
| 334 | + EXPECT_EQ(exp2.size(), view(2).size()); |
| 335 | + for (std::size_t i = 0; i < exp2.size(); ++i) |
| 336 | + EXPECT_EQ(*exp2.begin(), *view(2).begin()); |
| 337 | +} |
| 338 | + |
| 339 | +template <typename CollectionT, bool OfPairsT> |
| 340 | +void ReadCollectionFail(std::string_view ntplName, std::string_view path) |
| 341 | +{ |
| 342 | + auto reader = RNTupleReader::Open(ntplName, path); |
| 343 | + ASSERT_EQ(3u, reader->GetNEntries()); |
| 344 | + |
| 345 | + try { |
| 346 | + reader->GetView<CollectionT>("f"); |
| 347 | + FAIL() << "this case of automatic collection schema evolution should have failed"; |
| 348 | + } catch (const ROOT::RException &err) { |
| 349 | + EXPECT_THAT(err.what(), testing::HasSubstr("incompatible type")); |
| 350 | + } |
| 351 | +} |
| 352 | +} // anonymous namespace |
| 353 | + |
| 354 | +namespace ROOT { |
| 355 | +template <> |
| 356 | +struct IsCollectionProxy<CollectionProxy<int>> : std::true_type {}; |
| 357 | +template <> |
| 358 | +struct IsCollectionProxy<CollectionProxy<short int>> : std::true_type {}; |
| 359 | +template <> |
| 360 | +struct IsCollectionProxy<CollectionProxy<std::pair<int, int>>> : std::true_type {}; |
| 361 | +template <> |
| 362 | +struct IsCollectionProxy<CollectionProxy<std::pair<short int, short int>>> : std::true_type {}; |
| 363 | +} // namespace ROOT |
| 364 | + |
| 365 | +TEST(RNTupleEvolution, Collections) |
| 366 | +{ |
| 367 | + FileRaii fileGuard("test_ntuple_evolution_collections.root"); |
| 368 | + auto f = std::unique_ptr<TFile>(TFile::Open(fileGuard.GetPath().c_str(), "UPDATE")); |
| 369 | + |
| 370 | + TClass::GetClass("CollectionProxy<int>")->CopyCollectionProxy(SimpleCollectionProxy<CollectionProxy<int>>()); |
| 371 | + TClass::GetClass("CollectionProxy<short int>") |
| 372 | + ->CopyCollectionProxy(SimpleCollectionProxy<CollectionProxy<short int>>()); |
| 373 | + TClass::GetClass("CollectionProxy<std::pair<int, int>>") |
| 374 | + ->CopyCollectionProxy(SimpleCollectionProxy<CollectionProxy<std::pair<int, int>>>()); |
| 375 | + TClass::GetClass("CollectionProxy<std::pair<short int, short int>>") |
| 376 | + ->CopyCollectionProxy(SimpleCollectionProxy<CollectionProxy<std::pair<short int, short int>>>()); |
| 377 | + |
| 378 | + { |
| 379 | + auto model = RNTupleModel::Create(); |
| 380 | + model->AddField(ROOT::RVectorField::CreateUntyped("f", std::make_unique<RField<int>>("x"))); |
| 381 | + model->Freeze(); |
| 382 | + auto v = std::static_pointer_cast<std::vector<int>>(model->GetDefaultEntry().GetPtr<void>("f")); |
| 383 | + auto writer = ROOT::RNTupleWriter::Append(std::move(model), "untyped", *f); |
| 384 | + *v = {1, 2, 3}; |
| 385 | + writer->Fill(); |
| 386 | + v->clear(); |
| 387 | + writer->Fill(); |
| 388 | + *v = {4}; |
| 389 | + writer->Fill(); |
| 390 | + } |
| 391 | + { |
| 392 | + auto model = RNTupleModel::Create(); |
| 393 | + model->AddField(ROOT::RVectorField::CreateUntyped("f", std::make_unique<RField<std::pair<int, int>>>("x"))); |
| 394 | + model->Freeze(); |
| 395 | + auto v = std::static_pointer_cast<std::vector<std::pair<int, int>>>(model->GetDefaultEntry().GetPtr<void>("f")); |
| 396 | + auto writer = ROOT::RNTupleWriter::Append(std::move(model), "untypedOfPairs", *f); |
| 397 | + *v = {{1, 2}, {3, 4}, {5, 6}}; |
| 398 | + writer->Fill(); |
| 399 | + v->clear(); |
| 400 | + writer->Fill(); |
| 401 | + *v = {{7, 8}}; |
| 402 | + writer->Fill(); |
| 403 | + } |
| 404 | + { |
| 405 | + auto model = RNTupleModel::Create(); |
| 406 | + auto proxy = model->MakeField<CollectionProxy<int>>("f"); |
| 407 | + auto writer = RNTupleWriter::Append(std::move(model), "proxy", *f); |
| 408 | + proxy->v = {1, 2, 3}; |
| 409 | + writer->Fill(); |
| 410 | + proxy->v.clear(); |
| 411 | + writer->Fill(); |
| 412 | + proxy->v = {4}; |
| 413 | + writer->Fill(); |
| 414 | + } |
| 415 | + { |
| 416 | + auto model = RNTupleModel::Create(); |
| 417 | + auto proxy = model->MakeField<CollectionProxy<std::pair<int, int>>>("f"); |
| 418 | + auto writer = RNTupleWriter::Append(std::move(model), "proxyOfPairs", *f); |
| 419 | + proxy->v = {{1, 2}, {3, 4}, {5, 6}}; |
| 420 | + writer->Fill(); |
| 421 | + proxy->v.clear(); |
| 422 | + writer->Fill(); |
| 423 | + proxy->v = {{7, 8}}; |
| 424 | + writer->Fill(); |
| 425 | + } |
| 426 | + |
| 427 | + WriteCollection<std::vector<int>, false>("vector", *f); |
| 428 | + WriteCollection<ROOT::RVec<int>, false>("rvec", *f); |
| 429 | + WriteCollection<std::set<int>, false>("set", *f); |
| 430 | + WriteCollection<std::unordered_set<int>, false>("unordered_set", *f); |
| 431 | + WriteCollection<std::multiset<int>, false>("multiset", *f); |
| 432 | + WriteCollection<std::unordered_multiset<int>, false>("unordered_multiset", *f); |
| 433 | + WriteCollection<std::map<int, int>, true>("map", *f); |
| 434 | + WriteCollection<std::unordered_map<int, int>, true>("unordered_map", *f); |
| 435 | + WriteCollection<std::multimap<int, int>, true>("multimap", *f); |
| 436 | + WriteCollection<std::unordered_multimap<int, int>, true>("unordered_multimap", *f); |
| 437 | + |
| 438 | + WriteCollection<std::vector<std::pair<int, int>>, true>("vectorOfPairs", *f); |
| 439 | + WriteCollection<ROOT::RVec<std::pair<int, int>>, true>("rvecOfPairs", *f); |
| 440 | + WriteCollection<std::set<std::pair<int, int>>, true>("setOfPairs", *f); |
| 441 | + WriteCollection<std::multiset<std::pair<int, int>>, true>("multisetOfPairs", *f); |
| 442 | + |
| 443 | + // All variations written out. Now test the collection matrix. |
| 444 | + |
| 445 | + ReadCollection<std::vector<short int>, false>("untyped", fileGuard.GetPath()); |
| 446 | + ReadCollection<std::vector<short int>, false>("proxy", fileGuard.GetPath()); |
| 447 | + ReadCollection<std::vector<short int>, false>("rvec", fileGuard.GetPath()); |
| 448 | + ReadCollection<std::vector<short int>, false>("set", fileGuard.GetPath()); |
| 449 | + ReadCollection<std::vector<short int>, false>("unordered_set", fileGuard.GetPath()); |
| 450 | + ReadCollection<std::vector<short int>, false>("multiset", fileGuard.GetPath()); |
| 451 | + ReadCollection<std::vector<short int>, false>("unordered_multiset", fileGuard.GetPath()); |
| 452 | + ReadCollection<std::vector<std::pair<short int, short int>>, true>("map", fileGuard.GetPath()); |
| 453 | + ReadCollection<std::vector<std::pair<short int, short int>>, true>("unordered_map", fileGuard.GetPath()); |
| 454 | + ReadCollection<std::vector<std::pair<short int, short int>>, true>("multimap", fileGuard.GetPath()); |
| 455 | + ReadCollection<std::vector<std::pair<short int, short int>>, true>("unordered_multimap", fileGuard.GetPath()); |
| 456 | + |
| 457 | + ReadCollection<ROOT::RVec<short int>, false>("untyped", fileGuard.GetPath()); |
| 458 | + ReadCollection<ROOT::RVec<short int>, false>("proxy", fileGuard.GetPath()); |
| 459 | + ReadCollection<ROOT::RVec<short int>, false>("vector", fileGuard.GetPath()); |
| 460 | + ReadCollection<ROOT::RVec<short int>, false>("set", fileGuard.GetPath()); |
| 461 | + ReadCollection<ROOT::RVec<short int>, false>("unordered_set", fileGuard.GetPath()); |
| 462 | + ReadCollection<ROOT::RVec<short int>, false>("multiset", fileGuard.GetPath()); |
| 463 | + ReadCollection<ROOT::RVec<short int>, false>("unordered_multiset", fileGuard.GetPath()); |
| 464 | + ReadCollection<ROOT::RVec<std::pair<short int, short int>>, true>("map", fileGuard.GetPath()); |
| 465 | + ReadCollection<ROOT::RVec<std::pair<short int, short int>>, true>("unordered_map", fileGuard.GetPath()); |
| 466 | + ReadCollection<ROOT::RVec<std::pair<short int, short int>>, true>("multimap", fileGuard.GetPath()); |
| 467 | + ReadCollection<ROOT::RVec<std::pair<short int, short int>>, true>("unordered_multimap", fileGuard.GetPath()); |
| 468 | + |
| 469 | + ReadCollectionFail<std::set<short int>, false>("untyped", fileGuard.GetPath()); |
| 470 | + ReadCollectionFail<std::set<short int>, false>("proxy", fileGuard.GetPath()); |
| 471 | + ReadCollectionFail<std::set<short int>, false>("vector", fileGuard.GetPath()); |
| 472 | + ReadCollectionFail<std::set<short int>, false>("rvec", fileGuard.GetPath()); |
| 473 | + ReadCollection<std::set<short int>, false>("unordered_set", fileGuard.GetPath()); |
| 474 | + ReadCollectionFail<std::set<short int>, false>("multiset", fileGuard.GetPath()); |
| 475 | + ReadCollectionFail<std::set<short int>, false>("unordered_multiset", fileGuard.GetPath()); |
| 476 | + ReadCollection<std::set<std::pair<short int, short int>>, true>("map", fileGuard.GetPath()); |
| 477 | + ReadCollectionFail<std::set<std::pair<short int, short int>>, true>("unordered_map", fileGuard.GetPath()); |
| 478 | + ReadCollectionFail<std::set<std::pair<short int, short int>>, true>("multimap", fileGuard.GetPath()); |
| 479 | + ReadCollectionFail<std::set<std::pair<short int, short int>>, true>("unordered_multimap", fileGuard.GetPath()); |
| 480 | + |
| 481 | + ReadCollectionFail<std::unordered_set<short int>, false>("untyped", fileGuard.GetPath()); |
| 482 | + ReadCollectionFail<std::unordered_set<short int>, false>("proxy", fileGuard.GetPath()); |
| 483 | + ReadCollectionFail<std::unordered_set<short int>, false>("vector", fileGuard.GetPath()); |
| 484 | + ReadCollectionFail<std::unordered_set<short int>, false>("rvec", fileGuard.GetPath()); |
| 485 | + ReadCollection<std::unordered_set<short int>, false>("set", fileGuard.GetPath()); |
| 486 | + ReadCollectionFail<std::unordered_set<short int>, false>("multiset", fileGuard.GetPath()); |
| 487 | + ReadCollectionFail<std::unordered_set<short int>, false>("unordered_multiset", fileGuard.GetPath()); |
| 488 | + |
| 489 | + ReadCollection<std::multiset<short int>, false>("untyped", fileGuard.GetPath()); |
| 490 | + ReadCollection<std::multiset<short int>, false>("proxy", fileGuard.GetPath()); |
| 491 | + ReadCollection<std::multiset<short int>, false>("vector", fileGuard.GetPath()); |
| 492 | + ReadCollection<std::multiset<short int>, false>("rvec", fileGuard.GetPath()); |
| 493 | + ReadCollection<std::multiset<short int>, false>("unordered_set", fileGuard.GetPath()); |
| 494 | + ReadCollection<std::multiset<short int>, false>("set", fileGuard.GetPath()); |
| 495 | + ReadCollection<std::multiset<short int>, false>("unordered_multiset", fileGuard.GetPath()); |
| 496 | + ReadCollection<std::multiset<std::pair<short int, short int>>, true>("map", fileGuard.GetPath()); |
| 497 | + ReadCollection<std::multiset<std::pair<short int, short int>>, true>("unordered_map", fileGuard.GetPath()); |
| 498 | + ReadCollection<std::multiset<std::pair<short int, short int>>, true>("multimap", fileGuard.GetPath()); |
| 499 | + ReadCollection<std::multiset<std::pair<short int, short int>>, true>("unordered_multimap", fileGuard.GetPath()); |
| 500 | + |
| 501 | + ReadCollection<std::unordered_multiset<short int>, false>("untyped", fileGuard.GetPath()); |
| 502 | + ReadCollection<std::unordered_multiset<short int>, false>("proxy", fileGuard.GetPath()); |
| 503 | + ReadCollection<std::unordered_multiset<short int>, false>("vector", fileGuard.GetPath()); |
| 504 | + ReadCollection<std::unordered_multiset<short int>, false>("rvec", fileGuard.GetPath()); |
| 505 | + ReadCollection<std::unordered_multiset<short int>, false>("unordered_set", fileGuard.GetPath()); |
| 506 | + ReadCollection<std::unordered_multiset<short int>, false>("set", fileGuard.GetPath()); |
| 507 | + ReadCollection<std::unordered_multiset<short int>, false>("multiset", fileGuard.GetPath()); |
| 508 | + |
| 509 | + ReadCollectionFail<std::map<short int, short int>, true>("untypedOfPairs", fileGuard.GetPath()); |
| 510 | + ReadCollectionFail<std::map<short int, short int>, true>("proxyOfPairs", fileGuard.GetPath()); |
| 511 | + ReadCollectionFail<std::map<short int, short int>, true>("vectorOfPairs", fileGuard.GetPath()); |
| 512 | + ReadCollectionFail<std::map<short int, short int>, true>("rvecOfPairs", fileGuard.GetPath()); |
| 513 | + ReadCollection<std::map<short int, short int>, true>("setOfPairs", fileGuard.GetPath()); |
| 514 | + ReadCollectionFail<std::map<short int, short int>, true>("multisetOfPairs", fileGuard.GetPath()); |
| 515 | + ReadCollection<std::map<short int, short int>, true>("unordered_map", fileGuard.GetPath()); |
| 516 | + ReadCollectionFail<std::map<short int, short int>, true>("multimap", fileGuard.GetPath()); |
| 517 | + ReadCollectionFail<std::map<short int, short int>, true>("unordered_multimap", fileGuard.GetPath()); |
| 518 | + |
| 519 | + ReadCollectionFail<std::unordered_map<short int, short int>, true>("untypedOfPairs", fileGuard.GetPath()); |
| 520 | + ReadCollectionFail<std::unordered_map<short int, short int>, true>("proxyOfPairs", fileGuard.GetPath()); |
| 521 | + ReadCollectionFail<std::unordered_map<short int, short int>, true>("vectorOfPairs", fileGuard.GetPath()); |
| 522 | + ReadCollectionFail<std::unordered_map<short int, short int>, true>("rvecOfPairs", fileGuard.GetPath()); |
| 523 | + ReadCollection<std::unordered_map<short int, short int>, true>("setOfPairs", fileGuard.GetPath()); |
| 524 | + ReadCollectionFail<std::unordered_map<short int, short int>, true>("multisetOfPairs", fileGuard.GetPath()); |
| 525 | + ReadCollection<std::unordered_map<short int, short int>, true>("map", fileGuard.GetPath()); |
| 526 | + ReadCollectionFail<std::unordered_map<short int, short int>, true>("multimap", fileGuard.GetPath()); |
| 527 | + ReadCollectionFail<std::unordered_map<short int, short int>, true>("unordered_multimap", fileGuard.GetPath()); |
| 528 | + |
| 529 | + ReadCollection<std::multimap<short int, short int>, true>("untypedOfPairs", fileGuard.GetPath()); |
| 530 | + ReadCollection<std::multimap<short int, short int>, true>("proxyOfPairs", fileGuard.GetPath()); |
| 531 | + ReadCollection<std::multimap<short int, short int>, true>("vectorOfPairs", fileGuard.GetPath()); |
| 532 | + ReadCollection<std::multimap<short int, short int>, true>("rvecOfPairs", fileGuard.GetPath()); |
| 533 | + ReadCollection<std::multimap<short int, short int>, true>("setOfPairs", fileGuard.GetPath()); |
| 534 | + ReadCollection<std::multimap<short int, short int>, true>("multisetOfPairs", fileGuard.GetPath()); |
| 535 | + ReadCollection<std::multimap<short int, short int>, true>("map", fileGuard.GetPath()); |
| 536 | + ReadCollection<std::multimap<short int, short int>, true>("unordered_map", fileGuard.GetPath()); |
| 537 | + ReadCollection<std::multimap<short int, short int>, true>("multimap", fileGuard.GetPath()); |
| 538 | + ReadCollection<std::multimap<short int, short int>, true>("unordered_multimap", fileGuard.GetPath()); |
| 539 | + |
| 540 | + ReadCollection<std::unordered_multimap<short int, short int>, true>("untypedOfPairs", fileGuard.GetPath()); |
| 541 | + ReadCollection<std::unordered_multimap<short int, short int>, true>("proxyOfPairs", fileGuard.GetPath()); |
| 542 | + ReadCollection<std::unordered_multimap<short int, short int>, true>("vectorOfPairs", fileGuard.GetPath()); |
| 543 | + ReadCollection<std::unordered_multimap<short int, short int>, true>("rvecOfPairs", fileGuard.GetPath()); |
| 544 | + ReadCollection<std::unordered_multimap<short int, short int>, true>("setOfPairs", fileGuard.GetPath()); |
| 545 | + ReadCollection<std::unordered_multimap<short int, short int>, true>("multisetOfPairs", fileGuard.GetPath()); |
| 546 | + ReadCollection<std::unordered_multimap<short int, short int>, true>("map", fileGuard.GetPath()); |
| 547 | + ReadCollection<std::unordered_multimap<short int, short int>, true>("unordered_map", fileGuard.GetPath()); |
| 548 | + ReadCollection<std::unordered_multimap<short int, short int>, true>("multimap", fileGuard.GetPath()); |
| 549 | + ReadCollection<std::unordered_multimap<short int, short int>, true>("unordered_multimap", fileGuard.GetPath()); |
| 550 | +} |
0 commit comments