@@ -798,3 +798,157 @@ TEST_F(RNTupleProcessorTest, PrintStructureJoinedChainAsymmetric)
798798 " +-----------------------------+\n " ;
799799 EXPECT_EQ (exp2, os2.str ());
800800}
801+
802+ // This test is a translation using RNTupleProcessor of the test
803+ // introduced by https://github.com/root-project/root/pull/19322,
804+ // to ensure that the TTree friendship mechanism works equivalently
805+ // with the RNTuple join mechanism.
806+ class GH16805ProcessorTest : public testing ::Test {
807+ protected:
808+ const std::vector<std::string> fStepZeroFiles {
809+ " gh16805_rntuple_stepzero_0.root" ,
810+ " gh16805_rntuple_stepzero_1.root"
811+ };
812+
813+ const std::vector<std::string> fJoinFiles {
814+ " gh16805_rntuple_join_0.root" ,
815+ " gh16805_rntuple_join_1.root" ,
816+ " gh16805_rntuple_join_2.root"
817+ };
818+
819+ const std::string fStepOneFile = " gh16805_rntuple_stepone.root" ;
820+
821+ void WriteStepZero (const std::string &fileName, int begin, int end)
822+ {
823+ auto model = ROOT::RNTupleModel::Create ();
824+
825+ auto br1 = model->MakeField <int >(" stepZeroBr1" );
826+ auto br2 = model->MakeField <int >(" stepZeroBr2" );
827+
828+ auto writer = ROOT::RNTupleWriter::Recreate (std::move (model), " stepzero" , fileName);
829+
830+ for (int i = begin; i < end; ++i) {
831+ *br1 = i;
832+ *br2 = 2 * i;
833+ writer->Fill ();
834+ }
835+ }
836+
837+ void WriteStepOne (const std::string &fileName, int begin, int end)
838+ {
839+ auto model = ROOT::RNTupleModel::Create ();
840+
841+ auto br1 = model->MakeField <int >(" stepOneBr1" );
842+
843+ auto writer = ROOT::RNTupleWriter::Recreate (std::move (model), " stepone" , fileName);
844+
845+ for (int i = begin; i < end; ++i) {
846+ *br1 = i;
847+ writer->Fill ();
848+ }
849+ }
850+
851+ void WriteJoin (const std::string &fileName, int begin, int end)
852+ {
853+ auto model = ROOT::RNTupleModel::Create ();
854+
855+ auto br1 = model->MakeField <int >(" joinBr1" );
856+ auto br2 = model->MakeField <int >(" joinBr2" );
857+
858+ auto writer = ROOT::RNTupleWriter::Recreate (std::move (model), " topLevelJoin" , fileName);
859+
860+ for (int i = begin; i < end; ++i) {
861+ *br1 = i;
862+ *br2 = 2 * i;
863+ writer->Fill ();
864+ }
865+ }
866+
867+ void SetUp () override
868+ {
869+ WriteStepZero (fStepZeroFiles [0 ], 0 , 10 );
870+ WriteStepZero (fStepZeroFiles [1 ], 10 , 20 );
871+
872+ WriteJoin (fJoinFiles [0 ], 200 , 207 );
873+ WriteJoin (fJoinFiles [1 ], 207 , 214 );
874+ WriteJoin (fJoinFiles [2 ], 214 , 220 );
875+
876+ WriteStepOne (fStepOneFile , 100 , 120 );
877+ }
878+
879+ void TearDown () override
880+ {
881+ for (const auto &f : fStepZeroFiles )
882+ std::remove (f.c_str ());
883+
884+ for (const auto &f : fJoinFiles )
885+ std::remove (f.c_str ());
886+
887+ std::remove (fStepOneFile .c_str ());
888+ }
889+ };
890+
891+ TEST_F (GH16805ProcessorTest, JoinReading)
892+ {
893+ std::vector<RNTupleOpenSpec> stepOneSpecs{
894+ {" stepone" , fStepOneFile }
895+ };
896+
897+ std::vector<RNTupleOpenSpec> stepZeroSpecs{
898+ {" stepzero" , fStepZeroFiles [0 ]},
899+ {" stepzero" , fStepZeroFiles [1 ]}
900+ };
901+
902+ std::vector<RNTupleOpenSpec> joinSpecs{
903+ {" topLevelJoin" , fJoinFiles [0 ]},
904+ {" topLevelJoin" , fJoinFiles [1 ]},
905+ {" topLevelJoin" , fJoinFiles [2 ]}
906+ };
907+
908+ auto stepOneProc =
909+ RNTupleProcessor::CreateChain (stepOneSpecs, " stepone" );
910+
911+ auto stepZeroProc =
912+ RNTupleProcessor::CreateChain (stepZeroSpecs, " stepzero" );
913+
914+ auto joinProc =
915+ RNTupleProcessor::CreateChain (joinSpecs, " topLevelJoin" );
916+
917+ auto joinedWithJoin =
918+ RNTupleProcessor::CreateJoin (
919+ std::move (stepOneProc),
920+ std::move (joinProc),
921+ {}
922+ );
923+
924+ auto joinedAll =
925+ RNTupleProcessor::CreateJoin (
926+ std::move (joinedWithJoin),
927+ std::move (stepZeroProc),
928+ {}
929+ );
930+
931+ auto stepOneBr1 = joinedAll->RequestField <int >(" stepOneBr1" );
932+ auto joinBr1 = joinedAll->RequestField <int >(" topLevelJoin.joinBr1" );
933+ auto joinBr2 = joinedAll->RequestField <int >(" topLevelJoin.joinBr2" );
934+ auto stepZeroBr1 = joinedAll->RequestField <int >(" stepzero.stepZeroBr1" );
935+ auto stepZeroBr2 = joinedAll->RequestField <int >(" stepzero.stepZeroBr2" );
936+
937+ std::size_t i = 0 ;
938+
939+ for (auto idx : *joinedAll) {
940+ EXPECT_EQ (i, idx);
941+
942+ EXPECT_EQ (static_cast <int >(i), *stepZeroBr1);
943+ EXPECT_EQ (static_cast <int >(2 * i), *stepZeroBr2);
944+ EXPECT_EQ (static_cast <int >(100 + i), *stepOneBr1);
945+ EXPECT_EQ (static_cast <int >(200 + i), *joinBr1);
946+ EXPECT_EQ (static_cast <int >(2 * (200 + i)), *joinBr2);
947+
948+ ++i;
949+ }
950+
951+ EXPECT_EQ (20u , i);
952+ EXPECT_EQ (20u , joinedAll->GetNEntriesProcessed ());
953+ }
954+
0 commit comments