@@ -1335,6 +1335,71 @@ mod tests {
13351335 assert_eq ! ( class_def. attributes[ 0 ] . source_location. line, 3 ) ;
13361336 }
13371337
1338+ fn parse_single_class_member_file ( member : & str ) -> Result < ClassUmlFile , ClassError > {
1339+ let input = format ! ( "@startuml\n class A {{\n {member}\n }}\n @enduml\n " ) ;
1340+ let mut parser = PumlClassParser ;
1341+ parser. parse_file (
1342+ & std:: rc:: Rc :: new ( std:: path:: PathBuf :: from ( "test.puml" ) ) ,
1343+ & input,
1344+ LogLevel :: Info ,
1345+ )
1346+ }
1347+
1348+ #[ test]
1349+ fn test_parse_empty_template_args_in_types ( ) {
1350+ let result = parse_single_class_member_file (
1351+ "+Run(const safecpp::Scope<>& scope, std::vector<Foo<>> items): Bar<>" ,
1352+ )
1353+ . unwrap ( ) ;
1354+
1355+ let ClassUmlTopLevel :: Types ( Element :: ClassDef ( class_def) ) = & result. elements [ 0 ] else {
1356+ panic ! ( "expected class element" ) ;
1357+ } ;
1358+
1359+ let method = & class_def. methods [ 0 ] ;
1360+ assert_eq ! (
1361+ method. params[ 0 ] . param_type. as_deref( ) ,
1362+ Some ( "const safecpp::Scope<>&" )
1363+ ) ;
1364+ assert_eq ! (
1365+ method. params[ 1 ] . param_type. as_deref( ) ,
1366+ Some ( "std::vector<Foo<>>" )
1367+ ) ;
1368+ assert_eq ! ( method. r#type. as_deref( ) , Some ( "Bar<>" ) ) ;
1369+ }
1370+
1371+ #[ test]
1372+ fn test_parse_empty_template_args_in_attribute ( ) {
1373+ let result = parse_single_class_member_file ( "+scope : safecpp::Scope<>" ) . unwrap ( ) ;
1374+
1375+ let ClassUmlTopLevel :: Types ( Element :: ClassDef ( class_def) ) = & result. elements [ 0 ] else {
1376+ panic ! ( "expected class element" ) ;
1377+ } ;
1378+
1379+ assert_eq ! (
1380+ class_def. attributes[ 0 ] . r#type. as_deref( ) ,
1381+ Some ( "safecpp::Scope<>" )
1382+ ) ;
1383+ }
1384+
1385+ #[ test]
1386+ fn test_parse_const_qualifier_after_empty_template_args ( ) {
1387+ let result = parse_single_class_member_file ( "+Get(): Foo<> <<const>>" ) . unwrap ( ) ;
1388+
1389+ let ClassUmlTopLevel :: Types ( Element :: ClassDef ( class_def) ) = & result. elements [ 0 ] else {
1390+ panic ! ( "expected class element" ) ;
1391+ } ;
1392+
1393+ assert_eq ! ( class_def. methods[ 0 ] . r#type. as_deref( ) , Some ( "Foo<>" ) ) ;
1394+ assert_eq ! ( class_def. methods[ 0 ] . modifiers, vec![ "<<const>>" ] ) ;
1395+ }
1396+
1397+ #[ test]
1398+ fn test_parse_malformed_template_args_rejected ( ) {
1399+ assert ! ( parse_single_class_member_file( "+f(Foo<int, > a)" ) . is_err( ) ) ;
1400+ assert ! ( parse_single_class_member_file( "+f(Foo<<int>> a)" ) . is_err( ) ) ;
1401+ }
1402+
13381403 #[ test]
13391404 fn test_parse_type_alias_source_location ( ) {
13401405 let input = r#"@startuml
0 commit comments