diff --git a/roottest/root/dataframe/CMakeLists.txt b/roottest/root/dataframe/CMakeLists.txt index a66a524e31ee0..779ad45a9fa9f 100644 --- a/roottest/root/dataframe/CMakeLists.txt +++ b/roottest/root/dataframe/CMakeLists.txt @@ -215,15 +215,7 @@ ROOTTEST_ADD_TEST(typeguessing OUTREF test_typeguessing.ref FIXTURES_REQUIRED root-dataframe-typeguessing-fixture) -ROOTTEST_GENERATE_EXECUTABLE(misc - test_misc.cxx - LIBRARIES ${DFLIBRARIES} GenVector - FIXTURES_SETUP root-dataframe-misc-fixture) - -ROOTTEST_ADD_TEST(misc - EXEC ./misc - OUTREF test_misc.ref - FIXTURES_REQUIRED root-dataframe-misc-fixture) +ROOT_ADD_GTEST(misc test_misc.cxx LIBRARIES ROOT::ROOTDataFrame ROOT::GenVector) ROOTTEST_ADD_TEST(ctors MACRO test_ctors.C+ diff --git a/roottest/root/dataframe/test_misc.cxx b/roottest/root/dataframe/test_misc.cxx index f501c380b92ed..69fca1add07e1 100644 --- a/roottest/root/dataframe/test_misc.cxx +++ b/roottest/root/dataframe/test_misc.cxx @@ -8,169 +8,184 @@ #include #include +#include using FourVector = ROOT::Math::XYZTVector; using FourVectors = std::vector; using CylFourVector = ROOT::Math::RhoEtaPhiVector; -void getTracks(FourVectors& tracks) { +void getTracks(FourVectors &tracks) +{ static TRandom3 R(1); - const double M = 0.13957; // set pi+ mass + const double M = 0.13957; // set pi+ mass auto nPart = R.Poisson(5); tracks.clear(); tracks.reserve(nPart); for (size_t i = 0; i < nPart; ++i) { - double px = R.Gaus(0,10); - double py = R.Gaus(0,10); - double pt = sqrt(px*px +py*py); - double eta = R.Uniform(-3,3); - double phi = R.Uniform(0.0 , 2*TMath::Pi() ); - CylFourVector vcyl( pt, eta, phi); + double px = R.Gaus(0, 10); + double py = R.Gaus(0, 10); + double pt = sqrt(px * px + py * py); + double eta = R.Uniform(-3, 3); + double phi = R.Uniform(0.0, 2 * TMath::Pi()); + CylFourVector vcyl(pt, eta, phi); // set energy - double E = sqrt( vcyl.R()*vcyl.R() + M*M); - FourVector q( vcyl.X(), vcyl.Y(), vcyl.Z(), E); + double E = sqrt(vcyl.R() * vcyl.R() + M * M); + FourVector q(vcyl.X(), vcyl.Y(), vcyl.Z(), E); // fill track vector tracks.emplace_back(q); } } -// A simple helper function to fill a test tree and save it to file -// This makes the example stand-alone -void FillTree(const char* filename, const char* treeName) { - TFile f(filename,"RECREATE"); - TTree t(treeName,treeName); - double b1; - int b2; - float b3; - float b4; - std::vector tracks; - std::vector dv {-1,2,3,4}; - std::vector sv {-1,2,3,4}; - std::list sl {1,2,3,4}; - t.Branch("b1", &b1); - t.Branch("b2", &b2); - t.Branch("b3", &b3); - t.Branch("b4", &b4); - t.Branch("tracks", &tracks); - t.Branch("dv", &dv); - t.Branch("sl", &sl); - t.Branch("sv", &sv); - - for(int i = 0; i < 20; ++i) { - b1 = i; - b2 = i*i; - b3 = sqrt(i*i*i); - b4 = i; - getTracks(tracks); - dv.emplace_back(i); - sl.emplace_back(i); - sv.emplace_back(i * 0.5); - t.Fill(); +struct RootTestRDFMisc : public ::testing::Test { + constexpr static auto fFileName = "test_misc.root"; + constexpr static auto fTreeName = "myTree"; + static void SetUpTestCase() + { + auto f = std::make_unique(fFileName, "RECREATE"); + auto t = std::make_unique(fTreeName, fTreeName); + + double b1; + int b2; + float b3; + float b4; + std::vector tracks; + std::vector dv{-1, 2, 3, 4}; + std::vector sv{-1, 2, 3, 4}; + std::list sl{1, 2, 3, 4}; + t->Branch("b1", &b1); + t->Branch("b2", &b2); + t->Branch("b3", &b3); + t->Branch("b4", &b4); + t->Branch("tracks", &tracks); + t->Branch("dv", &dv); + t->Branch("sl", &sl); + t->Branch("sv", &sv); + + for (int i = 0; i < 20; ++i) { + b1 = i; + b2 = i * i; + b3 = sqrt(i * i * i); + b4 = i; + getTracks(tracks); + dv.emplace_back(i); + sl.emplace_back(i); + sv.emplace_back(i * 0.5); + t->Fill(); + } + f->Write(); } - t.Write(); - f.Close(); - return; -} + static void TearDownTestCase() { std::remove(fFileName); } +}; -// check that value has both same value and same type as ref -template -void CheckRes(const T& v, const T& ref, const char* msg) { - if (v!=ref) { - std::cerr << "***FAILED*** " << msg << std::endl; +template +void expect_vec_eq(const T0 &v1, const T1 &v2) +{ + ASSERT_EQ(v1.size(), v2.size()) << "Vectors 'v1' and 'v2' are of unequal length"; + for (std::size_t i = 0ull; i < v1.size(); ++i) { + if constexpr (std::is_floating_point::value) + EXPECT_FLOAT_EQ(v1[i], v2[i]) << "Vectors 'v1' and 'v2' differ at index " << i; + else + EXPECT_EQ(v1[i], v2[i]) << "Vectors 'v1' and 'v2' differ at index " << i; } } -void test_misc() { - // Prepare an input tree to run on - auto fileName = "test_misc.root"; - auto treeName = "myTree"; - FillTree(fileName,treeName); +TEST_F(RootTestRDFMisc, Test1) +{ - // Define data-frame - ROOT::RDataFrame d(treeName, fileName); - // ...and two dummy filters + ROOT::RDataFrame d(fTreeName, fFileName); auto ok = []() { return true; }; - auto ko = []() { return false; }; - // TEST 1: no-op filter and Run - d.Filter(ok).Foreach([](double x) { std::cout << x << std::endl; }, {"b1"}); + // Foreach with an upstream filter returning always true: should see all values + std::vector b1Values; + d.Filter(ok).Foreach([&b1Values](double x) { b1Values.push_back(x); }, {"b1"}); + expect_vec_eq(b1Values, std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}); +} - // TEST 2: Forked actions - // always apply first filter before doing three different actions +TEST_F(RootTestRDFMisc, Test2) +{ + // Ensure filters are applied before doing any action + ROOT::RDataFrame d(fTreeName, fFileName); + auto ok = []() { return true; }; + auto ko = []() { return false; }; auto dd = d.Filter(ok); - dd.Foreach([](double x) { std::cout << x << " "; }, {"b1"}); - dd.Foreach([](int y) { std::cout << y << std::endl; }, {"b2"}); + + std::vector b2Values; + dd.Foreach([&b2Values](int y) { b2Values.push_back(y); }, {"b2"}); + expect_vec_eq( + b2Values, std::vector{0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361}); auto c = dd.Count(); - // ... and another filter-and-foreach + EXPECT_EQ(*c, 20ULL) << "Count after a filter that returns always true should be 20."; + auto ddd = dd.Filter(ko); - ddd.Foreach([]() { std::cout << "ERROR" << std::endl; }); - auto cv = *c; - std::cout << "c " << cv << std::endl; - CheckRes(cv,20ULL,"Forked Actions"); - - // TEST 3: default branches - ROOT::RDataFrame d2(treeName, fileName, {"b1"}); - auto d2f = d2.Filter([](double b1) { return b1 < 5; }).Filter(ok); - auto c2 = d2f.Count(); - d2f.Foreach([](double b1) { std::cout << b1 << std::endl; }); - auto c2v = *c2; - std::cout << "c2 " << c2v << std::endl; - CheckRes(c2v,5ULL,"Default branches"); - - // TEST 4: execute Run lazily and implicitly - ROOT::RDataFrame d3(treeName, fileName, {"b1"}); - auto d3f = d3.Filter([](double b1) { return b1 < 4; }).Filter(ok); - auto c3 = d3f.Count(); - auto c3v = *c3; - std::cout << "c3 " << c3v << std::endl; - CheckRes(c3v,4ULL,"Execute Run lazily and implicitly"); - - // TEST 5: non trivial branch - ROOT::RDataFrame d4(treeName, fileName, {"tracks"}); - auto d4f = d4.Filter([](FourVectors const & tracks) { return tracks.size() > 7; }); - auto c4 = d4f.Count(); - auto c4v = *c4; - std::cout << "c4 " << c4v << std::endl; - CheckRes(c4v,1ULL,"Non trivial test"); - - // TEST 6: Create a histogram - ROOT::RDataFrame d5(treeName, fileName, {"b2"}); - auto h1 = d5.Histo1D(); - auto h2 = d5.Histo1D("b1"); - TH1D dvHisto("dvHisto","The DV histo", 64, -8, 8); - auto h3 = d5.Histo1D(std::move(dvHisto),"dv"); - auto h4 = d5.Histo1D>("sl"); - std::cout << "Histo1: nEntries " << h1->GetEntries() << std::endl; - std::cout << "Histo2: nEntries " << h2->GetEntries() << std::endl; - std::cout << "Histo3: nEntries " << h3->GetEntries() << std::endl; - std::cout << "Histo4: nEntries " << h4->GetEntries() << std::endl; - - // TEST 7: Define - ROOT::RDataFrame d6(treeName, fileName); - auto r6 = d6.Define("iseven", [](int b2) { return b2 % 2 == 0; }, {"b2"}) + std::vector b2ValuesEmpty; + ddd.Foreach([&b2ValuesEmpty](int y) { b2ValuesEmpty.push_back(y); }, {"b2"}); + expect_vec_eq(b2ValuesEmpty, std::vector{}); +} + +TEST_F(RootTestRDFMisc, Test3) +{ + auto ok = []() { return true; }; + + // Use default column names + ROOT::RDataFrame d(fTreeName, fFileName, {"b1"}); + auto df = d.Filter([](double b1) { return b1 < 5; }).Filter(ok); + std::vector b1Values; + df.Foreach([&b1Values](double b1) { b1Values.push_back(b1); }, {"b1"}); + expect_vec_eq(b1Values, std::vector{0, 1, 2, 3, 4}); +} + +TEST_F(RootTestRDFMisc, Test4) +{ + ROOT::RDataFrame d(fTreeName, fFileName, {"tracks"}); + auto df = d.Filter([](FourVectors const &tracks) { return tracks.size() > 7; }); + auto c = df.Count(); + EXPECT_EQ(*c, 1); +} + +TEST_F(RootTestRDFMisc, Test5) +{ + ROOT::RDataFrame d(fTreeName, fFileName, {"b2"}); + auto h1 = d.Histo1D(); + auto h2 = d.Histo1D("b1"); + TH1D dvHisto("dvHisto", "The DV histo", 64, -8, 8); + auto h3 = d.Histo1D(std::move(dvHisto), "dv"); + auto h4 = d.Histo1D>("sl"); + EXPECT_EQ(h1->GetEntries(), 20); + EXPECT_EQ(h2->GetEntries(), 20); + EXPECT_EQ(h3->GetEntries(), 290); + EXPECT_EQ(h4->GetEntries(), 290); +} + +TEST_F(RootTestRDFMisc, Test6) +{ + ROOT::RDataFrame d(fTreeName, fFileName); + auto r = d.Define("iseven", [](int b2) { return b2 % 2 == 0; }, {"b2"}) .Filter([](bool iseven) { return iseven; }, {"iseven"}) .Count(); - auto c6v = *r6; - std::cout << c6v << std::endl; - CheckRes(c6v, 10ULL, "Define"); - - // TEST 8: Define with default branches, filters, non-trivial types - ROOT::RDataFrame d7(treeName, fileName, {"tracks"}); - auto dd7 = d7.Filter([](int b2) { return b2 % 2 == 0; }, {"b2"}) - .Define("ptsum", [](FourVectors const & tracks) { - double sum = 0; - for(auto& track: tracks) - sum += track.Pt(); - return sum; }); - auto c7 = dd7.Count(); - auto h7 = dd7.Histo1D("ptsum"); - auto c7v = *c7; - CheckRes(c7v, 10ULL, "Define complicated"); - std::cout << "Define Histo entries: " << h7->GetEntries() << std::endl; - std::cout << "Define Histo mean: " << h7->GetMean() << std::endl; + EXPECT_EQ(*r, 10); +} + +TEST_F(RootTestRDFMisc, Test7) +{ + ROOT::RDataFrame d(fTreeName, fFileName, {"tracks"}); + auto dd = d.Filter([](int b2) { return b2 % 2 == 0; }, {"b2"}).Define("ptsum", [](FourVectors const &tracks) { + double sum = 0; + for (auto &track : tracks) + sum += track.Pt(); + return sum; + }); + auto c = dd.Count(); + auto h = dd.Histo1D("ptsum"); + EXPECT_EQ(*c, 10); + EXPECT_EQ(h->GetEntries(), 10); + EXPECT_FLOAT_EQ(h->GetMean(), 60.952423); +} + +TEST_F(RootTestRDFMisc, Test8) +{ // TEST 9: Get minimum, maximum, sum, mean - ROOT::RDataFrame d8(treeName, fileName, {"b2"}); + ROOT::RDataFrame d8(fTreeName, fFileName, {"b2"}); auto min_b2 = d8.Min(); auto min_dv = d8.Min("dv"); auto max_b2 = d8.Max(); @@ -193,120 +208,135 @@ void test_misc() { auto mean_b2v = *mean_b2; auto mean_dvv = *mean_dv; - CheckRes(min_b2v, 0., "Min of ints"); - CheckRes(min_dvv, -1., "Min of vector"); - CheckRes(max_b2v, 361., "Max of ints"); - CheckRes(max_dvv, 19., "Max of vector"); - CheckRes(sum_b2v, 2470., "Sum of ints"); - CheckRes(sum_dvv, 1490., "Sum of vector"); - CheckRes(sum_b2_initv, 2471, "Sum of ints with init"); - CheckRes(sum_dv_initv, 1491., "Sum of vector with init"); - CheckRes(mean_b2v, 123.5, "Mean of ints"); - CheckRes(mean_dvv, 5.1379310344827588963, "Mean of vector"); - - std::cout << "Min b2: " << *min_b2 << std::endl; - std::cout << "Min dv: " << *min_dv << std::endl; - std::cout << "Max b2: " << *max_b2 << std::endl; - std::cout << "Max dv: " << *max_dv << std::endl; - std::cout << "Sum b2: " << *sum_b2 << std::endl; - std::cout << "Sum dv: " << *sum_dv << std::endl; - std::cout << "Sum b2 init: " << *sum_b2_init << std::endl; - std::cout << "Sum dv init: " << *sum_dv_init << std::endl; - std::cout << "Mean b2: " << *mean_b2 << std::endl; - std::cout << "Mean dv: " << *mean_dv << std::endl; - - // TEST 10: Get a full column - ROOT::RDataFrame d9(treeName, fileName, {"tracks"}); - auto dd9 = d9.Filter([](int b2) { return b2 % 2 == 0; }, {"b2"}) - .Define("ptsum", [](FourVectors const & tracks) { - double sum = 0; - for(auto& track: tracks) - sum += track.Pt(); - return sum; }); - auto b2List = dd9.Take("b2"); - auto ptsumVec = dd9.Take>("ptsum"); - - for (auto& v : b2List) { // Test also the iteration without dereferencing - std::cout << v << std::endl; - } + EXPECT_FLOAT_EQ(min_b2v, 0.); + EXPECT_FLOAT_EQ(min_dvv, -1.); + EXPECT_FLOAT_EQ(max_b2v, 361.); + EXPECT_FLOAT_EQ(max_dvv, 19.); + EXPECT_FLOAT_EQ(sum_b2v, 2470.); + EXPECT_FLOAT_EQ(sum_dvv, 1490.); + EXPECT_FLOAT_EQ(sum_b2_initv, 2471.); + EXPECT_FLOAT_EQ(sum_dv_initv, 1491.); + EXPECT_FLOAT_EQ(mean_b2v, 123.5); + EXPECT_FLOAT_EQ(mean_dvv, 5.1379310344827588963); +} - for (auto& v : *ptsumVec) { - std::cout << v << std::endl; - } +TEST_F(RootTestRDFMisc, Test9) +{ + ROOT::RDataFrame d(fTreeName, fFileName, {"tracks"}); + auto dd = d.Filter([](int b2) { return b2 % 2 == 0; }, {"b2"}).Define("ptsum", [](FourVectors const &tracks) { + double sum = 0; + for (auto &track : tracks) + sum += track.Pt(); + return sum; + }); + auto b2List = dd.Take("b2"); + auto ptsumVec = dd.Take>("ptsum"); + + expect_vec_eq(*b2List, std::vector{0, 4, 16, 36, 64, 100, 144, 196, 256, 324}); + expect_vec_eq(*ptsumVec, std::vector{61.0508, 61.095249, 34.602367, 39.667374, 77.2068, 28.842136, 90.5761, + 115.61565, 50.1965, 50.671272}); +} + +TEST_F(RootTestRDFMisc, Test10) +{ + + // Different filters can be applied correctly even in-between runs + ROOT::RDataFrame d(fTreeName, fFileName, {"tracks"}); + auto df = d.Filter([](FourVectors const &tracks) { return tracks.size() > 2; }); + auto c = df.Count(); + EXPECT_EQ(*c, 18); + auto df_2 = df.Filter([](FourVectors const &tracks) { return tracks.size() < 5; }); + auto c_2 = df_2.Count(); + EXPECT_EQ(*c_2, 8); +} - // TEST 11: Re-hang action to RDataFrameProxy after running - ROOT::RDataFrame d10(treeName, fileName, {"tracks"}); - auto d10f = d10.Filter([](FourVectors const & tracks) { return tracks.size() > 2; }); - auto c10 = d10f.Count(); - std::cout << "Count for the first run is " << *c10 << std::endl; - auto d10f_2 = d10f.Filter([](FourVectors const & tracks) { return tracks.size() < 5; }); - auto c10_2 = d10f_2.Count(); - std::cout << "Count for the second run after adding a filter is " << *c10_2 << std::endl; - std::cout << "Count for the first run was " << *c10 << std::endl; - - // TEST 12: head node which goes out of scope should remain valid - auto l = [](FourVectors const & tracks) { return tracks.size() > 2; }; - auto giveMeFilteredDF = [&](){ - ROOT::RDataFrame d11(treeName, fileName, {"tracks"}); - auto a = d11.Filter(l); +TEST_F(RootTestRDFMisc, Test11) +{ + // head node which goes out of scope does not invalidate computation graph + auto l = [](FourVectors const &tracks) { return tracks.size() > 2; }; + auto giveMeFilteredDF = [&]() { + ROOT::RDataFrame d(fTreeName, fFileName, {"tracks"}); + auto a = d.Filter(l); return a; }; auto filteredDF = giveMeFilteredDF(); auto c11 = filteredDF.Count(); - std::cout << *c11 << std::endl; + EXPECT_EQ(*c11, 18); +} - // TEST 13: an action result pointer goes out of scope and the chain is ran - ROOT::RDataFrame d11(treeName, fileName); - auto d11c = d.Count(); +TEST_F(RootTestRDFMisc, Test12) +{ + // Even if action pointers attached to the same computation graph go out of scope, the graph remains valid for the + // action pointer that is still in scope. + ROOT::RDataFrame d(fTreeName, fFileName); + auto c = d.Count(); { - std::vector v; - for (int i=0;i<10000;++i) + std::vector v; + for (int i = 0; i < 10000; ++i) v.emplace_back(d.Count()); } - std::cout << "Count with action pointers which went out of scope: " << *d11c << std::endl; - - // TEST 14: fill 1D histograms - ROOT::RDataFrame d12(treeName, fileName, {"b1","b2"}); - auto wh1 = d12.Histo1D(); - auto wh2 = d12.Histo1D, std::list>("dv","sl"); - std::cout << "Wh1 Histo entries: " << wh1->GetEntries() << std::endl; - std::cout << "Wh1 Histo mean: " << wh1->GetMean() << std::endl; - std::cout << "Wh2 Histo entries: " << wh2->GetEntries() << std::endl; - std::cout << "Wh2 Histo mean: " << wh2->GetMean() << std::endl; - - // TEST 15: fill 2D histograms - ROOT::RDataFrame d13(treeName, fileName, {"b1","b2","b3"}); - auto h12d = d13.Histo2D(TH2D("h1","",64,0,1024,64,0,1024)); - auto h22d = d13.Histo2D, std::list>(TH2D("h2","",64,0,1024,64,0,1024),"dv","sl"); - auto h32d = d13.Histo2D(TH2D("h3","",64,0,1024,64,0,1024)); - std::cout << "h12d Histo entries: " << h12d->GetEntries() << std::endl; - std::cout << "h22d Histo entries: " << h22d->GetEntries() << std::endl; - std::cout << "h32d Histo entries: " << h32d->GetEntries() << " sum of weights: " << h32d->GetSumOfWeights() << std::endl; - - // TEST 15: fill 3D histograms - ROOT::RDataFrame d14(treeName, fileName, {"b1","b2","b3","b4"}); - auto h13d = d14.Histo3D(TH3D("h4","",64,0,1024,64,0,1024,64,0,1024)); - auto h23d = d14.Histo3D, - std::list, - std::vector>(TH3D("h5","",64,0,1024,64,0,1024,64,0,1024),"dv","sl","sv"); - auto h33d = d14.Histo3D(TH3D("h6","",64,0,1024,64,0,1024,64,0,1024)); - std::cout << "h13d Histo entries: " << h13d->GetEntries() << std::endl; - std::cout << "h23d Histo entries: " << h23d->GetEntries() << std::endl; - std::cout << "h33d Histo entries: " << h33d->GetEntries() << " sum of weights: " << h33d->GetSumOfWeights() << std::endl; - - // TEST 16: Take a collection of collections + EXPECT_EQ(*c, 20); +} + +TEST_F(RootTestRDFMisc, Test13) +{ + // Fill 1D histograms also using default column names + ROOT::RDataFrame d(fTreeName, fFileName, {"b1", "b2"}); + auto wh1 = d.Histo1D(); + auto wh2 = d.Histo1D, std::list>("dv", "sl"); + + EXPECT_EQ(wh1->GetEntries(), 20); + EXPECT_FLOAT_EQ(wh1->GetMean(), 14.615385); + EXPECT_EQ(wh2->GetEntries(), 290); + EXPECT_FLOAT_EQ(wh2->GetMean(), 9.05882); +} + +TEST_F(RootTestRDFMisc, Test14) +{ + // Fill 2D histograms also using default column names + ROOT::RDataFrame d(fTreeName, fFileName, {"b1", "b2", "b3"}); + auto h2d = d.Histo2D(TH2D("h1", "", 64, 0, 1024, 64, 0, 1024)); + auto h2dd = d.Histo2D, std::list>(TH2D("h2", "", 64, 0, 1024, 64, 0, 1024), "dv", "sl"); + auto h2ddd = d.Histo2D(TH2D("h3", "", 64, 0, 1024, 64, 0, 1024)); + + EXPECT_EQ(h2d->GetEntries(), 20); + EXPECT_EQ(h2dd->GetEntries(), 290); + EXPECT_EQ(h2ddd->GetEntries(), 20); + EXPECT_FLOAT_EQ(h2ddd->GetSumOfWeights(), 671.354); +} + +TEST_F(RootTestRDFMisc, Test15) +{ + // Fill 3D histograms also using default column names + ROOT::RDataFrame d(fTreeName, fFileName, {"b1", "b2", "b3", "b4"}); + auto h3d = d.Histo3D(TH3D("h4", "", 64, 0, 1024, 64, 0, 1024, 64, 0, 1024)); + auto h3dd = d.Histo3D, std::list, std::vector>( + TH3D("h5", "", 64, 0, 1024, 64, 0, 1024, 64, 0, 1024), "dv", "sl", "sv"); + auto h3ddd = d.Histo3D(TH3D("h6", "", 64, 0, 1024, 64, 0, 1024, 64, 0, 1024)); + + EXPECT_EQ(h3d->GetEntries(), 20); + EXPECT_EQ(h3dd->GetEntries(), 290); + EXPECT_EQ(h3ddd->GetEntries(), 20); + EXPECT_FLOAT_EQ(h3ddd->GetSumOfWeights(), 190.); +} + +TEST_F(RootTestRDFMisc, Test16) +{ + // Take a collection of collections ROOT::RDataFrame d15(1); - auto vb = d15.Define("v", [](){std::vector v {1,2,3}; return v;}).Take>("v"); - int nentries = 0; - for (auto&& el : vb) { - std::cout << "Entry " << nentries++ << std::endl; - for (auto&& i: el) { - std::cout << i << std::endl; - } - } + auto vb = d15.Define("v", + []() { + std::vector v{1, 2, 3}; + return v; + }) + .Take>("v"); + auto vbv = *vb; + ASSERT_EQ(vbv.size(), 1); + expect_vec_eq(vbv[0], std::vector{1, 2, 3}); } -int main() { - test_misc(); - return 0; +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/roottest/root/dataframe/test_misc.ref b/roottest/root/dataframe/test_misc.ref deleted file mode 100644 index dab0e127e20ec..0000000000000 --- a/roottest/root/dataframe/test_misc.ref +++ /dev/null @@ -1,105 +0,0 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 0 -1 -4 -9 -16 -25 -36 -49 -64 -81 -100 -121 -144 -169 -196 -225 -256 -289 -324 -361 -c 20 -0 -1 -2 -3 -4 -c2 5 -c3 4 -c4 1 -Histo1: nEntries 20 -Histo2: nEntries 20 -Histo3: nEntries 290 -Histo4: nEntries 290 -10 -Define Histo entries: 10 -Define Histo mean: 60.9524 -Min b2: 0 -Min dv: -1 -Max b2: 361 -Max dv: 19 -Sum b2: 2470 -Sum dv: 1490 -Sum b2 init: 2471 -Sum dv init: 1491 -Mean b2: 123.5 -Mean dv: 5.13793 -0 -4 -16 -36 -64 -100 -144 -196 -256 -324 -61.0508 -61.0952 -34.6024 -39.6674 -77.2068 -28.8421 -90.5761 -115.616 -50.1965 -50.6713 -Count for the first run is 18 -Count for the second run after adding a filter is 8 -Count for the first run was 18 -18 -Count with action pointers which went out of scope: 20 -Wh1 Histo entries: 20 -Wh1 Histo mean: 14.6154 -Wh2 Histo entries: 290 -Wh2 Histo mean: 9.05882 -h12d Histo entries: 20 -h22d Histo entries: 290 -h32d Histo entries: 20 sum of weights: 671.354 -h13d Histo entries: 20 -h23d Histo entries: 290 -h33d Histo entries: 20 sum of weights: 190 -Entry 0 -1 -2 -3