@@ -29,14 +29,85 @@ TEST(RNTupleCompat, Epoch)
2929 }
3030}
3131
32- TEST (RNTupleCompat, FeatureFlag )
32+ TEST (RNTupleCompat, FeatureFlagSupported )
3333{
34- FileRaii fileGuard (" test_ntuple_compat_feature_flag.root" );
34+ // Write all known feature flags in the header and verify we can read the RNTuple correctly.
35+ FileRaii fileGuard (" test_ntuple_compat_feature_flag_supported.root" );
3536
3637 RNTupleDescriptorBuilder descBuilder;
3738 descBuilder.SetVersionForWriting ();
3839 descBuilder.SetNTuple (" ntpl" , " " );
39- descBuilder.SetFeature (RNTupleDescriptor::kFeatureFlagTest );
40+ for (unsigned int flag = 0 ; flag < RNTupleDescriptor::kFeatureFlag_COUNT ; ++flag)
41+ descBuilder.SetFeature (flag);
42+ descBuilder.AddField (RFieldDescriptorBuilder::FromField (ROOT::RFieldZero ()).FieldId (0 ).MakeDescriptor ().Unwrap ());
43+ ASSERT_TRUE (static_cast <bool >(descBuilder.EnsureValidDescriptor ()));
44+
45+ RNTupleWriteOptions options;
46+ auto writer = RNTupleFileWriter::Recreate (" ntpl" , fileGuard.GetPath (), EContainerFormat::kTFile , options);
47+ RNTupleSerializer serializer;
48+
49+ auto ctx = serializer.SerializeHeader (nullptr , descBuilder.GetDescriptor ()).Unwrap ();
50+ auto buffer = std::make_unique<unsigned char []>(ctx.GetHeaderSize ());
51+ ctx = serializer.SerializeHeader (buffer.get (), descBuilder.GetDescriptor ()).Unwrap ();
52+ writer->WriteNTupleHeader (buffer.get (), ctx.GetHeaderSize (), ctx.GetHeaderSize ());
53+
54+ auto szFooter = serializer.SerializeFooter (nullptr , descBuilder.GetDescriptor (), ctx).Unwrap ();
55+ buffer = std::make_unique<unsigned char []>(szFooter);
56+ serializer.SerializeFooter (buffer.get (), descBuilder.GetDescriptor (), ctx);
57+ writer->WriteNTupleFooter (buffer.get (), szFooter, szFooter);
58+
59+ writer->Commit ();
60+ // Call destructor to flush data to disk
61+ writer = nullptr ;
62+
63+ auto pageSource = RPageSource::Create (" ntpl" , fileGuard.GetPath ());
64+ EXPECT_NO_THROW (pageSource->Attach ());
65+ }
66+
67+ TEST (RNTupleCompat, FeatureFlagSupportedFooter)
68+ {
69+ // Write all known feature flags in the footer and verify we can read the RNTuple correctly.
70+ FileRaii fileGuard (" test_ntuple_compat_feature_flag_supported_footer.root" );
71+
72+ RNTupleDescriptorBuilder descBuilder;
73+ descBuilder.SetVersionForWriting ();
74+ descBuilder.SetNTuple (" ntpl" , " " );
75+ descBuilder.AddField (RFieldDescriptorBuilder::FromField (ROOT::RFieldZero ()).FieldId (0 ).MakeDescriptor ().Unwrap ());
76+ ASSERT_TRUE (static_cast <bool >(descBuilder.EnsureValidDescriptor ()));
77+
78+ RNTupleWriteOptions options;
79+ auto writer = RNTupleFileWriter::Recreate (" ntpl" , fileGuard.GetPath (), EContainerFormat::kTFile , options);
80+ RNTupleSerializer serializer;
81+
82+ auto ctx = serializer.SerializeHeader (nullptr , descBuilder.GetDescriptor ()).Unwrap ();
83+ auto buffer = std::make_unique<unsigned char []>(ctx.GetHeaderSize ());
84+ ctx = serializer.SerializeHeader (buffer.get (), descBuilder.GetDescriptor ()).Unwrap ();
85+ writer->WriteNTupleHeader (buffer.get (), ctx.GetHeaderSize (), ctx.GetHeaderSize ());
86+
87+ for (unsigned int flag = 0 ; flag < RNTupleDescriptor::kFeatureFlag_COUNT ; ++flag)
88+ descBuilder.SetFeature (flag);
89+
90+ auto szFooter = serializer.SerializeFooter (nullptr , descBuilder.GetDescriptor (), ctx).Unwrap ();
91+ buffer = std::make_unique<unsigned char []>(szFooter);
92+ serializer.SerializeFooter (buffer.get (), descBuilder.GetDescriptor (), ctx);
93+ writer->WriteNTupleFooter (buffer.get (), szFooter, szFooter);
94+
95+ writer->Commit ();
96+ // Call destructor to flush data to disk
97+ writer = nullptr ;
98+
99+ auto pageSource = RPageSource::Create (" ntpl" , fileGuard.GetPath ());
100+ EXPECT_NO_THROW (pageSource->Attach ());
101+ }
102+
103+ TEST (RNTupleCompat, FeatureFlagUnsupported)
104+ {
105+ FileRaii fileGuard (" test_ntuple_compat_feature_flag_unsupported.root" );
106+
107+ RNTupleDescriptorBuilder descBuilder;
108+ descBuilder.SetVersionForWriting ();
109+ descBuilder.SetNTuple (" ntpl" , " " );
110+ descBuilder.SetFeature (RNTupleDescriptor::kFeatureFlag_Test );
40111 descBuilder.AddField (RFieldDescriptorBuilder::FromField (ROOT::RFieldZero ()).FieldId (0 ).MakeDescriptor ().Unwrap ());
41112 ASSERT_TRUE (static_cast <bool >(descBuilder.EnsureValidDescriptor ()));
42113
@@ -67,9 +138,9 @@ TEST(RNTupleCompat, FeatureFlag)
67138 }
68139}
69140
70- TEST (RNTupleCompat, FeatureFlagInFooter )
141+ TEST (RNTupleCompat, FeatureFlagUnsupportedInFooter )
71142{
72- FileRaii fileGuard (" test_ntuple_compat_feature_flag_footer .root" );
143+ FileRaii fileGuard (" test_ntuple_compat_feature_flag_unsupported_footer .root" );
73144
74145 RNTupleDescriptorBuilder descBuilder;
75146 descBuilder.SetVersionForWriting ();
@@ -87,7 +158,7 @@ TEST(RNTupleCompat, FeatureFlagInFooter)
87158 writer->WriteNTupleHeader (buffer.get (), ctx.GetHeaderSize (), ctx.GetHeaderSize ());
88159
89160 // Write the feature flags in the footer
90- descBuilder.SetFeature (RNTupleDescriptor::kFeatureFlagTest );
161+ descBuilder.SetFeature (RNTupleDescriptor::kFeatureFlag_Test );
91162
92163 auto szFooter = serializer.SerializeFooter (nullptr , descBuilder.GetDescriptor (), ctx).Unwrap ();
93164 buffer = std::make_unique<unsigned char []>(szFooter);
@@ -107,6 +178,49 @@ TEST(RNTupleCompat, FeatureFlagInFooter)
107178 }
108179}
109180
181+ TEST (RNTupleCompat, FeatureFlagMixSupportedUnsupported)
182+ {
183+ FileRaii fileGuard (" test_ntuple_compat_feature_flag_mix_supported.root" );
184+
185+ RNTupleDescriptorBuilder descBuilder;
186+ descBuilder.SetVersionForWriting ();
187+ descBuilder.SetNTuple (" ntpl" , " " );
188+ for (unsigned int flag = 0 ; flag < RNTupleDescriptor::kFeatureFlag_COUNT ; ++flag)
189+ descBuilder.SetFeature (flag);
190+ descBuilder.AddField (RFieldDescriptorBuilder::FromField (ROOT::RFieldZero ()).FieldId (0 ).MakeDescriptor ().Unwrap ());
191+ ASSERT_TRUE (static_cast <bool >(descBuilder.EnsureValidDescriptor ()));
192+
193+ RNTupleWriteOptions options;
194+ auto writer = RNTupleFileWriter::Recreate (" ntpl" , fileGuard.GetPath (), EContainerFormat::kTFile , options);
195+ RNTupleSerializer serializer;
196+
197+ auto ctx = serializer.SerializeHeader (nullptr , descBuilder.GetDescriptor ()).Unwrap ();
198+ auto buffer = std::make_unique<unsigned char []>(ctx.GetHeaderSize ());
199+ ctx = serializer.SerializeHeader (buffer.get (), descBuilder.GetDescriptor ()).Unwrap ();
200+ writer->WriteNTupleHeader (buffer.get (), ctx.GetHeaderSize (), ctx.GetHeaderSize ());
201+
202+ // This is unsupported!
203+ descBuilder.SetFeature (RNTupleDescriptor::kFeatureFlag_COUNT );
204+
205+ auto szFooter = serializer.SerializeFooter (nullptr , descBuilder.GetDescriptor (), ctx).Unwrap ();
206+ buffer = std::make_unique<unsigned char []>(szFooter);
207+ serializer.SerializeFooter (buffer.get (), descBuilder.GetDescriptor (), ctx);
208+ writer->WriteNTupleFooter (buffer.get (), szFooter, szFooter);
209+
210+ writer->Commit ();
211+ // Call destructor to flush data to disk
212+ writer = nullptr ;
213+
214+ auto pageSource = RPageSource::Create (" ntpl" , fileGuard.GetPath ());
215+ try {
216+ pageSource->Attach ();
217+ FAIL () << " opening an RNTuple that uses an unsupported feature should fail" ;
218+ } catch (const ROOT ::RException &err) {
219+ EXPECT_THAT (err.what (), testing::HasSubstr (" unsupported format feature: " +
220+ std::to_string (RNTupleDescriptor::kFeatureFlag_COUNT )));
221+ }
222+ }
223+
110224TEST (RNTupleCompat, FwdCompat_FutureNTupleAnchor)
111225{
112226 using ROOT ::RXTuple;
0 commit comments