@@ -1222,7 +1222,7 @@ static void check_markdown_attributes_node(test_batch_runner *runner, char *mark
12221222 cmark_node_free (doc );
12231223}
12241224
1225- static void verify_custome_attributes_node (test_batch_runner * runner ) {
1225+ static void verify_custom_attributes_node (test_batch_runner * runner ) {
12261226 // Should produce a TEXT node since there's no `()` to signify attributes
12271227 check_markdown_attributes_node (runner , "^[]" , CMARK_NODE_TEXT , NULL );
12281228 check_markdown_attributes_node (runner , "^[](" , CMARK_NODE_TEXT , NULL );
@@ -1234,6 +1234,103 @@ static void verify_custome_attributes_node(test_batch_runner *runner) {
12341234 check_markdown_attributes_node (runner , "^[](rainbow: 'extreme')" , CMARK_NODE_ATTRIBUTE , "rainbow: 'extreme'" );
12351235}
12361236
1237+ static cmark_node * parse_custom_attributues_footnote (test_batch_runner * runner , const char * markdown , cmark_node * * retdoc ) {
1238+ cmark_node * doc = cmark_parse_document (markdown , strlen (markdown ), CMARK_OPT_DEFAULT );
1239+ cmark_node * pg = cmark_node_first_child (doc );
1240+ INT_EQ (runner , cmark_node_get_type (pg ), CMARK_NODE_PARAGRAPH , "markdown '%s' did not produce a paragraph node" , markdown );
1241+ * retdoc = doc ;
1242+ return cmark_node_first_child (pg );
1243+ }
1244+
1245+ static void verify_custom_attributes_footnote_basic (test_batch_runner * runner ) {
1246+ static const char markdown [] =
1247+ "^[caffe][1]\n"
1248+ "\n"
1249+ "^[1]: rainbow: 'extreme', colors: { r: 255, g: 0, b: 0 }, corgicopter: true" ;
1250+ cmark_node * doc ;
1251+ cmark_node * attributeNode = parse_custom_attributues_footnote (runner , markdown , & doc );
1252+ INT_EQ (runner , cmark_node_get_type (attributeNode ), CMARK_NODE_ATTRIBUTE , "markdown '%s' did not produce an attribute node" , markdown );
1253+ STR_EQ (runner , cmark_node_get_attributes (attributeNode ),
1254+ "rainbow: 'extreme', colors: { r: 255, g: 0, b: 0 }, corgicopter: true" ,
1255+ "markdown '%s' did not produce the right attribute in footnote" , markdown );
1256+
1257+ cmark_node_free (doc );
1258+ }
1259+
1260+ static void verify_custom_attributes_footnote_multiple_footnotes (test_batch_runner * runner ) {
1261+ static const char markdown [] =
1262+ "^[food][1] and ^[drinks][2]\n"
1263+ "\n"
1264+ "^[1]: rainbow: 'fun'\n"
1265+ "^[2]: magic: 42" ;
1266+ cmark_node * doc ;
1267+ cmark_node * attributeNode1 = parse_custom_attributues_footnote (runner , markdown , & doc );
1268+ INT_EQ (runner , cmark_node_get_type (attributeNode1 ), CMARK_NODE_ATTRIBUTE , "markdown '%s' did not produce an attribute node" , markdown );
1269+ STR_EQ (runner , cmark_node_get_attributes (attributeNode1 ), "rainbow: 'fun'" , "markdown '%s' did not produce the right attribute in footnote" , markdown );
1270+ cmark_node * textNode = cmark_node_next (attributeNode1 ); // "and"
1271+ cmark_node * attributeNode2 = cmark_node_next (textNode );
1272+ INT_EQ (runner , cmark_node_get_type (attributeNode2 ), CMARK_NODE_ATTRIBUTE , "markdown '%s' did not produce an attribute node" , markdown );
1273+ STR_EQ (runner , cmark_node_get_attributes (attributeNode2 ), "magic: 42" , "markdown '%s' did not produce the right attribute in footnote" , markdown );
1274+
1275+ cmark_node_free (doc );
1276+ }
1277+
1278+ static void verify_custom_attributes_footnote_reuse (test_batch_runner * runner ) {
1279+ static const char markdown [] =
1280+ "^[pizza][1], ^[sandwich][2], ^[ice cream][2], and ^[salad][1]\n"
1281+ "\n"
1282+ "^[1]: has_tomato: true\n"
1283+ "^[2]: price: 12" ;
1284+ cmark_node * doc ;
1285+ cmark_node * pizzaNode = parse_custom_attributues_footnote (runner , markdown , & doc );
1286+ INT_EQ (runner , cmark_node_get_type (pizzaNode ), CMARK_NODE_ATTRIBUTE , "markdown '%s' did not produce an attribute node" , markdown );
1287+ STR_EQ (runner , cmark_node_get_attributes (pizzaNode ), "has_tomato: true" , "markdown '%s' did not produce the right attribute in footnote" , markdown );
1288+ cmark_node * sandwichNode = cmark_node_next (cmark_node_next (pizzaNode ));
1289+ INT_EQ (runner , cmark_node_get_type (sandwichNode ), CMARK_NODE_ATTRIBUTE , "markdown '%s' did not produce an attribute node" , markdown );
1290+ STR_EQ (runner , cmark_node_get_attributes (sandwichNode ), "price: 12" , "markdown '%s' did not produce the right attribute in footnote" , markdown );
1291+ cmark_node * icecreamNode = cmark_node_next (cmark_node_next (sandwichNode ));
1292+ INT_EQ (runner , cmark_node_get_type (icecreamNode ), CMARK_NODE_ATTRIBUTE , "markdown '%s' did not produce an attribute node" , markdown );
1293+ STR_EQ (runner , cmark_node_get_attributes (icecreamNode ), "price: 12" , "markdown '%s' did not produce the right attribute in footnote" , markdown );
1294+ cmark_node * saladNode = cmark_node_next (cmark_node_next (icecreamNode ));
1295+ INT_EQ (runner , cmark_node_get_type (saladNode ), CMARK_NODE_ATTRIBUTE , "markdown '%s' did not produce an attribute node" , markdown );
1296+ STR_EQ (runner , cmark_node_get_attributes (saladNode ), "has_tomato: true" , "markdown '%s' did not produce the right attribute in footnote" , markdown );
1297+
1298+ cmark_node_free (doc );
1299+ }
1300+
1301+ static void verify_custom_attributes_footnote_mixed_content (test_batch_runner * runner ) {
1302+ static const char markdown [] =
1303+ "^[attribute1][1], [a link][2], ^[attribute2][3], ^[attribute3][1]\n"
1304+ "\n"
1305+ "^[1]: rainbow: 'fun'\n"
1306+ "[2]: https://www.example.com\n"
1307+ "Lorem ipsum\n"
1308+ "\n"
1309+ "^[3]: universe: 42\n" ;
1310+ cmark_node * doc ;
1311+ cmark_node * attributeNode1 = parse_custom_attributues_footnote (runner , markdown , & doc );
1312+ INT_EQ (runner , cmark_node_get_type (attributeNode1 ), CMARK_NODE_ATTRIBUTE , "markdown '%s' did not produce an attribute node" , markdown );
1313+ STR_EQ (runner , cmark_node_get_attributes (attributeNode1 ), "rainbow: 'fun'" , "markdown '%s' did not produce the right attribute in footnote" , markdown );
1314+ cmark_node * linkNode = cmark_node_next (cmark_node_next (attributeNode1 ));
1315+ INT_EQ (runner , cmark_node_get_type (linkNode ), CMARK_NODE_LINK , "markdown '%s' did not produce an link node" , markdown );
1316+ STR_EQ (runner , cmark_node_get_url (linkNode ), "https://www.example.com" , "markdown '%s' did not produce the right link in footnote" , markdown );
1317+ cmark_node * attributeNode2 = cmark_node_next (cmark_node_next (linkNode ));
1318+ INT_EQ (runner , cmark_node_get_type (attributeNode2 ), CMARK_NODE_ATTRIBUTE , "markdown '%s' did not produce an attribute node" , markdown );
1319+ STR_EQ (runner , cmark_node_get_attributes (attributeNode2 ), "universe: 42" , "markdown '%s' did not produce the right attribute in footnote" , markdown );
1320+ cmark_node * attributeNode3 = cmark_node_next (cmark_node_next (attributeNode2 ));
1321+ INT_EQ (runner , cmark_node_get_type (attributeNode3 ), CMARK_NODE_ATTRIBUTE , "markdown '%s' did not produce an attribute node" , markdown );
1322+ STR_EQ (runner , cmark_node_get_attributes (attributeNode3 ), "rainbow: 'fun'" , "markdown '%s' did not produce the right attribute in footnote" , markdown );
1323+
1324+ cmark_node_free (doc );
1325+ }
1326+
1327+ static void verify_custom_attributes_node_with_footnote (test_batch_runner * runner ) {
1328+ verify_custom_attributes_footnote_basic (runner );
1329+ verify_custom_attributes_footnote_multiple_footnotes (runner );
1330+ verify_custom_attributes_footnote_reuse (runner );
1331+ verify_custom_attributes_footnote_mixed_content (runner );
1332+ }
1333+
12371334typedef void (* reentrant_call_func ) (void );
12381335
12391336static cmark_node * reentrant_parse_inline_ext (cmark_syntax_extension * self , cmark_parser * parser ,
@@ -1327,7 +1424,8 @@ int main() {
13271424 ref_source_pos (runner );
13281425 inline_only_opt (runner );
13291426 preserve_whitespace_opt (runner );
1330- verify_custome_attributes_node (runner );
1427+ verify_custom_attributes_node (runner );
1428+ verify_custom_attributes_node_with_footnote (runner );
13311429 parser_interrupt (runner );
13321430
13331431 test_print_summary (runner );
0 commit comments