@@ -2915,6 +2915,90 @@ TEST(RNTupleMerger, MergeLMExtBig)
29152915 }
29162916}
29172917
2918+ TEST (RNTupleMerger, MergeFirstNoEntries)
2919+ {
2920+ // Try merging two ntuples with different schemas, the first of which has no entries.
2921+ FileRaii fileGuard1 (" test_ntuple_merge_first_noentries_1.root" );
2922+ FileRaii fileGuard2 (" test_ntuple_merge_first_noentries_2.root" );
2923+ {
2924+ auto model = RNTupleModel::Create ();
2925+ model->MakeField <float >(" foo" );
2926+ model->MakeField <int >(" bar" );
2927+ auto ntuple = RNTupleWriter::Recreate (std::move (model), " ntuple" , fileGuard1.GetPath ());
2928+ }
2929+
2930+ {
2931+ auto model = RNTupleModel::Create ();
2932+ auto p = model->MakeField <double >(" baz" );
2933+ auto ntuple = RNTupleWriter::Recreate (std::move (model), " ntuple" , fileGuard2.GetPath ());
2934+ for (int i = 0 ; i < 10 ; ++i) {
2935+ *p = i;
2936+ ntuple->Fill ();
2937+ }
2938+ }
2939+
2940+ // Now merge the inputs
2941+ FileRaii fileGuardOut (" test_ntuple_merge_first_noentries_out.root" );
2942+ {
2943+ // Gather the input sources
2944+ std::vector<std::unique_ptr<RPageSource>> sources;
2945+ sources.push_back (RPageSource::Create (" ntuple" , fileGuard1.GetPath (), RNTupleReadOptions ()));
2946+ sources.push_back (RPageSource::Create (" ntuple" , fileGuard2.GetPath (), RNTupleReadOptions ()));
2947+ std::vector<RPageSource *> sourcePtrs;
2948+ for (const auto &s : sources) {
2949+ sourcePtrs.push_back (s.get ());
2950+ }
2951+
2952+ RNTupleMergeOptions opts;
2953+ {
2954+ auto destination = std::make_unique<RPageSinkFile>(" ntuple" , fileGuardOut.GetPath (), RNTupleWriteOptions ());
2955+ opts.fMergingMode = ENTupleMergingMode::kFilter ;
2956+ RNTupleMerger merger{std::move (destination)};
2957+ auto res = merger.Merge (sourcePtrs, opts);
2958+ // Should fail because the second input doesn't have all the fields of the first
2959+ EXPECT_FALSE (bool (res));
2960+ }
2961+ {
2962+ auto destination = std::make_unique<RPageSinkFile>(" ntuple" , fileGuardOut.GetPath (), RNTupleWriteOptions ());
2963+ opts.fMergingMode = ENTupleMergingMode::kStrict ;
2964+ RNTupleMerger merger{std::move (destination)};
2965+ auto res = merger.Merge (sourcePtrs, opts);
2966+ EXPECT_FALSE (bool (res));
2967+ }
2968+ {
2969+ auto destination = std::make_unique<RPageSinkFile>(" ntuple" , fileGuardOut.GetPath (), RNTupleWriteOptions ());
2970+ opts.fMergingMode = ENTupleMergingMode::kUnion ;
2971+ RNTupleMerger merger{std::move (destination)};
2972+ auto res = merger.Merge (sourcePtrs, opts);
2973+ EXPECT_TRUE (bool (res));
2974+ }
2975+ }
2976+
2977+ {
2978+ auto ntupleOut = RNTupleReader::Open (" ntuple" , fileGuardOut.GetPath ());
2979+ EXPECT_EQ (ntupleOut->GetNEntries (), 10 );
2980+ EXPECT_EQ (ntupleOut->GetDescriptor ().GetNFields (), 4 ); // zero field + the 3 we added
2981+ auto pFoo = ntupleOut->GetModel ().GetDefaultEntry ().GetPtr <float >(" foo" );
2982+ auto pBar = ntupleOut->GetModel ().GetDefaultEntry ().GetPtr <int >(" bar" );
2983+ auto pBaz = ntupleOut->GetModel ().GetDefaultEntry ().GetPtr <double >(" baz" );
2984+ for (int i : ntupleOut->GetEntryRange ()) {
2985+ ntupleOut->LoadEntry (i);
2986+ EXPECT_FLOAT_EQ (*pFoo, 0 );
2987+ EXPECT_EQ (*pBar, 0 );
2988+ EXPECT_DOUBLE_EQ (*pBaz, i);
2989+ }
2990+
2991+ const auto &descFoo = ntupleOut->GetDescriptor ().GetColumnDescriptor (0 );
2992+ const auto &descBar = ntupleOut->GetDescriptor ().GetColumnDescriptor (1 );
2993+ const auto &descBaz = ntupleOut->GetDescriptor ().GetColumnDescriptor (2 );
2994+ EXPECT_FALSE (descFoo.IsDeferredColumn ());
2995+ // The columns extended from the second input are not deferred as they normally would, because the first
2996+ // input had 0 entries, so they still start at index 0.
2997+ EXPECT_FALSE (descBar.IsDeferredColumn ());
2998+ EXPECT_FALSE (descBaz.IsDeferredColumn ());
2999+ }
3000+ }
3001+
29183002TEST (RNTupleMerger, MergeEmptySchema)
29193003{
29203004 // Try merging two ntuples with an empty schema
@@ -2969,9 +3053,9 @@ TEST(RNTupleMerger, MergeEmptySchema)
29693053 // We expect the output ntuple to have no entries
29703054 {
29713055 auto ntupleOut = RNTupleReader::Open (" ntuple" , fileGuardOut.GetPath ());
2972- ASSERT_EQ (ntupleOut->GetNEntries (), 0 );
3056+ EXPECT_EQ (ntupleOut->GetNEntries (), 0 );
29733057 // We expect to see only the zero field
2974- ASSERT_EQ (ntupleOut->GetDescriptor ().GetNFields (), 1 );
3058+ EXPECT_EQ (ntupleOut->GetDescriptor ().GetNFields (), 1 );
29753059 }
29763060}
29773061
0 commit comments