diff --git a/builtins/glew/CMakeLists.txt b/builtins/glew/CMakeLists.txt index d999c9fb9aa2a..24dc07d4fbda9 100644 --- a/builtins/glew/CMakeLists.txt +++ b/builtins/glew/CMakeLists.txt @@ -45,7 +45,7 @@ target_compile_options(GLEW PRIVATE ${GLEW_DEFINITIONS}) target_include_directories(GLEW INTERFACE $) target_link_libraries(GLEW PRIVATE OpenGL::GL OpenGL::GLU) -add_library(GLEW::GLEW ALIAS GLEW) +target_link_libraries(GLEW::GLEW INTERFACE GLEW) set(GLEW_LIBRARY $ CACHE INTERNAL "") set(GLEW_LIBRARIES GLEW::GLEW CACHE INTERNAL "") diff --git a/cmake/modules/RootBuildOptions.cmake b/cmake/modules/RootBuildOptions.cmake index c740b610b97aa..66848be90d704 100644 --- a/cmake/modules/RootBuildOptions.cmake +++ b/cmake/modules/RootBuildOptions.cmake @@ -318,12 +318,6 @@ elseif(APPLE) set(x11_defvalue OFF) endif() -# Current limitations for modules: -#---Modules are disabled on aarch64 platform (due ODR violations) -if(CMAKE_SYSTEM_PROCESSOR MATCHES aarch64) - set(runtime_cxxmodules_defvalue OFF) -endif() - # builtin_openssl is only supported on macOS if(builtin_openssl AND NOT APPLE) message(FATAL_ERROR ">>> Option 'builtin_openssl' is only supported on macOS.") diff --git a/cmake/modules/SearchInstalledSoftware.cmake b/cmake/modules/SearchInstalledSoftware.cmake index d5ab7e2113585..24b2277943a1d 100644 --- a/cmake/modules/SearchInstalledSoftware.cmake +++ b/cmake/modules/SearchInstalledSoftware.cmake @@ -100,9 +100,6 @@ if(cocoa) if(APPLE) set(x11 OFF CACHE BOOL "Disabled because cocoa requested (${x11_description})" FORCE) set(builtin_freetype ON CACHE BOOL "Enabled because needed for Cocoa graphics (${builtin_freetype_description})" FORCE) - if(NOT opengl) - message(FATAL_ERROR "Option \"cocoa=ON\" requires \"opengl=ON\"!") - endif() else() message(STATUS "Cocoa option can only be enabled on MacOSX platform") set(cocoa OFF CACHE BOOL "Disabled because only available on MacOSX (${cocoa_description})" FORCE) @@ -607,7 +604,9 @@ endif() find_package(Python3 3.8 COMPONENTS ${python_components}) #---Check for OpenGL installation------------------------------------------------------- -if(opengl) +# OpenGL is required by various graf3d features that are enabled with opengl=ON, +# or by the Cocoa-related code that always requires it. +if(opengl OR cocoa) message(STATUS "Looking for OpenGL") if(APPLE) set(CMAKE_FIND_FRAMEWORK FIRST) @@ -635,10 +634,17 @@ if(NOT WIN32 AND NOT APPLE) set(opengl OFF CACHE BOOL "OpenGL requires x11" FORCE) endif() endif() +# The opengl flag enables the graf3d features that depend on OpenGL, and these +# features also depend on asimage. Therefore, the configuration will fail if +# asimage is off. See also: https://github.com/root-project/root/issues/16250 +if(opengl AND NOT asimage) + message(FATAL_ERROR "OpenGL features enabled with \"opengl=ON\" require \"asimage=ON\"") +endif() #---Check for GLEW ------------------------------------------------------------------- -# Opengl is "must" requirement for Glew. -if(opengl AND NOT builtin_glew) +# Glew is required by various graf3d features that are enabled with opengl=ON, +# or by the Cocoa-related code that always requires it. +if((opengl OR cocoa) AND NOT builtin_glew) message(STATUS "Looking for GLEW") if(fail-on-missing) find_package(GLEW REQUIRED) @@ -665,6 +671,7 @@ endif() if(builtin_glew) list(APPEND ROOT_BUILTINS GLEW) + add_library(GLEW::GLEW INTERFACE IMPORTED GLOBAL) add_subdirectory(builtins/glew) endif() diff --git a/graf2d/cocoa/CMakeLists.txt b/graf2d/cocoa/CMakeLists.txt index 8f2f944bc4867..28d6097fb6e23 100644 --- a/graf2d/cocoa/CMakeLists.txt +++ b/graf2d/cocoa/CMakeLists.txt @@ -39,7 +39,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(GCocoa "-framework Cocoa" "-framework OpenGL" ${FREETYPE_LIBRARIES} - RGlew + GLEW::GLEW ) target_include_directories(GCocoa PRIVATE ${CMAKE_SOURCE_DIR}/graf3d/gl/inc) @@ -48,11 +48,4 @@ target_include_directories(GCocoa PRIVATE ${CMAKE_SOURCE_DIR}/graf3d/gl/inc) target_compile_options(GCocoa PRIVATE -ObjC++ -Wno-deprecated-declarations) target_include_directories(GCocoa PRIVATE ${FREETYPE_INCLUDE_DIRS}) -if(opengl) # special case when cocoa is enabled but not opengl (i.e. gminimal=ON) - target_include_directories(GCocoa PRIVATE ${OPENGL_INCLUDE_DIR}) -else() - target_include_directories(GCocoa PRIVATE - ${CMAKE_SOURCE_DIR}/graf3d/gl/inc - ) -endif(opengl) - +target_include_directories(GCocoa PRIVATE ${OPENGL_INCLUDE_DIR}) diff --git a/graf2d/cocoa/src/TGCocoa.mm b/graf2d/cocoa/src/TGCocoa.mm index 46fc2d4c072c8..ffd8bdba35e3d 100644 --- a/graf2d/cocoa/src/TGCocoa.mm +++ b/graf2d/cocoa/src/TGCocoa.mm @@ -13,11 +13,7 @@ #include "TGCocoa.h" -// We want to pickup ROOT's glew and not the system OpenGL coming from: -// ROOTOpenGLView.h ->QuartzWindow.h->Cocoa.h -// Allowing TU's which include the system GL and then glew (from TGLIncludes) -// leads to gltypes.h redefinition errors. -#include "TGLIncludes.h" +#include #include "ROOTOpenGLView.h" #include "CocoaConstants.h" diff --git a/js/build/jsroot.js b/js/build/jsroot.js index 591e7d82e16eb..ef4ac568b6c86 100644 --- a/js/build/jsroot.js +++ b/js/build/jsroot.js @@ -12,7 +12,7 @@ const version_id = 'dev', /** @summary version date * @desc Release date in format day/month/year like '14/04/2022' */ -version_date = '2/10/2024', +version_date = '8/10/2024', /** @summary version id and date * @desc Produced by concatenation of {@link version_id} and {@link version_date} @@ -9790,13 +9790,13 @@ function approximateLabelWidth(label, font, fsize) { /** @summary array defines features supported by latex parser, used by both old and new parsers * @private */ const latex_features = [ - { name: '#it{' }, // italic - { name: '#bf{' }, // bold + { name: '#it{', bi: 'italic' }, // italic + { name: '#bf{', bi: 'bold' }, // bold { name: '#underline{', deco: 'underline' }, // underline { name: '#overline{', deco: 'overline' }, // overline { name: '#strike{', deco: 'line-through' }, // line through - { name: '#kern[', arg: 'float' }, // horizontal shift - { name: '#lower[', arg: 'float' }, // vertical shift + { name: '#kern[', arg: 'float', shift: 'x' }, // horizontal shift + { name: '#lower[', arg: 'float', shift: 'y' }, // vertical shift { name: '#scale[', arg: 'float' }, // font scale { name: '#color[', arg: 'int' }, // font color { name: '#font[', arg: 'int' }, // font face @@ -10132,8 +10132,7 @@ function parseLatex(node, arg, label, curr) { elem.attr('fill', curr.color || arg.color || null); // set font size directly to element to avoid complex control - if (curr.fisze !== curr.font.size) - elem.attr('font-size', Math.round(curr.fsize)); + elem.attr('font-size', Math.max(1, Math.round(curr.fsize))); if (curr.font?.isSymbol) { elem.text(replaceSymbols(s, curr.font.isSymbol)); @@ -10417,16 +10416,18 @@ function parseLatex(node, arg, label, curr) { continue; } - if (found.name === '#bf{' || found.name === '#it{') { + if (found.bi) { // bold or italic const sublabel = extractSubLabel(); - if (sublabel === -1) return false; + if (sublabel === -1) + return false; const subpos = createSubPos(); - if (found.name === '#bf{') - subpos.bold = !subpos.bold; - else - subpos.italic = !subpos.italic; + let value; + for (let c = curr; c && (value === undefined && c); c = c.parent) + value = c[found.bi]; + + subpos[found.bi] = !value; parseLatex(currG(), arg, sublabel, subpos); @@ -10453,7 +10454,7 @@ function parseLatex(node, arg, label, curr) { label = label.slice(pos + 2); } - if ((found.name === '#kern[') || (found.name === '#lower[')) { + if (found.shift) { const sublabel = extractSubLabel(); if (sublabel === -1) return false; @@ -10462,9 +10463,12 @@ function parseLatex(node, arg, label, curr) { parseLatex(currG(), arg, sublabel, subpos); let shiftx = 0, shifty = 0; - if (found.name === 'kern[') shiftx = foundarg; else shifty = foundarg; + if (found.shift === 'x') + shiftx = foundarg * subpos.rect.width; + else + shifty = foundarg * subpos.rect.height; - positionGNode(subpos, curr.x + shiftx * subpos.rect.width, curr.y + shifty * subpos.rect.height); + positionGNode(subpos, curr.x + shiftx, curr.y + shifty); shiftX(subpos.rect.width * (shiftx > 0 ? 1 + foundarg : 1)); @@ -10479,6 +10483,11 @@ function parseLatex(node, arg, label, curr) { subpos = createSubPos(); gg.attr('href', foundarg); + if (!isBatchMode()) { + gg.on('mouseenter', () => gg.style('text-decoration', 'underline')) + .on('mouseleave', () => gg.style('text-decoration', null)) + .append('svg:title').text(`link on ${foundarg}`); + } parseLatex(gg, arg, sublabel, subpos); @@ -73527,10 +73536,10 @@ class TPavePainter extends ObjectPainter { } else if ((opt === 'postitle') || painter.isDummyPos(pave)) { const st = gStyle, fp = painter.getFramePainter(); if (st && fp) { - const midx = st.fTitleX, y2 = st.fTitleY; + const midx = st.fTitleX, y2 = st.fTitleY, fsz = st.fTitleFontSize; let w = st.fTitleW, h = st.fTitleH; - if (!h) h = (y2 - fp.fY2NDC) * 0.7; + if (!h) h = Math.max((y2 - fp.fY2NDC) * 0.7, (fsz < 1) ? 1.1 * fsz : 1.1 * fsz / fp.getFrameWidth()); if (!w) w = fp.fX2NDC - fp.fX1NDC; if (!Number.isFinite(h) || (h <= 0)) h = 0.06; if (!Number.isFinite(w) || (w <= 0)) w = 0.44; @@ -82308,9 +82317,7 @@ let TH1Painter$2 = class TH1Painter extends THistPainter { if (show_markers) { // draw markers also when e2 option was specified - let style = this.options.MarkStyle; - if (!style && (histo.fMarkerStyle === 1)) style = 8; // as in recent ROOT changes - this.createAttMarker({ attr: histo, style }); // when style not configured, it will be ignored + this.createAttMarker({ attr: histo, style: this.options.MarkStyle }); // when style not configured, it will be ignored if (this.markeratt.size > 0) { // simply use relative move from point, can optimize in the future path_marker = ''; @@ -147115,8 +147122,11 @@ async function drawText$1() { fact = 0.8; } - if (is_url) - this.draw_g.attr('href', text.fName).append('title').text(`Link on ${text.fName}`); + if (is_url) { + this.draw_g.attr('href', text.fName); + if (!this.isBatchMode()) + this.draw_g.append('svg:title').text(`link on ${text.fName}`); + } return this.startTextDrawingAsync(this.textatt.font, this.textatt.getSize(w, h, fact, 0.05)) .then(() => this.drawText(arg)) diff --git a/js/changes.md b/js/changes.md index ba546bbe8b579..f732fe054f1dc 100644 --- a/js/changes.md +++ b/js/changes.md @@ -36,6 +36,8 @@ 33. Fix - properly redraw TMultiGraph 34. Fix - show empty bin in TProfile2D if it has entries #316 35. Fix - unzooming on log scale was extending range forevever +36. Fix - do not force style 8 for hist markers +37. Fix - ensure minimal hist title height ## Changes in 7.7.4 diff --git a/js/modules/base/latex.mjs b/js/modules/base/latex.mjs index 89f7c4fca2893..f22a2361526d3 100644 --- a/js/modules/base/latex.mjs +++ b/js/modules/base/latex.mjs @@ -1,4 +1,4 @@ -import { loadScript, settings, isNodeJs, isStr, source_dir, browser } from '../core.mjs'; +import { loadScript, settings, isNodeJs, isStr, source_dir, browser, isBatchMode } from '../core.mjs'; import { getElementRect, _loadJSDOM, makeTranslate } from './BasePainter.mjs'; import { FontHandler, kSymbol, kWingdings, kTimes } from './FontHandler.mjs'; @@ -236,13 +236,13 @@ function approximateLabelWidth(label, font, fsize) { /** @summary array defines features supported by latex parser, used by both old and new parsers * @private */ const latex_features = [ - { name: '#it{' }, // italic - { name: '#bf{' }, // bold + { name: '#it{', bi: 'italic' }, // italic + { name: '#bf{', bi: 'bold' }, // bold { name: '#underline{', deco: 'underline' }, // underline { name: '#overline{', deco: 'overline' }, // overline { name: '#strike{', deco: 'line-through' }, // line through - { name: '#kern[', arg: 'float' }, // horizontal shift - { name: '#lower[', arg: 'float' }, // vertical shift + { name: '#kern[', arg: 'float', shift: 'x' }, // horizontal shift + { name: '#lower[', arg: 'float', shift: 'y' }, // vertical shift { name: '#scale[', arg: 'float' }, // font scale { name: '#color[', arg: 'int' }, // font color { name: '#font[', arg: 'int' }, // font face @@ -578,8 +578,7 @@ function parseLatex(node, arg, label, curr) { elem.attr('fill', curr.color || arg.color || null); // set font size directly to element to avoid complex control - if (curr.fisze !== curr.font.size) - elem.attr('font-size', Math.round(curr.fsize)); + elem.attr('font-size', Math.max(1, Math.round(curr.fsize))); if (curr.font?.isSymbol) { elem.text(replaceSymbols(s, curr.font.isSymbol)); @@ -863,16 +862,18 @@ function parseLatex(node, arg, label, curr) { continue; } - if (found.name === '#bf{' || found.name === '#it{') { + if (found.bi) { // bold or italic const sublabel = extractSubLabel(); - if (sublabel === -1) return false; + if (sublabel === -1) + return false; const subpos = createSubPos(); - if (found.name === '#bf{') - subpos.bold = !subpos.bold; - else - subpos.italic = !subpos.italic; + let value; + for (let c = curr; c && (value === undefined && c); c = c.parent) + value = c[found.bi]; + + subpos[found.bi] = !value; parseLatex(currG(), arg, sublabel, subpos); @@ -899,7 +900,7 @@ function parseLatex(node, arg, label, curr) { label = label.slice(pos + 2); } - if ((found.name === '#kern[') || (found.name === '#lower[')) { + if (found.shift) { const sublabel = extractSubLabel(); if (sublabel === -1) return false; @@ -908,9 +909,12 @@ function parseLatex(node, arg, label, curr) { parseLatex(currG(), arg, sublabel, subpos); let shiftx = 0, shifty = 0; - if (found.name === 'kern[') shiftx = foundarg; else shifty = foundarg; + if (found.shift === 'x') + shiftx = foundarg * subpos.rect.width; + else + shifty = foundarg * subpos.rect.height; - positionGNode(subpos, curr.x + shiftx * subpos.rect.width, curr.y + shifty * subpos.rect.height); + positionGNode(subpos, curr.x + shiftx, curr.y + shifty); shiftX(subpos.rect.width * (shiftx > 0 ? 1 + foundarg : 1)); @@ -925,6 +929,11 @@ function parseLatex(node, arg, label, curr) { subpos = createSubPos(); gg.attr('href', foundarg); + if (!isBatchMode()) { + gg.on('mouseenter', () => gg.style('text-decoration', 'underline')) + .on('mouseleave', () => gg.style('text-decoration', null)) + .append('svg:title').text(`link on ${foundarg}`); + } parseLatex(gg, arg, sublabel, subpos); diff --git a/js/modules/core.mjs b/js/modules/core.mjs index 13c73eef3f805..2b23542938817 100644 --- a/js/modules/core.mjs +++ b/js/modules/core.mjs @@ -4,7 +4,7 @@ const version_id = 'dev', /** @summary version date * @desc Release date in format day/month/year like '14/04/2022' */ -version_date = '2/10/2024', +version_date = '8/10/2024', /** @summary version id and date * @desc Produced by concatenation of {@link version_id} and {@link version_date} diff --git a/js/modules/draw/more.mjs b/js/modules/draw/more.mjs index fc8c90ebc513f..b321ab9aab193 100644 --- a/js/modules/draw/more.mjs +++ b/js/modules/draw/more.mjs @@ -60,8 +60,11 @@ async function drawText() { fact = 0.8; } - if (is_url) - this.draw_g.attr('href', text.fName).append('title').text(`Link on ${text.fName}`); + if (is_url) { + this.draw_g.attr('href', text.fName); + if (!this.isBatchMode()) + this.draw_g.append('svg:title').text(`link on ${text.fName}`); + } return this.startTextDrawingAsync(this.textatt.font, this.textatt.getSize(w, h, fact, 0.05)) .then(() => this.drawText(arg)) diff --git a/js/modules/hist/TPavePainter.mjs b/js/modules/hist/TPavePainter.mjs index 130b50232be13..a591bf658d4a8 100644 --- a/js/modules/hist/TPavePainter.mjs +++ b/js/modules/hist/TPavePainter.mjs @@ -1398,10 +1398,10 @@ class TPavePainter extends ObjectPainter { } else if ((opt === 'postitle') || painter.isDummyPos(pave)) { const st = gStyle, fp = painter.getFramePainter(); if (st && fp) { - const midx = st.fTitleX, y2 = st.fTitleY; + const midx = st.fTitleX, y2 = st.fTitleY, fsz = st.fTitleFontSize; let w = st.fTitleW, h = st.fTitleH; - if (!h) h = (y2 - fp.fY2NDC) * 0.7; + if (!h) h = Math.max((y2 - fp.fY2NDC) * 0.7, (fsz < 1) ? 1.1 * fsz : 1.1 * fsz / fp.getFrameWidth()); if (!w) w = fp.fX2NDC - fp.fX1NDC; if (!Number.isFinite(h) || (h <= 0)) h = 0.06; if (!Number.isFinite(w) || (w <= 0)) w = 0.44; diff --git a/js/modules/hist2d/TH1Painter.mjs b/js/modules/hist2d/TH1Painter.mjs index dd9d0239683ac..367d8cee978aa 100644 --- a/js/modules/hist2d/TH1Painter.mjs +++ b/js/modules/hist2d/TH1Painter.mjs @@ -566,9 +566,7 @@ class TH1Painter extends THistPainter { if (show_markers) { // draw markers also when e2 option was specified - let style = this.options.MarkStyle; - if (!style && (histo.fMarkerStyle === 1)) style = 8; // as in recent ROOT changes - this.createAttMarker({ attr: histo, style }); // when style not configured, it will be ignored + this.createAttMarker({ attr: histo, style: this.options.MarkStyle }); // when style not configured, it will be ignored if (this.markeratt.size > 0) { // simply use relative move from point, can optimize in the future path_marker = ''; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index eb4a8ca8c0b31..5c4ff82b10ed8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -183,7 +183,7 @@ if(ROOT_opengl_FOUND) FAILREGEX "FAILED|Error in" LABELS longtest) endif() - if(FIREFOX_EXECUTABLE) + if(FIREFOX_EXECUTABLE AND NOT APPLE) ROOT_ADD_TEST(test-stressgraphics-firefox RUN_SERIAL ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib:$ENV{LD_LIBRARY_PATH} diff --git a/tree/ntuple/v7/src/RNTupleModel.cxx b/tree/ntuple/v7/src/RNTupleModel.cxx index 766aad03cbc13..61099751d44ce 100644 --- a/tree/ntuple/v7/src/RNTupleModel.cxx +++ b/tree/ntuple/v7/src/RNTupleModel.cxx @@ -49,6 +49,19 @@ ROOT::Experimental::RNTupleModel::RProjectedFields::EnsureValidMapping(const RFi return R__FAIL("field mapping type mismatch: " + source->GetFieldName() + " --> " + target->GetFieldName()); } + auto fnHasArrayParent = [](const RFieldBase &f) -> bool { + auto parent = f.GetParent(); + while (parent) { + if (parent->GetNRepetitions() > 0) + return true; + parent = parent->GetParent(); + } + return false; + }; + if (fnHasArrayParent(*source) || fnHasArrayParent(*target)) { + return R__FAIL("unsupported field mapping across fixed-size arrays"); + } + // We support projections only across records and collections. In the following, we check that the projected // field is on the same path of collection fields in the field tree than the source field. @@ -56,8 +69,10 @@ ROOT::Experimental::RNTupleModel::RProjectedFields::EnsureValidMapping(const RFi auto fnBreakPoint = [](const RFieldBase *f) -> const RFieldBase * { auto parent = f->GetParent(); while (parent) { - if (parent->GetStructure() != ENTupleStructure::kRecord) + if ((parent->GetStructure() != ENTupleStructure::kRecord) && + (parent->GetStructure() != ENTupleStructure::kLeaf)) { return parent; + } parent = parent->GetParent(); } // We reached the zero field diff --git a/tree/ntuple/v7/test/ntuple_project.cxx b/tree/ntuple/v7/test/ntuple_project.cxx index c210275f02f48..39cf2c018d974 100644 --- a/tree/ntuple/v7/test/ntuple_project.cxx +++ b/tree/ntuple/v7/test/ntuple_project.cxx @@ -6,21 +6,24 @@ TEST(RNTupleProjection, Basics) auto model = RNTupleModel::Create(); model->MakeField("met", 42.0); + model->MakeField>("atomicNumber", 7); auto fvec = model->MakeField>("vec"); fvec->emplace_back(1.0); fvec->emplace_back(2.0); auto f1 = RFieldBase::Create("missingE", "float").Unwrap(); model->AddProjectedField(std::move(f1), [](const std::string &) { return "met"; }); - auto f2 = RFieldBase::Create("aliasVec", "std::vector").Unwrap(); - model->AddProjectedField(std::move(f2), [](const std::string &fieldName) { + auto f2 = RFieldBase::Create("number", "int").Unwrap(); + model->AddProjectedField(std::move(f2), [](const std::string &) { return "atomicNumber._0"; }); + auto f3 = RFieldBase::Create("aliasVec", "std::vector").Unwrap(); + model->AddProjectedField(std::move(f3), [](const std::string &fieldName) { if (fieldName == "aliasVec") return "vec"; else return "vec._0"; }); - auto f3 = RFieldBase::Create("vecSize", "ROOT::Experimental::RNTupleCardinality").Unwrap(); - model->AddProjectedField(std::move(f3), [](const std::string &) { return "vec"; }); + auto f4 = RFieldBase::Create("vecSize", "ROOT::Experimental::RNTupleCardinality").Unwrap(); + model->AddProjectedField(std::move(f4), [](const std::string &) { return "vec"; }); { auto writer = RNTupleWriter::Recreate(std::move(model), "A", fileGuard.GetPath()); @@ -35,9 +38,11 @@ TEST(RNTupleProjection, Basics) EXPECT_TRUE(desc.GetFieldDescriptor(missingEFieldId).IsProjectedField()); EXPECT_EQ(metFieldId, desc.GetFieldDescriptor(missingEFieldId).GetProjectionSourceId()); auto viewMissingE = reader->GetView("missingE"); + auto viewNumber = reader->GetView("number"); auto viewAliasVec = reader->GetView>("aliasVec"); auto viewVecSize = reader->GetView>("vecSize"); EXPECT_FLOAT_EQ(42.0, viewMissingE(0)); + EXPECT_EQ(7, viewNumber(0)); EXPECT_EQ(2U, viewAliasVec(0).size()); EXPECT_FLOAT_EQ(1.0, viewAliasVec(0).at(0)); EXPECT_FLOAT_EQ(2.0, viewAliasVec(0).at(1)); @@ -48,11 +53,14 @@ TEST(RNTupleProjection, Basics) auto reconstructedModel = reader->GetDescriptor().CreateModel(options); auto itrFields = reconstructedModel->GetFieldZero().cbegin(); EXPECT_EQ("met", itrFields->GetQualifiedFieldName()); + EXPECT_EQ("atomicNumber", (++itrFields)->GetQualifiedFieldName()); + EXPECT_EQ("atomicNumber._0", (++itrFields)->GetQualifiedFieldName()); EXPECT_EQ("vec", (++itrFields)->GetQualifiedFieldName()); EXPECT_EQ("vec._0", (++itrFields)->GetQualifiedFieldName()); EXPECT_EQ(reconstructedModel->GetFieldZero().cend(), ++itrFields); auto itrProjectedFields = reconstructedModel->GetProjectedFields().GetFieldZero()->cbegin(); EXPECT_EQ("missingE", itrProjectedFields->GetQualifiedFieldName()); + EXPECT_EQ("number", (++itrProjectedFields)->GetQualifiedFieldName()); EXPECT_EQ("aliasVec", (++itrProjectedFields)->GetQualifiedFieldName()); EXPECT_EQ("aliasVec._0", (++itrProjectedFields)->GetQualifiedFieldName()); EXPECT_EQ("vecSize", (++itrProjectedFields)->GetQualifiedFieldName()); @@ -68,6 +76,7 @@ TEST(RNTupleProjection, CatchInvalidMappings) model->MakeField>("vec"); model->MakeField>("variant"); model->MakeField>>("nnlo"); + model->MakeField>("lorentz"); auto f1 = RFieldBase::Create("fail", "float").Unwrap(); try { @@ -126,10 +135,18 @@ TEST(RNTupleProjection, CatchInvalidMappings) EXPECT_THAT(err.what(), testing::HasSubstr("unsupported field mapping ")); } - auto f6 = RFieldBase::Create("fail", "std::vector").Unwrap(); + auto f6 = RFieldBase::Create("fail", "float").Unwrap(); + try { + model->AddProjectedField(std::move(f6), [](const std::string &) { return "lorentz._0"; }).ThrowOnError(); + FAIL() << "mapping across fixed-size array should throw"; + } catch (const RException &err) { + EXPECT_THAT(err.what(), testing::HasSubstr("unsupported field mapping ")); + } + + auto f7 = RFieldBase::Create("fail", "std::vector").Unwrap(); try { model - ->AddProjectedField(std::move(f6), + ->AddProjectedField(std::move(f7), [](const std::string &fieldName) { if (fieldName == "fail") return "nnlo._0";