@@ -394,3 +394,133 @@ TEST(TFileMerger, MergeSelectiveTutorial)
394394 EXPECT_NE (file.Get <TNtuple>(" ntuple" ), nullptr );
395395 }
396396}
397+
398+ // https://github.com/root-project/root/issues/14558
399+ TEST (TFileMerger, ImportBranches)
400+ {
401+ TTree atree (" atree" , " atitle" );
402+ int value;
403+ atree.Branch (" a" , &value);
404+ value = 11 ;
405+ atree.Fill ();
406+ TTree abtree (" abtree" , " abtitle" );
407+ abtree.Branch (" a" , &value);
408+ abtree.Branch (" b" , &value);
409+ value = 42 ;
410+ abtree.Fill ();
411+
412+ TTree dummy (" ztree" , " zeroBranches" );
413+ TList treelist;
414+
415+ // Case 1 - Static: ZeroBranches + 1 entry (1 branch) + 1 entry (2 branch)
416+ treelist.Add (&dummy);
417+ treelist.Add (&atree);
418+ treelist.Add (&abtree);
419+ std::unique_ptr<TFile> file1 (TFile::Open (" b4716.root" , " RECREATE" ));
420+ auto rtree = TTree::MergeTrees (&treelist, " ImportBranches" );
421+ file1->Write ();
422+ ASSERT_TRUE (rtree->FindBranch (" a" ));
423+ EXPECT_EQ (rtree->FindBranch (" a" )->GetEntries (), 2 );
424+ ASSERT_TRUE (rtree->FindBranch (" b" ));
425+ EXPECT_EQ (rtree->FindBranch (" b" )->GetEntries (), 2 );
426+ ASSERT_TRUE (atree.FindBranch (" a" ));
427+ ASSERT_FALSE (atree.FindBranch (" b" ));
428+ ASSERT_TRUE (abtree.FindBranch (" a" ));
429+ ASSERT_TRUE (abtree.FindBranch (" b" ));
430+ EXPECT_EQ (atree.FindBranch (" a" )->GetEntries (), 1 );
431+ EXPECT_EQ (abtree.FindBranch (" a" )->GetEntries (), 1 );
432+ EXPECT_EQ (abtree.FindBranch (" b" )->GetEntries (), 1 );
433+ EXPECT_EQ (dummy.FindBranch (" a" ), nullptr );
434+ EXPECT_EQ (dummy.FindBranch (" b" ), nullptr );
435+
436+ // Case 2 - this (ZeroBranches) + 1 entry (1 branch) + 1 entry (2 branch)
437+ treelist.Clear ();
438+ treelist.Add (&atree);
439+ treelist.Add (&abtree);
440+ std::unique_ptr<TFile> file2 (TFile::Open (" c4716.root" , " RECREATE" ));
441+ TFileMergeInfo info2 (file2.get ());
442+ info2.fOptions += " ImportBranches" ;
443+ dummy.Merge (&treelist, &info2);
444+ file2->Write ();
445+ ASSERT_TRUE (dummy.FindBranch (" a" ));
446+ EXPECT_EQ (dummy.FindBranch (" a" )->GetEntries (), 2 );
447+ ASSERT_TRUE (dummy.FindBranch (" b" ));
448+ EXPECT_EQ (dummy.FindBranch (" b" )->GetEntries (), 2 );
449+ EXPECT_EQ (atree.GetName (),
450+ " ztree" ); // As a side effect of trees with zero branches being ignored but it's name kept since it's first
451+ // in list, the first tree with branches (name) gets ztree's name.
452+ ASSERT_TRUE (atree.FindBranch (" a" ));
453+ EXPECT_EQ (atree.FindBranch (" a" )->GetEntries (), 2 ); // As a side effect, the first with branches (atree) has been
454+ // modified and has now 2 entries instead of 1, and ztree's name
455+ ASSERT_TRUE (atree.FindBranch (" b" ));
456+ EXPECT_EQ (atree.FindBranch (" b" )->GetEntries (), 2 ); // As a side effect, the first with branches (atree) has been
457+ // modified and has now 2 entries instead of 1, and ztree's name
458+ ASSERT_TRUE (abtree.FindBranch (" a" ));
459+ ASSERT_TRUE (abtree.FindBranch (" b" ));
460+ EXPECT_EQ (abtree.FindBranch (" a" )->GetEntries (), 1 );
461+ EXPECT_EQ (abtree.FindBranch (" b" )->GetEntries (), 1 );
462+
463+ // Case 3 - this (0 entry / 1 branch) + 1 entry (1 branch) + 1 entry (2 branch)
464+ TTree atree_ (" atree" , " atitle" ); // Recreate original atree
465+ int value;
466+ atree_.Branch (" a" , &value);
467+ value = 11 ;
468+ atree_.Fill ();
469+ treelist.Clear ();
470+ treelist.Add (&atree_);
471+ treelist.Add (&abtree);
472+ TTree a0tree (" a0tree" , " a0title" );
473+ a0tree.Branch (" a" , &value);
474+ std::unique_ptr<TFile> file3 (TFile::Open (" d4716.root" , " RECREATE" ));
475+ TFileMergeInfo info3 (file3.get ());
476+ info3.fOptions += " ImportBranches" ;
477+ a0tree.Merge (&treelist, &info3);
478+ file3->Write ();
479+ ASSERT_TRUE (a0tree.FindBranch (" a" ));
480+ EXPECT_EQ (a0tree.FindBranch (" a" )->GetEntries (), 2 );
481+ ASSERT_TRUE (a0tree.FindBranch (" b" ));
482+ EXPECT_EQ (a0tree.FindBranch (" b" )->GetEntries (), 2 );
483+ ASSERT_TRUE (atree_.FindBranch (" a" ));
484+ ASSERT_FALSE (atree_.FindBranch (" b" ));
485+ ASSERT_TRUE (abtree.FindBranch (" a" ));
486+ ASSERT_TRUE (abtree.FindBranch (" b" ));
487+ EXPECT_EQ (atree_.FindBranch (" a" )->GetEntries (), 1 );
488+ EXPECT_EQ (abtree.FindBranch (" a" )->GetEntries (), 1 );
489+ EXPECT_EQ (abtree.FindBranch (" b" )->GetEntries (), 1 );
490+
491+ // Case 4 - this 1 entry (3 branch) + 1 entry (1 branch) + (0 entry / 1 branch)
492+ TTree abctree (" abctree" , " abctitle" );
493+ abctree.Branch (" a" , &value);
494+ abctree.Branch (" b" , &value);
495+ abctree.Branch (" c" , &value);
496+ value = 11 ;
497+ abctree.Fill ();
498+ TTree ctree (" ctree" , " ctitle" );
499+ ctree.Branch (" c" , &value);
500+ value = 42 ;
501+ ctree.Fill ();
502+ TTree c0tree (" c0tree" , " c0title" );
503+ c0tree.Branch (" c" , &value);
504+ std::unique_ptr<TFile> file4 (TFile::Open (" e4716.root" , " RECREATE" ));
505+ TFileMergeInfo info4 (file4.get ());
506+ info4.fOptions += " ImportBranches" ;
507+ treelist.Clear ();
508+ treelist.Add (&ctree);
509+ treelist.Add (&c0tree);
510+ abctree.Merge (&treelist, &info4);
511+ file4->Write ();
512+ ASSERT_TRUE (abctree.FindBranch (" a" ));
513+ ASSERT_TRUE (abctree.FindBranch (" b" );
514+ ASSERT_TRUE (abctree.FindBranch (" c" ));
515+ EXPECT_EQ (abctree.FindBranch (" a" )->GetEntries (), 2 );
516+ EXPECT_EQ (abctree.FindBranch (" b" )->GetEntries (), 2 );
517+ EXPECT_EQ (abctree.FindBranch (" c" )->GetEntries (), 2 );
518+ ASSERT_FALSE (ctree.FindBranch (" a" ));
519+ ASSERT_FALSE (ctree.FindBranch (" b" ));
520+ ASSERT_TRUE (ctree.FindBranch (" c" ));
521+ EXPECT_EQ (ctree.FindBranch (" c" )->GetEntries (), 1 );
522+ ASSERT_FALSE (c0tree.FindBranch (" a" ));
523+ ASSERT_FALSE (c0tree.FindBranch (" b" ));
524+ ASSERT_TRUE (c0tree.FindBranch (" c" ));
525+ EXPECT_EQ (c0tree.FindBranch (" c" )->GetEntries (), 0 );
526+ }
0 commit comments