From 3a00eabc98440cdfbed60876b50ff12a36a46bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20Marjam=C3=A4ki?= Date: Wed, 24 Jun 2026 16:06:58 +0000 Subject: [PATCH] Add GH20033 regression test for joined processors --- tree/ntuple/test/ntuple_processor.cxx | 184 ++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/tree/ntuple/test/ntuple_processor.cxx b/tree/ntuple/test/ntuple_processor.cxx index d38dfb58ee672..56e370da70889 100644 --- a/tree/ntuple/test/ntuple_processor.cxx +++ b/tree/ntuple/test/ntuple_processor.cxx @@ -4,6 +4,12 @@ #include +#include + +#include + +#include + TEST(RNTupleProcessor, EmptyNTuple) { FileRaii fileGuard("test_ntuple_processor_empty.root"); @@ -952,3 +958,181 @@ TEST_F(GH16805ProcessorTest, JoinReading) EXPECT_EQ(20u, joinedAll->GetNEntriesProcessed()); } +using GH20033ProcessorConfig = std::tuple; + +class GH20033ProcessorTest : public testing::TestWithParam { +protected: + + const std::array fStepZeroFiles{ + "gh20033_rntuple_stepzero_0.root", + "gh20033_rntuple_stepzero_1.root" + }; + + // Muut analyysivaiheet omissa tiedostoissaan + const std::string fStepOneFile = "gh20033_rntuple_stepone.root"; + const std::string fStepTwoFile = "gh20033_rntuple_steptwo.root"; + const std::string fStepThreeFile = "gh20033_rntuple_stepthree.root"; + const std::string fStepFourFile = "gh20033_rntuple_stepfour.root"; + + // Luo stepZero-RNTuplen ja täyttää sen testidatalla + static void WriteStepZero(const std::string &fileName, int begin, int end) + { + auto model = RNTupleModel::Create(); + + auto stepZeroBr1 = model->MakeField("stepZeroBr1"); + auto stepZeroBr2 = model->MakeField("stepZeroBr2"); + auto value = model->MakeField("value"); + + auto writer = RNTupleWriter::Recreate(std::move(model), "stepzero", fileName); + + for (int i = begin; i < end; ++i) { + *stepZeroBr1 = i; + *stepZeroBr2 = 2 * i; + *value = i; + writer->Fill(); + } + } + + static void WriteStepFile(const std::string &fileName, + std::string_view ntupleName, + std::string_view fieldName, + int offset) + { + auto model = RNTupleModel::Create(); + + auto field = model->MakeField(std::string(fieldName)); + + auto value = model->MakeField("value"); + + auto writer = RNTupleWriter::Recreate(std::move(model), ntupleName, fileName); + + for (int i = 0; i < 20; ++i) { + *field = offset + i; + *value = offset + i; + writer->Fill(); + } + } + + void SetUp() override + { + + WriteStepZero(fStepZeroFiles[0], 0, 10); + WriteStepZero(fStepZeroFiles[1], 10, 20); + + WriteStepFile(fStepOneFile, "stepone", "stepOneBr1", 100); + WriteStepFile(fStepTwoFile, "steptwo", "stepTwoBr1", 200); + WriteStepFile(fStepThreeFile, "stepthree", "stepThreeBr1", 300); + WriteStepFile(fStepFourFile, "stepfour", "stepFourBr1", 400); + } + + void TearDown() override + { + for (const auto &fileName : fStepZeroFiles) + std::remove(fileName.c_str()); + + std::remove(fStepOneFile.c_str()); + std::remove(fStepTwoFile.c_str()); + std::remove(fStepThreeFile.c_str()); + std::remove(fStepFourFile.c_str()); + } + + std::unique_ptr CreateStepProcessor(std::string_view ntupleName, + const std::string &fileName, + bool useChain) + { + if (useChain) { + std::vector specs{{std::string(ntupleName), fileName}}; + return RNTupleProcessor::CreateChain(specs, std::string(ntupleName)); + } + + return RNTupleProcessor::Create({std::string(ntupleName), fileName}, std::string(ntupleName)); + } + + std::unique_ptr CreateJoinedProcessor() + { + std::vector stepZeroSpecs{ + {"stepzero", fStepZeroFiles[0]}, + {"stepzero", fStepZeroFiles[1]} + }; + + auto stepZeroProc = RNTupleProcessor::CreateChain(stepZeroSpecs, "stepzero"); + + const auto &[chainStepOne, chainStepTwo, chainStepThree, chainStepFour] = GetParam(); + + auto stepOneProc = CreateStepProcessor("stepone", fStepOneFile, chainStepOne); + auto stepTwoProc = CreateStepProcessor("steptwo", fStepTwoFile, chainStepTwo); + auto stepThreeProc = CreateStepProcessor("stepthree", fStepThreeFile, chainStepThree); + auto stepFourProc = CreateStepProcessor("stepfour", fStepFourFile, chainStepFour); + + auto joined = RNTupleProcessor::CreateJoin(std::move(stepFourProc), std::move(stepThreeProc), {}); + joined = RNTupleProcessor::CreateJoin(std::move(joined), std::move(stepTwoProc), {}); + joined = RNTupleProcessor::CreateJoin(std::move(joined), std::move(stepOneProc), {}); + joined = RNTupleProcessor::CreateJoin(std::move(joined), std::move(stepZeroProc), {}); + + return joined; + } +}; + +TEST_P(GH20033ProcessorTest, Regression) +{ + auto proc = CreateJoinedProcessor(); + + auto stepFourBr1 = proc->RequestField("stepFourBr1"); + auto stepThreeBr1 = proc->RequestField("stepthree.stepThreeBr1"); + auto stepTwoBr1 = proc->RequestField("steptwo.stepTwoBr1"); + auto stepOneBr1 = proc->RequestField("stepone.stepOneBr1"); + auto stepZeroBr1 = proc->RequestField("stepzero.stepZeroBr1"); + auto stepZeroBr2 = proc->RequestField("stepzero.stepZeroBr2"); + + std::size_t nEntries = 0; + + for (auto idx : *proc) { + EXPECT_EQ(nEntries, idx); + + EXPECT_EQ(static_cast(400 + idx), *stepFourBr1); + EXPECT_EQ(static_cast(300 + idx), *stepThreeBr1); + EXPECT_EQ(static_cast(200 + idx), *stepTwoBr1); + EXPECT_EQ(static_cast(100 + idx), *stepOneBr1); + EXPECT_EQ(static_cast(idx), *stepZeroBr1); + EXPECT_EQ(static_cast(2 * idx), *stepZeroBr2); + + ++nEntries; + } + + EXPECT_EQ(20u, nEntries); + EXPECT_EQ(20u, proc->GetNEntriesProcessed()); +} + +TEST_P(GH20033ProcessorTest, SameFieldName) +{ + auto proc = CreateJoinedProcessor(); + + auto stepFourValue = proc->RequestField("value"); + auto stepThreeValue = proc->RequestField("stepthree.value"); + auto stepTwoValue = proc->RequestField("steptwo.value"); + auto stepOneValue = proc->RequestField("stepone.value"); + auto stepZeroValue = proc->RequestField("stepzero.value"); + + std::size_t nEntries = 0; + + for (auto idx : *proc) { + EXPECT_EQ(nEntries, idx); + + EXPECT_EQ(static_cast(400 + idx), *stepFourValue); + EXPECT_EQ(static_cast(300 + idx), *stepThreeValue); + EXPECT_EQ(static_cast(200 + idx), *stepTwoValue); + EXPECT_EQ(static_cast(100 + idx), *stepOneValue); + EXPECT_EQ(static_cast(idx), *stepZeroValue); + + ++nEntries; + } + + EXPECT_EQ(20u, nEntries); + EXPECT_EQ(20u, proc->GetNEntriesProcessed()); +} + +INSTANTIATE_TEST_SUITE_P( + CreateVsCreateChain, + GH20033ProcessorTest, + testing::Combine(testing::Bool(), testing::Bool(), testing::Bool(), testing::Bool()) +);