@@ -287,6 +287,100 @@ TEST_F(ValidateExtensionRegistrationTest,
287287 EXPECT_EQ (result->funcs .size (), 1u );
288288}
289289
290+ // A v2 type whose encode_vdf_name is malformed fails validation.
291+ TEST_F (ValidateExtensionRegistrationTest, V2TypeBadVdfName) {
292+ const char *bad_names[] = {
293+ " MYTYPE::transform" , // unrecognised method suffix
294+ " WRONGTYPE::from_string" , // prefix does not match type name
295+ " ::MYTPE::transform" ,
296+ " MYTPE::::transform" ,
297+ };
298+
299+ for (const char *bad_name : bad_names) {
300+ vef_type_desc_t td = {};
301+ td.protocol = VEF_PROTOCOL_2;
302+ td.name = " MYTYPE" ;
303+ td.persisted_length = 16 ;
304+ td.max_decode_buffer_length = 256 ;
305+ td.encode_vdf_name = bad_name;
306+
307+ vef_type_desc_t *types[] = {&td};
308+ vef_registration_t reg = {};
309+ reg.protocol = VEF_PROTOCOL_2;
310+ reg.deprecated_extension_name = " my_ext" ;
311+ reg.type_count = 1 ;
312+ reg.types = types;
313+
314+ std::string error;
315+ auto result = villagesql::veb::validate_extension_registration (
316+ make_ext_reg (®, VEF_PROTOCOL_2), " my_ext" , " 1.0.0" , error);
317+
318+ EXPECT_FALSE (result.has_value ()) << " bad_name=" << bad_name;
319+ EXPECT_NE (error.find (" MYTYPE" ), std::string::npos)
320+ << " bad_name=" << bad_name;
321+ }
322+ }
323+
324+ // A v2 type registration using valid VDF names succeeds end-to-end.
325+ TEST_F (ValidateExtensionRegistrationTest, V2TypeValidVdfNames) {
326+ vef_type_desc_t td = {};
327+ td.protocol = VEF_PROTOCOL_2;
328+ td.name = " MYTYPE" ;
329+ td.persisted_length = 16 ;
330+ td.max_decode_buffer_length = 256 ;
331+ td.encode_vdf_name = " MYTYPE::from_string" ;
332+ td.decode_vdf_name = " MYTYPE::to_string" ;
333+ td.compare_vdf_name = " MYTYPE::compare" ;
334+
335+ vef_type_t str_type = {VEF_TYPE_STRING, nullptr };
336+ vef_type_t int_type = {VEF_TYPE_INT, nullptr };
337+ vef_type_t custom_mytype = {VEF_TYPE_CUSTOM, " MYTYPE" };
338+
339+ vef_type_t encode_params[] = {str_type};
340+ vef_signature_t encode_sig = {1 , encode_params, custom_mytype};
341+ vef_func_desc_t encode_fd = {};
342+ encode_fd.protocol = VEF_PROTOCOL_2;
343+ encode_fd.name = " MYTYPE::from_string" ;
344+ encode_fd.signature = &encode_sig;
345+ encode_fd.vdf = stub_vdf;
346+
347+ vef_type_t decode_params[] = {custom_mytype};
348+ vef_signature_t decode_sig = {1 , decode_params, str_type};
349+ vef_func_desc_t decode_fd = {};
350+ decode_fd.protocol = VEF_PROTOCOL_2;
351+ decode_fd.name = " MYTYPE::to_string" ;
352+ decode_fd.signature = &decode_sig;
353+ decode_fd.vdf = stub_vdf;
354+
355+ vef_type_t compare_params[] = {custom_mytype, custom_mytype};
356+ vef_signature_t compare_sig = {2 , compare_params, int_type};
357+ vef_func_desc_t compare_fd = {};
358+ compare_fd.protocol = VEF_PROTOCOL_2;
359+ compare_fd.name = " MYTYPE::compare" ;
360+ compare_fd.signature = &compare_sig;
361+ compare_fd.vdf = stub_vdf;
362+
363+ vef_type_desc_t *types[] = {&td};
364+ vef_func_desc_t *funcs[] = {&encode_fd, &decode_fd, &compare_fd};
365+
366+ vef_registration_t reg = {};
367+ reg.protocol = VEF_PROTOCOL_2;
368+ reg.deprecated_extension_name = " my_ext" ;
369+ reg.type_count = 1 ;
370+ reg.types = types;
371+ reg.func_count = 3 ;
372+ reg.funcs = funcs;
373+
374+ std::string error;
375+ auto result = villagesql::veb::validate_extension_registration (
376+ make_ext_reg (®, VEF_PROTOCOL_2), " my_ext" , " 1.0.0" , error);
377+
378+ ASSERT_TRUE (result.has_value ());
379+ EXPECT_TRUE (error.empty ());
380+ ASSERT_EQ (result->types .size (), 1u );
381+ EXPECT_EQ (result->types [0 ].type_name (), " MYTYPE" );
382+ }
383+
290384// Multiple types and funcs are all validated and returned.
291385TEST_F (ValidateExtensionRegistrationTest, MultipleTypesAndFuncs) {
292386 vef_type_desc_t td1 = make_v1_type (" TYPE_A" );
0 commit comments